Skip to content

Commit

Permalink
[DEPLOY-178]: Adds Scroll L2EP Contracts (#11405)
Browse files Browse the repository at this point in the history
* Adds scroll L2EP contracts and tests

* fixes comments, adds fixed solidity compiler version, and adds scroll tech contracts as a dev dependency

* renames SCROLL_CROSS_DOMAIN_MESSENGER to i_SCROLL_CROSS_DOMAIN_MESSENGER for solhint

* removes unnecessary solhint disable rule

* moves scroll mocks from tests folder to l2ep folder

* resolve solhint errors for scroll

* proposed restructure to reduce inheritance

* removes extraneous comments from scroll contracts and refactors typeAndVersion

* use named parameters in mappings for scroll contracts

* removes extraneous empty comments from scroll contracts (again)

* removes unnecessary comment from scroll cross domain governor

* adds minor formatting updates to scroll mocks

* adds onlyL1Owner modifier back to ScrollCrossDomainGovernor

* adds style and formatting improvements

* adds formatting updates

* refactors scroll sequencer uptime feed to reduce gas and updates test suites

---------

Co-authored-by: Rens Rooimans <[email protected]>
  • Loading branch information
chris-de-leon-cll and RensR authored Dec 12, 2023
1 parent dfc62cc commit 82faf5d
Show file tree
Hide file tree
Showing 15 changed files with 1,961 additions and 3 deletions.
2 changes: 1 addition & 1 deletion contracts/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ test = 'src/v0.8/automation/test'
optimizer_runs = 1000000
src = 'src/v0.8/l2ep'
test = 'src/v0.8/l2ep/test'

solc_version = '0.8.19'

[profile.llo-feeds]
optimizer_runs = 1000000
Expand Down
1 change: 1 addition & 0 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@nomiclabs/hardhat-waffle": "2.0.6",
"@openzeppelin/hardhat-upgrades": "1.28.0",
"@scroll-tech/contracts": "0.1.0",
"@openzeppelin/test-helpers": "^0.5.16",
"@typechain/ethers-v5": "^7.2.0",
"@typechain/hardhat": "^7.0.0",
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.19;

interface ScrollSequencerUptimeFeedInterface {
function updateStatus(bool status, uint64 timestamp) external;
}
65 changes: 65 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,65 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import {TypeAndVersionInterface} from "../../../interfaces/TypeAndVersionInterface.sol";
import {ForwarderInterface} from "../interfaces/ForwarderInterface.sol";

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/all-caps-constant-storage-variables
string public constant override typeAndVersion = "ScrollCrossDomainForwarder 1.0.0";

address internal immutable i_scrollCrossDomainMessenger;

/// @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");
i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr);
}

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

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

/// @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 == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger");
// solhint-disable-next-line custom-errors
require(
IScrollMessenger(i_scrollCrossDomainMessenger).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 {
// solhint-disable-next-line custom-errors
require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger");
// solhint-disable-next-line custom-errors
require(
IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner,
"Must be proposed L1 owner"
);
_;
}
}
92 changes: 92 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,92 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

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

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 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, TypeAndVersionInterface, CrossDomainForwarder {
// solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables
string public constant override typeAndVersion = "ScrollCrossDomainGovernor 1.0.0";

address internal immutable i_scrollCrossDomainMessenger;

/// @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");
i_scrollCrossDomainMessenger = address(crossDomainMessengerAddr);
}

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

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

/// @notice The address of the Scroll Cross Domain Messenger contract
function crossDomainMessenger() external view returns (address) {
return address(i_scrollCrossDomainMessenger);
}

/// @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 == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger");
// solhint-disable-next-line custom-errors
require(
IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == l1Owner(),
"xDomain sender is not the L1 owner"
);
_;
}

/// @notice The call MUST come from either the L1 owner (via cross-chain message) or the L2 owner. Reverts otherwise.
modifier onlyLocalOrCrossDomainOwner() {
// 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 == i_scrollCrossDomainMessenger || 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 == i_scrollCrossDomainMessenger) {
// solhint-disable-next-line custom-errors
require(
IScrollMessenger(i_scrollCrossDomainMessenger).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 {
// solhint-disable-next-line custom-errors
require(msg.sender == i_scrollCrossDomainMessenger, "Sender is not the L2 messenger");
// solhint-disable-next-line custom-errors
require(
IScrollMessenger(i_scrollCrossDomainMessenger).xDomainMessageSender() == s_l1PendingOwner,
"Must be proposed L1 owner"
);
_;
}
}
Loading

0 comments on commit 82faf5d

Please sign in to comment.