# `X402.Scheme.UptoEVM`
[🔗](https://github.com/cardotrejos/x402/blob/v0.9.0/lib/x402/scheme/upto_evm.ex#L1)

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 /supported` — `X402.Facilitator.supported/1`); signing
  without it fails with `{:error, {:missing_extra, "facilitatorAddress"}}`.
* **Server** — `c:X402.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
  `t: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.

# `validation_error`

```elixir
@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.

# `networks`
*since 0.6.0* 

```elixir
@spec networks() :: [String.t()]
```

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

## Examples

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

# `precheck`
*since 0.6.0* 

```elixir
@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* 

```elixir
@spec scheme() :: String.t()
```

Returns `"upto"`.

## Examples

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

# `sign`
*since 0.6.0* 

```elixir
@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?`
*since 0.6.0* 

```elixir
@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`
*since 0.6.0* 

```elixir
@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}}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
