QuadraticSwapFees
Author: Will
A library to calculate fees that grow with respect to price deviation from a reference point. This library relies on a reference reserve from the start of the block to determine what the overall growth in price has been in the current block. Fee Model Overview: The fee structure uses two distinct models depending on the magnitude of price deviation:
- Quadratic Fee Model (for moderate price changes):
- Used when price deviation is relatively small
- Fee grows proportionally to the square of the price movement
- This creates a smooth, incentive-aligned fee curve that discourages large single swaps while keeping fees reasonable for normal market activity
- Key property: If one swap would pay fee
F, splitting it into two equal swaps would pay two fees that sum to approximatelyF
- Linear Fee Model (for extreme price changes):
- Used when price deviation exceeds the quadratic threshold
- Fee grows linearly beyond the threshold point, capping at
MAX_QUADRATIC_FEE_PERCENT - This prevents fees from becoming prohibitively expensive for very large swaps while still maintaining strong economic disincentives against massive price manipulations
- The linear growth provides a more predictable fee structure for extreme market conditions Why Two Models?
- Quadratic fees alone would become so high that the invariant curve property of being monotonic, leading larger swaps amounts in would eventually lead to less assets out than smaller swaps in.
- Linear fees alone wouldn't provide enough protection against price manipulation for moderate swaps Price Movement Behavior:
- If the price moves away from the reference, and then back toward it, the fee is minimal until the price again crosses the starting reference price
- Only the net price deviation from the start-of-block reference is charged
State Variables
MIN_FEE_Q64
Minimum fee is one tenth of a basis point.
uint256 public constant MIN_FEE_Q64 = 0x1999999999999999;
BIPS_Q64
10000 bips per 100 percent in Q64.
uint256 public constant BIPS_Q64 = 0x27100000000000000000;
MAX_QUADRATIC_FEE_PERCENT
Max percent fee growing at a quadratic rate. After this the growths slows down.
uint256 internal constant MAX_QUADRATIC_FEE_PERCENT = 40;
N
A scaler that controls how fast the fee grows, at 20, 9x price change will be a 40% fee.
uint256 internal constant N = 20;
RESERVE_MULTIPLIER
A reserve multiplier used to determine the boundary at which we switch from quadratic to linear fee.
uint256 private constant RESERVE_MULTIPLIER = 2;
LINEAR_START_REFERENCE_SCALER
the at which we switch from quadratic fee to a more linear fee.
uint256 private constant LINEAR_START_REFERENCE_SCALER = 4;
MAX_QUADRATIC_FEE_PERCENT_BIPS
the fee at LINEAR_START_REFERENCE_SCALER in bips
uint256 private constant MAX_QUADRATIC_FEE_PERCENT_BIPS = 4000;
N_TIMES_BIPS_Q64_PER_PERCENT
or N times bips in one percent in Q64
uint256 private constant N_TIMES_BIPS_Q64_PER_PERCENT = 0x7d00000000000000000;
TWO_Q64
2 times Q64 or Q65
uint256 private constant TWO_Q64 = 0x20000000000000000;
MAX_QUADRATIC_FEE_Q64
MAX_QUADRATIC_FEE_PERCENT in Q64,
uint256 private constant MAX_QUADRATIC_FEE_Q64 = 0x280000000000000000;
Functions
calculateSwapFeeBipsQ64
Computes the swap fee based on the input amount and the pool's
currentReserve and referenceReserve for the input asset.
Control flow by scenario:
currentReserve >= referenceReserve(price already at/away from reference):- If
input + RESERVE_MULTIPLIER * currentReserve < referenceReserve * LINEAR_START_REFERENCE_SCALER: Use the quadratic fee model (closer to reference, pre-threshold). - Otherwise: Use the linear fee model (farther from reference, post-threshold).
currentReserve < referenceReserve(price at/moving back toward the start-of-block reference):- If
input + currentReserve <= referenceReserve: Does not cross the reference. Only the global minimum fee will apply at the end. - If
input + currentReserve > referenceReserve: Crosses the reference. The portion beyond the reference (pastBy) is charged using either the quadratic or linear model depending onpastBy: pastBy > RESERVE_MULTIPLIER * referenceReserve→ use linear fee model- otherwise → use quadratic fee model
The resulting fee for the beyond-reference portion is then weighted by
pastBy / input.