Skip to content

fix(arc-testnet): native USDC has 18 decimals, fix broken explorer URL - #19

Open
Ccheh wants to merge 1 commit into
circlefin:masterfrom
Ccheh:fix-arc-chain-config
Open

fix(arc-testnet): native USDC has 18 decimals, fix broken explorer URL#19
Ccheh wants to merge 1 commit into
circlefin:masterfrom
Ccheh:fix-arc-chain-config

Conversation

@Ccheh

@Ccheh Ccheh commented May 13, 2026

Copy link
Copy Markdown

Two real chain-configuration bugs in `lib/circle/gateway-sdk.ts` that propagate into any fork using this sample as a template.

1. Wrong native decimals

```diff

  • nativeCurrency: { name: 'USD Coin', symbol: 'USDC', decimals: 6 },
  • nativeCurrency: { name: 'USDC', symbol: 'USDC', decimals: 18 },
    ```

Arc's native gas token uses 18 decimals (like ETH on other EVM chains), not 6. ERC-20 USDC at `0x3600...` has 6 decimals as a view, but the chain-level `nativeCurrency.decimals` in a viem/wagmi `Chain` definition refers to native gas, which is 18 on Arc. Quoted from `circlefin/skills/use-arc/SKILL.md`:

"Dual decimals: Native gas uses 18 decimals (like ETH on other chains). ERC-20 USDC uses 6 decimals. Mixing these up will produce incorrect amounts."

Empirical confirmation: `circlefin/arc-commerce/lib/wagmi/config.ts` correctly uses `decimals: 18`. The current value of 6 causes any `formatEther`/`formatUnits` against this `nativeCurrency` to be off by a factor of `10^12`.

2. Broken block explorer URL

```diff

`explorer.arc.testnet.circle.com` returns HTTP 000 (DNS does not resolve):

```bash
$ curl -sI -o /dev/null -w "%{http_code}\n" "https://explorer.arc.testnet.circle.com"
000
$ curl -sI -o /dev/null -w "%{http_code}\n" "https://testnet.arcscan.app"
200
```

`testnet.arcscan.app` is the canonical Arc Testnet explorer (referenced in `circlefin/skills/use-arc/SKILL.md`, this repo's own `lib/constants/block-explorers.ts`, and `circlefin/arc-commerce`). Any "View on Explorer" link built from this chain config currently 404s.


Companion PR with the same fixes plus a third (wrong native token symbol "ARC") for `arc-multichain-wallet`: circlefin/arc-multichain-wallet#37.

@Sertug17

Copy link
Copy Markdown

+1 — verified locally on a fresh clone. Confirmed both fixes:

decimals: 6 → 18: Arc Testnet uses USDC as native gas with
18 decimals. With decimals: 6, viem's formatEther/formatUnits
defaults would be off by 10^12.

Explorer URL: Reproduced — https://explorer.arc.testnet.circle.com
returns HTTP 000 (ECONNREFUSED), while https://testnet.arcscan.app
resolves with HTTP 200.

Apologies — I just opened #21 with the same decimals fix before
seeing this PR. Now closed in favor of yours; this is the more
complete fix (covers both lines).

Hopefully gets a review soon — clean, well-scoped, fully justified.

@osr21

osr21 commented Jun 15, 2026

Copy link
Copy Markdown

Good catch — nativeCurrency.decimals: 18 is correct for the chain config context and this fix is right.

Worth documenting the underlying reason explicitly, because it's a persistent source of confusion for developers new to Arc: USDC exists in two distinct forms on Arc that use different decimal precisions:

Context Address Decimals API
Native gas token — (no address) 18 eth_getBalance, MetaMask gas display, viem.getBalance(), Chain.nativeCurrency.decimals
ERC-20 USDC 0x3600000000000000000000000000000000000000 6 approve(), transfer(), balanceOf(), smart contract interactions

The EIP-155 Chain definition's nativeCurrency.decimals always refers to the native gas precision — which is 18 on every EVM chain, Arc included, because the EVM's internal unit (wei) uses 18 decimals regardless of what the token is. But when you call USDC.decimals() on the ERC-20, you get 6.

Practical rules for Arc apps:

// Chain config — always 18 (native gas)
nativeCurrency: { name: "USDC", symbol: "USDC", decimals: 18 }

// Gas balance display
const gasBalance = await client.getBalance({ address });
const displayGas = formatUnits(gasBalance, 18); // "1.5 USDC"

// ERC-20 token amounts — always 6 decimals
const tokenBalance = await client.readContract({ functionName: "balanceOf", ... });
const displayToken = formatUnits(tokenBalance, 6); // "1.500000 USDC"

// Smart contract / API storage — raw 6-decimal base units
const rawAmount = parseUnits("5.00", 6); // BigInt(5_000_000)

Using 6 where 18 is expected (or vice versa) produces a silent 10¹²× error — amounts appear correct in wallet UIs but are wildly wrong on-chain.

Reference: osr21/arc-stablecoin-dapp — architecture docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants