How Uniswap V2 computes the mintFee
Uniswap V2 was designed to collect 1/6th of the swap fees to the protocol. Since a swap fee is 0.3%, 1/6th of that is 0.05%, so 0.05% of every trade would go to the protocol.
Although this feature was never actually activated, we discuss this feature anyway since some forks may use it. It is also very easy to get the calculation wrong, so investing the time now to understand it will help you catch errors in similar calculations later.
Prerequisites
You need to be familiar with all the prior chapters in the Uniswap V2 Book to be able to follow along.
Collecting protocol fees during swaps is inefficient
It would be inefficient to collect 0.05% of the fee on every trade because that would require additional token transfers. Transferring ERC20 tokens requires a storage update, so transferring to two addresses instead of one would be considerably more expensive.
Therefore, the fee is collected when a liquidity provider calls burn or mint. Since these operations are infrequent compared to [swapping tokens](swapping tokens), this will lead to gas savings. To collect the mintFee
, the contract calculates the amount of fees collected since that last happened, and mints enough LP tokens to the beneficiary address such that the beneficiary is entitled to 1/6th of the fee.
Terminology of fee and mintFee
To avoid confusion in terminology, we refer to “fee” as the 0.3% collected from traders during the swap, and the “mintFee” the 1/6th of the 0.3% fee. Yes, having fee in both terms is not great nomenclature, but that’s what we have to work with.
Liquidity is the square root of the products of the token balances in the pool. The justification for this formula was discussed in the Uniswap V2 swap function article. Some literature refers to this as $\sqrt{k}$ where $k = xy$ and $x$ and $x$ are the token balances in the pool (the reserves of $x$ and $y$). We refer to liquidity with $\ell$ since it is shorter to write than $\sqrt{k}$.
Computing the mintFee assumptions
For this to work, Uniswap V2 relies on the following two invariants:
- If
mint()
and burn()
are not called, the liquidity of the pool can only increase. - The increase in liquidity is purely due to fees (or donations).
By measuring the increase in liquidity since the last
mint()
or burn()
transaction, the pool knows how much fees were collected.
These would be good invariant tests to write, but for now we will take for granted that they are true.
Example calculation of mintFee
Suppose at $t_1$ the pool starts at 10 token0
and 10 token1
.
After a lot of trading and fee collection, the new pool balance is 40 token0
and 40 token1
at $t_2$.
Liquidity is measured as the square root of the product of the two tokens, i.e. $\ell = \sqrt{k}$. The liquidity was 10 at $t_1$ and 40 at $t_2$. Said another way, $\ell_1 = 10$ and $\ell_2 = 40$. We are going to charge a fee on the growth from 10 to 40.
30 units of liquidity out of the total 40 at $t_2$ is due to swap fees.
We want to mint enough LP tokens, the “mintFee” such that the beneficiary receives 1/6th of the “fee portion” of the pool. That is, they should be entitled to 5 units of liquidity (30 / 6) that came from profit.
The protocol should not collect fees on any of the “original liquidiy” i.e. $\ell_1$. The protocol should only collect fees on the delta, i.e. $\ell_2 – \ell_1$.
When mint()
or burn()
is called, Uniswap mints LP tokens to the protocol fee recipient. This causes a dilution such that the current supply of LP tokens can redeem the original liquidity plus 5/6ths of the “profit liquidity” (liquidity from swap fees).
Deriving the mint fee formula
Let’s use the following notation:
$s$ supply of LP tokens before the dilutive protocol fee LP tokens are minted.
$\eta$ is the amount of LP tokens that will be minted to the protocol. It should be enough to redeem 1/6th of the profit liquidity.
$\ell_1$ is the liquidity of the original deposit, i.e. liquidity the LPs provided.
$\ell_2$ is the liquidity of the original deposits and the liquidity that results from swap fees.
$d$ is the amount of liquidity owed to the LPs net of the protocol fee. That is, the LPs should be entitled to their original deposit and 5/6ths of the profit.
$p$ is the amount of liquidity owed to the protocol. This is 5/6ths of $\ell_2 – \ell_1$.
To compute $\eta$ we observe the following invariant must be true:
$$
\frac{\eta}{p}=\frac{s}{d}
$$
In other words, the previous total supply, $s$ LP tokens can redeem the liquidity due to the LPs, and $\eta$ LP tokens can redeem the amount due to the protocol.
The graphic below solves for $\eta$ in terms of the change in liquidity.

The _mintFee()
code of Uniswap V2
With that derivation in mind, the bulk of the Uniswap V2 _mintFee
function should be self-explanatory. Here are some changes in notation:
- current liquidity after fees $\ell_2$ is
rootK
- previous liquidity $\ell_1$ is
kLast
- the supply of LP tokens before dilution $s$ is
totalSupply
- the function is state changing, it mints the mintFee inside the function rather than return the calculation of the mintFee (blue highlight)
- the fee can be switched on an off with the flag
feeOn
which we haven’t discussed yet

We will dive into this function some more, but first we want to note where kLast
gets updated.
Where klast
gets updated
In the code above, kLast is not set unless feeOn
is switched to false
. It is set at the completion of mint and burn but not swap because we are interested in measuring the growth of fees due to swaps between liquidity deposit and withdrawal events. The place kLast
is set is marked with a yellow box.
Mint function updating klast

Burn function updating klast

_mintFee
code conditions
Now that we understand how kLast is updated, we can fully explain the _mintFee function.

Let’s consider the possibilities in the code snippet above, repeated for convenience.
- The
feeOn
is false
, nothing is minted (green highlight) - The
feeOn
is false
, kLast
is zero (yellow highlight) - The
feeOn
is false
, kLast
is not zero (yellow highlight) - The
feeOn
is true
, but there was no growth in liquidity (orange highlight) - The
feeOn
is true
, and there was liquidity growth (orange highlight), so the mint fee applies (blue highlight)
It’s easier to see the logic in a decision tree, so here is the decision tree with the branches colored the same as the if statements.

Learn more with RareSkills
Please see our blockchain bootcamp to see our course offerings.
Originally Published November 14, 2023