Skip to content

Commit c964c68

Browse files
committed
feat(arbitrum): add gateway contracts
1 parent f56e256 commit c964c68

File tree

4 files changed

+126
-2
lines changed

4 files changed

+126
-2
lines changed

contracts/src/bridge/arbitrum/L1Bridge.sol

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ contract L1Bridge {
3939
uint256 _maxGas,
4040
uint256 _gasPriceBid
4141
) external payable returns (uint256) {
42-
(uint256 baseSubmissionCost, ) = arbRetryableTx.getSubmissionPrice(_calldata.length);
42+
uint256 baseSubmissionCost = getSubmissionPrice(_calldata.length);
4343

4444
uint256 ticketID = inbox.createRetryableTicket{value: msg.value}(
4545
l2Target,
@@ -55,4 +55,9 @@ contract L1Bridge {
5555
emit RetryableTicketCreated(ticketID);
5656
return ticketID;
5757
}
58+
59+
function getSubmissionPrice(uint256 _calldatasize) public view returns (uint256) {
60+
(uint256 submissionCost, ) = arbRetryableTx.getSubmissionPrice(_calldatasize);
61+
return submissionCost;
62+
}
5863
}

contracts/src/bridge/arbitrum/L2Bridge.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ contract L2Bridge {
2020
* @param _calldata The L1 encoded message data.
2121
* @return Unique id to track the message request/transaction.
2222
*/
23-
function sendCrossDomainMessage(bytes memory _calldata) external payable returns (uint256) {
23+
function sendCrossDomainMessage(bytes memory _calldata) external returns (uint256) {
2424
uint256 withdrawalId = arbsys.sendTxToL1(l1Target, _calldata);
2525

2626
emit L2ToL1TxCreated(withdrawalId);
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../../arbitration/IArbitrable.sol";
6+
import "../../arbitration/IArbitrator.sol";
7+
import "../../bridge/arbitrum/L1Bridge.sol";
8+
9+
import "./HomeGateway.sol";
10+
11+
contract ForeignGateway is IArbitrator {
12+
// L1 bridge with the HomeGateway as the l2target
13+
L1Bridge internal l1bridge;
14+
15+
// For now this is just a constant, but we'd probably need to
16+
// implement the same arbitrationCost calculation code we'll have
17+
// in the V2 court.
18+
uint256 internal internalArbitrationCost;
19+
20+
constructor(uint256 _arbitrationCost, L1Bridge _l1bridge) {
21+
internalArbitrationCost = _arbitrationCost;
22+
l1bridge = _l1bridge;
23+
}
24+
25+
function createDispute(uint256 _choices, bytes calldata _extraData) external payable returns (uint256 disputeID) {
26+
require(msg.value >= arbitrationCost(_extraData), "Not paid enough for arbitration");
27+
28+
bytes4 methodSelector = HomeGateway.relayCreateDispute.selector;
29+
bytes memory data = abi.encodeWithSelector(methodSelector, msg.data);
30+
31+
uint256 bridgeCost = l1bridge.getSubmissionPrice(data.length);
32+
// We only pay for the submissionPrice gas cost
33+
// which is minimum gas cost required for submitting a
34+
// arbitrum retryable ticket to the retry buffer for
35+
// bridge to L2.
36+
// For immediate inclusion a user/bot needs to pay (GasPrice x MaxGas)
37+
// with the associated ticketId that is emitted by this function
38+
// after the ticket is successfully submitted.
39+
// For more details, see:
40+
// https://developer.offchainlabs.com/docs/l1_l2_messages#retryable-tickets-contract-api
41+
//
42+
// We do NOT forward the arbitrationCost to the HomeGateway yet,
43+
// only the calldata.
44+
l1bridge.sendCrossDomainMessage{value: bridgeCost}(data, 0, 0);
45+
46+
disputeId = 0; // TODO: map to the actual disputeID we get from the V2 court
47+
emit DisputeCreation(disputeId, IArbitrable(msg.sender));
48+
return disputeId;
49+
}
50+
51+
function arbitrationCost(bytes calldata _extraData) public view returns (uint256 cost) {
52+
// Calculate the size of calldata that will be passed to the L2 bridge
53+
// as that is a factor for the bridging cost.
54+
// Calldata size of relayCreateDispute:
55+
// relayCreateDispute methodId +
56+
// (createDispute methodId + uint256 _choices + bytes _extraData)
57+
// 4 + 4 + 32 + dynamic
58+
uint256 calldatasize = 40 + _extraData.length;
59+
60+
uint256 bridgeCost = l1bridge.getSubmissionPrice(calldatasize);
61+
return bridgeCost + internalArbitrationCost;
62+
}
63+
64+
/**
65+
* Relay the rule call from the home gateway to the arbitrable.
66+
*
67+
* @param _data The calldata to relay
68+
*/
69+
function relayRule(bytes memory _data) external {
70+
address arbitrable = address(0); // see the TODO above about the disputeId
71+
72+
// solhint-disable-next-line avoid-low-level-calls
73+
(bool success, ) = arbitrable.call(_data);
74+
require(success, "Failed to call contract");
75+
}
76+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../../arbitration/IArbitrable.sol";
6+
import "../../arbitration/IArbitrator.sol";
7+
import "../../bridge/arbitrum/L2Bridge.sol";
8+
9+
import "./ForeignGateway.sol";
10+
11+
contract HomeGateway is IArbitrable {
12+
// L2 bridge with the ForeignGateway as the l1target
13+
L2Bridge internal l2bridge;
14+
address public arbitrator;
15+
16+
constructor(address _arbitrator, L2Bridge _l2bridge) {
17+
arbitrator = _arbitrator;
18+
l2bridge = _l2bridge;
19+
}
20+
21+
function rule(uint256, uint256) external {
22+
require(msg.sender == arbitrator, "Only Arbitrator");
23+
24+
bytes4 methodSelector = ForeignGateway.relayRule.selector;
25+
bytes memory data = abi.encodeWithSelector(methodSelector, msg.data);
26+
27+
l2bridge.sendCrossDomainMessage(data);
28+
}
29+
30+
/**
31+
* Relay the createDispute call from the foreign gateway to the arbitrator.
32+
*
33+
* // TODO: Implement the evidence redirection from the Evidence v2 standard.
34+
* // TODO: Return the actual disputeId from the court to the ForeignGateway
35+
* for it to maintain it's internal mapping.
36+
* @param _data The calldata to relay
37+
*/
38+
function relayCreateDispute(bytes memory _data) external {
39+
// solhint-disable-next-line avoid-low-level-calls
40+
(bool success, ) = arbitrator.call(_data);
41+
require(success, "Failed to call contract");
42+
}
43+
}

0 commit comments

Comments
 (0)