Represents a V2 or EIP-1559 transaction.
API Functions
| Function | Arity | Description | Param Kinds |
|---|---|---|---|
from_json | 1 | Decode an EIP-1559 transaction JSON object from eth_getBlockBy* into a V2 struct. | params: exchange_data |
recover_signer | 1 | Recover the signer address from a signed EIP-1559 transaction. | transaction: value |
get_signature | 1 | Extract the packed signature from a signed EIP-1559 transaction. | transaction: value |
add_signature | 4 | Attach a packed Ethereum signature to an EIP-1559 transaction. | transaction: value, signature: value |
add_signature | 4 | Attach an Ethereum signature to an EIP-1559 transaction. | transaction: value, v: value, r: value, s: value |
decode | 1 | Decode typed RLP bytes into an EIP-1559 transaction struct. | trx_enc: value |
encode | 1 | Encode an EIP-1559 transaction as typed RLP bytes for signing or broadcast. | transaction: value |
new | 12 | Construct an EIP-1559 transaction struct with explicit signature fields. | nonce: exchange_data, max_priority_fee_per_gas: exchange_data, max_fee_per_gas: exchange_data, gas_limit: exchange_data, destination: value, amount: value, data: value, access_list: value, signature_y_parity: value, signature_r: value, signature_s: value, chain_id: exchange_data |
new | 12 | Construct an EIP-1559 transaction struct. | nonce: exchange_data, max_priority_fee_per_gas: exchange_data, max_fee_per_gas: exchange_data, gas_limit: exchange_data, destination: value, amount: value, data: value, access_list: value, chain_id: exchange_data |
Summary
Functions
Adds a signature to a transaction from a packed binary (r <> s <> v), deriving signature_y_parity from v.
Adds a signature to a transaction. This overwrites the signature_y_parity, signature_r and signature_s fields.
Decode an RLP-encoded transaction.
Build an RLP-encoded transaction. Note: if the transaction does not have a signature
set (that is, signature_y_parity, signature_r or signature_s are nil), then
we will encode a partial transaction (which can be used for signing).
Decodes an EIP-1559 (type 2) transaction object as returned in the
transactions array of eth_getBlockByNumber / eth_getBlockByHash
when include_transaction_details: true is requested.
Recovers a signature from a transaction, if it's been signed. Otherwise returns an error.
Constructs a new V2 (EIP-1559) Ethereum transaction.
Like new/9 but also accepts explicit signature fields (signature_y_parity, signature_r, signature_s).
Recovers the signer from a given transaction, if it's been signed.
Types
@type t() :: %Cartouche.Transaction.V2{ access_list: [{<<_::160>>, [<<_::256>>]}], amount: integer(), chain_id: integer(), data: binary(), destination: <<_::160>> | nil, gas_limit: integer(), max_fee_per_gas: integer(), max_priority_fee_per_gas: integer(), nonce: integer(), signature_r: <<_::256>> | nil, signature_s: <<_::256>> | nil, signature_y_parity: boolean() | nil }
Functions
Adds a signature to a transaction from a packed binary (r <> s <> v), deriving signature_y_parity from v.
Adds a signature to a transaction. This overwrites the signature_y_parity, signature_r and signature_s fields.
Examples
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], 1, 0x01, 0x02, :goerli)
...> |> Cartouche.Transaction.V2.add_signature(true, <<1::256>>, <<2::256>>)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [<<2::160>>, <<3::160>>],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], 1, 0x01, 0x02, :goerli)
...> |> Cartouche.Transaction.V2.add_signature(<<1::256, 2::256, 1::8>>)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [<<2::160>>, <<3::160>>],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], 1, 0x01, 0x02, :goerli)
...> |> Cartouche.Transaction.V2.add_signature(<<1::256, 2::256, 27::8>>)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [<<2::160>>, <<3::160>>],
signature_y_parity: false,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], 1, 0x01, 0x02, :goerli)
...> |> Cartouche.Transaction.V2.add_signature(<<1::256, 2::256, 38::8>>)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [<<2::160>>, <<3::160>>],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], 1, 0x01, 0x02, :goerli)
...> |> Cartouche.Transaction.V2.add_signature(<<1::256, 2::256, 3838::16>>)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [<<2::160>>, <<3::160>>],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}
Decode an RLP-encoded transaction.
Accepts both signed payloads and unsigned signing payloads. Unsigned
payloads omit signature_y_parity, signature_r, and signature_s; those
fields decode as nil.
Examples
iex> use Cartouche.Hex
iex> Cartouche.Transaction.V2.decode(~h[0x02EF0501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203C0010102])
{:ok, %Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}}
iex> use Cartouche.Hex
iex> Cartouche.Transaction.V2.decode(~h[0x02F87F0501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203F84FF7940000000000000000000000000000000000000002E1A00000000000000000000000000000000000000000000000000000000000000016D6940000000000000000000000000000000000000003C0010102])
{:ok, %Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [{<<2::160>>, [<<22::256>>]}, {<<3::160>>, []}],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}}
iex> use Cartouche.Hex
iex> Cartouche.Transaction.V2.decode(~h[0x02F9027382210501843B9ACA00843C2390F1830493E09400AEA4B2242ABC8BB4BB78D537A67A245A7BEC6480B90204DEFF4B240000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000A000000000000000000000000000000000000000000000000000000000000007B0000000000000000000000003B72952436D0DCACFA7D7691C0CF4DE6DD5BAA7E0000000000000000000000003B72952436D0DCACFA7D7691C0CF4DE6DD5BAA7E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B2C639C533813F4AA9D7837CAF62653D097FF85000000000000000000000000833589FCD6EDB6E08F4C7C32D4F71B54BDA0291300000000000000000000000000000000000000000000000000000000000AAE6000000000000000000000000000000000000000000000000000000000000AAE60000000000000000000000000000000000000000000000000000000000000000A00000000000000000000000000000000000000000000000000000000002ADA240000000000000000000000000000000000000000000000000000000067D38314000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000C080A0019C8102CB582C309B0D2ABABB6AEB683A8FBC7E2044665F84669F0A73865B9AA03732EB6644FC11E850A0FED8EBE403B4C2F5D1F1AEC961EACCF1F7BAA55615A6])
{:ok, %Cartouche.Transaction.V2{
chain_id: 8453,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 1008963825,
gas_limit: 300000,
destination: ~h[0x00aea4b2242abc8bb4bb78d537a67a245a7bec64],
amount: 0,
data: ~h[0xdeff4b240000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000003b72952436d0dcacfa7d7691c0cf4de6dd5baa7e0000000000000000000000003b72952436d0dcacfa7d7691c0cf4de6dd5baa7e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000aae6000000000000000000000000000000000000000000000000000000000000aae60000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000002ada240000000000000000000000000000000000000000000000000000000067d38314000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000],
access_list: [],
signature_y_parity: false,
signature_r: ~h[0x019c8102cb582c309b0d2ababb6aeb683a8fbc7e2044665f84669f0a73865b9a],
signature_s: ~h[0x3732eb6644fc11e850a0fed8ebe403b4c2f5d1f1aec961eaccf1f7baa55615a6]
}}
@spec encode( t() | %Cartouche.Transaction.V2{ access_list: list() | nil, amount: integer() | nil, chain_id: integer() | nil, data: binary() | nil, destination: <<_::160>> | nil, gas_limit: integer() | nil, max_fee_per_gas: integer() | nil, max_priority_fee_per_gas: integer() | nil, nonce: integer() | nil, signature_r: nil, signature_s: nil, signature_y_parity: nil } ) :: binary()
Build an RLP-encoded transaction. Note: if the transaction does not have a signature
set (that is, signature_y_parity, signature_r or signature_s are nil), then
we will encode a partial transaction (which can be used for signing).
Examples
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [], :goerli)
...> |> Cartouche.Transaction.V2.encode()
...> |> Cartouche.Hex.encode_big_hex()
"0x02EC0501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203C0"
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], :goerli)
...> |> Cartouche.Transaction.V2.encode()
...> |> Cartouche.Hex.encode_big_hex()
"0x02F8560501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203EA940000000000000000000000000000000000000002940000000000000000000000000000000000000003"
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [], true, <<0x01::256>>, <<0x02::256>>, :goerli)
...> |> Cartouche.Transaction.V2.encode()
...> |> Cartouche.Hex.encode_big_hex()
"0x02EF0501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203C0010102"
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], true, <<0x01::256>>, <<0x02::256>>, :goerli)
...> |> Cartouche.Transaction.V2.encode()
...> |> Cartouche.Hex.encode_big_hex()
"0x02F8590501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203EA940000000000000000000000000000000000000002940000000000000000000000000000000000000003010102"
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [{<<2::160>>, [<<22::256>>]}, {<<3::160>>, []}], true, <<0x01::256>>, <<0x00, 0x02::248>>, :goerli)
...> |> Cartouche.Transaction.V2.encode()
...> |> Cartouche.Hex.encode_big_hex()
"0x02F87F0501843B9ACA0085174876E800830186A09400000000000000000000000000000000000000010283010203F84FF7940000000000000000000000000000000000000002E1A00000000000000000000000000000000000000000000000000000000000000016D6940000000000000000000000000000000000000003C0010102"
iex> use Cartouche.Hex
iex> %Cartouche.Transaction.V2{
...> chain_id: 8453,
...> nonce: 1,
...> max_priority_fee_per_gas: 1000000000,
...> max_fee_per_gas: 1008963825,
...> gas_limit: 300000,
...> destination: ~h[0x00aea4b2242abc8bb4bb78d537a67a245a7bec64],
...> amount: 0,
...> data: ~h[0xdeff4b240000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000007b0000000000000000000000003b72952436d0dcacfa7d7691c0cf4de6dd5baa7e0000000000000000000000003b72952436d0dcacfa7d7691c0cf4de6dd5baa7e00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000000000000000000000000000000000000000aae6000000000000000000000000000000000000000000000000000000000000aae60000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000002ada240000000000000000000000000000000000000000000000000000000067d38314000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000],
...> access_list: [],
...> signature_y_parity: false,
...> signature_r: ~h[0x019c8102cb582c309b0d2ababb6aeb683a8fbc7e2044665f84669f0a73865b9a],
...> signature_s: ~h[0x3732eb6644fc11e850a0fed8ebe403b4c2f5d1f1aec961eaccf1f7baa55615a6]
...> }
...> |> Cartouche.Transaction.V2.encode()
...> |> Cartouche.Hex.encode_big_hex()
"0x02F9027382210501843B9ACA00843C2390F1830493E09400AEA4B2242ABC8BB4BB78D537A67A245A7BEC6480B90204DEFF4B240000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000A000000000000000000000000000000000000000000000000000000000000007B0000000000000000000000003B72952436D0DCACFA7D7691C0CF4DE6DD5BAA7E0000000000000000000000003B72952436D0DCACFA7D7691C0CF4DE6DD5BAA7E00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B2C639C533813F4AA9D7837CAF62653D097FF85000000000000000000000000833589FCD6EDB6E08F4C7C32D4F71B54BDA0291300000000000000000000000000000000000000000000000000000000000AAE6000000000000000000000000000000000000000000000000000000000000AAE60000000000000000000000000000000000000000000000000000000000000000A00000000000000000000000000000000000000000000000000000000002ADA240000000000000000000000000000000000000000000000000000000067D38314000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000C080A0019C8102CB582C309B0D2ABABB6AEB683A8FBC7E2044665F84669F0A73865B9AA03732EB6644FC11E850A0FED8EBE403B4C2F5D1F1AEC961EACCF1F7BAA55615A6"
Decodes an EIP-1559 (type 2) transaction object as returned in the
transactions array of eth_getBlockByNumber / eth_getBlockByHash
when include_transaction_details: true is requested.
signature_y_parity is taken from the "yParity" field (typed-tx
canonical) or, when absent, derived from "v" (legacy backwards-compat
field, which on typed transactions always holds the y-parity bit
directly). signature_r and signature_s are normalised to 32-byte
binaries even when the wire encoding strips leading zeros.
Examples
iex> use Cartouche.Hex
iex> %{
...> "type" => "0x2",
...> "chainId" => "0x1",
...> "nonce" => "0x1",
...> "maxPriorityFeePerGas" => "0x3b9aca00",
...> "maxFeePerGas" => "0x174876e800",
...> "gas" => "0x186a0",
...> "to" => "0x0000000000000000000000000000000000000001",
...> "value" => "0x2",
...> "input" => "0x010203",
...> "accessList" => [],
...> "yParity" => "0x1",
...> "r" => "0x1",
...> "s" => "0x2"
...> }
...> |> Cartouche.Transaction.V2.from_json()
%Cartouche.Transaction.V2{
chain_id: 1,
nonce: 1,
max_priority_fee_per_gas: 1_000_000_000,
max_fee_per_gas: 100_000_000_000,
gas_limit: 100_000,
destination: ~h[0x0000000000000000000000000000000000000001],
amount: 2,
data: <<1, 2, 3>>,
access_list: [],
signature_y_parity: true,
signature_r: <<1::256>>,
signature_s: <<2::256>>
}
Recovers a signature from a transaction, if it's been signed. Otherwise returns an error.
Examples
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], true, <<0x01::256>>, <<0x02::256>>, :goerli)
...> |> Cartouche.Transaction.V2.get_signature()
{:ok, <<1::256, 2::256, 1::8>>}
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], :goerli)
...> |> Cartouche.Transaction.V2.get_signature()
{:error, "transaction missing signature"}
@spec new( integer(), integer() | {integer(), :wei | :gwei} | nil, integer() | {integer(), :wei | :gwei} | nil, integer(), <<_::160>>, integer() | {integer(), :wei | :gwei}, binary(), list(), atom() | integer() | nil ) :: t()
Constructs a new V2 (EIP-1559) Ethereum transaction.
Examples
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [{<<2::160>>, [<<22::256>>]}, {<<3::160>>, []}], :goerli)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [{<<2::160>>, [<<22::256>>]}, {<<3::160>>, []}],
signature_y_parity: nil,
signature_r: nil,
signature_s: nil
}
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [{<<2::160>>, [<<22::256>>]}, {<<3::160>>, []}], true, <<0x01::256>>, <<0x02::256>>, :goerli)
%Cartouche.Transaction.V2{
chain_id: 5,
nonce: 1,
max_priority_fee_per_gas: 1000000000,
max_fee_per_gas: 100000000000,
gas_limit: 100000,
destination: <<1::160>>,
amount: 2,
data: <<1, 2, 3>>,
access_list: [{<<2::160>>, [<<22::256>>]}, {<<3::160>>, []}],
signature_y_parity: true,
signature_r: <<0x01::256>>,
signature_s: <<0x02::256>>
}
@spec new( integer(), integer() | {integer(), :wei | :gwei} | nil, integer() | {integer(), :wei | :gwei} | nil, integer(), <<_::160>>, integer() | {integer(), :wei | :gwei}, binary(), list(), boolean() | nil, <<_::256>> | nil, <<_::256>> | nil, atom() | integer() | nil ) :: t()
Like new/9 but also accepts explicit signature fields (signature_y_parity, signature_r, signature_s).
Recovers the signer from a given transaction, if it's been signed.
Examples
iex> {:ok, address} =
...> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], true, <<0x01::256>>, <<0x02::256>>, :goerli)
...> |> Cartouche.Transaction.V2.recover_signer()
...> Cartouche.Hex.to_address(address)
"0xC002Ca628F93e1550b5f30Ed10902A9e7783364B"
iex> Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [<<2::160>>, <<3::160>>], :goerli)
...> |> Cartouche.Transaction.V2.recover_signer()
{:error, "transaction missing signature"}