Saros
  • SAROS
  • SAROS DLMM
  • SAROS AMM
  • SAROS PERPS
  • SAROS MOBILE APP
  • SAROS DLMM
    • Onboarding and Guides
      • Saros DLMM: Introduction
      • Liquidity Lifecycle: Deployment, Management & Rebalancing
      • Permissionless Saros DLMM Pools
      • Understanding Your Risks as a Liquidity Provider on Saros DLMM
    • Shapes and Strategies
      • Liquidity Shapes
      • Getting Started with Basic Liquidity Strategies
      • Advanced Liquidity Strategies on Saros
      • Managing Out-of-Range Liquidity on Saros
      • Single-Sided Liquidity Strategies on Saros
    • Rewards
      • Concentrated Incentives (CI) on Saros
    • Technical Design
    • Technical Guides
      • Add liquidity
      • Create a pair
      • User Position
      • Swap tokens
      • Removing Liquidity
  • SAROS MOBILE APP
    • Mobile App
      • How to install Saros Super App
      • How to set up Saros Super App
      • How to add a new Hot Wallet
      • How to add View-only wallet
      • How to log in to Social Account
      • How to manage wallets
      • How to send or receive a token
      • How to send or receive NFTs
      • How to send multiple NFTs to an address
      • How to swap tokens
      • How to add a custom token
      • How to manage tokens
      • General Settings
      • How to use DApp browser
      • How to turn on Biometric and change Passcode
      • Migrate Ramper V2 on Super App
      • How to use Discover
      • How to buy crypto
    • Extension
      • How to install Saros Wallet Extension
      • How to set up Saros Extension Wallet
      • How to add a new Hot Wallet on Saros Extension
      • How to Add view-only wallet
      • How to manage wallets
      • How to send or receive a token
      • How to send or receive NFTs
      • How to add a custom token?
      • How to manage tokens
      • General settings
      • How to change the password?
      • Migrate Ramper V2 on Extension
      • How to log in to Social Account
      • How to use Discover
      • How to buy crypto
      • How to send multiple NFTs in one transaction with Multisend
      • How to Manage Notifications
      • How to swap on Saros Extension
      • Action on X
    • FAQs
  • SAROS AMM
    • SarosSwap
      • How To Swap on SarosSwap
    • SarosFarm
      • How to Add Liquidity
      • How to Remove Liquidity
      • How to Farm on SarosFarm
      • How to Claim the Reward
    • SarosStake
      • How to stake
      • How to unstake
      • How to harvest
    • SarosSnapShot
    • SarosPerpetual
      • Trading Basics
      • Getting Started
      • Deposit/Withdraw
      • Order Management
    • FAQs
      • Is Saros safe? Has Saros been audited?
      • Why did my transaction fail?
      • How to resolve the "No wallet" error when connecting wallet to Saros Finance
      • What is the difference between APY and APR?
      • How to get farming pool Txid
      • What are liquidity provider tokens?
      • When will you open more pools?
      • What wallets can I use with Saros? How do I connect my wallet to Saros?
      • My LP tokens aren’t showing up on the site or in my wallet?
      • How do I get airdrops?
      • Can I use Saros on my phone?
      • What is price impact?
      • What is slippage tolerance? How can I adjust it when swapping?
      • What fees do I pay when I exchange tokens?
      • Are there any fees associated with the SarosFarm?
      • How to calculate and distribute the reward on SarosFarm?
      • Can I withdraw my liquidity anytime?
      • Where can I check Saros Analytics?
      • I can't find an answer for my question. Where do I find an answer?
      • How could I report a bug?
      • How to check wallet information on Saros
    • Go to DEX
  • SAROS GARDEN
    • Introduction
    • How to stake on Saros Garden
    • How to unstake from Saros Garden
  • ALL ABOUT $SAROS
    • Saros Token ($SAROS)
  • INTEGRATION
    • Saros Super App
    • Saros DEX
  • Saros DLMM
  • LEGAL
    • TERMS OF SERVICE
    • Privacy Policy
  • AUDITS
    • SarosSwap
    • SarosFarm & SarosStake
  • OFFICIAL LINKS
    • Saros Community
    • Brand Assets
Powered by GitBook
On this page
  • Overview​
  • Deriving PDAs​
  • Creating Token Vaults​
  • Initializing the Quote Asset Badge​
  • Initializing the Pair​
  • Initializing Bin Arrays​
  • Complete End‑to‑End Example
  1. SAROS DLMM
  2. Technical Guides

Create a pair

PreviousAdd liquidityNextUser Position

Last updated 16 days ago

Overview

This guide outlines how to establish a new token pair on a Saros DLMM pool via your frontend. The workflow is encapsulated in a single user transaction and includes:

  1. Deriving required PDAs (Program Derived Addresses)

  2. Creating the quote asset badge

  3. Initializing the pool pair

  4. Setting up the bin arrays

Deriving PDAs

Before creating a pair, you need to derive several PDAs:

import { PublicKey } from "@solana/web3.js";
import { BN } from "@project-serum/anchor";
import { utils } from "@coral-xyz/anchor";

// Configuration PDA
const config = new PublicKey("address");

// Token mints
const tokenX = new PublicKey("address");
const tokenY = new PublicKey("address");

const BIN_STEP = 20;

const BIN_ARRAY_INDEX = 0; // Example value

const ACTIVE_ID = 8388608; // Example value (2^23)

// Derive bin step config PDA
const [binStepConfig] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("bin_step_config")),
    config.toBuffer(),
    new Uint8Array([BIN_STEP]),
  ],
  program.programId
);

// Derive quote asset badge PDA
const [quoteAssetBadge] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("quote_asset_badge")),
    config.toBuffer(),
    tokenY.toBuffer(),
  ],
  program.programId
);

// Derive pair PDA
const [pair] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("pair")),
    config.toBuffer(),
    tokenX.toBuffer(),
    tokenY.toBuffer(),
    new Uint8Array([BIN_STEP]),
  ],
  program.programId
);

// Derive bin array PDAs
const [binArrayLower] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("bin_array")),
    pair.toBuffer(),
    new BN(BIN_ARRAY_INDEX).toArrayLike(Buffer, "le", 4),
  ],
  program.programId
);

const [binArrayUpper] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("bin_array")),
    pair.toBuffer(),
    new BN(BIN_ARRAY_INDEX + 1).toArrayLike(Buffer, "le", 4),
  ],
  program.programId
);

For the pair to function, you need to create token vaults for both tokens:

import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token";

// Create token vaults for the pair
const pairVaultX = await getOrCreateAssociatedTokenAccount(
  connection,
  wallet.payer,
  tokenX,
  pair,
  true
);

const pairVaultY = await getOrCreateAssociatedTokenAccount(
  connection,
  wallet.payer,
  tokenY,
  pair,
  true
);

The quote asset badge identifies which token is the quote asset (token Y):

// Initialize quote asset badge
await program.methods
  .initializeQuoteAssetBadge()
  .accounts({
    quoteAssetBadge: quoteAssetBadge,
    liquidityBookConfig: config,
    tokenMint: tokenY,
    presetAuthority: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

Now you can initialize the pair with the specified active binitializeConfigD:

// Initialize pair
await program.methods
  .initializePair(new BN(ACTIVE_ID))
  .accounts({
    liquidityBookConfig: config,
    binStepConfig: binStepConfig,
    quoteAssetBadge: quoteAssetBadge,
    pair: pair,
    tokenMintX: tokenX,
    tokenMintY: tokenY,
    user: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

Finally, you need to initialize the bin arrays for the pair:

// Initialize lower bin array
await program.methods
  .initializeBinArray(new BN(BIN_ARRAY_INDEX))
  .accounts({
    pair: pair,
    binArray: binArrayLower,
    user: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

// Initialize upper bin array
await program.methods
  .initializeBinArray(new BN(BIN_ARRAY_INDEX + 1))
  .accounts({
    pair: pair,
    binArray: binArrayUpper,
    user: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

Complete End‑to‑End Example

Below is a consolidated script that ties together all the preceding steps:

import { PublicKey } from "@solana/web3.js";
import { BN, Program, utils } from "@coral-xyz/anchor";
import { getOrCreateAssociatedTokenAccount } from "@solana/spl-token";

// Configuration
const config = new PublicKey("9aXo79uWCtxxxmssuTmAjCSGyP1sMxhQZdKZhrcMxGzz");
const tokenX = new PublicKey("FtJADTW8HSB4t6QQ4WsR8kcrrZ6oVaoVJk7KEWQZDJqt");
const tokenY = new PublicKey("Chc7CkBPvBsyNAmxAcupVox6pB5wcU2yuXD5PJAqQteb");
const BIN_STEP = 20;
const BIN_ARRAY_INDEX = 0;
const ACTIVE_ID = 8388608;

// Derive PDAs
const [binStepConfig] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("bin_step_config")),
    config.toBuffer(),
    new Uint8Array([BIN_STEP]),
  ],
  program.programId
);

const [quoteAssetBadge] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("quote_asset_badge")),
    config.toBuffer(),
    tokenY.toBuffer(),
  ],
  program.programId
);

const [pair] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("pair")),
    config.toBuffer(),
    tokenX.toBuffer(),
    tokenY.toBuffer(),
    new Uint8Array([BIN_STEP]),
  ],
  program.programId
);

const [binArrayLower] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("bin_array")),
    pair.toBuffer(),
    new BN(BIN_ARRAY_INDEX).toArrayLike(Buffer, "le", 4),
  ],
  program.programId
);

const [binArrayUpper] = PublicKey.findProgramAddressSync(
  [
    Buffer.from(utils.bytes.utf8.encode("bin_array")),
    pair.toBuffer(),
    new BN(BIN_ARRAY_INDEX + 1).toArrayLike(Buffer, "le", 4),
  ],
  program.programId
);

// Create token vaults
const pairVaultX = await getOrCreateAssociatedTokenAccount(
  connection,
  wallet.payer,
  tokenX,
  pair,
  true
);

const pairVaultY = await getOrCreateAssociatedTokenAccount(
  connection,
  wallet.payer,
  tokenY,
  pair,
  true
);

// Initialize quote asset badge
await program.methods
  .initializeQuoteAssetBadge()
  .accounts({
    quoteAssetBadge: quoteAssetBadge,
    liquidityBookConfig: config,
    tokenMint: tokenY,
    presetAuthority: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

// Initialize pair
await program.methods
  .initializePair(new BN(ACTIVE_ID))
  .accounts({
    liquidityBookConfig: config,
    binStepConfig: binStepConfig,
    quoteAssetBadge: quoteAssetBadge,
    pair: pair,
    tokenMintX: tokenX,
    tokenMintY: tokenY,
    user: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

// Initialize bin arrays
await program.methods
  .initializeBinArray(new BN(BIN_ARRAY_INDEX))
  .accounts({
    pair: pair,
    binArray: binArrayLower,
    user: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

await program.methods
  .initializeBinArray(new BN(BIN_ARRAY_INDEX + 1))
  .accounts({
    pair: pair,
    binArray: binArrayUpper,
    user: wallet.publicKey,
  })
  .signers([wallet.payer])
  .rpc();

console.log("Pair created successfully!");
console.log("Pair address:", pair.toBase58());
console.log("Bin array lower address:", binArrayLower.toBase58());
console.log("Bin array upper address:", binArrayUpper.toBase58());

Creating Token Vaults

Initializing the Quote Asset Badge

Initializing the Pair

Initializing Bin Arrays

​
​
​
​
​
​