EIP-712 & EIP-2612 Signing Flows
Off-chain typed data signing for gasless token operations
EIP-712 Core
EIP-3009 (TransferWithAuth)
EIP-2612 (Permit)
Comparison
Agent Swarm Pattern
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
address from Token sender (agent wallet)
address to Token recipient (service)
uint256 value Amount in smallest unit (6 decimals for USDC)
uint256 validAfter Earliest timestamp signature is valid
uint256 validBefore Latest timestamp — expiry window
bytes32 nonce Random 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)
address owner Token holder signing the permit
address spender Address being approved to spend
uint256 value Allowance amount
uint256 nonce Sequential nonce (auto-incremented)
uint256 deadline Expiry timestamp
diff vs EIP-3009 Sequential 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.