EIP-712 & EIP-2612 Signing Flows

Off-chain typed data signing for gasless token operations

EIP-712: Typed Structured Data Hashing & Signing Domain Separator string name// "USDC" string version// "2" uint256 chainId// 42161 address contract// 0xaf88… Prevents cross-chain / cross-contract replay ↑ REPLAY PROTECTION Type Definitions // Like a Solidity struct struct Transfer { address from; address to; uint256 value; } keccak256 of type string → typeHash Message Values from:0xAgent… to:0xService… value:1000000 (1 USDC) nonce:0x7a3f… deadline:1712438400 Actual data being signed Final Signable Payload digest = keccak256( "\x19\x01" || domainSeparator || structHash(message) ) ECDSA Sign (Private Key) → produces (v, r, s) signature Signature verifiable on-chain via ecrecover(digest, v, r, s)
Key insight: The three-layer hash (domain + type + values) means a signature for USDC on Arbitrum can never be replayed on Ethereum mainnet, or against a different contract, even if the message values are identical. This is what makes EIP-712 safe for agent wallets.
EIP-3009: TransferWithAuthorization (Gasless USDC) Agent Wallet API / Relayer USDC Contract 1 Construct EIP-712 from: agent address to: service address value: payment amount validBefore: now + 60s 2 Sign with private key → (v, r, s) + typed data 3 API request + signature (no ETH needed!) 4 Verify signature Submit tx on-chain 5 transferWithAuthorization() from, to, value, validAfter, validBefore, nonce, v, r, s 6 ecrecover → verify USDC transferred! nonce invalidated API response (data/signal) Agent paid for service atomically
TransferWithAuthorization Struct
addressfromToken sender (agent wallet)
addresstoToken recipient (service)
uint256valueAmount in smallest unit (6 decimals for USDC)
uint256validAfterEarliest timestamp signature is valid
uint256validBeforeLatest timestamp — expiry window
bytes32nonceRandom nonce (prevents replay)
This is the x402 pattern from Envy: The agent never needs ETH for gas. It signs a USDC authorization off-chain, attaches it to the API request, and the relayer handles the on-chain submission. One atomic operation — pay and get service.
EIP-2612: Permit (Gasless Approve) Token Owner DeFi Protocol Token Contract Blockchain OLD WAY: Two transactions, two gas fees TX 1: approve(spender, amount) — costs gas ⛽ TX 2: transferFrom(owner, to, amount) — costs gas ⛽ EIP-2612 WAY: One signature + one transaction 1 Sign permit off-chain owner: myAddress spender: protocolAddr value, deadline, nonce 2 Send (v, r, s) No gas needed! 3 permit(owner, spender, value, deadline, v, r, s) Sets allowance without owner's gas 4 transferFrom(owner, protocol, value) Now protocol can pull tokens 5 Tokens move Single TX, protocol pays gas Owner signed once off-chain → approve + transfer in 1 TX Protocol batches permit() + transferFrom() in one call
Permit Struct (EIP-2612)
addressownerToken holder signing the permit
addressspenderAddress being approved to spend
uint256valueAllowance amount
uint256nonceSequential nonce (auto-incremented)
uint256deadlineExpiry timestamp
diffvs EIP-3009Sequential nonce (not random), sets allowance (not transfer)

EIP-3009 vs EIP-2612 — Side by Side

EIP-3009: TransferWithAuthorization Operation:Direct transfer (atomic) Steps:Sign → Submit → Done Nonce:Random bytes32 (parallel-safe) Gas paid by:Relayer / service provider Time-bound:validAfter + validBefore Token support:USDC (Circle), few others Best for:Agent-to-service payments Pay-per-request APIs Concurrent operations Used by: Envy (x402), Circle APIs EIP-2612: Permit Operation:Approve (then transferFrom) Steps:Sign → permit() → transferFrom() Nonce:Sequential uint256 (ordered) Gas paid by:Spender / protocol Time-bound:deadline only Token support:Most ERC-20s (DAI, UNI, AAVE…) Best for:DeFi deposit flows LP provision, staking Batch approve+action Used by: Uniswap, Aave, most DeFi
Agent Swarm: EIP-712 + Turnkey TEE Signing Private keys never leave the enclave — agents sign via API 🔒 Turnkey TEE Secure Enclave (AWS Nitro) Sub-org 1 → Key A Sub-org 2 → Key B Agent 1 (Trading) Strategy: momentum Coins: BTC, ETH Policy: max $100/tx No private key in memory Agent 2 (DeFi) Strategy: yield farming Protocol: Aave Policy: max $500/day No private key in memory Agent 3 (Payments) Job: pay for API calls Token: USDC (x402) Policy: max $1/request No private key in memory Agent N (…) Any single-purpose job Own sub-org + key Own policy limits Lightweight + stateless EIP-712 hash → ← (v,r,s) Signing Flow (per agent) 1.Agent constructs EIP-712 typed data (domain + type + values) 2.Agent sends hash to Turnkey API → TEE signs with sub-org key 3.Turnkey policy engine checks: amount ≤ limit? rate ≤ threshold? 4.Signature returned → agent attaches to API request or on-chain tx
Defense in depth: Even if an agent is compromised, damage is bounded by three layers: the Turnkey policy engine (amount/rate limits per sub-org), the EIP-712 domain separator (signatures can't cross chains/contracts), and the validBefore timestamp (signatures expire in seconds). No single breach gives unlimited access.