Skip to main content
Contract verification allows users and developers to view and interact with your contract source code on block explorers like Etherscan.

Automatic Verification

The easiest way to verify contracts is during deployment by adding the --verify flag to your Forge script command.

During Deployment

forge script script/DeployAllContracts.s.sol:DeployAllContracts \
  --rpc-url $ETH_RPC_URL \
  --private-key $PRIVATE_KEY \
  --broadcast \
  --verify
Ensure the ETHERSCAN_API_KEY environment variable is set before using the --verify flag.

Manual Verification

If automatic verification fails or you need to verify an already deployed contract, use the forge verify-contract command.

Prerequisites

1

Set environment variables

export CHAIN_ID=1  # Target network chain ID
export ETHERSCAN_API_KEY=your_api_key_here
2

Identify contract addresses

Find the deployed contract addresses in networks.json or from your deployment output.

Verify FlashLoanRouter

The FlashLoanRouter is initialized with the CoW Settlement contract address (0x9008D19f58AAbD9eD0D60971565AA8510560ab41).
forge verify-contract \
  0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69 \
  src/FlashLoanRouter.sol:FlashLoanRouter \
  --chain-id $CHAIN_ID \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args $(cast abi-encode "constructor(address)" 0x9008D19f58AAbD9eD0D60971565AA8510560ab41)
The constructor argument is the CoW Settlement contract address, which is consistent across all supported networks.

Verify AaveBorrower

The AaveBorrower is initialized with the FlashLoanRouter address.
forge verify-contract \
  0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A \
  src/AaveBorrower.sol:AaveBorrower \
  --chain-id $CHAIN_ID \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args $(cast abi-encode "constructor(address)" 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69)

Verify ERC3156Borrower

The ERC3156Borrower is also initialized with the FlashLoanRouter address.
forge verify-contract \
  0x47d71b4B3336AB2729436186C216955F3C27cD04 \
  src/ERC3156Borrower.sol:ERC3156Borrower \
  --chain-id $CHAIN_ID \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args $(cast abi-encode "constructor(address)" 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69)

Understanding Constructor Arguments

The cast abi-encode command encodes constructor arguments in the format expected by Etherscan.

Syntax

cast abi-encode "constructor(type1,type2,...)" arg1 arg2 ...

Examples

# For contracts with single address parameter
cast abi-encode "constructor(address)" 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69

Network-Specific API Keys

Different networks require different API keys:
NetworkExplorerAPI Key Environment Variable
EthereumEtherscanETHERSCAN_API_KEY
PolygonPolygonscanPOLYGONSCAN_API_KEY
ArbitrumArbiscanARBISCAN_API_KEY
OptimismOptimistic EtherscanOPTIMISM_API_KEY
BaseBasescanBASESCAN_API_KEY
BSCBscScanBSCSCAN_API_KEY
AvalancheSnowtraceSNOWTRACE_API_KEY
GnosisGnosisscanGNOSISSCAN_API_KEY
LineaLineascanLINEASCAN_API_KEY
Most explorers use the same API key infrastructure. Register at the respective explorer website to obtain your API key.

Verification Status

After running the verification command, you’ll see one of these outputs:
Start verifying contract `0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69` deployed on mainnet
Submitting verification for [src/FlashLoanRouter.sol:FlashLoanRouter] "0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69".
Submitted contract for verification:
        Response: `OK`
        GUID: `abc123...`
        URL: https://etherscan.io/address/0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69
Contract verification status:
Response: `OK`
Details: `Pass - Verified`
The contract is successfully verified and visible on the explorer.
Contract source code already verified
The contract was previously verified. No action needed.
Error: Verification failed
Response: `NOTOK`
Details: `Error message here`
Common causes:
  • Incorrect constructor arguments
  • Wrong compiler version or settings
  • Invalid API key
  • Network issues
See troubleshooting section below.

Troubleshooting

Ensure you’re using the correct addresses for constructor arguments:
  • FlashLoanRouter: Uses CoW Settlement address 0x9008D19f58AAbD9eD0D60971565AA8510560ab41
  • Borrower contracts: Use FlashLoanRouter address 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69
Verify addresses in networks.json for the specific network.
The contracts are compiled with specific settings from foundry.toml:
solc = "0.8.28"
evm_version = "cancun"
optimizer = true
optimizer_runs = 1000000
Forge automatically uses these settings during verification.
Block explorer APIs have rate limits. If you encounter rate limiting:
  1. Wait a few minutes before retrying
  2. Verify contracts sequentially, not in parallel
  3. Check your API key tier for rate limit details
Verify your API key is:
  • Correctly set in environment variables
  • Valid and not expired
  • For the correct network (e.g., mainnet vs testnet)
  • Has verification permissions enabled

Verify Multiple Contracts

To verify all three contracts sequentially:
#!/bin/bash

source .env

echo "Verifying FlashLoanRouter..."
forge verify-contract \
  0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69 \
  src/FlashLoanRouter.sol:FlashLoanRouter \
  --chain-id $CHAIN_ID \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args $(cast abi-encode "constructor(address)" 0x9008D19f58AAbD9eD0D60971565AA8510560ab41)

echo "Verifying AaveBorrower..."
forge verify-contract \
  0x7d9C4DeE56933151Bc5C909cfe09DEf0d315CB4A \
  src/AaveBorrower.sol:AaveBorrower \
  --chain-id $CHAIN_ID \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args $(cast abi-encode "constructor(address)" 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69)

echo "Verifying ERC3156Borrower..."
forge verify-contract \
  0x47d71b4B3336AB2729436186C216955F3C27cD04 \
  src/ERC3156Borrower.sol:ERC3156Borrower \
  --chain-id $CHAIN_ID \
  --etherscan-api-key $ETHERSCAN_API_KEY \
  --constructor-args $(cast abi-encode "constructor(address)" 0x9da8B48441583a2b93e2eF8213aAD0EC0b392C69)

echo "Verification complete!"
Make the script executable with chmod +x verify-all.sh before running.

Next Steps

Last modified on March 4, 2026