Uniswap Smart Contract Breakdown. Explaining its functionality by… | by Nazar Ilamanov | Feb, 2022

Explaining its functionality by grouping lines of code

Nazar Ilamanov
  • How Uniswap code is organized
  • Uniswap functionalities
  • Core contracts: Pair (hard)
  • Core contracts: Factory (easy)
  • Periphery contract: Router (easy)
  • Fully annotated code

The whole purpose of Uniswap is to allow you to swap one ERC20 token for another. For example, you need Dogecoin but you only have Shiba coin. Uniswap allows you to sell your Dogecoin and get Shiba in return. This is all done in an automatic and decentralized fashion. Uniswap is just a decentralized exchange.

  1. Automated market makers (AMM): There is no centralized matchmaker. There are people who provide both tokens (Dogecoin and Shiba). They are called liquidity providers. These liquidity providers create a pool of Dogecoin and Shiba tokens. Now traders can come and deposit Dogecoin and get Shiba in return. This is done automatically, without a centralized entity. Traders pay a small percentage fee for the trade which goes to liquidity providers for their services.
From “Uniswap — a Unique Exchange”

Uniswap has 3 versions.

  • v1 is too simple and does not have all the modern features.
  • v3 is essentially v2 but improved and optimized — its code is way more complicated than v2.

Uniswap has 4 smart contracts in total. They are divided into core and periphery.

  1. Periphery is for interacting with the core.
  1. Factory — creates and keeps track of all Pair contracts
  2. ERC20 — for keeping track of ownership of pool. Think of the pool as a property. When liquidity providers provide funds to the pool, they get “pool ownership tokens” in return. These ownership tokens earn rewards (by traders paying a small percentage for each trade). When liquidity providers want their funds back, they just submit the ownership tokens back and get their funds + the rewards that were accumulated. The ERC20 contract keeps track of the ownership tokens.

We talked about the 4 smart contracts that Uniswap has and how they are organized. But what’s the main functionality that these contracts implement? The main functionality is the following:

  1. Functions for liquid providers — deposit more funds and withdraw the funds along with the rewards
  2. Functions for traders — swapping
  3. Managing pool ownership tokens
  4. Protocol fee — Uniswap v2 introduced a switchable protocol fee. This protocol fee goes to the Uniswap team for their efforts in maintaining Uniswap. At the moment, this protocol fee is turned off but it can be turned on in the future. When it’s on, the traders will still pay the same fee for trading but 1/6 of this fee will now go to the Uniswap team and the rest 5/6 will go to the liquidity providers as the reward for providing their funds.

Let’s now dig into the actual Solidity code of the Uniswap smart contracts. We will start with the Pair contract. This is the most complex of the 4 smart contracts. The rest will get easier.

  • It implements the IUniswapV2Pair interface, which is just an interface for this contract (can be found here). It also extends the UniswapV2ERC20 contract. Why? For managing the pool ownership tokens. We will learn more about it later.
  • SafeMath is a library for dealing with overflow/underflow. UQ112x112 is a library for supporting floating numbers. Solidity does not support floats by default. This library represents floats using 224 bits. The First 112 bits are for the whole number, and the last 112 bits are for the fractional part.

Managing the funds

A Uniswap Pair is an exchange between a pair of tokens such as Dogecoin and Shiba. These tokens are represented as token0 and token1 in the contract. They are the addresses of the ERC20 smart contracts that implement them.

This is how funds are managed across 3 smart contracts
  • _reserve0 and _reserve1 are Uniswap’s previously known balances (last time balanceOf was checked).
  • All we do in this function is check for overflow (line 74), update price oracle (this will be explained in a later section), update reserves, and update a Sync event.

Minting and Burning

Now onto the next functionality — minting and burning. Minting is when a liquidity provider adds funds to the pool and as a result, new pool ownership tokens are minted (created out of thin air) for the liquidity provider. Burning is the opposite — liquidity provider withdraws funds (and the accumulated rewards) and his pool ownership tokens are destroyed (destroyed).

  • We read the balances of our contract (the Pair contract) on lines 112 and 113 and then calculate the amount of each token that was deposited.
  • The pink part of the code is for the optional protocol fee. We will examine it later.
  • totalSupply indicates the total supply of the pool ownership tokens and is a stored variable in the UniswapV2ERC20 contract (see my breakdown of it here). The Pair contract extends UniswapV2ERC20 which is why it has access to the totalSupply variable.
  • If totalSupply is 0, it means that this pool is brand new and we need to lock in MINIMIUM_LIQUIDITY amount of pool ownership tokens to avoid division by zero in the liquidity calculations. The way it’s locked in is by sending it to the address zero. (No one knows the private key that will lead to the address zero so by sending funds to the address zero, you essentially lock the funds forever).
  • liquidity variable is the amount of new pool ownership tokens that need to be minted to the liquidity provider. The liquidity provider gets a proportional amount of pool ownership tokens depending on how much new funds he provides (line 123)
  • We finally mint new pool ownership tokens to the to address (line 126). to is the address of the liquidity provider (this will be provided by the Periphery contract called the Router which calls the mint function)
  • balance0 and balance1 are total balances of the tokens in this pool. liquidity is the amount of pool ownership tokens that the liquidity provider (who wishes to cash out) has. Why do access the liquidity as the balance of address(this)? Because the liquidity was transferred to the Pair contract by the Periphery contract before calling the burn function.
  • We calculate the amounts of tokens to withdraw to the liquidity provider proportionally to how much liquidity (pool ownership tokens) he has (lines 144 and 145)
  • We then burn his liquidity and transfer the tokens to him.
  • Rewards to the liquidity provider are automatically withdrawn along with his funds. The math makes sure that rewards are accumulated properly and that you get more than you deposited.

Leave a Comment