diff --git a/src/justfile b/src/justfile index 20695cf623..cb900f8f43 100644 --- a/src/justfile +++ b/src/justfile @@ -70,28 +70,53 @@ simulate-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEP [ -z "{{NETWORK}}" ] && { echo -e "\n\033[31mError: No network specified\033[0m"; show_usage; exit 1; } ETH_RPC_URL=$("$root_dir"/src/script/get-rpc-url.sh "{{NETWORK}}") + + # Load FORK_BLOCK_NUMBER from the task's .env file if available + if [ -n "{{TASK}}" ]; then + task_env_file="${root_dir}/src/tasks/{{NETWORK}}/{{TASK}}/.env" + if [ -f "$task_env_file" ]; then + set -a + source "$task_env_file" + set +a + fi + else + # For full stack simulations, find the first .env file that contains FORK_BLOCK_NUMBER + # Search through .env files in numerical order by task number + for env_file in $(find "${root_dir}/src/tasks/{{NETWORK}}" -name ".env" -type f | sort -V); do + if grep -q "FORK_BLOCK_NUMBER" "$env_file" 2>/dev/null; then + set -a + source "$env_file" + set +a + break + fi + done + fi + + # Get fork block arguments - will be used for all tasks in the stack + fork_block_args=$(just --justfile "$root_just_file" _get-fork-block-args) + echo -e "\n⏳ Stacked Task simulation in progress..." if [ -z "{{TASK}}" ]; then echo -e "⏳ You are simulating all tasks for network: {{NETWORK}}\n" just list-stack {{NETWORK}} - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string)" {{NETWORK}} --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string)" {{NETWORK}} --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} elif [ -z "{{CHILD_SAFE_NAME_DEPTH_1}}" ] && [ -z "{{CHILD_SAFE_NAME_DEPTH_2}}" ]; then echo -e "⏳ You are simulating the task: {{TASK}} for network: '{{NETWORK}}' on the root safe\n" just list-stack {{NETWORK}} {{TASK}} - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "{{TASK}}" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "{{TASK}}" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} else task_dir_path="${root_dir}/src/tasks/{{NETWORK}}/{{TASK}}" child_safe_depth_1=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_1}}") child_safe_depth_2=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_2}}") just list-stack {{NETWORK}} {{TASK}} - + if [ "$child_safe_depth_2" != "$ZERO_ADDRESS" ]; then echo -e "⏳ You are simulating the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_2\n" - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} else echo -e "⏳ You are simulating the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_1\n" - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} fi fi echo -e "\n⚠️ Please note: Some Tenderly links may not work when running a stacked simulation. Check out Tenderly's Virtual TestNets as a workaround.⚠️" @@ -119,6 +144,17 @@ sign-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2 child_safe_depth_1=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_1}}") child_safe_depth_2=$(just --justfile "$root_just_file" _fetch-safe "$task_dir_path" "{{CHILD_SAFE_NAME_DEPTH_2}}") + # Load FORK_BLOCK_NUMBER from the task's .env file if available + task_env_file="$task_dir_path/.env" + if [ -f "$task_env_file" ]; then + set -a + source "$task_env_file" + set +a + fi + + # Get fork block arguments + fork_block_args=$(just --justfile "$root_just_file" _get-fork-block-args) + HD_PATH=${HD_PATH:-0} USE_KEYSTORE=${USE_KEYSTORE:-} signer_info=$(just --justfile "$root_just_file" _get-signer-args "$HD_PATH" "$USE_KEYSTORE") @@ -126,20 +162,20 @@ sign-stack NETWORK="" TASK="" CHILD_SAFE_NAME_DEPTH_1="" CHILD_SAFE_NAME_DEPTH_2 export SIGNING_MODE_IN_PROGRESS=true export STACKED_SIGNING_MODE=true - + if [ "$child_safe_depth_2" != "$ZERO_ADDRESS" ]; then echo -e "⏳ You are signing the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_2\n" ${root_dir}/bin/eip712sign ${signer_args} -- \ - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_2" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} elif [ -z "{{CHILD_SAFE_NAME_DEPTH_1}}" ] && [ -z "{{CHILD_SAFE_NAME_DEPTH_2}}" ]; then echo -e "⏳ You are signing the task: {{TASK}} for network: '{{NETWORK}}' on the root safe\n" just list-stack {{NETWORK}} {{TASK}} ${root_dir}/bin/eip712sign ${signer_args} -- \ - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "{{TASK}}" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string)" "{{NETWORK}}" "{{TASK}}" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} else echo -e "⏳ You are signing the task: {{TASK}} for network: '{{NETWORK}}' on the nested safe: $child_safe_depth_1\n" ${root_dir}/bin/eip712sign ${signer_args} -- \ - forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} + forge script ${root_dir}/src/tasks/StackedSimulator.sol:StackedSimulator --sig "simulateStack(string,string,address)" "{{NETWORK}}" "{{TASK}}" "$child_safe_depth_1" --ffi --fork-url $ETH_RPC_URL --fork-retries {{forge_fork_retries}} --fork-retry-backoff {{forge_fork_retry_backoff}} ${fork_block_args} fi echo -e "\n⚠️ Please note: Some Tenderly links may not work when running a stacked simulation. Check out Tenderly's Virtual TestNets as a workaround.⚠️" diff --git a/src/tasks/TaskManager.sol b/src/tasks/TaskManager.sol index c260dab888..bcc31c3660 100644 --- a/src/tasks/TaskManager.sol +++ b/src/tasks/TaskManager.sol @@ -105,7 +105,7 @@ contract TaskManager is Script { string memory formattedRootSafe = vm.toString(config.rootSafe).green().bold(); - setTenderlyGasEnv(config.basePath); + setEnv(config.basePath); string[] memory parts = vm.split(config.basePath, "/"); string memory taskName = parts[parts.length - 1]; @@ -234,25 +234,34 @@ contract TaskManager is Script { ); } - /// @notice Sets the TENDERLY_GAS environment variable for the task if it exists. - function setTenderlyGasEnv(string memory basePath) public { + /// @notice Sets environment variables from the task's .env file if it exists. + function setEnv(string memory basePath) public { string memory envFile = string.concat(basePath, "/", ".env"); if (vm.isFile(envFile)) { string memory envContent = vm.readFile(envFile); string[] memory lines = vm.split(envContent, "\n"); for (uint256 i = 0; i < lines.length; i++) { - if (lines[i].contains("TENDERLY_GAS=")) { + // Skip empty lines and comments + if (bytes(lines[i]).length == 0 || lines[i].startsWith("#")) { + continue; + } + + // Parse key=value pairs + if (lines[i].contains("=")) { string[] memory keyValue = vm.split(lines[i], "="); - if (keyValue.length == 2) { - vm.setEnv("TENDERLY_GAS", keyValue[1]); - return; + if (keyValue.length >= 2) { + // Trim whitespace from key and value, then set the environment variable + string memory key = vm.trim(keyValue[0]); + string memory value = vm.trim(keyValue[1]); + vm.setEnv(key, value); } } } + } else { + // If no .env file exists, set TENDERLY_GAS to empty for backwards compatibility + vm.setEnv("TENDERLY_GAS", ""); } - // If no TENDERLY_GAS is found, set it as empty. - vm.setEnv("TENDERLY_GAS", ""); } /// @notice Useful function to tell if a task is nested or not based on the task config. diff --git a/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/.env b/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/.env index adf17d369c..205f6ffe64 100644 --- a/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/.env +++ b/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/.env @@ -1 +1,2 @@ TENDERLY_GAS=15000000 +FORK_BLOCK_NUMBER=23491327 diff --git a/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/README.md b/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/README.md index d32a8453fd..a4792f1560 100644 --- a/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/README.md +++ b/src/tasks/eth/022-U16a-opcm-upgrade-v410-base/README.md @@ -25,7 +25,7 @@ cd superchain-ops git pull ``` -## Step 3. Install & Configure Mise +## Step 3. Install & Configure Mise Install Mise by executing the following commands. When the Bash script runs, follow the instructions in the log output to activate mise in your shell. @@ -57,12 +57,12 @@ Base has a doubly-nested safe architecture which is supported by superchain-ops. ```bash # # ┌─────────────────────────────────────────────┐ ┌─────────────────────────────────────────────┐ ┌─────────────────────────────────────────────┐ -# │ Base Council │ │ Base Operations │ │ Foundation Operations (FOS) │ +# │ Base Council │ │ Base Operations │ │ Foundation Operations (FOS) │ # │ (7 of 10) │ │ (3 of 6) │ │ (5 of 7) │ # │ 0x20AcF55A3DCfe07fC4cecaCFa1628F788EC8A4Dd │ │ 0x9C4a57Feb77e294Fd7BF5EBE9AB01CAA0a90A110 │ │ 0x9BA6e03D8B90dE867373Db8cF1A58d2F7F006b3A │ # └─────────────────────┬───────────────────────┘ └─────────────────────┬───────────────────────┘ └─────────────────────┬───────────────────────┘ # │ │ │ -# └─────────────────┬───────────────────────────────────┘ │ +# └─────────────────┬───────────────────────────────────┘ │ # ▼ │ # ┌─────────────────────────────────────────────┐ │ # │ Base Nested │ │ @@ -87,18 +87,18 @@ First, simulate the upgrade transaction using the command below corresponding to cd tasks/eth/022-U16a-opcm-upgrade-v410-base # Base Council: 0x20AcF55A3DCfe07fC4cecaCFa1628F788EC8A4Dd -# ┌────────────────────┐ +# ┌────────────────────┐ # │ Child Safe Depth 2 │ # │ 'base-council' │ -# └────────────────────┘ -# │ +# └────────────────────┘ +# │ # └─────────────────┬ -# ▼ +# ▼ # ┌────────────────────┐ # │ Child Safe Depth 1 │ # │ 'base-nested' │ # └────────────────────┘ -# │ +# │ # └──────────┬ # ▼ # ┌─────────────────┐ @@ -111,18 +111,18 @@ SIMULATE_WITHOUT_LEDGER=1 just --dotenv-path $(pwd)/.env simulate base-nested ba # Normalized Hash: 0x1040a2a57a0fc30a1ff18d3c0e35898dbf98c89dc172945b99a0f3b65508c659 # Base Operations: 0x9C4a57Feb77e294Fd7BF5EBE9AB01CAA0a90A110 -# ┌────────────────────┐ +# ┌────────────────────┐ # │ Child Safe Depth 2 │ # │ 'base-operations' │ -# └────────────────────┘ -# │ +# └────────────────────┘ +# │ # └─────────────────┬ -# ▼ +# ▼ # ┌────────────────────┐ # │ Child Safe Depth 1 │ # │ 'base-nested' │ # └────────────────────┘ -# │ +# │ # └──────────┬ # ▼ # ┌─────────────────┐ @@ -140,7 +140,7 @@ SIMULATE_WITHOUT_LEDGER=1 just --dotenv-path $(pwd)/.env simulate base-nested ba # │ Child Safe Depth 1 │ # │ 'FOS' │ # └────────────────────┘ -# │ +# │ # └──────────┬ # ▼ # ┌─────────────────┐ @@ -217,7 +217,7 @@ Now, perform the signing for whichever of the safes you are a member of: ```bash cd src/tasks/eth/022-U16a-opcm-upgrade-v410-base -just --dotenv-path $(pwd)/.env sign base-nested base-council +just --dotenv-path $(pwd)/.env sign base-nested base-council # Expected Hashes # Domain Hash: 0x1fbfdc61ceb715f63cb17c56922b88c3a980f1d83873df2b9325a579753e8aa3 # Message Hash: 0x520aeeb85997f9db884ae07d1da74b5251550f49ab662b9ada3fa34572ece772 diff --git a/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/.env b/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/.env index 16c7320407..ec1f573a10 100644 --- a/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/.env +++ b/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/.env @@ -1 +1,2 @@ TENDERLY_GAS=32000000 +FORK_BLOCK_NUMBER=23491327 diff --git a/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/README.md b/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/README.md index dd29134478..12100f664d 100644 --- a/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/README.md +++ b/src/tasks/eth/023-U16a-opcm-upgrade-v410-op-soneium-ink/README.md @@ -1,6 +1,6 @@ # 023-U16a-opcm-upgrade-v410-op-soneium-ink: Upgrade 16a: OP, Soneium, Ink on Mainnet -Status: [READY TO SIGN]() +Status: [EXECUTED](https://etherscan.io/tx/0x744cf7d28324729cace731ac736872da669439a0d380f1f52b8d31af203f7329) ## Objective @@ -44,4 +44,4 @@ just --dotenv-path $(pwd)/.env sign foundation # Security Council - Simulate and Sign SIMULATE_WITHOUT_LEDGER=1 just --dotenv-path $(pwd)/.env simulate council just --dotenv-path $(pwd)/.env sign council -``` \ No newline at end of file +``` diff --git a/src/tasks/eth/024-U16a-opcm-upgrade-v410-unichain/README.md b/src/tasks/eth/024-U16a-opcm-upgrade-v410-unichain/README.md index a13b104991..d1ec5bb71f 100644 --- a/src/tasks/eth/024-U16a-opcm-upgrade-v410-unichain/README.md +++ b/src/tasks/eth/024-U16a-opcm-upgrade-v410-unichain/README.md @@ -1,6 +1,6 @@ # 024-U16a-opcm-upgrade-v410-unichain: Upgrade 16a: Unichain -Status: [READY TO SIGN]() +Status: [EXECUTED](https://etherscan.io/tx/0xc98240172fa3950ec9c62f32cc09d0eb0ed21684b02f1b2677357674cda64ca5) ## Objective diff --git a/test/tasks/TaskManager.t.sol b/test/tasks/TaskManager.t.sol index ff1ee8afbf..0e9ba7538e 100644 --- a/test/tasks/TaskManager.t.sol +++ b/test/tasks/TaskManager.t.sol @@ -26,23 +26,28 @@ contract TaskManagerUnitTest is StateOverrideManager, Test { function testSetTenderlyGasEnv() public { TaskManager tm = new TaskManager(); - tm.setTenderlyGasEnv("./src/tasks/sep/000-opcm-upgrade-v200/"); + tm.setEnv("./src/tasks/sep/000-opcm-upgrade-v200/"); assertEq(vm.envString("TENDERLY_GAS"), "30000000"); - tm.setTenderlyGasEnv("./src/tasks/sep/001-opcm-upgrade-v200/"); + tm.setEnv("./src/tasks/sep/001-opcm-upgrade-v200/"); assertEq(vm.envString("TENDERLY_GAS"), "16000000"); - tm.setTenderlyGasEnv("./src/tasks/sep/002-unichain-superchain-config-fix/"); + tm.setEnv("./src/tasks/sep/002-unichain-superchain-config-fix/"); assertEq(vm.envString("TENDERLY_GAS"), ""); - tm.setTenderlyGasEnv("./src/tasks/sep/003-opcm-upgrade-v200/"); + tm.setEnv("./src/tasks/sep/003-opcm-upgrade-v200/"); assertEq(vm.envString("TENDERLY_GAS"), "16000000"); - tm.setTenderlyGasEnv("./src/tasks/eth/000-opcm-upgrade-v200/"); + tm.setEnv("./src/tasks/eth/000-opcm-upgrade-v200/"); assertEq(vm.envString("TENDERLY_GAS"), "30000000"); - tm.setTenderlyGasEnv("./src/tasks/eth/002-opcm-upgrade-v200/"); + tm.setEnv("./src/tasks/eth/002-opcm-upgrade-v200/"); assertEq(vm.envString("TENDERLY_GAS"), "16000000"); + + // Test loading multiple environment variables including FORK_BLOCK_NUMBER + tm.setEnv("./src/tasks/eth/022-U16a-opcm-upgrade-v410-base/"); + assertEq(vm.envString("TENDERLY_GAS"), "15000000"); + assertEq(vm.envString("FORK_BLOCK_NUMBER"), "23491327"); } function createStateDiff(address who, bytes32 slot, bytes32 oldValue, bytes32 newValue) diff --git a/test/tasks/example/eth/013-U16-base/.env b/test/tasks/example/eth/013-U16-base/.env index b4b63fd552..3504c5992a 100644 --- a/test/tasks/example/eth/013-U16-base/.env +++ b/test/tasks/example/eth/013-U16-base/.env @@ -1,3 +1,4 @@ TENDERLY_GAS=27000000 NESTED_SAFE_NAME_DEPTH_1=base-nested NESTED_SAFE_NAME_DEPTH_2=base-council +FORK_BLOCK_NUMBER=23491327