# Get All User Positions and Withdrawals for a Pool

Similar to deposits, cases may exist where dApps may require <mark style="color:yellow;">fetch</mark> user positions and their <mark style="color:yellow;">withdrawals</mark> for a particular pool. The steps involved are quite similar to fetching deposits:&#x20;

* For a pool address, we <mark style="color:yellow;">fetch</mark> all the <mark style="color:yellow;">pool specific details</mark>, such as the tokens involved, its *activeId*, or *lastUpdatedAt* value. This can be obtained by <mark style="color:yellow;">querying</mark> the `meteora_dlmm_LbPair` account, with `pubkey` field being *\_eq* to the pool address.
* We <mark style="color:yellow;">fetch</mark> all the <mark style="color:yellow;">position details</mark> and the users for that particular pool, by querying the `meteora_dlmm_Position` and `meteora_dlmm_PositionV2` accounts, by filtering the `LbPair` field being equal to the pool address.
* Once we have the position addresses from the previous step, we <mark style="color:yellow;">get</mark> all <mark style="color:yellow;">transactions</mark> for the position address of each position. With SHYFT's parsed transactions, we can directly get the amounts withdrawn from the pool, for that particular position.

{% tabs %}
{% tab title="Code Snippet" %}
{% code overflow="wrap" %}

```javascript
import { ShyftSdk, Network } from "@shyft-to/js";

const SHYFT_API_KEY = "YOUR_SHYFT_API_KEY";

const shyft = new ShyftSdk({ apiKey: SHYFT_API_KEY, network: Network.Mainnet });

async function getPoolDetails(poolAddress) {
  //querying pool details with LbPair address
  const operationsDoc = `
      query MyQuery {
        meteora_dlmm_LbPair(
          where: {pubkey: {_eq: ${JSON.stringify(poolAddress)}}}
        ) {
          activeId
          tokenXMint
          tokenYMint
          pubkey
          
        }
      }
    `; //you can cherrypick the fields as per your requirement

  const result = await fetch(
    `https://programs.shyft.to/v0/graphql/accounts?api_key=${SHYFT_API_KEY}&network=mainnet-beta`, //SHYFT's GQL endpoint
    {
      method: "POST",
      body: JSON.stringify({
        query: operationsDoc,
        variables: {},
        operationName: "MyQuery",
      }),
    },
  );

  const { errors, data } = await result.json();
  if (errors) {
    return {
      meteora_dlmm_LbPair: [],
    };
  }

  return data;
}
async function getPositionsByPool(poolAddress) {
  //querying pool details with LbPair address
  const operationsDoc = `
      query MyQuery {
         meteora_dlmm_Position(
          where: {lbPair: {_eq: ${JSON.stringify(poolAddress)}}}
        ) {
          _lamports
          lbPair
          owner
          pubkey
        }
        meteora_dlmm_PositionV2(
          where: {lbPair: {_eq: ${JSON.stringify(poolAddress)}}}
        ) {
          _lamports
          lbPair
          owner
          pubkey
        }
      }
    `; //you can cherrypick the fields as per your requirement

  const result = await fetch(
    `https://programs.shyft.to/v0/graphql/accounts?api_key=${SHYFT_API_KEY}&network=mainnet-beta`, //SHYFT's GQL endpoint
    {
      method: "POST",
      body: JSON.stringify({
        query: operationsDoc,
        variables: {},
        operationName: "MyQuery",
      }),
    },
  );

  const { errors, data } = await result.json();
  if (errors) {
    return {
      positionsV1: [],
      positionV2: [],
    };
  }
  let positionsV1 = [];
  let positionsV2 = [];

  if (data.meteora_dlmm_Position.length > 0) {
    positionsV1 = data.meteora_dlmm_Position;
  }
  if (data.meteora_dlmm_PositionV2.length > 0) {
    positionsV2 = data.meteora_dlmm_PositionV2;
  }

  return {
    positionsV1: positionsV1,
    positionsV2: positionsV2,
  };
}

async function getUserWithdrawsByPositionV1(positionAddress,tokenX,tokenY) {
    let genesisTxnReached = false;
    let removeLiquidityTxns = [];
    let lastSignature = undefined;
  
  
    while (!genesisTxnReached) {
        const transactions = await shyft.transaction.history({
            account: positionAddress,
            network: Network.Mainnet,
            txNum: 10,
            beforeTxSignature: lastSignature
        });
        transactions.map((txn) => {
            if(txn.type === "REMOVE_LIQUIDITY")
                removeLiquidityTxns.push(txn);
        });
  
        if(transactions.length < 10){
            genesisTxnReached = true;
            break;
        }
        lastSignature = transactions[transactions.length - 1].signatures[0];
    }
    const removedLiquidityDetails = [];
  
    if(removeLiquidityTxns.length > 0){
  
        removeLiquidityTxns.forEach((removeLiquidityTxn) => {
            let eachRemovedTxn = {
                "txn_id":removeLiquidityTxn.signatures[0],
                "onchain_timestamp": removeLiquidityTxn.timestamp,
            };
            removeLiquidityTxn.actions.map((action) => {
                if(action.type === "REMOVE_LIQUIDITY"){
                    action.info.liquidity_removed.map((liquidityDetails) => {
                        if(liquidityDetails.token_address === tokenX){
                            eachRemovedTxn = {
                                ...eachRemovedTxn,
                                "tokenX_amount":liquidityDetails.amount_raw,
                                "tokenX_address":liquidityDetails.token_address
                            }
                        }
                        if(liquidityDetails.token_address === tokenY){
                            eachRemovedTxn = {
                                ...eachRemovedTxn,
                                "tokenY_amount":liquidityDetails.amount_raw,
                                "tokenY_address":liquidityDetails.token_address
                            }
                        }
                    })
                }
            })
            removedLiquidityDetails.push(eachRemovedTxn);
        });
    }
    return removedLiquidityDetails;
  }
  
  async function getUserWithdrawsByPositionV2(ownerAddress, positionAddress, lbPair, tokenX, tokenY) {
    let genesisTxnReached = false;
    let tokenTransferTxns = [];
    let lastSignature = undefined;
  
    while (!genesisTxnReached) {
        const transactions = await shyft.transaction.history({
            account: positionAddress,
            network: Network.Mainnet,
            txNum: 10,
            beforeTxSignature: lastSignature
        });
        
        transactions.map((txn) => {
            if(txn.type === "TOKEN_TRANSFER")
            {
                txn.actions.map((action) => {
                    if(action.type === "TOKEN_TRANSFER" && action.info.sender === lbPair && action.info.receiver === ownerAddress){
                        tokenTransferTxns.push(txn)
                    }
                })
            }
        });
  
        if(transactions.length < 10){
            genesisTxnReached = true;
            break;
        }
        lastSignature = transactions[transactions.length - 1].signatures[0];
    }
    const removedLiquidityDetails = [];
  
    if(tokenTransferTxns.length > 0){
  
        tokenTransferTxns.forEach((tokenTransferTxn) => {
  
            let eachRemovedTxn = {
                "txn_id":tokenTransferTxn.signatures[0],
                "onchain_timestamp": tokenTransferTxn.timestamp,
            };
            tokenTransferTxn.actions.map((action) => {
                if(action.type === "TOKEN_TRANSFER"){
                    if(action.info.token_address === tokenX){
                        eachRemovedTxn = {
                            ...eachRemovedTxn,
                            "tokenX_amount":action.info.amount_raw,
                            "tokenX_address":action.info.token_address
                        }
                    }
                    if(action.info.token_address === tokenY){
                        eachRemovedTxn = {
                            ...eachRemovedTxn,
                            "tokenY_amount":action.info.amount_raw,
                            "tokenY_address":action.info.token_address
                        }
                    }
  
                }
            })
            if(removedLiquidityDetails.length === 0 || removedLiquidityDetails.map((txn) => txn.txn_id).includes(eachRemovedTxn.txn_id) === false)
                removedLiquidityDetails.push(eachRemovedTxn);
        });
    }
    return removedLiquidityDetails;
  }


async function getUserPoolDetails(poolAddress) {
    let allPoolPositionDetails = [];
    let allPoolPositionDetailsV1 = [];
  const poolDetails = await getPoolDetails(poolAddress);
  const tokenMintX = poolDetails.meteora_dlmm_LbPair[0].tokenXMint;
  const tokenMintY = poolDetails.meteora_dlmm_LbPair[0].tokenYMint;
  console.log("Tokens involved in this pool");
  console.log("TokenX:", tokenMintX);
  console.log("TokenY:", tokenMintY);
  const positions = await getPositionsByPool(poolAddress);

  for (let i = 0; i < positions.positionsV1.length; i++) {
    const currentPositionV1 = positions.positionsV1[i];
    const liquidityDetails = await getUserWithdrawsByPositionV1(
      currentPositionV1.pubkey,
      tokenMintX,
      tokenMintY,
    );

    allPoolPositionDetailsV1.push({
      owner: currentPositionV1.owner,
      positionAddress: currentPositionV1.pubkey,
      poolAddress: poolAddress,
      liquidityWithdrawDetails: liquidityDetails,
    });
  }
  for (let i = 0; i < positions.positionsV2.length; i++) {
    const currentPositionV2 = positions.positionsV2[i];
    const liquidityDetails = await getUserWithdrawsByPositionV2(
      currentPositionV2.owner,
      currentPositionV2.pubkey,
      poolAddress,
      tokenMintX,
      tokenMintY,
    );

    allPoolPositionDetails.push({
      owner: currentPositionV2.owner,
      positionAddress: currentPositionV2.pubkey,
      poolAddress: poolAddress,
      liquidityWithdrawDetails: liquidityDetails,
    });
    
  }
  console.dir({
    poolAddress: poolAddress,
    tokenXMint: tokenMintX,
    tokenYMint: tokenMintY,
    allPoolPositionV1Details: allPoolPositionDetailsV1,
    allPoolPositionV2Details: allPoolPositionDetails
  },{depth:null})
}
getUserPoolDetails("FFpF3BNiBvtewyACdxvvedLDdbZ3einkkpJ7NnknpeqU");
//replace with your pool address
```

{% endcode %}
{% endtab %}

{% tab title="Response" %}
{% code overflow="wrap" %}

```json
{
  poolAddress: "FFpF3BNiBvtewyACdxvvedLDdbZ3einkkpJ7NnknpeqU",
  tokenXMint: "HUBsveNpjo5pWqNkH57QzxjQASdTVXcSK7bVKTSZtcSX",
  tokenYMint: "So11111111111111111111111111111111111111112",
  allPoolPositionV1Details: [
    {
      owner: "8JoJZkwoTB1SfMztNBCT9vh9eH2wcMLZQPHKgpToZLCK",
      positionAddress: "FebBcTw8ETzTaHnQLSEvnWy2oHUSGvZr94bpphgR7e7L",
      poolAddress: "FFpF3BNiBvtewyACdxvvedLDdbZ3einkkpJ7NnknpeqU",
      liquidityWithdrawDetails: [
        {
          txn_id: "3PEGuEVFhnxThRZUyanf31MMELPKYR99fxqT5yHrUVkK7QVRmJf3xkkgKbaN6PxrARVYvDZeNPHfYKur7cihe1sK",
          onchain_timestamp: "2024-05-13T08:13:51.000Z",
          tokenY_amount: 100621198,
          tokenY_address: "So11111111111111111111111111111111111111112"
        }
      ]
    }
 ],
  allPoolPositionV2Details: [
  [
    {
      owner: "8JoJZkwoTB1SfMztNBCT9vh9eH2wcMLZQPHKgpToZLCK",
      positionAddress: "FebBcTw8ETzTaHnQLSEvnWy2oHUSGvZr94bpphgR7e7L",
      poolAddress: "FFpF3BNiBvtewyACdxvvedLDdbZ3einkkpJ7NnknpeqU",
      liquidityWithdrawDetails: [
        {
          txn_id: "2PEGuEVFhnxThRZUyanf31MMELPKYR99fxqT5yHrUVkK7QVRmJf3xkkgKbaN6PxrARVYvDZeNPHfYKur7cihe1sK",
          onchain_timestamp: "2024-05-13T08:13:51.000Z",
          tokenY_amount: 100621198,
          tokenY_address: "So11111111111111111111111111111111111111112"
        }
      ]
    },
    {
      owner: "7wYK2PJb8rtP5PS4BJFVLNTQ3VxSTxw4pyFyY64AZWbn",
      positionAddress: "8UzTcZibL4zrjk9FGWiRvggBRdbFqKzKKPFgBC4m8vJ5",
      poolAddress: "FFpF3BNiBvtewyACdxvvedLDdbZ3einkkpJ7NnknpeqU",
      liquidityWithdrawDetails: [
        {
          txn_id: "4vZb7t9rMuFf119SjLA7HxfpJMVa2Rem3Zu63r5mh1Lzrgu5RYDKp12KRbi5zNAhMnL2W81rCgHhyk2iD1MTxptc",
          onchain_timestamp: "2024-05-02T02:34:27.000Z",
          tokenX_amount: 160407001,
          tokenX_address: "HUBsveNpjo5pWqNkH57QzxjQASdTVXcSK7bVKTSZtcSX",
          tokenY_amount: 19865223729,
          tokenY_address: "So11111111111111111111111111111111111111112"
        }
      ]
    }
  ]
}
//This is a sample response, please reinforce and filter according to your requirement
```

{% endcode %}
{% endtab %}
{% endtabs %}
