Skip to main content
Use Arc’s ERC-20 USDC interface exclusively for all pool accounting, token addresses, and reserve math. The native interface (address.balance, msg.value) uses 18 decimals and is for gas operations only; mixing it with the 6-decimal ERC-20 interface silently breaks constant-product calculations by a factor of 1012. The following steps apply this principle and address five other changes required before deploying to Arc.

Prerequisites

Before you begin, ensure that you’ve:
  • Read the stablecoin-native model concept page to understand Arc’s dual USDC interface
  • Reviewed the EVM differences reference for a complete list of protocol divergences
  • Obtained Arc testnet RPC access at https://rpc.testnet.arc.io (chain ID 5042002)

Steps

Step 1. Set the pool token to the ERC-20 USDC address

Use 0x3600000000000000000000000000000000000000 as the USDC pair address in all pool and router configuration. On other EVM blockchains, protocols use a WETH-style adapter contract to give the native asset an ERC-20 interface. Arc’s native USDC already has a built-in ERC-20 interface, so no adapter is needed. The address 0x3600000000000000000000000000000000000000 is that interface. It already implements transfer, approve, and transferFrom over the native balance.
Do not pair native USDC against the ERC-20 USDC interface as two separate pool tokens. Both interfaces draw from the same underlying balance, so pairing them is equivalent to pairing an asset with itself. A pool configured this way is immediately insolvent.
Two additional mistakes to avoid:
  • The zero address (0x0000000000000000000000000000000000000000) is not USDC. Do not use it as a token address. Value-bearing transfers to it revert on Arc; see Value transfer rules.
  • Any address other than 0x3600000000000000000000000000000000000000 used to represent USDC creates a separate, unrelated token that does not share the native balance.
Update your pool factory, router configuration, and any initialization scripts to reference 0x3600000000000000000000000000000000000000 directly.

Step 2. Account for the 10¹² decimal offset in offchain tooling

Arc’s native USDC has 18 decimals (address.balance, eth_getBalance, msg.value) and the ERC-20 interface has 6 decimals (balanceOf, transfer). The conversion factor between them is 1012. Pool contracts that follow the ERC-20 prescription do not encounter this offset: deposits go through transferFrom, reserves are read from balanceOf, and nonpayable functions block native USDC from entering pool logic. The offset matters in offchain code: monitoring scripts, indexers, and SDK integrations that read eth_getBalance or address.balance must convert to 6-decimal units before comparing or displaying values. Use these constants in your offchain scripts and SDK integrations:

Step 3. Remove WETH-style wrap/unwrap code paths

On most EVM blockchains, the native asset has no ERC-20 interface, so pools use a wrapper contract (WETH, WMATIC, and so on) with deposit() and withdraw() functions. On Arc, native USDC already has a built-in ERC-20 interface. Any WETH-style wrap/unwrap code paths are unnecessary and create double-accounting bugs by crediting balances twice. Replace the wrapped native address constant and remove all deposit() and withdraw() call sites:
Note that internal-only wrapping that is not exposed to users (for example, an internal accounting abstraction similar to what Chainlink uses) is acceptable. User-facing WUSDC wrapper contracts are not.

Step 4. Audit allowance-dependent sweep and security logic

ERC-20 allowances control transfers initiated through transferFrom. They do not gate direct native transfers. A contract holding an approve from a user can still have its native USDC balance moved by a direct native send (call{value: ...}) without any allowance check. Any sweep mechanism or authorization boundary that relies on ERC-20 allowance limits to protect the contract’s native USDC balance is ineffective. Audit your pool’s security logic for this pattern and apply one of the following approaches:
  • Mark the contract nonpayable on functions that should not receive native USDC, preventing accidental native deposits.
  • Add an explicit receive() function that either reverts or records the incoming balance, so the contract behaves predictably on both the native and ERC-20 paths.

Step 5. Replace onchain randomness and audit emergency-shutdown patterns

Two EVM opcodes behave differently on Arc and require review before deployment.
PREVRANDAO always returns 0 on Arc. Any protocol that uses block.difficulty or prevrandao for randomness receives a constant value, making lottery mechanics, shuffle algorithms, and similar constructs predictable and exploitable. Replace these with a verifiable random function (VRF) or oracle-based randomness. See Oracles for available providers on Arc.
Emergency-shutdown and escape-hatch patterns that use SELFDESTRUCT also require review. On Arc, a contract’s USDC balance is its native balance, so SELFDESTRUCT transfers that USDC to the beneficiary address. On Ethereum, the ERC-20 USDC balance lives in the token contract and is unaffected by SELFDESTRUCT.
SELFDESTRUCT moves native USDC on Arc. Protocols with emergency-shutdown patterns that call SELFDESTRUCT will transfer the contract’s entire USDC balance to the beneficiary. Audit every code path that calls SELFDESTRUCT and verify that the USDC transfer is intentional.

Step 6. Test against an Arc RPC endpoint, not a local Anvil fork

Local EVM simulators run a standard EVM and cannot reproduce the following Arc-specific behaviors:
  • Native-coin precompile behavior
  • EIP-7708 Transfer events on native USDC movements
  • Blocklist enforcement on value transfers
  • Arc’s native USDC value transfer rules
Run all pool invariant math and value transfer tests against https://rpc.testnet.arc.io (chain ID 5042002). For a complete porting walkthrough covering contract deployment and verification, see Porting contracts to Arc.