Add Liquidity
Prereq: Initial Liquidity
This page covers the necessary concepts to understand the add liquidity flow in Uniswap V2, after initial liquidity is added.
Concepts
Section titled “Concepts”LP tokens are ERC20 tokens that are minted to the LP.
Let’s analyze the formula that calculates LP tokens to the LP.
// contracts/uniswap-v2/v2-core/contracts/UniswapV2Pair.sol:122:124} else { liquidity = Math.min(amount0.mul(_totalSupply) / _reserve0, amount1.mul(_totalSupply) / _reserve1);}It calculates the pro-rata shares (no dilution) and sends them to the LP using the formula:
- Only deposits in proportion to the reserve ratio are accepted
- which means both token changes will be the same proportion
- The formula enforces the above by accepting the minimum % change for both tokens.
Let’s look at an example:
| Item | Balanced deposit | Unbalanced deposit |
|---|---|---|
| Pool reserves | 100 ETH + 200,000 USDC | 100 ETH + 200,000 USDC |
| Total LP shares | 1,000 | 1,000 |
| Deposit | 10 ETH + 20,000 USDC | 10 ETH + 10,000 USDC |
| Implied increase from X side | 10/100 = 10% | 10/100 = 10% |
| Implied increase from Y side | 20,000/200,000 = 10% | 10,000/200,000 = 5% |
| Shares minted |
Amounts
Section titled “Amounts”The router computes the maximum amount of tokens A and B that the LP can deposit to preserve the pool proportions, before passing to mint:
// contracts/uniswap-v2/v2-periphery/contracts/libraries/UniswapV2Library.sol:37:39require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');amountB = amountA.mul(reserveB) / reserveA;Loading graph...
Function Trace
Section titled “Function Trace”In this example we will increase the pool liquidity
This is the code that runs to produce the function trace
// UniswapV2Workflows:addLiquidity:91:116async addLiquidity({ user = USER_1.address, amountADesired = 200n * _1e18, amountBDesired = 200n * _1e18, amountAMin = 50n * _1e18, amountBMin = 50n * _1e18,} = {}) { const { erc20TokenA, erc20TokenB } = await this.initialLiquidity({ user: USER_1.address, amountADesired: 200n * _1e18, amountBDesired: 400n * _1e18, });
const trace = await this._addLiquidity( erc20TokenA, erc20TokenB, amountADesired, amountBDesired, amountAMin, amountBMin, user, this.maxUint256() );
return { trace, ercTokenA: erc20TokenA, ercTokenB: erc20TokenB };}
// UniswapV2Workflows:_addLiquidity:173:200private async _addLiquidity( tokenA: UniswapV2ERC20, tokenB: UniswapV2ERC20, amountADesired: bigint, amountBDesired: bigint, amountAMin: bigint, amountBMin: bigint, user: Address, deadline: bigint, trace = true) { const { router2 } = this.deployment;
await this.transferErc20(tokenA, USER_0.address, user, amountADesired); await this.transferErc20(tokenB, USER_0.address, user, amountBDesired);
await this.approve(tokenA, router2.address, amountADesired, user); await this.approve(tokenB, router2.address, amountBDesired, user);
return await this.lensClient.contract( router2, 'addLiquidity', [tokenA.address, tokenB.address, amountADesired, amountBDesired, amountAMin, amountBMin, user, deadline], user, undefined, trace );}EVM LENS
Function Trace
WorkflowAdd Liquidity
DescriptionSee the function trace and protocol source code
NETWORK STATUS: ONLINE
BROWSER VM