-
Notifications
You must be signed in to change notification settings - Fork 93
Solidity Bindings
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: