Skip to content

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

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

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