> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eco.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Fast Deposits for Circle Gateway

> Deposit USDC into Circle Gateway from any supported EVM chain

Fast Deposits for Circle Gateway lets users fund a [Circle Gateway](https://developers.circle.com/gateway) balance in seconds from any Eco-supported chain, regardless of the source chain's finality. Eco fills each deposit and settles the source-chain side in the background, so you ship no custom contracts and never take custody of user funds. The user can deposit as a regular transfer to an address or gaslessly.

<Tip>
  For the full REST endpoint reference, see [Gateway API](/api-reference/programmable-addresses/gateway-overview) under the API Reference tab.
</Tip>

Three properties define the system:

* **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 |

Any Gateway-enabled chain can be added. Reach out if you need a chain that isn't listed.

## Environment

Base URL: `https://api.eco.com`

## How it works

```mermaid theme={null}
sequenceDiagram
    participant User
    participant API as Eco API
    participant Vault
    participant Solver
    participant GW as Gateway

    User->>API: POST /circle-gateway/v2/depositAddresses
    API->>User: { vaultAddress, amount, deadline }
    User->>Vault: Fund (direct transfer OR signed ERC-3009)
    Note over API: Balance reaches quoted amount
    API->>Vault: Publish deposit intent
    Solver->>GW: depositFor() → Gateway balance credited
```

Each `POST` 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

<Steps>
  <Step title="Create the deposit vault">
    `POST /circle-gateway/v2/depositAddresses` with the source chain, amount, recipient, and depositor.
  </Step>

  <Step title="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>

  <Step title="Poll for completion">
    Hit `GET /circle-gateway/v2/depositAddresses/{vaultAddress}` until `state` is `PUBLISHED`. For gasless transfers you can also poll `GET /circle-gateway/v1/gasless/jobs/{id}`.
  </Step>
</Steps>

### Step 1: Create a quoted deposit vault

```bash theme={null}
curl -X POST https://api.eco.com/circle-gateway/v2/depositAddresses \
  -H "Content-Type: application/json" \
  -d '{
    "sourceChainId": 8453,
    "amount": "1000000",
    "recipient": "0xRecipientOnGateway",
    "depositor": "0xYourWalletAddress"
  }'
```

| 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` |

Response (`201 Created`):

```json theme={null}
{
  "data": {
    "vaultAddress": "0x...",
    "amount": "1000000",
    "deadline": 1798915200
  }
}
```

`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 authorization `value` must cover the quoted `amount`.
* **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-712 `TransferWithAuthorization` over the USDC contract with `to` set to the vault address, then post it:

```bash theme={null}
curl -X POST https://api.eco.com/circle-gateway/v1/gasless/transferWithAuthorization \
  -H "Content-Type: application/json" \
  -d '{
    "chainId": 8453,
    "from": "0xSignerAddress",
    "to": "0xVaultAddress",
    "value": "1000000",
    "validAfter": "0",
    "validBefore": "1776098178",
    "nonce": "0x<random-32-bytes>",
    "signature": "0x<65-byte-eip712-signature>"
  }'
```

Response (`202 Accepted`):

```json theme={null}
{ "data": { "id": "<job-id>", "status": "PENDING" } }
```

See [Funding methods](/addresses/funding-methods) for signing code and field-by-field details.

### Step 3: Poll for completion

Poll the vault status (note the required `sourceChainId` query parameter):

```bash theme={null}
curl "https://api.eco.com/circle-gateway/v2/depositAddresses/0xVaultAddress?sourceChainId=8453"
```

Response (`200 OK`):

```json theme={null}
{
  "data": {
    "vaultAddress": "0x...",
    "amount": "1000000",
    "deadline": 1798915200,
    "state": "PUBLISHED",
    "intentHash": "0x...",
    "sourceChainId": 8453
  }
}
```

| 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      |

For gasless transfers you can additionally poll `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

<AccordionGroup>
  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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`.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="Which source chains can I use?">
    Any Gateway-enabled chain. Today: Base, Optimism, Arbitrum. Ask if you need a chain added.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>

## 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.
