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

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 `c: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.

# `precheck_failure`

```elixir
@type precheck_failure() ::
  :pay_to_mismatch
  | :amount_mismatch
  | :invalid_authorization_value
  | :token_mismatch
  | :spender_mismatch
  | :authorization_not_yet_valid
  | :authorization_expired
  | :invalid_authorization_timing
```

Reasons an authorization pre-check fails.

# `authorization_precheck`
*since 0.6.0* 

```elixir
@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` (default `false`) — require `authorization.value`
  to equal the requirements' `amount` exactly. Use for `exact`-style
  schemes; for ceiling schemes such as `upto`, 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}}

# `permit2_precheck`
*since 0.9.0* 

```elixir
@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` (default `false`) — require `permitted.amount`
  to equal the requirements' `amount` exactly (the `exact` scheme's
  Permit2 transfer method). For `upto`, the permitted amount is a
  ceiling.
* `:spender` — the proxy contract the authorization must name as
  `spender` (`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}}

# `time_buffer_seconds`
*since 0.6.0* 

```elixir
@spec time_buffer_seconds() :: pos_integer()
```

Returns the settlement buffer applied to `validBefore`, in seconds.

## Examples

    iex> X402.Scheme.EVM.time_buffer_seconds()
    6

---

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