> For the complete documentation index, see [llms.txt](https://docs.valantis.xyz/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.valantis.xyz/amms-and-vaults/design-space/modules/swap-fee-module.md).

# Swap Fee Module

*The Swap Fee Module implementation for **STEX** is detailed* [*here*](/amms-and-vaults/staked-amm/swap.md)*.*

<figure><img src="https://986147118-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F1hNJeG4CApeBcE2NlR61%2Fuploads%2Fgit-blob-51eb0ac00ad31effb0a8f73473415a6bb90fa45a%2FSwap%20Fee%20Module%20Fig.%201_V2%20(1).jpg?alt=media" alt=""><figcaption><p>Swap Fee Module in context</p></figcaption></figure>

The Swap Fee Module is responsible for calculating the fees applied at swap time. It is an optional module. When Swap Fee Module is not set, the pool will use the default constant swap fee set at construction.

At the beginning of each swap, the following function gets called:

```solidity
struct SwapFeeModuleData {
    uint256 feeInBips;
    bytes internalContext;
}

function getSwapFeeInBips(
        address _tokenIn,
        address _tokenOut,
        uint256 _amountIn,
        address _user,
        bytes memory _swapFeeModuleContext
    ) external returns (SwapFeeModuleData memory swapFeeModuleData);
```

It takes the following inputs:

* `_tokenIn` Input token for the swap.
* `_tokenOut` Output token for the swap.
* `_amountIn` Input token amount which `_user` wants to trade.
* `_user` address of `msg.sender` in the pool’s swap function.
* `_swapFeeModuleContext` Optional bytes encoded calldata for the case where the Swap Fee Module leverages off-chain or external data to function. For example, this can be used to provide signed price feeds or volatility estimates.

The module returns the fee amount to be charged in basis points (`swapFeeModuleData.feeInBips`) and arbitrary internal context as bytes for the case where the Swap Fee Module needs to be called once again at the end of the swap (`swapFeeModuleData.internalContext`). **IMPORTANT:** Since the Swap Fee Module gets queried before the Liquidity Module, there is no way to know in advance how much liquidity will be filled when quoting fees. Hence the `swapFeeModuleData.feeInBips` should be understood as follows:

First, we calculate `amountInMinusFee` as follows:

```solidity
uint256 amountInMinusFee = Math.mulDiv(_amountIn, 1e4, 1e4 + swapFeeModuleData.feeInBips);
```

Note that `swapFeeModuleData.feeInBips` must not be greater than `1e4`, meaning that the maximum possible swap fee is 50%.

Then, once the Liquidity Module gets queried and returns `liquidityQuote.amountInFilled`, the `effectiveFee` is calculated as follows:

```solidity
uint256 effectiveFee = Math.mulDiv(liquidityQuote.amountInFilled, swapFeeModuleData.feeInBips, 1e4, Math.Rounding.Up);
```

We round up to ensure that fee calculation goes in favor of the pool.

So the total amount that the user gets changed in tokenIn will be `liquidityQuote.amountInFilled + effectiveFee`

`swapFeeModuleData.feeInBips` should be interpreted as the fee multiplier in basis points which gets applied to the tokenIn amount filled by the liquidity module, not the user’s initial `_amountIn`

If `swapFeeModuleData.internalContext` is a non-empty byte encoded payload, the following function gets called after execution of the swap:

```solidity
function callbackOnSwapEnd(
        uint256 _effectiveFee,
        uint256 _amountInUsed,
        uint256 _amountOut,
        SwapFeeModuleData memory _swapFeeModuleData
    ) external;
```

This allows the Swap Fee Module to make any required internal state updates.

Swap Fee Modules can be reusable across both Universal and Sovereign pools without requiring developers to re-write nor replace Liquidity Modules. They can implement any kind of fee calculation logic, as long as they do not quote a fee above 50% of the input token amount on each swap.

**Alternatively**, in the case where a Swap Fee Module is not added to the pool (`swapFeeModule = address(0)`), the pool will use an immutable fee multiplier to calculate swap fees, lowering gas costs. Even after whitelisting a swap fee module, `poolManager` can always reset it to `address(0)`, in which case a default constant swap fee would be applied.

**Alternatively**, both the Swap Fee Module and the immutable default fee can be ignored and the Liquidity Module can consider fee accounting logic when providing price quotes. Though this removes the ability for a Pool Manager to collect fees.

**NOTE:** The Swap Fee Module can only be changed by the Pool Manager once every 3 days. This prevents unexpected changes in Swap Fee logic.
