JSON-RPC

Arc differences

Read this page before shipping anything that moves money. Every item here is a protocol fact, and every one of them has a standard EVM assumption on the other side of it.

01USDC has two decimal interfaces over one balance

Native USDC is 18 decimals; the ERC-20 interface at 0x3600...0000 is 6. They are the same balance. A zero balanceOf does not mean an empty account, because the ERC-20 view truncates sub-USDC fractions. Mixing them is off by a factor of 10^12.

02Transactions under 20 Gwei are dropped silently

A transaction with maxFeePerGas below the base fee floor never enters a block and never produces a receipt or an error. It simply never existed.

03One transfer emits two logs

An ERC-20 transfer() emits a 6-decimal Transfer from the token contract and an 18-decimal EIP-7708 Transfer from the system emitter. A plain native send emits only the system log. Gas deductions emit no log at all.

04The mempool is closed

eth_newPendingTransactionFilter and newPendingTransactions subscriptions return -32001. eth_getBlockByNumber("pending") fails too: Circle's public mainnet endpoint answers -32014, other nodes return null. arc-node hides pending data by default since v0.7.0, so there is no public mempool to watch or front-run.

05Finality is deterministic

A block is either absent or irreversible. There are no reorgs, no confirmation depth and no uncles, so an indexer needs no rollback path and a webhook is safe at one confirmation. The finalized tag returns the latest block.

06The base fee is not burned, and the next one is in the header

Base fee and tip both go to the block's miner address. The next block's base fee is published as 8 big-endian bytes in the parent header's extraData, so a fee quote needs no estimate. The floor is 20 Gwei and the ceiling 20,000 Gwei.

07tx.from is not always the payer

Memo and Multicall3From keep the original caller as msg.sender through the CallFrom precompile, and relayed transfers carry the real sender only in the Transfer log. Attribute USDC movement from the log, not from the transaction.

08History starts about a minute behind the tip

At half-second blocks the usual 127-block archive boundary is roughly sixty seconds old, so almost every historical read is an archive read.

09Timestamps are non-decreasing, not increasing

Sub-second blocks share a block.timestamp. The ordering key is block number and log index, never the timestamp.

10A transfer can revert with a full balance

Transfers to the zero address, burns, transfers to a self-destructed account or a precompile, and any transfer touching a blocklisted address all revert. The revert still consumes gas.

What we handle for you

Four of these are enforced at our endpoint rather than left in your integration. Balances come back at both scales with a truncation flag, sub-floor transactions are rejected with -32020 instead of dropped, the transfer feed de-duplicates the two emitters, and pre-flight tells you whether a transfer will revert on a blocklist rule before you spend the 20 Gwei.

The other four are yours: order by (blockNumber, logIndex), drop your reorg handling, expect archive reads for anything older than a minute, and do not assume a value transfer to a contract succeeds.