> ## 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 Native Integration

> How to read balances and transfer native USDC on Polygon PoS using viem.

<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 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](/payment-services/stablecoins/usdc-gateway-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 |

## Example: Read Balance and Transfer

The following example uses [viem](https://viem.sh/) to check the USDC balance
and send 1 USDC on Polygon.

```ts theme={null}
// 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();
```
