@parifi/sdk
Version:
Parifi SDK with common utility functions
1,662 lines (1,640 loc) • 81.9 kB
JavaScript
// src/pyth/pyth.ts
import axios from "axios";
// src/common/constants.ts
import { Decimal } from "decimal.js";
var PRECISION_MULTIPLIER = new Decimal("10000");
var DEVIATION_PRECISION_MULTIPLIER = new Decimal(10).pow(12);
var SECONDS_IN_A_YEAR = new Decimal(365 * 24 * 60 * 60);
var MAX_FEE = new Decimal(1e7);
var WAD = new Decimal(10).pow(18);
var EMPTY_BYTES32 = "0x0000000000000000000000000000000000000000000000000000000000000000";
var DECIMAL_10 = new Decimal(10);
var DECIMAL_ZERO = new Decimal(0);
var DEFAULT_BATCH_COUNT = 10;
var BIGINT_ZERO = BigInt(0);
var GAS_LIMIT_SETTLEMENT = 1e7;
var GAS_LIMIT_LIQUIDATION = 15e6;
var ONE_GWEI = 1e9;
var DEFAULT_GAS_PRICE = 2 * ONE_GWEI;
var PYTH_ETH_USD_PRICE_ID_BETA = "0xca80ba6dc32e08d06f1aa886011eed1d77c77be9eb761cc10d72b7d0a2fd57a6";
var PYTH_ETH_USD_PRICE_ID_STABLE = "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace";
var PYTH_USDC_USD_PRICE_ID_BETA = "0x41f3625971ca2ed2263e78573fe5ce23e13d2558ed3f2e47ab0f84fb9e7ae722";
var PYTH_USDC_USD_PRICE_ID_STABLE = "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a";
var FACTORY_ADDRESS_SIMPLE_ACCOUNT = "0x91E60e0613810449d098b0b5Ec8b51A0FE8c8985";
var SUBGRAPH_HELPER_ADDRESS = "0xf012d32505df6853187170F00C7b789A8ecC41c2";
var SYMBOL_TO_PYTH_FEED = /* @__PURE__ */ new Map([
// market
["BTC", "0xc9d8b075a5c69303365ae23633d4e085199bf5c520a3b90fed1322a0342ffc33"],
["SOL", "0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d"],
["WIF", "0x4ca4beeca86f0d164160323817a4e42b10010a724c2217c6ee41b54cd4cc61fc"],
["ETH", "0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace"],
["AAVE", "0x2b9ab1e972a281585084148ba1389800799bd4be63b957507db1349314e47445"],
["ADA", "0x2a01deaec9e51a579277b34b122399984d0bbf57e2458a7e42fecd2829867a0d"],
["ARB", "0x3fa4252848f9f0a1480be62745a4629d9eb1322aebab8a791e344b3b9c1adcf5"],
["AVAX", "0x93da3352f9f1d105fdfe4971cfa80e9dd777bfc5d0f683ebb6e1294b92137bb7"],
["BCH", "0x3dd2b63686a450ec7290df3a1e0b583c0481f651351edfa7636f39aed55cf8a3"],
["BNB", "0x2f95862b045670cd22bee3114c39763a4a08beeb663b145d283c31d7d1101c4f"],
["CRV", "0xa19d04ac696c7a6616d291c7e5d1377cc8be437c327b75adb5dc1bad745fcae8"],
["DOGE", "0xdcef50dd0a4cd2dcc17e45df1676dcb336a11a61c69df7a0299b0150c672d25c"],
["DYDX", "0x6489800bb8974169adfe35937bf6736507097d13c190d760c557108c7e93a81b"],
["GMX", "0xb962539d0fcb272a494d65ea56f94851c2bcf8823935da05bd628916e2e9edbf"],
["LINK", "0x8ac0c70fff57e9aefdf5edf44b51d62c2d433653cbb2cf5cc06bb115af04d221"],
["LTC", "0x6e3f3fa8253588df9326580180233eb791e03b443a3ba7a1d892e73874e19a54"],
["MKR", "0x9375299e31c0deb9c6bc378e6329aab44cb48ec655552a70d4b9050346a30378"],
["NEAR", "0xc415de8d2eba7db216527dff4b60e8f3a5311c740dadb233e13e12547e226750"],
["OP", "0x385f64d993f7b77d8182ed5003d97c60aa3361f3cecfe711544d2d59165e9bdf"],
["ORDI", "0x193c739db502aadcef37c2589738b1e37bdb257d58cf1ab3c7ebc8e6df4e3ec0"],
["PEPE", "0xd69731a2e74ac1ce884fc3890f7ee324b6deb66147055249568869ed700882e4"],
["POL", "0xffd11c5a1cfd42f80afb2df4d9f264c15f956d68153335374ec10722edd70472"],
["PYTH", "0x0bbf28e9a841a1cc788f6a361b17ca072d0ea3098a1e5df1c3922d06719579ff"],
["RUNE", "0x5fcf71143bb70d41af4fa9aa1287e2efd3c5911cee59f909f915c9f61baacb1e"],
["SHIB", "0xf0d57deca57b3da2fe63a493f4c25925fdfd8edf834b20f93e1f84dbd1504d4a"],
["STX", "0xec7a775f46379b5e943c3526b1c8d54cd49749176b0b98e02dde68d1bd335c17"],
["TIA", "0x09f7c1d7dfbb7df2b8fe3d3d87ee94a2259d212da4f30c1f0540d066dfa44723"],
["UNI", "0x78d185a741d07edb3412b09008b7c5cfb9bbbd7d568bf00ba737b456ba171501"],
["XLM", "0xb7a8eba68a997cd0210c2e1e4ee811ad2d174b3611c22d9ebf16f4cb7e9ba850"],
["XRP", "0xec5d399846a9209f3fe5881d70aae9268c94339ff9817e8d18ff19fa05eea1c8"],
// collateral
["USDC", "0xeaa020c61cc479712813461ce153894a96a6c00b21ed0cfc2798d1f9a9e9c94a"],
["USDE", "0x6ec879b1e9963de5ee97e9c8710b742d6228252a5e2ca12d4ae81d7fe5ee8c5d"],
["DAI", "0xb0948a5e5313200c632b51bb5ca32f6de0d36e9950a942d19751e833f70dabfd"]
]);
var collateralMappingWithRegularSymbol = /* @__PURE__ */ new Map([
["seth", "eth"],
["wbtc", "btc"],
["fbtc", "btc"],
["wsteth", "eth"],
["fdai", "dai"],
["susdc", "usdc"],
["susde", "usde"],
["steth", "eth"],
["fsol", "sol"],
["fusdc", "usdc"],
["fusdt", "usdt"],
["ssol", "sol"],
["sdai", "dai"],
["usdx", "usdc"],
["stbtc", "btc"]
]);
var SUPPORTED_CHAINS = /* @__PURE__ */ ((SUPPORTED_CHAINS2) => {
SUPPORTED_CHAINS2[SUPPORTED_CHAINS2["BASE"] = 8453] = "BASE";
return SUPPORTED_CHAINS2;
})(SUPPORTED_CHAINS || {});
var REWARD_DISTRIBUTOR_ADDRESSES = {
[8453 /* BASE */]: {
esprf: "0x6511718804180CC57833fEA036389A24604Dfc69",
prf: "0x0000000000000000000000000000000000000000",
rt: "0x648d6D711860699A11aBa192E9daBAfb6408af18"
}
};
var REWARD_DISTRIBUTOR_ABI = [
{
inputs: [{ internalType: "contract IERC20", name: "_rewardToken", type: "address" }],
stateMutability: "nonpayable",
type: "constructor"
},
{ inputs: [], name: "AccessControlBadConfirmation", type: "error" },
{
inputs: [
{ internalType: "address", name: "account", type: "address" },
{ internalType: "bytes32", name: "neededRole", type: "bytes32" }
],
name: "AccessControlUnauthorizedAccount",
type: "error"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "address", name: "user", type: "address" },
{ indexed: false, internalType: "uint256", name: "amount", type: "uint256" }
],
name: "RewardClaimed",
type: "event"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "bytes32", name: "role", type: "bytes32" },
{ indexed: true, internalType: "bytes32", name: "previousAdminRole", type: "bytes32" },
{ indexed: true, internalType: "bytes32", name: "newAdminRole", type: "bytes32" }
],
name: "RoleAdminChanged",
type: "event"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "bytes32", name: "role", type: "bytes32" },
{ indexed: true, internalType: "address", name: "account", type: "address" },
{ indexed: true, internalType: "address", name: "sender", type: "address" }
],
name: "RoleGranted",
type: "event"
},
{
anonymous: false,
inputs: [
{ indexed: true, internalType: "bytes32", name: "role", type: "bytes32" },
{ indexed: true, internalType: "address", name: "account", type: "address" },
{ indexed: true, internalType: "address", name: "sender", type: "address" }
],
name: "RoleRevoked",
type: "event"
},
{
inputs: [],
name: "DEFAULT_ADMIN_ROLE",
outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
stateMutability: "view",
type: "function"
},
{
inputs: [],
name: "actualRound",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ internalType: "uint256", name: "_round", type: "uint256" },
{ internalType: "uint256", name: "amount", type: "uint256" },
{ internalType: "bytes32[]", name: "proof", type: "bytes32[]" }
],
name: "claimReward",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "uint256[]", name: "_rounds", type: "uint256[]" },
{ internalType: "uint256[]", name: "amounts", type: "uint256[]" },
{ internalType: "bytes32[][]", name: "proofs", type: "bytes32[][]" }
],
name: "claimRewards",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "uint256", name: "", type: "uint256" },
{ internalType: "address", name: "", type: "address" }
],
name: "claimed",
outputs: [{ internalType: "uint256", name: "", type: "uint256" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "bytes32", name: "role", type: "bytes32" }],
name: "getRoleAdmin",
outputs: [{ internalType: "bytes32", name: "", type: "bytes32" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "account", type: "address" }
],
name: "grantRole",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "account", type: "address" }
],
name: "hasRole",
outputs: [{ internalType: "bool", name: "", type: "bool" }],
stateMutability: "view",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "callerConfirmation", type: "address" }
],
name: "renounceRole",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "bytes32", name: "role", type: "bytes32" },
{ internalType: "address", name: "account", type: "address" }
],
name: "revokeRole",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [],
name: "rewardToken",
outputs: [{ internalType: "contract IERC20", name: "", type: "address" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "uint256", name: "_round", type: "uint256" }],
name: "setActualRound",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [
{ internalType: "uint256", name: "_round", type: "uint256" },
{ internalType: "bytes32", name: "_root", type: "bytes32" }
],
name: "setRootPerRound",
outputs: [],
stateMutability: "nonpayable",
type: "function"
},
{
inputs: [{ internalType: "bytes4", name: "interfaceId", type: "bytes4" }],
name: "supportsInterface",
outputs: [{ internalType: "bool", name: "", type: "bool" }],
stateMutability: "view",
type: "function"
},
{
inputs: [{ internalType: "uint256", name: "", type: "uint256" }],
name: "verifiersPerRound",
outputs: [{ internalType: "contract Verifier", name: "", type: "address" }],
stateMutability: "view",
type: "function"
}
];
// src/common/helpers.ts
import { formatEther, parseEther } from "viem";
var getDiff = (a, b) => {
return a.gt(b) ? a.minus(b) : b.minus(a);
};
var addDelay = async (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
var getCurrentTimestampInSeconds = () => {
return Math.floor(Date.now() / 1e3);
};
var getUniqueValuesFromArray = (originalArray) => {
const uniqueArray = [];
const seenValues = /* @__PURE__ */ new Set();
originalArray.forEach((item) => {
if (!seenValues.has(item)) {
uniqueArray.push(item);
seenValues.add(item);
}
});
return uniqueArray;
};
function convertWeiToEther(amountInWei) {
if (amountInWei == void 0) {
throw new Error("Invalid amount received during conversion: undefined");
}
if (typeof amountInWei == "bigint") {
return Number(formatEther(amountInWei));
} else if (typeof amountInWei == "string") {
return Number(formatEther(BigInt(amountInWei)));
} else {
throw new Error("Expected string or bigint for conversion");
}
}
function convertEtherToWei(amount) {
if (amount == void 0) {
throw new Error("Invalid amount received during conversion: undefined");
}
if (typeof amount == "number") {
return parseEther(amount.toString());
} else if (typeof amount == "string") {
return parseEther(amount);
} else {
throw new Error("Expected string or bigint for conversion");
}
}
// src/pyth/pyth.ts
import Decimal2 from "decimal.js";
// src/pyth/pythMapper.ts
var mapPythPriceResponseToInterface = (response) => {
return response.map((item) => ({
id: item.id || "",
price: {
price: item.price.price || "0",
conf: item.price.conf || "0",
expo: item.price.expo || 0,
publish_time: item.price.publish_time || 0
},
ema_price: {
price: item.ema_price.price || "0",
conf: item.ema_price.conf || "0",
expo: item.ema_price.expo || 0,
publish_time: item.ema_price.publish_time || 0
}
}));
};
// src/pyth/pyth.ts
var getPythClient = async (pythServiceEndpoint, pythServiceUsername, pythServicePassword, isStable = true) => {
try {
const config = {
baseURL: pythServiceEndpoint || (isStable ? "https://hermes.pyth.network" : "https://hermes-beta.pyth.network"),
auth: pythServiceUsername && pythServicePassword ? {
username: pythServiceUsername,
password: pythServicePassword
} : void 0
};
return axios.create(config);
} catch (error) {
console.log("Error when creating Pyth instance:", error);
throw error;
}
};
var getVaaPriceUpdateData = async (priceIds, pythClient) => {
const uniquePriceIds = getUniqueValuesFromArray(priceIds);
let priceUpdateData = [];
if (pythClient) {
try {
const response = await pythClient.get("/api/latest_vaas", {
params: {
ids: uniquePriceIds
}
});
priceUpdateData = response.data;
} catch (error) {
console.log("Error fetching data from Pyth", error);
throw error;
}
}
return priceUpdateData.map((vaa) => "0x" + Buffer.from(vaa, "base64").toString("hex"));
};
var formatPythPrice = (pythPrice, pythExponent) => {
const adjustedFactor = new Decimal2(10).pow(pythExponent);
return new Decimal2(pythPrice).mul(adjustedFactor);
};
var getLatestFormattedPrice = async (priceIds, pythClient) => {
let formattedPrices = [];
const priceData = await getLatestPricesFromPyth(priceIds, pythClient);
priceData.map((pythPrice) => {
const formattedPrice = formatPythPrice(Number(pythPrice.price.price), pythPrice.price.expo);
formattedPrices.push({
priceId: `0x${pythPrice.id}`,
formattedPrice
});
});
return formattedPrices;
};
var getLatestPricesFromPyth = async (priceIds, pythClient) => {
const uniquePriceIds = getUniqueValuesFromArray(priceIds);
const pythPriceResponses = [];
if (pythClient) {
try {
const response = await pythClient.get("/api/latest_price_feeds", {
params: {
ids: uniquePriceIds,
verbose: false,
binary: false
}
});
return mapPythPriceResponseToInterface(response.data);
} catch (error) {
console.log("Error fetching latest prices from Pyth", error);
throw error;
}
}
return pythPriceResponses;
};
// src/pyth/index.ts
var Pyth = class {
constructor(pythConfig) {
this.pythConfig = pythConfig;
this.pythClient = {};
}
async initPyth() {
this.pythClient = await getPythClient(
this.pythConfig.pythEndpoint,
this.pythConfig.username,
this.pythConfig.password,
this.pythConfig.isStable
);
}
async getVaaPriceUpdateData(priceIds) {
return await getVaaPriceUpdateData(priceIds, this.pythClient);
}
formatPythPrice(pythPrice, pythExponent) {
return formatPythPrice(pythPrice, pythExponent);
}
async getLatestPricesFromPyth(priceIds) {
return await getLatestPricesFromPyth(priceIds, this.pythClient);
}
async getLatestFormattedPrice(priceIds) {
return await getLatestFormattedPrice(priceIds, this.pythClient);
}
};
// src/subgraph/positions/index.ts
import { request } from "graphql-request";
// src/subgraph/positions/subgraphQueries.ts
import { gql } from "graphql-request";
var fetchPositionsByUserQuery = (userAddress, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: { owner: "${userAddress}", type: PERP }) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: {status_in: [OPEN, CLOSED, LIQUIDATED]}) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchPositionsByUserQueryAndStatus = (userAddress, status, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: { owner: "${userAddress}", type: PERP }
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: {status: ${status} }) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchOpenPositionsByUser = (userAddress, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: {
owner: "${userAddress}",
type: PERP,
openPositionCount_gt: 0
}
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: {status: OPEN }) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchUserPositionHistory = (userAddress, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: { owner: "${userAddress}", type: PERP }
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: {status_in: [CLOSED, LIQUIDATED]}) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchPositionByIdQuery = (positionId) => gql`
{
position(
id: "${positionId}"
) {
id
market {
id,
marketName,
marketSymbol,
feedId
}
snxAccount{
id
accountId
}
isLong
positionSize
avgPrice
avgPriceDec
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}`;
var fetchUserPositionHistoryWithTime = (userAddress, startTimestamp, endTimestamp, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: {
owner: "${userAddress}",
type: PERP
}
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions( where: {
status_in: [CLOSED, LIQUIDATED],
createdTimestamp_gte: ${startTimestamp}
createdTimestamp_lte: ${endTimestamp}
}) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
positionCollateral
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchUserOpenPositionsWithTime = (userAddress, startTimestamp, endTimestamp, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: {
owner: "${userAddress}",
type: PERP,
positions_: {
status: OPEN,
createdTimestamp_gte: ${startTimestamp}
createdTimestamp_lte: ${endTimestamp}
}
}
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchLiquidatedPositionsBySnxAccount = (snxAccountId, lastRefresh) => gql`
{
snxAccount(id: "${snxAccountId}"
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: { status: LIQUIDATED, lastRefresh_gt: ${lastRefresh} }) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchAllOpenPositionsWithTime = (startTimestamp, endTimestamp, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: {
type: PERP
openPositionCount_gt:0
}
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: {
status: OPEN,
createdTimestamp_gte: ${startTimestamp}
createdTimestamp_lte: ${endTimestamp}
})
{
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
var fetchAllPositionHistoryWithTime = (startTimestamp, endTimestamp, count = 20, skip = 0) => gql`
{
snxAccounts(
first: ${count}
skip: ${skip}
where: {
type: PERP
totalPositionsCount_gt :0
}
) {
id
accountId
owner {
id
}
collateralDeposits {
id
collateralName
collateralSymbol
collateralDecimals
collateralAddress
currentDepositedAmount
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
}
positions(where: {
status_in: [CLOSED, LIQUIDATED],
createdTimestamp_gte: ${startTimestamp}
createdTimestamp_lte: ${endTimestamp}
}) {
id
market {
id
marketName
marketSymbol
feedId
}
positionSize
avgPrice
avgPriceDec
isLong
createdTimestamp
status
txHash
liquidationTxHash
closingPrice
realizedPositionPnl
realizedPnlAfterFees
totalFeesPaid
createdTimestamp
lastRefresh
lastRefreshISO
canBeLiquidated
snapshotCollateralValueUsd
}
}
}`;
// src/error/not-found.error.ts
var NotFoundError = class extends Error {
constructor(message) {
super(message);
this.name = this.constructor.name;
}
};
// src/common/subgraphMapper.ts
var mapResponseToWallet = (response) => {
if (!response) return void 0;
try {
return {
id: response?.id
// snxAccounts: mapSnxAccountsArray(response.snxAccounts)
};
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToSnxAccount = (response) => {
if (!response) return void 0;
try {
return {
id: response?.id,
type: response?.type,
accountId: response?.accountId,
owner: response?.owner ?? mapResponseToWallet(response?.owner),
totalOrdersCount: response?.totalOrdersCount,
totalPositionsCount: response?.totalPositionsCount,
openPositionCount: response?.openPositionCount,
countProfitablePositions: response?.countProfitablePositions,
countLossPositions: response?.countLossPositions,
countLiquidatedPositions: response?.countLiquidatedPositions,
realizedPnlFromPositions: response?.realizedPnlFromPositions,
totalFeesPaid: response?.totalFeesPaid,
finalPnlAfterFees: response?.finalPnlAfterFees,
totalVolumeInUsd: response?.totalVolumeInUsd,
totalAccruedBorrowingFeesInUsd: response?.totalAccruedBorrowingFeesInUsd,
integratorFeesGenerated: response?.integratorFeesGenerated,
orders: response?.orders ? mapResponseToOrderArray(response?.orders) : [],
positions: response?.positions ? mapResponseToPositionArray(response?.positions) : [],
collateralDeposits: response?.collateralDeposits ? mapResponseToCollateralDepositArray(response?.collateralDeposits) : []
};
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToSnxAccountArray = (response) => {
if (!response) return void 0;
try {
return response.map((snxAccount) => {
return mapResponseToSnxAccount(snxAccount);
});
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToMarket = (response) => {
if (!response) return void 0;
if (response?.marketName === "" || response?.marketSymbol === "") return void 0;
try {
return {
id: response?.id ?? "",
marketName: response?.marketName ?? "",
marketSymbol: response?.marketSymbol ?? "",
feedId: response?.feedId ?? "",
skew: response?.skew ?? "0",
size: response?.size ?? "0",
maxOpenInterest: response?.maxOpenInterest ?? "0",
interestRate: response?.interestRate ?? "0",
currentFundingRate: response?.currentFundingRate ?? "0",
currentFundingVelocity: response?.currentFundingVelocity ?? "0",
indexPrice: response?.indexPrice ?? "0",
skewScale: response?.skewScale ?? "0",
maxFundingVelocity: response?.maxFundingVelocity ?? "0",
makerFee: response?.makerFee ?? "0",
takerFee: response?.takerFee ?? "0",
maxMarketValue: response?.maxMarketValue ?? "0",
maxMarketSize: response?.maxMarketSize ?? "0",
marketPrice: response?.marketPrice ?? "0",
initialMarginRatioD18: response?.initialMarginRatioD18 ?? "0",
maintenanceMarginRatioD18: response?.maintenanceMarginRatioD18 ?? "0",
minimumInitialMarginRatioD18: response?.minimumInitialMarginRatioD18 ?? "0",
flagRewardRatioD18: response?.flagRewardRatioD18 ?? "0",
minimumPositionMargin: response?.minimumPositionMargin ?? "0",
openInterestUsd: response?.openInterestUsd ?? "0"
};
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToMarketArray = (response) => {
if (!response) return void 0;
try {
return response.map((market) => {
return mapResponseToMarket(market);
});
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToOrder = (response) => {
if (!response) return void 0;
try {
return {
id: response?.id,
market: response?.market ?? mapResponseToMarket(response?.market),
snxAccountId: response?.snxAccount?.id,
isLimitOrder: response?.isLimitOrder,
acceptablePrice: response?.acceptablePrice,
commitmentTime: response?.commitmentTime,
expectedPriceTime: response?.expectedPriceTime,
settlementTime: response?.settlementTime,
expirationTime: response?.expirationTime,
trackingCode: response?.trackingCode,
deltaSize: response?.deltaSize,
deltaSizeUsd: response?.deltaSizeUsd,
executionPrice: response?.executionPrice,
collectedFees: response?.collectedFees,
settlementReward: response?.settlementReward,
referralFees: response?.referralFees,
partnerAddress: response?.partnerAddress,
txHash: response?.txHash,
createdTimestamp: response?.createdTimestamp,
status: response?.status,
settledTxHash: response?.settledTxHash,
cancellationTxHash: response?.cancellationTxHash,
settledTimestamp: response?.settledTimestamp,
settledTimestampISO: response?.settledTimestampISO,
settledBy: response?.settledBy ?? mapResponseToWallet(response?.settledBy),
snapshotCollateralValueUsd: response?.snapshotCollateralValueUsd
};
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToOrderArray = (response) => {
if (!response) return void 0;
try {
return response.map((order) => {
return mapResponseToOrder(order);
});
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
function mapResponseToCollateralDeposit(response) {
if (!response) return void 0;
try {
return {
id: response?.id,
snxAccountId: response?.snxAccountId,
collateralId: response?.collateralId,
collateralName: response?.collateralName,
collateralSymbol: response?.collateralSymbol,
collateralDecimals: response?.collateralDecimals,
collateralAddress: response?.collateralAddress,
currentDepositedAmount: response?.currentDepositedAmount,
totalAmountDeposited: response?.totalAmountDeposited,
totalAmountWithdrawn: response?.totalAmountWithdrawn,
totalAmountLiquidated: response?.totalAmountLiquidated
};
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
}
var mapResponseToCollateralDepositArray = (response) => {
if (!response) return void 0;
try {
return response.map((deposit) => {
return mapResponseToCollateralDeposit(deposit);
});
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToPosition = (response) => {
if (!response) return void 0;
try {
return {
id: response?.id,
market: response?.market ?? mapResponseToMarket(response?.market),
snxAccountId: response?.snxAccountId,
isLong: response?.isLong,
positionSize: response?.positionSize,
avgPrice: response?.avgPrice,
avgPriceDec: response?.avgPriceDec,
status: response?.status,
txHash: response?.txHash,
liquidationTxHash: response?.liquidationTxHash,
closingPrice: response?.closingPrice,
realizedPositionPnl: response?.realizedPositionPnl,
totalFeesPaid: response?.totalFeesPaid,
realizedPnlAfterFees: response?.realizedPnlAfterFees,
createdTimestamp: response?.createdTimestamp,
lastRefresh: response?.lastRefresh,
lastRefreshISO: response?.lastRefreshISO,
accruedBorrowingFees: response?.accruedBorrowingFees,
canBeLiquidated: response?.canBeLiquidated,
snapshotCollateralValueUsd: response?.snapshotCollateralValueUsd
};
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
var mapResponseToPositionArray = (response) => {
if (!response) return void 0;
try {
return response.map((position) => {
return mapResponseToPosition(position);
});
} catch (error) {
console.log("Error while mapping data", error);
return void 0;
}
};
// src/subgraph/positions/index.ts
var getAllPositionsByUserAddress = async (subgraphEndpoint, userAddress, count = 10, skip = 0) => {
try {
const subgraphResponse = await request(subgraphEndpoint, fetchPositionsByUserQuery(userAddress, count, skip));
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getOpenPositionsByUserAddress = async (subgraphEndpoint, userAddress, count = 10, skip = 0) => {
try {
const subgraphResponse = await request(subgraphEndpoint, fetchOpenPositionsByUser(userAddress, count, skip));
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getClosedPositionsByUserAddress = async (subgraphEndpoint, userAddress, count = 10, skip = 0) => {
try {
const subgraphResponse = await request(
subgraphEndpoint,
fetchPositionsByUserQueryAndStatus(userAddress, "CLOSED", count, skip)
);
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getLiquidatedPositionsByUserAddress = async (subgraphEndpoint, userAddress, count = 10, skip = 0) => {
try {
const subgraphResponse = await request(
subgraphEndpoint,
fetchPositionsByUserQueryAndStatus(userAddress, "LIQUIDATED", count, skip)
);
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getPositionById = async (subgraphEndpoint, positionId) => {
try {
let subgraphResponse = await request(subgraphEndpoint, fetchPositionByIdQuery(positionId));
console.log("subgraph response:", subgraphResponse);
const position = mapResponseToPosition(subgraphResponse?.position);
if (position) return position;
throw new NotFoundError("Position id not found");
} catch (error) {
console.error("Error fetching position:", error);
throw new NotFoundError("Position id not found");
}
};
var getUserPositionsHistory = async (subgraphEndpoint, userAddress, count = 100, skip = 0) => {
try {
const subgraphResponse = await request(subgraphEndpoint, fetchUserPositionHistory(userAddress, count, skip));
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getUserPositionHistoryWithTime = async (subgraphEndpoint, userAddress, startTime, endTime, count = 100, skip = 0) => {
try {
const subgraphResponse = await request(
subgraphEndpoint,
fetchUserPositionHistoryWithTime(userAddress, startTime, endTime, count, skip)
);
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getUserOpenPositionsWithTime = async (subgraphEndpoint, userAddress, startTime, endTime, count = 10, skip = 0) => {
try {
const subgraphResponse = await request(
subgraphEndpoint,
fetchUserOpenPositionsWithTime(userAddress, startTime, endTime, count, skip)
);
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getUserLiquidatedPositionsBySnxAccount = async (subgraphEndpoint, snxAccountId, lastRefresh) => {
let formattedSnxAccountId = snxAccountId;
try {
if (!snxAccountId.includes("PERP")) {
formattedSnxAccountId = "PERP-".concat(snxAccountId);
}
const subgraphResponse = await request(
subgraphEndpoint,
fetchLiquidatedPositionsBySnxAccount(formattedSnxAccountId, lastRefresh)
);
const snxAccount = mapResponseToSnxAccount(subgraphResponse?.snxAccount);
return snxAccount;
} catch (error) {
console.error("Error fetching positions:", error);
return void 0;
}
};
var getAllOpenPositionsWithTime = async (subgraphEndpoint, startTime, endTime, count = 10, skip = 0) => {
try {
const subgraphResponse = await request(
subgraphEndpoint,
fetchAllOpenPositionsWithTime(startTime, endTime, count, skip)
);
console.log("subgraphresponse", subgraphResponse);
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
var getAllPositionHistoryWithTime = async (subgraphEndpoint, startTime, endTime, count = 100, skip = 0) => {
try {
const subgraphResponse = await request(
subgraphEndpoint,
fetchAllPositionHistoryWithTime(startTime, endTime, count, skip)
);
const snxAccounts = mapResponseToSnxAccountArray(subgraphResponse?.snxAccounts);
return snxAccounts ?? [];
} catch (error) {
console.error("Error fetching positions:", error);
return [];
}
};
// src/perps/positions.ts
import Decimal3 from "decimal.js";
var getProfitOrLossInUsd = (marketPrice, avgPrice, positionSize) => {
const profitOrLossPerToken = new Decimal3(marketPrice).minus(avgPrice);
return new Decimal3(positionSize).times(profitOrLossPerToken);
};
var calculateSizeFromCollateralAndLeverage = (collateralValueInUsd, leverage, marketPrice) => {
const sizeInUsd = new Decimal3(collateralValueInUsd).times(leverage);
return sizeInUsd.div(marketPrice);
};
var calculateCollateralFromSizeAndLeverage = (sizeInUsd, leverage, collateralPrice) => {
const collateralInUsd = new Decimal3(sizeInUsd).div(leverage);
return collateralInUsd.div(collateralPrice);
};
var calculateLeverageFromCollateralAndSize = (collateralValueInUsd, sizeInUsd) => {
return sizeInUsd / collateralValueInUsd;
};
// src/perps/offchain.ts
var calculateUnrealizedPnlForPositions = (positions, priceData) => {
let totalUnrealizedPnl = DECIMAL_ZERO;
positions.forEach((position) => {
const currentPrice = getPriceFromPriceArray(priceData, position.market?.feedId);
const unrealizedPnl = getProfitOrLossInUsd(
currentPrice,
convertWeiToEther(position.avgPrice),
convertWeiToEther(position.positionSize)
);
totalUnrealizedPnl = totalUnrealizedPnl.add(unrealizedPnl);
});
return totalUnrealizedPnl;
};
var calculateUsdValueOfCollateralDeposits = (collateralDeposits, priceData) => {
let totalCollateralValueInUsd = DECIMAL_ZERO;
collateralDeposits.forEach((deposit) => {
const price = getPriceFromPriceArray(priceData, void 0, deposit.collateralSymbol);
const usdValue = convertWeiToEther(deposit.currentDepositedAmount) * price;
totalCollateralValueInUsd = totalCollateralValueInUsd.add(usdValue);
});
return totalCollateralValueInUsd;
};
var getPriceFromPriceArray = (priceData, priceId, tokenSymbol) => {
if (!priceId && !tokenSymbol) return 0;
if (!priceId) {
const formattedSymbol = collateralMappingWithRegularSymbol.get(tokenSymbol?.toLowerCase() || "") || tokenSymbol?.toLowerCase();
priceId = SYMBOL_TO_PYTH_FEED.get(formattedSymbol?.toUpperCase() || "");
}
const price = priceId ? priceData.find((p) => p.id === priceId.slice(2))?.price || 0 : 0;
console.log("price: ", priceId, price);
return price;
};
var calculateLiquidationPriceOffchain = ({
availableMarginInUsd,
marginBufferInUsd,
formattedPositionSize,
formattedMarketPrice
}) => {
if (formattedPositionSize == 0) return formattedMarketPrice;
if (availableMarginInUsd == 0) return 0;
const lossPerToken = Math.abs((marginBufferInUsd - availableMarginInUsd) / formattedPositionSize);
let liquidationPrice;
if (formattedPositionSize > 0) {
liquidationPrice = formattedMarketPrice - lossPerToken;
} else {
liquidationPrice = formattedMarketPrice + lossPerToken;
}
return liquidationPrice;
};
// src/subgraph/portfolio/index.ts
var getPortfolioStats = async (subgraphEndpoint, userAddress, priceData) => {
const snxAccountPositionData = await getAllPositionsByUserAddress(subgraphEndpoint, userAddress, 100);
let collateralDeposits = [];
let positionsArray = [];
let realizedPnl = DECIMAL_ZERO;
snxAccountPositionData.forEach((snxAccount) => {
if (snxAccount.collateralDeposits) {
collateralDeposits = collateralDeposits.concat(snxAccount.collateralDeposits);
}
if (snxAccount.positions) {
positionsArray = positionsArray.concat(snxAccount.positions);
}
});
const { openPositions, otherPositions } = splitPositionsByStatus(positionsArray);
const unrealizedPnl = calculateUnrealizedPnlForPositions(openPositions, priceData);
const collateralValueInUsd = calculateUsdValueOfCollateralDeposits(collateralDeposits, priceData);
return {
collateralValueInUsd,
unrealizedPnl,
realizedPnl
};
};
var splitPositionsByStatus = (positions) => {
const openPositions = [];
const otherPositions = [];
positions.forEach((position) => {
if (position.status === "OPEN") {
openPositions.push(position);
} else {
otherPositions.push(position);
}
});
return { openPositions, otherPositions };
};
function transformPriceArray(priceArray) {
return priceArray.map((obj) => ({
id: obj.id,
price: Number(obj.price.price) / 10 ** Math.abs(obj.price.expo)
}));
}
// src/subgraph/markets/index.ts
import { request as request2 } from "graphql-request";
// src/subgraph/markets/subgraphQueries.ts
import { gql as gql2 } from "graphql-request";
var fetchAllMarketsDataQuery = gql2`
{
markets {
id
marketName
marketSymbol
marketPrice
feedId
skew
size
maxOpenInterest
maxMarketValue
interestRate
currentFundingRate
currentFundingVelocity
indexPrice
skewScale
maxFundingVelocity
makerFee
takerFee
marketPrice
initialMarginRatioD18
minimumPositionMargin
maintenanceMarginRatioD18
minimumInitialMarginRatioD18
}
}
`;
var fetchMarketByIdQuery = (marketId) => gql2`
{
market(id: "${marketId}") {
id
marketName
marketSymbol
marketPrice
feedId
skew
size
maxOpenInterest
maxMarketValue
interestRate
currentFundingRate
currentFundingVelocity
indexPrice
skewScale
maxFundingVelocity
makerFee
takerFee
marketPrice
initialMarginRatioD18
minimumPositionMargin
maintenanceMarginRatioD18
minimumInitialMarginRatioD18
}
}
`;
// src/subgraph/markets/index.ts
var getAllMarketsFromSubgraph = async (subgraphEndpoint) => {
try {
const subgraphResponse = await request2(subgraphEndpoint, fetchAllMarketsDataQuery);
if (!subgraphResponse) throw Error(`Error while fetching markets`);
const markets = mapResponseToMarketArray(subgraphResponse.markets)?.filter((market) => !!market);
if (markets) return markets;
throw new NotFoundError("Markets not found");
} catch (error) {
console.log("Markets not found. Subgraph request failed", error);
return [];
}
};
var getMarketById = async (subgraphEndpoint, marketId) => {
try {
const subgraphResponse = await request2(subgraphEndpoint, fetchMarketByIdQuery(marketId));
if (!subgraphResponse) throw Error(`Error while fetching markets`);
if (subgraphResponse) {
const market = mapResponseToMarket(subgraphResponse.market);
if (market && market.id === marketId) {
return market;
}
}
throw Error(`Market with Market Id ${marketId} Not Found`);
} catch (error) {
console.log(`Market with Market Id ${marketId} Not Found`, error);
throw error;
}
};
// src/subgraph/index.ts
import request7, { GraphQLClient } from "graphql-request";
// src/subgraph/common/index.ts
import { Chain } from "@parifi/references";
import dotenv from "dotenv";
dotenv.config();
var publicSubgraphEndpoints = {
[Chain.ARBITRUM_SEPOLIA]: process.env.SUBGRAPH_ENDPOINT || "",
[Chain.ARBITRUM_MAINNET]: "https://api.studio.thegraph.com/query/68480/parifi-arbitrum/version/latest"
};
var getPublicSubgraphEndpoint = (chainId) => {
return publicSubgraphEndpoints[chainId];
};
// src/subgraph/accounts/index.ts
import Decimal4 from "decimal.js";
import { request as request3 } from "graphql-request";
// src/subgraph/accounts/subgraphQueries.ts
import { gql as gql3 } from "graphql-request";
var fetchRealizedPnlData = (userAddress) => gql3`
{
account(id: "${userAddress.toLowerCase()}") {
id
totalRealizedPnlPositions
totalRealizedPnlVaults
}
}
`;
var fetchAccountByWalletAddress = (walletAddress) => gql3`
{
wallet(id: "${walletAddress}") {
id
}
}
`;
var fetchLeaderboardUserData = (userAddresses) => gql3`
{
accounts(
where: {id_in: [${userAddresses.map((id) => `"${id}"`).join(", ")}]}
) {
id
totalOrdersCount
totalPositionsCount
countProfitablePositions
countLossPositions
countLiquidatedPositions
totalVolumeInUsd
totalVolumeInUsdLongs
totalVolumeInUsdShorts
totalRealizedPnlPositions
totalAccruedBorrowingFeesInUsd
}
}`;
var fetchIntegratorFees = (userAddresses) => gql3`
{
snxAccounts(where:
{
owner_in: [${userAddresses.map((id) => `"${id}"`).join(", ")}],
type: PERP
}) {
id
accountId
owner {
id
}
integratorFeesGenerated
}
}
`;
var checkExistingUser = (userAddress) => gql3`
{
snxAccounts(
where: {
owner: "${userAddress}",
type: PERP,
}
) {
id
accountId
totalOrdersCount
}
}
`;
var depositedCollateralForSnxAccountsQuery = (accountIds) => gql3`
{
snxAccounts
(where :{
accountId_in : [${accountIds.map((id) => `"${id}"`).join(", ")}]
})
{
owner{
id
}
accountId
collateralDeposits {
totalAmountDeposited
totalAmountWithdrawn
totalAmountLiquidated
currentDepositedAmount
collateralName
collateralSymbol
collateralDecimals
}
}
}
`;
// src/subgraph/accounts/index.ts
var getRealizedPnlForUser = async (subgraphEndpoint, userAddress) => {
try {
const query = fetchRealizedPnlData(userAddress);
const subgraphResponse = await request3(subgraphEndpoint, query);
const realizedPnlResponse = subgraphResponse;
if (realizedPnl