X402.Extensions.SIWX.Message (X402 v0.9.0)

Copy Markdown View Source

CAIP-122 message text for Sign-In-With-X challenges.

Builds the exact text a wallet signs for a SIWX proof, routed by the CAIP-2 namespace of chainId:

  • eip155:* — EIP-4361 (Sign-In With Ethereum), whose Chain ID line carries the numeric chain reference. When no statement is present the address is followed by two blank lines, as the EIP-4361 ABNF (and the reference siwe library) produce.
  • solana:* — Sign-In With Solana, identical apart from the Solana account header and the genesis-hash chain reference. Without a statement the address is followed by a single blank line, matching the reference x402 implementation.

Field values are read from the wire (camelCase string) keys or their snake_case atom equivalents, so both a decoded SIGN-IN-WITH-X payload and a locally built map work.

Summary

Types

Errors returned by build/1.

Chain family derived from a CAIP-2 chain id.

Functions

Builds the CAIP-122 message text for a fields map.

Returns the chain reference rendered on the Chain ID line.

Returns the chain family of a CAIP-2 chain id.

Returns the signature type a chain family authenticates with.

Types

build_error()

@type build_error() :: :invalid_fields | :invalid_chain_id | :unsupported_chain

Errors returned by build/1.

family()

@type family() :: :eip155 | :solana

Chain family derived from a CAIP-2 chain id.

Functions

build(fields)

(since 0.9.0)
@spec build(map()) :: {:ok, String.t()} | {:error, build_error()}

Builds the CAIP-122 message text for a fields map.

Requires domain, address, uri, version, chainId, nonce, and issuedAt; statement, expirationTime, notBefore, requestId, and resources are optional and omitted from the text when absent (an empty resources list is treated as absent).

Examples

iex> {:ok, text} = X402.Extensions.SIWX.Message.build(%{
...>   "domain" => "api.example.com",
...>   "address" => "0x857b06519E91e3A54538791bDbb0E22373e36b66",
...>   "statement" => "Sign in to access premium data",
...>   "uri" => "https://api.example.com/premium-data",
...>   "version" => "1",
...>   "chainId" => "eip155:8453",
...>   "nonce" => "a1b2c3d4e5f67890a1b2c3d4e5f67890",
...>   "issuedAt" => "2024-01-15T10:30:00.000Z",
...>   "expirationTime" => "2024-01-15T10:35:00.000Z",
...>   "resources" => ["https://api.example.com/premium-data"]
...> })
iex> String.split(text, "\n")
[
  "api.example.com wants you to sign in with your Ethereum account:",
  "0x857b06519E91e3A54538791bDbb0E22373e36b66",
  "",
  "Sign in to access premium data",
  "",
  "URI: https://api.example.com/premium-data",
  "Version: 1",
  "Chain ID: 8453",
  "Nonce: a1b2c3d4e5f67890a1b2c3d4e5f67890",
  "Issued At: 2024-01-15T10:30:00.000Z",
  "Expiration Time: 2024-01-15T10:35:00.000Z",
  "Resources:",
  "- https://api.example.com/premium-data"
]

iex> X402.Extensions.SIWX.Message.build(%{"domain" => "api.example.com"})
{:error, :invalid_fields}

chain_reference(chain_id)

(since 0.9.0)
@spec chain_reference(String.t()) :: String.t()

Returns the chain reference rendered on the Chain ID line.

Examples

iex> X402.Extensions.SIWX.Message.chain_reference("eip155:8453")
"8453"

iex> X402.Extensions.SIWX.Message.chain_reference("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")
"5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"

family(arg1)

(since 0.9.0)
@spec family(term()) ::
  {:ok, family()} | {:error, :invalid_chain_id | :unsupported_chain}

Returns the chain family of a CAIP-2 chain id.

Examples

iex> X402.Extensions.SIWX.Message.family("eip155:8453")
{:ok, :eip155}

iex> X402.Extensions.SIWX.Message.family("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp")
{:ok, :solana}

iex> X402.Extensions.SIWX.Message.family("eip155:base")
{:error, :invalid_chain_id}

iex> X402.Extensions.SIWX.Message.family("cosmos:hub")
{:error, :unsupported_chain}

signature_type(atom)

(since 0.9.0)
@spec signature_type(family()) :: String.t()

Returns the signature type a chain family authenticates with.

Examples

iex> X402.Extensions.SIWX.Message.signature_type(:eip155)
"eip191"

iex> X402.Extensions.SIWX.Message.signature_type(:solana)
"ed25519"