X402.Scheme.UptoEVM (X402 v0.6.0)

Copy Markdown View Source

Built-in X402.Scheme for upto payments on EVM (eip155:*) networks.

Implements both roles:

  • Client — signs a Permit2 PermitWitnessTransferFrom through X402.Permit2, producing the %{"signature" => ..., "permit2Authorization" => ...} scheme payload. The signed permitted.amount is the advertised maximum; the server settles for the actual usage, up to that ceiling. An entry is signable when its network is EVM (eip155:*) and its extra carries the facilitatorAddress the witness must bind (facilitators announce it via GET /supportedX402.Facilitator.supported/1); signing without it fails with {:error, {:missing_extra, "facilitatorAddress"}}.
  • ServerX402.Scheme.validate_payload/3 validates that the payment value the client signed does not exceed the advertised maximum (the requirements' amount, with maxPrice and maxAmountRequired fallbacks), recognizing the Permit2 (permit2Authorization.permitted.amount), maxAmount, value, and EIP-3009 authorization.value payload shapes. Failures are {:error, {:invalid_upto_payment, reason}} — see validation_error/0.

Pre-checks reuse the shared EIP-3009 authorization checks (X402.Scheme.EVM.authorization_precheck/3 — payTo binding and validity window) without the exact-amount equality: for upto, the signed value is a ceiling, not the settled amount. Permit2 payloads carry no payload.authorization map and pass through to the facilitator.

Summary

Types

Reasons an upto payment fails ceiling validation.

Functions

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

Runs X402.Scheme.EVM.authorization_precheck/3 without exact-amount equality — for upto, the signed value is a ceiling.

Returns "upto".

Signs the Permit2 upto scheme payload via X402.Permit2.sign_upto/2.

Whether the client can sign this requirements entry.

Validates that the signed payment value stays within the ceiling.

Types

validation_error()

@type validation_error() ::
  :missing_max_price
  | :missing_payment_value
  | :invalid_max_price
  | :invalid_payment_value
  | :payment_value_exceeds_max_price

Reasons an upto payment fails ceiling validation.

Functions

networks()

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

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

Examples

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

precheck(payload, requirements, opts)

(since 0.6.0)
@spec precheck(map(), map(), keyword()) ::
  :ok | {:error, {:precheck_failed, X402.Scheme.EVM.precheck_failure()}}

Runs X402.Scheme.EVM.authorization_precheck/3 without exact-amount equality — for upto, the signed value is a ceiling.

scheme()

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

Returns "upto".

Examples

iex> X402.Scheme.UptoEVM.scheme()
"upto"

sign(requirements, signer, opts)

(since 0.6.0)
@spec sign(map(), X402.Signer.t(), keyword()) :: {:ok, map()} | {:error, term()}

Signs the Permit2 upto scheme payload via X402.Permit2.sign_upto/2.

The client's build options are ignored — the authorization is valid immediately (witness.validAfter "0") and expires after the requirements' maxTimeoutSeconds, mirroring the reference SDKs.

signable?(requirements)

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

Whether the client can sign this requirements entry.

Requires an EVM (eip155:*) network the Permit2 domain can be derived from and a facilitatorAddress in extra for the witness binding.

Examples

iex> X402.Scheme.UptoEVM.signable?(%{
...>   "network" => "eip155:84532",
...>   "extra" => %{"facilitatorAddress" => "0x2222222222222222222222222222222222222222"}
...> })
true

iex> X402.Scheme.UptoEVM.signable?(%{"network" => "eip155:84532", "extra" => %{}})
false

validate_payload(payload, requirements, opts)

(since 0.6.0)
@spec validate_payload(map(), map(), keyword()) ::
  :ok | {:error, {:invalid_upto_payment, validation_error()}}

Validates that the signed payment value stays within the ceiling.

Examples

iex> X402.Scheme.UptoEVM.validate_payload(
...>   %{"payload" => %{"value" => "9000"}},
...>   %{"amount" => "10000"},
...>   []
...> )
:ok

iex> X402.Scheme.UptoEVM.validate_payload(
...>   %{"payload" => %{"value" => "10001"}},
...>   %{"amount" => "10000"},
...>   []
...> )
{:error, {:invalid_upto_payment, :payment_value_exceeds_max_price}}