@exponent-labs/exponent-fetcher 0.9.11 → 0.9.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/build/constants.js +3 -3
  2. package/build/constants.js.map +1 -1
  3. package/build/exponentFetcher.d.ts +18 -16
  4. package/build/exponentFetcher.js +74 -141
  5. package/build/exponentFetcher.js.map +1 -1
  6. package/build/utils/adrena.d.ts +0 -2
  7. package/build/utils/adrena.js +1 -2
  8. package/build/utils/adrena.js.map +1 -1
  9. package/build/utils/fragmetric.d.ts +0 -2
  10. package/build/utils/fragmetric.js +2 -2
  11. package/build/utils/fragmetric.js.map +1 -1
  12. package/build/utils/jito.d.ts +0 -2
  13. package/build/utils/jito.js +1 -2
  14. package/build/utils/jito.js.map +1 -1
  15. package/build/utils/jupiter.d.ts +0 -2
  16. package/build/utils/jupiter.js +2 -3
  17. package/build/utils/jupiter.js.map +1 -1
  18. package/build/utils/kamino.d.ts +0 -2
  19. package/build/utils/kamino.js +1 -2
  20. package/build/utils/kamino.js.map +1 -1
  21. package/build/utils/meteora.d.ts +0 -3
  22. package/build/utils/meteora.js +5 -5
  23. package/build/utils/meteora.js.map +1 -1
  24. package/build/utils/ore.d.ts +6 -21
  25. package/build/utils/ore.js +30 -85
  26. package/build/utils/ore.js.map +1 -1
  27. package/build/utils/perena.d.ts +0 -2
  28. package/build/utils/perena.js +2 -3
  29. package/build/utils/perena.js.map +1 -1
  30. package/build/utils/sanctum.d.ts +0 -2
  31. package/build/utils/sanctum.js +1 -2
  32. package/build/utils/sanctum.js.map +1 -1
  33. package/build/utils/solstice.d.ts +9 -2
  34. package/build/utils/solstice.js +20 -2
  35. package/build/utils/solstice.js.map +1 -1
  36. package/package.json +21 -21
  37. package/src/exponentFetcher.ts +75 -155
  38. package/src/utils/ore.ts +36 -122
  39. package/src/utils/solstice.ts +27 -0
@@ -85,9 +85,7 @@ import { computeD, getAmountByShare } from "./utils/meteora"
85
85
  import { calculateOreExchangeRate } from "./utils/ore"
86
86
  import { getPerenaLpMint, getPerenaStablePoolData } from "./utils/perena"
87
87
  import { calculateSanctumIndex } from "./utils/sanctum"
88
- import { calculateSolsticeRedemptionRate } from "./utils/solstice"
89
-
90
- const KAMINO_VAULT_GLOBAL_CONFIG = new web3.PublicKey("BKyTcUe6daNG8HbgBix2ugdRHbykG2dK9hPBBqhUyoEX")
88
+ import { calculateSolsticeGlamVaultExchangeRate, calculateSolsticeRedemptionRate } from "./utils/solstice"
91
89
 
92
90
  export function serializeAnchorizedPNumFromJson(pnum: AnchorizedPNum): AnchorizedPNumJson {
93
91
  const serializedArray = pnum[0].map((bn) => bn.toString())
@@ -350,6 +348,11 @@ export class ExponentFetcher {
350
348
  },
351
349
  })),
352
350
  },
351
+ crossingSplit: {
352
+ crossLeftIdx: raw.crossingSplit.crossLeftIdx,
353
+ crossRightIdx: raw.crossingSplit.crossRightIdx,
354
+ lpBalanceCrossing: raw.crossingSplit.lpBalanceCrossing,
355
+ },
353
356
  }
354
357
 
355
358
  return deserializeLpPositionCLMM(v)
@@ -477,7 +480,7 @@ export class ExponentFetcher {
477
480
  * Layout matches Rust struct `Ticks` with `RedBlackTree<u32, Tick, 1000>`:
478
481
  * - Discriminator: 8 bytes
479
482
  * - RedBlackTree header: root(4) + padding(12) + size(8) + bump(4) + freeIdx(4) = 32 bytes
480
- * - 1000 RBTree nodes, each: nodeHeader(16) + key(4) + padding(4) + Tick = variable bytes
483
+ * - 1000 RBTree nodes, each: nodeHeader(16) + key(4) + padding(4) + Tick(416) = 440 bytes
481
484
  * - Ticks footer: market(32) + feeGrowthPt(16) + feeGrowthSy(16) + prefixSum(8) + spotPrice(8) + currentTick(4) + padding(12) = 96 bytes
482
485
  */
483
486
  export function deserializeMarketThreeTicks(data: Buffer): Ticks {
@@ -577,13 +580,13 @@ export function deserializeMarketThreeTicks(data: Buffer): Ticks {
577
580
  const principalSy = readU64() // 8 bytes
578
581
  const principalShareSupply = readPreciseNumberAsBigint() // 32 bytes - kept as bigint for arithmetic
579
582
 
580
- // FarmYieldTrackers: 2 x FarmYieldTracker(32 bytes) = 64 bytes
583
+ // FarmYieldTrackers: 3 x FarmYieldTracker(32 bytes) = 96 bytes
581
584
  const farms: { lastSeenIndex: number }[] = []
582
585
  for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
583
586
  farms.push({ lastSeenIndex: readPreciseNumberAsFloat() })
584
587
  }
585
588
 
586
- // EmissionYieldTrackers: 2 x EmissionYieldTracker(64 bytes) = 128 bytes
589
+ // EmissionYieldTrackers: 3 x EmissionYieldTracker(64 bytes) = 192 bytes
587
590
  const emissions: { lastSeenIndex: number; lastPositionIndex: number }[] = []
588
591
  for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
589
592
  emissions.push({
@@ -632,76 +635,7 @@ export function deserializeMarketThreeTicks(data: Buffer): Ticks {
632
635
  }
633
636
  }
634
637
 
635
- /** Decoded account may use snake_case (from JSON IDL); normalize to camelCase for app use. */
636
- function normalizeCpiContext(a: { altIndex?: number; alt_index?: number; isSigner?: boolean; is_signer?: boolean; isWritable?: boolean; is_writable?: boolean }): { altIndex: number; isSigner: boolean; isWritable: boolean } {
637
- return {
638
- altIndex: a.altIndex ?? (a as { alt_index?: number }).alt_index ?? 0,
639
- isSigner: a.isSigner ?? (a as { is_signer?: boolean }).is_signer ?? false,
640
- isWritable: a.isWritable ?? (a as { is_writable?: boolean }).is_writable ?? false,
641
- }
642
- }
643
-
644
- function normalizeCpiAccountIndexes(
645
- raw: {
646
- getSyState?: unknown[]
647
- get_sy_state?: unknown[]
648
- withdrawSy?: unknown[]
649
- withdraw_sy?: unknown[]
650
- depositSy?: unknown[]
651
- deposit_sy?: unknown[]
652
- claimEmission?: unknown[][]
653
- claim_emission?: unknown[][]
654
- getPositionState?: unknown[]
655
- get_position_state?: unknown[]
656
- }
657
- ): CpiAccountIndexes {
658
- const arr = (key: string, snake: string) => {
659
- const a = (raw as Record<string, unknown>)[key] ?? (raw as Record<string, unknown>)[snake]
660
- return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x as Record<string, unknown>)) : []
661
- }
662
- const arr2 = (key: string, snake: string) => {
663
- const a = (raw as Record<string, unknown>)[key] ?? (raw as Record<string, unknown>)[snake]
664
- return Array.isArray(a) ? a.map((inner) => (Array.isArray(inner) ? inner.map((x) => normalizeCpiContext(x as Record<string, unknown>)) : [])) : []
665
- }
666
- return {
667
- getSyState: arr("getSyState", "get_sy_state"),
668
- withdrawSy: arr("withdrawSy", "withdraw_sy"),
669
- depositSy: arr("depositSy", "deposit_sy"),
670
- claimEmission: arr2("claimEmission", "claim_emission"),
671
- getPositionState: arr("getPositionState", "get_position_state"),
672
- }
673
- }
674
-
675
- function normalizeMarketCpiCoreIndexes(
676
- raw: {
677
- stripSy?: unknown[]
678
- strip_sy?: unknown[]
679
- mergeSy?: unknown[]
680
- merge_sy?: unknown[]
681
- }
682
- ): MarketCpiCoreIndexes {
683
- const arr = (key: string, snake: string) => {
684
- const a = (raw as Record<string, unknown>)[key] ?? (raw as Record<string, unknown>)[snake]
685
- return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x as Record<string, unknown>)) : []
686
- }
687
- return {
688
- stripSy: arr("stripSy", "strip_sy"),
689
- mergeSy: arr("mergeSy", "merge_sy"),
690
- }
691
- }
692
-
693
638
  export function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
694
- const rawCpiSy = m.cpiSyAccounts ?? (m as unknown as { cpi_sy_accounts?: unknown }).cpi_sy_accounts
695
- const rawCpiCore = m.cpiCoreAccounts ?? (m as unknown as { cpi_core_accounts?: unknown }).cpi_core_accounts
696
- const cpiSyAccounts =
697
- rawCpiSy != null && typeof rawCpiSy === "object"
698
- ? normalizeCpiAccountIndexes(rawCpiSy as Parameters<typeof normalizeCpiAccountIndexes>[0])
699
- : (m.cpiSyAccounts ?? { getSyState: [], withdrawSy: [], depositSy: [], claimEmission: [], getPositionState: [] })
700
- const cpiCoreAccounts =
701
- rawCpiCore != null && typeof rawCpiCore === "object"
702
- ? normalizeMarketCpiCoreIndexes(rawCpiCore as Parameters<typeof normalizeMarketCpiCoreIndexes>[0])
703
- : (m.cpiCoreAccounts ?? { stripSy: [], mergeSy: [] })
704
-
705
639
  return {
706
640
  addressLookupTable: m.addressLookupTable,
707
641
  mintSy: m.mintSy,
@@ -714,7 +648,7 @@ export function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
714
648
  selfAddress: m.selfAddress,
715
649
  syProgram: m.syProgram,
716
650
  statusFlags: m.statusFlags,
717
- cpiSyAccounts,
651
+ cpiSyAccounts: m.cpiSyAccounts,
718
652
  isCurrentFlashSwap: m.isCurrentFlashSwap,
719
653
  lpFarm: m.lpFarm,
720
654
  mintYt: m.mintYt,
@@ -743,7 +677,7 @@ export function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
743
677
  syBalance: BigInt(m.financials.syBalance.toString()),
744
678
  liquidityBalance: BigInt(m.financials.liquidityBalance.toString()),
745
679
  },
746
- cpiCoreAccounts,
680
+ cpiCoreAccounts: m.cpiCoreAccounts,
747
681
  exponentCoreProgram: m.exponentCoreProgram,
748
682
  seedId: m.seedId,
749
683
  }
@@ -812,6 +746,12 @@ function deserializeLpPositionCLMM(x: LpPositionCLMMRaw): LpPositionCLMM {
812
746
  lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
813
747
  })),
814
748
  })),
749
+ crossingSplit: {
750
+ crossLeftIdx: x.crossingSplit.crossLeftIdx,
751
+ crossRightIdx: x.crossingSplit.crossRightIdx,
752
+ lpBalanceCrossing: BigInt(x.crossingSplit.lpBalanceCrossing.toString()),
753
+ isActive: x.crossingSplit.crossLeftIdx !== 0xffffffff && x.crossingSplit.crossRightIdx !== 0xffffffff,
754
+ },
815
755
  }
816
756
  }
817
757
 
@@ -867,7 +807,8 @@ function deserializeOrderbook(data: Buffer): Orderbook {
867
807
  offset += 8
868
808
  const priceDecimals = data.readUint8(offset)
869
809
  offset += 1
870
- // Skip ConfigurationOptions padding: _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] + _reserved[1024] = 1135 bytes
810
+ // Skip ConfigurationOptions padding/reserve:
811
+ // _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] + _reserved[1024]
871
812
  offset += 1135
872
813
 
873
814
  // Pubkeys
@@ -882,14 +823,7 @@ function deserializeOrderbook(data: Buffer): Orderbook {
882
823
  const cpiAccountOrderbook = readPubkey()
883
824
  const admin = readPubkey()
884
825
 
885
- // last_sy_exchange_rate (Number type = 32 bytes, PreciseNumber with 12 decimals)
886
- const lastSyExchangeRateRaw = (() => {
887
- let val = 0n
888
- for (let i = 0; i < 4; i++) {
889
- val += data.readBigUInt64LE(offset + i * 8) << BigInt(i * 64)
890
- }
891
- return val
892
- })()
826
+ // Skip last_sy_exchange_rate (Number type = 32 bytes)
893
827
  offset += 32
894
828
 
895
829
  // OrderbookFinancials struct
@@ -1045,12 +979,7 @@ function deserializeOrderbook(data: Buffer): Orderbook {
1045
979
  offset += 4
1046
980
  const user = new web3.PublicKey(data.slice(offset, offset + 32))
1047
981
  offset += 32
1048
- const yieldIndexRaw: AnchorizedPNum = [[new BN(0), new BN(0), new BN(0), new BN(0)]]
1049
- for (let word = 0; word < 4; word++) {
1050
- yieldIndexRaw[0][word] = new BN(data.subarray(offset + word * 8, offset + (word + 1) * 8), "le")
1051
- }
1052
- const yieldIndex = deserializeAnchorizedPNum(yieldIndexRaw)
1053
- offset += 32
982
+ /*const yieldIndex = data.readBigUInt64LE(offset).toString();*/ offset += 32
1054
983
  const ptAmount = data.readBigUInt64LE(offset)
1055
984
  offset += 8
1056
985
  const syAmount = data.readBigUInt64LE(offset)
@@ -1063,7 +992,7 @@ function deserializeOrderbook(data: Buffer): Orderbook {
1063
992
  offset += 8
1064
993
  offset += 8 // reserved
1065
994
  // if (user.toBase58() == "11111111111111111111111111111111") continue
1066
- userEscrows.push({ user, yieldIndex, ptAmount, syAmount, ytAmount, stakedYtAmount, staged })
995
+ userEscrows.push({ user, yieldIndex: 0, ptAmount, syAmount, ytAmount, stakedYtAmount, staged })
1067
996
  }
1068
997
 
1069
998
  // ─── Finally, seed_id + signer_bump + reserved ─────────────────────────────
@@ -1092,14 +1021,13 @@ function deserializeOrderbook(data: Buffer): Orderbook {
1092
1021
  tokenEscrowYt,
1093
1022
  tokenEscrowPt,
1094
1023
  cpiAccountOrderbook,
1095
- lastSyExchangeRate: lastSyExchangeRateRaw,
1096
1024
  financials,
1097
1025
  prices,
1098
1026
  configurationOptions,
1099
1027
  offers,
1100
1028
  userEscrows,
1101
- offersBumpIndex,
1102
1029
  offersFreeListHead,
1030
+ offersBumpIndex,
1103
1031
  }
1104
1032
  }
1105
1033
 
@@ -1109,6 +1037,7 @@ function deserializeMarginfiSyMeta(x: MarginfiSyMetaRaw): MarginfiSyMeta {
1109
1037
  maxSySupply: BigInt(x.maxSySupply.toString()),
1110
1038
  minMintSize: BigInt(x.minMintSize.toString()),
1111
1039
  minRedeemSize: BigInt(x.minRedeemSize.toString()),
1040
+ lastSlotCached: BigInt(x.lastSlotCached.toString()),
1112
1041
  }
1113
1042
  }
1114
1043
 
@@ -1320,13 +1249,13 @@ export interface Tick {
1320
1249
  principalSy: bigint
1321
1250
  apyBasePoints: number
1322
1251
  principalShareSupply: bigint
1323
- /** Farm yield trackers (2 trackers) */
1252
+ /** Farm yield trackers (3 trackers) */
1324
1253
  farms: { lastSeenIndex: number }[]
1325
- /** Emission yield trackers (2 trackers) */
1254
+ /** Emission yield trackers (3 trackers) */
1326
1255
  emissions: { lastSeenIndex: number; lastPositionIndex: number }[]
1327
1256
  /** Last split epoch for this tick */
1328
1257
  lastSplitEpoch: bigint
1329
- /** Frozen liquidity that cannot be withdrawn */
1258
+ /** Minimum liquidity retained on ticks used by wrapper-base liquidity */
1330
1259
  frozenLiquidity: bigint
1331
1260
  }
1332
1261
 
@@ -1502,16 +1431,12 @@ export interface Orderbook {
1502
1431
  tokenEscrowPt: web3.PublicKey
1503
1432
  cpiAccountOrderbook: web3.PublicKey
1504
1433
  admin: web3.PublicKey
1505
- /** Raw 256-bit PreciseNumber (12 decimals) for last SY exchange rate */
1506
- lastSyExchangeRate: bigint
1507
1434
  configurationOptions: ConfigurationOptions
1508
1435
  financials: OrderbookFinancials
1509
1436
  prices: PriceTreeNode[]
1510
1437
  offers: OfferNode[]
1511
1438
  userEscrows: UserEscrowNode[]
1512
- /** Next offer index that will be allocated (from NodeAllocator free list) */
1513
1439
  offersFreeListHead: number
1514
- /** Bump index boundary for offers allocator */
1515
1440
  offersBumpIndex: number
1516
1441
  }
1517
1442
 
@@ -1590,6 +1515,11 @@ interface LpPositionCLMMRaw {
1590
1515
  emissions: { trackers: { staged: BN; lastSeenIndex: AnchorizedPNum }[] }
1591
1516
  }[]
1592
1517
  }
1518
+ crossingSplit: {
1519
+ crossLeftIdx: number
1520
+ crossRightIdx: number
1521
+ lpBalanceCrossing: BN
1522
+ }
1593
1523
  }
1594
1524
 
1595
1525
  export interface LpPositionCLMM {
@@ -1610,6 +1540,12 @@ export interface LpPositionCLMM {
1610
1540
  lpShare: bigint
1611
1541
  emissions: { staged: bigint; lastSeenIndex: number }[]
1612
1542
  }[]
1543
+ crossingSplit: {
1544
+ crossLeftIdx: number
1545
+ crossRightIdx: number
1546
+ lpBalanceCrossing: bigint
1547
+ isActive: boolean
1548
+ }
1613
1549
  }
1614
1550
 
1615
1551
  export interface LpFarm {
@@ -1717,6 +1653,8 @@ interface KaminoSyMetaRaw {
1717
1653
  /** Where the SY tokens get deposited */
1718
1654
  tokenSyEscrow: web3.PublicKey
1719
1655
  emissions: SyEmissionRaw[]
1656
+ lastIndex: AnchorizedPNum
1657
+ lastSlotCached: BN
1720
1658
  }
1721
1659
 
1722
1660
  export interface YtPositionRaw {
@@ -1781,14 +1719,14 @@ export interface OfferNodeRaw {
1781
1719
 
1782
1720
  export interface UserEscrowNodeRaw {
1783
1721
  user: web3.PublicKey
1784
- yieldIndex: number
1722
+ yieldIndex: BN
1785
1723
  ptAmount: BN
1786
1724
  syAmount: BN
1787
1725
  ytAmount: BN
1788
1726
  staged: number
1789
1727
  }
1790
1728
 
1791
- function deserializeAnchorizedPNum(x: AnchorizedPNum): number {
1729
+ export function deserializeAnchorizedPNum(x: AnchorizedPNum): number {
1792
1730
  return parseFloat(PreciseNumber.fromRaw(x[0]).valueString)
1793
1731
  }
1794
1732
 
@@ -2025,70 +1963,28 @@ export async function fetchKaminoVaultIndex({
2025
1963
 
2026
1964
  const data = coder.accounts.decode("VaultState", account.data)
2027
1965
 
2028
- const activeAllocations = data.vault_allocation_strategy
2029
- .filter((allocation) => allocation.reserve.toBase58() !== web3.PublicKey.default.toBase58())
2030
- const activeReserves = activeAllocations.map((allocation) => allocation.reserve)
1966
+ const activeReserves = data.vault_allocation_strategy
1967
+ .map((r) => r.reserve)
1968
+ .filter((reserve) => reserve.toBase58() !== web3.PublicKey.default.toBase58())
2031
1969
 
2032
- const [activeReservesData, tokenMintInfo, sharesMintInfo] = await Promise.all([
2033
- connection.getMultipleAccountsInfo(activeReserves),
2034
- connection.getAccountInfo(data.token_mint),
2035
- connection.getAccountInfo(data.shares_mint),
2036
- ])
2037
- const decodedReserves = activeReservesData.map((accountInfo, index) => {
2038
- if (!accountInfo?.data) {
2039
- throw new Error(`Missing Kamino reserve account ${activeReserves[index].toBase58()}`)
2040
- }
2041
- return Reserve.decode(accountInfo.data)
2042
- })
2043
- const collateralMintInfos = await connection.getMultipleAccountsInfo(
2044
- decodedReserves.map((reserve) => reserve.collateral.mintPubkey),
2045
- )
1970
+ console.log("activeReserves", activeReserves)
1971
+ const activeReservesData = await connection.getMultipleAccountsInfo(activeReserves)
2046
1972
 
2047
1973
  const reserves = activeReserves.map((r, i) => {
2048
- const reserveAccount = decodedReserves[i]
2049
- const allocation = activeAllocations[i]
2050
- const [lendingMarketAuthority] = web3.PublicKey.findProgramAddressSync(
2051
- [Buffer.from("lma"), reserveAccount.lendingMarket.toBuffer()],
2052
- new web3.PublicKey("KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD"),
2053
- )
2054
-
1974
+ console.log("r.data", activeReservesData[i].data)
2055
1975
  return {
2056
1976
  reserveAddress: r,
2057
- marketAddress: reserveAccount.lendingMarket,
2058
- ctokenVault: allocation.ctoken_vault,
2059
- lendingMarketAuthority,
2060
- pythOracle: reserveAccount.config.tokenInfo.pythConfiguration.price,
2061
- switchboardPriceOracle: reserveAccount.config.tokenInfo.switchboardConfiguration.priceAggregator,
2062
- switchboardTwapOracle: reserveAccount.config.tokenInfo.switchboardConfiguration.twapAggregator,
2063
- scopePrices: reserveAccount.config.tokenInfo.scopeConfiguration.priceFeed,
2064
- reserveLiquiditySupply: reserveAccount.liquidity.supplyVault,
2065
- reserveCollateralMint: reserveAccount.collateral.mintPubkey,
2066
- reserveCollateralTokenProgram: collateralMintInfos[i]?.owner ?? web3.PublicKey.default,
1977
+ reserve: Reserve.decode(activeReservesData[i].data).lendingMarket,
2067
1978
  }
2068
1979
  })
2069
1980
 
1981
+ console.log("reserves", reserves)
2070
1982
  const tokenVault = data.token_vault
2071
1983
  const tokenMint = data.token_mint
2072
1984
  const baseVaultAuthority = data.base_vault_authority
2073
1985
  const sharesMint = data.shares_mint
2074
- const vaultLookupTable = data.vault_lookup_table ?? web3.PublicKey.default
2075
- const tokenProgram = tokenMintInfo?.owner ?? web3.PublicKey.default
2076
- const sharesTokenProgram = sharesMintInfo?.owner ?? web3.PublicKey.default
2077
1986
 
2078
- return {
2079
- index: 1,
2080
- tokenVault,
2081
- tokenMint,
2082
- tokenProgram,
2083
- // Kamino Vault withdraw expects the singleton program global config account.
2084
- // It is not stored on VaultState, so fetch it from the known program-wide address.
2085
- globalConfig: KAMINO_VAULT_GLOBAL_CONFIG,
2086
- baseVaultAuthority,
2087
- sharesMint,
2088
- sharesTokenProgram,
2089
- vaultLookupTable,
2090
- reserves,
2091
- }
1987
+ return { index: 1, tokenVault, tokenMint, baseVaultAuthority, sharesMint, reserves }
2092
1988
  }
2093
1989
 
2094
1990
  export async function fetchFragmetricSupportedTokenIndex({
@@ -2258,6 +2154,30 @@ export async function fetchSolsticeRedemptionRate({
2258
2154
  return calculateSolsticeRedemptionRate({ yieldPool: accountInfos[0].data, vestingSchedule: accountInfos[1].data })
2259
2155
  }
2260
2156
 
2157
+ export async function fetchSolsticeGlamVaultExchangeRate({
2158
+ connection,
2159
+ stakingVaultSlxAta,
2160
+ slxMint,
2161
+ stslxMint,
2162
+ }: {
2163
+ connection: web3.Connection
2164
+ stakingVaultSlxAta: web3.PublicKey
2165
+ slxMint: web3.PublicKey
2166
+ stslxMint: web3.PublicKey
2167
+ }): Promise<number> {
2168
+ const accountInfos = await connection.getMultipleAccountsInfo([stakingVaultSlxAta, slxMint, stslxMint])
2169
+
2170
+ if (!accountInfos[0] || !accountInfos[1] || !accountInfos[2]) {
2171
+ throw new Error("One or more Solstice GLAM vault accounts not found")
2172
+ }
2173
+
2174
+ return calculateSolsticeGlamVaultExchangeRate({
2175
+ stakingVaultSlxAta: accountInfos[0].data,
2176
+ slxMint: accountInfos[1].data,
2177
+ stslxMint: accountInfos[2].data,
2178
+ })
2179
+ }
2180
+
2261
2181
  const REFLECT_ORACLE_LEN = 17
2262
2182
  const REFLECT_MAX_STALENESS_SLOTS = 15000000
2263
2183