-
Notifications
You must be signed in to change notification settings - Fork 49
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
Changes from all commits
037ac8f
5e049b4
2bc7e15
312d2a8
dfe5ee8
6981ded
d8e4d50
1194070
4adff44
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
} | ||
} |
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."); | ||
|
||
// 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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bridging from L2 to L1 does not need any bridging cost/fees. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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); | ||
} | ||
} |
This file was deleted.
This file was deleted.
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; | ||
} | ||
} |
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); | ||
} | ||
} |
This file was deleted.
There was a problem hiding this comment.
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.