From 89d25188684f4bdade591b4c95c318081a53fc90 Mon Sep 17 00:00:00 2001 From: Hrishikesh Bhat Date: Mon, 28 Feb 2022 10:43:09 +0530 Subject: [PATCH 01/19] added challenge for FastBridgeReceiver created challenge path & required modifications. --- contracts/src/bridge/FastBridgeReceiver.sol | 122 ++++++++++++++++-- contracts/src/bridge/FastBridgeSender.sol | 6 +- contracts/src/bridge/SafeBridgeArbitrum.sol | 9 +- .../bridge/interfaces/IFastBridgeReceiver.sol | 2 + .../src/bridge/interfaces/ISafeBridge.sol | 2 + .../src/bridge/interfaces/arbitrum/Inbox.sol | 103 +++++++++++++++ .../src/bridge/interfaces/arbitrum/Outbox.sol | 39 ++++++ 7 files changed, 271 insertions(+), 12 deletions(-) create mode 100644 contracts/src/bridge/interfaces/arbitrum/Inbox.sol create mode 100644 contracts/src/bridge/interfaces/arbitrum/Outbox.sol diff --git a/contracts/src/bridge/FastBridgeReceiver.sol b/contracts/src/bridge/FastBridgeReceiver.sol index 7c1fd9715..cebb24f51 100644 --- a/contracts/src/bridge/FastBridgeReceiver.sol +++ b/contracts/src/bridge/FastBridgeReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz] + * @authors: [@shalzz, @hrishibhat] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -11,8 +11,13 @@ pragma solidity ^0.8.0; import "./interfaces/IFastBridgeReceiver.sol"; +import "./interfaces/arbitrum/Inbox.sol"; +import "./interfaces/arbitrum/Outbox.sol"; contract FastBridgeReceiver is IFastBridgeReceiver { + IInbox public inbox; + address public safebridge; + address public fastBridgeSender; address public governor; uint256 public claimDeposit; uint256 public challengeDuration; @@ -22,12 +27,23 @@ contract FastBridgeReceiver is IFastBridgeReceiver { uint256 claimedAt; uint256 claimDeposit; bool relayed; + bool honest; } + struct Challenge { + address challenge; + uint256 challengedAt; + uint256 challengeDeposit; + bool challenged; + bool honest; + } + // messageHash => Claim mapping(bytes32 => Claim) public claims; + mapping(bytes32 => Challenge) public challenges; event ClaimReceived(bytes32 messageHash, uint256 claimedAt); + event ClaimChallenged(bytes32 messageHash, uint256 challengedAt); modifier onlyByGovernor() { require(governor == msg.sender, "Access not allowed: Governor only."); @@ -35,10 +51,16 @@ contract FastBridgeReceiver is IFastBridgeReceiver { } constructor( + address _inbox, + address _safebridge, + address _fastBridgeSender, address _governor, uint256 _claimDeposit, uint256 _challengeDuration ) { + inbox = IInbox(_inbox); + safebridge = _safebridge; + fastBridgeSender = _fastBridgeSender; governor = _governor; claimDeposit = _claimDeposit; challengeDuration = _challengeDuration; @@ -52,6 +74,7 @@ contract FastBridgeReceiver is IFastBridgeReceiver { bridger: msg.sender, claimedAt: block.timestamp, claimDeposit: msg.value, + honest: false, relayed: false }); @@ -59,35 +82,116 @@ contract FastBridgeReceiver is IFastBridgeReceiver { } function verifyAndRelay(bytes32 _messageHash, bytes memory _encodedData) external { - require(keccak256(_encodedData) == _messageHash, "Invalid hash"); Claim storage claim = claims[_messageHash]; require(claim.bridger != address(0), "Claim does not exist"); require(claim.claimedAt + challengeDuration < block.timestamp, "Challenge period not over"); require(claim.relayed == false, "Message already relayed"); - // Decode the receiver address from the data encoded by the IFastBridgeSender - (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); - (bool success, ) = address(receiver).call(data); - require(success, "Failed to call contract"); + Challenge storage challenge = challenges[_messageHash]; + if(challenge.challenged == true){ + if(keccak256(_encodedData) == _messageHash){ + challenge.honest == false; + claim.honest == true; + // Decode the receiver address from the data encoded by the IFastBridgeSender + (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); + (bool success, ) = address(receiver).call(data); + require(success, "Failed to call contract"); + + claim.relayed = true; + } + else{ + challenge.honest == true; + claim.honest == false; + } + } + } + + function relayRule(bytes memory _encodedData) external { + IBridge bridge = inbox.bridge(); + require(msg.sender == address(bridge), "Not called by the Bridge"); - claim.relayed = true; + IOutbox outbox = IOutbox(inbox.bridge().activeOutbox()); + address l2Sender = outbox.l2ToL1Sender(); + require(l2Sender == safebridge, "Can be relayed only by Safe Bridge"); + + Challenge storage challenge = challenges[_messageHash]; + Claim storage claim = claims[_messageHash]; + + require(challenge.honest == true, "This claim is not challenged"); + + if(keccak256(_encodedData) == _messageHash){ + challenge.honest == false; + claim.honest == true; + // Decode the receiver address from the data encoded by the IFastBridgeSender + (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); + (bool success, ) = address(receiver).call(data); + require(success, "Failed to call contract"); + + claim.relayed = true; + } } function withdrawClaimDeposit(bytes32 _messageHash) external { Claim storage claim = claims[_messageHash]; require(claim.bridger != address(0), "Claim does not exist"); require(claim.claimedAt + challengeDuration < block.timestamp, "Challenge period not over"); + require(claim.relayed == true, "Claim not relayed"); + Challenge storage challenge = challenges[_messageHash]; uint256 amount = claim.claimDeposit; + if(challenge.honest == false){ + amount += challenge.challengeDeposit; + challenge.challengeDeposit = 0; + } + claim.claimDeposit = 0; payable(claim.bridger).send(amount); } - function challenge() external { - revert("Not Implemented"); + function challenge(bytes32 _messageHash) external payable { + Claim storage claim = claims[_messageHash]; + require(claim.bridger != address(0), "Claim does not exist"); + require(block.timestamp - claim.claimedAt < challengeDuration, "Challenge period over"); + require(msg.value >= challengeDeposit, "Not enough challenge deposit"); + require(challenges[_messageHash].challenger == address(0), "Claim already challenged"); + + challenges[_messageHash] = Challenge({ + challenger: msg.sender, + challengedAt: block.timestamp, + challengeDeposit: msg.value, + challenged: true, + honest: false + }); + + emit ClaimChallenged(_messageHash, block.timestamp); + } + function withdrawChallengeDeposit(bytes32 _messageHash) external { + Challenge storage challenge = challenges[_messageHash]; + require(challenge.challenger != address(0), "Challenge does not exist"); + require(challenge.honest == true, "Challenge not honest"); + + Claim storage claim = claims[_messageHash]; + require(block.timestamp > claim.claimedAt + challengeDuration, "Challenge period not over"); + require(claim.relayed == true, "Claim not relayed"); + + uint256 amount = challenge.challengeDeposit; + if(claim.honest == false){ + amount += claim.claimDeposit; + claim.claimDeposit = 0; + } + + challenge.challengeDeposit = 0; + payable(challenge.challenger).send(amount); + } + //**** View Functions ****// + function challengePeriod(bytes messageHash) public view returns(uint start, uint end) { + start = claims[_messageHash].claimedAt; + end = start + challengeDuration; + return (start, end); + } //**** Governor functions ****// function setClaimDeposit(uint256 _claimDeposit) external onlyByGovernor { diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index 3d855a357..9999b7710 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz] + * @authors: [@shalzz, @hrishibhat] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -72,7 +72,9 @@ contract FastBridgeSender is IFastBridgeSender { // IFastBridgeReceiver function. // TODO: add access checks for this on the FastBridgeReceiver. // TODO: how much ETH should be provided for bridging? add an ISafeBridge.bridgingCost() + bytes memory encodedData = abi.encode(_receiver, _calldata); - safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedData); + bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, encodedData); + safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } } diff --git a/contracts/src/bridge/SafeBridgeArbitrum.sol b/contracts/src/bridge/SafeBridgeArbitrum.sol index fd168137f..fd146f993 100644 --- a/contracts/src/bridge/SafeBridgeArbitrum.sol +++ b/contracts/src/bridge/SafeBridgeArbitrum.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz] + * @authors: [@shalzz, @hrishibhat] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -14,13 +14,20 @@ import "./interfaces/arbitrum/IArbSys.sol"; import "./interfaces/arbitrum/AddressAliasHelper.sol"; import "./interfaces/ISafeBridge.sol"; +import "./interfaces/IFastBridgeSender.sol"; contract SafeBridgeArbitrum is ISafeBridge { IArbSys constant arbsys = IArbSys(address(100)); + IFastBridgeSender public fastBridgeSender; event L2ToL1TxCreated(uint256 indexed withdrawalId); + constructor(IFastBridgeSender _fastBridgeSender) { + fastBridgeSender = _fastBridgeSender; + } function sendSafe(address _receiver, bytes memory _calldata) external payable override returns (uint256) { + require(msg.sender == address(fastBridgeSender), "Access not allowed: Fast Bridge Sender only."); + uint256 withdrawalId = arbsys.sendTxToL1(_receiver, _calldata); emit L2ToL1TxCreated(withdrawalId); diff --git a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol index bbb50572c..81772cfa2 100644 --- a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol +++ b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol @@ -7,6 +7,8 @@ interface IFastBridgeReceiver { function verifyAndRelay(bytes32 _messageHash, bytes memory _calldata) external; + function relayRule(bytes memory _calldata) external; + function withdrawClaimDeposit(bytes32 _messageHash) external; function claimDeposit() external view returns (uint256 amount); diff --git a/contracts/src/bridge/interfaces/ISafeBridge.sol b/contracts/src/bridge/interfaces/ISafeBridge.sol index b3aef94c4..4f7a226b6 100644 --- a/contracts/src/bridge/interfaces/ISafeBridge.sol +++ b/contracts/src/bridge/interfaces/ISafeBridge.sol @@ -11,4 +11,6 @@ interface ISafeBridge { * @return Unique id to track the message request/transaction. */ function sendSafe(address _receiver, bytes memory _calldata) external payable returns (uint256); + + function bridgingCost() external view returns(uint256 amount); } diff --git a/contracts/src/bridge/interfaces/arbitrum/Inbox.sol b/contracts/src/bridge/interfaces/arbitrum/Inbox.sol new file mode 100644 index 000000000..9216d9b6c --- /dev/null +++ b/contracts/src/bridge/interfaces/arbitrum/Inbox.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: Apache-2.0 +pragma solidity >=0.7.0; + + +interface IInbox { + + + function sendL2Message(bytes calldata messageData) external returns (uint256); + + function sendUnsignedTransaction( + uint256 maxGas, + uint256 gasPriceBid, + uint256 nonce, + address destAddr, + uint256 amount, + bytes calldata data + ) external returns (uint256); + + function sendContractTransaction( + uint256 maxGas, + uint256 gasPriceBid, + address destAddr, + uint256 amount, + bytes calldata data + ) external returns (uint256); + + function sendL1FundedUnsignedTransaction( + uint256 maxGas, + uint256 gasPriceBid, + uint256 nonce, + address destAddr, + bytes calldata data + ) external payable returns (uint256); + + function sendL1FundedContractTransaction( + uint256 maxGas, + uint256 gasPriceBid, + address destAddr, + bytes calldata data + ) external payable returns (uint256); + + function createRetryableTicket( + address destAddr, + uint256 arbTxCallValue, + uint256 maxSubmissionCost, + address submissionRefundAddress, + address valueRefundAddress, + uint256 maxGas, + uint256 gasPriceBid, + bytes calldata data + ) external payable returns (uint256); + + function depositEth(uint256 maxSubmissionCost) external payable returns (uint256); + + function bridge() external view returns (IBridge); +} + + +interface IBridge { + event MessageDelivered( + uint256 indexed messageIndex, + bytes32 indexed beforeInboxAcc, + address inbox, + uint8 kind, + address sender, + bytes32 messageDataHash + ); + + function deliverMessageToInbox( + uint8 kind, + address sender, + bytes32 messageDataHash + ) external payable returns (uint256); + + function executeCall( + address destAddr, + uint256 amount, + bytes calldata data + ) external returns (bool success, bytes memory returnData); + + // These are only callable by the admin + function setInbox(address inbox, bool enabled) external; + + function setOutbox(address inbox, bool enabled) external; + + // View functions + + function activeOutbox() external view returns (address); + + function allowedInboxes(address inbox) external view returns (bool); + + function allowedOutboxes(address outbox) external view returns (bool); + + function inboxAccs(uint256 index) external view returns (bytes32); + + function messageCount() external view returns (uint256); +} + +interface IMessageProvider { + event InboxMessageDelivered(uint256 indexed messageNum, bytes data); + + event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); +} \ No newline at end of file diff --git a/contracts/src/bridge/interfaces/arbitrum/Outbox.sol b/contracts/src/bridge/interfaces/arbitrum/Outbox.sol new file mode 100644 index 000000000..d4f35c4dc --- /dev/null +++ b/contracts/src/bridge/interfaces/arbitrum/Outbox.sol @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: Apache-2.0 + +/* + * Copyright 2021, Offchain Labs, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +pragma solidity >=0.7.0; + +interface IOutbox { + event OutboxEntryCreated( + uint256 indexed batchNum, + uint256 outboxIndex, + bytes32 outputRoot, + uint256 numInBatch + ); + + function l2ToL1Sender() external view returns (address); + + function l2ToL1Block() external view returns (uint256); + + function l2ToL1EthBlock() external view returns (uint256); + + function l2ToL1Timestamp() external view returns (uint256); + + function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths) + external; +} \ No newline at end of file From cddc2b7af73c23caedb6a82d4e6aeb15aa158ca4 Mon Sep 17 00:00:00 2001 From: Hrishikesh Bhat Date: Mon, 7 Mar 2022 00:14:23 +0530 Subject: [PATCH 02/19] changes in the fastBridgeReceiver --- contracts/src/bridge/FastBridgeReceiver.sol | 65 +++++++++---------- contracts/src/bridge/FastBridgeSender.sol | 2 +- contracts/src/bridge/SafeBridgeArbitrum.sol | 2 +- .../bridge/interfaces/IFastBridgeReceiver.sol | 2 +- 4 files changed, 35 insertions(+), 36 deletions(-) diff --git a/contracts/src/bridge/FastBridgeReceiver.sol b/contracts/src/bridge/FastBridgeReceiver.sol index cebb24f51..628bec132 100644 --- a/contracts/src/bridge/FastBridgeReceiver.sol +++ b/contracts/src/bridge/FastBridgeReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz, @hrishibhat] + * @authors: [@shalzz*, @hrishibhat] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -20,6 +20,7 @@ contract FastBridgeReceiver is IFastBridgeReceiver { address public fastBridgeSender; address public governor; uint256 public claimDeposit; + uint256 public challengeDeposit; uint256 public challengeDuration; struct Claim { @@ -31,10 +32,9 @@ contract FastBridgeReceiver is IFastBridgeReceiver { } struct Challenge { - address challenge; + address challenger; uint256 challengedAt; uint256 challengeDeposit; - bool challenged; bool honest; } @@ -89,22 +89,18 @@ contract FastBridgeReceiver is IFastBridgeReceiver { require(claim.relayed == false, "Message already relayed"); Challenge storage challenge = challenges[_messageHash]; - if(challenge.challenged == true){ - if(keccak256(_encodedData) == _messageHash){ - challenge.honest == false; - claim.honest == true; - // Decode the receiver address from the data encoded by the IFastBridgeSender - (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); - (bool success, ) = address(receiver).call(data); - require(success, "Failed to call contract"); - - claim.relayed = true; - } - else{ - challenge.honest == true; - claim.honest == false; - } + require(challenge.challenger == address(0), "This claim is Challenged"); + + if(keccak256(_encodedData) == _messageHash){ + claim.honest = true; + // Decode the receiver address from the data encoded by the IFastBridgeSender + (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); + (bool success, ) = address(receiver).call(data); + require(success, "Failed to call contract"); + + claim.relayed = true; } + } function relayRule(bytes memory _encodedData) external { @@ -115,21 +111,26 @@ contract FastBridgeReceiver is IFastBridgeReceiver { address l2Sender = outbox.l2ToL1Sender(); require(l2Sender == safebridge, "Can be relayed only by Safe Bridge"); + bytes32 _messageHash = keccak256(_encodedData); Challenge storage challenge = challenges[_messageHash]; Claim storage claim = claims[_messageHash]; + require(claim.relayed != true, "Claim already relayed"); + + if (claim.bridger != address(0) && challenge.challenger != address(0)) { + challenge.honest = false; + claim.honest = true; + } else { + challenge.honest = true; + claim.honest = false; + } - require(challenge.honest == true, "This claim is not challenged"); - - if(keccak256(_encodedData) == _messageHash){ - challenge.honest == false; - claim.honest == true; - // Decode the receiver address from the data encoded by the IFastBridgeSender - (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); - (bool success, ) = address(receiver).call(data); - require(success, "Failed to call contract"); + // Decode the receiver address from the data encoded by the IFastBridgeSender + (address receiver, bytes memory data) = abi.decode(_encodedData, (address, bytes)); + (bool success, ) = address(receiver).call(data); + require(success, "Failed to call contract"); - claim.relayed = true; - } + claim.relayed = true; + } function withdrawClaimDeposit(bytes32 _messageHash) external { @@ -150,7 +151,7 @@ contract FastBridgeReceiver is IFastBridgeReceiver { } function challenge(bytes32 _messageHash) external payable { - Claim storage claim = claims[_messageHash]; + Claim memory claim = claims[_messageHash]; require(claim.bridger != address(0), "Claim does not exist"); require(block.timestamp - claim.claimedAt < challengeDuration, "Challenge period over"); require(msg.value >= challengeDeposit, "Not enough challenge deposit"); @@ -160,12 +161,10 @@ contract FastBridgeReceiver is IFastBridgeReceiver { challenger: msg.sender, challengedAt: block.timestamp, challengeDeposit: msg.value, - challenged: true, honest: false }); emit ClaimChallenged(_messageHash, block.timestamp); - } function withdrawChallengeDeposit(bytes32 _messageHash) external { @@ -187,7 +186,7 @@ contract FastBridgeReceiver is IFastBridgeReceiver { payable(challenge.challenger).send(amount); } //**** View Functions ****// - function challengePeriod(bytes messageHash) public view returns(uint start, uint end) { + function challengePeriod(bytes32 _messageHash) public view returns(uint start, uint end) { start = claims[_messageHash].claimedAt; end = start + challengeDuration; return (start, end); diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index 9999b7710..67710245c 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz, @hrishibhat] + * @authors: [@shalzz*, @hrishibhat] * @reviewers: [] * @auditors: [] * @bounties: [] diff --git a/contracts/src/bridge/SafeBridgeArbitrum.sol b/contracts/src/bridge/SafeBridgeArbitrum.sol index fd146f993..43f1af389 100644 --- a/contracts/src/bridge/SafeBridgeArbitrum.sol +++ b/contracts/src/bridge/SafeBridgeArbitrum.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz, @hrishibhat] + * @authors: [@shalzz*, @hrishibhat] * @reviewers: [] * @auditors: [] * @bounties: [] diff --git a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol index 81772cfa2..a87bd71bf 100644 --- a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol +++ b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol @@ -11,5 +11,5 @@ interface IFastBridgeReceiver { function withdrawClaimDeposit(bytes32 _messageHash) external; - function claimDeposit() external view returns (uint256 amount); + function viewClaimDeposit() external view returns (uint256 amount); } From f07b40df89860ea31edb4ec9347a4f1273d0521a Mon Sep 17 00:00:00 2001 From: shotaro Date: Wed, 9 Mar 2022 12:08:21 +0000 Subject: [PATCH 03/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 37 ++++++++++++++++++----- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index 67710245c..d2f504b6f 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -13,27 +13,38 @@ pragma solidity ^0.8.0; import "./interfaces/ISafeBridge.sol"; import "./interfaces/IFastBridgeSender.sol"; import "./interfaces/IFastBridgeReceiver.sol"; +import "../gateway/interfaces/IForeignGateway.sol" +import "../gateway/HomeGateway.sol" +import "../arbitration/KlerosCore.sol"; contract FastBridgeSender is IFastBridgeSender { ISafeBridge public safebridge; IFastBridgeReceiver public fastBridgeReceiver; address public fastSender; - + address public foreignGateway; + HomeGateway public homeGateway; + KlerosCore public core; // The Kleros Core arbitrator + /** * The bridgers need to watch for these events and * relay the messageHash on the FastBridgeReceiver. */ event OutgoingMessage(address target, bytes32 messageHash, bytes message); - constructor(ISafeBridge _safebridge, IFastBridgeReceiver _fastBridgeReceiver) { + constructor(ISafeBridge _safebridge, IFastBridgeReceiver _fastBridgeReceiver, KlerosCore _core, address, _foreignGateway, HomeGateway _homeGateway) { safebridge = _safebridge; fastBridgeReceiver = _fastBridgeReceiver; + core = _core; + foreignGateway = _foreignGateway; + homeGateway = _homeGateway; } function setFastSender(address _fastSender) external { require(fastSender == address(0)); fastSender = _fastSender; } + + /** * Sends an arbitrary message from one domain to another @@ -42,13 +53,13 @@ contract FastBridgeSender is IFastBridgeSender { * @param _receiver The L1 contract address who will receive the calldata * @param _calldata The receiving domain encoded message data. */ - function sendFast(address _receiver, bytes memory _calldata) external { + function sendFast(bytes memory _calldata) external { require(msg.sender == fastSender, "Access not allowed: Fast Sender only."); // Encode the receiver address with the function signature + arguments i.e calldata - bytes memory encodedData = abi.encode(_receiver, _calldata); + bytes memory encodedData = abi.encode(foreignGateway, _calldata); - emit OutgoingMessage(_receiver, keccak256(encodedData), encodedData); + emit OutgoingMessage(foreignGateway, keccak256(encodedData), encodedData); } /** @@ -63,7 +74,7 @@ contract FastBridgeSender is IFastBridgeSender { * @param _receiver The L1 contract address who will receive the calldata * @param _calldata The receiving domain encoded message data. */ - function sendSafe(address _receiver, bytes memory _calldata) external payable { + function sendSafe(uint256 _disputeID) external payable { // The safe bridge sends the encoded data to the FastBridgeReceiver // in order for the FastBridgeReceiver to resolve any potential // challenges and then forwards the message to the actual @@ -73,7 +84,19 @@ contract FastBridgeSender is IFastBridgeSender { // TODO: add access checks for this on the FastBridgeReceiver. // TODO: how much ETH should be provided for bridging? add an ISafeBridge.bridgingCost() - bytes memory encodedData = abi.encode(_receiver, _calldata); + + Dispute storage dispute = core.disputes[_disputeID]; + require(dispute.ruled, "Ruling not requested for execution."); + + + bytes32 disputeHash = homeGateway.disputeIDtoHash[_disputeID]; + RelayedData memory relayedData = homeGateway.disputeHashtoRelayedData[disputeHash]; + uint256 ruling = core.currentRuling(_disputeID); + + bytes4 methodSelector = IForeignGateway.relayRule.selector; + bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); + + bytes memory encodedData = abi.encode(foreignGateway, data); bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } From dccd57f67f5760fcffce98524391d152117319aa Mon Sep 17 00:00:00 2001 From: shotaro Date: Wed, 9 Mar 2022 12:15:19 +0000 Subject: [PATCH 04/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index d2f504b6f..c1edca1cd 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -86,7 +86,7 @@ contract FastBridgeSender is IFastBridgeSender { Dispute storage dispute = core.disputes[_disputeID]; - require(dispute.ruled, "Ruling not requested for execution."); + //require(dispute.ruled, "Ruling not requested for execution."); bytes32 disputeHash = homeGateway.disputeIDtoHash[_disputeID]; @@ -94,7 +94,7 @@ contract FastBridgeSender is IFastBridgeSender { uint256 ruling = core.currentRuling(_disputeID); bytes4 methodSelector = IForeignGateway.relayRule.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); + bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer, dispute.ruled); bytes memory encodedData = abi.encode(foreignGateway, data); bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, encodedData); From 2464dab98b9ab932e023aab9d7207b6760b9624c Mon Sep 17 00:00:00 2001 From: shotaro Date: Wed, 9 Mar 2022 12:51:07 +0000 Subject: [PATCH 05/19] Create FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index c1edca1cd..950cc0e24 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -94,10 +94,10 @@ contract FastBridgeSender is IFastBridgeSender { uint256 ruling = core.currentRuling(_disputeID); bytes4 methodSelector = IForeignGateway.relayRule.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer, dispute.ruled); + bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); bytes memory encodedData = abi.encode(foreignGateway, data); - bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, encodedData); + bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } } From 716ee423c40f999b458c75f9ce627c79817ec26c Mon Sep 17 00:00:00 2001 From: shotaro Date: Wed, 9 Mar 2022 12:56:29 +0000 Subject: [PATCH 06/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index 950cc0e24..a41a1aad5 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -97,7 +97,7 @@ contract FastBridgeSender is IFastBridgeSender { bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); bytes memory encodedData = abi.encode(foreignGateway, data); - bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, encodedData); + bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, disputeHash, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } } From f8dbe51b36ad1a375f9fca977bdcf51d42827b06 Mon Sep 17 00:00:00 2001 From: shotaro Date: Wed, 9 Mar 2022 13:11:12 +0000 Subject: [PATCH 07/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 1 + 1 file changed, 1 insertion(+) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index a41a1aad5..23df0d2a4 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -97,6 +97,7 @@ contract FastBridgeSender is IFastBridgeSender { bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); bytes memory encodedData = abi.encode(foreignGateway, data); + // TO DO, remove duplicate disputeHash bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, disputeHash, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } From 105c0374a65aa38accdf4f47a9b01f8228d65bd9 Mon Sep 17 00:00:00 2001 From: shotaro Date: Wed, 9 Mar 2022 13:14:19 +0000 Subject: [PATCH 08/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index 23df0d2a4..b97954082 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -97,8 +97,8 @@ contract FastBridgeSender is IFastBridgeSender { bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); bytes memory encodedData = abi.encode(foreignGateway, data); - // TO DO, remove duplicate disputeHash - bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, disputeHash, encodedData); + + bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } } From c40426fa333beb751906f8bb3ad754efa847220b Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 10:36:10 +0000 Subject: [PATCH 09/19] Update FastBridgeSender.sol reverting my commits to maintain the bridge reciever as relatively app agnostic, but still need to implement a contorl flow to relay correct dispute rulings directly from kleros core --- contracts/src/bridge/FastBridgeSender.sol | 40 +++++------------------ 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index b97954082..67710245c 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -13,38 +13,27 @@ pragma solidity ^0.8.0; import "./interfaces/ISafeBridge.sol"; import "./interfaces/IFastBridgeSender.sol"; import "./interfaces/IFastBridgeReceiver.sol"; -import "../gateway/interfaces/IForeignGateway.sol" -import "../gateway/HomeGateway.sol" -import "../arbitration/KlerosCore.sol"; contract FastBridgeSender is IFastBridgeSender { ISafeBridge public safebridge; IFastBridgeReceiver public fastBridgeReceiver; address public fastSender; - address public foreignGateway; - HomeGateway public homeGateway; - KlerosCore public core; // The Kleros Core arbitrator - + /** * The bridgers need to watch for these events and * relay the messageHash on the FastBridgeReceiver. */ event OutgoingMessage(address target, bytes32 messageHash, bytes message); - constructor(ISafeBridge _safebridge, IFastBridgeReceiver _fastBridgeReceiver, KlerosCore _core, address, _foreignGateway, HomeGateway _homeGateway) { + constructor(ISafeBridge _safebridge, IFastBridgeReceiver _fastBridgeReceiver) { safebridge = _safebridge; fastBridgeReceiver = _fastBridgeReceiver; - core = _core; - foreignGateway = _foreignGateway; - homeGateway = _homeGateway; } function setFastSender(address _fastSender) external { require(fastSender == address(0)); fastSender = _fastSender; } - - /** * Sends an arbitrary message from one domain to another @@ -53,13 +42,13 @@ contract FastBridgeSender is IFastBridgeSender { * @param _receiver The L1 contract address who will receive the calldata * @param _calldata The receiving domain encoded message data. */ - function sendFast(bytes memory _calldata) external { + function sendFast(address _receiver, bytes memory _calldata) external { require(msg.sender == fastSender, "Access not allowed: Fast Sender only."); // Encode the receiver address with the function signature + arguments i.e calldata - bytes memory encodedData = abi.encode(foreignGateway, _calldata); + bytes memory encodedData = abi.encode(_receiver, _calldata); - emit OutgoingMessage(foreignGateway, keccak256(encodedData), encodedData); + emit OutgoingMessage(_receiver, keccak256(encodedData), encodedData); } /** @@ -74,7 +63,7 @@ contract FastBridgeSender is IFastBridgeSender { * @param _receiver The L1 contract address who will receive the calldata * @param _calldata The receiving domain encoded message data. */ - function sendSafe(uint256 _disputeID) external payable { + function sendSafe(address _receiver, bytes memory _calldata) external payable { // The safe bridge sends the encoded data to the FastBridgeReceiver // in order for the FastBridgeReceiver to resolve any potential // challenges and then forwards the message to the actual @@ -84,21 +73,8 @@ contract FastBridgeSender is IFastBridgeSender { // TODO: add access checks for this on the FastBridgeReceiver. // TODO: how much ETH should be provided for bridging? add an ISafeBridge.bridgingCost() - - Dispute storage dispute = core.disputes[_disputeID]; - //require(dispute.ruled, "Ruling not requested for execution."); - - - bytes32 disputeHash = homeGateway.disputeIDtoHash[_disputeID]; - RelayedData memory relayedData = homeGateway.disputeHashtoRelayedData[disputeHash]; - uint256 ruling = core.currentRuling(_disputeID); - - bytes4 methodSelector = IForeignGateway.relayRule.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, ruling, relayedData.relayer); - - bytes memory encodedData = abi.encode(foreignGateway, data); - - bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, dispute.ruled, encodedData); + bytes memory encodedData = abi.encode(_receiver, _calldata); + bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } } From b6d855df8c45c78c125ef26eb9062dedd4cbfc15 Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 18:48:28 +0000 Subject: [PATCH 10/19] Update FastBridgeReceiver.sol --- contracts/src/bridge/FastBridgeReceiver.sol | 193 ++++++++++++-------- 1 file changed, 114 insertions(+), 79 deletions(-) diff --git a/contracts/src/bridge/FastBridgeReceiver.sol b/contracts/src/bridge/FastBridgeReceiver.sol index 628bec132..db61b3d9e 100644 --- a/contracts/src/bridge/FastBridgeReceiver.sol +++ b/contracts/src/bridge/FastBridgeReceiver.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz*, @hrishibhat] + * @authors: [@shalzz*, @hrishibhat*, @shotaronowhere] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -25,9 +25,9 @@ contract FastBridgeReceiver is IFastBridgeReceiver { struct Claim { address bridger; + bytes32 messageHash; uint256 claimedAt; uint256 claimDeposit; - bool relayed; bool honest; } @@ -38,12 +38,13 @@ contract FastBridgeReceiver is IFastBridgeReceiver { bool honest; } - // messageHash => Claim - mapping(bytes32 => Claim) public claims; - mapping(bytes32 => Challenge) public challenges; + // fastMessageIndex => Claim[] + mapping(uint256 => Claim[]) public claims; + mapping(uint256 => Challenge[]) public challenges; + mapping(uint256 => bool) public relayed; - event ClaimReceived(bytes32 messageHash, uint256 claimedAt); - event ClaimChallenged(bytes32 messageHash, uint256 challengedAt); + event ClaimReceived(uint256 _fastMessageIndex, bytes32 _messageHash, uint256 claimedAt); + event ClaimChallenged(uint256 _fastMessageIndex, uint256 _claimIndex, bytes32 _messageHash, uint256 challengedAt); modifier onlyByGovernor() { require(governor == msg.sender, "Access not allowed: Governor only."); @@ -66,44 +67,50 @@ contract FastBridgeReceiver is IFastBridgeReceiver { challengeDuration = _challengeDuration; } - function claim(bytes32 _messageHash) external payable { + function claim(uint256 _fastMessageIndex, bytes32 _messageHash) external payable override { require(msg.value >= claimDeposit, "Not enough claim deposit"); - require(claims[_messageHash].bridger == address(0), "Claimed already made"); + require(relayed[_fastMessageIndex] == false, "Message already relayed."); + // only accept additional claims if the previous claims are successfully challenged + // AND the message is not yet relayed + require(claims[_fastMessageIndex].length == 0 || challenges[_fastMessageIndex][claims[_fastMessageIndex].length-1].honest, "There is a previous unresolved claim"); - claims[_messageHash] = Claim({ + claims[_fastMessageIndex].push( Claim({ bridger: msg.sender, + messageHash: _messageHash, claimedAt: block.timestamp, claimDeposit: msg.value, - honest: false, - relayed: false - }); + honest: false + })); - emit ClaimReceived(_messageHash, block.timestamp); + emit ClaimReceived(_fastMessageIndex, _messageHash, block.timestamp); } - function verifyAndRelay(bytes32 _messageHash, bytes memory _encodedData) external { + function verifyAndRelay(uint _fastMessageIndex, bytes memory _encodedData) external override{ + + Claim[] storage claimsForIndex = claims[_fastMessageIndex]; + require(claimsForIndex.length>0, "Claim does not exist"); + - Claim storage claim = claims[_messageHash]; - require(claim.bridger != address(0), "Claim does not exist"); - require(claim.claimedAt + challengeDuration < block.timestamp, "Challenge period not over"); - require(claim.relayed == false, "Message already relayed"); + require(claimsForIndex[claimsForIndex.length-1].claimedAt + challengeDuration < block.timestamp, "Challenge period not over"); + require(relayed[_fastMessageIndex] == false, "Message already relayed"); - Challenge storage challenge = challenges[_messageHash]; - require(challenge.challenger == address(0), "This claim is Challenged"); + Challenge[] storage challengesForIndex = challenges[_fastMessageIndex]; - if(keccak256(_encodedData) == _messageHash){ - claim.honest = true; + require(challengesForIndex.length 0){ + // has claims + if (claimsForIndex[claimsForIndex.length-1].messageHash == messageHash){ + claimsForIndex[claimsForIndex.length-1].honest = true; + } else if(challengesForIndex.length > 0){ + // has challenges + challengesForIndex[challengesForIndex.length - 1].honest = true; + } + } else{ + // no claims, no challenges + } + // dispute ruled + if (dataWithReceiver.length != 0){ + // Decode the receiver address from the data encoded by the IFastBridgeSender + (address receiver, bytes memory data) = abi.decode(dataWithReceiver, (address, bytes)); + (bool success, ) = address(receiver).call(data); + require(success, "Failed to call contract"); - claim.relayed = true; + relayed[_fastMessageIndex] = true; + } + } - function withdrawClaimDeposit(bytes32 _messageHash) external { - Claim storage claim = claims[_messageHash]; - require(claim.bridger != address(0), "Claim does not exist"); - require(claim.claimedAt + challengeDuration < block.timestamp, "Challenge period not over"); - require(claim.relayed == true, "Claim not relayed"); - - Challenge storage challenge = challenges[_messageHash]; - uint256 amount = claim.claimDeposit; - if(challenge.honest == false){ - amount += challenge.challengeDeposit; - challenge.challengeDeposit = 0; + function withdrawClaimDeposit(uint256 _fastMessageIndex) external override{ + Claim[] storage claimsForIndex = claims[_fastMessageIndex]; + require(claimsForIndex.length>0, "Claim does not exist"); + + + require(claimsForIndex[claimsForIndex.length-1].claimedAt + challengeDuration < block.timestamp, "Challenge period not over"); + require(relayed[_fastMessageIndex] == true, "Claim not relayed"); + + Challenge[] storage challengesForIndex = challenges[_fastMessageIndex]; + + uint256 amount = 0; + if(claimsForIndex[claimsForIndex.length-1].honest == true){ + amount += claimsForIndex[claimsForIndex.length-1].claimDeposit; + if(challengesForIndex.length == claimsForIndex.length){ + if(challengesForIndex[challengesForIndex.length - 1].honest == false){ + amount += challengesForIndex[challengesForIndex.length - 1].challengeDeposit; + challengesForIndex[challengesForIndex.length - 1].challengeDeposit = 0; + } + } } - claim.claimDeposit = 0; - payable(claim.bridger).send(amount); + claimsForIndex[claimsForIndex.length-1].claimDeposit = 0; + payable(claimsForIndex[claimsForIndex.length-1].bridger).send(amount); } - function challenge(bytes32 _messageHash) external payable { - Claim memory claim = claims[_messageHash]; - require(claim.bridger != address(0), "Claim does not exist"); - require(block.timestamp - claim.claimedAt < challengeDuration, "Challenge period over"); + function challenge(uint256 _fastMessageIndex) external payable { + Claim[] memory claimsForIndex = claims[_fastMessageIndex]; + require(claimsForIndex.length > 0, "Claim does not exist"); + require(relayed[_fastMessageIndex] == false, "Message already relayed"); + require(block.timestamp - claimsForIndex[claimsForIndex.length-1].claimedAt < challengeDuration, "Challenge period over"); require(msg.value >= challengeDeposit, "Not enough challenge deposit"); - require(challenges[_messageHash].challenger == address(0), "Claim already challenged"); + require(challenges[_fastMessageIndex][claimsForIndex.length-1].challenger == address(0), "Claim already challenged"); - challenges[_messageHash] = Challenge({ + challenges[_fastMessageIndex].push(Challenge({ challenger: msg.sender, challengedAt: block.timestamp, challengeDeposit: msg.value, honest: false - }); + })); - emit ClaimChallenged(_messageHash, block.timestamp); + emit ClaimChallenged(_fastMessageIndex,claimsForIndex.length-1, claimsForIndex[claimsForIndex.length-1].messageHash, block.timestamp); } - function withdrawChallengeDeposit(bytes32 _messageHash) external { - Challenge storage challenge = challenges[_messageHash]; - require(challenge.challenger != address(0), "Challenge does not exist"); - require(challenge.honest == true, "Challenge not honest"); + function withdrawChallengeDeposit(uint256 _fastMessageIndex, uint256 challengeIndex) external { + Challenge[] storage challengesForIndex = challenges[_fastMessageIndex]; + require(challengesForIndex.length>0 && challengeIndex < challengesForIndex.length, "Challenge does not exist"); - Claim storage claim = claims[_messageHash]; - require(block.timestamp > claim.claimedAt + challengeDuration, "Challenge period not over"); - require(claim.relayed == true, "Claim not relayed"); + Claim[] storage claimsForIndex = claims[_fastMessageIndex]; - uint256 amount = challenge.challengeDeposit; - if(claim.honest == false){ - amount += claim.claimDeposit; - claim.claimDeposit = 0; + uint256 amount = 0; + if(challengesForIndex[challengeIndex].honest == true){ + amount += challengesForIndex[challengeIndex].challengeDeposit; + if(claimsForIndex[challengeIndex].honest == false){ + amount += claimsForIndex[challengeIndex].claimDeposit; + claimsForIndex[challengeIndex].claimDeposit = 0; + } } - challenge.challengeDeposit = 0; - payable(challenge.challenger).send(amount); + + challengesForIndex[challengeIndex].challengeDeposit = 0; + payable(challengesForIndex[challengeIndex].challenger).send(amount); } //**** View Functions ****// - function challengePeriod(bytes32 _messageHash) public view returns(uint start, uint end) { - start = claims[_messageHash].claimedAt; - end = start + challengeDuration; + function challengePeriod(uint256 _fastMessageIndex) public view returns(uint start, uint end) { + if (claims[_fastMessageIndex].length > 0){ + start = claims[_fastMessageIndex][claims[_fastMessageIndex].length-1].claimedAt; + end = start + challengeDuration; + } + return (start, end); } + //**** Governor functions ****// function setClaimDeposit(uint256 _claimDeposit) external onlyByGovernor { claimDeposit = _claimDeposit; } + function viewClaimDeposit() external override view returns (uint256 amount){ + return 0; + } + function setChallengePeriodDuration(uint256 _challengeDuration) external onlyByGovernor { challengeDuration = _challengeDuration; } From 1c5244a30485414857c3427d2e2be15bf211e743 Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 18:48:48 +0000 Subject: [PATCH 11/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index 67710245c..fa10ceee2 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz*, @hrishibhat] + * @authors: [@shalzz*, @hrishibhat*, @shotaronowhere] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -18,12 +18,13 @@ contract FastBridgeSender is IFastBridgeSender { ISafeBridge public safebridge; IFastBridgeReceiver public fastBridgeReceiver; address public fastSender; - + mapping(uint256 => bytes) public fastMessages; + uint256 fastMessageIndex; /** * The bridgers need to watch for these events and * relay the messageHash on the FastBridgeReceiver. */ - event OutgoingMessage(address target, bytes32 messageHash, bytes message); + event OutgoingMessage(address target, bytes32 messageHash, uint256 fastMessageIndex, bytes message); constructor(ISafeBridge _safebridge, IFastBridgeReceiver _fastBridgeReceiver) { safebridge = _safebridge; @@ -42,13 +43,15 @@ contract FastBridgeSender is IFastBridgeSender { * @param _receiver The L1 contract address who will receive the calldata * @param _calldata The receiving domain encoded message data. */ - function sendFast(address _receiver, bytes memory _calldata) external { + function sendFast(address _receiver, bytes memory _calldata) external override { require(msg.sender == fastSender, "Access not allowed: Fast Sender only."); // Encode the receiver address with the function signature + arguments i.e calldata bytes memory encodedData = abi.encode(_receiver, _calldata); + fastMessages[fastMessageIndex] = encodedData; + fastMessageIndex += 1; - emit OutgoingMessage(_receiver, keccak256(encodedData), encodedData); + emit OutgoingMessage(_receiver, keccak256(encodedData), fastMessageIndex-1, encodedData); } /** @@ -60,10 +63,10 @@ contract FastBridgeSender is IFastBridgeSender { * It may require some ETH (or whichever native token) to pay for the bridging cost, * depending on the underlying safe bridge. * - * @param _receiver The L1 contract address who will receive the calldata - * @param _calldata The receiving domain encoded message data. + * @param _fastMessageIndex The index of messageHash to send */ - function sendSafe(address _receiver, bytes memory _calldata) external payable { + function sendSafe(uint256 _fastMessageIndex) external payable { + // The safe bridge sends the encoded data to the FastBridgeReceiver // in order for the FastBridgeReceiver to resolve any potential // challenges and then forwards the message to the actual @@ -73,7 +76,7 @@ contract FastBridgeSender is IFastBridgeSender { // TODO: add access checks for this on the FastBridgeReceiver. // TODO: how much ETH should be provided for bridging? add an ISafeBridge.bridgingCost() - bytes memory encodedData = abi.encode(_receiver, _calldata); + bytes memory encodedData = abi.encode(_fastMessageIndex, fastMessages[_fastMessageIndex]); bytes memory encodedTxData = abi.encodeWithSelector(fastBridgeReceiver.relayRule.selector, encodedData); safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedTxData); } From 81dafdbbb01fd27591422a65d9f5f691dff9794a Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 18:49:54 +0000 Subject: [PATCH 12/19] Update IFastBridgeReceiver.sol --- contracts/src/bridge/interfaces/IFastBridgeReceiver.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol index a87bd71bf..f55f17ed2 100644 --- a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol +++ b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol @@ -3,13 +3,13 @@ pragma solidity ^0.8.0; interface IFastBridgeReceiver { - function claim(bytes32 _messageHash) external payable; + function claim(uint256 _fastMessageIndex, bytes32 _messageHash) external payable; - function verifyAndRelay(bytes32 _messageHash, bytes memory _calldata) external; + function verifyAndRelay(uint _fastMessageIndex, bytes memory _encodedData) external; - function relayRule(bytes memory _calldata) external; + function relayRule(bytes memory _encodedData) external; - function withdrawClaimDeposit(bytes32 _messageHash) external; + function withdrawClaimDeposit(uint256 _fastMessageIndex) external; function viewClaimDeposit() external view returns (uint256 amount); } From 1f178b5dde8b69dee58ae8ad7ccd738616677dd8 Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 18:51:21 +0000 Subject: [PATCH 13/19] Update ForeignGateway.sol --- contracts/src/gateway/ForeignGateway.sol | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/contracts/src/gateway/ForeignGateway.sol b/contracts/src/gateway/ForeignGateway.sol index 0b5114dc0..9f9d947a0 100644 --- a/contracts/src/gateway/ForeignGateway.sol +++ b/contracts/src/gateway/ForeignGateway.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz] + * @authors: [@shalzz*, @shotaronowhere] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -27,8 +27,8 @@ contract ForeignGateway is IForeignGateway { // feeForJuror by subcourtID uint256[] internal feeForJuror; - uint256 public chainID; - uint256 public homeChainID; + uint256 public override chainID; + uint256 public override homeChainID; struct DisputeData { uint248 id; @@ -41,7 +41,7 @@ contract ForeignGateway is IForeignGateway { address public governor; IFastBridgeReceiver public fastbridge; - address public homeGateway; + address public override homeGateway; event OutgoingDispute( bytes32 disputeHash, @@ -88,7 +88,7 @@ contract ForeignGateway is IForeignGateway { feeForJuror[_subcourtID] = _feeForJuror; } - function createDispute(uint256 _choices, bytes calldata _extraData) external payable returns (uint256 disputeID) { + function createDispute(uint256 _choices, bytes calldata _extraData) external payable override returns (uint256 disputeID) { require(msg.value >= arbitrationCost(_extraData), "Not paid enough for arbitration"); (uint96 subcourtID, ) = extraDataToSubcourtIDMinJurors(_extraData); @@ -121,7 +121,7 @@ contract ForeignGateway is IForeignGateway { emit DisputeCreation(disputeID, IArbitrable(msg.sender)); } - function arbitrationCost(bytes calldata _extraData) public view returns (uint256 cost) { + function arbitrationCost(bytes calldata _extraData) public view override returns (uint256 cost) { (uint96 subcourtID, uint256 minJurors) = extraDataToSubcourtIDMinJurors(_extraData); cost = feeForJuror[subcourtID] * minJurors; @@ -134,7 +134,7 @@ contract ForeignGateway is IForeignGateway { bytes32 _disputeHash, uint256 _ruling, address _relayer - ) external onlyFromFastBridge { + ) external override onlyFromFastBridge { DisputeData storage dispute = disputeHashtoDisputeData[_disputeHash]; require(dispute.id != 0, "Dispute does not exist"); @@ -147,7 +147,7 @@ contract ForeignGateway is IForeignGateway { arbitrable.rule(dispute.id, _ruling); } - function withdrawFees(bytes32 _disputeHash) external { + function withdrawFees(bytes32 _disputeHash) external override { DisputeData storage dispute = disputeHashtoDisputeData[_disputeHash]; require(dispute.id != 0, "Dispute does not exist"); require(dispute.ruled, "Not ruled yet"); @@ -157,7 +157,7 @@ contract ForeignGateway is IForeignGateway { payable(dispute.relayer).transfer(amount); } - function disputeHashToForeignID(bytes32 _disputeHash) external view returns (uint256) { + function disputeHashToForeignID(bytes32 _disputeHash) external view override returns (uint256) { return disputeHashtoDisputeData[_disputeHash].id; } From cdf388f0ae9b863c2b73b4a2553ae4f6704c5048 Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 18:52:11 +0000 Subject: [PATCH 14/19] Update HomeGateway.sol --- contracts/src/gateway/HomeGateway.sol | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/contracts/src/gateway/HomeGateway.sol b/contracts/src/gateway/HomeGateway.sol index 3fdba3775..19d1ac0c6 100644 --- a/contracts/src/gateway/HomeGateway.sol +++ b/contracts/src/gateway/HomeGateway.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT /** - * @authors: [@shalzz] + * @authors: [@shalzz*, @shotaronowhere] * @reviewers: [] * @auditors: [] * @bounties: [] @@ -19,12 +19,13 @@ import "./interfaces/IHomeGateway.sol"; contract HomeGateway is IHomeGateway { mapping(uint256 => bytes32) public disputeIDtoHash; mapping(bytes32 => uint256) public disputeHashtoID; + mapping(bytes32 => bool) public disputeHashtoRuled; IArbitrator public arbitrator; IFastBridgeSender public fastbridge; - address public foreignGateway; - uint256 public chainID; - uint256 public foreignChainID; + address public override foreignGateway; + uint256 public override chainID; + uint256 public override foreignChainID; struct RelayedData { uint256 arbitrationCost; @@ -70,7 +71,7 @@ contract HomeGateway is IHomeGateway { uint256 _choices, bytes calldata _extraData, address _arbitrable - ) external payable { + ) external payable override{ bytes32 disputeHash = keccak256( abi.encodePacked( _originalChainID, @@ -97,19 +98,20 @@ contract HomeGateway is IHomeGateway { emit Dispute(arbitrator, disputeID, 0, 0); } - function rule(uint256 _disputeID, uint256 _ruling) external { + function rule(uint256 _disputeID, uint256 _ruling) external override{ require(msg.sender == address(arbitrator), "Only Arbitrator"); bytes32 disputeHash = disputeIDtoHash[_disputeID]; RelayedData memory relayedData = disputeHashtoRelayedData[disputeHash]; + bytes4 methodSelector = IForeignGateway.relayRule.selector; - bytes memory data = abi.encodeWithSelector(methodSelector, disputeHash, _ruling, relayedData.relayer); + bytes memory data = abi.encodeWithSelector( methodSelector, disputeHash, _ruling, relayedData.relayer); fastbridge.sendFast(foreignGateway, data); } - function disputeHashToHomeID(bytes32 _disputeHash) external view returns (uint256) { + function disputeHashToHomeID(bytes32 _disputeHash) external view override returns (uint256) { return disputeHashtoID[_disputeHash]; } } From b649e203d8edc255f4d3ce126c37001c7a681d3d Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 18:54:55 +0000 Subject: [PATCH 15/19] Update HomeGateway.sol --- contracts/src/gateway/HomeGateway.sol | 1 - 1 file changed, 1 deletion(-) diff --git a/contracts/src/gateway/HomeGateway.sol b/contracts/src/gateway/HomeGateway.sol index 19d1ac0c6..135050d8e 100644 --- a/contracts/src/gateway/HomeGateway.sol +++ b/contracts/src/gateway/HomeGateway.sol @@ -19,7 +19,6 @@ import "./interfaces/IHomeGateway.sol"; contract HomeGateway is IHomeGateway { mapping(uint256 => bytes32) public disputeIDtoHash; mapping(bytes32 => uint256) public disputeHashtoID; - mapping(bytes32 => bool) public disputeHashtoRuled; IArbitrator public arbitrator; IFastBridgeSender public fastbridge; From 04b31ba1139c60eae7c0503c66d2ef5a1c3cc4bf Mon Sep 17 00:00:00 2001 From: shotaro Date: Fri, 11 Mar 2022 19:08:22 +0000 Subject: [PATCH 16/19] Update FastBridgeReceiver.sol --- contracts/src/bridge/FastBridgeReceiver.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/bridge/FastBridgeReceiver.sol b/contracts/src/bridge/FastBridgeReceiver.sol index db61b3d9e..e5497721d 100644 --- a/contracts/src/bridge/FastBridgeReceiver.sol +++ b/contracts/src/bridge/FastBridgeReceiver.sol @@ -181,7 +181,7 @@ contract FastBridgeReceiver is IFastBridgeReceiver { require(relayed[_fastMessageIndex] == false, "Message already relayed"); require(block.timestamp - claimsForIndex[claimsForIndex.length-1].claimedAt < challengeDuration, "Challenge period over"); require(msg.value >= challengeDeposit, "Not enough challenge deposit"); - require(challenges[_fastMessageIndex][claimsForIndex.length-1].challenger == address(0), "Claim already challenged"); + require(challenges[_fastMessageIndex].length < claimsForIndex.length, "Claim already challenged"); challenges[_fastMessageIndex].push(Challenge({ challenger: msg.sender, @@ -227,7 +227,7 @@ contract FastBridgeReceiver is IFastBridgeReceiver { function setClaimDeposit(uint256 _claimDeposit) external onlyByGovernor { claimDeposit = _claimDeposit; } - + //TODO function viewClaimDeposit() external override view returns (uint256 amount){ return 0; } From b40367292cb71cbd0f474de3ed5766d4ebf34ef5 Mon Sep 17 00:00:00 2001 From: shotaro Date: Mon, 14 Mar 2022 11:07:34 +0000 Subject: [PATCH 17/19] Update FastBridgeSender.sol removed unnecessary function selector wrapping --- contracts/src/bridge/FastBridgeSender.sol | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index fa10ceee2..b714c4874 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -75,9 +75,9 @@ contract FastBridgeSender is IFastBridgeSender { // IFastBridgeReceiver function. // TODO: add access checks for this on the FastBridgeReceiver. // TODO: how much ETH should be provided for bridging? add an ISafeBridge.bridgingCost() + require(_fastMessageIndex Date: Mon, 14 Mar 2022 12:43:40 +0000 Subject: [PATCH 18/19] Update FastBridgeSender.sol fixing function selector for safe bridge --- contracts/src/bridge/FastBridgeSender.sol | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index b714c4874..b8727244b 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -48,7 +48,7 @@ contract FastBridgeSender is IFastBridgeSender { // Encode the receiver address with the function signature + arguments i.e calldata bytes memory encodedData = abi.encode(_receiver, _calldata); - fastMessages[fastMessageIndex] = encodedData; + fastMessages[fastMessageIndex] = _calldata; fastMessageIndex += 1; emit OutgoingMessage(_receiver, keccak256(encodedData), fastMessageIndex-1, encodedData); @@ -78,6 +78,7 @@ contract FastBridgeSender is IFastBridgeSender { require(_fastMessageIndex Date: Mon, 14 Mar 2022 13:00:36 +0000 Subject: [PATCH 19/19] Update FastBridgeSender.sol --- contracts/src/bridge/FastBridgeSender.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol index b8727244b..5ce7d65bb 100644 --- a/contracts/src/bridge/FastBridgeSender.sol +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -48,7 +48,7 @@ contract FastBridgeSender is IFastBridgeSender { // Encode the receiver address with the function signature + arguments i.e calldata bytes memory encodedData = abi.encode(_receiver, _calldata); - fastMessages[fastMessageIndex] = _calldata; + fastMessages[fastMessageIndex] = encodedData; fastMessageIndex += 1; emit OutgoingMessage(_receiver, keccak256(encodedData), fastMessageIndex-1, encodedData);