From ac1a9d8fb82a7c63df279d492ec6b288dd097939 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Tue, 2 Jul 2024 17:27:21 +0800 Subject: [PATCH 01/14] add SendMessageToDelegateOwner.s.sol --- .../script/SendMessageToDelegateOwner.s.sol | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 packages/protocol/script/SendMessageToDelegateOwner.s.sol diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol new file mode 100644 index 0000000000..acd06601b1 --- /dev/null +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +import "forge-std/src/Script.sol"; +import "../contracts/L2/DelegateOwner.sol"; +import "../contracts/bridge/IBridge.sol"; +import "../test/common/TestMulticall3.sol"; + +contract SendMessageToDelegateOwner is Script { + address public delegateOwner = 0x904aa0aC002532f1410457484893107757683F53; + address public multicall3 = 0xcA11bde05977b3631167028862bE2a173976CA11; + address public l1Bridge = 0xd60247c6848B7Ca29eDdF63AA924E53dB6Ddd8EC; + + modifier broadcast() { + vm.startBroadcast(); + _; + vm.stopBroadcast(); + } + + function run() external broadcast { + TestMulticall3.Call3[] memory calls = new TestMulticall3.Call3[](2); + calls[0].target = address(delegateOwner); + calls[0].allowFailure = false; + calls[0].callData = + abi.encodeCall(DelegateOwner.setAdmin, (0x4757D97449acA795510b9f3152C6a9019A3545c3)); + + calls[1].target = address(delegateOwner); + calls[1].allowFailure = false; + calls[1].callData = + abi.encodeCall(DelegateOwner.setAdmin, (0x55d79345Afc87806B690C9f96c4D7BfE2Bca8268)); + + DelegateOwner.Call memory dcall = DelegateOwner.Call({ + txId: 0, + target: multicall3, + isDelegateCall: true, + txdata: abi.encodeCall(TestMulticall3.aggregate3, (calls)) + }); + + IBridge.Message memory message = IBridge.Message({ + id: 0, + fee: 0, + gasLimit: 1_000_000, // cannot be zero + from: msg.sender, + srcChainId: 1, + srcOwner: msg.sender, + destChainId: 167_000, + destOwner: delegateOwner, + to: delegateOwner, + value: 0, + data: abi.encode(dcall) + }); + + IBridge(l1Bridge).sendMessage(message); + } +} From e4fb7bd1a3f720e8a873d0bd30c7f2afd5111e14 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Wed, 3 Jul 2024 13:00:48 +0800 Subject: [PATCH 02/14] Update packages/protocol/script/SendMessageToDelegateOwner.s.sol Co-authored-by: D <51912515+adaki2004@users.noreply.github.com> --- packages/protocol/script/SendMessageToDelegateOwner.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index acd06601b1..008d9ab05d 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -30,7 +30,7 @@ contract SendMessageToDelegateOwner is Script { abi.encodeCall(DelegateOwner.setAdmin, (0x55d79345Afc87806B690C9f96c4D7BfE2Bca8268)); DelegateOwner.Call memory dcall = DelegateOwner.Call({ - txId: 0, + txId: 0, // Has to match with DelegateOwner's nextTxId target: multicall3, isDelegateCall: true, txdata: abi.encodeCall(TestMulticall3.aggregate3, (calls)) From a7338e2c6e5d2f6a3616154a9fb1e96454759e3b Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Wed, 3 Jul 2024 13:00:23 +0800 Subject: [PATCH 03/14] more --- packages/protocol/deployments/mainnet-contract-logs-L2.md | 2 +- packages/protocol/script/SendMessageToDelegateOwner.s.sol | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/protocol/deployments/mainnet-contract-logs-L2.md b/packages/protocol/deployments/mainnet-contract-logs-L2.md index 1d555d10b8..51b42b2cc7 100644 --- a/packages/protocol/deployments/mainnet-contract-logs-L2.md +++ b/packages/protocol/deployments/mainnet-contract-logs-L2.md @@ -115,7 +115,7 @@ #### delegate_owner -- proxy: `0x904aa0aC002532f1410457484893107757683F53` +- proxy: `0x2f46c57046672e71d02ed0f0b71dfa42c7f3c488` - impl: `0x9F0C40A474E0FB6b27D71c43Aff840B9c42f0C44` - admin: `0x8F13E3a9dFf52e282884aA70eAe93F57DD601298` - remoteOwner: `0x8F13E3a9dFf52e282884aA70eAe93F57DD601298` diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index 008d9ab05d..aeebc807c6 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -7,7 +7,7 @@ import "../contracts/bridge/IBridge.sol"; import "../test/common/TestMulticall3.sol"; contract SendMessageToDelegateOwner is Script { - address public delegateOwner = 0x904aa0aC002532f1410457484893107757683F53; + address public delegateOwner = 0x2F46C57046672E71d02ed0f0B71dFa42C7F3C488; address public multicall3 = 0xcA11bde05977b3631167028862bE2a173976CA11; address public l1Bridge = 0xd60247c6848B7Ca29eDdF63AA924E53dB6Ddd8EC; From 024ff3588f559fd2da87cc8fc5e267eb602965ee Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Thu, 11 Jul 2024 18:23:41 +0800 Subject: [PATCH 04/14] more --- .../deployments/mainnet-contract-logs-L2.md | 8 +-- .../script/DeployL2DelegateOwner.s.sol | 6 +- .../script/L1DelegateOwnerBatching.s.sol | 68 ------------------- .../script/SendMessageToDelegateOwner.s.sol | 6 +- 4 files changed, 11 insertions(+), 77 deletions(-) delete mode 100644 packages/protocol/script/L1DelegateOwnerBatching.s.sol diff --git a/packages/protocol/deployments/mainnet-contract-logs-L2.md b/packages/protocol/deployments/mainnet-contract-logs-L2.md index 51b42b2cc7..ad9bb2645c 100644 --- a/packages/protocol/deployments/mainnet-contract-logs-L2.md +++ b/packages/protocol/deployments/mainnet-contract-logs-L2.md @@ -115,10 +115,10 @@ #### delegate_owner -- proxy: `0x2f46c57046672e71d02ed0f0b71dfa42c7f3c488` -- impl: `0x9F0C40A474E0FB6b27D71c43Aff840B9c42f0C44` -- admin: `0x8F13E3a9dFf52e282884aA70eAe93F57DD601298` -- remoteOwner: `0x8F13E3a9dFf52e282884aA70eAe93F57DD601298` +- proxy: `0x5995941Df88F30Ac140515AA39832db963E2f863` +- impl: `0x2D2F4C692a7940e6Cc8e261692a5e20955BAb311` +- admin: `0x3c181965C5cFAE61a9010A283e5e0C1445649810` // owned by Daniel W +- remoteOwner: `0x3c181965C5cFAE61a9010A283e5e0C1445649810` // owned by Daniel W - todo: - test various use cases - transfer remote owner to `admin.taiko.eth` diff --git a/packages/protocol/script/DeployL2DelegateOwner.s.sol b/packages/protocol/script/DeployL2DelegateOwner.s.sol index a44dc00123..108ea7abbe 100644 --- a/packages/protocol/script/DeployL2DelegateOwner.s.sol +++ b/packages/protocol/script/DeployL2DelegateOwner.s.sol @@ -7,8 +7,10 @@ import "../contracts/L2/DelegateOwner.sol"; // forge script --rpc-url https://rpc.mainnet.taiko.xyz script/DeployL2DelegateOwner.s.sol contract DeployL2DelegateOwner is DeployCapability { address public l2Sam = 0x1670000000000000000000000000000000000006; - address public l1Owner = 0x8F13E3a9dFf52e282884aA70eAe93F57DD601298; // Daniel's EOA - address public l2Admin = 0x8F13E3a9dFf52e282884aA70eAe93F57DD601298; // same + address public testAccount2 = 0x3c181965C5cFAE61a9010A283e5e0C1445649810; // owned by Daniel W + + address public l1Owner = testAccount2; + address public l2Admin = testAccount2; modifier broadcast() { vm.startBroadcast(); diff --git a/packages/protocol/script/L1DelegateOwnerBatching.s.sol b/packages/protocol/script/L1DelegateOwnerBatching.s.sol deleted file mode 100644 index c818703cab..0000000000 --- a/packages/protocol/script/L1DelegateOwnerBatching.s.sol +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.24; - -import "../test/DeployCapability.sol"; -import "../contracts/L2/DelegateOwner.sol"; -import "../contracts/bridge/Bridge.sol"; -import "../test/common/TestMulticall3.sol"; - -// forge script \ -// --rpc-url https://mainnet.infura.io/v3/... \ -// --private-key ... \ -// --legacy \ -// --broadcast \ -// script/DeployL2DelegateOwner.s.sol -contract L2DelegateOwnerBatching is DeployCapability { - address public l2Admin = 0x8F13E3a9dFf52e282884aA70eAe93F57DD601298; // same - address public l2DelegateOwner = 0x08c82ab90f86BF8d98440b96754a67411D656130; - address public constant l2Multicall3 = 0xcA11bde05977b3631167028862bE2a173976CA11; - - modifier broadcast() { - vm.startBroadcast(); - _; - vm.stopBroadcast(); - } - - function run() external broadcast { - TestMulticall3.Call3[] memory calls = new TestMulticall3.Call3[](2); - calls[0].target = 0x08c82ab90f86BF8d98440b96754a67411D656130; - calls[0].allowFailure = false; - calls[0].callData = - abi.encodeCall(DelegateOwner.setAdmin, (0x4757D97449acA795510b9f3152C6a9019A3545c3)); - - calls[1].target = 0xf4707c2821b3067bdF9c4D48eB133851FF3e7ea7; - calls[1].allowFailure = false; - calls[1].callData = - abi.encodeCall(UUPSUpgradeable.upgradeTo, (0x0167000000000000000000000000000000010002)); - - sendMessage(0, calls); - } - - function sendMessage(uint64 txId, TestMulticall3.Call3[] memory calls) internal { - IBridge.Message memory message; - message.fee = 20_000_000_000_000; - message.gasLimit = 2_000_000; - message.destChainId = 167_000; - - // TODO: What if l2Admin becomes 0x0? - message.srcOwner = l2Admin; - message.destOwner = l2Admin; - message.to = l2DelegateOwner; - - message.data = abi.encodeCall( - DelegateOwner.onMessageInvocation, - abi.encode( - DelegateOwner.Call( - txId, - l2Multicall3, - true, // DELEGATECALL - abi.encodeCall(TestMulticall3.aggregate3, (calls)) - ) - ) - ); - - Bridge(0xd60247c6848B7Ca29eDdF63AA924E53dB6Ddd8EC).sendMessage{ value: message.fee }( - message - ); - } -} diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index aeebc807c6..f2a7139e5a 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -7,9 +7,10 @@ import "../contracts/bridge/IBridge.sol"; import "../test/common/TestMulticall3.sol"; contract SendMessageToDelegateOwner is Script { - address public delegateOwner = 0x2F46C57046672E71d02ed0f0B71dFa42C7F3C488; + address public delegateOwner = 0x5995941Df88F30Ac140515AA39832db963E2f863; address public multicall3 = 0xcA11bde05977b3631167028862bE2a173976CA11; address public l1Bridge = 0xd60247c6848B7Ca29eDdF63AA924E53dB6Ddd8EC; + address public testAccount1 = 0x3b7c503e18E197F92028b02Fe52BD674E7289cCa; // owned by Daniel W modifier broadcast() { vm.startBroadcast(); @@ -26,8 +27,7 @@ contract SendMessageToDelegateOwner is Script { calls[1].target = address(delegateOwner); calls[1].allowFailure = false; - calls[1].callData = - abi.encodeCall(DelegateOwner.setAdmin, (0x55d79345Afc87806B690C9f96c4D7BfE2Bca8268)); + calls[1].callData = abi.encodeCall(DelegateOwner.setAdmin, (testAccount1)); DelegateOwner.Call memory dcall = DelegateOwner.Call({ txId: 0, // Has to match with DelegateOwner's nextTxId From 92f645df9f00bc6e7e9c3c57bdb0fe5e387e410d Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:24:15 +0800 Subject: [PATCH 05/14] more --- .../script/SendMessageToDelegateOwner.s.sol | 12 +- packages/protocol/test/L2/DelegateOwner.t.sol | 10 +- .../protocol/test/common/TestMulticall3.sol | 57 ---- .../test/thirdparty/muticall3/Multicall3.sol | 260 ++++++++++++++++++ 4 files changed, 271 insertions(+), 68 deletions(-) delete mode 100644 packages/protocol/test/common/TestMulticall3.sol create mode 100644 packages/protocol/test/thirdparty/muticall3/Multicall3.sol diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index f2a7139e5a..6537515d49 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -4,13 +4,13 @@ pragma solidity 0.8.24; import "forge-std/src/Script.sol"; import "../contracts/L2/DelegateOwner.sol"; import "../contracts/bridge/IBridge.sol"; -import "../test/common/TestMulticall3.sol"; +import "../test/thirdparty/muticall3/Multicall3.sol"; contract SendMessageToDelegateOwner is Script { address public delegateOwner = 0x5995941Df88F30Ac140515AA39832db963E2f863; address public multicall3 = 0xcA11bde05977b3631167028862bE2a173976CA11; address public l1Bridge = 0xd60247c6848B7Ca29eDdF63AA924E53dB6Ddd8EC; - address public testAccount1 = 0x3b7c503e18E197F92028b02Fe52BD674E7289cCa; // owned by Daniel W + address public testAccount1 = 0x3c181965C5cFAE61a9010A283e5e0C1445649810; // owned by Daniel W modifier broadcast() { vm.startBroadcast(); @@ -19,13 +19,13 @@ contract SendMessageToDelegateOwner is Script { } function run() external broadcast { - TestMulticall3.Call3[] memory calls = new TestMulticall3.Call3[](2); - calls[0].target = address(delegateOwner); + Multicall3.Call3[] memory calls = new Multicall3.Call3[](2); + calls[0].target = delegateOwner; calls[0].allowFailure = false; calls[0].callData = abi.encodeCall(DelegateOwner.setAdmin, (0x4757D97449acA795510b9f3152C6a9019A3545c3)); - calls[1].target = address(delegateOwner); + calls[1].target = delegateOwner; calls[1].allowFailure = false; calls[1].callData = abi.encodeCall(DelegateOwner.setAdmin, (testAccount1)); @@ -33,7 +33,7 @@ contract SendMessageToDelegateOwner is Script { txId: 0, // Has to match with DelegateOwner's nextTxId target: multicall3, isDelegateCall: true, - txdata: abi.encodeCall(TestMulticall3.aggregate3, (calls)) + txdata: abi.encodeCall(Multicall3.aggregate3, (calls)) }); IBridge.Message memory message = IBridge.Message({ diff --git a/packages/protocol/test/L2/DelegateOwner.t.sol b/packages/protocol/test/L2/DelegateOwner.t.sol index ef690e99d4..f6dac44860 100644 --- a/packages/protocol/test/L2/DelegateOwner.t.sol +++ b/packages/protocol/test/L2/DelegateOwner.t.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.24; -import "../common/TestMulticall3.sol"; +import "../thirdparty/muticall3/Multicall3.sol"; import "../TaikoTest.sol"; contract Target is EssentialContract { @@ -17,7 +17,7 @@ contract TestDelegateOwner is TaikoTest { SignalService public signalService; AddressManager public addressManager; DelegateOwner public delegateOwner; - TestMulticall3 public multicall; + Multicall3 public multicall; uint64 remoteChainId = uint64(block.chainid + 1); address remoteBridge = vm.addr(0x2000); @@ -30,7 +30,7 @@ contract TestDelegateOwner is TaikoTest { vm.startPrank(owner); - multicall = new TestMulticall3(); + multicall = new Multicall3(); addressManager = AddressManager( deployProxy({ @@ -169,7 +169,7 @@ contract TestDelegateOwner is TaikoTest { }) ); - TestMulticall3.Call3[] memory calls = new TestMulticall3.Call3[](4); + Multicall3.Call3[] memory calls = new Multicall3.Call3[](4); calls[0].target = address(target1); calls[0].allowFailure = false; calls[0].callData = abi.encodeCall(EssentialContract.pause, ()); @@ -191,7 +191,7 @@ contract TestDelegateOwner is TaikoTest { uint64(0), address(multicall), true, // DELEGATECALL - abi.encodeCall(TestMulticall3.aggregate3, (calls)) + abi.encodeCall(Multicall3.aggregate3, (calls)) ) ); diff --git a/packages/protocol/test/common/TestMulticall3.sol b/packages/protocol/test/common/TestMulticall3.sol deleted file mode 100644 index bc0620169b..0000000000 --- a/packages/protocol/test/common/TestMulticall3.sol +++ /dev/null @@ -1,57 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.24; - -/// @title Multicall3 -/// @notice Aggregate results from multiple function calls -/// @dev Multicall & Multicall2 backwards-compatible -/// @dev Aggregate methods are marked `payable` to save 24 gas per call -/// @author Michael Elliot -/// @author Joshua Levine -/// @author Nick Johnson -/// @author Andreas Bigger -/// @author Matt Solomon -contract TestMulticall3 { - struct Call3 { - address target; - bool allowFailure; - bytes callData; - } - - struct Result { - bool success; - bytes returnData; - } - - /// @notice Aggregate calls, ensuring each returns success if required - /// @param calls An array of Call3 structs - /// @return returnData An array of Result structs - function aggregate3(Call3[] calldata calls) - public - payable - returns (Result[] memory returnData) - { - uint256 length = calls.length; - returnData = new Result[](length); - Call3 calldata calli; - for (uint256 i = 0; i < length; ++i) { - Result memory result = returnData[i]; - calli = calls[i]; - (result.success, result.returnData) = calli.target.call(calli.callData); - assembly { - // Revert if the call fails and failure is not allowed - // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` - if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { - // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) - mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) - // set data offset - mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) - // set length of revert string - mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) - // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) - mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) - revert(0x00, 0x64) - } - } - } - } -} diff --git a/packages/protocol/test/thirdparty/muticall3/Multicall3.sol b/packages/protocol/test/thirdparty/muticall3/Multicall3.sol new file mode 100644 index 0000000000..205cc0b7e6 --- /dev/null +++ b/packages/protocol/test/thirdparty/muticall3/Multicall3.sol @@ -0,0 +1,260 @@ +/** + * Submitted for verification at taikoscan.io on 2024-05-30 + */ + +// SPDX-License-Identifier: MIT +pragma solidity 0.8.24; + +/// @title Multicall3 +/// @notice Aggregate results from multiple function calls +/// @dev Multicall & Multicall2 backwards-compatible +/// @dev Aggregate methods are marked `payable` to save 24 gas per call +/// @author Michael Elliot +/// @author Joshua Levine +/// @author Nick Johnson +/// @author Andreas Bigger +/// @author Matt Solomon +contract Multicall3 { + struct Call { + address target; + bytes callData; + } + + struct Call3 { + address target; + bool allowFailure; + bytes callData; + } + + struct Call3Value { + address target; + bool allowFailure; + uint256 value; + bytes callData; + } + + struct Result { + bool success; + bytes returnData; + } + + /// @notice Backwards-compatible call aggregation with Multicall + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return returnData An array of bytes containing the responses + function aggregate(Call[] calldata calls) + public + payable + returns (uint256 blockNumber, bytes[] memory returnData) + { + blockNumber = block.number; + uint256 length = calls.length; + returnData = new bytes[](length); + Call calldata call; + for (uint256 i = 0; i < length;) { + bool success; + call = calls[i]; + (success, returnData[i]) = call.target.call(call.callData); + require(success, "Multicall3: call failed"); + unchecked { + ++i; + } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls without requiring success + /// @param requireSuccess If true, require all calls to succeed + /// @param calls An array of Call structs + /// @return returnData An array of Result structs + function tryAggregate( + bool requireSuccess, + Call[] calldata calls + ) + public + payable + returns (Result[] memory returnData) + { + uint256 length = calls.length; + returnData = new Result[](length); + Call calldata call; + for (uint256 i = 0; i < length;) { + Result memory result = returnData[i]; + call = calls[i]; + (result.success, result.returnData) = call.target.call(call.callData); + if (requireSuccess) require(result.success, "Multicall3: call failed"); + unchecked { + ++i; + } + } + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function tryBlockAndAggregate( + bool requireSuccess, + Call[] calldata calls + ) + public + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) + { + blockNumber = block.number; + blockHash = blockhash(block.number); + returnData = tryAggregate(requireSuccess, calls); + } + + /// @notice Backwards-compatible with Multicall2 + /// @notice Aggregate calls and allow failures using tryAggregate + /// @param calls An array of Call structs + /// @return blockNumber The block number where the calls were executed + /// @return blockHash The hash of the block where the calls were executed + /// @return returnData An array of Result structs + function blockAndAggregate(Call[] calldata calls) + public + payable + returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData) + { + (blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls); + } + + /// @notice Aggregate calls, ensuring each returns success if required + /// @param calls An array of Call3 structs + /// @return returnData An array of Result structs + function aggregate3(Call3[] calldata calls) + public + payable + returns (Result[] memory returnData) + { + uint256 length = calls.length; + returnData = new Result[](length); + Call3 calldata calli; + for (uint256 i = 0; i < length;) { + Result memory result = returnData[i]; + calli = calls[i]; + (result.success, result.returnData) = calli.target.call(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x64) + } + } + unchecked { + ++i; + } + } + } + + /// @notice Aggregate calls with a msg value + /// @notice Reverts if msg.value is less than the sum of the call values + /// @param calls An array of Call3Value structs + /// @return returnData An array of Result structs + function aggregate3Value(Call3Value[] calldata calls) + public + payable + returns (Result[] memory returnData) + { + uint256 valAccumulator; + uint256 length = calls.length; + returnData = new Result[](length); + Call3Value calldata calli; + for (uint256 i = 0; i < length;) { + Result memory result = returnData[i]; + calli = calls[i]; + uint256 val = calli.value; + // Humanity will be a Type V Kardashev Civilization before this overflows - andreas + // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256 + unchecked { + valAccumulator += val; + } + (result.success, result.returnData) = calli.target.call{ value: val }(calli.callData); + assembly { + // Revert if the call fails and failure is not allowed + // `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)` + if iszero(or(calldataload(add(calli, 0x20)), mload(result))) { + // set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)"))) + mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000) + // set data offset + mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020) + // set length of revert string + mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017) + // set revert string: bytes32(abi.encodePacked("Multicall3: call failed")) + mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000) + revert(0x00, 0x84) + } + } + unchecked { + ++i; + } + } + // Finally, make sure the msg.value = SUM(call[0...i].value) + require(msg.value == valAccumulator, "Multicall3: value mismatch"); + } + + /// @notice Returns the block hash for the given block number + /// @param blockNumber The block number + function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) { + blockHash = blockhash(blockNumber); + } + + /// @notice Returns the block number + function getBlockNumber() public view returns (uint256 blockNumber) { + blockNumber = block.number; + } + + /// @notice Returns the block coinbase + function getCurrentBlockCoinbase() public view returns (address coinbase) { + coinbase = block.coinbase; + } + + /// @notice Returns the block difficulty + function getCurrentBlockDifficulty() public view returns (uint256 difficulty) { + difficulty = block.difficulty; + } + + /// @notice Returns the block gas limit + function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) { + gaslimit = block.gaslimit; + } + + /// @notice Returns the block timestamp + function getCurrentBlockTimestamp() public view returns (uint256 timestamp) { + timestamp = block.timestamp; + } + + /// @notice Returns the (ETH) balance of a given address + function getEthBalance(address addr) public view returns (uint256 balance) { + balance = addr.balance; + } + + /// @notice Returns the block hash of the last block + function getLastBlockHash() public view returns (bytes32 blockHash) { + unchecked { + blockHash = blockhash(block.number - 1); + } + } + + /// @notice Gets the base fee of the given block + /// @notice Can revert if the BASEFEE opcode is not implemented by the given chain + function getBasefee() public view returns (uint256 basefee) { + basefee = block.basefee; + } + + /// @notice Returns the chain id + function getChainId() public view returns (uint256 chainid) { + chainid = block.chainid; + } +} From 510304769f660fd0d7c31e52b42fbf4abb795db9 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:26:18 +0800 Subject: [PATCH 06/14] Update .eslintignore --- packages/protocol/.eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/protocol/.eslintignore b/packages/protocol/.eslintignore index dcb9ae39ee..cdbbc4fbb4 100644 --- a/packages/protocol/.eslintignore +++ b/packages/protocol/.eslintignore @@ -3,4 +3,5 @@ artifacts cache coverage lib +test/thirdparty/ contracts/automata-attestation/ \ No newline at end of file From cf9ac1d7dff1abda1c03d5e0a02b4a9a102bc970 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:27:18 +0800 Subject: [PATCH 07/14] more --- packages/protocol/.eslintignore | 2 +- packages/protocol/.solhintignore | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/protocol/.eslintignore b/packages/protocol/.eslintignore index cdbbc4fbb4..dcdd38e480 100644 --- a/packages/protocol/.eslintignore +++ b/packages/protocol/.eslintignore @@ -3,5 +3,5 @@ artifacts cache coverage lib -test/thirdparty/ +contracts/test/thirdparty/ contracts/automata-attestation/ \ No newline at end of file diff --git a/packages/protocol/.solhintignore b/packages/protocol/.solhintignore index b98f25593a..368bfb6661 100644 --- a/packages/protocol/.solhintignore +++ b/packages/protocol/.solhintignore @@ -3,5 +3,6 @@ lib/ contracts/test/TestLibRLPReader.sol **/contracts/thirdparty/**/*.sol /contracts/automata-attestation/ +test/thirdparty/** test/GasComparison.t.sol test/TestLn.sol \ No newline at end of file From 51c34e083868bd8376fa8b0599fccf51d65a98e5 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:36:57 +0800 Subject: [PATCH 08/14] Update SendMessageToDelegateOwner.s.sol --- packages/protocol/script/SendMessageToDelegateOwner.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index 6537515d49..ea6173be97 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -47,7 +47,7 @@ contract SendMessageToDelegateOwner is Script { destOwner: delegateOwner, to: delegateOwner, value: 0, - data: abi.encode(dcall) + data: abi.encodeCall(DelegateOwner.onMessageInvocation, abi.encode(dcall)) }); IBridge(l1Bridge).sendMessage(message); From 3b7ec4d8e56ebe0db10a7cccb56d3f3223afbef1 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:42:34 +0800 Subject: [PATCH 09/14] Update DelegateOwner.sol --- packages/protocol/contracts/L2/DelegateOwner.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/protocol/contracts/L2/DelegateOwner.sol b/packages/protocol/contracts/L2/DelegateOwner.sol index 6d2a6d4cf5..7149d1d47a 100644 --- a/packages/protocol/contracts/L2/DelegateOwner.sol +++ b/packages/protocol/contracts/L2/DelegateOwner.sol @@ -38,9 +38,9 @@ contract DelegateOwner is EssentialContract, IMessageInvocable { /// @param txId The transaction ID. /// @param target The target address. /// @param isDelegateCall True if the call is a `delegatecall`. - /// @param selector The function selector. + /// @param txdata The transaction data. event MessageInvoked( - uint64 indexed txId, address indexed target, bool isDelegateCall, bytes4 indexed selector + uint64 indexed txId, address indexed target, bool isDelegateCall, bytes txdata ); /// @notice Emitted when the admin has been changed. @@ -133,7 +133,7 @@ contract DelegateOwner is EssentialContract, IMessageInvocable { : call.target.call{ value: msg.value }(call.txdata); if (!success) LibBytes.revertWithExtractedError(result); - emit MessageInvoked(call.txId, call.target, call.isDelegateCall, bytes4(call.txdata)); + emit MessageInvoked(call.txId, call.target, call.isDelegateCall, call.txdata); } function _isAdminOrRemoteOwner(address _sender) private view returns (bool) { From 931991af118264011e5cc46031d0290a6470342f Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:46:12 +0800 Subject: [PATCH 10/14] Update DelegateOwner.sol --- packages/protocol/contracts/L2/DelegateOwner.sol | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/protocol/contracts/L2/DelegateOwner.sol b/packages/protocol/contracts/L2/DelegateOwner.sol index 7149d1d47a..dc5cfd294d 100644 --- a/packages/protocol/contracts/L2/DelegateOwner.sol +++ b/packages/protocol/contracts/L2/DelegateOwner.sol @@ -123,7 +123,13 @@ contract DelegateOwner is EssentialContract, IMessageInvocable { function _invokeCall(bytes calldata _data, bool _verifyTxId) private { Call memory call = abi.decode(_data, (Call)); - if (_verifyTxId && call.txId != nextTxId++) revert DO_INVALID_TX_ID(); + if (call.txId == 0) { + call.txId = nextTxId; + } else if (_verifyTxId && call.txId != nextTxId) { + revert DO_INVALID_TX_ID(); + } + + nextTxId += 1; // By design, the target must be a contract address if the txdata is not empty if (call.txdata.length != 0 && !Address.isContract(call.target)) revert DO_INVALID_TARGET(); From d286f98f763e03db0b781e61cc73528a119ff2fd Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:53:13 +0800 Subject: [PATCH 11/14] more --- packages/protocol/deployments/mainnet-contract-logs-L2.md | 2 +- packages/protocol/script/SendMessageToDelegateOwner.s.sol | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/protocol/deployments/mainnet-contract-logs-L2.md b/packages/protocol/deployments/mainnet-contract-logs-L2.md index ad9bb2645c..a255de1dfe 100644 --- a/packages/protocol/deployments/mainnet-contract-logs-L2.md +++ b/packages/protocol/deployments/mainnet-contract-logs-L2.md @@ -116,7 +116,7 @@ #### delegate_owner - proxy: `0x5995941Df88F30Ac140515AA39832db963E2f863` -- impl: `0x2D2F4C692a7940e6Cc8e261692a5e20955BAb311` +- impl: `0x1f0511cDae2fbfD93563469dA02b82dEd320C8Bd` - admin: `0x3c181965C5cFAE61a9010A283e5e0C1445649810` // owned by Daniel W - remoteOwner: `0x3c181965C5cFAE61a9010A283e5e0C1445649810` // owned by Daniel W - todo: diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index ea6173be97..7096ba6b10 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -8,6 +8,7 @@ import "../test/thirdparty/muticall3/Multicall3.sol"; contract SendMessageToDelegateOwner is Script { address public delegateOwner = 0x5995941Df88F30Ac140515AA39832db963E2f863; + address public delegateOwnerImpl = 0x1f0511cDae2fbfD93563469dA02b82dEd320C8Bd; address public multicall3 = 0xcA11bde05977b3631167028862bE2a173976CA11; address public l1Bridge = 0xd60247c6848B7Ca29eDdF63AA924E53dB6Ddd8EC; address public testAccount1 = 0x3c181965C5cFAE61a9010A283e5e0C1445649810; // owned by Daniel W @@ -27,10 +28,10 @@ contract SendMessageToDelegateOwner is Script { calls[1].target = delegateOwner; calls[1].allowFailure = false; - calls[1].callData = abi.encodeCall(DelegateOwner.setAdmin, (testAccount1)); + calls[1].callData = abi.encodeCall(UUPSUpgradeable.upgradeTo, (delegateOwnerImpl)); DelegateOwner.Call memory dcall = DelegateOwner.Call({ - txId: 0, // Has to match with DelegateOwner's nextTxId + txId: 1, // Has to match with DelegateOwner's nextTxId target: multicall3, isDelegateCall: true, txdata: abi.encodeCall(Multicall3.aggregate3, (calls)) From 9e355f72477721e032e1d4e51897bb2458c518a5 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:56:28 +0800 Subject: [PATCH 12/14] Update SendMessageToDelegateOwner.s.sol --- packages/protocol/script/SendMessageToDelegateOwner.s.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index 7096ba6b10..0afaccd0f8 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -31,7 +31,7 @@ contract SendMessageToDelegateOwner is Script { calls[1].callData = abi.encodeCall(UUPSUpgradeable.upgradeTo, (delegateOwnerImpl)); DelegateOwner.Call memory dcall = DelegateOwner.Call({ - txId: 1, // Has to match with DelegateOwner's nextTxId + txId: 1, // Has to match with DelegateOwner's nextTxId or 0 target: multicall3, isDelegateCall: true, txdata: abi.encodeCall(Multicall3.aggregate3, (calls)) From f5b8299224bc50ca1c60b41e5e466d0f391adb17 Mon Sep 17 00:00:00 2001 From: Daniel Wang <99078276+dantaik@users.noreply.github.com> Date: Fri, 19 Jul 2024 15:01:03 +0800 Subject: [PATCH 13/14] Update packages/protocol/.solhintignore --- packages/protocol/.solhintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/protocol/.solhintignore b/packages/protocol/.solhintignore index 368bfb6661..9597bc92c5 100644 --- a/packages/protocol/.solhintignore +++ b/packages/protocol/.solhintignore @@ -3,6 +3,6 @@ lib/ contracts/test/TestLibRLPReader.sol **/contracts/thirdparty/**/*.sol /contracts/automata-attestation/ -test/thirdparty/** +test/thirdparty/ test/GasComparison.t.sol test/TestLn.sol \ No newline at end of file From da508350f0cf10d6bebf7663e6c903f70001f138 Mon Sep 17 00:00:00 2001 From: Daniel Wang Date: Fri, 19 Jul 2024 14:57:28 +0800 Subject: [PATCH 14/14] Update SendMessageToDelegateOwner.s.sol --- packages/protocol/script/SendMessageToDelegateOwner.s.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/protocol/script/SendMessageToDelegateOwner.s.sol b/packages/protocol/script/SendMessageToDelegateOwner.s.sol index 0afaccd0f8..66bed56a7c 100644 --- a/packages/protocol/script/SendMessageToDelegateOwner.s.sol +++ b/packages/protocol/script/SendMessageToDelegateOwner.s.sol @@ -37,6 +37,7 @@ contract SendMessageToDelegateOwner is Script { txdata: abi.encodeCall(Multicall3.aggregate3, (calls)) }); + // Use https://bridge.taiko.xyz/relayer to manually trigger the message if necessary. IBridge.Message memory message = IBridge.Message({ id: 0, fee: 0,