Skip to main content

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.
NOTE

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.


_3
import { SigningCosmWasmClient } from "@cosmjs/cosmwasm-stargate";
_3
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
_3
import { GasPrice } from "@cosmjs/stargate";

Step 2: Define Constants

Specify the required constants, such as the RPC URL, mnemonic, and factory contract address.

NOTE

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.


_3
const rpc = '<rpc-url>'
_3
const mnemonic = ''
_3
const factoryContractAddress = 'sei1cp0hjmhwn9mz8rd4t29zjx2sks5mlxsjzhch2ef3yr4q2ssqwuvst5lyc9' // sei testnet

Step 3: Create a Wallet

Create a wallet using the mnemonic for the specific chain prefix.


_4
const 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.


_2
const firstAccount = await wallet.getAccounts();
_2
const walletAddress = firstAccount[0].address

Step 5: Set Up the Signing Client

Configure the signing client for connecting to the chain.


_5
const 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.


_12
const 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
_12
start();

Create an XYK Pair

Step 1: Define the Create XYK Pair Message

Create the create xyk pair message with asset details.


_19
const 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.


_9
const executeCreateXYKPair = await signingClient.execute(
_9
walletAddress,
_9
factoryContractAddress,
_9
createPairMsg,
_9
"auto", // fee
_9
"" // memo
_9
);
_9
_9
console.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.


_3
let 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.


_24
const 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.


_9
const executeCreateStablePair = await signingClient.execute(
_9
walletAddress,
_9
factoryContractAddress,
_9
createStablePairMsg,
_9
"auto", // fee
_9
"" // memo
_9
);
_9
_9
console.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.


_19
const 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.


_1
const 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.


_9
const 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.


_9
const executeIncreaseTokenAllowance = await signingClient.execute(
_9
walletAddress,
_9
"<CW20TokenAddr>",
_9
increaseTokenAllowanceMsg,
_9
"auto", // fee
_9
"" // memo
_9
);
_9
_9
console.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.


_22
const 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.


_10
const 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
_10
console.log(JSON.stringify(executeProvideLiquidity));