Swap Fees

More Details

For more detailed information on Swap Fees please see the Swap Fee Concepts section.

A swap fee is charged for each swap, as well as on the non-proportional amounts in add/remove liquidity operations. The swap fee is always charged on the amount in:

  • EXACT_IN, on the given amount:
// Round up to avoid losses during precision loss.
locals.totalSwapFeeAmountScaled18 = poolSwapParams.amountGivenScaled18.mulUp(swapState.swapFeePercentage);
poolSwapParams.amountGivenScaled18 -= locals.totalSwapFeeAmountScaled18;
  • EXACT_OUT, on the calculated amount:
// 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 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()
);

The @bush.fi/mathsopen in new window Vault applies exactly this logic, including the rounding, so you do not need to reimplement it; swapFee in the pool state is the static fee and the hook maths (if any) supplies the dynamic one.

Swap fees come in two different forms for Bush pools:

  • Static Swap Fee:
    • Initially set as part of the pool registration.
    • Authorized addresses can then change the value by invoking the vault.setStaticSwapFeePercentage(address pool, uint256 swapFeePercentage) function.
    • If the static swap fee is changed, the Vault emits SwapFeePercentageChanged(pool, swapFeePercentage).
    • Note - setStaticSwapFeePercentage can also be called as part of a regular hook
    • Read it with getStaticSwapFeePercentage(pool) on the Vault, or from the pool's get<Pool>DynamicData().staticSwapFeePercentage.
  • Dynamic Swap Fee Using Hooks:
    • Using Hooks a pool can be set up to use dynamic swap fees.
    • The Vault uses the onComputeDynamicSwapFeePercentage() hook to fetch the dynamic swap fee. This function can implement arbitrary logic.
    • Even when a pool is set to use dynamic swap fees, it still maintains a static swap fee. However, this static fee is not utilized directly (the StableSurge hook, for example, uses it as the floor).
    • Whether a pool uses a dynamic fee is in getHooksConfig(pool).shouldCallComputeDynamicSwapFee. See the Hooks Reference for the supported hooks and their maths.

The pseudo logic to determine how the swap fee is calculated looks like:

swapFeePercentage =
     Pool has DynamicSwapFee => call DynamicSwapFeeHook in the pool
     else => load static Swap fee percentage from Vault

Aggregate fee

A portion of every swap fee is taken by the protocol and pool creator, the aggregate swap fee. It is charged out of the swap fee, not on top of it, so it does not change the amount the trader receives - but it does change how much of the fee stays in the pool and therefore the pool's balances after the swap. It is read with getPoolConfig(pool).aggregateSwapFeePercentage and is the aggregateSwapFee field of the maths pool state. It changes on AggregateSwapFeePercentageChanged.