# `Cartouche.Transaction`
[🔗](https://github.com/zenhive/cartouche/blob/main/lib/cartouche/transaction.ex#L1)

A module to help build, sign and encode Ethereum transactions.

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `build_signed_trx_v2` | 9 | Build and sign an EIP-1559 transaction. | `address: value`, `nonce: exchange_data`, `call_data: value`, `max_priority_fee_per_gas: exchange_data`, `max_fee_per_gas: exchange_data`, `gas_limit: exchange_data`, `amount: value`, `access_list: value`, `opts: value` |
| `build_signed_trx` | 7 | Build and sign a legacy transaction. | `address: value`, `nonce: exchange_data`, `call_data: value`, `gas_price: exchange_data`, `gas_limit: exchange_data`, `value: value`, `opts: value` |
| `build_trx_v2` | 9 | Build an EIP-1559 transaction for a contract call or raw calldata. | `address: value`, `nonce: exchange_data`, `call_data: value`, `max_priority_fee_per_gas: exchange_data`, `max_fee_per_gas: exchange_data`, `gas_limit: exchange_data`, `amount: value`, `access_list: value`, `chain_id: exchange_data` |
| `build_trx` | 7 | Build a legacy transaction for a contract call or raw calldata. | `address: value`, `nonce: exchange_data`, `call_data: value`, `gas_price: exchange_data`, `gas_limit: exchange_data`, `value: value`, `chain_id: exchange_data` |
| `decode` | 1 | Decode raw Ethereum transaction bytes into the matching transaction struct (V1/V_2930/V2/V3/V4 by envelope byte). | `encoded: value` |
| `encode` | 1 | Encode a concrete transaction struct (V1/V2/V3/V4) into raw RLP/typed-RLP transaction bytes by dispatching on struct. | `transaction: value` |

# `build_signed_trx`

```elixir
@spec build_signed_trx(
  &lt;&lt;_::160&gt;&gt;,
  integer(),
  binary() | {String.t(), [term()]},
  integer() | {integer(), :wei | :gwei} | nil,
  integer(),
  integer() | {integer(), :wei | :gwei},
  Keyword.t()
) :: {:ok, Cartouche.Transaction.V1.t()} | {:error, String.t()}
```

Builds and signs a transaction, to be ready to be passed to JSON-RPC.

Optionally takes a callback to modify the transaction before it is signed.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> {:ok, signed_trx} = Cartouche.Transaction.build_signed_trx(<<1::160>>, 5, {"baz(uint,address)", [50, :binary.decode_unsigned(<<1::160>>)]}, {50, :gwei}, 100_000, 0, signer: signer_proc, chain_id: :goerli)
    iex> {:ok, signer} = Cartouche.Transaction.V1.recover_signer(signed_trx, 5)
    iex> Cartouche.Hex.to_address(signer)
    "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

# `build_signed_trx_v2`

```elixir
@spec build_signed_trx_v2(
  &lt;&lt;_::160&gt;&gt;,
  integer(),
  binary() | {String.t(), [term()]},
  integer() | {integer(), :wei | :gwei} | nil,
  integer() | {integer(), :wei | :gwei} | nil,
  integer(),
  integer() | {integer(), :wei | :gwei},
  list(),
  Keyword.t()
) :: {:ok, Cartouche.Transaction.V2.t()} | {:error, String.t()}
```

Builds and signs a V2 transaction, to be ready to be passed to JSON-RPC.

Optionally takes a callback to modify the transaction before it is signed.

## Examples

    iex> signer_proc = Cartouche.Test.Signer.start_signer()
    iex> {:ok, signed_trx} = Cartouche.Transaction.build_signed_trx_v2(<<1::160>>, 5, {"baz(uint,address)", [50, :binary.decode_unsigned(<<1::160>>)]}, {50, :gwei}, {10, :gwei}, 100_000, 0, [], signer: signer_proc, chain_id: :goerli)
    iex> {:ok, signer} = Cartouche.Transaction.V2.recover_signer(signed_trx)
    iex> Cartouche.Hex.to_address(signer)
    "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"

# `build_trx`

```elixir
@spec build_trx(
  &lt;&lt;_::160&gt;&gt;,
  integer(),
  binary() | {String.t(), [term()]},
  integer() | {integer(), :wei | :gwei} | nil,
  integer(),
  integer() | {integer(), :wei | :gwei},
  atom() | integer() | nil
) :: Cartouche.Transaction.V1.t()
```

Builds a v1-style call to a given contract

## Examples

    iex> use Cartouche.Hex
    iex> Cartouche.Transaction.build_trx(<<1::160>>, 5, {"baz(uint,address)", [50, :binary.decode_unsigned(<<1::160>>)]}, {50, :gwei}, 100_000, 0, 5)
    %Cartouche.Transaction.V1{
      nonce: 5,
      gas_price: 50000000000,
      gas_limit: 100000,
      to: <<1::160>>,
      value: 0,
      data: ~h[0xA291ADD600000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001],
      v: 5,
      r: 0,
      s: 0
    }

    iex> use Cartouche.Hex
    iex> call_data = ~h[0xA291ADD600000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001]
    ...> Cartouche.Transaction.build_trx(<<1::160>>, 5, call_data, {50, :gwei}, 100_000, 0, 5)
    %Cartouche.Transaction.V1{
      nonce: 5,
      gas_price: 50000000000,
      gas_limit: 100000,
      to: <<1::160>>,
      value: 0,
      data: ~h[0xA291ADD600000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001],
      v: 5,
      r: 0,
      s: 0
    }

# `build_trx_v2`

```elixir
@spec build_trx_v2(
  &lt;&lt;_::160&gt;&gt;,
  integer(),
  binary() | {String.t(), [term()]},
  integer() | {integer(), :wei | :gwei} | nil,
  integer() | {integer(), :wei | :gwei} | nil,
  integer(),
  integer() | {integer(), :wei | :gwei},
  list(),
  atom() | integer() | nil
) :: Cartouche.Transaction.V2.t()
```

Builds a v2 (eip-1559)-style call to a given contract

## Examples

    iex> use Cartouche.Hex
    iex> Cartouche.Transaction.build_trx_v2(<<1::160>>, 6, {"baz(uint,address)", [50, :binary.decode_unsigned(<<1::160>>)]}, {50, :gwei}, {10, :gwei}, 100_000, 0, [<<1::160>>], :goerli)
    %Cartouche.Transaction.V2{
      chain_id: 5,
      nonce: 6,
      max_priority_fee_per_gas: 50000000000,
      max_fee_per_gas: 10000000000,
      gas_limit: 100000,
      destination: <<1::160>>,
      amount: 0,
      data: ~h[0xA291ADD600000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001],
      access_list: [<<1::160>>],
      signature_y_parity: nil,
      signature_r: nil,
      signature_s: nil
    }

    iex> use Cartouche.Hex
    iex> call_data = ~h[0xA291ADD600000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001]
    ...> Cartouche.Transaction.build_trx_v2(<<1::160>>, 5, call_data, {50, :gwei}, {10, :gwei}, 100_000, 0, [<<1::160>>], :goerli)
    %Cartouche.Transaction.V2{
      chain_id: 5,
      nonce: 5,
      max_priority_fee_per_gas: 50000000000,
      max_fee_per_gas: 10000000000,
      gas_limit: 100000,
      destination: <<1::160>>,
      amount: 0,
      data: ~h[0xA291ADD600000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000001],
      access_list: [<<1::160>>],
      signature_y_parity: nil,
      signature_r: nil,
      signature_s: nil
    }

# `decode`

```elixir
@spec decode(binary()) ::
  {:ok,
   Cartouche.Transaction.V1.t()
   | Cartouche.Transaction.V_2930.t()
   | Cartouche.Transaction.V2.t()
   | Cartouche.Transaction.V3.t()
   | Cartouche.Transaction.V4.t()}
  | {:error, String.t() | :empty_transaction | :unknown_envelope_type}
```

Decodes raw Ethereum transaction bytes into the matching transaction struct.

Dispatches typed envelopes by their first byte:

  * `0x01` - `Cartouche.Transaction.V_2930`
  * `0x02` - `Cartouche.Transaction.V2`
  * `0x03` - `Cartouche.Transaction.V3`
  * `0x04` - `Cartouche.Transaction.V4`

Legacy transactions are untyped RLP and are decoded as
`Cartouche.Transaction.V1` when the first byte is an RLP prefix (`>= 0x80`).
Empty input returns `{:error, :empty_transaction}`. Unknown typed envelopes
(`< 0x80` except supported typed envelopes) return `{:error, :unknown_envelope_type}`.

## Examples

    iex> tx = Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
    iex> {:ok, decoded} = Cartouche.Transaction.decode(Cartouche.Transaction.V1.encode(tx))
    iex> decoded == tx
    true

    iex> Cartouche.Transaction.decode(<<>>)
    {:error, :empty_transaction}

# `encode`

```elixir
@spec encode(
  Cartouche.Transaction.V1.t()
  | Cartouche.Transaction.V2.t()
  | Cartouche.Transaction.V3.t()
  | Cartouche.Transaction.V4.t()
) :: binary()
```

Encodes a concrete transaction struct into raw transaction bytes, mirroring `decode/1`.

Dispatches by struct so callers don't need to know which versioned encoder to
invoke. The output is the same shape `decode/1` accepts:

  * `%Cartouche.Transaction.V1{}` - untyped RLP-encoded legacy/EIP-155 bytes
    (leading byte `>= 0x80`).
  * `%Cartouche.Transaction.V2{}` - `0x02`-prefixed EIP-2718 typed RLP.
  * `%Cartouche.Transaction.V3{}` - `0x03`-prefixed EIP-2718 typed RLP
    (EIP-4844 blob transaction envelope).
  * `%Cartouche.Transaction.V4{}` - `0x04`-prefixed EIP-2718 typed RLP
    (EIP-7702 authorization-list transaction envelope).

Each leaf encoder already emits the EIP-2718 envelope byte where applicable;
this function is a pure pattern-match-and-delegate.

## Examples

    iex> tx = Cartouche.Transaction.V1.new(1, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, :kovan)
    iex> {:ok, ^tx} = tx |> Cartouche.Transaction.encode() |> Cartouche.Transaction.decode()
    iex> Cartouche.Transaction.encode(tx) == Cartouche.Transaction.V1.encode(tx)
    true

    iex> tx = Cartouche.Transaction.V2.new(1, {1, :gwei}, {100, :gwei}, 100_000, <<1::160>>, {2, :wei}, <<1, 2, 3>>, [], :goerli)
    iex> <<0x02, _::binary>> = Cartouche.Transaction.encode(tx)
    iex> {:ok, ^tx} = tx |> Cartouche.Transaction.encode() |> Cartouche.Transaction.decode()

---

*Consult [api-reference.md](api-reference.md) for complete listing*
