Skip to main content

Verification Logic

The facilitator performs these checks in order:
  1. Type guard: Payload matches Eip3009Payload or Permit2Payload (includes signature and salt).
  2. Scheme match: requirements.scheme === "auth-capture" and payload.accepted.scheme === "auth-capture".
  3. Network match: payload.accepted.network === requirements.network and format is eip155:<chainId>.
  4. Extra validation: All required extra fields present.
  5. Method routing: extra.assetTransferMethod (default "eip3009") matches the payload shape.
  6. Deadline ordering: refundDeadline >= captureDeadline, captureDeadline > now + 6s, and the payload’s validBefore (EIP-3009) or deadline (Permit2) <= captureDeadline.
  7. Time window: validBefore / deadline > now + 6s (not expired) and validAfter <= now (active, EIP-3009 only).
  8. Spender / collector match: authorization.to === EIP3009_TOKEN_COLLECTOR_ADDRESS (EIP-3009) or permit2Authorization.spender === PERMIT2_TOKEN_COLLECTOR_ADDRESS (Permit2).
  9. Token match: permit2Authorization.permitted.token === requirements.asset (Permit2 only, EIP-3009 binds via signing domain).
  10. Signature verify: Recover signer from EIP-712 (ReceiveWithAuthorization or PermitTransferFrom); must match payer.
  11. Amount: Authorization amount matches requirements.amount.
  12. Nonce match: Reconstruct PaymentInfo from extra + salt + payer + requirements; recompute the payer-agnostic hash; assert it matches the wire nonce. This transitively enforces equality on every field encoded in PaymentInfo (receiver, token, deadlines, fee bounds, feeRecipient).
  13. Simulate: Call AuthCaptureEscrow.authorize(...) or .charge(...) via eth_call to verify success.
The SAFETY_MARGIN_SECONDS constant is 6, which is why deadline comparisons use now + 6s.

EIP-6492 Support

For smart wallet clients, the signature may be EIP-6492 wrapped (containing deployment bytecode). The facilitator extracts the inner ECDSA signature for verification. The on-chain ERC6492SignatureHandler in the token collector handles wallet deployment during settlement.

Settlement Logic

  1. Re-verify the payload (catch expired/invalid payloads before spending gas).
  2. Determine function: extra.autoCapture === true ? "charge" : "authorize".
  3. Resolve collector: EIP3009_TOKEN_COLLECTOR_ADDRESS or PERMIT2_TOKEN_COLLECTOR_ADDRESS (per assetTransferMethod).
  4. Encode collectorData: raw ERC-3009 signature, or ABI-encoded Permit2 signature.
  5. Call escrow: AuthCaptureEscrow.<functionName>(paymentInfo, amount, tokenCollector, collectorData).
  6. Wait for receipt: 60s timeout.
  7. Return result: tx hash, network, payer.

Error Codes

Verification Errors

Settlement Errors

Next Steps

Wire Format

PaymentRequirements and PaymentPayload shapes.

PaymentInfo Struct

On-chain struct, expiry ordering, and safety guarantees.