Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions FIX_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Fix for Issue #7: Gnosisscan Verification Bug

## Problem
The L2 bridge contracts verification on Gnosisscan was failing due to `QuorumBitmapHistoryLib` being an external library that requires special handling during verification.

## Root Causes
1. QuorumBitmapHistoryLib is deployed as an external library (not inlined)
2. Forge's automatic verification doesn't handle library linking properly for Gnosisscan
3. Mixing external libraries with Optimism's internal RLP libraries causes verification conflicts

## Solution Implemented

### 1. New Deployment Script with Library Support
Created `DeployL2WithVerification.s.sol` that:
- Explicitly deploys QuorumBitmapHistoryLib as a separate contract
- Saves the library address for use in verification
- Maintains compatibility with existing deployment flow

### 2. Enhanced Deployment Shell Script
Created `deploy-bridge-with-verification.sh` that:
- Deploys the library separately
- Verifies each contract with proper library linking
- Handles verification failures gracefully
- Provides clear instructions for manual verification if needed

### 3. Updated Main Deployment Script
Modified `deploy-bridge.sh` to:
- Deploy contracts first, then verify separately
- Verify SignatureConsumer (which doesn't need library linking)
- Provide clear instructions for contracts that need manual verification
- Handle missing API keys gracefully

### 4. Helper Scripts and Documentation
- `find-library-address.sh`: Helps locate the deployed library address
- `VerifyL2Contracts.s.sol`: Provides verification instructions
- `VERIFICATION_GUIDE.md`: Comprehensive guide for manual verification

## Files Changed
1. `/e2e/docker/scripts/deploy-bridge.sh` - Updated with better verification handling
2. `/e2e/docker/scripts/run-testnet.sh` - Updated to use new script when available
3. `/contracts/script/e2e/DeployL2WithVerification.s.sol` - New deployment script
4. `/e2e/docker/scripts/deploy-bridge-with-verification.sh` - New verification script
5. `/contracts/script/e2e/VerifyL2Contracts.s.sol` - Verification helper
6. `/e2e/scripts/find-library-address.sh` - Library address finder
7. `/e2e/VERIFICATION_GUIDE.md` - Comprehensive verification guide
8. `/FIX_SUMMARY.md` - This summary

## How to Use

### Option 1: Automatic Verification (Recommended)
```bash
# Set environment variables including L2_ETHERSCAN_API_KEY
export L2_ETHERSCAN_API_KEY="your_api_key"

# Run deployment - will use improved script automatically
cd e2e/docker/scripts
./run-testnet.sh
```

### Option 2: Manual Verification
Follow the instructions in `/e2e/VERIFICATION_GUIDE.md` for step-by-step manual verification.

### Option 3: Deploy with Explicit Library
Use the `DeployL2WithVerification` script:
```bash
forge script DeployL2WithVerification --broadcast --rpc-url $L2_RPC_URL
```

## Testing
1. Submodules have been initialized to ensure all dependencies are available
2. Contracts compile successfully with `forge build`
3. Library bytecode is deployable (verified with `forge inspect`)

## Notes
- The fix maintains backward compatibility
- No changes to contract logic, only deployment and verification processes
- The solution provides multiple approaches to handle different scenarios
- Clear documentation for manual intervention when automatic verification fails

## Future Improvements
Consider:
1. Automating library address extraction from transaction receipts
2. Creating a GitHub Action for automated verification
3. Contributing upstream to Foundry for better library verification support
58 changes: 58 additions & 0 deletions contracts/script/e2e/DeployL2WithVerification.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.12;

import {Script, console} from "forge-std/Script.sol";
import {RegistryCoordinatorMimic} from "../../src/RegistryCoordinatorMimic.sol";
import {SP1Helios} from "@sp1-helios/SP1Helios.sol";
import {BLSSignatureChecker} from "@eigenlayer-middleware/BLSSignatureChecker.sol";
import {ISlashingRegistryCoordinator} from "@eigenlayer-middleware/interfaces/ISlashingRegistryCoordinator.sol";
import {QuorumBitmapHistoryLib} from "@eigenlayer-middleware/libraries/QuorumBitmapHistoryLib.sol";
import {SP1HeliosMock} from "./contracts/SP1HeliosMock.sol";
import {SignatureConsumer} from "./contracts/SignatureConsumer.sol";

contract DeployL2WithVerification is Script {
function setUp() public {}

function run() public {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
address middlewareShim = vm.envAddress("MIDDLEWARE_SHIM_ADDRESS");
address sp1heliosAddress = vm.envAddress("SP1HELIOS_ADDRESS");
bool isSp1HeliosMock = vm.envBool("IS_SP1HELIOS_MOCK");
string memory outPath = vm.envString("L2_OUT_PATH");

vm.startBroadcast(deployerPrivateKey);

// Deploy QuorumBitmapHistoryLib as a separate library contract
console.log("Deploying QuorumBitmapHistoryLib...");
address quorumBitmapHistoryLib = address(new QuorumBitmapHistoryLib());
console.log("QuorumBitmapHistoryLib deployed at:", quorumBitmapHistoryLib);

if (isSp1HeliosMock) {
console.log("SP1Helios is mocked, deploying mock...");
SP1HeliosMock sp1heliosMock = new SP1HeliosMock();
sp1heliosAddress = address(sp1heliosMock);
console.log("SP1HeliosMock deployed at:", sp1heliosAddress);
}

RegistryCoordinatorMimic registryCoordinatorMimic =
new RegistryCoordinatorMimic(SP1Helios(sp1heliosAddress), address(middlewareShim));
console.log("RegistryCoordinatorMimic deployed at:", address(registryCoordinatorMimic));

BLSSignatureChecker blsSignatureChecker =
new BLSSignatureChecker(ISlashingRegistryCoordinator(address(registryCoordinatorMimic)));
console.log("BLSSignatureChecker deployed at:", address(blsSignatureChecker));

SignatureConsumer signatureConsumer = new SignatureConsumer(address(blsSignatureChecker));
console.log("SignatureConsumer deployed at:", address(signatureConsumer));

// Include the library address in the output for verification
string memory json = vm.serializeAddress("object key", "quorumBitmapHistoryLib", quorumBitmapHistoryLib);
json = vm.serializeAddress("object key", "registryCoordinatorMimic", address(registryCoordinatorMimic));
json = vm.serializeAddress("object key", "blsSignatureChecker", address(blsSignatureChecker));
json = vm.serializeAddress("object key", "signatureConsumer", address(signatureConsumer));
vm.writeFile(outPath, json);
console.log("Deployment info written to", outPath);

vm.stopBroadcast();
}
}
47 changes: 47 additions & 0 deletions contracts/script/e2e/VerifyL2Contracts.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.12;

import {Script, console} from "forge-std/Script.sol";

contract VerifyL2Contracts is Script {
function run() public view {
string memory l2OutPath = vm.envString("L2_OUT_PATH");
string memory l2RpcUrl = vm.envString("L2_RPC_URL");
string memory l2EtherscanApiKey = vm.envString("L2_ETHERSCAN_API_KEY");

// Read the deployment addresses from the output file
string memory deploymentData = vm.readFile(l2OutPath);

console.log("=====================================");
console.log("L2 Contract Verification Instructions");
console.log("=====================================");
console.log("");
console.log("The QuorumBitmapHistoryLib is an external library that needs special handling.");
console.log("");
console.log("To verify the contracts on Gnosisscan, run the following commands:");
console.log("");

// Parse JSON to get addresses (this is pseudo-code, actual implementation would need proper JSON parsing)
console.log("1. First, verify the QuorumBitmapHistoryLib if deployed separately:");
console.log(" forge verify-contract <LIBRARY_ADDRESS> QuorumBitmapHistoryLib \\");
console.log(" --rpc-url", l2RpcUrl, "\\");
console.log(" --etherscan-api-key", l2EtherscanApiKey, "\\");
console.log(" --compiler-version v0.8.27+commit.40a35a09");
console.log("");

console.log("2. Then verify the main contracts with library linking:");
console.log(" forge verify-contract <CONTRACT_ADDRESS> <CONTRACT_NAME> \\");
console.log(" --rpc-url", l2RpcUrl, "\\");
console.log(" --etherscan-api-key", l2EtherscanApiKey, "\\");
console.log(" --libraries QuorumBitmapHistoryLib:<LIBRARY_ADDRESS> \\");
console.log(" --constructor-args <ENCODED_ARGS>");
console.log("");

console.log("Note: Replace placeholders with actual addresses from", l2OutPath);
console.log("");
console.log("Alternative: Use forge's built-in verification during deployment:");
console.log(" forge script DeployL2 --broadcast --verify \\");
console.log(" --rpc-url", l2RpcUrl, "\\");
console.log(" --etherscan-api-key", l2EtherscanApiKey);
}
}
138 changes: 138 additions & 0 deletions e2e/VERIFICATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Gnosisscan Verification Guide

## Issue Description

The L2 bridge contracts verification on Gnosisscan does not work fully due to the use of `QuorumBitmapHistoryLib`, which is an external library in the EigenLayer middleware. This causes issues with automatic verification through forge scripts.

## Root Causes

1. **External Library Dependency**: `QuorumBitmapHistoryLib` is deployed as an external library, not inlined during compilation
2. **Library Linking Requirements**: Verification requires explicit library linking with the `--libraries` flag
3. **Mixed Library Types**: Potential conflicts between external libraries (QuorumBitmapHistoryLib) and internal libraries (Optimism's RLP libraries) during verification

## Affected Contracts

- `RegistryCoordinatorMimic` - Uses QuorumBitmapHistoryLib
- `BLSSignatureChecker` - Uses QuorumBitmapHistoryLib
- `SignatureConsumer` - No library issues (can be verified normally)

## Solutions

### Solution 1: Deploy Library Separately (Recommended)

Use the new `DeployL2WithVerification` script that deploys the library as a separate contract:

```bash
# Set environment variables
export L2_RPC_URL="<your_gnosis_rpc>"
export L2_ETHERSCAN_API_KEY="<your_gnosisscan_api_key>"
export PRIVATE_KEY="<deployer_private_key>"
export MIDDLEWARE_SHIM_ADDRESS="<from_l1_deployment>"
export SP1HELIOS_ADDRESS="<sp1_helios_address>"
export IS_SP1HELIOS_MOCK=false
export L2_OUT_PATH="./artifacts/l2-deploy.json"

# Run the deployment with verification script
forge script DeployL2WithVerification --broadcast --rpc-url $L2_RPC_URL

# The script will output the library address, use it for verification
```

### Solution 2: Manual Verification Steps

If automatic verification fails:

1. **Deploy contracts normally**:
```bash
forge script DeployL2 --broadcast --rpc-url $L2_RPC_URL
```

2. **Extract the library address from deployment logs**:
Look for `QuorumBitmapHistoryLib` deployment in the broadcast files or transaction logs

3. **Verify each contract manually**:

```bash
# Get addresses from l2-deploy.json
REGISTRY_COORDINATOR=$(cat artifacts/l2-deploy.json | jq -r '.registryCoordinatorMimic')
BLS_CHECKER=$(cat artifacts/l2-deploy.json | jq -r '.blsSignatureChecker')
SIGNATURE_CONSUMER=$(cat artifacts/l2-deploy.json | jq -r '.signatureConsumer')
LIBRARY_ADDRESS="<extracted_library_address>"

# Verify SignatureConsumer (no library needed)
forge verify-contract $SIGNATURE_CONSUMER \
SignatureConsumer \
--rpc-url $L2_RPC_URL \
--etherscan-api-key $L2_ETHERSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(address)" $BLS_CHECKER)

# Verify RegistryCoordinatorMimic with library
forge verify-contract $REGISTRY_COORDINATOR \
RegistryCoordinatorMimic \
--rpc-url $L2_RPC_URL \
--etherscan-api-key $L2_ETHERSCAN_API_KEY \
--libraries QuorumBitmapHistoryLib:$LIBRARY_ADDRESS \
--constructor-args $(cast abi-encode "constructor(address,address)" $SP1HELIOS_ADDRESS $MIDDLEWARE_SHIM_ADDRESS)

# Verify BLSSignatureChecker with library
forge verify-contract $BLS_CHECKER \
BLSSignatureChecker \
--rpc-url $L2_RPC_URL \
--etherscan-api-key $L2_ETHERSCAN_API_KEY \
--libraries QuorumBitmapHistoryLib:$LIBRARY_ADDRESS \
--constructor-args $(cast abi-encode "constructor(address)" $REGISTRY_COORDINATOR)
```

### Solution 3: Gnosisscan Web Interface

If command-line verification fails:

1. Go to Gnosisscan.io
2. Navigate to each contract address
3. Click "Verify and Publish"
4. Select compiler version matching foundry.toml
5. For contracts using QuorumBitmapHistoryLib:
- Enable "Optimization"
- Add library addresses in the "Library" section
- Paste the flattened source code

## Finding the Library Address

The QuorumBitmapHistoryLib address can be found in:

1. **Broadcast files**: Check `broadcast/DeployL2.s.sol/<chain_id>/run-latest.json`
2. **Transaction logs**: Look for CREATE2 operations in the deployment transaction
3. **Etherscan/Gnosisscan**: Check internal transactions of the deployment

## Compiler Settings

Ensure these settings match when verifying:
- Solidity version: Check each contract's pragma
- Optimizer: Enabled with 200 runs (default Foundry setting)
- EVM version: Paris (or as specified in foundry.toml)

## Known Issues

1. **API Rate Limiting**: Gnosisscan may throttle verification requests. Wait and retry if you get rate limit errors.
2. **Compiler Version Mismatch**: Different contracts may use different Solidity versions. Check the pragma in each file.
3. **Library Already Deployed**: If the library was already deployed in a previous transaction, use that address instead of deploying again.

## Testing Verification Locally

Before deploying to mainnet/testnet:

```bash
# Compile and check for library usage
forge build --force
forge inspect QuorumBitmapHistoryLib bytecode
forge inspect RegistryCoordinatorMimic bytecode | grep -c "__" # Check for library placeholders
```

## Alternative: Modify Contracts (Not Recommended)

As a last resort, you could modify the contracts to not use external libraries, but this would require:
1. Inlining the QuorumBitmapHistoryLib functions
2. Extensive testing to ensure functionality remains the same
3. Potential gas cost increases

This approach is not recommended as it changes the audited code.
Loading