From f85fbf10711cd1c7f9f0493bc30d54441c0d96b0 Mon Sep 17 00:00:00 2001 From: Calvin Yuen Date: Tue, 26 Aug 2025 15:00:55 +0800 Subject: [PATCH 1/3] fix: Apply cumulative deposit interest in drift vault --- projects/vectis/spotMarkets.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/projects/vectis/spotMarkets.js b/projects/vectis/spotMarkets.js index f910b07be1..80eaba6ac2 100644 --- a/projects/vectis/spotMarkets.js +++ b/projects/vectis/spotMarkets.js @@ -116,7 +116,9 @@ function processSpotPosition(position, spotMarketAccountInfo) { return -balance; // Return negative for borrows } - return balance; // Return positive for deposits + const cumulativeDepositInterest = getSpotMarketCumulativeDepositInterest(spotMarketAccountInfo); + + return balance * cumulativeDepositInterest / BigInt(10 ** 10); // Return positive for deposits } function getSpotMarketCumulativeBorrowInterest(accountInfo) { @@ -133,6 +135,20 @@ function getSpotMarketCumulativeBorrowInterest(accountInfo) { } +function getSpotMarketCumulativeDepositInterest(accountInfo) { + if (!accountInfo) { + throw new Error(`No account info found for market`); + } + + const CUMULATIVE_DEPOSIT_INTEREST_OFFSET = 8 + 48 + 32 + 256 + (16 * 8) + 8 - 16; // 16 bytes before the borrow interest + + const lower64Bits = accountInfo.data.readBigInt64LE(CUMULATIVE_DEPOSIT_INTEREST_OFFSET); + const upper64Bits = accountInfo.data.readBigInt64LE(CUMULATIVE_DEPOSIT_INTEREST_OFFSET + 8); + + return (upper64Bits << 64n) + lower64Bits; + } + + function processPerpPosition(position) { From d73d8748610a5dc19cb4ff6f0662b988b63f3c20 Mon Sep 17 00:00:00 2001 From: Calvin Yuen Date: Mon, 1 Sep 2025 11:50:26 +0800 Subject: [PATCH 2/3] feat: Add TVL from jup perp, solana wallet and hyperliquid net equity --- projects/vectis/constant.js | 11 +++++++++ projects/vectis/helpers.js | 27 ++++++++++++++++++++-- projects/vectis/index.js | 45 ++++++++++++++++++++++++++++++++----- 3 files changed, 76 insertions(+), 7 deletions(-) create mode 100644 projects/vectis/constant.js diff --git a/projects/vectis/constant.js b/projects/vectis/constant.js new file mode 100644 index 0000000000..bdefdf6975 --- /dev/null +++ b/projects/vectis/constant.js @@ -0,0 +1,11 @@ +const JUP_PERP_PROGRAM_ID = "PERPHjGBqRHArX4DySjwM6UJHiR3sWAatqfdBS2qQJu"; + +const JLP_MINT = "27G8MtK7VtTcCHkpASjSDdkWWYfoqT6ggEuKidVJidD4"; + +const BASE_URL = "https://api.vectis.finance"; + +module.exports = { + JUP_PERP_PROGRAM_ID, + JLP_MINT, + BASE_URL, +}; diff --git a/projects/vectis/helpers.js b/projects/vectis/helpers.js index 75ff53ca5d..3809e45f90 100644 --- a/projects/vectis/helpers.js +++ b/projects/vectis/helpers.js @@ -1,6 +1,7 @@ const { PublicKey } = require("@solana/web3.js"); const { getMultipleAccounts } = require('../helper/solana') const axios = require("axios"); +const { BASE_URL } = require("./constant"); function deserializeUserPositions(accountInfo) { if (!accountInfo) { @@ -110,7 +111,7 @@ async function fetchVaultUserAddressesWithOffset(data, offset) { async function fetchVaultAddresses() { try { - const response = await axios.get('https://api.vectis.finance/strategy/fetchAllVaultAddresses'); + const response = await axios.get(`${BASE_URL}/strategy/fetchAllVaultAddresses`); if (response.status !== 200) { throw new Error(`HTTP error! status: ${response.status}`); @@ -123,6 +124,28 @@ async function fetchVaultAddresses() { } } +async function fetchPositionAddresses() { + try { + const response = await axios.get(`${BASE_URL}/voltr/position-addresses`); + + if (response.status !== 200) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + return response.data.data; + } catch (error) { + console.error('Error fetching position addresses:', error); + throw error; + } +} + + -module.exports = { readPublicKeyFromBuffer, deserializeUserPositions, fetchVaultUserAddressesWithOffset, fetchVaultAddresses}; +module.exports = { + readPublicKeyFromBuffer, + deserializeUserPositions, + fetchVaultUserAddressesWithOffset, + fetchPositionAddresses, + fetchVaultAddresses +}; diff --git a/projects/vectis/index.js b/projects/vectis/index.js index a95692c710..7821e3cd6b 100644 --- a/projects/vectis/index.js +++ b/projects/vectis/index.js @@ -1,20 +1,25 @@ const { getTokenMintFromMarketIndex, processSpotPosition, processPerpPosition, getPerpTokenMintFromMarketIndex, getVaultPublicKey, DRIFT_VAULT_PROGRAM_ID, VOLTR_PROGRAM_ID } = require("./spotMarkets"); -const { deserializeUserPositions, fetchVaultUserAddressesWithOffset, fetchVaultAddresses} = require("./helpers"); +const { deserializeUserPositions, fetchVaultUserAddressesWithOffset, fetchVaultAddresses, fetchPositionAddresses} = require("./helpers"); const { getPerpMarketFundingRates } = require("./spotMarkets"); -const { getMultipleAccounts, getProvider} = require('../helper/solana'); +const { getMultipleAccounts, getProvider, getAssociatedTokenAddress, sumTokens2} = require('../helper/solana'); const { Program } = require("@coral-xyz/anchor"); +const { Program : ProgramSerum } = require("@project-serum/anchor"); const voltrIdl = require("./voltr-idl"); const { PublicKey } = require("@solana/web3.js"); +const { JLP_MINT, JUP_PERP_PROGRAM_ID } = require("./constant"); +const ADDRESSES = require('../helper/coreAssets.json') +const { post } = require('../helper/http'); - - - module.exports = { +module.exports = { timetravel: false, doublecounted: true, methodology: "Calculate sum of spot positions in vaults with unrealized profit and loss", solana: { tvl, }, + arbitrum: { + tvl: hyperliquidTvl, + }, }; /** * Vault Equity Calculation Formula: @@ -114,4 +119,34 @@ async function tvl(api) { api.add(mint, balance) }) + // HyperLoop Prime A + const positionAddresses = await fetchPositionAddresses(); + + const idl = await ProgramSerum.fetchIdl(JUP_PERP_PROGRAM_ID, provider); + const program = new ProgramSerum(idl, JUP_PERP_PROGRAM_ID, provider); + const jupiterAccounts = await program.account["borrowPosition"].fetchMultiple( + positionAddresses.jupiter + ); + for (const account of jupiterAccounts) { + api.add(JLP_MINT, account.lockedCollateral); + const BORROW_SIZE_PRECISION = 1000; + api.add(ADDRESSES.solana.USDC, -account.borrowSize / BORROW_SIZE_PRECISION); + } + + const tokenAccounts = positionAddresses.solana.map((address) => + getAssociatedTokenAddress(ADDRESSES.solana.USDC, address) + ); + await sumTokens2({ tokenAccounts, api }); +} + +async function hyperliquidTvl(api) { + const positionAddresses = await fetchPositionAddresses(); + for (const address of positionAddresses.hyperliquid) { + let hyperliquidData = await post("https://api.hyperliquid.xyz/info", { + type: "clearinghouseState", + user: address, + }); + hyperliquidData = parseInt(hyperliquidData.marginSummary.accountValue); + api.addCGToken("usd-coin", hyperliquidData); + } } \ No newline at end of file From 58bdf536f7eceae663a09c6797834bcb7f331cd1 Mon Sep 17 00:00:00 2001 From: Calvin Yuen Date: Tue, 2 Sep 2025 09:43:49 +0800 Subject: [PATCH 3/3] fix: remove arbitrum TVL calculation and add to solana --- projects/vectis/index.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/projects/vectis/index.js b/projects/vectis/index.js index 7821e3cd6b..83a7a251dd 100644 --- a/projects/vectis/index.js +++ b/projects/vectis/index.js @@ -17,9 +17,6 @@ module.exports = { solana: { tvl, }, - arbitrum: { - tvl: hyperliquidTvl, - }, }; /** * Vault Equity Calculation Formula: @@ -137,10 +134,8 @@ async function tvl(api) { getAssociatedTokenAddress(ADDRESSES.solana.USDC, address) ); await sumTokens2({ tokenAccounts, api }); -} -async function hyperliquidTvl(api) { - const positionAddresses = await fetchPositionAddresses(); + for (const address of positionAddresses.hyperliquid) { let hyperliquidData = await post("https://api.hyperliquid.xyz/info", { type: "clearinghouseState", @@ -149,4 +144,5 @@ async function hyperliquidTvl(api) { hyperliquidData = parseInt(hyperliquidData.marginSummary.accountValue); api.addCGToken("usd-coin", hyperliquidData); } -} \ No newline at end of file +} +