Get pool and create pool

In this section, we provide a simple example for getting pool address of a pair or creating a pool.

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

You should notice that, example and interfaces in this chapter require the sdk with minimum version of 1.5.0.

1. Some imports

1import {BaseChain, ChainId, initialChainTable} from 'iziswap-sdk/lib/base/types'
2import {privateKey} from '../../.secret'
3import Web3 from 'web3';
4import { getCreatePoolCall, getFactoryContract, getPoolAddress } from 'iziswap-sdk/lib/pool/funcs';
5import { BigNumber } from 'bignumber.js'

Detail of these imports can be viewed in the following content.

2. Specify chain, rpc, web3, and account

1const chain:BaseChain = initialChainTable[ChainId.BSCTestnet]
2const rpc = 'https://data-seed-prebsc-1-s3.binance.org:8545/'
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)

where

    • BaseChain is a data structure to describe a chain, in this example we use bsc test chain.

    • ChainId is an enum to describe chain id, value of the enum is equal to value of chain id.

    • initialChainTable is a mapping from some most used ChainId to BaseChain. You can fill fields of BaseChain by yourself.

    • privateKey is a string, which is your private key, and should be configured by your self.

    • web3 is a public package to interact with block chain.

    • rpc is the rpc url on the chain you specified.

3. Get web3.eth.Contract object of factory

1const factoryAddress = '0x7fc0574eAe768B109EF38BC32665e6421c52Ee9d'
2const factoryContract = getFactoryContract(factoryAddress, web3)

Here, getFactoryContract is an api provided by our sdk, which returns a web3.eth.Contract object of FactoryContract.

4. Choose token pair of the pool

1const testAAddress = '0xCFD8A067e1fa03474e79Be646c5f6b6A27847399'
2const testBAddress = '0xAD1F11FBB288Cd13819cCB9397E59FAAB4Cdc16F'
3
4// feeRate = feeContractNumber / 1e6
5// etc, 3000 means 0.3%
6// you should choose a proper feeRate of new pool
7// which should be supported by factory on that chain
8const feeContractNumber = 3000;

Here, we will create a pool of pair (testAAddress, testBAddress, feeContractNumber), Where

    • testAAddress: address of an erc20 token.

    • testBAddress: address of another erc20 token.

    • feeContractNumber: an int number, fee/1e6 is fee rate of pool, etc, 3000 means 0.3% fee rate.

You can fill testAAddress and testBAddress with your expected erc20 token address, and fill feeContractNumber with your expected fee number.

But notice that, when you fill value of feeContractNumber, you should garrantee that the corresponding fee rate is supported by iZiSwap on that chain.

In general, the supported fee rates for the mainnet are 500 (0.05%), 3000 (0.3%), and 10000 (1%); and for the testnet are 400 (0.04%), 2000 (0.2%) and 10000 (1%).

5. Check whether the pool has been created

1const poolAddress = await getPoolAddress(factoryContract, testAAddress, testBAddress, feeContractNumber);
2if (!(new BigNumber(poolAddress).eq('0'))) {
3    // if poolAddress is not zero address,
4    //     this means some one has created the pool with same token pair (testAAddress, testBAddress, feeContractNumber) before.
5    //     in this situation,  we can not create pool with same token pair (testAAddress, testBAddress, feeContractNumber) in the following code.
6    console.log('pool has been created! Address: ', poolAddress);
7    return;
8}

The function getPoolAddress(…) imported from ‘iziswap-sdk/lib/pool/funcs’ queries factoryContract to get iZiSwap pool address of token pair (testAAddress, testBAddress, feeContractNumber), where

    • factoryContract: iZiSwap Factory contract, acquired in step 3.

    • testAAddress: address of an erc20 token, filled in step 4.

    • testBAddress: address of another erc20 token, filled in step 4.

    • feeContractNumber: an int number, fee/1e6 is fee rate of pool, etc, 3000 means 0.3% fee rate.

You should notice that the function getPoolAddress imported from ‘iziswap-sdk/lib/pool/funcs’ requires the sdk with minimum version of 1.5.0.

If poolAddress is zero address, we can use following steps to create a pool of this pair, otherwise, we cannot create pool with this pair again.

And due to the fact this example has been tested, which means the pool of this token pair (testAAddress, testBAddress, feeContractNumber) has been created successfully. If you donot modify any element (testAAddress or testBAddress or feeContractNumber) of this token pair and run this example directly, your code will exit in this step.

6. Get calling for creating the pool.

 1// you can choose a proper initial point, which
 2// specify init price of tokenX (by tokenY)
 3const initPointXByY = 100;
 4const gasPrice = '5000000000';
 5
 6// get calling
 7// before calling getCreatePoolCall(...)
 8// we should garrentee that
 9// tokenXAddress.toLowerCase() < tokenYAddress.toLowerCase()
10let tokenXAddress = testAAddress;
11let tokenYAddress = testBAddress;
12if (tokenXAddress.toLowerCase() > tokenYAddress.toLowerCase()) {
13    tokenXAddress = testBAddress;
14    tokenYAddress = testAAddress;
15}
16const {createPoolCalling, options} = getCreatePoolCall(
17    factoryContract,
18    tokenXAddress,
19    tokenYAddress,
20    feeContractNumber,
21    initPointXByY,
22    account.address,
23    chain,
24    gasPrice,
25)

The function getCreatePoolCall(…) imported from ‘iziswap-sdk/lib/pool/funcs’ will return corresponding txn data for creating a new pool, where

    • factoryContract: iZiSwap Factory contract, acquired in step 3.

    • tokenXAddress: address of tokenX, here tokenXAddress is min{tokenAAddress, tokenBAddress}.

    • tokenYAddress: address of tokenY, here tokenYAddress is max{tokenAAddress, tokenBAddress}.

    • feeContractNumber: an int number, fee/1e6 is fee rate of pool, etc, 3000 means 0.3% fee rate.

    • initPointXByY: an int number specifying initial point (see here) of the pool.

    • account.address: address of your private key, acquired in step 2.

    • chain: chain object, acquired in step 2.

    • gasPrice: gas price, string or int number.

The function getCreatePoolCall returns 2 object, createPoolCalling and options. When createPoolCalling and options are ready, we can estimate gas.

When calling this function, you should garrentee that tokenXAddress.toLowerCase() < tokenYAddress.toLowerCase(), otherwise the returned createPoolCalling and options will be undefined.

Another thing you should notice is that the function getCreatePoolCall imported from ‘iziswap-sdk/lib/pool/funcs’ requires the sdk with minimum version of 1.5.0.

7. Estimate gas (optional)

You can skip this step if you do not want to limit gas.

1// esitmate gas
2// if error occurs when estimating gas,
3//     this means some one might create the pool before with
4//     same token pair (testAAddress, testBAddress, feeContractNumber) before
5//     you can call getPoolAddress(...) to get the pool address
6//     as mentioned above
7const gasLimit = await createPoolCalling.estimateGas(options)
8console.log('gas limit: ', gasLimit)

8. Finally, send transaction!

Now, we can send transaction to mint a new liquidity position.

For metamask or other injected wallet provider, you can easily write

1await createPoolCalling.send({...options, gas: new BigNumber(gasLimit * 1.1).toFixed(0, 2)})

Otherwise, if you are running codes in console, you could use the following code

 1// sign transaction
 2const signedTx = await web3.eth.accounts.signTransaction(
 3    {
 4        ...options,
 5        to: factoryAddress,
 6        data: createPoolCalling.encodeABI(),
 7        gas: new BigNumber(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);

Finally, we have successfully created a pool (if no revert occurred).