Get All User Positions and Deposits for a Pool
Fetch all user positions for a pool for Meteora DLMM and their deposit amounts
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
lastUpdatedAt
}
}
`; //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 getUserDepositsByPositionV1(positionAddress, tokenX, tokenY) {
let addLiquidityFound = false;
let genesisTxnReached = false;
let addLiquidity = [];
let lastSignature = undefined;
while (!addLiquidityFound || !genesisTxnReached) {
const transactions = await shyft.transaction.history({
account: positionAddress,
network: Network.Mainnet,
txNum: 10,
beforeTxSignature: lastSignature,
});
transactions.map((txn) => {
if (txn.type === "ADD_LIQUIDITY") addLiquidity.push(txn);
addLiquidityFound = true;
});
if (transactions.length < 10) {
genesisTxnReached = true;
break;
}
lastSignature = transactions[transactions.length - 1].signatures[0];
}
const amountAddedDetails = [];
addLiquidity.map((addLiquidityTxn) => {
addLiquidityTxn.actions.map((action) => {
let eachAddedTxn = {
txn_id: addLiquidityTxn.signatures[0],
onchain_timestamp: addLiquidityTxn.timestamp,
};
if (action.type === "ADD_LIQUIDITY") {
action.info.liquidity_added.map((liquidityDetails) => {
if (liquidityDetails.token_address === tokenX) {
eachAddedTxn = {
...eachAddedTxn,
tokenX_amount: liquidityDetails.amount_raw,
tokenX_address: liquidityDetails.token_address,
};
}
if (liquidityDetails.token_address === tokenY) {
eachAddedTxn = {
...eachAddedTxn,
tokenY_amount: liquidityDetails.amount_raw,
tokenY_address: liquidityDetails.token_address,
};
}
});
if (eachAddedTxn.tokenX_amount && eachAddedTxn.tokenY_amount)
amountAddedDetails.push(eachAddedTxn);
}
});
});
return amountAddedDetails;
}
async function getUserDepositsByPositionV2(
ownerAddress,
positionAddress,
lbPair,
tokenX,
tokenY,
) {
let genesisTxnReached = false;
let tokenTransferTxns = [];
let oneSideTokenTransferTxns = [];
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 === ownerAddress &&
action.info.receiver === lbPair
) {
tokenTransferTxns.push(txn);
}
});
}
if(txn.type === "ADDLIQUIDITYBYSTRATEGYONESIDE") {
oneSideTokenTransferTxns.push(txn)
};
if (txn.type === "INITIALIZEPOSITION") tokenTransferTxns.push(txn);
// addLiquidity = txn;
});
if (transactions.length < 10) {
genesisTxnReached = true;
break;
}
lastSignature = transactions[transactions.length - 1].signatures[0];
}
const addedLiquidityDetails = [];
if (tokenTransferTxns.length > 0) {
tokenTransferTxns.forEach((tokenTransferTxn) => {
let eachAddedTxn = {
txn_id: tokenTransferTxn.signatures[0],
onchain_timestamp: tokenTransferTxn.timestamp,
};
tokenTransferTxn.actions.map((action) => {
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)
addedLiquidityDetails.push(eachAddedTxn);
});
}
if (oneSideTokenTransferTxns.length > 0) {
oneSideTokenTransferTxns.forEach((oneSideTokenTransferTxn) => {
let eachAddedTxn = {
txn_id: oneSideTokenTransferTxn.signatures[0],
onchain_timestamp: oneSideTokenTransferTxn.timestamp,
};
oneSideTokenTransferTxn.actions.map((action) => {
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,
tokenY_amount: 0,
tokenY_address: null,
};
}
if (action.info.token_address === tokenY) {
eachAddedTxn = {
...eachAddedTxn,
tokenY_amount: action.info.amount_raw,
tokenY_address: action.info.token_address,
tokenX_amount: 0,
tokenX_address: null,
};
}
}
});
addedLiquidityDetails.push(eachAddedTxn);
});
}
return addedLiquidityDetails;
}
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;
const positions = await getPositionsByPool(poolAddress);
for (let i = 0; i < positions.positionsV1.length; i++) {
const currentPositionV1 = positions.positionsV1[i];
const liquidityDetails = await getUserDepositsByPositionV1(
currentPositionV1.pubkey,
tokenMintX,
tokenMintY,
);
allPoolPositionDetailsV1.push({
owner: currentPositionV1.owner,
positionAddress: currentPositionV1.pubkey,
poolAddress: poolAddress,
liquidityAddedDetails: liquidityDetails,
});
}
for (let i = 0; i < positions.positionsV2.length; i++) {
const currentPositionV2 = positions.positionsV2[i];
const liquidityDetails = await getUserDepositsByPositionV2(
currentPositionV2.owner,
currentPositionV2.pubkey,
poolAddress,
tokenMintX,
tokenMintY,
);
allPoolPositionDetails.push({
owner: currentPositionV2.owner,
positionAddress: currentPositionV2.pubkey,
poolAddress: poolAddress,
liquidityAddedDetails: liquidityDetails,
});
}
console.dir({
poolAddress: poolAddress,
tokenXMint: tokenMintX,
tokenYMint: tokenMintY,
allPoolPositionV1Details: allPoolPositionDetailsV1,
allPoolPositionV2Details: allPoolPositionDetails
},{depth:null})
}
getUserPoolDetails("FFpF3BNiBvtewyACdxvvedLDdbZ3einkkpJ7NnknpeqU");
//enter your pool addressLast updated