Skip to content
Afr Schoe edited this page Feb 8, 2022 · 1 revision

The Eth:: module supports all known transaction types. It will default to EIP-1559 transactions on the Ethereum network.

To create a transaction, create the payload first. To use a different network, just provide a chain_id. Note the Eth::Unit:: submodule for convenience.

payload = {
  chain_id: Eth::Chain::GOERLI,
  nonce: 5,
  priority_fee: 3 * Eth::Unit::GWEI,
  max_gas_fee: 69 * Eth::Unit::GWEI,
  gas_limit: 230_420,
  to: "0xCaA29806044A08E533963b2e573C1230A2cd9a2d",
  value: 0.069423 * Eth::Unit::ETHER,
}
# => {:chain_id=>5, :nonce=>5, :priority_fee=>0.3e10, :max_gas_fee=>0.69e11, :gas_limit=>230420, :to=>"0xCaA29806044A08E533963b2e573C1230A2cd9a2d", :value=>0.69423e17}

Create a new transaction with the payload. Note, because we specified priority_fee and max_gas_fee, it automatically creates an Eth::Tx::Eip1559 object indicating we want to create a type-2 transaction (EIP-1559).

tx = Eth::Tx.new payload
# => #<Eth::Tx::Eip1559:0x0000557e35fc5a68 @access_list=[], @amount=69423000000000000, @chain_id=5, @destination="CaA29806044A08E533963b2e573C1230A2cd9a2d", @gas_limit=230420, @max_fee_per_gas=69000000000, @max_priority_fee_per_gas=3000000000, @payload="", @sender="", @signature_r=0, @signature_s=0, @signature_y_parity=nil, @signer_nonce=5, @type=2>

Transactions can be signed by simply passing a keypair to the sign method.

signer_key = Eth::Key.new priv: "30137644b564785d01420f8043f043d74dcca64008e57c59f8ce713a0005a54b"
# => #<Eth::Key:0x0000557e36243178 @private_key=#<Secp256k1::PrivateKey:0x0000557e36242d40 @data="0\x13vD\xB5dx]\x01B\x0F\x80C\xF0C\xD7M\xCC\xA6@\b\xE5|Y\xF8\xCEq:\x00\x05\xA5K">, @public_key=#<Secp256k1::PublicKey:0x0000557e36242cf0>>
tx.sign signer_key
# => "cba302c0ebf8d0205a78ae97f560419b407e32e2426f416abc95a9bfc9dac09c"

This returns the transaction hash. To get the signed, raw transaction use hex.

tx.hex
# => "02f873050584b2d05e00851010b872008303841494caa29806044a08e533963b2e573c1230a2cd9a2d87f6a3d9c63df00080c080a03aa187d10b138d3e0155729adb961cd89e10f988ba2d19d6869770b9e5a23d10a04d40864600136ae214916043c7d63b849c98db757e95c86983a036982816e1af"

That's it. It can be broadcasted through whatever client one desires.

To create a legacy transaction (type 0), just replace the priority_fee and max_gas_fee options in the payload by gas_price. You'll receive an Eth::Tx::Legacy object that can be signed in the same way.

legacy_payload = {
  chain_id: Eth::Chain::ROPSTEN,
  nonce: 137,
  gas_price: 42 * Eth::Unit::GWEI,
  gas_limit: Eth::Tx::DEFAULT_GAS_LIMIT,
  to: "0xCaA29806044A08E533963b2e573C1230A2cd9a2d",
  value: 1 * Eth::Unit::ETHER,
}
#=> {:chain_id=>3, :nonce=>137, :gas_price=>0.42e11, :gas_limit=>21000, :to=>"0xCaA29806044A08E533963b2e573C1230A2cd9a2d", :value=>0.1e19}
legacy_tx = Eth::Tx.new legacy_payload
=> #<Eth::Tx::Legacy:0x0000558e5508e9c0
 @amount=1000000000000000000,  @chain_id=3,  @destination="CaA29806044A08E533963b2e573C1230A2cd9a2d",  @gas_limit=21000,  @gas_price=42000000000,  @payload="",  @sender="",  @signature_r=0,  @signature_s=0,  @signature_v=3,  @signer_nonce=137,  @type=0>

Type-1 transactions (EIP-2930) are also supported, by simply providing an access_list.

access_list = [["de0b295669a9fd93d5f28d9ec85e40f4cb697bae", ["0000000000000000000000000000000000000000000000000000000000000003", "0000000000000000000000000000000000000000000000000000000000000007"]], ["bb9bc244d798123fde783fcc1c72d3bb8c189413", []]]
# => [["de0b295669a9fd93d5f28d9ec85e40f4cb697bae", ["0000000000000000000000000000000000000000000000000000000000000003", "0000000000000000000000000000000000000000000000000000000000000007"]], ["bb9bc244d798123fde783fcc1c72d3bb8c189413", []]]
intrinsic_gas = Eth::Tx.estimate_intrinsic_gas "", access_list
# => 29600
type1_payload = {
  chain_id: Eth::Chain::PRIVATE_GETH,
  nonce: 0,
  gas_price: 1 * Eth::Unit::GWEI,
  gas_limit: intrinsic_gas,
  to: "0xCaA29806044A08E533963b2e573C1230A2cd9a2d",
  access_list: access_list
}
# => {:chain_id=>1337, :nonce=>0, :gas_price=>0.1e10, :gas_limit=>29600, :to=>"0xCaA29806044A08E533963b2e573C1230A2cd9a2d", :access_list=> [["de0b295669a9fd93d5f28d9ec85e40f4cb697bae", ["0000000000000000000000000000000000000000000000000000000000000003", "0000000000000000000000000000000000000000000000000000000000000007"]], ["bb9bc244d798123fde783fcc1c72d3bb8c189413", []]]}
type1_tx = Eth::Tx.new type1_payload
# => #<Eth::Tx::Eip2930:0x0000558e54fc5f48 @access_list=[["\xDE\v)Vi\xA9\xFD\x93\xD5\xF2\x8D\x9E\xC8^@\xF4\xCBi{\xAE",  ["\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\a"]], ["\xBB\x9B\xC2D\xD7\x98\x12?\xDEx?\xCC\x1Cr\xD3\xBB\x8C\x18\x94\x13", []]], @amount=0, @chain_id=1337, @destination="CaA29806044A08E533963b2e573C1230A2cd9a2d", @gas_limit=29600, @gas_price=1000000000, @payload="", @sender="", @signature_r=0, @signature_s=0, @signature_y_parity=nil, @signer_nonce=0, @type=1>

Note, how Eth::Tx.estimate_intrinsic_gas can compute the required gas_limit by passing the data payload and access list to it.

You can also decode raw transactions and create unsigned copies.

decoded_tx = Eth::Tx.decode "02f873050584b2d05e00851010b872008303841494caa29806044a08e533963b2e573c1230a2cd9a2d87f6a3d9c63df00080c080a03aa187d10b138d3e0155729adb961cd89e10f988ba2d19d6869770b9e5a23d10a04d40864600136ae214916043c7d63b849c98db757e95c86983a036982816e1af"
# => #<Eth::Tx::Eip1559:0x0000558e54f0fa18  @access_list=[],  @amount=69423000000000000,  @chain_id=5,  @destination="caa29806044a08e533963b2e573c1230a2cd9a2d",  @gas_limit=230420,  @max_fee_per_gas=69000000000,  @max_priority_fee_per_gas=3000000000,  @payload="",  @sender="0c53FFA57Ec554451315c2568d22477dB8e71356",  @signature_r="3aa187d10b138d3e0155729adb961cd89e10f988ba2d19d6869770b9e5a23d10",  @signature_s="4d40864600136ae214916043c7d63b849c98db757e95c86983a036982816e1af",  @signature_y_parity=0,  @signer_nonce=5,  @type=2>
tx_copy = Eth::Tx.unsigned_copy decoded_tx
# => #<Eth::Tx::Eip1559:0x0000558e55077568  @access_list=[],  @amount=69423000000000000,  @chain_id=5,  @destination="caa29806044a08e533963b2e573c1230a2cd9a2d",  @gas_limit=230420,  @max_fee_per_gas=69000000000,  @max_priority_fee_per_gas=3000000000,  @payload="",  @sender="",  @signature_r=0,  @signature_s=0,  @signature_y_parity=nil,  @signer_nonce=5,  @type=2>

That's it. Check out the API documentation for a more complete picture.

Clone this wiki locally