Skip to content

Commit 1afc05b

Browse files
committed
feat: added safe bridge messag enveloppe, refactored safe bridge abstraction
1 parent 762ff8a commit 1afc05b

12 files changed

+133
-79
lines changed

contracts/deploy/01-foreign-chain.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ const deployForeignGateway: DeployFunction = async (hre: HardhatRuntimeEnvironme
5050
let nonce;
5151
if (chainId === ForeignChains.HARDHAT) {
5252
nonce = await ethers.provider.getTransactionCount(deployer);
53-
nonce += 5; // HomeGatewayToEthereum deploy tx will be the 6th after this, same network for both home/foreign.
53+
nonce += 4; // HomeGatewayToEthereum deploy tx will be the 6th after this, same network for both home/foreign.
5454
} else {
5555
const homeChainProvider = new providers.JsonRpcProvider(homeNetworks[chainId].url);
5656
nonce = await homeChainProvider.getTransactionCount(deployer);
57-
nonce += 2; // HomeGatewayToEthereum deploy tx will the third tx after this on its home network, so we add two to the current nonce.
57+
nonce += 1; // HomeGatewayToEthereum deploy tx will the third tx after this on its home network, so we add two to the current nonce.
5858
}
5959
const { claimDeposit, challengeDuration, homeChainId } = paramsByChainId[chainId];
6060
const challengeDeposit = claimDeposit;
@@ -65,7 +65,14 @@ const deployForeignGateway: DeployFunction = async (hre: HardhatRuntimeEnvironme
6565

6666
const fastBridgeReceiver = await deploy("FastBridgeReceiverOnEthereum", {
6767
from: deployer,
68-
args: [deployer, claimDeposit, challengeDeposit, challengeDuration],
68+
args: [
69+
deployer,
70+
ethers.constants.AddressZero, // should be safeBridgeSender
71+
ethers.constants.AddressZero, // should be Arbitrum Inbox
72+
claimDeposit,
73+
challengeDeposit,
74+
challengeDuration,
75+
],
6976
log: true,
7077
});
7178

contracts/deploy/02-home-chain.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,6 @@ const deployHomeGateway: DeployFunction = async (hre: HardhatRuntimeEnvironment)
1414
const deployer = (await getNamedAccounts()).deployer ?? (await hre.ethers.getSigners())[0].address;
1515
console.log("deployer: %s", deployer);
1616

17-
const safeBridge = await deploy("SafeBridgeSenderToEthereum", {
18-
from: deployer,
19-
log: true,
20-
}); // nonce
21-
2217
// The object below is not available when launching the hardhat node.
2318
// TODO: use deterministic deployments
2419
const fastBridgeReceiver =
@@ -27,9 +22,9 @@ const deployHomeGateway: DeployFunction = async (hre: HardhatRuntimeEnvironment)
2722
: await hre.companionNetworks.foreign.deployments.get("FastBridgeReceiverOnEthereum");
2823
const fastBridgeSender = await deploy("FastBridgeSenderToEthereum", {
2924
from: deployer,
30-
args: [deployer, safeBridge.address, fastBridgeReceiver.address],
25+
args: [deployer, fastBridgeReceiver.address],
3126
log: true,
32-
}); // nonce+1
27+
}); // nonce+0
3328

3429
const klerosCore = await deployments.get("KlerosCore");
3530
const foreignGateway =
@@ -41,7 +36,7 @@ const deployHomeGateway: DeployFunction = async (hre: HardhatRuntimeEnvironment)
4136
from: deployer,
4237
args: [klerosCore.address, fastBridgeSender.address, foreignGateway.address, foreignChainId],
4338
log: true,
44-
}); // nonce+2
39+
}); // nonce+1
4540

4641
const fastSender = await hre.ethers
4742
.getContractAt("FastBridgeSenderToEthereum", fastBridgeSender.address)

contracts/src/bridge/FastBridgeReceiverOnEthereum.sol

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,14 @@
1010

1111
pragma solidity ^0.8.0;
1212

13+
import "./SafeBridgeReceiverOnEthereum.sol";
1314
import "./interfaces/IFastBridgeReceiver.sol";
14-
import "./interfaces/arbitrum/IInbox.sol";
15-
import "./interfaces/arbitrum/IOutbox.sol";
1615

1716
/**
1817
* Fast Bridge Receiver on Ethereum from Arbitrum
1918
* Counterpart of `FastBridgeSenderToEthereum`
2019
*/
21-
contract FastBridgeReceiverOnEthereum is IFastBridgeReceiver {
20+
contract FastBridgeReceiverOnEthereum is SafeBridgeReceiverOnEthereum, IFastBridgeReceiver {
2221
// ************************************* //
2322
// * Enums / Structs * //
2423
// ************************************* //
@@ -34,7 +33,6 @@ contract FastBridgeReceiverOnEthereum is IFastBridgeReceiver {
3433
// * Storage * //
3534
// ************************************* //
3635

37-
address public governor;
3836
uint256 public override claimDeposit;
3937
uint256 public override challengeDeposit;
4038
uint256 public override challengeDuration;
@@ -47,22 +45,14 @@ contract FastBridgeReceiverOnEthereum is IFastBridgeReceiver {
4745
event ClaimReceived(bytes32 indexed messageHash, uint256 claimedAt);
4846
event ClaimChallenged(bytes32 indexed _messageHash, uint256 challengedAt);
4947

50-
// ************************************* //
51-
// * Function Modifiers * //
52-
// ************************************* //
53-
54-
modifier onlyByGovernor() {
55-
require(governor == msg.sender, "Access not allowed: Governor only.");
56-
_;
57-
}
58-
5948
constructor(
6049
address _governor,
50+
address _safeBridgeSender,
51+
address _inbox,
6152
uint256 _claimDeposit,
6253
uint256 _challengeDeposit,
6354
uint256 _challengeDuration
64-
) {
65-
governor = _governor;
55+
) SafeBridgeReceiverOnEthereum(_governor, _safeBridgeSender, _inbox) {
6656
claimDeposit = _claimDeposit;
6757
challengeDeposit = _challengeDeposit;
6858
challengeDuration = _challengeDuration;
@@ -108,6 +98,8 @@ contract FastBridgeReceiverOnEthereum is IFastBridgeReceiver {
10898
}
10999

110100
function verifyAndRelaySafe(bytes32 _messageHash, bytes memory _encodedData) external override {
101+
require(isSentBySafeBridge(), "Access not allowed: SafeBridgeSender only.");
102+
111103
// TODO
112104
revert("Not Implemented");
113105
}

contracts/src/bridge/FastBridgeSenderToEthereum.sol

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,20 @@
1010

1111
pragma solidity ^0.8.0;
1212

13-
import "./interfaces/ISafeBridge.sol";
13+
import "./SafeBridgeSenderToEthereum.sol";
1414
import "./interfaces/IFastBridgeSender.sol";
1515
import "./interfaces/IFastBridgeReceiver.sol";
1616

1717
/**
1818
* Fast Bridge Sender to Ethereum from Arbitrum
1919
* Counterpart of `FastBridgeReceiverOnEthereum`
2020
*/
21-
contract FastBridgeSenderToEthereum is IFastBridgeSender {
21+
contract FastBridgeSenderToEthereum is SafeBridgeSenderToEthereum, IFastBridgeSender {
2222
// ************************************* //
2323
// * Storage * //
2424
// ************************************* //
2525

2626
address public governor;
27-
ISafeBridge public safebridge;
2827
IFastBridgeReceiver public fastBridgeReceiver;
2928
address public fastSender;
3029

@@ -47,13 +46,8 @@ contract FastBridgeSenderToEthereum is IFastBridgeSender {
4746
_;
4847
}
4948

50-
constructor(
51-
address _governor,
52-
ISafeBridge _safebridge,
53-
IFastBridgeReceiver _fastBridgeReceiver
54-
) {
49+
constructor(address _governor, IFastBridgeReceiver _fastBridgeReceiver) SafeBridgeSenderToEthereum() {
5550
governor = _governor;
56-
safebridge = _safebridge;
5751
fastBridgeReceiver = _fastBridgeReceiver;
5852
}
5953

@@ -72,9 +66,9 @@ contract FastBridgeSenderToEthereum is IFastBridgeSender {
7266
require(msg.sender == fastSender, "Access not allowed: Fast Sender only.");
7367

7468
// Encode the receiver address with the function signature + arguments i.e calldata
75-
bytes memory encodedData = abi.encode(_receiver, _calldata);
69+
bytes memory messageData = abi.encode(_receiver, _calldata);
7670

77-
emit OutgoingMessage(_receiver, keccak256(encodedData), encodedData);
71+
emit OutgoingMessage(_receiver, keccak256(messageData), messageData);
7872
}
7973

8074
/**
@@ -89,17 +83,15 @@ contract FastBridgeSenderToEthereum is IFastBridgeSender {
8983
* @param _receiver The L1 contract address who will receive the calldata
9084
* @param _calldata The receiving domain encoded message data.
9185
*/
92-
function sendSafe(address _receiver, bytes memory _calldata) external payable {
93-
// The safe bridge sends the encoded data to the FastBridgeReceiverOnEthereum
94-
// in order for the FastBridgeReceiverOnEthereum to resolve any potential
95-
// challenges and then forwards the message to the actual
96-
// intended recipient encoded in `data`
97-
// TODO: For this encodedData needs to be wrapped into an
98-
// IFastBridgeReceiver function.
99-
// TODO: add access checks for this on the FastBridgeReceiverOnEthereum.
100-
// TODO: how much ETH should be provided for bridging? add an ISafeBridge.bridgingCost()
101-
bytes memory encodedData = abi.encode(_receiver, _calldata);
102-
safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedData);
86+
function sendSafeFallback(address _receiver, bytes memory _calldata) external payable override {
87+
bytes memory messageData = abi.encode(_receiver, _calldata);
88+
89+
// Safe Bridge message envelope
90+
bytes4 methodSelector = IFastBridgeReceiver.verifyAndRelaySafe.selector;
91+
bytes memory safeMessageData = abi.encodeWithSelector(methodSelector, keccak256(messageData), messageData);
92+
93+
// TODO: how much ETH should be provided for bridging? add an ISafeBridgeSender.bridgingCost() if needed
94+
_sendSafe(address(fastBridgeReceiver), safeMessageData);
10395
}
10496

10597
// ************************ //
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
/**
4+
* @authors: [@jaybuidl, @shalzz]
5+
* @reviewers: []
6+
* @auditors: []
7+
* @bounties: []
8+
* @deployments: []
9+
*/
10+
11+
pragma solidity ^0.8.0;
12+
13+
import "./interfaces/ISafeBridgeReceiver.sol";
14+
import "./interfaces/arbitrum/IInbox.sol";
15+
import "./interfaces/arbitrum/IOutbox.sol";
16+
17+
/**
18+
* Safe Bridge Receiver on Ethereum from Arbitrum
19+
* Counterpart of `SafeBridgeSenderToEthereum`
20+
*/
21+
contract SafeBridgeReceiverOnEthereum is ISafeBridgeReceiver {
22+
// ************************************* //
23+
// * Storage * //
24+
// ************************************* //
25+
26+
address public governor;
27+
address public safeBridgeSender;
28+
IInbox public inbox;
29+
30+
// ************************************* //
31+
// * Function Modifiers * //
32+
// ************************************* //
33+
34+
modifier onlyByGovernor() {
35+
require(governor == msg.sender, "Access not allowed: Governor only.");
36+
_;
37+
}
38+
39+
constructor(
40+
address _governor,
41+
address _safeBridgeSender,
42+
address _inbox
43+
) {
44+
governor = _governor;
45+
inbox = IInbox(_inbox);
46+
safeBridgeSender = _safeBridgeSender;
47+
}
48+
49+
// ************************************* //
50+
// * Views * //
51+
// ************************************* //
52+
53+
function isSentBySafeBridge() internal view override returns (bool) {
54+
IOutbox outbox = IOutbox(inbox.bridge().activeOutbox());
55+
return outbox.l2ToL1Sender() == safeBridgeSender;
56+
}
57+
58+
// ************************ //
59+
// * Governance * //
60+
// ************************ //
61+
62+
function setSafeBridgeSender(address _safeBridgeSender) external onlyByGovernor {
63+
safeBridgeSender = _safeBridgeSender;
64+
}
65+
66+
function setInbox(address _inbox) external onlyByGovernor {
67+
inbox = IInbox(_inbox);
68+
}
69+
}

contracts/src/bridge/SafeBridgeSenderToArbitrumFromEthereum.sol

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,13 @@ pragma solidity ^0.8.0;
1313
import "./interfaces/arbitrum/IInbox.sol";
1414
import "./interfaces/arbitrum/IOutbox.sol";
1515
import "./interfaces/arbitrum/IArbRetryableTx.sol";
16-
17-
import "./interfaces/ISafeBridge.sol";
16+
import "./interfaces/ISafeBridgeSender.sol";
1817

1918
/**
2019
* Safe Bridge Sender to Arbitrum from Ethereum
2120
* Counterpart of `SafeBridgeReceiverOnArbitrumFromEthereum` if any
2221
*/
23-
contract SafeBridgeSenderToArbitrumFromEthereum is ISafeBridge {
22+
contract SafeBridgeSenderToArbitrumFromEthereum is ISafeBridgeSender {
2423
IArbRetryableTx public constant ARBITRUM_RETRYABLE_TX = IArbRetryableTx(address(110));
2524
address public immutable safeBridgeSender;
2625
IInbox public immutable inbox;
@@ -62,7 +61,7 @@ contract SafeBridgeSenderToArbitrumFromEthereum is ISafeBridge {
6261
* @param _calldata The encoded message data.
6362
* @return Unique id to track the message request/transaction.
6463
*/
65-
function sendSafe(address _receiver, bytes memory _calldata) external payable override returns (uint256) {
64+
function _sendSafe(address _receiver, bytes memory _calldata) internal override returns (uint256) {
6665
require(msg.sender == safeBridgeSender, "Access not allowed: Safe Bridge Sender only.");
6766

6867
uint256 baseSubmissionCost = bridgingCost(_calldata.length);

contracts/src/bridge/SafeBridgeSenderToEthereum.sol

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MIT
22

33
/**
4-
* @authors: [@shalzz]
4+
* @authors: [@shalzz, @jaybuidl]
55
* @reviewers: []
66
* @auditors: []
77
* @bounties: []
@@ -13,18 +13,18 @@ pragma solidity ^0.8.0;
1313
import "./interfaces/arbitrum/IArbSys.sol";
1414
import "./interfaces/arbitrum/AddressAliasHelper.sol";
1515

16-
import "./interfaces/ISafeBridge.sol";
16+
import "./interfaces/ISafeBridgeSender.sol";
1717

1818
/**
1919
* Safe Bridge Sender to Ethereum from Arbitrum
20-
* Counterpart of `SafeBridgeReceiverOnEthereum` if any
20+
* Counterpart of `SafeBridgeReceiverOnEthereum`
2121
*/
22-
contract SafeBridgeSenderToEthereum is ISafeBridge {
22+
contract SafeBridgeSenderToEthereum is ISafeBridgeSender {
2323
IArbSys public constant ARB_SYS = IArbSys(address(100));
2424

2525
event L2ToL1TxCreated(uint256 indexed withdrawalId);
2626

27-
function sendSafe(address _receiver, bytes memory _calldata) external payable override returns (uint256) {
27+
function _sendSafe(address _receiver, bytes memory _calldata) internal override returns (uint256) {
2828
uint256 withdrawalId = ARB_SYS.sendTxToL1(_receiver, _calldata);
2929

3030
emit L2ToL1TxCreated(withdrawalId);

contracts/src/bridge/SafeBridgeSenderToGnosis.sol

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@
1111
pragma solidity ^0.8.0;
1212

1313
import "./interfaces/gnosis-chain/IAMB.sol";
14-
import "./interfaces/ISafeBridge.sol";
14+
import "./interfaces/ISafeBridgeSender.sol";
1515

1616
/**
1717
* Safe Bridge Sender to Gnosis from Ethereum
1818
* Counterpart of `SafeBridgeReceiverOnGnosis` if any
1919
*/
20-
contract SafeBridgeSenderToGnosis is ISafeBridge {
20+
contract SafeBridgeSenderToGnosis is ISafeBridgeSender {
2121
IAMB public immutable amb;
2222

2323
constructor(IAMB _amb) {
2424
amb = _amb;
2525
}
2626

27-
function sendSafe(address _receiver, bytes memory _calldata) external payable override returns (uint256) {
27+
function _sendSafe(address _receiver, bytes memory _calldata) internal override returns (uint256) {
2828
bytes32 id = amb.requireToPassMessage(_receiver, _calldata, amb.maxGasPerTx());
2929
return uint256(id);
3030
}

contracts/src/bridge/interfaces/IFastBridgeSender.sol

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@ interface IFastBridgeSender {
77
* Sends an arbitrary message from one domain to another
88
* via the fast bridge mechanism
99
*
10-
* TODO: probably needs some access control either on the sender side
11-
* or the receiver side
12-
*
1310
* @param _receiver The L1 contract address who will receive the calldata
1411
* @param _calldata The receiving domain encoded message data.
1512
*/
1613
function sendFast(address _receiver, bytes memory _calldata) external;
14+
15+
/**
16+
* Sends an arbitrary message from one domain to another
17+
* via the fast bridge mechanism
18+
*
19+
* @param _receiver The L1 contract address who will receive the calldata
20+
* @param _calldata The receiving domain encoded message data.
21+
*/
22+
function sendSafeFallback(address _receiver, bytes memory _calldata) external payable;
1723
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
abstract contract ISafeBridgeReceiver {
6+
function isSentBySafeBridge() internal view virtual returns (bool);
7+
}

0 commit comments

Comments
 (0)