@exponent-labs/exponent-fetcher 0.9.11 → 0.9.12
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.js +3 -3
- package/build/constants.js.map +1 -1
- package/build/exponentFetcher.d.ts +11 -17
- package/build/exponentFetcher.js +60 -142
- package/build/exponentFetcher.js.map +1 -1
- package/build/utils/adrena.d.ts +0 -2
- package/build/utils/adrena.js +1 -2
- package/build/utils/adrena.js.map +1 -1
- package/build/utils/fragmetric.d.ts +0 -2
- package/build/utils/fragmetric.js +2 -2
- package/build/utils/fragmetric.js.map +1 -1
- package/build/utils/jito.d.ts +0 -2
- package/build/utils/jito.js +1 -2
- package/build/utils/jito.js.map +1 -1
- package/build/utils/jupiter.d.ts +0 -2
- package/build/utils/jupiter.js +2 -3
- package/build/utils/jupiter.js.map +1 -1
- package/build/utils/kamino.d.ts +0 -2
- package/build/utils/kamino.js +1 -2
- package/build/utils/kamino.js.map +1 -1
- package/build/utils/meteora.d.ts +0 -3
- package/build/utils/meteora.js +5 -5
- package/build/utils/meteora.js.map +1 -1
- package/build/utils/ore.d.ts +6 -21
- package/build/utils/ore.js +30 -85
- package/build/utils/ore.js.map +1 -1
- package/build/utils/perena.d.ts +0 -2
- package/build/utils/perena.js +2 -3
- package/build/utils/perena.js.map +1 -1
- package/build/utils/sanctum.d.ts +0 -2
- package/build/utils/sanctum.js +1 -2
- package/build/utils/sanctum.js.map +1 -1
- package/build/utils/solstice.d.ts +0 -2
- package/build/utils/solstice.js +1 -2
- package/build/utils/solstice.js.map +1 -1
- package/package.json +21 -21
- package/src/exponentFetcher.ts +46 -155
- package/src/utils/ore.ts +36 -122
package/src/exponentFetcher.ts
CHANGED
|
@@ -87,8 +87,6 @@ import { getPerenaLpMint, getPerenaStablePoolData } from "./utils/perena"
|
|
|
87
87
|
import { calculateSanctumIndex } from "./utils/sanctum"
|
|
88
88
|
import { calculateSolsticeRedemptionRate } from "./utils/solstice"
|
|
89
89
|
|
|
90
|
-
const KAMINO_VAULT_GLOBAL_CONFIG = new web3.PublicKey("BKyTcUe6daNG8HbgBix2ugdRHbykG2dK9hPBBqhUyoEX")
|
|
91
|
-
|
|
92
90
|
export function serializeAnchorizedPNumFromJson(pnum: AnchorizedPNum): AnchorizedPNumJson {
|
|
93
91
|
const serializedArray = pnum[0].map((bn) => bn.toString())
|
|
94
92
|
return { 0: serializedArray }
|
|
@@ -350,6 +348,11 @@ export class ExponentFetcher {
|
|
|
350
348
|
},
|
|
351
349
|
})),
|
|
352
350
|
},
|
|
351
|
+
crossingSplit: {
|
|
352
|
+
crossLeftIdx: raw.crossingSplit.crossLeftIdx,
|
|
353
|
+
crossRightIdx: raw.crossingSplit.crossRightIdx,
|
|
354
|
+
lpBalanceCrossing: raw.crossingSplit.lpBalanceCrossing,
|
|
355
|
+
},
|
|
353
356
|
}
|
|
354
357
|
|
|
355
358
|
return deserializeLpPositionCLMM(v)
|
|
@@ -477,7 +480,7 @@ export class ExponentFetcher {
|
|
|
477
480
|
* Layout matches Rust struct `Ticks` with `RedBlackTree<u32, Tick, 1000>`:
|
|
478
481
|
* - Discriminator: 8 bytes
|
|
479
482
|
* - RedBlackTree header: root(4) + padding(12) + size(8) + bump(4) + freeIdx(4) = 32 bytes
|
|
480
|
-
* - 1000 RBTree nodes, each: nodeHeader(16) + key(4) + padding(4) + Tick =
|
|
483
|
+
* - 1000 RBTree nodes, each: nodeHeader(16) + key(4) + padding(4) + Tick(416) = 440 bytes
|
|
481
484
|
* - Ticks footer: market(32) + feeGrowthPt(16) + feeGrowthSy(16) + prefixSum(8) + spotPrice(8) + currentTick(4) + padding(12) = 96 bytes
|
|
482
485
|
*/
|
|
483
486
|
export function deserializeMarketThreeTicks(data: Buffer): Ticks {
|
|
@@ -577,13 +580,13 @@ export function deserializeMarketThreeTicks(data: Buffer): Ticks {
|
|
|
577
580
|
const principalSy = readU64() // 8 bytes
|
|
578
581
|
const principalShareSupply = readPreciseNumberAsBigint() // 32 bytes - kept as bigint for arithmetic
|
|
579
582
|
|
|
580
|
-
// FarmYieldTrackers:
|
|
583
|
+
// FarmYieldTrackers: 3 x FarmYieldTracker(32 bytes) = 96 bytes
|
|
581
584
|
const farms: { lastSeenIndex: number }[] = []
|
|
582
585
|
for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
|
|
583
586
|
farms.push({ lastSeenIndex: readPreciseNumberAsFloat() })
|
|
584
587
|
}
|
|
585
588
|
|
|
586
|
-
// EmissionYieldTrackers:
|
|
589
|
+
// EmissionYieldTrackers: 3 x EmissionYieldTracker(64 bytes) = 192 bytes
|
|
587
590
|
const emissions: { lastSeenIndex: number; lastPositionIndex: number }[] = []
|
|
588
591
|
for (let j = 0; j < PERSONAL_TICK_YIELD_TRACKER_SIZE; j++) {
|
|
589
592
|
emissions.push({
|
|
@@ -632,76 +635,7 @@ export function deserializeMarketThreeTicks(data: Buffer): Ticks {
|
|
|
632
635
|
}
|
|
633
636
|
}
|
|
634
637
|
|
|
635
|
-
/** Decoded account may use snake_case (from JSON IDL); normalize to camelCase for app use. */
|
|
636
|
-
function normalizeCpiContext(a: { altIndex?: number; alt_index?: number; isSigner?: boolean; is_signer?: boolean; isWritable?: boolean; is_writable?: boolean }): { altIndex: number; isSigner: boolean; isWritable: boolean } {
|
|
637
|
-
return {
|
|
638
|
-
altIndex: a.altIndex ?? (a as { alt_index?: number }).alt_index ?? 0,
|
|
639
|
-
isSigner: a.isSigner ?? (a as { is_signer?: boolean }).is_signer ?? false,
|
|
640
|
-
isWritable: a.isWritable ?? (a as { is_writable?: boolean }).is_writable ?? false,
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
function normalizeCpiAccountIndexes(
|
|
645
|
-
raw: {
|
|
646
|
-
getSyState?: unknown[]
|
|
647
|
-
get_sy_state?: unknown[]
|
|
648
|
-
withdrawSy?: unknown[]
|
|
649
|
-
withdraw_sy?: unknown[]
|
|
650
|
-
depositSy?: unknown[]
|
|
651
|
-
deposit_sy?: unknown[]
|
|
652
|
-
claimEmission?: unknown[][]
|
|
653
|
-
claim_emission?: unknown[][]
|
|
654
|
-
getPositionState?: unknown[]
|
|
655
|
-
get_position_state?: unknown[]
|
|
656
|
-
}
|
|
657
|
-
): CpiAccountIndexes {
|
|
658
|
-
const arr = (key: string, snake: string) => {
|
|
659
|
-
const a = (raw as Record<string, unknown>)[key] ?? (raw as Record<string, unknown>)[snake]
|
|
660
|
-
return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x as Record<string, unknown>)) : []
|
|
661
|
-
}
|
|
662
|
-
const arr2 = (key: string, snake: string) => {
|
|
663
|
-
const a = (raw as Record<string, unknown>)[key] ?? (raw as Record<string, unknown>)[snake]
|
|
664
|
-
return Array.isArray(a) ? a.map((inner) => (Array.isArray(inner) ? inner.map((x) => normalizeCpiContext(x as Record<string, unknown>)) : [])) : []
|
|
665
|
-
}
|
|
666
|
-
return {
|
|
667
|
-
getSyState: arr("getSyState", "get_sy_state"),
|
|
668
|
-
withdrawSy: arr("withdrawSy", "withdraw_sy"),
|
|
669
|
-
depositSy: arr("depositSy", "deposit_sy"),
|
|
670
|
-
claimEmission: arr2("claimEmission", "claim_emission"),
|
|
671
|
-
getPositionState: arr("getPositionState", "get_position_state"),
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
function normalizeMarketCpiCoreIndexes(
|
|
676
|
-
raw: {
|
|
677
|
-
stripSy?: unknown[]
|
|
678
|
-
strip_sy?: unknown[]
|
|
679
|
-
mergeSy?: unknown[]
|
|
680
|
-
merge_sy?: unknown[]
|
|
681
|
-
}
|
|
682
|
-
): MarketCpiCoreIndexes {
|
|
683
|
-
const arr = (key: string, snake: string) => {
|
|
684
|
-
const a = (raw as Record<string, unknown>)[key] ?? (raw as Record<string, unknown>)[snake]
|
|
685
|
-
return Array.isArray(a) ? a.map((x) => normalizeCpiContext(x as Record<string, unknown>)) : []
|
|
686
|
-
}
|
|
687
|
-
return {
|
|
688
|
-
stripSy: arr("stripSy", "strip_sy"),
|
|
689
|
-
mergeSy: arr("mergeSy", "merge_sy"),
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
|
|
693
638
|
export function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
|
|
694
|
-
const rawCpiSy = m.cpiSyAccounts ?? (m as unknown as { cpi_sy_accounts?: unknown }).cpi_sy_accounts
|
|
695
|
-
const rawCpiCore = m.cpiCoreAccounts ?? (m as unknown as { cpi_core_accounts?: unknown }).cpi_core_accounts
|
|
696
|
-
const cpiSyAccounts =
|
|
697
|
-
rawCpiSy != null && typeof rawCpiSy === "object"
|
|
698
|
-
? normalizeCpiAccountIndexes(rawCpiSy as Parameters<typeof normalizeCpiAccountIndexes>[0])
|
|
699
|
-
: (m.cpiSyAccounts ?? { getSyState: [], withdrawSy: [], depositSy: [], claimEmission: [], getPositionState: [] })
|
|
700
|
-
const cpiCoreAccounts =
|
|
701
|
-
rawCpiCore != null && typeof rawCpiCore === "object"
|
|
702
|
-
? normalizeMarketCpiCoreIndexes(rawCpiCore as Parameters<typeof normalizeMarketCpiCoreIndexes>[0])
|
|
703
|
-
: (m.cpiCoreAccounts ?? { stripSy: [], mergeSy: [] })
|
|
704
|
-
|
|
705
639
|
return {
|
|
706
640
|
addressLookupTable: m.addressLookupTable,
|
|
707
641
|
mintSy: m.mintSy,
|
|
@@ -714,7 +648,7 @@ export function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
|
|
|
714
648
|
selfAddress: m.selfAddress,
|
|
715
649
|
syProgram: m.syProgram,
|
|
716
650
|
statusFlags: m.statusFlags,
|
|
717
|
-
cpiSyAccounts,
|
|
651
|
+
cpiSyAccounts: m.cpiSyAccounts,
|
|
718
652
|
isCurrentFlashSwap: m.isCurrentFlashSwap,
|
|
719
653
|
lpFarm: m.lpFarm,
|
|
720
654
|
mintYt: m.mintYt,
|
|
@@ -743,9 +677,8 @@ export function deserializeMarketThree(m: MarketThreeRaw): MarketThree {
|
|
|
743
677
|
syBalance: BigInt(m.financials.syBalance.toString()),
|
|
744
678
|
liquidityBalance: BigInt(m.financials.liquidityBalance.toString()),
|
|
745
679
|
},
|
|
746
|
-
cpiCoreAccounts,
|
|
680
|
+
cpiCoreAccounts: m.cpiCoreAccounts,
|
|
747
681
|
exponentCoreProgram: m.exponentCoreProgram,
|
|
748
|
-
seedId: m.seedId,
|
|
749
682
|
}
|
|
750
683
|
}
|
|
751
684
|
|
|
@@ -812,6 +745,12 @@ function deserializeLpPositionCLMM(x: LpPositionCLMMRaw): LpPositionCLMM {
|
|
|
812
745
|
lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
|
|
813
746
|
})),
|
|
814
747
|
})),
|
|
748
|
+
crossingSplit: {
|
|
749
|
+
crossLeftIdx: x.crossingSplit.crossLeftIdx,
|
|
750
|
+
crossRightIdx: x.crossingSplit.crossRightIdx,
|
|
751
|
+
lpBalanceCrossing: BigInt(x.crossingSplit.lpBalanceCrossing.toString()),
|
|
752
|
+
isActive: x.crossingSplit.crossLeftIdx !== 0xffffffff && x.crossingSplit.crossRightIdx !== 0xffffffff,
|
|
753
|
+
},
|
|
815
754
|
}
|
|
816
755
|
}
|
|
817
756
|
|
|
@@ -867,7 +806,8 @@ function deserializeOrderbook(data: Buffer): Orderbook {
|
|
|
867
806
|
offset += 8
|
|
868
807
|
const priceDecimals = data.readUint8(offset)
|
|
869
808
|
offset += 1
|
|
870
|
-
// Skip ConfigurationOptions padding:
|
|
809
|
+
// Skip ConfigurationOptions padding/reserve:
|
|
810
|
+
// _placeholder_one[15] + _placeholder_two[32] + _placeholder_three[32] + _placeholder_four[32] + _reserved[1024]
|
|
871
811
|
offset += 1135
|
|
872
812
|
|
|
873
813
|
// Pubkeys
|
|
@@ -882,14 +822,7 @@ function deserializeOrderbook(data: Buffer): Orderbook {
|
|
|
882
822
|
const cpiAccountOrderbook = readPubkey()
|
|
883
823
|
const admin = readPubkey()
|
|
884
824
|
|
|
885
|
-
// last_sy_exchange_rate (Number type = 32 bytes
|
|
886
|
-
const lastSyExchangeRateRaw = (() => {
|
|
887
|
-
let val = 0n
|
|
888
|
-
for (let i = 0; i < 4; i++) {
|
|
889
|
-
val += data.readBigUInt64LE(offset + i * 8) << BigInt(i * 64)
|
|
890
|
-
}
|
|
891
|
-
return val
|
|
892
|
-
})()
|
|
825
|
+
// Skip last_sy_exchange_rate (Number type = 32 bytes)
|
|
893
826
|
offset += 32
|
|
894
827
|
|
|
895
828
|
// OrderbookFinancials struct
|
|
@@ -1045,12 +978,7 @@ function deserializeOrderbook(data: Buffer): Orderbook {
|
|
|
1045
978
|
offset += 4
|
|
1046
979
|
const user = new web3.PublicKey(data.slice(offset, offset + 32))
|
|
1047
980
|
offset += 32
|
|
1048
|
-
const
|
|
1049
|
-
for (let word = 0; word < 4; word++) {
|
|
1050
|
-
yieldIndexRaw[0][word] = new BN(data.subarray(offset + word * 8, offset + (word + 1) * 8), "le")
|
|
1051
|
-
}
|
|
1052
|
-
const yieldIndex = deserializeAnchorizedPNum(yieldIndexRaw)
|
|
1053
|
-
offset += 32
|
|
981
|
+
/*const yieldIndex = data.readBigUInt64LE(offset).toString();*/ offset += 32
|
|
1054
982
|
const ptAmount = data.readBigUInt64LE(offset)
|
|
1055
983
|
offset += 8
|
|
1056
984
|
const syAmount = data.readBigUInt64LE(offset)
|
|
@@ -1063,7 +991,7 @@ function deserializeOrderbook(data: Buffer): Orderbook {
|
|
|
1063
991
|
offset += 8
|
|
1064
992
|
offset += 8 // reserved
|
|
1065
993
|
// if (user.toBase58() == "11111111111111111111111111111111") continue
|
|
1066
|
-
userEscrows.push({ user, yieldIndex, ptAmount, syAmount, ytAmount, stakedYtAmount, staged })
|
|
994
|
+
userEscrows.push({ user, yieldIndex: 0, ptAmount, syAmount, ytAmount, stakedYtAmount, staged })
|
|
1067
995
|
}
|
|
1068
996
|
|
|
1069
997
|
// ─── Finally, seed_id + signer_bump + reserved ─────────────────────────────
|
|
@@ -1092,14 +1020,13 @@ function deserializeOrderbook(data: Buffer): Orderbook {
|
|
|
1092
1020
|
tokenEscrowYt,
|
|
1093
1021
|
tokenEscrowPt,
|
|
1094
1022
|
cpiAccountOrderbook,
|
|
1095
|
-
lastSyExchangeRate: lastSyExchangeRateRaw,
|
|
1096
1023
|
financials,
|
|
1097
1024
|
prices,
|
|
1098
1025
|
configurationOptions,
|
|
1099
1026
|
offers,
|
|
1100
1027
|
userEscrows,
|
|
1101
|
-
offersBumpIndex,
|
|
1102
1028
|
offersFreeListHead,
|
|
1029
|
+
offersBumpIndex,
|
|
1103
1030
|
}
|
|
1104
1031
|
}
|
|
1105
1032
|
|
|
@@ -1285,7 +1212,6 @@ export interface MarketThree {
|
|
|
1285
1212
|
}[]
|
|
1286
1213
|
}
|
|
1287
1214
|
liquidityNetBalanceLimits: LiquidityNetBalanceLimits
|
|
1288
|
-
seedId: number[]
|
|
1289
1215
|
}
|
|
1290
1216
|
|
|
1291
1217
|
export interface Ticks {
|
|
@@ -1320,13 +1246,13 @@ export interface Tick {
|
|
|
1320
1246
|
principalSy: bigint
|
|
1321
1247
|
apyBasePoints: number
|
|
1322
1248
|
principalShareSupply: bigint
|
|
1323
|
-
/** Farm yield trackers (
|
|
1249
|
+
/** Farm yield trackers (3 trackers) */
|
|
1324
1250
|
farms: { lastSeenIndex: number }[]
|
|
1325
|
-
/** Emission yield trackers (
|
|
1251
|
+
/** Emission yield trackers (3 trackers) */
|
|
1326
1252
|
emissions: { lastSeenIndex: number; lastPositionIndex: number }[]
|
|
1327
1253
|
/** Last split epoch for this tick */
|
|
1328
1254
|
lastSplitEpoch: bigint
|
|
1329
|
-
/**
|
|
1255
|
+
/** Minimum liquidity retained on ticks used by wrapper-base liquidity */
|
|
1330
1256
|
frozenLiquidity: bigint
|
|
1331
1257
|
}
|
|
1332
1258
|
|
|
@@ -1502,16 +1428,12 @@ export interface Orderbook {
|
|
|
1502
1428
|
tokenEscrowPt: web3.PublicKey
|
|
1503
1429
|
cpiAccountOrderbook: web3.PublicKey
|
|
1504
1430
|
admin: web3.PublicKey
|
|
1505
|
-
/** Raw 256-bit PreciseNumber (12 decimals) for last SY exchange rate */
|
|
1506
|
-
lastSyExchangeRate: bigint
|
|
1507
1431
|
configurationOptions: ConfigurationOptions
|
|
1508
1432
|
financials: OrderbookFinancials
|
|
1509
1433
|
prices: PriceTreeNode[]
|
|
1510
1434
|
offers: OfferNode[]
|
|
1511
1435
|
userEscrows: UserEscrowNode[]
|
|
1512
|
-
/** Next offer index that will be allocated (from NodeAllocator free list) */
|
|
1513
1436
|
offersFreeListHead: number
|
|
1514
|
-
/** Bump index boundary for offers allocator */
|
|
1515
1437
|
offersBumpIndex: number
|
|
1516
1438
|
}
|
|
1517
1439
|
|
|
@@ -1590,6 +1512,11 @@ interface LpPositionCLMMRaw {
|
|
|
1590
1512
|
emissions: { trackers: { staged: BN; lastSeenIndex: AnchorizedPNum }[] }
|
|
1591
1513
|
}[]
|
|
1592
1514
|
}
|
|
1515
|
+
crossingSplit: {
|
|
1516
|
+
crossLeftIdx: number
|
|
1517
|
+
crossRightIdx: number
|
|
1518
|
+
lpBalanceCrossing: BN
|
|
1519
|
+
}
|
|
1593
1520
|
}
|
|
1594
1521
|
|
|
1595
1522
|
export interface LpPositionCLMM {
|
|
@@ -1610,6 +1537,12 @@ export interface LpPositionCLMM {
|
|
|
1610
1537
|
lpShare: bigint
|
|
1611
1538
|
emissions: { staged: bigint; lastSeenIndex: number }[]
|
|
1612
1539
|
}[]
|
|
1540
|
+
crossingSplit: {
|
|
1541
|
+
crossLeftIdx: number
|
|
1542
|
+
crossRightIdx: number
|
|
1543
|
+
lpBalanceCrossing: bigint
|
|
1544
|
+
isActive: boolean
|
|
1545
|
+
}
|
|
1613
1546
|
}
|
|
1614
1547
|
|
|
1615
1548
|
export interface LpFarm {
|
|
@@ -1781,7 +1714,7 @@ export interface OfferNodeRaw {
|
|
|
1781
1714
|
|
|
1782
1715
|
export interface UserEscrowNodeRaw {
|
|
1783
1716
|
user: web3.PublicKey
|
|
1784
|
-
yieldIndex:
|
|
1717
|
+
yieldIndex: BN
|
|
1785
1718
|
ptAmount: BN
|
|
1786
1719
|
syAmount: BN
|
|
1787
1720
|
ytAmount: BN
|
|
@@ -2025,70 +1958,28 @@ export async function fetchKaminoVaultIndex({
|
|
|
2025
1958
|
|
|
2026
1959
|
const data = coder.accounts.decode("VaultState", account.data)
|
|
2027
1960
|
|
|
2028
|
-
const
|
|
2029
|
-
.
|
|
2030
|
-
|
|
1961
|
+
const activeReserves = data.vault_allocation_strategy
|
|
1962
|
+
.map((r) => r.reserve)
|
|
1963
|
+
.filter((reserve) => reserve.toBase58() !== web3.PublicKey.default.toBase58())
|
|
2031
1964
|
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
connection.getAccountInfo(data.token_mint),
|
|
2035
|
-
connection.getAccountInfo(data.shares_mint),
|
|
2036
|
-
])
|
|
2037
|
-
const decodedReserves = activeReservesData.map((accountInfo, index) => {
|
|
2038
|
-
if (!accountInfo?.data) {
|
|
2039
|
-
throw new Error(`Missing Kamino reserve account ${activeReserves[index].toBase58()}`)
|
|
2040
|
-
}
|
|
2041
|
-
return Reserve.decode(accountInfo.data)
|
|
2042
|
-
})
|
|
2043
|
-
const collateralMintInfos = await connection.getMultipleAccountsInfo(
|
|
2044
|
-
decodedReserves.map((reserve) => reserve.collateral.mintPubkey),
|
|
2045
|
-
)
|
|
1965
|
+
console.log("activeReserves", activeReserves)
|
|
1966
|
+
const activeReservesData = await connection.getMultipleAccountsInfo(activeReserves)
|
|
2046
1967
|
|
|
2047
1968
|
const reserves = activeReserves.map((r, i) => {
|
|
2048
|
-
|
|
2049
|
-
const allocation = activeAllocations[i]
|
|
2050
|
-
const [lendingMarketAuthority] = web3.PublicKey.findProgramAddressSync(
|
|
2051
|
-
[Buffer.from("lma"), reserveAccount.lendingMarket.toBuffer()],
|
|
2052
|
-
new web3.PublicKey("KLend2g3cP87fffoy8q1mQqGKjrxjC8boSyAYavgmjD"),
|
|
2053
|
-
)
|
|
2054
|
-
|
|
1969
|
+
console.log("r.data", activeReservesData[i].data)
|
|
2055
1970
|
return {
|
|
2056
1971
|
reserveAddress: r,
|
|
2057
|
-
|
|
2058
|
-
ctokenVault: allocation.ctoken_vault,
|
|
2059
|
-
lendingMarketAuthority,
|
|
2060
|
-
pythOracle: reserveAccount.config.tokenInfo.pythConfiguration.price,
|
|
2061
|
-
switchboardPriceOracle: reserveAccount.config.tokenInfo.switchboardConfiguration.priceAggregator,
|
|
2062
|
-
switchboardTwapOracle: reserveAccount.config.tokenInfo.switchboardConfiguration.twapAggregator,
|
|
2063
|
-
scopePrices: reserveAccount.config.tokenInfo.scopeConfiguration.priceFeed,
|
|
2064
|
-
reserveLiquiditySupply: reserveAccount.liquidity.supplyVault,
|
|
2065
|
-
reserveCollateralMint: reserveAccount.collateral.mintPubkey,
|
|
2066
|
-
reserveCollateralTokenProgram: collateralMintInfos[i]?.owner ?? web3.PublicKey.default,
|
|
1972
|
+
reserve: Reserve.decode(activeReservesData[i].data).lendingMarket,
|
|
2067
1973
|
}
|
|
2068
1974
|
})
|
|
2069
1975
|
|
|
1976
|
+
console.log("reserves", reserves)
|
|
2070
1977
|
const tokenVault = data.token_vault
|
|
2071
1978
|
const tokenMint = data.token_mint
|
|
2072
1979
|
const baseVaultAuthority = data.base_vault_authority
|
|
2073
1980
|
const sharesMint = data.shares_mint
|
|
2074
|
-
const vaultLookupTable = data.vault_lookup_table ?? web3.PublicKey.default
|
|
2075
|
-
const tokenProgram = tokenMintInfo?.owner ?? web3.PublicKey.default
|
|
2076
|
-
const sharesTokenProgram = sharesMintInfo?.owner ?? web3.PublicKey.default
|
|
2077
1981
|
|
|
2078
|
-
return {
|
|
2079
|
-
index: 1,
|
|
2080
|
-
tokenVault,
|
|
2081
|
-
tokenMint,
|
|
2082
|
-
tokenProgram,
|
|
2083
|
-
// Kamino Vault withdraw expects the singleton program global config account.
|
|
2084
|
-
// It is not stored on VaultState, so fetch it from the known program-wide address.
|
|
2085
|
-
globalConfig: KAMINO_VAULT_GLOBAL_CONFIG,
|
|
2086
|
-
baseVaultAuthority,
|
|
2087
|
-
sharesMint,
|
|
2088
|
-
sharesTokenProgram,
|
|
2089
|
-
vaultLookupTable,
|
|
2090
|
-
reserves,
|
|
2091
|
-
}
|
|
1982
|
+
return { index: 1, tokenVault, tokenMint, baseVaultAuthority, sharesMint, reserves }
|
|
2092
1983
|
}
|
|
2093
1984
|
|
|
2094
1985
|
export async function fetchFragmetricSupportedTokenIndex({
|
package/src/utils/ore.ts
CHANGED
|
@@ -3,12 +3,12 @@ import { web3 } from "@coral-xyz/anchor"
|
|
|
3
3
|
import { MintLayout } from "@solana/spl-token"
|
|
4
4
|
import Decimal from "decimal.js"
|
|
5
5
|
|
|
6
|
-
// Steel's Numeric type is
|
|
7
|
-
const
|
|
6
|
+
// Steel's Numeric type is an I80F48 fixed-point number.
|
|
7
|
+
const NUMERIC_SCALE = new Decimal(2).pow(48)
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Represents a Numeric value from the steel crate
|
|
11
|
-
* Steel's Numeric is a
|
|
11
|
+
* Steel's Numeric is a signed 128-bit I80F48 value.
|
|
12
12
|
*/
|
|
13
13
|
export interface Numeric {
|
|
14
14
|
rawValue: BN // The raw u128 value
|
|
@@ -23,7 +23,7 @@ function deserializeNumeric(data: Buffer, offset: number): Numeric {
|
|
|
23
23
|
const low = new BN(data.slice(offset, offset + 8), "le")
|
|
24
24
|
const high = new BN(data.slice(offset + 8, offset + 16), "le")
|
|
25
25
|
const rawValue = low.add(high.shln(64))
|
|
26
|
-
const decimalValue = new Decimal(rawValue.toString()).div(
|
|
26
|
+
const decimalValue = new Decimal(rawValue.toString()).div(NUMERIC_SCALE)
|
|
27
27
|
return { rawValue, decimalValue }
|
|
28
28
|
}
|
|
29
29
|
|
|
@@ -32,19 +32,13 @@ function deserializeNumeric(data: Buffer, offset: number): Numeric {
|
|
|
32
32
|
* Matches the Rust struct in solana/libraries/ore_cpi/src/state/stake.rs
|
|
33
33
|
*/
|
|
34
34
|
export interface Stake {
|
|
35
|
-
/// The authority of this
|
|
35
|
+
/// The authority of this staker account.
|
|
36
36
|
authority: web3.PublicKey
|
|
37
37
|
/// The balance of this stake account.
|
|
38
38
|
balance: BN
|
|
39
|
-
///
|
|
40
|
-
|
|
41
|
-
///
|
|
42
|
-
bufferB: BN
|
|
43
|
-
/// Buffer c (placeholder)
|
|
44
|
-
bufferC: BN
|
|
45
|
-
/// Buffer d (placeholder)
|
|
46
|
-
bufferD: BN
|
|
47
|
-
/// The lamport reserve to pay fees for auto-compounding bots.
|
|
39
|
+
/// The lamport fee to pay for auto-compounding bots.
|
|
40
|
+
compoundFee: BN
|
|
41
|
+
/// The lamport reserve to pay auto-compounding fees.
|
|
48
42
|
compoundFeeReserve: BN
|
|
49
43
|
/// The timestamp of last claim.
|
|
50
44
|
lastClaimAt: BN
|
|
@@ -58,8 +52,6 @@ export interface Stake {
|
|
|
58
52
|
rewards: BN
|
|
59
53
|
/// The total amount of ORE this staker has earned over its lifetime.
|
|
60
54
|
lifetimeRewards: BN
|
|
61
|
-
/// Buffer f (placeholder)
|
|
62
|
-
bufferF: BN
|
|
63
55
|
}
|
|
64
56
|
|
|
65
57
|
/**
|
|
@@ -67,41 +59,25 @@ export interface Stake {
|
|
|
67
59
|
* Matches the Rust struct in solana/libraries/ore_cpi/src/state/treasury.rs
|
|
68
60
|
*/
|
|
69
61
|
export interface Treasury {
|
|
70
|
-
/// The amount of SOL collected for buy-bury operations.
|
|
71
|
-
balance: BN
|
|
72
|
-
/// Buffer a (placeholder)
|
|
73
|
-
bufferA: BN
|
|
74
|
-
/// The amount of ORE in the motherlode rewards pool.
|
|
75
|
-
motherlode: BN
|
|
76
|
-
/// The cumulative ORE distributed to miners, divided by the total unclaimed ORE at the time of distribution.
|
|
77
|
-
minerRewardsFactor: Numeric
|
|
78
62
|
/// The cumulative ORE distributed to stakers, divided by the total stake at the time of distribution.
|
|
79
|
-
|
|
80
|
-
/// Buffer b (placeholder)
|
|
81
|
-
bufferB: BN
|
|
82
|
-
/// The current total amount of refined ORE mining rewards.
|
|
83
|
-
totalRefined: BN
|
|
63
|
+
rewardsFactor: Numeric
|
|
84
64
|
/// The current total amount of ORE staking deposits.
|
|
85
65
|
totalStaked: BN
|
|
86
|
-
/// The current total amount of unclaimed ORE mining rewards.
|
|
87
|
-
totalUnclaimed: BN
|
|
88
66
|
}
|
|
89
67
|
|
|
90
68
|
/**
|
|
91
69
|
* Deserialize Stake account from Buffer
|
|
92
70
|
* Skips the 8-byte steel discriminator and deserializes the struct fields
|
|
93
71
|
*
|
|
94
|
-
* Account layout (
|
|
72
|
+
* Account layout (120 bytes total):
|
|
95
73
|
* - discriminator: 8 bytes
|
|
96
74
|
* - authority: 32 bytes
|
|
97
75
|
* - balance: 8 bytes
|
|
98
|
-
* -
|
|
99
|
-
* - compound_fee_reserve: 8 bytes
|
|
76
|
+
* - compound_fee, compound_fee_reserve: 16 bytes (2 x u64)
|
|
100
77
|
* - last_claim_at, last_deposit_at, last_withdraw_at: 24 bytes (3 x i64)
|
|
101
|
-
* - rewards_factor: 16 bytes (
|
|
78
|
+
* - rewards_factor: 16 bytes (I80F48 Numeric)
|
|
102
79
|
* - rewards: 8 bytes
|
|
103
80
|
* - lifetime_rewards: 8 bytes
|
|
104
|
-
* - buffer_f: 8 bytes
|
|
105
81
|
*/
|
|
106
82
|
function deserializeStakeAccount(stakeData: Buffer): Stake {
|
|
107
83
|
const DISCRIMINATOR_SIZE = 8
|
|
@@ -115,20 +91,8 @@ function deserializeStakeAccount(stakeData: Buffer): Stake {
|
|
|
115
91
|
const balance = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
116
92
|
offset += 8
|
|
117
93
|
|
|
118
|
-
//
|
|
119
|
-
const
|
|
120
|
-
offset += 8
|
|
121
|
-
|
|
122
|
-
// buffer_b: u64 (8 bytes)
|
|
123
|
-
const bufferB = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
124
|
-
offset += 8
|
|
125
|
-
|
|
126
|
-
// buffer_c: u64 (8 bytes)
|
|
127
|
-
const bufferC = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
128
|
-
offset += 8
|
|
129
|
-
|
|
130
|
-
// buffer_d: u64 (8 bytes)
|
|
131
|
-
const bufferD = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
94
|
+
// compound_fee: u64 (8 bytes)
|
|
95
|
+
const compoundFee = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
132
96
|
offset += 8
|
|
133
97
|
|
|
134
98
|
// compound_fee_reserve: u64 (8 bytes)
|
|
@@ -147,7 +111,7 @@ function deserializeStakeAccount(stakeData: Buffer): Stake {
|
|
|
147
111
|
const lastWithdrawAt = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
148
112
|
offset += 8
|
|
149
113
|
|
|
150
|
-
// rewards_factor: Numeric (16 bytes =
|
|
114
|
+
// rewards_factor: Numeric (16 bytes = I80F48)
|
|
151
115
|
const rewardsFactor = deserializeNumeric(stakeData, offset)
|
|
152
116
|
offset += 16
|
|
153
117
|
|
|
@@ -157,18 +121,11 @@ function deserializeStakeAccount(stakeData: Buffer): Stake {
|
|
|
157
121
|
|
|
158
122
|
// lifetime_rewards: u64 (8 bytes)
|
|
159
123
|
const lifetimeRewards = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
160
|
-
offset += 8
|
|
161
|
-
|
|
162
|
-
// buffer_f: u64 (8 bytes)
|
|
163
|
-
const bufferF = new BN(stakeData.slice(offset, offset + 8), "le")
|
|
164
124
|
|
|
165
125
|
return {
|
|
166
126
|
authority,
|
|
167
127
|
balance,
|
|
168
|
-
|
|
169
|
-
bufferB,
|
|
170
|
-
bufferC,
|
|
171
|
-
bufferD,
|
|
128
|
+
compoundFee,
|
|
172
129
|
compoundFeeReserve,
|
|
173
130
|
lastClaimAt,
|
|
174
131
|
lastDepositAt,
|
|
@@ -176,7 +133,6 @@ function deserializeStakeAccount(stakeData: Buffer): Stake {
|
|
|
176
133
|
rewardsFactor,
|
|
177
134
|
rewards,
|
|
178
135
|
lifetimeRewards,
|
|
179
|
-
bufferF,
|
|
180
136
|
}
|
|
181
137
|
}
|
|
182
138
|
|
|
@@ -184,67 +140,25 @@ function deserializeStakeAccount(stakeData: Buffer): Stake {
|
|
|
184
140
|
* Deserialize Treasury account from Buffer
|
|
185
141
|
* Skips the 8-byte steel discriminator and deserializes the struct fields
|
|
186
142
|
*
|
|
187
|
-
* Account layout (
|
|
143
|
+
* Account layout (32 bytes total):
|
|
188
144
|
* - discriminator: 8 bytes
|
|
189
|
-
* -
|
|
190
|
-
* - buffer_a: 8 bytes
|
|
191
|
-
* - motherlode: 8 bytes
|
|
192
|
-
* - miner_rewards_factor: 16 bytes (u128 Numeric)
|
|
193
|
-
* - stake_rewards_factor: 16 bytes (u128 Numeric)
|
|
194
|
-
* - buffer_b: 8 bytes
|
|
195
|
-
* - total_refined: 8 bytes
|
|
145
|
+
* - rewards_factor: 16 bytes (I80F48 Numeric)
|
|
196
146
|
* - total_staked: 8 bytes
|
|
197
|
-
* - total_unclaimed: 8 bytes
|
|
198
147
|
*/
|
|
199
148
|
function deserializeTreasuryAccount(treasuryData: Buffer): Treasury {
|
|
200
149
|
const DISCRIMINATOR_SIZE = 8
|
|
201
150
|
let offset = DISCRIMINATOR_SIZE
|
|
202
151
|
|
|
203
|
-
//
|
|
204
|
-
const
|
|
205
|
-
offset += 8
|
|
206
|
-
|
|
207
|
-
// buffer_a: u64 (8 bytes)
|
|
208
|
-
const bufferA = new BN(treasuryData.slice(offset, offset + 8), "le")
|
|
209
|
-
offset += 8
|
|
210
|
-
|
|
211
|
-
// motherlode: u64 (8 bytes)
|
|
212
|
-
const motherlode = new BN(treasuryData.slice(offset, offset + 8), "le")
|
|
213
|
-
offset += 8
|
|
214
|
-
|
|
215
|
-
// miner_rewards_factor: Numeric (16 bytes = u128)
|
|
216
|
-
const minerRewardsFactor = deserializeNumeric(treasuryData, offset)
|
|
217
|
-
offset += 16
|
|
218
|
-
|
|
219
|
-
// stake_rewards_factor: Numeric (16 bytes = u128)
|
|
220
|
-
const stakeRewardsFactor = deserializeNumeric(treasuryData, offset)
|
|
152
|
+
// rewards_factor: Numeric (16 bytes = I80F48)
|
|
153
|
+
const rewardsFactor = deserializeNumeric(treasuryData, offset)
|
|
221
154
|
offset += 16
|
|
222
155
|
|
|
223
|
-
// buffer_b: u64 (8 bytes)
|
|
224
|
-
const bufferB = new BN(treasuryData.slice(offset, offset + 8), "le")
|
|
225
|
-
offset += 8
|
|
226
|
-
|
|
227
|
-
// total_refined: u64 (8 bytes)
|
|
228
|
-
const totalRefined = new BN(treasuryData.slice(offset, offset + 8), "le")
|
|
229
|
-
offset += 8
|
|
230
|
-
|
|
231
156
|
// total_staked: u64 (8 bytes)
|
|
232
157
|
const totalStaked = new BN(treasuryData.slice(offset, offset + 8), "le")
|
|
233
|
-
offset += 8
|
|
234
|
-
|
|
235
|
-
// total_unclaimed: u64 (8 bytes)
|
|
236
|
-
const totalUnclaimed = new BN(treasuryData.slice(offset, offset + 8), "le")
|
|
237
158
|
|
|
238
159
|
return {
|
|
239
|
-
|
|
240
|
-
bufferA,
|
|
241
|
-
motherlode,
|
|
242
|
-
minerRewardsFactor,
|
|
243
|
-
stakeRewardsFactor,
|
|
244
|
-
bufferB,
|
|
245
|
-
totalRefined,
|
|
160
|
+
rewardsFactor,
|
|
246
161
|
totalStaked,
|
|
247
|
-
totalUnclaimed,
|
|
248
162
|
}
|
|
249
163
|
}
|
|
250
164
|
|
|
@@ -254,8 +168,8 @@ function deserializeTreasuryAccount(treasuryData: Buffer): Treasury {
|
|
|
254
168
|
*
|
|
255
169
|
* Exchange rate formula: (stake.balance + total_rewards) / stORE_supply
|
|
256
170
|
*
|
|
257
|
-
* Where total_rewards is calculated using ORE protocol's Stake::
|
|
258
|
-
* 1. accumulated_rewards = treasury.
|
|
171
|
+
* Where total_rewards is calculated using ORE protocol's Stake::update_rewards:
|
|
172
|
+
* 1. accumulated_rewards = treasury.rewards_factor - stake.rewards_factor
|
|
259
173
|
* 2. personal_rewards = accumulated_rewards * stake.balance
|
|
260
174
|
* 3. total_rewards = stake.rewards + personal_rewards
|
|
261
175
|
*
|
|
@@ -265,8 +179,7 @@ function deserializeTreasuryAccount(treasuryData: Buffer): Treasury {
|
|
|
265
179
|
* the exchange rate. The stake.balance is only updated via ORE program
|
|
266
180
|
* deposit/withdraw instructions.
|
|
267
181
|
*
|
|
268
|
-
* Note: Numeric values are stored as fixed-point numbers
|
|
269
|
-
* When multiplying two Numeric values, the result is divided by 1e12 to maintain scale.
|
|
182
|
+
* Note: Numeric values are stored as I80F48 fixed-point numbers.
|
|
270
183
|
*/
|
|
271
184
|
export function calculateOreExchangeRate(accounts: {
|
|
272
185
|
stakeAccount: Buffer
|
|
@@ -291,22 +204,19 @@ export function calculateOreExchangeRate(accounts: {
|
|
|
291
204
|
// This prevents exchange rate manipulation via direct token transfers
|
|
292
205
|
const stakeBalance = stake.balance.toNumber()
|
|
293
206
|
|
|
294
|
-
// Calculate accrued rewards using ORE protocol's
|
|
295
|
-
// This mirrors the exact logic from Stake::
|
|
296
|
-
const
|
|
207
|
+
// Calculate accrued rewards using ORE protocol's update_rewards algorithm
|
|
208
|
+
// This mirrors the exact logic from Stake::update_rewards() in ore_cpi
|
|
209
|
+
const treasuryRewardsFactorDecimal = treasury.rewardsFactor.decimalValue
|
|
297
210
|
const stakeRewardsFactorDecimal = stake.rewardsFactor.decimalValue
|
|
298
211
|
|
|
299
212
|
let newlyAccruedRewards = 0
|
|
300
|
-
if (
|
|
301
|
-
// accumulated_rewards = treasury.
|
|
302
|
-
const accumulatedRewards =
|
|
213
|
+
if (treasuryRewardsFactorDecimal.gt(stakeRewardsFactorDecimal)) {
|
|
214
|
+
// accumulated_rewards = treasury.rewards_factor - stake.rewards_factor
|
|
215
|
+
const accumulatedRewards = treasuryRewardsFactorDecimal.minus(stakeRewardsFactorDecimal)
|
|
303
216
|
|
|
304
217
|
// personal_rewards = accumulated_rewards * stake.balance
|
|
305
|
-
//
|
|
306
|
-
//
|
|
307
|
-
// the result is (a * b) / 1e12 to maintain scale. Then to_u64() divides by 1e12.
|
|
308
|
-
// Since decimalValue already gives us the decimal representation (divided by 1e12),
|
|
309
|
-
// we just multiply by balance and floor the result.
|
|
218
|
+
// Since decimalValue already gives us the decoded fixed-point value, we just
|
|
219
|
+
// multiply by balance and floor the result.
|
|
310
220
|
const personalRewards = accumulatedRewards.mul(new Decimal(stakeBalance))
|
|
311
221
|
newlyAccruedRewards = Math.floor(personalRewards.toNumber())
|
|
312
222
|
}
|
|
@@ -318,5 +228,9 @@ export function calculateOreExchangeRate(accounts: {
|
|
|
318
228
|
const totalBalanceWithRewards = stakeBalance + totalRewards
|
|
319
229
|
|
|
320
230
|
// Calculate exchange rate: (stake.balance + accrued_rewards) / stORE_supply
|
|
231
|
+
if (totalBalanceWithRewards === 0) {
|
|
232
|
+
return 1
|
|
233
|
+
}
|
|
234
|
+
|
|
321
235
|
return totalBalanceWithRewards / storeSupply
|
|
322
236
|
}
|