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

# USDC Gateway Integration

> How to integrate USDC on Polygon using Circle's Gateway (CCTP) for cross-chain transfers.

<Warning title="Security notice">
  The following examples are demonstrations of integrations and should not be
  used in production. In production, store sensitive information such as API keys
  and private keys in a secrets manager or vault.
</Warning>

This guide covers the Gateway approach to USDC on Polygon. Gateway USDC uses
Circle's Cross-Chain Transfer Protocol (CCTP), which lets users hold a single
omnichain balance and move it across chains without separate per-chain contracts.

For payments that stay within Polygon, see
[USDC Native Integration](/payment-services/stablecoins/usdc-native-integration/).

| Approach     | Description                                                            | When to use                                                |
| ------------ | ---------------------------------------------------------------------- | ---------------------------------------------------------- |
| Native USDC  | Standard ERC-20 contract directly on Polygon PoS                       | When you only need payments within Polygon                 |
| Gateway USDC | Circle's cross-chain system that moves USDC between blockchains (CCTP) | When your users need to send or receive USDC across chains |

## How Gateway USDC Works

The Circle Gateway is a cross-chain USDC liquidity layer:

* **Deposits**: Users send USDC to a Gateway Wallet contract.
* **Attestations**: Circle verifies the burn event on the source chain.
* **Mints**: A Gateway Minter contract releases the same amount on the destination chain.

This design allows trust-minimized USDC movement between chains.

## Example: Deposit, Attest, and Mint

The following example:

1. Deposits USDC into the Gateway wallet on Polygon
2. Requests an attestation from Circle's API
3. Mints the funds back via the Gateway Minter

```ts theme={null}
import { createPublicClient, createWalletClient, http, parseUnits } from "viem";
import { polygon } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
import { fetch } from "undici";

const USDC = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359";
const GATEWAY_WALLET = "0x77777777Dcc4d5A8B6E418Fd04D8997ef11000eE";
const GATEWAY_MINTER = "0x2222222d7164433c4C09B0b0D809a9b52C04C205";

const erc20 = [
  { type: "function", name: "decimals", stateMutability: "view", inputs: [], outputs: [{ type: "uint8" }] },
  { type: "function", name: "approve", stateMutability: "nonpayable", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [{ type: "bool" }] },
];

const gatewayWalletAbi = [
  { type: "function", name: "deposit", stateMutability: "nonpayable", inputs: [{ type: "address" }, { type: "uint256" }], outputs: [] },
];

const gatewayMinterAbi = [
  { type: "function", name: "gatewayMint", stateMutability: "nonpayable", inputs: [{ type: "bytes" }, { type: "bytes" }], outputs: [] },
];

const account = privateKeyToAccount(process.env.PRIV_KEY as `0x${string}`);
const rpc = http(process.env.POLYGON_RPC_URL);
const pub = createPublicClient({ chain: polygon, transport: rpc });
const wallet = createWalletClient({ chain: polygon, transport: rpc, account });

async function gatewayTransfer() {
  // 1. Approve + deposit
  const decimals = await pub.readContract({ address: USDC, abi: erc20, functionName: "decimals" });
  const amount = parseUnits("25", Number(decimals));

  await wallet.writeContract({ address: USDC, abi: erc20, functionName: "approve", args: [GATEWAY_WALLET, amount] });
  await wallet.writeContract({ address: GATEWAY_WALLET, abi: gatewayWalletAbi, functionName: "deposit", args: [USDC, amount] });

  // 2. Request attestation from Circle Gateway API
  const res = await fetch("https://gateway-api.circle.com/v1/transfer", {
    method: "POST",
    headers: { "content-type": "application/json", authorization: `Bearer ${process.env.CIRCLE_API_KEY}` },
    body: JSON.stringify({
      burnIntent: {
        spec: {
          version: 1,
          sourceDomain: 7, // Polygon domain ID
          destinationDomain: 7, // same-chain "withdraw", or change for cross-chain
          sourceContract: GATEWAY_WALLET,
          destinationContract: GATEWAY_MINTER,
          sourceToken: USDC,
          destinationToken: USDC,
          sourceDepositor: account.address,
          destinationRecipient: "0xRecipient...",
          value: amount.toString(),
        },
      },
    }),
  });
  const { attestationPayload, signature } = await res.json();

  // 3. Submit attestation to GatewayMinter
  const tx = await wallet.writeContract({
    address: GATEWAY_MINTER,
    abi: gatewayMinterAbi,
    functionName: "gatewayMint",
    args: [attestationPayload as `0x${string}`, signature as `0x${string}`],
  });
  console.log("gatewayMint tx:", tx);
}

gatewayTransfer();
```
