# `Onchain.Signer`
[🔗](https://github.com/ZenHive/onchain/blob/v0.5.0/lib/onchain/signer.ex#L1)

EIP-1559 transaction building, signing, encoding, and broadcasting.

Stateless pipeline — no GenServer, no application config. Private key is
always passed explicitly. Uses `Signet.Signer.sign_direct/4` for signing
and `Signet.Transaction.V2` for transaction construction.

## Pipeline

`build_transaction/3` → `sign_transaction/3` → `encode_transaction/1` → `RPC.eth_send_raw_transaction/2`

Or use `send_transaction/3` for the full pipeline in one call.

## Functions

| Function | Purpose |
|----------|---------|
| `address_from_key/1` | Derive checksummed address from private key |
| `build_transaction/3` | Build unsigned EIP-1559 transaction |
| `sign_transaction/3` | Sign transaction with private key |
| `encode_transaction/1` | Encode signed transaction to hex |
| `send_transaction/3` | Full pipeline: build → sign → encode → broadcast |

## API Functions
| Function | Arity | Description | Param Kinds |
| --- | --- | --- | --- |
| `send_transaction!` | 3 | Build, sign, encode, and broadcast a transaction in one call. Raises on error. | `to: value`, `calldata: value`, `opts: value` |
| `send_transaction` | 3 | Build, sign, encode, and broadcast a transaction in one call. | `to: value`, `calldata: value`, `opts: value` |
| `encode_transaction!` | 1 | Encode a signed transaction to 0x-prefixed hex for broadcast. Raises on error. | `signed_trx: value` |
| `encode_transaction` | 1 | Encode a signed transaction to 0x-prefixed hex for broadcast. | `signed_trx: value` |
| `sign_transaction!` | 3 | Sign a transaction with a private key. Raises on error. | `unsigned_trx: value`, `private_key: value`, `chain_id: value` |
| `sign_transaction` | 3 | Sign a transaction with a private key. | `unsigned_trx: value`, `private_key: value`, `chain_id: value` |
| `build_transaction!` | 3 | Build an unsigned EIP-1559 transaction. Raises on error. | `to: value`, `calldata: value`, `opts: value` |
| `build_transaction` | 3 | Build an unsigned EIP-1559 transaction. | `to: value`, `calldata: value`, `opts: value` |
| `address_from_key!` | 1 | Derive checksummed Ethereum address from a private key. Raises on error. | `private_key: value` |
| `address_from_key` | 1 | Derive checksummed Ethereum address from a private key. | `private_key: value` |

# `address_from_key`

```elixir
@spec address_from_key(binary()) ::
  {:ok, String.t()} | {:error, {:invalid_private_key, term()}}
```

Derive checksummed Ethereum address from a private key.

## Parameters

  * `private_key` - 32-byte binary or hex string (with or without 0x) (value)

## Returns

EIP-55 checksummed address (`{:ok, String.t()} | {:error, {:invalid_private_key, term()}}`)

```elixir
# descripex:contract
%{
  params: %{
    private_key: %{
      description: "32-byte binary or hex string (with or without 0x)",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, String.t()} | {:error, {:invalid_private_key, term()}}",
    description: "EIP-55 checksummed address",
    example: "0x63Cc7c25e0cdb121aBb0fE477a6b9901889F99A7"
  }
}
```

# `address_from_key!`

```elixir
@spec address_from_key!(binary()) :: String.t()
```

Derive checksummed Ethereum address from a private key. Raises on error.

## Parameters

  * `private_key` - 32-byte binary or hex string (with or without 0x) (value)

## Returns

EIP-55 checksummed address (`string`)

```elixir
# descripex:contract
%{
  params: %{
    private_key: %{
      description: "32-byte binary or hex string (with or without 0x)",
      kind: :value
    }
  },
  returns: %{type: :string, description: "EIP-55 checksummed address"}
}
```

# `build_transaction`

```elixir
@spec build_transaction(binary(), binary() | {:raw, binary()}, keyword()) ::
  {:ok, Signet.Transaction.V2.t()} | {:error, term()}
```

Build an unsigned EIP-1559 transaction.

## Parameters

  * `to` - Destination address (hex string or 20-byte binary) (value)
  * `calldata` - Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), \{:raw, binary\} for literal bytes that start with 0x, or <<>> for plain ETH transfer (value)
  * `opts` - Required: :nonce, :chain_id. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list. Gas params accept integers (wei) or \{n, :gwei\} tuples. (value)

## Returns

Unsigned EIP-1559 transaction struct (`{:ok, %Signet.Transaction.V2{}} | {:error, term()}`)

```elixir
# descripex:contract
%{
  params: %{
    opts: %{
      description: "Required: :nonce, :chain_id. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list. Gas params accept integers (wei) or {n, :gwei} tuples.",
      kind: :value
    },
    to: %{
      description: "Destination address (hex string or 20-byte binary)",
      kind: :value
    },
    calldata: %{
      description: "Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), {:raw, binary} for literal bytes that start with 0x, or <<>> for plain ETH transfer",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, %Signet.Transaction.V2{}} | {:error, term()}",
    description: "Unsigned EIP-1559 transaction struct"
  }
}
```

# `build_transaction!`

```elixir
@spec build_transaction!(binary(), binary() | {:raw, binary()}, keyword()) ::
  Signet.Transaction.V2.t()
```

Build an unsigned EIP-1559 transaction. Raises on error.

## Parameters

  * `to` - Destination address (hex string or 20-byte binary) (value)
  * `calldata` - Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), \{:raw, binary\} for literal bytes that start with 0x, or <<>> for plain ETH transfer (value)
  * `opts` - Required: :nonce, :chain_id. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list. Gas params accept integers (wei) or \{n, :gwei\} tuples. (value)

## Returns

Unsigned EIP-1559 transaction struct (`%Signet.Transaction.V2{}`)

```elixir
# descripex:contract
%{
  params: %{
    opts: %{
      description: "Required: :nonce, :chain_id. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list. Gas params accept integers (wei) or {n, :gwei} tuples.",
      kind: :value
    },
    to: %{
      description: "Destination address (hex string or 20-byte binary)",
      kind: :value
    },
    calldata: %{
      description: "Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), {:raw, binary} for literal bytes that start with 0x, or <<>> for plain ETH transfer",
      kind: :value
    }
  },
  returns: %{
    type: "%Signet.Transaction.V2{}",
    description: "Unsigned EIP-1559 transaction struct"
  }
}
```

# `encode_transaction`

```elixir
@spec encode_transaction(Signet.Transaction.V2.t()) ::
  {:ok, String.t()} | {:error, {:encode_error, :unsigned_transaction}}
```

Encode a signed transaction to 0x-prefixed hex for broadcast.

## Parameters

  * `signed_trx` - Signed %Signet.Transaction.V2\{\} struct (value)

## Returns

0x-prefixed hex string ready for eth_sendRawTransaction (`{:ok, String.t()} | {:error, {:encode_error, :unsigned_transaction}}`)

```elixir
# descripex:contract
%{
  params: %{
    signed_trx: %{
      description: "Signed %Signet.Transaction.V2{} struct",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, String.t()} | {:error, {:encode_error, :unsigned_transaction}}",
    description: "0x-prefixed hex string ready for eth_sendRawTransaction",
    example: "0x02f8..."
  }
}
```

# `encode_transaction!`

```elixir
@spec encode_transaction!(Signet.Transaction.V2.t()) :: String.t()
```

Encode a signed transaction to 0x-prefixed hex for broadcast. Raises on error.

## Parameters

  * `signed_trx` - Signed %Signet.Transaction.V2\{\} struct (value)

## Returns

0x-prefixed hex string ready for broadcast (`string`)

```elixir
# descripex:contract
%{
  params: %{
    signed_trx: %{
      description: "Signed %Signet.Transaction.V2{} struct",
      kind: :value
    }
  },
  returns: %{
    type: :string,
    description: "0x-prefixed hex string ready for broadcast"
  }
}
```

# `send_transaction`

```elixir
@spec send_transaction(binary(), binary() | {:raw, binary()}, keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

Build, sign, encode, and broadcast a transaction in one call.

## Parameters

  * `to` - Destination address (hex string or 20-byte binary) (value)
  * `calldata` - Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), \{:raw, binary\} for literal bytes that start with 0x, or <<>> for plain ETH transfer (value)
  * `opts` - Required: :private_key, :nonce, :chain_id, :rpc_url. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list (value)

## Returns

Transaction hash hex string (`{:ok, String.t()} | {:error, term()}`)

```elixir
# descripex:contract
%{
  params: %{
    opts: %{
      description: "Required: :private_key, :nonce, :chain_id, :rpc_url. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list",
      kind: :value
    },
    to: %{
      description: "Destination address (hex string or 20-byte binary)",
      kind: :value
    },
    calldata: %{
      description: "Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), {:raw, binary} for literal bytes that start with 0x, or <<>> for plain ETH transfer",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, String.t()} | {:error, term()}",
    description: "Transaction hash hex string"
  }
}
```

# `send_transaction!`

```elixir
@spec send_transaction!(binary(), binary() | {:raw, binary()}, keyword()) ::
  String.t()
```

Build, sign, encode, and broadcast a transaction in one call. Raises on error.

## Parameters

  * `to` - Destination address (hex string or 20-byte binary) (value)
  * `calldata` - Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), \{:raw, binary\} for literal bytes that start with 0x, or <<>> for plain ETH transfer (value)
  * `opts` - Required: :private_key, :nonce, :chain_id, :rpc_url. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list (value)

## Returns

Transaction hash hex string (`string`)

```elixir
# descripex:contract
%{
  params: %{
    opts: %{
      description: "Required: :private_key, :nonce, :chain_id, :rpc_url. Optional: :gas_limit, :max_fee_per_gas, :max_priority_fee_per_gas, :value, :access_list",
      kind: :value
    },
    to: %{
      description: "Destination address (hex string or 20-byte binary)",
      kind: :value
    },
    calldata: %{
      description: "Raw binary calldata (use Hex.decode!/1 on ABI.encode_call output), {:raw, binary} for literal bytes that start with 0x, or <<>> for plain ETH transfer",
      kind: :value
    }
  },
  returns: %{type: :string, description: "Transaction hash hex string"}
}
```

# `sign_transaction`

```elixir
@spec sign_transaction(Signet.Transaction.V2.t(), binary(), pos_integer()) ::
  {:ok, Signet.Transaction.V2.t()}
  | {:error, {:sign_error, term()} | {:invalid_private_key, term()}}
```

Sign a transaction with a private key.

## Parameters

  * `unsigned_trx` - Unsigned %Signet.Transaction.V2\{\} struct (value)
  * `private_key` - 32-byte binary or hex string (with or without 0x) (value)
  * `chain_id` - Chain ID integer (1 = mainnet, 11155111 = Sepolia) (value)

## Returns

Signed transaction with signature fields populated (`{:ok, %Signet.Transaction.V2{}} | {:error, {:sign_error, term()}}`)

```elixir
# descripex:contract
%{
  params: %{
    private_key: %{
      description: "32-byte binary or hex string (with or without 0x)",
      kind: :value
    },
    chain_id: %{
      description: "Chain ID integer (1 = mainnet, 11155111 = Sepolia)",
      kind: :value
    },
    unsigned_trx: %{
      description: "Unsigned %Signet.Transaction.V2{} struct",
      kind: :value
    }
  },
  returns: %{
    type: "{:ok, %Signet.Transaction.V2{}} | {:error, {:sign_error, term()}}",
    description: "Signed transaction with signature fields populated"
  }
}
```

# `sign_transaction!`

```elixir
@spec sign_transaction!(Signet.Transaction.V2.t(), binary(), pos_integer()) ::
  Signet.Transaction.V2.t()
```

Sign a transaction with a private key. Raises on error.

## Parameters

  * `unsigned_trx` - Unsigned %Signet.Transaction.V2\{\} struct (value)
  * `private_key` - 32-byte binary or hex string (with or without 0x) (value)
  * `chain_id` - Chain ID integer (1 = mainnet, 11155111 = Sepolia) (value)

## Returns

Signed transaction with signature fields populated (`%Signet.Transaction.V2{}`)

```elixir
# descripex:contract
%{
  params: %{
    private_key: %{
      description: "32-byte binary or hex string (with or without 0x)",
      kind: :value
    },
    chain_id: %{
      description: "Chain ID integer (1 = mainnet, 11155111 = Sepolia)",
      kind: :value
    },
    unsigned_trx: %{
      description: "Unsigned %Signet.Transaction.V2{} struct",
      kind: :value
    }
  },
  returns: %{
    type: "%Signet.Transaction.V2{}",
    description: "Signed transaction with signature fields populated"
  }
}
```

---

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