DEV Community

Dmitry Zakharov
Dmitry Zakharov

Posted on

How to Add a New Pool to Uniswap V3


Many existing projects use the third version of a well-known Uniswap protocol as Oracle to get the current price for many assets. Uniswap V3 can also be used in one of the strategies like yearn or harvest strategies as a pool of liquidity, which can create profits for your deposit through time. Some projects also add integration with Uniswap V3 to increase user experience and make users' lives a little bit easier. In all of these scenarios, it is crucial to check how the poisoned pool, which can be added by a hacker to uniswap can affect the protocol. To check this scenario, we create a test in the hardhat environment.

Adding liquidity pool to UniswapV3

The code snippet in the hardhat testing environment is presented below. All necessary notes to the code are given as well.

const tokenFactory = await ethers.getContractFactory("EvilToken");
const evilToken = await tokenFactory.connect(deployer).deploy();
const positionManager = await ethers.getContractAt('INonfungiblePositionManager', "0xC36442b4a4522E871399CD717aBDD847Ab11FE88");
const WETH = await ethers.getContractAt('IWETH', addresses.tokens.WETH);
// call approve for tokens before adding a new pool
call approveawait WETH.connect(deployer).approve(positionManager.address, ethers.utils.parseEther('0.1'), {gasPrice: 0});
await evilToken.connect(deployer).approve(positionManager.address, ethers.utils.parseEther('100'), {gasPrice: 0});
let multiCallParams = [
// first call
"0x13ead562" + // encoded function signature ( createAndInitializePoolIfNecessary(address, address, uint24, uint160) )
"000000000000000000000000" + evilToken.address.toLowerCase().substring(2) + // token1 address
"000000000000000000000000" +  WETH.address.toLowerCase().substring(2) + // token2 address
"00000000000000000000000000000000000000000000000000000000000001f4" + // fee
"000000000000000000000000000000000000000005b96aabfac7cdc4b3b58fc2", // sqrtPriceX96
// second call
"0x88316456" + // encoded function signature ( mint((address,address,uint24,int24,int24,uint256,uint256,uint256,uint256,address,uint256)) )
"000000000000000000000000" + evilToken.address.toLowerCase().substring(2) + // token1 address
"000000000000000000000000" +  WETH.address.toLowerCase().substring(2) + // token2 address
"00000000000000000000000000000000000000000000000000000000000001f4" + // fee
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff89f0e" + // tick lower
"0000000000000000000000000000000000000000000000000000000000010dd8" + // tick upper
"00000000000000000000000000000000000000000000000ad5a4b6712c4647c3" + // amount 1 desired
"000000000000000000000000000000000000000000000000016345785d8a0000" + // amount 2 desired
"00000000000000000000000000000000000000000000000acebaf563cd50439c" + // min amount 1 expected
"000000000000000000000000000000000000000000000000016261cfc3291456" + // min amount 2 expected 
"000000000000000000000000" + signer3.address.toLowerCase().substring(2) + // deployer address "00000000000000000000000000000000000000000000000000000000610bb8b6" // deadline
// adding a new liquidity pool through the position manager
await positionManager.connect(deployer).multicall(multiCallParams, {gasPrice: 0});
Enter fullscreen mode Exit fullscreen mode

In this test, EvilToken is a standard ERC20 token that can be minted or burned by the deployer, positionManager is one of Uniswap V3 ecosystem's smart contracts which gives access to adding new pools of liquidity, WETH is a token representing wrapped ether. multiCallParams is an array of bytes which contains all necessary parameters to deploy a new liquidity pool. It is worth saying that some of the parameters used in multiCallParams cannot be easily calculated, like sqrtPriceX96 or tick_lower. To calculate these parameters, you can use a Uniswap V3 dApp in the ropsten network. It is very easy to calculate these parameters through dApp. First, you create a new liquidity pool in dApp with parameters that you want to use, and then you just decompile your transaction in ropsten etherscan and get values of the necessary parameters in byte representation.

Top comments (0)