Skip to content

Native USDC Developer Guide

USDC enables the seamless transfer of digital dollars on the Codex network using a smart contract. This guide will walk you through building a simple React app that allows users to connect their wallet and send USDC transactions over the Codex Testnet.

Prerequisites

Before you begin, ensure you have the following:

Development Environment

  • Node.js (16+) installed (comes with npm).
  • MetaMask browser extension installed.

Fund Your Wallet

You’ll need two types of tokens to test USDC transfers:

  1. Native gas token (ETH on Codex Testnet) to cover transaction fees

    • Send Sepolia Testnet ETH to 0xcf4df2bdb14c8fdb25fdaccec10ce5c4baedb3de
    • You’ll receive Codex Testnet ETH in return
  2. USDC tokens for testing

Project Setup

Step 1: Create a new project

Run the following commands to set up your project:

Terminal window
mkdir usdc-transfer-app
cd usdc-transfer-app
npm init -y

Step 2: Install dependencies

Run the following command to install required libraries:

Terminal window
npm install react@latest react-dom@latest @types/react@latest @types/react-dom@latest @vitejs/plugin-react@latest typescript@latest vite@latest viem@latest

Step 3: Ensure package.json is configured

After installing dependencies, open your package.json file, remove "type" : "commonjs" and verify that it looks similar to this:

{
"name": "usdc-transfer-app",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"@types/react": "^19.1.2",
"@types/react-dom": "^19.1.2",
"@vitejs/plugin-react": "^4.4.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"typescript": "^5.8.3",
"viem": "^2.28.0",
"vite": "^6.3.2"
}
}

Step 4: If your package.json does not have the scripts section

Manually add the following inside package.json:

"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
}

This ensures that you can run the project using:

Terminal window
npm run dev

Configure Blockchain Clients

Setting up public and wallet clients

Create a src/clients.ts file and add:

import {
http,
createPublicClient,
createWalletClient,
custom,
defineChain
} from "viem";
declare global {
interface Window {
ethereum: any;
}
}
// Custom Codex chain definition with Thirdweb RPC
const codexTestnet = defineChain({
id: 812242,
name: "Codex Testnet",
nativeCurrency: {
decimals: 18,
name: "Codex",
symbol: "CDX"
},
rpcUrls: {
default: {
http: ["https://812242.rpc.thirdweb.com"]
}
},
blockExplorers: {
default: {
name: "Codex Explorer",
url: "https://explorer.codex-stg.xyz/"
}
},
testnet: true
});
export const publicClient = createPublicClient({
chain: codexTestnet,
transport: http()
});
export const walletClient = createWalletClient({
chain: codexTestnet,
transport: custom(window.ethereum)
});

Define USDC Contract Details

Add this to src/constants.ts:

export const USDC_CONTRACT_ADDRESS =
"0x6d7f141b6819C2c9CC2f818e6ad549E7Ca090F8f";
export const USDC_ABI = [
{
constant: false,
inputs: [
{ name: "_to", type: "address" },
{ name: "_value", type: "uint256" }
],
name: "transfer",
outputs: [{ name: "", type: "bool" }],
type: "function"
},
{
constant: true,
inputs: [{ name: "_owner", type: "address" }],
name: "balanceOf",
outputs: [{ name: "balance", type: "uint256" }],
type: "function"
}
];

Implement Wallet Connection & USDC Transfer

Create src/App.tsx

import React, { useState } from "react";
import { publicClient, walletClient } from "./clients";
import { USDC_CONTRACT_ADDRESS, USDC_ABI } from "./constants";
import { type Address, type Hash, type TransactionReceipt } from "viem";
function USDCApp() {
const [account, setAccount] = useState<Address>();
const [balance, setBalance] = useState<string>();
const [hash, setHash] = useState<Hash>();
const [receipt, setReceipt] = useState<TransactionReceipt>();
const [recipient, setRecipient] = useState<string>("");
const [amount, setAmount] = useState<string>("");
const [isTransferring, setIsTransferring] = useState(false);
// Fetch USDC balance
const fetchBalance = async (address: Address) => {
const balance = (await publicClient.readContract({
address: USDC_CONTRACT_ADDRESS,
abi: USDC_ABI,
functionName: "balanceOf",
args: [address]
})) as bigint;
setBalance((Number(balance) / 10 ** 6).toFixed(2));
};
// Connect Wallet
const connect = async () => {
const [address] = await walletClient.requestAddresses();
setAccount(address);
fetchBalance(address);
};
// Transfer USDC
const transferUSDC = async (e: React.FormEvent) => {
e.preventDefault();
if (!account || !recipient || !amount) return;
try {
setIsTransferring(true);
const amountInWei = BigInt(Math.floor(Number(amount) * 10 ** 6));
const { request } = await publicClient.simulateContract({
account,
address: USDC_CONTRACT_ADDRESS,
abi: USDC_ABI,
functionName: "transfer",
args: [recipient as Address, amountInWei]
});
const hash = await walletClient.writeContract(request);
setHash(hash);
const receipt = await publicClient.waitForTransactionReceipt({ hash });
setReceipt(receipt);
// Refresh balance after transfer
await fetchBalance(account);
// Clear form
setRecipient("");
setAmount("");
} catch (error) {
console.error("Transfer failed:", error);
} finally {
setIsTransferring(false);
}
};
return (
<div>
<h1>USDC Transfer Sample App</h1>
{account ? (
<>
<p>
<strong>Connected Wallet:</strong> {account}
</p>
<p>
<strong>USDC Balance:</strong>{" "}
{balance ? `${balance} USDC` : "Fetching..."}
</p>
<form onSubmit={transferUSDC} style={{ marginTop: "20px" }}>
<div style={{ marginBottom: "10px" }}>
<label>
Recipient Address:
<input
type="text"
value={recipient}
onChange={(e) => setRecipient(e.target.value)}
placeholder="0x..."
style={{ marginLeft: "10px", width: "300px" }}
/>
</label>
</div>
<div style={{ marginBottom: "10px" }}>
<label>
Amount (USDC):
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="0.00"
step="0.01"
min="0"
style={{ marginLeft: "10px" }}
/>
</label>
</div>
<button type="submit" disabled={isTransferring}>
{isTransferring ? "Transferring..." : "Transfer USDC"}
</button>
</form>
{hash && (
<div style={{ marginTop: "20px" }}>
<p>
<strong>Transaction Hash:</strong> {hash}
</p>
</div>
)}
{receipt && (
<div style={{ marginTop: "10px" }}>
<p>
<strong>Transaction Status:</strong>{" "}
{receipt.status === "success" ? "Success" : "Failed"}
</p>
</div>
)}
</>
) : (
<button onClick={connect}>Connect Wallet</button>
)}
</div>
);
}
export default USDCApp;

Configure Your Entry Point

Create src/main.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import USDCApp from "./App";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<USDCApp />
</React.StrictMode>
);

Create Your HTML File

Create index.html in your root directory

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>USDC Transfer Sample App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

Start Your Application

Run the following command:

Terminal window
npm run dev

Then open http://localhost:5173 in your browser.