diff --git a/contracts/src/bridge/FastBridgeReceiver.sol b/contracts/src/bridge/FastBridgeReceiver.sol new file mode 100644 index 000000000..7c1fd9715 --- /dev/null +++ b/contracts/src/bridge/FastBridgeReceiver.sol @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: MIT + +/** + * @authors: [@shalzz] + * @reviewers: [] + * @auditors: [] + * @bounties: [] + * @deployments: [] + */ + +pragma solidity ^0.8.0; + +import "./interfaces/IFastBridgeReceiver.sol"; + +contract FastBridgeReceiver is IFastBridgeReceiver { + address public governor; + uint256 public claimDeposit; + uint256 public challengeDuration; + + struct Claim { + address bridger; + uint256 claimedAt; + uint256 claimDeposit; + bool relayed; + } + + // messageHash => Claim + mapping(bytes32 => Claim) public claims; + + event ClaimReceived(bytes32 messageHash, uint256 claimedAt); + + modifier onlyByGovernor() { + require(governor == msg.sender, "Access not allowed: Governor only."); + _; + } + + constructor( + address _governor, + uint256 _claimDeposit, + uint256 _challengeDuration + ) { + governor = _governor; + claimDeposit = _claimDeposit; + challengeDuration = _challengeDuration; + } + + function claim(bytes32 _messageHash) external payable { + require(msg.value >= claimDeposit, "Not enough claim deposit"); + require(claims[_messageHash].bridger == address(0), "Claimed already made"); + + claims[_messageHash] = Claim({ + bridger: msg.sender, + claimedAt: block.timestamp, + claimDeposit: msg.value, + relayed: false + }); + + emit ClaimReceived(_messageHash, block.timestamp); + } + + 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"); + + 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"); + + uint256 amount = claim.claimDeposit; + claim.claimDeposit = 0; + payable(claim.bridger).send(amount); + } + + function challenge() external { + revert("Not Implemented"); + } + + //**** Governor functions ****// + + function setClaimDeposit(uint256 _claimDeposit) external onlyByGovernor { + claimDeposit = _claimDeposit; + } + + function setChallengePeriodDuration(uint256 _challengeDuration) external onlyByGovernor { + challengeDuration = _challengeDuration; + } +} diff --git a/contracts/src/bridge/FastBridgeSender.sol b/contracts/src/bridge/FastBridgeSender.sol new file mode 100644 index 000000000..afc655ab0 --- /dev/null +++ b/contracts/src/bridge/FastBridgeSender.sol @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: MIT + +/** + * @authors: [@shalzz] + * @reviewers: [] + * @auditors: [] + * @bounties: [] + * @deployments: [] + */ + +pragma solidity ^0.8.0; + +import "./interfaces/ISafeBridge.sol"; +import "./interfaces/IFastBridgeSender.sol"; +import "./interfaces/IFastBridgeReceiver.sol"; + +contract FastBridgeSender is IFastBridgeSender { + ISafeBridge public safebridge; + IFastBridgeReceiver public fastBridgeReceiver; + address public fastSender; + + /** + * 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, + address _fastSender + ) { + safebridge = _safebridge; + fastBridgeReceiver = _fastBridgeReceiver; + fastSender = _fastSender; + } + + /** + * Sends an arbitrary message from one domain to another + * via the fast bridge mechanism + * + * @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 { + 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); + + emit OutgoingMessage(_receiver, keccak256(encodedData), encodedData); + } + + /** + * Sends an arbitrary message from one domain to another + * via the safe bridge mechanism, which relies on the chain's native bridge. + * + * It is unnecessary during normal operations but essential only in case of challenge. + * + * 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. + */ + 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 + // intended recipient encoded in `data` + // TODO: For this encodedData needs to be wrapped into an + // 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); + } +} diff --git a/contracts/src/bridge/IL1Bridge.sol b/contracts/src/bridge/IL1Bridge.sol deleted file mode 100644 index f6792732e..000000000 --- a/contracts/src/bridge/IL1Bridge.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/** - * This is essentially an interface but defined as an abstract contract - * to declare functions as internal instead of as external - */ -abstract contract IL1Bridge { - /** - * Sends an arbitrary message from one domain to another. - * - * @dev The caller needs to pay some ETH to cover the gas costs - * of the call on L2. Excess ETH that is not used by gas costs will - * be refunded to the `msg.sender` address on L2. - * - * @notice if a user does not desire immediate redemption, they should - * provide a DepositValue of at least CallValue + MaxSubmissionCost. - * If they do desire immediate execution, they should provide a DepositValue - * of at least CallValue + MaxSubmissionCost + (GasPrice x MaxGas). - * - * @param _calldata The L2 encoded message data. - * @param _maxGas Gas limit for immediate L2 execution attempt. - * @param _gasPriceBid L2 Gas price bid for immediate L2 execution attempt. - * @return Unique id to track the message request/transaction. - */ - function sendCrossDomainMessage( - bytes memory _calldata, - uint256 _maxGas, - uint256 _gasPriceBid - ) internal virtual returns (uint256); - - function bridgingCost(uint256 _calldatasize) internal view virtual returns (uint256); - - function onlyCrossChainSender() internal virtual; -} diff --git a/contracts/src/bridge/IL2Bridge.sol b/contracts/src/bridge/IL2Bridge.sol deleted file mode 100644 index f50db5cb6..000000000 --- a/contracts/src/bridge/IL2Bridge.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -/** - * This is essentially an interface but defined as an abstract contract - * to declare functions as internal instead of as external - */ -abstract contract IL2Bridge { - /** - * Sends an arbitrary message from one domain to another. - * - * @param _calldata The L1 encoded message data. - * @return Unique id to track the message request/transaction. - */ - function sendCrossDomainMessage(bytes memory _calldata) internal virtual returns (uint256); - - function onlyCrossChainSender() internal virtual; -} diff --git a/contracts/src/bridge/SafeBridgeArbitrum.sol b/contracts/src/bridge/SafeBridgeArbitrum.sol new file mode 100644 index 000000000..fd168137f --- /dev/null +++ b/contracts/src/bridge/SafeBridgeArbitrum.sol @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: MIT + +/** + * @authors: [@shalzz] + * @reviewers: [] + * @auditors: [] + * @bounties: [] + * @deployments: [] + */ + +pragma solidity ^0.8.0; + +import "./interfaces/arbitrum/IArbSys.sol"; +import "./interfaces/arbitrum/AddressAliasHelper.sol"; + +import "./interfaces/ISafeBridge.sol"; + +contract SafeBridgeArbitrum is ISafeBridge { + IArbSys constant arbsys = IArbSys(address(100)); + + event L2ToL1TxCreated(uint256 indexed withdrawalId); + + function sendSafe(address _receiver, bytes memory _calldata) external payable override returns (uint256) { + uint256 withdrawalId = arbsys.sendTxToL1(_receiver, _calldata); + + emit L2ToL1TxCreated(withdrawalId); + return withdrawalId; + } +} diff --git a/contracts/src/bridge/SafeBridgeGnosis.sol b/contracts/src/bridge/SafeBridgeGnosis.sol new file mode 100644 index 000000000..34324bca6 --- /dev/null +++ b/contracts/src/bridge/SafeBridgeGnosis.sol @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: MIT + +/** + * @authors: [@shalzz] + * @reviewers: [] + * @auditors: [] + * @bounties: [] + * @deployments: [] + */ + +pragma solidity ^0.8.0; + +import "./interfaces/gnosis-chain/IAMB.sol"; +import "./interfaces/ISafeBridge.sol"; + +contract SafeBridgeGnosis is ISafeBridge { + IAMB amb; + + constructor(IAMB _amb) { + amb = _amb; + } + + function sendSafe(address _receiver, bytes memory _calldata) external payable override returns (uint256) { + bytes32 id = amb.requireToPassMessage(_receiver, _calldata, amb.maxGasPerTx()); + return uint256(id); + } +} diff --git a/contracts/src/bridge/arbitrum/ArbL1Bridge.sol b/contracts/src/bridge/arbitrum/ArbL1Bridge.sol deleted file mode 100644 index 48a5fa2a3..000000000 --- a/contracts/src/bridge/arbitrum/ArbL1Bridge.sol +++ /dev/null @@ -1,81 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** - * @authors: [@shalzz] - * @reviewers: [] - * @auditors: [] - * @bounties: [] - * @deployments: [] - */ - -pragma solidity ^0.8.0; - -import "./interfaces/IInbox.sol"; -import "./interfaces/IOutbox.sol"; -import "./interfaces/IArbRetryableTx.sol"; - -import "../IL1Bridge.sol"; - -contract ArbL1Bridge is IL1Bridge { - address public l2Target; - IInbox public inbox; - IArbRetryableTx constant arbRetryableTx = IArbRetryableTx(address(110)); - - event RetryableTicketCreated(uint256 indexed ticketId); - - constructor(address _l2Target, address _inbox) { - l2Target = _l2Target; - inbox = IInbox(_inbox); - } - - /** - * Sends an arbitrary message from one domain to another. - * - * @dev The caller needs to pay some ETH to cover the gas costs - * of the call on L2. Excess ETH that is not used by gas costs will - * be refunded to the `msg.sender` address on L2. - * - * @notice if a user does not desire immediate redemption, they should - * provide a DepositValue of at least CallValue + MaxSubmissionCost. - * If they do desire immediate execution, they should provide a DepositValue - * of at least CallValue + MaxSubmissionCost + (GasPrice x MaxGas). - * - * @param _calldata The L2 encoded message data. - * @param _maxGas Gas limit for immediate L2 execution attempt. - * @param _gasPriceBid L2 Gas price bid for immediate L2 execution attempt. - * @return Unique id to track the message request/transaction. - */ - function sendCrossDomainMessage( - bytes memory _calldata, - uint256 _maxGas, - uint256 _gasPriceBid - ) internal override returns (uint256) { - uint256 baseSubmissionCost = bridgingCost(_calldata.length); - require(msg.value >= baseSubmissionCost + (_maxGas * _gasPriceBid)); - - uint256 ticketID = inbox.createRetryableTicket{value: msg.value}( - l2Target, - 0, - baseSubmissionCost, - msg.sender, - msg.sender, - _maxGas, - _gasPriceBid, - _calldata - ); - - emit RetryableTicketCreated(ticketID); - return ticketID; - } - - function bridgingCost(uint256 _calldatasize) internal view override returns (uint256) { - (uint256 submissionCost, ) = arbRetryableTx.getSubmissionPrice(_calldatasize); - return submissionCost; - } - - function onlyCrossChainSender() internal override { - IOutbox outbox = IOutbox(inbox.bridge().activeOutbox()); - address l2Sender = outbox.l2ToL1Sender(); - require(l2Sender == l2Target, "Only L2 target"); - } -} diff --git a/contracts/src/bridge/arbitrum/ArbL2Bridge.sol b/contracts/src/bridge/arbitrum/ArbL2Bridge.sol deleted file mode 100644 index 2f3b12180..000000000 --- a/contracts/src/bridge/arbitrum/ArbL2Bridge.sol +++ /dev/null @@ -1,44 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** - * @authors: [@shalzz] - * @reviewers: [] - * @auditors: [] - * @bounties: [] - * @deployments: [] - */ - -pragma solidity ^0.8.0; - -import "./interfaces/IArbSys.sol"; -import "./AddressAliasHelper.sol"; - -import "../IL2Bridge.sol"; - -contract ArbL2Bridge is IL2Bridge { - address public l1Target; - IArbSys constant arbsys = IArbSys(address(100)); - - event L2ToL1TxCreated(uint256 indexed withdrawalId); - - constructor(address _l1Target) { - l1Target = _l1Target; - } - - /** - * Sends an arbitrary message from one domain to another. - * - * @param _calldata The L1 encoded message data. - * @return Unique id to track the message request/transaction. - */ - function sendCrossDomainMessage(bytes memory _calldata) internal override returns (uint256) { - uint256 withdrawalId = arbsys.sendTxToL1(l1Target, _calldata); - - emit L2ToL1TxCreated(withdrawalId); - return withdrawalId; - } - - function onlyCrossChainSender() internal override { - require(msg.sender == AddressAliasHelper.applyL1ToL2Alias(l1Target), "Only L1 target"); - } -} diff --git a/contracts/src/bridge/arbitrum/interfaces/IArbRetryableTx.sol b/contracts/src/bridge/arbitrum/interfaces/IArbRetryableTx.sol deleted file mode 100644 index 5143a22cd..000000000 --- a/contracts/src/bridge/arbitrum/interfaces/IArbRetryableTx.sol +++ /dev/null @@ -1,72 +0,0 @@ -pragma solidity >=0.7.0; - -/** - * @title precompiled contract in every Arbitrum chain for retryable transaction related data retrieval and interactions. Exists at 0x000000000000000000000000000000000000006E - */ -interface IArbRetryableTx { - /** - * @notice Redeem a redeemable tx. - * Revert if called by an L2 contract, or if txId does not exist, or if txId reverts. - * If this returns, txId has been completed and is no longer available for redemption. - * If this reverts, txId is still available for redemption (until it times out or is canceled). - @param txId unique identifier of retryable message: keccak256(keccak256(ArbchainId, inbox-sequence-number), uint(0) ) - */ - function redeem(bytes32 txId) external; - - /** - * @notice Return the minimum lifetime of redeemable txn. - * @return lifetime in seconds - */ - function getLifetime() external view returns (uint256); - - /** - * @notice Return the timestamp when ticketId will age out, or zero if ticketId does not exist. - * The timestamp could be in the past, because aged-out tickets might not be discarded immediately. - * @param ticketId unique ticket identifier - * @return timestamp for ticket's deadline - */ - function getTimeout(bytes32 ticketId) external view returns (uint256); - - /** - * @notice Return the price, in wei, of submitting a new retryable tx with a given calldata size. - * @param calldataSize call data size to get price of (in wei) - * @return (price, nextUpdateTimestamp). Price is guaranteed not to change until nextUpdateTimestamp. - */ - function getSubmissionPrice(uint256 calldataSize) external view returns (uint256, uint256); - - /** - * @notice Return the price, in wei, of extending the lifetime of ticketId by an additional lifetime period. Revert if ticketId doesn't exist. - * @param ticketId unique ticket identifier - * @return (price, nextUpdateTimestamp). Price is guaranteed not to change until nextUpdateTimestamp. - */ - function getKeepalivePrice(bytes32 ticketId) external view returns (uint256, uint256); - - /** - @notice Deposits callvalue into the sender's L2 account, then adds one lifetime period to the life of ticketId. - * If successful, emits LifetimeExtended event. - * Revert if ticketId does not exist, or if the timeout of ticketId is already at least one lifetime period in the future, or if the sender has insufficient funds (after the deposit). - * @param ticketId unique ticket identifier - * @return New timeout of ticketId. - */ - function keepalive(bytes32 ticketId) external payable returns (uint256); - - /** - * @notice Return the beneficiary of ticketId. - * Revert if ticketId doesn't exist. - * @param ticketId unique ticket identifier - * @return address of beneficiary for ticket - */ - function getBeneficiary(bytes32 ticketId) external view returns (address); - - /** - * @notice Cancel ticketId and refund its callvalue to its beneficiary. - * Revert if ticketId doesn't exist, or if called by anyone other than ticketId's beneficiary. - * @param ticketId unique ticket identifier - */ - function cancel(bytes32 ticketId) external; - - event TicketCreated(bytes32 indexed ticketId); - event LifetimeExtended(bytes32 indexed ticketId, uint256 newTimeout); - event Redeemed(bytes32 indexed ticketId); - event Canceled(bytes32 indexed ticketId); -} diff --git a/contracts/src/bridge/arbitrum/interfaces/IBridge.sol b/contracts/src/bridge/arbitrum/interfaces/IBridge.sol deleted file mode 100644 index 631fce68f..000000000 --- a/contracts/src/bridge/arbitrum/interfaces/IBridge.sol +++ /dev/null @@ -1,65 +0,0 @@ -// 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.8.0; - -interface IBridge { - event MessageDelivered( - uint256 indexed messageIndex, - bytes32 indexed beforeInboxAcc, - address inbox, - uint8 kind, - address sender, - bytes32 messageDataHash - ); - - event BridgeCallTriggered(address indexed outbox, address indexed destAddr, uint256 amount, bytes data); - - event InboxToggle(address indexed inbox, bool enabled); - - event OutboxToggle(address indexed outbox, bool enabled); - - 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); -} diff --git a/contracts/src/bridge/arbitrum/interfaces/IInbox.sol b/contracts/src/bridge/arbitrum/interfaces/IInbox.sol deleted file mode 100644 index 2b85aa0ed..000000000 --- a/contracts/src/bridge/arbitrum/interfaces/IInbox.sol +++ /dev/null @@ -1,81 +0,0 @@ -// 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.8.0; - -import "./IBridge.sol"; -import "./IMessageProvider.sol"; - -interface IInbox is IMessageProvider { - 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); - - function pauseCreateRetryables() external; - - function unpauseCreateRetryables() external; - - function startRewriteAddress() external; - - function stopRewriteAddress() external; -} diff --git a/contracts/src/bridge/arbitrum/interfaces/IMessageProvider.sol b/contracts/src/bridge/arbitrum/interfaces/IMessageProvider.sol deleted file mode 100644 index 76208e215..000000000 --- a/contracts/src/bridge/arbitrum/interfaces/IMessageProvider.sol +++ /dev/null @@ -1,25 +0,0 @@ -// 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.8.0; - -interface IMessageProvider { - event InboxMessageDelivered(uint256 indexed messageNum, bytes data); - - event InboxMessageDeliveredFromOrigin(uint256 indexed messageNum); -} diff --git a/contracts/src/bridge/arbitrum/interfaces/IOutbox.sol b/contracts/src/bridge/arbitrum/interfaces/IOutbox.sol deleted file mode 100644 index 9128a2049..000000000 --- a/contracts/src/bridge/arbitrum/interfaces/IOutbox.sol +++ /dev/null @@ -1,50 +0,0 @@ -// 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.8.0; - -interface IOutbox { - event OutboxEntryCreated( - uint256 indexed batchNum, - uint256 outboxEntryIndex, - bytes32 outputRoot, - uint256 numInBatch - ); - event OutBoxTransactionExecuted( - address indexed destAddr, - address indexed l2Sender, - uint256 indexed outboxEntryIndex, - uint256 transactionIndex - ); - - 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 l2ToL1BatchNum() external view returns (uint256); - - function l2ToL1OutputId() external view returns (bytes32); - - function processOutgoingMessages(bytes calldata sendsData, uint256[] calldata sendLengths) external; - - function outboxEntryExists(uint256 batchNum) external view returns (bool); -} diff --git a/contracts/src/bridge/gnosis-chain/GnosisL1Bridge.sol b/contracts/src/bridge/gnosis-chain/GnosisL1Bridge.sol deleted file mode 100644 index 7f9050ce2..000000000 --- a/contracts/src/bridge/gnosis-chain/GnosisL1Bridge.sol +++ /dev/null @@ -1,50 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** - * @authors: [@shalzz] - * @reviewers: [] - * @auditors: [] - * @bounties: [] - * @deployments: [] - */ - -pragma solidity ^0.8.0; - -import "./interfaces/IAMB.sol"; - -import "../IL1Bridge.sol"; - -contract GnosisL1Bridge is IL1Bridge { - address public l2Target; - IAMB amb; - - constructor(address _l2Target, IAMB _amb) { - l2Target = _l2Target; - amb = _amb; - } - - function sendCrossDomainMessage( - bytes memory _calldata, - uint256 _maxGas, - uint256 _gasPriceBid - ) internal override returns (uint256) { - bytes32 id = amb.requireToPassMessage(l2Target, _calldata, amb.maxGasPerTx()); - return uint256(id); - } - - /** - * @dev The xDai bridge gas cost doesn't depend on the calldata size - * - */ - function bridgingCost( - uint256 /* _calldatasize */ - ) internal view override returns (uint256) { - return 0; - } - - function onlyCrossChainSender() internal override { - require(msg.sender == address(amb), "Only AMB allowed"); - // require(amb.messageSourceChainId() == foreignChainId, "Only foreign chain allowed"); - require(amb.messageSender() == l2Target, "Only foreign gateway allowed"); - } -} diff --git a/contracts/src/bridge/gnosis-chain/GnosisL2Bridge.sol b/contracts/src/bridge/gnosis-chain/GnosisL2Bridge.sol deleted file mode 100644 index d35e07046..000000000 --- a/contracts/src/bridge/gnosis-chain/GnosisL2Bridge.sol +++ /dev/null @@ -1,36 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** - * @authors: [@shalzz] - * @reviewers: [] - * @auditors: [] - * @bounties: [] - * @deployments: [] - */ - -pragma solidity ^0.8.0; - -import "./interfaces/IAMB.sol"; - -import "../IL2Bridge.sol"; - -contract GnosisL2Bridge is IL2Bridge { - address public l1Target; - IAMB amb; - - constructor(address _l1Target, IAMB _amb) { - l1Target = _l1Target; - amb = _amb; - } - - function sendCrossDomainMessage(bytes memory _calldata) internal override returns (uint256) { - bytes32 id = amb.requireToPassMessage(l1Target, _calldata, amb.maxGasPerTx()); - return uint256(id); - } - - function onlyCrossChainSender() internal override { - require(msg.sender == address(amb), "Only AMB allowed"); - // require(amb.messageSourceChainId() == homeChainId, "Only home chain allowed"); - require(amb.messageSender() == l1Target, "Only home gateway allowed"); - } -} diff --git a/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol new file mode 100644 index 000000000..bbb50572c --- /dev/null +++ b/contracts/src/bridge/interfaces/IFastBridgeReceiver.sol @@ -0,0 +1,13 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IFastBridgeReceiver { + function claim(bytes32 _messageHash) external payable; + + function verifyAndRelay(bytes32 _messageHash, bytes memory _calldata) external; + + function withdrawClaimDeposit(bytes32 _messageHash) external; + + function claimDeposit() external view returns (uint256 amount); +} diff --git a/contracts/src/bridge/interfaces/IFastBridgeSender.sol b/contracts/src/bridge/interfaces/IFastBridgeSender.sol new file mode 100644 index 000000000..ee097700b --- /dev/null +++ b/contracts/src/bridge/interfaces/IFastBridgeSender.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface IFastBridgeSender { + /** + * Sends an arbitrary message from one domain to another + * via the fast bridge mechanism + * + * TODO: probably needs some access control either on the sender side + * or the receiver side + * + * @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; +} diff --git a/contracts/src/bridge/interfaces/ISafeBridge.sol b/contracts/src/bridge/interfaces/ISafeBridge.sol new file mode 100644 index 000000000..b3aef94c4 --- /dev/null +++ b/contracts/src/bridge/interfaces/ISafeBridge.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +interface ISafeBridge { + /** + * Sends an arbitrary message from one domain to another. + * + * @param _receiver The L1 contract address who will receive the calldata + * @param _calldata The L2 encoded message data. + * @return Unique id to track the message request/transaction. + */ + function sendSafe(address _receiver, bytes memory _calldata) external payable returns (uint256); +} diff --git a/contracts/src/bridge/arbitrum/AddressAliasHelper.sol b/contracts/src/bridge/interfaces/arbitrum/AddressAliasHelper.sol similarity index 100% rename from contracts/src/bridge/arbitrum/AddressAliasHelper.sol rename to contracts/src/bridge/interfaces/arbitrum/AddressAliasHelper.sol diff --git a/contracts/src/bridge/arbitrum/interfaces/IArbSys.sol b/contracts/src/bridge/interfaces/arbitrum/IArbSys.sol similarity index 100% rename from contracts/src/bridge/arbitrum/interfaces/IArbSys.sol rename to contracts/src/bridge/interfaces/arbitrum/IArbSys.sol diff --git a/contracts/src/bridge/gnosis-chain/interfaces/IAMB.sol b/contracts/src/bridge/interfaces/gnosis-chain/IAMB.sol similarity index 100% rename from contracts/src/bridge/gnosis-chain/interfaces/IAMB.sol rename to contracts/src/bridge/interfaces/gnosis-chain/IAMB.sol diff --git a/contracts/src/gateway/BaseHomeGateway.sol b/contracts/src/gateway/BaseHomeGateway.sol deleted file mode 100644 index 8c997c295..000000000 --- a/contracts/src/gateway/BaseHomeGateway.sol +++ /dev/null @@ -1,118 +0,0 @@ -// SPDX-License-Identifier: MIT - -/** - * @authors: [@shalzz] - * @reviewers: [] - * @auditors: [] - * @bounties: [] - * @deployments: [] - */ - -pragma solidity ^0.8.0; - -import "../arbitration/IArbitrator.sol"; -import "../bridge/IL2Bridge.sol"; - -import "./interfaces/IHomeGateway.sol"; -import "./interfaces/IForeignGateway.sol"; - -abstract contract BaseHomeGateway is IL2Bridge, IHomeGateway { - mapping(uint256 => bytes32) public disputeIDtoHash; - mapping(bytes32 => uint256) public disputeHashtoID; - - IForeignGateway public foreignGateway; - IArbitrator public arbitrator; - uint256 public chainID; - - struct RelayedData { - uint256 choices; - uint256 arbitrationCost; - address forwarder; - bytes extraData; - } - mapping(bytes32 => RelayedData) public disputeHashtoRelayedData; - - modifier onlyFromL1() { - onlyCrossChainSender(); - _; - } - - constructor(IArbitrator _arbitrator, IForeignGateway _foreignGateway) { - arbitrator = _arbitrator; - foreignGateway = _foreignGateway; - - uint256 id; - assembly { - id := chainid() - } - chainID = id; - - emit MetaEvidence(0, "BRIDGE"); - } - - function rule(uint256 _disputeID, uint256 _ruling) external { - 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.forwarder); - - sendCrossDomainMessage(data); - } - - /** - * @dev Handle the cross-chain call from the foreign gateway. - * - * @param _disputeHash disputeHash - * @param _choices number of ruling choices - * @param _extraData extraData - * @param _arbitrationCost We get the actual arbitrationCost paid by the - * arbitrable here in case they paid more than the min arbitrationCost - */ - function handleIncomingDispute( - bytes32 _disputeHash, - uint256 _choices, - bytes calldata _extraData, - uint256 _arbitrationCost - ) external onlyFromL1 { - RelayedData storage relayedData = disputeHashtoRelayedData[_disputeHash]; - relayedData.choices = _choices; - relayedData.extraData = _extraData; - relayedData.arbitrationCost = _arbitrationCost; - } - - function relayCreateDispute(bytes32 _disputeHash) external payable { - RelayedData storage relayedData = disputeHashtoRelayedData[_disputeHash]; - require(relayedData.forwarder == address(0), "Dispute already forwarded"); - - require(msg.value >= relayedData.arbitrationCost, "Not enough arbitration cost paid"); - - uint256 disputeID = arbitrator.createDispute{value: msg.value}(relayedData.choices, relayedData.extraData); - disputeIDtoHash[disputeID] = _disputeHash; - disputeHashtoID[_disputeHash] = disputeID; - relayedData.forwarder = msg.sender; - - emit Dispute(arbitrator, disputeID, 0, 0); - } - - function homeDisputeHashToID(bytes32 _disputeHash) external view returns (uint256) { - return disputeHashtoID[_disputeHash]; - } - - function homeToForeignDisputeID(uint256 _homeDisputeID) external view returns (uint256) { - bytes32 disputeHash = disputeIDtoHash[_homeDisputeID]; - require(disputeHash != 0, "Dispute does not exist"); - - return foreignGateway.foreignDisputeHashToID(disputeHash); - } - - function foreignChainID(uint256 _homeDisputeID) external view returns (uint256) { - return foreignGateway.chainID(); - } - - function foreignBridge(uint256 _homeDisputeID) external view returns (address) { - return address(foreignGateway); - } -} diff --git a/contracts/src/gateway/BaseForeignGateway.sol b/contracts/src/gateway/ForeignGateway.sol similarity index 58% rename from contracts/src/gateway/BaseForeignGateway.sol rename to contracts/src/gateway/ForeignGateway.sol index efa6d0fb8..0b5114dc0 100644 --- a/contracts/src/gateway/BaseForeignGateway.sol +++ b/contracts/src/gateway/ForeignGateway.sol @@ -11,38 +11,49 @@ pragma solidity ^0.8.0; import "../arbitration/IArbitrable.sol"; -import "../bridge/IL1Bridge.sol"; +import "../bridge/interfaces/IFastBridgeReceiver.sol"; -import "./interfaces/IHomeGateway.sol"; import "./interfaces/IForeignGateway.sol"; -abstract contract BaseForeignGateway is IL1Bridge, IForeignGateway { +contract ForeignGateway is IForeignGateway { // The global default minimum number of jurors in a dispute. uint256 public constant MIN_JURORS = 3; // @dev Note the disputeID needs to start from one as // the KlerosV1 proxy governor depends on this implementation. + // We now also depend on localDisputeID not being zero + // at any point. uint256 internal localDisputeID = 1; // feeForJuror by subcourtID uint256[] internal feeForJuror; + uint256 public chainID; + uint256 public homeChainID; struct DisputeData { uint248 id; bool ruled; address arbitrable; uint256 paid; - address forwarder; + address relayer; } - mapping(uint256 => bytes32) public disputeIDtoHash; mapping(bytes32 => DisputeData) public disputeHashtoDisputeData; - IHomeGateway public homeGateway; - uint256 public chainID; address public governor; - - modifier onlyFromL2() { - onlyCrossChainSender(); + IFastBridgeReceiver public fastbridge; + address public homeGateway; + + event OutgoingDispute( + bytes32 disputeHash, + bytes32 blockhash, + uint256 localDisputeID, + uint256 _choices, + bytes _extraData, + address arbitrable + ); + + modifier onlyFromFastBridge() { + require(address(fastbridge) == msg.sender, "Access not allowed: Fast Bridge only."); _; } @@ -53,18 +64,20 @@ abstract contract BaseForeignGateway is IL1Bridge, IForeignGateway { constructor( address _governor, - IHomeGateway _homeGateway, - uint256[] memory _feeForJuror + IFastBridgeReceiver _fastbridge, + uint256[] memory _feeForJuror, + address _homeGateway, + uint256 _homeChainID ) { governor = _governor; - homeGateway = _homeGateway; + fastbridge = _fastbridge; feeForJuror = _feeForJuror; + homeGateway = _homeGateway; + homeChainID = _homeChainID; - uint256 id; assembly { - id := chainid() + sstore(chainID.slot, chainid()) } - chainID = id; } /** @dev Changes the `feeForJuror` property value of a specified subcourt. @@ -88,62 +101,30 @@ abstract contract BaseForeignGateway is IL1Bridge, IForeignGateway { blockhash(block.number - 1), "createDispute", disputeID, - arbitrationCost(_extraData), _choices, _extraData, msg.sender + // TODO: actual arbitration Cost + // nbVotes * feeForJuror[subcourtID] // we calculate the min amount required for nbVotes ) ); - disputeIDtoHash[disputeID] = disputeHash; disputeHashtoDisputeData[disputeHash] = DisputeData({ id: uint248(disputeID), arbitrable: msg.sender, paid: msg.value, - forwarder: address(0), + relayer: address(0), ruled: false }); - bytes4 methodSelector = IHomeGateway.handleIncomingDispute.selector; - bytes memory data = abi.encodeWithSelector( - methodSelector, - disputeHash, - _choices, - _extraData, - nbVotes * feeForJuror[subcourtID] // we calculate the min amount required for nbVotes - ); - - // We only pay for the submissionPrice gas cost - // which is minimum gas cost required for submitting a - // arbitrum retryable ticket to the retry buffer for - // bridge to L2. - // For immediate inclusion a user/bot needs to pay (GasPrice x MaxGas) - // with the associated ticketId that is emitted by this function - // after the ticket is successfully submitted. - // For more details, see: - // https://developer.offchainlabs.com/docs/l1_l2_messages#retryable-tickets-contract-api - // - // We do NOT forward the arbitrationCost ETH funds to the HomeGateway yet, - // only the calldata. - sendCrossDomainMessage(data, 0, 0); - + emit OutgoingDispute(disputeHash, blockhash(block.number - 1), disputeID, _choices, _extraData, msg.sender); emit DisputeCreation(disputeID, IArbitrable(msg.sender)); } function arbitrationCost(bytes calldata _extraData) public view returns (uint256 cost) { (uint96 subcourtID, uint256 minJurors) = extraDataToSubcourtIDMinJurors(_extraData); - // Calculate the size of calldata that will be passed to the L2 bridge - // as that is a factor for the bridging cost. - // Calldata size of handleIncomingDispute: - // methodId + bytes32 disputeHash + uint256 _choices + bytes _extraData + uint256 _arbitrationCost) - // 4 + 32 + 32 + dynamic + 32 - uint256 calldatasize = 100 + _extraData.length; - - uint256 bridgeCost = bridgingCost(calldatasize); - uint256 arbCost = feeForJuror[subcourtID] * minJurors; - - return bridgeCost + arbCost; + cost = feeForJuror[subcourtID] * minJurors; } /** @@ -152,13 +133,15 @@ abstract contract BaseForeignGateway is IL1Bridge, IForeignGateway { function relayRule( bytes32 _disputeHash, uint256 _ruling, - address _forwarder - ) external onlyFromL2 { + address _relayer + ) external onlyFromFastBridge { DisputeData storage dispute = disputeHashtoDisputeData[_disputeHash]; + require(dispute.id != 0, "Dispute does not exist"); require(!dispute.ruled, "Cannot rule twice"); + dispute.ruled = true; - dispute.forwarder = _forwarder; + dispute.relayer = _relayer; IArbitrable arbitrable = IArbitrable(dispute.arbitrable); arbitrable.rule(dispute.id, _ruling); @@ -166,32 +149,18 @@ abstract contract BaseForeignGateway is IL1Bridge, IForeignGateway { function withdrawFees(bytes32 _disputeHash) external { DisputeData storage dispute = disputeHashtoDisputeData[_disputeHash]; + require(dispute.id != 0, "Dispute does not exist"); require(dispute.ruled, "Not ruled yet"); uint256 amount = dispute.paid; dispute.paid = 0; - payable(dispute.forwarder).transfer(amount); + payable(dispute.relayer).transfer(amount); } - function foreignDisputeHashToID(bytes32 _disputeHash) external view returns (uint256) { + function disputeHashToForeignID(bytes32 _disputeHash) external view returns (uint256) { return disputeHashtoDisputeData[_disputeHash].id; } - function disputeID(uint256 _foreignDisputeID) external view returns (uint256) { - bytes32 disputeHash = disputeIDtoHash[_foreignDisputeID]; - require(disputeHash != 0, "Dispute does not exist"); - - return homeGateway.homeDisputeHashToID(disputeHash); - } - - function homeChainID(uint256 _disputeID) external view returns (uint256) { - return homeGateway.chainID(); - } - - function homeBridge(uint256 _disputeID) external view returns (address) { - return address(homeGateway); - } - function extraDataToSubcourtIDMinJurors(bytes memory _extraData) internal view diff --git a/contracts/src/gateway/HomeGateway.sol b/contracts/src/gateway/HomeGateway.sol new file mode 100644 index 000000000..3fdba3775 --- /dev/null +++ b/contracts/src/gateway/HomeGateway.sol @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: MIT + +/** + * @authors: [@shalzz] + * @reviewers: [] + * @auditors: [] + * @bounties: [] + * @deployments: [] + */ + +pragma solidity ^0.8.0; + +import "../arbitration/IArbitrator.sol"; +import "../bridge/interfaces/IFastBridgeSender.sol"; + +import "./interfaces/IForeignGateway.sol"; +import "./interfaces/IHomeGateway.sol"; + +contract HomeGateway is IHomeGateway { + mapping(uint256 => bytes32) public disputeIDtoHash; + mapping(bytes32 => uint256) public disputeHashtoID; + + IArbitrator public arbitrator; + IFastBridgeSender public fastbridge; + address public foreignGateway; + uint256 public chainID; + uint256 public foreignChainID; + + struct RelayedData { + uint256 arbitrationCost; + address relayer; + } + mapping(bytes32 => RelayedData) public disputeHashtoRelayedData; + + constructor( + IArbitrator _arbitrator, + IFastBridgeSender _fastbridge, + address _foreignGateway, + uint256 _foreignChainID + ) { + arbitrator = _arbitrator; + fastbridge = _fastbridge; + foreignGateway = _foreignGateway; + foreignChainID = _foreignChainID; + + assembly { + sstore(chainID.slot, chainid()) + } + + emit MetaEvidence(0, "BRIDGE"); + } + + /** + * @dev Provide the same parameters as on the originalChain while creating a + * dispute. Providing incorrect parameters will create a different hash + * than on the originalChain and will not affect the actual dispute/arbitrable's + * ruling. + * + * @param _originalChainID originalChainId + * @param _originalBlockHash originalBlockHash + * @param _originalDisputeID originalDisputeID + * @param _choices number of ruling choices + * @param _extraData extraData + * @param _arbitrable arbitrable + */ + function relayCreateDispute( + uint256 _originalChainID, + bytes32 _originalBlockHash, + uint256 _originalDisputeID, + uint256 _choices, + bytes calldata _extraData, + address _arbitrable + ) external payable { + bytes32 disputeHash = keccak256( + abi.encodePacked( + _originalChainID, + _originalBlockHash, + "createDispute", + _originalDisputeID, + _choices, + _extraData, + _arbitrable + ) + ); + RelayedData storage relayedData = disputeHashtoRelayedData[disputeHash]; + require(relayedData.relayer == address(0), "Dispute already relayed"); + + // TODO: will mostly be replaced by the actual arbitrationCost paid on the foreignChain. + relayedData.arbitrationCost = arbitrator.arbitrationCost(_extraData); + require(msg.value >= relayedData.arbitrationCost, "Not enough arbitration cost paid"); + + uint256 disputeID = arbitrator.createDispute{value: msg.value}(_choices, _extraData); + disputeIDtoHash[disputeID] = disputeHash; + disputeHashtoID[disputeHash] = disputeID; + relayedData.relayer = msg.sender; + + emit Dispute(arbitrator, disputeID, 0, 0); + } + + function rule(uint256 _disputeID, uint256 _ruling) external { + 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); + + fastbridge.sendFast(foreignGateway, data); + } + + function disputeHashToHomeID(bytes32 _disputeHash) external view returns (uint256) { + return disputeHashtoID[_disputeHash]; + } +} diff --git a/contracts/src/gateway/arbitrum/ArbitrumGateway.sol b/contracts/src/gateway/arbitrum/ArbitrumGateway.sol deleted file mode 100644 index c30bee17f..000000000 --- a/contracts/src/gateway/arbitrum/ArbitrumGateway.sol +++ /dev/null @@ -1,17 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../../arbitration/IArbitrator.sol"; -import "../../bridge/arbitrum/ArbL2Bridge.sol"; - -import "../interfaces/IHomeGateway.sol"; -import "../BaseHomeGateway.sol"; - -contract ArbitrumGateway is BaseHomeGateway, ArbL2Bridge { - constructor( - IArbitrator _arbitrator, - IForeignGateway _foreignGateway, - address _l1Target - ) BaseHomeGateway(_arbitrator, _foreignGateway) ArbL2Bridge(_l1Target) {} -} diff --git a/contracts/src/gateway/arbitrum/EthereumToArbitrumGateway.sol b/contracts/src/gateway/arbitrum/EthereumToArbitrumGateway.sol deleted file mode 100644 index a20578c20..000000000 --- a/contracts/src/gateway/arbitrum/EthereumToArbitrumGateway.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../../bridge/arbitrum/ArbL1Bridge.sol"; - -import "../interfaces/IForeignGateway.sol"; -import "../BaseForeignGateway.sol"; - -contract EthereumToArbitrumGateway is BaseForeignGateway, ArbL1Bridge { - constructor( - address _governor, - IHomeGateway _homeGateway, - uint256[] memory _feeForJuror, - address _l2Target, - address _inbox - ) BaseForeignGateway(_governor, _homeGateway, _feeForJuror) ArbL1Bridge(_l2Target, _inbox) {} -} diff --git a/contracts/src/gateway/arbitrum/GnosisToEthereumGateway.sol b/contracts/src/gateway/arbitrum/GnosisToEthereumGateway.sol deleted file mode 100644 index 4ae3c1222..000000000 --- a/contracts/src/gateway/arbitrum/GnosisToEthereumGateway.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../../bridge/gnosis-chain/GnosisL1Bridge.sol"; -import "../../bridge/gnosis-chain/interfaces/IAMB.sol"; - -import "../interfaces/IForeignGateway.sol"; -import "../BaseForeignGateway.sol"; - -contract EthereumGateway is BaseForeignGateway, GnosisL1Bridge { - constructor( - address _governor, - IHomeGateway _homeGateway, - uint256[] memory _feeForJuror, - address _l2Target, - IAMB _amb - ) BaseForeignGateway(_governor, _homeGateway, _feeForJuror) GnosisL1Bridge(_l2Target, _amb) {} -} diff --git a/contracts/src/gateway/gnosis-chain/GnosisGateway.sol b/contracts/src/gateway/gnosis-chain/GnosisGateway.sol deleted file mode 100644 index 062f3551b..000000000 --- a/contracts/src/gateway/gnosis-chain/GnosisGateway.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../../arbitration/IArbitrator.sol"; -import "../../bridge/gnosis-chain/GnosisL2Bridge.sol"; -import "../../bridge/gnosis-chain/interfaces/IAMB.sol"; - -import "../interfaces/IHomeGateway.sol"; -import "../BaseHomeGateway.sol"; - -contract GnosisToEthereumGateway is BaseHomeGateway, GnosisL2Bridge { - constructor( - IArbitrator _arbitrator, - IForeignGateway _foreignGateway, - address _l1Target, - IAMB _amb - ) BaseHomeGateway(_arbitrator, _foreignGateway) GnosisL2Bridge(_l1Target, _amb) {} -} diff --git a/contracts/src/gateway/interfaces/IForeignEvidence.sol b/contracts/src/gateway/interfaces/IForeignEvidence.sol deleted file mode 100644 index 88b4d0538..000000000 --- a/contracts/src/gateway/interfaces/IForeignEvidence.sol +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -interface IForeignEvidence { - function disputeID(uint256 _foreignDisputeID) external view returns (uint256); - - function homeChainID(uint256 _disputeID) external view returns (uint256); - - function homeBridge(uint256 _disputeID) external view returns (address); -} diff --git a/contracts/src/gateway/interfaces/IForeignGateway.sol b/contracts/src/gateway/interfaces/IForeignGateway.sol index 04de45ba0..a507b0ed3 100644 --- a/contracts/src/gateway/interfaces/IForeignGateway.sol +++ b/contracts/src/gateway/interfaces/IForeignGateway.sol @@ -3,13 +3,10 @@ pragma solidity ^0.8.0; import "../../arbitration/IArbitrator.sol"; -import "./IForeignEvidence.sol"; -interface IForeignGateway is IArbitrator, IForeignEvidence { +interface IForeignGateway is IArbitrator { function chainID() external view returns (uint256); - function foreignDisputeHashToID(bytes32 _disputeHash) external view returns (uint256); - /** * Relay the rule call from the home gateway to the arbitrable. */ @@ -20,4 +17,12 @@ interface IForeignGateway is IArbitrator, IForeignEvidence { ) external; function withdrawFees(bytes32 _disputeHash) external; + + // For cross-chain Evidence standard + + function disputeHashToForeignID(bytes32 _disputeHash) external view returns (uint256); + + function homeChainID() external view returns (uint256); + + function homeGateway() external view returns (address); } diff --git a/contracts/src/gateway/interfaces/IHomeEvidence.sol b/contracts/src/gateway/interfaces/IHomeEvidence.sol deleted file mode 100644 index bda0011d4..000000000 --- a/contracts/src/gateway/interfaces/IHomeEvidence.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT - -pragma solidity ^0.8.0; - -import "../../evidence/IEvidence.sol"; - -interface IHomeEvidence is IEvidence { - function homeToForeignDisputeID(uint256 _homeDisputeID) external view returns (uint256); - - function foreignChainID(uint256 _homeDisputeID) external view returns (uint256); - - function foreignBridge(uint256 _homeDisputeID) external view returns (address); -} diff --git a/contracts/src/gateway/interfaces/IHomeGateway.sol b/contracts/src/gateway/interfaces/IHomeGateway.sol index 15ce5f498..581db61bd 100644 --- a/contracts/src/gateway/interfaces/IHomeGateway.sol +++ b/contracts/src/gateway/interfaces/IHomeGateway.sol @@ -3,22 +3,25 @@ pragma solidity ^0.8.0; import "../../arbitration/IArbitrable.sol"; -import "./IHomeEvidence.sol"; +import "../../evidence/IEvidence.sol"; -interface IHomeGateway is IArbitrable, IHomeEvidence { +interface IHomeGateway is IArbitrable, IEvidence { function chainID() external view returns (uint256); - function homeDisputeHashToID(bytes32 _disputeHash) external view returns (uint256); - - /** - * Handle the cross-chain call from the foreign gateway. - */ - function handleIncomingDispute( - bytes32 _disputeHash, + function relayCreateDispute( + uint256 _originalChainID, + bytes32 _originalBlockHash, + uint256 _originalDisputeID, uint256 _choices, bytes calldata _extraData, - uint256 numOfJurors - ) external; + address _arbitrable + ) external payable; + + // For cross-chain Evidence standard + + function disputeHashToHomeID(bytes32 _disputeHash) external view returns (uint256); + + function foreignChainID() external view returns (uint256); - function relayCreateDispute(bytes32 _disputeHash) external payable; + function foreignGateway() external view returns (address); }