@exponent-labs/exponent-fetcher 0.1.7 → 0.9.0
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/build/constants.d.ts +26 -0
- package/build/constants.js +58 -0
- package/build/constants.js.map +1 -0
- package/build/exponentFetcher.d.ts +328 -31
- package/build/exponentFetcher.js +779 -168
- package/build/exponentFetcher.js.map +1 -1
- package/build/index.d.ts +11 -0
- package/build/index.js +11 -0
- package/build/index.js.map +1 -1
- package/build/utils/adrena.d.ts +13 -0
- package/build/utils/adrena.js +29 -0
- package/build/utils/adrena.js.map +1 -0
- package/build/utils/fragmetric.d.ts +17 -0
- package/build/utils/fragmetric.js +23 -0
- package/build/utils/fragmetric.js.map +1 -0
- package/build/utils/jito.d.ts +7 -0
- package/build/utils/jito.js +29 -0
- package/build/utils/jito.js.map +1 -0
- package/build/utils/jupiter.d.ts +30 -0
- package/build/utils/jupiter.js +63 -0
- package/build/utils/jupiter.js.map +1 -0
- package/build/utils/kamino.d.ts +5 -0
- package/build/utils/kamino.js +10 -0
- package/build/utils/kamino.js.map +1 -0
- package/build/utils/meteora.d.ts +19 -0
- package/build/utils/meteora.js +36 -1
- package/build/utils/meteora.js.map +1 -1
- package/build/utils/ore.d.ts +74 -0
- package/build/utils/ore.js +217 -0
- package/build/utils/ore.js.map +1 -0
- package/build/utils/perena.d.ts +12 -0
- package/build/utils/perena.js +27 -0
- package/build/utils/perena.js.map +1 -0
- package/build/utils/sanctum.d.ts +6 -0
- package/build/utils/sanctum.js +26 -0
- package/build/utils/sanctum.js.map +1 -0
- package/build/utils/solstice.d.ts +12 -0
- package/build/utils/solstice.js +45 -0
- package/build/utils/solstice.js.map +1 -0
- package/package.json +21 -18
- package/src/constants.ts +56 -0
- package/src/exponentFetcher.ts +1238 -222
- package/src/index.ts +11 -0
- package/src/utils/adrena.ts +44 -0
- package/src/utils/fragmetric.ts +34 -0
- package/src/utils/jito.ts +30 -0
- package/src/utils/jupiter.ts +98 -0
- package/src/utils/kamino.ts +6 -0
- package/src/utils/meteora.ts +73 -1
- package/src/utils/ore.ts +322 -0
- package/src/utils/perena.ts +28 -0
- package/src/utils/sanctum.ts +24 -0
- package/src/utils/solstice.ts +51 -0
- package/tsconfig.json +4 -1
package/build/exponentFetcher.js
CHANGED
|
@@ -3,18 +3,19 @@ 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.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.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
|
-
const
|
|
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");
|
|
14
|
+
const exponent_clmm_idl_1 = require("@exponent-labs/exponent-clmm-idl");
|
|
13
15
|
const exponent_idl_1 = require("@exponent-labs/exponent-idl");
|
|
16
|
+
const exponent_orderbook_idl_1 = require("@exponent-labs/exponent-orderbook-idl");
|
|
14
17
|
const exponent_types_1 = require("@exponent-labs/exponent-types");
|
|
15
|
-
const
|
|
16
|
-
const jupiter_lend_idl_1 = require("@exponent-labs/jupiter-lend-idl");
|
|
17
|
-
const kamino_vault_idl_1 = require("@exponent-labs/kamino-vault-idl");
|
|
18
|
+
const exponent_types_2 = require("@exponent-labs/exponent-types");
|
|
18
19
|
const generic_sy_idl_1 = require("@exponent-labs/generic-sy-idl");
|
|
19
20
|
const jito_restaking_sy_idl_1 = require("@exponent-labs/jito-restaking-sy-idl");
|
|
20
21
|
const jito_restaking_sy_idl_2 = require("@exponent-labs/jito-restaking-sy-idl");
|
|
@@ -22,17 +23,22 @@ const kamino_reserve_deserializer_1 = require("@exponent-labs/kamino-reserve-des
|
|
|
22
23
|
const kamino_reserve_deserializer_2 = require("@exponent-labs/kamino-reserve-deserializer");
|
|
23
24
|
const kamino_sy_idl_1 = require("@exponent-labs/kamino-sy-idl");
|
|
24
25
|
const kamino_sy_idl_2 = require("@exponent-labs/kamino-sy-idl");
|
|
26
|
+
const kamino_vault_idl_1 = require("@exponent-labs/kamino-vault-idl");
|
|
25
27
|
const marginfi_sy_idl_1 = require("@exponent-labs/marginfi-sy-idl");
|
|
26
28
|
const meteora_idl_1 = require("@exponent-labs/meteora-idl");
|
|
27
29
|
const perena_sy_idl_1 = require("@exponent-labs/perena-sy-idl");
|
|
28
30
|
const perena_sy_idl_2 = require("@exponent-labs/perena-sy-idl");
|
|
29
31
|
const precise_number_1 = require("@exponent-labs/precise-number");
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
32
|
+
const constants_1 = require("./constants");
|
|
33
|
+
const adrena_1 = require("./utils/adrena");
|
|
34
|
+
const fragmetric_1 = require("./utils/fragmetric");
|
|
35
|
+
const jito_1 = require("./utils/jito");
|
|
36
|
+
const jupiter_1 = require("./utils/jupiter");
|
|
33
37
|
const meteora_1 = require("./utils/meteora");
|
|
34
|
-
|
|
35
|
-
const
|
|
38
|
+
const ore_1 = require("./utils/ore");
|
|
39
|
+
const perena_1 = require("./utils/perena");
|
|
40
|
+
const sanctum_1 = require("./utils/sanctum");
|
|
41
|
+
const solstice_1 = require("./utils/solstice");
|
|
36
42
|
function serializeAnchorizedPNumFromJson(pnum) {
|
|
37
43
|
const serializedArray = pnum[0].map((bn) => bn.toString());
|
|
38
44
|
return { 0: serializedArray };
|
|
@@ -81,6 +87,8 @@ class ExponentFetcher {
|
|
|
81
87
|
jitoRestakingSyProgram;
|
|
82
88
|
perenaSyProgram;
|
|
83
89
|
genericStandardProgram;
|
|
90
|
+
exponentClmmProgram;
|
|
91
|
+
orderbookProgram;
|
|
84
92
|
connection;
|
|
85
93
|
coreProgramId;
|
|
86
94
|
marginfiSyProgramId;
|
|
@@ -105,6 +113,8 @@ class ExponentFetcher {
|
|
|
105
113
|
this.jitoRestakingSyProgram = new anchor_1.Program(jito_restaking_sy_idl_2.IDL, provider);
|
|
106
114
|
this.perenaSyProgram = new anchor_1.Program(perena_sy_idl_2.IDL, provider);
|
|
107
115
|
this.genericStandardProgram = new anchor_1.Program(generic_sy_idl_1.IDL, provider);
|
|
116
|
+
this.exponentClmmProgram = new anchor_1.Program(exponent_clmm_idl_1.IDL, provider);
|
|
117
|
+
this.orderbookProgram = new anchor_1.Program(exponent_orderbook_idl_1.IDL, provider);
|
|
108
118
|
}
|
|
109
119
|
async fetchVault(address) {
|
|
110
120
|
try {
|
|
@@ -128,6 +138,28 @@ class ExponentFetcher {
|
|
|
128
138
|
throw e;
|
|
129
139
|
}
|
|
130
140
|
}
|
|
141
|
+
async fetchOrderbook(address) {
|
|
142
|
+
try {
|
|
143
|
+
const o = (await this.connection.getAccountInfo(address)).data;
|
|
144
|
+
return deserializeOrderbook(o);
|
|
145
|
+
}
|
|
146
|
+
catch (e) {
|
|
147
|
+
console.error(`Error fetching orderbook ${address.toBase58()}`);
|
|
148
|
+
console.error(e);
|
|
149
|
+
throw e;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
async fetchOrderbookCpiAccounts(address) {
|
|
153
|
+
try {
|
|
154
|
+
const orderbookCpiAccounts = await this.orderbookProgram.account.cpiAccountsOrderbook.fetch(address);
|
|
155
|
+
return orderbookCpiAccounts;
|
|
156
|
+
}
|
|
157
|
+
catch (e) {
|
|
158
|
+
console.error(`Error fetching orderbook ${address.toBase58()}`);
|
|
159
|
+
console.error(e);
|
|
160
|
+
throw e;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
131
163
|
async fetchMarginfiSyMeta(address) {
|
|
132
164
|
const x = await this.marginfiSyProgram.account.syMeta.fetch(address);
|
|
133
165
|
return deserializeMarginfiSyMeta(x);
|
|
@@ -200,10 +232,59 @@ class ExponentFetcher {
|
|
|
200
232
|
const x = await this.program.account.lpPosition.fetch(address);
|
|
201
233
|
return deserializeLpPosition(x);
|
|
202
234
|
}
|
|
235
|
+
async fetchLpPositionCLMM(address) {
|
|
236
|
+
try {
|
|
237
|
+
const raw = await this.exponentClmmProgram.account.lpPosition.fetch(address);
|
|
238
|
+
const v = {
|
|
239
|
+
owner: raw.owner,
|
|
240
|
+
market: raw.market,
|
|
241
|
+
feeInsideLastPt: raw.feeInsideLastPt,
|
|
242
|
+
feeInsideLastSy: raw.feeInsideLastSy,
|
|
243
|
+
lpBalance: raw.lpBalance,
|
|
244
|
+
tokensOwedSy: raw.tokensOwedSy,
|
|
245
|
+
tokensOwedPt: raw.tokensOwedPt,
|
|
246
|
+
lowerTickIdx: raw.lowerTickIdx,
|
|
247
|
+
upperTickIdx: raw.upperTickIdx,
|
|
248
|
+
farms: {
|
|
249
|
+
trackers: raw.farms.trackers.map((t) => ({
|
|
250
|
+
staged: t.staged,
|
|
251
|
+
lastSeenIndex: t.lastSeenIndex,
|
|
252
|
+
})),
|
|
253
|
+
},
|
|
254
|
+
shareTrackers: {
|
|
255
|
+
trackers: raw.shareTrackers.trackers.map((tracker) => ({
|
|
256
|
+
tickIdx: tracker.tickIdx,
|
|
257
|
+
rightTickIdx: tracker.rightTickIdx,
|
|
258
|
+
splitEpoch: tracker.splitEpoch,
|
|
259
|
+
lpShare: tracker.lpShare,
|
|
260
|
+
emissions: {
|
|
261
|
+
trackers: tracker.emissions.trackers.map((e) => ({
|
|
262
|
+
staged: e.staged,
|
|
263
|
+
lastSeenIndex: e.lastSeenIndex,
|
|
264
|
+
})),
|
|
265
|
+
},
|
|
266
|
+
})),
|
|
267
|
+
},
|
|
268
|
+
};
|
|
269
|
+
return deserializeLpPositionCLMM(v);
|
|
270
|
+
}
|
|
271
|
+
catch (e) {
|
|
272
|
+
console.error(`Error fetching clmm lp position ${address.toBase58()}`);
|
|
273
|
+
console.error(e);
|
|
274
|
+
throw e;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
203
277
|
async fetchYtPosition(address) {
|
|
204
278
|
const x = await this.program.account.yieldTokenPosition.fetch(address);
|
|
205
279
|
return deserializeYtPosition(x);
|
|
206
280
|
}
|
|
281
|
+
/** Batch fetch multiple YT positions in a single RPC call */
|
|
282
|
+
async fetchYtPositions(addresses) {
|
|
283
|
+
if (addresses.length === 0)
|
|
284
|
+
return [];
|
|
285
|
+
const results = await this.program.account.yieldTokenPosition.fetchMultiple(addresses);
|
|
286
|
+
return results.map((x) => (x ? deserializeYtPosition(x) : null));
|
|
287
|
+
}
|
|
207
288
|
async fetchJitoRestakingSyMeta(address) {
|
|
208
289
|
const x = await this.jitoRestakingSyProgram.account.syMeta.fetch(address);
|
|
209
290
|
return (0, exponent_types_1.deserializeJitoRestakingSyMetaAccountRaw)(x);
|
|
@@ -216,8 +297,314 @@ class ExponentFetcher {
|
|
|
216
297
|
const x = await this.genericStandardProgram.account.syMeta.fetch(address);
|
|
217
298
|
return (0, exponent_types_1.deserializeGenericSyMetaAccountRaw)(x);
|
|
218
299
|
}
|
|
300
|
+
async fetchAllMarketThree() {
|
|
301
|
+
//TODO Replace with the following code when all damaged markets are removed onchain
|
|
302
|
+
// const marketsProgramAccounts: ProgramAccount<MarketThreeRaw>[] =
|
|
303
|
+
// await this.exponentClmmProgram.account.marketThree.all()
|
|
304
|
+
// return marketsProgramAccounts.map(({ account }) => deserializeMarketThree(account))
|
|
305
|
+
const MARKET_THREE_DISCRIMINATOR = Buffer.from([242, 240, 26, 15, 148, 186, 185, 205]);
|
|
306
|
+
const marketsProgramAccounts = await this.connection.getProgramAccounts(this.exponentClmmProgram.programId, {
|
|
307
|
+
filters: [
|
|
308
|
+
{
|
|
309
|
+
memcmp: {
|
|
310
|
+
offset: 0,
|
|
311
|
+
bytes: bs58_1.default.encode(MARKET_THREE_DISCRIMINATOR),
|
|
312
|
+
},
|
|
313
|
+
},
|
|
314
|
+
],
|
|
315
|
+
});
|
|
316
|
+
return marketsProgramAccounts
|
|
317
|
+
.filter(({ pubkey }) => !(0, constants_1.isMarketIgnored)(pubkey.toBase58()))
|
|
318
|
+
.map(({ account, pubkey }) => {
|
|
319
|
+
try {
|
|
320
|
+
return this.exponentClmmProgram.coder.accounts.decode("marketThree", account.data);
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
323
|
+
return null;
|
|
324
|
+
}
|
|
325
|
+
})
|
|
326
|
+
.filter((m) => !!m);
|
|
327
|
+
}
|
|
328
|
+
async fetchMarketThree(address) {
|
|
329
|
+
const addressStr = address.toBase58();
|
|
330
|
+
if ((0, constants_1.isMarketIgnored)(addressStr)) {
|
|
331
|
+
throw new constants_1.IgnoredClmmEntityError("market", addressStr);
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
const m = await this.exponentClmmProgram.account.marketThree.fetch(address);
|
|
335
|
+
return deserializeMarketThree(m);
|
|
336
|
+
}
|
|
337
|
+
catch (e) {
|
|
338
|
+
console.error(`Error fetching market ${addressStr}`);
|
|
339
|
+
console.error(e);
|
|
340
|
+
throw e;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
async fetchAllMarketThreeTicks() {
|
|
344
|
+
const TICKS_DISCRIMINATOR = Buffer.from([122, 104, 41, 141, 214, 36, 222, 37]);
|
|
345
|
+
const ticksAccounts = await this.connection.getProgramAccounts(this.exponentClmmProgram.programId, {
|
|
346
|
+
filters: [
|
|
347
|
+
{
|
|
348
|
+
memcmp: {
|
|
349
|
+
offset: 0,
|
|
350
|
+
bytes: bs58_1.default.encode(TICKS_DISCRIMINATOR),
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
],
|
|
354
|
+
});
|
|
355
|
+
return ticksAccounts
|
|
356
|
+
.filter(({ pubkey }) => !(0, constants_1.isTicksIgnored)(pubkey.toBase58()))
|
|
357
|
+
.map(({ account }) => deserializeMarketThreeTicks(account.data));
|
|
358
|
+
}
|
|
359
|
+
async fetchMarketThreeTicks(address) {
|
|
360
|
+
const addressStr = address.toBase58();
|
|
361
|
+
if ((0, constants_1.isTicksIgnored)(addressStr)) {
|
|
362
|
+
throw new constants_1.IgnoredClmmEntityError("ticks", addressStr);
|
|
363
|
+
}
|
|
364
|
+
try {
|
|
365
|
+
const m = (await this.connection.getAccountInfo(address)).data;
|
|
366
|
+
return deserializeMarketThreeTicks(m);
|
|
367
|
+
}
|
|
368
|
+
catch (e) {
|
|
369
|
+
console.error(`Error fetching ticks ${addressStr}`);
|
|
370
|
+
console.error(e);
|
|
371
|
+
throw e;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
219
374
|
}
|
|
220
375
|
exports.ExponentFetcher = ExponentFetcher;
|
|
376
|
+
/**
|
|
377
|
+
* Deserializes a CLMM Ticks account from raw buffer data.
|
|
378
|
+
*
|
|
379
|
+
* Layout matches Rust struct `Ticks` with `RedBlackTree<u32, Tick, 1000>`:
|
|
380
|
+
* - Discriminator: 8 bytes
|
|
381
|
+
* - RedBlackTree header: root(4) + padding(12) + size(8) + bump(4) + freeIdx(4) = 32 bytes
|
|
382
|
+
* - 1000 RBTree nodes, each: nodeHeader(16) + key(4) + padding(4) + Tick = variable bytes
|
|
383
|
+
* - Ticks footer: market(32) + feeGrowthPt(16) + feeGrowthSy(16) + prefixSum(8) + spotPrice(8) + currentTick(4) + padding(12) = 96 bytes
|
|
384
|
+
*/
|
|
385
|
+
function deserializeMarketThreeTicks(data) {
|
|
386
|
+
const MAX_TICK_NODES = 1000;
|
|
387
|
+
const PERSONAL_TICK_YIELD_TRACKER_SIZE = 2;
|
|
388
|
+
let offset = 8; // Skip discriminator
|
|
389
|
+
// ─── Helper functions ─────────────────────────────────────────────────────
|
|
390
|
+
const readU64 = () => {
|
|
391
|
+
const val = data.readBigUInt64LE(offset);
|
|
392
|
+
offset += 8;
|
|
393
|
+
return val;
|
|
394
|
+
};
|
|
395
|
+
const readU128 = () => {
|
|
396
|
+
const lo = data.readBigUInt64LE(offset);
|
|
397
|
+
const hi = data.readBigUInt64LE(offset + 8);
|
|
398
|
+
offset += 16;
|
|
399
|
+
return (hi << 64n) + lo;
|
|
400
|
+
};
|
|
401
|
+
const readI128 = () => {
|
|
402
|
+
const lo = data.readBigUInt64LE(offset);
|
|
403
|
+
const hi = data.readBigInt64LE(offset + 8); // High part is signed
|
|
404
|
+
offset += 16;
|
|
405
|
+
return (hi << 64n) + lo;
|
|
406
|
+
};
|
|
407
|
+
const readF64 = () => {
|
|
408
|
+
const val = data.readDoubleLE(offset);
|
|
409
|
+
offset += 8;
|
|
410
|
+
return val;
|
|
411
|
+
};
|
|
412
|
+
const readU32 = () => {
|
|
413
|
+
const val = data.readUInt32LE(offset);
|
|
414
|
+
offset += 4;
|
|
415
|
+
return val;
|
|
416
|
+
};
|
|
417
|
+
const readPubkey = () => {
|
|
418
|
+
const pk = new anchor_1.web3.PublicKey(data.slice(offset, offset + 32));
|
|
419
|
+
offset += 32;
|
|
420
|
+
return pk;
|
|
421
|
+
};
|
|
422
|
+
/** Reads a PreciseNumber (Number type in Rust) as float - 32 bytes (4 x u64) */
|
|
423
|
+
const readPreciseNumberAsFloat = () => {
|
|
424
|
+
const nums = [];
|
|
425
|
+
for (let i = 0; i < 4; i++) {
|
|
426
|
+
nums.push(new anchor_1.BN(data.slice(offset + i * 8, offset + (i + 1) * 8), undefined, "le"));
|
|
427
|
+
}
|
|
428
|
+
offset += 32;
|
|
429
|
+
return parseFloat(precise_number_1.PreciseNumber.fromRaw(nums).valueString);
|
|
430
|
+
};
|
|
431
|
+
/** Reads a PreciseNumber (Number type in Rust) as raw bigint - 32 bytes (4 x u64 = 256 bits) */
|
|
432
|
+
const readPreciseNumberAsBigint = () => {
|
|
433
|
+
let val = 0n;
|
|
434
|
+
for (let i = 0; i < 4; i++) {
|
|
435
|
+
const chunk = data.readBigUInt64LE(offset + i * 8);
|
|
436
|
+
val += chunk << BigInt(i * 64);
|
|
437
|
+
}
|
|
438
|
+
offset += 32;
|
|
439
|
+
return val;
|
|
440
|
+
};
|
|
441
|
+
const skip = (bytes) => {
|
|
442
|
+
offset += bytes;
|
|
443
|
+
};
|
|
444
|
+
// ─── Parse RedBlackTree header ────────────────────────────────────────────
|
|
445
|
+
skip(4); // root: u32
|
|
446
|
+
skip(12); // padding to align NodeAllocator
|
|
447
|
+
skip(8); // size: u64
|
|
448
|
+
skip(4); // bump_index: u32
|
|
449
|
+
skip(4); // free_list_head: u32
|
|
450
|
+
// ─── Parse tick nodes ─────────────────────────────────────────────────────
|
|
451
|
+
const ticks = [];
|
|
452
|
+
for (let i = 0; i < MAX_TICK_NODES; i++) {
|
|
453
|
+
// RBNode header: left(4) + right(4) + parent(4) + color(4) = 16 bytes
|
|
454
|
+
skip(16);
|
|
455
|
+
// Key: u32 + padding to 8 bytes
|
|
456
|
+
const apyBasePoints = readU32();
|
|
457
|
+
skip(4); // padding
|
|
458
|
+
// Tick value (416 bytes total)
|
|
459
|
+
const feeGrowthOutsidePt = readU128(); // 16 bytes
|
|
460
|
+
const feeGrowthOutsideSy = readU128(); // 16 bytes
|
|
461
|
+
const liquidityNet = readI128(); // 16 bytes
|
|
462
|
+
const liquidityGross = readU64(); // 8 bytes
|
|
463
|
+
const spotPrice = readF64(); // 8 bytes
|
|
464
|
+
const principalPt = readU64(); // 8 bytes
|
|
465
|
+
const principalSy = readU64(); // 8 bytes
|
|
466
|
+
const principalShareSupply = readPreciseNumberAsBigint(); // 32 bytes - kept as bigint for arithmetic
|
|
467
|
+
// FarmYieldTrackers: 2 x FarmYieldTracker(32 bytes) = 64 bytes
|
|
468
|
+
const farms = [];
|
|
469
|
+
for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
|
|
470
|
+
farms.push({ lastSeenIndex: readPreciseNumberAsFloat() });
|
|
471
|
+
}
|
|
472
|
+
// EmissionYieldTrackers: 2 x EmissionYieldTracker(64 bytes) = 128 bytes
|
|
473
|
+
const emissions = [];
|
|
474
|
+
for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
|
|
475
|
+
emissions.push({
|
|
476
|
+
lastSeenIndex: readPreciseNumberAsFloat(),
|
|
477
|
+
lastPositionIndex: readPreciseNumberAsFloat(),
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
const lastSplitEpoch = readU64(); // 8 bytes
|
|
481
|
+
const frozenLiquidity = readU64(); // 8 bytes
|
|
482
|
+
ticks.push({
|
|
483
|
+
apyBasePoints,
|
|
484
|
+
liquidityNet,
|
|
485
|
+
feeGrowthOutsidePt,
|
|
486
|
+
feeGrowthOutsideSy,
|
|
487
|
+
liquidityGross,
|
|
488
|
+
impliedRate: spotPrice, // Legacy field name kept for compatibility
|
|
489
|
+
principalPt,
|
|
490
|
+
principalSy,
|
|
491
|
+
principalShareSupply,
|
|
492
|
+
farms,
|
|
493
|
+
emissions,
|
|
494
|
+
lastSplitEpoch,
|
|
495
|
+
frozenLiquidity,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
// ─── Parse Ticks footer ───────────────────────────────────────────────────
|
|
499
|
+
const market = readPubkey(); // 32 bytes
|
|
500
|
+
const feeGrowthIndexGlobalPt = readU128(); // 16 bytes
|
|
501
|
+
const feeGrowthIndexGlobalSy = readU128(); // 16 bytes
|
|
502
|
+
const currentPrefixSum = readU64(); // 8 bytes
|
|
503
|
+
const currentSpotPrice = readF64(); // 8 bytes
|
|
504
|
+
const currentTick = readU32(); // 4 bytes
|
|
505
|
+
skip(12); // padding
|
|
506
|
+
return {
|
|
507
|
+
ticksTree: ticks,
|
|
508
|
+
market,
|
|
509
|
+
feeGrowthIndexGlobalPt,
|
|
510
|
+
feeGrowthIndexGlobalSy,
|
|
511
|
+
currentPrefixSum,
|
|
512
|
+
currentSpotPrice,
|
|
513
|
+
currentTick,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
exports.deserializeMarketThreeTicks = deserializeMarketThreeTicks;
|
|
517
|
+
/** Decoded account may use snake_case (from JSON IDL); normalize to camelCase for app use. */
|
|
518
|
+
function normalizeCpiContext(a) {
|
|
519
|
+
return {
|
|
520
|
+
altIndex: a.altIndex ?? a.alt_index ?? 0,
|
|
521
|
+
isSigner: a.isSigner ?? a.is_signer ?? false,
|
|
522
|
+
isWritable: a.isWritable ?? a.is_writable ?? false,
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function normalizeCpiAccountIndexes(raw) {
|
|
526
|
+
const arr = (key, snake) => {
|
|
527
|
+
const a = raw[key] ?? raw[snake];
|
|
528
|
+
return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x)) : [];
|
|
529
|
+
};
|
|
530
|
+
const arr2 = (key, snake) => {
|
|
531
|
+
const a = raw[key] ?? raw[snake];
|
|
532
|
+
return Array.isArray(a) ? a.map((inner) => (Array.isArray(inner) ? inner.map((x) => normalizeCpiContext(x)) : [])) : [];
|
|
533
|
+
};
|
|
534
|
+
return {
|
|
535
|
+
getSyState: arr("getSyState", "get_sy_state"),
|
|
536
|
+
withdrawSy: arr("withdrawSy", "withdraw_sy"),
|
|
537
|
+
depositSy: arr("depositSy", "deposit_sy"),
|
|
538
|
+
claimEmission: arr2("claimEmission", "claim_emission"),
|
|
539
|
+
getPositionState: arr("getPositionState", "get_position_state"),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function normalizeMarketCpiCoreIndexes(raw) {
|
|
543
|
+
const arr = (key, snake) => {
|
|
544
|
+
const a = raw[key] ?? raw[snake];
|
|
545
|
+
return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x)) : [];
|
|
546
|
+
};
|
|
547
|
+
return {
|
|
548
|
+
stripSy: arr("stripSy", "strip_sy"),
|
|
549
|
+
mergeSy: arr("mergeSy", "merge_sy"),
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function deserializeMarketThree(m) {
|
|
553
|
+
const rawCpiSy = m.cpiSyAccounts ?? m.cpi_sy_accounts;
|
|
554
|
+
const rawCpiCore = m.cpiCoreAccounts ?? m.cpi_core_accounts;
|
|
555
|
+
const cpiSyAccounts = rawCpiSy != null && typeof rawCpiSy === "object"
|
|
556
|
+
? normalizeCpiAccountIndexes(rawCpiSy)
|
|
557
|
+
: (m.cpiSyAccounts ?? { getSyState: [], withdrawSy: [], depositSy: [], claimEmission: [], getPositionState: [] });
|
|
558
|
+
const cpiCoreAccounts = rawCpiCore != null && typeof rawCpiCore === "object"
|
|
559
|
+
? normalizeMarketCpiCoreIndexes(rawCpiCore)
|
|
560
|
+
: (m.cpiCoreAccounts ?? { stripSy: [], mergeSy: [] });
|
|
561
|
+
return {
|
|
562
|
+
addressLookupTable: m.addressLookupTable,
|
|
563
|
+
mintSy: m.mintSy,
|
|
564
|
+
mintPt: m.mintPt,
|
|
565
|
+
vault: m.vault,
|
|
566
|
+
tokenSyEscrow: m.tokenSyEscrow,
|
|
567
|
+
tokenPtEscrow: m.tokenPtEscrow,
|
|
568
|
+
tokenFeeTreasurySy: m.tokenFeeTreasurySy,
|
|
569
|
+
tokenFeeTreasuryPt: m.tokenFeeTreasuryPt,
|
|
570
|
+
selfAddress: m.selfAddress,
|
|
571
|
+
syProgram: m.syProgram,
|
|
572
|
+
statusFlags: m.statusFlags,
|
|
573
|
+
cpiSyAccounts,
|
|
574
|
+
isCurrentFlashSwap: m.isCurrentFlashSwap,
|
|
575
|
+
lpFarm: m.lpFarm,
|
|
576
|
+
mintYt: m.mintYt,
|
|
577
|
+
tokenYtEscrow: m.tokenYtEscrow,
|
|
578
|
+
emissions: {
|
|
579
|
+
trackers: m.emissions.trackers.map((t) => ({
|
|
580
|
+
tokenEscrow: t.tokenEscrow,
|
|
581
|
+
lpShareIndex: deserializeAnchorizedPNum(t.lpShareIndex),
|
|
582
|
+
lastSeenStaged: Number(t.lastSeenStaged),
|
|
583
|
+
})),
|
|
584
|
+
},
|
|
585
|
+
liquidityNetBalanceLimits: m.liquidityNetBalanceLimits,
|
|
586
|
+
admin: m.admin,
|
|
587
|
+
ticks: m.ticks,
|
|
588
|
+
configurationOptions: {
|
|
589
|
+
lnFeeRateRoot: m.configurationOptions.lnFeeRateRoot,
|
|
590
|
+
treasuryFeeBps: m.configurationOptions.treasuryFeeBps,
|
|
591
|
+
minLpTickAmount: BigInt(m.configurationOptions.minLpTickAmount.toString()),
|
|
592
|
+
epsilonClamp: m.configurationOptions.epsilonClamp,
|
|
593
|
+
maxLpSupply: BigInt(m.configurationOptions.maxLpSupply.toString()),
|
|
594
|
+
tickSpace: m.configurationOptions.tickSpace,
|
|
595
|
+
},
|
|
596
|
+
financials: {
|
|
597
|
+
expirationTs: BigInt(m.financials.expirationTs),
|
|
598
|
+
ptBalance: BigInt(m.financials.ptBalance.toString()),
|
|
599
|
+
syBalance: BigInt(m.financials.syBalance.toString()),
|
|
600
|
+
liquidityBalance: BigInt(m.financials.liquidityBalance.toString()),
|
|
601
|
+
},
|
|
602
|
+
cpiCoreAccounts,
|
|
603
|
+
exponentCoreProgram: m.exponentCoreProgram,
|
|
604
|
+
seedId: m.seedId,
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
exports.deserializeMarketThree = deserializeMarketThree;
|
|
221
608
|
function deserializeMarketTwo(m) {
|
|
222
609
|
return {
|
|
223
610
|
ptBalance: BigInt(m.financials.ptBalance.toString()),
|
|
@@ -255,6 +642,33 @@ function deserializeMarketTwo(m) {
|
|
|
255
642
|
seedId: m.seedId,
|
|
256
643
|
};
|
|
257
644
|
}
|
|
645
|
+
function deserializeLpPositionCLMM(x) {
|
|
646
|
+
return {
|
|
647
|
+
owner: x.owner,
|
|
648
|
+
market: x.market,
|
|
649
|
+
feeInsideLastPt: BigInt(x.feeInsideLastPt.toString()),
|
|
650
|
+
feeInsideLastSy: BigInt(x.feeInsideLastSy.toString()),
|
|
651
|
+
lpBalance: BigInt(x.lpBalance.toString()),
|
|
652
|
+
tokensOwedSy: BigInt(x.tokensOwedSy.toString()),
|
|
653
|
+
tokensOwedPt: BigInt(x.tokensOwedPt.toString()),
|
|
654
|
+
lowerTickIdx: x.lowerTickIdx,
|
|
655
|
+
upperTickIdx: x.upperTickIdx,
|
|
656
|
+
farms: x.farms.trackers.map((t) => ({
|
|
657
|
+
staged: BigInt(t.staged.toString()),
|
|
658
|
+
lastSeenIndex: parseFloat(precise_number_1.PreciseNumber.fromRaw(t.lastSeenIndex[0]).valueString),
|
|
659
|
+
})),
|
|
660
|
+
shareTrackers: x.shareTrackers.trackers.map((tracker) => ({
|
|
661
|
+
tickIdx: tracker.tickIdx,
|
|
662
|
+
rightTickIdx: tracker.rightTickIdx,
|
|
663
|
+
splitEpoch: BigInt(tracker.splitEpoch.toString()),
|
|
664
|
+
lpShare: anchorizedPNumToRawBigint(tracker.lpShare),
|
|
665
|
+
emissions: tracker.emissions.trackers.map((e) => ({
|
|
666
|
+
staged: BigInt(e.staged.toString()),
|
|
667
|
+
lastSeenIndex: parseFloat(precise_number_1.PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
|
|
668
|
+
})),
|
|
669
|
+
})),
|
|
670
|
+
};
|
|
671
|
+
}
|
|
258
672
|
function deserializeVault(x) {
|
|
259
673
|
return {
|
|
260
674
|
syProgram: x.syProgram,
|
|
@@ -285,6 +699,243 @@ function deserializeVault(x) {
|
|
|
285
699
|
maxPySupply: BigInt(x.maxPySupply.toString()),
|
|
286
700
|
};
|
|
287
701
|
}
|
|
702
|
+
function deserializeOrderbook(data) {
|
|
703
|
+
let offset = 0;
|
|
704
|
+
// 1) Skip Anchor discriminator
|
|
705
|
+
offset += anchor_1.DISCRIMINATOR_SIZE;
|
|
706
|
+
const readPubkey = () => {
|
|
707
|
+
const pk = new anchor_1.web3.PublicKey(data.slice(offset, offset + 32));
|
|
708
|
+
offset += 32;
|
|
709
|
+
return pk;
|
|
710
|
+
};
|
|
711
|
+
// ConfigurationOptions struct
|
|
712
|
+
const thresholdAmount = data.readBigUInt64LE(offset);
|
|
713
|
+
offset += 8;
|
|
714
|
+
const lnMakerFeeRate = data.readDoubleLE(offset);
|
|
715
|
+
offset += 8;
|
|
716
|
+
const lnTakerFeeRate = data.readDoubleLE(offset);
|
|
717
|
+
offset += 8;
|
|
718
|
+
const priceDecimals = data.readUint8(offset);
|
|
719
|
+
offset += 1;
|
|
720
|
+
// Skip ConfigurationOptions padding: _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] + _reserved[1024] = 1135 bytes
|
|
721
|
+
offset += 1135;
|
|
722
|
+
// Pubkeys
|
|
723
|
+
const vault = readPubkey();
|
|
724
|
+
const yieldPosition = readPubkey();
|
|
725
|
+
const addressLookupTable = readPubkey();
|
|
726
|
+
const exponentCoreProgram = readPubkey();
|
|
727
|
+
const syProgram = readPubkey();
|
|
728
|
+
const tokenEscrowSy = readPubkey();
|
|
729
|
+
const tokenEscrowYt = readPubkey();
|
|
730
|
+
const tokenEscrowPt = readPubkey();
|
|
731
|
+
const cpiAccountOrderbook = readPubkey();
|
|
732
|
+
const admin = readPubkey();
|
|
733
|
+
// last_sy_exchange_rate (Number type = 32 bytes, PreciseNumber with 12 decimals)
|
|
734
|
+
const lastSyExchangeRateRaw = (() => {
|
|
735
|
+
let val = 0n;
|
|
736
|
+
for (let i = 0; i < 4; i++) {
|
|
737
|
+
val += data.readBigUInt64LE(offset + i * 8) << BigInt(i * 64);
|
|
738
|
+
}
|
|
739
|
+
return val;
|
|
740
|
+
})();
|
|
741
|
+
offset += 32;
|
|
742
|
+
// OrderbookFinancials struct
|
|
743
|
+
// Skip last_seen_sy_index (Number type = 32 bytes)
|
|
744
|
+
offset += 32;
|
|
745
|
+
const ytBalance = data.readBigUInt64LE(offset);
|
|
746
|
+
offset += 8;
|
|
747
|
+
const syBalance = data.readBigUInt64LE(offset);
|
|
748
|
+
offset += 8;
|
|
749
|
+
const ptBalance = data.readBigUInt64LE(offset);
|
|
750
|
+
offset += 8;
|
|
751
|
+
const ytFeeBalance = data.readBigUInt64LE(offset);
|
|
752
|
+
offset += 8;
|
|
753
|
+
const syFeeBalance = data.readBigUInt64LE(offset);
|
|
754
|
+
offset += 8;
|
|
755
|
+
const ptFeeBalance = data.readBigUInt64LE(offset);
|
|
756
|
+
offset += 8;
|
|
757
|
+
const stagedSyBalance = data.readBigUInt64LE(offset);
|
|
758
|
+
offset += 8;
|
|
759
|
+
const expirationTs = data.readUInt32LE(offset);
|
|
760
|
+
offset += 4;
|
|
761
|
+
// Skip financials _padding: [u8; 4]
|
|
762
|
+
offset += 4;
|
|
763
|
+
const configurationOptions = {
|
|
764
|
+
priceDecimals,
|
|
765
|
+
thresholdAmount,
|
|
766
|
+
lnMakerFeeRate,
|
|
767
|
+
lnTakerFeeRate,
|
|
768
|
+
};
|
|
769
|
+
const financials = {
|
|
770
|
+
expirationTs,
|
|
771
|
+
syBalance: syBalance,
|
|
772
|
+
ytBalance: ytBalance,
|
|
773
|
+
ptBalance: ptBalance,
|
|
774
|
+
ytFeeBalance,
|
|
775
|
+
syFeeBalance,
|
|
776
|
+
ptFeeBalance,
|
|
777
|
+
stagedSy: stagedSyBalance,
|
|
778
|
+
};
|
|
779
|
+
// console.log("financials", financials)
|
|
780
|
+
// ─── Parse RedBlackTree slab ───────────────────────────────────────────────
|
|
781
|
+
// RedBlackTree struct: root: u32, _padding: [u32; 3], allocator: NodeAllocator<...>
|
|
782
|
+
// Total before allocator = 4 + 12 = 16 bytes
|
|
783
|
+
const root = data.readUInt32LE(offset);
|
|
784
|
+
offset += 4;
|
|
785
|
+
const padding = 12; // _padding: [u32; 3] in RedBlackTree struct
|
|
786
|
+
offset += padding;
|
|
787
|
+
// NodeAllocator<T=RBNode<u32,PriceNode>, N=MAX_PRICE_NODES, R=3>
|
|
788
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
789
|
+
const priceTreeSize = Number(data.readBigUInt64LE(offset));
|
|
790
|
+
offset += 8;
|
|
791
|
+
const _priceTreeBump = data.readUInt32LE(offset);
|
|
792
|
+
offset += 4;
|
|
793
|
+
const _priceTreeFreeIdx = data.readUInt32LE(offset);
|
|
794
|
+
offset += 4;
|
|
795
|
+
// each RBNode entry = registers[3] + key:u32 + first_offer:u32
|
|
796
|
+
const prices = [];
|
|
797
|
+
for (let i = 0; i < exponent_types_2.MAX_PRICE_NODES; i++) {
|
|
798
|
+
const left = data.readUInt32LE(offset);
|
|
799
|
+
offset += 4;
|
|
800
|
+
const right = data.readUInt32LE(offset);
|
|
801
|
+
offset += 4;
|
|
802
|
+
const parent = data.readUInt32LE(offset);
|
|
803
|
+
offset += 4;
|
|
804
|
+
offset += 4; // skip color
|
|
805
|
+
const key = data.readUInt32LE(offset);
|
|
806
|
+
offset += 4;
|
|
807
|
+
const firstOfferSellYt = data.readUInt32LE(offset);
|
|
808
|
+
offset += 4;
|
|
809
|
+
const firstOfferBuyYt = data.readUInt32LE(offset);
|
|
810
|
+
offset += 4;
|
|
811
|
+
const lastOfferSellYt = data.readUInt32LE(offset);
|
|
812
|
+
offset += 4;
|
|
813
|
+
const lastOfferBuyYt = data.readUInt32LE(offset);
|
|
814
|
+
offset += 4;
|
|
815
|
+
if (key === 0)
|
|
816
|
+
continue;
|
|
817
|
+
prices.push({ key, firstOfferSellYt, firstOfferBuyYt, lastOfferSellYt, lastOfferBuyYt, parent, left, right });
|
|
818
|
+
}
|
|
819
|
+
// ─── Parse Offers slab ────────────────────────────────────────────────────
|
|
820
|
+
// NodeAllocator<Offer, MAX_OFFERS, 4>
|
|
821
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
822
|
+
const offersSize = Number(data.readBigUInt64LE(offset));
|
|
823
|
+
offset += 8;
|
|
824
|
+
const offersBumpIndex = data.readUInt32LE(offset);
|
|
825
|
+
offset += 4;
|
|
826
|
+
const offersFreeListHead = data.readUInt32LE(offset);
|
|
827
|
+
offset += 4;
|
|
828
|
+
const offers = [];
|
|
829
|
+
for (let i = 0; i < exponent_types_2.MAX_OFFERS; i++) {
|
|
830
|
+
const register = data.readUInt32LE(offset);
|
|
831
|
+
offset += 4;
|
|
832
|
+
const nextOfferPointer = data.readUInt32LE(offset);
|
|
833
|
+
offset += 4;
|
|
834
|
+
const userVaultPointer = data.readUInt32LE(offset);
|
|
835
|
+
offset += 4;
|
|
836
|
+
const pricePointer = data.readUInt32LE(offset);
|
|
837
|
+
offset += 4;
|
|
838
|
+
const amount = data.readBigUInt64LE(offset);
|
|
839
|
+
offset += 8;
|
|
840
|
+
const expiryAt = data.readUInt32LE(offset);
|
|
841
|
+
offset += 4;
|
|
842
|
+
const createdAt = data.readUInt32LE(offset);
|
|
843
|
+
offset += 4;
|
|
844
|
+
const virtualOffer = data.readUInt8(offset) !== 0;
|
|
845
|
+
offset += 1;
|
|
846
|
+
const orderTypeFlag = data.readUInt8(offset);
|
|
847
|
+
offset += 1;
|
|
848
|
+
const fillOrKill = data.readUInt8(offset) !== 0;
|
|
849
|
+
offset += 1;
|
|
850
|
+
offset += 5; // reserved padding
|
|
851
|
+
if (userVaultPointer === 0)
|
|
852
|
+
continue;
|
|
853
|
+
offers.push({
|
|
854
|
+
offerIndex: i + 1,
|
|
855
|
+
nextOfferPointer,
|
|
856
|
+
amount,
|
|
857
|
+
userVaultPointer,
|
|
858
|
+
expiryAt,
|
|
859
|
+
createdAt,
|
|
860
|
+
virtualOffer,
|
|
861
|
+
orderTypeFlag,
|
|
862
|
+
fillOrKill,
|
|
863
|
+
pricePointer,
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
// ─── Parse UserEscrow slab ────────────────────────────────────────────────
|
|
867
|
+
// NodeAllocator<UserEscrow, MAX_USER_ESCROWS, 2>
|
|
868
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
869
|
+
const escSize = Number(data.readBigUInt64LE(offset));
|
|
870
|
+
offset += 8;
|
|
871
|
+
const _escBump = data.readUInt32LE(offset);
|
|
872
|
+
offset += 4;
|
|
873
|
+
const _escFreeIdx = data.readUInt32LE(offset);
|
|
874
|
+
offset += 4;
|
|
875
|
+
// each Node = [ no registers ] + UserEscrow.value
|
|
876
|
+
const userEscrows = [];
|
|
877
|
+
for (let i = 0; i < exponent_types_2.MAX_USER_ESCROWS; i++) {
|
|
878
|
+
const register = data.readUInt32LE(offset);
|
|
879
|
+
offset += 4;
|
|
880
|
+
const register2 = data.readUInt32LE(offset);
|
|
881
|
+
offset += 4;
|
|
882
|
+
const user = new anchor_1.web3.PublicKey(data.slice(offset, offset + 32));
|
|
883
|
+
offset += 32;
|
|
884
|
+
const yieldIndexRaw = [[new anchor_1.BN(0), new anchor_1.BN(0), new anchor_1.BN(0), new anchor_1.BN(0)]];
|
|
885
|
+
for (let word = 0; word < 4; word++) {
|
|
886
|
+
yieldIndexRaw[0][word] = new anchor_1.BN(data.subarray(offset + word * 8, offset + (word + 1) * 8), "le");
|
|
887
|
+
}
|
|
888
|
+
const yieldIndex = deserializeAnchorizedPNum(yieldIndexRaw);
|
|
889
|
+
offset += 32;
|
|
890
|
+
const ptAmount = data.readBigUInt64LE(offset);
|
|
891
|
+
offset += 8;
|
|
892
|
+
const syAmount = data.readBigUInt64LE(offset);
|
|
893
|
+
offset += 8;
|
|
894
|
+
const ytAmount = data.readBigUInt64LE(offset);
|
|
895
|
+
offset += 8;
|
|
896
|
+
const stakedYtAmount = data.readBigInt64LE(offset);
|
|
897
|
+
offset += 8;
|
|
898
|
+
const staged = data.readBigInt64LE(offset);
|
|
899
|
+
offset += 8;
|
|
900
|
+
offset += 8; // reserved
|
|
901
|
+
// if (user.toBase58() == "11111111111111111111111111111111") continue
|
|
902
|
+
userEscrows.push({ user, yieldIndex, ptAmount, syAmount, ytAmount, stakedYtAmount, staged });
|
|
903
|
+
}
|
|
904
|
+
// ─── Finally, seed_id + signer_bump + reserved ─────────────────────────────
|
|
905
|
+
// seed_id: [u8; 4]
|
|
906
|
+
const seedId = [
|
|
907
|
+
data.readUInt8(offset),
|
|
908
|
+
data.readUInt8(offset + 1),
|
|
909
|
+
data.readUInt8(offset + 2),
|
|
910
|
+
data.readUInt8(offset + 3),
|
|
911
|
+
];
|
|
912
|
+
offset += 4;
|
|
913
|
+
// signer_bump: [u8; 1]
|
|
914
|
+
const signerBump = data.readUInt8(offset);
|
|
915
|
+
offset += 1;
|
|
916
|
+
// _reserved: [u8; 3] - skip
|
|
917
|
+
offset += 3;
|
|
918
|
+
return {
|
|
919
|
+
vault,
|
|
920
|
+
yieldPosition,
|
|
921
|
+
addressLookupTable,
|
|
922
|
+
exponentCoreProgram,
|
|
923
|
+
syProgram,
|
|
924
|
+
admin,
|
|
925
|
+
tokenEscrowSy,
|
|
926
|
+
tokenEscrowYt,
|
|
927
|
+
tokenEscrowPt,
|
|
928
|
+
cpiAccountOrderbook,
|
|
929
|
+
lastSyExchangeRate: lastSyExchangeRateRaw,
|
|
930
|
+
financials,
|
|
931
|
+
prices,
|
|
932
|
+
configurationOptions,
|
|
933
|
+
offers,
|
|
934
|
+
userEscrows,
|
|
935
|
+
offersBumpIndex,
|
|
936
|
+
offersFreeListHead,
|
|
937
|
+
};
|
|
938
|
+
}
|
|
288
939
|
function deserializeMarginfiSyMeta(x) {
|
|
289
940
|
return {
|
|
290
941
|
...x,
|
|
@@ -320,6 +971,7 @@ function deserializeLpPosition(x) {
|
|
|
320
971
|
})),
|
|
321
972
|
};
|
|
322
973
|
}
|
|
974
|
+
exports.deserializeLpPosition = deserializeLpPosition;
|
|
323
975
|
function deserializeYtPosition(x) {
|
|
324
976
|
return {
|
|
325
977
|
owner: x.owner,
|
|
@@ -329,6 +981,7 @@ function deserializeYtPosition(x) {
|
|
|
329
981
|
emissions: x.emissions.map(deserializeYieldTokenTracker),
|
|
330
982
|
};
|
|
331
983
|
}
|
|
984
|
+
exports.deserializeYtPosition = deserializeYtPosition;
|
|
332
985
|
function deserializeYieldTokenTracker(x) {
|
|
333
986
|
return {
|
|
334
987
|
staged: BigInt(x.staged.toString()),
|
|
@@ -340,10 +993,13 @@ async function fetchKaminoReserve(address, connection) {
|
|
|
340
993
|
if (!reserve) {
|
|
341
994
|
throw new Error("Reserve not found");
|
|
342
995
|
}
|
|
996
|
+
const rawScopePriceFeed = reserve.config.tokenInfo.scopeConfiguration.priceFeed;
|
|
997
|
+
const scopePriceFeed = rawScopePriceFeed.equals(anchor_1.web3.PublicKey.default) ? undefined : rawScopePriceFeed;
|
|
343
998
|
return {
|
|
344
999
|
lendingMarket: reserve.lendingMarket,
|
|
345
1000
|
baseMint: reserve.liquidity.mintPubkey,
|
|
346
1001
|
assetShareValue: reserve.getCollateralExchangeRate(),
|
|
1002
|
+
scopePriceFeed,
|
|
347
1003
|
};
|
|
348
1004
|
}
|
|
349
1005
|
exports.fetchKaminoReserve = fetchKaminoReserve;
|
|
@@ -403,27 +1059,20 @@ exports.deserializeEmission = deserializeEmission;
|
|
|
403
1059
|
function deserializeAnchorizedPNum(x) {
|
|
404
1060
|
return parseFloat(precise_number_1.PreciseNumber.fromRaw(x[0]).valueString);
|
|
405
1061
|
}
|
|
1062
|
+
/** Convert PreciseNumber (Number type in Rust) from Anchor format to raw 256-bit bigint */
|
|
1063
|
+
function anchorizedPNumToRawBigint(pnum) {
|
|
1064
|
+
const bnArray = pnum[0];
|
|
1065
|
+
let val = 0n;
|
|
1066
|
+
for (let i = 0; i < 4; i++) {
|
|
1067
|
+
val += BigInt(bnArray[i].toString()) << BigInt(i * 64);
|
|
1068
|
+
}
|
|
1069
|
+
return val;
|
|
1070
|
+
}
|
|
1071
|
+
exports.anchorizedPNumToRawBigint = anchorizedPNumToRawBigint;
|
|
406
1072
|
/** Fetch the exchange rate of a JitoRestaking vault's VRT to JitoSOL */
|
|
407
1073
|
async function fetchJitoVaultData({ connection, vaultAddress, }) {
|
|
408
1074
|
const vaultAccountInfo = await connection.getAccountInfo(vaultAddress);
|
|
409
|
-
|
|
410
|
-
// the vault has an 8 byte discriminator at the beginning
|
|
411
|
-
const discriminatorOffset = 8;
|
|
412
|
-
const vrtMintOffset = 32 + discriminatorOffset;
|
|
413
|
-
const vrtSupplyOffset = 96 + discriminatorOffset;
|
|
414
|
-
const jitoVaultTotalDepositsOffset = 104 + discriminatorOffset;
|
|
415
|
-
const mintBase = new anchor_1.web3.PublicKey(d.slice(vrtMintOffset, vrtMintOffset + 32));
|
|
416
|
-
// For Borsh, numbers are serialized in little-endian format
|
|
417
|
-
const jitoVaultTotalSharesBuffer = d.slice(vrtSupplyOffset, vrtSupplyOffset + 8);
|
|
418
|
-
const jitoVaultTotalShares = new anchor_1.BN(jitoVaultTotalSharesBuffer, "le");
|
|
419
|
-
const jitoVaultTotalDepositsBuffer = d.slice(jitoVaultTotalDepositsOffset, jitoVaultTotalDepositsOffset + 8);
|
|
420
|
-
const jitoVaultTotalDeposits = new anchor_1.BN(jitoVaultTotalDepositsBuffer, "le");
|
|
421
|
-
const jitoVaultTotalSharesD = new decimal_js_1.default(jitoVaultTotalShares.toString());
|
|
422
|
-
const jitoVaultTotalDepositsD = new decimal_js_1.default(jitoVaultTotalDeposits.toString());
|
|
423
|
-
const exchangeRate = jitoVaultTotalDepositsD.isZero()
|
|
424
|
-
? "1.0"
|
|
425
|
-
: jitoVaultTotalDepositsD.div(jitoVaultTotalSharesD).toString();
|
|
426
|
-
return { exchangeRate: parseFloat(exchangeRate), mintBase };
|
|
1075
|
+
return (0, jito_1.decodeJitoVaultData)(vaultAccountInfo.data);
|
|
427
1076
|
}
|
|
428
1077
|
async function fetchJitoSolToSolExchangeRate({ connection, interfaceType, accounts, }) {
|
|
429
1078
|
if (interfaceType.splStakePool) {
|
|
@@ -438,16 +1087,13 @@ async function fetchSplStakePoolIndex({ connection, stakePool, }) {
|
|
|
438
1087
|
}
|
|
439
1088
|
exports.fetchSplStakePoolIndex = fetchSplStakePoolIndex;
|
|
440
1089
|
async function fetchPerenaStablePoolData({ connection, perenaStablePool, }) {
|
|
441
|
-
const
|
|
1090
|
+
const lpMint = (0, perena_1.getPerenaLpMint)(perenaStablePool);
|
|
442
1091
|
const [accountInfo, lpMintInfo] = await connection.getMultipleAccountsInfo([perenaStablePool, lpMint]);
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
const invT = Buffer.from(invTBuffer).readBigUInt64LE(0);
|
|
449
|
-
const exchangeRate = new decimal_js_1.default(invT.toString()).div(new decimal_js_1.default(lpMintDeserialized.supply.toString())).toString();
|
|
450
|
-
return { lpSupply: lpMintDeserialized.supply, invT, exchangeRate, lpMint };
|
|
1092
|
+
const { lpSupply, invT, exchangeRate } = (0, perena_1.getPerenaStablePoolData)({
|
|
1093
|
+
perenaStablePoolData: accountInfo.data,
|
|
1094
|
+
lpMintData: lpMintInfo.data,
|
|
1095
|
+
});
|
|
1096
|
+
return { lpSupply, invT, exchangeRate, lpMint };
|
|
451
1097
|
}
|
|
452
1098
|
exports.fetchPerenaStablePoolData = fetchPerenaStablePoolData;
|
|
453
1099
|
/**
|
|
@@ -477,40 +1123,14 @@ exports.fetchJitoRestaking = fetchJitoRestaking;
|
|
|
477
1123
|
* and tracks last_* values to compute the next index increment similar to the program.
|
|
478
1124
|
*/
|
|
479
1125
|
async function fetchJupiterPerpsIndex({ connection, pool, lastFeeUsdResetUnixTimestamp, lastRealizedFeeUsd, lastAumUsd, currentIndex, lastRealizedFeeUsdUpdateUnixTimestamp, }) {
|
|
480
|
-
// Decode pool account using helper that leverages Anchor 0.29.0
|
|
481
1126
|
const accountInfo = await connection.getAccountInfo(pool);
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const timeBetweenResets = Number(account.poolApr.lastUpdated) - lastFeeUsdResetUnixTimestamp;
|
|
490
|
-
const feeAprBps = new anchor_1.BN(account.poolApr.feeAprBps);
|
|
491
|
-
const estTotalFees = lastAumUsd.gt(new anchor_1.BN(0)) && timeBetweenResets > 0
|
|
492
|
-
? feeAprBps.mul(lastAumUsd).mul(new anchor_1.BN(timeBetweenResets)).div(new anchor_1.BN(SECONDS_PER_YEAR)).div(new anchor_1.BN(10_000))
|
|
493
|
-
: new anchor_1.BN(0);
|
|
494
|
-
const missingFees = estTotalFees.sub(lastRealizedFeeUsd);
|
|
495
|
-
const feesSinceReset = new anchor_1.BN(account.poolApr.realizedFeeUsd.toString());
|
|
496
|
-
newFeesBn = missingFees.add(feesSinceReset);
|
|
497
|
-
}
|
|
498
|
-
else {
|
|
499
|
-
newFeesBn = new anchor_1.BN(account.poolApr.realizedFeeUsd.toString()).sub(lastRealizedFeeUsd);
|
|
500
|
-
}
|
|
501
|
-
const aumUsd = new anchor_1.BN(account.aumUsd.toString());
|
|
502
|
-
const indexIncrease = new decimal_js_1.default(newFeesBn.toString()).div(new decimal_js_1.default(aumUsd.toString())).toNumber();
|
|
503
|
-
const currentIndexNum = parseFloat(precise_number_1.PreciseNumber.fromRaw(currentIndex[0]).valueString);
|
|
504
|
-
const nextIndex = currentIndexNum + indexIncrease;
|
|
505
|
-
return {
|
|
506
|
-
index: nextIndex,
|
|
507
|
-
newState: {
|
|
508
|
-
lastAumUsd: aumUsd,
|
|
509
|
-
lastRealizedFeeUsd: new anchor_1.BN(account.poolApr.realizedFeeUsd.toString()),
|
|
510
|
-
lastFeeUsdResetUnixTimestamp: Number(account.poolApr.lastUpdated),
|
|
511
|
-
lastRealizedFeeUsdUpdateUnixTimestamp: Math.floor(Date.now() / 1000),
|
|
512
|
-
},
|
|
513
|
-
};
|
|
1127
|
+
return (0, jupiter_1.calculateJupiterPerpsIndex)({ pool: accountInfo.data }, {
|
|
1128
|
+
lastFeeUsdResetUnixTimestamp,
|
|
1129
|
+
lastRealizedFeeUsd,
|
|
1130
|
+
lastAumUsd,
|
|
1131
|
+
currentIndex,
|
|
1132
|
+
lastRealizedFeeUsdUpdateUnixTimestamp,
|
|
1133
|
+
});
|
|
514
1134
|
}
|
|
515
1135
|
exports.fetchJupiterPerpsIndex = fetchJupiterPerpsIndex;
|
|
516
1136
|
async function fetchPyth(connection) {
|
|
@@ -543,28 +1163,27 @@ async function fetchGenericSyMetaIndex({ connection, genericSyMeta, }) {
|
|
|
543
1163
|
}
|
|
544
1164
|
exports.fetchGenericSyMetaIndex = fetchGenericSyMetaIndex;
|
|
545
1165
|
async function fetchFragmetricIndex({ connection, fragmetricFund, }) {
|
|
546
|
-
const
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const receiptTokenMint = new anchor_1.web3.PublicKey(data.receipt_token_mint);
|
|
551
|
-
const wrappedTokenMint = new anchor_1.web3.PublicKey(data.wrapped_token.mint);
|
|
1166
|
+
const fragmetricFundRaw = await connection.getAccountInfo(fragmetricFund);
|
|
1167
|
+
const { index, receiptTokenMint, wrappedTokenMint } = (0, fragmetric_1.calculateFragmetricIndex)({
|
|
1168
|
+
fragmetricFund: fragmetricFundRaw.data,
|
|
1169
|
+
});
|
|
552
1170
|
return { index, receiptTokenMint, wrappedTokenMint };
|
|
553
1171
|
}
|
|
554
1172
|
exports.fetchFragmetricIndex = fetchFragmetricIndex;
|
|
555
1173
|
async function fetchJupiterLendIndex({ connection, jupiterLendAccount, }) {
|
|
556
1174
|
const account = await connection.getAccountInfo(jupiterLendAccount);
|
|
557
|
-
const coder = new anchor_2.BorshCoder(jupiter_lend_idl_1.IDL);
|
|
558
|
-
const data = coder.accounts.decode("Lending", account.data);
|
|
559
|
-
const index = Number(data.token_exchange_price) / Number(10 ** 12);
|
|
560
|
-
const tokenReservesLiquidity = data.token_reserves_liquidity;
|
|
561
|
-
const lendingSupplyPosition = data.supply_position_on_liquidity;
|
|
562
|
-
const rewardsRateModel = data.rewards_rate_model;
|
|
563
1175
|
const rateModel = jupiterLendAccount.equals(new anchor_1.web3.PublicKey("BeAqbxfrcXmzEYT2Ra62oW2MqkuFDHaCtps47Mzg6Zj3"))
|
|
564
1176
|
? new anchor_1.web3.PublicKey("Acvyi9HBGmqh3Exe1N4PjBVyY8fokq2AdC6fSLqV6KSo")
|
|
565
1177
|
: new anchor_1.web3.PublicKey("6iHHKAK9Mqjn57CVmWe4szAPyTH8s8pniXSj6vWaKW5r");
|
|
566
|
-
|
|
567
|
-
return {
|
|
1178
|
+
const { index, baseTokenMint, tokenReservesLiquidity, lendingSupplyPosition, rewardsRateModel } = (0, jupiter_1.calculateJupiterLendIndex)({ jupiterLend: account.data });
|
|
1179
|
+
return {
|
|
1180
|
+
rateModel,
|
|
1181
|
+
index,
|
|
1182
|
+
baseTokenMint,
|
|
1183
|
+
tokenReservesLiquidity,
|
|
1184
|
+
lendingSupplyPosition,
|
|
1185
|
+
rewardsRateModel,
|
|
1186
|
+
};
|
|
568
1187
|
}
|
|
569
1188
|
exports.fetchJupiterLendIndex = fetchJupiterLendIndex;
|
|
570
1189
|
async function fetchKaminoVaultIndex({ connection, kaminoVaultAccount, }) {
|
|
@@ -593,24 +1212,18 @@ async function fetchKaminoVaultIndex({ connection, kaminoVaultAccount, }) {
|
|
|
593
1212
|
exports.fetchKaminoVaultIndex = fetchKaminoVaultIndex;
|
|
594
1213
|
async function fetchFragmetricSupportedTokenIndex({ connection, fragmetricFund, index, }) {
|
|
595
1214
|
const account = await connection.getAccountInfo(fragmetricFund);
|
|
596
|
-
|
|
597
|
-
const data = coder.accounts.decode("FundAccount", account.data);
|
|
598
|
-
const syIndex = Number(10 ** data.supported_tokens[index].decimals) /
|
|
599
|
-
Number(data.supported_tokens[index].one_token_as_receipt_token);
|
|
600
|
-
const receiptTokenMint = new anchor_1.web3.PublicKey(data.receipt_token_mint);
|
|
601
|
-
const wrappedTokenMint = new anchor_1.web3.PublicKey(data.wrapped_token.mint);
|
|
602
|
-
return { index: syIndex, receiptTokenMint, wrappedTokenMint };
|
|
1215
|
+
return (0, fragmetric_1.calculateFragmetricSupportedTokenIndex)({ fragmetricFund: account.data }, index);
|
|
603
1216
|
}
|
|
604
1217
|
exports.fetchFragmetricSupportedTokenIndex = fetchFragmetricSupportedTokenIndex;
|
|
605
1218
|
async function fetchMeteoraIndex({ connection, accounts, onChainTime, }) {
|
|
606
1219
|
try {
|
|
607
1220
|
const VIRTUAL_PRICE_PRECISION = new anchor_1.BN(100_000_000);
|
|
608
|
-
const pool = await (0, meteora_idl_1.
|
|
1221
|
+
const pool = await (0, meteora_idl_1.fetchPoolAccount)(connection, accounts.pool);
|
|
609
1222
|
const poolMint = await (0, spl_token_1.getMint)(connection, pool.lpMint);
|
|
610
1223
|
const poolLpSupply = new anchor_1.BN(poolMint.supply.toString());
|
|
611
1224
|
const poolLpDecimals = Number(poolMint.decimals.toString());
|
|
612
|
-
const vaultA = await (0, meteora_idl_1.
|
|
613
|
-
const vaultB = await (0, meteora_idl_1.
|
|
1225
|
+
const vaultA = await (0, meteora_idl_1.fetchVaultAccount)(connection, accounts.vaultA);
|
|
1226
|
+
const vaultB = await (0, meteora_idl_1.fetchVaultAccount)(connection, accounts.vaultB);
|
|
614
1227
|
const vaultLpMintA = await (0, spl_token_1.getMint)(connection, vaultA.lpMint);
|
|
615
1228
|
const vaultLpMintB = await (0, spl_token_1.getMint)(connection, vaultB.lpMint);
|
|
616
1229
|
const vaultALpSupply = vaultLpMintA.supply;
|
|
@@ -640,7 +1253,6 @@ async function fetchMeteoraIndex({ connection, accounts, onChainTime, }) {
|
|
|
640
1253
|
exports.fetchMeteoraIndex = fetchMeteoraIndex;
|
|
641
1254
|
async function fetchAdrenaIndex({ connection, accounts, previousTotalFees, currentIndex, }) {
|
|
642
1255
|
try {
|
|
643
|
-
const zero = new anchor_1.BN(0);
|
|
644
1256
|
// Fetch all account data in a single RPC call
|
|
645
1257
|
const accountInfos = await connection.getMultipleAccountsInfo([
|
|
646
1258
|
accounts.pool,
|
|
@@ -652,19 +1264,13 @@ async function fetchAdrenaIndex({ connection, accounts, previousTotalFees, curre
|
|
|
652
1264
|
if (!accountInfos[0] || !accountInfos[1] || !accountInfos[2] || !accountInfos[3] || !accountInfos[4]) {
|
|
653
1265
|
throw new Error("One or more Adrena accounts not found");
|
|
654
1266
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
yieldIncrement = 0;
|
|
663
|
-
}
|
|
664
|
-
let feeDifference = currentTotalFees.gte(previousTotalFees) ? currentTotalFees.sub(previousTotalFees) : zero;
|
|
665
|
-
yieldIncrement = feeDifference.toNumber() / aumValue.toNumber();
|
|
666
|
-
let currentIndexNumber = parseFloat(precise_number_1.PreciseNumber.fromRaw(currentIndex[0]).valueString);
|
|
667
|
-
return { index: currentIndexNumber + yieldIncrement };
|
|
1267
|
+
return (0, adrena_1.calculateAdrenaIndex)({
|
|
1268
|
+
pool: accountInfos[0].data,
|
|
1269
|
+
custody1: accountInfos[1].data,
|
|
1270
|
+
custody2: accountInfos[2].data,
|
|
1271
|
+
custody3: accountInfos[3].data,
|
|
1272
|
+
custody4: accountInfos[4].data,
|
|
1273
|
+
}, previousTotalFees, currentIndex);
|
|
668
1274
|
}
|
|
669
1275
|
catch (error) {
|
|
670
1276
|
throw error;
|
|
@@ -672,70 +1278,75 @@ async function fetchAdrenaIndex({ connection, accounts, previousTotalFees, curre
|
|
|
672
1278
|
}
|
|
673
1279
|
exports.fetchAdrenaIndex = fetchAdrenaIndex;
|
|
674
1280
|
async function fetchSanctumIndex({ connection, accounts, }) {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
const lpTokenSupplyBn = new anchor_1.BN(lpMint.supply.toString());
|
|
681
|
-
const poolTotalSolValueBn = new anchor_1.BN(poolState.totalSolValue.toString());
|
|
682
|
-
if (lpTokenSupplyBn.eq(zeroBn) || poolTotalSolValueBn.eq(zeroBn)) {
|
|
683
|
-
return 1;
|
|
684
|
-
}
|
|
685
|
-
const exchangeRateBn = lpTokenSupplyBn.mul(precision).div(poolTotalSolValueBn);
|
|
686
|
-
const exchangeRate = new decimal_js_1.default(exchangeRateBn.toString()).div(precision.toString()).toNumber();
|
|
687
|
-
return 1 / exchangeRate; // We return inverse exchange rate
|
|
688
|
-
}
|
|
689
|
-
catch (error) {
|
|
690
|
-
throw error;
|
|
691
|
-
}
|
|
1281
|
+
const [poolStateAccountRaw, lpMintAccountRaw] = await Promise.all([accounts.poolState, accounts.lpMint].map((pk) => connection.getAccountInfo(pk)));
|
|
1282
|
+
return (0, sanctum_1.calculateSanctumIndex)({
|
|
1283
|
+
poolStateAccountData: poolStateAccountRaw.data,
|
|
1284
|
+
lpMintAccountData: lpMintAccountRaw.data,
|
|
1285
|
+
});
|
|
692
1286
|
}
|
|
693
1287
|
exports.fetchSanctumIndex = fetchSanctumIndex;
|
|
694
1288
|
async function fetchSolsticeRedemptionRate({ connection, yieldPool, vestingSchedule, }) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
throw new Error("One or more Solstice accounts not found");
|
|
700
|
-
}
|
|
701
|
-
// Decode accounts using solstice-idl package function
|
|
702
|
-
const { yieldPoolAccount, vestingScheduleAccount } = (0, solstice_idl_1.decodeYieldPoolAndVestingScheduleAccounts)(accountInfos);
|
|
703
|
-
// Extract fields for calculation (convert BN to bigint)
|
|
704
|
-
const poolTotalAssets = BigInt(yieldPoolAccount.total_assets.toString());
|
|
705
|
-
const poolSharesSupply = BigInt(yieldPoolAccount.shares_supply.toString());
|
|
706
|
-
const vestingAmount = BigInt(vestingScheduleAccount.vesting_amount.toString());
|
|
707
|
-
// Calculate total vested assets (mimicking the Rust logic)
|
|
708
|
-
let totalVestedAssets;
|
|
709
|
-
if (vestingAmount === 0n) {
|
|
710
|
-
totalVestedAssets = poolTotalAssets; // If no vesting amount, all assets are considered vested
|
|
711
|
-
}
|
|
712
|
-
else {
|
|
713
|
-
const vestingStart = BigInt(vestingScheduleAccount.start_time.toString());
|
|
714
|
-
const vestingEnd = BigInt(vestingScheduleAccount.end_time.toString());
|
|
715
|
-
const currentTime = BigInt(Math.floor(Date.now() / 1000)); // Current Unix timestamp
|
|
716
|
-
// Calculate unvested amount
|
|
717
|
-
let unvestedAmount;
|
|
718
|
-
if (currentTime > vestingEnd) {
|
|
719
|
-
unvestedAmount = 0n; // If current time passed the vesting end, no unvested amount
|
|
720
|
-
}
|
|
721
|
-
else {
|
|
722
|
-
unvestedAmount = (vestingAmount * (vestingEnd - currentTime)) / (vestingEnd - vestingStart);
|
|
723
|
-
}
|
|
724
|
-
totalVestedAssets = poolTotalAssets - unvestedAmount;
|
|
725
|
-
}
|
|
726
|
-
// Calculate redemption rate: (total_vested_assets + 1) / (pool_shares_supply + 1)
|
|
727
|
-
const redemptionRate = Number(totalVestedAssets + 1n) / Number(poolSharesSupply + 1n);
|
|
728
|
-
return {
|
|
729
|
-
redemptionRate,
|
|
730
|
-
totalAssets: poolTotalAssets.toString(),
|
|
731
|
-
sharesSupply: poolSharesSupply.toString(),
|
|
732
|
-
vestingAmount: vestingAmount.toString(),
|
|
733
|
-
totalVestedAssets: totalVestedAssets.toString(),
|
|
734
|
-
};
|
|
735
|
-
}
|
|
736
|
-
catch (error) {
|
|
737
|
-
throw error;
|
|
1289
|
+
// Fetch both accounts in a single RPC call for efficiency
|
|
1290
|
+
const accountInfos = await connection.getMultipleAccountsInfo([yieldPool, vestingSchedule]);
|
|
1291
|
+
if (!accountInfos[0] || !accountInfos[1]) {
|
|
1292
|
+
throw new Error("One or more Solstice accounts not found");
|
|
738
1293
|
}
|
|
1294
|
+
return (0, solstice_1.calculateSolsticeRedemptionRate)({ yieldPool: accountInfos[0].data, vestingSchedule: accountInfos[1].data });
|
|
739
1295
|
}
|
|
740
1296
|
exports.fetchSolsticeRedemptionRate = fetchSolsticeRedemptionRate;
|
|
1297
|
+
const REFLECT_ORACLE_LEN = 17;
|
|
1298
|
+
const REFLECT_MAX_STALENESS_SLOTS = 15000000;
|
|
1299
|
+
async function fetchReflectRedemptionRate({ connection, oracle, }) {
|
|
1300
|
+
const accountInfo = await connection.getAccountInfo(oracle);
|
|
1301
|
+
if (!accountInfo) {
|
|
1302
|
+
throw new Error("Reflect oracle account not found");
|
|
1303
|
+
}
|
|
1304
|
+
if (accountInfo.data.length !== REFLECT_ORACLE_LEN) {
|
|
1305
|
+
throw new Error(`Reflect oracle account has invalid length: ${accountInfo.data.length}`);
|
|
1306
|
+
}
|
|
1307
|
+
const slot = Number(accountInfo.data.readBigUInt64LE(0));
|
|
1308
|
+
const price = Number(accountInfo.data.readBigUInt64LE(8));
|
|
1309
|
+
const precision = accountInfo.data.readUInt8(16);
|
|
1310
|
+
const currentSlot = await connection.getSlot();
|
|
1311
|
+
if (slot > currentSlot) {
|
|
1312
|
+
throw new Error("Reflect oracle slot is ahead of the current slot");
|
|
1313
|
+
}
|
|
1314
|
+
const slotDelta = currentSlot - slot;
|
|
1315
|
+
if (slotDelta > REFLECT_MAX_STALENESS_SLOTS) {
|
|
1316
|
+
throw new Error("Reflect oracle data is stale");
|
|
1317
|
+
}
|
|
1318
|
+
const scale = Math.pow(10, precision);
|
|
1319
|
+
if (scale === 0) {
|
|
1320
|
+
throw new Error("Invalid oracle precision");
|
|
1321
|
+
}
|
|
1322
|
+
return price / scale;
|
|
1323
|
+
}
|
|
1324
|
+
exports.fetchReflectRedemptionRate = fetchReflectRedemptionRate;
|
|
1325
|
+
async function fetchOreExchangeRate({ connection, storeMint, stakeAccount, treasury, }) {
|
|
1326
|
+
// Fetch all accounts in parallel for efficiency
|
|
1327
|
+
const [storeMintInfo, stakeAccountInfo, treasuryAccountInfo] = await Promise.all([
|
|
1328
|
+
connection.getAccountInfo(storeMint),
|
|
1329
|
+
connection.getAccountInfo(stakeAccount),
|
|
1330
|
+
connection.getAccountInfo(treasury),
|
|
1331
|
+
]);
|
|
1332
|
+
if (!storeMintInfo || !stakeAccountInfo || !treasuryAccountInfo) {
|
|
1333
|
+
throw new Error("One or more ORE accounts not found");
|
|
1334
|
+
}
|
|
1335
|
+
return (0, ore_1.calculateOreExchangeRate)({
|
|
1336
|
+
stakeAccount: stakeAccountInfo.data,
|
|
1337
|
+
treasuryAccount: treasuryAccountInfo.data,
|
|
1338
|
+
storeMint: storeMintInfo.data,
|
|
1339
|
+
});
|
|
1340
|
+
}
|
|
1341
|
+
exports.fetchOreExchangeRate = fetchOreExchangeRate;
|
|
1342
|
+
async function fetchChainlinkRate({ connection, priceFeed, }) {
|
|
1343
|
+
const accountInfo = await connection.getAccountInfo(priceFeed);
|
|
1344
|
+
if (!accountInfo) {
|
|
1345
|
+
throw new Error("Chainlink price feed account not found");
|
|
1346
|
+
}
|
|
1347
|
+
const { answer, header } = (0, chainlink_idl_1.decodeChainlinkPriceAccount)(accountInfo);
|
|
1348
|
+
const scale = Math.pow(10, header.decimals);
|
|
1349
|
+
return Number(answer) / scale;
|
|
1350
|
+
}
|
|
1351
|
+
exports.fetchChainlinkRate = fetchChainlinkRate;
|
|
741
1352
|
//# sourceMappingURL=exponentFetcher.js.map
|