Skip to content
Afr Schoe edited this page May 16, 2022 · 1 revision

The eth gem comes with Solidity compiler bindings, i.e., if you have a compiler compiled (solc) it is able to read and compile smart contracts from within Ruby.

Note that usually, you don't want to interact with Solidity directly. We have a smart contract functionality available in Eth::Contract that takes care of all the logic and also compiles your contract if necessary. This section below is aimed at developers that require, for any reason, to directly interact with the Solidity compiler.

The Eth::Solidity class allows for wrapping a system-level solidity compiler.

solc = Eth::Solidity.new
# => #<Eth::Solidity:0x000055a508e030c8 @compiler="/usr/bin/solc">

To compile a contract, simply pass a .sol file to the compiler. Note that the solidity contract needs to match your system's Solidity compiler version.

contract = solc.compile "spec/fixtures/contracts/greeter.sol"
# => {"Greeter"=>
#   {"abi"=>
#     [{"inputs"=>[{"internalType"=>"string", "name"=>"message", "type"=>"string"}], "stateMutability"=>"nonpayable", "type"=>"constructor"},
#      {"inputs"=>[], "name"=>"greet", "outputs"=>[{"internalType"=>"string", "name"=>"", "type"=>"string"}], "stateMutability"=>"view", "type"=>"function"},
#      {"inputs"=>[], "name"=>"kill", "outputs"=>[], "stateMutability"=>"nonpayable", "type"=>"function"}],
#    "bin"=>
#     "608060405234801561001057600080fd5b506040516103fe3803806103fe83398101604081905261002f9161010a565b600080546001600160a01b03191633179055805161005490600190602084019061005b565b5050610213565b828054610067906101d9565b90600052602060002090601f01602090048101928261008957600085556100cf565b82601f106100a257805160ff19168380011785556100cf565b828001600101855582156100cf579182015b828111156100cf5782518255916020019190600101906100b4565b506100db9291506100df565b5090565b5b808211156100db57600081556001016100e0565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561011d57600080fd5b82516001600160401b038082111561013457600080fd5b818501915085601f83011261014857600080fd5b81518181111561015a5761015a6100f4565b604051601f8201601f19908116603f01168101908382118183101715610182576101826100f4565b81604052828152888684870101111561019a57600080fd5b600093505b828410156101bc578484018601518185018701529285019261019f565b828411156101cd5760008684830101525b98975050505050505050565b600181811c908216806101ed57607f821691505b60208210810361020d57634e487b7160e01b600052602260045260246000fd5b50919050565b6101dc806102226000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806341c0e1b51461003b578063cfae321714610045575b600080fd5b610043610063565b005b61004d610085565b60405161005a9190610117565b60405180910390f35b6000546001600160a01b03163303610083576000546001600160a01b0316ff5b565b6060600180546100949061016c565b80601f01602080910402602001604051908101604052809291908181526020018280546100c09061016c565b801561010d5780601f106100e25761010080835404028352916020019161010d565b820191906000526020600020905b8154815290600101906020018083116100f057829003601f168201915b5050505050905090565b600060208083528351808285015260005b8181101561014457858101830151858201604001528201610128565b81811115610156576000604083870101525b50601f01601f1916929092016040019392505050565b600181811c9082168061018057607f821691505b6020821081036101a057634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220db6585b230c7143cf1501be9777110cdf752198b8e39406b7fa1a0be34ac6fe064736f6c634300080d0033"},
#  "Mortal"=>
#   {"abi"=>[{"inputs"=>[], "stateMutability"=>"nonpayable", "type"=>"constructor"}, {"inputs"=>[], "name"=>"kill", "outputs"=>[], "stateMutability"=>"nonpayable", "type"=>"function"}],
#    "bin"=>
#     "6080604052348015600f57600080fd5b50600080546001600160a01b03191633179055608c806100306000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806341c0e1b514602d575b600080fd5b60336035565b005b6000546001600160a01b031633036054576000546001600160a01b0316ff5b56fea2646970667358221220d08f29516776e81bbb1a8424abdd8a1223d043c7cd194e29262bdea11acdf91264736f6c634300080d0033"}}

The compiler returns a JSON object containing all contracts from the file including ABI and payload.

The payload should be stripped before handing it over to transactions.

payload = contract["Greeter"]["bin"].strip
# => "608060405234801561001057600080fd5b506040516103fe3803806103fe83398101604081905261002f9161010a565b600080546001600160a01b03191633179055805161005490600190602084019061005b565b5050610213565b828054610067906101d9565b90600052602060002090601f01602090048101928261008957600085556100cf565b82601f106100a257805160ff19168380011785556100cf565b828001600101855582156100cf579182015b828111156100cf5782518255916020019190600101906100b4565b506100db9291506100df565b5090565b5b808211156100db57600081556001016100e0565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561011d57600080fd5b82516001600160401b038082111561013457600080fd5b818501915085601f83011261014857600080fd5b81518181111561015a5761015a6100f4565b604051601f8201601f19908116603f01168101908382118183101715610182576101826100f4565b81604052828152888684870101111561019a57600080fd5b600093505b828410156101bc578484018601518185018701529285019261019f565b828411156101cd5760008684830101525b98975050505050505050565b600181811c908216806101ed57607f821691505b60208210810361020d57634e487b7160e01b600052602260045260246000fd5b50919050565b6101dc806102226000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806341c0e1b51461003b578063cfae321714610045575b600080fd5b610043610063565b005b61004d610085565b60405161005a9190610117565b60405180910390f35b6000546001600160a01b03163303610083576000546001600160a01b0316ff5b565b6060600180546100949061016c565b80601f01602080910402602001604051908101604052809291908181526020018280546100c09061016c565b801561010d5780601f106100e25761010080835404028352916020019161010d565b820191906000526020600020905b8154815290600101906020018083116100f057829003601f168201915b5050505050905090565b600060208083528351808285015260005b8181101561014457858101830151858201604001528201610128565b81811115610156576000604083870101525b50601f01601f1916929092016040019392505050565b600181811c9082168061018057607f821691505b6020821081036101a057634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220db6585b230c7143cf1501be9777110cdf752198b8e39406b7fa1a0be34ac6fe064736f6c634300080d0033"

The payload can be used to estimate the intrinsic gas required. Don't forget add the CREATE gas.

gas = Eth::Tx.estimate_intrinsic_gas(payload) + Eth::Tx::CREATE_GAS
# => 68548

The resulting payload and gas limit can be used to construct transaction parameters.

params = {
  chain_id: Eth::Chain::GOERLI,
  nonce: 5,
  priority_fee: 3 * Eth::Unit::GWEI,
  max_gas_fee: 69 * Eth::Unit::GWEI,
  gas_limit: gas,
  data: payload,
}
# => {:chain_id=>5,
#  :nonce=>5,
#  :priority_fee=>0.3e10,
#  :max_gas_fee=>0.69e11,
#  :gas_limit=>68548,
#  :data=>
#   "608060405234801561001057600080fd5b506040516103fe3803806103fe83398101604081905261002f9161010a565b600080546001600160a01b03191633179055805161005490600190602084019061005b565b5050610213565b828054610067906101d9565b90600052602060002090601f01602090048101928261008957600085556100cf565b82601f106100a257805160ff19168380011785556100cf565b828001600101855582156100cf579182015b828111156100cf5782518255916020019190600101906100b4565b506100db9291506100df565b5090565b5b808211156100db57600081556001016100e0565b634e487b7160e01b600052604160045260246000fd5b6000602080838503121561011d57600080fd5b82516001600160401b038082111561013457600080fd5b818501915085601f83011261014857600080fd5b81518181111561015a5761015a6100f4565b604051601f8201601f19908116603f01168101908382118183101715610182576101826100f4565b81604052828152888684870101111561019a57600080fd5b600093505b828410156101bc578484018601518185018701529285019261019f565b828411156101cd5760008684830101525b98975050505050505050565b600181811c908216806101ed57607f821691505b60208210810361020d57634e487b7160e01b600052602260045260246000fd5b50919050565b6101dc806102226000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c806341c0e1b51461003b578063cfae321714610045575b600080fd5b610043610063565b005b61004d610085565b60405161005a9190610117565b60405180910390f35b6000546001600160a01b03163303610083576000546001600160a01b0316ff5b565b6060600180546100949061016c565b80601f01602080910402602001604051908101604052809291908181526020018280546100c09061016c565b801561010d5780601f106100e25761010080835404028352916020019161010d565b820191906000526020600020905b8154815290600101906020018083116100f057829003601f168201915b5050505050905090565b600060208083528351808285015260005b8181101561014457858101830151858201604001528201610128565b81811115610156576000604083870101525b50601f01601f1916929092016040019392505050565b600181811c9082168061018057607f821691505b6020821081036101a057634e487b7160e01b600052602260045260246000fd5b5091905056fea2646970667358221220db6585b230c7143cf1501be9777110cdf752198b8e39406b7fa1a0be34ac6fe064736f6c634300080d0033"}

The following transaction could be used to deploy the Greeter contract to the Goerli testnet.

Eth::Tx.new params
# => #<Eth::Tx::Eip1559:0x000055a508f83bc8
#  @access_list=[],
#  @amount=0,
#  @chain_id=5,
#  @destination="",
#  @gas_limit=68548,
#  @max_fee_per_gas=69000000000,
#  @max_priority_fee_per_gas=3000000000,
#  @payload=
#   "`\x80`@R4\x80\x15a\x00\x10W`\x00\x80\xFD[P`@Qa\x03\xFE8\x03\x80a\x03\xFE\x839\x81\x01`@\x81\x90Ra\x00/\x91a\x01\nV[`\x00\x80T`\x01`\x01`\xA0\e\x03\x19\x163\x17\x90U\x80Qa\x00T\x90`\x01\x90` \x84\x01\x90a\x00[V[PPa\x02\x13V[\x82\x80Ta\x00g\x90a\x01\xD9V[\x90`\x00R` `\x00 \x90`\x1F\x01` \x90\x04\x81\x01\x92\x82a\x00\x89W`\x00\x85Ua\x00\xCFV[\x82`\x1F\x10a\x00\xA2W\x80Q`\xFF\x19\x16\x83\x80\x01\x17\x85Ua\x00\xCFV[\x82\x80\x01`\x01\x01\x85U\x82\x15a\x00\xCFW\x91\x82\x01[\x82\x81\x11\x15a\x00\xCFW\x82Q\x82U\x91` \x01\x91\x90`\x01\x01\x90a\x00\xB4V[Pa\x00\xDB\x92\x91Pa\x00\xDFV[P\x90V[[\x80\x82\x11\x15a\x00\xDBW`\x00\x81U`\x01\x01a\x00\xE0V[cNH{q`\xE0\e`\x00R`A`\x04R`$`\x00\xFD[`\x00` \x80\x83\x85\x03\x12\x15a\x01\x1DW`\x00\x80\xFD[\x82Q`\x01`\x01`@\e\x03\x80\x82\x11\x15a\x014W`\x00\x80\xFD[\x81\x85\x01\x91P\x85`\x1F\x83\x01\x12a\x01HW`\x00\x80\xFD[\x81Q\x81\x81\x11\x15a\x01ZWa\x01Za\x00\xF4V[`@Q`\x1F\x82\x01`\x1F\x19\x90\x81\x16`?\x01\x16\x81\x01\x90\x83\x82\x11\x81\x83\x10\x17\x15a\x01\x82Wa\x01\x82a\x00\xF4V[\x81`@R\x82\x81R\x88\x86\x84\x87\x01\x01\x11\x15a\x01\x9AW`\x00\x80\xFD[`\x00\x93P[\x82\x84\x10\x15a\x01\xBCW\x84\x84\x01\x86\x01Q\x81\x85\x01\x87\x01R\x92\x85\x01\x92a\x01\x9FV[\x82\x84\x11\x15a\x01\xCDW`\x00\x86\x84\x83\x01\x01R[\x98\x97PPPPPPPPV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x01\xEDW`\x7F\x82\x16\x91P[` \x82\x10\x81\x03a\x02\rWcNH{q`\xE0\e`\x00R`\"`\x04R`$`\x00\xFD[P\x91\x90PV[a\x01\xDC\x80a\x02\"`\x009`\x00\xF3\xFE`\x80`@R4\x80\x15a\x00\x10W`\x00\x80\xFD[P`\x046\x10a\x006W`\x005`\xE0\x1C\x80cA\xC0\xE1\xB5\x14a\x00;W\x80c\xCF\xAE2\x17\x14a\x00EW[`\x00\x80\xFD[a\x00Ca\x00cV[\x00[a\x00Ma\x00\x85V[`@Qa\x00Z\x91\x90a\x01\x17V[`@Q\x80\x91\x03\x90\xF3[`\x00T`\x01`\x01`\xA0\e\x03\x163\x03a\x00\x83W`\x00T`\x01`\x01`\xA0\e\x03\x16\xFF[V[```\x01\x80Ta\x00\x94\x90a\x01lV[\x80`\x1F\x01` \x80\x91\x04\x02` \x01`@Q\x90\x81\x01`@R\x80\x92\x91\x90\x81\x81R` \x01\x82\x80Ta\x00\xC0\x90a\x01lV[\x80\x15a\x01\rW\x80`\x1F\x10a\x00\xE2Wa\x01\x00\x80\x83T\x04\x02\x83R\x91` \x01\x91a\x01\rV[\x82\x01\x91\x90`\x00R` `\x00 \x90[\x81T\x81R\x90`\x01\x01\x90` \x01\x80\x83\x11a\x00\xF0W\x82\x90\x03`\x1F\x16\x82\x01\x91[PPPPP\x90P\x90V[`\x00` \x80\x83R\x83Q\x80\x82\x85\x01R`\x00[\x81\x81\x10\x15a\x01DW\x85\x81\x01\x83\x01Q\x85\x82\x01`@\x01R\x82\x01a\x01(V[\x81\x81\x11\x15a\x01VW`\x00`@\x83\x87\x01\x01R[P`\x1F\x01`\x1F\x19\x16\x92\x90\x92\x01`@\x01\x93\x92PPPV[`\x01\x81\x81\x1C\x90\x82\x16\x80a\x01\x80W`\x7F\x82\x16\x91P[` \x82\x10\x81\x03a\x01\xA0WcNH{q`\xE0\e`\x00R`\"`\x04R`$`\x00\xFD[P\x91\x90PV\xFE\xA2dipfsX\"\x12 \xDBe\x85\xB20\xC7\x14<\xF1P\e\xE9wq\x10\xCD\xF7R\x19\x8B\x8E9@k\x7F\xA1\xA0\xBE4\xACo\xE0dsolcC\x00\b\r\x003",
#  @sender="",
#  @signature_r=0,
#  @signature_s=0,
#  @signature_y_parity=nil,
#  @signer_nonce=5,
#  @type=2>

Now, you just have to sign and broadcast the transaction.

As mentioned earlier, before working with solc directly, take a look at the Contract class which might be what you need in most cases, see:

Clone this wiki locally