@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.
- package/build/constants.js +3 -3
- package/build/constants.js.map +1 -1
- package/build/exponentFetcher.d.ts +18 -16
- package/build/exponentFetcher.js +74 -141
- 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 +9 -2
- package/build/utils/solstice.js +20 -2
- package/build/utils/solstice.js.map +1 -1
- package/package.json +21 -21
- package/src/exponentFetcher.ts +75 -155
- package/src/utils/ore.ts +36 -122
- 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
|
|
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
|
}
|
package/src/utils/solstice.ts
CHANGED
|
@@ -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
|
+
}
|