@exponent-labs/exponent-vaults-fetcher 0.9.24 → 0.9.26

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.
package/src/fetcher.ts CHANGED
@@ -4,14 +4,15 @@ import { ExponentVaults, IDL, PROGRAM_ID } from "@exponent-labs/exponent-vaults-
4
4
  import { ExponentVaultsPDA } from "@exponent-labs/exponent-vaults-pda"
5
5
 
6
6
  import { IGNORED_VAULTS } from "./constants"
7
- import { transformAnchorData } from "./typeUtils"
8
7
  import { decodePriceInterfaceAccounts } from "./priceInterfaceAccounts"
8
+ import { transformAnchorData } from "./typeUtils"
9
9
  import { ActionProposal, ExponentPrices, ExponentVault, WithdrawalAccount } from "./types"
10
10
 
11
11
  const EXPONENT_PRICES_META_DISCRIMINATOR = Buffer.from([188, 97, 196, 52, 192, 41, 211, 196])
12
12
  const MAX_PRICES = 1024
13
13
  const MAX_PRICE_MANAGERS = 8
14
14
  const MAX_AUTHORIZED_VAULT_CREATORS = 128
15
+ const MAX_GET_MULTIPLE_ACCOUNTS_INFO_KEYS = 100
15
16
  const PRICE_NODE_REGISTERS = 4
16
17
  const PRICE_USAGE_AMOUNT_REGISTER = 1
17
18
 
@@ -21,6 +22,10 @@ const U64_BYTES = 8
21
22
  const ZERO_PUBKEY = new web3.PublicKey(new Uint8Array(PUBKEY_BYTES))
22
23
 
23
24
  const EXPONENT_PRICE_SIZE = 224
25
+ const EXPONENT_PRICE_PRICE_DECIMALS_OFFSET = 160
26
+ const EXPONENT_PRICE_UNDERLYING_DECIMALS_OFFSET = 161
27
+ const EXPONENT_PRICE_SY_PRICE_ID_OFFSET = 168
28
+ const EXPONENT_PRICE_IS_INVERSE_OFFSET = 192
24
29
  const PRICE_NODE_SIZE = EXPONENT_PRICE_SIZE
25
30
  const NODE_REGISTERS_SIZE = PRICE_NODE_REGISTERS * U32_BYTES
26
31
  const PRICE_NODE_WRAPPED_SIZE = NODE_REGISTERS_SIZE + PRICE_NODE_SIZE
@@ -257,9 +262,9 @@ export class ExponentVaultsFetcher {
257
262
  }))
258
263
  }
259
264
 
260
- async fetchAllWithdrawalAccountsDeserialized(filters?: web3.GetProgramAccountsFilter[]): Promise<
261
- DecodedAccount<WithdrawalAccount>[]
262
- > {
265
+ async fetchAllWithdrawalAccountsDeserialized(
266
+ filters?: web3.GetProgramAccountsFilter[],
267
+ ): Promise<DecodedAccount<WithdrawalAccount>[]> {
263
268
  const accounts = await this.fetchAllWithdrawalAccounts(filters)
264
269
  return accounts.map(({ publicKey, account }) => ({
265
270
  publicKey,
@@ -366,6 +371,10 @@ export class ExponentVaultsFetcher {
366
371
  const priceInterfaceAccounts = new web3.PublicKey(
367
372
  data.subarray(valueOffset + 128, valueOffset + 128 + PUBKEY_BYTES),
368
373
  )
374
+ const priceDecimals = data.readUInt8(valueOffset + EXPONENT_PRICE_PRICE_DECIMALS_OFFSET)
375
+ const underlyingDecimals = data.readUInt8(valueOffset + EXPONENT_PRICE_UNDERLYING_DECIMALS_OFFSET)
376
+ const syPriceId = data.readBigUInt64LE(valueOffset + EXPONENT_PRICE_SY_PRICE_ID_OFFSET)
377
+ const isInverse = data.readUInt8(valueOffset + EXPONENT_PRICE_IS_INVERSE_OFFSET) !== 0
369
378
 
370
379
  return {
371
380
  active,
@@ -379,9 +388,13 @@ export class ExponentVaultsFetcher {
379
388
  lastUpdatedAt,
380
389
  lastUpdatedSlot,
381
390
  priceType,
391
+ priceDecimals,
392
+ underlyingDecimals,
393
+ syPriceId,
382
394
  impliedApyBps,
383
395
  impliedApy: impliedApyBps === null ? null : impliedApyBps / 1_000_000,
384
396
  priceInterfaceAccounts,
397
+ isInverse,
385
398
  interfaceAccounts: [],
386
399
  scopeConfig: null,
387
400
  },
@@ -420,20 +433,34 @@ export class ExponentVaultsFetcher {
420
433
  const activePriceEntries = prices.filter((entry) => entry !== null) as NonNullable<
421
434
  ExponentPrices["prices"][number]
422
435
  >[]
423
- const uniqueInterfaceAccounts = [
424
- ...new Map(
425
- activePriceEntries.map((entry) => [entry.priceInterfaceAccounts.toBase58(), entry.priceInterfaceAccounts]),
426
- ).values(),
427
- ].filter((pubkey) => !pubkey.equals(ZERO_PUBKEY))
428
-
429
- if (uniqueInterfaceAccounts.length > 0) {
430
- const infos = await Promise.all(
431
- uniqueInterfaceAccounts.map((pubkey) => this.program.provider.connection.getAccountInfo(pubkey)),
432
- )
436
+ const priceEntriesByInterfaceAccount = new Map<
437
+ string,
438
+ { entries: NonNullable<ExponentPrices["prices"][number]>[]; key: web3.PublicKey }
439
+ >()
440
+ for (const entry of activePriceEntries) {
441
+ const key = entry.priceInterfaceAccounts
442
+ if (key.equals(ZERO_PUBKEY)) continue
443
+
444
+ const keyString = key.toBase58()
445
+ const group = priceEntriesByInterfaceAccount.get(keyString)
446
+ if (group) {
447
+ group.entries.push(entry)
448
+ } else {
449
+ priceEntriesByInterfaceAccount.set(keyString, { entries: [entry], key })
450
+ }
451
+ }
433
452
 
434
- for (let i = 0; i < uniqueInterfaceAccounts.length; i++) {
435
- const key = uniqueInterfaceAccounts[i]
436
- const info = infos[i]
453
+ const priceInterfaceAccountGroups = [...priceEntriesByInterfaceAccount.values()]
454
+ for (let start = 0; start < priceInterfaceAccountGroups.length; start += MAX_GET_MULTIPLE_ACCOUNTS_INFO_KEYS) {
455
+ const groups = priceInterfaceAccountGroups.slice(start, start + MAX_GET_MULTIPLE_ACCOUNTS_INFO_KEYS)
456
+ const infos = await this.program.provider.connection.getMultipleAccountsInfo(groups.map((group) => group.key))
457
+ if (infos.length !== groups.length) {
458
+ throw new Error(`PriceInterfaceAccounts batch size mismatch: requested ${groups.length}, got ${infos.length}`)
459
+ }
460
+
461
+ for (let index = 0; index < groups.length; index++) {
462
+ const { entries, key } = groups[index]
463
+ const info = infos[index]
437
464
  if (!info) {
438
465
  throw new Error(`PriceInterfaceAccounts account not found: ${key.toBase58()}`)
439
466
  }
@@ -444,11 +471,9 @@ export class ExponentVaultsFetcher {
444
471
  }
445
472
 
446
473
  const decoded = decodePriceInterfaceAccounts(info.data)
447
- for (const entry of activePriceEntries) {
448
- if (entry.priceInterfaceAccounts.equals(key)) {
449
- entry.interfaceAccounts = decoded.interfaceAccounts
450
- entry.scopeConfig = decoded.scopeConfig
451
- }
474
+ for (const entry of entries) {
475
+ entry.interfaceAccounts = decoded.interfaceAccounts
476
+ entry.scopeConfig = decoded.scopeConfig
452
477
  }
453
478
  }
454
479
  }
package/src/types.ts CHANGED
@@ -220,9 +220,13 @@ export type ExponentPrice = {
220
220
  lastUpdatedAt: bigint
221
221
  lastUpdatedSlot: bigint
222
222
  priceType: number
223
+ priceDecimals: number
224
+ underlyingDecimals: number
225
+ syPriceId: bigint
223
226
  impliedApyBps: number | null
224
227
  impliedApy: number | null
225
228
  priceInterfaceAccounts: web3.PublicKey
229
+ isInverse: boolean
226
230
  interfaceAccounts: web3.PublicKey[]
227
231
  scopeConfig?: ScopePriceConfig | null
228
232
  }