@exponent-labs/exponent-fetcher 0.1.7 → 0.1.8
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/exponentFetcher.d.ts +303 -31
- package/build/exponentFetcher.js +666 -168
- package/build/exponentFetcher.js.map +1 -1
- package/build/index.d.ts +10 -0
- package/build/index.js +10 -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 +20 -18
- package/src/exponentFetcher.ts +1077 -222
- package/src/index.ts +10 -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 +2 -0
package/src/exponentFetcher.ts
CHANGED
|
@@ -1,14 +1,31 @@
|
|
|
1
|
-
import { AnchorProvider, BN, Idl, Program, Wallet, web3 } from "@coral-xyz/anchor"
|
|
1
|
+
import { AnchorProvider, BN, DISCRIMINATOR_SIZE, Idl, Program, ProgramAccount, Wallet, web3 } from "@coral-xyz/anchor"
|
|
2
2
|
import { BorshCoder } from "@coral-xyz/anchor"
|
|
3
3
|
import { getStakePoolAccount } from "@solana/spl-stake-pool"
|
|
4
4
|
import { getAccount, getMint } from "@solana/spl-token"
|
|
5
|
-
import
|
|
5
|
+
import bs58 from "bs58"
|
|
6
6
|
import Decimal from "decimal.js"
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
CustodyState,
|
|
10
|
+
FeesStats,
|
|
11
|
+
PoolState,
|
|
12
|
+
calculateTotalFeesFromCustodies,
|
|
13
|
+
decodePoolAccount as decodeAdrenaPoolAccount,
|
|
14
|
+
decodeCustodyAccount,
|
|
15
|
+
decodePoolAndCustodyAccounts,
|
|
16
|
+
} from "@exponent-labs/adrena-idl"
|
|
17
|
+
import {
|
|
18
|
+
PROGRAM_ID as EXPONENT_CLMM_PROGRAM_ID,
|
|
19
|
+
ExponentClmm,
|
|
20
|
+
IDL as ExponentClmmIdl,
|
|
21
|
+
} from "@exponent-labs/exponent-clmm-idl"
|
|
7
22
|
import { ExponentCore, IDL, PROGRAM_ID } from "@exponent-labs/exponent-idl"
|
|
23
|
+
import { IDL as EXPONENT_ORDERBOOK_IDL, ExponentOrderbook } from "@exponent-labs/exponent-orderbook-idl"
|
|
8
24
|
import {
|
|
9
25
|
AnchorizedPNum,
|
|
10
26
|
AnchorizedPNumJson,
|
|
11
27
|
CpiAccountIndexes,
|
|
28
|
+
ExponentCoreCpiIndexes,
|
|
12
29
|
GenericSyMetaAccount,
|
|
13
30
|
GenericSyMetaAccountRaw,
|
|
14
31
|
InterfaceType,
|
|
@@ -16,6 +33,7 @@ import {
|
|
|
16
33
|
JitoRestakingSyMetaAccountRaw,
|
|
17
34
|
MarginfiSyMeta,
|
|
18
35
|
MarginfiSyMetaRaw,
|
|
36
|
+
MarketCpiCoreIndexes,
|
|
19
37
|
PerenaSyMetaAccount,
|
|
20
38
|
PerenaSyMetaAccountRaw,
|
|
21
39
|
SyEmissionRaw,
|
|
@@ -25,50 +43,59 @@ import {
|
|
|
25
43
|
deserializeJitoRestakingSyMetaAccountRaw,
|
|
26
44
|
deserializePerenaSyMetaAccountRaw,
|
|
27
45
|
} from "@exponent-labs/exponent-types"
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
import {
|
|
47
|
+
MAX_OFFERS,
|
|
48
|
+
MAX_PRICE_NODES,
|
|
49
|
+
MAX_USER_ESCROWS,
|
|
50
|
+
OfferNode,
|
|
51
|
+
PriceTreeNode,
|
|
52
|
+
UserEscrowNode,
|
|
53
|
+
} from "@exponent-labs/exponent-types"
|
|
31
54
|
import { GenericStandard } from "@exponent-labs/generic-sy-idl"
|
|
32
55
|
import { PROGRAM_ID as GENERIC_STANDARD_PROGRAM_ID, IDL as GenericStandardIdl } from "@exponent-labs/generic-sy-idl"
|
|
33
56
|
import { PROGRAM_ID as JITO_RESTAKING_SY_PROGRAM_ID } from "@exponent-labs/jito-restaking-sy-idl"
|
|
34
57
|
import { JitoRestakingStandard, IDL as JitoRestakingSyIdl } from "@exponent-labs/jito-restaking-sy-idl"
|
|
58
|
+
// Decode Jupiter Perps pool accounts via helper using Anchor 0.29.0
|
|
59
|
+
import { decodePoolAccount as decodeJupiterPerpsPoolAccount } from "@exponent-labs/jupiter-perps-idl"
|
|
35
60
|
import { Obligation, Reserve } from "@exponent-labs/kamino-reserve-deserializer"
|
|
36
61
|
import { PROGRAM_ID as KAMINO_LEND_PROGRAM_ID } from "@exponent-labs/kamino-reserve-deserializer"
|
|
37
62
|
import { PROGRAM_ID as KAMINO_STANDARD_PROGRAM_ID } from "@exponent-labs/kamino-sy-idl"
|
|
38
63
|
import { KaminoLendStandard } from "@exponent-labs/kamino-sy-idl"
|
|
39
64
|
import { IDL as KaminoSyIdl } from "@exponent-labs/kamino-sy-idl"
|
|
65
|
+
import { IDL as KaminoVaultIdl } from "@exponent-labs/kamino-vault-idl"
|
|
40
66
|
import {
|
|
41
67
|
PROGRAM_ID as MARGINFI_SY_PROGRAM_ID,
|
|
42
68
|
MarginfiStandard,
|
|
43
69
|
IDL as MarginfiSyIdl,
|
|
44
70
|
} from "@exponent-labs/marginfi-sy-idl"
|
|
45
|
-
import {
|
|
71
|
+
import { fetchPoolAccount, fetchVaultAccount } from "@exponent-labs/meteora-idl"
|
|
46
72
|
import { PROGRAM_ID as PERENA_STANDARD_PROGRAM_ID } from "@exponent-labs/perena-sy-idl"
|
|
47
73
|
import { IDL as PerenaSyIdl } from "@exponent-labs/perena-sy-idl"
|
|
48
74
|
import { PerenaStandard } from "@exponent-labs/perena-sy-idl"
|
|
49
75
|
import { PreciseNumber } from "@exponent-labs/precise-number"
|
|
50
|
-
import { decodePoolStateAccount } from "@exponent-labs/sanctum-idl"
|
|
51
|
-
import {
|
|
52
|
-
decodePoolAccount as decodeAdrenaPoolAccount,
|
|
53
|
-
decodeCustodyAccount,
|
|
54
|
-
CustodyState,
|
|
55
|
-
FeesStats,
|
|
56
|
-
PoolState,
|
|
57
|
-
decodePoolAndCustodyAccounts,
|
|
58
|
-
calculateTotalFeesFromCustodies,
|
|
59
|
-
} from "@exponent-labs/adrena-idl"
|
|
60
76
|
import { decodeYieldPoolAndVestingScheduleAccounts } from "@exponent-labs/solstice-idl"
|
|
61
77
|
|
|
78
|
+
import { calculateAdrenaIndex } from "./utils/adrena"
|
|
79
|
+
import { calculateFragmetricIndex, calculateFragmetricSupportedTokenIndex } from "./utils/fragmetric"
|
|
80
|
+
import { decodeJitoVaultData } from "./utils/jito"
|
|
81
|
+
import { calculateJupiterLendIndex, calculateJupiterPerpsIndex } from "./utils/jupiter"
|
|
62
82
|
import { computeD, getAmountByShare } from "./utils/meteora"
|
|
63
|
-
import {
|
|
64
|
-
|
|
65
|
-
import {
|
|
83
|
+
import { calculateOreExchangeRate } from "./utils/ore"
|
|
84
|
+
import { getPerenaLpMint, getPerenaStablePoolData } from "./utils/perena"
|
|
85
|
+
import { calculateSanctumIndex } from "./utils/sanctum"
|
|
86
|
+
import { calculateSolsticeRedemptionRate } from "./utils/solstice"
|
|
66
87
|
|
|
67
88
|
export function serializeAnchorizedPNumFromJson(pnum: AnchorizedPNum): AnchorizedPNumJson {
|
|
68
89
|
const serializedArray = pnum[0].map((bn) => bn.toString())
|
|
69
90
|
return { 0: serializedArray }
|
|
70
91
|
}
|
|
71
92
|
|
|
93
|
+
function readU128LE(buf: Buffer, offset: number): bigint {
|
|
94
|
+
const lo = buf.readBigUInt64LE(offset)
|
|
95
|
+
const hi = buf.readBigUInt64LE(offset + 8)
|
|
96
|
+
return (hi << 64n) + lo
|
|
97
|
+
}
|
|
98
|
+
|
|
72
99
|
export function deserializeAnchorizedPNumFromJson(serialized: AnchorizedPNumJson): AnchorizedPNum {
|
|
73
100
|
const bnArray = serialized[0].map((str) => new BN(str))
|
|
74
101
|
return { 0: bnArray }
|
|
@@ -111,6 +138,8 @@ export class ExponentFetcher {
|
|
|
111
138
|
public jitoRestakingSyProgram: Program<JitoRestakingStandard>
|
|
112
139
|
public perenaSyProgram: Program<PerenaStandard>
|
|
113
140
|
public genericStandardProgram: Program<GenericStandard>
|
|
141
|
+
public exponentClmmProgram: Program<ExponentClmm>
|
|
142
|
+
public orderbookProgram: Program<ExponentOrderbook>
|
|
114
143
|
public connection: web3.Connection
|
|
115
144
|
public coreProgramId: web3.PublicKey
|
|
116
145
|
public marginfiSyProgramId: web3.PublicKey
|
|
@@ -156,6 +185,8 @@ export class ExponentFetcher {
|
|
|
156
185
|
)
|
|
157
186
|
this.perenaSyProgram = new Program<PerenaStandard>(PerenaSyIdl as PerenaStandard, provider)
|
|
158
187
|
this.genericStandardProgram = new Program<GenericStandard>(GenericStandardIdl, provider)
|
|
188
|
+
this.exponentClmmProgram = new Program<ExponentClmm>(ExponentClmmIdl as ExponentClmm, provider)
|
|
189
|
+
this.orderbookProgram = new Program<ExponentOrderbook>(EXPONENT_ORDERBOOK_IDL as ExponentOrderbook, provider)
|
|
159
190
|
}
|
|
160
191
|
|
|
161
192
|
async fetchVault(address: web3.PublicKey) {
|
|
@@ -180,6 +211,30 @@ export class ExponentFetcher {
|
|
|
180
211
|
}
|
|
181
212
|
}
|
|
182
213
|
|
|
214
|
+
async fetchOrderbook(address: web3.PublicKey): Promise<Orderbook> {
|
|
215
|
+
try {
|
|
216
|
+
const o = (await this.connection.getAccountInfo(address)).data
|
|
217
|
+
|
|
218
|
+
return deserializeOrderbook(o)
|
|
219
|
+
} catch (e) {
|
|
220
|
+
console.error(`Error fetching orderbook ${address.toBase58()}`)
|
|
221
|
+
console.error(e)
|
|
222
|
+
throw e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async fetchOrderbookCpiAccounts(address: web3.PublicKey): Promise<OrderbookCpiAccountsRaw> {
|
|
227
|
+
try {
|
|
228
|
+
const orderbookCpiAccounts: OrderbookCpiAccountsRaw =
|
|
229
|
+
await this.orderbookProgram.account.cpiAccountsOrderbook.fetch(address)
|
|
230
|
+
return orderbookCpiAccounts
|
|
231
|
+
} catch (e) {
|
|
232
|
+
console.error(`Error fetching orderbook ${address.toBase58()}`)
|
|
233
|
+
console.error(e)
|
|
234
|
+
throw e
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
183
238
|
async fetchMarginfiSyMeta(address: web3.PublicKey): Promise<MarginfiSyMeta> {
|
|
184
239
|
const x: MarginfiSyMetaRaw = await this.marginfiSyProgram.account.syMeta.fetch(address)
|
|
185
240
|
return deserializeMarginfiSyMeta(x)
|
|
@@ -263,11 +318,62 @@ export class ExponentFetcher {
|
|
|
263
318
|
return deserializeLpPosition(x)
|
|
264
319
|
}
|
|
265
320
|
|
|
321
|
+
async fetchLpPositionCLMM(address: web3.PublicKey) {
|
|
322
|
+
try {
|
|
323
|
+
const raw = await this.exponentClmmProgram.account.lpPosition.fetch(address)
|
|
324
|
+
|
|
325
|
+
const v: LpPositionCLMMRaw = {
|
|
326
|
+
owner: raw.owner,
|
|
327
|
+
market: raw.market,
|
|
328
|
+
feeInsideLastPt: raw.feeInsideLastPt,
|
|
329
|
+
feeInsideLastSy: raw.feeInsideLastSy,
|
|
330
|
+
lpBalance: raw.lpBalance,
|
|
331
|
+
tokensOwedSy: raw.tokensOwedSy,
|
|
332
|
+
tokensOwedPt: raw.tokensOwedPt,
|
|
333
|
+
lowerTickIdx: raw.lowerTickIdx,
|
|
334
|
+
upperTickIdx: raw.upperTickIdx,
|
|
335
|
+
farms: {
|
|
336
|
+
trackers: raw.farms.trackers.map((t: any) => ({
|
|
337
|
+
staged: t.staged,
|
|
338
|
+
lastSeenIndex: t.lastSeenIndex,
|
|
339
|
+
})),
|
|
340
|
+
},
|
|
341
|
+
shareTrackers: {
|
|
342
|
+
trackers: raw.shareTrackers.trackers.map((tracker: any) => ({
|
|
343
|
+
tickIdx: tracker.tickIdx,
|
|
344
|
+
rightTickIdx: tracker.rightTickIdx,
|
|
345
|
+
splitEpoch: tracker.splitEpoch,
|
|
346
|
+
lpShare: tracker.lpShare,
|
|
347
|
+
emissions: {
|
|
348
|
+
trackers: tracker.emissions.trackers.map((e: any) => ({
|
|
349
|
+
staged: e.staged,
|
|
350
|
+
lastSeenIndex: e.lastSeenIndex,
|
|
351
|
+
})),
|
|
352
|
+
},
|
|
353
|
+
})),
|
|
354
|
+
},
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
return deserializeLpPositionCLMM(v)
|
|
358
|
+
} catch (e) {
|
|
359
|
+
console.error(`Error fetching clmm lp position ${address.toBase58()}`)
|
|
360
|
+
console.error(e)
|
|
361
|
+
throw e
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
266
365
|
async fetchYtPosition(address: web3.PublicKey): Promise<YtPosition> {
|
|
267
366
|
const x: YtPositionRaw = await this.program.account.yieldTokenPosition.fetch(address)
|
|
268
367
|
return deserializeYtPosition(x)
|
|
269
368
|
}
|
|
270
369
|
|
|
370
|
+
/** Batch fetch multiple YT positions in a single RPC call */
|
|
371
|
+
async fetchYtPositions(addresses: web3.PublicKey[]): Promise<(YtPosition | null)[]> {
|
|
372
|
+
if (addresses.length === 0) return []
|
|
373
|
+
const results = await this.program.account.yieldTokenPosition.fetchMultiple(addresses)
|
|
374
|
+
return results.map((x) => (x ? deserializeYtPosition(x as YtPositionRaw) : null))
|
|
375
|
+
}
|
|
376
|
+
|
|
271
377
|
async fetchJitoRestakingSyMeta(address: web3.PublicKey): Promise<JitoRestakingSyMetaAccount> {
|
|
272
378
|
const x: JitoRestakingSyMetaAccountRaw = await this.jitoRestakingSyProgram.account.syMeta.fetch(address)
|
|
273
379
|
|
|
@@ -284,6 +390,256 @@ export class ExponentFetcher {
|
|
|
284
390
|
|
|
285
391
|
return deserializeGenericSyMetaAccountRaw(x)
|
|
286
392
|
}
|
|
393
|
+
|
|
394
|
+
async fetchAllMarketThree(): Promise<MarketThree[]> {
|
|
395
|
+
//TODO Replace with the following code when all damaged markets are removed onchain
|
|
396
|
+
// const marketsProgramAccounts: ProgramAccount<MarketThreeRaw>[] =
|
|
397
|
+
// await this.exponentClmmProgram.account.marketThree.all()
|
|
398
|
+
// return marketsProgramAccounts.map(({ account }) => deserializeMarketThree(account))
|
|
399
|
+
|
|
400
|
+
const MARKET_THREE_DISCRIMINATOR = Buffer.from([242, 240, 26, 15, 148, 186, 185, 205])
|
|
401
|
+
const marketsProgramAccounts = await this.connection.getProgramAccounts(this.exponentClmmProgram.programId, {
|
|
402
|
+
filters: [
|
|
403
|
+
{
|
|
404
|
+
memcmp: {
|
|
405
|
+
offset: 0,
|
|
406
|
+
bytes: bs58.encode(MARKET_THREE_DISCRIMINATOR),
|
|
407
|
+
},
|
|
408
|
+
},
|
|
409
|
+
],
|
|
410
|
+
})
|
|
411
|
+
|
|
412
|
+
return marketsProgramAccounts
|
|
413
|
+
.map(({ account, pubkey }) => {
|
|
414
|
+
try {
|
|
415
|
+
return this.exponentClmmProgram.coder.accounts.decode("marketThree", account.data)
|
|
416
|
+
} catch (error) {
|
|
417
|
+
return null
|
|
418
|
+
}
|
|
419
|
+
})
|
|
420
|
+
.filter((m) => !!m)
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
async fetchMarketThree(address: web3.PublicKey): Promise<MarketThree> {
|
|
424
|
+
try {
|
|
425
|
+
const m: MarketThreeRaw = await this.exponentClmmProgram.account.marketThree.fetch(address)
|
|
426
|
+
return deserializeMarketThree(m)
|
|
427
|
+
} catch (e) {
|
|
428
|
+
console.error(`Error fetching market ${address.toBase58()}`)
|
|
429
|
+
console.error(e)
|
|
430
|
+
throw e
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
async fetchAllMarketThreeTicks(): Promise<Ticks[]> {
|
|
435
|
+
const TICKS_DISCRIMINATOR = Buffer.from([122, 104, 41, 141, 214, 36, 222, 37])
|
|
436
|
+
|
|
437
|
+
const ticksAccounts = await this.connection.getProgramAccounts(this.exponentClmmProgram.programId, {
|
|
438
|
+
filters: [
|
|
439
|
+
{
|
|
440
|
+
memcmp: {
|
|
441
|
+
offset: 0,
|
|
442
|
+
bytes: bs58.encode(TICKS_DISCRIMINATOR),
|
|
443
|
+
},
|
|
444
|
+
},
|
|
445
|
+
],
|
|
446
|
+
})
|
|
447
|
+
|
|
448
|
+
return ticksAccounts.map(({ account }) => deserializeMarketThreeTicks(account.data))
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
async fetchMarketThreeTicks(address: web3.PublicKey): Promise<Ticks> {
|
|
452
|
+
try {
|
|
453
|
+
const m = (await this.connection.getAccountInfo(address)).data
|
|
454
|
+
return deserializeMarketThreeTicks(m)
|
|
455
|
+
} catch (e) {
|
|
456
|
+
console.error(`Error fetching market ${address.toBase58()}`)
|
|
457
|
+
console.error(e)
|
|
458
|
+
throw e
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
export function deserializeMarketThreeTicks(data: Buffer): Ticks {
|
|
464
|
+
let offset = 8
|
|
465
|
+
const MAX_TICK_NODES = 100
|
|
466
|
+
const PERSONAL_TICK_YIELD_TRACKER_SIZE = 3
|
|
467
|
+
|
|
468
|
+
const readPubkey = (): web3.PublicKey => {
|
|
469
|
+
const pk = new web3.PublicKey(data.slice(offset, offset + 32))
|
|
470
|
+
offset += 32
|
|
471
|
+
return pk
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
const readNumber = (): number => {
|
|
475
|
+
// Number is 32 bytes (4 x u64)
|
|
476
|
+
const nums = []
|
|
477
|
+
for (let i = 0; i < 4; i++) {
|
|
478
|
+
nums.push(new BN(data.slice(offset + i * 8, offset + (i + 1) * 8), undefined, "le"))
|
|
479
|
+
}
|
|
480
|
+
offset += 32
|
|
481
|
+
return parseFloat(PreciseNumber.fromRaw(nums).valueString)
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
// ─── Parse RedBlackTree slab ───────────────────────────────────────────────
|
|
485
|
+
// repr(C) gives: root: u32, pad to align NodeAllocator's u64, then the NodeAllocator header
|
|
486
|
+
|
|
487
|
+
const root = data.readUInt32LE(offset)
|
|
488
|
+
offset += 4
|
|
489
|
+
const padTo8 = 12
|
|
490
|
+
offset += padTo8
|
|
491
|
+
|
|
492
|
+
// NodeAllocator<T=RBNode<u32,PriceNode>, N=MAX_PRICE_NODES, R=3>
|
|
493
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
494
|
+
|
|
495
|
+
const tickTreeSize = Number(data.readBigUInt64LE(offset))
|
|
496
|
+
offset += 8
|
|
497
|
+
|
|
498
|
+
const ticksTreeBump = data.readUInt32LE(offset)
|
|
499
|
+
offset += 4
|
|
500
|
+
|
|
501
|
+
const ticksTreeFreeIdx = data.readUInt32LE(offset)
|
|
502
|
+
offset += 4
|
|
503
|
+
|
|
504
|
+
const ticks: Tick[] = []
|
|
505
|
+
|
|
506
|
+
for (let i = 0; i < MAX_TICK_NODES; i++) {
|
|
507
|
+
const left = data.readUInt32LE(offset)
|
|
508
|
+
offset += 4
|
|
509
|
+
const right = data.readUInt32LE(offset)
|
|
510
|
+
offset += 4
|
|
511
|
+
const parent = data.readUInt32LE(offset)
|
|
512
|
+
offset += 4
|
|
513
|
+
offset += 4 // skip color
|
|
514
|
+
|
|
515
|
+
const apyBasePoints = data.readUInt32LE(offset)
|
|
516
|
+
offset += 8
|
|
517
|
+
|
|
518
|
+
const feeGrowthOutsidePt = readU128LE(data, offset)
|
|
519
|
+
offset += 16
|
|
520
|
+
const feeGrowthOutsideSy = readU128LE(data, offset)
|
|
521
|
+
offset += 16
|
|
522
|
+
const liquidityNet = data.readBigInt64LE(offset)
|
|
523
|
+
offset += 8
|
|
524
|
+
const liquidityGross = data.readBigInt64LE(offset)
|
|
525
|
+
offset += 8
|
|
526
|
+
const impliedRate = data.readDoubleLE(offset)
|
|
527
|
+
offset += 8
|
|
528
|
+
const principalPt = data.readBigInt64LE(offset)
|
|
529
|
+
offset += 8
|
|
530
|
+
const principalSy = data.readBigInt64LE(offset)
|
|
531
|
+
offset += 8
|
|
532
|
+
const principalShareSupply = data.readBigInt64LE(offset)
|
|
533
|
+
offset += 8
|
|
534
|
+
|
|
535
|
+
// Parse FarmYieldTrackers (3 trackers x 32 bytes each)
|
|
536
|
+
const farms = []
|
|
537
|
+
for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
|
|
538
|
+
farms.push({ lastSeenIndex: readNumber() })
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// Parse EmissionYieldTrackers (3 trackers x 64 bytes each)
|
|
542
|
+
const emissions = []
|
|
543
|
+
for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
|
|
544
|
+
const lastSeenIndex = readNumber()
|
|
545
|
+
const lastPositionIndex = readNumber()
|
|
546
|
+
emissions.push({ lastSeenIndex, lastPositionIndex })
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
// Parse last_split_epoch (u64)
|
|
550
|
+
const lastSplitEpoch = data.readBigUInt64LE(offset)
|
|
551
|
+
offset += 8
|
|
552
|
+
|
|
553
|
+
// Skip padding (u64)
|
|
554
|
+
offset += 8
|
|
555
|
+
|
|
556
|
+
if (apyBasePoints === 0) continue
|
|
557
|
+
ticks.push({
|
|
558
|
+
apyBasePoints,
|
|
559
|
+
liquidityNet,
|
|
560
|
+
feeGrowthOutsidePt,
|
|
561
|
+
feeGrowthOutsideSy,
|
|
562
|
+
liquidityGross,
|
|
563
|
+
impliedRate,
|
|
564
|
+
principalPt,
|
|
565
|
+
principalSy,
|
|
566
|
+
principalShareSupply,
|
|
567
|
+
farms,
|
|
568
|
+
emissions,
|
|
569
|
+
lastSplitEpoch,
|
|
570
|
+
})
|
|
571
|
+
// console.log(ticks)
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
const market = readPubkey()
|
|
575
|
+
const feeGrowthIndexGlobalPt = readU128LE(data, offset)
|
|
576
|
+
offset += 16
|
|
577
|
+
const feeGrowthIndexGlobalSy = readU128LE(data, offset)
|
|
578
|
+
offset += 16
|
|
579
|
+
const currentPrefixSum = data.readBigUInt64LE(offset) // Active liquidity at current tick
|
|
580
|
+
offset += 8
|
|
581
|
+
const currentSpotPrice = data.readDoubleLE(offset)
|
|
582
|
+
offset += 8
|
|
583
|
+
const currentTick = data.readUint32LE(offset)
|
|
584
|
+
offset += 4
|
|
585
|
+
offset += 12 // padding
|
|
586
|
+
|
|
587
|
+
return {
|
|
588
|
+
ticksTree: ticks,
|
|
589
|
+
market,
|
|
590
|
+
feeGrowthIndexGlobalPt,
|
|
591
|
+
feeGrowthIndexGlobalSy,
|
|
592
|
+
currentPrefixSum,
|
|
593
|
+
currentSpotPrice,
|
|
594
|
+
currentTick,
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
|
|
599
|
+
return {
|
|
600
|
+
addressLookupTable: m.addressLookupTable,
|
|
601
|
+
mintSy: m.mintSy,
|
|
602
|
+
mintPt: m.mintPt,
|
|
603
|
+
vault: m.vault,
|
|
604
|
+
tokenSyEscrow: m.tokenSyEscrow,
|
|
605
|
+
tokenPtEscrow: m.tokenPtEscrow,
|
|
606
|
+
tokenFeeTreasurySy: m.tokenFeeTreasurySy,
|
|
607
|
+
tokenFeeTreasuryPt: m.tokenFeeTreasuryPt,
|
|
608
|
+
selfAddress: m.selfAddress,
|
|
609
|
+
syProgram: m.syProgram,
|
|
610
|
+
statusFlags: m.statusFlags,
|
|
611
|
+
cpiSyAccounts: m.cpiSyAccounts,
|
|
612
|
+
isCurrentFlashSwap: m.isCurrentFlashSwap,
|
|
613
|
+
lpFarm: m.lpFarm,
|
|
614
|
+
mintYt: m.mintYt,
|
|
615
|
+
tokenYtEscrow: m.tokenYtEscrow,
|
|
616
|
+
emissions: {
|
|
617
|
+
trackers: m.emissions.trackers.map((t) => ({
|
|
618
|
+
tokenEscrow: t.tokenEscrow,
|
|
619
|
+
lpShareIndex: deserializeAnchorizedPNum(t.lpShareIndex),
|
|
620
|
+
lastSeenStaged: Number(t.lastSeenStaged),
|
|
621
|
+
})),
|
|
622
|
+
},
|
|
623
|
+
liquidityNetBalanceLimits: m.liquidityNetBalanceLimits,
|
|
624
|
+
admin: m.admin,
|
|
625
|
+
ticks: m.ticks,
|
|
626
|
+
configurationOptions: {
|
|
627
|
+
lnFeeRateRoot: m.configurationOptions.lnFeeRateRoot,
|
|
628
|
+
treasuryFeeBps: m.configurationOptions.treasuryFeeBps,
|
|
629
|
+
minLpTickAmount: BigInt(m.configurationOptions.minLpTickAmount.toString()),
|
|
630
|
+
epsilonClamp: m.configurationOptions.epsilonClamp,
|
|
631
|
+
maxLpSupply: BigInt(m.configurationOptions.maxLpSupply.toString()),
|
|
632
|
+
tickSpace: m.configurationOptions.tickSpace,
|
|
633
|
+
},
|
|
634
|
+
financials: {
|
|
635
|
+
expirationTs: BigInt(m.financials.expirationTs),
|
|
636
|
+
ptBalance: BigInt(m.financials.ptBalance.toString()),
|
|
637
|
+
syBalance: BigInt(m.financials.syBalance.toString()),
|
|
638
|
+
liquidityBalance: BigInt(m.financials.liquidityBalance.toString()),
|
|
639
|
+
},
|
|
640
|
+
cpiCoreAccounts: m.cpiCoreAccounts,
|
|
641
|
+
exponentCoreProgram: m.exponentCoreProgram,
|
|
642
|
+
}
|
|
287
643
|
}
|
|
288
644
|
|
|
289
645
|
function deserializeMarketTwo(m: MarketTwoRaw): MarketTwo {
|
|
@@ -324,6 +680,34 @@ function deserializeMarketTwo(m: MarketTwoRaw): MarketTwo {
|
|
|
324
680
|
}
|
|
325
681
|
}
|
|
326
682
|
|
|
683
|
+
function deserializeLpPositionCLMM(x: LpPositionCLMMRaw): LpPositionCLMM {
|
|
684
|
+
return {
|
|
685
|
+
owner: x.owner,
|
|
686
|
+
market: x.market,
|
|
687
|
+
feeInsideLastPt: BigInt(x.feeInsideLastPt.toString()),
|
|
688
|
+
feeInsideLastSy: BigInt(x.feeInsideLastSy.toString()),
|
|
689
|
+
lpBalance: BigInt(x.lpBalance.toString()),
|
|
690
|
+
tokensOwedSy: BigInt(x.tokensOwedSy.toString()),
|
|
691
|
+
tokensOwedPt: BigInt(x.tokensOwedPt.toString()),
|
|
692
|
+
lowerTickIdx: x.lowerTickIdx,
|
|
693
|
+
upperTickIdx: x.upperTickIdx,
|
|
694
|
+
farms: x.farms.trackers.map((t) => ({
|
|
695
|
+
staged: BigInt(t.staged.toString()),
|
|
696
|
+
lastSeenIndex: parseFloat(PreciseNumber.fromRaw(t.lastSeenIndex[0]).valueString),
|
|
697
|
+
})),
|
|
698
|
+
shareTrackers: x.shareTrackers.trackers.map((tracker) => ({
|
|
699
|
+
tickIdx: tracker.tickIdx,
|
|
700
|
+
rightTickIdx: tracker.rightTickIdx,
|
|
701
|
+
splitEpoch: BigInt(tracker.splitEpoch.toString()),
|
|
702
|
+
lpShare: BigInt(tracker.lpShare.toString()),
|
|
703
|
+
emissions: tracker.emissions.trackers.map((e) => ({
|
|
704
|
+
staged: BigInt(e.staged.toString()),
|
|
705
|
+
lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
|
|
706
|
+
})),
|
|
707
|
+
})),
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
327
711
|
function deserializeVault(x: VaultRaw): Vault {
|
|
328
712
|
return {
|
|
329
713
|
syProgram: x.syProgram,
|
|
@@ -355,6 +739,246 @@ function deserializeVault(x: VaultRaw): Vault {
|
|
|
355
739
|
}
|
|
356
740
|
}
|
|
357
741
|
|
|
742
|
+
function deserializeOrderbook(data: Buffer): Orderbook {
|
|
743
|
+
let offset = 0
|
|
744
|
+
|
|
745
|
+
// 1) Skip Anchor discriminator
|
|
746
|
+
offset += DISCRIMINATOR_SIZE
|
|
747
|
+
|
|
748
|
+
const readPubkey = (): web3.PublicKey => {
|
|
749
|
+
const pk = new web3.PublicKey(data.slice(offset, offset + 32))
|
|
750
|
+
offset += 32
|
|
751
|
+
return pk
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// ConfigurationOptions struct
|
|
755
|
+
const thresholdAmount = data.readBigUInt64LE(offset)
|
|
756
|
+
offset += 8
|
|
757
|
+
const lnMakerFeeRate = data.readDoubleLE(offset)
|
|
758
|
+
offset += 8
|
|
759
|
+
const lnTakerFeeRate = data.readDoubleLE(offset)
|
|
760
|
+
offset += 8
|
|
761
|
+
const priceDecimals = data.readUint8(offset)
|
|
762
|
+
offset += 1
|
|
763
|
+
// Skip ConfigurationOptions padding: _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] = 111 bytes
|
|
764
|
+
offset += 111
|
|
765
|
+
|
|
766
|
+
// Pubkeys
|
|
767
|
+
const vault = readPubkey()
|
|
768
|
+
const yieldPosition = readPubkey()
|
|
769
|
+
const addressLookupTable = readPubkey()
|
|
770
|
+
const exponentCoreProgram = readPubkey()
|
|
771
|
+
const syProgram = readPubkey()
|
|
772
|
+
const tokenEscrowSy = readPubkey()
|
|
773
|
+
const tokenEscrowYt = readPubkey()
|
|
774
|
+
const tokenEscrowPt = readPubkey()
|
|
775
|
+
const cpiAccountOrderbook = readPubkey()
|
|
776
|
+
const admin = readPubkey()
|
|
777
|
+
|
|
778
|
+
// Skip last_sy_exchange_rate (Number type = 32 bytes)
|
|
779
|
+
offset += 32
|
|
780
|
+
|
|
781
|
+
// OrderbookFinancials struct
|
|
782
|
+
// Skip last_seen_sy_index (Number type = 32 bytes)
|
|
783
|
+
offset += 32
|
|
784
|
+
const ytBalance = data.readBigUInt64LE(offset)
|
|
785
|
+
offset += 8
|
|
786
|
+
const syBalance = data.readBigUInt64LE(offset)
|
|
787
|
+
offset += 8
|
|
788
|
+
const ptBalance = data.readBigUInt64LE(offset)
|
|
789
|
+
offset += 8
|
|
790
|
+
const ytFeeBalance = data.readBigUInt64LE(offset)
|
|
791
|
+
offset += 8
|
|
792
|
+
const syFeeBalance = data.readBigUInt64LE(offset)
|
|
793
|
+
offset += 8
|
|
794
|
+
const ptFeeBalance = data.readBigUInt64LE(offset)
|
|
795
|
+
offset += 8
|
|
796
|
+
const stagedSyBalance = data.readBigUInt64LE(offset)
|
|
797
|
+
offset += 8
|
|
798
|
+
const expirationTs = data.readUInt32LE(offset)
|
|
799
|
+
offset += 4
|
|
800
|
+
// Skip financials _padding: [u8; 4]
|
|
801
|
+
offset += 4
|
|
802
|
+
|
|
803
|
+
const configurationOptions: ConfigurationOptions = {
|
|
804
|
+
priceDecimals,
|
|
805
|
+
thresholdAmount,
|
|
806
|
+
lnMakerFeeRate,
|
|
807
|
+
lnTakerFeeRate,
|
|
808
|
+
}
|
|
809
|
+
const financials: OrderbookFinancials = {
|
|
810
|
+
expirationTs,
|
|
811
|
+
syBalance: syBalance,
|
|
812
|
+
ytBalance: ytBalance,
|
|
813
|
+
ptBalance: ptBalance,
|
|
814
|
+
ytFeeBalance,
|
|
815
|
+
syFeeBalance,
|
|
816
|
+
ptFeeBalance,
|
|
817
|
+
stagedSy: stagedSyBalance,
|
|
818
|
+
}
|
|
819
|
+
// console.log("financials", financials)
|
|
820
|
+
// ─── Parse RedBlackTree slab ───────────────────────────────────────────────
|
|
821
|
+
// repr(C) gives: root: u32, pad to align NodeAllocator’s u64, then the NodeAllocator header
|
|
822
|
+
|
|
823
|
+
const root = data.readUInt32LE(offset)
|
|
824
|
+
offset += 4
|
|
825
|
+
const padTo8 = 8
|
|
826
|
+
offset += padTo8
|
|
827
|
+
|
|
828
|
+
// NodeAllocator<T=RBNode<u32,PriceNode>, N=MAX_PRICE_NODES, R=3>
|
|
829
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
830
|
+
|
|
831
|
+
const priceTreeSize = Number(data.readBigUInt64LE(offset))
|
|
832
|
+
offset += 8
|
|
833
|
+
|
|
834
|
+
const _priceTreeBump = data.readUInt32LE(offset)
|
|
835
|
+
offset += 4
|
|
836
|
+
|
|
837
|
+
const _priceTreeFreeIdx = data.readUInt32LE(offset)
|
|
838
|
+
offset += 4
|
|
839
|
+
|
|
840
|
+
// each RBNode entry = registers[3] + key:u32 + first_offer:u32
|
|
841
|
+
const prices: PriceTreeNode[] = []
|
|
842
|
+
for (let i = 0; i < MAX_PRICE_NODES; i++) {
|
|
843
|
+
const left = data.readUInt32LE(offset)
|
|
844
|
+
offset += 4
|
|
845
|
+
const right = data.readUInt32LE(offset)
|
|
846
|
+
offset += 4
|
|
847
|
+
const parent = data.readUInt32LE(offset)
|
|
848
|
+
offset += 4
|
|
849
|
+
offset += 4 // skip color
|
|
850
|
+
const key = data.readUInt32LE(offset)
|
|
851
|
+
offset += 4
|
|
852
|
+
|
|
853
|
+
const firstOfferSellYt = data.readUInt32LE(offset)
|
|
854
|
+
offset += 4
|
|
855
|
+
const firstOfferBuyYt = data.readUInt32LE(offset)
|
|
856
|
+
offset += 4
|
|
857
|
+
const lastOfferSellYt = data.readUInt32LE(offset)
|
|
858
|
+
offset += 4
|
|
859
|
+
const lastOfferBuyYt = data.readUInt32LE(offset)
|
|
860
|
+
offset += 4
|
|
861
|
+
if (key === 0) continue
|
|
862
|
+
prices.push({ key, firstOfferSellYt, firstOfferBuyYt, lastOfferSellYt, lastOfferBuyYt, parent, left, right })
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// ─── Parse Offers slab ────────────────────────────────────────────────────
|
|
866
|
+
// NodeAllocator<Offer, MAX_OFFERS, 4>
|
|
867
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
868
|
+
|
|
869
|
+
const offersSize = Number(data.readBigUInt64LE(offset))
|
|
870
|
+
offset += 8
|
|
871
|
+
const _offersBump = data.readUInt32LE(offset)
|
|
872
|
+
offset += 4
|
|
873
|
+
const _offersFreeIdx = data.readUInt32LE(offset)
|
|
874
|
+
offset += 4
|
|
875
|
+
|
|
876
|
+
const offers: OfferNode[] = []
|
|
877
|
+
for (let i = 0; i < MAX_OFFERS; i++) {
|
|
878
|
+
const register = data.readUInt32LE(offset)
|
|
879
|
+
offset += 4
|
|
880
|
+
const nextOfferPointer = data.readUInt32LE(offset)
|
|
881
|
+
offset += 4
|
|
882
|
+
const userVaultPointer = data.readUInt32LE(offset)
|
|
883
|
+
offset += 4
|
|
884
|
+
const pricePointer = data.readUInt32LE(offset)
|
|
885
|
+
offset += 4
|
|
886
|
+
const amount = data.readBigUInt64LE(offset)
|
|
887
|
+
offset += 8
|
|
888
|
+
const expiryAt = data.readUInt32LE(offset)
|
|
889
|
+
offset += 4
|
|
890
|
+
const createdAt = data.readUInt32LE(offset)
|
|
891
|
+
offset += 4
|
|
892
|
+
const virtualOffer = data.readUInt8(offset) !== 0
|
|
893
|
+
offset += 1
|
|
894
|
+
const orderTypeFlag = data.readUInt8(offset)
|
|
895
|
+
offset += 1
|
|
896
|
+
const fillOrKill = data.readUInt8(offset) !== 0
|
|
897
|
+
offset += 1
|
|
898
|
+
offset += 5 // reserved padding
|
|
899
|
+
if (userVaultPointer === 0) continue
|
|
900
|
+
offers.push({
|
|
901
|
+
nextOfferPointer,
|
|
902
|
+
amount,
|
|
903
|
+
userVaultPointer,
|
|
904
|
+
expiryAt,
|
|
905
|
+
createdAt,
|
|
906
|
+
virtualOffer,
|
|
907
|
+
orderTypeFlag,
|
|
908
|
+
fillOrKill,
|
|
909
|
+
pricePointer,
|
|
910
|
+
})
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// ─── Parse UserEscrow slab ────────────────────────────────────────────────
|
|
914
|
+
// NodeAllocator<UserEscrow, MAX_USER_ESCROWS, 2>
|
|
915
|
+
// header: size:u64, bump_index:u32, free_list_head:u32
|
|
916
|
+
const escSize = Number(data.readBigUInt64LE(offset))
|
|
917
|
+
offset += 8
|
|
918
|
+
const _escBump = data.readUInt32LE(offset)
|
|
919
|
+
offset += 4
|
|
920
|
+
const _escFreeIdx = data.readUInt32LE(offset)
|
|
921
|
+
offset += 4
|
|
922
|
+
|
|
923
|
+
// each Node = [ no registers ] + UserEscrow.value
|
|
924
|
+
const userEscrows: UserEscrowNode[] = []
|
|
925
|
+
for (let i = 0; i < MAX_USER_ESCROWS; i++) {
|
|
926
|
+
const register = data.readUInt32LE(offset)
|
|
927
|
+
offset += 4
|
|
928
|
+
const register2 = data.readUInt32LE(offset)
|
|
929
|
+
offset += 4
|
|
930
|
+
const user = new web3.PublicKey(data.slice(offset, offset + 32))
|
|
931
|
+
offset += 32
|
|
932
|
+
/*const yieldIndex = data.readBigUInt64LE(offset).toString();*/ offset += 32
|
|
933
|
+
const ptAmount = data.readBigUInt64LE(offset)
|
|
934
|
+
offset += 8
|
|
935
|
+
const syAmount = data.readBigUInt64LE(offset)
|
|
936
|
+
offset += 8
|
|
937
|
+
const ytAmount = data.readBigUInt64LE(offset)
|
|
938
|
+
offset += 8
|
|
939
|
+
const stakedYtAmount = data.readBigInt64LE(offset)
|
|
940
|
+
offset += 8
|
|
941
|
+
const staged = data.readBigInt64LE(offset)
|
|
942
|
+
offset += 8
|
|
943
|
+
offset += 8 // reserved
|
|
944
|
+
if (user.toBase58() == "11111111111111111111111111111111") continue
|
|
945
|
+
userEscrows.push({ user, yieldIndex: 0, ptAmount, syAmount, ytAmount, stakedYtAmount, staged })
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// ─── Finally, seed_id + signer_bump + reserved ─────────────────────────────
|
|
949
|
+
// seed_id: [u8; 4]
|
|
950
|
+
const seedId = [
|
|
951
|
+
data.readUInt8(offset),
|
|
952
|
+
data.readUInt8(offset + 1),
|
|
953
|
+
data.readUInt8(offset + 2),
|
|
954
|
+
data.readUInt8(offset + 3),
|
|
955
|
+
]
|
|
956
|
+
offset += 4
|
|
957
|
+
// signer_bump: [u8; 1]
|
|
958
|
+
const signerBump = data.readUInt8(offset)
|
|
959
|
+
offset += 1
|
|
960
|
+
// _reserved: [u8; 3] - skip
|
|
961
|
+
offset += 3
|
|
962
|
+
|
|
963
|
+
return {
|
|
964
|
+
vault,
|
|
965
|
+
yieldPosition,
|
|
966
|
+
addressLookupTable,
|
|
967
|
+
exponentCoreProgram,
|
|
968
|
+
syProgram,
|
|
969
|
+
admin,
|
|
970
|
+
tokenEscrowSy,
|
|
971
|
+
tokenEscrowYt,
|
|
972
|
+
tokenEscrowPt,
|
|
973
|
+
cpiAccountOrderbook,
|
|
974
|
+
financials,
|
|
975
|
+
prices,
|
|
976
|
+
configurationOptions,
|
|
977
|
+
offers,
|
|
978
|
+
userEscrows,
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
|
|
358
982
|
function deserializeMarginfiSyMeta(x: MarginfiSyMetaRaw): MarginfiSyMeta {
|
|
359
983
|
return {
|
|
360
984
|
...x,
|
|
@@ -386,7 +1010,7 @@ function deserializeSyEmissionRaw(x: {
|
|
|
386
1010
|
}
|
|
387
1011
|
}
|
|
388
1012
|
|
|
389
|
-
function deserializeLpPosition(x: LpPositionRaw): LpPosition {
|
|
1013
|
+
export function deserializeLpPosition(x: LpPositionRaw): LpPosition {
|
|
390
1014
|
return {
|
|
391
1015
|
owner: x.owner,
|
|
392
1016
|
market: x.market,
|
|
@@ -402,7 +1026,7 @@ function deserializeLpPosition(x: LpPositionRaw): LpPosition {
|
|
|
402
1026
|
}
|
|
403
1027
|
}
|
|
404
1028
|
|
|
405
|
-
function deserializeYtPosition(x: YtPositionRaw): YtPosition {
|
|
1029
|
+
export function deserializeYtPosition(x: YtPositionRaw): YtPosition {
|
|
406
1030
|
return {
|
|
407
1031
|
owner: x.owner,
|
|
408
1032
|
vault: x.vault,
|
|
@@ -419,16 +1043,30 @@ function deserializeYieldTokenTracker(x: YieldTokenTrackerRaw): YieldTokenTracke
|
|
|
419
1043
|
}
|
|
420
1044
|
}
|
|
421
1045
|
|
|
422
|
-
export
|
|
1046
|
+
export interface KaminoReserveSummary {
|
|
1047
|
+
lendingMarket: web3.PublicKey
|
|
1048
|
+
baseMint: web3.PublicKey
|
|
1049
|
+
assetShareValue: Decimal
|
|
1050
|
+
scopePriceFeed?: web3.PublicKey
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
export async function fetchKaminoReserve(
|
|
1054
|
+
address: web3.PublicKey,
|
|
1055
|
+
connection: web3.Connection,
|
|
1056
|
+
): Promise<KaminoReserveSummary> {
|
|
423
1057
|
const reserve = await Reserve.fetch(connection, address)
|
|
424
1058
|
if (!reserve) {
|
|
425
1059
|
throw new Error("Reserve not found")
|
|
426
1060
|
}
|
|
427
1061
|
|
|
1062
|
+
const rawScopePriceFeed = reserve.config.tokenInfo.scopeConfiguration.priceFeed
|
|
1063
|
+
const scopePriceFeed = rawScopePriceFeed.equals(web3.PublicKey.default) ? undefined : rawScopePriceFeed
|
|
1064
|
+
|
|
428
1065
|
return {
|
|
429
1066
|
lendingMarket: reserve.lendingMarket,
|
|
430
1067
|
baseMint: reserve.liquidity.mintPubkey,
|
|
431
1068
|
assetShareValue: reserve.getCollateralExchangeRate(),
|
|
1069
|
+
scopePriceFeed,
|
|
432
1070
|
}
|
|
433
1071
|
}
|
|
434
1072
|
|
|
@@ -492,6 +1130,157 @@ export function deserializeEmission(emission: VaultEmissionJson): VaultEmission
|
|
|
492
1130
|
}
|
|
493
1131
|
}
|
|
494
1132
|
|
|
1133
|
+
export interface MarketThree {
|
|
1134
|
+
admin: web3.PublicKey
|
|
1135
|
+
addressLookupTable: web3.PublicKey
|
|
1136
|
+
mintPt: web3.PublicKey
|
|
1137
|
+
mintSy: web3.PublicKey
|
|
1138
|
+
mintYt: web3.PublicKey
|
|
1139
|
+
vault: web3.PublicKey
|
|
1140
|
+
tokenPtEscrow: web3.PublicKey
|
|
1141
|
+
tokenSyEscrow: web3.PublicKey
|
|
1142
|
+
tokenYtEscrow: web3.PublicKey
|
|
1143
|
+
tokenFeeTreasurySy: web3.PublicKey
|
|
1144
|
+
tokenFeeTreasuryPt: web3.PublicKey
|
|
1145
|
+
syProgram: web3.PublicKey
|
|
1146
|
+
exponentCoreProgram: web3.PublicKey
|
|
1147
|
+
selfAddress: web3.PublicKey
|
|
1148
|
+
ticks: web3.PublicKey
|
|
1149
|
+
statusFlags: number
|
|
1150
|
+
configurationOptions: MarketConfigurationOptions
|
|
1151
|
+
financials: MarketThreeFinancials
|
|
1152
|
+
cpiSyAccounts: CpiAccountIndexes
|
|
1153
|
+
cpiCoreAccounts: MarketCpiCoreIndexes
|
|
1154
|
+
isCurrentFlashSwap: boolean
|
|
1155
|
+
lpFarm: LpFarm
|
|
1156
|
+
emissions: {
|
|
1157
|
+
trackers: {
|
|
1158
|
+
tokenEscrow: web3.PublicKey
|
|
1159
|
+
lpShareIndex: number
|
|
1160
|
+
lastSeenStaged: number
|
|
1161
|
+
}[]
|
|
1162
|
+
}
|
|
1163
|
+
liquidityNetBalanceLimits: LiquidityNetBalanceLimits
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
export interface Ticks {
|
|
1167
|
+
/** Current tick (left boundary of the active interval) */
|
|
1168
|
+
currentTick: number
|
|
1169
|
+
/** Array of ticks (simplified from RBTree for TypeScript) */
|
|
1170
|
+
ticksTree: Tick[]
|
|
1171
|
+
/** Market address this ticks account belongs to */
|
|
1172
|
+
market: web3.PublicKey
|
|
1173
|
+
/** Fee growth index global for PT */
|
|
1174
|
+
feeGrowthIndexGlobalPt: bigint
|
|
1175
|
+
/** Fee growth index global for SY */
|
|
1176
|
+
feeGrowthIndexGlobalSy: bigint
|
|
1177
|
+
/** Current prefix sum - the active liquidity at the current tick */
|
|
1178
|
+
currentPrefixSum: bigint
|
|
1179
|
+
/** Current spot price (ln implied rate) */
|
|
1180
|
+
currentSpotPrice: number
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
export interface Tick {
|
|
1184
|
+
liquidityNet: bigint
|
|
1185
|
+
/** Total liquidity referencing this tick as a boundary */
|
|
1186
|
+
liquidityGross: bigint
|
|
1187
|
+
/** Fee growth index outside this tick for PT */
|
|
1188
|
+
feeGrowthOutsidePt: bigint
|
|
1189
|
+
/** Fee growth index outside this tick for SY */
|
|
1190
|
+
feeGrowthOutsideSy: bigint
|
|
1191
|
+
/** Principal PT accrued in the interval starting at this tick */
|
|
1192
|
+
impliedRate: number
|
|
1193
|
+
principalPt: bigint
|
|
1194
|
+
/** Principal SY accrued in the interval starting at this tick */
|
|
1195
|
+
principalSy: bigint
|
|
1196
|
+
apyBasePoints: number
|
|
1197
|
+
principalShareSupply: bigint
|
|
1198
|
+
/** Farm yield trackers (3 trackers) */
|
|
1199
|
+
farms: { lastSeenIndex: number }[]
|
|
1200
|
+
/** Emission yield trackers (3 trackers) */
|
|
1201
|
+
emissions: { lastSeenIndex: number; lastPositionIndex: number }[]
|
|
1202
|
+
/** Last split epoch for this tick */
|
|
1203
|
+
lastSplitEpoch: bigint
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
export interface MarketThreeRaw {
|
|
1207
|
+
admin: web3.PublicKey
|
|
1208
|
+
addressLookupTable: web3.PublicKey
|
|
1209
|
+
mintPt: web3.PublicKey
|
|
1210
|
+
mintSy: web3.PublicKey
|
|
1211
|
+
mintYt: web3.PublicKey
|
|
1212
|
+
vault: web3.PublicKey
|
|
1213
|
+
tokenPtEscrow: web3.PublicKey
|
|
1214
|
+
tokenSyEscrow: web3.PublicKey
|
|
1215
|
+
tokenYtEscrow: web3.PublicKey
|
|
1216
|
+
tokenFeeTreasurySy: web3.PublicKey
|
|
1217
|
+
tokenFeeTreasuryPt: web3.PublicKey
|
|
1218
|
+
syProgram: web3.PublicKey
|
|
1219
|
+
exponentCoreProgram: web3.PublicKey
|
|
1220
|
+
selfAddress: web3.PublicKey
|
|
1221
|
+
ticks: web3.PublicKey
|
|
1222
|
+
statusFlags: number
|
|
1223
|
+
configurationOptions: MarketConfigurationOptionsRaw
|
|
1224
|
+
financials: MarketThreeFinancialsRaw
|
|
1225
|
+
cpiSyAccounts: CpiAccountIndexes
|
|
1226
|
+
cpiCoreAccounts: MarketCpiCoreIndexes
|
|
1227
|
+
isCurrentFlashSwap: boolean
|
|
1228
|
+
lpFarm: LpFarm
|
|
1229
|
+
emissions: MarketEmissions
|
|
1230
|
+
liquidityNetBalanceLimits: LiquidityNetBalanceLimits
|
|
1231
|
+
seedId: number[]
|
|
1232
|
+
}
|
|
1233
|
+
|
|
1234
|
+
export interface MarketConfigurationOptions {
|
|
1235
|
+
/** ln of fee rate root */
|
|
1236
|
+
lnFeeRateRoot: number
|
|
1237
|
+
/** Treasury fee in basis points */
|
|
1238
|
+
treasuryFeeBps: number
|
|
1239
|
+
/** Minimum LP amount per tick */
|
|
1240
|
+
minLpTickAmount: bigint
|
|
1241
|
+
/** Epsilon clamp for numerical stability */
|
|
1242
|
+
epsilonClamp: number
|
|
1243
|
+
/** Maximum LP supply */
|
|
1244
|
+
maxLpSupply: bigint
|
|
1245
|
+
/** Tick space */
|
|
1246
|
+
tickSpace: number
|
|
1247
|
+
// priceDecimals: number ??
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
export interface MarketThreeFinancials {
|
|
1251
|
+
expirationTs: bigint
|
|
1252
|
+
ptBalance: bigint
|
|
1253
|
+
syBalance: bigint
|
|
1254
|
+
liquidityBalance: bigint
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
export interface MarketConfigurationOptionsRaw {
|
|
1258
|
+
lnFeeRateRoot: number
|
|
1259
|
+
treasuryFeeBps: number
|
|
1260
|
+
minLpTickAmount: BN
|
|
1261
|
+
epsilonClamp: number
|
|
1262
|
+
maxLpSupply: BN
|
|
1263
|
+
tickSpace: number
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
export interface OrderbookConfigurationOptionsRaw {
|
|
1267
|
+
thresholdAmount: BN
|
|
1268
|
+
lnMakerFeeRate: number
|
|
1269
|
+
lnTakerFeeRate: number
|
|
1270
|
+
priceDecimals: number
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
export interface MarketThreeFinancialsRaw {
|
|
1274
|
+
/** Expiration timestamp */
|
|
1275
|
+
expirationTs: number
|
|
1276
|
+
/** PT balance in the market */
|
|
1277
|
+
ptBalance: BN
|
|
1278
|
+
/** SY balance in the market */
|
|
1279
|
+
syBalance: BN
|
|
1280
|
+
/** Total liquidity balance */
|
|
1281
|
+
liquidityBalance: BN
|
|
1282
|
+
}
|
|
1283
|
+
|
|
495
1284
|
export interface MarketTwo {
|
|
496
1285
|
ptBalance: bigint
|
|
497
1286
|
syBalance: bigint
|
|
@@ -557,6 +1346,42 @@ export interface Vault {
|
|
|
557
1346
|
maxPySupply: bigint
|
|
558
1347
|
}
|
|
559
1348
|
|
|
1349
|
+
interface OrderbookFinancials {
|
|
1350
|
+
expirationTs: number
|
|
1351
|
+
ytBalance: bigint
|
|
1352
|
+
syBalance: bigint
|
|
1353
|
+
ptBalance: bigint
|
|
1354
|
+
ytFeeBalance: bigint
|
|
1355
|
+
syFeeBalance: bigint
|
|
1356
|
+
ptFeeBalance: bigint
|
|
1357
|
+
stagedSy: bigint
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
export interface ConfigurationOptions {
|
|
1361
|
+
priceDecimals: number
|
|
1362
|
+
thresholdAmount: bigint
|
|
1363
|
+
lnMakerFeeRate: number
|
|
1364
|
+
lnTakerFeeRate: number
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
export interface Orderbook {
|
|
1368
|
+
vault: web3.PublicKey
|
|
1369
|
+
yieldPosition: web3.PublicKey
|
|
1370
|
+
addressLookupTable: web3.PublicKey
|
|
1371
|
+
exponentCoreProgram: web3.PublicKey
|
|
1372
|
+
syProgram: web3.PublicKey
|
|
1373
|
+
tokenEscrowSy: web3.PublicKey
|
|
1374
|
+
tokenEscrowYt: web3.PublicKey
|
|
1375
|
+
tokenEscrowPt: web3.PublicKey
|
|
1376
|
+
cpiAccountOrderbook: web3.PublicKey
|
|
1377
|
+
admin: web3.PublicKey
|
|
1378
|
+
configurationOptions: ConfigurationOptions
|
|
1379
|
+
financials: OrderbookFinancials
|
|
1380
|
+
prices: PriceTreeNode[]
|
|
1381
|
+
offers: OfferNode[]
|
|
1382
|
+
userEscrows: UserEscrowNode[]
|
|
1383
|
+
}
|
|
1384
|
+
|
|
560
1385
|
export interface KaminoSyMeta {
|
|
561
1386
|
kaminoReserve: web3.PublicKey
|
|
562
1387
|
kaminoObligation: web3.PublicKey
|
|
@@ -604,7 +1429,7 @@ export interface YieldTokenTracker {
|
|
|
604
1429
|
lastSeenIndex: number
|
|
605
1430
|
}
|
|
606
1431
|
|
|
607
|
-
interface LpPositionRaw {
|
|
1432
|
+
export interface LpPositionRaw {
|
|
608
1433
|
owner: web3.PublicKey
|
|
609
1434
|
market: web3.PublicKey
|
|
610
1435
|
lpBalance: BN
|
|
@@ -612,6 +1437,48 @@ interface LpPositionRaw {
|
|
|
612
1437
|
farms: { trackers: { staged: BN; lastSeenIndex: AnchorizedPNum }[] }
|
|
613
1438
|
}
|
|
614
1439
|
|
|
1440
|
+
interface LpPositionCLMMRaw {
|
|
1441
|
+
owner: web3.PublicKey
|
|
1442
|
+
market: web3.PublicKey
|
|
1443
|
+
feeInsideLastPt: BN
|
|
1444
|
+
feeInsideLastSy: BN
|
|
1445
|
+
lpBalance: BN
|
|
1446
|
+
tokensOwedSy: BN
|
|
1447
|
+
tokensOwedPt: BN
|
|
1448
|
+
lowerTickIdx: number
|
|
1449
|
+
upperTickIdx: number
|
|
1450
|
+
farms: { trackers: { staged: BN; lastSeenIndex: AnchorizedPNum }[] }
|
|
1451
|
+
shareTrackers: {
|
|
1452
|
+
trackers: {
|
|
1453
|
+
tickIdx: number
|
|
1454
|
+
rightTickIdx: number
|
|
1455
|
+
splitEpoch: BN
|
|
1456
|
+
lpShare: BN
|
|
1457
|
+
emissions: { trackers: { staged: BN; lastSeenIndex: AnchorizedPNum }[] }
|
|
1458
|
+
}[]
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
export interface LpPositionCLMM {
|
|
1463
|
+
owner: web3.PublicKey
|
|
1464
|
+
market: web3.PublicKey
|
|
1465
|
+
feeInsideLastPt: bigint
|
|
1466
|
+
feeInsideLastSy: bigint
|
|
1467
|
+
lpBalance: bigint
|
|
1468
|
+
tokensOwedSy: bigint
|
|
1469
|
+
tokensOwedPt: bigint
|
|
1470
|
+
lowerTickIdx: number
|
|
1471
|
+
upperTickIdx: number
|
|
1472
|
+
farms: { staged: bigint; lastSeenIndex: number }[]
|
|
1473
|
+
shareTrackers: {
|
|
1474
|
+
tickIdx: number
|
|
1475
|
+
rightTickIdx: number
|
|
1476
|
+
splitEpoch: bigint
|
|
1477
|
+
lpShare: bigint
|
|
1478
|
+
emissions: { staged: bigint; lastSeenIndex: number }[]
|
|
1479
|
+
}[]
|
|
1480
|
+
}
|
|
1481
|
+
|
|
615
1482
|
export interface LpFarm {
|
|
616
1483
|
lastSeenTimestamp: number
|
|
617
1484
|
farmEmissions: FarmEmissionRaw[]
|
|
@@ -636,7 +1503,7 @@ export interface MarketEmissions {
|
|
|
636
1503
|
trackers: MarketEmission[]
|
|
637
1504
|
}
|
|
638
1505
|
|
|
639
|
-
interface MarketEmission {
|
|
1506
|
+
export interface MarketEmission {
|
|
640
1507
|
tokenEscrow: web3.PublicKey
|
|
641
1508
|
lpShareIndex: AnchorizedPNum
|
|
642
1509
|
lastSeenStaged: BN
|
|
@@ -719,7 +1586,7 @@ interface KaminoSyMetaRaw {
|
|
|
719
1586
|
emissions: SyEmissionRaw[]
|
|
720
1587
|
}
|
|
721
1588
|
|
|
722
|
-
interface YtPositionRaw {
|
|
1589
|
+
export interface YtPositionRaw {
|
|
723
1590
|
owner: web3.PublicKey
|
|
724
1591
|
vault: web3.PublicKey
|
|
725
1592
|
ytBalance: BN
|
|
@@ -732,6 +1599,62 @@ interface YieldTokenTrackerRaw {
|
|
|
732
1599
|
lastSeenIndex: AnchorizedPNum
|
|
733
1600
|
}
|
|
734
1601
|
|
|
1602
|
+
export interface OrderbookCpiAccountsRaw {
|
|
1603
|
+
syCpiAccounts: CpiAccountIndexes
|
|
1604
|
+
exponentCoreCpiAccounts: ExponentCoreCpiIndexes
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
interface OrderbookRaw {
|
|
1608
|
+
vault: web3.PublicKey
|
|
1609
|
+
yieldPosition: web3.PublicKey
|
|
1610
|
+
addressLookupTable: web3.PublicKey
|
|
1611
|
+
exponentCoreProgram: web3.PublicKey
|
|
1612
|
+
cpiAccountOrderbook: web3.PublicKey
|
|
1613
|
+
tokenEscrowSy: web3.PublicKey
|
|
1614
|
+
tokenEscrowYt: web3.PublicKey
|
|
1615
|
+
tokenEscrowPt: web3.PublicKey
|
|
1616
|
+
nodeCount: number
|
|
1617
|
+
financials: OrderbookFinancialsRaw
|
|
1618
|
+
prices: PriceTreeNodeRaw[]
|
|
1619
|
+
offers: OfferNodeRaw[]
|
|
1620
|
+
userEscrows: UserEscrowNodeRaw[]
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
interface OrderbookFinancialsRaw {
|
|
1624
|
+
expirationTs: number
|
|
1625
|
+
ytBalance: BN
|
|
1626
|
+
syBalance: BN
|
|
1627
|
+
ptBalance: BN
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
export interface PriceTreeNodeRaw {
|
|
1631
|
+
key: number
|
|
1632
|
+
firstOffer: number
|
|
1633
|
+
parent: number
|
|
1634
|
+
left: number
|
|
1635
|
+
right: number
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
export interface OfferNodeRaw {
|
|
1639
|
+
register: number
|
|
1640
|
+
amount: BN
|
|
1641
|
+
userVaultPointer: number
|
|
1642
|
+
expiryAt: number
|
|
1643
|
+
createdAt: number
|
|
1644
|
+
virtualOffer: boolean
|
|
1645
|
+
orderTypeFlag: number
|
|
1646
|
+
fillOrKill: boolean
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
export interface UserEscrowNodeRaw {
|
|
1650
|
+
user: web3.PublicKey
|
|
1651
|
+
yieldIndex: BN
|
|
1652
|
+
ptAmount: BN
|
|
1653
|
+
syAmount: BN
|
|
1654
|
+
ytAmount: BN
|
|
1655
|
+
staged: number
|
|
1656
|
+
}
|
|
1657
|
+
|
|
735
1658
|
function deserializeAnchorizedPNum(x: AnchorizedPNum): number {
|
|
736
1659
|
return parseFloat(PreciseNumber.fromRaw(x[0]).valueString)
|
|
737
1660
|
}
|
|
@@ -745,30 +1668,7 @@ async function fetchJitoVaultData({
|
|
|
745
1668
|
vaultAddress: web3.PublicKey
|
|
746
1669
|
}) {
|
|
747
1670
|
const vaultAccountInfo = await connection.getAccountInfo(vaultAddress)
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
// the vault has an 8 byte discriminator at the beginning
|
|
751
|
-
const discriminatorOffset = 8
|
|
752
|
-
const vrtMintOffset = 32 + discriminatorOffset
|
|
753
|
-
const vrtSupplyOffset = 96 + discriminatorOffset
|
|
754
|
-
const jitoVaultTotalDepositsOffset = 104 + discriminatorOffset
|
|
755
|
-
const mintBase = new web3.PublicKey(d.slice(vrtMintOffset, vrtMintOffset + 32))
|
|
756
|
-
|
|
757
|
-
// For Borsh, numbers are serialized in little-endian format
|
|
758
|
-
const jitoVaultTotalSharesBuffer = d.slice(vrtSupplyOffset, vrtSupplyOffset + 8)
|
|
759
|
-
const jitoVaultTotalShares = new BN(jitoVaultTotalSharesBuffer, "le")
|
|
760
|
-
|
|
761
|
-
const jitoVaultTotalDepositsBuffer = d.slice(jitoVaultTotalDepositsOffset, jitoVaultTotalDepositsOffset + 8)
|
|
762
|
-
const jitoVaultTotalDeposits = new BN(jitoVaultTotalDepositsBuffer, "le")
|
|
763
|
-
|
|
764
|
-
const jitoVaultTotalSharesD = new Decimal(jitoVaultTotalShares.toString())
|
|
765
|
-
const jitoVaultTotalDepositsD = new Decimal(jitoVaultTotalDeposits.toString())
|
|
766
|
-
|
|
767
|
-
const exchangeRate = jitoVaultTotalDepositsD.isZero()
|
|
768
|
-
? "1.0"
|
|
769
|
-
: jitoVaultTotalDepositsD.div(jitoVaultTotalSharesD).toString()
|
|
770
|
-
|
|
771
|
-
return { exchangeRate: parseFloat(exchangeRate), mintBase }
|
|
1671
|
+
return decodeJitoVaultData(vaultAccountInfo.data)
|
|
772
1672
|
}
|
|
773
1673
|
|
|
774
1674
|
async function fetchJitoSolToSolExchangeRate({
|
|
@@ -810,23 +1710,16 @@ export async function fetchPerenaStablePoolData({
|
|
|
810
1710
|
connection: web3.Connection
|
|
811
1711
|
perenaStablePool: web3.PublicKey
|
|
812
1712
|
}) {
|
|
813
|
-
const
|
|
814
|
-
[perenaStablePool.toBuffer(), Buffer.from("liquidity")],
|
|
815
|
-
new web3.PublicKey("NUMERUNsFCP3kuNmWZuXtm1AaQCPj9uw6Guv2Ekoi5P"),
|
|
816
|
-
)
|
|
1713
|
+
const lpMint = getPerenaLpMint(perenaStablePool)
|
|
817
1714
|
|
|
818
1715
|
const [accountInfo, lpMintInfo] = await connection.getMultipleAccountsInfo([perenaStablePool, lpMint])
|
|
819
|
-
const lpMintDeserialized = MintLayout.decode(lpMintInfo.data)
|
|
820
|
-
const d = accountInfo.data
|
|
821
|
-
|
|
822
|
-
const discriminatorOffset = 8
|
|
823
|
-
const invTOffset = discriminatorOffset + 32 + 32 + 32 + 32 // 4 Pubkeys before invT
|
|
824
|
-
const invTBuffer = d.slice(invTOffset, invTOffset + 8)
|
|
825
|
-
const invT = Buffer.from(invTBuffer).readBigUInt64LE(0)
|
|
826
1716
|
|
|
827
|
-
const exchangeRate =
|
|
1717
|
+
const { lpSupply, invT, exchangeRate } = getPerenaStablePoolData({
|
|
1718
|
+
perenaStablePoolData: accountInfo.data,
|
|
1719
|
+
lpMintData: lpMintInfo.data,
|
|
1720
|
+
})
|
|
828
1721
|
|
|
829
|
-
return { lpSupply
|
|
1722
|
+
return { lpSupply, invT, exchangeRate, lpMint }
|
|
830
1723
|
}
|
|
831
1724
|
|
|
832
1725
|
/**
|
|
@@ -880,53 +1773,19 @@ export async function fetchJupiterPerpsIndex({
|
|
|
880
1773
|
lastAumUsd: BN
|
|
881
1774
|
currentIndex: AnchorizedPNum
|
|
882
1775
|
lastRealizedFeeUsdUpdateUnixTimestamp: number
|
|
883
|
-
}): Promise<{
|
|
884
|
-
index: number
|
|
885
|
-
newState: {
|
|
886
|
-
lastAumUsd: BN
|
|
887
|
-
lastRealizedFeeUsd: BN
|
|
888
|
-
lastFeeUsdResetUnixTimestamp: number
|
|
889
|
-
lastRealizedFeeUsdUpdateUnixTimestamp: number
|
|
890
|
-
}
|
|
891
|
-
}> {
|
|
892
|
-
// Decode pool account using helper that leverages Anchor 0.29.0
|
|
1776
|
+
}): Promise<ReturnType<typeof calculateJupiterPerpsIndex>> {
|
|
893
1777
|
const accountInfo = await connection.getAccountInfo(pool)
|
|
894
|
-
const account: any = decodeJupiterPerpsPoolAccount(accountInfo?.data as Buffer)
|
|
895
|
-
const SECONDS_PER_YEAR = 365 * 24 * 60 * 60
|
|
896
|
-
|
|
897
|
-
let newFeesBn: BN
|
|
898
1778
|
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
: new BN(0)
|
|
908
|
-
|
|
909
|
-
const missingFees = estTotalFees.sub(lastRealizedFeeUsd)
|
|
910
|
-
const feesSinceReset = new BN(account.poolApr.realizedFeeUsd.toString())
|
|
911
|
-
newFeesBn = missingFees.add(feesSinceReset)
|
|
912
|
-
} else {
|
|
913
|
-
newFeesBn = new BN(account.poolApr.realizedFeeUsd.toString()).sub(lastRealizedFeeUsd)
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
const aumUsd = new BN(account.aumUsd.toString())
|
|
917
|
-
const indexIncrease = new Decimal(newFeesBn.toString()).div(new Decimal(aumUsd.toString())).toNumber()
|
|
918
|
-
const currentIndexNum = parseFloat(PreciseNumber.fromRaw(currentIndex[0]).valueString)
|
|
919
|
-
const nextIndex = currentIndexNum + indexIncrease
|
|
920
|
-
|
|
921
|
-
return {
|
|
922
|
-
index: nextIndex,
|
|
923
|
-
newState: {
|
|
924
|
-
lastAumUsd: aumUsd,
|
|
925
|
-
lastRealizedFeeUsd: new BN(account.poolApr.realizedFeeUsd.toString()),
|
|
926
|
-
lastFeeUsdResetUnixTimestamp: Number(account.poolApr.lastUpdated),
|
|
927
|
-
lastRealizedFeeUsdUpdateUnixTimestamp: Math.floor(Date.now() / 1000),
|
|
1779
|
+
return calculateJupiterPerpsIndex(
|
|
1780
|
+
{ pool: accountInfo.data },
|
|
1781
|
+
{
|
|
1782
|
+
lastFeeUsdResetUnixTimestamp,
|
|
1783
|
+
lastRealizedFeeUsd,
|
|
1784
|
+
lastAumUsd,
|
|
1785
|
+
currentIndex,
|
|
1786
|
+
lastRealizedFeeUsdUpdateUnixTimestamp,
|
|
928
1787
|
},
|
|
929
|
-
|
|
1788
|
+
)
|
|
930
1789
|
}
|
|
931
1790
|
|
|
932
1791
|
export async function fetchPyth(connection: web3.Connection): Promise<string> {
|
|
@@ -975,13 +1834,11 @@ export async function fetchFragmetricIndex({
|
|
|
975
1834
|
connection: web3.Connection
|
|
976
1835
|
fragmetricFund: web3.PublicKey
|
|
977
1836
|
}) {
|
|
978
|
-
const
|
|
979
|
-
const coder = new BorshCoder(FragmetricIdl as Idl)
|
|
980
|
-
const data = coder.accounts.decode("FundAccount", account.data)
|
|
981
|
-
const index = Number(data.one_receipt_token_as_sol) / Number(10 ** data.receipt_token_decimals)
|
|
1837
|
+
const fragmetricFundRaw = await connection.getAccountInfo(fragmetricFund)
|
|
982
1838
|
|
|
983
|
-
const receiptTokenMint =
|
|
984
|
-
|
|
1839
|
+
const { index, receiptTokenMint, wrappedTokenMint } = calculateFragmetricIndex({
|
|
1840
|
+
fragmetricFund: fragmetricFundRaw.data,
|
|
1841
|
+
})
|
|
985
1842
|
|
|
986
1843
|
return { index, receiptTokenMint, wrappedTokenMint }
|
|
987
1844
|
}
|
|
@@ -992,21 +1849,24 @@ export async function fetchJupiterLendIndex({
|
|
|
992
1849
|
}: {
|
|
993
1850
|
connection: web3.Connection
|
|
994
1851
|
jupiterLendAccount: web3.PublicKey
|
|
995
|
-
}) {
|
|
1852
|
+
}): Promise<ReturnType<typeof calculateJupiterLendIndex> & { rateModel: web3.PublicKey }> {
|
|
996
1853
|
const account = await connection.getAccountInfo(jupiterLendAccount)
|
|
997
|
-
|
|
998
|
-
const data = coder.accounts.decode("Lending", account.data)
|
|
999
|
-
const index = Number(data.token_exchange_price) / Number(10 ** 12)
|
|
1000
|
-
const tokenReservesLiquidity = data.token_reserves_liquidity
|
|
1001
|
-
const lendingSupplyPosition = data.supply_position_on_liquidity
|
|
1002
|
-
const rewardsRateModel = data.rewards_rate_model
|
|
1854
|
+
|
|
1003
1855
|
const rateModel = jupiterLendAccount.equals(new web3.PublicKey("BeAqbxfrcXmzEYT2Ra62oW2MqkuFDHaCtps47Mzg6Zj3"))
|
|
1004
1856
|
? new web3.PublicKey("Acvyi9HBGmqh3Exe1N4PjBVyY8fokq2AdC6fSLqV6KSo")
|
|
1005
1857
|
: new web3.PublicKey("6iHHKAK9Mqjn57CVmWe4szAPyTH8s8pniXSj6vWaKW5r")
|
|
1006
1858
|
|
|
1007
|
-
|
|
1859
|
+
const { index, baseTokenMint, tokenReservesLiquidity, lendingSupplyPosition, rewardsRateModel } =
|
|
1860
|
+
calculateJupiterLendIndex({ jupiterLend: account.data })
|
|
1008
1861
|
|
|
1009
|
-
return {
|
|
1862
|
+
return {
|
|
1863
|
+
rateModel,
|
|
1864
|
+
index,
|
|
1865
|
+
baseTokenMint,
|
|
1866
|
+
tokenReservesLiquidity,
|
|
1867
|
+
lendingSupplyPosition,
|
|
1868
|
+
rewardsRateModel,
|
|
1869
|
+
}
|
|
1010
1870
|
}
|
|
1011
1871
|
|
|
1012
1872
|
export async function fetchKaminoVaultIndex({
|
|
@@ -1053,18 +1913,10 @@ export async function fetchFragmetricSupportedTokenIndex({
|
|
|
1053
1913
|
connection: web3.Connection
|
|
1054
1914
|
fragmetricFund: web3.PublicKey
|
|
1055
1915
|
index: number
|
|
1056
|
-
}) {
|
|
1916
|
+
}): Promise<ReturnType<typeof calculateFragmetricSupportedTokenIndex>> {
|
|
1057
1917
|
const account = await connection.getAccountInfo(fragmetricFund)
|
|
1058
|
-
const coder = new BorshCoder(FragmetricIdl as Idl)
|
|
1059
|
-
const data = coder.accounts.decode("FundAccount", account.data)
|
|
1060
|
-
const syIndex =
|
|
1061
|
-
Number(10 ** data.supported_tokens[index].decimals) /
|
|
1062
|
-
Number(data.supported_tokens[index].one_token_as_receipt_token)
|
|
1063
|
-
|
|
1064
|
-
const receiptTokenMint = new web3.PublicKey(data.receipt_token_mint)
|
|
1065
|
-
const wrappedTokenMint = new web3.PublicKey(data.wrapped_token.mint)
|
|
1066
1918
|
|
|
1067
|
-
return {
|
|
1919
|
+
return calculateFragmetricSupportedTokenIndex({ fragmetricFund: account.data }, index)
|
|
1068
1920
|
}
|
|
1069
1921
|
|
|
1070
1922
|
interface AccountsInterface {
|
|
@@ -1090,14 +1942,14 @@ export async function fetchMeteoraIndex({
|
|
|
1090
1942
|
try {
|
|
1091
1943
|
const VIRTUAL_PRICE_PRECISION = new BN(100_000_000)
|
|
1092
1944
|
|
|
1093
|
-
const pool = await
|
|
1945
|
+
const pool = await fetchPoolAccount(connection, accounts.pool)
|
|
1094
1946
|
|
|
1095
1947
|
const poolMint = await getMint(connection, pool.lpMint)
|
|
1096
1948
|
const poolLpSupply = new BN(poolMint.supply.toString())
|
|
1097
1949
|
const poolLpDecimals = Number(poolMint.decimals.toString())
|
|
1098
1950
|
|
|
1099
|
-
const vaultA = await
|
|
1100
|
-
const vaultB = await
|
|
1951
|
+
const vaultA = await fetchVaultAccount(connection, accounts.vaultA)
|
|
1952
|
+
const vaultB = await fetchVaultAccount(connection, accounts.vaultB)
|
|
1101
1953
|
|
|
1102
1954
|
const vaultLpMintA = await getMint(connection, vaultA.lpMint)
|
|
1103
1955
|
const vaultLpMintB = await getMint(connection, vaultB.lpMint)
|
|
@@ -1155,8 +2007,6 @@ export async function fetchAdrenaIndex({
|
|
|
1155
2007
|
index: number
|
|
1156
2008
|
}> {
|
|
1157
2009
|
try {
|
|
1158
|
-
const zero = new BN(0)
|
|
1159
|
-
|
|
1160
2010
|
// Fetch all account data in a single RPC call
|
|
1161
2011
|
const accountInfos = await connection.getMultipleAccountsInfo([
|
|
1162
2012
|
accounts.pool,
|
|
@@ -1170,25 +2020,17 @@ export async function fetchAdrenaIndex({
|
|
|
1170
2020
|
throw new Error("One or more Adrena accounts not found")
|
|
1171
2021
|
}
|
|
1172
2022
|
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
let feeDifference = currentTotalFees.gte(previousTotalFees) ? currentTotalFees.sub(previousTotalFees) : zero
|
|
1186
|
-
|
|
1187
|
-
yieldIncrement = feeDifference.toNumber() / aumValue.toNumber()
|
|
1188
|
-
|
|
1189
|
-
let currentIndexNumber = parseFloat(PreciseNumber.fromRaw(currentIndex[0]).valueString)
|
|
1190
|
-
|
|
1191
|
-
return { index: currentIndexNumber + yieldIncrement }
|
|
2023
|
+
return calculateAdrenaIndex(
|
|
2024
|
+
{
|
|
2025
|
+
pool: accountInfos[0].data,
|
|
2026
|
+
custody1: accountInfos[1].data,
|
|
2027
|
+
custody2: accountInfos[2].data,
|
|
2028
|
+
custody3: accountInfos[3].data,
|
|
2029
|
+
custody4: accountInfos[4].data,
|
|
2030
|
+
},
|
|
2031
|
+
previousTotalFees,
|
|
2032
|
+
currentIndex,
|
|
2033
|
+
)
|
|
1192
2034
|
} catch (error) {
|
|
1193
2035
|
throw error
|
|
1194
2036
|
}
|
|
@@ -1201,26 +2043,14 @@ export async function fetchSanctumIndex({
|
|
|
1201
2043
|
connection: web3.Connection
|
|
1202
2044
|
accounts: AccountsInterface
|
|
1203
2045
|
}): Promise<number> {
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
const zeroBn = new BN(0)
|
|
1209
|
-
const precision = new BN(10 ** lpMint.decimals)
|
|
1210
|
-
const lpTokenSupplyBn = new BN(lpMint.supply.toString())
|
|
1211
|
-
const poolTotalSolValueBn = new BN(poolState.totalSolValue.toString())
|
|
1212
|
-
|
|
1213
|
-
if (lpTokenSupplyBn.eq(zeroBn) || poolTotalSolValueBn.eq(zeroBn)) {
|
|
1214
|
-
return 1
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
const exchangeRateBn = lpTokenSupplyBn.mul(precision).div(poolTotalSolValueBn)
|
|
1218
|
-
const exchangeRate = new Decimal(exchangeRateBn.toString()).div(precision.toString()).toNumber()
|
|
2046
|
+
const [poolStateAccountRaw, lpMintAccountRaw] = await Promise.all(
|
|
2047
|
+
[accounts.poolState, accounts.lpMint].map((pk) => connection.getAccountInfo(pk)),
|
|
2048
|
+
)
|
|
1219
2049
|
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
}
|
|
2050
|
+
return calculateSanctumIndex({
|
|
2051
|
+
poolStateAccountData: poolStateAccountRaw.data,
|
|
2052
|
+
lpMintAccountData: lpMintAccountRaw.data,
|
|
2053
|
+
})
|
|
1224
2054
|
}
|
|
1225
2055
|
|
|
1226
2056
|
export async function fetchSolsticeRedemptionRate({
|
|
@@ -1231,60 +2061,85 @@ export async function fetchSolsticeRedemptionRate({
|
|
|
1231
2061
|
connection: web3.Connection
|
|
1232
2062
|
yieldPool: web3.PublicKey
|
|
1233
2063
|
vestingSchedule: web3.PublicKey
|
|
1234
|
-
}): Promise<{
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
sharesSupply: string
|
|
1238
|
-
vestingAmount: string
|
|
1239
|
-
totalVestedAssets: string
|
|
1240
|
-
}> {
|
|
1241
|
-
try {
|
|
1242
|
-
// Fetch both accounts in a single RPC call for efficiency
|
|
1243
|
-
const accountInfos = await connection.getMultipleAccountsInfo([yieldPool, vestingSchedule])
|
|
2064
|
+
}): Promise<ReturnType<typeof calculateSolsticeRedemptionRate>> {
|
|
2065
|
+
// Fetch both accounts in a single RPC call for efficiency
|
|
2066
|
+
const accountInfos = await connection.getMultipleAccountsInfo([yieldPool, vestingSchedule])
|
|
1244
2067
|
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
2068
|
+
if (!accountInfos[0] || !accountInfos[1]) {
|
|
2069
|
+
throw new Error("One or more Solstice accounts not found")
|
|
2070
|
+
}
|
|
1248
2071
|
|
|
1249
|
-
|
|
1250
|
-
|
|
2072
|
+
return calculateSolsticeRedemptionRate({ yieldPool: accountInfos[0].data, vestingSchedule: accountInfos[1].data })
|
|
2073
|
+
}
|
|
1251
2074
|
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
const poolSharesSupply = BigInt(yieldPoolAccount.shares_supply.toString())
|
|
1255
|
-
const vestingAmount = BigInt(vestingScheduleAccount.vesting_amount.toString())
|
|
2075
|
+
const REFLECT_ORACLE_LEN = 17
|
|
2076
|
+
const REFLECT_MAX_STALENESS_SLOTS = 150
|
|
1256
2077
|
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
// Calculate unvested amount
|
|
1267
|
-
let unvestedAmount: bigint
|
|
1268
|
-
if (currentTime > vestingEnd) {
|
|
1269
|
-
unvestedAmount = 0n // If current time passed the vesting end, no unvested amount
|
|
1270
|
-
} else {
|
|
1271
|
-
unvestedAmount = (vestingAmount * (vestingEnd - currentTime)) / (vestingEnd - vestingStart)
|
|
1272
|
-
}
|
|
2078
|
+
export async function fetchReflectRedemptionRate({
|
|
2079
|
+
connection,
|
|
2080
|
+
oracle,
|
|
2081
|
+
}: {
|
|
2082
|
+
connection: web3.Connection
|
|
2083
|
+
oracle: web3.PublicKey
|
|
2084
|
+
}): Promise<number> {
|
|
2085
|
+
const accountInfo = await connection.getAccountInfo(oracle)
|
|
1273
2086
|
|
|
1274
|
-
|
|
1275
|
-
|
|
2087
|
+
if (!accountInfo) {
|
|
2088
|
+
throw new Error("Reflect oracle account not found")
|
|
2089
|
+
}
|
|
1276
2090
|
|
|
1277
|
-
|
|
1278
|
-
|
|
2091
|
+
if (accountInfo.data.length !== REFLECT_ORACLE_LEN) {
|
|
2092
|
+
throw new Error(`Reflect oracle account has invalid length: ${accountInfo.data.length}`)
|
|
2093
|
+
}
|
|
1279
2094
|
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
}
|
|
1288
|
-
|
|
2095
|
+
const slot = Number(accountInfo.data.readBigUInt64LE(0))
|
|
2096
|
+
const price = Number(accountInfo.data.readBigUInt64LE(8))
|
|
2097
|
+
const precision = accountInfo.data.readUInt8(16)
|
|
2098
|
+
|
|
2099
|
+
const currentSlot = await connection.getSlot()
|
|
2100
|
+
if (slot > currentSlot) {
|
|
2101
|
+
throw new Error("Reflect oracle slot is ahead of the current slot")
|
|
2102
|
+
}
|
|
2103
|
+
const slotDelta = currentSlot - slot
|
|
2104
|
+
|
|
2105
|
+
if (slotDelta > REFLECT_MAX_STALENESS_SLOTS) {
|
|
2106
|
+
throw new Error("Reflect oracle data is stale")
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
const scale = Math.pow(10, precision)
|
|
2110
|
+
|
|
2111
|
+
if (scale === 0) {
|
|
2112
|
+
throw new Error("Invalid oracle precision")
|
|
1289
2113
|
}
|
|
2114
|
+
|
|
2115
|
+
return price / scale
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
export async function fetchOreExchangeRate({
|
|
2119
|
+
connection,
|
|
2120
|
+
storeMint,
|
|
2121
|
+
stakeAccount,
|
|
2122
|
+
treasury,
|
|
2123
|
+
}: {
|
|
2124
|
+
connection: web3.Connection
|
|
2125
|
+
storeMint: web3.PublicKey
|
|
2126
|
+
stakeAccount: web3.PublicKey
|
|
2127
|
+
treasury: web3.PublicKey
|
|
2128
|
+
}): Promise<number> {
|
|
2129
|
+
// Fetch all accounts in parallel for efficiency
|
|
2130
|
+
const [storeMintInfo, stakeAccountInfo, treasuryAccountInfo] = await Promise.all([
|
|
2131
|
+
connection.getAccountInfo(storeMint),
|
|
2132
|
+
connection.getAccountInfo(stakeAccount),
|
|
2133
|
+
connection.getAccountInfo(treasury),
|
|
2134
|
+
])
|
|
2135
|
+
|
|
2136
|
+
if (!storeMintInfo || !stakeAccountInfo || !treasuryAccountInfo) {
|
|
2137
|
+
throw new Error("One or more ORE accounts not found")
|
|
2138
|
+
}
|
|
2139
|
+
|
|
2140
|
+
return calculateOreExchangeRate({
|
|
2141
|
+
stakeAccount: stakeAccountInfo.data,
|
|
2142
|
+
treasuryAccount: treasuryAccountInfo.data,
|
|
2143
|
+
storeMint: storeMintInfo.data,
|
|
2144
|
+
})
|
|
1290
2145
|
}
|