Fee Calculations
Make sure that the fees do not change unexpectedly
Use Case
In AMMs and other DeFi protocols, trading fees are a critical security parameter that directly impacts user returns and protocol revenue. Unexpected fee changes can lead to:
- Unauthorized fee manipulation by malicious actors
- Protocol revenue loss through fee bypasses
- User losses from unexpected fee increases
- Market manipulation through fee changes
This assertion is particularly important because:
- Fees are a primary revenue source for many DeFi protocols
- Fee changes can be used as an attack vector to drain protocol value
- Users rely on consistent fee structures for trading strategies
- Protocol sustainability depends on predictable fee mechanisms
Applicable Protocols
- AMMs (Automated Market Makers) like Velodrome, Aerodrome, and Curve
- DEX aggregators that charge routing fees
- Lending protocols with origination fees
- Yield aggregators with performance fees
- Cross-chain bridges with transfer fees
Each protocol type needs this assertion because:
- AMMs: Fee changes can be used to manipulate price impact and drain liquidity
- DEX aggregators: Fee manipulation could bypass routing security
- Lending protocols: Fee changes could affect interest calculations
- Yield aggregators: Performance fee changes could drain protocol value
- Bridges: Fee changes could be used to manipulate cross-chain arbitrage
Explanation
The assertion uses a whitelist approach to control fee changes:
-
Trigger Registration:
- Uses
registerStorageChangeTrigger
to detect any changes to the fee storage slot - When triggered, we know a fee change has occurred
- Uses
-
Whitelist Validation:
- Maintains hardcoded allowed fee values for both stable and non-stable pools
- For stable pools: allows 0.1% (1) and 0.15% (15)
- For non-stable pools: allows 0.25% (25) and 0.30% (30)
- When a change occurs, verifies the new fee matches one of the allowed values
- Prevents unauthorized fee modifications
The assertion uses the following cheatcodes and functions:
registerStorageChangeTrigger()
: Detects changes to the fee storage slotph.load()
: Retrieves the new fee value after a changegetStateChangesUint()
: Gets all state changes for the fee storage slot to verify intermediate changes
This approach ensures that:
- Only whitelisted fee values are allowed
- Protocol can still update fees through proper channels
- Unauthorized fee modifications are prevented
- All intermediate fee changes in the callstack are also validated
For more information about cheatcodes, see the Cheatcodes Documentation.
Code Example
Note: This code example is maintained in the Phylax Assertion Examples Repository. For a full examples with mock protocol code and tests please refer to the repository.
Testing
To test this assertion:
- Deploy the assertion contract with a test pool
- Execute transactions that should maintain fees
- Attempt transactions that would modify fees
- Verify the assertion catches unauthorized changes
Assertion Best Practices
- Use whitelists to explicitly define allowed fee values