Skip to content

bug: testnet.arcscan.app contract verification API rejects all standard Blockscout formats #210

Open

Description

@osr21

Summary

The testnet.arcscan.app block explorer's contract verification API does not accept submissions via any standard Blockscout format. The only working verification path is the browser UI — which doesn't scale for multi-contract or multi-chain deployments.

Reproduction

Tested with four contracts (Paymaster, GasRelayer, FeeRouter, YieldVault) compiled with:

  • Solidity 0.8.20
  • Optimizer: enabled, 200 runs
  • evmVersion: "paris"

Format 1: Blockscout v1 flat source (POST /api?module=contract&action=verifysourcecode)

curl -X POST "https://testnet.arcscan.app/api?module=contract&action=verifysourcecode" \
  --data-urlencode "addressHash=0x..." \
  --data-urlencode "name=Paymaster" \
  --data-urlencode "codeformat=solidity-single-file" \
  --data-urlencode "compilerVersion=v0.8.20+commit.a1b79de6" \
  --data-urlencode "optimization=true" \
  --data-urlencode "optimizationRuns=200" \
  --data-urlencode "evmVersion=paris" \
  --data-urlencode "contractSourceCode@Paymaster.sol"

Response: {"message":"Missing codeformat field","result":null,"status":"0"}

This error is returned even when codeformat is included in the request body. Tested with both application/x-www-form-urlencoded and multipart/form-data content types.

Format 2: Blockscout v2 JSON (POST /api/v2/smart-contracts/{address}/verification/via/flattened-code)

curl -X POST "https://testnet.arcscan.app/api/v2/smart-contracts/0x.../verification/via/flattened-code" \
  -H "Content-Type: application/json" \
  -d '{"compiler_version":"v0.8.20+commit.a1b79de6","contract_name":"Paymaster","files":{"Paymaster.sol":"..."},"is_optimization_enabled":true,"optimization_runs":200,"evm_version":"paris","constructor_args":"..."}'

Response: "Bad request"

Format 3: Blockscout v2 multipart

curl -X POST "https://testnet.arcscan.app/api/v2/smart-contracts/0x.../verification/via/flattened-code" \
  -F "compiler_version=v0.8.20+commit.a1b79de6" \
  -F "contract_name=Paymaster" \
  -F "files[]=@Paymaster.sol;type=text/plain" \
  -F "is_optimization_enabled=true" \
  -F "optimization_runs=200" \
  -F "evm_version=paris" \
  -F "constructor_args=..."

Response: "Bad request"

Hardhat and Foundry

npx hardhat verify --network arcTestnet 0x...
# Error: Failed to send contract verification request.
# Endpoint URL: https://testnet.arcscan.app/api?module=contract&action=verifysourcecode
# Reason: Missing codeformat field
forge verify-contract 0x... Paymaster \
  --verifier blockscout \
  --verifier-url https://testnet.arcscan.app/api
# same underlying v1 error

What works

The browser UI works:

  1. Open https://testnet.arcscan.app/address/{address}
  2. Click Contract → Verify & Publish
  3. Choose Solidity (Single file)
  4. Fill in compiler version, optimizer settings, paste source, paste constructor args

This works but requires one browser session per contract per chain — not viable for a 4-contract × 4-chain deployment.

Impact

  • Builders cannot use hardhat-verify, forge verify-contract, or custom CI scripts to verify contracts on Arc
  • All four standard Blockscout API formats fail
  • No verified source means no ABI auto-read in Arcscan, which blocks contract UI and read/write tabs for users

Questions

  1. Is programmatic API verification intentionally disabled on testnet.arcscan.app?
  2. If not, what field name or format does the endpoint actually expect?
  3. Is there a plan to expose a working verification endpoint, or to integrate with a hosted verification service (e.g. Sourcify)?

Workaround (until fixed)

Use the Blockscout UI manually per contract. If deploying multiple contracts, keep a script that generates the ABI-encoded constructor args for each — the UI accepts a hex-encoded constructor arguments field.

import { ethers } from "ethers";
const coder = ethers.AbiCoder.defaultAbiCoder();

// Paymaster: constructor(address usdc, address relayer, address feeRecipient, uint256 gasRate)
const args = coder.encode(
  ["address","address","address","uint256"],
  [USDC_ADDRESS, RELAYER, FEE_RECIPIENT, GAS_RATE]
).slice(2); // remove 0x prefix — paste this into the Arcscan UI

Activity

  1. kutluhaneth46 commented on Sep 12, 2026

    @kutluhaneth46
    Contributor

    Taking this. The v1 contract verify API does accept submissions when the request uses Etherscan-compatible field names; I will document the working Hardhat/Foundry path and the Blockscout-native field-name pitfall that produces the Misleading Missing codeformat error.

  2. kutluhaneth46 commented on Sep 12, 2026

    @kutluhaneth46
    Contributor

    Root cause confirmed: Arcscan /api speaks the Etherscan V1 verify dialect. Blockscout-native fields (addressHash, name, contractSourceCode) produce the misleading Missing codeformat field response even when codeformat is present. Etherscan-compatible fields (contractaddress, contractname, sourceCode, codeformat, …) accept the submission (status: 1 + GUID).

    Opened a docs + Foundry config PR: #396

  3. osr21 commented on Sep 14, 2026

    @osr21
    Author

    External, unaffiliated contributor to Arc and Circle — advisory only, no write access. Verified the claims below independently against live endpoints before posting.


    Confirmed the field-name diagnosis: hitting testnet.arcscan.app/api?module=contract&action=verifysourcecode with Blockscout-native fields reproduces the exact Missing codeformat field response, and switching to Etherscan V1 field names gets past that stage to a different validation error — consistent with the endpoint speaking the Etherscan dialect, not Blockscout's own. Also checked hardhat.config.ts on main: there's currently no etherscan/customChains/sourcify entry at all, so the Hardhat half of this issue stays open even once #396 merges — worth its own issue rather than assuming it rides along with the Foundry fix.

    On the "hosted verification service" question in the original report: Sourcify already supports this chain today. Its public chain registry lists Arc Testnet (chain ID 5042002) as supported: true, and the Memo contract used in #396's own repro (0x5294E9927c3306DcBaDb03fe70b92e01cCede505) already has an exact_match verification recorded there from 2026-06-03 — earlier than, and independent of, its Arcscan verification (Arcscan's own record for the same address shows is_verified_via_sourcify: false, so the two verification stores aren't linked to each other). Practically, that means @nomicfoundation/hardhat-verify's built-in sourcify: { enabled: true } (or sourcify-cli directly) verifies against Arc Testnet right now with none of the Etherscan-dialect handling #396 has to document for Arcscan. For anyone blocked on CI verification today, that's a working path in parallel with the Arcscan fix, not just a fallback once Hardhat wiring for Arcscan lands.

  4. kutluhaneth46 commented on Sep 14, 2026

    @kutluhaneth46
    Contributor

    Thanks @osr21 for the independent confirmation on the field-name diagnosis, and for the Sourcify note.

    Agree the Hardhat half should not ride silently on #396. That path is already tracked separately in #384, which wires @nomicfoundation/hardhat-verify + Arcscan customChains for Arc Testnet in this repo. #396 stays focused on the Arcscan Etherscan-dialect docs and Foundry config; #384 covers the in-repo Hardhat reference.

    The Sourcify observation is useful for anyone blocked on CI today: Arc Testnet is already in Sourcify's public registry, and the Memo address from the #396 repro has an exact_match there independent of Arcscan. Worth calling out as a parallel verification path while Arcscan Hardhat wiring lands.

  5. huklaa commented on Oct 9, 2026

    @huklaa

    @ZhiyuCircle @romac — could you assign #210 to me (@huklaa), or approve the scope below? With #396 now closed, I would like to take responsibility for the remaining Arcscan API verification guidance.

    My proposed approach:

    I will credit the diagnosis and prior work recorded by @kutluhaneth46 and @osr21, and distinguish fresh verification from checking an already-verified contract. Per CONTRIBUTING.md, I will wait for maintainer assignment/approval before submitting a PR. Please confirm the scope and whether the explorer/docs owners should be involved.

  6. osr21 commented on Oct 9, 2026

    @osr21
    Author

    @huklaa I agree to this, @ZhiyuCircle please assign @huklaa

  7. huklaa commented on Oct 9, 2026

    @huklaa

    Thanks @osr21. I have prepared a scoped draft on my fork: https://github.com/huklaa/arc-node/blob/docs-210-verification-evidence/docs/arcscan-verification.md . It credits the prior diagnosis and keeps Hardhat work in #384 / #84.

    New checks: the pinned Foundry v1.4.4 already uses Sourcify v2; no toolchain upgrade is needed just for that API migration. The existing Memo record reports runtimeMatch=exact_match but creationMatch=null, so I document that distinction. Its original compiler/optimizer/EVM settings and remappings also need to be preserved, rather than assuming today's repository defaults reproduce the deployment.

    The draft covers terminal status polling and independent source/ABI checks; a GUID alone is not success. Fresh Arcscan validation is still outstanding: the read-only API request returned 403 in my environment and the embedded browser could not open that endpoint. I have not deployed or submitted a new verification.

    I remain available to take this on once a maintainer confirms assignment/scope. A maintainer-approved, existing unverified deployment with its original build artifacts would let me complete the fresh end-to-end verification before an upstream PR.

  8. osr21 commented on Oct 10, 2026

    @osr21
    Author

    Be sure to give credit

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingecosystemComponent: ecosystem

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions