> ## Documentation Index
> Fetch the complete documentation index at: https://docs.phylax.systems/llms.txt
> Use this file to discover all available pages before exploring further.

# Fee Calculations

> Make sure that the fees do not change unexpectedly

## When to Use This Pattern

Prevents unauthorized fee manipulation in AMMs and DeFi protocols by using a whitelist approach to control fee changes. Critical for AMMs (Velodrome, Aerodrome, Curve), DEX aggregators, lending protocols with origination fees, yield aggregators with performance fees, and cross-chain bridges with transfer fees.

Unexpected fee changes can lead to unauthorized manipulation, protocol revenue loss, user losses, or market manipulation through fee bypasses.

## What This Pattern Checks

Uses a whitelist approach to control fee changes:

* `registerTxEndTrigger()`: Detect changes to fee storage slot
* `ph.loadStateAt()`: Retrieve new fee value after change
* Maintains hardcoded allowed fee values for stable pools (0.1%, 0.15%) and non-stable pools (0.25%, 0.30%)

When triggered, verifies the new fee matches one of the allowed values, preventing unauthorized modifications while allowing proper protocol updates.

For more information about cheatcodes, see the [Cheatcodes Documentation](/credible/cheatcodes-reference).

## Assertion Pattern

```solidity theme={null}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Assertion} from "credible-std/Assertion.sol";
import {AssertionSpec} from "credible-std/SpecRecorder.sol";
import {PhEvm} from "credible-std/PhEvm.sol";

contract AmmFeeVerificationAssertion is Assertion {
    bytes32 internal constant FEE_SLOT = bytes32(uint256(1));
    bytes32 internal constant STABLE_SLOT = bytes32(uint256(2));

    uint256 private constant STABLE_POOL_FEE_1 = 1;
    uint256 private constant STABLE_POOL_FEE_2 = 15;
    uint256 private constant NON_STABLE_POOL_FEE_1 = 25;
    uint256 private constant NON_STABLE_POOL_FEE_2 = 30;

    constructor() {
        registerAssertionSpec(AssertionSpec.Reshiram);
    }

    function triggers() external view override {
        registerTxEndTrigger(this.assertFeeVerification.selector);
    }

    /// @notice Checks that the post-transaction fee is one of the allowed values.
    function assertFeeVerification() external view {
        address pool = ph.getAssertionAdopter();
        PhEvm.ForkId memory postFork = _postTx();

        bool isStable = uint256(ph.loadStateAt(pool, STABLE_SLOT, postFork)) != 0;
        uint256 newFee = uint256(ph.loadStateAt(pool, FEE_SLOT, postFork));
        bool isAllowed = isStable
            ? (newFee == STABLE_POOL_FEE_1 || newFee == STABLE_POOL_FEE_2)
            : (newFee == NON_STABLE_POOL_FEE_1 || newFee == NON_STABLE_POOL_FEE_2);

        require(isAllowed, "Fee change to unauthorized value");
    }
}
```

<Note>Full examples and mock protocol code are available in [credible-std](https://github.com/phylaxsystems/credible-std/tree/master/examples/assertions-book).</Note>

## Related Patterns

* [Price Within Ticks](/assertions-book/assertions/ass15-price-within-ticks)
