« All posts

Self-Hosting an x402 Facilitator: EIP-3009 Gotchas

DeskCrew shares four critical EIP-3009 pitfalls discovered while self-hosting an x402 payment facilitator, including a bug that could have cost real money.

DeskCrew, a support-tool platform that lets AI agents pay per action in USDC via the x402 (HTTP-402) protocol, decided to self-host its entire payment stack — facilitator, relayer and settlement confirmation — instead of relying on a hosted provider. That choice surfaced four subtle but costly pitfalls in the EIP-3009 authorization model.

The most dangerous one: checking whether a nonce was "consumed" on the USDC contract is not proof that money actually moved. Because the payer controls that nonce, they can cancel it or burn it via a self-transfer, making the system record a payment as settled while the wallet received nothing — a gap an adversarial agent could exploit to get free service at scale. The fix was to verify the on-chain Transfer event adjacent to AuthorizationUsed in the same transaction, rather than trusting nonce state. The other three lessons cover using a uniquely-constrained "claim" table keyed by nonce to guarantee exactly-once execution, treating multi-chain support as a real engineering effort rather than a copy-paste job (different USDC contracts per chain, and Solana lacking EIP-3009 entirely), and distinguishing genuine payment demand from mere discovery traffic (manifest fetches, quotes) in funnel metrics.

The takeaway generalizes well beyond DeskCrew: verification should be anchored to actual value transfer on-chain, not to states an adversary can influence. For engineers building or integrating x402-style micropayment flows, it's a concrete reminder that "signature verified" and "payment received" are not interchangeable.