| name | contract-verification |
| description | Use when verifying deployed contracts on block explorers. Covers forge verify-contract, Etherscan/Basescan/Arbiscan APIs, Blockscout verification, constructor args encoding, flattening, proxy verification, and multi-file verification. |
Contract Verification
Why Verify
Verified contracts show source code on block explorers, enabling:
- Public auditability
- Etherscan read/write UI for interaction
- Trust from users and integrators
- Required for many DeFi integrations
forge verify-contract
forge verify-contract 0xContractAddress src/MyContract.sol:MyContract \
--chain-id 1 \
--etherscan-api-key $ETHERSCAN_API_KEY
forge verify-contract 0xContractAddress src/MyToken.sol:MyToken \
--chain-id 1 \
--etherscan-api-key $ETHERSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(string,string,uint256)" "MyToken" "MTK" 1000000000000000000000000)
forge verify-contract 0xContractAddress src/MyContract.sol:MyContract \
--chain-id 1 \
--etherscan-api-key $ETHERSCAN_API_KEY \
--compiler-version v0.8.28 \
--num-of-optimizations 200
forge verify-contract 0xContractAddress src/MyContract.sol:MyContract \
--chain-id 1 \
--etherscan-api-key $ETHERSCAN_API_KEY \
--watch
Chain-Specific Verification
forge verify-contract $ADDR MyContract \
--chain-id 1 --etherscan-api-key $ETHERSCAN_API_KEY
forge verify-contract $ADDR MyContract \
--chain-id 8453 \
--verifier etherscan \
--verifier-url https://api.basescan.org/api \
--etherscan-api-key $BASESCAN_API_KEY
forge verify-contract $ADDR MyContract \
--chain-id 10 \
--verifier etherscan \
--verifier-url https://api-optimistic.etherscan.io/api \
--etherscan-api-key $OPSCAN_API_KEY
forge verify-contract $ADDR MyContract \
--chain-id 42161 \
--verifier etherscan \
--verifier-url https://api.arbiscan.io/api \
--etherscan-api-key $ARBISCAN_API_KEY
Blockscout Verification
forge verify-contract $ADDR MyContract \
--chain-id 8453 \
--verifier blockscout \
--verifier-url https://base.blockscout.com/api/
Constructor Arguments
The most common verification failure is incorrect constructor args:
cast abi-encode "constructor(address,uint256,string)" \
0xAdminAddress 1000000 "MyToken"
cast abi-encode "constructor(address[])" \
"[0xAddr1,0xAddr2,0xAddr3]"
Flattening
When verification tools fail with import resolution, flatten the contract:
forge flatten src/MyContract.sol > MyContract.flat.sol
Proxy Verification
Verify Implementation
forge verify-contract $IMPL_ADDR src/MyContract.sol:MyContract \
--chain-id 1 --etherscan-api-key $ETHERSCAN_API_KEY
Mark Proxy on Etherscan
After verifying the implementation, mark the proxy:
curl "https://api.etherscan.io/api?module=contract&action=verifyproxycontract&apikey=$ETHERSCAN_API_KEY" \
-d "address=$PROXY_ADDR"
curl "https://api.etherscan.io/api?module=contract&action=checkproxyverification&guid=$GUID&apikey=$ETHERSCAN_API_KEY"
Verify ERC-1967 Proxy
forge verify-contract $PROXY_ADDR \
lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967Proxy \
--chain-id 1 \
--etherscan-api-key $ETHERSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(address,bytes)" $IMPL_ADDR $INIT_DATA)
Verification in Forge Scripts
forge script script/Deploy.s.sol \
--rpc-url $ETH_RPC_URL \
--broadcast \
--verify \
--etherscan-api-key $ETHERSCAN_API_KEY
foundry.toml Etherscan Config
[etherscan]
mainnet = { key = "${ETHERSCAN_API_KEY}" }
sepolia = { key = "${ETHERSCAN_API_KEY}" }
base = { key = "${BASESCAN_API_KEY}", url = "https://api.basescan.org/api" }
optimism = { key = "${OPSCAN_API_KEY}", url = "https://api-optimistic.etherscan.io/api" }
arbitrum = { key = "${ARBISCAN_API_KEY}", url = "https://api.arbiscan.io/api" }
With this config, forge verify-contract auto-selects the right API based on --chain-id.
Troubleshooting
"Compiler version mismatch"
forge build --force
forge verify-contract $ADDR MyContract --compiler-version v0.8.28+commit.7893614a
"Constructor arguments mismatch"
cast tx $DEPLOY_TX_HASH input --rpc-url $ETH_RPC_URL
"Bytecode mismatch"
Ensure identical compiler settings:
- Same solc version
- Same optimizer settings (enabled, runs)
- Same EVM version
- Same via-ir setting
- Same remappings
forge build --force
cast code $ADDR --rpc-url $ETH_RPC_URL > deployed.hex
Verification Checklist