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

refactor(contracts-rfq): mark new methods as V2 #3410

Merged
merged 2 commits into from
Nov 25, 2024
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
18 changes: 9 additions & 9 deletions packages/contracts-rfq/contracts/FastBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

/// @inheritdoc IFastBridge
function bridge(BridgeParams memory params) external payable {
bridge({
bridgeV2({
params: params,
paramsV2: BridgeParamsV2({
quoteRelayer: address(0),
Expand All @@ -81,25 +81,25 @@
/// @dev Replaced by `cancel`.
/// @inheritdoc IFastBridge
function refund(bytes calldata request) external {
cancel(request);
cancelV2(request);
}

// ══════════════════════════════════════ EXTERNAL MUTABLE (AGENT FACING) ══════════════════════════════════════════

/// @inheritdoc IFastBridge
function relay(bytes calldata request) external payable {
// `relay` override will validate the request.
relay({request: request, relayer: msg.sender});
relayV2({request: request, relayer: msg.sender});
}

/// @inheritdoc IFastBridge
function prove(bytes calldata request, bytes32 destTxHash) external {
request.validateV2();
prove({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});
proveV2({transactionId: keccak256(request), destTxHash: destTxHash, relayer: msg.sender});
}

/// @inheritdoc IFastBridgeV2
function claim(bytes calldata request) external {
function claimV2(bytes calldata request) external {
// `claim` override will validate the request.
claim({request: request, to: address(0)});
}
Expand Down Expand Up @@ -177,108 +177,108 @@
// ═══════════════════════════════════════ PUBLIC MUTABLE (USER FACING) ════════════════════════════════════════════

/// @inheritdoc IFastBridgeV2
function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {
function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) public payable {
// If relayer exclusivity is not intended for this bridge, set exclusivityEndTime to static zero.
// Otherwise, set exclusivity to expire at the current block ts offset by quoteExclusivitySeconds.
int256 exclusivityEndTime = 0;
if (paramsV2.quoteRelayer != address(0)) {
exclusivityEndTime = int256(block.timestamp) + paramsV2.quoteExclusivitySeconds;
}
_validateBridgeParams(params, paramsV2, exclusivityEndTime);

// Transfer tokens to bridge contract. We use the actual transferred amount in case of transfer fees.
uint256 originAmount = _takeBridgedUserAsset(params.originToken, params.originAmount);

// Track the amount of origin token owed to protocol.
uint256 originFeeAmount = 0;
if (protocolFeeRate > 0) {
originFeeAmount = (originAmount * protocolFeeRate) / FEE_BPS;
// The Relayer filling this request will be paid the originAmount after fees.
// Note: the protocol fees will be accumulated only when the Relayer claims the origin collateral.
originAmount -= originFeeAmount;
}

// Hash the bridge request and set the initial status to REQUESTED.
bytes memory request = BridgeTransactionV2Lib.encodeV2(
BridgeTransactionV2({
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,
deadline: params.deadline,
// Increment the sender's nonce on every bridge.
nonce: senderNonces[params.sender]++,
exclusivityRelayer: paramsV2.quoteRelayer,
// We checked exclusivityEndTime to be in range [0 .. params.deadline] above, so can safely cast.
exclusivityEndTime: uint256(exclusivityEndTime),
zapNative: paramsV2.zapNative,
zapData: paramsV2.zapData
})
);
bytes32 transactionId = keccak256(request);
// Note: the tx status will be updated throughout the tx lifecycle, while destChainId is set once here.
bridgeTxDetails[transactionId].status = BridgeStatus.REQUESTED;
bridgeTxDetails[transactionId].destChainId = params.dstChainId;

emit BridgeRequested({
transactionId: transactionId,
sender: params.sender,
request: request,
destChainId: params.dstChainId,
originToken: params.originToken,
destToken: params.destToken,
originAmount: originAmount,
destAmount: params.destAmount,
sendChainGas: paramsV2.zapNative != 0
});
emit BridgeQuoteDetails(transactionId, paramsV2.quoteId);
}

/// @inheritdoc IFastBridgeV2
function cancel(bytes calldata request) public {
function cancelV2(bytes calldata request) public {
// Decode the request and check that it could be cancelled.
request.validateV2();
bytes32 transactionId = keccak256(request);

// Can only cancel a REQUESTED transaction after its deadline expires.
BridgeTxDetails storage $ = bridgeTxDetails[transactionId];
if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();

// Permissionless cancel is only allowed after `cancelDelay` on top of the deadline.
uint256 deadline = request.deadline();
if (!hasRole(CANCELER_ROLE, msg.sender)) deadline += cancelDelay;
if (block.timestamp <= deadline) revert DeadlineNotExceeded();

// Update status to REFUNDED.
// Note: this is a storage write.
$.status = BridgeStatus.REFUNDED;

// Return the full amount (collateral + protocol fees) to the original sender.
// The protocol fees are only accumulated when the transaction is claimed, so we don't need to update them here.
address to = request.originSender();
address token = request.originToken();
uint256 amount = request.originAmount() + request.originFeeAmount();

// Emit the event before any external calls.
emit BridgeDepositRefunded(transactionId, to, token, amount);

// Return the funds to the original sender as last transaction action.
if (token == NATIVE_GAS_TOKEN) {
Address.sendValue(payable(to), amount);
} else {
IERC20(token).safeTransfer(to, amount);
}
}

Check notice

Code scanning / Slither

Block timestamp Low

FastBridgeV2.cancelV2(bytes) uses timestamp for comparisons
Dangerous comparisons:
- block.timestamp <= deadline

// ═══════════════════════════════════════ PUBLIC MUTABLE (AGENT FACING) ═══════════════════════════════════════════

/// @inheritdoc IFastBridgeV2
function relay(bytes calldata request, address relayer) public payable {
function relayV2(bytes calldata request, address relayer) public payable {
// Decode the request and check that it could be relayed.
request.validateV2();
bytes32 transactionId = keccak256(request);
Expand Down Expand Up @@ -347,7 +347,7 @@
}

/// @inheritdoc IFastBridgeV2
function prove(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {
function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) public onlyRole(PROVER_ROLE) {
// Can only prove a REQUESTED transaction.
BridgeTxDetails storage $ = bridgeTxDetails[transactionId];
if ($.status != BridgeStatus.REQUESTED) revert StatusIncorrect();
Expand Down
10 changes: 5 additions & 5 deletions packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -70,28 +70,28 @@ interface IFastBridgeV2 is IFastBridge {
/// to provide temporary exclusivity fill rights for the quote relayer.
/// @param params The parameters required to bridge
/// @param paramsV2 The parameters for exclusivity fill rights (optional, can be left empty)
function bridge(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;
function bridgeV2(BridgeParams memory params, BridgeParamsV2 memory paramsV2) external payable;

/// @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;
function relayV2(bytes memory request, address relayer) external payable;

/// @notice Provides proof on origin side that relayer provided funds on destination side of bridge transaction
/// @param transactionId The transaction id associated with the encoded bridge transaction to prove
/// @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(bytes32 transactionId, bytes32 destTxHash, address relayer) external;
function proveV2(bytes32 transactionId, bytes32 destTxHash, address relayer) external;

/// @notice Completes bridge transaction on origin chain by claiming originally deposited capital.
/// @notice 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;
function claimV2(bytes memory request) external;

/// @notice Cancels an outstanding bridge transaction in case optimistic bridging failed and returns the full amount
/// to the original sender.
/// @param request The encoded bridge transaction to refund
function cancel(bytes memory request) external;
function cancelV2(bytes memory request) external;

/// @notice Checks if a transaction has been relayed
/// @param transactionId The ID of the transaction to check
Expand Down
2 changes: 1 addition & 1 deletion packages/contracts-rfq/test/FastBridgeV2.Dst.Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ contract FastBridgeV2DstBaseTest is FastBridgeV2Test {
{
bytes memory request = BridgeTransactionV2Lib.encodeV2(bridgeTx);
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.relay{value: msgValue}(request, relayer);
fastBridge.relayV2{value: msgValue}(request, relayer);
}
}
6 changes: 3 additions & 3 deletions packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -453,19 +453,19 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest {
// V1 doesn't have any version field
expectRevertUnsupportedVersion(0);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relay(mockRequestV1, relayerB);
fastBridge.relayV2(mockRequestV1, relayerB);
}

function test_relay_withRelayerAddress_revert_invalidRequestV2() public {
expectRevertInvalidEncodedTx();
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relay(invalidRequestV2, relayerB);
fastBridge.relayV2(invalidRequestV2, relayerB);
}

function test_relay_withRelayerAddress_revert_requestV3() public {
expectRevertUnsupportedVersion(3);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.relay(mockRequestV3, relayerB);
fastBridge.relayV2(mockRequestV3, relayerB);
}

function test_relay_withRelayerAddress_revert_chainIncorrect() public {
Expand Down
8 changes: 4 additions & 4 deletions packages/contracts-rfq/test/FastBridgeV2.Src.Base.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ abstract contract FastBridgeV2SrcBaseTest is FastBridgeV2Test {
public
{
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.bridge{value: msgValue}(params, paramsV2);
fastBridge.bridgeV2{value: msgValue}(params, paramsV2);
}

function prove(address caller, bytes32 transactionId, bytes32 destTxHash, address relayer) public {
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.prove(transactionId, destTxHash, relayer);
fastBridge.proveV2(transactionId, destTxHash, relayer);
}

function prove(address caller, IFastBridgeV2.BridgeTransactionV2 memory bridgeTx, bytes32 destTxHash) public {
Expand All @@ -83,7 +83,7 @@ abstract contract FastBridgeV2SrcBaseTest is FastBridgeV2Test {

function claim(address caller, IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public {
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.claim(BridgeTransactionV2Lib.encodeV2(bridgeTx));
fastBridge.claimV2(BridgeTransactionV2Lib.encodeV2(bridgeTx));
}

function claim(address caller, IFastBridgeV2.BridgeTransactionV2 memory bridgeTx, address to) public {
Expand All @@ -98,7 +98,7 @@ abstract contract FastBridgeV2SrcBaseTest is FastBridgeV2Test {

function cancel(address caller, IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public virtual {
vm.prank({msgSender: caller, txOrigin: caller});
fastBridge.cancel(BridgeTransactionV2Lib.encodeV2(bridgeTx));
fastBridge.cancelV2(BridgeTransactionV2Lib.encodeV2(bridgeTx));
}

function test_nonce() public view {
Expand Down
12 changes: 6 additions & 6 deletions packages/contracts-rfq/test/FastBridgeV2.Src.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -998,19 +998,19 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest {
// V1 doesn't have any version field
expectRevertUnsupportedVersion(0);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.claim(mockRequestV1);
fastBridge.claimV2(mockRequestV1);
}

function test_claim_revert_invalidRequestV2() public {
expectRevertInvalidEncodedTx();
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.claim(invalidRequestV2);
fastBridge.claimV2(invalidRequestV2);
}

function test_claim_revert_requestV3() public {
expectRevertUnsupportedVersion(3);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.claim(mockRequestV3);
fastBridge.claimV2(mockRequestV3);
}

function test_claim_toDiffAddress_revert_requestV1() public {
Expand All @@ -1036,18 +1036,18 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest {
// V1 doesn't have any version field
expectRevertUnsupportedVersion(0);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.cancel(mockRequestV1);
fastBridge.cancelV2(mockRequestV1);
}

function test_cancel_revert_invalidRequestV2() public {
expectRevertInvalidEncodedTx();
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.cancel(invalidRequestV2);
fastBridge.cancelV2(invalidRequestV2);
}

function test_cancel_revert_requestV3() public {
expectRevertUnsupportedVersion(3);
vm.prank({msgSender: relayerA, txOrigin: relayerA});
fastBridge.cancel(mockRequestV3);
fastBridge.cancelV2(mockRequestV3);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ contract FastBridgeV2TokenZapV1SrcTest is TokenZapV1IntegrationTest {
public
{
vm.prank({msgSender: user, txOrigin: user});
fastBridge.bridge{value: isToken ? 0 : SRC_AMOUNT}(params, paramsV2);
fastBridge.bridgeV2{value: isToken ? 0 : SRC_AMOUNT}(params, paramsV2);
}

function expectEventBridgeRequested(
Expand Down
Loading