@exponent-labs/exponent-fetcher 0.1.8 → 0.9.1

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.
@@ -3,13 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.fetchOreExchangeRate = exports.fetchReflectRedemptionRate = exports.fetchSolsticeRedemptionRate = exports.fetchSanctumIndex = exports.fetchAdrenaIndex = exports.fetchMeteoraIndex = exports.fetchFragmetricSupportedTokenIndex = exports.fetchKaminoVaultIndex = exports.fetchJupiterLendIndex = exports.fetchFragmetricIndex = exports.fetchGenericSyMetaIndex = exports.fetchPyth = exports.fetchJupiterPerpsIndex = exports.fetchJitoRestaking = exports.fetchPerenaStablePoolData = exports.fetchSplStakePoolIndex = exports.deserializeEmission = exports.serializeEmission = exports.fetchAllKaminoObligationsByKaminoReserve = exports.fetchKaminoReserve = exports.deserializeYtPosition = exports.deserializeLpPosition = exports.deserializeMarketThreeTicks = exports.ExponentFetcher = exports.MyWallet = exports.deserializeAnchorizedPNumFromJson = exports.serializeAnchorizedPNumFromJson = void 0;
6
+ exports.fetchChainlinkRate = exports.fetchOreExchangeRate = exports.fetchReflectRedemptionRate = exports.fetchSolsticeRedemptionRate = exports.fetchSanctumIndex = exports.fetchAdrenaIndex = exports.fetchMeteoraIndex = exports.fetchFragmetricSupportedTokenIndex = exports.fetchKaminoVaultIndex = exports.fetchJupiterLendIndex = exports.fetchFragmetricIndex = exports.fetchGenericSyMetaIndex = exports.fetchPyth = exports.fetchJupiterPerpsIndex = exports.fetchJitoRestaking = exports.fetchPerenaStablePoolData = exports.fetchSplStakePoolIndex = exports.anchorizedPNumToRawBigint = exports.deserializeEmission = exports.serializeEmission = exports.fetchAllKaminoObligationsByKaminoReserve = exports.fetchKaminoReserve = exports.deserializeYtPosition = exports.deserializeLpPosition = exports.deserializeMarketThree = exports.deserializeMarketThreeTicks = exports.ExponentFetcher = exports.MyWallet = exports.deserializeAnchorizedPNumFromJson = exports.serializeAnchorizedPNumFromJson = void 0;
7
7
  const anchor_1 = require("@coral-xyz/anchor");
8
8
  const anchor_2 = require("@coral-xyz/anchor");
9
9
  const spl_stake_pool_1 = require("@solana/spl-stake-pool");
10
10
  const spl_token_1 = require("@solana/spl-token");
11
11
  const bs58_1 = __importDefault(require("bs58"));
12
12
  const decimal_js_1 = __importDefault(require("decimal.js"));
13
+ const chainlink_idl_1 = require("@exponent-labs/chainlink-idl");
13
14
  const exponent_clmm_idl_1 = require("@exponent-labs/exponent-clmm-idl");
14
15
  const exponent_idl_1 = require("@exponent-labs/exponent-idl");
15
16
  const exponent_orderbook_idl_1 = require("@exponent-labs/exponent-orderbook-idl");
@@ -28,6 +29,7 @@ const meteora_idl_1 = require("@exponent-labs/meteora-idl");
28
29
  const perena_sy_idl_1 = require("@exponent-labs/perena-sy-idl");
29
30
  const perena_sy_idl_2 = require("@exponent-labs/perena-sy-idl");
30
31
  const precise_number_1 = require("@exponent-labs/precise-number");
32
+ const constants_1 = require("./constants");
31
33
  const adrena_1 = require("./utils/adrena");
32
34
  const fragmetric_1 = require("./utils/fragmetric");
33
35
  const jito_1 = require("./utils/jito");
@@ -37,16 +39,12 @@ const ore_1 = require("./utils/ore");
37
39
  const perena_1 = require("./utils/perena");
38
40
  const sanctum_1 = require("./utils/sanctum");
39
41
  const solstice_1 = require("./utils/solstice");
42
+ const KAMINO_VAULT_GLOBAL_CONFIG = new anchor_1.web3.PublicKey("BKyTcUe6daNG8HbgBix2ugdRHbykG2dK9hPBBqhUyoEX");
40
43
  function serializeAnchorizedPNumFromJson(pnum) {
41
44
  const serializedArray = pnum[0].map((bn) => bn.toString());
42
45
  return { 0: serializedArray };
43
46
  }
44
47
  exports.serializeAnchorizedPNumFromJson = serializeAnchorizedPNumFromJson;
45
- function readU128LE(buf, offset) {
46
- const lo = buf.readBigUInt64LE(offset);
47
- const hi = buf.readBigUInt64LE(offset + 8);
48
- return (hi << 64n) + lo;
49
- }
50
48
  function deserializeAnchorizedPNumFromJson(serialized) {
51
49
  const bnArray = serialized[0].map((str) => new anchor_1.BN(str));
52
50
  return { 0: bnArray };
@@ -317,6 +315,7 @@ class ExponentFetcher {
317
315
  ],
318
316
  });
319
317
  return marketsProgramAccounts
318
+ .filter(({ pubkey }) => !(0, constants_1.isMarketIgnored)(pubkey.toBase58()))
320
319
  .map(({ account, pubkey }) => {
321
320
  try {
322
321
  return this.exponentClmmProgram.coder.accounts.decode("marketThree", account.data);
@@ -328,12 +327,16 @@ class ExponentFetcher {
328
327
  .filter((m) => !!m);
329
328
  }
330
329
  async fetchMarketThree(address) {
330
+ const addressStr = address.toBase58();
331
+ if ((0, constants_1.isMarketIgnored)(addressStr)) {
332
+ throw new constants_1.IgnoredClmmEntityError("market", addressStr);
333
+ }
331
334
  try {
332
335
  const m = await this.exponentClmmProgram.account.marketThree.fetch(address);
333
336
  return deserializeMarketThree(m);
334
337
  }
335
338
  catch (e) {
336
- console.error(`Error fetching market ${address.toBase58()}`);
339
+ console.error(`Error fetching market ${addressStr}`);
337
340
  console.error(e);
338
341
  throw e;
339
342
  }
@@ -350,32 +353,75 @@ class ExponentFetcher {
350
353
  },
351
354
  ],
352
355
  });
353
- return ticksAccounts.map(({ account }) => deserializeMarketThreeTicks(account.data));
356
+ return ticksAccounts
357
+ .filter(({ pubkey }) => !(0, constants_1.isTicksIgnored)(pubkey.toBase58()))
358
+ .map(({ account }) => deserializeMarketThreeTicks(account.data));
354
359
  }
355
360
  async fetchMarketThreeTicks(address) {
361
+ const addressStr = address.toBase58();
362
+ if ((0, constants_1.isTicksIgnored)(addressStr)) {
363
+ throw new constants_1.IgnoredClmmEntityError("ticks", addressStr);
364
+ }
356
365
  try {
357
366
  const m = (await this.connection.getAccountInfo(address)).data;
358
367
  return deserializeMarketThreeTicks(m);
359
368
  }
360
369
  catch (e) {
361
- console.error(`Error fetching market ${address.toBase58()}`);
370
+ console.error(`Error fetching ticks ${addressStr}`);
362
371
  console.error(e);
363
372
  throw e;
364
373
  }
365
374
  }
366
375
  }
367
376
  exports.ExponentFetcher = ExponentFetcher;
377
+ /**
378
+ * Deserializes a CLMM Ticks account from raw buffer data.
379
+ *
380
+ * Layout matches Rust struct `Ticks` with `RedBlackTree<u32, Tick, 1000>`:
381
+ * - Discriminator: 8 bytes
382
+ * - RedBlackTree header: root(4) + padding(12) + size(8) + bump(4) + freeIdx(4) = 32 bytes
383
+ * - 1000 RBTree nodes, each: nodeHeader(16) + key(4) + padding(4) + Tick = variable bytes
384
+ * - Ticks footer: market(32) + feeGrowthPt(16) + feeGrowthSy(16) + prefixSum(8) + spotPrice(8) + currentTick(4) + padding(12) = 96 bytes
385
+ */
368
386
  function deserializeMarketThreeTicks(data) {
369
- let offset = 8;
370
- const MAX_TICK_NODES = 100;
371
- const PERSONAL_TICK_YIELD_TRACKER_SIZE = 3;
387
+ const MAX_TICK_NODES = 1000;
388
+ const PERSONAL_TICK_YIELD_TRACKER_SIZE = 2;
389
+ let offset = 8; // Skip discriminator
390
+ // ─── Helper functions ─────────────────────────────────────────────────────
391
+ const readU64 = () => {
392
+ const val = data.readBigUInt64LE(offset);
393
+ offset += 8;
394
+ return val;
395
+ };
396
+ const readU128 = () => {
397
+ const lo = data.readBigUInt64LE(offset);
398
+ const hi = data.readBigUInt64LE(offset + 8);
399
+ offset += 16;
400
+ return (hi << 64n) + lo;
401
+ };
402
+ const readI128 = () => {
403
+ const lo = data.readBigUInt64LE(offset);
404
+ const hi = data.readBigInt64LE(offset + 8); // High part is signed
405
+ offset += 16;
406
+ return (hi << 64n) + lo;
407
+ };
408
+ const readF64 = () => {
409
+ const val = data.readDoubleLE(offset);
410
+ offset += 8;
411
+ return val;
412
+ };
413
+ const readU32 = () => {
414
+ const val = data.readUInt32LE(offset);
415
+ offset += 4;
416
+ return val;
417
+ };
372
418
  const readPubkey = () => {
373
419
  const pk = new anchor_1.web3.PublicKey(data.slice(offset, offset + 32));
374
420
  offset += 32;
375
421
  return pk;
376
422
  };
377
- const readNumber = () => {
378
- // Number is 32 bytes (4 x u64)
423
+ /** Reads a PreciseNumber (Number type in Rust) as float - 32 bytes (4 x u64) */
424
+ const readPreciseNumberAsFloat = () => {
379
425
  const nums = [];
380
426
  for (let i = 0; i < 4; i++) {
381
427
  nums.push(new anchor_1.BN(data.slice(offset + i * 8, offset + (i + 1) * 8), undefined, "le"));
@@ -383,94 +429,81 @@ function deserializeMarketThreeTicks(data) {
383
429
  offset += 32;
384
430
  return parseFloat(precise_number_1.PreciseNumber.fromRaw(nums).valueString);
385
431
  };
386
- // ─── Parse RedBlackTree slab ───────────────────────────────────────────────
387
- // repr(C) gives: root: u32, pad to align NodeAllocator's u64, then the NodeAllocator header
388
- const root = data.readUInt32LE(offset);
389
- offset += 4;
390
- const padTo8 = 12;
391
- offset += padTo8;
392
- // NodeAllocator<T=RBNode<u32,PriceNode>, N=MAX_PRICE_NODES, R=3>
393
- // header: size:u64, bump_index:u32, free_list_head:u32
394
- const tickTreeSize = Number(data.readBigUInt64LE(offset));
395
- offset += 8;
396
- const ticksTreeBump = data.readUInt32LE(offset);
397
- offset += 4;
398
- const ticksTreeFreeIdx = data.readUInt32LE(offset);
399
- offset += 4;
432
+ /** Reads a PreciseNumber (Number type in Rust) as raw bigint - 32 bytes (4 x u64 = 256 bits) */
433
+ const readPreciseNumberAsBigint = () => {
434
+ let val = 0n;
435
+ for (let i = 0; i < 4; i++) {
436
+ const chunk = data.readBigUInt64LE(offset + i * 8);
437
+ val += chunk << BigInt(i * 64);
438
+ }
439
+ offset += 32;
440
+ return val;
441
+ };
442
+ const skip = (bytes) => {
443
+ offset += bytes;
444
+ };
445
+ // ─── Parse RedBlackTree header ────────────────────────────────────────────
446
+ skip(4); // root: u32
447
+ skip(12); // padding to align NodeAllocator
448
+ skip(8); // size: u64
449
+ skip(4); // bump_index: u32
450
+ skip(4); // free_list_head: u32
451
+ // ─── Parse tick nodes ─────────────────────────────────────────────────────
400
452
  const ticks = [];
401
453
  for (let i = 0; i < MAX_TICK_NODES; i++) {
402
- const left = data.readUInt32LE(offset);
403
- offset += 4;
404
- const right = data.readUInt32LE(offset);
405
- offset += 4;
406
- const parent = data.readUInt32LE(offset);
407
- offset += 4;
408
- offset += 4; // skip color
409
- const apyBasePoints = data.readUInt32LE(offset);
410
- offset += 8;
411
- const feeGrowthOutsidePt = readU128LE(data, offset);
412
- offset += 16;
413
- const feeGrowthOutsideSy = readU128LE(data, offset);
414
- offset += 16;
415
- const liquidityNet = data.readBigInt64LE(offset);
416
- offset += 8;
417
- const liquidityGross = data.readBigInt64LE(offset);
418
- offset += 8;
419
- const impliedRate = data.readDoubleLE(offset);
420
- offset += 8;
421
- const principalPt = data.readBigInt64LE(offset);
422
- offset += 8;
423
- const principalSy = data.readBigInt64LE(offset);
424
- offset += 8;
425
- const principalShareSupply = data.readBigInt64LE(offset);
426
- offset += 8;
427
- // Parse FarmYieldTrackers (3 trackers x 32 bytes each)
454
+ // RBNode header: left(4) + right(4) + parent(4) + color(4) = 16 bytes
455
+ skip(16);
456
+ // Key: u32 + padding to 8 bytes
457
+ const apyBasePoints = readU32();
458
+ skip(4); // padding
459
+ // Tick value (416 bytes total)
460
+ const feeGrowthOutsidePt = readU128(); // 16 bytes
461
+ const feeGrowthOutsideSy = readU128(); // 16 bytes
462
+ const liquidityNet = readI128(); // 16 bytes
463
+ const liquidityGross = readU64(); // 8 bytes
464
+ const spotPrice = readF64(); // 8 bytes
465
+ const principalPt = readU64(); // 8 bytes
466
+ const principalSy = readU64(); // 8 bytes
467
+ const principalShareSupply = readPreciseNumberAsBigint(); // 32 bytes - kept as bigint for arithmetic
468
+ // FarmYieldTrackers: 2 x FarmYieldTracker(32 bytes) = 64 bytes
428
469
  const farms = [];
429
470
  for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
430
- farms.push({ lastSeenIndex: readNumber() });
471
+ farms.push({ lastSeenIndex: readPreciseNumberAsFloat() });
431
472
  }
432
- // Parse EmissionYieldTrackers (3 trackers x 64 bytes each)
473
+ // EmissionYieldTrackers: 2 x EmissionYieldTracker(64 bytes) = 128 bytes
433
474
  const emissions = [];
434
475
  for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
435
- const lastSeenIndex = readNumber();
436
- const lastPositionIndex = readNumber();
437
- emissions.push({ lastSeenIndex, lastPositionIndex });
476
+ emissions.push({
477
+ lastSeenIndex: readPreciseNumberAsFloat(),
478
+ lastPositionIndex: readPreciseNumberAsFloat(),
479
+ });
438
480
  }
439
- // Parse last_split_epoch (u64)
440
- const lastSplitEpoch = data.readBigUInt64LE(offset);
441
- offset += 8;
442
- // Skip padding (u64)
443
- offset += 8;
444
- if (apyBasePoints === 0)
445
- continue;
481
+ const lastSplitEpoch = readU64(); // 8 bytes
482
+ const frozenLiquidity = readU64(); // 8 bytes
446
483
  ticks.push({
447
484
  apyBasePoints,
448
485
  liquidityNet,
449
486
  feeGrowthOutsidePt,
450
487
  feeGrowthOutsideSy,
451
488
  liquidityGross,
452
- impliedRate,
489
+ impliedRate: spotPrice, // Legacy field name kept for compatibility
453
490
  principalPt,
454
491
  principalSy,
455
492
  principalShareSupply,
456
493
  farms,
457
494
  emissions,
458
495
  lastSplitEpoch,
496
+ frozenLiquidity,
459
497
  });
460
- // console.log(ticks)
461
498
  }
462
- const market = readPubkey();
463
- const feeGrowthIndexGlobalPt = readU128LE(data, offset);
464
- offset += 16;
465
- const feeGrowthIndexGlobalSy = readU128LE(data, offset);
466
- offset += 16;
467
- const currentPrefixSum = data.readBigUInt64LE(offset); // Active liquidity at current tick
468
- offset += 8;
469
- const currentSpotPrice = data.readDoubleLE(offset);
470
- offset += 8;
471
- const currentTick = data.readUint32LE(offset);
472
- offset += 4;
473
- offset += 12; // padding
499
+ // ─── Parse Ticks footer ───────────────────────────────────────────────────
500
+ const market = readPubkey(); // 32 bytes
501
+ const feeGrowthIndexGlobalPt = readU128(); // 16 bytes
502
+ const feeGrowthIndexGlobalSy = readU128(); // 16 bytes
503
+ const currentPrefixSum = readU64(); // 8 bytes
504
+ const currentSpotPrice = readF64(); // 8 bytes
505
+ const currentTick = readU32(); // 4 bytes
506
+ skip(12); // padding
474
507
  return {
475
508
  ticksTree: ticks,
476
509
  market,
@@ -482,7 +515,50 @@ function deserializeMarketThreeTicks(data) {
482
515
  };
483
516
  }
484
517
  exports.deserializeMarketThreeTicks = deserializeMarketThreeTicks;
518
+ /** Decoded account may use snake_case (from JSON IDL); normalize to camelCase for app use. */
519
+ function normalizeCpiContext(a) {
520
+ return {
521
+ altIndex: a.altIndex ?? a.alt_index ?? 0,
522
+ isSigner: a.isSigner ?? a.is_signer ?? false,
523
+ isWritable: a.isWritable ?? a.is_writable ?? false,
524
+ };
525
+ }
526
+ function normalizeCpiAccountIndexes(raw) {
527
+ const arr = (key, snake) => {
528
+ const a = raw[key] ?? raw[snake];
529
+ return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x)) : [];
530
+ };
531
+ const arr2 = (key, snake) => {
532
+ const a = raw[key] ?? raw[snake];
533
+ return Array.isArray(a) ? a.map((inner) => (Array.isArray(inner) ? inner.map((x) => normalizeCpiContext(x)) : [])) : [];
534
+ };
535
+ return {
536
+ getSyState: arr("getSyState", "get_sy_state"),
537
+ withdrawSy: arr("withdrawSy", "withdraw_sy"),
538
+ depositSy: arr("depositSy", "deposit_sy"),
539
+ claimEmission: arr2("claimEmission", "claim_emission"),
540
+ getPositionState: arr("getPositionState", "get_position_state"),
541
+ };
542
+ }
543
+ function normalizeMarketCpiCoreIndexes(raw) {
544
+ const arr = (key, snake) => {
545
+ const a = raw[key] ?? raw[snake];
546
+ return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x)) : [];
547
+ };
548
+ return {
549
+ stripSy: arr("stripSy", "strip_sy"),
550
+ mergeSy: arr("mergeSy", "merge_sy"),
551
+ };
552
+ }
485
553
  function deserializeMarketThree(m) {
554
+ const rawCpiSy = m.cpiSyAccounts ?? m.cpi_sy_accounts;
555
+ const rawCpiCore = m.cpiCoreAccounts ?? m.cpi_core_accounts;
556
+ const cpiSyAccounts = rawCpiSy != null && typeof rawCpiSy === "object"
557
+ ? normalizeCpiAccountIndexes(rawCpiSy)
558
+ : (m.cpiSyAccounts ?? { getSyState: [], withdrawSy: [], depositSy: [], claimEmission: [], getPositionState: [] });
559
+ const cpiCoreAccounts = rawCpiCore != null && typeof rawCpiCore === "object"
560
+ ? normalizeMarketCpiCoreIndexes(rawCpiCore)
561
+ : (m.cpiCoreAccounts ?? { stripSy: [], mergeSy: [] });
486
562
  return {
487
563
  addressLookupTable: m.addressLookupTable,
488
564
  mintSy: m.mintSy,
@@ -495,7 +571,7 @@ function deserializeMarketThree(m) {
495
571
  selfAddress: m.selfAddress,
496
572
  syProgram: m.syProgram,
497
573
  statusFlags: m.statusFlags,
498
- cpiSyAccounts: m.cpiSyAccounts,
574
+ cpiSyAccounts,
499
575
  isCurrentFlashSwap: m.isCurrentFlashSwap,
500
576
  lpFarm: m.lpFarm,
501
577
  mintYt: m.mintYt,
@@ -524,10 +600,12 @@ function deserializeMarketThree(m) {
524
600
  syBalance: BigInt(m.financials.syBalance.toString()),
525
601
  liquidityBalance: BigInt(m.financials.liquidityBalance.toString()),
526
602
  },
527
- cpiCoreAccounts: m.cpiCoreAccounts,
603
+ cpiCoreAccounts,
528
604
  exponentCoreProgram: m.exponentCoreProgram,
605
+ seedId: m.seedId,
529
606
  };
530
607
  }
608
+ exports.deserializeMarketThree = deserializeMarketThree;
531
609
  function deserializeMarketTwo(m) {
532
610
  return {
533
611
  ptBalance: BigInt(m.financials.ptBalance.toString()),
@@ -584,7 +662,7 @@ function deserializeLpPositionCLMM(x) {
584
662
  tickIdx: tracker.tickIdx,
585
663
  rightTickIdx: tracker.rightTickIdx,
586
664
  splitEpoch: BigInt(tracker.splitEpoch.toString()),
587
- lpShare: BigInt(tracker.lpShare.toString()),
665
+ lpShare: anchorizedPNumToRawBigint(tracker.lpShare),
588
666
  emissions: tracker.emissions.trackers.map((e) => ({
589
667
  staged: BigInt(e.staged.toString()),
590
668
  lastSeenIndex: parseFloat(precise_number_1.PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
@@ -640,8 +718,8 @@ function deserializeOrderbook(data) {
640
718
  offset += 8;
641
719
  const priceDecimals = data.readUint8(offset);
642
720
  offset += 1;
643
- // Skip ConfigurationOptions padding: _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] = 111 bytes
644
- offset += 111;
721
+ // Skip ConfigurationOptions padding: _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] + _reserved[1024] = 1135 bytes
722
+ offset += 1135;
645
723
  // Pubkeys
646
724
  const vault = readPubkey();
647
725
  const yieldPosition = readPubkey();
@@ -653,7 +731,14 @@ function deserializeOrderbook(data) {
653
731
  const tokenEscrowPt = readPubkey();
654
732
  const cpiAccountOrderbook = readPubkey();
655
733
  const admin = readPubkey();
656
- // Skip last_sy_exchange_rate (Number type = 32 bytes)
734
+ // last_sy_exchange_rate (Number type = 32 bytes, PreciseNumber with 12 decimals)
735
+ const lastSyExchangeRateRaw = (() => {
736
+ let val = 0n;
737
+ for (let i = 0; i < 4; i++) {
738
+ val += data.readBigUInt64LE(offset + i * 8) << BigInt(i * 64);
739
+ }
740
+ return val;
741
+ })();
657
742
  offset += 32;
658
743
  // OrderbookFinancials struct
659
744
  // Skip last_seen_sy_index (Number type = 32 bytes)
@@ -694,11 +779,12 @@ function deserializeOrderbook(data) {
694
779
  };
695
780
  // console.log("financials", financials)
696
781
  // ─── Parse RedBlackTree slab ───────────────────────────────────────────────
697
- // repr(C) gives: root: u32, pad to align NodeAllocator’s u64, then the NodeAllocator header
782
+ // RedBlackTree struct: root: u32, _padding: [u32; 3], allocator: NodeAllocator<...>
783
+ // Total before allocator = 4 + 12 = 16 bytes
698
784
  const root = data.readUInt32LE(offset);
699
785
  offset += 4;
700
- const padTo8 = 8;
701
- offset += padTo8;
786
+ const padding = 12; // _padding: [u32; 3] in RedBlackTree struct
787
+ offset += padding;
702
788
  // NodeAllocator<T=RBNode<u32,PriceNode>, N=MAX_PRICE_NODES, R=3>
703
789
  // header: size:u64, bump_index:u32, free_list_head:u32
704
790
  const priceTreeSize = Number(data.readBigUInt64LE(offset));
@@ -736,9 +822,9 @@ function deserializeOrderbook(data) {
736
822
  // header: size:u64, bump_index:u32, free_list_head:u32
737
823
  const offersSize = Number(data.readBigUInt64LE(offset));
738
824
  offset += 8;
739
- const _offersBump = data.readUInt32LE(offset);
825
+ const offersBumpIndex = data.readUInt32LE(offset);
740
826
  offset += 4;
741
- const _offersFreeIdx = data.readUInt32LE(offset);
827
+ const offersFreeListHead = data.readUInt32LE(offset);
742
828
  offset += 4;
743
829
  const offers = [];
744
830
  for (let i = 0; i < exponent_types_2.MAX_OFFERS; i++) {
@@ -766,6 +852,7 @@ function deserializeOrderbook(data) {
766
852
  if (userVaultPointer === 0)
767
853
  continue;
768
854
  offers.push({
855
+ offerIndex: i + 1,
769
856
  nextOfferPointer,
770
857
  amount,
771
858
  userVaultPointer,
@@ -795,7 +882,12 @@ function deserializeOrderbook(data) {
795
882
  offset += 4;
796
883
  const user = new anchor_1.web3.PublicKey(data.slice(offset, offset + 32));
797
884
  offset += 32;
798
- /*const yieldIndex = data.readBigUInt64LE(offset).toString();*/ offset += 32;
885
+ const yieldIndexRaw = [[new anchor_1.BN(0), new anchor_1.BN(0), new anchor_1.BN(0), new anchor_1.BN(0)]];
886
+ for (let word = 0; word < 4; word++) {
887
+ yieldIndexRaw[0][word] = new anchor_1.BN(data.subarray(offset + word * 8, offset + (word + 1) * 8), "le");
888
+ }
889
+ const yieldIndex = deserializeAnchorizedPNum(yieldIndexRaw);
890
+ offset += 32;
799
891
  const ptAmount = data.readBigUInt64LE(offset);
800
892
  offset += 8;
801
893
  const syAmount = data.readBigUInt64LE(offset);
@@ -807,9 +899,8 @@ function deserializeOrderbook(data) {
807
899
  const staged = data.readBigInt64LE(offset);
808
900
  offset += 8;
809
901
  offset += 8; // reserved
810
- if (user.toBase58() == "11111111111111111111111111111111")
811
- continue;
812
- userEscrows.push({ user, yieldIndex: 0, ptAmount, syAmount, ytAmount, stakedYtAmount, staged });
902
+ // if (user.toBase58() == "11111111111111111111111111111111") continue
903
+ userEscrows.push({ user, yieldIndex, ptAmount, syAmount, ytAmount, stakedYtAmount, staged });
813
904
  }
814
905
  // ─── Finally, seed_id + signer_bump + reserved ─────────────────────────────
815
906
  // seed_id: [u8; 4]
@@ -836,11 +927,14 @@ function deserializeOrderbook(data) {
836
927
  tokenEscrowYt,
837
928
  tokenEscrowPt,
838
929
  cpiAccountOrderbook,
930
+ lastSyExchangeRate: lastSyExchangeRateRaw,
839
931
  financials,
840
932
  prices,
841
933
  configurationOptions,
842
934
  offers,
843
935
  userEscrows,
936
+ offersBumpIndex,
937
+ offersFreeListHead,
844
938
  };
845
939
  }
846
940
  function deserializeMarginfiSyMeta(x) {
@@ -966,6 +1060,16 @@ exports.deserializeEmission = deserializeEmission;
966
1060
  function deserializeAnchorizedPNum(x) {
967
1061
  return parseFloat(precise_number_1.PreciseNumber.fromRaw(x[0]).valueString);
968
1062
  }
1063
+ /** Convert PreciseNumber (Number type in Rust) from Anchor format to raw 256-bit bigint */
1064
+ function anchorizedPNumToRawBigint(pnum) {
1065
+ const bnArray = pnum[0];
1066
+ let val = 0n;
1067
+ for (let i = 0; i < 4; i++) {
1068
+ val += BigInt(bnArray[i].toString()) << BigInt(i * 64);
1069
+ }
1070
+ return val;
1071
+ }
1072
+ exports.anchorizedPNumToRawBigint = anchorizedPNumToRawBigint;
969
1073
  /** Fetch the exchange rate of a JitoRestaking vault's VRT to JitoSOL */
970
1074
  async function fetchJitoVaultData({ connection, vaultAddress, }) {
971
1075
  const vaultAccountInfo = await connection.getAccountInfo(vaultAddress);
@@ -1087,24 +1191,60 @@ async function fetchKaminoVaultIndex({ connection, kaminoVaultAccount, }) {
1087
1191
  const account = await connection.getAccountInfo(kaminoVaultAccount);
1088
1192
  const coder = new anchor_2.BorshCoder(kamino_vault_idl_1.IDL);
1089
1193
  const data = coder.accounts.decode("VaultState", account.data);
1090
- const activeReserves = data.vault_allocation_strategy
1091
- .map((r) => r.reserve)
1092
- .filter((reserve) => reserve.toBase58() !== anchor_1.web3.PublicKey.default.toBase58());
1093
- console.log("activeReserves", activeReserves);
1094
- const activeReservesData = await connection.getMultipleAccountsInfo(activeReserves);
1194
+ const activeAllocations = data.vault_allocation_strategy
1195
+ .filter((allocation) => allocation.reserve.toBase58() !== anchor_1.web3.PublicKey.default.toBase58());
1196
+ const activeReserves = activeAllocations.map((allocation) => allocation.reserve);
1197
+ const [activeReservesData, tokenMintInfo, sharesMintInfo] = await Promise.all([
1198
+ connection.getMultipleAccountsInfo(activeReserves),
1199
+ connection.getAccountInfo(data.token_mint),
1200
+ connection.getAccountInfo(data.shares_mint),
1201
+ ]);
1202
+ const decodedReserves = activeReservesData.map((accountInfo, index) => {
1203
+ if (!accountInfo?.data) {
1204
+ throw new Error(`Missing Kamino reserve account ${activeReserves[index].toBase58()}`);
1205
+ }
1206
+ return kamino_reserve_deserializer_1.Reserve.decode(accountInfo.data);
1207
+ });
1208
+ const collateralMintInfos = await connection.getMultipleAccountsInfo(decodedReserves.map((reserve) => reserve.collateral.mintPubkey));
1095
1209
  const reserves = activeReserves.map((r, i) => {
1096
- console.log("r.data", activeReservesData[i].data);
1210
+ const reserveAccount = decodedReserves[i];
1211
+ const allocation = activeAllocations[i];
1212
+ const [lendingMarketAuthority] = anchor_1.web3.PublicKey.findProgramAddressSync([Buffer.from("lma"), reserveAccount.lendingMarket.toBuffer()], new anchor_1.web3.PublicKey("KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD"));
1097
1213
  return {
1098
1214
  reserveAddress: r,
1099
- reserve: kamino_reserve_deserializer_1.Reserve.decode(activeReservesData[i].data).lendingMarket,
1215
+ marketAddress: reserveAccount.lendingMarket,
1216
+ ctokenVault: allocation.ctoken_vault,
1217
+ lendingMarketAuthority,
1218
+ pythOracle: reserveAccount.config.tokenInfo.pythConfiguration.price,
1219
+ switchboardPriceOracle: reserveAccount.config.tokenInfo.switchboardConfiguration.priceAggregator,
1220
+ switchboardTwapOracle: reserveAccount.config.tokenInfo.switchboardConfiguration.twapAggregator,
1221
+ scopePrices: reserveAccount.config.tokenInfo.scopeConfiguration.priceFeed,
1222
+ reserveLiquiditySupply: reserveAccount.liquidity.supplyVault,
1223
+ reserveCollateralMint: reserveAccount.collateral.mintPubkey,
1224
+ reserveCollateralTokenProgram: collateralMintInfos[i]?.owner ?? anchor_1.web3.PublicKey.default,
1100
1225
  };
1101
1226
  });
1102
- console.log("reserves", reserves);
1103
1227
  const tokenVault = data.token_vault;
1104
1228
  const tokenMint = data.token_mint;
1105
1229
  const baseVaultAuthority = data.base_vault_authority;
1106
1230
  const sharesMint = data.shares_mint;
1107
- return { index: 1, tokenVault, tokenMint, baseVaultAuthority, sharesMint, reserves };
1231
+ const vaultLookupTable = data.vault_lookup_table ?? anchor_1.web3.PublicKey.default;
1232
+ const tokenProgram = tokenMintInfo?.owner ?? anchor_1.web3.PublicKey.default;
1233
+ const sharesTokenProgram = sharesMintInfo?.owner ?? anchor_1.web3.PublicKey.default;
1234
+ return {
1235
+ index: 1,
1236
+ tokenVault,
1237
+ tokenMint,
1238
+ tokenProgram,
1239
+ // Kamino Vault withdraw expects the singleton program global config account.
1240
+ // It is not stored on VaultState, so fetch it from the known program-wide address.
1241
+ globalConfig: KAMINO_VAULT_GLOBAL_CONFIG,
1242
+ baseVaultAuthority,
1243
+ sharesMint,
1244
+ sharesTokenProgram,
1245
+ vaultLookupTable,
1246
+ reserves,
1247
+ };
1108
1248
  }
1109
1249
  exports.fetchKaminoVaultIndex = fetchKaminoVaultIndex;
1110
1250
  async function fetchFragmetricSupportedTokenIndex({ connection, fragmetricFund, index, }) {
@@ -1192,7 +1332,7 @@ async function fetchSolsticeRedemptionRate({ connection, yieldPool, vestingSched
1192
1332
  }
1193
1333
  exports.fetchSolsticeRedemptionRate = fetchSolsticeRedemptionRate;
1194
1334
  const REFLECT_ORACLE_LEN = 17;
1195
- const REFLECT_MAX_STALENESS_SLOTS = 150;
1335
+ const REFLECT_MAX_STALENESS_SLOTS = 15000000;
1196
1336
  async function fetchReflectRedemptionRate({ connection, oracle, }) {
1197
1337
  const accountInfo = await connection.getAccountInfo(oracle);
1198
1338
  if (!accountInfo) {
@@ -1236,4 +1376,14 @@ async function fetchOreExchangeRate({ connection, storeMint, stakeAccount, treas
1236
1376
  });
1237
1377
  }
1238
1378
  exports.fetchOreExchangeRate = fetchOreExchangeRate;
1379
+ async function fetchChainlinkRate({ connection, priceFeed, }) {
1380
+ const accountInfo = await connection.getAccountInfo(priceFeed);
1381
+ if (!accountInfo) {
1382
+ throw new Error("Chainlink price feed account not found");
1383
+ }
1384
+ const { answer, header } = (0, chainlink_idl_1.decodeChainlinkPriceAccount)(accountInfo);
1385
+ const scale = Math.pow(10, header.decimals);
1386
+ return Number(answer) / scale;
1387
+ }
1388
+ exports.fetchChainlinkRate = fetchChainlinkRate;
1239
1389
  //# sourceMappingURL=exponentFetcher.js.map