X402.ERC6492 (X402 v0.6.0)

Copy Markdown View Source

ERC-6492 signature wrapper parsing and building.

ERC-6492 lets a not-yet-deployed ("counterfactual") smart wallet produce a verifiable signature by wrapping the wallet's inner signature together with the factory call that would deploy it:

abi.encode((factory, factoryCalldata, innerSignature)) || magic_suffix

where the magic suffix is the 32-byte value 0x6492...6492.

This module is pure binary handling — no cryptography and no RPC. Whether a wrapped signature is actually valid is decided by X402.Verify.EVM: a counterfactual signature is never accepted until an on-chain simulation proves the deployed wallet would accept it (fail-closed, mirroring the reference Go implementation).

Summary

Types

A parsed signature.

Functions

Returns the 32-byte ERC-6492 magic suffix.

Parses a signature, unwrapping the ERC-6492 envelope when present.

Builds an ERC-6492 wrapped signature from its parts.

Returns true when the signature carries the ERC-6492 magic suffix.

Types

parsed()

@type parsed() :: %{
  wrapped?: boolean(),
  factory: String.t() | nil,
  factory_calldata: binary() | nil,
  inner_signature: binary()
}

A parsed signature.

wrapped? is true when the ERC-6492 magic suffix was present. factory and factory_calldata are nil unless the wrapper carried deployment information (a non-zero factory address with non-empty calldata). inner_signature is the raw signature bytes — the unwrapped inner signature for wrapped input, the input itself otherwise.

Functions

magic_suffix()

(since 0.6.0)
@spec magic_suffix() :: <<_::256>>

Returns the 32-byte ERC-6492 magic suffix.

Examples

iex> byte_size(X402.ERC6492.magic_suffix())
32

parse(signature)

(since 0.6.0)
@spec parse(binary()) ::
  {:ok, parsed()} | {:error, :invalid_signature | :invalid_erc6492_wrapper}

Parses a signature, unwrapping the ERC-6492 envelope when present.

Accepts raw bytes or a 0x-prefixed hex string. Signatures without the magic suffix parse as wrapped?: false with the bytes passed through as inner_signature. A wrapper whose factory is the zero address or whose calldata is empty parses with factory: nil (no deployment information), matching the reference implementations.

Returns {:error, :invalid_erc6492_wrapper} when the magic suffix is present but the ABI-encoded prefix is malformed, and {:error, :invalid_signature} for non-hex string input.

Examples

iex> {:ok, parsed} = X402.ERC6492.parse(:binary.copy(<<0x01>>, 65))
iex> {parsed.wrapped?, parsed.factory, byte_size(parsed.inner_signature)}
{false, nil, 65}

iex> inner = :binary.copy(<<0x07>>, 65)
iex> {:ok, wrapped} =
...>   X402.ERC6492.wrap("0x2222222222222222222222222222222222222222", <<0xAB, 0xCD>>, inner)
iex> {:ok, parsed} = X402.ERC6492.parse(wrapped)
iex> {parsed.wrapped?, parsed.factory, parsed.factory_calldata, parsed.inner_signature}
{true, "0x2222222222222222222222222222222222222222", <<0xAB, 0xCD>>, inner}

iex> X402.ERC6492.parse("0xzz")
{:error, :invalid_signature}

wrap(factory, factory_calldata, inner_signature)

(since 0.6.0)
@spec wrap(String.t(), binary(), binary()) ::
  {:ok, binary()} | {:error, :invalid_address}

Builds an ERC-6492 wrapped signature from its parts.

factory is a 0x-prefixed EVM address; factory_calldata and inner_signature are raw bytes. Returns the raw wrapped bytes (abi.encode((address, bytes, bytes)) || magic_suffix).

Examples

iex> {:ok, wrapped} =
...>   X402.ERC6492.wrap(
...>     "0x2222222222222222222222222222222222222222",
...>     <<0xAB>>,
...>     :binary.copy(<<0x01>>, 65)
...>   )
iex> X402.ERC6492.wrapped?(wrapped)
true

iex> X402.ERC6492.wrap("0x123", <<>>, <<>>)
{:error, :invalid_address}

wrapped?(signature)

(since 0.6.0)
@spec wrapped?(binary()) :: boolean()

Returns true when the signature carries the ERC-6492 magic suffix.

Accepts raw bytes or a 0x-prefixed hex string.

Examples

iex> X402.ERC6492.wrapped?(<<1, 2, 3>>)
false

iex> {:ok, wrapped} =
...>   X402.ERC6492.wrap(
...>     "0x2222222222222222222222222222222222222222",
...>     <<0xAB>>,
...>     :binary.copy(<<0x01>>, 65)
...>   )
iex> X402.ERC6492.wrapped?(wrapped)
true