Skip to main content
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.
This guide covers native USDC on Polygon PoS. Native USDC behaves like any other ERC-20 token: you can read balances, approve spenders, and transfer tokens directly onchain. For cross-chain USDC transfers using Circle’s CCTP, see USDC Gateway Integration.
ApproachDescriptionWhen to use
Native USDCStandard ERC-20 contract directly on Polygon PoSWhen you only need payments within Polygon
Gateway USDCCircle’s cross-chain system that moves USDC between blockchains (CCTP)When your users need to send or receive USDC across chains

Example: Read Balance and Transfer

The following example uses viem to check the USDC balance and send 1 USDC on Polygon.
// pnpm add viem
import { createPublicClient, createWalletClient, http, parseUnits } from "viem";
import { polygon } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

// Native USDC contract on Polygon PoS (not bridged USDC.e)
const USDC = "0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359";

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

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 main() {
  const me = account.address;
  const decimals = await pub.readContract({ address: USDC, abi: erc20, functionName: "decimals" });
  const bal = await pub.readContract({ address: USDC, abi: erc20, functionName: "balanceOf", args: [me] });
  console.log("Balance:", Number(bal) / 10 ** Number(decimals), "USDC");

  // Send 1 USDC
  const amount = parseUnits("1", Number(decimals));
  const hash = await wallet.writeContract({ address: USDC, abi: erc20, functionName: "transfer", args: ["0xRecipient...", amount] });
  console.log("tx:", hash);
}

main();