Before you start
- Connect your tooling to Arc Testnet. See Connect to Arc.
- Have your contract source and its test suite ready.
- Get testnet USDC from the Circle Faucet to pay for gas and fund test transfers.
Steps
1
Audit balance and decimal assumptions
Search your contract for places that read
balanceOf or address.balance
and for any logic that compares or combines the two.- Convert before comparing: the ERC-20 view uses 6 decimals and the native view uses 18 for the same balance.
- Treat the ERC-20
balanceOfas inexact. It truncates anything below 1×10⁻⁶ USDC, so0.0000001USDC reads as0and100.0000001USDC reads as100. AbalanceOfof0does not mean the native balance is0.
2
Audit value transfers
Find every native send and every path that forwards value.
- Handle reverts: a native transfer can revert even with a sufficient
balance, for example a transfer to the zero address, a transfer to or from
a blocklisted address, or any transfer that would burn value. Gas is
consumed on a revert. Check
receipt.status === 0to detect it.
3
Audit approvals and sweeps
Review allowances and any “sweep” logic.
- Don’t treat an ERC-20 allowance as a complete spending control on a
contract.
USDC.approveboundstransferFromcalls only. If the contract you’re building also exposes functions that send native USDC, those paths move USDC regardless of any allowance. Account for all transfer paths in your access controls, not just the ERC-20 interface. - If a contract is meant to hold USDC only as an ERC-20 token and not to act on native value, don’t let it sweep its native balance. Native USDC and the ERC-20 USDC interface are the same asset, so a native sweep also moves the users’ ERC-20 USDC balance.
- Don’t pair “native” against the ERC-20 USDC interface in a liquidity pool. Both legs are the same asset, so the pairing is meaningless.
4
Audit DEX, AMM, and router contracts
If you are porting a DEX, AMM, or router (for example, Uniswap V2, Uniswap
V3, or a fork), there is no wrapped native token on Arc and no
WUSDC/WETH equivalent is needed.-
Use the ERC-20 USDC contract directly as the pair token. Arc’s ERC-20
USDC interface at
0x3600000000000000000000000000000000000000is the canonical token. Treat it like any other ERC-20 in your pool, pair, and router code. -
Do not deploy a
WUSDCwrapper contract. Wrapping the native asset on Arc fragments liquidity and can create user confusion. The ERC-20 interface already exposestransfer,approve, andtransferFromover the same underlying native balance. -
Replace
WETH-style code paths. Removedeposit()/withdraw()wrap-and-unwrap calls, and replace anyWETHaddress constant in your router or periphery contracts with the ERC-20 USDC address above. Routes that accepted raw native value viamsg.valuecan either keep accepting native USDC, or be simplified to ERC-20-only flows since both interfaces move the same balance. Mind the decimals when you mix paths:msg.valueis denominated in 18-decimal native USDC, while the ERC-20 USDC interface uses 6 decimals. -
Don’t alias the EIP-7528 native-asset sentinel that DeFi SDKs use in
routing tables to Arc’s ERC-20 USDC address
(
0x3600000000000000000000000000000000000000). Aliasing it conflates native value transfers with ERC-20 transfers. -
Do not bridge or deploy
USDC.e/wUSDCvariants. All USDC on Arc arrives via CCTP as the native asset. See Bridges for the bridging rules.
5
Audit SELFDESTRUCT usage
If your contract uses
SELFDESTRUCT, confirm it doesn’t depend on burning,
on sending value to a destructed account, or on retaining USDC afterward.- A contract’s USDC is its native balance, so self-destructing transfers that USDC to the beneficiary. On other chains the ERC-20 USDC balance would remain in the token contract.
- Self-destructing to yourself with a balance, to the zero address with a balance, to a blocklisted address, or to an already self-destructed account all revert.
- A non-zero-value call to a contract after it self-destructs reverts on Arc, even though it succeeds on Ethereum.
6
Audit randomness sources
Replace any use of
block.prevrandao with a VRF or randomness oracle. On
Arc, PREVRANDAO always returns 0. Contracts that use it for lottery,
shuffle, or relay logic will always receive 0.7
Test against an Arc RPC endpoint
Run your test suite against Arc Testnet, not a local EVM simulator. Tools
like Foundry’s
anvil run a standard EVM and cannot reproduce Arc’s
precompiles, EIP-7708 Transfer events, or USDC blocklist enforcement.8
Exercise the revert paths
Confirm your contract handles a blocklist revert gracefully using the seeded
blocklisted test address on the contract
addresses
page. A value transfer to or from it reverts at runtime, including when it is
the beneficiary of a
SELFDESTRUCT.