Skip to content

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.

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:

sminted=min(xinxreservestotal,yinyreservestotal)s_{minted} = \min \left( \frac{x_{in}}{x_{reserve}} \cdot s_{total}, \frac{y_{in}}{y_{reserve}} \cdot s_{total} \right)
  • 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:

ItemBalanced depositUnbalanced deposit
Pool reserves100 ETH + 200,000 USDC100 ETH + 200,000 USDC
Total LP shares1,0001,000
Deposit10 ETH + 20,000 USDC10 ETH + 10,000 USDC
Implied increase from X side10/100 = 10%10/100 = 10%
Implied increase from Y side20,000/200,000 = 10%10,000/200,000 = 5%
Shares mintedmin(10%,10%)=10%\min(10\%,10\%) = 10\%min(10%,5%)=5%\min(10\%,5\%) = 5\%

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:

deposited tokenA amountdeposited tokenB amount=current tokenA reservescurrent tokenB reserves\frac{ {\text{deposited tokenA amount}} } { {\text{deposited tokenB amount}} } = \frac{ {\text{current tokenA reserves}} } { {\text{current tokenB reserves}} }
// contracts/uniswap-v2/v2-periphery/contracts/libraries/UniswapV2Library.sol:37:39
require(amountA > 0, 'UniswapV2Library: INSUFFICIENT_AMOUNT');
require(reserveA > 0 && reserveB > 0, 'UniswapV2Library: INSUFFICIENT_LIQUIDITY');
amountB = amountA.mul(reserveB) / reserveA;
Loading graph...

In this example we will increase the pool liquidity

This is the code that runs to produce the function trace

// UniswapV2Workflows:addLiquidity:91:116
async 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:200
private 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