Skip to main content
Contract verification publishes your source code on block explorers, allowing anyone to verify that the deployed bytecode matches the source code.

Why Verify Contracts?

Transparency

  • Users can read and audit the contract code
  • Builds trust in the protocol
  • Enables community security review

Functionality

  • Block explorers can decode function calls
  • Events display with readable parameter names
  • Users can interact with contracts directly via UI

Compliance

  • Required for many DEX listings
  • Necessary for security audits
  • Standard practice for DeFi protocols

Automated Verification

The zkp2p-contracts repository includes automated verification scripts.

Base Mainnet

This command:
  1. Reads all deployments from deployments/base/
  2. Verifies each contract on Basescan
  3. Uses a 600ms delay between verifications (rate limiting)
  4. Skips already verified contracts
  5. Reports verification status

Base Sepolia Testnet

Uses a 5-second delay between verifications.

Base Staging

Verifies staging deployments on Base mainnet Basescan.

Manual Verification

Using Hardhat Verify Plugin

Single Contract

Example: Verify Escrow

Constructor Arguments from Deployment

Extract constructor args from deployment file:
Output:

Using Basescan Web Interface

1. Navigate to Contract

Go to your contract on Basescan:

2. Click “Verify and Publish”

On the contract page, select the “Contract” tab, then “Verify and Publish”.

3. Fill Verification Form

Compiler Type: Solidity (Single file) or Solidity (Standard-JSON-Input) Compiler Version: v0.8.18+commit.87f61d96 Open Source License Type: MIT Optimization: Enabled Optimization Runs: 200 Via IR: Yes These values match hardhat.config.ts:

4. Upload Contract Code

For Standard JSON Input:
Or manually combine:
  • Main contract source
  • All imported dependencies
  • OpenZeppelin contracts
  • Interfaces

5. Submit for Verification

Basescan will:
  • Compile your source code
  • Compare bytecode to deployed contract
  • Display verification result

Verification Script Details

The automated verification task is defined in tasks/etherscanVerifyWithDelay.ts:

How It Works

  1. Load Deployments: Reads all .json files from deployments/<network>/
  2. Iterate Contracts: Processes each contract sequentially
  3. Verify: Calls Hardhat verify plugin with saved constructor args
  4. Handle Errors: Skips already-verified contracts, logs failures
  5. Rate Limiting: Waits specified delay between requests
  6. Summary: Reports verification statistics

Configuration

API Keys

Set your Basescan API key in .env:
Get API keys:

Hardhat Config

Configure verification in hardhat.config.ts:

Verification Status

Check if a contract is verified:

Via Block Explorer

Visit the contract page. Verified contracts show:
  • Green checkmark next to contract address
  • “Contract Source Code Verified” badge
  • Readable source code in “Contract” tab

Via API

Response includes:

Troubleshooting

”Already Verified” Error

Cause: Contract was previously verified Solution: No action needed. Contract is verified. Verify: Check block explorer for green checkmark

”Invalid API Key” Error

Cause: Missing or incorrect Basescan API key Solution:
  1. Get API key from basescan.org/apis
  2. Add to .env: BASESCAN_API_KEY=your_key_here
  3. Restart verification

”Bytecode Does Not Match” Error

Cause: Deployed bytecode differs from compiled source Possible Reasons:
  • Wrong compiler version
  • Different optimization settings
  • Wrong via IR setting
  • Modified source code after deployment
  • Incorrect constructor arguments
Solution:
  1. Check compiler settings match hardhat.config.ts
  2. Verify constructor arguments from deployment JSON
  3. Ensure source code matches deployed version
  4. Try compiling locally and comparing bytecode:

“Max Rate Limit Reached” Error

Cause: Too many verification requests in short time Solution: Increase delay between verifications:
Or wait 5-10 minutes and retry.

”Contract Size Exceeds Limit” Error

Cause: Contract bytecode larger than 24KB Solution:
  • Refactor contract into smaller modules
  • Use libraries for common functionality
  • Enable optimizer with higher runs
  • Remove unnecessary code

”Failed to Fetch Constructor Arguments” Error

Cause: Can’t automatically detect constructor args from blockchain Solution: Manually specify arguments:

Verification Checklist

After verification, confirm:
  • Contract shows as verified on Basescan
  • Source code is readable on “Contract” tab
  • Constructor arguments are correct
  • Read/Write functions work on block explorer UI
  • Contract ABI matches deployment JSON
  • All dependencies are verified (registries, etc.)
  • Contract name matches source file

Best Practices

1. Verify Immediately After Deployment

Run verification right after deployment:

2. Save Deployment Artifacts

Commit deployments/ directory to version control:
This preserves:
  • Contract addresses
  • Constructor arguments
  • Deployment transaction hashes
  • ABIs

3. Document Verification

Record verification details:

4. Test on Testnet First

Practice verification on Base Sepolia:
Confirm the process works before mainnet deployment.

5. Verify Dependencies

Ensure all registry contracts are verified:
  • PaymentVerifierRegistry
  • NullifierRegistry
  • EscrowRegistry
  • RelayerRegistry
  • PostIntentHookRegistry

Reading Verified Contracts

Once verified, anyone can:

View Source Code

Interact with Contract

Connect wallet and call functions directly.

Read Contract State

Query view functions without connecting wallet.

View Events

See decoded event logs with parameter names.

Next Steps

After verifying contracts:
  1. Configure payment methods
  2. Set up relayers
  3. Test core functionality
  4. Monitor contract events
Verification is a one-time process per deployment. Once verified, the contract remains verified permanently on the block explorer.
Always verify the contract address matches your deployment before interacting. Scammers may deploy fake contracts with similar names.