Collect a liquidity position

In this example, we first fetch all liquidities of an account, then select one of it and collect fee or decreased token from it.

The full example code of this chapter can be spotted here.

1. Fetch liquidity positions

 1const chain:BaseChain = initialChainTable[ChainId.BSC]
 2const rpc = 'https://bsc-dataseed2.defibit.io/'
 3console.log('rpc: ', rpc)
 4const web3 = new Web3(new Web3.providers.HttpProvider(rpc))
 5const account =  web3.eth.accounts.privateKeyToAccount(privateKey)
 6console.log('address: ', account.address)
 7
 8const liquidityManagerAddress = '0x93C22Fbeff4448F2fb6e432579b0638838Ff9581'
 9const liquidityManagerContract = getLiquidityManagerContract(liquidityManagerAddress, web3)
10
11console.log('liquidity manager address: ', liquidityManagerAddress)
12
13const testAAddress = '0xCFD8A067e1fa03474e79Be646c5f6b6A27847399'
14const testBAddress = '0xAD1F11FBB288Cd13819cCB9397E59FAAB4Cdc16F'
15
16const testA = await fetchToken(testAAddress, chain, web3)
17const testB = await fetchToken(testBAddress, chain, web3)
18const fee = 2000 // 2000 means 0.2%
19
20const liquidities = await fetchLiquiditiesOfAccount(
21    chain,
22    web3,
23    liquidityManagerContract,
24    account.address,
25    [testA]
26)
27console.log('liquidity len: ', liquidities.length)
28console.log('liquidity: ', liquidities)

The code above is nearly the same as Fetch liquidity positions, you can view more detailed explains through this link

2. Select one of your liquidity positions to collect

1const liquidity0 = liquidities[0]

of course one can only collect his/her liquidity, cannot collect others.

3. Set max amount of tokenX and tokenY you would collect

 1const tokenA = liquidity0.tokenX
 2const tokenB = liquidity0.tokenY
 3
 4const maxAmountA = liquidity0.remainTokenX
 5const maxAmountB = liquidity0.remainTokenY
 6
 7console.log('tokenA: ', tokenA)
 8console.log('tokenB: ', tokenB)
 9
10console.log('maxAmountA: ', maxAmountA)
11console.log('maxAmountB: ', maxAmountB)

4. Get calling of getCollectLiquidityCall

 1const gasPrice = '5000000000'
 2
 3const {collectLiquidityCalling, options} = getCollectLiquidityCall(
 4    liquidityManagerContract,
 5    account.address,
 6    chain,
 7    {
 8        tokenId: liquidity0.tokenId,
 9        tokenA,
10        tokenB,
11        maxAmountA,
12        maxAmountB
13    } as CollectLiquidityParam,
14    gasPrice
15)

the function getCollectLiquidityCall(…) has following params

 1/**
 2 * @param liquidityManagerContract: web3.eth.Contract, the liquidity manager contract obj
 3 * @param account: string, string of owner's address
 4 * @param chain: BaseChain, the obj describing chain we are using
 5 * @param params: CollectLiquidityParam, specify two tokens and max undecimal amount you want to collect
 6 * @param gasPrice: string| number, gas price
 7 */
 8 export const getCollectLiquidityCall = (
 9    liquidityManagerContract: Contract,
10    account: string,
11    chain: BaseChain,
12    params: CollectLiquidityParam,
13    gasPrice: number | string
14)

Notice: if tokenX(tokenA) or tokenY(tokenB) is chain gas token (like ETH on ethereum or BNB on bsc), and you want to collect tokenX or tokenY in form of native or wrapped-native token, you can refer to following section

5. collect native or wrapped native token

In the sdk version 1.2.* or later,

If you want to collect in form of native token(like BNB on bsc or ETH on ethereum …), you should replace define code of tokenA and tokenB in section 2 with following code (here we are working on bsc chain), and fill strictERC20Token of CollectLiquidityParam in section above as undefined by default. And the options calculated in section above will contain the corresponding msg.value.

 1const BNBAddress = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
 2
 3const tokenA = liquidity0.tokenX
 4const tokenB = liquidity0.tokenY
 5
 6if (params.tokenA.address.toLowerCase() === BNBAddress.toLowerCase()) {
 7    params.tokenA.symbol = 'BNB';
 8}
 9if (params.tokenB.address.toLowerCase() === BNBAddress.toLowerCase()) {
10    params.tokenB.symbol = 'BNB';
11}

If you want to collect in form of wrapped-native token(like WBNB on bsc or WETH on ethereum …), you should replace define code of tokenA and tokenB in section 2 with following code (here we are working on bsc chain), and fill strictERC20Token of CollectLiquidityParam in section above as undefined by default.

 1const BNBAddress = '0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c';
 2
 3const tokenA = liquidity0.tokenX
 4const tokenB = liquidity0.tokenY
 5
 6if (params.tokenA.address.toLowerCase() === BNBAddress.toLowerCase()) {
 7    params.tokenA.symbol = 'WBNB'; // only difference to above code
 8}
 9if (params.tokenB.address.toLowerCase() === BNBAddress.toLowerCase()) {
10    params.tokenB.symbol = 'WBNB'; // only difference to above code
11}

we can see that, the only difference of collection native token and wrapped-native token is symbol field of tokenA or tokenB.

In the sdk version 1.1.* or before, one should specify a field named strictERC20Token to indicate that. true for collecting token in form of Wrapped Chain Token, false for paying in form of Chain Token. But we suggest you to upgrade your sdk to latest version.

6. Estimate gas (optional)

of course you can skip this step if you don’t want to limit gas

1const gasLimit = await collectLiquidityCalling.estimateGas(options)
2console.log('gas limit: ', gasLimit)

7. Send transaction!

for metamask or other explorer’s wallet provider, you can easily write

1await collectLiquidityCalling.send({...options, gas: Number(gasLimit)})

otherwise, you could use following code

 1// sign transaction
 2const signedTx = await web3.eth.accounts.signTransaction(
 3    {
 4        ...options,
 5        to: liquidityManagerAddress,
 6        data: collectLiquidityCalling.encodeABI(),
 7        gas: new BigNumber(Number(gasLimit) * 1.1).toFixed(0, 2),
 8    },
 9    privateKey
10)
11// send transaction
12const tx = await web3.eth.sendSignedTransaction(signedTx.rawTransaction);
13console.log('tx: ', tx);

after sending transaction, we will successfully collect token from the liqudity (if no revert occurred)