@exponent-labs/exponent-sdk 0.0.3

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 (68) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/build/addressLookupTableUtil.d.ts +12 -0
  3. package/build/addressLookupTableUtil.js +32 -0
  4. package/build/addressLookupTableUtil.js.map +1 -0
  5. package/build/environment.d.ts +10 -0
  6. package/build/environment.js +13 -0
  7. package/build/environment.js.map +1 -0
  8. package/build/events.d.ts +339 -0
  9. package/build/events.js +231 -0
  10. package/build/events.js.map +1 -0
  11. package/build/flavors.d.ts +24 -0
  12. package/build/flavors.js +713 -0
  13. package/build/flavors.js.map +1 -0
  14. package/build/index.d.ts +11 -0
  15. package/build/index.js +45 -0
  16. package/build/index.js.map +1 -0
  17. package/build/lpPosition.d.ts +35 -0
  18. package/build/lpPosition.js +103 -0
  19. package/build/lpPosition.js.map +1 -0
  20. package/build/market.d.ts +567 -0
  21. package/build/market.js +1445 -0
  22. package/build/market.js.map +1 -0
  23. package/build/syPosition.d.ts +6 -0
  24. package/build/syPosition.js +115 -0
  25. package/build/syPosition.js.map +1 -0
  26. package/build/tokenUtil.d.ts +3 -0
  27. package/build/tokenUtil.js +23 -0
  28. package/build/tokenUtil.js.map +1 -0
  29. package/build/utils/altUtil.d.ts +8 -0
  30. package/build/utils/altUtil.js +35 -0
  31. package/build/utils/altUtil.js.map +1 -0
  32. package/build/utils/binSolver.d.ts +1 -0
  33. package/build/utils/binSolver.js +45 -0
  34. package/build/utils/binSolver.js.map +1 -0
  35. package/build/utils/binSolver.test.d.ts +1 -0
  36. package/build/utils/binSolver.test.js +15 -0
  37. package/build/utils/binSolver.test.js.map +1 -0
  38. package/build/utils/index.d.ts +6 -0
  39. package/build/utils/index.js +31 -0
  40. package/build/utils/index.js.map +1 -0
  41. package/build/utils/ix.d.ts +6 -0
  42. package/build/utils/ix.js +3 -0
  43. package/build/utils/ix.js.map +1 -0
  44. package/build/vault.d.ts +289 -0
  45. package/build/vault.js +615 -0
  46. package/build/vault.js.map +1 -0
  47. package/build/ytPosition.d.ts +86 -0
  48. package/build/ytPosition.js +231 -0
  49. package/build/ytPosition.js.map +1 -0
  50. package/jest.config.js +5 -0
  51. package/package.json +42 -0
  52. package/src/addressLookupTableUtil.ts +34 -0
  53. package/src/environment.ts +19 -0
  54. package/src/events.ts +595 -0
  55. package/src/flavors.ts +773 -0
  56. package/src/index.ts +11 -0
  57. package/src/lpPosition.ts +129 -0
  58. package/src/market.ts +2338 -0
  59. package/src/syPosition.ts +151 -0
  60. package/src/tokenUtil.ts +20 -0
  61. package/src/utils/altUtil.ts +47 -0
  62. package/src/utils/binSolver.test.ts +15 -0
  63. package/src/utils/binSolver.ts +44 -0
  64. package/src/utils/index.ts +32 -0
  65. package/src/utils/ix.ts +7 -0
  66. package/src/vault.ts +999 -0
  67. package/src/ytPosition.ts +313 -0
  68. package/tsconfig.json +38 -0
package/src/flavors.ts ADDED
@@ -0,0 +1,773 @@
1
+ import { BN, web3 } from "@coral-xyz/anchor"
2
+ import { ExponentFetcher, fetchKaminoReserve } from "@exponent-labs/exponent-fetcher"
3
+ import { Environment } from "./environment"
4
+ import { MfiSySdk } from "@exponent-labs/marginfi-sy-sdk"
5
+ import { getMeta, KAMINO_LEND_PROGRAM_ID } from "@exponent-labs/kamino-lend-standard"
6
+ import { KlendSySdk } from "@exponent-labs/kamino-sy-sdk"
7
+ import {
8
+ FlavorKaminoStateJson,
9
+ FlavorKaminoState,
10
+ FlavorMarginfiState,
11
+ FlavorMarginfiStateJson,
12
+ FlavorKamino,
13
+ FlavorMarginfi,
14
+ FlavorDiscriminator,
15
+ MintSyArgs,
16
+ RedeemSyArgs,
17
+ Flavor,
18
+ CpiAccountsRaw,
19
+ FlavorJitoRestaking,
20
+ FlavorJitoRestakingState,
21
+ FlavorJitoRestakingStateJson,
22
+ FlavorPerena,
23
+ FlavorPerenaState,
24
+ FlavorPerenaStateJson,
25
+ FlavorGeneric,
26
+ FlavorGenericState,
27
+ InterfaceInstructionArgs,
28
+ FlavorGenericStateJson,
29
+ } from "@exponent-labs/exponent-types"
30
+ import { JitoRestakingSySdk } from "@exponent-labs/jito-restaking-sy-sdk"
31
+ import { PreciseNumber } from "@exponent-labs/precise-number"
32
+ import { PerenaSySdk } from "@exponent-labs/perena-sy-sdk"
33
+ import { GenericSySdk } from "@exponent-labs/generic-sy-sdk"
34
+
35
+ export function serializeFlavorMarginfi(flavor: FlavorMarginfiState): FlavorMarginfiStateJson {
36
+ return {
37
+ flavor: "marginfi",
38
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
39
+ mintBase: flavor.mintBase.toString(),
40
+ baseTokenProgram: flavor.baseTokenProgram.toString(),
41
+ emissions: flavor.emissions.map((e) => ({
42
+ exchangeRate: parseFloat(PreciseNumber.fromRaw(e.exchangeRate[0]).valueString),
43
+ mint: e.mint.toString(),
44
+ tokenProgram: e.tokenProgram.toString(),
45
+ })),
46
+ bank: flavor.bank.toString(),
47
+ emissionMint: flavor.emissionMint?.toString(),
48
+ emissionTokenProgram: flavor.emissionTokenProgram?.toString(),
49
+ mfiSyState: {
50
+ selfAddress: flavor.mfiSyState.selfAddress.toString(),
51
+ marginfiSyProgramId: flavor.mfiSyState.marginfiSyProgramId.toString(),
52
+ syRate: flavor.mfiSyState.syRate,
53
+ mintBase: flavor.mfiSyState.mintBase.toString(),
54
+ tokenProgramBase: flavor.mfiSyState.tokenProgramBase.toString(),
55
+ marginfiProgramId: flavor.mfiSyState.marginfiProgramId.toString(),
56
+ marginfiGroupId: flavor.mfiSyState.marginfiGroupId.toString(),
57
+ emissionsMint: flavor.mfiSyState.emissionsMint?.toString() || null,
58
+ emissionsTokenProgram: flavor.mfiSyState.emissionsTokenProgram?.toString() || null,
59
+ account: {
60
+ marginfiBank: flavor.mfiSyState.account.marginfiBank.toString(),
61
+ marginfiAccount: flavor.mfiSyState.account.marginfiAccount.toString(),
62
+ mintSy: flavor.mfiSyState.account.mintSy.toString(),
63
+ tokenSyEscrow: flavor.mfiSyState.account.tokenSyEscrow.toString(),
64
+ maxSySupply: flavor.mfiSyState.account.maxSySupply.toString(),
65
+ minMintSize: flavor.mfiSyState.account.minMintSize.toString(),
66
+ minRedeemSize: flavor.mfiSyState.account.minRedeemSize.toString(),
67
+ emissions: flavor.mfiSyState.account.emissions.map((e) => ({
68
+ mint: e.mint.toString(),
69
+ tokenProgram: e.tokenProgram.toString(),
70
+ escrowAccount: e.escrowAccount.toString(),
71
+ index: parseFloat(PreciseNumber.fromRaw(e.index[0]).valueString),
72
+ lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
73
+ lastSeenTotalAccruedEmissions: e.lastSeenTotalAccruedEmissions.toString(),
74
+ totalClaimedEmissions: e.totalClaimedEmissions.toString(),
75
+ treasuryEmission: e.treasuryEmission.toString(),
76
+ })),
77
+ },
78
+ },
79
+ }
80
+ }
81
+
82
+ export function deserializeFlavorMarginfi(flavor: FlavorMarginfiStateJson): FlavorMarginfiState {
83
+ return {
84
+ flavor: "marginfi",
85
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
86
+ mintBase: new web3.PublicKey(flavor.mintBase),
87
+ baseTokenProgram: new web3.PublicKey(flavor.baseTokenProgram),
88
+ emissions: flavor.emissions.map((e) => ({
89
+ exchangeRate: { 0: [new BN(PreciseNumber.fromRaw([new BN(e.exchangeRate)]).valueString)] },
90
+ mint: new web3.PublicKey(e.mint),
91
+ tokenProgram: new web3.PublicKey(e.tokenProgram),
92
+ })),
93
+ bank: new web3.PublicKey(flavor.bank),
94
+ emissionMint: flavor.emissionMint ? new web3.PublicKey(flavor.emissionMint) : undefined,
95
+ emissionTokenProgram: flavor.emissionTokenProgram ? new web3.PublicKey(flavor.emissionTokenProgram) : undefined,
96
+ mfiSyState: {
97
+ selfAddress: new web3.PublicKey(flavor.mfiSyState.selfAddress),
98
+ marginfiSyProgramId: new web3.PublicKey(flavor.mfiSyState.marginfiSyProgramId),
99
+ syRate: flavor.mfiSyState.syRate,
100
+ mintBase: new web3.PublicKey(flavor.mfiSyState.mintBase),
101
+ tokenProgramBase: new web3.PublicKey(flavor.mfiSyState.tokenProgramBase),
102
+ marginfiProgramId: new web3.PublicKey(flavor.mfiSyState.marginfiProgramId),
103
+ marginfiGroupId: new web3.PublicKey(flavor.mfiSyState.marginfiGroupId),
104
+ emissionsMint: flavor.mfiSyState.emissionsMint ? new web3.PublicKey(flavor.mfiSyState.emissionsMint) : null,
105
+ emissionsTokenProgram: flavor.mfiSyState.emissionsTokenProgram
106
+ ? new web3.PublicKey(flavor.mfiSyState.emissionsTokenProgram)
107
+ : null,
108
+ account: {
109
+ marginfiBank: new web3.PublicKey(flavor.mfiSyState.account.marginfiBank),
110
+ marginfiAccount: new web3.PublicKey(flavor.mfiSyState.account.marginfiAccount),
111
+ mintSy: new web3.PublicKey(flavor.mfiSyState.account.mintSy),
112
+ tokenSyEscrow: new web3.PublicKey(flavor.mfiSyState.account.tokenSyEscrow),
113
+ maxSySupply: BigInt(flavor.mfiSyState.account.maxSySupply),
114
+ minMintSize: BigInt(flavor.mfiSyState.account.minMintSize),
115
+ minRedeemSize: BigInt(flavor.mfiSyState.account.minRedeemSize),
116
+ emissions: flavor.mfiSyState.account.emissions.map((emission) => ({
117
+ mint: new web3.PublicKey(emission.mint),
118
+ tokenProgram: new web3.PublicKey(emission.tokenProgram),
119
+ escrowAccount: new web3.PublicKey(emission.escrowAccount),
120
+ index: { 0: [new BN(emission.index)] },
121
+ lastSeenIndex: { 0: [new BN(emission.lastSeenIndex)] },
122
+ lastSeenTotalAccruedEmissions: new BN(emission.lastSeenTotalAccruedEmissions),
123
+ totalClaimedEmissions: new BN(emission.totalClaimedEmissions),
124
+ treasuryEmission: new BN(emission.treasuryEmission),
125
+ })),
126
+ },
127
+ },
128
+ }
129
+ }
130
+
131
+ export function serializeFlavorKamino(flavor: FlavorKaminoState): FlavorKaminoStateJson {
132
+ return {
133
+ flavor: "kamino",
134
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
135
+ mintBase: flavor.mintBase.toString(),
136
+ baseTokenProgram: flavor.baseTokenProgram.toString(),
137
+ emissions: flavor.emissions.map((e) => ({
138
+ exchangeRate: parseFloat(PreciseNumber.fromRaw(e.exchangeRate[0]).valueString),
139
+ mint: e.mint.toString(),
140
+ tokenProgram: e.tokenProgram.toString(),
141
+ })),
142
+ kaminoSyState: {
143
+ selfAddress: flavor.kaminoSyState.selfAddress.toString(),
144
+ klendSyProgramId: flavor.kaminoSyState.klendSyProgramId.toString(),
145
+ syRate: flavor.kaminoSyState.syRate,
146
+ mintBase: flavor.kaminoSyState.mintBase.toString(),
147
+ tokenProgramBase: flavor.kaminoSyState.tokenProgramBase.toString(),
148
+ klendProgramId: flavor.kaminoSyState.klendProgramId.toString(),
149
+ klendMarketId: flavor.kaminoSyState.klendMarketId.toString(),
150
+ account: {
151
+ kaminoReserve: flavor.kaminoSyState.account.kaminoReserve.toString(),
152
+ kaminoObligation: flavor.kaminoSyState.account.kaminoObligation.toString(),
153
+ kaminoFarm: flavor.kaminoSyState.account.kaminoFarm.toString(),
154
+ kaminoUserMetadata: flavor.kaminoSyState.account.kaminoUserMetadata.toString(),
155
+ mintSy: flavor.kaminoSyState.account.mintSy.toString(),
156
+ tokenSyEscrow: flavor.kaminoSyState.account.tokenSyEscrow.toString(),
157
+ minMintSize: flavor.kaminoSyState.account.minMintSize.toString(),
158
+ minRedeemSize: flavor.kaminoSyState.account.minRedeemSize.toString(),
159
+ userState: flavor.kaminoSyState.account.userState.toString(),
160
+ maxSySupply: flavor.kaminoSyState.account.maxSySupply.toString(),
161
+ emissions: flavor.kaminoSyState.account.emissions.map((e) => ({
162
+ mint: e.mint.toString(),
163
+ tokenProgram: e.tokenProgram.toString(),
164
+ escrowAccount: e.escrowAccount.toString(),
165
+ index: parseFloat(PreciseNumber.fromRaw(e.index[0]).valueString),
166
+ lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
167
+ lastSeenTotalAccruedEmissions: e.lastSeenTotalAccruedEmissions.toString(),
168
+ totalClaimedEmissions: e.totalClaimedEmissions.toString(),
169
+ treasuryEmission: e.treasuryEmission.toString(),
170
+ })),
171
+ },
172
+ },
173
+ }
174
+ }
175
+
176
+ export function deserializeFlavorKamino(flavor: FlavorKaminoStateJson): FlavorKaminoState {
177
+ return {
178
+ flavor: "kamino",
179
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
180
+ mintBase: new web3.PublicKey(flavor.mintBase),
181
+ baseTokenProgram: new web3.PublicKey(flavor.baseTokenProgram),
182
+ emissions: flavor.emissions.map((e) => ({
183
+ exchangeRate: { 0: [new BN(PreciseNumber.fromRaw([new BN(e.exchangeRate)]).valueString)] },
184
+ mint: new web3.PublicKey(e.mint),
185
+ tokenProgram: new web3.PublicKey(e.tokenProgram),
186
+ })),
187
+ kaminoSyState: {
188
+ selfAddress: new web3.PublicKey(flavor.kaminoSyState.selfAddress),
189
+ klendSyProgramId: new web3.PublicKey(flavor.kaminoSyState.klendSyProgramId),
190
+ syRate: flavor.kaminoSyState.syRate,
191
+ mintBase: new web3.PublicKey(flavor.kaminoSyState.mintBase),
192
+ tokenProgramBase: new web3.PublicKey(flavor.kaminoSyState.tokenProgramBase),
193
+ klendProgramId: new web3.PublicKey(flavor.kaminoSyState.klendProgramId),
194
+ klendMarketId: new web3.PublicKey(flavor.kaminoSyState.klendMarketId),
195
+ account: {
196
+ kaminoReserve: new web3.PublicKey(flavor.kaminoSyState.account.kaminoReserve),
197
+ kaminoObligation: new web3.PublicKey(flavor.kaminoSyState.account.kaminoObligation),
198
+ kaminoFarm: new web3.PublicKey(flavor.kaminoSyState.account.kaminoFarm),
199
+ kaminoUserMetadata: new web3.PublicKey(flavor.kaminoSyState.account.kaminoUserMetadata),
200
+ mintSy: new web3.PublicKey(flavor.kaminoSyState.account.mintSy),
201
+ tokenSyEscrow: new web3.PublicKey(flavor.kaminoSyState.account.tokenSyEscrow),
202
+ minMintSize: flavor.kaminoSyState.account.minMintSize,
203
+ minRedeemSize: flavor.kaminoSyState.account.minRedeemSize,
204
+ userState: new web3.PublicKey(flavor.kaminoSyState.account.userState),
205
+ maxSySupply: flavor.kaminoSyState.account.maxSySupply,
206
+ emissions: flavor.kaminoSyState.account.emissions.map((emission) => ({
207
+ mint: new web3.PublicKey(emission.mint),
208
+ tokenProgram: new web3.PublicKey(emission.tokenProgram),
209
+ escrowAccount: new web3.PublicKey(emission.escrowAccount),
210
+ index: { 0: [new BN(emission.index)] },
211
+ lastSeenIndex: { 0: [new BN(emission.lastSeenIndex)] },
212
+ lastSeenTotalAccruedEmissions: new BN(emission.lastSeenTotalAccruedEmissions),
213
+ totalClaimedEmissions: new BN(emission.totalClaimedEmissions),
214
+ treasuryEmission: new BN(emission.treasuryEmission),
215
+ })),
216
+ },
217
+ },
218
+ }
219
+ }
220
+
221
+ export function serializeFlavorJitoRestaking(flavor: FlavorJitoRestakingState): FlavorJitoRestakingStateJson {
222
+ return {
223
+ flavor: "jitoRestaking",
224
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
225
+ mintBase: flavor.mintBase.toString(),
226
+ baseTokenProgram: flavor.baseTokenProgram.toString(),
227
+ emissions: flavor.emissions.map((e) => ({
228
+ exchangeRate: parseFloat(PreciseNumber.fromRaw(e.exchangeRate[0]).valueString),
229
+ mint: e.mint.toString(),
230
+ tokenProgram: e.tokenProgram.toString(),
231
+ })),
232
+ jitoSyState: {
233
+ selfAddress: flavor.jitoSyState.selfAddress.toString(),
234
+ syRate: flavor.jitoSyState.syRate,
235
+ underlyingExchangeRate: flavor.jitoSyState.underlyingExchangeRate,
236
+ mintBase: flavor.jitoSyState.mintBase.toString(),
237
+ tokenProgramBase: flavor.jitoSyState.tokenProgramBase.toString(),
238
+ account: {
239
+ jitoVault: flavor.jitoSyState.account.jitoVault.toString(),
240
+ mintSy: flavor.jitoSyState.account.mintSy.toString(),
241
+ tokenSyEscrow: flavor.jitoSyState.account.tokenSyEscrow.toString(),
242
+ minMintSize: flavor.jitoSyState.account.minMintSize.toString(),
243
+ minRedeemSize: flavor.jitoSyState.account.minRedeemSize.toString(),
244
+ maxSySupply: flavor.jitoSyState.account.maxSySupply.toString(),
245
+ interfaceAccounts: flavor.jitoSyState.account.interfaceAccounts.map((a) => a.toString()),
246
+ interfaceType: flavor.jitoSyState.account.interfaceType,
247
+ emissions: flavor.jitoSyState.account.emissions.map((e) => ({
248
+ mint: e.mint.toString(),
249
+ tokenProgram: e.tokenProgram.toString(),
250
+ escrowAccount: e.escrowAccount.toString(),
251
+ index: parseFloat(PreciseNumber.fromRaw(e.index[0]).valueString),
252
+ lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
253
+ lastSeenTotalAccruedEmissions: e.lastSeenTotalAccruedEmissions.toString(),
254
+ totalClaimedEmissions: e.totalClaimedEmissions.toString(),
255
+ treasuryEmission: e.treasuryEmission.toString(),
256
+ })),
257
+ },
258
+ },
259
+ }
260
+ }
261
+
262
+ export function deserializeFlavorJitoRestaking(flavor: FlavorJitoRestakingStateJson): FlavorJitoRestakingState {
263
+ return {
264
+ flavor: "jitoRestaking",
265
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
266
+ mintBase: new web3.PublicKey(flavor.mintBase),
267
+ baseTokenProgram: new web3.PublicKey(flavor.baseTokenProgram),
268
+ emissions: flavor.emissions.map((e) => ({
269
+ exchangeRate: { 0: [new BN(PreciseNumber.fromRaw([new BN(e.exchangeRate)]).valueString)] },
270
+ mint: new web3.PublicKey(e.mint),
271
+ tokenProgram: new web3.PublicKey(e.tokenProgram),
272
+ })),
273
+ jitoSyState: {
274
+ selfAddress: new web3.PublicKey(flavor.jitoSyState.selfAddress),
275
+ syRate: flavor.jitoSyState.syRate,
276
+ underlyingExchangeRate: flavor.jitoSyState.underlyingExchangeRate,
277
+ mintBase: new web3.PublicKey(flavor.jitoSyState.mintBase),
278
+ tokenProgramBase: new web3.PublicKey(flavor.jitoSyState.tokenProgramBase),
279
+ account: {
280
+ jitoVault: new web3.PublicKey(flavor.jitoSyState.account.jitoVault),
281
+ mintSy: new web3.PublicKey(flavor.jitoSyState.account.mintSy),
282
+ tokenSyEscrow: new web3.PublicKey(flavor.jitoSyState.account.tokenSyEscrow),
283
+ minMintSize: new BN(flavor.jitoSyState.account.minMintSize),
284
+ minRedeemSize: new BN(flavor.jitoSyState.account.minRedeemSize),
285
+ maxSySupply: new BN(flavor.jitoSyState.account.maxSySupply),
286
+ interfaceAccounts: flavor.jitoSyState.account.interfaceAccounts.map((a) => new web3.PublicKey(a)),
287
+ interfaceType: flavor.jitoSyState.account.interfaceType,
288
+ emissions: flavor.jitoSyState.account.emissions.map((emission) => ({
289
+ mint: new web3.PublicKey(emission.mint),
290
+ tokenProgram: new web3.PublicKey(emission.tokenProgram),
291
+ escrowAccount: new web3.PublicKey(emission.escrowAccount),
292
+ index: { 0: [new BN(emission.index)] },
293
+ lastSeenIndex: { 0: [new BN(emission.lastSeenIndex)] },
294
+ lastSeenTotalAccruedEmissions: new BN(emission.lastSeenTotalAccruedEmissions),
295
+ totalClaimedEmissions: new BN(emission.totalClaimedEmissions),
296
+ treasuryEmission: new BN(emission.treasuryEmission),
297
+ })),
298
+ },
299
+ },
300
+ }
301
+ }
302
+
303
+ export function serializeFlavorParena(flavor: FlavorPerenaState): FlavorPerenaStateJson {
304
+ return {
305
+ flavor: "perena",
306
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
307
+ baseTokenProgram: flavor.baseTokenProgram.toString(),
308
+ mintBase: flavor.mintBase.toString(),
309
+ emissions: flavor.emissions.map((e) => ({
310
+ exchangeRate: parseFloat(PreciseNumber.fromRaw(e.exchangeRate[0]).valueString),
311
+ mint: e.mint.toString(),
312
+ tokenProgram: e.tokenProgram.toString(),
313
+ })),
314
+ perenaSyState: {
315
+ selfAddress: flavor.perenaSyState.selfAddress.toString(),
316
+ syRate: flavor.perenaSyState.syRate,
317
+ mintBase: flavor.perenaSyState.lpMint.toString(),
318
+ tokenProgramBase: flavor.perenaSyState.tokenProgramBase.toString(),
319
+ underlyingExchangeRate: Number(flavor.perenaSyState.syRate),
320
+ account: {
321
+ perenaStablePool: flavor.perenaSyState.account.perenaStablePool.toString(),
322
+ mintSy: flavor.perenaSyState.account.mintSy.toString(),
323
+ tokenSyEscrow: flavor.perenaSyState.account.tokenSyEscrow.toString(),
324
+ minMintSize: flavor.perenaSyState.account.minMintSize.toString(),
325
+ minRedeemSize: flavor.perenaSyState.account.minRedeemSize.toString(),
326
+ maxSySupply: flavor.perenaSyState.account.maxSySupply.toString(),
327
+ emissions: flavor.perenaSyState.account.emissions.map((e) => ({
328
+ mint: e.mint.toString(),
329
+ tokenProgram: e.tokenProgram.toString(),
330
+ escrowAccount: e.escrowAccount.toString(),
331
+ index: parseFloat(PreciseNumber.fromRaw(e.index[0]).valueString),
332
+ lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
333
+ lastSeenTotalAccruedEmissions: e.lastSeenTotalAccruedEmissions.toString(),
334
+ totalClaimedEmissions: e.totalClaimedEmissions.toString(),
335
+ treasuryEmission: e.treasuryEmission.toString(),
336
+ })),
337
+ interfaceAccounts: flavor.perenaSyState.account.interfaceAccounts.map((a) => a.toString()),
338
+ },
339
+ },
340
+ }
341
+ }
342
+
343
+ export function serializeFlavorGeneric(flavor: FlavorGenericState): FlavorGenericStateJson {
344
+ return {
345
+ flavor: "generic",
346
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
347
+ baseTokenProgram: flavor.baseTokenProgram.toString(),
348
+ mintBase: flavor.mintBase.toString(),
349
+ emissions: flavor.emissions.map((e) => ({
350
+ exchangeRate: parseFloat(PreciseNumber.fromRaw(e.exchangeRate[0]).valueString),
351
+ mint: e.mint.toString(),
352
+ tokenProgram: e.tokenProgram.toString(),
353
+ })),
354
+ genericSyState: {
355
+ selfAddress: flavor.genericSyState.selfAddress.toString(),
356
+ syRate: flavor.genericSyState.syRate,
357
+ tokenProgramBase: flavor.genericSyState.tokenProgramBase.toString(),
358
+ account: {
359
+ yieldBearingMint: flavor.genericSyState.account.yieldBearingMint.toString(),
360
+ mintSy: flavor.genericSyState.account.mintSy.toString(),
361
+ tokenSyEscrow: flavor.genericSyState.account.tokenSyEscrow.toString(),
362
+ minMintSize: flavor.genericSyState.account.minMintSize.toString(),
363
+ minRedeemSize: flavor.genericSyState.account.minRedeemSize.toString(),
364
+ maxSySupply: flavor.genericSyState.account.maxSySupply.toString(),
365
+ hook: {
366
+ ...flavor.genericSyState.account.hook,
367
+ preMintHookDiscriminator: Buffer.from(flavor.genericSyState.account.hook.preMintHookDiscriminator),
368
+ postRedeemHookDiscriminator: Buffer.from(flavor.genericSyState.account.hook.postRedeemHookDiscriminator),
369
+ },
370
+ emissions: flavor.genericSyState.account.emissions.map((e) => ({
371
+ mint: e.mint.toString(),
372
+ tokenProgram: e.tokenProgram.toString(),
373
+ escrowAccount: e.escrowAccount.toString(),
374
+ index: parseFloat(PreciseNumber.fromRaw(e.index[0]).valueString),
375
+ lastSeenIndex: parseFloat(PreciseNumber.fromRaw(e.lastSeenIndex[0]).valueString),
376
+ lastSeenTotalAccruedEmissions: e.lastSeenTotalAccruedEmissions.toString(),
377
+ totalClaimedEmissions: e.totalClaimedEmissions.toString(),
378
+ treasuryEmission: e.treasuryEmission.toString(),
379
+ })),
380
+ interfaceAccounts: flavor.genericSyState.account.interfaceAccounts.map((a) => a.toString()),
381
+ interfaceType: flavor.genericSyState.account.interfaceType,
382
+ index: parseFloat(PreciseNumber.fromRaw(flavor.genericSyState.account.index[0]).valueString),
383
+ },
384
+ },
385
+ }
386
+ }
387
+
388
+ export function deserializeFlavorParena(flavor: FlavorPerenaStateJson): FlavorPerenaState {
389
+ return {
390
+ flavor: "perena",
391
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
392
+ baseTokenProgram: new web3.PublicKey(flavor.baseTokenProgram),
393
+ mintBase: new web3.PublicKey(flavor.mintBase),
394
+ perenaSyState: {
395
+ selfAddress: new web3.PublicKey(flavor.perenaSyState.selfAddress),
396
+ syRate: flavor.perenaSyState.syRate,
397
+ account: {
398
+ perenaStablePool: new web3.PublicKey(flavor.perenaSyState.account.perenaStablePool),
399
+ mintSy: new web3.PublicKey(flavor.perenaSyState.account.mintSy),
400
+ tokenSyEscrow: new web3.PublicKey(flavor.perenaSyState.account.tokenSyEscrow),
401
+ minMintSize: new BN(flavor.perenaSyState.account.minMintSize),
402
+ minRedeemSize: new BN(flavor.perenaSyState.account.minRedeemSize),
403
+ maxSySupply: new BN(flavor.perenaSyState.account.maxSySupply),
404
+ emissions: flavor.perenaSyState.account.emissions.map((emission) => ({
405
+ mint: new web3.PublicKey(emission.mint),
406
+ tokenProgram: new web3.PublicKey(emission.tokenProgram),
407
+ escrowAccount: new web3.PublicKey(emission.escrowAccount),
408
+ index: { 0: [new BN(emission.index)] },
409
+ lastSeenIndex: { 0: [new BN(emission.lastSeenIndex)] },
410
+ lastSeenTotalAccruedEmissions: new BN(emission.lastSeenTotalAccruedEmissions),
411
+ totalClaimedEmissions: new BN(emission.totalClaimedEmissions),
412
+ treasuryEmission: new BN(emission.treasuryEmission),
413
+ })),
414
+ interfaceAccounts: flavor.perenaSyState.account.interfaceAccounts.map((a) => new web3.PublicKey(a)),
415
+ },
416
+ lpMint: new web3.PublicKey(flavor.perenaSyState.mintBase),
417
+ tokenProgramBase: new web3.PublicKey(flavor.perenaSyState.tokenProgramBase),
418
+ },
419
+ emissions: flavor.emissions.map((e) => ({
420
+ exchangeRate: { 0: [new BN(PreciseNumber.fromRaw([new BN(e.exchangeRate)]).valueString)] },
421
+ mint: new web3.PublicKey(e.mint),
422
+ tokenProgram: new web3.PublicKey(e.tokenProgram),
423
+ })),
424
+ }
425
+ }
426
+
427
+ export function deserializeFlavorGeneric(flavor: FlavorGenericStateJson): FlavorGenericState {
428
+ return {
429
+ flavor: "generic",
430
+ currentSyExchangeRate: flavor.currentSyExchangeRate,
431
+ mintBase: new web3.PublicKey(flavor.mintBase),
432
+ baseTokenProgram: new web3.PublicKey(flavor.baseTokenProgram),
433
+ emissions: flavor.emissions.map((e) => ({
434
+ exchangeRate: { 0: [new BN(PreciseNumber.fromRaw([new BN(e.exchangeRate)]).valueString)] },
435
+ mint: new web3.PublicKey(e.mint),
436
+ tokenProgram: new web3.PublicKey(e.tokenProgram),
437
+ })),
438
+ genericSyState: {
439
+ selfAddress: new web3.PublicKey(flavor.genericSyState.selfAddress),
440
+ syRate: flavor.genericSyState.syRate,
441
+ tokenProgramBase: new web3.PublicKey(flavor.genericSyState.tokenProgramBase),
442
+ account: {
443
+ mintSy: new web3.PublicKey(flavor.genericSyState.account.mintSy),
444
+ yieldBearingMint: new web3.PublicKey(flavor.genericSyState.account.yieldBearingMint),
445
+ tokenSyEscrow: new web3.PublicKey(flavor.genericSyState.account.tokenSyEscrow),
446
+ interfaceAccounts: flavor.genericSyState.account.interfaceAccounts.map((a) => new web3.PublicKey(a)),
447
+ interfaceType: flavor.genericSyState.account.interfaceType,
448
+ maxSySupply: new BN(flavor.genericSyState.account.maxSySupply),
449
+ minMintSize: new BN(flavor.genericSyState.account.minMintSize),
450
+ minRedeemSize: new BN(flavor.genericSyState.account.minRedeemSize),
451
+ hook: {
452
+ enabled: flavor.genericSyState.account.hook.enabled,
453
+ interfaceEmissionsAccountsUntil: flavor.genericSyState.account.hook.interfaceEmissionsAccountsUntil,
454
+ preMintHookDiscriminator: Array.from(flavor.genericSyState.account.hook.preMintHookDiscriminator),
455
+ postRedeemHookDiscriminator: Array.from(flavor.genericSyState.account.hook.postRedeemHookDiscriminator),
456
+ programId: new web3.PublicKey(flavor.genericSyState.account.hook.programId),
457
+ },
458
+ emissions: flavor.genericSyState.account.emissions.map((e) => ({
459
+ mint: new web3.PublicKey(e.mint),
460
+ tokenProgram: new web3.PublicKey(e.tokenProgram),
461
+ escrowAccount: new web3.PublicKey(e.escrowAccount),
462
+ index: { 0: [new BN(e.index)] },
463
+ lastSeenIndex: { 0: [new BN(e.lastSeenIndex)] },
464
+ lastSeenTotalAccruedEmissions: new BN(e.lastSeenTotalAccruedEmissions),
465
+ totalClaimedEmissions: new BN(e.totalClaimedEmissions),
466
+ treasuryEmission: new BN(e.treasuryEmission),
467
+ })),
468
+ index: { 0: [new BN(flavor.genericSyState.account.index)] },
469
+ },
470
+ },
471
+ }
472
+ }
473
+
474
+ /** Synchronous version to create Marginfi Flavor from data */
475
+ export function makeFlavorMarginfiSync(data: FlavorMarginfiState): FlavorMarginfi {
476
+ const mfiSySdk = new MfiSySdk(data.mfiSyState)
477
+ return {
478
+ ...data,
479
+ flavor: "marginfi",
480
+ ixMintSy: (args) => mfiSySdk.ixMintSy(args),
481
+ ixRedeemSy: (args) => mfiSySdk.ixRedeemSy(args),
482
+ preIxs: async (args) => [],
483
+ postIxs: async (args) => [],
484
+ }
485
+ }
486
+
487
+ export function makeFlavorKaminoSync(data: FlavorKaminoState): FlavorKamino {
488
+ const klendSdk = new KlendSySdk(data.kaminoSyState)
489
+
490
+ return {
491
+ ...data,
492
+ flavor: "kamino",
493
+ ixMintSy: (args) => klendSdk.ixMintSy(args),
494
+ ixRedeemSy: (args) => klendSdk.ixRedeemSy(args),
495
+ preIxs: async (args) => klendSdk.ixRefreshObligationAndFarms(args.signer),
496
+ postIxs: async (args) => [klendSdk.ixRefreshObligationAndFarms(args.signer)[2]],
497
+ }
498
+ }
499
+
500
+ export function makeFlavorJitoRestakingSync(data: FlavorJitoRestakingState): FlavorJitoRestaking {
501
+ const jitoSdk = new JitoRestakingSySdk(data.jitoSyState)
502
+
503
+ return {
504
+ ...data,
505
+ flavor: "jitoRestaking",
506
+ ixMintSy: (args) => jitoSdk.ixMintSy(args),
507
+ ixRedeemSy: (args) => jitoSdk.ixRedeemSy(args),
508
+ preIxs: async (args) => [],
509
+ postIxs: async (args) => [],
510
+ }
511
+ }
512
+
513
+ export function makeFlavorPerenaSync(data: FlavorPerenaState): FlavorPerena {
514
+ const sySdk = new PerenaSySdk(data.perenaSyState)
515
+ return {
516
+ ...data,
517
+ flavor: "perena",
518
+ ixMintSy: (args) => sySdk.ixMintSy(args),
519
+ ixRedeemSy: (args) => sySdk.ixRedeemSy(args),
520
+ preIxs: async () => [],
521
+ postIxs: async () => [],
522
+ }
523
+ }
524
+
525
+ export function makeFlavorGenericSync(data: FlavorGenericState): FlavorGeneric {
526
+ const sySdk = new GenericSySdk(data.genericSyState)
527
+ return {
528
+ ...data,
529
+ flavor: "generic",
530
+ ixMintSy: (args) => sySdk.ixMintSy(args),
531
+ ixRedeemSy: (args) => sySdk.ixRedeemSy(args),
532
+ preIxs: async () => [],
533
+ postIxs: async () => [],
534
+ }
535
+ }
536
+
537
+ export function flavorFinder(env: Environment, syProgram: web3.PublicKey): FlavorDiscriminator {
538
+ if (env.marginfiSyProgramId.equals(syProgram)) {
539
+ return "marginfi"
540
+ } else if (env.kaminoSyProgramId.equals(syProgram)) {
541
+ return "kamino"
542
+ } else if (env.jitoRestakingSyProgramId.equals(syProgram)) {
543
+ return "jitoRestaking"
544
+ } else if (env.perenaSyProgramId.equals(syProgram)) {
545
+ return "perena"
546
+ } else if (env.genericSyProgramId.equals(syProgram)) {
547
+ return "generic"
548
+ } else {
549
+ throw new Error("Unknown flavor")
550
+ }
551
+ }
552
+
553
+ export async function makeFlavor(
554
+ fetcher: ExponentFetcher,
555
+ env: Environment,
556
+ /** The actual SY program linked to the market */
557
+ syProgram: web3.PublicKey,
558
+ cpiAccounts: CpiAccountsRaw,
559
+ ): Promise<Flavor> {
560
+ const fd = flavorFinder(env, syProgram)
561
+ if (fd === "marginfi") {
562
+ return makeMarginfiFlavor(fetcher, env.marginfiSyProgramId, cpiAccounts)
563
+ } else if (fd === "kamino") {
564
+ return makeKaminoFlavor(fetcher, env.kaminoSyProgramId, cpiAccounts)
565
+ } else if (fd === "jitoRestaking") {
566
+ return makeJitoRestakingFlavor(fetcher, env.jitoRestakingSyProgramId, cpiAccounts)
567
+ } else if (fd === "perena") {
568
+ return makePerenaFlavor(fetcher, env.perenaSyProgramId, cpiAccounts)
569
+ } else if (fd === "generic") {
570
+ return makeGenericFlavor(fetcher, env.genericSyProgramId, cpiAccounts)
571
+ }
572
+ {
573
+ throw new Error("Unknown flavor")
574
+ }
575
+ }
576
+
577
+ async function makeMarginfiFlavor(
578
+ fetcher: ExponentFetcher,
579
+ marginfiSyProgramId: web3.PublicKey,
580
+ cpiAccounts: CpiAccountsRaw,
581
+ ): Promise<FlavorMarginfi> {
582
+ /** Solana's convention is to use the Program ID for the account address if the account is null */
583
+ const isNone = (x: web3.PublicKey) => x.equals(marginfiSyProgramId)
584
+ const mapOptAccount = (x: web3.PublicKey) => (isNone(x) ? undefined : x)
585
+
586
+ // TODO - I do not like hard-coding these magic numbers
587
+ const bank = cpiAccounts.getSyState[2].pubkey
588
+ const emissionMint = cpiAccounts.getSyState[5].pubkey
589
+ const emissionTokenProgram = cpiAccounts.getSyState[11].pubkey
590
+
591
+ const mfiSySdk = await MfiSySdk.load({
592
+ cnx: fetcher.connection,
593
+ mfiBank: bank,
594
+ mfiSyProgramId: marginfiSyProgramId,
595
+ })
596
+ const currentSyExchangeRate = Number(mfiSySdk.state.syRate)
597
+ const emissions = mfiSySdk.account.emissions.map((e) => ({
598
+ exchangeRate: e.index,
599
+ mint: e.mint,
600
+ tokenProgram: e.tokenProgram,
601
+ }))
602
+ const ixMintSy = (args: MintSyArgs) => mfiSySdk.ixMintSy(args)
603
+ const ixRedeemSy = (args: RedeemSyArgs) => mfiSySdk.ixRedeemSy(args)
604
+ const mintBase = mfiSySdk.mintBase
605
+ const baseTokenProgram = mfiSySdk.tokenProgramBase
606
+
607
+ return {
608
+ flavor: "marginfi",
609
+ ixMintSy,
610
+ ixRedeemSy,
611
+ currentSyExchangeRate,
612
+ emissions,
613
+ bank,
614
+ mintBase,
615
+ baseTokenProgram,
616
+ mfiSyState: mfiSySdk.state,
617
+ emissionMint: mapOptAccount(emissionMint),
618
+ emissionTokenProgram: mapOptAccount(emissionTokenProgram),
619
+ preIxs: async (args) => [],
620
+ postIxs: async (args) => [],
621
+ }
622
+ }
623
+
624
+ async function makeKaminoFlavor(
625
+ fetcher: ExponentFetcher,
626
+ kaminoSyProgramId: web3.PublicKey,
627
+ cpiAccounts: CpiAccountsRaw,
628
+ ): Promise<FlavorKamino> {
629
+ const isNone = (x: web3.PublicKey) => x.equals(kaminoSyProgramId)
630
+ const mapOptAccount = (x: web3.PublicKey) => (isNone(x) ? undefined : x)
631
+
632
+ // TODO - I do not like hard-coding these magic numbers
633
+ const reserve = cpiAccounts.getSyState[0].pubkey
634
+ const reserveAcct = await fetchKaminoReserve(reserve, fetcher.connection)
635
+
636
+ const mintBase = reserveAcct.baseMint
637
+
638
+ // TODO - don't do this
639
+ const baseTokenProgram = await fetcher.connection.getAccountInfo(mintBase).then((a) => a.owner)
640
+
641
+ const meta = getMeta(reserve, kaminoSyProgramId)
642
+
643
+ const syMeta = await fetcher.fetchKaminoSyMeta(meta)
644
+
645
+ const klendSdk = await KlendSySdk.load({
646
+ cnx: fetcher.connection,
647
+ klendMarketId: reserveAcct.lendingMarket,
648
+ klendReserve: reserve,
649
+ klendSyProgramId: kaminoSyProgramId,
650
+ klendProgramId: KAMINO_LEND_PROGRAM_ID,
651
+ })
652
+
653
+ return {
654
+ flavor: "kamino",
655
+ currentSyExchangeRate: reserveAcct.assetShareValue.toNumber(),
656
+ kaminoSyState: klendSdk.state,
657
+ emissions: syMeta.emissions.map((e) => ({
658
+ exchangeRate: e.lastSeenIndex,
659
+ mint: e.mint,
660
+ tokenProgram: e.tokenProgram,
661
+ })),
662
+ mintBase,
663
+ baseTokenProgram,
664
+ ixMintSy: (args) => {
665
+ return klendSdk.ixMintSy(args)
666
+ },
667
+ ixRedeemSy: (args) => {
668
+ return klendSdk.ixRedeemSy(args)
669
+ },
670
+ preIxs: async (args) => klendSdk.ixRefreshObligationAndFarms(args.signer),
671
+ postIxs: async (args) => [klendSdk.ixRefreshObligationAndFarms(args.signer)[2]],
672
+ }
673
+ }
674
+
675
+ async function makeJitoRestakingFlavor(
676
+ fetcher: ExponentFetcher,
677
+ jitoRestakingSyProgramId: web3.PublicKey,
678
+ cpiAccounts: CpiAccountsRaw,
679
+ ): Promise<FlavorJitoRestaking> {
680
+ // TODO - I do not like hard-coding these magic numbers
681
+ const jitoVault = cpiAccounts.getSyState[1].pubkey
682
+ // const recentBlockhash = await fetcher.connection.getLatestBlockhash().then((b) => b.blockhash)
683
+
684
+ const jitoSdk = await JitoRestakingSySdk.load({
685
+ cnx: fetcher.connection,
686
+ jitoVault,
687
+ jitoRestakingSyProgramId,
688
+ })
689
+
690
+ return {
691
+ flavor: "jitoRestaking",
692
+ currentSyExchangeRate: Number(jitoSdk.state.syRate),
693
+ jitoSyState: jitoSdk.state,
694
+ emissions: jitoSdk.emissions.map((e) => ({
695
+ exchangeRate: e.index,
696
+ mint: e.mint,
697
+ tokenProgram: e.tokenProgram,
698
+ })),
699
+ mintBase: jitoSdk.mintBase,
700
+ baseTokenProgram: jitoSdk.tokenProgramBase,
701
+ ixMintSy: (args) => jitoSdk.ixMintSy(args),
702
+ ixRedeemSy: (args) => jitoSdk.ixRedeemSy(args),
703
+ preIxs: async () => [],
704
+ postIxs: async () => [],
705
+ }
706
+ }
707
+
708
+ async function makePerenaFlavor(
709
+ fetcher: ExponentFetcher,
710
+ perenaSyProgramId: web3.PublicKey,
711
+ cpiAccounts: CpiAccountsRaw,
712
+ ): Promise<FlavorPerena> {
713
+ const perenaStablePool = cpiAccounts.getSyState[1].pubkey
714
+
715
+ const sySdk = await PerenaSySdk.load({
716
+ cnx: fetcher.connection,
717
+ perenaStablePool,
718
+ perenaSyProgramId,
719
+ })
720
+
721
+ return {
722
+ flavor: "perena",
723
+ currentSyExchangeRate: Number(sySdk.state.syRate),
724
+ mintBase: sySdk.mintBase,
725
+ baseTokenProgram: sySdk.tokenProgramBase,
726
+ ixMintSy: (args) => sySdk.ixMintSy(args),
727
+ ixRedeemSy: (args) => sySdk.ixRedeemSy(args),
728
+ preIxs: async () => [],
729
+ postIxs: async () => [],
730
+ perenaSyState: sySdk.state,
731
+ emissions: sySdk.emissions.map((e) => ({
732
+ exchangeRate: e.index,
733
+ mint: e.mint,
734
+ tokenProgram: e.tokenProgram,
735
+ })),
736
+ }
737
+ }
738
+
739
+ async function makeGenericFlavor(
740
+ fetcher: ExponentFetcher,
741
+ genericStandardProgramId: web3.PublicKey,
742
+ cpiAccounts: CpiAccountsRaw,
743
+ ): Promise<FlavorGeneric> {
744
+ const genericSyMeta = cpiAccounts.depositSy[1].pubkey
745
+
746
+ const sySdk = await GenericSySdk.loadFromSyMeta({
747
+ cnx: fetcher.connection,
748
+ genericStandardProgramId,
749
+ syMetaAddress: genericSyMeta,
750
+ })
751
+
752
+ let preIxs = []
753
+ let postIxs = []
754
+
755
+ const isFragmetric = "fragmetric" in sySdk.state.account.interfaceType
756
+
757
+ return {
758
+ flavor: "generic",
759
+ currentSyExchangeRate: sySdk.state.syRate,
760
+ mintBase: sySdk.state.account.yieldBearingMint,
761
+ baseTokenProgram: sySdk.tokenProgramBase,
762
+ ixMintSy: (args) => sySdk.ixMintSy(args),
763
+ ixRedeemSy: (args) => sySdk.ixRedeemSy(args),
764
+ preIxs: async () => preIxs,
765
+ postIxs: async () => postIxs,
766
+ genericSyState: sySdk.state,
767
+ emissions: sySdk.emissions.map((e) => ({
768
+ exchangeRate: e.index,
769
+ mint: e.mint,
770
+ tokenProgram: e.tokenProgram,
771
+ })),
772
+ }
773
+ }