Shared local pre-checks for EVM authorization-style scheme payloads.
Used by the built-in X402.Scheme.ExactEVM and X402.Scheme.UptoEVM
schemes to implement X402.Scheme.precheck/3, and reusable by
third-party EVM scheme modules whose payloads carry an EIP-3009-style
payload.authorization object.
The checks mirror the first checks every reference facilitator performs
(payTo equality, exact amount equality, time window), so junk traffic is
rejected without paying a facilitator verify call. Two payload shapes are
covered — EIP-3009 payload.authorization
(authorization_precheck/3) and Permit2 payload.permit2Authorization
(permit2_precheck/3); payloads without the expected map are skipped
entirely, as is any individual absent field: the facilitator remains the
authority, these checks only fail fast on certain mismatch.
Summary
Types
Reasons an authorization pre-check fails.
Functions
Runs cheap local checks on an EIP-3009-style payload.authorization.
Runs cheap local checks on a Permit2 payload.permit2Authorization.
Returns the settlement buffer applied to validBefore, in seconds.
Types
Functions
@spec authorization_precheck(map(), map(), keyword()) :: :ok | {:error, {:precheck_failed, precheck_failure()}}
Runs cheap local checks on an EIP-3009-style payload.authorization.
Checks, in order: the authorization's to must equal the requirements'
payTo (case-insensitive for hex addresses); with enforce_exact_amount: true the authorization's value must equal the requirements' amount;
and the validAfter/validBefore window must cover now (with a
6s settlement buffer on validBefore). Payloads
without a payload.authorization map pass with :ok, as does any
individual absent field.
Options
:enforce_exact_amount(defaultfalse) — requireauthorization.valueto equal the requirements'amountexactly. Use forexact-style schemes; for ceiling schemes such asupto, the signed value is a maximum, not the settled amount.
Examples
iex> X402.Scheme.EVM.authorization_precheck(%{"payload" => %{}}, %{})
:ok
iex> payload = %{
...> "payload" => %{"authorization" => %{"to" => "0xAb", "value" => "10"}}
...> }
iex> requirements = %{"payTo" => "0xab", "amount" => "10"}
iex> X402.Scheme.EVM.authorization_precheck(payload, requirements,
...> enforce_exact_amount: true
...> )
:ok
iex> payload = %{
...> "payload" => %{"authorization" => %{"to" => "0xother", "value" => "10"}}
...> }
iex> X402.Scheme.EVM.authorization_precheck(payload, %{"payTo" => "0xab"})
{:error, {:precheck_failed, :pay_to_mismatch}}
@spec permit2_precheck(map(), map(), keyword()) :: :ok | {:error, {:precheck_failed, precheck_failure()}}
Runs cheap local checks on a Permit2 payload.permit2Authorization.
Checks, in order: the witness to must equal the requirements' payTo;
with enforce_exact_amount: true the permitted.amount must equal the
requirements' amount; the permitted.token must equal the
requirements' asset; the spender must equal the :spender option
when one is given; and the witness.validAfter/deadline window must
cover now (with a 6s settlement buffer on
deadline). Addresses compare case-insensitively. Payloads without a
payload.permit2Authorization map pass with :ok, as does any
individual absent field.
Options
:enforce_exact_amount(defaultfalse) — requirepermitted.amountto equal the requirements'amountexactly (theexactscheme's Permit2 transfer method). Forupto, the permitted amount is a ceiling.:spender— the proxy contract the authorization must name asspender(X402.Permit2.exact_proxy_address/0/X402.Permit2.upto_proxy_address/0). Skipped when absent.
Examples
iex> X402.Scheme.EVM.permit2_precheck(%{"payload" => %{}}, %{})
:ok
iex> payload = %{
...> "payload" => %{
...> "permit2Authorization" => %{
...> "permitted" => %{"token" => "0xAAAA", "amount" => "10"},
...> "spender" => "0x402085c248EeA27D92E8b30b2C58ed07f9E20001",
...> "witness" => %{"to" => "0xAb", "validAfter" => "0"}
...> }
...> }
...> }
iex> requirements = %{"payTo" => "0xab", "amount" => "10", "asset" => "0xaaaa"}
iex> X402.Scheme.EVM.permit2_precheck(payload, requirements,
...> enforce_exact_amount: true,
...> spender: "0x402085c248eea27d92e8b30b2c58ed07f9e20001"
...> )
:ok
iex> payload = %{
...> "payload" => %{
...> "permit2Authorization" => %{"witness" => %{"to" => "0xother"}}
...> }
...> }
iex> X402.Scheme.EVM.permit2_precheck(payload, %{"payTo" => "0xab"})
{:error, {:precheck_failed, :pay_to_mismatch}}
@spec time_buffer_seconds() :: pos_integer()
Returns the settlement buffer applied to validBefore, in seconds.
Examples
iex> X402.Scheme.EVM.time_buffer_seconds()
6