Skip to content

Commit 8d95e33

Browse files
committed
feat(gateway): add access control functions
Note they will always revert right now as the actual sender of the cross domain message will be the wrapper bridge contracts. We need to either have the bridge contracts be inherited or pass their address to the constructor of the other bridge in addition to the address of the gateway.
1 parent 2f0542b commit 8d95e33

File tree

5 files changed

+64
-2
lines changed

5 files changed

+64
-2
lines changed
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
/*
4+
* Copyright 2019-2021, Offchain Labs, Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
pragma solidity >=0.7.0;
20+
21+
library AddressAliasHelper {
22+
uint160 constant offset = uint160(0x1111000000000000000000000000000000001111);
23+
24+
/// @notice Utility function that converts the address in the L1 that submitted a tx to
25+
/// the inbox to the msg.sender viewed in the L2
26+
/// @param l1Address the address in the L1 that triggered the tx to L2
27+
/// @return l2Address L2 address as viewed in msg.sender
28+
function applyL1ToL2Alias(address l1Address) internal pure returns (address l2Address) {
29+
l2Address = address(uint160(l1Address) + offset);
30+
}
31+
32+
/// @notice Utility function that converts the msg.sender viewed in the L2 to the
33+
/// address in the L1 that submitted a tx to the inbox
34+
/// @param l2Address L2 address as viewed in msg.sender
35+
/// @return l1Address the address in the L1 that triggered the tx to L2
36+
function undoL1ToL2Alias(address l2Address) internal pure returns (address l1Address) {
37+
l1Address = address(uint160(l2Address) - offset);
38+
}
39+
}

contracts/src/bridge/arbitrum/L1Bridge.sol

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pragma solidity ^0.8.0;
44

55
import "./interfaces/IInbox.sol";
6+
import "./interfaces/IOutbox.sol";
67
import "./interfaces/IArbRetryableTx.sol";
78

89
contract L1Bridge {
@@ -60,4 +61,10 @@ contract L1Bridge {
6061
(uint256 submissionCost, ) = arbRetryableTx.getSubmissionPrice(_calldatasize);
6162
return submissionCost;
6263
}
64+
65+
function onlyAuthorized(address _sender) external {
66+
IOutbox outbox = IOutbox(inbox.bridge().activeOutbox());
67+
address l2Sender = outbox.l2ToL1Sender();
68+
require(l2Sender == l2Target, "Only L2 target");
69+
}
6370
}

contracts/src/bridge/arbitrum/L2Bridge.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
pragma solidity ^0.8.0;
44

55
import "./interfaces/IArbSys.sol";
6+
import "./AddressAliasHelper.sol";
67

78
contract L2Bridge {
89
address public l1Target;
@@ -26,4 +27,8 @@ contract L2Bridge {
2627
emit L2ToL1TxCreated(withdrawalId);
2728
return withdrawalId;
2829
}
30+
31+
function onlyAuthorized(address _sender) external {
32+
require(_sender == AddressAliasHelper.applyL1ToL2Alias(l1Target), "Only L1 target");
33+
}
2934
}

contracts/src/gateway/arbitrum/ArbitrumGateway.sol

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@ import "../IForeignGateway.sol";
1010

1111
contract ArbitrumGateway is IHomeGateway {
1212
// L2 bridge with the ForeignGateway as the l1target
13+
1314
L2Bridge internal l2bridge;
1415
address public arbitrator;
1516

17+
modifier onlyFromL1() {
18+
l2bridge.onlyAuthorized(msg.sender);
19+
_;
20+
}
21+
1622
constructor(address _arbitrator, L2Bridge _l2bridge) {
1723
arbitrator = _arbitrator;
1824
l2bridge = _l2bridge;
@@ -35,7 +41,7 @@ contract ArbitrumGateway is IHomeGateway {
3541
* for it to maintain it's internal mapping.
3642
* @param _data The calldata to relay
3743
*/
38-
function relayCreateDispute(bytes memory _data) external {
44+
function relayCreateDispute(bytes memory _data) external onlyFromL1 {
3945
// solhint-disable-next-line avoid-low-level-calls
4046
(bool success, ) = arbitrator.call(_data);
4147
require(success, "Failed to call contract");

contracts/src/gateway/arbitrum/EthereumGateway.sol

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,11 @@ contract EthereumGateway is IForeignGateway {
1717
// in the V2 court.
1818
uint256 internal internalArbitrationCost;
1919

20+
modifier onlyFromL2() {
21+
l1bridge.onlyAuthorized(msg.sender);
22+
_;
23+
}
24+
2025
constructor(uint256 _arbitrationCost, L1Bridge _l1bridge) {
2126
internalArbitrationCost = _arbitrationCost;
2227
l1bridge = _l1bridge;
@@ -66,7 +71,7 @@ contract EthereumGateway is IForeignGateway {
6671
*
6772
* @param _data The calldata to relay
6873
*/
69-
function relayRule(bytes memory _data) external {
74+
function relayRule(bytes memory _data) external onlyFromL2 {
7075
address arbitrable = address(0); // see the TODO above about the disputeId
7176

7277
// solhint-disable-next-line avoid-low-level-calls

0 commit comments

Comments
 (0)