The evolution of on-chain markets brought us to the idea of Automated Market Makers (AMM).
As the name implies, this algorithm works exactly like market makers but in an automated way.
Moreover, it is decentralized and permissionless, that is:
It is not governed by a single entity
All assets are not stored in one place
Anyone can use it from anywhere
What is an AMM ?
An AMM is a set of smart contracts that define how liquidity is managed.
Each trading pair is a separate contract that stores both ETH and USDC and that's programmed to mediate trades: exchanging ETH for USDC and vice versa.
The core idea is pooling: each contract is a pool that stores liquidity and lets different users (including other smart contracts) trade in a permissionless way.
There are two roles, liquidity providers and traders, and these roles interact with each other through pools of liquidity, and the way they can interact with pools is programmed and immutable.
What makes this approach different from centralized exchanges is that the smart contracts are fully automated and not managed by anyone.
There are no managers, admins, privileged users, etc.
There are only liquidity providers and traders, and all the algorithms are programmed, immutable, and public.
Constant Function Market Makers
The constant function formula says: after each trade, k must remain unchanged.
When traders make trades, they put some amount of one token into a pool (the token they want to sell) and remove some amount of another token from the pool (the token they want to buy).
This changes the reserves of the pool, and the constant function formula says that the product of reserves must not change.
This simple requirement is the core algorithm of how Uniswap V2 works.
The Trade Function
Now that we know what pools are, let's write a formula of how trading happens in a pool.
(x+rΔx)(y−Δy)=k
There is a pool with some amount of token0 (x) and some amount of token1 (y)
When we buy token1 for token0, we give some amount of token0 to the pool (Δx)
The pool gives us some amount of token1 in exchange (Δy)
The pool also takes a small fee (r=1−swap fee) from the amount of token0 we gave.
The reserve of token0 changes x+rΔx and the reserve of token1 changes as well y−Δy
We are basically giving a pool some amount of token0 and getting some amount of token1.
The job of the pool is to give us a correct amount of token1 calculated at a fair price. This leads us to the following conclusion: pools decide what trade prices are.
Pricing
Since Uniswap pools are separate smart contracts, tokens in a pool are priced in terms of each other.
For example, ETH/USDC pool, ETH is priced in terms of USDC, and USDC is priced in terms of ETH.
If 1 ETH costs 1000 USDC, then 1 USDC costs 0.001 ETH.
The same is true for any other pool
In the real world, everything is priced based on the law of supply and demand.
This also holds true for AMMs.
We will put the demand part aside for now and focus on supply.
The prices of tokens in a pool are determined by the supply of tokens, that is by the amounts of reserves of the tokens that the pool is holding.
Token prices are simply relations of reserves:
Px=xy,Py=yx
Such prices are called spot prices and they only reflect current market prices.
However, the actual price of a trade is calculated differently.
And this is where we need to bring the demand part back.
Concluding from the law of supply and demand, high demand increases the price - and this is a property we need to have in a permissionless system.
We want the price to be high when demand is high, and we can use the pool reserves to measure the demand: the more tokens you want to remove from a pool the higher the impact of demand is.
Let's return to the trade formula and look at it closer
(x+rΔx)(y−Δy)=k
As you can see, we can derive Δx and Δy from it, which means we can calculate the output amount of a trade based on the input amount and vice versa.
Δy=x+rΔxyrΔx
Δx=r(y−Δy)xΔy
In fact these formulas free us from calculating prices.
We can always find the output amount using the Δy formula (when we want to sell a known amount of tokens) and we can always find the input amount using the Δx formula (when we want to buy a known amount of tokens)
Notice that each of these formulas is a relation of reserves (x/y or y/x) and they also take the trade amount (Δx in the former and Δy in the latter) into consideration.