Skip to content

Commit

Permalink
feat: add cross domain message context function (ethereum-optimism#12477
Browse files Browse the repository at this point in the history
)

* 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 <agusnduha@gmail.com>

* fix: remove superchain erc20 base (#70)

* refactor: update isuperchainweth (#71)


---------

Co-authored-by: agusduha <agusnduha@gmail.com>

* 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 <ng@defi.sucks>
Co-authored-by: 0xParticle <particle@defi.sucks>
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 <agusnduha@gmail.com>
Co-authored-by: 0xng <ng@defi.sucks>
Co-authored-by: 0xParticle <particle@defi.sucks>
Co-authored-by: gotzenx <78360669+gotzenx@users.noreply.github.com>
  • Loading branch information
6 people authored Oct 17, 2024
1 parent 3af1faf commit 71ca0f1
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 26 deletions.
8 changes: 4 additions & 4 deletions packages/contracts-bedrock/semver-lock.json
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@
"sourceCodeHash": "0xd08a2e6514dbd44e16aa312a1b27b2841a9eab5622cbd05a39c30f543fad673c"
},
"src/L2/L2ToL2CrossDomainMessenger.sol": {
"initCodeHash": "0x6f19eb8ff0950156b65cd92872240c0153ac5f3b6f0861d57bf561fdbcacbeac",
"sourceCodeHash": "0xfea53344596d735eff3be945ed1300dc75a6f8b7b2c02c0043af5b0036f5f239"
"initCodeHash": "0xf760d814018281b36d9a6a0ab16a23348effb33cf0ab299e3022b59283e46160",
"sourceCodeHash": "0xe8d99e4702d90814089c4a80e259c891a95f6d4750c7220fc6b2672c26ef2700"
},
"src/L2/OptimismSuperchainERC20.sol": {
"initCodeHash": "0xd5c84e45746fd741d541a917ddc1cc0c7043c6b21d5c18040d4bc999d6a7b2db",
Expand All @@ -128,8 +128,8 @@
"sourceCodeHash": "0x75d061633a141af11a19b86e599a1725dfae8d245dcddfb6bb244a50d5e53f96"
},
"src/L2/SuperchainTokenBridge.sol": {
"initCodeHash": "0x07fc1d495928d9c13bd945a049d17e1d105d01c2082a7719e5d18cbc0e1c7d9e",
"sourceCodeHash": "0xaf2458e48dcadcafa8940cde7368549eae2280eef91247600d864ddac20f5d82"
"initCodeHash": "0xef7590c30630a75f105384e339e52758569c25a5aa0a5934c521e004b8f86220",
"sourceCodeHash": "0x4f539e9d9096d31e861982b8f751fa2d7de0849590523375cf92e175294d1036"
},
"src/L2/SuperchainWETH.sol": {
"initCodeHash": "0x50f6ea9bfe650fcf792e98e44b1bf66c036fd0e6d4b753da680253d7d8609816",
Expand Down
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
14 changes: 12 additions & 2 deletions packages/contracts-bedrock/src/L2/L2ToL2CrossDomainMessenger.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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).
Expand Down
12 changes: 5 additions & 7 deletions packages/contracts-bedrock/src/L2/SuperchainTokenBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
20 changes: 7 additions & 13 deletions packages/contracts-bedrock/test/L2/SuperchainTokenBridge.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -139,18 +139,19 @@ contract SuperchainTokenBridgeTest is Bridge_Initializer {
function testFuzz_relayERC20_notCrossDomainSender_reverts(
address _token,
address _crossDomainMessageSender,
uint256 _source,
address _to,
uint256 _amount
)
public
{
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
Expand All @@ -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
Expand Down

0 comments on commit 71ca0f1

Please sign in to comment.