- Non-custodial: Eco never holds user funds. USDC moves from the user’s wallet into a dedicated source-chain vault that can only fund the quoted deposit intent. If the intent is never fulfilled, funds return to the
refundRecipient(defaults to the depositor). - Permissionless: Any wallet or application can request a deposit vault via the API. No whitelisting, no KYC gate.
- Per-intent vaults: Each vault is created for every intent and carries a quote
deadline. The vault address is derived deterministically from the quoted intent.
Supported chains
| Source chains | Destination |
|---|---|
| Base, Optimism, Arbitrum | Gateway on Polygon |
Environment
Base URL:https://api.eco.com
How it works
EachPOST creates a quoted Routes intent and returns its vault address. When the vault’s USDC balance reaches the quoted amount, Eco publishes the intent and a solver fulfills it on Polygon by calling Gateway’s depositFor for the recipient. The solver is repaid from the vault once fulfillment is proven.
Quickstart
Create the deposit vault
POST /circle-gateway/v2/depositAddresses with the source chain, amount, recipient, and depositor.Fund it, gasless or direct
Collect an ERC-3009 signature and call
POST /circle-gateway/v1/gasless/transferWithAuthorization, or just do a vanilla ERC-20 transfer. Send at least the quoted amount before the deadline.Step 1: Create a quoted deposit vault
| Field | Type | Required | Description |
|---|---|---|---|
sourceChainId | number | Yes | Source chain (one of the supported chains above) |
amount | string | Yes | Source-chain USDC amount in base units (6 decimals) |
recipient | string | Yes | Recipient credited on Gateway (Polygon) |
depositor | string | Yes | Address that will fund the vault |
refundRecipient | string | No | Address that receives expiry refunds. Defaults to depositor |
201 Created):
deadline is the quote expiry in Unix seconds. Fund the vault before it passes. Repeating the same request while the quote is pending and unexpired returns the same vaultAddress; a different amount (or an expired quote) produces a new vault.
Step 2: Fund the vault
Three ways, pick one:- ERC-3009
transferWithAuthorization(recommended for gasless UX). Single transaction, no user gas. The authorizationvaluemust cover the quotedamount. - EIP-2612 Permit. Two transactions (
permit()and the pull into the vault), no user gas. - Direct ERC-20 transfer. Sender pays gas.
Recommended: ERC-3009 gasless transfer
Have the user sign an EIP-712TransferWithAuthorization over the USDC contract with to set to the vault address, then post it:
202 Accepted):
Step 3: Poll for completion
Poll the vault status (note the requiredsourceChainId query parameter):
200 OK):
| State | Meaning |
|---|---|
PENDING | Vault created, waiting for funds |
FUNDING_DETECTED | Vault balance reached the quoted amount |
PUBLISHED | Deposit intent published; solver fulfillment follows in seconds |
EXPIRED_UNFUNDED | Quote deadline passed before the vault was funded |
FAILED | Publishing failed; funds follow the refund path |
REFUNDED_BY_USER | Depositor reclaimed the funds |
RECOVERY_PUBLISHED | Recovery service published a recovery intent for the funds |
GET /circle-gateway/v1/gasless/jobs/{id}, which transitions PENDING → (PERMIT_SENT for Permit only) → COMPLETED or FAILED and includes transferTxHash when complete. The intentHash comes from the vault status endpoint above.
To confirm the deposit reached Gateway, query Circle Gateway’s balance API for the recipient address.
FAQ
How do I know when funds have landed in Gateway?
How do I know when funds have landed in Gateway?
Poll
GET /circle-gateway/v2/depositAddresses/{vaultAddress}?sourceChainId={id} until state is PUBLISHED, then confirm the credited balance by querying Circle Gateway’s balance API for the recipient address.What happens if the gasless job ends up `FAILED`?
What happens if the gasless job ends up `FAILED`?
Nothing.
FAILED means the service couldn’t initiate the transfer (e.g. signature invalid, balance dropped, deadline expired). USDC never left the user’s wallet. The signature just expires. Submit a new one to retry.What if I send less than the quoted amount?
What if I send less than the quoted amount?
The deposit isn’t triggered until the vault balance reaches the quoted
amount, so the vault stays PENDING. Top it up before the deadline. If the deadline passes first, the quote moves to EXPIRED_UNFUNDED and any funds in the vault are recoverable to the refundRecipient.What if USDC arrives at the vault but the deposit to Gateway never happens?
What if USDC arrives at the vault but the deposit to Gateway never happens?
The vault status tells you which path the funds took:
FAILED means publishing didn’t complete, REFUNDED_BY_USER means the depositor reclaimed the funds, and RECOVERY_PUBLISHED means an independent recovery service stepped in. In every non-PUBLISHED outcome, funds return to the refundRecipient. Refund and recovery are permissionless, so you (or anyone) can also drive them yourself.How fast is end-to-end?
How fast is end-to-end?
On Base Sepolia → Polygon Amoy we typically see 20–40 seconds from submission to Gateway balance update. Time scales with source-chain finality.
Permit vs ERC-3009, which should I prefer?
Permit vs ERC-3009, which should I prefer?
ERC-3009
transferWithAuthorization, single transaction, cleaner UX, USDC-native. Use Permit if the token you’re working with supports permit() but not ERC-3009.Which source chains can I use?
Which source chains can I use?
Any Gateway-enabled chain. Today: Base, Optimism, Arbitrum. Ask if you need a chain added.
Is the vault address the same every time?
Is the vault address the same every time?
While a quote is pending and unexpired, repeating the same request returns the same
vaultAddress. A different amount, a different recipient, or an expired quote produces a new vault. Always send users the address from the latest response.Security
- Each quote maps to a dedicated vault derived deterministically from the intent it funds. No shared contract state.
- USDC in a vault can only fund the quoted deposit intent or be refunded to the
refundRecipient. It cannot be redirected. - Refunds and recovery are driven by an independent, permissionless service. Funds cannot be stuck.
- Full audit reports (Cantina) are available on request.
- Eco never holds or touches user funds.
