This guide explains how to verify all EthAura contracts on Etherscan after deployment.
With the ERC-1967 proxy pattern, you need to verify:
- P256AccountFactory - The factory contract
- P256Account Implementation - The shared implementation contract
- Proxy Accounts (Optional) - Individual user accounts (auto-detected by Etherscan)
- Deployed contracts on the target network
- Factory address from deployment
- Etherscan API key - Get from etherscan.io/myapikey
- Foundry installed and configured
# Set environment variables
export FACTORY_ADDRESS=0x... # Your deployed factory address
export ETHERSCAN_API_KEY=your_api_key
# Run verification script
./scripts/verify-contracts.sh sepoliaThe script automatically:
- ✅ Fetches implementation address from factory
- ✅ Verifies factory contract
- ✅ Verifies implementation contract
- ✅ Provides Etherscan links
- ✅ Handles rate limiting
- ✅ Shows verification status
sepolia- Sepolia testnetmainnet- Ethereum mainnet
=== EthAura Contract Verification ===
Network: sepolia (Chain ID: 11155111)
Factory Address: 0x1234...
Implementation Address: 0x5678...
=== Verifying P256AccountFactory ===
✓ P256AccountFactory verified successfully!
=== Verifying P256Account Implementation ===
✓ P256Account Implementation verified successfully!
=== Verification Summary ===
✓ Factory verified
✓ Implementation verified
=== Etherscan Links ===
Factory: https://sepolia.etherscan.io/address/0x1234...#code
Implementation: https://sepolia.etherscan.io/address/0x5678...#code
All contracts verified successfully! ✓
export FACTORY_ADDRESS=0x... # Your factory address
# Get implementation address
cast call $FACTORY_ADDRESS "IMPLEMENTATION()(address)" --rpc-url sepoliaforge verify-contract \
--chain-id 11155111 \
--num-of-optimizations 200 \
--watch \
--constructor-args $(cast abi-encode "constructor(address)" 0x0000000071727De22E5E9d8BAf0edAc6f37da032) \
--etherscan-api-key $ETHERSCAN_API_KEY \
--compiler-version v0.8.23 \
$FACTORY_ADDRESS \
src/P256AccountFactory.sol:P256AccountFactoryforge verify-contract \
--chain-id 11155111 \
--num-of-optimizations 200 \
--watch \
--constructor-args $(cast abi-encode "constructor(address)" 0x0000000071727De22E5E9d8BAf0edAc6f37da032) \
--etherscan-api-key $ETHERSCAN_API_KEY \
--compiler-version v0.8.23 \
$IMPLEMENTATION_ADDRESS \
src/P256Account.sol:P256Account# Set factory address
export FACTORY_ADDRESS=0x...
# Run verification script (shows commands)
forge script script/Verify.s.sol --rpc-url sepoliaThis will print all verification commands with correct parameters.
Good news: ERC-1967 proxies are automatically detected by Etherscan!
Once the implementation is verified:
- Navigate to any proxy account address on Etherscan
- Etherscan will automatically show:
- ✅ "Read as Proxy" tab
- ✅ "Write as Proxy" tab
- ✅ Link to implementation contract
- ✅ All implementation functions
No manual verification needed! 🎉
If Etherscan doesn't auto-detect the proxy:
forge verify-contract \
--chain-id 11155111 \
--num-of-optimizations 200 \
--watch \
--constructor-args $(cast abi-encode "constructor(address,bytes)" $IMPLEMENTATION_ADDRESS 0x) \
--etherscan-api-key $ETHERSCAN_API_KEY \
--compiler-version v0.8.23 \
$PROXY_ADDRESS \
lib/openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Proxy.sol:ERC1967ProxyAfter verification, check on Etherscan:
- Factory contract shows green checkmark ✓
- Implementation contract shows green checkmark ✓
- Factory "Read Contract" tab works
- Can call
IMPLEMENTATION()to see implementation address - Proxy accounts show "Read as Proxy" tab
- Proxy points to correct implementation address
- All contract functions are visible and documented
Problem: Error: Verification failed
Solutions:
- Check compiler version matches:
v0.8.23 - Check optimization settings:
200 runs - Verify constructor args are correct
- Check
ETHERSCAN_API_KEYis set and valid - Wait a few minutes and try again (rate limiting)
Problem: Error: Constructor arguments mismatch
Solution:
# Verify constructor args encoding
cast abi-encode "constructor(address)" 0x0000000071727De22E5E9d8BAf0edAc6f37da032Should output the correct encoded args.
Problem: Error: Rate limit exceeded
Solution:
- Wait 5-10 minutes between verification attempts
- Use
--watchflag to automatically retry - Upgrade Etherscan API key tier
Problem: Error: Compiler version mismatch
Solution:
# Check foundry.toml
cat foundry.toml | grep solc
# Should show: solc = "0.8.23"Problem: Etherscan doesn't show "Read as Proxy" tab
Solutions:
- Wait a few minutes (Etherscan needs time to detect)
- Verify implementation contract first
- Check proxy points to correct implementation:
cast call $PROXY_ADDRESS "implementation()(address)" --rpc-url sepolia
- Manually verify proxy (see above)
For debugging, you can export the standard JSON input:
forge verify-contract \
--show-standard-json-input \
$FACTORY_ADDRESS \
src/P256AccountFactory.sol:P256AccountFactory \
> verification-input.jsonThen verify on Etherscan UI:
- Go to contract address
- Click "Verify & Publish"
- Select "Solidity (Standard JSON Input)"
- Upload
verification-input.json
CHAIN_ID=11155111
ENTRYPOINT=0x0000000071727De22E5E9d8BAf0edAc6f37da032
EXPLORER=https://sepolia.etherscan.ioCHAIN_ID=1
ENTRYPOINT=0x0000000071727De22E5E9d8BAf0edAc6f37da032
EXPLORER=https://etherscan.ioAfter successful verification:
-
Test Read Functions
- Visit factory on Etherscan
- Go to "Read Contract" tab
- Call
IMPLEMENTATION()to verify it returns correct address
-
Test Proxy Functions
- Visit a proxy account on Etherscan
- Go to "Read as Proxy" tab
- Verify you can see all P256Account functions
-
Update Documentation
- Add verified contract addresses to README
- Update deployment documentation
- Share Etherscan links with team
-
Monitor
- Set up Etherscan alerts for contract events
- Monitor for any unusual activity
- Track gas usage
- ✅ Verification makes contract source code public
- ✅ Users can audit the code on Etherscan
- ✅ Increases trust and transparency
- ✅ Required for most integrations
⚠️ Never share private keys in verification process⚠️ Double-check addresses before verification
# Automated verification (recommended)
export FACTORY_ADDRESS=0x...
export ETHERSCAN_API_KEY=your_key
./scripts/verify-contracts.sh sepolia
# Get implementation address
cast call $FACTORY_ADDRESS "IMPLEMENTATION()(address)" --rpc-url sepolia
# Check verification status
open https://sepolia.etherscan.io/address/$FACTORY_ADDRESS#codeNeed help? Check the troubleshooting section or open an issue on GitHub.