From 71ca0f17b4aa43f33480cc88ded8f05c9c3ab5f7 Mon Sep 17 00:00:00 2001 From: Disco <131301107+0xDiscotech@users.noreply.github.com> Date: Thu, 17 Oct 2024 19:01:44 -0300 Subject: [PATCH] feat: add cross domain message context function (#12477) * feat: add superchain erc20 bridge (#61) * feat: add superchain erc20 bridge * fix: interfaces and versions * refactor: optimism superchain erc20 redesign (#62) * refactor: use oz upgradeable erc20 as dependency * chore: update interfaces * fix: tests based on changes * refactor: remove op as dependency * feat: add check for supererc20 bridge on modifier * chore: update tests and interfaces * chore: update stack vars name on test * chore: remove empty gitmodules file * chore: update superchain weth errors * test: add superchain erc20 bridge tests (#65) * test: add superchain erc20 bridge tests * test: add optimism superchain erc20 beacon tests * test: remove unnecessary test * test: tests fixes * test: tests fixes * chore: update missing bridge on natspec (#69) * chore: update missing bridge on natspec * fix: natspecs --------- Co-authored-by: agusduha * fix: remove superchain erc20 base (#70) * refactor: update isuperchainweth (#71) --------- Co-authored-by: agusduha * feat: rename mint/burn and add SuperchainERC20 (#74) * refactor: rename mint and burn functions on superchain erc20 * chore: rename optimism superchain erc20 to superchain erc20 * feat: create optimism superchain erc20 contract * chore: update natspec and errors * fix: superchain erc20 tests * refactor: make superchain erc20 abstract * refactor: move storage and erc20 metadata functions to implementation * chore: update interfaces * chore: update superchain erc20 events * fix: tests * fix: natspecs * fix: add semmver lock and snapshots * fix: remove unused imports * fix: natspecs --------- Co-authored-by: 0xDiscotech <131301107+0xDiscotech@users.noreply.github.com> * fix: refactor zero check (#76) * fix: pre pr * fix: semver natspec check failure (#79) * fix: semver natspec check failure * fix: ignore mock contracts in semver natspec script * fix: error message * feat: add crosschain erc20 interface (#80) * feat: add crosschain erc20 interface * fix: refactor interfaces * fix: superchain bridge natspec (#83) * fix: superchain weth natspec (#84) Co-authored-by: 0xng Co-authored-by: 0xParticle Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com> * fix: stop inheriting superchain interfaces (#85) * fix: stop inheriting superchain interfaces * fix: move events and erros into the implementation * fix: make superchainERC20 inherits from crosschainERC20 * fix: superchain bridge rename (#86) * fix: fee vault compiler error (#87) * fix: remove unused imports * fix: refactor common errors (#90) * fix: refactor common errors * fix: remove unused version * feat: add cross domain context function * fix: reuse unauthorized error (#92) * fix: superchain erc20 factory conflicts * fix: rename crosschain functions (#94) * chore: run pre-pr * chore: run pre-pr * fix: mocked calls on tests * feat: add cross domain message context function (#98) ---- Co-Authored-by: AgusDuha <81362284+agusduha@users.noreply.github.com> --------- Co-authored-by: AgusDuha <81362284+agusduha@users.noreply.github.com> Co-authored-by: agusduha Co-authored-by: 0xng Co-authored-by: 0xParticle Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com> --- packages/contracts-bedrock/semver-lock.json | 8 ++--- .../abi/L2ToL2CrossDomainMessenger.json | 18 +++++++++++ .../src/L2/L2ToL2CrossDomainMessenger.sol | 14 +++++++-- .../src/L2/SuperchainTokenBridge.sol | 12 ++++---- .../IL2ToL2CrossDomainMessenger.sol | 5 ++++ .../test/L2/L2ToL2CrossDomainMessenger.t.sol | 30 +++++++++++++++++++ .../test/L2/SuperchainTokenBridge.t.sol | 20 +++++-------- 7 files changed, 81 insertions(+), 26 deletions(-) diff --git a/packages/contracts-bedrock/semver-lock.json b/packages/contracts-bedrock/semver-lock.json index 61a067d80987..476c37fc2cf6 100644 --- a/packages/contracts-bedrock/semver-lock.json +++ b/packages/contracts-bedrock/semver-lock.json @@ -104,8 +104,8 @@ "sourceCodeHash": "0xd08a2e6514dbd44e16aa312a1b27b2841a9eab5622cbd05a39c30f543fad673c" }, "src/L2/L2ToL2CrossDomainMessenger.sol": { - "initCodeHash": "0x6f19eb8ff0950156b65cd92872240c0153ac5f3b6f0861d57bf561fdbcacbeac", - "sourceCodeHash": "0xfea53344596d735eff3be945ed1300dc75a6f8b7b2c02c0043af5b0036f5f239" + "initCodeHash": "0xf760d814018281b36d9a6a0ab16a23348effb33cf0ab299e3022b59283e46160", + "sourceCodeHash": "0xe8d99e4702d90814089c4a80e259c891a95f6d4750c7220fc6b2672c26ef2700" }, "src/L2/OptimismSuperchainERC20.sol": { "initCodeHash": "0xd5c84e45746fd741d541a917ddc1cc0c7043c6b21d5c18040d4bc999d6a7b2db", @@ -128,8 +128,8 @@ "sourceCodeHash": "0x75d061633a141af11a19b86e599a1725dfae8d245dcddfb6bb244a50d5e53f96" }, "src/L2/SuperchainTokenBridge.sol": { - "initCodeHash": "0x07fc1d495928d9c13bd945a049d17e1d105d01c2082a7719e5d18cbc0e1c7d9e", - "sourceCodeHash": "0xaf2458e48dcadcafa8940cde7368549eae2280eef91247600d864ddac20f5d82" + "initCodeHash": "0xef7590c30630a75f105384e339e52758569c25a5aa0a5934c521e004b8f86220", + "sourceCodeHash": "0x4f539e9d9096d31e861982b8f751fa2d7de0849590523375cf92e175294d1036" }, "src/L2/SuperchainWETH.sol": { "initCodeHash": "0x50f6ea9bfe650fcf792e98e44b1bf66c036fd0e6d4b753da680253d7d8609816", diff --git a/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json b/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json index 2676f90b0491..f6d2692bae53 100644 --- a/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json +++ b/packages/contracts-bedrock/snapshots/abi/L2ToL2CrossDomainMessenger.json @@ -1,4 +1,22 @@ [ + { + "inputs": [], + "name": "crossDomainMessageContext", + "outputs": [ + { + "internalType": "address", + "name": "sender_", + "type": "address" + }, + { + "internalType": "uint256", + "name": "source_", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, { "inputs": [], "name": "crossDomainMessageSender", diff --git a/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol index 4c1ffc38760f..0d7b46080fc9 100644 --- a/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol @@ -64,8 +64,8 @@ contract L2ToL2CrossDomainMessenger is IL2ToL2CrossDomainMessenger, ISemver, Tra uint16 public constant messageVersion = uint16(0); /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.7 - string public constant version = "1.0.0-beta.7"; + /// @custom:semver 1.0.0-beta.8 + string public constant version = "1.0.0-beta.8"; /// @notice Mapping of message hashes to boolean receipt values. Note that a message will only be present in this /// mapping if it has successfully been relayed on this chain, and can therefore not be relayed again. @@ -114,6 +114,16 @@ contract L2ToL2CrossDomainMessenger is IL2ToL2CrossDomainMessenger, ISemver, Tra } } + /// @notice Retrieves the context of the current cross domain message. If not entered, reverts. + /// @return sender_ Address of the sender of the current cross domain message. + /// @return source_ Chain ID of the source of the current cross domain message. + function crossDomainMessageContext() external view onlyEntered returns (address sender_, uint256 source_) { + assembly { + sender_ := tload(CROSS_DOMAIN_MESSAGE_SENDER_SLOT) + source_ := tload(CROSS_DOMAIN_MESSAGE_SOURCE_SLOT) + } + } + /// @notice Sends a message to some target address on a destination chain. Note that if the call always reverts, /// then the message will be unrelayable and any ETH sent will be permanently locked. The same will occur /// if the target on the other chain is considered unsafe (see the _isUnsafeTarget() function). diff --git a/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol b/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol index 1dcc233638f5..284beb79ec0e 100644 --- a/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol +++ b/packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol @@ -42,8 +42,8 @@ contract SuperchainTokenBridge { address internal constant MESSENGER = Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER; /// @notice Semantic version. - /// @custom:semver 1.0.0-beta.1 - string public constant version = "1.0.0-beta.1"; + /// @custom:semver 1.0.0-beta.2 + string public constant version = "1.0.0-beta.2"; /// @notice Sends tokens to a target address on another chain. /// @dev Tokens are burned on the source chain. @@ -80,11 +80,9 @@ contract SuperchainTokenBridge { function relayERC20(address _token, address _from, address _to, uint256 _amount) external { if (msg.sender != MESSENGER) revert Unauthorized(); - if (IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageSender() != address(this)) { - revert InvalidCrossDomainSender(); - } - - uint256 source = IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageSource(); + (address crossDomainMessageSender, uint256 source) = + IL2ToL2CrossDomainMessenger(MESSENGER).crossDomainMessageContext(); + if (crossDomainMessageSender != address(this)) revert InvalidCrossDomainSender(); ISuperchainERC20(_token).crosschainMint(_to, _amount); diff --git a/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol b/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol index 2b5b945dec73..f8a803d78be8 100644 --- a/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol +++ b/packages/contracts-bedrock/src/L2/interfaces/IL2ToL2CrossDomainMessenger.sol @@ -27,6 +27,11 @@ interface IL2ToL2CrossDomainMessenger { /// @return source_ Chain ID of the source of the current cross domain message. function crossDomainMessageSource() external view returns (uint256 source_); + /// @notice Retrieves the context of the current cross domain message. If not entered, reverts. + /// @return sender_ Address of the sender of the current cross domain message. + /// @return source_ Chain ID of the source of the current cross domain message. + function crossDomainMessageContext() external view returns (address sender_, uint256 source_); + /// @notice Sends a message to some target address on a destination chain. Note that if the call /// always reverts, then the message will be unrelayable, and any ETH sent will be /// permanently locked. The same will occur if the target on the other chain is diff --git a/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol b/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol index f5ff43c832ca..e0149e8aab78 100644 --- a/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol +++ b/packages/contracts-bedrock/test/L2/L2ToL2CrossDomainMessenger.t.sol @@ -744,4 +744,34 @@ contract L2ToL2CrossDomainMessengerTest is Test { // Call `crossDomainMessageSource` to provoke revert l2ToL2CrossDomainMessenger.crossDomainMessageSource(); } + + /// @dev Tests that the `crossDomainMessageContext` function returns the correct value. + function testFuzz_crossDomainMessageContext_succeeds(address _sender, uint256 _source) external { + // Set `entered` to non-zero value to prevent NotEntered revert + l2ToL2CrossDomainMessenger.setEntered(1); + // Ensure that the contract is now entered + assertEq(l2ToL2CrossDomainMessenger.entered(), true); + + // Set cross domain message source in the transient storage + l2ToL2CrossDomainMessenger.setCrossDomainMessageSender(_sender); + l2ToL2CrossDomainMessenger.setCrossDomainMessageSource(_source); + + // Check that the `crossDomainMessageContext` function returns the correct value + (address crossDomainContextSender, uint256 crossDomainContextSource) = + l2ToL2CrossDomainMessenger.crossDomainMessageContext(); + assertEq(crossDomainContextSender, _sender); + assertEq(crossDomainContextSource, _source); + } + + /// @dev Tests that the `crossDomainMessageContext` function reverts when not entered. + function test_crossDomainMessageContext_notEntered_reverts() external { + // Ensure that the contract is not entered + assertEq(l2ToL2CrossDomainMessenger.entered(), false); + + // Expect a revert with the NotEntered selector + vm.expectRevert(NotEntered.selector); + + // Call `crossDomainMessageContext` to provoke revert + l2ToL2CrossDomainMessenger.crossDomainMessageContext(); + } } diff --git a/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol b/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol index 8367112a5942..e40904324d0c 100644 --- a/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol +++ b/packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol @@ -139,6 +139,7 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { function testFuzz_relayERC20_notCrossDomainSender_reverts( address _token, address _crossDomainMessageSender, + uint256 _source, address _to, uint256 _amount ) @@ -146,11 +147,11 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { { vm.assume(_crossDomainMessageSender != address(superchainTokenBridge)); - // Mock the call over the `crossDomainMessageSender` function setting a wrong sender + // Mock the call over the `crossDomainMessageContext` function setting a wrong sender vm.mockCall( Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, - abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageSender.selector), - abi.encode(_crossDomainMessageSender) + abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageContext.selector), + abi.encode(_crossDomainMessageSender, _source) ); // Expect the revert with `InvalidCrossDomainSender` selector @@ -165,18 +166,11 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer { function testFuzz_relayERC20_succeeds(address _from, address _to, uint256 _amount, uint256 _source) public { vm.assume(_to != ZERO_ADDRESS); - // Mock the call over the `crossDomainMessageSender` function setting the same address as value + // Mock the call over the `crossDomainMessageContext` function setting the same address as value _mockAndExpect( Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, - abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageSender.selector), - abi.encode(address(superchainTokenBridge)) - ); - - // Mock the call over the `crossDomainMessageSource` function setting the source chain ID as value - _mockAndExpect( - Predeploys.L2_TO_L2_CROSS_DOMAIN_MESSENGER, - abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageSource.selector), - abi.encode(_source) + abi.encodeWithSelector(IL2ToL2CrossDomainMessenger.crossDomainMessageContext.selector), + abi.encode(address(superchainTokenBridge), _source) ); // Get the total supply and balance of `_to` before the relay to compare later on the assertions