Skip to main content

@faremeter/payment-evm

@faremeter/payment-evm implements the Coinbase x402 exact scheme on EVM chains. It provides:
Source: GitHub › packages/payment-evm
  • A client handler that signs EIP-3009 TransferWithAuthorization payloads using a local or Ledger-backed wallet.
  • A facilitator handler that validates client payloads, verifies signatures, and submits the transfer on-chain.
  • Shared constants and type guards you can reuse in custom flows.
The package expects USDC-style tokens that support transferWithAuthorization. Asset metadata (contract addresses, forwarders, etc.) comes from @faremeter/info/evm.

Quick start

import { createPaymentHandler } from "@faremeter/payment-evm/exact";
import { createLocalWallet } from "@faremeter/wallet-evm";
import { baseMainnet } from "./chains";

const wallet = await createLocalWallet(baseMainnet, process.env.PRIVATE_KEY!);

const handler = createPaymentHandler(wallet, {
  asset: "USDC", // optional override, defaults to USDC
});

// Provide to @faremeter/fetch
const fetchWithPayments = wrap(fetch, { handlers: [handler] });
On the merchant side:
import { createFacilitatorHandler } from "@faremeter/payment-evm/exact";
import { baseMainnet } from "./chains";

const handler = await createFacilitatorHandler(
  baseMainnet,
  process.env.FACILITATOR_PRIVATE_KEY!,
  "USDC",
);

const routes = createFacilitatorRoutes({ handlers: [handler] });

Modules

exact/createPaymentHandler(wallet, opts?)

Creates a PaymentHandler compatible with @faremeter/fetch.
  • wallet: object exposing { chain, address, account } where account.signTypedData follows the viem signature contract. @faremeter/wallet-evm and @faremeter/wallet-ledger return compatible wallets.
  • opts.asset: asset to request. Accepts token symbols defined in @faremeter/info/evm or custom contract descriptors ({ address, contractName, ... }).
Behavior:
  • Detects the x402 network from wallet.chain.id and validates the asset.
  • Filters incoming requirements to ones matching the network + asset.
  • For each match, returns a PaymentExecer that:
    • Generates an EIP-3009 authorization (nonce, validity window).
    • Validates/augments EIP-712 domain details from the requirement payload.
    • Signs typed data with the wallet and returns { payload: { authorization, signature } }.
Throws when payTo is not a valid EVM address or when domain metadata is malformed.

exact/createFacilitatorHandler(chain, privateKey, asset, opts?)

Creates a FacilitatorHandler suitable for @faremeter/facilitator.
  • chain: ChainInfo (id, RPC URLs) describing the network you serve.
  • privateKey: EVM private key used to submit transactions. Must pass @faremeter/types/evm.isPrivateKey.
  • asset: token symbol or explicit asset info understood by @faremeter/info/evm.
  • opts.network: override the x402 network identifier if it differs from chain.id.
  • opts.transport: custom viem transport (defaults to http(chain.rpcUrls.default.http[0])).
Handler responsibilities:
  • getSupported: returns the supported { scheme: "exact", network, x402Version: 1 }.
  • getRequirements: filters incoming requirements and fills:
    • asset: resolved contract address.
    • maxTimeoutSeconds: 300 (5 minutes).
    • extra: EIP-712 domain metadata (chainId, verifying contract, etc.).
  • handleSettle: validates the payload (x402ExactPayload), checks amount and destination, verifies on-chain nonce usage, and broadcasts a transferWithAuthorization transaction.
Errors throw on signature mismatch, invalid authorization windows, incorrect destination, and failed transactions. null is returned when the requirement doesn’t belong to this handler, allowing other handlers to try.

Constants and helpers

  • X402_EXACT_SCHEME: literal "exact".
  • TRANSFER_WITH_AUTHORIZATION_ABI: viem-compatible ABI definitions used for reading/writing USDC authorizations.
  • EIP712_TYPES: TransferWithAuthorization typed-data schema.
  • x402ExactPayload: arktype runtime validator for payloads – use it to guard custom integrations.
  • eip712Domain: arktype validator for allowed domain overrides.
  • generateMatcher(network, asset): internal helper that derives a requirements matcher via @faremeter/types/x402.generateRequirementsMatcher.
  • generateDomain(publicClient, chainId, asset): fetches USDC contract name/version to build the EIP-712 domain.
  • generateForwarderDomain(chainId, info): constructs domains when using a forwarder contract.

Usage patterns

  • Ledger support: Combine with @faremeter/wallet-ledger.createLedgerEvmWallet to sign authorizations on a Ledger device while reusing the exact same handler API.
  • Forwarders: If @faremeter/info/evm describes a forwarder, the facilitator automatically fills the extra field with the forwarder’s domain metadata.
  • Custom assets: Extend @faremeter/info/evm token catalog and pass the new symbol as asset. Both client and facilitator will share the same metadata.
  • Observability: The facilitator emits warnings via ["faremeter","payment-evm"] (through Logtape). Capture those during settlement to identify mismatches.
  • @faremeter/info/evm: token catalogs and helper lookups used by both handlers.
  • @faremeter/types: x402 schemas, FacilitatorHandler, and validation utilities.
  • @faremeter/fetch & @faremeter/facilitator: client/server orchestration around these handlers.