Arc network
CrackPay runs on Arc, Circle's Layer 1 blockchain where USDC is the gas token.
CrackPay runs on Arc mainnet at www.crackpay.xyz, with real USDC. Each CrackPay deployment is on exactly one network, and your app runs on whichever network opened it, so read the chain from the provider rather than hardcoding it (see Choosing the network).
Arc mainnet
| Chain ID | 5042 (0x13b2) |
| viem / wagmi | arc from viem/chains / wagmi/chains; arcMainnet in the SDK |
| RPC | https://rpc.mainnet.arc.io |
| Explorer | https://explorer.arc.io |
| Faucet | None. Real USDC. |
Arc Testnet
| Chain ID | 5042002 (0x4cef52) |
| viem / wagmi | arcTestnet from viem/chains / wagmi/chains and the SDK |
| RPC | https://rpc.testnet.arc.network |
| Explorer | https://explorer.testnet.arc.io |
| Faucet | faucet.circle.com, choose Arc Testnet |
Tokens
| Token | Mainnet | Testnet | Decimals |
|---|---|---|---|
| USDC (ERC-20 interface) | 0x3600000000000000000000000000000000000000 | 0x3600000000000000000000000000000000000000 | 6 |
| EURC | 0xbEf5f6d51CB62b58e6A8f77868681825C6fe21c1 | 0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a | 6 |
EURC's address differs between the networks. Look tokens up with
getTokens(chainId) from the SDK. The older tokens export is testnet only.
Choosing the network
import { connectCrackPay } from "@crackpay/miniapp-sdk/viem";
import { getTokens } from "@crackpay/miniapp-sdk";
const crackpay = await connectCrackPay();
if (!crackpay) throw new Error("Open this app in CrackPay.");
crackpay.chain.id; // 5042 on mainnet, 5042002 on testnet
const tokens = getTokens(crackpay.chain.id)!;
With the bare provider, call eth_chainId and pass the result to
getArcChain(). Keep your own contract addresses per chain ID, and deploy and
list them on every network you support.
USDC has two scales
USDC is Arc's native token and an ERC-20 token. They are the same balance, seen through two interfaces:
| Interface | Decimals | Where you meet it |
|---|---|---|
| Native | 18 | A transaction's value, eth_getBalance, msg.value |
| ERC-20 | 6 | balanceOf, transfer, approve |
One dollar is parseEther("1") as a native value and parseUnits("1", 6)
through the token contract.
- Never add the two, and never show both. They are one balance.
- For display, read
balanceOfand format with 6 decimals. - Never pass a 6-decimal amount as a
value: it would send a trillionth of what you meant.
No gas token
Gas is paid in USDC, and CrackPay handles it. Users never need anything else, and your app never sets gas fields.
Finality
Blocks are final in under a second. There are no confirmations to wait for.