docs: add CCTP V2 integration guide for Arc Testnet (closes #110) - #127
docs: add CCTP V2 integration guide for Arc Testnet (closes #110)#127zkasuran wants to merge 2 commits into
Conversation
Documents the Arc-specific details needed to move native USDC on and off Arc with CCTP V2, addressing circlefin#110: - Arc CCTP domain is 26 (verified against Circle's supported-blockchains list; the testnet shares the mainnet domain). - All Arc CCTP contracts are V2. The V1 depositForBurn selector (0x6fd3504e) reverts against the V2 TokenMessenger; the V2 selector is 0x8e0250ee. Both were checked by computing keccak of the signatures. - Burns sourced from Arc should use minFinalityThreshold 2000 (finalized); 1000 can leave the attestation stuck pending. - eth_estimateGas can return data:null for depositForBurn, so pass an explicit gasLimit. - How to fetch the attestation from the Iris API and the fee endpoint. Contract addresses are from Circle's EVM smart contracts reference and the TokenMessenger was confirmed to have code on Arc Testnet. Adds a link from the README documentation section.
|
Independently verified the technical values in this guide and they all check out:
One small wording nit: the guide says "a value above 2000 is capped to 2000," but per the technical guide the rule is "any value below 1000 is treated as 1000, and any value above 1000 is treated as 2000" — so The gas-limit (600k) and USDC-system-address gotchas raised on #110 are already covered here. LGTM. |
The guide said a value above 2000 is capped to 2000, which reads as if 1500 stays 1500. Circle's technical guide states the real rule: any value below 1000 is treated as 1000 and any value above 1000 is treated as 2000, so everything between rounds up to a finalized transfer.
|
Good catch, fixed in The line now states the rule from Circle's technical guide: any value below 1000 is treated as 1000 and any value above 1000 is treated as 2000. So 1500 rounds up to a finalized transfer instead of staying at 1500. I pulled the guide again before rewording, because "capped to 2000" implies a scale that does not exist. Thanks for the independent check on the domain, the four V2 addresses and the selectors. |
|
Good guide — the domain, contract addresses, and selector split are correct. A few additions from having run this integration end-to-end on Arc Testnet that might be worth folding in: USDC decimal trapThe guide correctly states USDC on Arc lives at
|
| Source | Destination | Typical wait (minFinalityThreshold 2000) |
|---|---|---|
| Arc | any | 1–3 min |
| Ethereum Sepolia | Arc | 2–5 min |
| Base Sepolia | Arc | 2–5 min |
| Avalanche Fuji | Arc | 2–5 min |
Practical polling recipe: 5-second interval, 20-minute timeout. Attestations that have not completed after 20 minutes almost always indicate an on-chain revert or an incorrect source domain passed to the Iris endpoint — inspect the burn receipt before re-polling.
destinationCaller semantics (non-zero case)
The guide shows bytes32(0) (anyone may relay), which is the right default for most integrations. For completeness: if destinationCaller is set to a specific address (left-padded to 32 bytes), only that address can call receiveMessage on the destination chain. This is useful for atomic relayers that need to prevent front-running, but requires the caller address to also be left-padded to 32 bytes (same padding rule as mintRecipient).
RPC reliability (Sepolia)
If the guide grows to include testnet setup: rpc.sepolia.org is unreliable. https://ethereum-sepolia-rpc.publicnode.com has been stable for high-volume CCTP testing.
Arc Testnet block explorer
For any burn/mint transaction links in examples: the canonical Arc Testnet explorer is https://testnet.arcscan.app with the standard /tx/{hash} path. Earlier URLs (explorer.testnet.arc.network, explorer.arc.io) are dead.
Overall this fills a real gap — the V1/V2 selector split and the minFinalityThreshold two-tier behaviour are the two most common failure modes for developers porting older CCTP code to Arc, and neither was documented anywhere before this.
What this does
Adds a CCTP V2 integration guide at
docs/cctp-v2-integration.mdand links it from the README documentation section. It resolves #110.The guide documents the Arc-specific details a developer needs to move native USDC on and off Arc with Cross-Chain Transfer Protocol V2, which are not currently in this repo or obvious from Circle's general docs:
destinationDomainindepositForBurn.depositForBurnselector (0x6fd3504e) reverts against the V2 TokenMessenger. The V2 selector is0x8e0250ee. This trips up code ported from older Circle examples.minFinalityThreshold: 2000for burns sourced from Arc. 1000 (Fast Transfer) can leave the attestation stuckpending.eth_estimateGascan returndata: nullfordepositForBurn, so pass an explicitgasLimit(covered with the typical gas range).How I verified the values
0x8FE6…2DAAreturns contract code (2175 bytes) on Arc Testnet viaeth_getCode.depositForBurn(uint256,uint32,bytes32,address,bytes32,uint256,uint32)=0x8e0250ee, V1depositForBurn(uint256,uint32,bytes32,address)=0x6fd3504e.minFinalityThresholdsemantics (1000 = Fast/confirmed, 2000 = Standard/finalized): Circle's contract interfaces. The "use 2000 on Arc" guidance comes from the field report in docs: CCTP V2 integration on Arc Testnet — domain 26, minFinalityThreshold 2000, V1 selector incompatible #110; I documented it as Arc behavior, not as a Circle spec./v2/messages/{sourceDomain}and/v2/burn/USDC/fees/{src}/{dst}paths return well-formed responses against the sandbox host.Docs-only change, no code touched.
AI disclosure
This guide was prepared with help from Claude (Anthropic), which drafted the prose. Every value (domain, contract addresses, selectors, finality thresholds, API paths) was verified against Circle's official documentation, an on-chain
eth_getCodecall, a local keccak computation of the selectors, and live calls to the Iris sandbox API before submitting. The verification steps are listed above so they can be rechecked.