Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safer swap fee bounds #1054

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions pkg/interfaces/contracts/vault/ISwapFeePercentageBounds.sol
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,12 @@ pragma solidity ^0.8.24;
*
* A minimum swap fee might be necessary to ensure mathematical soundness (e.g., Weighted Pools, which use the power
* function in the invariant). A maximum swap fee is general protection for users. With no limits at the Vault level,
* a pool could specify a 100% swap fee, effectively disabling trading. Though there are some use cases, such as
* LVR/MEV strategies, where a 100% fee makes sense.
* a pool could specify a near 100% swap fee, effectively disabling trading. Though there are some use cases, such as
* LVR/MEV strategies, where a very high fee makes sense.
*
* Note that the Vault does ensure that dynamic and aggregate fees are less than 100% to prevent attempting to allocate
* more fees than were collected by the operation. The true `MAX_FEE_PERCENTAGE` is defined in VaultTypes.sol, and is
* the highest value below 100% that satisfies the precision requirements.
*/
interface ISwapFeePercentageBounds {
/// @return minimumSwapFeePercentage The minimum swap fee percentage for a pool
Expand Down
4 changes: 3 additions & 1 deletion pkg/interfaces/contracts/vault/VaultTypes.sol
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,7 @@ struct BufferWrapOrUnwrapParams {
// between 0% and 100% (step 0.00001%). Protocol and pool creator fees are set in the `ProtocolFeeController`, and
// ensure both constituent and aggregate fees do not exceed this precision.
uint256 constant FEE_BITLENGTH = 24;
uint256 constant MAX_FEE_PERCENTAGE = 1e18; // 100%
uint256 constant FEE_SCALING_FACTOR = 1e11;
// Used to ensure the safety of fee-related math (e.g., pools or hooks don't set it greater than 100%).
// This is the highest value that meets the precision requirements and is < 100%.
uint256 constant MAX_FEE_PERCENTAGE = (1e18 / FEE_SCALING_FACTOR - 1) * FEE_SCALING_FACTOR;
4 changes: 2 additions & 2 deletions pkg/vault/contracts/ProtocolFeeController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.s
import { SafeCast } from "@openzeppelin/contracts/utils/math/SafeCast.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { FEE_SCALING_FACTOR, MAX_FEE_PERCENTAGE } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";
import { IProtocolFeeController } from "@balancer-labs/v3-interfaces/contracts/vault/IProtocolFeeController.sol";
import { FEE_SCALING_FACTOR } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";
import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol";
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";

Expand Down Expand Up @@ -140,7 +140,7 @@ contract ProtocolFeeController is
}

modifier withValidPoolCreatorFee(uint256 newPoolCreatorFeePercentage) {
if (newPoolCreatorFeePercentage > FixedPoint.ONE) {
if (newPoolCreatorFeePercentage > MAX_FEE_PERCENTAGE) {
revert PoolCreatorFeePercentageTooHigh();
}
_;
Expand Down
6 changes: 4 additions & 2 deletions pkg/vault/contracts/Vault.sol
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,10 @@ contract Vault is IVaultMain, VaultCommon, Proxy {
}
} else {
// To ensure symmetry with EXACT_IN, the swap fee used by ExactOut is
// `amountCalculated * fee% / (100% - fee%)`. Add it to the calculated amountIn. Round up to avoid losses
// during precision loss.
// `amountCalculated * fee% / (100% - fee%)`. Add it to the calculated amountIn. Round up to avoid losing
// value due to precision loss. Note that if the `swapFeePercentage` were 100% here, this would revert with
// division by zero. We protect against this by ensuring in PoolConfigLib and HooksConfigLib that all swap
// fees (static, dynamic, pool creator, and aggregate) are less than 100%.
locals.totalSwapFeeAmountScaled18 = amountCalculatedScaled18.mulDivUp(
swapState.swapFeePercentage,
swapState.swapFeePercentage.complement()
Expand Down
6 changes: 4 additions & 2 deletions pkg/vault/contracts/lib/HooksConfigLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

pragma solidity ^0.8.24;

import { IHooks } from "@balancer-labs/v3-interfaces/contracts/vault/IHooks.sol";
import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol";
import { IHooks } from "@balancer-labs/v3-interfaces/contracts/vault/IHooks.sol";
import "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";

import { WordCodec } from "@balancer-labs/v3-solidity-utils/contracts/helpers/WordCodec.sol";
Expand Down Expand Up @@ -189,7 +189,9 @@ library HooksConfigLib {
revert IVaultErrors.DynamicSwapFeeHookFailed();
}

if (swapFeePercentage > FixedPoint.ONE) {
// A 100% fee is not supported. In the ExactOut case, the Vault divides by the complement of the swap fee.
// The minimum precision constraint provides an additional buffer.
if (swapFeePercentage > MAX_FEE_PERCENTAGE) {
revert IVaultErrors.PercentageAboveMax();
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/vault/contracts/lib/PoolConfigLib.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ library PoolConfigLib {
}

function setStaticSwapFeePercentage(PoolConfigBits config, uint256 value) internal pure returns (PoolConfigBits) {
// A 100% fee is not supported. In the ExactOut case, the Vault divides by the complement of the swap fee.
// The minimum precision constraint provides an additional buffer.
if (value > MAX_FEE_PERCENTAGE) {
revert IVaultErrors.PercentageAboveMax();
}
Expand Down
4 changes: 2 additions & 2 deletions pkg/vault/test/.contract-sizes/VaultAdmin
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Bytecode 13.985
InitCode 15.064
Bytecode 14.056
InitCode 15.135
4 changes: 2 additions & 2 deletions pkg/vault/test/.contract-sizes/VaultExtension
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Bytecode 19.778
InitCode 20.931
Bytecode 19.693
InitCode 20.846
20 changes: 3 additions & 17 deletions pkg/vault/test/foundry/DynamicFeePoolTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,8 @@ contract DynamicFeePoolTest is BaseVaultTest {
router.swapSingleTokenExactOut(pool, dai, usdc, defaultAmount, MAX_UINT256, MAX_UINT256, false, bytes(""));
}

function testSwapTooSmallAmountCalculated() public {
// Near 100% swap fee will result in near 0 amount calculated.
PoolHooksMock(poolHooksContract).setDynamicSwapFeePercentage(FixedPoint.ONE - 1);
PoolHooksMock(poolHooksContract).setSpecialSender(bob);

vm.prank(alice);
vm.expectRevert(IVaultErrors.TradeAmountTooSmall.selector);
router.swapSingleTokenExactIn(pool, dai, usdc, defaultAmount, 0, MAX_UINT256, false, bytes(""));
}

function testSwapCallsComputeFeeWithSender() public {
// Set a 100% fee, and bob as 0 swap fee sender.
// Set a near 100% fee, and bob as 0 swap fee sender.
PoolHooksMock(poolHooksContract).setDynamicSwapFeePercentage(99e16);
PoolHooksMock(poolHooksContract).setSpecialSender(bob);

Expand All @@ -186,7 +176,7 @@ contract DynamicFeePoolTest is BaseVaultTest {
router.swapSingleTokenExactIn(pool, dai, usdc, defaultAmount, 0, MAX_UINT256, false, bytes(""));

uint256 aliceBalanceAfter = usdc.balanceOf(alice);
// 100% fee; should get nothing.
// Near 100% fee; should get nothing.
assertEq(aliceBalanceAfter - aliceBalanceBefore, defaultAmount.mulDown(1e16), "Wrong alice balance (high fee)");

// Now set Alice as the special 0-fee sender.
Expand Down Expand Up @@ -249,11 +239,7 @@ contract DynamicFeePoolTest is BaseVaultTest {
}

function testSwapChargesFees__Fuzz(uint256 dynamicSwapFeePercentage) public {
dynamicSwapFeePercentage = bound(
dynamicSwapFeePercentage,
0,
FixedPoint.ONE - PRODUCTION_MIN_TRADE_AMOUNT.divDown(defaultAmount)
);
dynamicSwapFeePercentage = bound(dynamicSwapFeePercentage, 0, MAX_FEE_PERCENTAGE);
PoolHooksMock(poolHooksContract).setDynamicSwapFeePercentage(dynamicSwapFeePercentage);

vm.prank(alice);
Expand Down
16 changes: 8 additions & 8 deletions pkg/vault/test/foundry/E2eBatchSwap.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import "forge-std/Test.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { IAuthentication } from "@balancer-labs/v3-interfaces/contracts/solidity-utils/helpers/IAuthentication.sol";
import { IBasePool } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePool.sol";
import { IBatchRouter } from "@balancer-labs/v3-interfaces/contracts/vault/IBatchRouter.sol";
import { IProtocolFeeController } from "@balancer-labs/v3-interfaces/contracts/vault/IProtocolFeeController.sol";
import { Rounding } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";
import { Rounding, MAX_FEE_PERCENTAGE } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";
import { IBatchRouter } from "@balancer-labs/v3-interfaces/contracts/vault/IBatchRouter.sol";
import { IBasePool } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePool.sol";

import { ArrayHelpers } from "@balancer-labs/v3-solidity-utils/contracts/test/ArrayHelpers.sol";
import { CastingHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/CastingHelpers.sol";
import { ERC20TestToken } from "@balancer-labs/v3-solidity-utils/contracts/test/ERC20TestToken.sol";
import { ArrayHelpers } from "@balancer-labs/v3-solidity-utils/contracts/test/ArrayHelpers.sol";
import { FixedPoint } from "@balancer-labs/v3-solidity-utils/contracts/math/FixedPoint.sol";

import { PoolMock } from "../../contracts/test/PoolMock.sol";
Expand Down Expand Up @@ -82,10 +82,10 @@ contract E2eBatchSwapTest is BaseVaultTest {
vm.stopPrank();

vm.startPrank(poolCreator);
// Set pool creator fee to 100%, so protocol + creator fees equals the total charged fees.
feeController.setPoolCreatorSwapFeePercentage(poolA, FixedPoint.ONE);
feeController.setPoolCreatorSwapFeePercentage(poolB, FixedPoint.ONE);
feeController.setPoolCreatorSwapFeePercentage(poolC, FixedPoint.ONE);
// Set pool creator fee as close as possible to 100%, so protocol + creator fees ~ the total charged fees.
feeController.setPoolCreatorSwapFeePercentage(poolA, MAX_FEE_PERCENTAGE);
feeController.setPoolCreatorSwapFeePercentage(poolB, MAX_FEE_PERCENTAGE);
feeController.setPoolCreatorSwapFeePercentage(poolC, MAX_FEE_PERCENTAGE);
vm.stopPrank();

tokensToTrack = [address(tokenA), address(tokenB), address(tokenC), address(tokenD)].toMemoryArray().asIERC20();
Expand Down
4 changes: 2 additions & 2 deletions pkg/vault/test/foundry/E2eErc4626Swaps.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ contract E2eErc4626SwapsTest is BaseERC4626BufferTest {
);

vm.prank(poolCreator);
// Set pool creator fee to 100%, so protocol + creator fees equals the total charged fees.
feeController.setPoolCreatorSwapFeePercentage(pool, FixedPoint.ONE);
// Set pool creator fee close to 100%, so protocol + creator fees ~ the total charged fees.
feeController.setPoolCreatorSwapFeePercentage(pool, MAX_FEE_PERCENTAGE);

minPoolSwapFeePercentage = IBasePool(pool).getMinimumSwapFeePercentage();
maxPoolSwapFeePercentage = IBasePool(pool).getMaximumSwapFeePercentage();
Expand Down
4 changes: 2 additions & 2 deletions pkg/vault/test/foundry/E2eSwap.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ contract E2eSwapTest is BaseVaultTest {
);

vm.prank(poolCreator);
// Set pool creator fee to 100%, so protocol + creator fees equals the total charged fees.
feeController.setPoolCreatorSwapFeePercentage(pool, FixedPoint.ONE);
// Set pool creator fee near 100%, so protocol + creator fees ~ the total charged fees.
feeController.setPoolCreatorSwapFeePercentage(pool, MAX_FEE_PERCENTAGE);

minPoolSwapFeePercentage = IBasePool(pool).getMinimumSwapFeePercentage();
maxPoolSwapFeePercentage = IBasePool(pool).getMaximumSwapFeePercentage();
Expand Down
12 changes: 6 additions & 6 deletions pkg/vault/test/foundry/ProtocolFeeController.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { IAuthentication } from "@balancer-labs/v3-interfaces/contracts/solidity-utils/helpers/IAuthentication.sol";
import { IProtocolFeeController } from "@balancer-labs/v3-interfaces/contracts/vault/IProtocolFeeController.sol";
import { PoolConfig, FEE_SCALING_FACTOR } from "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";
import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol";
import { IVaultEvents } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultEvents.sol";
import { IVaultAdmin } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultAdmin.sol";
import { IPoolInfo } from "@balancer-labs/v3-interfaces/contracts/pool-utils/IPoolInfo.sol";
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";
import "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";

import { FixedPoint } from "@balancer-labs/v3-solidity-utils/contracts/math/FixedPoint.sol";

Expand Down Expand Up @@ -601,18 +601,18 @@ contract ProtocolFeeControllerTest is BaseVaultTest {
feeController.withdrawPoolCreatorFees(pool, alice);
}

function test100PercentPoolCreatorFee() public {
function testMaxPoolCreatorFee() public {
// Protocol fees will be zero.
pool = createPool();

// Set 100% pool creator fees
vm.startPrank(lp);
feeController.setPoolCreatorSwapFeePercentage(pool, FixedPoint.ONE);
feeController.setPoolCreatorSwapFeePercentage(pool, MAX_FEE_PERCENTAGE);

// Check initial conditions: aggregate swap fee percentage should be 100%.
(uint256 aggregateSwapFeePercentage, uint256 aggregateYieldFeePercentage) = IPoolInfo(pool)
.getAggregateFeePercentages();
assertEq(aggregateSwapFeePercentage, FixedPoint.ONE, "Aggregate swap fee != 100%");
assertEq(aggregateSwapFeePercentage, MAX_FEE_PERCENTAGE, "Aggregate swap fee != max (~100%)");
assertEq(aggregateYieldFeePercentage, 0, "Aggregate swap fee is not zero");

vault.manualSetAggregateSwapFeeAmount(pool, dai, PROTOCOL_SWAP_FEE_AMOUNT);
Expand Down Expand Up @@ -985,7 +985,7 @@ contract ProtocolFeeControllerTest is BaseVaultTest {
uint256 poolCreatorFeePercentage
) public {
protocolSwapFeePercentage = bound(protocolSwapFeePercentage, FEE_SCALING_FACTOR, MAX_PROTOCOL_SWAP_FEE_PCT);
poolCreatorFeePercentage = bound(poolCreatorFeePercentage, FEE_SCALING_FACTOR, FixedPoint.ONE);
poolCreatorFeePercentage = bound(poolCreatorFeePercentage, FEE_SCALING_FACTOR, MAX_FEE_PERCENTAGE);

// Ensure valid precision of each component.
protocolSwapFeePercentage = (protocolSwapFeePercentage / FEE_SCALING_FACTOR) * FEE_SCALING_FACTOR;
Expand Down Expand Up @@ -1051,7 +1051,7 @@ contract ProtocolFeeControllerTest is BaseVaultTest {
uint256 poolCreatorFeePercentage
) public {
protocolYieldFeePercentage = bound(protocolYieldFeePercentage, FEE_SCALING_FACTOR, MAX_PROTOCOL_YIELD_FEE_PCT);
poolCreatorFeePercentage = bound(poolCreatorFeePercentage, FEE_SCALING_FACTOR, FixedPoint.ONE);
poolCreatorFeePercentage = bound(poolCreatorFeePercentage, FEE_SCALING_FACTOR, MAX_FEE_PERCENTAGE);

// Ensure valid precision of each component.
protocolYieldFeePercentage = (protocolYieldFeePercentage / FEE_SCALING_FACTOR) * FEE_SCALING_FACTOR;
Expand Down
12 changes: 6 additions & 6 deletions pkg/vault/test/foundry/Registration.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ pragma solidity ^0.8.24;

import "forge-std/Test.sol";

import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";

import { IHooks } from "@balancer-labs/v3-interfaces/contracts/vault/IHooks.sol";
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";
import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol";
import { IVaultEvents } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultEvents.sol";
import { IHooks } from "@balancer-labs/v3-interfaces/contracts/vault/IHooks.sol";
import { IVault } from "@balancer-labs/v3-interfaces/contracts/vault/IVault.sol";
import "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";

import { CastingHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/CastingHelpers.sol";
import { ArrayHelpers } from "@balancer-labs/v3-solidity-utils/contracts/test/ArrayHelpers.sol";
import { InputHelpers } from "@balancer-labs/v3-solidity-utils/contracts/helpers/InputHelpers.sol";
import { ArrayHelpers } from "@balancer-labs/v3-solidity-utils/contracts/test/ArrayHelpers.sol";
import { FixedPoint } from "@balancer-labs/v3-solidity-utils/contracts/math/FixedPoint.sol";

import { PoolMock } from "../../contracts/test/PoolMock.sol";
import { HooksConfigLib } from "../../contracts/lib/HooksConfigLib.sol";
import { PoolMock } from "../../contracts/test/PoolMock.sol";
import { BaseVaultTest } from "./utils/BaseVaultTest.sol";

contract RegistrationTest is BaseVaultTest {
Expand Down Expand Up @@ -121,7 +121,7 @@ contract RegistrationTest is BaseVaultTest {
}

function testRegisterSetSwapFeePercentage__Fuzz(uint256 swapFeePercentage) public {
swapFeePercentage = bound(swapFeePercentage, 0, FixedPoint.ONE);
swapFeePercentage = bound(swapFeePercentage, 0, MAX_FEE_PERCENTAGE);
PoolRoleAccounts memory roleAccounts;
TokenConfig[] memory tokenConfig = vault.buildTokenConfig(standardPoolTokens);
LiquidityManagement memory liquidityManagement;
Expand Down
4 changes: 2 additions & 2 deletions pkg/vault/test/foundry/YieldFees.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -232,9 +232,9 @@ contract YieldFeesTest is BaseVaultTest {
}

function testYieldFeesOnSwap() public {
// Protocol yield fee 20%, and pool creator yield fees 100%.
// Protocol yield fee 20%, and pool creator yield fees near 100%.
uint256 protocolYieldFeePercentage = 20e16;
uint256 poolCreatorFeePercentage = 100e16;
uint256 poolCreatorFeePercentage = 99e16;

uint256 aggregateYieldFeePercentage = feeController.computeAggregateFeePercentage(
protocolYieldFeePercentage,
Expand Down
24 changes: 19 additions & 5 deletions pkg/vault/test/foundry/unit/HooksConfigLibHelpers.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@ pragma solidity ^0.8.24;

import "forge-std/Test.sol";

import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol";
import { IBasePool } from "@balancer-labs/v3-interfaces/contracts/vault/IBasePool.sol";
import { IHooks } from "@balancer-labs/v3-interfaces/contracts/vault/IHooks.sol";
import { IVaultErrors } from "@balancer-labs/v3-interfaces/contracts/vault/IVaultErrors.sol";
import "@balancer-labs/v3-interfaces/contracts/vault/VaultTypes.sol";

import { HooksConfigLibMock } from "@balancer-labs/v3-vault/contracts/test/HooksConfigLibMock.sol";
import { WordCodec } from "@balancer-labs/v3-solidity-utils/contracts/helpers/WordCodec.sol";
import { PoolConfigConst } from "@balancer-labs/v3-vault/contracts/lib/PoolConfigConst.sol";
import { FixedPoint } from "@balancer-labs/v3-solidity-utils/contracts/math/FixedPoint.sol";
import { HooksConfigLib } from "@balancer-labs/v3-vault/contracts/lib/HooksConfigLib.sol";
import { WordCodec } from "@balancer-labs/v3-solidity-utils/contracts/helpers/WordCodec.sol";
import { HooksConfigLibMock } from "@balancer-labs/v3-vault/contracts/test/HooksConfigLibMock.sol";

import { VaultContractsDeployer } from "../utils/VaultContractsDeployer.sol";

Expand All @@ -32,9 +33,9 @@ contract HooksConfigLibHelpersTest is VaultContractsDeployer {
// callComputeDynamicSwapFeeHook
function testCallComputeDynamicSwapFee() public {
uint256 swapFeePercentage = MAX_FEE_PERCENTAGE;

PoolSwapParams memory swapParams;
uint256 staticSwapFeePercentage = swapFeePercentage - 1;

uint256 staticSwapFeePercentage = swapFeePercentage;
vm.mockCall(
hooksContract,
abi.encodeCall(IHooks.onComputeDynamicSwapFeePercentage, (swapParams, pool, staticSwapFeePercentage)),
Expand All @@ -51,6 +52,19 @@ contract HooksConfigLibHelpersTest is VaultContractsDeployer {
assertEq(value, swapFeePercentage, "swap fee percentage mismatch");
}

function testCallComputeDynamicSwapFeeAboveMax() public {
PoolSwapParams memory swapParams;

vm.mockCall(
hooksContract,
abi.encodeCall(IHooks.onComputeDynamicSwapFeePercentage, (swapParams, pool, MAX_FEE_PERCENTAGE)),
abi.encode(true, MAX_FEE_PERCENTAGE + 1)
);

vm.expectRevert(abi.encodeWithSelector(IVaultErrors.PercentageAboveMax.selector));
hooksConfigLibMock.callComputeDynamicSwapFeeHook(swapParams, pool, MAX_FEE_PERCENTAGE, IHooks(hooksContract));
}

function testCallComputeDynamicSwapFeeRevertIfCallIsNotSuccess() public {
uint256 swapFeePercentage = MAX_FEE_PERCENTAGE;

Expand Down
Loading
Loading