Building on Arc
Arc is not a generic EVM chain. Four of its properties shaped this protocol, and two of them are genuine traps.
Gas is USDC
Arc is Circle's stablecoin-native L1. Transaction fees are denominated in USDC rather than a volatile gas token, blocks are about half a second, and finality is deterministic.
For a liquidity protocol this is unusually convenient: the thing users pay gas in, the thing every token is paired against, and the thing fees are paid out in are all the same asset.
USDC has two representations
The native asset carries 18 decimals. The canonical ERC-20 interface exposes the same balance with 6.
native gas token 18 decimals — what you pay gas in ERC-20 interface 6 decimals — 0x3600...0000 same balance, two precisions. the gap between them is exactly 1e12.
There is no WETH
Delta on Robinhood Chain streams its fee rewards in WETH. Arc has no wrapped ether at all, so this implementation streams in USDC instead — which is also what every token pairs against, making it the natural denominator rather than a compromise.
USDC is not an ordinary ERC-20
This one is only visible if you look. Arc's USDC is a thin wrapper over two chain precompiles:
| Precompile | Role |
|---|---|
0x1800…0001 | Compliance check — isBlocklisted(address), consulted on every transfer. |
0x1800…0000 | The actual native balance move, including the 6-to-18 decimal conversion. |
Two consequences follow, and both are load-bearing.
- Transfers revert for blocklisted parties. Any USDC push sitting on a shared code path is therefore a freeze vector controlled by a third party. This is why protocol fees are pulled, not pushed — see Security.
- USDC cannot execute a transfer inside a Foundry fork. The precompiles have no implementation in the local EVM, so a forked test that moves USDC dies with a stack underflow. Tooling that simulates locally before broadcasting — including
forge script— cannot run any flow that touches it.
Uniswap v4, with no oracle
Uniswap v2, v3, v4 and UniswapX are all live on Arc. v4 moved price oracles out of the core pool and into hooks, which means a protocol operating on pools it does not own has no oracle available to it.
Slice therefore accumulates its own. Every permissionless poke() records a time-weighted observation; automated swaps require both a long enough window and that the spot price has not diverged from the average. An attacker has to hold a dislocated price across the entire window, not for a single block.
Testnet differs from mainnet
The Uniswap PoolManager and the USDC interface sit at identical addresses on both networks. PositionManager and UniversalRouter do not — they have no code at their mainnet addresses on testnet. Slice calls neither, but do not assume an address resolves just because it does on mainnet.