# Get All Withdraws for a User

Positions in liquidity pairs represent the <mark style="color:yellow;">ownership stake</mark> of liquidity. Similar to deposits, liquidity providers (users) can also withdraw liquidity from a liquidity pool. With SHYFT's graphQL APIs, we can find out how much <mark style="color:yellow;">liquidity</mark> one particular liquidity provider has <mark style="color:yellow;">withdrawn</mark>. The process however involves two simple steps:

1. Suppose we have a liquidity provider (user) address, we fetch all the positions on meteora that the provider holds, and their `lbPair` details. This step should give us the position address(s) for the provider, and the tokens involved for each of the related pool. (A liquidity provider may have positions for multiple pools)
2. Once we have the above details, we get all the <mark style="color:yellow;">transactions</mark> for the position address received. The liquidity withdrawn details are stored in the remove liquidity transactions for positionsV1, and as token transfers for PositionsV2 (with sender being the pool address).

You can directly copy paste this code on <mark style="color:yellow;">replit</mark> and see it in action.

{% 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 getLbPairDetails(lbPairAddress) {
    const LbPairDetails = 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: `
                query MyQuery {
                    meteora_dlmm_LbPair(
                        where: {pubkey: {_eq: ${JSON.stringify(lbPairAddress)}}}
                ) {
                    pubkey
                    tokenXMint
                    tokenYMint
                    }
                }
            `, //querying the LB pair details
            variables: {},
            operationName: "MyQuery",
          }),
        }
      );
      const LBPairResponse = await LbPairDetails.json();

      return{
        pubkey: LBPairResponse.data.meteora_dlmm_LbPair[0].pubkey,
        tokenY: LBPairResponse.data.meteora_dlmm_LbPair[0].tokenYMint,
        tokenX: LBPairResponse.data.meteora_dlmm_LbPair[0].tokenXMint,
      };

}

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_symbol":liquidityDetails.symbol,
                              "tokenX_address":liquidityDetails.token_address
                          }
                      }
                      if(liquidityDetails.token_address === tokenY){
                          eachRemovedTxn = {
                              ...eachRemovedTxn,
                              "tokenY_amount":liquidityDetails.amount_raw,
                              // "tokenY_symbol":liquidityDetails.symbol,
                              "tokenY_address":liquidityDetails.token_address
                          }
                      }
                  })
              }
          })
          removedLiquidityDetails.push(eachRemovedTxn);
      });
  }
  console.log(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
      });
      console.log("Current Txn length:", transactions.length);
      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);
      });
  }
  console.log(removedLiquidityDetails);
}

async function getPositionLiquidityWithdraws(ownerAddress) {
  //getting all positions for the user and the lbPair address
  const operationsDoc = `
      query MyQuery {
        meteora_dlmm_PositionV2(
          where: {owner: {_eq: ${JSON.stringify(ownerAddress)}}}
        ) {
          upperBinId
          lowerBinId
          totalClaimedFeeYAmount
          totalClaimedFeeXAmount
          lbPair
          owner
          pubkey
        }
        meteora_dlmm_Position(
          where: {owner: {_eq: ${JSON.stringify(ownerAddress)}}}
        ) {
          lbPair
          lowerBinId
          upperBinId
          totalClaimedFeeYAmount
          totalClaimedFeeXAmount
          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();

    //adding a delay of 2 seconds to avoid rate limiting, only for free API Keys.
    await new Promise((resolve) => setTimeout(resolve, 2000));

    if (data.meteora_dlmm_Position.length > 0) {
      for (let index = 0; index < data.meteora_dlmm_Position.length; index++) {
        const position = data.meteora_dlmm_Position[index];

        //get all Lb pair details for the position
        const LbPairDetails = await getLbPairDetails(position.lbPair);
        // getting deposit values from transactions
        await getUserWithdrawsByPositionV1(position.pubkey, LbPairDetails.tokenX, LbPairDetails.tokenY)


      }
    }

    //adding a delay of 2 seconds to avoid rate limiting, only for free API Keys.
    await new Promise((resolve) => setTimeout(resolve, 2000));

    if (data.meteora_dlmm_PositionV2.length > 0) {
      for (let index = 0; index < data.meteora_dlmm_PositionV2.length; index++) {
        const position = data.meteora_dlmm_PositionV2[index];

        //get all Lb pair details for the positionV2
        const LbPairDetails = await getLbPairDetails(position.lbPair);
          // getting deposit values from transactions
        await getUserWithdrawsByPositionV2(position.owner, position.pubkey, position.lbPair, LbPairDetails.tokenX, LbPairDetails.tokenY)
      }
    }
  }
  getPositionLiquidityWithdraws("Hox8Ueuu8jb4pRuQfKTGxGfyiYetzAo7BMMzkDTJs917")
```

{% endcode %}
{% endtab %}

{% tab title="Response" %}

```json
[
  {
    "txn_id": "DzV1iioFdF65GTCog78AsJB4TWiQ9oSMMNoZm1KrES2iva24n9f5vY9vWd3VYAozX4dKMu2jHTUJRLZfvy3MAKw",
    "onchain_timestamp": "2023-12-24T02:46:00.000Z",
    "tokenX_amount": 248114633,
    "tokenX_address": "27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4",
    "tokenY_amount": 248114633,
    "tokenY_address": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
  }
]//sample response
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.shyft.to/solana-indexers/case-studies/meteora/get-all-withdraws-for-a-user.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
