Both Uniswap V1 and V2 have the same simple approach to fees. A flat 0.30% fee is applied to every trade, which is added to the Uniswap pair’s reserves.
The way Uniswap processes fees is elegantly simple. Like everything else I have seen in the Uniswap V2 contracts, the system they use is lean and nothing is wasted. The contracts squeeze every drop of functionality they can out of every line of code.
This focus on simplicity is one of the reasons it has been such a robust automated market maker exchange. However, this is also why it can be a non-trivial task to calculate the amount of fees a Uniswap pair has collected.
To figure it all out, we must first understand its constant product formula and the meaning of
Trades on a Uniswap pair are priced using a constant product formula. This means that no matter what amount of tokens are added (or in the case of flash swaps, removed) from a pair’s reserves, the product of the reserves must remain constant.
This formula, most simply expressed as
x * y = k, states that trades must not change the product (
k) of a pair’s reserve balances (
y). (Uniswap V2)
The value of
k can only change when liquidity is deposited or withdrawn. This property is fundamental to how Uniswap calculates fees. By reducing the amount paid into a Uniswap pair by the 0.30% fee before checking that the
k value has remained constant, the fee is essentially added to the reserves as new liquidity. Because no additional liquidity tokens are minted, this new liquidity is owned proportionally by all of a pair’s liquidity providers.
This is what I meant by elegant simplicity. The fees are not some tacked on feature. There is no need for gas intensive internal accounting to calculate and distribute them. They fit perfectly into the Uniswap system.
Using “k” to calculate fees
Now we know that a Uniswap pair treats fees exactly like it treats liquidity. As a pair accumulates fees, its
k value grows. But we also know that the
k value can change as normal liquidity is deposited or withdrawn.
A Uniswap pair discriminates between the two by calculating fees on every liquidity event, comparing the last
k value to the most recent one. This captures the change in
k independent of changes that resulted from minting or burning liquidity tokens.
To go from the change in
k between two liquidity events, to the amount of fees collected as a percentage of the pair’s total liquidity, we use the following formula from the “Uniswap v2 Core” whitepaper:
Note the use of square roots. Because
k is the product of a pair’s reserves, the square root of
k is also the geometric mean of a pair’s reserves.
The geometric mean is useful because it is a better representation of the total size of a pair’s reserves than
k alone. Because collecting fees adds to a pair’s reserves, the growth of the geometric mean is the best way to calculate them.
From here we can combine the amount of fees expressed as a percentage of the pair’s total liquidity, with the total value of the pair’s reserves, to get the value of collected fees.
The total value of a Uniswap pair’s reserves can be calculated using the new Uniswap V2 oracles, but I will leave that topic for another article.
My team used these techniques in the HackMoney Virtual DeFi Hackathon to build theDALP(you can view our pitch video here). DALP stands for Decentralized Autonomous Liquidity Provider. Users can purchase DALP tokens and let the DALP automatically reallocated their liquidity to the highest-earning Uniswap pairs.
To eliminate the need for manual governance, it was essential that we were able to rate Uniswap pairs against each other on-chain. This meant we had to fully understand how Uniswap calculated fees and how we could perform our own calculations. Check out our
DALPManager contract to see how we did it.
Special thanks to the DALP team
“Uniswap V2.” Uniswap/docs, https://uniswap.org/docs/v2. Accessed 28 May 2020.
Adams, Hayden, et al. “Uniswap v2 Core.” March 2020, https://uniswap.org/whitepaper.pdf