Skip to content

docs: add Arc contract deployment notes#151

Open
westkite1201 wants to merge 2 commits into
circlefin:mainfrom
westkite1201:docs/arc-contract-deployment-notes
Open

docs: add Arc contract deployment notes#151
westkite1201 wants to merge 2 commits into
circlefin:mainfrom
westkite1201:docs/arc-contract-deployment-notes

Conversation

@westkite1201

Copy link
Copy Markdown

Summary

  • Add a contract deployment guide for Arc Testnet
  • Document Arc Testnet chain metadata, RPC, Arcscan explorer URL, and USDC native gas metadata
  • Document evmVersion: "paris" for Solidity/Foundry deployments to avoid newer-opcode compatibility issues
  • Add a Hardhat @nomicfoundation/hardhat-verify customChains example for Arcscan/Blockscout verification

Related issues

Validation

  • npx prettier --check README.md docs/deploying-contracts.md
  • git diff --check

@osr21

osr21 commented Jun 16, 2026

Copy link
Copy Markdown

Here's what we found deploying and verifying three contracts on Arc Testnet with Foundry — happy to have any of this incorporated.


Foundry config (foundry.toml)

[profile.default]
solc          = "0.8.20"
evm_version   = "paris"   # REQUIRED — Arc does not support post-Paris opcodes (PUSH0 etc.)
optimizer     = true
optimizer_runs = 200
via_ir        = true       # needed if any contract hits the stack-depth limit

[rpc_endpoints]
arc_testnet = "https://rpc.testnet.arc.network"

evm_version = "paris" is mandatory. The default (shanghai/cancun) emits PUSH0 opcodes that Arc does not support. The deploy tx will succeed but the bytecode will be invalid.


Deploy

forge script script/Deploy.s.sol:Deploy \
  --rpc-url https://rpc.testnet.arc.network \
  --private-key "$DEPLOYER_PRIVATE_KEY" \
  --broadcast --config-path foundry.toml

Deployer wallet needs Arc Testnet USDC (also the native gas token). Get it at https://faucet.circle.com.


Arcscan source verification (Blockscout)

forge verify-contract \
  --verifier blockscout \
  --verifier-url "https://testnet.arcscan.app/api/" \
  --compiler-version 0.8.20 --chain 5042002 \
  <ADDRESS> src/<Contract>.sol:<Contract>

For contracts with constructor args:

  --constructor-args $(cast abi-encode "constructor(address,address)" <ARG1> <ARG2>)

Arcscan display tip

Add address public owner = msg.sender; to your contract. Blockscout reads this and shows it prominently in the contract overview — useful for anyone auditing on-chain.


Arc Testnet quick-reference

Item Value
Chain ID 5042002 (0x4cef52)
RPC https://rpc.testnet.arc.network
Explorer https://testnet.arcscan.app
USDC (native gas) 0x3600000000000000000000000000000000000000
EURC 0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a
CCTP Domain 26
TokenMessengerV2 0x8FE6B999Dc680CcFDD5Bf7EB0974218be2542DAA
MessageTransmitterV2 0xE737e5cEBEEBa77EFE34D4aa090756590b1CE275

Reference implementation with full deploy + verify setup: osr21/arc-stablecoin-dapp.

@osr21

osr21 commented Jun 22, 2026

Copy link
Copy Markdown

The updated doc incorporates the earlier deployment notes well. A few remaining gaps from our deployment experience that are worth adding:


1. forge verify-contract needs --evm-version paris

The current verify commands are:

forge verify-contract \
  --verifier blockscout \
  --verifier-url "https://testnet.arcscan.app/api/" \
  --compiler-version 0.8.20 \
  --chain 5042002 \
  <contract-address> src/<Contract>.sol:<Contract>

Blockscout recompiles the submitted source to confirm the bytecode matches what's on-chain. Without --evm-version paris, the Blockscout recompile uses a newer EVM target, emits PUSH0 or other post-Paris opcodes, and produces different bytecode — so verification fails with a bytecode mismatch. Add --evm-version paris to both verify examples:

forge verify-contract \
  --verifier blockscout \
  --verifier-url "https://testnet.arcscan.app/api/" \
  --compiler-version 0.8.20 \
  --evm-version paris \
  --chain 5042002 \
  <contract-address> src/<Contract>.sol:<Contract>

This is the most common reason Arcscan verification silently succeeds (returns 200) but the contract never shows as verified.


2. Arc native USDC has a decimal split — the quick-reference table should note it

The table lists Native USDC / gas | 0x3600...0000 but doesn't mention the split:

  • ERC-20 interface (transfers, approvals, balances) — 6 decimals, same as Circle USDC on every other chain
  • Native gas accounting (block explorer display, eth_getBalance) — 18 decimals

Calling transfer(recipient, 1_000_000) moves 1 USDC, not 0.000000000001 USDC. This is correct and expected — but developers who inspect a wallet's gas balance in the explorer and then try to replicate that value in an ERC-20 call will get the arithmetic wrong. A one-line note in the table or a dedicated note below it would save integrators a lot of debugging:

| Native USDC / gas | 0x3600000000000000000000000000000000000000 — 6 decimals for ERC-20 calls, 18 for native gas |


3. via_ir = true should be marked optional

As currently written, via_ir = true is in [profile.default] with only a comment saying it's "useful when your contract hits Solidity's stack-depth limit." Readers will include it in every project config by default. It should be called out as optional more explicitly — it can increase compile time by 5–10× on larger contracts and changes code-generation behaviour in ways that occasionally surface edge-case bugs. Suggested change:

# via_ir = true  # Uncomment only if your contract hits the stack-depth limit.
                 # Significantly increases compile time.

4. --compiler-version should note it must match the actual build

Both verify examples hardcode --compiler-version 0.8.20. If a developer follows the Hardhat config at the top of the doc (which uses 0.8.24) and then copies the Foundry verify command, verification will fail with a version mismatch. Worth adding a note: "Replace 0.8.20 with the Solidity version that was used to compile the contract — it must match exactly."

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