> ## Documentation Index
> Fetch the complete documentation index at: https://creator-a1160a86.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Adding liquidity

In the last tutorial, we created a pool for PYUSD with WSOL as the quote token.
Now we are going to add liquidity to that pool.

To add liquidity, we must check the existence of the required bins and vault accounts for the pair,
or create them if they don't exist. Then we will create positions for the user in the required bins and
add liquidity to those positions.

## Create Pool Metadata

Update your `constants.ts` file to include the pool metadata so we can reuse it
throughout this tutorial.

```Typescript constants.ts theme={null}
// ... 
export const PYUSD_WSOL_POOL_DEVNET = {
    address: "H9EPqQKCvv9ddzK6KHjo8vvUPMLMJXmMmru9KUYNaDFQ",
    baseToken: PYUSD_TOKEN_DEVNET,
    quoteToken: WSOL_TOKEN_DEVNET,
    slippage: 0.5,
}
```

> [!NOTE]
>
> Have a Keypair set up, or set up your custom wallet interface using the wallet provider of your choice.
> For this tutorial, I'm using a wallet object created with Keypair.generate() from @solana/web3.js.

## Get Pair On-chain Metadata

Now let's write the main logic. Create a new file called `adding-liquidity.ts`. Here we will add
the following logic.

Use the `sarosDLMM` instance to get the pair’s on-chain metadata. This provides the current active
bin index of the pool, which is needed to construct our bin array.

```Typescript theme={null}
import { sarosDLMM } from "./service.js";

const pair = new PublicKey(PYUSD_WSOL_POOL_DEVNET.address);
const pairInfo = await sarosDLMM.getPairAccount(pair);
```

## Maintain a Global Transaction Queue

We will sign and send many transactions to add liquidity to the pool. For that, we'll use a
global transaction queue that stores all transactions.

```Typescript theme={null}
const txQueue: Transaction[] = [];
```

## Prepare Bin and Vault Accounts

1. Create a temporary `Transaction` object that contains instructions to load bin and vault accounts.

```Typescript theme={null}
const binsAndVaultsTx = new Transaction();
```

2. Select the bin range where we want to add liquidity.

```Typescript theme={null}
const binRange: [number, number] = [-5, 5];
```

3. Bins are structured in arrays, with each array containing 256 bins. So we have to
   find the bin arrays containing the bins for the selected bin range.

![Bin structure](https://mintcdn.com/creator-a1160a86/bhdvESYVf3sBmmjR/images/bin-structure.png?fit=max\&auto=format\&n=bhdvESYVf3sBmmjR\&q=85\&s=c31c2d159a8ddfa26b885257a5435de8)

```Typescript theme={null}
// ...
import { getMaxBinArray } from "@saros-labs/saros-dlmm-sdk";

// ...
const activeBin = pairInfo.activeBin;
const binArrayList = getMaxBinArray(binRange, activeBin);
```

4. For the required bin arrays, check whether they exist on-chain. If not, create them.
   The `getBinArray` method checks if the bin array PDA exists on-chain. If not, it builds transaction
   instructions to create the bin array and updates `binsAndVaultsTx`.

```Typescript adding-liquidity.ts theme={null}
// ...
import { getBinArray } from "@saros-labs/saros-dlmm-sdk";

// ...
await Promise.all([
  ...binArrayList.map(async (bin) => {
    await sarosDLMM.getBinArray({
      binArrayIndex: bin.binArrayLowerIndex,
      pair,
      payer: wallet.publicKey,
      transaction: binsAndVaultsTx as any,
    });
    await sarosDLMM.getBinArray({
      binArrayIndex: bin.binArrayUpperIndex,
      pair,
      payer: wallet.publicKey,
      transaction: binsAndVaultsTx as any,
    });
  }),
]);
```

5. Next, check the pair vault account (ATA) and user vault account (ATA) for the pair. These
   accounts don't exist for a newly created pair or for a user interacting with this pair for the first time.

The `getPairVaultInfo` and `getUserVaultInfo` methods check whether the vault accounts exist on-chain. If not,
they build transaction instructions to create the vault accounts and update `binsAndVaultsTx`.

```Typescript adding-liquidity.ts theme={null}
// ...
import { getPairVault } from "@saros-labs/saros-dlmm-sdk";

// ...
await Promise.all([
   ...[PYUSD_WSOL_POOL_DEVNET.baseToken, PYUSD_WSOL_POOL_DEVNET.quoteToken].map(async (token) => {
    await sarosDLMM.getPairVaultInfo({
      pair,
      payer: wallet.publicKey,
      transaction: binsAndVaultsTx as any,
      tokenAddress: new PublicKey(token.mintAddress),
    });
    await sarosDLMM.getUserVaultInfo({
      payer: wallet.publicKey,
      transaction: binsAndVaultsTx as any,
      tokenAddress: new PublicKey(token.mintAddress),
    });
   }
]);
```

6. Now it's time to add the built instructions to the global transaction queue.

```Typescript adding-liquidity.ts theme={null}
// ...
if (binsAndVaultsTx.instructions.length > 0) {
  binsAndVaultsTx.recentBlockhash = blockhash;
  binsAndVaultsTx.feePayer = wallet.publicKey;
  txQueue.push(binsAndVaultsTx);
}
```

## Create User Positions

Now we need to create positions for the user in the required bins, and then add liquidity to those positions.

### 1. Calculate the required positions

1. Previously, we represented 256 bins in a `binArray`. To add positions, we further divide the
   `binArray` into bin groups of 16 bins. A single position covers 16 bins (Saros DLMM standard).

Let's use the `getMaxPosition` method to calculate the relative positions (with respect to the active bin) required to add liquidity.

```Typescript adding-liquidity.ts theme={null}
// ...
import { getMaxPosition } from "@saros-labs/saros-dlmm-sdk";

// ...
const maxPositionList = getMaxPosition(binRange, activeBin);
```

2. Next, find all existing user positions in the pair.

```Typescript adding-liquidity.ts theme={null}
// ...
const userPositions = await sarosDLMM.getUserPositions({ payer: wallet.publicKey, pair });
```

3. Choose a distribution strategy to decide how the user should distribute liquidity across the required bins.
   \[!NOTE] We have 3 strategies to distribute liquidity: "BidAsk", "Curve", and "Spot".

```Typescript adding-liquidity.ts theme={null}
// ...
const maxLiquidityDistribution = createUniformDistribution({ shape: LiquidityShape.Spot, binRange });
```

The `maxLiquidityDistribution` is an array of objects with `relativeBinId`, `distributionX`,
and `distributionY` token percentages.

### 2. Create positions

For each required relative position, find the mint address, the liquidity distribution of depositing tokens,
and the lower and upper bin array index. With the position mint address and bin array indexes, the program will find the
bins to add liquidity to. The liquidity distribution determines the percentage of tokens to deposit in that position.

1. Find the user's existing position in this bin group.

```Typescript adding-liquidity.ts theme={null}
const maxLiquidityDistributions = await Promise.all(
  maxPositionList.map(async (position) => {
    const currentPosition = userPositions.find(findPosition(position, activeBin));
  }),
);
```

2. Calculate the liquidity distribution for this position.

```Typescript adding-liquidity.ts theme={null}
const startIndex =
      maxLiquidityDistribution.findIndex((item) => item.relativeBinId === range[0]) ?? 0;
    const endIndex =
      (maxLiquidityDistribution.findIndex((item) => item.relativeBinId === range[1]) ?? maxLiquidityDistribution.length - 1) + 1;

    const liquidityDistribution = maxLiquidityDistribution.slice(startIndex, endIndex);
```

3. Calculate the bin arrays in which the position is to be created.

```Typescript adding-liquidity.ts theme={null}
const binArray = binArrayList.find(
      (item) =>
        item.binArrayLowerIndex * 256 <= binLower &&
        (item.binArrayUpperIndex + 1) * 256 > binUpper
    )!;

    const binArrayLower = await sarosDLMM.getBinArray({
      binArrayIndex: binArray.binArrayLowerIndex,
      pair: new PublicKey(pair),
      payer: wallet.publicKey,
    });
    const binArrayUpper = await sarosDLMM.getBinArray({
      binArrayIndex: binArray.binArrayUpperIndex,
      pair: new PublicKey(pair),
      payer: wallet.publicKey,
    });
```

4. Find the mint address of the position.

If there is no existing position, create a new position.

```Typescript adding-liquidity.ts theme={null}
let positionMint: PublicKey;

    if (!currentPosition) {
      const createPositionTx = new Transaction();
      const newPositionMint = Keypair.generate();

      await sarosDLMM.createPosition({
        pair: new PublicKey(pair),
        payer: wallet.publicKey,
        relativeBinIdLeft: range[0]!,
        relativeBinIdRight: range[1]!,
        binArrayIndex: binArray.binArrayLowerIndex,
        positionMint: newPositionMint.publicKey,
        transaction: createPositionTx as any,
      });

      createPositionTx.recentBlockhash = blockhash;
      createPositionTx.feePayer = wallet.publicKey;
      createPositionTx.sign(wallet, newPositionMint);
      txQueue.push(createPositionTx);
      positionMint = newPositionMint.publicKey;
    } else {
      positionMint = currentPosition.positionMint;
    }
```

Finally, return the calculated values.

```Typescript adding-liquidity.ts theme={null}
 return {
      positionMint,
      position,
      liquidityDistribution,
      binArrayLower: binArrayLower.toString(),
      binArrayUpper: binArrayUpper.toString(),
    };
```

## Add Liquidity into Positions

In the previous step, we created positions that will hold user liquidity.
Now we will add liquidity to those positions.

```Typescript adding-liquidity.ts theme={null}

await Promise.all(
  maxLiquidityDistributions.map(async (maxLiquidityDistribution) => {
    const { positionMint, liquidityDistribution, binArrayLower, binArrayUpper } =
      maxLiquidityDistribution;

    const addLiquidityTx = new Transaction();

    const amountX = Number(
      new bigDecimal(Math.pow(10, PYUSD_TOKEN_DEVNET.decimals)).multiply(
        new bigDecimal(0.1)
      ).getValue()
    );
    const amountY = Number(
      new bigDecimal(Math.pow(10, WSOL_TOKEN_DEVNET.decimals)).multiply(
        new bigDecimal(0.1)
      ).getValue()
    );

    await sarosDLMM.addLiquidityIntoPosition({
      amountX,
      amountY,
      positionMint,
      liquidityDistribution,
      binArrayLower: new PublicKey(binArrayLower),
      binArrayUpper: new PublicKey(binArrayUpper),
      transaction: addLiquidityTx as any,
      payer: wallet.publicKey,
      pair,
    });

    addLiquidityTx.recentBlockhash = blockhash;
    addLiquidityTx.feePayer = wallet.publicKey;
    txQueue.push(addLiquidityTx);
  })
);

```

## Sign and Send Transactions

We have built the instructions to add liquidity to the positions and added them to the global transaction queue.
You can use your favorite wallet provider to sign and send the transactions.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.