Skip to content
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

feat(contracts-rfq): relay/prove/claim with different address [SLT-130] #3138

Merged
merged 19 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"files.trimTrailingWhitespace": true,
"solidity.packageDefaultDependenciesContractsDirectory": "contracts",
"solidity.packageDefaultDependenciesDirectory": "lib",
"solidity.compileUsingRemoteVersion": "v0.8.17+commit.8df45f5f",
"solidity.compileUsingRemoteVersion": "v0.8.24+commit.e11b9ed9",
parodime marked this conversation as resolved.
Show resolved Hide resolved
"solidity.formatter": "prettier",
"solidity.defaultCompiler": "remote",
"tailwindCSS.classAttributes": [
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/Admin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

Check warning

Code scanning / Slither

Different pragma directives are used Warning

3 different versions of Solidity are used:
- Version constraint ^0.8.20 is used by:
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
- Version constraint 0.8.20 is used by:
-0.8.20
- Version constraint ^0.8.4 is used by:
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4

Check warning

Code scanning / Slither

Different pragma directives are used Warning

3 different versions of Solidity are used:
- Version constraint ^0.8.20 is used by:
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
-^0.8.20
- Version constraint 0.8.24 is used by:
-0.8.24
- Version constraint ^0.8.4 is used by:
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4
-^0.8.4

Check warning

Code scanning / Slither

Incorrect versions of Solidity Warning

Version constraint ^0.8.20 contains known severe issues (https://solidity.readthedocs.io/en/latest/bugs.html)
- VerbatimInvalidDeduplication
- FullInlinerNonExpressionSplitArgumentEvaluationOrder
- MissingSideEffectsOnSelectorAccess.
It is used by:
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20

Check warning

Code scanning / Slither

Incorrect versions of Solidity Warning

Version constraint ^0.8.20 contains known severe issues (https://solidity.readthedocs.io/en/latest/bugs.html)
- VerbatimInvalidDeduplication
- FullInlinerNonExpressionSplitArgumentEvaluationOrder
- MissingSideEffectsOnSelectorAccess.
It is used by:
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20

Check warning

Code scanning / Slither

Incorrect versions of Solidity Warning

Version constraint ^0.8.20 contains known severe issues (https://solidity.readthedocs.io/en/latest/bugs.html)
- VerbatimInvalidDeduplication
- FullInlinerNonExpressionSplitArgumentEvaluationOrder
- MissingSideEffectsOnSelectorAccess.
It is used by:
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20
- ^0.8.20

import {AccessControlEnumerable} from "@openzeppelin/contracts/access/extensions/AccessControlEnumerable.sol";

Expand Down
287 changes: 287 additions & 0 deletions packages/contracts-rfq/contracts/FastBridgeV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "./libs/Errors.sol";
import {UniversalTokenLib} from "./libs/UniversalToken.sol";

import {Admin} from "./Admin.sol";
import {IFastBridge} from "./interfaces/IFastBridge.sol";
import {IFastBridgeV2} from "./interfaces/IFastBridgeV2.sol";

contract FastBridgeV2 is IFastBridge, IFastBridgeV2, Admin {
parodime marked this conversation as resolved.
Show resolved Hide resolved
using SafeERC20 for IERC20;
using UniversalTokenLib for address;

/// @notice Dispute period for relayed transactions
uint256 public constant DISPUTE_PERIOD = 30 minutes;

/// @notice Delay for a transaction after which it could be permisionlessly refunded
uint256 public constant REFUND_DELAY = 7 days;

/// @notice Minimum deadline period to relay a requested bridge transaction
uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes;

enum BridgeStatus {
NULL, // doesn't exist yet
REQUESTED,
RELAYER_PROVED,
RELAYER_CLAIMED,
REFUNDED
}

/// @notice Status of the bridge tx on origin chain
mapping(bytes32 => BridgeStatus) public bridgeStatuses;
/// @notice Proof of relayed bridge tx on origin chain
mapping(bytes32 => BridgeProof) public bridgeProofs;
/// @notice Whether bridge has been relayed on destination chain
mapping(bytes32 => bool) public bridgeRelays;

/// @dev to prevent replays
uint256 public nonce;
// @dev the block the contract was deployed at
uint256 public immutable deployBlock;

constructor(address _owner) Admin(_owner) {
deployBlock = block.number;
}

/// @notice Pulls a requested token from the user to the requested recipient.
/// @dev Be careful of re-entrancy issues when msg.value > 0 and recipient != address(this)
function _pullToken(address recipient, address token, uint256 amount) internal returns (uint256 amountPulled) {
if (token != UniversalTokenLib.ETH_ADDRESS) {
token.assertIsContract();
// Record token balance before transfer
amountPulled = IERC20(token).balanceOf(recipient);
// Token needs to be pulled only if msg.value is zero
// This way user can specify WETH as the origin asset
IERC20(token).safeTransferFrom(msg.sender, recipient, amount);
// Use the difference between the recorded balance and the current balance as the amountPulled
amountPulled = IERC20(token).balanceOf(recipient) - amountPulled;
} else {
// Otherwise, we need to check that ETH amount matches msg.value
if (amount != msg.value) revert MsgValueIncorrect();
// Transfer value to recipient if not this address
if (recipient != address(this)) token.universalTransfer(recipient, amount);
// We will forward msg.value in the external call later, if recipient is not this contract
amountPulled = msg.value;
}
}
Comment on lines +51 to +70
Copy link
Contributor

Choose a reason for hiding this comment

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

Address Reentrancy in _pullToken Function

The _pullToken function performs external calls that could introduce reentrancy risks, especially when transferring ETH.

Recommendation:

  • Ensure that all functions calling _pullToken are protected with nonReentrant.
  • Follow the checks-effects-interactions pattern by updating state before external calls.


/// @inheritdoc IFastBridge
function getBridgeTransaction(bytes memory request) public pure returns (BridgeTransaction memory) {
return abi.decode(request, (BridgeTransaction));
}

/// @inheritdoc IFastBridge
function bridge(BridgeParams memory params) external payable {
// check bridge params
if (params.dstChainId == block.chainid) revert ChainIncorrect();
if (params.originAmount == 0 || params.destAmount == 0) revert AmountIncorrect();
if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress();
if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort();

// transfer tokens to bridge contract
// @dev use returned originAmount in request in case of transfer fees
uint256 originAmount = _pullToken(address(this), params.originToken, params.originAmount);

// track amount of origin token owed to protocol
uint256 originFeeAmount;

Check warning

Code scanning / Slither

Uninitialized local variables Medium

if (protocolFeeRate > 0) originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;
originAmount -= originFeeAmount; // remove from amount used in request as not relevant for relayers
Comment on lines +90 to +92
Copy link
Contributor

Choose a reason for hiding this comment

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

Declare Missing Variables and Constants Used in Calculations

The variables protocolFeeRate, FEE_BPS, protocolFees, and chainGasAmount are used but not declared in the contract. This will result in compilation errors.

Please declare these variables and constants. For example:

+uint256 public protocolFeeRate; // Fee rate set by the protocol
+uint256 public constant FEE_BPS = 10_000; // Basis points for fee calculation
+mapping(address => uint256) public protocolFees; // Accumulated protocol fees per token
+uint256 public chainGasAmount; // Gas amount for cross-chain transactions

Also applies to: 150-151, 240-240


// set status to requested
bytes memory request = abi.encode(
BridgeTransaction({
originChainId: uint32(block.chainid),
destChainId: params.dstChainId,
originSender: params.sender,
destRecipient: params.to,
originToken: params.originToken,
destToken: params.destToken,
originAmount: originAmount,
destAmount: params.destAmount,
originFeeAmount: originFeeAmount,
sendChainGas: params.sendChainGas,
deadline: params.deadline,
nonce: nonce++ // increment nonce on every bridge
})
);
bytes32 transactionId = keccak256(request);
bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;

emit BridgeRequested(
transactionId,
params.sender,
request,
params.dstChainId,
params.originToken,
params.destToken,
originAmount,
params.destAmount,
params.sendChainGas
);
}
Comment on lines +78 to +125
Copy link
Contributor

Choose a reason for hiding this comment

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

Add Reentrancy Protection to bridge Function

The bridge function is an external payable function that involves token transfers via _pullToken, which may invoke external code. Since state variables are updated after external calls, there's a risk of reentrancy attacks.

Recommendation:

Introduce reentrancy protection by inheriting from OpenZeppelin's ReentrancyGuard and adding the nonReentrant modifier to the bridge function.

+ import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

- contract FastBridgeV2 is IFastBridge, IFastBridgeV2, Admin {
+ contract FastBridgeV2 is IFastBridge, IFastBridgeV2, Admin, ReentrancyGuard {

  // ...

- function bridge(BridgeParams memory params) external payable {
+ function bridge(BridgeParams memory params) external payable nonReentrant {
    // existing code
}

Committable suggestion was skipped due to low confidence.

ChiTimesChi marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +78 to +125

Check notice

Code scanning / Slither

Block timestamp Low


/// @inheritdoc IFastBridge
function relay(bytes memory request) external payable {
relay(request, msg.sender);
}

/// @inheritdoc IFastBridgeV2
function relay(bytes memory request, address relayer) public payable {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();

// check haven't exceeded deadline for relay to happen
if (block.timestamp > transaction.deadline) revert DeadlineExceeded();

// mark bridge transaction as relayed
if (bridgeRelays[transactionId]) revert TransactionRelayed();
bridgeRelays[transactionId] = true;

// transfer tokens to recipient on destination chain and gas rebate if requested
address to = transaction.destRecipient;
address token = transaction.destToken;
uint256 amount = transaction.destAmount;

uint256 rebate = chainGasAmount;
if (!transaction.sendChainGas) {
// forward erc20
rebate = 0;
_pullToken(to, token, amount);
} else if (token == UniversalTokenLib.ETH_ADDRESS) {
// lump in gas rebate into amount in native gas token
_pullToken(to, token, amount + rebate);
} else {
// forward erc20 then forward gas rebate in native gas token
_pullToken(to, token, amount);
_pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);
}

emit BridgeRelayed(
transactionId,
relayer,
to,
transaction.originChainId,
transaction.originToken,
transaction.destToken,
transaction.originAmount,
transaction.destAmount,
rebate
);
}
Comment on lines +133 to +175
Copy link
Contributor

Choose a reason for hiding this comment

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

Restrict relayer Parameter in relay Function

The relay function allows callers to specify any relayer address, which could lead to misrepresentation or misuse.

Recommendation:

Restrict the relayer to msg.sender to ensure the correct relayer is recorded.

- function relay(bytes memory request, address relayer) public payable {
+ function relay(bytes memory request) public payable {
+     address relayer = msg.sender;
      // existing code
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function relay(bytes memory request, address relayer) public payable {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();
// check haven't exceeded deadline for relay to happen
if (block.timestamp > transaction.deadline) revert DeadlineExceeded();
// mark bridge transaction as relayed
if (bridgeRelays[transactionId]) revert TransactionRelayed();
bridgeRelays[transactionId] = true;
// transfer tokens to recipient on destination chain and gas rebate if requested
address to = transaction.destRecipient;
address token = transaction.destToken;
uint256 amount = transaction.destAmount;
uint256 rebate = chainGasAmount;
if (!transaction.sendChainGas) {
// forward erc20
rebate = 0;
_pullToken(to, token, amount);
} else if (token == UniversalTokenLib.ETH_ADDRESS) {
// lump in gas rebate into amount in native gas token
_pullToken(to, token, amount + rebate);
} else {
// forward erc20 then forward gas rebate in native gas token
_pullToken(to, token, amount);
_pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);
}
emit BridgeRelayed(
transactionId,
relayer,
to,
transaction.originChainId,
transaction.originToken,
transaction.destToken,
transaction.originAmount,
transaction.destAmount,
rebate
);
}
function relay(bytes memory request) public payable {
address relayer = msg.sender;
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (transaction.destChainId != uint32(block.chainid)) revert ChainIncorrect();
// check haven't exceeded deadline for relay to happen
if (block.timestamp > transaction.deadline) revert DeadlineExceeded();
// mark bridge transaction as relayed
if (bridgeRelays[transactionId]) revert TransactionRelayed();
bridgeRelays[transactionId] = true;
// transfer tokens to recipient on destination chain and gas rebate if requested
address to = transaction.destRecipient;
address token = transaction.destToken;
uint256 amount = transaction.destAmount;
uint256 rebate = chainGasAmount;
if (!transaction.sendChainGas) {
// forward erc20
rebate = 0;
_pullToken(to, token, amount);
} else if (token == UniversalTokenLib.ETH_ADDRESS) {
// lump in gas rebate into amount in native gas token
_pullToken(to, token, amount + rebate);
} else {
// forward erc20 then forward gas rebate in native gas token
_pullToken(to, token, amount);
_pullToken(to, UniversalTokenLib.ETH_ADDRESS, rebate);
}
emit BridgeRelayed(
transactionId,
relayer,
to,
transaction.originChainId,
transaction.originToken,
transaction.destToken,
transaction.originAmount,
transaction.destAmount,
rebate
);
}

Comment on lines +133 to +175
Copy link
Contributor

Choose a reason for hiding this comment

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

Add Reentrancy Guard to the relay Function

The relay function is public and payable, and it calls _pullToken, which involves external calls and token transfers. This could expose the contract to reentrancy attacks if not protected.

Apply the following changes to secure the relay function:

-function relay(bytes memory request, address relayer) public payable {
+function relay(bytes memory request, address relayer) public payable nonReentrant {

Committable suggestion was skipped due to low confidence.

Comment on lines +133 to +175

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low

Reentrancy in FastBridgeV2.relay(bytes,address):
External calls:
- _pullToken(to,token,amount)
- returndata = address(token).functionCall(data)
- IERC20(token).safeTransferFrom(msg.sender,recipient,amount)
- (success,returndata) = target.call{value: value}(data)
- (success,None) = to.call{value: value}()
- token.universalTransfer(recipient,amount)
- IERC20(token).safeTransfer(to,value)
- _pullToken(to,token,amount + rebate)
- returndata = address(token).functionCall(data)
- IERC20(token).safeTransferFrom(msg.sender,recipient,amount)
- (success,returndata) = target.call{value: value}(data)
- (success,None) = to.call{value: value}()
- token.universalTransfer(recipient,amount)
- IERC20(token).safeTransfer(to,value)
- _pullToken(to,token,amount)
- returndata = address(token).functionCall(data)
- IERC20(token).safeTransferFrom(msg.sender,recipient,amount)
- (success,returndata) = target.call{value: value}(data)
- (success,None) = to.call{value: value}()
- token.universalTransfer(recipient,amount)
- IERC20(token).safeTransfer(to,value)
- _pullToken(to,UniversalTokenLib.ETH_ADDRESS,rebate)
- returndata = address(token).functionCall(data)
- IERC20(token).safeTransferFrom(msg.sender,recipient,amount)
- (success,returndata) = target.call{value: value}(data)
- (success,None) = to.call{value: value}()
- token.universalTransfer(recipient,amount)
- IERC20(token).safeTransfer(to,value)
External calls sending eth:
- _pullToken(to,token,amount)
- (success,returndata) = target.call{value: value}(data)
- (success,None) = to.call{value: value}()
- _pullToken(to,token,amount + rebate)
- (success,returndata) = target.call{value: value}(data)
- [(success,None) = to.call{value:
Comment on lines +133 to +175

Check notice

Code scanning / Slither

Block timestamp Low

FastBridgeV2.relay(bytes,address) uses timestamp for comparisons
Dangerous comparisons:
- block.timestamp > transaction.deadline

/// @inheritdoc IFastBridge
function prove(bytes memory request, bytes32 destTxHash) external {
prove(request, destTxHash, msg.sender);
}

/// @inheritdoc IFastBridgeV2
function prove(bytes memory request, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {
bytes32 transactionId = keccak256(request);
// update bridge tx status given proof provided
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;
bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: relayer}); // overflow ok

emit BridgeProofProvided(transactionId, relayer, destTxHash);
}
Comment on lines +183 to +191
Copy link
Contributor

Choose a reason for hiding this comment

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

Check for Duplicate Proofs in prove Function

There is no check to prevent a proof from being submitted multiple times for the same transaction.

Recommendation:

Add a check to ensure that a proof cannot be submitted if one already exists.

function prove(bytes memory request, bytes32 destTxHash) public onlyRole(RELAYER_ROLE) {
    bytes32 transactionId = keccak256(request);
+   if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
    // existing code
}

Committable suggestion was skipped due to low confidence.


Validate relayer Address in prove Function

In the prove function, the relayer address is provided as a parameter without validation, which could allow incorrect association of the relayer.

Recommendation:

Use msg.sender as the relayer to ensure accuracy and security.

- function prove(bytes memory request, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {
+ function prove(bytes memory request, bytes32 destTxHash) public onlyRole(RELAYER_ROLE) {
+     address relayer = msg.sender;
      // existing code
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function prove(bytes memory request, bytes32 destTxHash, address relayer) public onlyRole(RELAYER_ROLE) {
bytes32 transactionId = keccak256(request);
// update bridge tx status given proof provided
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;
bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: relayer}); // overflow ok
emit BridgeProofProvided(transactionId, relayer, destTxHash);
}
function prove(bytes memory request, bytes32 destTxHash) public onlyRole(RELAYER_ROLE) {
address relayer = msg.sender;
bytes32 transactionId = keccak256(request);
// update bridge tx status given proof provided
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.RELAYER_PROVED;
bridgeProofs[transactionId] = BridgeProof({timestamp: uint96(block.timestamp), relayer: relayer}); // overflow ok
emit BridgeProofProvided(transactionId, relayer, destTxHash);
}


/// @notice Calculates time since proof submitted
/// @dev proof.timestamp stores casted uint96(block.timestamp) block timestamps for gas optimization
/// _timeSince(proof) can accomodate rollover case when block.timestamp > type(uint96).max but
/// proof.timestamp < type(uint96).max via unchecked statement
/// @param proof The bridge proof
/// @return delta Time delta since proof submitted
function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {
unchecked {
delta = uint96(block.timestamp) - proof.timestamp;
}
}
Comment on lines +199 to +203
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure Safe Arithmetic in _timeSince Function

The _timeSince function uses unchecked subtraction between uint96 timestamps, which could lead to underflow if proof.timestamp is greater than block.timestamp.

Recommendation:

Use safe arithmetic or validate timestamps to prevent underflow.

function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {
-     unchecked {
-         delta = uint96(block.timestamp) - proof.timestamp;
-     }
+     require(uint96(block.timestamp) >= proof.timestamp, "Invalid timestamp");
+     delta = uint96(block.timestamp) - proof.timestamp;
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {
unchecked {
delta = uint96(block.timestamp) - proof.timestamp;
}
}
function _timeSince(BridgeProof memory proof) internal view returns (uint256 delta) {
require(uint96(block.timestamp) >= proof.timestamp, "Invalid timestamp");
delta = uint96(block.timestamp) - proof.timestamp;
}


/// @inheritdoc IFastBridge
function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
BridgeProof memory proof = bridgeProofs[transactionId];
if (proof.relayer != relayer) revert SenderIncorrect();
return _timeSince(proof) > DISPUTE_PERIOD;
}
Comment on lines +206 to +211
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid Reverting in canClaim Function

The canClaim function reverts on incorrect status or sender, which may not be ideal for a view function meant to inform callers.

Recommendation:

Return false instead of reverting to provide a smoother user experience.

function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {
-     if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
+     if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) return false;
      BridgeProof memory proof = bridgeProofs[transactionId];
-     if (proof.relayer != relayer) revert SenderIncorrect();
+     if (proof.relayer != relayer) return false;
      return _timeSince(proof) > DISPUTE_PERIOD;
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
BridgeProof memory proof = bridgeProofs[transactionId];
if (proof.relayer != relayer) revert SenderIncorrect();
return _timeSince(proof) > DISPUTE_PERIOD;
}
function canClaim(bytes32 transactionId, address relayer) external view returns (bool) {
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) return false;
BridgeProof memory proof = bridgeProofs[transactionId];
if (proof.relayer != relayer) return false;
return _timeSince(proof) > DISPUTE_PERIOD;
}

Comment on lines +206 to +211

Check notice

Code scanning / Slither

Block timestamp Low


/// @inheritdoc IFastBridgeV2
function claim(bytes memory request) external {
claim(request, address(0));
}

/// @inheritdoc IFastBridge
function claim(bytes memory request, address to) public {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);

// update bridge tx status if able to claim origin collateral
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();

BridgeProof memory proof = bridgeProofs[transactionId];

// if "to" is zero addr, permissionlessly send funds to proven relayer
if (to == address(0)) {
to = proof.relayer;
} else if (proof.relayer != msg.sender) {
revert SenderIncorrect();
}

if (_timeSince(proof) <= DISPUTE_PERIOD) revert DisputePeriodNotPassed();

bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;

// update protocol fees if origin fee amount exists
if (transaction.originFeeAmount > 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;

// transfer origin collateral less fee to specified address
address token = transaction.originToken;
uint256 amount = transaction.originAmount;
token.universalTransfer(to, amount);
Comment on lines +243 to +245
Copy link
Contributor

Choose a reason for hiding this comment

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

Use SafeERC20 Library for Token Transfers

When transferring tokens, it's safer to use OpenZeppelin's SafeERC20 library to handle any potential anomalies with ERC20 tokens that do not return a boolean value on transfer.

Modify the token transfer to use safeTransfer:

-token.universalTransfer(to, amount);
+IERC20(token).safeTransfer(to, amount);

Committable suggestion was skipped due to low confidence.


emit BridgeDepositClaimed(transactionId, proof.relayer, to, token, amount);
}
Comment on lines +214 to +248
Copy link
Contributor

Choose a reason for hiding this comment

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

Simplify Recipient Logic in claim Function

The recipient logic in the claim function adds complexity and could be streamlined.

Recommendation:

Standardize the recipient to be the proof.relayer to reduce conditional checks.

function claim(bytes memory request) external {
-     claim(request, address(0));
+     claim(request);
}

- function claim(bytes memory request, address to) public {
+ function claim(bytes memory request) public {
      bytes32 transactionId = keccak256(request);
      BridgeTransaction memory transaction = getBridgeTransaction(request);
      // existing code
-     if (to == address(0)) {
-         to = proof.relayer;
-     } else if (proof.relayer != msg.sender) {
-         revert SenderIncorrect();
-     }
+     address to = proof.relayer;
      // existing code
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function claim(bytes memory request) external {
claim(request, address(0));
}
/// @inheritdoc IFastBridge
function claim(bytes memory request, address to) public {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
// update bridge tx status if able to claim origin collateral
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
BridgeProof memory proof = bridgeProofs[transactionId];
// if "to" is zero addr, permissionlessly send funds to proven relayer
if (to == address(0)) {
to = proof.relayer;
} else if (proof.relayer != msg.sender) {
revert SenderIncorrect();
}
if (_timeSince(proof) <= DISPUTE_PERIOD) revert DisputePeriodNotPassed();
bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;
// update protocol fees if origin fee amount exists
if (transaction.originFeeAmount > 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;
// transfer origin collateral less fee to specified address
address token = transaction.originToken;
uint256 amount = transaction.originAmount;
token.universalTransfer(to, amount);
emit BridgeDepositClaimed(transactionId, proof.relayer, to, token, amount);
}
function claim(bytes memory request) external {
claim(request);
}
/// @inheritdoc IFastBridge
function claim(bytes memory request) public {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
// update bridge tx status if able to claim origin collateral
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
BridgeProof memory proof = bridgeProofs[transactionId];
address to = proof.relayer;
if (_timeSince(proof) <= DISPUTE_PERIOD) revert DisputePeriodNotPassed();
bridgeStatuses[transactionId] = BridgeStatus.RELAYER_CLAIMED;
// update protocol fees if origin fee amount exists
if (transaction.originFeeAmount > 0) protocolFees[transaction.originToken] += transaction.originFeeAmount;
// transfer origin collateral less fee to specified address
address token = transaction.originToken;
uint256 amount = transaction.originAmount;
token.universalTransfer(to, amount);
emit BridgeDepositClaimed(transactionId, proof.relayer, to, token, amount);
}

Comment on lines +219 to +248

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low

Comment on lines +219 to +248

Check notice

Code scanning / Slither

Block timestamp Low

FastBridgeV2.claim(bytes,address) uses timestamp for comparisons
Dangerous comparisons:
- _timeSince(proofBlockTimestamp) <= DISPUTE_PERIOD

/// @inheritdoc IFastBridge
function dispute(bytes32 transactionId) external onlyRole(GUARD_ROLE) {
if (bridgeStatuses[transactionId] != BridgeStatus.RELAYER_PROVED) revert StatusIncorrect();
if (_timeSince(bridgeProofs[transactionId]) > DISPUTE_PERIOD) revert DisputePeriodPassed();

// @dev relayer gets slashed effectively if dest relay has gone thru
bridgeStatuses[transactionId] = BridgeStatus.REQUESTED;
delete bridgeProofs[transactionId];

emit BridgeProofDisputed(transactionId, msg.sender);
}
Comment on lines +251 to +260

Check notice

Code scanning / Slither

Block timestamp Low

FastBridgeV2.dispute(bytes32) uses timestamp for comparisons
Dangerous comparisons:
- _timeSince(bridgeProofs[transactionId]) > DISPUTE_PERIOD

/// @inheritdoc IFastBridge
function refund(bytes memory request) external {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);

if (hasRole(REFUNDER_ROLE, msg.sender)) {
// Refunder can refund if deadline has passed
if (block.timestamp <= transaction.deadline) revert DeadlineNotExceeded();
} else {
// Permissionless refund is allowed after REFUND_DELAY
if (block.timestamp <= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();
}

// set status to refunded if still in requested state
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;

// transfer origin collateral back to original sender
address to = transaction.originSender;
address token = transaction.originToken;
uint256 amount = transaction.originAmount + transaction.originFeeAmount;
token.universalTransfer(to, amount);
Comment on lines +280 to +283
Copy link
Contributor

Choose a reason for hiding this comment

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

Use SafeERC20 Library in refund Function

Similar to the previous suggestion, ensure the use of safeTransfer when refunding tokens to the user to handle any potential token transfer issues.

Update the token transfer in the refund function:

-token.universalTransfer(to, amount);
+IERC20(token).safeTransfer(to, amount);

Committable suggestion was skipped due to low confidence.


emit BridgeDepositRefunded(transactionId, to, token, amount);
}
Comment on lines +263 to +286
Copy link
Contributor

Choose a reason for hiding this comment

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

Add Reentrancy Protection to refund Function

The refund function involves transferring tokens back to the sender after external calls, which may lead to reentrancy vulnerabilities.

Recommendation:

Apply the nonReentrant modifier to the refund function.

- function refund(bytes memory request) external {
+ function refund(bytes memory request) external nonReentrant {
    // existing code
}
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function refund(bytes memory request) external {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (hasRole(REFUNDER_ROLE, msg.sender)) {
// Refunder can refund if deadline has passed
if (block.timestamp <= transaction.deadline) revert DeadlineNotExceeded();
} else {
// Permissionless refund is allowed after REFUND_DELAY
if (block.timestamp <= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();
}
// set status to refunded if still in requested state
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;
// transfer origin collateral back to original sender
address to = transaction.originSender;
address token = transaction.originToken;
uint256 amount = transaction.originAmount + transaction.originFeeAmount;
token.universalTransfer(to, amount);
emit BridgeDepositRefunded(transactionId, to, token, amount);
}
function refund(bytes memory request) external nonReentrant {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (hasRole(REFUNDER_ROLE, msg.sender)) {
// Refunder can refund if deadline has passed
if (block.timestamp <= transaction.deadline) revert DeadlineNotExceeded();
} else {
// Permissionless refund is allowed after REFUND_DELAY
if (block.timestamp <= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();
}
// set status to refunded if still in requested state
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;
// transfer origin collateral back to original sender
address to = transaction.originSender;
address token = transaction.originToken;
uint256 amount = transaction.originAmount + transaction.originFeeAmount;
token.universalTransfer(to, amount);
emit BridgeDepositRefunded(transactionId, to, token, amount);
}

Comment on lines +262 to +286
Copy link
Contributor

Choose a reason for hiding this comment

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

Add Reentrancy Guard to the refund Function

The refund function is external and transfers tokens back to the user using token.universalTransfer(to, amount);. Without reentrancy protection, this could be exploited by malicious actors.

Apply the following change to add a reentrancy guard:

-function refund(bytes memory request) external {
+function refund(bytes memory request) external nonReentrant {
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/// @inheritdoc IFastBridge
function refund(bytes memory request) external {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (hasRole(REFUNDER_ROLE, msg.sender)) {
// Refunder can refund if deadline has passed
if (block.timestamp <= transaction.deadline) revert DeadlineNotExceeded();
} else {
// Permissionless refund is allowed after REFUND_DELAY
if (block.timestamp <= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();
}
// set status to refunded if still in requested state
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;
// transfer origin collateral back to original sender
address to = transaction.originSender;
address token = transaction.originToken;
uint256 amount = transaction.originAmount + transaction.originFeeAmount;
token.universalTransfer(to, amount);
emit BridgeDepositRefunded(transactionId, to, token, amount);
}
/// @inheritdoc IFastBridge
function refund(bytes memory request) external nonReentrant {
bytes32 transactionId = keccak256(request);
BridgeTransaction memory transaction = getBridgeTransaction(request);
if (hasRole(REFUNDER_ROLE, msg.sender)) {
// Refunder can refund if deadline has passed
if (block.timestamp <= transaction.deadline) revert DeadlineNotExceeded();
} else {
// Permissionless refund is allowed after REFUND_DELAY
if (block.timestamp <= transaction.deadline + REFUND_DELAY) revert DeadlineNotExceeded();
}
// set status to refunded if still in requested state
if (bridgeStatuses[transactionId] != BridgeStatus.REQUESTED) revert StatusIncorrect();
bridgeStatuses[transactionId] = BridgeStatus.REFUNDED;
// transfer origin collateral back to original sender
address to = transaction.originSender;
address token = transaction.originToken;
uint256 amount = transaction.originAmount + transaction.originFeeAmount;
token.universalTransfer(to, amount);
emit BridgeDepositRefunded(transactionId, to, token, amount);
}

Comment on lines +263 to +286

Check notice

Code scanning / Slither

Reentrancy vulnerabilities Low

Comment on lines +263 to +286

Check notice

Code scanning / Slither

Block timestamp Low

}
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/interfaces/IAdmin.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.20;

interface IAdmin {
// ============ Events ============
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.20;

interface IFastBridge {
struct BridgeTransaction {
Expand Down
23 changes: 23 additions & 0 deletions packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
Copy link
Contributor

Choose a reason for hiding this comment

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

Update Solidity pragma version for broader compatibility

Consider using a caret (^) pragma to allow for future compatible compiler versions. Changing pragma solidity ^0.8.20; to pragma solidity ^0.8.0; can increase the range of compiler versions that can be used, providing more flexibility for developers.

Apply this change:

-pragma solidity ^0.8.20;
+pragma solidity ^0.8.0;
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pragma solidity ^0.8.20;
pragma solidity ^0.8.0;


import {IFastBridge} from "./IFastBridge.sol";

interface IFastBridgeV2 is IFastBridge {

/// @notice Relays destination side of bridge transaction by off-chain relayer
/// @param request The encoded bridge transaction to relay on destination chain
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
function relay(bytes memory request, address relayer) external payable;
Comment on lines +8 to +11
Copy link
Contributor

Choose a reason for hiding this comment

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

Validate the necessity of the relayer parameter in relay function

The relay function includes a relayer address parameter. Since interfaces cannot implement logic, it's important to ensure that the implementation will correctly handle this parameter. Consider whether the relayer address should be obtained from msg.sender within the implementation to prevent potential misuse where a caller could specify a different relayer address, which might introduce security risks.

Copy link
Contributor

Choose a reason for hiding this comment

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

Review the necessity of passing relayer as a parameter

Passing the relayer address explicitly in the relay function may introduce security risks. Since any caller could specify an arbitrary relayer address, consider using msg.sender as the relayer to ensure that the entity initiating the relay is correctly associated.


/// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction
/// @param request The encoded bridge transaction to prove on origin chain
/// @param destTxHash The destination tx hash proving bridge transaction was relayed
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
function prove(bytes memory request, bytes32 destTxHash, address relayer) external;
Comment on lines +13 to +17
Copy link
Contributor

Choose a reason for hiding this comment

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

Assess the use of the relayer parameter in prove function

Similar to the relay function, the prove function takes a relayer address as a parameter. Verify whether it's necessary to pass the relayer explicitly, or if it should be derived from msg.sender during implementation. This could prevent scenarios where a malicious actor proves a transaction on behalf of another relayer without authorization.

Copy link
Contributor

Choose a reason for hiding this comment

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

Validate the relayer parameter in prove function

Similar to the relay function, passing relayer as a parameter in prove could allow malicious actors to misrepresent the relayer's identity. Ensure that the implementation validates the authenticity of the relayer address or considers using msg.sender instead.


/// @notice Completes bridge transaction on origin chain by claiming originally deposited capital. Can only send funds to the relayer address on the proof.
/// @param request The encoded bridge transaction to claim on origin chain
function claim(bytes memory request) external;
Comment on lines +8 to +21
Copy link
Contributor

Choose a reason for hiding this comment

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

Enhance function documentation for clarity

The function comments can be improved to provide clearer guidance:

  • Specify the expected behavior and any assumptions.
  • Clarify the roles and responsibilities of the caller and the relayer.
  • Highlight any security considerations or requirements.

Consider revising the documentation as follows:

For relay:

 /// @notice Relays the destination side of a bridge transaction by an off-chain relayer.
 /// @param request The encoded bridge transaction to relay on the destination chain.
-/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed.
+/// @param relayer The address of the relayer. This address should control the origin funds when claimed to ensure secure transactions.

Apply similar enhancements to the prove and claim function comments.

Committable suggestion was skipped due to low confidence.


}
Comment on lines +1 to +23
Copy link
Contributor

Choose a reason for hiding this comment

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

Add events for important state-changing functions

Interfaces often include event declarations for significant actions to enhance transparency and enable off-chain monitoring. Consider adding events for the relay, prove, and claim functions to allow tracking when these actions occur in the implementing contracts.

Apply the following changes to declare events:

 interface IFastBridgeV2 is IFastBridge {

+    /// @notice Emitted when a relay is initiated
+    /// @param request The encoded bridge transaction relayed
+    /// @param relayer The address of the relayer
+    event RelayInitiated(bytes indexed request, address indexed relayer);

     /// @notice Relays destination side of bridge transaction by off-chain relayer
     /// @param request The encoded bridge transaction to relay on destination chain
     /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
     function relay(bytes memory request, address relayer) external payable;

+    /// @notice Emitted when a proof is submitted
+    /// @param request The encoded bridge transaction proved
+    /// @param destTxHash The destination transaction hash
+    /// @param relayer The address of the relayer
+    event ProofSubmitted(bytes indexed request, bytes32 indexed destTxHash, address indexed relayer);

     /// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction
     /// @param request The encoded bridge transaction to prove on origin chain
     /// @param destTxHash The destination tx hash proving bridge transaction was relayed
     /// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
     function prove(bytes memory request, bytes32 destTxHash, address relayer) external;

+    /// @notice Emitted when a claim is made
+    /// @param request The encoded bridge transaction claimed
+    /// @param claimant The address of the claimant
+    event ClaimMade(bytes indexed request, address indexed claimant);

     /// @notice Completes bridge transaction on origin chain by claiming originally deposited capital. Can only send funds to the relayer address on the proof.
     /// @param request The encoded bridge transaction to claim on origin chain
     function claim(bytes memory request) external;

 }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IFastBridge} from "./IFastBridge.sol";
interface IFastBridgeV2 is IFastBridge {
/// @notice Relays destination side of bridge transaction by off-chain relayer
/// @param request The encoded bridge transaction to relay on destination chain
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
function relay(bytes memory request, address relayer) external payable;
/// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction
/// @param request The encoded bridge transaction to prove on origin chain
/// @param destTxHash The destination tx hash proving bridge transaction was relayed
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
function prove(bytes memory request, bytes32 destTxHash, address relayer) external;
/// @notice Completes bridge transaction on origin chain by claiming originally deposited capital. Can only send funds to the relayer address on the proof.
/// @param request The encoded bridge transaction to claim on origin chain
function claim(bytes memory request) external;
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {IFastBridge} from "./IFastBridge.sol";
interface IFastBridgeV2 is IFastBridge {
/// @notice Emitted when a relay is initiated
/// @param request The encoded bridge transaction relayed
/// @param relayer The address of the relayer
event RelayInitiated(bytes indexed request, address indexed relayer);
/// @notice Relays destination side of bridge transaction by off-chain relayer
/// @param request The encoded bridge transaction to relay on destination chain
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
function relay(bytes memory request, address relayer) external payable;
/// @notice Emitted when a proof is submitted
/// @param request The encoded bridge transaction proved
/// @param destTxHash The destination transaction hash
/// @param relayer The address of the relayer
event ProofSubmitted(bytes indexed request, bytes32 indexed destTxHash, address indexed relayer);
/// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction
/// @param request The encoded bridge transaction to prove on origin chain
/// @param destTxHash The destination tx hash proving bridge transaction was relayed
/// @param relayer The address of the relaying entity which should have control of the origin funds when claimed
function prove(bytes memory request, bytes32 destTxHash, address relayer) external;
/// @notice Emitted when a claim is made
/// @param request The encoded bridge transaction claimed
/// @param claimant The address of the claimant
event ClaimMade(bytes indexed request, address indexed claimant);
/// @notice Completes bridge transaction on origin chain by claiming originally deposited capital. Can only send funds to the relayer address on the proof.
/// @param request The encoded bridge transaction to claim on origin chain
function claim(bytes memory request) external;
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.20;

/// @notice Interface for a contract that can be called multiple times by the same caller. Inspired by MulticallV3:
/// https://github.com/mds1/multicall/blob/master/src/Multicall3.sol
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/libs/Errors.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

error DeadlineExceeded();
error DeadlineNotExceeded();
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/contracts/libs/UniversalToken.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

import {TokenNotContract} from "./Errors.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma solidity ^0.8.20;

import {IMulticallTarget} from "../interfaces/IMulticallTarget.sol";

Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/script/ConfigureFastBridge.s.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

import {FastBridge} from "../contracts/FastBridge.sol";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.20;
pragma solidity ^0.8.20;

import {FastBridge} from "../contracts/FastBridge.sol";

Expand Down
Loading
Loading