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

Activity

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