Programming DeFi: Uniswap. Part 1 - Going the distance (jeiwan.net)
V1 was originally developed using Vyper. In this tutorial, it is rewritten using Solidity v0.8
Core formula:
$$ x*y=k $$
$x,y$ are token reserves (amount of tokens), $k$ is a constant.
Price formula:
$$ (x+\Delta x)(y-\Delta y)=x*y=k
$$
$$ \Delta y=\frac{y\Delta x}{x+\Delta x} $$
Let x be ETH, y be USDT. If I want to swap 1 ETH to USDT
$\Delta x = 1 eth$, the amount of USDT I can receive $\Delta y$ can be calculated by the above formula.
From that formula, we can write Solidity functions to calculate prices and perform swapping.
function getAmount(
uint256 inputAmount,
uint256 inputReserve,
uint256 outputReserve
) private pure returns (uint256) {
require(inputReserve > 0 && outputReserve > 0, "invalid reserves");
return (inputAmount * outputReserve) / (inputReserve + inputAmount);
}
function getTokenAmount(uint256 _ethSold) public view returns (uint256) {
require(_ethSold > 0, "ethSold is too small");
uint256 tokenReserve = getReserve();
// tokenReserve: y
// _ethSold: delta x
// address(this).balance: x
// delta y = y * delta x / (x + delta x)
return getAmount(_ethSold, address(this).balance, tokenReserve);
}
function getEthAmount(uint256 _tokenSold) public view returns (uint256) {
require(_tokenSold > 0, "tokenSold is too small");
uint256 tokenReserve = getReserve();
// _tokenSold: delta y
// tokenReserve: y
// address(this).balance: x
// delta x = x * delta y / (y + delta y)
return getAmount(_tokenSold, tokenReserve, address(this).balance);
}
<aside> 💡 Handle slippage effects: buyers get slightly less than expected.
</aside>