From 3e0129f0d265eae2283d58bf0fcc78ea0f21a085 Mon Sep 17 00:00:00 2001 From: Mikhail Melnik Date: Tue, 19 Nov 2024 17:42:00 +0400 Subject: [PATCH] upgrade FeeTaker --- contracts/extensions/AmountGetterBase.sol | 71 ++++++++ contracts/extensions/AmountGetterWithFee.sol | 113 ++++++++++++ contracts/extensions/FeeTaker.sol | 172 ++++++------------- test/FeeTaker.js | 74 ++++---- 4 files changed, 277 insertions(+), 153 deletions(-) create mode 100644 contracts/extensions/AmountGetterBase.sol create mode 100644 contracts/extensions/AmountGetterWithFee.sol diff --git a/contracts/extensions/AmountGetterBase.sol b/contracts/extensions/AmountGetterBase.sol new file mode 100644 index 00000000..8206ee09 --- /dev/null +++ b/contracts/extensions/AmountGetterBase.sol @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.23; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { IAmountGetter } from "../interfaces/IAmountGetter.sol"; +import { IOrderMixin } from "../interfaces/IOrderMixin.sol"; + +/// @title Base price getter contract that either calls external getter or applies linear formula +contract AmountGetterBase is IAmountGetter { + function getMakingAmount( + IOrderMixin.Order calldata order, + bytes calldata extension, + bytes32 orderHash, + address taker, + uint256 takingAmount, + uint256 remainingMakingAmount, + bytes calldata extraData + ) external view returns (uint256) { + return _getMakingAmount(order, extension, orderHash, taker, takingAmount, remainingMakingAmount, extraData); + } + + function getTakingAmount( + IOrderMixin.Order calldata order, + bytes calldata extension, + bytes32 orderHash, + address taker, + uint256 makingAmount, + uint256 remainingMakingAmount, + bytes calldata extraData + ) external view returns (uint256) { + return _getTakingAmount(order, extension, orderHash, taker, makingAmount, remainingMakingAmount, extraData); + } + + function _getMakingAmount( + IOrderMixin.Order calldata order, + bytes calldata extension, + bytes32 orderHash, + address taker, + uint256 takingAmount, + uint256 remainingMakingAmount, + bytes calldata extraData + ) internal view virtual returns (uint256) { + if (extraData.length >= 20) { + return IAmountGetter(address(bytes20(extraData))).getMakingAmount( + order, extension, orderHash, taker, takingAmount, remainingMakingAmount, extraData[20:] + ); + } else { + return Math.mulDiv(order.makingAmount, takingAmount, order.takingAmount); + } + } + + function _getTakingAmount( + IOrderMixin.Order calldata order, + bytes calldata extension, + bytes32 orderHash, + address taker, + uint256 makingAmount, + uint256 remainingMakingAmount, + bytes calldata extraData + ) internal view virtual returns (uint256) { + if (extraData.length >= 20) { + return IAmountGetter(address(bytes20(extraData))).getTakingAmount( + order, extension, orderHash, taker, makingAmount, remainingMakingAmount, extraData[20:] + ); + } else { + return Math.mulDiv(order.takingAmount, makingAmount, order.makingAmount, Math.Rounding.Ceil); + } + } +} diff --git a/contracts/extensions/AmountGetterWithFee.sol b/contracts/extensions/AmountGetterWithFee.sol new file mode 100644 index 00000000..d8daa84b --- /dev/null +++ b/contracts/extensions/AmountGetterWithFee.sol @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.23; + +import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; + +import { IOrderMixin } from "../interfaces/IOrderMixin.sol"; +import { AmountGetterBase } from "./AmountGetterBase.sol"; + +/// @title Price getter contract that adds fee calculation +contract AmountGetterWithFee is AmountGetterBase { + /// @dev Allows fees in range [1e-5, 0.65535] + uint256 internal constant _FEE_BASE = 1e5; + uint256 internal constant _DISCOUNT_BASE = 100; + + /** + * @dev Calculates makingAmount with fee. + */ + function _getMakingAmount( + IOrderMixin.Order calldata order, + bytes calldata extension, + bytes32 orderHash, + address taker, + uint256 takingAmount, + uint256 remainingMakingAmount, + bytes calldata extraData + ) internal view override returns (uint256) { + unchecked { + (, uint256 integratorFee, uint256 resolverFee, bytes calldata tail) = _parseFeeData(extraData, taker, _isWhitelistedGetterImpl); + return Math.mulDiv( + super._getMakingAmount(order, extension, orderHash, taker, takingAmount, remainingMakingAmount, tail), + _FEE_BASE, + _FEE_BASE + integratorFee + resolverFee + ); + } + } + + /** + * @dev Calculates takingAmount with fee. + */ + function _getTakingAmount( + IOrderMixin.Order calldata order, + bytes calldata extension, + bytes32 orderHash, + address taker, + uint256 makingAmount, + uint256 remainingMakingAmount, + bytes calldata extraData + ) internal view override returns (uint256) { + unchecked { + (, uint256 integratorFee, uint256 resolverFee, bytes calldata tail) = _parseFeeData(extraData, taker, _isWhitelistedGetterImpl); + return Math.mulDiv( + super._getTakingAmount(order, extension, orderHash, taker, makingAmount, remainingMakingAmount, tail), + _FEE_BASE + integratorFee + resolverFee, + _FEE_BASE, + Math.Rounding.Ceil + ); + } + } + + /** + * @dev `extraData` consists of: + * 2 bytes — integrator fee percentage (in 1e5) + * 2 bytes — resolver fee percentage (in 1e5) + * 1 byte - whitelist discount numerator (in 1e2) + * bytes — whitelist structure determined by `_isWhitelisted` implementation + * bytes — custom data (optional) + * @param _isWhitelisted internal function to parse and check whitelist + */ + function _parseFeeData( + bytes calldata extraData, + address taker, + function (bytes calldata, address) internal view returns (bool, bytes calldata) _isWhitelisted + ) internal view returns (bool isWhitelisted, uint256 integratorFee, uint256 resolverFee, bytes calldata tail) { + unchecked { + integratorFee = uint256(uint16(bytes2(extraData))); + resolverFee = uint256(uint16(bytes2(extraData[2:]))); + uint256 whitelistDiscountNumerator = uint256(uint8(bytes1(extraData[4:]))); + (isWhitelisted, tail) = _isWhitelisted(extraData[5:], taker); + if (isWhitelisted) { + resolverFee = resolverFee * whitelistDiscountNumerator / _DISCOUNT_BASE; + } + } + } + + /** + * @dev Validates whether the taker is whitelisted. + * @param whitelistData Whitelist data is a tightly packed struct of the following format: + * ``` + * 1 byte - size of the whitelist + * (bytes10)[N] whiteliested addresses; + * ``` + * Only 10 lowest bytes of the address are used for comparison. + * @param taker The taker address to check. + * @return isWhitelisted Whether the taker is whitelisted. + * @return tail Remaining calldata. + */ + function _isWhitelistedGetterImpl(bytes calldata whitelistData, address taker) internal pure returns (bool isWhitelisted, bytes calldata tail) { + unchecked { + uint80 maskedTakerAddress = uint80(uint160(taker)); + uint256 size = uint8(whitelistData[0]); + bytes calldata whitelist = whitelistData[1:1 + 10 * size]; + tail = whitelistData[1 + 10 * size:]; + for (uint256 i = 0; i < size; i++) { + uint80 whitelistedAddress = uint80(bytes10(whitelist[:10])); + if (maskedTakerAddress == whitelistedAddress) { + return (true, tail); + } + whitelist = whitelist[10:]; + } + } + } +} diff --git a/contracts/extensions/FeeTaker.sol b/contracts/extensions/FeeTaker.sol index 69c240c0..18445a13 100644 --- a/contracts/extensions/FeeTaker.sol +++ b/contracts/extensions/FeeTaker.sol @@ -9,33 +9,39 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol"; import { Math } from "@openzeppelin/contracts/utils/math/Math.sol"; -import { IAmountGetter } from "../interfaces/IAmountGetter.sol"; import { IOrderMixin } from "../interfaces/IOrderMixin.sol"; import { IPostInteraction } from "../interfaces/IPostInteraction.sol"; import { MakerTraits, MakerTraitsLib } from "../libraries/MakerTraitsLib.sol"; +import { AmountGetterWithFee } from "./AmountGetterWithFee.sol"; /// @title Helper contract that adds feature of collecting fee in takerAsset -contract FeeTaker is IPostInteraction, IAmountGetter, Ownable { +contract FeeTaker is IPostInteraction, AmountGetterWithFee, Ownable { using AddressLib for Address; using SafeERC20 for IERC20; using UniERC20 for IERC20; using MakerTraitsLib for MakerTraits; + bytes1 private constant _CUSTOM_RECEIVER_FLAG = 0x01; + /** * @dev The caller is not the limit order protocol contract. */ error OnlyLimitOrderProtocol(); + /** + * @dev The taker is not whitelisted and does not have access token. + */ + error OnlyWhitelistOrAccessToken(); + /** * @dev Eth transfer failed. The target fallback may have reverted. */ error EthTransferFailed(); - /// @dev Allows fees in range [1e-5, 0.65535] - uint256 internal constant _FEE_BASE = 1e5; - address private immutable _LIMIT_ORDER_PROTOCOL; address private immutable _WETH; + /// @notice Contract address whose tokens allow filling limit orders with a fee for resolvers that are outside the whitelist + IERC20 private immutable _ACCESS_TOKEN; /// @dev Modifier to check if the caller is the limit order protocol contract. modifier onlyLimitOrderProtocol { @@ -46,10 +52,14 @@ contract FeeTaker is IPostInteraction, IAmountGetter, Ownable { /** * @notice Initializes the contract. * @param limitOrderProtocol The limit order protocol contract. + * @param accessToken Contract address whose tokens allow filling limit orders with a fee for resolvers that are outside the whitelist. + * @param weth The WETH address. + * @param owner The owner of the contract. */ - constructor(address limitOrderProtocol, address weth, address owner) Ownable(owner) { + constructor(address limitOrderProtocol, IERC20 accessToken, address weth, address owner) Ownable(owner) { _LIMIT_ORDER_PROTOCOL = limitOrderProtocol; _WETH = weth; + _ACCESS_TOKEN = accessToken; } /** @@ -57,101 +67,66 @@ contract FeeTaker is IPostInteraction, IAmountGetter, Ownable { */ receive() external payable {} - /** - * @dev Calculate makingAmount with fee. - * `extraData` consists of: - * 2 bytes — integrator fee percentage (in 1e5) - * 2 bytes — resolver fee percentage (in 1e5) - * 1 byte - taker whitelist size - * (bytes10)[N] — taker whitelist - */ - function getMakingAmount( + function postInteraction( IOrderMixin.Order calldata order, bytes calldata extension, bytes32 orderHash, address taker, + uint256 makingAmount, uint256 takingAmount, uint256 remainingMakingAmount, bytes calldata extraData - ) external view returns (uint256 calculatedMakingAmount) { - unchecked { - (uint256 integratorFee, uint256 resolverFee, bytes calldata tail) = _parseFeeData(extraData, taker); - if (tail.length > 20) { - calculatedMakingAmount = IAmountGetter(address(bytes20(tail))).getMakingAmount( - order, extension, orderHash, taker, takingAmount, remainingMakingAmount, tail[20:] - ); - } else { - calculatedMakingAmount = order.makingAmount; - } - calculatedMakingAmount = Math.mulDiv(calculatedMakingAmount, _FEE_BASE, _FEE_BASE + integratorFee + resolverFee, Math.Rounding.Floor); - return Math.mulDiv(calculatedMakingAmount, takingAmount, order.takingAmount, Math.Rounding.Floor); - } + ) external onlyLimitOrderProtocol { + _postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, extraData); } /** - * @dev Calculate takingAmount with fee. - * `extraData` consists of: - * 2 bytes — integrator fee percentage (in 1e5) - * 2 bytes — resolver fee percentage (in 1e5) - * 1 byte - taker whitelist size - * (bytes10)[N] — taker whitelist + * @notice Retrieves funds accidently sent directly to the contract address + * @param token ERC20 token to retrieve + * @param amount amount to retrieve */ - function getTakingAmount( - IOrderMixin.Order calldata order, - bytes calldata extension, - bytes32 orderHash, - address taker, - uint256 makingAmount, - uint256 remainingMakingAmount, - bytes calldata extraData - ) external view returns (uint256 calculatedTakingAmount) { - unchecked { - (uint256 integratorFee, uint256 resolverFee, bytes calldata tail) = _parseFeeData(extraData, taker); - if (tail.length > 20) { - calculatedTakingAmount = IAmountGetter(address(bytes20(tail))).getTakingAmount( - order, extension, orderHash, taker, makingAmount, remainingMakingAmount, tail[20:] - ); - } else { - calculatedTakingAmount = order.takingAmount; - } - calculatedTakingAmount = Math.mulDiv(calculatedTakingAmount, _FEE_BASE + integratorFee + resolverFee, _FEE_BASE, Math.Rounding.Ceil); - return Math.mulDiv(calculatedTakingAmount, makingAmount, order.makingAmount, Math.Rounding.Ceil); - } + function rescueFunds(IERC20 token, uint256 amount) external onlyOwner { + token.uniTransfer(payable(msg.sender), amount); } /** * @notice See {IPostInteraction-postInteraction}. * @dev Takes the fee in taking tokens and transfers the rest to the maker. * `extraData` consists of: - * 2 bytes — integrator fee percentage (in 1e5) - * 2 bytes — resolver fee percentage (in 1e5) - * 1 byte - taker whitelist size - * (bytes10)[N] — taker whitelist + * 1 byte - flags * 20 bytes — fee recipient * 20 bytes — receiver of taking tokens (optional, if not set, maker is used) + * 2 bytes — integrator fee percentage (in 1e5) + * 2 bytes — resolver fee percentage (in 1e5) + * bytes — whitelist structure determined by `_isWhitelistedPostInteractionImpl` implementation + * bytes — custom data to call extra postInteraction (optional) */ - function postInteraction( + function _postInteraction( IOrderMixin.Order calldata order, - bytes calldata /* extension */, - bytes32 /* orderHash */, + bytes calldata extension, + bytes32 orderHash, address taker, - uint256 /* makingAmount */, + uint256 makingAmount, uint256 takingAmount, - uint256 /* remainingMakingAmount */, + uint256 remainingMakingAmount, bytes calldata extraData - ) external onlyLimitOrderProtocol { + ) internal virtual { unchecked { - (uint256 integratorFee, uint256 resolverFee, bytes calldata tail) = _parseFeeData(extraData, taker); - address feeRecipient = address(bytes20(tail)); - tail = tail[20:]; - uint256 denominator = _FEE_BASE + integratorFee + resolverFee; - // fee is calculated as a sum of separate fees to limit rounding errors - uint256 fee = Math.mulDiv(takingAmount, integratorFee, denominator) + Math.mulDiv(takingAmount, resolverFee, denominator); + bool customReceiver = extraData[0] & _CUSTOM_RECEIVER_FLAG == _CUSTOM_RECEIVER_FLAG; + address feeRecipient = address(bytes20(extraData[1:21])); + extraData = extraData[21:]; address receiver = order.maker.get(); - if (tail.length > 0) { - receiver = address(bytes20(tail)); + if (customReceiver) { + receiver = address(bytes20(extraData)); + extraData = extraData[20:]; } + (bool isWhitelisted, uint256 integratorFee, uint256 resolverFee, bytes calldata tail) = _parseFeeData(extraData, taker, _isWhitelistedPostInteractionImpl); + if (!isWhitelisted && _ACCESS_TOKEN.balanceOf(taker) == 0) revert OnlyWhitelistOrAccessToken(); + + uint256 denominator = _FEE_BASE + integratorFee + resolverFee; + // fee is calculated as a sum of separate fees to limit rounding errors + uint256 fee = Math.mulDiv(takingAmount, integratorFee, denominator) + Math.mulDiv(takingAmount, resolverFee, denominator); if (order.takerAsset.get() == address(_WETH) && order.makerTraits.unwrapWeth()) { if (fee > 0) { @@ -164,16 +139,19 @@ contract FeeTaker is IPostInteraction, IAmountGetter, Ownable { } IERC20(order.takerAsset.get()).safeTransfer(receiver, takingAmount - fee); } + + if (tail.length >= 20) { + IPostInteraction(address(bytes20(tail))).postInteraction(order, extension, orderHash, taker, makingAmount, takingAmount, remainingMakingAmount, tail[20:]); + } } } /** - * @notice Retrieves funds accidently sent directly to the contract address - * @param token ERC20 token to retrieve - * @param amount amount to retrieve + * @dev Parses fee data from `extraData`. + * Override this function if whitelist structure in postInteraction is different from getters. */ - function rescueFunds(IERC20 token, uint256 amount) external onlyOwner { - token.uniTransfer(payable(msg.sender), amount); + function _isWhitelistedPostInteractionImpl(bytes calldata whitelistData, address taker) internal view virtual returns (bool isWhitelisted, bytes calldata tail) { + return _isWhitelistedGetterImpl(whitelistData, taker); } function _sendEth(address target, uint256 amount) private { @@ -182,42 +160,4 @@ contract FeeTaker is IPostInteraction, IAmountGetter, Ownable { revert EthTransferFailed(); } } - - /** - * @dev Validates whether the resolver is whitelisted. - * @param whitelist Whitelist is tightly packed struct of the following format: - * ``` - * (bytes10)[N] resolversAddresses; - * ``` - * Only 10 lowest bytes of the resolver address are used for comparison. - * @param resolver The resolver to check. - * @return Whether the resolver is whitelisted. - */ - function _isWhitelisted(bytes calldata whitelist, address resolver) private pure returns (bool) { - unchecked { - uint80 maskedResolverAddress = uint80(uint160(resolver)); - uint256 size = whitelist.length / 10; - for (uint256 i = 0; i < size; i++) { - uint80 whitelistedAddress = uint80(bytes10(whitelist[:10])); - if (maskedResolverAddress == whitelistedAddress) { - return true; - } - whitelist = whitelist[10:]; - } - return false; - } - } - - function _parseFeeData(bytes calldata extraData, address taker) private pure returns (uint256 integratorFee, uint256 resolverFee, bytes calldata tail) { - unchecked { - integratorFee = uint256(uint16(bytes2(extraData))); - resolverFee = uint256(uint16(bytes2(extraData[2:]))); - uint256 whitelistEnd = 5 + 10 * uint256(uint8(extraData[4])); - bytes calldata whitelist = extraData[5:whitelistEnd]; - if (!_isWhitelisted(whitelist, taker)) { - resolverFee *= 2; - } - tail = extraData[whitelistEnd:]; - } - } } diff --git a/test/FeeTaker.js b/test/FeeTaker.js index cdf5c942..63dbb45f 100644 --- a/test/FeeTaker.js +++ b/test/FeeTaker.js @@ -30,7 +30,7 @@ describe('FeeTaker', function () { await inch.connect(addr1).approve(swap, ether('1000000')); const FeeTaker = await ethers.getContractFactory('FeeTaker'); - const feeTaker = await FeeTaker.deploy(swap, weth, addr); + const feeTaker = await FeeTaker.deploy(swap, inch, weth, addr); return { dai, weth, inch, swap, chainId, feeTaker }; }; @@ -54,8 +54,8 @@ describe('FeeTaker', function () { }, { postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'address'], - [await feeTaker.getAddress(), fee, fee, '0x00', feeRecipient], + ['address', 'bytes1', 'address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), '0x00', feeRecipient, fee, fee, 50, '0x00'], ), }, ); @@ -90,8 +90,8 @@ describe('FeeTaker', function () { }, { postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'address', 'address'], - [await feeTaker.getAddress(), fee, fee, '0x00', feeRecipient, makerReceiver], + ['address', 'bytes1', 'address', 'address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), '0x01', feeRecipient, makerReceiver, fee, fee, 50, '0x00'], ), }, ); @@ -132,16 +132,16 @@ describe('FeeTaker', function () { // * 1 byte - taker whitelist size // * (bytes10)[N] — taker whitelist postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'bytes', 'address'], - [await feeTaker.getAddress(), integratorFee, resolverFee, '0x0a', whitelist, feeRecipient], + ['address', 'bytes1', 'address', 'uint16', 'uint16', 'uint8', 'bytes1', 'bytes'], + [await feeTaker.getAddress(), '0x00', feeRecipient, integratorFee, resolverFee, 50, '0x0a', whitelist], ), makingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'bytes'], - [await feeTaker.getAddress(), integratorFee, resolverFee, '0x0a', whitelist], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1', 'bytes'], + [await feeTaker.getAddress(), integratorFee, resolverFee, 50, '0x0a', whitelist], ), takingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'bytes'], - [await feeTaker.getAddress(), integratorFee, resolverFee, '0x0a', whitelist], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1', 'bytes'], + [await feeTaker.getAddress(), integratorFee, resolverFee, 50, '0x0a', whitelist], ), }, ); @@ -154,7 +154,7 @@ describe('FeeTaker', function () { const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args); console.log(`GasUsed: ${(await (await fillTx).wait()).gasUsed.toString()}`); - const feeCalculated = takingAmount * (integratorFee + resolverFee) / BigInt(1e5); + const feeCalculated = takingAmount * (integratorFee + resolverFee / 2n) / BigInt(1e5); await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]); await expect(fillTx).to.changeTokenBalances(weth, [addr, addr1, addr2], [-takingAmount - feeCalculated, takingAmount, feeCalculated]); }); @@ -185,16 +185,16 @@ describe('FeeTaker', function () { // * 1 byte - taker whitelist size // * (bytes10)[N] — taker whitelist postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'bytes', 'address'], - [await feeTaker.getAddress(), integratorFee, resolverFee, '0x0a', whitelist, feeRecipient], + ['address', 'bytes1', 'address', 'uint16', 'uint16', 'uint8', 'bytes1', 'bytes'], + [await feeTaker.getAddress(), '0x00', feeRecipient, integratorFee, resolverFee, 50, '0x0a', whitelist], ), makingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'bytes'], - [await feeTaker.getAddress(), integratorFee, resolverFee, '0x0a', whitelist], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1', 'bytes'], + [await feeTaker.getAddress(), integratorFee, resolverFee, 50, '0x0a', whitelist], ), takingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'bytes'], - [await feeTaker.getAddress(), integratorFee, resolverFee, '0x0a', whitelist], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1', 'bytes'], + [await feeTaker.getAddress(), integratorFee, resolverFee, 50, '0x0a', whitelist], ), }, ); @@ -207,7 +207,7 @@ describe('FeeTaker', function () { const fillTx = swap.fillOrderArgs(order, r, vs, makingAmount, takerTraits.traits, takerTraits.args); console.log(`GasUsed: ${(await (await fillTx).wait()).gasUsed.toString()}`); - const feeCalculated = takingAmount * (integratorFee + resolverFee + resolverFee) / BigInt(1e5); + const feeCalculated = takingAmount * (integratorFee + resolverFee) / BigInt(1e5); await expect(fillTx).to.changeTokenBalances(dai, [addr, addr1], [makingAmount, -makingAmount]); await expect(fillTx).to.changeTokenBalances(weth, [addr, addr1, addr2], @@ -236,16 +236,16 @@ describe('FeeTaker', function () { }, { postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'address', 'address'], - [await feeTaker.getAddress(), fee, 0, '0x00', feeRecipient, makerReceiver], + ['address', 'bytes1', 'address', 'address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), '0x01', feeRecipient, makerReceiver, fee, 0, 50, '0x00'], ), makingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1'], - [await feeTaker.getAddress(), fee, 0, '0x00'], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), fee, 0, 50, '0x00'], ), takingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1'], - [await feeTaker.getAddress(), fee, 0, '0x00'], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), fee, 0, 50, '0x00'], ), }, ); @@ -281,16 +281,16 @@ describe('FeeTaker', function () { }, { postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'address'], - [await feeTaker.getAddress(), fee, 0, '0x00', feeRecipient], + ['address', 'bytes1', 'address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), '0x00', feeRecipient, fee, 0, 50, '0x00'], ), makingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1'], - [await feeTaker.getAddress(), fee, 0, '0x00'], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), fee, 0, 50, '0x00'], ), takingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1'], - [await feeTaker.getAddress(), fee, 0, '0x00'], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), fee, 0, 50, '0x00'], ), }, ); @@ -328,16 +328,16 @@ describe('FeeTaker', function () { }, { postInteraction: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1', 'address', 'address'], - [await feeTaker.getAddress(), fee, 0, '0x00', feeRecipient, makerReceiver], + ['address', 'bytes1', 'address', 'address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), '0x01', feeRecipient, makerReceiver, fee, 0, 50, '0x00'], ), makingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1'], - [await feeTaker.getAddress(), fee, 0, '0x00'], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), fee, 0, 50, '0x00'], ), takingAmountData: ethers.solidityPacked( - ['address', 'uint16', 'uint16', 'bytes1'], - [await feeTaker.getAddress(), fee, 0, '0x00'], + ['address', 'uint16', 'uint16', 'uint8', 'bytes1'], + [await feeTaker.getAddress(), fee, 0, 50, '0x00'], ), }, );