Skip to content

Commit

Permalink
feat: support contracts verification (#57)
Browse files Browse the repository at this point in the history
  • Loading branch information
yiweichi authored Nov 4, 2024
1 parent a507de4 commit a976769
Show file tree
Hide file tree
Showing 10 changed files with 263 additions and 33 deletions.
13 changes: 13 additions & 0 deletions .github/workflows/docker-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,16 @@ jobs:
file: docker/Dockerfile.gen-configs
tags: |
${{ env.REPOSITORY }}:gen-configs-${{ github.sha }}
- name: Build verify image
id: build_verify_image
env:
REPOSITORY: scrolltech/scroll-stack-contracts
uses: docker/build-push-action@v3
with:
platforms: linux/amd64,linux/arm64
push: true
context: .
file: docker/Dockerfile.verify
tags: |
${{ env.REPOSITORY }}:verify-${{ github.sha }}
2 changes: 1 addition & 1 deletion docker/Dockerfile.deploy
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RUN curl -L https://foundry.paradigm.xyz | bash
ENV PATH="/root/.foundry/bin:${PATH}"

# Run foundryup to update Foundry
RUN foundryup -v nightly-56dbd20c7179570c53b6c17ff34daa7273a4ddae
RUN foundryup -v nightly-fdd321bac95f0935529164a88faf99d4d5cfa321

# copy dependencies
COPY ./lib /contracts/lib
Expand Down
2 changes: 1 addition & 1 deletion docker/Dockerfile.gen-configs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ RUN curl -L https://foundry.paradigm.xyz | bash
ENV PATH="/root/.foundry/bin:${PATH}"

# Run foundryup to update Foundry
RUN foundryup -v nightly-56dbd20c7179570c53b6c17ff34daa7273a4ddae
RUN foundryup -v nightly-fdd321bac95f0935529164a88faf99d4d5cfa321

# copy dependencies
COPY ./lib /contracts/lib
Expand Down
45 changes: 45 additions & 0 deletions docker/Dockerfile.verify
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Use the latest node Debian slim base image
# This makes installing yarn dep much easier
FROM node:20-bookworm-slim

# Switch to bash shell
SHELL ["/bin/bash", "-c"]

WORKDIR /root

# Install dependencies
RUN apt update
RUN apt install --yes curl bash coreutils git jq ca-certificates

# Download and run the Foundry installation script
RUN curl -L https://foundry.paradigm.xyz | bash

# Set the environment variables to ensure Foundry tools are in the PATH
ENV PATH="/root/.foundry/bin:${PATH}"

# Run foundryup to update Foundry
RUN foundryup -v nightly-fdd321bac95f0935529164a88faf99d4d5cfa321

# copy dependencies
COPY ./lib /contracts/lib
COPY ./node_modules/@openzeppelin /contracts/node_modules/@openzeppelin
COPY ./node_modules/hardhat /contracts/node_modules/hardhat

# copy configurations
COPY foundry.toml /contracts/foundry.toml
COPY remappings.txt /contracts/remappings.txt

# copy source code
COPY ./src /contracts/src
COPY ./scripts /contracts/scripts

# compile contracts
ENV FOUNDRY_EVM_VERSION="cancun"
ENV FOUNDRY_BYTECODE_HASH="none"

WORKDIR /contracts
RUN forge build

COPY ./docker/scripts/verify.sh /contracts/docker/scripts/verify.sh

ENTRYPOINT ["/bin/bash", "/contracts/docker/scripts/verify.sh"]
10 changes: 10 additions & 0 deletions docker/config-example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ L2_WHITELIST = "0x5300000000000000000000000000000000000003"
L2_WETH = "0x5300000000000000000000000000000000000004"
L2_TX_FEE_VAULT = "0x5300000000000000000000000000000000000005"

[contracts.verify]

VERIFIER_TYPE_L1 = "blockscout"
VERIFIER_TYPE_L2 = "blockscout"
EXPLORER_URI_L1 = "http://l1-explorer.scrollsdk"
EXPLORER_URI_L2 = "http://blockscout.scrollsdk"
RPC_URI_L1 = "http://l1-devnet.scrollsdk"
RPC_URI_L2 = "http://l2-rpc.scrollsdk"
EXPLORER_API_KEY_L1 = ""
EXPLORER_API_KEY_L2 = ""

[coordinator]

Expand Down
150 changes: 150 additions & 0 deletions docker/scripts/verify.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/bin/sh

# extract values from config file
config_file="./volume/config.toml"
CHAIN_ID_L1=$(grep -E "^CHAIN_ID_L1 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2-)
CHAIN_ID_L2=$(grep -E "^CHAIN_ID_L2 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2-)
RPC_URI_L1=$(grep -E "^RPC_URI_L1 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
RPC_URI_L2=$(grep -E "^RPC_URI_L2 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
VERIFIER_TYPE_L1=$(grep -E "^VERIFIER_TYPE_L1 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
VERIFIER_TYPE_L2=$(grep -E "^VERIFIER_TYPE_L2 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
EXPLORER_URI_L1=$(grep -E "^EXPLORER_URI_L1 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
EXPLORER_URI_L2=$(grep -E "^EXPLORER_URI_L2 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
EXPLORER_API_KEY_L1=$(grep -E "^EXPLORER_API_KEY_L1 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
EXPLORER_API_KEY_L2=$(grep -E "^EXPLORER_API_KEY_L2 =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2- | tr -d '"')
ALTERNATIVE_GAS_TOKEN_ENABLED=$(grep -E "^ALTERNATIVE_GAS_TOKEN_ENABLED =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2-)
TEST_ENV_MOCK_FINALIZE_ENABLED=$(grep -E "^TEST_ENV_MOCK_FINALIZE_ENABLED =" "$config_file" | sed 's/ *= */=/' | cut -d'=' -f2-)

# extract contract name and address
extract_contract_info() {
contract_name=$(cut -d "=" -f 1 <<< "$line" | tr -d '"')
contract_addr=$(cut -d "=" -f 2 <<< "$line" | tr -d '"' | tr -d ' ')
}

get_source_code_name() {
# specially handle the case where alternative gas token is enabled
if [[ "$ALTERNATIVE_GAS_TOKEN_ENABLED" == "true" && "$1" =~ ^(L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR|L2_TX_FEE_VAULT_ADDR)$ ]]; then
case "$1" in
L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR) echo L1ScrollMessengerNonETH ;;
L2_TX_FEE_VAULT_ADDR) echo L2TxFeeVaultWithGasToken ;;
*)
esac
# specially handle the case where mock finalize is enabled
elif [[ "$TEST_ENV_MOCK_FINALIZE_ENABLED" == "true" && "$1" =~ ^(L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR)$ ]]; then
case "$1" in
L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR) echo ScrollChainMockFinalize ;;
*)
esac
else
case "$1" in
L1_WETH_ADDR) echo WrappedEther ;;
L1_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR) echo EmptyContract ;;
L1_PROXY_ADMIN_ADDR) echo ProxyAdminSetOwner ;;
L1_WHITELIST_ADDR) echo Whitelist ;;
L1_SCROLL_CHAIN_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_SCROLL_MESSENGER_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_ENFORCED_TX_GATEWAY_IMPLEMENTATION_ADDR) echo EnforcedTxGateway ;;
L1_ENFORCED_TX_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_ZKEVM_VERIFIER_V2_ADDR) echo ZkEvmVerifierV2 ;;
L1_MULTIPLE_VERSION_ROLLUP_VERIFIER_ADDR ) echo MultipleVersionRollupVerifierSetOwner ;;
L1_MESSAGE_QUEUE_IMPLEMENTATION_ADDR) echo L1MessageQueueWithGasPriceOracle ;;
L1_MESSAGE_QUEUE_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_SCROLL_CHAIN_IMPLEMENTATION_ADDR) echo ScrollChain ;;
L1_GATEWAY_ROUTER_IMPLEMENTATION_ADDR) echo L1GatewayRouter ;;
L1_GATEWAY_ROUTER_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_ETH_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_WETH_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_STANDARD_ERC20_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_CUSTOM_ERC20_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_ERC721_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_ERC1155_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_MESSAGE_QUEUE_ADDR) echo L2MessageQueue ;;
L1_GAS_PRICE_ORACLE_ADDR) echo L1GasPriceOracle ;;
L1_GAS_TOKEN_GATEWAY_IMPLEMENTATION_ADDR) echo L1GasTokenGateway ;;
L1_GAS_TOKEN_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L1_WRAPPED_TOKEN_GATEWAY_ADDR) echo L1WrappedTokenGateway ;;
L2_WHITELIST_ADDR) echo Whitelist ;;
L2_WETH_ADDR) echo WrappedEther ;;
L2_TX_FEE_VAULT_ADDR) echo L2TxFeeVault ;;
L2_PROXY_ADMIN_ADDR) echo ProxyAdminSetOwner ;;
L2_PROXY_IMPLEMENTATION_PLACEHOLDER_ADDR) echo EmptyContract ;;
L2_SCROLL_MESSENGER_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_ETH_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_WETH_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_STANDARD_ERC20_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_CUSTOM_ERC20_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_ERC721_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_ERC1155_GATEWAY_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_SCROLL_STANDARD_ERC20_ADDR) echo ScrollStandardERC20 ;;
L2_SCROLL_STANDARD_ERC20_FACTORY_ADDR) echo ScrollStandardERC20FactorySetOwner ;;
L1_SCROLL_MESSENGER_IMPLEMENTATION_ADDR) echo L1ScrollMessenger ;;
L1_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR) echo L1StandardERC20Gateway ;;
L1_ETH_GATEWAY_IMPLEMENTATION_ADDR) echo L1ETHGateway ;;
L1_WETH_GATEWAY_IMPLEMENTATION_ADDR) echo L1WETHGateway ;;
L1_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR) echo L1CustomERC20Gateway ;;
L1_ERC721_GATEWAY_IMPLEMENTATION_ADDR) echo L1ERC721Gateway ;;
L1_ERC1155_GATEWAY_IMPLEMENTATION_ADDR ) echo L1ERC1155Gateway ;;
L2_SCROLL_MESSENGER_IMPLEMENTATION_ADDR) echo L2ScrollMessenger ;;
L2_GATEWAY_ROUTER_IMPLEMENTATION_ADDR) echo L2GatewayRouter ;;
L2_GATEWAY_ROUTER_PROXY_ADDR) echo TransparentUpgradeableProxy ;;
L2_STANDARD_ERC20_GATEWAY_IMPLEMENTATION_ADDR) echo L2StandardERC20Gateway ;;
L2_ETH_GATEWAY_IMPLEMENTATION_ADDR) echo L2ETHGateway ;;
L2_WETH_GATEWAY_IMPLEMENTATION_ADDR) echo L2WETHGateway ;;
L2_CUSTOM_ERC20_GATEWAY_IMPLEMENTATION_ADDR) echo L2CustomERC20Gateway ;;
L2_ERC721_GATEWAY_IMPLEMENTATION_ADDR) echo L2ERC721Gateway ;;
L2_ERC1155_GATEWAY_IMPLEMENTATION_ADDR) echo L2ERC1155Gateway ;;
*) echo "" ;; # default: return void string
esac
fi
}

# read the file line by line
while IFS= read -r line; do
extract_contract_info "$line"

# get contracts deployment layer
if [[ "$contract_name" =~ ^L1 ]]; then
layer="L1"
elif [[ "$contract_name" =~ ^L2 ]]; then
layer="L2"
# specially handle contract_name L1_GAS_PRICE_ORACLE_ADDR
if [[ "$contract_name" == "L1_GAS_PRICE_ORACLE_ADDR" ]]; then
layer="L1"
fi
else
echo "wrong contract name, not starts with L1 or L2, contract_name: $contract_name"
continue
fi

source_code_name=$(get_source_code_name $contract_name)

# skip if source_code_name or contract_addr is empty
if [[ -z $source_code_name || -z $contract_addr ]]; then
echo "empty source_code_name: $source_code_name or contract_addr: $contract_addr"
continue
fi

# verify contract
echo ""
echo "verifing contract $contract_name with address $contract_addr on $layer"
EXTRA_PARAMS=""
if [[ "$layer" == "L1" ]]; then
if [[ "$VERIFIER_TYPE_L1" == "etherscan" ]]; then
EXTRA_PARAMS="--api-key $EXPLORER_API_KEY_L1"
elif [[ "$VERIFIER_TYPE_L1" == "blockscout" ]]; then
EXTRA_PARAMS="--verifier-url ${EXPLORER_URI_L1}/api/ --verifier $VERIFIER_TYPE_L1"
elif [[ "$VERIFIER_TYPE_L1" == "sourcify" ]]; then
EXTRA_PARAMS="--api-key $EXPLORER_API_KEY_L1 --verifier-url $EXPLORER_URI_L1 --verifier $VERIFIER_TYPE_L1"
fi
forge verify-contract $contract_addr $source_code_name --rpc-url $RPC_URI_L1 --chain-id $CHAIN_ID_L1 --watch --guess-constructor-args --skip-is-verified-check $EXTRA_PARAMS
elif [[ "$layer" == "L2" ]]; then
if [[ "$VERIFIER_TYPE_L2" == "etherscan" ]]; then
EXTRA_PARAMS="--api-key $EXPLORER_API_KEY_L2"
elif [[ "$VERIFIER_TYPE_L2" == "blockscout" ]]; then
EXTRA_PARAMS="--verifier-url ${EXPLORER_URI_L2}/api/ --verifier $VERIFIER_TYPE_L2"
elif [[ "$VERIFIER_TYPE_L2" == "sourcify" ]]; then
EXTRA_PARAMS="--api-key $EXPLORER_API_KEY_L2 --verifier-url $EXPLORER_URI_L2 --verifier $VERIFIER_TYPE_L2"
fi
forge verify-contract $contract_addr $source_code_name --rpc-url $RPC_URI_L2 --chain-id $CHAIN_ID_L2 --watch --guess-constructor-args --skip-is-verified-check $EXTRA_PARAMS
fi
done < ./volume/config-contracts.toml
34 changes: 3 additions & 31 deletions scripts/deterministic/DeployScroll.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity =0.8.24;

import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";
import {ProxyAdminSetOwner} from "./contracts/ProxyAdminSetOwner.sol";
import {TransparentUpgradeableProxy, ITransparentUpgradeableProxy} from "@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";

Expand All @@ -19,7 +19,7 @@ import {L1ScrollMessenger} from "../../src/L1/L1ScrollMessenger.sol";
import {L1StandardERC20Gateway} from "../../src/L1/gateways/L1StandardERC20Gateway.sol";
import {L1WETHGateway} from "../../src/L1/gateways/L1WETHGateway.sol";
import {L2GasPriceOracle} from "../../src/L1/rollup/L2GasPriceOracle.sol";
import {MultipleVersionRollupVerifier} from "../../src/L1/rollup/MultipleVersionRollupVerifier.sol";
import {MultipleVersionRollupVerifierSetOwner} from "./contracts/MultipleVersionRollupVerifierSetOwner.sol";
import {ScrollChain} from "../../src/L1/rollup/ScrollChain.sol";
import {ZkEvmVerifierV2} from "../../src/libraries/verifier/ZkEvmVerifierV2.sol";
import {GasTokenExample} from "../../src/alternative-gas-token/GasTokenExample.sol";
Expand All @@ -42,7 +42,7 @@ import {L2TxFeeVaultWithGasToken} from "../../src/alternative-gas-token/L2TxFeeV
import {Whitelist} from "../../src/L2/predeploys/Whitelist.sol";
import {WrappedEther} from "../../src/L2/predeploys/WrappedEther.sol";
import {ScrollStandardERC20} from "../../src/libraries/token/ScrollStandardERC20.sol";
import {ScrollStandardERC20Factory} from "../../src/libraries/token/ScrollStandardERC20Factory.sol";
import {ScrollStandardERC20FactorySetOwner} from "./contracts/ScrollStandardERC20FactorySetOwner.sol";

import {ScrollChainMockFinalize} from "../../src/mocks/ScrollChainMockFinalize.sol";

Expand All @@ -53,34 +53,6 @@ import "./DeterministicDeployment.sol";
/// @dev The minimum deployer account balance.
uint256 constant MINIMUM_DEPLOYER_BALANCE = 0.1 ether;

contract ProxyAdminSetOwner is ProxyAdmin {
/// @dev allow setting the owner in the constructor, otherwise
/// DeterministicDeploymentProxy would become the owner.
constructor(address owner) {
_transferOwnership(owner);
}
}

contract MultipleVersionRollupVerifierSetOwner is MultipleVersionRollupVerifier {
/// @dev allow setting the owner in the constructor, otherwise
/// DeterministicDeploymentProxy would become the owner.
constructor(
address owner,
uint256[] memory _versions,
address[] memory _verifiers
) MultipleVersionRollupVerifier(_versions, _verifiers) {
_transferOwnership(owner);
}
}

contract ScrollStandardERC20FactorySetOwner is ScrollStandardERC20Factory {
/// @dev allow setting the owner in the constructor, otherwise
/// DeterministicDeploymentProxy would become the owner.
constructor(address owner, address _implementation) ScrollStandardERC20Factory(_implementation) {
_transferOwnership(owner);
}
}

contract DeployScroll is DeterministicDeployment {
using stdToml for string;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.24;

import {MultipleVersionRollupVerifier} from "../../../src/L1/rollup/MultipleVersionRollupVerifier.sol";

contract MultipleVersionRollupVerifierSetOwner is MultipleVersionRollupVerifier {
/// @dev allow setting the owner in the constructor, otherwise
/// DeterministicDeploymentProxy would become the owner.
constructor(
address owner,
uint256[] memory _versions,
address[] memory _verifiers
) MultipleVersionRollupVerifier(_versions, _verifiers) {
_transferOwnership(owner);
}
}
12 changes: 12 additions & 0 deletions scripts/deterministic/contracts/ProxyAdminSetOwner.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.24;

import {ProxyAdmin} from "@openzeppelin/contracts/proxy/transparent/ProxyAdmin.sol";

contract ProxyAdminSetOwner is ProxyAdmin {
/// @dev allow setting the owner in the constructor, otherwise
/// DeterministicDeploymentProxy would become the owner.
constructor(address owner) {
_transferOwnership(owner);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity =0.8.24;

import {ScrollStandardERC20Factory} from "../../../src/libraries/token/ScrollStandardERC20Factory.sol";

contract ScrollStandardERC20FactorySetOwner is ScrollStandardERC20Factory {
/// @dev allow setting the owner in the constructor, otherwise
/// DeterministicDeploymentProxy would become the owner.
constructor(address owner, address _implementation) ScrollStandardERC20Factory(_implementation) {
_transferOwnership(owner);
}
}

0 comments on commit a976769

Please sign in to comment.