Liquidity Management Tutorial

Learn how to add and remove liquidity from pools using the Saros SDK with this comprehensive guide.

Overview

This tutorial will guide you through the process of providing liquidity to pools and withdrawing it using the Saros SDK. Liquidity providers earn fees from trades that occur in their pools.

45 min
Estimated Time
Intermediate
Difficulty
Solana
Blockchain

1. Prerequisites

Before starting this tutorial, ensure you have the following:

  • Node.js 16+ and npm/yarn installed
  • Basic knowledge of TypeScript/JavaScript
  • A Solana wallet with some SOL for transaction fees
  • Token accounts for the tokens you want to provide as liquidity
  • Understanding of how liquidity pools work (recommended)
Install Dependencies
// Install the required packages
npm install @saros-finance/sdk @solana/web3.js

// Import the necessary modules
import { 
  getPoolInfo, 
  depositAllTokenTypes, 
  withdrawAllTokenTypes, 
  getTokenMintInfo, 
  getTokenAccountInfo, 
  getInfoTokenByMint,
  genConnectionSolana,
  convertBalanceToWei
} from '@saros-finance/sdk';
import { PublicKey } from '@solana/web3.js';
import BN from 'bn.js';

2. Set up Connection

First, we need to establish a connection to the Solana network and configure our wallet.

Connection Setup
// Generate a connection to the Solana network
const connection = genConnectionSolana();

// Define your wallet address (in a real app, this would come from a connected wallet)
const accountSol = 'YOUR_WALLET_PUBLIC_KEY';

// Define the payer account object
const payerAccount = { publicKey: new PublicKey(accountSol) };

3. Configure Tokens

Define the tokens for your liquidity pool, including their mint addresses and SPL token accounts.

Token Configuration
// Configure the tokens for the liquidity pool
// Example: C98-USDC liquidity pool

const USDC_TOKEN = {
  id: 'usd-coin',
  mintAddress: 'EPjFWdd5AufqSSqeM2qN1zzybapC8G4wEGGkZwyTDt1v',
  symbol: 'usdc',
  name: 'USD Coin',
  decimals: '6',
  addressSPL: 'FXRiEosEvHnpc3XZY1NS7an2PB1SunnYW1f5zppYhXb3',
};

const C98_TOKEN = {
  id: 'coin98',
  mintAddress: 'C98A4nkJXhpVZNAZdHUA95RpTF3T4whtQubL3YobiUX9',
  symbol: 'C98',
  name: 'Coin98',
  decimals: '6',
  addressSPL: 'EKCdCBjfQ6t5FBfDC2zvmr27PgfVVZU37C8LUE4UenKb',
};

4. Configure Pool

Set up the pool parameters for liquidity operations. You'll need to know the pool address and token information.

Pool Configuration
// Configure the pool parameters
const poolParams = {
  address: '2wUvdZA8ZsY714Y5wUL9fkFmupJGGwzui2N74zqJWgty',
  tokens: {
    C98A4nkJXhpVZNAZdHUA95RpTF3T4whtQubL3YobiUX9: {
      ...C98_TOKEN,
    },
    EPjFWdd5AufqSSqeM2qN1zzybapC8G4wEGGkZwyTDt1v: {
      ...USDC_TOKEN,
    },
  },
  tokenIds: [
    'C98A4nkJXhpVZNAZdHUA95RpTF3T4whtQubL3YobiUX9',
    'EPjFWdd5AufqSSqeM2qN1zzybapC8G4wEGGkZwyTDt1v',
  ],
};

5. Get Pool Information

Retrieve information about the liquidity pool to understand its current state.

Get Pool Information
// Get information about the liquidity pool
const poolAccountInfo = await getPoolInfo(
  connection,
  new PublicKey(poolParams.address)
);

console.log('Pool Info:', poolAccountInfo);

6. Add Liquidity

Add liquidity to the pool by depositing tokens and receiving LP tokens in return.

Add Liquidity
// Add liquidity to the pool
const SLIPPAGE = 0.5; // 0.5% slippage tolerance

// Get pool LP token mint information
const newPoolLpMintInfo = await getTokenMintInfo(
  connection,
  poolAccountInfo.lpTokenMint
);

// Calculate LP token supply
const lpTokenSupply = newPoolLpMintInfo.supply
  ? newPoolLpMintInfo.supply.toNumber()
  : 0;

// Convert token amounts
const convertFromAmount = convertBalanceToWei(1, USDC_TOKEN.decimals);
const newPoolToken0AccountInfo = await getTokenAccountInfo(
  connection,
  poolAccountInfo.token0Account
);

// Calculate LP token amount to receive
const lpTokenAmount =
  (parseFloat(convertFromAmount) * lpTokenSupply) /
  newPoolToken0AccountInfo.amount.toNumber();

// Add liquidity to the pool
const result = await depositAllTokenTypes(
  connection,
  accountSol,
  new PublicKey(accountSol),
  new PublicKey(C98_TOKEN.addressSPL),
  new PublicKey(USDC_TOKEN.addressSPL),
  lpTokenAmount,
  new PublicKey(poolParams.address),
  new PublicKey('SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr'), // Program address
  C98_TOKEN.mintAddress,
  USDC_TOKEN.mintAddress,
  SLIPPAGE
);

// Handle the result
if (result.isError) {
  console.log(`Add liquidity failed: ${result.mess}`);
} else {
  console.log(`Liquidity added successfully! Transaction hash: ${result.hash}`);
}
Understanding Add Liquidity
1. Calculate Amounts: We calculate the LP token amount the user will receive based on their deposit.
2. Execute Deposit: We use depositAllTokenTypes to add liquidity to the pool.
3. Receive LP Tokens: The user receives LP tokens proportional to their share of the pool.

7. Remove Liquidity

Remove liquidity from the pool by burning LP tokens and receiving the underlying tokens back.

Remove Liquidity
// Remove liquidity from the pool
// Get LP token information
const lpTokenMint = poolAccountInfo.lpTokenMint.toString();
const newPoolToken0AccountInfo = await getTokenAccountInfo(
  connection,
  poolAccountInfo.token0Account
);

// Calculate LP token amount to redeem
const lpTokenAmount =
  (parseFloat(1) * lpTokenSupply) /
  newPoolToken0AccountInfo.amount.toNumber();

// Get user's LP token account
const infoLpUser = await getInfoTokenByMint(lpTokenMint, accountSol);

// Remove liquidity from the pool
const result = await withdrawAllTokenTypes(
  connection,
  accountSol,
  infoLpUser.pubkey,
  C98_TOKEN.addressSPL,
  USDC_TOKEN.addressSPL,
  lpTokenAmount,
  new PublicKey(poolParams.address),
  new PublicKey('SSwapUtytfBdBn1b9NUGG6foMVPtcWgpRU32HToDUZr'), // Program address
  C98_TOKEN.mintAddress,
  USDC_TOKEN.mintAddress,
  SLIPPAGE
);

// Handle the result
if (result.isError) {
  console.log(`Remove liquidity failed: ${result.mess}`);
} else {
  console.log(`Liquidity removed successfully! Transaction hash: ${result.hash}`);
}
Understanding Remove Liquidity
1. Calculate Amounts: We calculate the token amounts the user will receive based on their LP token burn.
2. Execute Withdrawal: We use withdrawAllTokenTypes to remove liquidity from the pool.
3. Receive Tokens: The user receives the underlying tokens proportional to their LP token burn.
📚 Next Steps
Continue learning with these related tutorials
💡 Key Takeaways
Impermanent Loss: Understand the concept of impermanent loss when providing liquidity.
Fee Earnings: Liquidity providers earn a portion of the trading fees generated by the pool.
Slippage Protection: Use slippage protection when adding or removing liquidity to prevent unfavorable trades.
Pool Selection: Research pools carefully before providing liquidity to understand the risks and rewards.
Network Configuration: Use the correct RPC endpoints for devnet, testnet, or mainnet depending on your environment.