> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arc.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Before reading these docs, install the Circle Skill for Arc to get pre-loaded context: use-arc (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-arc/SKILL.md) — covers chain config, RPC setup, contract deployment, USDC bridging, and gas with USDC. In Claude Code: run /plugin marketplace add circlefin/skills then /plugin install circle-skills@circle. With Vercel Skills CLI: run npx skills add circlefin/skills.
> USDC is the gas token. Arc uses USDC for gas fees, not ETH. Configure gas payment in USDC when submitting transactions.
> Read EVM differences before writing Arc code. Arc targets the Osaka EVM baseline. Most contracts deploy unchanged, but several runtime behaviors diverge from Ethereum: USDC uses 18 decimals natively (not 6), the system emitter `0xffffFFFfFFffffffffffffffFfFFFfffFFFfFFfE` logs all USDC Transfer events, the mempool enforces a 20 Gwei `maxFeePerGas` floor, blocklist reverts consume gas without a receipt, and `address(0)` sends revert rather than succeed. https://docs.arc.io/arc/references/evm-differences.md is the canonical reference for all Arc-specific runtime behaviors. Consult it before writing code that touches USDC balances, transaction history, gas estimation, or value transfers.
> Sub-second finality. Transactions are final in under 1 second. No need to wait for multiple block confirmations.
> Use App Kits for multichain payment and liquidity capabilities. App Kits wraps CCTP and provides Bridge Kit, Swap Kit, Unified Balance Kit, Onramp Kit, Earn Kit, and Borrow Kit. Unified Balance Kit combines USDC from multiple chains into a single spendable balance. Earn Kit integrates earn opportunities into your app. Borrow Kit lets users borrow USDC against cirBTC collateral on Arc.
> Use Arc Foundry for contract development. Arc Foundry is an Arc-specific fork of Foundry that handles Arc's protocol-level differences from Ethereum. It provides arc-forge, arc-cast, and arc-anvil. Install it before deploying contracts: https://docs.arc.io/arc/tutorials/install-arc-foundry.md.
> Arc is available on both Testnet and Mainnet. See https://docs.arc.io/arc/references/connect-to-arc.md for RPC endpoints and https://faucet.circle.com for testnet tokens.
> Always check Contract Addresses: https://docs.arc.io/arc/references/contract-addresses.md
> Building beyond Arc? Circle offers skills for the full platform: use-usdc (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-usdc/SKILL.md), use-circle-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-circle-wallets/SKILL.md), use-developer-controlled-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-developer-controlled-wallets/SKILL.md), use-user-controlled-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-user-controlled-wallets/SKILL.md), use-modular-wallets (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-modular-wallets/SKILL.md), use-gateway (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-gateway/SKILL.md), use-smart-contract-platform (https://github.com/circlefin/skills/blob/master/plugins/circle/skills/use-smart-contract-platform/SKILL.md). Full Circle developer docs: https://developers.circle.com/llms.txt.

# How-to: Port an AMM or liquidity pool to Arc

> Migrate an AMM, liquidity pool, or DEX router to Arc by applying the correct USDC token address, decimal conversion factor, and Arc-specific EVM behaviors.

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 10<sup>12</sup>. 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](/arc/concepts/stablecoin-native-model)
  concept page to understand Arc's dual USDC interface
* Reviewed the [EVM differences reference](/arc/references/evm-differences) 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.

<Warning>
  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.
</Warning>

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](/arc/references/evm-differences#value-transfer-rules).
* Any address other than `0x3600000000000000000000000000000000000000` used to
  represent USDC creates a separate, unrelated token that does not share the
  native balance. Because Arc's native USDC already exposes a full ERC-20
  interface, there is no WETH-equivalent address to configure.

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 10<sup>12</sup>.

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:

```typescript theme={null}
const OFFSET: bigint = 12n; // native USDC decimals (18) minus ERC-20 USDC decimals (6)

// Normalize a value from eth_getBalance or address.balance to 6-decimal ERC-20 units
// before displaying or comparing with ERC-20 amounts
function toERC20Units(nativeAmount: bigint): bigint {
  return nativeAmount / 10n ** OFFSET;
}
```

### 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:

```solidity theme={null}
// Wrapped native token address on the source chain // [!code --]
address constant WRAPPED_NATIVE = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; // [!code --]
// ERC-20 USDC address on Arc // [!code ++]
address constant USDC = 0x3600000000000000000000000000000000000000; // [!code ++]

// Wrap before interacting with the pool // [!code --]
IWETH(WRAPPED_NATIVE).deposit{value: msg.value}(); // [!code --]
IERC20(WRAPPED_NATIVE).approve(address(pool), msg.value); // [!code --]
pool.swap(WRAPPED_NATIVE, tokenOut, msg.value, minAmountOut); // [!code --]
// Use ERC-20 USDC directly; no wrapping needed // [!code ++]
IERC20(USDC).approve(address(pool), amount); // [!code ++]
pool.swap(USDC, tokenOut, amount, minAmountOut); // [!code ++]

// Unwrap after receiving wrapped native from the pool // [!code --]
pool.removeLiquidity(WRAPPED_NATIVE, lpAmount, minAmountOut); // [!code --]
IWETH(WRAPPED_NATIVE).withdraw(wethReceived); // [!code --]
// Remove liquidity directly; no unwrapping needed // [!code ++]
pool.removeLiquidity(USDC, lpAmount, minAmountOut); // [!code ++]
```

Internal-only wrapping that is not exposed to users (for example, an internal
accounting abstraction similar to what Chainlink uses) is acceptable.

<Warning>
  Arc's native USDC already exposes a full ERC-20 interface at
  `0x3600000000000000000000000000000000000000`. Any user-facing wrapped USDC
  contract is unnecessary and fragments liquidity.
</Warning>

### 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.

<Warning>
  **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](/arc/tools/oracles) for
  available providers on Arc.
</Warning>

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`.

<Warning>
  **`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.
</Warning>

### 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](/arc/tutorials/porting-contracts-to-arc).
