@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
@@ -0,0 +1,313 @@
1
+ import { AnchorProvider, BN, Program, web3 } from "@coral-xyz/anchor"
2
+ import { ExponentCore, IDL } from "@exponent-labs/exponent-idl"
3
+ import { Environment } from "./environment"
4
+ import { ExponentFetcher, YieldTokenTracker, YtPosition as YtPositionState } from "@exponent-labs/exponent-fetcher"
5
+ import { Vault } from "./vault"
6
+ import { getAssociatedTokenAddressSync, TOKEN_PROGRAM_ID } from "@solana/spl-token"
7
+ import { ClaimAmount } from "@exponent-labs/exponent-ix"
8
+ import { InstructionAccounts } from "./utils"
9
+ import { ExponentPDA } from "@exponent-labs/exponent-pda"
10
+ import { MyWallet } from "./market"
11
+ import { VaultJson } from "@exponent-labs/exponent-types"
12
+ import { PreciseNumber } from "@exponent-labs/precise-number"
13
+
14
+ export class YtPosition {
15
+ public coreProgram: Program<ExponentCore>
16
+ constructor(
17
+ public env: Environment,
18
+ public connection: web3.Connection,
19
+ public selfAddress: web3.PublicKey,
20
+ public state: YtPositionState,
21
+ public vault: Vault,
22
+ ) {
23
+ const mockWallet = new MyWallet(web3.Keypair.generate())
24
+ this.coreProgram = new Program(IDL as ExponentCore, new AnchorProvider(connection, mockWallet))
25
+ }
26
+
27
+ /** Loads the YT position by address, and loads Vault, too
28
+ * DEPRECATED - use loadByOwner instead - loading the vault is expensive
29
+ */
30
+ static async load(env: Environment, connection: web3.Connection, address: web3.PublicKey) {
31
+ const fetcher = new ExponentFetcher({ connection })
32
+ const x = await fetcher.fetchYtPosition(address)
33
+ const vault = await Vault.load(env, connection, x.vault)
34
+ return new YtPosition(env, connection, address, x, vault)
35
+ }
36
+
37
+ /** Loads the YT position by owner, but require a loaded Vault */
38
+ static async loadByOwner(env: Environment, connection: web3.Connection, owner: web3.PublicKey, vault: Vault) {
39
+ const pda = new ExponentPDA(env.coreProgramId)
40
+ const address = pda.yieldPosition({ vault: vault.selfAddress, owner })
41
+ const fetcher = new ExponentFetcher({ connection })
42
+ const x = await fetcher.fetchYtPosition(address)
43
+ return new YtPosition(env, connection, address, x, vault)
44
+ }
45
+
46
+ async reload(conn = this.connection) {
47
+ const x = await YtPosition.load(this.env, conn, this.selfAddress)
48
+ this.state = x.state
49
+ return x
50
+ }
51
+
52
+ toJson(): YtPositionJson {
53
+ return ytPositionToJson(this)
54
+ }
55
+
56
+ get ytBalance() {
57
+ return this.state.ytBalance
58
+ }
59
+
60
+ get owner() {
61
+ return this.state.owner
62
+ }
63
+
64
+ get stagedInterest(): bigint {
65
+ return this.state.interest.staged
66
+ }
67
+
68
+ /**
69
+ * Returns the claimable interest in base amount
70
+ * @param currentIndex - The current SY exchange rate for the vault's SY token
71
+ * @returns The claimable interest in raw base token units
72
+ */
73
+ getClaimableInterest(currentIndex: number): number {
74
+ const interestDelta = 1 / this.state.interest.lastSeenIndex - 1 / currentIndex
75
+ let toCollectSy = Math.floor(
76
+ Number(this.state.ytBalance.toString()) * interestDelta + Number(this.state.interest.staged),
77
+ )
78
+
79
+ // Ensure toCollectSy is not negative
80
+ toCollectSy = Math.max(0, toCollectSy)
81
+
82
+ const feeSy = Math.floor((toCollectSy * this.vault.state.interestBpsFee + 9999) / 10000)
83
+ const userSy = Math.max(0, toCollectSy - feeSy)
84
+ let baseAmount = Math.floor(userSy * currentIndex)
85
+
86
+ // Ensure final amount is non-negative
87
+ return Math.max(0, baseAmount > 0 ? baseAmount - 1 : baseAmount)
88
+ }
89
+
90
+ getClaimableEmissions() {
91
+ // Calculate total SY balance (staged + converted YT balance)
92
+ const totalSyBalance =
93
+ Number(this.state.interest.staged) + Number(this.state.ytBalance) / this.vault.currentSyExchangeRate
94
+
95
+ return this.vault.syEmissions.map((e, index) => {
96
+ // Use initial index if user doesn't have a position yet (lastSeenIndex is 0)
97
+ const lastSeenIndex = this.state.emissions[index]?.lastSeenIndex ?? 0
98
+
99
+ const earnedEmission =
100
+ totalSyBalance * (Number(PreciseNumber.fromRaw(e.index[0]).valueString) - Number(lastSeenIndex))
101
+
102
+ return {
103
+ mint: e.mint,
104
+ amount: Math.floor(earnedEmission) + Number(this.state.emissions[index]?.staged ?? 0),
105
+ }
106
+ })
107
+ }
108
+
109
+ /** Instruction for depositing YT into the vault */
110
+ ixDepositYt({ amount, ytSrc }: { amount: bigint; ytSrc?: web3.PublicKey }) {
111
+ const { mainAccounts, remainingAccounts } = this.depositYtAccounts({ ytSrc })
112
+ return this.coreProgram.methods
113
+ .depositYt(new BN(amount.toString()))
114
+ .accountsStrict(mainAccounts)
115
+ .remainingAccounts(remainingAccounts)
116
+ .instruction()
117
+ }
118
+
119
+ /** Instruction for withdrawing YT from the vault */
120
+ ixWithdrawYt({ amount, ytDst }: { amount: bigint; ytDst?: web3.PublicKey }) {
121
+ const { mainAccounts, remainingAccounts } = this.withdrawYtAccounts({ ytDst })
122
+ return this.coreProgram.methods
123
+ .withdrawYt(new BN(amount.toString()))
124
+ .accountsStrict(mainAccounts)
125
+ .remainingAccounts(remainingAccounts)
126
+ .instruction()
127
+ }
128
+
129
+ ixStageYield({ payer }: { payer: web3.PublicKey }) {
130
+ return this.coreProgram.methods
131
+ .stageYtYield()
132
+ .accountsStrict({
133
+ addressLookupTable: this.vault.addressLookupTable,
134
+ vault: this.vault.selfAddress,
135
+ payer,
136
+ syProgram: this.vault.state.syProgram,
137
+ yieldPosition: this.vault.state.yieldPositonAddress,
138
+ systemProgram: web3.SystemProgram.programId,
139
+ userYieldPosition: this.selfAddress,
140
+ eventAuthority: this.vault.eventAuthority,
141
+ program: this.coreProgram.programId,
142
+ })
143
+ .remainingAccounts(this.vault.cpiAccounts.getSyState)
144
+ .instruction()
145
+ }
146
+
147
+ ixCollectInterest({ signer, syDst, amount }: { signer: web3.PublicKey; syDst?: web3.PublicKey; amount?: bigint }) {
148
+ const tokenSyDst = syDst || getAssociatedTokenAddressSync(this.vault.mintSy, signer, true, TOKEN_PROGRAM_ID)
149
+ const claimAmount: ClaimAmount = amount !== undefined ? { some: { 0: new BN(amount.toString()) } } : { all: {} }
150
+ return this.coreProgram.methods
151
+ .collectInterest(claimAmount)
152
+ .accountsStrict({
153
+ addressLookupTable: this.vault.addressLookupTable,
154
+ authority: this.vault.authority,
155
+ vault: this.vault.selfAddress,
156
+ syProgram: this.vault.state.syProgram,
157
+ tokenProgram: TOKEN_PROGRAM_ID,
158
+ yieldPosition: this.selfAddress,
159
+ owner: signer,
160
+ escrowSy: this.vault.state.escrowSy,
161
+ treasurySyTokenAccount: this.vault.state.treasurySyTokenAccount,
162
+ tokenSyDst,
163
+ eventAuthority: this.vault.eventAuthority,
164
+ program: this.coreProgram.programId,
165
+ })
166
+ .remainingAccounts(this.vault.cpiAccounts.withdrawSy)
167
+ .instruction()
168
+ }
169
+
170
+ ixCollectEmission({
171
+ owner,
172
+ emissionIndex,
173
+ emissionDst,
174
+ amount,
175
+ }: {
176
+ owner: web3.PublicKey
177
+ emissionIndex: number
178
+ emissionDst?: web3.PublicKey
179
+ amount?: bigint
180
+ }) {
181
+ const emission = this.vault.state.emissions[emissionIndex]
182
+ const emissionSy = this.vault.flavor.emissions[emissionIndex]
183
+ emissionDst = emissionDst || getAssociatedTokenAddressSync(emissionSy.mint, owner, true, emissionSy.tokenProgram)
184
+ const claimAmount: ClaimAmount = amount !== undefined ? { some: { 0: new BN(amount.toString()) } } : { all: {} }
185
+
186
+ return this.coreProgram.methods
187
+ .collectEmission(emissionIndex, claimAmount)
188
+ .accountsStrict({
189
+ addressLookupTable: this.vault.addressLookupTable,
190
+ authority: this.vault.authority,
191
+ emissionEscrow: emission.tokenAccount,
192
+ vault: this.selfAddress,
193
+ syProgram: this.vault.state.syProgram,
194
+ owner,
195
+ treasuryEmissionTokenAccount: emission.treasuryTokenAccount,
196
+ emissionDst,
197
+ position: this.selfAddress,
198
+ tokenProgram: this.vault.flavor.emissions[emissionIndex].tokenProgram,
199
+ eventAuthority: this.vault.eventAuthority,
200
+ program: this.coreProgram.programId,
201
+ })
202
+ .remainingAccounts(this.vault.cpiAccounts.claimEmission[emissionIndex])
203
+ .instruction()
204
+ }
205
+
206
+ depositYtAccounts({ ytSrc }: { ytSrc?: web3.PublicKey }): InstructionAccounts<DepositYtAccounts> {
207
+ ytSrc = ytSrc || getAssociatedTokenAddressSync(this.vault.mintYt, this.owner, true, TOKEN_PROGRAM_ID)
208
+ return {
209
+ mainAccounts: {
210
+ depositor: this.owner,
211
+ ytSrc,
212
+ vault: this.vault.selfAddress,
213
+ userYieldPosition: this.selfAddress,
214
+ escrowYt: this.vault.state.escrowYt,
215
+ tokenProgram: TOKEN_PROGRAM_ID,
216
+ syProgram: this.vault.state.syProgram,
217
+ addressLookupTable: this.vault.addressLookupTable,
218
+ yieldPosition: this.vault.state.yieldPositonAddress,
219
+ systemProgram: web3.SystemProgram.programId,
220
+ eventAuthority: this.vault.eventAuthority,
221
+ program: this.coreProgram.programId,
222
+ },
223
+ remainingAccounts: this.vault.cpiAccounts.getSyState,
224
+ }
225
+ }
226
+
227
+ withdrawYtAccounts({ ytDst }: { ytDst?: web3.PublicKey }): InstructionAccounts<WithdrawYtAccounts> {
228
+ ytDst = ytDst || getAssociatedTokenAddressSync(this.vault.mintYt, this.owner, true, TOKEN_PROGRAM_ID)
229
+ return {
230
+ mainAccounts: {
231
+ owner: this.owner,
232
+ vault: this.vault.selfAddress,
233
+ userYieldPosition: this.selfAddress,
234
+ ytDst,
235
+ escrowYt: this.vault.state.escrowYt,
236
+ tokenProgram: TOKEN_PROGRAM_ID,
237
+ authority: this.vault.authority,
238
+ syProgram: this.vault.state.syProgram,
239
+ addressLookupTable: this.vault.addressLookupTable,
240
+ yieldPosition: this.vault.state.yieldPositonAddress,
241
+ systemProgram: web3.SystemProgram.programId,
242
+ eventAuthority: this.vault.eventAuthority,
243
+ program: this.coreProgram.programId,
244
+ },
245
+ remainingAccounts: this.vault.cpiAccounts.getSyState,
246
+ }
247
+ }
248
+ }
249
+
250
+ export type YtPositionJson = {
251
+ owner: string
252
+ ytBalance: string
253
+ interest: YieldTokenTrackerJson
254
+ claimableInterest: number
255
+ emissions: YieldTokenTrackerJson[]
256
+ vault: VaultJson
257
+ }
258
+
259
+ export type YieldTokenTrackerJson = {
260
+ lastSeenIndex: number
261
+ staged: string
262
+ }
263
+
264
+ function ytPositionToJson(x: YtPosition): YtPositionJson {
265
+ return {
266
+ owner: x.owner.toBase58(),
267
+ ytBalance: x.ytBalance.toString(),
268
+ interest: yieldTokenTrackerToJson(x.state.interest),
269
+ emissions: x.state.emissions.map(yieldTokenTrackerToJson),
270
+ claimableInterest: x.getClaimableInterest(x.vault.currentSyExchangeRate),
271
+ vault: x.vault.toJson(),
272
+ }
273
+ }
274
+
275
+ function yieldTokenTrackerToJson(x: YieldTokenTracker): YieldTokenTrackerJson {
276
+ return {
277
+ lastSeenIndex: x.lastSeenIndex,
278
+ staged: x.staged.toString(),
279
+ }
280
+ }
281
+
282
+ type DepositYtAccounts = {
283
+ [K in
284
+ | "depositor"
285
+ | "vault"
286
+ | "userYieldPosition"
287
+ | "ytSrc"
288
+ | "escrowYt"
289
+ | "tokenProgram"
290
+ | "syProgram"
291
+ | "addressLookupTable"
292
+ | "yieldPosition"
293
+ | "systemProgram"
294
+ | "eventAuthority"
295
+ | "program"]: web3.PublicKey
296
+ }
297
+
298
+ type WithdrawYtAccounts = {
299
+ [K in
300
+ | "owner"
301
+ | "vault"
302
+ | "userYieldPosition"
303
+ | "ytDst"
304
+ | "escrowYt"
305
+ | "tokenProgram"
306
+ | "authority"
307
+ | "syProgram"
308
+ | "addressLookupTable"
309
+ | "yieldPosition"
310
+ | "systemProgram"
311
+ | "eventAuthority"
312
+ | "program"]: web3.PublicKey
313
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "compilerOptions": {
3
+ "rootDir": "src",
4
+ "sourceMap": true,
5
+ "incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */,
6
+ "composite": true /* Enable constraints that allow a TypeScript project to be used with project references. */,
7
+ "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */,
8
+ "module": "CommonJS" /* Specify what module code is generated. */,
9
+ "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */,
10
+ "outDir": "./build" /* Specify an output folder for all emitted files. */,
11
+ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */,
12
+ "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */,
13
+ "skipLibCheck": true /* Skip type checking all .d.ts files. */,
14
+ "types": ["jest"]
15
+ },
16
+
17
+ "include": ["src"],
18
+ "exclude": ["build"],
19
+ "references": [
20
+ { "path": "../exponent-idl" },
21
+ { "path": "../exponent-fetcher" },
22
+ { "path": "../marginfi-sy-pda" },
23
+ { "path": "../market-math" },
24
+ { "path": "../marginfi-util" },
25
+ { "path": "../exponent-pda" },
26
+ { "path": "../marginfi-sy-sdk" },
27
+ { "path": "../kamino-sy-sdk" },
28
+ { "path": "../exponent-types" },
29
+ { "path": "../jito-restaking-sy-sdk" },
30
+ { "path": "../jito-restaking-sy-idl" },
31
+ { "path": "../perena-sy-sdk" },
32
+ { "path": "../perena-sy-idl" },
33
+ { "path": "../perena-sy-pda" },
34
+ { "path": "../generic-sy-sdk" },
35
+ { "path": "../generic-sy-idl" },
36
+ { "path": "../generic-sy-pda" }
37
+ ]
38
+ }