Skip to content

Partial Fast Bridge #36

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions contracts/src/bridge/FastBridgeReceiver.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}
78 changes: 78 additions & 0 deletions contracts/src/bridge/FastBridgeSender.sol
Original file line number Diff line number Diff line change
@@ -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.");
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason I didn't add this initially was to make the fast bridge app-agnostic.


// 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()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bridging from L2 to L1 does not need any bridging cost/fees.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. Given the existing native bridges, the fees would be required only for L1 to L2, and we are not using the SafeBridge for it right now. So it's more for future proofing.

bytes memory encodedData = abi.encode(_receiver, _calldata);
safebridge.sendSafe{value: msg.value}(address(fastBridgeReceiver), encodedData);
}
}
36 changes: 0 additions & 36 deletions contracts/src/bridge/IL1Bridge.sol

This file was deleted.

19 changes: 0 additions & 19 deletions contracts/src/bridge/IL2Bridge.sol

This file was deleted.

29 changes: 29 additions & 0 deletions contracts/src/bridge/SafeBridgeArbitrum.sol
Original file line number Diff line number Diff line change
@@ -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;
}
}
27 changes: 27 additions & 0 deletions contracts/src/bridge/SafeBridgeGnosis.sol
Original file line number Diff line number Diff line change
@@ -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);
}
}
81 changes: 0 additions & 81 deletions contracts/src/bridge/arbitrum/ArbL1Bridge.sol

This file was deleted.

Loading