From f51287c00a5348681bd2906ef99130d531de3cc7 Mon Sep 17 00:00:00 2001 From: Amanda Sposito Date: Tue, 15 May 2018 18:08:14 -0300 Subject: [PATCH] Add solidity command line compiler to smart contracts --- .../smart_contract/solidity/code_compiler.ex | 61 +++++++++++++++++++ .../solidity/code_compiler_test.exs | 60 ++++++++++++++++++ solc.bash | 3 + 3 files changed, 124 insertions(+) create mode 100644 apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex create mode 100644 apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs create mode 100755 solc.bash diff --git a/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex new file mode 100644 index 0000000000..6100496ab5 --- /dev/null +++ b/apps/explorer/lib/explorer/smart_contract/solidity/code_compiler.ex @@ -0,0 +1,61 @@ +defmodule Explorer.SmartContract.Solidity.CodeCompiler do + @doc ~S""" + Compiles a code in the solidity command line. + + Returns a `Map`. + + ## Examples + iex(1)> Explorer.SmartContract.Solidity.CodeCompiler.run("SimpleStorage", "pragma solidity ^0.4.23; contract SimpleStorage {uint storedData; function set(uint x) public {storedData = x; } function get() public constant returns (uint) {return storedData; } }") + %{ + "contracts" => %{ + "SimpleStorage" => %{ + "SimpleStorage" => %{ + "evm" => %{ + "bytecode" => %{ + "linkReferences" => %{}, + "object" => "608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a7230582034dc7149794530e246d2c1bba8bfaf0ccf5d7ee9bb359cd1cdd7b65d1b23bdf90029", + "opcodes" => "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0xDF DUP1 PUSH2 0x1F PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN STOP PUSH1 0x80 PUSH1 0x40 MSTORE PUSH1 0x4 CALLDATASIZE LT PUSH1 0x49 JUMPI PUSH1 0x0 CALLDATALOAD PUSH29 0x100000000000000000000000000000000000000000000000000000000 SWAP1 DIV PUSH4 0xFFFFFFFF AND DUP1 PUSH4 0x60FE47B1 EQ PUSH1 0x4E JUMPI DUP1 PUSH4 0x6D4CE63C EQ PUSH1 0x78 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x59 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x76 PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 DUP1 DUP1 CALLDATALOAD SWAP1 PUSH1 0x20 ADD SWAP1 SWAP3 SWAP2 SWAP1 POP POP POP PUSH1 0xA0 JUMP JUMPDEST STOP JUMPDEST CALLVALUE DUP1 ISZERO PUSH1 0x83 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x8A PUSH1 0xAA JUMP JUMPDEST PUSH1 0x40 MLOAD DUP1 DUP3 DUP2 MSTORE PUSH1 0x20 ADD SWAP2 POP POP PUSH1 0x40 MLOAD DUP1 SWAP2 SUB SWAP1 RETURN JUMPDEST DUP1 PUSH1 0x0 DUP2 SWAP1 SSTORE POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 SLOAD SWAP1 POP SWAP1 JUMP STOP LOG1 PUSH6 0x627A7A723058 KECCAK256 CALLVALUE 0xdc PUSH18 0x49794530E246D2C1BBA8BFAF0CCF5D7EE9BB CALLDATALOAD SWAP13 0xd1 0xcd 0xd7 0xb6 0x5d SHL 0x23 0xbd 0xf9 STOP 0x29 ", + "sourceMap" => "25:157:0:-;;;;8:9:-1;5:2;;;30:1;27;20:12;5:2;25:157:0;;;;;;;" + } + }, + "metadata" => "{\"compiler\":{\"version\":\"0.4.23+commit.124ca40d\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"constant\":false,\"inputs\":[{\"name\":\"x\",\"type\":\"uint256\"}],\"name\":\"set\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"get\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"methods\":{}},\"userdoc\":{\"methods\":{}}},\"settings\":{\"compilationTarget\":{\"SimpleStorage\":\"SimpleStorage\"},\"evmVersion\":\"byzantium\",\"libraries\":{},\"optimizer\":{\"enabled\":false,\"runs\":200},\"remappings\":[]},\"sources\":{\"SimpleStorage\":{\"keccak256\":\"0x3f5ecc4c6077dffdfc98d9781295205833bf0558bc2a0c86fc3d5f246808ba34\",\"urls\":[\"bzzr://60d588b13340f26a038f51934f9b8c3cf3928372bc4358848a86960040a3a8e2\"]}},\"version\":1}" + } + } + }, + "sources" => %{"SimpleStorage" => %{"id" => 0}} + } + + """ + def run(name, code) do + { response, _status } = System.cmd( + Path.expand("../../solc.bash"), + [generate_settings(name, code)] + ) + + Jason.decode!(response) + end + + def generate_settings(name, code) do + """ + { + "language": "Solidity", + "sources": { + "#{name}": + { + "content": "#{code}" + } + }, + "settings": { + "outputSelection": { + "*": { + "*": [ "metadata", "evm.bytecode" ] + }, + "def": { + "MyContract": [ "abi", "evm.bytecode.opcodes" ] + } + } + } + } + """ + end +end diff --git a/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs new file mode 100644 index 0000000000..b3c4e13336 --- /dev/null +++ b/apps/explorer/test/explorer/smart_contract/solidity/code_compiler_test.exs @@ -0,0 +1,60 @@ +defmodule Explorer.SmartContract.Solidity.CodeCompilerTest do + use ExUnit.Case, async: true + + doctest Explorer.SmartContract.Solidity.CodeCompiler + + alias Explorer.SmartContract.Solidity.CodeCompiler + + describe "run" do + test "compiles a smart contract using the solidity command line" do + name = "SimpleStorage" + + code = """ + pragma solidity ^0.4.23; + + contract SimpleStorage { + uint storedData; + + function set(uint x) public { + storedData = x; + } + + function get() public constant returns (uint) { + return storedData; + } + } + """ + + response = CodeCompiler.run(name, code) + + assert response["contracts"] != nil + end + end + + describe "generate_settings" do + test "creates a json file with the solidity compiler expected settings" do + name = "SimpleStorage" + + code = """ + pragma solidity ^0.4.23; + + contract SimpleStorage { + uint storedData; + + function set(uint x) public { + storedData = x; + } + + function get() public constant returns (uint) { + return storedData; + } + } + """ + + generated = CodeCompiler.generate_settings(name, code) + + assert String.contains?(generated, "contract SimpleStorage") == true + assert String.contains?(generated, "settings") == true + end + end +end diff --git a/solc.bash b/solc.bash new file mode 100755 index 0000000000..1350298daa --- /dev/null +++ b/solc.bash @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "$1" | solc --standard-json