Get All Fees Claimed by a User

Fetch all Fees claimed in Meteora DLMM for a user

Along with percentage of ownership, positions also determine the rewards and fees earned by the liquidity providers for their participation. We can also find out the fees claimed by the liquidity provider. This again involves two simple steps:

  1. We fetch all the position address for the liquidity provider (or the user)

  2. Once we have the position address, we can fetch all transactions for each position address, and look for transactions of the 'CLAIMFEE' type. The actions array in each of these parsed (by SHYFT) 'CLAIMFEE' transactions will contain the details of the fees claimed.

You can directly copy paste this code on replit and see it in action.

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 getClaimfeeDetails(positionAddress: string) {

    let genesisTxnReached = false;
    let claimFeeTxns:any[] = [];
    let lastSignature = undefined;

    while (!genesisTxnReached) {
        const transactions:any = await shyft.transaction.history({
            account: positionAddress,
            network: Network.Mainnet,
            txNum: 10,
            beforeTxSignature: lastSignature
        });
        transactions.map((txn:any) => {
            if(txn.type === "CLAIMFEE")
                claimFeeTxns.push(txn);
        });

        if(transactions.length < 10){
            genesisTxnReached = true;
            break;
        }
        lastSignature = transactions[transactions.length - 1].signatures[0];
    }
    const amountClaimedDetails:any = [];
    claimFeeTxns.map((claimFeeTxn) => {
        const tokenX = claimFeeTxn.actions[0].info.tokenXMint;
        const tokenY = claimFeeTxn.actions[0].info.tokenYMint;

        let eachAddedTxn:any = {
            "txn_id":claimFeeTxn.signatures[0],
            "onchain_timestamp": claimFeeTxn.timestamp,
        };
        claimFeeTxn.actions.map((action:any) => {
            
            if(action.type === "TOKEN_TRANSFER"){
                if(action.info.token_address === tokenX){
                    eachAddedTxn = {
                        ...eachAddedTxn,
                        "tokenX_amount":action.info.amount_raw,
                        "tokenX_address":action.info.token_address
                    }
                }
                if(action.info.token_address === tokenY){
                    eachAddedTxn = {
                        ...eachAddedTxn,
                        "tokenY_amount":action.info.amount_raw,
                        "tokenY_address":action.info.token_address
                    }
                }
                if(eachAddedTxn.tokenX_amount && eachAddedTxn.tokenY_amount)
                    amountClaimedDetails.push(eachAddedTxn);
            }
        })
    })
    console.log(amountClaimedDetails);

}
// getClaimfeeDetails("CFUjqVgyzNfW88FxR3npGBNoPsyceec8CU3778rJ4F8b")


async function getPositionLiquidityDetails(ownerAddress:string) {
	//querying both position and positionV2 for the owner, or user wallet
    const operationsDoc = `
        query MyQuery {
          meteora_dlmm_PositionV2(
            where: {owner: {_eq: ${JSON.stringify(ownerAddress)}}}
          ) {
                lastUpdatedAt
                lbPair
                owner
                pubkey
            }
          meteora_dlmm_Position(
            where: {owner: {_eq: ${JSON.stringify(ownerAddress)}}}
          ) {
                lastUpdatedAt
                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();
    
      //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 fee claims for each position
          await getClaimfeeDetails(position.pubkey)
        }
      }
    
      //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 fee claims for each positionV2
          await getClaimfeeDetails(position.pubkey)
        }
     }
}

getPositionLiquidityDetails("5sJKcYqCWNPJ25PriinfeH7PbFsHxzQhe8kspg2UFexK")

The above function getClaimfeeDetails can also be used to fetch all claim rewards when only the position address in known.

Last updated