diff --git a/packages/contracts-rfq/contracts/FastBridgeV2.sol b/packages/contracts-rfq/contracts/FastBridgeV2.sol index 9f54c87f42..a25e9b7dc8 100644 --- a/packages/contracts-rfq/contracts/FastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/FastBridgeV2.sol @@ -5,19 +5,20 @@ import {SafeERC20, IERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeE import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {BridgeTransactionV2Lib} from "./libs/BridgeTransactionV2.sol"; -import {UniversalTokenLib} from "./libs/UniversalToken.sol"; import {Admin} from "./Admin.sol"; import {IFastBridge} from "./interfaces/IFastBridge.sol"; import {IFastBridgeV2} from "./interfaces/IFastBridgeV2.sol"; import {IFastBridgeV2Errors} from "./interfaces/IFastBridgeV2Errors.sol"; -import {IFastBridgeRecipient} from "./interfaces/IFastBridgeRecipient.sol"; +import {IZapRecipient} from "./interfaces/IZapRecipient.sol"; /// @notice FastBridgeV2 is a contract for bridging tokens across chains. contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { using BridgeTransactionV2Lib for bytes; using SafeERC20 for IERC20; - using UniversalTokenLib for address; + + /// @notice Address reserved for native gas token (ETH on Ethereum and most L2s, AVAX on Avalanche, etc) + address public constant NATIVE_GAS_TOKEN = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; /// @notice Dispute period for relayed transactions uint256 public constant DISPUTE_PERIOD = 30 minutes; @@ -28,8 +29,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { /// @notice Minimum deadline period to relay a requested bridge transaction uint256 public constant MIN_DEADLINE_PERIOD = 30 minutes; - /// @notice Maximum length of accepted callParams - uint256 public constant MAX_CALL_PARAMS_LENGTH = 2 ** 16 - 1; + /// @notice Maximum length of accepted zapData + uint256 public constant MAX_ZAP_DATA_LENGTH = 2 ** 16 - 1; /// @notice Status of the bridge tx on origin chain mapping(bytes32 => BridgeTxDetails) public bridgeTxDetails; @@ -56,8 +57,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), - callValue: 0, - callParams: bytes("") + zapNative: 0, + zapData: bytes("") }) }); } @@ -124,7 +125,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { // Emit the event before any external calls emit BridgeDepositRefunded(transactionId, to, token, amount); // Complete the user refund as the last transaction action - if (token == UniversalTokenLib.ETH_ADDRESS) { + if (token == NATIVE_GAS_TOKEN) { Address.sendValue(payable(to), amount); } else { IERC20(token).safeTransfer(to, amount); @@ -142,13 +143,13 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { /// @inheritdoc IFastBridge /// @dev This method is added to achieve backwards compatibility with decoding requests into V1 structs: - /// - `callValue` is partially reported as a zero/non-zero flag - /// - `callParams` is ignored + /// - `zapNative` is partially reported as a zero/non-zero flag + /// - `zapData` is ignored /// In order to process all kinds of requests use getBridgeTransactionV2 instead. function getBridgeTransaction(bytes calldata request) external view returns (BridgeTransaction memory) { // Try decoding into V2 struct first. This will revert if V1 struct is passed try this.getBridgeTransactionV2(request) returns (BridgeTransactionV2 memory txV2) { - // Note: we entirely ignore the callParams field, as it was not present in V1 + // Note: we entirely ignore the zapData field, as it was not present in V1 return BridgeTransaction({ originChainId: txV2.originChainId, destChainId: txV2.destChainId, @@ -159,7 +160,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { originAmount: txV2.originAmount, destAmount: txV2.destAmount, originFeeAmount: txV2.originFeeAmount, - sendChainGas: txV2.callValue != 0, + sendChainGas: txV2.zapNative != 0, deadline: txV2.deadline, nonce: txV2.nonce }); @@ -208,8 +209,8 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { exclusivityRelayer: paramsV2.quoteRelayer, // We checked exclusivityEndTime to be in range (0 .. params.deadline] above, so can safely cast exclusivityEndTime: uint256(exclusivityEndTime), - callValue: paramsV2.callValue, - callParams: paramsV2.callParams + zapNative: paramsV2.zapNative, + zapData: paramsV2.zapData }) ); bytes32 transactionId = keccak256(request); @@ -224,7 +225,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { destToken: params.destToken, originAmount: originAmount, destAmount: params.destAmount, - sendChainGas: paramsV2.callValue != 0 + sendChainGas: paramsV2.zapNative != 0 }); emit BridgeQuoteDetails(transactionId, paramsV2.quoteId); } @@ -238,11 +239,11 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { bridgeRelayDetails[transactionId] = BridgeRelay({blockNumber: uint48(block.number), blockTimestamp: uint48(block.timestamp), relayer: relayer}); - // transfer tokens to recipient on destination chain and do an arbitrary call if requested + // transfer tokens to recipient on destination chain and trigger Zap if requested address to = request.destRecipient(); address token = request.destToken(); uint256 amount = request.destAmount(); - uint256 callValue = request.callValue(); + uint256 zapNative = request.zapNative(); // Emit the event before any external calls emit BridgeRelayed({ @@ -254,33 +255,44 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { destToken: token, originAmount: request.originAmount(), destAmount: amount, - chainGasAmount: callValue + chainGasAmount: zapNative }); // All state changes have been done at this point, can proceed to the external calls. // This follows the checks-effects-interactions pattern to mitigate potential reentrancy attacks. - if (token == UniversalTokenLib.ETH_ADDRESS) { - // For ETH non-zero callValue is not allowed - if (callValue != 0) revert NativeTokenCallValueNotSupported(); + if (token == NATIVE_GAS_TOKEN) { + // For the native gas token, additional zapNative is not allowed + if (zapNative != 0) revert ZapNativeNotSupported(); // Check that the correct msg.value was sent if (msg.value != amount) revert MsgValueIncorrect(); + // Don't do a native transfer yet: we will handle it alongside the Zap below } else { // For ERC20s, we check that the correct msg.value was sent - if (msg.value != callValue) revert MsgValueIncorrect(); + if (msg.value != zapNative) revert MsgValueIncorrect(); // We need to transfer the tokens from the Relayer to the recipient first before performing an - // optional post-transfer arbitrary call. + // optional post-transfer Zap. IERC20(token).safeTransferFrom(msg.sender, to, amount); } + // At this point we have done: + // - Transferred the requested amount of ERC20 tokens to the recipient. + // At this point we have confirmed: + // - For ERC20s: msg.value matches the requested zapNative amount. + // - For the native gas token: msg.value matches the requested destAmount. + // Remaining optional things to do: + // - Forward the full msg.value to the recipient (if non-zero). + // - Trigger a Zap (if zapData is present). + bytes calldata zapData = request.zapData(); + if (zapData.length != 0) { + // Zap Data is present: Zap has been requested by the recipient. Trigger it forwarding the full msg.value. - bytes calldata callParams = request.callParams(); - if (callParams.length != 0) { - // Arbitrary call requested, perform it while supplying full msg.value to the recipient // Note: if token has a fee on transfers, the recipient will have received less than `amount`. // This is a very niche edge case and should be handled by the recipient contract. - _checkedCallRecipient({recipient: to, token: token, amount: amount, callParams: callParams}); + _triggerZapWithChecks({recipient: to, token: token, amount: amount, zapData: zapData}); } else if (msg.value != 0) { - // No arbitrary call requested, but msg.value was sent. This is either a relay with ETH, - // or a non-zero callValue request with an ERC20. In both cases, transfer the ETH to the recipient. + // Zap Data is missing, but msg.value was sent. This could happen in two different cases: + // - Relay with the native gas token is happening. + // - Relay with ERC20 is happening, with a `zapNative > 0` request. + // In both cases, we need to transfer the full msg.value to the recipient. Address.sendValue(payable(to), msg.value); } } @@ -337,7 +349,7 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { // Emit the event before any external calls emit BridgeDepositClaimed(transactionId, proofRelayer, to, token, amount); // Complete the relayer claim as the last transaction action - if (token == UniversalTokenLib.ETH_ADDRESS) { + if (token == NATIVE_GAS_TOKEN) { Address.sendValue(payable(to), amount); } else { IERC20(token).safeTransfer(to, amount); @@ -367,16 +379,17 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { /// claimed by the relayer who completed the relay on destination chain, or refunded back to the user, /// should no one complete the relay. function _takeBridgedUserAsset(address token, uint256 amount) internal returns (uint256 amountTaken) { - if (token == UniversalTokenLib.ETH_ADDRESS) { - // For ETH we just need to check that the supplied msg.value is correct. + if (token == NATIVE_GAS_TOKEN) { + // For the native gas token, we just need to check that the supplied msg.value is correct. // Supplied `msg.value` is already in FastBridgeV2 custody. if (amount != msg.value) revert MsgValueIncorrect(); amountTaken = msg.value; } else { // For ERC20s, token is explicitly transferred from the user to FastBridgeV2. // We don't allow non-zero `msg.value` to avoid extra funds from being stuck in FastBridgeV2. - token.assertIsContract(); if (msg.value != 0) revert MsgValueIncorrect(); + // Throw an explicit error if the provided token address is not a contract + if (token.code.length == 0) revert TokenNotContract(); amountTaken = IERC20(token).balanceOf(address(this)); IERC20(token).safeTransferFrom(msg.sender, address(this), amount); // Use the balance difference as the amount taken in case of fee on transfer tokens. @@ -384,26 +397,22 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { } } - /// @notice Calls the Recipient's hook function with the specified callParams and performs + /// @notice Calls the Recipient's hook function with the specified zapData and performs /// all the necessary checks for the returned value. - function _checkedCallRecipient( - address recipient, - address token, - uint256 amount, - bytes calldata callParams - ) - internal - { - bytes memory hookData = - abi.encodeCall(IFastBridgeRecipient.fastBridgeTransferReceived, (token, amount, callParams)); + function _triggerZapWithChecks(address recipient, address token, uint256 amount, bytes calldata zapData) internal { // This will bubble any revert messages from the hook function - bytes memory returnData = Address.functionCallWithValue({target: recipient, data: hookData, value: msg.value}); + bytes memory returnData = Address.functionCallWithValue({ + target: recipient, + data: abi.encodeCall(IZapRecipient.zap, (token, amount, zapData)), + // Note: see `relay()` for reasoning behind passing msg.value + value: msg.value + }); // Explicit revert if no return data at all if (returnData.length == 0) revert RecipientNoReturnValue(); // Check that exactly a single return value was returned if (returnData.length != 32) revert RecipientIncorrectReturnValue(); // Return value should be abi-encoded hook function selector - if (bytes32(returnData) != bytes32(IFastBridgeRecipient.fastBridgeTransferReceived.selector)) { + if (bytes32(returnData) != bytes32(IZapRecipient.zap.selector)) { revert RecipientIncorrectReturnValue(); } } @@ -439,9 +448,9 @@ contract FastBridgeV2 is Admin, IFastBridgeV2, IFastBridgeV2Errors { if (params.originToken == address(0) || params.destToken == address(0)) revert ZeroAddress(); if (params.deadline < block.timestamp + MIN_DEADLINE_PERIOD) revert DeadlineTooShort(); // Check V2 params - if (paramsV2.callParams.length > MAX_CALL_PARAMS_LENGTH) revert CallParamsLengthAboveMax(); - if (paramsV2.callValue != 0 && params.destToken == UniversalTokenLib.ETH_ADDRESS) { - revert NativeTokenCallValueNotSupported(); + if (paramsV2.zapData.length > MAX_ZAP_DATA_LENGTH) revert ZapDataLengthAboveMax(); + if (paramsV2.zapNative != 0 && params.destToken == NATIVE_GAS_TOKEN) { + revert ZapNativeNotSupported(); } // exclusivityEndTime must be in range (0 .. params.deadline] if (exclusivityEndTime <= 0 || exclusivityEndTime > int256(params.deadline)) { diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeRecipient.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeRecipient.sol deleted file mode 100644 index e76ee865cd..0000000000 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeRecipient.sol +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -interface IFastBridgeRecipient { - function fastBridgeTransferReceived( - address token, - uint256 amount, - bytes memory callParams - ) - external - payable - returns (bytes4); -} diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol index 54dbb5f3f6..8615d750d2 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2.sol @@ -30,23 +30,22 @@ interface IFastBridgeV2 is IFastBridge { /// for backwards compatibility. /// Note: quoteRelayer and quoteExclusivitySeconds are either both zero (indicating no exclusivity) /// or both non-zero (indicating exclusivity for the given period). - /// Note: callValue > 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (ETH_ADDRESS) + /// Note: zapNative > 0 can NOT be used with destToken = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE (native token) /// @param quoteRelayer Relayer that provided the quote for the transaction /// @param quoteExclusivitySeconds Period of time the quote relayer is guaranteed exclusivity after user's deposit /// @param quoteId Unique quote identifier used for tracking the quote - /// @param callValue ETH value to send to the recipient (if any) - /// @param callParams Parameters for the arbitrary call to the destination recipient (if any) + /// @param zapNative ETH value to send to the recipient (if any) + /// @param zapData Parameters for the Zap to the destination recipient (if any) struct BridgeParamsV2 { address quoteRelayer; int256 quoteExclusivitySeconds; bytes quoteId; - uint256 callValue; - bytes callParams; + uint256 zapNative; + bytes zapData; } /// @notice Updated bridge transaction struct to include parameters introduced in FastBridgeV2. /// Note: only `exclusivityRelayer` can fill such a transaction until `exclusivityEndTime`. - /// TODO: consider changing the encoding scheme to prevent spending extra gas on decoding. struct BridgeTransactionV2 { uint32 originChainId; uint32 destChainId; @@ -57,12 +56,13 @@ interface IFastBridgeV2 is IFastBridge { uint256 originAmount; // amount in on origin bridge less originFeeAmount uint256 destAmount; uint256 originFeeAmount; - uint256 callValue; // ETH value to send to the recipient (if any) - replaces V1's sendChainGas flag + // Note: sendChainGas flag from V1 is deprecated uint256 deadline; // user specified deadline for destination relay uint256 nonce; address exclusivityRelayer; uint256 exclusivityEndTime; - bytes callParams; + uint256 zapNative; // ETH value to send to the recipient (if any) + bytes zapData; // data to pass for the Zap action (if any) } event BridgeQuoteDetails(bytes32 indexed transactionId, bytes quoteId); diff --git a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol index f40b760c30..7eec1c9bbd 100644 --- a/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol +++ b/packages/contracts-rfq/contracts/interfaces/IFastBridgeV2Errors.sol @@ -1,15 +1,16 @@ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.20; interface IFastBridgeV2Errors { error AmountIncorrect(); - error CallParamsLengthAboveMax(); error ChainIncorrect(); error ExclusivityParamsIncorrect(); error MsgValueIncorrect(); - error NativeTokenCallValueNotSupported(); error SenderIncorrect(); error StatusIncorrect(); + error TokenNotContract(); + error ZapDataLengthAboveMax(); + error ZapNativeNotSupported(); error ZeroAddress(); error RecipientIncorrectReturnValue(); diff --git a/packages/contracts-rfq/contracts/interfaces/IZapRecipient.sol b/packages/contracts-rfq/contracts/interfaces/IZapRecipient.sol new file mode 100644 index 0000000000..94b9d2f27d --- /dev/null +++ b/packages/contracts-rfq/contracts/interfaces/IZapRecipient.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +interface IZapRecipient { + function zap(address token, uint256 amount, bytes memory zapData) external payable returns (bytes4); +} diff --git a/packages/contracts-rfq/contracts/libs/BridgeTransactionV2.sol b/packages/contracts-rfq/contracts/libs/BridgeTransactionV2.sol index ccdecf58c6..19932e88c7 100644 --- a/packages/contracts-rfq/contracts/libs/BridgeTransactionV2.sol +++ b/packages/contracts-rfq/contracts/libs/BridgeTransactionV2.sol @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.24; +pragma solidity ^0.8.20; import {IFastBridgeV2} from "../interfaces/IFastBridgeV2.sol"; @@ -22,8 +22,8 @@ library BridgeTransactionV2Lib { // uint256 nonce [218 .. 250) // address exclusivityRelayer [250 .. 270) // uint256 exclusivityEndTime [270 .. 302) - // uint256 callValue [302 .. 334) - // bytes callParams [334 .. ***) + // uint256 zapNative [302 .. 334) + // bytes zapData [334 .. ***) // forgefmt: disable-start uint256 private constant OFFSET_ORIGIN_CHAIN_ID = 2; @@ -39,8 +39,8 @@ library BridgeTransactionV2Lib { uint256 private constant OFFSET_NONCE = 218; uint256 private constant OFFSET_EXCLUSIVITY_RELAYER = 250; uint256 private constant OFFSET_EXCLUSIVITY_END_TIME = 270; - uint256 private constant OFFSET_CALL_VALUE = 302; - uint256 private constant OFFSET_CALL_PARAMS = 334; + uint256 private constant OFFSET_ZAP_NATIVE = 302; + uint256 private constant OFFSET_ZAP_DATA = 334; // forgefmt: disable-end error BridgeTransactionV2__InvalidEncodedTx(); @@ -50,7 +50,7 @@ library BridgeTransactionV2Lib { /// @dev Checks the minimum length and the version, use this function before decoding any of the fields. function validateV2(bytes calldata encodedTx) internal pure { // Check the minimum length: must at least include all static fields. - if (encodedTx.length < OFFSET_CALL_PARAMS) revert BridgeTransactionV2__InvalidEncodedTx(); + if (encodedTx.length < OFFSET_ZAP_DATA) revert BridgeTransactionV2__InvalidEncodedTx(); // Once we validated the length, we can be sure that the version field is present. uint16 version_ = version(encodedTx); if (version_ != VERSION) revert BridgeTransactionV2__UnsupportedVersion(version_); @@ -80,9 +80,9 @@ library BridgeTransactionV2Lib { // New V2 fields: exclusivity bridgeTx.exclusivityRelayer, bridgeTx.exclusivityEndTime, - // New V2 fields: arbitrary call - bridgeTx.callValue, - bridgeTx.callParams + // New V2 fields: Zap + bridgeTx.zapNative, + bridgeTx.zapData ); } @@ -103,12 +103,12 @@ library BridgeTransactionV2Lib { bridgeTx.originAmount = originAmount(encodedTx); bridgeTx.destAmount = destAmount(encodedTx); bridgeTx.originFeeAmount = originFeeAmount(encodedTx); - bridgeTx.callValue = callValue(encodedTx); bridgeTx.deadline = deadline(encodedTx); bridgeTx.nonce = nonce(encodedTx); bridgeTx.exclusivityRelayer = exclusivityRelayer(encodedTx); bridgeTx.exclusivityEndTime = exclusivityEndTime(encodedTx); - bridgeTx.callParams = callParams(encodedTx); + bridgeTx.zapNative = zapNative(encodedTx); + bridgeTx.zapData = zapData(encodedTx); } /// @notice Extracts the version from the encoded transaction. @@ -223,16 +223,16 @@ library BridgeTransactionV2Lib { } } - /// @notice Extracts the call value from the encoded transaction. - function callValue(bytes calldata encodedTx) internal pure returns (uint256 callValue_) { + /// @notice Extracts the Zap's native value from the encoded transaction. + function zapNative(bytes calldata encodedTx) internal pure returns (uint256 zapNative_) { // Load 32 bytes from the offset. No shift is applied, as we need the full 256 bits. assembly { - callValue_ := calldataload(add(encodedTx.offset, OFFSET_CALL_VALUE)) + zapNative_ := calldataload(add(encodedTx.offset, OFFSET_ZAP_NATIVE)) } } - /// @notice Extracts the call params from the encoded transaction. - function callParams(bytes calldata encodedTx) internal pure returns (bytes calldata callParams_) { - callParams_ = encodedTx[OFFSET_CALL_PARAMS:]; + /// @notice Extracts the Zap's data from the encoded transaction. + function zapData(bytes calldata encodedTx) internal pure returns (bytes calldata zapData_) { + zapData_ = encodedTx[OFFSET_ZAP_DATA:]; } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.Zap.t.sol similarity index 77% rename from packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol rename to packages/contracts-rfq/test/FastBridgeV2.Dst.Zap.t.sol index 1fb3ed8148..17c655825b 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.Zap.t.sol @@ -8,8 +8,8 @@ import {RecipientMock} from "./mocks/RecipientMock.sol"; import {Address} from "@openzeppelin/contracts/utils/Address.sol"; // solhint-disable func-name-mixedcase, ordering -contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { - bytes public constant CALL_PARAMS = abi.encode("Hello, world!"); +contract FastBridgeV2DstZapTest is FastBridgeV2DstExclusivityTest { + bytes public constant ZAP_DATA = abi.encode("Hello, world!"); bytes public constant REVERT_MSG = "GM, this is a revert"; function createFixtures() public virtual override { @@ -21,11 +21,11 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { function createFixturesV2() public virtual override { super.createFixturesV2(); - setTokenTestCallParams(CALL_PARAMS); - setEthTestCallParams(CALL_PARAMS); + setTokenTestZapData(ZAP_DATA); + setEthTestZapData(ZAP_DATA); } - /// @notice We override the "expect event" function to also check for the arbitrary call + /// @notice We override the "expect event" function to also check for the Zap /// made to the token recipient. function expectBridgeRelayed( IFastBridgeV2.BridgeTransactionV2 memory bridgeTx, @@ -49,10 +49,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { pure returns (bytes memory) { - // fastBridgeTransferReceived(token, amount, callParams) - return abi.encodeCall( - RecipientMock.fastBridgeTransferReceived, (bridgeTx.destToken, bridgeTx.destAmount, CALL_PARAMS) - ); + // zap(token, amount, zapData) + return abi.encodeCall(RecipientMock.zap, (bridgeTx.destToken, bridgeTx.destAmount, ZAP_DATA)); } // ═══════════════════════════════════════════════ RECIPIENT EOA ═══════════════════════════════════════════════════ @@ -83,13 +81,13 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { // ═════════════════════════════════════ EXCESSIVE RETURN VALUE RECIPIENT ══════════════════════════════════════════ - function test_relay_token_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_token_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual override { setTokenTestRecipient(excessiveReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddress_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddress_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual override @@ -99,35 +97,35 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withZapNative_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(excessiveReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(excessiveReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_eth_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_eth_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual override { setEthTestRecipient(excessiveReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } - function test_relay_eth_withRelayerAddress_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_eth_withRelayerAddress_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual override @@ -139,13 +137,13 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { // ═════════════════════════════════════ INCORRECT RETURN VALUE RECIPIENT ══════════════════════════════════════════ - function test_relay_token_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_token_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual override { setTokenTestRecipient(incorrectReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddress_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddress_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual override @@ -155,35 +153,35 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withZapNative_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(incorrectReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(incorrectReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_eth_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_eth_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual override { setEthTestRecipient(incorrectReturnValueRecipient); vm.expectRevert(RecipientIncorrectReturnValue.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } - function test_relay_eth_withRelayerAddress_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_eth_withRelayerAddress_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual override @@ -197,43 +195,43 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { // Note: in these tests NoOpRecipient doesn't implement hook function, so we expect a generic OZ library revert. - function test_relay_token_noOpRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_token_noOpRecipient_revertWhenZapDataPresent() public virtual override { setTokenTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddress_noOpRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_token_withRelayerAddress_noOpRecipient_revertWhenZapDataPresent() public virtual override { setTokenTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_noOpRecipient_revertWhenZapDataPresent() public virtual override { + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_noOpRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_noOpRecipient_revertWhenZapDataPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_eth_noOpRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_eth_noOpRecipient_revertWhenZapDataPresent() public virtual override { setEthTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } - function test_relay_eth_withRelayerAddress_noOpRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_eth_withRelayerAddress_noOpRecipient_revertWhenZapDataPresent() public virtual override { setEthTestRecipient(noOpRecipient); vm.expectRevert(Address.FailedInnerCall.selector); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); @@ -241,13 +239,13 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { // ═════════════════════════════════════════ NO RETURN VALUE RECIPIENT ═════════════════════════════════════════════ - function test_relay_token_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_token_noReturnValueRecipient_revertWhenZapDataPresent() public virtual override { setTokenTestRecipient(noReturnValueRecipient); vm.expectRevert(RecipientNoReturnValue.selector); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddress_noReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddress_noReturnValueRecipient_revertWhenZapDataPresent() public virtual override @@ -257,35 +255,31 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() - public - virtual - override - { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_noReturnValueRecipient_revertWhenZapDataPresent() public virtual override { + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noReturnValueRecipient); vm.expectRevert(RecipientNoReturnValue.selector); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_noReturnValueRecipient_revertWhenZapDataPresent() public virtual override { - setTokenTestCallValue(CALL_VALUE); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noReturnValueRecipient); vm.expectRevert(RecipientNoReturnValue.selector); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_eth_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual override { + function test_relay_eth_noReturnValueRecipient_revertWhenZapDataPresent() public virtual override { setEthTestRecipient(noReturnValueRecipient); vm.expectRevert(RecipientNoReturnValue.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } - function test_relay_eth_withRelayerAddress_noReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_eth_withRelayerAddress_noReturnValueRecipient_revertWhenZapDataPresent() public virtual override @@ -309,18 +303,18 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_revert_recipientReverts() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_revert_recipientReverts() public { + setTokenTestZapNative(ZAP_NATIVE); mockRecipientRevert(tokenTx); vm.expectRevert(REVERT_MSG); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_revert_recipientReverts() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative_revert_recipientReverts() public { + setTokenTestZapNative(ZAP_NATIVE); mockRecipientRevert(tokenTx); vm.expectRevert(REVERT_MSG); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } function test_relay_eth_revert_recipientReverts() public { @@ -335,8 +329,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } - function test_relay_eth_noCallParams_revert_recipientReverts() public { - setEthTestCallParams(""); + function test_relay_eth_noZapData_revert_recipientReverts() public { + setEthTestZapData(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); // Note: OZ library doesn't bubble the revert message for just sending ETH // (as opposed to doing an external hook call). Therefore we expect a generic library revert. @@ -344,8 +338,8 @@ contract FastBridgeV2DstArbitraryCallTest is FastBridgeV2DstExclusivityTest { relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); } - function test_relay_eth_withRelayerAddress_noCallParams_revert_recipientReverts() public { - setEthTestCallParams(""); + function test_relay_eth_withRelayerAddress_noZapData_revert_recipientReverts() public { + setEthTestZapData(""); vm.mockCallRevert({callee: userB, data: "", revertData: bytes(REVERT_MSG)}); // Note: OZ library doesn't bubble the revert message for just sending ETH // (as opposed to doing an external hook call). Therefore we expect a generic library revert. diff --git a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol index 5a9a6ae4df..6028e751d2 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Dst.t.sol @@ -23,7 +23,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { uint256 chainGasAmount ); - uint256 public constant CALL_VALUE = 1_337_420; + uint256 public constant ZAP_NATIVE = 1_337_420; address public excessiveReturnValueRecipient; address public incorrectReturnValueRecipient; @@ -57,8 +57,8 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { ethTx.destRecipient = recipient; } - function assertEmptyCallParams(bytes memory callParams) public pure { - assertEq(callParams.length, 0, "Invalid setup: callParams are not empty"); + function assertEmptyZapData(bytes memory zapData) public pure { + assertEq(zapData.length, 0, "Invalid setup: zapData are not empty"); } function expectBridgeRelayed( @@ -69,7 +69,7 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { public virtual { - uint256 chainGasAmount = bridgeTx.destToken == ETH_ADDRESS ? 0 : bridgeTx.callValue; + uint256 chainGasAmount = bridgeTx.destToken == ETH_ADDRESS ? 0 : bridgeTx.zapNative; vm.expectEmit(address(fastBridge)); emit BridgeRelayed({ transactionId: txId, @@ -158,132 +158,126 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { // ══════════════════════════════════════════ RELAYS WITH CALL VALUE ═══════════════════════════════════════════════ - function test_relay_token_withCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); bytes32 txId = getTxId(tokenTx); expectBridgeRelayed(tokenTx, txId, relayerA); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerA}); checkTokenBalances({recipient: userB, relayCaller: relayerA}); - assertEq(userB.balance, CALL_VALUE); + assertEq(userB.balance, ZAP_NATIVE); } - function test_relay_token_withRelayerAddressCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); bytes32 txId = getTxId(tokenTx); expectBridgeRelayed(tokenTx, txId, relayerA); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); checkRelayedViews({txId: txId, expectedRelayer: relayerA}); checkTokenBalances({recipient: userB, relayCaller: relayerB}); - assertEq(userB.balance, CALL_VALUE); + assertEq(userB.balance, ZAP_NATIVE); } // ═════════════════════════════════════ EXCESSIVE RETURN VALUE RECIPIENT ══════════════════════════════════════════ - // Note: in this test, the callParams are not present, and the below test functions succeed. - // Override them in the derived tests where callParams are present to check for a revert. + // Note: in this test, the zapData are not present, and the below test functions succeed. + // Override them in the derived tests where zapData are present to check for a revert. - function test_relay_token_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + function test_relay_token_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(excessiveReturnValueRecipient); test_relay_token(); } - function test_relay_token_withRelayerAddress_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddress_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(excessiveReturnValueRecipient); test_relay_token_withRelayerAddress(); } - function test_relay_token_withCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() - public - virtual - { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(excessiveReturnValueRecipient); - test_relay_token_withCallValue(); + test_relay_token_withZapNative(); } - function test_relay_token_withRelayerAddressCallValue_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(excessiveReturnValueRecipient); - test_relay_token_withRelayerAddressCallValue(); + test_relay_token_withRelayerAddressZapNative(); } - function test_relay_eth_excessiveReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + function test_relay_eth_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(excessiveReturnValueRecipient); test_relay_eth(); } - function test_relay_eth_withRelayerAddress_excessiveReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_eth_withRelayerAddress_excessiveReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(excessiveReturnValueRecipient); test_relay_eth_withRelayerAddress(); } // ═════════════════════════════════════ INCORRECT RETURN VALUE RECIPIENT ══════════════════════════════════════════ - // Note: in this test, the callParams are not present, and the below test functions succeed. - // Override them in the derived tests where callParams are present to check for a revert. + // Note: in this test, the zapData are not present, and the below test functions succeed. + // Override them in the derived tests where zapData are present to check for a revert. - function test_relay_token_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + function test_relay_token_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(incorrectReturnValueRecipient); test_relay_token(); } - function test_relay_token_withRelayerAddress_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddress_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(incorrectReturnValueRecipient); test_relay_token_withRelayerAddress(); } - function test_relay_token_withCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() - public - virtual - { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(incorrectReturnValueRecipient); - test_relay_token_withCallValue(); + test_relay_token_withZapNative(); } - function test_relay_token_withRelayerAddressCallValue_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(incorrectReturnValueRecipient); - test_relay_token_withRelayerAddressCallValue(); + test_relay_token_withRelayerAddressZapNative(); } - function test_relay_eth_incorrectReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + function test_relay_eth_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(incorrectReturnValueRecipient); test_relay_eth(); } - function test_relay_eth_withRelayerAddress_incorrectReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_eth_withRelayerAddress_incorrectReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(incorrectReturnValueRecipient); test_relay_eth_withRelayerAddress(); } @@ -301,18 +295,18 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { test_relay_token_withRelayerAddress(); } - function test_relay_token_withCallValue_nonPayableRecipient_revert() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_nonPayableRecipient_revert() public { + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(nonPayableRecipient); vm.expectRevert(); - relay({caller: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_nonPayableRecipient_revert() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative_nonPayableRecipient_revert() public { + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(nonPayableRecipient); vm.expectRevert(); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE, bridgeTx: tokenTx}); } function test_relay_eth_revert_nonPayableRecipient() public { @@ -329,89 +323,89 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { // ══════════════════════════════════════════════ NO-OP RECIPIENT ══════════════════════════════════════════════════ - // Note: in this test, the callParams are not present, and the below test functions succeed. - // Override them in the derived tests where callParams are present to check for a revert. + // Note: in this test, the zapData are not present, and the below test functions succeed. + // Override them in the derived tests where zapData are present to check for a revert. - function test_relay_token_noOpRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + function test_relay_token_noOpRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(noOpRecipient); test_relay_token(); } - function test_relay_token_withRelayerAddress_noOpRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + function test_relay_token_withRelayerAddress_noOpRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(noOpRecipient); test_relay_token_withRelayerAddress(); } - function test_relay_token_withCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_noOpRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noOpRecipient); - test_relay_token_withCallValue(); + test_relay_token_withZapNative(); } - function test_relay_token_withRelayerAddressCallValue_noOpRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative_noOpRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noOpRecipient); - test_relay_token_withRelayerAddressCallValue(); + test_relay_token_withRelayerAddressZapNative(); } - function test_relay_eth_noOpRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + function test_relay_eth_noOpRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(noOpRecipient); test_relay_eth(); } - function test_relay_eth_withRelayerAddress_noOpRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + function test_relay_eth_withRelayerAddress_noOpRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(noOpRecipient); test_relay_eth_withRelayerAddress(); } // ═════════════════════════════════════════ NO RETURN VALUE RECIPIENT ═════════════════════════════════════════════ - // Note: in this test, the callParams are not present, and the below test functions succeed. - // Override them in the derived tests where callParams are present to check for a revert. + // Note: in this test, the zapData are not present, and the below test functions succeed. + // Override them in the derived tests where zapData are present to check for a revert. - function test_relay_token_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + function test_relay_token_noReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(noReturnValueRecipient); test_relay_token(); } - function test_relay_token_withRelayerAddress_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); + function test_relay_token_withRelayerAddress_noReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); setTokenTestRecipient(noReturnValueRecipient); test_relay_token_withRelayerAddress(); } - function test_relay_token_withCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_noReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noReturnValueRecipient); - test_relay_token_withCallValue(); + test_relay_token_withZapNative(); } - function test_relay_token_withRelayerAddressCallValue_noReturnValueRecipient_revertWhenCallParamsPresent() + function test_relay_token_withRelayerAddressZapNative_noReturnValueRecipient_revertWhenZapDataPresent() public virtual { - assertEmptyCallParams(tokenTx.callParams); - setTokenTestCallValue(CALL_VALUE); + assertEmptyZapData(tokenTx.zapData); + setTokenTestZapNative(ZAP_NATIVE); setTokenTestRecipient(noReturnValueRecipient); - test_relay_token_withRelayerAddressCallValue(); + test_relay_token_withRelayerAddressZapNative(); } - function test_relay_eth_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + function test_relay_eth_noReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(noReturnValueRecipient); test_relay_eth(); } - function test_relay_eth_withRelayerAddress_noReturnValueRecipient_revertWhenCallParamsPresent() public virtual { - assertEmptyCallParams(ethTx.callParams); + function test_relay_eth_withRelayerAddress_noReturnValueRecipient_revertWhenZapDataPresent() public virtual { + assertEmptyZapData(ethTx.zapData); setEthTestRecipient(noReturnValueRecipient); test_relay_eth_withRelayerAddress(); } @@ -497,65 +491,65 @@ contract FastBridgeV2DstTest is FastBridgeV2DstBaseTest { relayWithAddress({caller: relayerA, relayer: address(0), msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_revert_zeroCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_revert_zeroZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); vm.expectRevert(MsgValueIncorrect.selector); relay({caller: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_revert_lowerCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_revert_lowerZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); vm.expectRevert(MsgValueIncorrect.selector); - relay({caller: relayerA, msgValue: CALL_VALUE - 1, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE - 1, bridgeTx: tokenTx}); } - function test_relay_token_withCallValue_revert_higherCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withZapNative_revert_higherZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); vm.expectRevert(MsgValueIncorrect.selector); - relay({caller: relayerA, msgValue: CALL_VALUE + 1, bridgeTx: tokenTx}); + relay({caller: relayerA, msgValue: ZAP_NATIVE + 1, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_revert_zeroCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative_revert_zeroZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); vm.expectRevert(MsgValueIncorrect.selector); relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: 0, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_revert_lowerCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative_revert_lowerZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); vm.expectRevert(MsgValueIncorrect.selector); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE - 1, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE - 1, bridgeTx: tokenTx}); } - function test_relay_token_withRelayerAddressCallValue_revert_higherCallValue() public { - setTokenTestCallValue(CALL_VALUE); + function test_relay_token_withRelayerAddressZapNative_revert_higherZapNative() public { + setTokenTestZapNative(ZAP_NATIVE); vm.expectRevert(MsgValueIncorrect.selector); - relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: CALL_VALUE + 1, bridgeTx: tokenTx}); + relayWithAddress({caller: relayerB, relayer: relayerA, msgValue: ZAP_NATIVE + 1, bridgeTx: tokenTx}); } - function test_relay_eth_withCallValue_revert_notSupported() public { - setEthTestCallValue(CALL_VALUE); - // Neither destAmount, CALL_VALUE, nor destAmount + CALL_VALUE should work here - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - relay({caller: relayerB, msgValue: CALL_VALUE, bridgeTx: ethTx}); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); + function test_relay_eth_withZapNative_revert_notSupported() public { + setEthTestZapNative(ZAP_NATIVE); + // Neither destAmount, ZAP_NATIVE, nor destAmount + ZAP_NATIVE should work here + vm.expectRevert(ZapNativeNotSupported.selector); + relay({caller: relayerB, msgValue: ZAP_NATIVE, bridgeTx: ethTx}); + vm.expectRevert(ZapNativeNotSupported.selector); relay({caller: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - relay({caller: relayerB, msgValue: ethParams.destAmount + CALL_VALUE, bridgeTx: ethTx}); + vm.expectRevert(ZapNativeNotSupported.selector); + relay({caller: relayerB, msgValue: ethParams.destAmount + ZAP_NATIVE, bridgeTx: ethTx}); } - function test_relay_eth_withRelayerAddressCallValue_revert_notSupported() public { - setEthTestCallValue(CALL_VALUE); - // Neither destAmount, CALL_VALUE, nor destAmount + CALL_VALUE should work here - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: CALL_VALUE, bridgeTx: ethTx}); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); + function test_relay_eth_withRelayerAddressZapNative_revert_notSupported() public { + setEthTestZapNative(ZAP_NATIVE); + // Neither destAmount, ZAP_NATIVE, nor destAmount + ZAP_NATIVE should work here + vm.expectRevert(ZapNativeNotSupported.selector); + relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ZAP_NATIVE, bridgeTx: ethTx}); + vm.expectRevert(ZapNativeNotSupported.selector); relayWithAddress({caller: relayerA, relayer: relayerB, msgValue: ethParams.destAmount, bridgeTx: ethTx}); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); + vm.expectRevert(ZapNativeNotSupported.selector); relayWithAddress({ caller: relayerA, relayer: relayerB, - msgValue: ethParams.destAmount + CALL_VALUE, + msgValue: ethParams.destAmount + ZAP_NATIVE, bridgeTx: ethTx }); } diff --git a/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol index 08d3bf65c7..fc27f5fd64 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Encoding.t.sol @@ -50,13 +50,13 @@ contract FastBridgeV2EncodingTest is FastBridgeV2Test { } /// @notice We expect all the V1 fields except for `sendChainGas` to match. - /// `sendChainGas` is replaced with `callValue` in V2, therefore we expect non-zero `callValue` + /// `sendChainGas` is replaced with `zapNative` in V2, therefore we expect non-zero `zapNative` /// to match `sendChainGas = true` in V1 function test_getBridgeTransaction_supportsV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTxV2) public view { bytes memory request = BridgeTransactionV2Lib.encodeV2(bridgeTxV2); IFastBridge.BridgeTransaction memory decodedTx = fastBridge.getBridgeTransaction(request); IFastBridge.BridgeTransaction memory expectedTx = extractV1(bridgeTxV2); - expectedTx.sendChainGas = bridgeTxV2.callValue > 0; + expectedTx.sendChainGas = bridgeTxV2.zapNative > 0; assertEq(decodedTx, expectedTx); } diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Zap.t.sol similarity index 62% rename from packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol rename to packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Zap.t.sol index 55958e937f..a89b9d928b 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.ArbitraryCall.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Dst.Zap.t.sol @@ -5,15 +5,15 @@ import {FastBridgeV2GasBenchmarkDstTest} from "./FastBridgeV2.GasBench.Dst.t.sol import {RecipientMock} from "./mocks/RecipientMock.sol"; // solhint-disable func-name-mixedcase, no-empty-blocks -contract FastBridgeV2GasBenchmarkDstArbitraryCallTest is FastBridgeV2GasBenchmarkDstTest { - // To get an idea about how much overhead the arbitrary call adds to the relaying process, we use a mock +contract FastBridgeV2GasBenchmarkDstZapTest is FastBridgeV2GasBenchmarkDstTest { + // To get an idea about how much overhead the Zap adds to the relaying process, we use a mock // recipient that has the hook function implemented as a no-op. - // The mocked callParams are chosen to be similar to the real use cases: + // The mocked zapData are chosen to be similar to the real use cases: // - user address // - some kind of ID to decide what to do with the tokens next /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. - function testFastBridgeV2GasBenchmarkDstArbitraryCallTest() external {} + function testFastBridgeV2GasBenchmarkDstZapTest() external {} function setUp() public virtual override { // In the inherited tests userB is always used as the recipient of the tokens. @@ -24,8 +24,8 @@ contract FastBridgeV2GasBenchmarkDstArbitraryCallTest is FastBridgeV2GasBenchmar function createFixturesV2() public virtual override { super.createFixturesV2(); - bytes memory mockCallParams = abi.encode(userA, keccak256("Random ID")); - setTokenTestCallParams(mockCallParams); - setEthTestCallParams(mockCallParams); + bytes memory mockZapData = abi.encode(userA, keccak256("Random ID")); + setTokenTestZapData(mockZapData); + setEthTestZapData(mockZapData); } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol index 0cb70ed357..6a8558bda8 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Encoding.t.sol @@ -17,8 +17,8 @@ contract FastBridgeV2GasBenchmarkEncodingTest is FastBridgeV2SrcBaseTest { fastBridge.getBridgeTransactionV2(request); } - function test_getBridgeTransactionV2_withArbitraryCall() public { - setTokenTestCallParams({callParams: abi.encode(userA, keccak256("Random ID"))}); + function test_getBridgeTransactionV2_withZap() public { + setTokenTestZapData({zapData: abi.encode(userA, keccak256("Random ID"))}); test_getBridgeTransactionV2(); } } diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol deleted file mode 100644 index d9291b8208..0000000000 --- a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.ArbitraryCall.t.sol +++ /dev/null @@ -1,21 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {FastBridgeV2GasBenchmarkSrcTest} from "./FastBridgeV2.GasBench.Src.t.sol"; - -// solhint-disable func-name-mixedcase, no-empty-blocks -contract FastBridgeV2GasBenchmarkSrcArbitraryCallTest is FastBridgeV2GasBenchmarkSrcTest { - /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. - function testFastBridgeV2GasBenchmarkSrcArbitraryCallTest() external {} - - function createFixturesV2() public virtual override { - super.createFixturesV2(); - bytes memory mockCallParams = abi.encode(userA, keccak256("Random ID")); - setTokenTestCallParams(mockCallParams); - setEthTestCallParams(mockCallParams); - bridgedTokenTx.callParams = mockCallParams; - bridgedEthTx.callParams = mockCallParams; - provenTokenTx.callParams = mockCallParams; - provenEthTx.callParams = mockCallParams; - } -} diff --git a/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.Zap.t.sol b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.Zap.t.sol new file mode 100644 index 0000000000..f493a6d45d --- /dev/null +++ b/packages/contracts-rfq/test/FastBridgeV2.GasBench.Src.Zap.t.sol @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FastBridgeV2GasBenchmarkSrcTest} from "./FastBridgeV2.GasBench.Src.t.sol"; + +// solhint-disable func-name-mixedcase, no-empty-blocks +contract FastBridgeV2GasBenchmarkSrcZapTest is FastBridgeV2GasBenchmarkSrcTest { + /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. + function testFastBridgeV2GasBenchmarkSrcZapTest() external {} + + function createFixturesV2() public virtual override { + super.createFixturesV2(); + bytes memory mockZapData = abi.encode(userA, keccak256("Random ID")); + setTokenTestZapData(mockZapData); + setEthTestZapData(mockZapData); + bridgedTokenTx.zapData = mockZapData; + bridgedEthTx.zapData = mockZapData; + provenTokenTx.zapData = mockZapData; + provenEthTx.zapData = mockZapData; + } +} diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol deleted file mode 100644 index 5b6e84b732..0000000000 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.ArbitraryCall.t.sol +++ /dev/null @@ -1,97 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {FastBridgeV2SrcExclusivityTest} from "./FastBridgeV2.Src.Exclusivity.t.sol"; - -// solhint-disable func-name-mixedcase, ordering -contract FastBridgeV2SrcArbitraryCallTest is FastBridgeV2SrcExclusivityTest { - bytes public constant CALL_PARAMS = abi.encode("Hello, World!"); - uint256 public constant CALL_VALUE = 1_337_420; - - function createFixturesV2() public virtual override { - super.createFixturesV2(); - setTokenTestCallParams(CALL_PARAMS); - setEthTestCallParams(CALL_PARAMS); - } - - // Contract should accept callParams with length up to 2^16 - 1, - // so that the callParams.length is encoded in 2 bytes. - - function test_bridge_token_callParamsLengthMax() public { - bytes memory callParams = new bytes(2 ** 16 - 1); - setTokenTestCallParams(callParams); - test_bridge_token(); - } - - function test_bridge_eth_callParamsLengthMax() public { - bytes memory callParams = new bytes(2 ** 16 - 1); - setEthTestCallParams(callParams); - test_bridge_eth(); - } - - function test_bridge_token_revert_callParamsLengthAboveMax() public { - bytes memory callParams = new bytes(2 ** 16); - setTokenTestCallParams(callParams); - vm.expectRevert(CallParamsLengthAboveMax.selector); - bridge({caller: userA, msgValue: 0, params: tokenParams, paramsV2: tokenParamsV2}); - } - - function test_bridge_eth_revert_callParamsLengthAboveMax() public { - bytes memory callParams = new bytes(2 ** 16); - setEthTestCallParams(callParams); - vm.expectRevert(CallParamsLengthAboveMax.selector); - bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); - } - - // ══════════════════════════════════════ WITH CALL VALUE, NO CALL PARAMS ══════════════════════════════════════════ - - function test_bridge_token_withCallValue_noCallParams() public { - setTokenTestCallParams(""); - setTokenTestCallValue(CALL_VALUE); - test_bridge_token(); - } - - function test_bridge_token_diffSender_withCallValue_noCallParams() public { - setTokenTestCallParams(""); - setTokenTestCallValue(CALL_VALUE); - test_bridge_token_diffSender(); - } - - function test_bridge_eth_withCallValue_noCallParams_revert() public { - setEthTestCallParams(""); - setEthTestCallValue(CALL_VALUE); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); - } - - function test_bridge_eth_diffSender_withCallValue_noCallParams_revert() public { - setEthTestCallParams(""); - setEthTestCallValue(CALL_VALUE); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); - } - - // ═══════════════════════════════════════ WITH CALL VALUE & CALL PARAMS ═══════════════════════════════════════════ - - function test_bridge_token_withCallValue_withCallParams() public { - setTokenTestCallValue(CALL_VALUE); - test_bridge_token(); - } - - function test_bridge_token_diffSender_withCallValue_withCallParams() public { - setTokenTestCallValue(CALL_VALUE); - test_bridge_token_diffSender(); - } - - function test_bridge_eth_withCallValue_withCallParams_revert() public { - setEthTestCallValue(CALL_VALUE); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); - } - - function test_bridge_eth_diffSender_withCallValue_withCallParams_revert() public { - setEthTestCallValue(CALL_VALUE); - vm.expectRevert(NativeTokenCallValueNotSupported.selector); - bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); - } -} diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.FBRV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.FBRV2.t.sol index 8aa4eddc30..4ed743181b 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.FBRV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.FBRV2.t.sol @@ -10,7 +10,6 @@ contract FastBridgeV2SrcFBRouterV2Test is FastBridgeV2SrcTest { address public router; error FastBridgeRouterV2__OriginSenderNotSpecified(); - error TokenNotContract(); function setUp() public virtual override { super.setUp(); diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.Zap.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.Zap.t.sol new file mode 100644 index 0000000000..56fdf29772 --- /dev/null +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.Zap.t.sol @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {FastBridgeV2SrcExclusivityTest} from "./FastBridgeV2.Src.Exclusivity.t.sol"; + +// solhint-disable func-name-mixedcase, ordering +contract FastBridgeV2SrcZapTest is FastBridgeV2SrcExclusivityTest { + bytes public constant ZAP_DATA = abi.encode("Hello, World!"); + uint256 public constant ZAP_NATIVE = 1_337_420; + + function createFixturesV2() public virtual override { + super.createFixturesV2(); + setTokenTestZapData(ZAP_DATA); + setEthTestZapData(ZAP_DATA); + } + + // Contract should accept zapData with length up to 2^16 - 1, + // so that the zapData.length is encoded in 2 bytes. + + function test_bridge_token_zapDataLengthMax() public { + bytes memory zapData = new bytes(2 ** 16 - 1); + setTokenTestZapData(zapData); + test_bridge_token(); + } + + function test_bridge_eth_zapDataLengthMax() public { + bytes memory zapData = new bytes(2 ** 16 - 1); + setEthTestZapData(zapData); + test_bridge_eth(); + } + + function test_bridge_token_revert_zapDataLengthAboveMax() public { + bytes memory zapData = new bytes(2 ** 16); + setTokenTestZapData(zapData); + vm.expectRevert(ZapDataLengthAboveMax.selector); + bridge({caller: userA, msgValue: 0, params: tokenParams, paramsV2: tokenParamsV2}); + } + + function test_bridge_eth_revert_zapDataLengthAboveMax() public { + bytes memory zapData = new bytes(2 ** 16); + setEthTestZapData(zapData); + vm.expectRevert(ZapDataLengthAboveMax.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + // ══════════════════════════════════════ WITH CALL VALUE, NO CALL PARAMS ══════════════════════════════════════════ + + function test_bridge_token_withZapNative_noZapData() public { + setTokenTestZapData(""); + setTokenTestZapNative(ZAP_NATIVE); + test_bridge_token(); + } + + function test_bridge_token_diffSender_withZapNative_noZapData() public { + setTokenTestZapData(""); + setTokenTestZapNative(ZAP_NATIVE); + test_bridge_token_diffSender(); + } + + function test_bridge_eth_withZapNative_noZapData_revert() public { + setEthTestZapData(""); + setEthTestZapNative(ZAP_NATIVE); + vm.expectRevert(ZapNativeNotSupported.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + function test_bridge_eth_diffSender_withZapNative_noZapData_revert() public { + setEthTestZapData(""); + setEthTestZapNative(ZAP_NATIVE); + vm.expectRevert(ZapNativeNotSupported.selector); + bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + // ═══════════════════════════════════════ WITH CALL VALUE & CALL PARAMS ═══════════════════════════════════════════ + + function test_bridge_token_withZapNative_withZapData() public { + setTokenTestZapNative(ZAP_NATIVE); + test_bridge_token(); + } + + function test_bridge_token_diffSender_withZapNative_withZapData() public { + setTokenTestZapNative(ZAP_NATIVE); + test_bridge_token_diffSender(); + } + + function test_bridge_eth_withZapNative_withZapData_revert() public { + setEthTestZapNative(ZAP_NATIVE); + vm.expectRevert(ZapNativeNotSupported.selector); + bridge({caller: userA, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } + + function test_bridge_eth_diffSender_withZapNative_withZapData_revert() public { + setEthTestZapNative(ZAP_NATIVE); + vm.expectRevert(ZapNativeNotSupported.selector); + bridge({caller: userB, msgValue: ethParams.originAmount, params: ethParams, paramsV2: ethParamsV2}); + } +} diff --git a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol index a29ba03168..060fbb8bab 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.Src.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.20; import {BridgeTransactionV2Lib} from "../contracts/libs/BridgeTransactionV2.sol"; +import {TokenNotContract} from "../contracts/libs/Errors.sol"; import {FastBridgeV2SrcBaseTest, IFastBridge, IFastBridgeV2} from "./FastBridgeV2.Src.Base.t.sol"; @@ -44,7 +45,7 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { destToken: bridgeTx.destToken, originAmount: bridgeTx.originAmount, destAmount: bridgeTx.destAmount, - sendChainGas: bridgeTx.callValue > 0 + sendChainGas: bridgeTx.zapNative > 0 }); } @@ -254,6 +255,12 @@ contract FastBridgeV2SrcTest is FastBridgeV2SrcBaseTest { bridge({caller: userA, msgValue: 0, params: tokenParams}); } + function test_bridge_revert_originTokenNotContract() public { + tokenParams.originToken = makeAddr("Random EOA"); + vm.expectRevert(TokenNotContract.selector); + bridge({caller: userA, msgValue: 0, params: tokenParams}); + } + function test_bridge_revert_deadlineTooClose() public { tokenParams.deadline = block.timestamp + MIN_DEADLINE - 1; vm.expectRevert(DeadlineTooShort.selector); diff --git a/packages/contracts-rfq/test/FastBridgeV2.t.sol b/packages/contracts-rfq/test/FastBridgeV2.t.sol index 7c3581e6ee..368fef07ac 100644 --- a/packages/contracts-rfq/test/FastBridgeV2.t.sol +++ b/packages/contracts-rfq/test/FastBridgeV2.t.sol @@ -77,10 +77,10 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { dstToken = new MockERC20("DstToken", 6); createFixtures(); mockRequestV1 = abi.encode(extractV1(tokenTx)); - // Invalid V2 request is formed before `createFixturesV2` to ensure it's not using callParams + // Invalid V2 request is formed before `createFixturesV2` to ensure it's not using zapData invalidRequestV2 = createInvalidRequestV2(BridgeTransactionV2Lib.encodeV2(tokenTx)); createFixturesV2(); - // Mock V3 request is formed after `createFixturesV2` to ensure it's using callParams if needed + // Mock V3 request is formed after `createFixturesV2` to ensure it's using zapData if needed mockRequestV3 = createMockRequestV3(BridgeTransactionV2Lib.encodeV2(ethTx)); fastBridge = deployFastBridge(); configureFastBridge(); @@ -161,15 +161,15 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), - callValue: 0, - callParams: bytes("") + zapNative: 0, + zapData: bytes("") }); ethParamsV2 = IFastBridgeV2.BridgeParamsV2({ quoteRelayer: address(0), quoteExclusivitySeconds: 0, quoteId: bytes(""), - callValue: 0, - callParams: bytes("") + zapNative: 0, + zapData: bytes("") }); tokenTx.exclusivityRelayer = address(0); @@ -197,14 +197,14 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { txV2.nonce = txV1.nonce; } - function setTokenTestCallParams(bytes memory callParams) public { - tokenParamsV2.callParams = callParams; - tokenTx.callParams = callParams; + function setTokenTestZapData(bytes memory zapData) public { + tokenParamsV2.zapData = zapData; + tokenTx.zapData = zapData; } - function setTokenTestCallValue(uint256 callValue) public { - tokenParamsV2.callValue = callValue; - tokenTx.callValue = callValue; + function setTokenTestZapNative(uint256 zapNative) public { + tokenParamsV2.zapNative = zapNative; + tokenTx.zapNative = zapNative; } function setTokenTestExclusivityParams(address relayer, uint256 exclusivitySeconds) public { @@ -216,14 +216,14 @@ abstract contract FastBridgeV2Test is Test, IFastBridgeV2Errors { tokenTx.exclusivityEndTime = block.timestamp + exclusivitySeconds; } - function setEthTestCallParams(bytes memory callParams) public { - ethParamsV2.callParams = callParams; - ethTx.callParams = callParams; + function setEthTestZapData(bytes memory zapData) public { + ethParamsV2.zapData = zapData; + ethTx.zapData = zapData; } - function setEthTestCallValue(uint256 callValue) public { - ethParamsV2.callValue = callValue; - ethTx.callValue = callValue; + function setEthTestZapNative(uint256 zapNative) public { + ethParamsV2.zapNative = zapNative; + ethTx.zapNative = zapNative; } function setEthTestExclusivityParams(address relayer, uint256 exclusivitySeconds) public { diff --git a/packages/contracts-rfq/test/harnesses/BridgeTransactionV2Harness.sol b/packages/contracts-rfq/test/harnesses/BridgeTransactionV2Harness.sol index 0d28bc21ce..947f8f2f16 100644 --- a/packages/contracts-rfq/test/harnesses/BridgeTransactionV2Harness.sol +++ b/packages/contracts-rfq/test/harnesses/BridgeTransactionV2Harness.sol @@ -52,8 +52,8 @@ contract BridgeTransactionV2Harness { return BridgeTransactionV2Lib.originFeeAmount(encodedTx); } - function callValue(bytes calldata encodedTx) public pure returns (uint256) { - return BridgeTransactionV2Lib.callValue(encodedTx); + function zapNative(bytes calldata encodedTx) public pure returns (uint256) { + return BridgeTransactionV2Lib.zapNative(encodedTx); } function deadline(bytes calldata encodedTx) public pure returns (uint256) { @@ -72,7 +72,7 @@ contract BridgeTransactionV2Harness { return BridgeTransactionV2Lib.exclusivityEndTime(encodedTx); } - function callParams(bytes calldata encodedTx) public pure returns (bytes calldata) { - return BridgeTransactionV2Lib.callParams(encodedTx); + function zapData(bytes calldata encodedTx) public pure returns (bytes calldata) { + return BridgeTransactionV2Lib.zapData(encodedTx); } } diff --git a/packages/contracts-rfq/test/libs/BridgeTransactionV2.t.sol b/packages/contracts-rfq/test/libs/BridgeTransactionV2.t.sol index ae4d042173..5ba37b8c08 100644 --- a/packages/contracts-rfq/test/libs/BridgeTransactionV2.t.sol +++ b/packages/contracts-rfq/test/libs/BridgeTransactionV2.t.sol @@ -29,12 +29,12 @@ contract BridgeTransactionV2Test is Test { assertEq(a.originAmount, b.originAmount); assertEq(a.destAmount, b.destAmount); assertEq(a.originFeeAmount, b.originFeeAmount); - assertEq(a.callValue, b.callValue); + assertEq(a.zapNative, b.zapNative); assertEq(a.deadline, b.deadline); assertEq(a.nonce, b.nonce); assertEq(a.exclusivityRelayer, b.exclusivityRelayer); assertEq(a.exclusivityEndTime, b.exclusivityEndTime); - assertEq(a.callParams, b.callParams); + assertEq(a.zapData, b.zapData); } function test_roundtrip(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public view { @@ -49,12 +49,12 @@ contract BridgeTransactionV2Test is Test { assertEq(harness.originAmount(encodedTx), bridgeTx.originAmount); assertEq(harness.destAmount(encodedTx), bridgeTx.destAmount); assertEq(harness.originFeeAmount(encodedTx), bridgeTx.originFeeAmount); - assertEq(harness.callValue(encodedTx), bridgeTx.callValue); + assertEq(harness.zapNative(encodedTx), bridgeTx.zapNative); assertEq(harness.deadline(encodedTx), bridgeTx.deadline); assertEq(harness.nonce(encodedTx), bridgeTx.nonce); assertEq(harness.exclusivityRelayer(encodedTx), bridgeTx.exclusivityRelayer); assertEq(harness.exclusivityEndTime(encodedTx), bridgeTx.exclusivityEndTime); - assertEq(harness.callParams(encodedTx), bridgeTx.callParams); + assertEq(harness.zapData(encodedTx), bridgeTx.zapData); } function test_roundtrip_decodeV2(IFastBridgeV2.BridgeTransactionV2 memory bridgeTx) public view { diff --git a/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol b/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol index 21f3484dd7..a024f36656 100644 --- a/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol +++ b/packages/contracts-rfq/test/mocks/ExcessiveReturnValueRecipient.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IFastBridgeRecipient} from "../../contracts/interfaces/IFastBridgeRecipient.sol"; +import {IZapRecipient} from "../../contracts/interfaces/IZapRecipient.sol"; // solhint-disable no-empty-blocks /// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION. @@ -13,7 +13,7 @@ contract ExcessiveReturnValueRecipient { function testExcessiveReturnValueRecipient() external {} /// @notice Incorrectly implemented - method returns excessive bytes. - function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4, uint256) { - return (IFastBridgeRecipient.fastBridgeTransferReceived.selector, 1337); + function zap(address, uint256, bytes memory) external payable returns (bytes4, uint256) { + return (IZapRecipient.zap.selector, 1337); } } diff --git a/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol b/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol index 0570f49cd0..030f8bf2f5 100644 --- a/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol +++ b/packages/contracts-rfq/test/mocks/IncorrectReturnValueRecipient.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IFastBridgeRecipient} from "../../contracts/interfaces/IFastBridgeRecipient.sol"; +import {IZapRecipient} from "../../contracts/interfaces/IZapRecipient.sol"; // solhint-disable no-empty-blocks /// @notice Incorrectly implemented recipient mock for testing purposes. DO NOT USE IN PRODUCTION. -contract IncorrectReturnValueRecipient is IFastBridgeRecipient { +contract IncorrectReturnValueRecipient is IZapRecipient { /// @notice Mock needs to accept ETH receive() external payable {} @@ -13,8 +13,8 @@ contract IncorrectReturnValueRecipient is IFastBridgeRecipient { function testIncorrectReturnValueRecipient() external {} /// @notice Incorrectly implemented - method returns incorrect value. - function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) { + function zap(address, uint256, bytes memory) external payable returns (bytes4) { // Flip the last bit - return IFastBridgeRecipient.fastBridgeTransferReceived.selector ^ 0x00000001; + return IZapRecipient.zap.selector ^ 0x00000001; } } diff --git a/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol b/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol index 1ba76e7402..7c61742f58 100644 --- a/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol +++ b/packages/contracts-rfq/test/mocks/NoReturnValueRecipient.sol @@ -11,5 +11,5 @@ contract NoReturnValueRecipient { function testNoReturnValueRecipient() external {} /// @notice Incorrectly implemented - method does not return anything. - function fastBridgeTransferReceived(address, uint256, bytes memory) external payable {} + function zap(address, uint256, bytes memory) external payable {} } diff --git a/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol b/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol index 2c80581943..9bc2ab6a07 100644 --- a/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol +++ b/packages/contracts-rfq/test/mocks/NonPayableRecipient.sol @@ -8,7 +8,7 @@ contract NonPayableRecipient { function testNonPayableRecipient() external {} /// @notice Incorrectly implemented - method is not payable. - function fastBridgeTransferReceived(address, uint256, bytes memory) external pure returns (bytes4) { - return NonPayableRecipient.fastBridgeTransferReceived.selector; + function zap(address, uint256, bytes memory) external pure returns (bytes4) { + return NonPayableRecipient.zap.selector; } } diff --git a/packages/contracts-rfq/test/mocks/RecipientMock.sol b/packages/contracts-rfq/test/mocks/RecipientMock.sol index f95422b322..d9d582e313 100644 --- a/packages/contracts-rfq/test/mocks/RecipientMock.sol +++ b/packages/contracts-rfq/test/mocks/RecipientMock.sol @@ -1,19 +1,19 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IFastBridgeRecipient} from "../../contracts/interfaces/IFastBridgeRecipient.sol"; +import {IZapRecipient} from "../../contracts/interfaces/IZapRecipient.sol"; // solhint-disable no-empty-blocks /// @notice Recipient mock for testing purposes. DO NOT USE IN PRODUCTION. -contract RecipientMock is IFastBridgeRecipient { +contract RecipientMock is IZapRecipient { /// @notice Mock needs to accept ETH receive() external payable {} /// @notice We include an empty "test" function so that this contract does not appear in the coverage report. function testRecipientMock() external {} - /// @notice Minimal viable implementation of the fastBridgeTransferReceived hook. - function fastBridgeTransferReceived(address, uint256, bytes memory) external payable returns (bytes4) { - return IFastBridgeRecipient.fastBridgeTransferReceived.selector; + /// @notice Minimal viable implementation of the zap hook. + function zap(address, uint256, bytes memory) external payable returns (bytes4) { + return IZapRecipient.zap.selector; } }