Built-in X402.Scheme for auth-capture payments on EVM (eip155:*)
networks.
Implements both roles:
- Client — signs the single token authorization the scheme needs:
an EIP-3009
ReceiveWithAuthorizationtoward the deployment's EIP-3009 token collector (default), or a witness-less Permit2PermitTransferFromtoward its Permit2 collector whenextra.assetTransferMethodis"permit2". The authorization's nonce is the payment'ssignatureNonce, which commits to everyPaymentInfofield the facilitator reconstructs;salt(and, when the bind is on,saltNonce) ride alongside. The payload is identical under both payment flows —extra.paymentFlowonly decides whether the facilitator settles it asauthorizeorcharge. - Server —
X402.Scheme.validate_payload/3runs the offline shape guard andX402.Scheme.precheck/3the full structural checklist (X402.Verify.AuthCaptureEVMat level:structural). Both report{:error, {:invalid_auth_capture_payment, reason}}.
reclaim_transaction/2 builds the payer's own reclaim call for a hold
the server never captured; the escrow restricts it to the payer, so it
is never relayed by a facilitator.
Summary
Functions
Returns ["eip155:*"] — every EVM network.
Runs the structural verification checklist locally (level :structural).
Builds the payer's reclaim(PaymentInfo) transaction for an escrowed
hold whose capture deadline has passed.
Returns "auth-capture".
Signs the auth-capture scheme payload for the selected transfer method.
Whether the client can sign this requirements entry: an EVM network, a
resolvable deployment, a supported transfer method and payment flow, and
the extra fields PaymentInfo needs.
Runs the offline shape guard (X402.Verify.AuthCaptureEVM.validate_shape/2).
Functions
@spec networks() :: [String.t()]
Returns ["eip155:*"] — every EVM network.
Examples
iex> X402.Scheme.AuthCaptureEVM.networks()
["eip155:*"]
@spec precheck(map(), map(), keyword()) :: :ok | {:error, {:invalid_auth_capture_payment, X402.AuthCapture.reason() | term()}}
Runs the structural verification checklist locally (level :structural).
Honors :now and :skew_seconds from opts for the deadline checks.
@spec reclaim_transaction(map(), map()) :: {:ok, %{to: String.t(), data: String.t(), value: 0}} | {:error, term()}
Builds the payer's reclaim(PaymentInfo) transaction for an escrowed
hold whose capture deadline has passed.
Accepts the signed payment payload (v2 envelope or inner payload) and the
requirements it was signed for, and returns the call the payer submits
from its own account: %{to: escrow, data: "0x...", value: 0}.
@spec scheme() :: String.t()
Returns "auth-capture".
Examples
iex> X402.Scheme.AuthCaptureEVM.scheme()
"auth-capture"
@spec sign(map(), X402.Signer.t(), keyword()) :: {:ok, map()} | {:error, term()}
Signs the auth-capture scheme payload for the selected transfer method.
The authorization is valid immediately (validAfter "0") and expires
at now + maxTimeoutSeconds, which is also PaymentInfo.preApprovalExpiry.
Options
:now(non_neg_integer/0) - Unix seconds the authorization window starts from (default: current time).:salt(String.t/0) - Unboundsalt(32-byte0xhex). Defaults to fresh random bytes.:salt_nonce(String.t/0) - BoundsaltNonce(32-byte0xhex). Defaults to fresh random bytes.
Whether the client can sign this requirements entry: an EVM network, a
resolvable deployment, a supported transfer method and payment flow, and
the extra fields PaymentInfo needs.
Examples
iex> X402.Scheme.AuthCaptureEVM.signable?(%{
...> "scheme" => "auth-capture",
...> "network" => "eip155:84532",
...> "amount" => "10000",
...> "asset" => "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
...> "payTo" => "0x209693Bc6afc0C5328bA36FaF03C514EF312287C",
...> "maxTimeoutSeconds" => 600,
...> "extra" => %{
...> "name" => "USDC",
...> "version" => "2",
...> "captureMode" => "deferred",
...> "captureAuthorizer" => "0x1563915e194d8cfba1943570603f7606a3115508",
...> "feeRecipient" => "0x0000000000000000000000000000000000000000",
...> "captureDeadline" => 1_800_000_000,
...> "refundDeadline" => 1_800_100_000,
...> "minFeeBps" => 0,
...> "maxFeeBps" => 0
...> }
...> })
true
iex> X402.Scheme.AuthCaptureEVM.signable?(%{"network" => "eip155:84532", "extra" => %{}})
false
@spec validate_payload(map(), map(), keyword()) :: :ok | {:error, {:invalid_auth_capture_payment, X402.AuthCapture.reason()}}
Runs the offline shape guard (X402.Verify.AuthCaptureEVM.validate_shape/2).
Examples
iex> X402.Scheme.AuthCaptureEVM.validate_payload(
...> %{"payload" => %{"salt" => "0x00"}},
...> %{"extra" => %{}},
...> []
...> )
{:error, {:invalid_auth_capture_payment, :payload_format}}