@exponent-labs/exponent-fetcher 0.9.11 → 0.9.13

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.
Files changed (39) hide show
  1. package/build/constants.js +3 -3
  2. package/build/constants.js.map +1 -1
  3. package/build/exponentFetcher.d.ts +18 -16
  4. package/build/exponentFetcher.js +74 -141
  5. package/build/exponentFetcher.js.map +1 -1
  6. package/build/utils/adrena.d.ts +0 -2
  7. package/build/utils/adrena.js +1 -2
  8. package/build/utils/adrena.js.map +1 -1
  9. package/build/utils/fragmetric.d.ts +0 -2
  10. package/build/utils/fragmetric.js +2 -2
  11. package/build/utils/fragmetric.js.map +1 -1
  12. package/build/utils/jito.d.ts +0 -2
  13. package/build/utils/jito.js +1 -2
  14. package/build/utils/jito.js.map +1 -1
  15. package/build/utils/jupiter.d.ts +0 -2
  16. package/build/utils/jupiter.js +2 -3
  17. package/build/utils/jupiter.js.map +1 -1
  18. package/build/utils/kamino.d.ts +0 -2
  19. package/build/utils/kamino.js +1 -2
  20. package/build/utils/kamino.js.map +1 -1
  21. package/build/utils/meteora.d.ts +0 -3
  22. package/build/utils/meteora.js +5 -5
  23. package/build/utils/meteora.js.map +1 -1
  24. package/build/utils/ore.d.ts +6 -21
  25. package/build/utils/ore.js +30 -85
  26. package/build/utils/ore.js.map +1 -1
  27. package/build/utils/perena.d.ts +0 -2
  28. package/build/utils/perena.js +2 -3
  29. package/build/utils/perena.js.map +1 -1
  30. package/build/utils/sanctum.d.ts +0 -2
  31. package/build/utils/sanctum.js +1 -2
  32. package/build/utils/sanctum.js.map +1 -1
  33. package/build/utils/solstice.d.ts +9 -2
  34. package/build/utils/solstice.js +20 -2
  35. package/build/utils/solstice.js.map +1 -1
  36. package/package.json +21 -21
  37. package/src/exponentFetcher.ts +75 -155
  38. package/src/utils/ore.ts +36 -122
  39. package/src/utils/solstice.ts +27 -0
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 a u128 with 12 decimal places of precision
7
- const NUMERIC_DECIMAL_PLACES = 12
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 u128 (16 bytes) with 1e12 scaling factor
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(new Decimal(10).pow(NUMERIC_DECIMAL_PLACES))
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 miner account.
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
- /// Buffer a (placeholder)
40
- bufferA: BN
41
- /// Buffer b (placeholder)
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
- stakeRewardsFactor: Numeric
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 (152 bytes total):
72
+ * Account layout (120 bytes total):
95
73
  * - discriminator: 8 bytes
96
74
  * - authority: 32 bytes
97
75
  * - balance: 8 bytes
98
- * - buffer_a through buffer_d: 32 bytes (4 x u64)
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 (u128 Numeric)
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
- // buffer_a: u64 (8 bytes)
119
- const bufferA = new BN(stakeData.slice(offset, offset + 8), "le")
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 = u128)
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
- bufferA,
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 (96 bytes total):
143
+ * Account layout (32 bytes total):
188
144
  * - discriminator: 8 bytes
189
- * - balance: 8 bytes
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
- // balance: u64 (8 bytes)
204
- const balance = new BN(treasuryData.slice(offset, offset + 8), "le")
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
- balance,
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::calculate_accrued_rewards:
258
- * 1. accumulated_rewards = treasury.stake_rewards_factor - stake.rewards_factor
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 with 1e12 precision.
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 calculate_accrued_rewards algorithm
295
- // This mirrors the exact logic from Stake::calculate_accrued_rewards() in ore_cpi
296
- const treasuryStakeRewardsFactorDecimal = treasury.stakeRewardsFactor.decimalValue
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 (treasuryStakeRewardsFactorDecimal.gt(stakeRewardsFactorDecimal)) {
301
- // accumulated_rewards = treasury.stake_rewards_factor - stake.rewards_factor
302
- const accumulatedRewards = treasuryStakeRewardsFactorDecimal.minus(stakeRewardsFactorDecimal)
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
- // In Rust: accumulated_rewards (as Numeric) * Numeric::from_u64(stake.balance)
306
- // The Numeric type uses 1e12 scaling internally. When multiplying two Numerics,
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
  }
@@ -1,4 +1,5 @@
1
1
  import { decodeYieldPoolAndVestingScheduleAccounts } from "@exponent-labs/solstice-idl"
2
+ import { AccountLayout, MintLayout } from "@solana/spl-token"
2
3
 
3
4
  export function calculateSolsticeRedemptionRate(accounts: { yieldPool: Buffer; vestingSchedule: Buffer }): {
4
5
  redemptionRate: number
@@ -49,3 +50,29 @@ export function calculateSolsticeRedemptionRate(accounts: { yieldPool: Buffer; v
49
50
  totalVestedAssets: totalVestedAssets.toString(),
50
51
  }
51
52
  }
53
+
54
+ /**
55
+ * Calculates the Solstice GLAM vault stSLX exchange rate using the same account
56
+ * layout and ratio as the Generic Standard on-chain interface.
57
+ */
58
+ export function calculateSolsticeGlamVaultExchangeRate(accounts: {
59
+ stakingVaultSlxAta: Buffer
60
+ slxMint: Buffer
61
+ stslxMint: Buffer
62
+ }): number {
63
+ const stakingVaultSlxAccount = AccountLayout.decode(accounts.stakingVaultSlxAta.subarray(0, AccountLayout.span))
64
+ const slxMint = MintLayout.decode(accounts.slxMint.subarray(0, MintLayout.span))
65
+ const stslxMint = MintLayout.decode(accounts.stslxMint.subarray(0, MintLayout.span))
66
+
67
+ const stakingVaultSlxBalance = BigInt(stakingVaultSlxAccount.amount.toString())
68
+ const stslxSupply = BigInt(stslxMint.supply.toString())
69
+
70
+ if (stakingVaultSlxBalance === 0n || stslxSupply === 0n) {
71
+ return 1
72
+ }
73
+
74
+ const numerator = stakingVaultSlxBalance * 10n ** BigInt(stslxMint.decimals)
75
+ const denominator = stslxSupply * 10n ** BigInt(slxMint.decimals)
76
+
77
+ return Number(numerator) / Number(denominator)
78
+ }