diff --git a/src/template/L1PortalExecuteL2Call.sol b/src/template/L1PortalExecuteL2Call.sol index bf38365a6b..36a88791a9 100644 --- a/src/template/L1PortalExecuteL2Call.sol +++ b/src/template/L1PortalExecuteL2Call.sol @@ -4,9 +4,10 @@ pragma solidity 0.8.15; import {VmSafe} from "forge-std/Vm.sol"; import {stdToml} from "forge-std/StdToml.sol"; -import {MultisigTaskPrinter} from "../libraries/MultisigTaskPrinter.sol"; -import {Action} from "../libraries/MultisigTypes.sol"; -import {SimpleTaskBase} from "../tasks/types/SimpleTaskBase.sol"; +import {MultisigTaskPrinter} from "src/libraries/MultisigTaskPrinter.sol"; +import {Action} from "src/libraries/MultisigTypes.sol"; +import {L2TaskBase} from "src/tasks/types/L2TaskBase.sol"; +import {SuperchainAddressRegistry} from "src/SuperchainAddressRegistry.sol"; /// @notice Interface for the OptimismPortal2 contract on L1. interface IOptimismPortal2 { @@ -17,12 +18,11 @@ interface IOptimismPortal2 { /// @notice Template to execute an L2 call via the L1 Optimism Portal from a nested L1 Safe. /// Sends an L2 transaction using OptimismPortal.depositTransaction with config-driven params. -contract L1PortalExecuteL2Call is SimpleTaskBase { +/// Supports: op-contracts/v4.6.0 +contract L1PortalExecuteL2Call is L2TaskBase { using stdToml for string; // -------- Config inputs -------- - /// @notice The address of the OptimismPortal2 contract on L1. - address payable public portal; /// @notice The address of the L2 target contract. address public l2Target; /// @notice The calldata to be executed on l2Target. @@ -41,7 +41,7 @@ contract L1PortalExecuteL2Call is SimpleTaskBase { /// Allowlist the OptimismPortal since it will mutate state (queue/event) on deposit. function _taskStorageWrites() internal pure override returns (string[] memory) { string[] memory _storageWrites = new string[](1); - _storageWrites[0] = "OptimismPortal"; + _storageWrites[0] = "OptimismPortalProxy"; return _storageWrites; } @@ -49,13 +49,12 @@ contract L1PortalExecuteL2Call is SimpleTaskBase { /// Allowlist the OptimismPortal to receive ETH (value) in the deposit call. function _taskBalanceChanges() internal pure override returns (string[] memory) { string[] memory _balanceChanges = new string[](1); - _balanceChanges[0] = "OptimismPortal"; + _balanceChanges[0] = "OptimismPortalProxy"; return _balanceChanges; } /// @notice Parse config and initialize template variables. /// Expected TOML keys: - /// - portal: address (L1 OptimismPortal) OR addresses.OptimismPortal in [addresses] /// - l2Target: address (L2 target address) /// - l2Data: hex string (e.g. 0x1234...) /// - gasLimit: uint (will be cast to uint64) @@ -64,14 +63,6 @@ contract L1PortalExecuteL2Call is SimpleTaskBase { function _templateSetup(string memory _taskConfigFilePath, address) internal override { string memory _toml = vm.readFile(_taskConfigFilePath); - // Resolve portal from registry first if available, else read explicit field. - try simpleAddrRegistry.get("OptimismPortal") returns (address p) { - portal = payable(p); - } catch { - portal = payable(_toml.readAddress(".portal")); - } - require(portal != address(0), "portal must be set (addresses.OptimismPortal or .portal)"); - l2Target = _toml.readAddress(".l2Target"); require(l2Target != address(0), "l2Target must be set"); @@ -95,8 +86,12 @@ contract L1PortalExecuteL2Call is SimpleTaskBase { /// @notice Build the portal deposit action. WARNING: State changes here are reverted after capture. function _build(address) internal override { - // Record the L1 portal call with value for action extraction. - IOptimismPortal2(portal).depositTransaction(l2Target, 0, gasLimit, isCreation, l2Data); + SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains(); + for (uint256 _i = 0; _i < chains.length; _i++) { + // Record the L1 portal call with value for action extraction. + IOptimismPortal2(superchainAddrRegistry.getAddress("OptimismPortalProxy", chains[_i].chainId)) + .depositTransaction(l2Target, 0, gasLimit, isCreation, l2Data); + } } /// @notice Validate that exactly one action to the portal with the expected calldata and value was captured. @@ -106,15 +101,22 @@ contract L1PortalExecuteL2Call is SimpleTaskBase { bool _found; uint256 _matches; - for (uint256 _i = 0; _i < _actions.length; _i++) { - if (_actions[_i].target == portal && _actions[_i].value == 0) { - if (keccak256(_actions[_i].arguments) == keccak256(_expected)) { - _found = true; - _matches++; + SuperchainAddressRegistry.ChainInfo[] memory chains = superchainAddrRegistry.getChains(); + for (uint256 _i = 0; _i < chains.length; _i++) { + for (uint256 _j = 0; _j < _actions.length; _j++) { + if ( + _actions[_j].target == superchainAddrRegistry.getAddress("OptimismPortalProxy", chains[_i].chainId) + && _actions[_j].value == 0 + ) { + if (keccak256(_actions[_j].arguments) == keccak256(_expected)) { + _found = true; + _matches++; + } } } } - require(_found && _matches == 1, "expected one portal deposit action"); + + require(_found && _matches == chains.length, "expected one portal deposit action for each chain"); MultisigTaskPrinter.printTitle("Validated portal deposit action"); } diff --git a/test/tasks/example/eth/014-noop-call-optimismportal/config.toml b/test/tasks/example/eth/014-noop-call-optimismportal/config.toml index 939b3c231d..318a8809d0 100644 --- a/test/tasks/example/eth/014-noop-call-optimismportal/config.toml +++ b/test/tasks/example/eth/014-noop-call-optimismportal/config.toml @@ -1,12 +1,9 @@ templateName = "L1PortalExecuteL2Call" -# Portal + L2 call params -portal = "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed" # L1 OptimismPortal +l2chains = [{name = "OP Mainnet", chainId = 10}] + +# L2 call params l2Target = "0xcDF27F107725988f2261Ce2256bDfCdE8B382B10" # OptimismGovernor Proxy l2Data = "0x3659cfe6000000000000000000000000ecbf4ed9f47302f00f0f039a691e7db83bdd2624" # upgradeTo(currentImpl) -> 0xecbf4ed9f47302f00f0f039a691e7db83bdd2624 gasLimit = 500000 isCreation = false - -[addresses] -ProxyAdminOwner = "0x5a0Aae59D09fccBdDb6C6CcEB07B7279367C3d2A" # 2-of-2 between council and foundation -OptimismPortal = "0xbEb5Fc579115071764c7423A4f12eDde41f106Ed" \ No newline at end of file