Skip to content

Commit

Permalink
Adds scroll L2EP contracts and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-de-leon-cll authored and mohamed-mehany committed Dec 1, 2023
1 parent 9bd3ecb commit ab23752
Show file tree
Hide file tree
Showing 14 changed files with 2,046 additions and 2 deletions.
1 change: 1 addition & 0 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@
},
"dependencies": {
"@eth-optimism/contracts": "0.5.37",
"@scroll-tech/contracts": "0.1.0",
"@openzeppelin/contracts": "4.9.3",
"@openzeppelin/contracts-upgradeable": "4.9.3"
}
Expand Down
17 changes: 15 additions & 2 deletions contracts/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ScrollSequencerUptimeFeedInterface {
function updateStatus(bool status, uint64 timestamp) external;
}
87 changes: 87 additions & 0 deletions contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainForwarder.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol";
// solhint-disable-next-line no-unused-import
import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol";

/* ./dev dependencies - to be moved from ./dev after audit */
import {CrossDomainForwarder} from "../CrossDomainForwarder.sol";
import {CrossDomainOwnable} from "../CrossDomainOwnable.sol";

import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol";
import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";

/**
* @title ScrollCrossDomainForwarder - L1 xDomain account representation
* @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination.
* @dev Any other L2 contract which uses this contract's address as a privileged position,
* can be considered to be owned by the `l1Owner`
*/
contract ScrollCrossDomainForwarder is TypeAndVersionInterface, CrossDomainForwarder {
// solhint-disable-next-line chainlink-solidity/prefix-immutable-variables-with-i
IScrollMessenger private immutable SCROLL_CROSS_DOMAIN_MESSENGER;

/**
* @notice creates a new Scroll xDomain Forwarder contract
* @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address
* @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn
*/
constructor(IScrollMessenger crossDomainMessengerAddr, address l1OwnerAddr) CrossDomainOwnable(l1OwnerAddr) {
// solhint-disable-next-line custom-errors
require(address(crossDomainMessengerAddr) != address(0), "Invalid xDomain Messenger address");
SCROLL_CROSS_DOMAIN_MESSENGER = crossDomainMessengerAddr;
}

/**
* @notice versions:
*
* - ScrollCrossDomainForwarder 1.0.0: initial release
*
* @inheritdoc TypeAndVersionInterface
*/
function typeAndVersion() external pure virtual override returns (string memory) {
return "ScrollCrossDomainForwarder 1.0.0";
}

/**
* @dev forwarded only if L2 Messenger calls with `xDomainMessageSender` being the L1 owner address
* @inheritdoc ForwarderInterface
*/
function forward(address target, bytes memory data) external virtual override onlyL1Owner {
Address.functionCall(target, data, "Forwarder call reverted");
}

/**
* @notice This is always the address of the Scroll Cross Domain Messenger contract
*/
function crossDomainMessenger() public view returns (address) {
return address(SCROLL_CROSS_DOMAIN_MESSENGER);
}

/**
* @notice The call MUST come from the L1 owner (via cross-chain message.) Reverts otherwise.
*/
modifier onlyL1Owner() override {
// solhint-disable-next-line custom-errors
require(msg.sender == crossDomainMessenger(), "Sender is not the L2 messenger");
// solhint-disable-next-line custom-errors
require(
IScrollMessenger(crossDomainMessenger()).xDomainMessageSender() == l1Owner(),
"xDomain sender is not the L1 owner"
);
_;
}

/**
* @notice The call MUST come from the proposed L1 owner (via cross-chain message.) Reverts otherwise.
*/
modifier onlyProposedL1Owner() override {
address messenger = crossDomainMessenger();
// solhint-disable-next-line custom-errors
require(msg.sender == messenger, "Sender is not the L2 messenger");
// solhint-disable-next-line custom-errors
require(IScrollMessenger(messenger).xDomainMessageSender() == s_l1PendingOwner, "Must be proposed L1 owner");
_;
}
}
71 changes: 71 additions & 0 deletions contracts/src/v0.8/l2ep/dev/scroll/ScrollCrossDomainGovernor.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {DelegateForwarderInterface} from "../interfaces/DelegateForwarderInterface.sol";
// solhint-disable-next-line no-unused-import
import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol";

import {ScrollCrossDomainForwarder} from "./ScrollCrossDomainForwarder.sol";

import {IScrollMessenger} from "@scroll-tech/contracts/libraries/IScrollMessenger.sol";
import {Address} from "../../../vendor/openzeppelin-solidity/v4.7.3/contracts/utils/Address.sol";

/**
* @title ScrollCrossDomainGovernor - L1 xDomain account representation (with delegatecall support) for Scroll
* @notice L2 Contract which receives messages from a specific L1 address and transparently forwards them to the destination.
* @dev Any other L2 contract which uses this contract's address as a privileged position,
* can be considered to be simultaneously owned by the `l1Owner` and L2 `owner`
*/
contract ScrollCrossDomainGovernor is DelegateForwarderInterface, ScrollCrossDomainForwarder {
/**
* @notice creates a new Scroll xDomain Forwarder contract
* @param crossDomainMessengerAddr the xDomain bridge messenger (Scroll bridge L2) contract address
* @param l1OwnerAddr the L1 owner address that will be allowed to call the forward fn
* @dev Empty constructor required due to inheriting from abstract contract CrossDomainForwarder
*/
constructor(
IScrollMessenger crossDomainMessengerAddr,
address l1OwnerAddr
) ScrollCrossDomainForwarder(crossDomainMessengerAddr, l1OwnerAddr) {}

/**
* @notice versions:
*
* - ScrollCrossDomainGovernor 1.0.0: initial release
*/
function typeAndVersion() external pure virtual override returns (string memory) {
return "ScrollCrossDomainGovernor 1.0.0";
}

/**
* @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner
* @inheritdoc ForwarderInterface
*/
function forward(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner {
Address.functionCall(target, data, "Governor call reverted");
}

/**
* @dev forwarded only if L2 Messenger calls with `msg.sender` being the L1 owner address, or called by the L2 owner
* @inheritdoc DelegateForwarderInterface
*/
function forwardDelegate(address target, bytes memory data) external override onlyLocalOrCrossDomainOwner {
Address.functionDelegateCall(target, data, "Governor delegatecall reverted");
}

/**
* @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise.
*/
modifier onlyLocalOrCrossDomainOwner() {
address messenger = crossDomainMessenger();
// 1. The delegatecall MUST come from either the L1 owner (via cross-chain message) or the L2 owner
// solhint-disable-next-line custom-errors
require(msg.sender == messenger || msg.sender == owner(), "Sender is not the L2 messenger or owner");
// 2. The L2 Messenger's caller MUST be the L1 Owner
if (msg.sender == messenger) {
// solhint-disable-next-line custom-errors
require(IScrollMessenger(messenger).xDomainMessageSender() == l1Owner(), "xDomain sender is not the L1 owner");
}
_;
}
}
Loading

0 comments on commit ab23752

Please sign in to comment.