This doc is related to basic implementation of Uniswap V1 and which is maintained in:
- Contracts :
/contracts/amm/uniswap-v1/
- Tests:
/test/amm/uniswap-v1
All the functions are properly documented. Hence we will just explain how we got the formula in the pricing function getAmount
.
First of all, if you are not familiar with DEX then get familiar with:
Uniswap is a leading DEX. There have been 3 versions. this tutorial focuses on the 1st version v1 and which was launched in November 2018. The documentation of Uniswap V1 can be found here.
An exchange is a ETH-ERC20 liquidity pool. Allowing :
- Liquidity providers (LP) can deposit equivalent amout of ETH & ERC20 and get liquidity pool tokens in exchange. Allowing them to collect fees on ETH <-> ERC20 swaps
- Users can swap ERC20 for ETH and vice-versa. Fees are 0,3 % per swap
A factory allows creation & deployment of any ETH-ERC20 exchange. Allowing:
- Keep track of all ETH-ERC20 exchanges
- Any ETH-ERC20 can support token to token swaps. E.g. : Let say there is a ETH-LINK exchange & ETH-USDT exchange. One can trade LINK for USDT in a single transaction (ETH is used as a bridge between both exchanges)
The pricing of ETH-ERC20 is based on the constant product formula:
In order to buy some amount of token B, one must sell a proportional amount of token B while maintaining k
constant (cf. curve below).
Therefore, after a given amount of token A are sold for tokens B , we still maintain the k constant.
Combining (1) and (2) :
We can then have an equation which gives us the relantionship between amount bought of Token B Δy(aka outputAmount) and the other variables which are known:
- x: current amount of token A (aka token A reserve)
- y : current amount of token B (aka token B reserve)
- Δx : sold amount of token A (aka inputAmount)
Note that this equation is not final as it doesn't take the fees into account. The fees in Uniswap v1 are 0,3%. Fees are always taken from the inputAmount :
Now if we combine (5) and (6):
which is the getAmount function in Exchange.sol:
function getAmount(
uint256 inputAmount,
uint256 inputReserve,
uint256 outputReserve
) private pure returns (uint256 outputAmount) {
require(inputReserve > 0 && outputReserve > 0, "Reserves cannot be null");
uint256 inputAmountWithFee = inputAmount * 997;
uint256 numerator = inputAmountWithFee * outputReserve;
uint256 denominator = (1000 * inputReserve + inputAmountWithFee);
outputAmount = numerator / denominator;
}
- Uniswap V1 Whitepaper
- Ivan Kuznetsov posts on uniswap: