X402.Scheme.AuthCaptureEVM (X402 v0.9.0)

Copy Markdown View Source

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 ReceiveWithAuthorization toward the deployment's EIP-3009 token collector (default), or a witness-less Permit2 PermitTransferFrom toward its Permit2 collector when extra.assetTransferMethod is "permit2". The authorization's nonce is the payment's signatureNonce, which commits to every PaymentInfo field the facilitator reconstructs; salt (and, when the bind is on, saltNonce) ride alongside. The payload is identical under both payment flows — extra.paymentFlow only decides whether the facilitator settles it as authorize or charge.
  • Server — X402.Scheme.validate_payload/3 runs the offline shape guard and X402.Scheme.precheck/3 the full structural checklist (X402.Verify.AuthCaptureEVM at 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.

Functions

networks()

(since 0.9.0)
@spec networks() :: [String.t()]

Returns ["eip155:*"] — every EVM network.

Examples

iex> X402.Scheme.AuthCaptureEVM.networks()
["eip155:*"]

precheck(payload, requirements, opts)

(since 0.9.0)
@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.

reclaim_transaction(payload, requirements)

(since 0.9.0)
@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}.

scheme()

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

Returns "auth-capture".

Examples

iex> X402.Scheme.AuthCaptureEVM.scheme()
"auth-capture"

sign(requirements, signer, opts \\ [])

(since 0.9.0)
@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) - Unbound salt (32-byte 0x hex). Defaults to fresh random bytes.

  • :salt_nonce (String.t/0) - Bound saltNonce (32-byte 0x hex). Defaults to fresh random bytes.

signable?(requirements)

(since 0.9.0)
@spec signable?(map()) :: boolean()

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

validate_payload(payload, requirements, opts)

(since 0.9.0)
@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}}