You most likely know the fixed product method (x*y=ok) that powers Uniswap. However how does the Uniswap sensible contract actually work beneath the hood?
On this article, we’re going to perceive how Uniswap is carried out by breaking down its sensible contract. We’re going to look at a few hundred strains of Solidity code that generate $1.28 billion in income day by day.
Spoiler alert: you will notice a really environment friendly, elegant, and safe Solidity code forward.
Right here is the define of this text:
- How Uniswap works at a excessive stage
- How Uniswap code is organized
- Uniswap functionalities
- Core contracts: Pair (laborious)
- Core contracts: Manufacturing facility (simple)
- Periphery contract: Router (simple)
- Totally annotated code
The entire objective of Uniswap is to permit you to swap one ERC20 token for one more. For instance, you want Dogecoin however you solely have Shiba coin. Uniswap lets you promote your Dogecoin and get Shiba in return. That is all finished in an automated and decentralized style. Uniswap is only a decentralized change.
Exchanges may be carried out in two methods.
- Order e-book mannequin: Consumers and sellers file orders. And the centralized system matches the purchase orders to the promote orders. That is how the standard inventory change works.
- Automated market makers (AMM): There is no such thing as a centralized matchmaker. There are individuals who present each tokens (Dogecoin and Shiba). They’re referred to as liquidity suppliers. These liquidity suppliers create a pool of Dogecoin and Shiba tokens. Now merchants can come and deposit Dogecoin and get Shiba in return. That is finished robotically, with out a centralized entity. Merchants pay a small share charge for the commerce which matches to liquidity suppliers for his or her companies.
Uniswap makes use of the AMM approach. How does it decide the change fee in a pool? i.e. what number of Shiba tokens is 1 Dogecoin value? That is decided by the fixed product method
(Dogecoin quantity)*(Shiba quantity)=ok. Throughout trades, this product should stay fixed.
Don’t fear if this isn’t fully clear. We’ll study extra about this method and market dynamics as we go alongside in the remainder of the article.
Uniswap has 3 variations.
- We’ll be working with v2.
- v1 is simply too easy and doesn’t have all the trendy options.
- v3 is basically v2 however improved and optimized — its code is far more difficult than v2.
If you wish to know extra concerning the variations between Uniswap variations, take a look at my screenshot essay.
Uniswap has 4 sensible contracts in whole. They’re divided into core and periphery.
- Core is for storing the funds (the tokens) and exposing features for swapping tokens, including funds, getting rewards, and so on.
- Periphery is for interacting with the core.
Core consists of the next sensible contracts:
- Pair — a sensible contract that implements the performance for swapping, minting, burning of tokens. This contract is created for each change pair like Dogecoin ↔ Shiba.
- Manufacturing facility — creates and retains monitor of all Pair contracts
- ERC20 — for protecting monitor of possession of pool. Consider the pool as a property. When liquidity suppliers present funds to the pool, they get “pool possession tokens” in return. These possession tokens earn rewards (by merchants paying a small share for every commerce). When liquidity suppliers need their funds again, they only submit the possession tokens again and get their funds + the rewards that had been accrued. The ERC20 contract retains monitor of the possession tokens.
Periphery consists of only one sensible contract:
- Router is for interacting with the core. Offers features resembling
swapETHForExactTokens, and so on.
We talked concerning the 4 sensible contracts that Uniswap has and the way they’re organized. However what’s the principle performance that these contracts implement? The principle performance is the next:
- Managing the funds (how tokens resembling Dogecoin and Shiba are managed within the pool)
- Capabilities for liquidity suppliers — deposit extra funds and withdraw the funds together with the rewards
- Capabilities for merchants — swapping
- Managing pool possession tokens
- Protocol charge — Uniswap v2 launched a switchable protocol charge. This protocol charge goes to the Uniswap group for his or her efforts in sustaining Uniswap. In the meanwhile, this protocol charge is turned off however it may be turned on sooner or later. When it’s on, the merchants will nonetheless pay the identical charge for buying and selling however 1/6 of this charge will now go to the Uniswap group and the remainder 5/6 will go to the liquidity suppliers because the reward for offering their funds.
Along with the principle performance described above, Uniswap has one other one that’s not core to Uniswap however it’s a helpful helper for different contracts within the Ethereum ecosystem:
- Worth oracle — Uniswap tracks costs of tokens relative to one another and can be utilized as a worth oracle for different sensible contracts within the Ethereum ecosystem. Because of arbitrage (which we are going to study later within the article), Uniswap costs are likely to intently observe the actual market costs of tokens. So the Uniswap worth oracle is a reasonably good approximation of the actual market costs.
Let’s now dig into the precise Solidity code of the Uniswap sensible contracts. We’ll begin with the Pair contract. That is essentially the most advanced of the 4 sensible contracts. The remainder will get simpler.
The Pair contract implements the change between a pair of tokens resembling Dogecoin and Shiba. The total code of the Pair sensible contract may be discovered on Github beneath v2-core/contracts/UniswapV2Pair.sol
Let’s break it down line-by-line.
First, the import statements:
Subsequent, the contract declaration:
- The contract identify is
- It implements the
IUniswapV2Pairinterface, which is simply an interface for this contract (may be discovered here). It additionally extends the
UniswapV2ERC20contract. Why? For managing the pool possession tokens. We’ll study extra about it later.
SafeMathis a library for coping with overflow/underflow.
UQ112x112is a library for supporting floating numbers. Solidity doesn’t assist floats by default. This library represents floats utilizing 224 bits. The First 112 bits are for the entire quantity, and the final 112 bits are for the fractional half.
Subsequent, we are going to group the code by the performance that it implements.
Managing the funds
A Uniswap Pair is an change between a pair of tokens resembling Dogecoin and Shiba. These tokens are represented as
token1 within the contract. They’re the addresses of the ERC20 sensible contracts that implement them.
reserve variables retailer how a lot of the token we have now on this Pair.
You would possibly marvel, the place is the precise token saved? That is finished within the ERC20 contract of the token itself. It’s not finished within the Pair contract. The Pair contract simply retains monitor of the reserves. From the ERC20’s perspective, the Pair contract is only a common person that may switch and obtain tokens, it has its personal stability, and so on.
The Pair contract calls ERC20’s features resembling
proprietor=Pair contract’s handle) and
switch to handle the tokens (see my ERC20 Smart Contract Breakdown if you happen to’re confused). Right here is an instance of how ERC20’s
switch operate is used within the Pair contract.
_update operate under is known as every time there are new funds deposited or withdrawn by the liquidity suppliers or tokens are swapped by the merchants.
Just a few issues occurring on this operate:
balance1are the balances of tokens within the ERC20. They’re the return worth of ERC20’s
_reserve1are Uniswap’s beforehand recognized balances (final time
- All we do on this operate is test for overflow (line 74), replace worth oracle (this might be defined in a later part), replace reserves, and replace a
What’s the distinction between the arguments
_reserve0, _reserve1 and the saved variables
reserve0, reserve1 (proven under)? They’re primarily the identical. The callers of the
_update operate have already got learn the
reserve variables from storage and simply move them as arguments to the
_update operate. That is only a method to save on fuel. Studying from storage is costlier than studying from reminiscence
You’ll discover this repeatedly: Uniswap completely loves effectivity and fuel financial savings. They squeeze out each single efficiency level they’ll from Solidity.
_reserve1are one instance of it.
Minting and Burning
Now onto the subsequent performance — minting and burning. Minting is when a liquidity supplier provides funds to the pool and consequently, new pool possession tokens are minted (created out of skinny air) for the liquidity supplier. Burning is the alternative — liquidity supplier withdraws funds (and the accrued rewards) and his pool possession tokens are burned (destroyed).
Let’s check out the
- Instantly you would possibly discover the fuel financial savings once more:
totalSupplyare transferred from storage to reminiscence (strains 111 and 118) in order that it’s cheaper to learn these values.
- We learn the balances of our contract (the Pair contract) on strains 112 and 113 after which calculate the quantity of every token that was deposited.
- The pink a part of the code is for the elective protocol charge. We’ll look at it later.
totalSupplysignifies the full provide of the pool possession tokens and is a saved variable within the
UniswapV2ERC20contract (see my breakdown of it here). The Pair contract extends
UniswapV2ERC20which is why it has entry to the
totalSupplyis 0, it signifies that this pool is model new and we have to lock in
MINIMIUM_LIQUIDITYquantity of pool possession tokens to keep away from division by zero within the liquidity calculations. The best way it’s locked in is by sending it to the handle zero. (nobody is aware of the non-public key that can result in the handle zero so by sending funds to the handle zero, you primarily lock the funds without end).
liquidityvariable is the quantity of latest pool possession tokens that have to be minted to the liquidity supplier. The liquidity supplier will get a proportional quantity of pool possession tokens relying on how a lot new funds he gives (line 123)
- We lastly mint new pool possession tokens to the
tohandle (line 126).
tois the handle of the liquidity supplier (this might be offered by the Periphery contract referred to as the Router which calls the
The best way including funds works is: they’re simply deposited to the ERC20 contracts (by calling
switch(from: liquidity supplier’s handle, to: Pair contract’s handle, quantity) for every token). Then the Pair contract will learn the balances (strains 112 and 113) and evaluate them to the final recognized balances (strains 114 and 115). That is how the Pair contract can deduce the quantities deposited.
burn operate is simply the mirror picture of the
- We once more see fuel financial savings on strains 135, 136, 137 and 143
balance1are whole balances of the tokens on this pool.
liquidityis the quantity of pool possession tokens that the liquidity supplier (who needs to money out) has. Why do entry the liquidity because the stability of
handle(this)? As a result of the liquidity was transferred to the Pair contract by the Periphery contract earlier than calling the
- We calculate the quantities of tokens to withdraw to the liquidity supplier proportionally to how a lot liquidity (pool possession tokens) he has (strains 144 and 145)
- We then burn his liquidity and switch the tokens to him.
- Rewards to the liquidity supplier are robotically withdrawn alongside together with his funds. The maths makes positive that rewards are accrued correctly and that you just get greater than you deposited.