Creating and Seeding a Pool
This tutorial will walk you step-by-step through creating and seeding pairs on Astroport. It covers:
- Creating a Pair: Learn how to initialize new trading pairs within liquidity pools, enabling fresh trading opportunities.
- Fetching Pool Information: Acquire the necessary skills to programmatically query and retrieve essential data about liquidity pools, including the pool address.
- Increasing Token Allowance: Implement token allowance mechanics, allowing smart contracts to interact with tokens on your behalf.
- Providing Liquidity: Understand and apply techniques to inject liquidity into trading pools.
This tutorial is applicable for creating and seeding pools on the Sei, Neutron, and Terra networks. It is currently not compatible with Injective due to the incompatibility of Injective transactions with CosmJs. A separate tutorial will be needed for handling transactions on the Injective network.
Setup
Step 1: Import Necessary Libraries
Import the required libraries to connect to the chain and perform transactions.
_3import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";_3import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";_3import { GasPrice } from "@cosmjs/stargate";
Step 2: Define Constants
Specify the required constants, such as the RPC URL, mnemonic, and factory contract address.
This tutorial includes the mnemonic directly in the code for quick setup. While convenient for testing, this exposes a sensitive piece of information and is not secure for production use. Always follow secure key management practices and never expose the mnemonic in real-world scenarios.
_3const rpc = '<rpc-url>'_3const mnemonic = ''_3const factoryContractAddress = 'sei1cp0hjmhwn9mz8rd4t29zjx2sks5mlxsjzhch2ef3yr4q2ssqwuvst5lyc9' // sei testnet
Step 3: Create a Wallet
Create a wallet using the mnemonic for the specific chain prefix.
_4const wallet = await DirectSecp256k1HdWallet.fromMnemonic(_4 mnemonic, { _4 prefix: "sei" // neutron, or terra_4 });
Step 4: Retrieve Wallet Address
Get the wallet address from the wallet.
_2const firstAccount = await wallet.getAccounts();_2const walletAddress = firstAccount[0].address
Step 5: Set Up the Signing Client
Configure the signing client for connecting to the chain.
_5const signingClient = await SigningCosmWasmClient.connectWithSigner(_5 rpc, _5 wallet, _5 { gasPrice: GasPrice.fromString("0.1usei") }_5)
Step 6: Wrap Code Inside an Async Function with Error Handling
Wrap the code inside a start() function, marked as async, to handle the asynchronous operations throughout the code. Also, include a try/catch block for robust error handling. This structure enables the use of await with async functions and ensures proper management of any errors that may occur.
_12const start = async () => {_12 try {_12 // Place all the code inside this try block_12_12 // ..._12_12 } catch (error) {_12 console.error('An error occurred:', error);_12 }_12}_12_12start();
Create an XYK Pair
Step 1: Define the Create XYK Pair Message
Create the create xyk pair message with asset details.
_19const createXYKPairMsg = {_19 "create_pair": {_19 "pair_type": {_19 "xyk": {}_19 },_19 "asset_infos": [_19 {_19 "token": {_19 "contract_addr": "<cw20-contract-address>"_19 }_19 },_19 {_19 "native_token": {_19 "denom": "usei"_19 }_19 }_19 ]_19 }_19};
Step 2: Execute the Create XYK Pair Transaction
Execute the create xyk pair transaction.
_9const executeCreateXYKPair = await signingClient.execute(_9 walletAddress,_9 factoryContractAddress,_9 createPairMsg,_9 "auto", // fee_9 "" // memo_9);_9_9console.log(JSON.stringify(executeCreateXYKPair));
Create a Stableswap Pair
Step 1: Create an Encoding Function
Define a function that will encode an object into Base64. This function will be used in the next step to encode the init_params
message.
_3let toBase64 = (obj) => {_3 return Buffer.from(JSON.stringify(obj)).toString("base64");_3};
Step 2: Define the Create Stable Pair Message
Create the message for creating a stableswap pair, including the encoding of the init_params
for amp
.
_24const createStablePairMsg = {_24 "create_pair": {_24 "pair_type": {_24 "stable": {}_24 },_24 "asset_infos": [_24 {_24 "token": {_24 "contract_addr": "<cw20-contract-address>"_24 }_24 },_24 {_24 "native_token": {_24 "denom": "ibc/..."_24 }_24 }_24 ], _24 "init_params": toBase64(_24 {_24 "amp": 10_24 }_24 )_24 }_24};
Step 3: Execute the Create Stable Pair Transaction
Execute the create stable pair transaction.
_9const executeCreateStablePair = await signingClient.execute(_9 walletAddress,_9 factoryContractAddress,_9 createStablePairMsg,_9 "auto", // fee_9 "" // memo_9);_9_9console.log(JSON.stringify(executeCreateStablePair));
Create a PCL Pair
Coming soon!
Fetching the Pool Address
Step 1: Query for Pair Address
Execute a query to fetch the pair address associated with the stableswap pool. The query includes the asset information required to identify the pool.
_19const pairQuery = await signingClient.queryContractSmart(_19 factoryContractAddress,_19 {_19 "pair": {_19 "asset_infos": [_19 {_19 "token": {_19 "contract_addr": "<cw20-contract-address>"_19 }_19 },_19 {_19 "native_token": {_19 "denom": "usei"_19 }_19 }_19 ]_19 }_19 }_19);
Step 2: Save the Pool Contract Address
Retrieve and save the pool contract address from the query result, so you can use it later in other operations.
_1const poolContractAddr = pairQuery.contract_addr
Increase Token Allowance
Before you can provide liquidity, you will need to increase the token allowance for any CW20 token involved in the pair. This allows the pool contract to access the specified amount of your tokens, facilitating the addition of liquidity.
To learn more about increasing allowances, visit the CW20 spec.
Step 1: Define the Increase Token Allowance Message
You need to define a message that specifies the amount by which to increase the allowance, the address of the spender (in this case, the pool contract address), and an optional expiration setting for the allowance.
_9const increaseTokenAllowanceMsg = {_9 "increase_allowance": {_9 "spender": poolContractAddr,_9 "amount": "1000000000000",_9 "expires": {_9 "never": {}_9 }_9 } _9};
Step 2: Execute the Increase Token Allowance Transaction
Next, you need to send a transaction to execute the allowance increase. This will modify the allowance that the specified spender has over your tokens.
_9const executeIncreaseTokenAllowance = await signingClient.execute(_9 walletAddress,_9 "<CW20TokenAddr>",_9 increaseTokenAllowanceMsg,_9 "auto", // fee_9 "" // memo_9);_9_9console.log(JSON.stringify(executeIncreaseTokenAllowance));
Provide Liquidity
Since this is a new pool without any previous token balance or ratios, you will have the flexibility to provide whatever ratio of tokens you choose for the pair. It's essential to note that the ratio you select will set the initial price for the trading pair in the pool.
Arbitrage traders will eventually resolve any imbalance in price, aligning it with the broader market. However, this also means that initial deposits should be as close as possible to external oracle prices or prevailing market rates.
Step 1: Define the Provide Liquidity Message
You must define a message that includes the assets you intend to add to the liquidity pool. These can include CW20 tokens and/or native tokens, along with their corresponding amounts.
_22const provideLiquidityMsg = {_22 "provide_liquidity": {_22 "assets": [_22 {_22 "info": {_22 "token": {_22 "contract_addr": "<cw20-contract-address>"_22 }_22 },_22 "amount": "1000000"_22 },_22 {_22 "info": {_22 "native_token": {_22 "denom": "usei"_22 }_22 },_22 "amount": "1000000"_22 }_22 ],_22 }_22};
Step 2: Execute the Provide Liquidity Transaction
After defining the assets, you'll need to execute a transaction to add them to the liquidity pool.
Please note that if you're providing native tokens as part of the liquidity, they will have to be explicitly appended to the transaction message.
_10const executeProvideLiquidity = await signingClient.execute(_10 walletAddress,_10 poolContractAddr,_10 provideLiquidityMsg,_10 "auto", // fee_10 "", // memo_10 [ { denom: "usei", amount: "1000000" } ] // coins to send_10);_10_10console.log(JSON.stringify(executeProvideLiquidity));