Developer insights

Arc Compatibility Guide for Existing EVM Apps

Hui Jing Chen pointing at a programming poster
Hui Jing Chen
Developer Relations Manager, APAC at Circle
September 10, 2026
4
min read
September 10, 2026
4
min read

Summary

Many EVM apps can deploy an Arc version without adopting a new programming model. The contracts remain Solidity, and the application can keep using JSON-RPC, EIP-1559 transactions, secp256k1 signing, and Ethereum-style addresses.

Familiar tools such as Foundry, Hardhat, viem, and ethers can continue to support the deployment. Wallets and existing ERC-20 integrations work on Arc without adopting a new asset or programming model.

The main compatibility review is the code that assumes Ethereum's native token or event behavior. Pay particular attention to balance reads, value transfers, and history indexing.

One major difference is that USDC is the native gas token. It pays transaction fees and supports native transfers. The same balance is available through the ERC-20 USDC interface, but the two interfaces use different decimal scales: 18 for native values and 6 for ERC-20 values.

How native and ERC-20 USDC share one balance on Arc

Native and ERC-20 calls serve different parts of an application, but they do not represent two separate assets:

Interface Precision Common use
Native (msg.value, address.balance, eth_getBalance) 18 decimals Gas, native sends, and payable calls
ERC-20 (balanceOf, transfer, allowances) 6 decimals Application transfers, approvals, and pool math


Convert the amount when it moves between the two interfaces. Native values stay in 18 decimals until they enter ERC-20 code; divide by 1012 at that point.

const OFFSET = 12n;

function toErc20Units(nativeAmount: bigint): bigint {
  return nativeAmount / 10n ** OFFSET;
}


Values smaller than 1×10−6 USDC disappear from the ERC-20 view. A balanceOf result of 0 does not prove that the native balance is zero. Code that reads both address.balance and balanceOf should treat them as two precision views of one balance, not as two deposits to add together.

Reusing the same raw integer across interfaces shifts the amount by 1012. One USDC is 1018 in native units and 106 in ERC-20 units, so an ERC-20 amount used as msg.value sends far too little USDC, and a native amount passed to ERC-20 transfer or transferFrom tries to send far too much. Convert at the boundary before the call.

Showing two USDC rows, or summing eth_getBalance with balanceOf, double-counts one balance. Present a single canonical view instead.

For a wallet or portfolio display, use the native balance as the canonical source: read eth_getBalance, convert its 18-decimal value to a human-readable USDC amount (for example, 176229835782048555593 is about 176.23 USDC), and show one row. Use balanceOf only when ERC-20 units are required, but never add it to eth_getBalance.

A contract that “sweeps only native” also moves ERC-20 USDC, because the interfaces share one balance. Review sweep and rescue paths before treating native and ERC-20 holdings as separable pots.

Liquidity integrations need the same distinction. Arc has no WUSDC or WETH-style wrapper. The ERC-20 USDC address is the pool token; pairing “native USDC” against that interface would pair an asset with itself. Deeper AMM changes belong in the DeFi integration and AMM and pools guidance.

The underlying model is explained in more detail at Stablecoin native model.

Native value still follows contract rules

Payable functions continue to work, but native USDC transfers are subject to Arc-specific value rules. A sufficient balance does not guarantee that a native-value call succeeds.

Sending to the zero address, transferring to or from a blocklisted address, burning value, or using certain SELFDESTRUCT paths can revert. A non-zero-value call to an account that self-destructed earlier in the same transaction can also revert.

These rules apply beyond simple wallet sends. Native value can reach a contract address and change its USDC balance, so an application should not assume that USDC enters a contract only through ERC-20 methods. A contract that forwards native value also needs a failed-call path, even when its balance check passed. The UI or backend should surface that failure.

The EVM differences reference covers the complete value-transfer rules. The Port a contract to Arc tutorial turns the same checks into a contract review sequence.

How to avoid double-counting transfers when indexing Arc

On Ethereum, a plain native send often leaves no ERC-20-style log. Arc emits an EIP-7708 Transfer from the system emitter for every native USDC movement, including the native leg of an ERC-20 transfer. That system event uses 18-decimal values. The ERC-20 USDC contract emits its own 6-decimal Transfer for ERC-20-interface activity. One transfer() call therefore produces both events, while a plain native send produces only the system event.

This event model breaks standard ERC-20-only indexing in two ways. Filtering only the ERC-20 contract misses native sends, and treating both emitters as separate movements double-counts every ERC-20 transfer().

Credit each underlying transfer once. Prefer the system emitter for native movements, convert 18-decimal values when normalizing to ERC-20 units, and do not add a second credit from the ERC-20 leg of the same transfer or from a balance delta. Vault and deposit services need the same rule. Current emitter addresses, event formats, and historical testnet details are in USDC system events and Index Arc events.

What to test before deploying an EVM app on Arc

Local Anvil or a standard EVM fork is useful for ordinary contract tests, but it does not reproduce Arc's precompiles, EIP-7708 logs, or blocklist enforcement. Arc Foundry is an Arc-enabled Foundry fork that provides arc-forge, arc-cast, and arc-anvil for local testing against Arc's EVM semantics. Arc-specific cases belong on Arc Testnet: https://rpc.testnet.arc.io, chain ID 5042002.

Tests should cover both sides of the balance model: an ERC-20 transfer with its allowance or transferFrom path, and a native send or payable call using msg.value. The resulting balance and history should reconcile to one application credit per underlying movement.

The suite should include a native transfer to a contract, a blocklist failure, and any SELFDESTRUCT or emergency-withdraw path that moves native USDC. If the application uses time ordering or randomness, it should account for repeated sub-second timestamps and avoid relying on block.prevrandao, which is always 0.

Arc's deterministic finality also changes confirmation logic. Once a transaction is included in a committed block, it is final; applications can omit Ethereum-style confirmation counters and reorganization rollback paths. Indexed activity should use block number and log index rather than assuming timestamps are unique.

Compatibility checklist

Before deploying the Arc version, confirm:

  • Arc Testnet is configured with USDC as the native currency.
  • The application presents one USDC balance, not separate native and ERC-20 assets.
  • Native and ERC-20 amounts are converted across the 18-to-6 decimal boundary.
  • History and crediting use the system emitter and do not count ERC-20 movements twice.
  • Native-value reverts are handled in the UI and backend.
  • Contract tests cover native sends, ERC-20 transfers, and contract recipients against an Arc RPC.
  • No production logic relies on PREVRANDAO for randomness or unique block timestamps.

Wallet teams can continue with Add Arc to a Wallet, indexers with Infrastructure integration, and DeFi teams with DeFi integration.

Circle Technology Services, LLC (“CTS”) is a software provider and does not provide regulated financial or advisory services. You are solely responsible for services you provide to users, including obtaining any necessary licenses or approvals and otherwise complying with applicable laws. For additional details, please click here to see the Circle Developer terms of service

Arc is an open L1 blockchain launched by Arc Network Services LLC ("Arc LLC") and operated by a permissioned validator set. Arc LLC provides software services only and does not offer regulated financial or advisory services. Arc has not been reviewed or approved by the New York State Department of Financial Services or any other regulatory authority.

The Arc network is provided "as is" and "as available." Use of Arc involves inherent risks associated with blockchain technology, including smart contract vulnerabilities, network disruptions, and the absence of recourse for transaction errors or losses. The ability to transact on Arc depends on the ability to obtain and use USDC to pay gas fees. Neither Arc LLC nor any permissioned validator is responsible for the content, accuracy, legality, or functionality of third-party applications, protocols, or services built on or integrated with Arc. You are solely responsible for features or services you provide to users, including obtaining any necessary licenses or approvals and otherwise complying with applicable laws.

All Arc features may be modified, delayed, or cancelled at any time without notice. Nothing herein constitutes a commitment, warranty, guarantee or legal, regulatory, tax, or investment advice. Coming soon.

USDC is issued by regulated affiliates of Circle. See Circle’s list of regulatory authorizations.

Contents