mirror of
https://github.com/autistic-symposium/mev-toolkit.git
synced 2025-04-27 19:26:15 -04:00
uniswap v2
tl; dr
- uniswap v2 introduced new features and optimizations in may 2020
- each Uniswap liquidity pool is a trading venue for a pair of ERC20 tokens

- whenever liquidity is deposited into a pool, unique tokens known as liquidity tokens are minted and sent to the provider's address
- if the provider is minting a new pool, the number of liquidity tokens they will receive will equal sqrt(x * y), where x and y represent the amount of each token provided.
- to retrieve the underlying liquidity, plus any fees accrued, liquidity providers must "burn" their liquidity tokens, effectively exchanging them for their portion of the liquidity pool, plus the proportional fee allocation.
arbitrage opportunities
💡 check my amm arbitrage toolkit for a clean nice code on uniswap v2 protocol
- let's chat about a bot looking for uniswap-like arbitrages which it could perform after the opportunity tx take advantages of liquidity disparities accross pools
- a pool with X WETH and Y USDC allows users to swap WETH and USDC, the governing principle of the pool is that the product of X * Y is always constant (the uniswap invariant)
- for a pool with reserves of (X, Y) we can work out how much USDC out we expect for selling delta X WETH
- the pool also takes a fee of ~30bps (~0.3%)
bots step
- once we figured out how to perform swaps to max profit, the bot needs to acquire delta X of the initial token to perform these swaps (e.g. using a flash loan from aave)
- then the bot needs to bundler the flash loan plus both swaps and transfer of flash loan back to aave into a single tx (this can be done using a custom smart contract that is pre-deployed on chain)
- once the tx is created and signed, it's submitted to the mempool to be mined. there are many other bots searching for the same opportunities
- we want to ensure that our tx gets mined first, this means our arb tx should follow the original tx in the same block and be mined immediatially aftward. this is what's known as "back run".
- in order to achieve a back run, the bot needs to first understand the gas price that the original tx offered, and then needs to copy these exact parameters in the arb tx
- finally, the tx is signed and submitted to the mempool directly by the bot for validation and free money
lp burn
- liquidity providers (LP) provide the pool with the two tokens that can be exchanged (token0 and token1).
- in return they receive a third token that represents partial ownership of the pool called a liquidity (pool) token.
- the function burn() is called when liquidity is withdrawn, and the liquidity tokens need to be burned, it sends the destination address the underlying tokens in proportion to the burned tokens.
- for example if there are 1000 token0, 500 token1, and 90 liquidity tokens in the pool. If someone gives 9 tokens to burn, this is burning 10% of the liquidity tokens, the user receives 100 token0 and 50 token1. balanceOf() function returns the token balance of the given address: balance0 = IERC20(_token0).balanceOf(address(this)) . address(this) refers to the address of the instance of the contract where the call is being made.
- the amount of liquidity tokens to remove: liquidity = IERC20(lpToken).balanceOf(address(this));.
- the totalSupply() function returns the total supply of the tokens. This means that the sum total of token balances of all of the token holders must match the total supply: uint256 _totalSupply = IERC20(lpToken).totalSupply().
- for completeness, this is how LP tokens got minted: https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2Pair.sol#L110
if (_totalSupply == 0) {
liquidity = Math.sqrt(amount0.mul(amount1)).sub(MINIMUM_LIQUIDITY);
_mint(address(0), MINIMUM_LIQUIDITY); // permanently lock the first MINIMUM_LIQUIDITY tokens
} else {
liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);
}