Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 18 additions & 7 deletions contracts/src/bridge/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

pragma solidity ^0.8.4;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

import "./IBridge.sol";
Expand All @@ -20,7 +20,7 @@ import {L1MessageType_batchPostingReport} from "../libraries/MessageTypes.sol";
* Since the escrow is held here, this contract also contains a list of allowed
* outboxes that can make calls from here and withdraw this escrow.
*/
contract Bridge is OwnableUpgradeable, DelegateCallAware, IBridge {
contract Bridge is Initializable, DelegateCallAware, IBridge {
using AddressUpgradeable for address;

struct InOutInfo {
Expand All @@ -42,13 +42,24 @@ contract Bridge is OwnableUpgradeable, DelegateCallAware, IBridge {
/// @dev Accumulator for sequencer inbox messages; tail represents hash of the current state; each element represents the inclusion of a new message.
bytes32[] public override sequencerInboxAccs;

IOwnable public override rollup;
address public sequencerInbox;

address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);

function initialize() external initializer onlyDelegated {
function initialize(IOwnable rollup_) external initializer onlyDelegated {
_activeOutbox = EMPTY_ACTIVEOUTBOX;
__Ownable_init();
rollup = rollup_;
}

modifier onlyRollupOrOwner() {
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}

/// @dev returns the address of current active Outbox, or zero if no outbox is active
Expand Down Expand Up @@ -197,12 +208,12 @@ contract Bridge is OwnableUpgradeable, DelegateCallAware, IBridge {
emit BridgeCallTriggered(msg.sender, to, value, data);
}

function setSequencerInbox(address _sequencerInbox) external override onlyOwner {
function setSequencerInbox(address _sequencerInbox) external override onlyRollupOrOwner {
sequencerInbox = _sequencerInbox;
emit SequencerInboxUpdated(_sequencerInbox);
}

function setDelayedInbox(address inbox, bool enabled) external override onlyOwner {
function setDelayedInbox(address inbox, bool enabled) external override onlyRollupOrOwner {
InOutInfo storage info = allowedDelayedInboxesMap[inbox];
bool alreadyEnabled = info.allowed;
emit InboxToggle(inbox, enabled);
Expand All @@ -222,7 +233,7 @@ contract Bridge is OwnableUpgradeable, DelegateCallAware, IBridge {
}
}

function setOutbox(address outbox, bool enabled) external override onlyOwner {
function setOutbox(address outbox, bool enabled) external override onlyRollupOrOwner {
if (outbox == EMPTY_ACTIVEOUTBOX) revert InvalidOutboxSet(outbox);

InOutInfo storage info = allowedOutboxesMap[outbox];
Expand Down
5 changes: 4 additions & 1 deletion contracts/src/bridge/IBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

pragma solidity ^0.8.4;

import {NotContract} from "../libraries/Error.sol";
import {NotContract, NotRollupOrOwner} from "../libraries/Error.sol";
import "./IOwnable.sol";

/// @dev Thrown when an un-authorized address tries to access an only-inbox function
/// @param sender The un-authorized sender
Expand Down Expand Up @@ -96,4 +97,6 @@ interface IBridge {
function delayedMessageCount() external view returns (uint256);

function sequencerMessageCount() external view returns (uint256);

function rollup() external view returns (IOwnable);
}
9 changes: 9 additions & 0 deletions contracts/src/bridge/IOwnable.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// Copyright 2021-2022, Offchain Labs, Inc.
// For license information, see https://github.com/nitro/blob/master/LICENSE
// SPDX-License-Identifier: BUSL-1.1

pragma solidity ^0.8.4;

interface IOwnable {
function owner() external view returns (address);
}
21 changes: 12 additions & 9 deletions contracts/src/bridge/Inbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import {
} from "../libraries/MessageTypes.sol";
import {MAX_DATA_SIZE} from "../libraries/Constants.sol";

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";

Expand All @@ -42,7 +41,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
event AllowListAddressSet(address indexed user, bool val);
event AllowListEnabledUpdated(bool isEnabled);

function setAllowList(address[] memory user, bool[] memory val) external onlyOwner {
function setAllowList(address[] memory user, bool[] memory val) external onlyRollupOrOwner {
require(user.length == val.length, "INVALID_INPUT");

for (uint256 i = 0; i < user.length; i++) {
Expand All @@ -51,7 +50,7 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {
}
}

function setAllowListEnabled(bool _allowListEnabled) external onlyOwner {
function setAllowListEnabled(bool _allowListEnabled) external onlyRollupOrOwner {
require(_allowListEnabled != allowListEnabled, "ALREADY_SET");
allowListEnabled = _allowListEnabled;
emit AllowListEnabledUpdated(_allowListEnabled);
Expand All @@ -68,20 +67,24 @@ contract Inbox is DelegateCallAware, PausableUpgradeable, IInbox {

/// ------------------------------------ allow list end ------------------------------------ ///

modifier onlyOwner() {
// whoevever owns the Bridge, also owns the Inbox. this is usually the rollup contract
address bridgeOwner = OwnableUpgradeable(address(bridge)).owner();
if (msg.sender != bridgeOwner) revert NotOwner(msg.sender, bridgeOwner);
modifier onlyRollupOrOwner() {
IOwnable rollup = bridge.rollup();
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}

/// @notice pauses all inbox functionality
function pause() external onlyOwner {
function pause() external onlyRollupOrOwner {
_pause();
}

/// @notice unpauses all inbox functionality
function unpause() external onlyOwner {
function unpause() external onlyRollupOrOwner {
_unpause();
}

Expand Down
6 changes: 3 additions & 3 deletions contracts/src/bridge/Outbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ contract Outbox is DelegateCallAware, IOutbox {

uint128 public constant OUTBOX_VERSION = 2;

function initialize(address _rollup, IBridge _bridge) external onlyDelegated {
if (rollup != address(0)) revert AlreadyInit();
function initialize(IBridge _bridge) external onlyDelegated {
if (address(bridge) != address(0)) revert AlreadyInit();
// address zero is returned if no context is set, but the values used in storage
// are non-zero to save users some gas (as storage refunds are usually maxed out)
// EIP-1153 would help here
Expand All @@ -53,8 +53,8 @@ contract Outbox is DelegateCallAware, IOutbox {
outputId: OUTPUTID_DEFAULT_CONTEXT,
sender: SENDER_DEFAULT_CONTEXT
});
rollup = _rollup;
bridge = _bridge;
rollup = address(_bridge.rollup());
}

function updateSendRoot(bytes32 root, bytes32 l2BlockHash) external override {
Expand Down
9 changes: 4 additions & 5 deletions contracts/src/bridge/SequencerInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
/// the sequencer inbox has authenticated the data. Currently not used.
bytes1 public constant DATA_AUTHENTICATED_FLAG = 0x40;

address public rollup;
IOwnable public rollup;
mapping(address => bool) public isBatchPoster;
ISequencerInbox.MaxTimeVariation public maxTimeVariation;

Expand All @@ -44,19 +44,18 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
mapping(bytes32 => DasKeySetInfo) public dasKeySetInfo;

modifier onlyRollupOwner() {
if (msg.sender != IRollupUserAbs(rollup).owner()) revert NotOwner(msg.sender, rollup);
if (msg.sender != rollup.owner()) revert NotOwner(msg.sender, address(rollup));
_;
}

function initialize(
IBridge bridge_,
address rollup_,
ISequencerInbox.MaxTimeVariation calldata maxTimeVariation_
) external onlyDelegated {
if (bridge != IBridge(address(0))) revert AlreadyInit();
if (bridge_ == IBridge(address(0))) revert HadZeroInit();
bridge = bridge_;
rollup = rollup_;
rollup = bridge_.rollup();
maxTimeVariation = maxTimeVariation_;
}

Expand Down Expand Up @@ -176,7 +175,7 @@ contract SequencerInbox is DelegateCallAware, GasRefundEnabled, ISequencerInbox
uint256 afterDelayedMessagesRead,
IGasRefunder gasRefunder
) external override refundsGas(gasRefunder) {
if (!isBatchPoster[msg.sender] && msg.sender != rollup) revert NotBatchPoster();
if (!isBatchPoster[msg.sender] && msg.sender != address(rollup)) revert NotBatchPoster();

(bytes32 dataHash, TimeBounds memory timeBounds) = formDataHash(
data,
Expand Down
6 changes: 6 additions & 0 deletions contracts/src/libraries/Error.sol
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,9 @@ error NotContract(address addr);
/// @param actualLength The length of the merkle proof provided
/// @param maxProofLength The max length a merkle proof can have
error MerkleProofTooLong(uint256 actualLength, uint256 maxProofLength);

/// @dev Thrown when an un-authorized address tries to access an admin function
/// @param sender The un-authorized sender
/// @param rollup The rollup, which would be authorized
/// @param owner The rollup's owner, which would be authorized
error NotRollupOrOwner(address sender, address rollup, address owner);
4 changes: 4 additions & 0 deletions contracts/src/mocks/BridgeStub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,8 @@ contract BridgeStub is IBridge {
function sequencerMessageCount() external view override returns (uint256) {
return sequencerInboxAccs.length;
}

function rollup() external pure override returns (IOwnable) {
revert("NOT_IMPLEMENTED");
}
}
2 changes: 1 addition & 1 deletion contracts/src/mocks/SequencerInboxStub.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ contract SequencerInboxStub is SequencerInbox {
ISequencerInbox.MaxTimeVariation memory maxTimeVariation_
) {
bridge = bridge_;
rollup = msg.sender;
rollup = IOwnable(msg.sender);
maxTimeVariation = maxTimeVariation_;
isBatchPoster[sequencer_] = true;
}
Expand Down
10 changes: 4 additions & 6 deletions contracts/src/rollup/BridgeCreator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,11 @@ contract BridgeCreator is Ownable {
);
}

frame.bridge.initialize();
frame.sequencerInbox.initialize(IBridge(frame.bridge), rollup, maxTimeVariation);
frame.bridge.initialize(IOwnable(rollup));
frame.sequencerInbox.initialize(IBridge(frame.bridge), maxTimeVariation);
frame.inbox.initialize(IBridge(frame.bridge), ISequencerInbox(frame.sequencerInbox));
frame.rollupEventInbox.initialize(address(frame.bridge), rollup);
frame.outbox.initialize(rollup, IBridge(frame.bridge));

frame.bridge.transferOwnership(rollup);
frame.rollupEventInbox.initialize(IBridge(frame.bridge));
frame.outbox.initialize(IBridge(frame.bridge));

return (
frame.bridge,
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/rollup/IRollupEventInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import "../bridge/IBridge.sol";
interface IRollupEventInbox {
function bridge() external view returns (IBridge);

function initialize(address _bridge, address _rollup) external;
function initialize(IBridge _bridge) external;

function rollup() external view returns (address);

Expand Down
5 changes: 2 additions & 3 deletions contracts/src/rollup/IRollupLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import "./RollupLib.sol";
import "./IRollupCore.sol";
import "../bridge/ISequencerInbox.sol";
import "../bridge/IOutbox.sol";
import "../bridge/IOwnable.sol";

interface IRollupUserAbs is IRollupCore {
interface IRollupUserAbs is IRollupCore, IOwnable {
/// @dev the user logic just validated configuration and shouldn't write to state during init
/// this allows the admin logic to ensure consistency on parameters.
function initialize(address stakeToken) external view;
Expand Down Expand Up @@ -54,8 +55,6 @@ interface IRollupUserAbs is IRollupCore {

function withdrawStakerFunds() external returns (uint256);

function owner() external view returns (address);

function createChallenge(
address[2] calldata stakers,
uint64[2] calldata nodeNums,
Expand Down
14 changes: 7 additions & 7 deletions contracts/src/rollup/RollupEventInbox.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,21 @@ contract RollupEventInbox is IRollupEventInbox, IDelayedMessageProvider, Delegat
uint8 internal constant REJECT_NODE_EVENT = 2;
uint8 internal constant STAKE_CREATED_EVENT = 3;

IBridge public bridge;
address public rollup;
IBridge public override bridge;
address public override rollup;

modifier onlyRollup() {
require(msg.sender == rollup, "ONLY_ROLLUP");
_;
}

function initialize(address _bridge, address _rollup) external onlyDelegated {
require(rollup == address(0), "ALREADY_INIT");
bridge = IBridge(_bridge);
rollup = _rollup;
function initialize(IBridge _bridge) external override onlyDelegated {
require(address(bridge) == address(0), "ALREADY_INIT");
bridge = _bridge;
rollup = address(_bridge.rollup());
}

function rollupInitialized(uint256 chainId) external onlyRollup {
function rollupInitialized(uint256 chainId) external override onlyRollup {
bytes memory initMsg = abi.encodePacked(chainId);
uint256 num = bridge.enqueueDelayedMessage(
INITIALIZATION_MSG_TYPE,
Expand Down
25 changes: 18 additions & 7 deletions contracts/src/test-helpers/BridgeTester.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

pragma solidity ^0.8.4;

import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol";

import "../bridge/IBridge.sol";
Expand All @@ -18,7 +18,7 @@ import "../libraries/DelegateCallAware.sol";
* Since the escrow is held here, this contract also contains a list of allowed
* outboxes that can make calls from here and withdraw this escrow.
*/
contract BridgeTester is OwnableUpgradeable, DelegateCallAware, IBridge {
contract BridgeTester is Initializable, DelegateCallAware, IBridge {
using AddressUpgradeable for address;

struct InOutInfo {
Expand All @@ -34,9 +34,20 @@ contract BridgeTester is OwnableUpgradeable, DelegateCallAware, IBridge {

address private _activeOutbox;

IOwnable public rollup;
address public sequencerInbox;

function setSequencerInbox(address _sequencerInbox) external override onlyOwner {
modifier onlyRollupOrOwner() {
if (msg.sender != address(rollup)) {
address rollupOwner = rollup.owner();
if (msg.sender != rollupOwner) {
revert NotRollupOrOwner(msg.sender, address(rollup), rollupOwner);
}
}
_;
}

function setSequencerInbox(address _sequencerInbox) external override onlyRollupOrOwner {
sequencerInbox = _sequencerInbox;
emit SequencerInboxUpdated(_sequencerInbox);
}
Expand All @@ -48,9 +59,9 @@ contract BridgeTester is OwnableUpgradeable, DelegateCallAware, IBridge {

address private constant EMPTY_ACTIVEOUTBOX = address(type(uint160).max);

function initialize() external initializer {
function initialize(IOwnable rollup_) external initializer {
_activeOutbox = EMPTY_ACTIVEOUTBOX;
__Ownable_init();
rollup = rollup_;
}

function activeOutbox() public view returns (address) {
Expand Down Expand Up @@ -162,7 +173,7 @@ contract BridgeTester is OwnableUpgradeable, DelegateCallAware, IBridge {
emit BridgeCallTriggered(msg.sender, to, value, data);
}

function setDelayedInbox(address inbox, bool enabled) external override onlyOwner {
function setDelayedInbox(address inbox, bool enabled) external override onlyRollupOrOwner {
InOutInfo storage info = allowedInboxesMap[inbox];
bool alreadyEnabled = info.allowed;
emit InboxToggle(inbox, enabled);
Expand All @@ -182,7 +193,7 @@ contract BridgeTester is OwnableUpgradeable, DelegateCallAware, IBridge {
}
}

function setOutbox(address outbox, bool enabled) external override onlyOwner {
function setOutbox(address outbox, bool enabled) external override onlyRollupOrOwner {
InOutInfo storage info = allowedOutboxesMap[outbox];
bool alreadyEnabled = info.allowed;
emit OutboxToggle(outbox, enabled);
Expand Down
Loading