diff --git a/README.md b/README.md index 3de4456..f58c312 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ To install the latest release version: forge install succinctlabs/sp1-contracts ``` -Add `@sp1-contracts/=lib/sp1-contracts/contracts/src/` in `remappings.txt.` +Add `@sp1-contracts/=lib/sp1-contracts/contracts/src/` in `remappings.txt`. ### Usage @@ -22,7 +22,8 @@ pragma solidity ^0.8.20; import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol"; contract MyContract { - address public constant SP1_VERIFIER = 0x3B6041173B80E77f038f3F2C0f9744f04837185e; + /// @dev Use the gateway address for your chain from the deployments/ folder + address public SP1_VERIFIER; bytes32 public constant PROGRAM_VKEY = ...; @@ -32,9 +33,9 @@ contract MyContract { } ``` -You can obtain the correct `SP1_VERIFIER` address for your chain by looking in the [deployments](./contracts/deployments) directory, it's recommended to use the `SP1_VERIFIER_GATEWAY` address which will automatically route proofs to the correct verifier based on their version. +You can obtain the correct `SP1_VERIFIER` address for your chain by looking in the [deployments](./contracts/deployments) directory. Use the `SP1_VERIFIER_GATEWAY` address which automatically routes proofs to the correct verifier based on their version. -You can obtain the correct `PROGRAM_VKEY` for your program calling the `setup` function for your ELF: +You can obtain the correct `PROGRAM_VKEY` for your program by calling the `setup` function for your ELF: ```rs let client = ProverClient::new(); @@ -44,49 +45,77 @@ You can obtain the correct `PROGRAM_VKEY` for your program calling the `setup` f ### Deployments -To deploy the contracts, ensure your [.env](./contracts/.env.example) file is configured with all the chains you want to deploy to. - -Then you can use the `forge script` command and specify the specific contract you want to deploy. For example, to deploy the SP1 Verifier Gateway for PLONK you can run: +To deploy contracts, configure your [.env](./contracts/.env.example) file: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/SP1VerifierGatewayPlonk.s.sol:SP1VerifierGatewayScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +cd sp1-contracts/contracts + +# Create .env with your values +PRIVATE_KEY=0x... +RPC_MAINNET=https://eth-mainnet.g.alchemy.com/v2/YOUR_KEY # Use Alchemy/Infura, not public RPCs +ETHERSCAN_API_KEY=... ``` -or to deploy the SP1 Verifier Gateway for Groth16 you can run: +> **Important**: +> - Run `source .env` before any forge commands (the scripts read env vars directly) +> - The `--rpc-url` CLI flag is ignored; scripts read `RPC_` from environment +> - Specify target chain with `CHAINS=` env var (e.g., `CHAINS=MAINNET`) + +Deploy the SP1 Verifier Gateway: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/SP1VerifierGatewayGroth16.s.sol:SP1VerifierGatewayScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +# Groth16 gateway +CHAINS=MAINNET FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/SP1VerifierGatewayGroth16.s.sol:SP1VerifierGatewayScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --broadcast + +# Plonk gateway (use different CREATE2_SALT to avoid collision) +CHAINS=MAINNET FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/SP1VerifierGatewayPlonk.s.sol:SP1VerifierGatewayScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --broadcast ``` ### Adding Verifiers -You can use the `forge script` command to specify which verifier you want to deploy and add to the gateway. For example to deploy the PLONK verifier and add it to the PLONK gateway you can run: +Deploy verifiers and optionally register them with the gateway: ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +# Deploy Groth16 verifier +CHAINS=MAINNET FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/v6.0.0-beta.1/SP1VerifierGroth16.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --broadcast + +# Deploy Plonk verifier +CHAINS=MAINNET FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/v6.0.0-beta.1/SP1VerifierPlonk.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --verify --verifier etherscan --broadcast ``` -or to deploy the Groth16 verifier and add it to the Groth16 gateway you can run: +By default, `REGISTER_ROUTE=false` so verifiers are deployed without registering routes. This is intended for multisig-owned gateways where route registration requires a separate multisig transaction. + +To deploy AND register routes in one step (only works if deployer owns the gateway): ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierGroth16.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast +REGISTER_ROUTE=true CHAINS=MAINNET FOUNDRY_PROFILE=deploy forge script ... ``` -Change `v3.0.0` to the desired version to add. +For multisig gateways, use the Safe Transaction Builder JSON generator after deploying: -### Freezing Verifiers +```bash +node script/utils/generate-safe-batch.js --chain=1 --version=v6.0.0-beta.1 +``` -> [!WARNING] -> **BE CAREFUL** When a freezing a verifier. Once it is frozen, it cannot be unfrozen, and it can no longer be routed to. +### Freezing Verifiers -To freeze a verifier on the gateway, run: +> [!WARNING] +> Once frozen, a verifier cannot be unfrozen and can no longer be routed to. ```bash -FOUNDRY_PROFILE=deploy forge script ./script/deploy/v3.0.0/SP1VerifierPlonk.s.sol:SP1VerifierScript --private-key $PRIVATE_KEY --verify --verifier etherscan --multi --broadcast --sig "freeze()" +CHAINS=MAINNET FOUNDRY_PROFILE=deploy forge script \ + ./script/deploy/v6.0.0-beta.1/SP1VerifierPlonk.s.sol:SP1VerifierScript \ + --private-key $PRIVATE_KEY --broadcast --sig "freeze()" ``` -Change `v3.0.0` to the desired version to freeze. - ## For Developers: Integrate SP1 Contracts This repository contains the EVM contracts for verifying SP1 PLONK EVM proofs. diff --git a/contracts/.env.example b/contracts/.env.example index 9982f9b..f6d8a23 100644 --- a/contracts/.env.example +++ b/contracts/.env.example @@ -10,7 +10,6 @@ CHAINS= ### RPCs for each chain ID RPC_MAINNET= RPC_SEPOLIA= -RPC_HOLESKY= RPC_ARBITRUM= RPC_ARBITRUM_SEPOLIA= RPC_BASE= @@ -19,37 +18,19 @@ RPC_OPTIMISM= RPC_OPTIMISM_SEPOLIA= RPC_SCROLL= RPC_SCROLL_SEPOLIA= +RPC_HOODI= RPC_HYPEREVM= +RPC_BSC= +RPC_MONAD= +RPC_XLAYER= +RPC_MEGA= +RPC_PLASMA= +RPC_TEMPO= -# Etherscan API keys for each chain ID -ETHERSCAN_API_KEY_MAINNET= -ETHERSCAN_API_KEY_SEPOLIA= -ETHERSCAN_API_KEY_HOLESKY= -ETHERSCAN_API_KEY_ARBITRUM= -ETHERSCAN_API_KEY_ARBITRUM_SEPOLIA= -ETHERSCAN_API_KEY_BASE= -ETHERSCAN_API_KEY_BASE_SEPOLIA= -ETHERSCAN_API_KEY_OPTIMISM= -ETHERSCAN_API_KEY_OPTIMISM_SEPOLIA= -ETHERSCAN_API_KEY_SCROLL= -ETHERSCAN_API_KEY_SCROLL_SEPOLIA= -ETHERSCAN_API_KEY_HOODI= -ETHERSCAN_API_KEY_HYPEREVM= - -# Etherscan API URLs for each chain ID -ETHERSCAN_API_URL_MAINNET=https://api.etherscan.io/api -ETHERSCAN_API_URL_HOLESKY=https://api-holesky.etherscan.io/api -ETHERSCAN_API_URL_SEPOLIA=https://api-sepolia.etherscan.io/api -ETHERSCAN_API_URL_ARBITRUM=https://api.arbiscan.io/api -ETHERSCAN_API_URL_ARBITRUM_SEPOLIA=https://api-sepolia.arbiscan.io/api -ETHERSCAN_API_URL_BASE=https://api.basescan.org/api -ETHERSCAN_API_URL_BASE_SEPOLIA=https://api-sepolia.basescan.org/api -ETHERSCAN_API_URL_OPTIMISM=https://api-optimistic.etherscan.io/api -ETHERSCAN_API_URL_OPTIMISM_SEPOLIA=https://api-sepolia-optimistic.etherscan.io/api -ETHERSCAN_API_URL_SCROLL=https://api.scrollscan.com/api -ETHERSCAN_API_URL_SCROLL_SEPOLIA=https://api-sepolia.scrollscan.com/api -ETHERSCAN_API_URL_HOODI=https://api.etherscan.io/v2/api?chainid=560048 -ETHERSCAN_API_URL_HYPEREVM=https://api.etherscan.io/v2/api?chainid=999 +# Etherscan V2 API key (single key works for 16/18 chains via etherscan.io) +ETHERSCAN_API_KEY= +# OKLink API key (for X Layer verification only, from oklink.com) +OKLINK_API_KEY= ## Contract Deployer Private Key PRIVATE_KEY= \ No newline at end of file diff --git a/contracts/.gitignore b/contracts/.gitignore index 3056dd4..c93edfa 100644 --- a/contracts/.gitignore +++ b/contracts/.gitignore @@ -9,4 +9,10 @@ broadcast/ docs/ # Dotenv file -.env \ No newline at end of file +.env + +# macOS +.DS_Store + +# Safe Transaction Builder generated files (keep committed for handoff) +# Regenerate with: node script/utils/generate-safe-batch.js \ No newline at end of file diff --git a/contracts/check-routes.sh b/contracts/check-routes.sh new file mode 100755 index 0000000..e3fd6e4 --- /dev/null +++ b/contracts/check-routes.sh @@ -0,0 +1,190 @@ +#!/usr/bin/env bash +# Check v6.0.0 route registration status on all 18 chains. +# Usage: ./check-routes.sh [path-to-.env] +# +# Reads gateway addresses from deployments/*.json and calls routes(bytes4) +# on each gateway to determine if the v6 verifiers are registered. + +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ENV_FILE="${1:-$SCRIPT_DIR/.env}" + +if [[ ! -f "$ENV_FILE" ]]; then + echo "Error: .env file not found at $ENV_FILE" + echo "Usage: $0 [path-to-.env]" + exit 1 +fi + +# Source env for RPC URLs +set -a +source "$ENV_FILE" +set +a + +# V6 verifier selectors (first 4 bytes of VERIFIER_HASH) +V6_GROTH16_SEL="0x0e78f4db" +V6_PLONK_SEL="0xbb1a6f29" + +# Expected v6 verifier addresses (CREATE2-deterministic, same on all chains) +V6_GROTH16="0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508" +V6_PLONK="0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" + +# Chain definitions: CHAIN_ID:NAME:RPC_VAR +CHAINS=( + # Testnets (run these first) + "11155111:Sepolia:RPC_SEPOLIA" + "421614:Arbitrum Sepolia:RPC_ARBITRUM_SEPOLIA" + "84532:Base Sepolia:RPC_BASE_SEPOLIA" + "11155420:OP Sepolia:RPC_OPTIMISM_SEPOLIA" + "534351:Scroll Sepolia:RPC_SCROLL_SEPOLIA" + "560048:Hoodi:RPC_HOODI" + # Mainnets + "1:Ethereum:RPC_MAINNET" + "10:Optimism:RPC_OPTIMISM" + "42161:Arbitrum:RPC_ARBITRUM" + "8453:Base:RPC_BASE" + "534352:Scroll:RPC_SCROLL" + "56:BSC:RPC_BSC" + "196:X Layer:RPC_XLAYER" + "143:Monad:RPC_MONAD" + "4326:MegaETH:RPC_MEGA" + "9745:Plasma:RPC_PLASMA" + "999:HyperEVM:RPC_HYPEREVM" + "4217:Tempo:RPC_TEMPO" +) + +# Colors +GREEN='\033[0;32m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +BOLD='\033[1m' +NC='\033[0m' + +DEPLOY_DIR="$SCRIPT_DIR/deployments" +TIMEOUT=15 + +# Counters +total=0 +registered=0 +not_registered=0 +errors=0 + +printf "\n${BOLD}SP1 v6.0.0 Route Registration Status${NC}\n" +printf "Groth16 verifier: ${CYAN}%s${NC}\n" "$V6_GROTH16" +printf "Plonk verifier: ${CYAN}%s${NC}\n" "$V6_PLONK" +printf "Groth16 selector: ${CYAN}%s${NC} Plonk selector: ${CYAN}%s${NC}\n\n" "$V6_GROTH16_SEL" "$V6_PLONK_SEL" + +printf "${BOLD}%-20s %-10s %-15s %-15s${NC}\n" "CHAIN" "ID" "GROTH16" "PLONK" +printf "%-20s %-10s %-15s %-15s\n" "--------------------" "----------" "---------------" "---------------" + +check_route() { + local gateway="$1" + local selector="$2" + local rpc="$3" + local expected_verifier="$4" + + local result + result=$(cast call "$gateway" "routes(bytes4)(address,bool)" "$selector" --rpc-url "$rpc" 2>&1) || { + echo "ERROR" + return + } + + # cast returns two lines: address and bool + local addr + local frozen + addr=$(echo "$result" | head -1 | tr -d '[:space:]') + frozen=$(echo "$result" | tail -1 | tr -d '[:space:]') + + # Zero address means not registered + if [[ "$addr" == "0x0000000000000000000000000000000000000000" ]]; then + echo "NOT_REGISTERED" + return + fi + + # Check if correct verifier is registered + local addr_lower + local expected_lower + addr_lower=$(echo "$addr" | tr '[:upper:]' '[:lower:]') + expected_lower=$(echo "$expected_verifier" | tr '[:upper:]' '[:lower:]') + + if [[ "$addr_lower" == "$expected_lower" ]]; then + if [[ "$frozen" == "true" ]]; then + echo "FROZEN" + else + echo "REGISTERED" + fi + else + echo "WRONG:${addr}" + fi +} + +for chain_def in "${CHAINS[@]}"; do + IFS=':' read -r chain_id chain_name rpc_var <<< "$chain_def" + + rpc_url="${!rpc_var:-}" + if [[ -z "$rpc_url" ]]; then + printf "${YELLOW}%-20s %-10s %-15s %-15s${NC}\n" "$chain_name" "$chain_id" "NO RPC" "NO RPC" + errors=$((errors + 2)) + total=$((total + 2)) + continue + fi + + deploy_file="$DEPLOY_DIR/${chain_id}.json" + if [[ ! -f "$deploy_file" ]]; then + printf "${YELLOW}%-20s %-10s %-15s %-15s${NC}\n" "$chain_name" "$chain_id" "NO DEPLOY" "NO DEPLOY" + errors=$((errors + 2)) + total=$((total + 2)) + continue + fi + + # Read gateway addresses from deployment JSON + gw_groth16=$(python3 -c "import json; print(json.load(open('$deploy_file'))['SP1_VERIFIER_GATEWAY_GROTH16'])") + gw_plonk=$(python3 -c "import json; print(json.load(open('$deploy_file'))['SP1_VERIFIER_GATEWAY_PLONK'])") + + # Check Groth16 route + g16_status=$(check_route "$gw_groth16" "$V6_GROTH16_SEL" "$rpc_url" "$V6_GROTH16") + # Check Plonk route + plonk_status=$(check_route "$gw_plonk" "$V6_PLONK_SEL" "$rpc_url" "$V6_PLONK") + + # Format output + format_status() { + local status="$1" + case "$status" in + REGISTERED) printf "${GREEN}%-15s${NC}" "REGISTERED" ;; + NOT_REGISTERED) printf "${RED}%-15s${NC}" "NOT REGISTERED" ;; + FROZEN) printf "${YELLOW}%-15s${NC}" "FROZEN" ;; + WRONG:*) printf "${RED}%-15s${NC}" "WRONG ADDR" ;; + ERROR) printf "${YELLOW}%-15s${NC}" "ERROR" ;; + esac + } + + printf "%-20s %-10s " "$chain_name" "$chain_id" + format_status "$g16_status" + printf " " + format_status "$plonk_status" + printf "\n" + + # Count + total=$((total + 2)) + for s in "$g16_status" "$plonk_status"; do + case "$s" in + REGISTERED) registered=$((registered + 1)) ;; + NOT_REGISTERED) not_registered=$((not_registered + 1)) ;; + *) errors=$((errors + 1)) ;; + esac + done +done + +printf "\n${BOLD}Summary${NC}\n" +printf "Total routes checked: %d\n" "$total" +printf "${GREEN}Registered: %d${NC}\n" "$registered" +printf "${RED}Not registered: %d${NC}\n" "$not_registered" +if [[ $errors -gt 0 ]]; then + printf "${YELLOW}Errors/Other: %d${NC}\n" "$errors" +fi + +if [[ $not_registered -eq 0 && $errors -eq 0 ]]; then + printf "\n${GREEN}${BOLD}All v6.0.0 routes are registered.${NC}\n" +elif [[ $registered -eq 0 ]]; then + printf "\n${RED}${BOLD}No v6.0.0 routes are registered yet (clean slate).${NC}\n" +fi diff --git a/contracts/deployments/1.json b/contracts/deployments/1.json index 8fc18ec..f0deac3 100644 --- a/contracts/deployments/1.json +++ b/contracts/deployments/1.json @@ -13,5 +13,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/10.json b/contracts/deployments/10.json index c657d9d..6f41fa1 100644 --- a/contracts/deployments/10.json +++ b/contracts/deployments/10.json @@ -9,5 +9,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/11155111.json b/contracts/deployments/11155111.json index f077254..d310f7d 100644 --- a/contracts/deployments/11155111.json +++ b/contracts/deployments/11155111.json @@ -22,5 +22,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/11155420.json b/contracts/deployments/11155420.json index d7b0c40..c51dacf 100644 --- a/contracts/deployments/11155420.json +++ b/contracts/deployments/11155420.json @@ -14,5 +14,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/143.json b/contracts/deployments/143.json new file mode 100644 index 0000000..a670c82 --- /dev/null +++ b/contracts/deployments/143.json @@ -0,0 +1,9 @@ +{ + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", + "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", + "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", + "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", + "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" +} \ No newline at end of file diff --git a/contracts/deployments/196.json b/contracts/deployments/196.json new file mode 100644 index 0000000..a670c82 --- /dev/null +++ b/contracts/deployments/196.json @@ -0,0 +1,9 @@ +{ + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", + "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", + "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", + "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", + "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" +} \ No newline at end of file diff --git a/contracts/deployments/42161.json b/contracts/deployments/42161.json index 8fc18ec..f0deac3 100644 --- a/contracts/deployments/42161.json +++ b/contracts/deployments/42161.json @@ -13,5 +13,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/421614.json b/contracts/deployments/421614.json index fcffb5d..68aac61 100644 --- a/contracts/deployments/421614.json +++ b/contracts/deployments/421614.json @@ -21,5 +21,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/4217.json b/contracts/deployments/4217.json new file mode 100644 index 0000000..a670c82 --- /dev/null +++ b/contracts/deployments/4217.json @@ -0,0 +1,9 @@ +{ + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", + "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", + "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", + "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", + "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" +} \ No newline at end of file diff --git a/contracts/deployments/4326.json b/contracts/deployments/4326.json new file mode 100644 index 0000000..a670c82 --- /dev/null +++ b/contracts/deployments/4326.json @@ -0,0 +1,9 @@ +{ + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", + "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", + "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", + "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", + "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" +} \ No newline at end of file diff --git a/contracts/deployments/534351.json b/contracts/deployments/534351.json index fcffb5d..68aac61 100644 --- a/contracts/deployments/534351.json +++ b/contracts/deployments/534351.json @@ -21,5 +21,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/534352.json b/contracts/deployments/534352.json index 8fc18ec..f0deac3 100644 --- a/contracts/deployments/534352.json +++ b/contracts/deployments/534352.json @@ -13,5 +13,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/56.json b/contracts/deployments/56.json index 61a0494..aa09a79 100644 --- a/contracts/deployments/56.json +++ b/contracts/deployments/56.json @@ -1,9 +1,11 @@ { - "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000010", + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", "SP1_VERIFIER_GATEWAY_GROTH16": "0x940467b232cAD6A44FF36F2FBBe98CBd6509EFf2", "SP1_VERIFIER_GATEWAY_PLONK": "0xfff6601146031815a84890aCBf0d926609a40249", "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0x43f784A74b363552c843398867735Dde025DCB45", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0x5E4badcBd7AC52FF0763dE511f227605A7C23599", "V5_0_0_SP1_VERIFIER_GROTH16": "0x4CC34b792E7F7F464dA9318887e127bb967eE569", - "V5_0_0_SP1_VERIFIER_PLONK": "0x8da95b4387da25389C32C5320e5b05E30CA16061" + "V5_0_0_SP1_VERIFIER_PLONK": "0x8da95b4387da25389C32C5320e5b05E30CA16061", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/560048.json b/contracts/deployments/560048.json index 4e5ba59..a670c82 100644 --- a/contracts/deployments/560048.json +++ b/contracts/deployments/560048.json @@ -1,6 +1,9 @@ { + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", - "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9" + "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/8453.json b/contracts/deployments/8453.json index 8fc18ec..f0deac3 100644 --- a/contracts/deployments/8453.json +++ b/contracts/deployments/8453.json @@ -13,5 +13,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/84532.json b/contracts/deployments/84532.json index fcffb5d..68aac61 100644 --- a/contracts/deployments/84532.json +++ b/contracts/deployments/84532.json @@ -21,5 +21,7 @@ "V4_0_0_RC_3_SP1_VERIFIER_GROTH16": "0xa27A057CAb1a4798c6242F6eE5b2416B7Cd45E5D", "V4_0_0_RC_3_SP1_VERIFIER_PLONK": "0xE00a3cBFC45241b33c0A44C78e26168CBc55EC63", "V5_0_0_SP1_VERIFIER_GROTH16": "0x50ACFBEdecf4cbe350E1a86fC6f03a821772f1e5", - "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459" + "V5_0_0_SP1_VERIFIER_PLONK": "0x0459d576A6223fEeA177Fb3DF53C9c77BF84C459", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/deployments/9745.json b/contracts/deployments/9745.json new file mode 100644 index 0000000..a670c82 --- /dev/null +++ b/contracts/deployments/9745.json @@ -0,0 +1,9 @@ +{ + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", + "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", + "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", + "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", + "V5_0_0_SP1_VERIFIER_PLONK": "0x4b1c210d746f117f7bCEA5DbC8eD8dcF351D65C9", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" +} \ No newline at end of file diff --git a/contracts/deployments/999.json b/contracts/deployments/999.json index b07ca53..c2b8f0c 100644 --- a/contracts/deployments/999.json +++ b/contracts/deployments/999.json @@ -1,8 +1,10 @@ { - "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000011", + "CREATE2_SALT": "0x0000000000000000000000000000000000000000000000000000000000000009", "OWNER": "0xDEd0000E32f8F40414d3ab3a830f735a3553E18e", "SP1_VERIFIER_GATEWAY_GROTH16": "0x7DA83eC4af493081500Ecd36d1a72c23F8fc2abd", "SP1_VERIFIER_GATEWAY_PLONK": "0x2a5A70409Ee9F057503a50E0F4614A6d8CcBb462", "V5_0_0_SP1_VERIFIER_GROTH16": "0x5A2823b1a5D55C5dD316F70b4cdB3B126fd561DE", - "V5_0_0_SP1_VERIFIER_PLONK": "0x13906A3dCB4A7DE9163F92C4f175d8A34EFd2990" + "V5_0_0_SP1_VERIFIER_PLONK": "0x13906A3dCB4A7DE9163F92C4f175d8A34EFd2990", + "V6_0_0_SP1_VERIFIER_GROTH16": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508", + "V6_0_0_SP1_VERIFIER_PLONK": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" } \ No newline at end of file diff --git a/contracts/foundry.toml b/contracts/foundry.toml index 347bfb3..1c1d7c9 100644 --- a/contracts/foundry.toml +++ b/contracts/foundry.toml @@ -23,7 +23,6 @@ ignore = ["lib/**", "src/v*/Groth16Verifier.sol", "src/v*/PlonkVerifier.sol", "s [rpc_endpoints] mainnet = "${RPC_MAINNET}" sepolia = "${RPC_SEPOLIA}" -holesky = "${RPC_HOLESKY}" hoodi = "${RPC_HOODI}" arbitrum = "${RPC_ARBITRUM}" arbitrum_sepolia = "${RPC_ARBITRUM_SEPOLIA}" @@ -34,18 +33,29 @@ optimism_sepolia = "${RPC_OPTIMISM_SEPOLIA}" scroll = "${RPC_SCROLL}" scroll_sepolia = "${RPC_SCROLL_SEPOLIA}" hyperevm = "${RPC_HYPEREVM}" +plasma = "${RPC_PLASMA}" +monad = "${RPC_MONAD}" +mega = "${RPC_MEGA}" +xlayer = "${RPC_XLAYER}" +bsc = "${RPC_BSC}" +tempo = "${RPC_TEMPO}" [etherscan] -mainnet = { key = "${ETHERSCAN_API_KEY_MAINNET}", url = "${ETHERSCAN_API_URL_MAINNET}" } -sepolia = { key = "${ETHERSCAN_API_KEY_SEPOLIA}", url = "${ETHERSCAN_API_URL_SEPOLIA}" } -holesky = { key = "${ETHERSCAN_API_KEY_HOLESKY}", url = "${ETHERSCAN_API_URL_HOLESKY}" } -hoodi = { key = "${ETHERSCAN_API_KEY_HOODI}", url = "${ETHERSCAN_API_URL_HOODI}" } -arbitrum = { key = "${ETHERSCAN_API_KEY_ARBITRUM}", url = "${ETHERSCAN_API_URL_ARBITRUM}" } -arbitrum_sepolia = { key = "${ETHERSCAN_API_KEY_ARBITRUM_SEPOLIA}", url = "${ETHERSCAN_API_URL_ARBITRUM_SEPOLIA}" } -base = { key = "${ETHERSCAN_API_KEY_BASE}", url = "${ETHERSCAN_API_URL_BASE}" } -base_sepolia = { key = "${ETHERSCAN_API_KEY_BASE_SEPOLIA}", url = "${ETHERSCAN_API_URL_BASE_SEPOLIA}" } -optimism = { key = "${ETHERSCAN_API_KEY_OPTIMISM}", url = "${ETHERSCAN_API_URL_OPTIMISM}" } -optimism_sepolia = { key = "${ETHERSCAN_API_KEY_OPTIMISM_SEPOLIA}", url = "${ETHERSCAN_API_URL_OPTIMISM_SEPOLIA}" } -scroll = { key = "${ETHERSCAN_API_KEY_SCROLL}", url = "${ETHERSCAN_API_URL_SCROLL}" } -scroll_sepolia = { key = "${ETHERSCAN_API_KEY_SCROLL_SEPOLIA}", url = "${ETHERSCAN_API_URL_SCROLL_SEPOLIA}" } -hyperevm = { key = "${ETHERSCAN_API_KEY_HYPEREVM}", url = "${ETHERSCAN_API_URL_HYPEREVM}" } \ No newline at end of file +mainnet = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=1" } +sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=11155111" } +hoodi = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=560048" } +arbitrum = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=42161" } +arbitrum_sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=421614" } +base = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=8453" } +base_sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=84532" } +optimism = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=10" } +optimism_sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=11155420" } +scroll = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=534352" } +scroll_sepolia = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=534351" } +hyperevm = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=999" } +bsc = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=56" } +monad = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=143" } +mega = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=4326" } +plasma = { key = "${ETHERSCAN_API_KEY}", url = "https://api.etherscan.io/v2/api?chainid=9745" } +xlayer = { key = "${OKLINK_API_KEY}", url = "https://www.oklink.com/api/v5/explorer/contract/verify-source-code-plugin/XLAYER" } +tempo = { key = "unused", url = "https://contracts.tempo.xyz/" } diff --git a/contracts/safe-batches/.gitkeep b/contracts/safe-batches/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/contracts/safe-batches/10_add-route_v6_0_0.json b/contracts/safe-batches/10_add-route_v6_0_0.json new file mode 100644 index 0000000..c818cd8 --- /dev/null +++ b/contracts/safe-batches/10_add-route_v6_0_0.json @@ -0,0 +1,50 @@ +{ + "version": "1.0", + "chainId": "10", + "createdAt": 1771377131865, + "meta": { + "name": "Add SP1 v6.0.0 Routes", + "description": "Add v6.0.0 verifiers on Optimism", + "checksum": "0x5163d8ab726172ae4c4496574e6491331fcfb22af31e5ee714e006c5bcd49acb" + }, + "transactions": [ + { + "to": "0x397A5f7f3dBd538f23DE225B51f532c34448dA9B", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508" + } + }, + { + "to": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" + } + } + ] +} \ No newline at end of file diff --git a/contracts/safe-batches/1_add-route_v6_0_0.json b/contracts/safe-batches/1_add-route_v6_0_0.json new file mode 100644 index 0000000..2e6a887 --- /dev/null +++ b/contracts/safe-batches/1_add-route_v6_0_0.json @@ -0,0 +1,50 @@ +{ + "version": "1.0", + "chainId": "1", + "createdAt": 1771377131836, + "meta": { + "name": "Add SP1 v6.0.0 Routes", + "description": "Add v6.0.0 verifiers on Ethereum", + "checksum": "0x3309f5bed1f5fbd25b9c7a01cb0ab586012f42cec23a58ef83c5391ee63a6cbf" + }, + "transactions": [ + { + "to": "0x397A5f7f3dBd538f23DE225B51f532c34448dA9B", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508" + } + }, + { + "to": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" + } + } + ] +} \ No newline at end of file diff --git a/contracts/safe-batches/42161_add-route_v6_0_0.json b/contracts/safe-batches/42161_add-route_v6_0_0.json new file mode 100644 index 0000000..d45b090 --- /dev/null +++ b/contracts/safe-batches/42161_add-route_v6_0_0.json @@ -0,0 +1,50 @@ +{ + "version": "1.0", + "chainId": "42161", + "createdAt": 1771377131873, + "meta": { + "name": "Add SP1 v6.0.0 Routes", + "description": "Add v6.0.0 verifiers on Arbitrum", + "checksum": "0xc4c259903a897eab6b150a4477e94c0ce87fcbd0d839bf1a7245f199183a8bae" + }, + "transactions": [ + { + "to": "0x397A5f7f3dBd538f23DE225B51f532c34448dA9B", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508" + } + }, + { + "to": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" + } + } + ] +} \ No newline at end of file diff --git a/contracts/safe-batches/534352_add-route_v6_0_0.json b/contracts/safe-batches/534352_add-route_v6_0_0.json new file mode 100644 index 0000000..8c7357d --- /dev/null +++ b/contracts/safe-batches/534352_add-route_v6_0_0.json @@ -0,0 +1,50 @@ +{ + "version": "1.0", + "chainId": "534352", + "createdAt": 1771377131889, + "meta": { + "name": "Add SP1 v6.0.0 Routes", + "description": "Add v6.0.0 verifiers on Scroll", + "checksum": "0x56a18360925c36eaf4fa7fd34d82ce4122eb990027d6031424b038c3b2acf119" + }, + "transactions": [ + { + "to": "0x397A5f7f3dBd538f23DE225B51f532c34448dA9B", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508" + } + }, + { + "to": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" + } + } + ] +} \ No newline at end of file diff --git a/contracts/safe-batches/8453_add-route_v6_0_0.json b/contracts/safe-batches/8453_add-route_v6_0_0.json new file mode 100644 index 0000000..6b7423b --- /dev/null +++ b/contracts/safe-batches/8453_add-route_v6_0_0.json @@ -0,0 +1,50 @@ +{ + "version": "1.0", + "chainId": "8453", + "createdAt": 1771377131881, + "meta": { + "name": "Add SP1 v6.0.0 Routes", + "description": "Add v6.0.0 verifiers on Base", + "checksum": "0x7550983e37a149e9a66027e4c0a04d3e1610ffba12ace8861887a0377d060c5d" + }, + "transactions": [ + { + "to": "0x397A5f7f3dBd538f23DE225B51f532c34448dA9B", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x99A74A05a0FaBEB217C1A329b0dac59a1FA52508" + } + }, + { + "to": "0x3B6041173B80E77f038f3F2C0f9744f04837185e", + "value": "0", + "data": null, + "contractMethod": { + "inputs": [ + { + "internalType": "address", + "name": "verifier", + "type": "address" + } + ], + "name": "addRoute", + "payable": false + }, + "contractInputsValues": { + "verifier": "0x8a0fd5e825D14368d90Fe68F31fceAe3E17AFc5C" + } + } + ] +} \ No newline at end of file diff --git a/contracts/script/deploy/v6.0.0/SP1VerifierGroth16.s.sol b/contracts/script/deploy/v6.0.0/SP1VerifierGroth16.s.sol index ea51d7a..eebc05e 100644 --- a/contracts/script/deploy/v6.0.0/SP1VerifierGroth16.s.sol +++ b/contracts/script/deploy/v6.0.0/SP1VerifierGroth16.s.sol @@ -12,14 +12,17 @@ contract SP1VerifierScript is BaseScript { function run() external multichain(KEY) broadcaster { // Read config bytes32 CREATE2_SALT = readBytes32("CREATE2_SALT"); - address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY_GROTH16"); // Deploy contract address verifier = address(new SP1Verifier{salt: CREATE2_SALT}()); - // Add the verifier to the gateway - SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); - gateway.addRoute(verifier); + // Register route to gateway (default: false for multisig deployments) + // Set REGISTER_ROUTE=true when deployer is gateway owner + if (vm.envOr("REGISTER_ROUTE", false)) { + address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY_GROTH16"); + SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); + gateway.addRoute(verifier); + } // Write address writeAddress(KEY, verifier); diff --git a/contracts/script/deploy/v6.0.0/SP1VerifierPlonk.s.sol b/contracts/script/deploy/v6.0.0/SP1VerifierPlonk.s.sol index 3680acd..5bae2b7 100644 --- a/contracts/script/deploy/v6.0.0/SP1VerifierPlonk.s.sol +++ b/contracts/script/deploy/v6.0.0/SP1VerifierPlonk.s.sol @@ -12,14 +12,17 @@ contract SP1VerifierScript is BaseScript { function run() external multichain(KEY) broadcaster { // Read config bytes32 CREATE2_SALT = readBytes32("CREATE2_SALT"); - address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY_PLONK"); // Deploy contract address verifier = address(new SP1Verifier{salt: CREATE2_SALT}()); - // Add the verifier to the gateway - SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); - gateway.addRoute(verifier); + // Register route to gateway (default: false for multisig deployments) + // Set REGISTER_ROUTE=true when deployer is gateway owner + if (vm.envOr("REGISTER_ROUTE", false)) { + address SP1_VERIFIER_GATEWAY = readAddress("SP1_VERIFIER_GATEWAY_PLONK"); + SP1VerifierGateway gateway = SP1VerifierGateway(SP1_VERIFIER_GATEWAY); + gateway.addRoute(verifier); + } // Write address writeAddress(KEY, verifier); diff --git a/contracts/script/utils/generate-safe-batch.js b/contracts/script/utils/generate-safe-batch.js new file mode 100755 index 0000000..46f7b48 --- /dev/null +++ b/contracts/script/utils/generate-safe-batch.js @@ -0,0 +1,197 @@ +#!/usr/bin/env node +const fs = require('fs'); +const path = require('path'); +const { execSync } = require('child_process'); + +const DEPLOY_DIR = path.join(__dirname, '../../deployments'); +// Only mainnets are multisig-owned — testnets are EOA-owned (use cast send --ledger) +const MULTISIG_CHAINS = [1, 10, 42161, 8453, 534352]; +const CHAIN_NAMES = { + 1: 'Ethereum', 10: 'Optimism', 42161: 'Arbitrum', 8453: 'Base', 534352: 'Scroll', + 11155111: 'Sepolia', 421614: 'Arbitrum Sepolia', + 84532: 'Base Sepolia', 11155420: 'Optimism Sepolia', 534351: 'Scroll Sepolia' +}; +const ADD_ROUTE_SELECTOR = '0x8c95ff1e'; // keccak256("addRoute(address)")[:4] +const FREEZE_ROUTE_SELECTOR = '0x191ffb1e'; // keccak256("freezeRoute(bytes4)")[:4] + +// VERIFIER_HASH first 4 bytes per version (for freeze) +const VERIFIER_SELECTORS = { + 'V5_0_0': { groth16: '0xa4594c59', plonk: '0xd4e8ecd2' }, + 'V6_0_0': { groth16: '0x0e78f4db', plonk: '0xbb1a6f29' }, +}; + +function versionToKey(v) { return v.toUpperCase().replace(/[.-]/g, '_'); } + +function createAddRouteTransaction(gateway, verifier) { + return { + to: gateway, + value: '0', + data: null, + contractMethod: { + inputs: [{ internalType: 'address', name: 'verifier', type: 'address' }], + name: 'addRoute', + payable: false + }, + contractInputsValues: { verifier } + }; +} + +function createFreezeRouteTransaction(gateway, selector) { + return { + to: gateway, + value: '0', + data: null, + contractMethod: { + inputs: [{ internalType: 'bytes4', name: 'selector', type: 'bytes4' }], + name: 'freezeRoute', + payable: false + }, + contractInputsValues: { selector } + }; +} + +// --- Safe TX Builder checksum (replicates checksum.ts from safe-global/safe-react-apps) --- + +function stringifyReplacer(_key, value) { + return value === undefined ? null : value; +} + +function serializeJSONObject(json) { + if (Array.isArray(json)) { + return `[${json.map(el => serializeJSONObject(el)).join(',')}]`; + } + if (typeof json === 'object' && json !== null) { + let acc = ''; + const keys = Object.keys(json).sort(); + acc += `{${JSON.stringify(keys, stringifyReplacer)}`; + for (let i = 0; i < keys.length; i++) { + acc += `${serializeJSONObject(json[keys[i]])},`; + } + return `${acc}}`; + } + return `${JSON.stringify(json, stringifyReplacer)}`; +} + +function calculateChecksum(batchFile) { + const serialized = serializeJSONObject({ + ...batchFile, + meta: { ...batchFile.meta, name: null }, + }); + // Convert to hex bytes to avoid shell escaping issues with JSON characters + const hexInput = '0x' + Buffer.from(serialized, 'utf8').toString('hex'); + const hex = execSync(`cast keccak ${hexInput}`, { encoding: 'utf8' }).trim(); + return hex; +} + +function addChecksum(batchFile) { + return { + ...batchFile, + meta: { ...batchFile.meta, checksum: calculateChecksum(batchFile) }, + }; +} + +function generateBatch(chainId, version, action) { + const file = path.join(DEPLOY_DIR, `${chainId}.json`); + if (!fs.existsSync(file)) { console.error(` No deployment file`); return null; } + + let d; + try { d = JSON.parse(fs.readFileSync(file, 'utf8')); } + catch (e) { console.error(` Bad JSON: ${e.message}`); return null; } + + const g16 = d['SP1_VERIFIER_GATEWAY_GROTH16'], plonk = d['SP1_VERIFIER_GATEWAY_PLONK']; + if (!g16 || !plonk) { console.error(` Missing gateway addresses`); return null; } + + const k = versionToKey(version); + const txs = []; + + if (action === 'freeze') { + const selectors = VERIFIER_SELECTORS[k]; + if (!selectors) { console.error(` No known selectors for ${version}`); return null; } + + txs.push(createFreezeRouteTransaction(g16, selectors.groth16)); + console.log(` Freeze Groth16: selector ${selectors.groth16} on ${g16}`); + txs.push(createFreezeRouteTransaction(plonk, selectors.plonk)); + console.log(` Freeze Plonk: selector ${selectors.plonk} on ${plonk}`); + } else { + if (d[`${k}_SP1_VERIFIER_GROTH16`]) { + txs.push(createAddRouteTransaction(g16, d[`${k}_SP1_VERIFIER_GROTH16`])); + console.log(` Groth16: ${d[`${k}_SP1_VERIFIER_GROTH16`]} -> ${g16}`); + } + if (d[`${k}_SP1_VERIFIER_PLONK`]) { + txs.push(createAddRouteTransaction(plonk, d[`${k}_SP1_VERIFIER_PLONK`])); + console.log(` Plonk: ${d[`${k}_SP1_VERIFIER_PLONK`]} -> ${plonk}`); + } + } + + if (!txs.length) { + console.error(` No transactions generated for ${version}`); + return null; + } + + const actionLabel = action === 'freeze' ? 'Freeze' : 'Add'; + return { + version: '1.0', + chainId: String(chainId), + createdAt: Date.now(), + meta: { + name: `${actionLabel} SP1 ${version} Routes`, + description: `${actionLabel} ${version} verifiers on ${CHAIN_NAMES[chainId] || chainId}` + }, + transactions: txs + }; +} + +function printUsage() { + const available = fs.readdirSync(DEPLOY_DIR).filter(f => f.endsWith('.json')).map(f => f.slice(0, -5)); + console.log(` +Usage: node generate-safe-batch.js [--chain=] [--version=] [--action=] + +Chain groups: + --chain=all All multisig chains: ${MULTISIG_CHAINS.join(', ')} + --chain= Single chain by ID + +Available chains: ${available.join(', ')} +Defaults: --chain=all --version=v6.0.0 --action=add +`); +} + +// Parse args +const args = { chain: 'all', version: 'v6.0.0', action: 'add' }; +for (const a of process.argv.slice(2)) { + if (a === '-h' || a === '--help') { printUsage(); process.exit(0); } + if (a.startsWith('--chain=')) args.chain = a.slice(8); + if (a.startsWith('--version=')) args.version = a.slice(10); + if (a.startsWith('--action=')) args.action = a.slice(9); +} + +if (!['add', 'freeze'].includes(args.action)) { + console.error(`Bad action: ${args.action} (use 'add' or 'freeze')`); + process.exit(1); +} + +// Resolve chains +let chains; +if (args.chain === 'all') chains = MULTISIG_CHAINS; +else chains = [parseInt(args.chain) || (console.error(`Bad chain: ${args.chain}`), process.exit(1))]; + +const actionLabel = args.action === 'freeze' ? 'freeze' : 'add-route'; +console.log(`\nGenerating ${actionLabel} batches for ${args.version} on ${args.chain}\n`); + +const outDir = path.join(__dirname, '../../safe-batches'); +fs.mkdirSync(outDir, { recursive: true }); + +let ok = 0; +for (const id of chains) { + console.log(`${CHAIN_NAMES[id] || id} (${id})...`); + const batch = generateBatch(id, args.version, args.action); + if (batch) { + const withChecksum = addChecksum(batch); + const out = path.join(outDir, `${id}_${actionLabel}_${versionToKey(args.version).toLowerCase()}.json`); + fs.writeFileSync(out, JSON.stringify(withChecksum, null, 2)); + console.log(` -> ${out}\n`); + ok++; + } else console.log(''); +} + +console.log(`Done: ${ok}/${chains.length} generated`); +if (ok) console.log(`Upload to Safe UI -> Transaction Builder`);