Cartouche.Transaction.V1 (Cartouche v0.3.0)

Copy Markdown View Source

Represents a V1 or "Legacy" (that is, pre-EIP-1559) transaction.

API Functions

FunctionArityDescriptionParam Kinds
from_json1Decode a legacy transaction JSON object from eth_getBlockBy* into a V1 struct.params: exchange_data
recover_signer2Recover the signer address from a signed legacy transaction.transaction: value, chain_id: exchange_data
get_signature1Extract the packed signature from a signed legacy transaction.transaction: value
add_signature2Attach an Ethereum signature to a legacy transaction.transaction: value, signature: value
decode1Decode RLP bytes into a legacy transaction struct.trx_enc: value
encode1Encode a legacy transaction as RLP bytes for signing or broadcast.transaction: value
new7Construct a legacy/EIP-155-style transaction struct.nonce: exchange_data, gas_price: exchange_data, gas_limit: exchange_data, to: value, value: value, data: value, chain_id: exchange_data

Summary

Functions

Adds a signature to a transaction. This overwrites the [chain_id, 0, 0] fields, as per EIP-155.

Decode an RLP-encoded transaction.

Build an RLP-encoded transaction. Note: transactions can be encoded before they are signed, which uses [chain_id, 0, 0] in the signature fields, otherwise those fields are [v, r, s].

Decodes a legacy (type 0) 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 V1 (Legacy) Ethereum transaction.

Recovers the signer from a given transaction, if it's been signed.

Types

t()

@type t() :: %Cartouche.Transaction.V1{
  data: binary(),
  gas_limit: integer(),
  gas_price: integer(),
  nonce: integer(),
  r: integer(),
  s: integer(),
  to: <<_::160>> | nil,
  v: integer(),
  value: integer()
}

Functions

add_signature(transaction, arg)

@spec add_signature(t(), <<_::512, _::_*8>>) :: t()

Adds a signature to a transaction. This overwrites the [chain_id, 0, 0] fields, as per EIP-155.

Examples

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.add_signature(<<1::256, 2::256, 3::8>>)
%Cartouche.Transaction.V1{
  nonce: 1,
  gas_price: 100000000000,
  gas_limit: 100000,
  to: <<1::160>>,
  value: 2,
  data: <<1, 2, 3>>,
  v: 3,
  r: 1,
  s: 2
}

decode(trx_enc)

@spec decode(binary()) :: {:ok, t()} | {:error, String.t()}

Decode an RLP-encoded transaction.

Examples

iex> use Cartouche.Hex
iex> ~h[0xE80185174876E800830186A094000000000000000000000000000000000000000102830102032A8080]
...> |> Cartouche.Transaction.V1.decode()
{:ok, %Cartouche.Transaction.V1{
  nonce: 1,
  gas_price: 100000000000,
  gas_limit: 100000,
  to: <<1::160>>,
  value: 2,
  data: <<1, 2, 3>>,
  v: 42,
  r: 0,
  s: 0
}}

encode(v1)

@spec encode(t()) :: binary()

Build an RLP-encoded transaction. Note: transactions can be encoded before they are signed, which uses [chain_id, 0, 0] in the signature fields, otherwise those fields are [v, r, s].

Examples

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.encode()
...> |> Base.encode16()
"E80185174876E800830186A094000000000000000000000000000000000000000102830102032A8080"

from_json(params)

@spec from_json(map()) :: t() | no_return()

Decodes a legacy (type 0) transaction object as returned in the transactions array of eth_getBlockByNumber / eth_getBlockByHash when include_transaction_details: true is requested.

to is preserved as nil for contract-creation transactions per the wire shape (the strict RLP decode/1 path requires an explicit 20-byte address; this JSON path does not).

Examples

iex> use Cartouche.Hex
iex> %{
...>   "type" => "0x0",
...>   "nonce" => "0x1",
...>   "gasPrice" => "0x174876e800",
...>   "gas" => "0x186a0",
...>   "to" => "0x0000000000000000000000000000000000000001",
...>   "value" => "0x2",
...>   "input" => "0x010203",
...>   "v" => "0x2a",
...>   "r" => "0x0",
...>   "s" => "0x0"
...> }
...> |> Cartouche.Transaction.V1.from_json()
%Cartouche.Transaction.V1{
  nonce: 1,
  gas_price: 100_000_000_000,
  gas_limit: 100_000,
  to: ~h[0x0000000000000000000000000000000000000001],
  value: 2,
  data: <<1, 2, 3>>,
  v: 0x2a,
  r: 0,
  s: 0
}

Contract creation: "to": null is preserved as to: nil.

iex> %{
...>   "type" => "0x0",
...>   "nonce" => "0x0",
...>   "gasPrice" => "0x1",
...>   "gas" => "0x186a0",
...>   "to" => nil,
...>   "value" => "0x0",
...>   "input" => "0x60606040",
...>   "v" => "0x1c",
...>   "r" => "0x0",
...>   "s" => "0x0"
...> }
...> |> Cartouche.Transaction.V1.from_json()
...> |> Map.fetch!(:to)
nil

get_signature(v1)

@spec get_signature(t()) :: {:ok, binary()} | {:error, String.t()}

Recovers a signature from a transaction, if it's been signed. Otherwise returns an error.

Examples

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.add_signature(<<1::256, 2::256, 3::8>>)
...> |> Cartouche.Transaction.V1.get_signature()
{:ok, <<1::256, 2::256, 3::8>>}

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.add_signature(<<1::256, 2::256, 0x05f5e0ff::32>>)
...> |> Cartouche.Transaction.V1.get_signature()
{:ok, <<1::256, 2::256, 0x05f5e0ff::32>>}

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.get_signature()
{:error, "transaction missing signature"}

new(nonce, gas_price, gas_limit, to, value, data, chain_id \\ nil)

@spec new(
  integer(),
  integer() | {integer(), :wei | :gwei} | nil,
  integer(),
  <<_::160>>,
  integer() | {integer(), :wei | :gwei},
  binary(),
  atom() | integer() | nil
) :: t()

Constructs a new V1 (Legacy) Ethereum transaction.

Examples

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
%Cartouche.Transaction.V1{
  nonce: 1,
  gas_price: 100000000000,
  gas_limit: 100000,
  to: <<1::160>>,
  value: 2,
  data: <<1, 2, 3>>,
  v: 42,
  r: 0,
  s: 0
}

recover_signer(transaction, chain_id)

@spec recover_signer(t(), atom() | integer()) ::
  {:ok, <<_::160>>} | {:error, String.t()}

Recovers the signer from a given transaction, if it's been signed.

Examples

iex> {:ok, address} =
...> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.add_signature(<<1::256, 2::256, 3::8>>)
...> |> Cartouche.Transaction.V1.recover_signer(:kovan)
...> Cartouche.Hex.to_address(address)
"0x47643AC1194d7e8C6d04dD631D456137028bBc1F"

iex> Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
...> |> Cartouche.Transaction.V1.recover_signer(:kovan)
{:error, "transaction missing signature"}