| Method | User txs | User needs gas? | When to use |
|---|---|---|---|
ERC-3009 transferWithAuthorization | 0 | No | Recommended — single-tx gasless (USDC-native) |
| EIP-2612 Permit | 0 | No | Fallback for tokens that support permit() but not ERC-3009 |
| Direct transfer | 1 | Yes | Sender already has source-chain gas |
prefetch=1) to serialize submissions and prevent operator-wallet nonce collisions under concurrent load.
Prerequisite for all three: call POST /api/v1/depositAddresses/gateway/polygon once to register the deposit address. The address is deterministic (CREATE2) and can be shared before it’s deployed on-chain — first deposit deploys it.
Reference UIs that implement the signing and polling end-to-end: gateway.eco.com (mainnet) and deposit-addresses-sandbox.vercel.app (preproduction).
ERC-3009 transferWithAuthorization
Recommended. USDC’s native gasless path. User signs aTransferWithAuthorization off-chain; the operator wallet submits a single transferWithAuthorization() call that moves tokens directly from the signer to the deposit address.
USDC’s EIP-712 domain name varies per chain — "USDC" on Base Sepolia, "USD Coin" elsewhere. Use the correct value for the chain you’re signing on.
PENDING → COMPLETED (or FAILED).
EIP-2612 Permit
Fallback when the token supportspermit() but not ERC-3009. User signs a Permit off-chain; the operator wallet submits two txs on their behalf:
permit(owner, spender = depositAddress, value, deadline, v, r, s)on the tokencreateIntentWithApproval(funder = owner)on the deposit contract, which atomicallytransferFroms the tokens and publishes the intent(s)
202 Accepted with { id, status: "PENDING" }. Status transitions PENDING → PERMIT_SENT → COMPLETED (or FAILED).
Direct transfer
The sender submits a vanilla ERC-20transfer() to the deposit address. Balance monitoring detects the deposit and kicks off deployment (first time) and intent creation.
POST to obtain the address. The sender pays gas.
Polling the job
status is COMPLETED or FAILED, with a 1–2 minute overall timeout.
Validation
The service rejects requests before queueing if any of:- Deposit address isn’t registered on
chainId - USDC isn’t configured for
chainId - Permit
deadline/ ERC-3009validBeforeis in the past, orvalidAfteris in the future value <= 0, or signer’s USDC balance is less thanvalue- Signature, nonce, or address fields don’t match the expected shapes (see Validation rules)
FAILED; the transaction is never retried automatically.