@exponent-labs/exponent-sdk 0.1.7 → 0.1.8

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 (92) hide show
  1. package/build/EventDecoderV2.d.ts +31 -0
  2. package/build/EventDecoderV2.js +76 -0
  3. package/build/EventDecoderV2.js.map +1 -0
  4. package/build/addressLookupTableUtil.d.ts +17 -1
  5. package/build/addressLookupTableUtil.js +35 -1
  6. package/build/addressLookupTableUtil.js.map +1 -1
  7. package/build/clmm/events.d.ts +10 -0
  8. package/build/clmm/events.js +10 -0
  9. package/build/clmm/events.js.map +1 -0
  10. package/build/clmm/index.d.ts +1 -0
  11. package/build/clmm/index.js +18 -0
  12. package/build/clmm/index.js.map +1 -0
  13. package/build/events.d.ts +200 -9
  14. package/build/events.js +73 -24
  15. package/build/events.js.map +1 -1
  16. package/build/eventsV2.d.ts +7 -0
  17. package/build/eventsV2.js +10 -0
  18. package/build/eventsV2.js.map +1 -0
  19. package/build/flavors.d.ts +2 -0
  20. package/build/flavors.js +81 -27
  21. package/build/flavors.js.map +1 -1
  22. package/build/index.d.ts +6 -0
  23. package/build/index.js +14 -4
  24. package/build/index.js.map +1 -1
  25. package/build/lpPosition.js +4 -1
  26. package/build/lpPosition.js.map +1 -1
  27. package/build/market.d.ts +14 -2
  28. package/build/market.js +70 -29
  29. package/build/market.js.map +1 -1
  30. package/build/marketThree.d.ts +664 -0
  31. package/build/marketThree.js +1415 -0
  32. package/build/marketThree.js.map +1 -0
  33. package/build/marketThree.test.d.ts +1 -0
  34. package/build/marketThree.test.js +166 -0
  35. package/build/marketThree.test.js.map +1 -0
  36. package/build/orderbook/events.d.ts +7 -0
  37. package/build/orderbook/events.js +10 -0
  38. package/build/orderbook/events.js.map +1 -0
  39. package/build/orderbook/index.d.ts +4 -0
  40. package/build/orderbook/index.js +41 -0
  41. package/build/orderbook/index.js.map +1 -0
  42. package/build/orderbook/math.d.ts +26 -0
  43. package/build/orderbook/math.js +111 -0
  44. package/build/orderbook/math.js.map +1 -0
  45. package/build/orderbook/orderbook.d.ts +175 -0
  46. package/build/orderbook/orderbook.js +756 -0
  47. package/build/orderbook/orderbook.js.map +1 -0
  48. package/build/orderbook/types.d.ts +49 -0
  49. package/build/orderbook/types.js +27 -0
  50. package/build/orderbook/types.js.map +1 -0
  51. package/build/orderbook/utils.d.ts +18 -0
  52. package/build/orderbook/utils.js +74 -0
  53. package/build/orderbook/utils.js.map +1 -0
  54. package/build/router.d.ts +92 -0
  55. package/build/router.js +214 -0
  56. package/build/router.js.map +1 -0
  57. package/build/syPosition.js +6 -0
  58. package/build/syPosition.js.map +1 -1
  59. package/build/utils/index.d.ts +3 -2
  60. package/build/utils/index.js +22 -1
  61. package/build/utils/index.js.map +1 -1
  62. package/build/vault.d.ts +3 -1
  63. package/build/vault.js +98 -62
  64. package/build/vault.js.map +1 -1
  65. package/build/ytPosition.d.ts +2 -0
  66. package/build/ytPosition.js +18 -5
  67. package/build/ytPosition.js.map +1 -1
  68. package/package.json +28 -23
  69. package/src/EventDecoderV2.ts +96 -0
  70. package/src/addressLookupTableUtil.ts +42 -1
  71. package/src/clmm/events.ts +17 -0
  72. package/src/clmm/index.ts +1 -0
  73. package/src/events.ts +280 -27
  74. package/src/eventsV2.ts +13 -0
  75. package/src/flavors.ts +97 -27
  76. package/src/index.ts +6 -0
  77. package/src/lpPosition.ts +5 -2
  78. package/src/market.ts +100 -31
  79. package/src/marketThree.test.ts +208 -0
  80. package/src/marketThree.ts +2430 -0
  81. package/src/orderbook/events.ts +13 -0
  82. package/src/orderbook/index.ts +12 -0
  83. package/src/orderbook/math.ts +122 -0
  84. package/src/orderbook/orderbook.ts +1153 -0
  85. package/src/orderbook/types.ts +45 -0
  86. package/src/orderbook/utils.ts +74 -0
  87. package/src/router.ts +360 -0
  88. package/src/syPosition.ts +4 -0
  89. package/src/utils/index.ts +27 -2
  90. package/src/vault.ts +100 -62
  91. package/src/ytPosition.ts +28 -7
  92. package/tsconfig.json +4 -1
@@ -0,0 +1,1153 @@
1
+ import { AnchorProvider, BN, Program, web3 } from "@coral-xyz/anchor"
2
+ import { TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync } from "@solana/spl-token"
3
+
4
+ import { EXPONENT_ADMIN_PROGRAM_ID, ExponentAdminPda } from "@exponent-labs/exponent-admin-pda"
5
+ import { ExponentFetcher } from "@exponent-labs/exponent-fetcher"
6
+ import { IDL as EXPONENT_CORE_IDL, ExponentCore } from "@exponent-labs/exponent-idl"
7
+ import { IDL as EXPONENT_ORDERBOOK_IDL, ExponentOrderbook } from "@exponent-labs/exponent-orderbook-idl"
8
+ import { ExponentOrderbookPDA, ExponentPDA } from "@exponent-labs/exponent-pda"
9
+ import { AccountInfo, ConfigurationOptions, OrderbookState } from "@exponent-labs/exponent-types"
10
+ import { ClaimAmount } from "@exponent-labs/marginfi-sy-sdk"
11
+
12
+ import {
13
+ fetchAddressLookupTable,
14
+ makeCoreCpiAccountMetaLists,
15
+ makeCpiAccountMetaLists,
16
+ } from "../addressLookupTableUtil"
17
+ import { Environment } from "../environment"
18
+ import {
19
+ makeFlavorGenericSync,
20
+ makeFlavorJitoRestakingSync,
21
+ makeFlavorKaminoSync,
22
+ makeFlavorMarginfiSync,
23
+ makeFlavorPerenaSync,
24
+ } from "../flavors"
25
+ import { MyWallet } from "../market"
26
+ import { InstructionAccounts, emitEventAuthority, uniqueRemainingAccounts } from "../utils"
27
+ import { CollectEmissionAccounts, Vault } from "../vault"
28
+ import {
29
+ MAX_FILLED_OFFERS,
30
+ PRICE_BASE_POINTS,
31
+ calcOutAmountOnCounterOfferFilling,
32
+ calcRemainingAmountOnCounterOfferFilling,
33
+ getOfferAmountToGet,
34
+ getOfferAmountToGetNoVirtual,
35
+ getOfferSize,
36
+ roundPriceApy,
37
+ } from "./math"
38
+ import { Offer, OfferOptionsAnchor, OfferType, OfferTypeAnchor, OrderbookLoadOptions, QuoteDirection } from "./types"
39
+ import {
40
+ getOfferDirectionFromQuoteDirection,
41
+ getOfferType,
42
+ getOfferTypeFromTradeDirection,
43
+ isQuoteInputTokenBase,
44
+ isQuoteOutputTokenBase,
45
+ priceToImpliedRate,
46
+ } from "./utils"
47
+ import { feeRate } from "@exponent-labs/market-math"
48
+
49
+ export class Orderbook {
50
+ private orderbookProgram: Program<ExponentOrderbook>
51
+ private coreProgram: Program<ExponentCore>
52
+
53
+ constructor(
54
+ public state: OrderbookState,
55
+ public selfAddress: web3.PublicKey,
56
+ public env: Environment,
57
+ public connection: web3.Connection,
58
+ public vaulLookupTable: web3.PublicKey,
59
+ ) {
60
+ this.orderbookProgram = new Program(
61
+ EXPONENT_ORDERBOOK_IDL as ExponentOrderbook,
62
+ new AnchorProvider(connection, new MyWallet(web3.Keypair.generate())),
63
+ )
64
+ this.coreProgram = new Program(
65
+ EXPONENT_CORE_IDL as ExponentCore,
66
+ new AnchorProvider(connection, new MyWallet(web3.Keypair.generate())),
67
+ )
68
+ }
69
+
70
+ static async load(
71
+ env: Environment,
72
+ connection: web3.Connection,
73
+ address: web3.PublicKey,
74
+ options: OrderbookLoadOptions = {},
75
+ vault?: Vault,
76
+ ) {
77
+ const fetcher = new ExponentFetcher({ connection })
78
+ const orderbook = await fetcher.fetchOrderbook(address)
79
+ const pda = new ExponentOrderbookPDA()
80
+ const orderbookCpiAccounts = await fetcher.fetchOrderbookCpiAccounts(
81
+ pda.orderbookCpiAccounts({ orderbook: address }),
82
+ )
83
+ const altOrderbook = await fetchAddressLookupTable(connection, orderbook.addressLookupTable)
84
+ const cpiAccounts = makeCpiAccountMetaLists(altOrderbook, orderbookCpiAccounts.syCpiAccounts)
85
+ const cpiCoreAccounts = makeCoreCpiAccountMetaLists(altOrderbook, orderbookCpiAccounts.exponentCoreCpiAccounts)
86
+ const loadedVault = vault || (await Vault.load(env, connection, orderbook.vault))
87
+ const flavor = (() => {
88
+ switch (loadedVault.flavor.flavor) {
89
+ case "marginfi":
90
+ return makeFlavorMarginfiSync(loadedVault.flavor)
91
+ case "kamino":
92
+ return makeFlavorKaminoSync(loadedVault.flavor)
93
+ case "jitoRestaking":
94
+ return makeFlavorJitoRestakingSync(loadedVault.flavor)
95
+ case "perena":
96
+ return makeFlavorPerenaSync(loadedVault.flavor)
97
+ case "generic":
98
+ return makeFlavorGenericSync(loadedVault.flavor, options.syConfig)
99
+ default:
100
+ throw new Error(`Unknown flavor: ${loadedVault.flavor}`)
101
+ }
102
+ })()
103
+
104
+ const state: OrderbookState = {
105
+ ...orderbook,
106
+ syCpiAccounts: cpiAccounts,
107
+ exponentCoreCpiAccounts: cpiCoreAccounts,
108
+ flavor,
109
+ }
110
+
111
+ return new Orderbook(state, address, env, connection, loadedVault.addressLookupTable)
112
+ }
113
+
114
+ async reload(conn: web3.Connection = this.connection) {
115
+ const v = await Orderbook.load(this.env, conn, this.selfAddress)
116
+ this.state = v.state
117
+ return v
118
+ }
119
+
120
+ get corePda() {
121
+ return new ExponentPDA()
122
+ }
123
+
124
+ get pda() {
125
+ return new ExponentOrderbookPDA(this.orderbookProgram.programId)
126
+ }
127
+
128
+ get adminPda() {
129
+ return new ExponentAdminPda(EXPONENT_ADMIN_PROGRAM_ID)
130
+ }
131
+
132
+ get eventAuthority() {
133
+ return emitEventAuthority(this.orderbookProgram.programId)
134
+ }
135
+
136
+ get coreEventAuthority() {
137
+ return emitEventAuthority(this.state.exponentCoreProgram)
138
+ }
139
+
140
+ get mintYt() {
141
+ return this.corePda.mintYt({ vault: this.state.vault })
142
+ }
143
+
144
+ get mintPt() {
145
+ return this.corePda.mintPt({ vault: this.state.vault })
146
+ }
147
+
148
+ get syCpiAccounts() {
149
+ return this.state.syCpiAccounts
150
+ }
151
+
152
+ get exponentCoreCpiAccounts() {
153
+ return this.state.exponentCoreCpiAccounts
154
+ }
155
+
156
+ get flavor() {
157
+ return this.state.flavor
158
+ }
159
+
160
+ get secondsRemaining() {
161
+ return Math.max(this.state.financials.expirationTs - Math.floor(Date.now() / 1000), 0)
162
+ }
163
+
164
+ /** Fee rate is 1 + the actual fee rate - is is for convenience with calculations
165
+ * A feeRate of 1.001 means the fee is 0.1%
166
+ * A feeRate of 1 means there is no fee
167
+ */
168
+ get makerFeeRate() {
169
+ if (this.secondsRemaining == 0) {
170
+ return 1
171
+ }
172
+
173
+ return feeRate({
174
+ lnFeeRateRoot: this.state.configurationOptions.lnMakerFeeRate,
175
+ secondsRemaining: this.secondsRemaining,
176
+ })
177
+ }
178
+
179
+ get takerFeeRate() {
180
+ if (this.secondsRemaining == 0) {
181
+ return 1
182
+ }
183
+
184
+ return feeRate({
185
+ lnFeeRateRoot: this.state.configurationOptions.lnTakerFeeRate,
186
+ secondsRemaining: this.secondsRemaining,
187
+ })
188
+ }
189
+
190
+
191
+
192
+ /** Post offer instruction */
193
+ ixPostOffer({
194
+ trader,
195
+ price,
196
+ amount,
197
+ offerType,
198
+ offerOption,
199
+ virtualOffer,
200
+ expirySeconds,
201
+ mintSy,
202
+ ptSrc: ptSrcParam,
203
+ ytSrc: ytSrcParam,
204
+ sySrc: sySrcParam,
205
+ }: {
206
+ trader: web3.PublicKey
207
+ price: number
208
+ amount: BN
209
+ offerType: OfferTypeAnchor
210
+ offerOption: OfferOptionsAnchor
211
+ virtualOffer: boolean
212
+ expirySeconds: number
213
+ mintSy: web3.PublicKey
214
+ ptSrc?: web3.PublicKey
215
+ ytSrc?: web3.PublicKey
216
+ sySrc?: web3.PublicKey
217
+ }) {
218
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
219
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
220
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
221
+ const impliedRate = priceToImpliedRate(price)
222
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
223
+ const remainingAccounts = uniqueRemainingAccounts([
224
+ ...this.syCpiAccounts.getSyState,
225
+ ...this.exponentCoreCpiAccounts.mergeSy,
226
+ ...this.exponentCoreCpiAccounts.stripSy,
227
+ ...this.exponentCoreCpiAccounts.depositYt,
228
+ ...this.exponentCoreCpiAccounts.withdrawYt,
229
+ ])
230
+ return this.orderbookProgram.methods
231
+ .postOffer(impliedRate, amount, offerType, virtualOffer, expirySeconds, offerOption)
232
+ .accountsStrict({
233
+ orderbook: this.selfAddress,
234
+ vault: this.state.vault,
235
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
236
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
237
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
238
+ yieldPosition: this.corePda.yieldPosition({ vault: this.state.vault, owner: this.selfAddress }),
239
+ systemProgram: web3.SystemProgram.programId,
240
+ syProgram: this.state.syProgram,
241
+ tokenProgram: TOKEN_PROGRAM_ID,
242
+ exponentCore: this.state.exponentCoreProgram,
243
+ addressLookupTable: this.state.addressLookupTable,
244
+ trader,
245
+ tokenSyTrader: sySrc,
246
+ tokenYtTrader: ytSrc,
247
+ tokenPtTrader: ptSrc,
248
+ eventAuthority: this.eventAuthority,
249
+ program: this.orderbookProgram.programId,
250
+ cpiAccountOrderbook,
251
+ })
252
+ .remainingAccounts(remainingAccounts)
253
+ .instruction()
254
+ }
255
+
256
+ /** Market offer instruction */
257
+ ixMarketOffer({
258
+ trader,
259
+ maxPriceApy,
260
+ amount,
261
+ minAmountOut,
262
+ offerType,
263
+ virtualOffer,
264
+ mintSy,
265
+ ptSrc: ptSrcParam,
266
+ ytSrc: ytSrcParam,
267
+ sySrc: sySrcParam,
268
+ }: {
269
+ trader: web3.PublicKey
270
+ maxPriceApy: number
271
+ amount: BN
272
+ minAmountOut: BN
273
+ offerType: OfferTypeAnchor
274
+ virtualOffer: boolean
275
+ mintSy: web3.PublicKey
276
+ ptSrc?: web3.PublicKey
277
+ ytSrc?: web3.PublicKey
278
+ sySrc?: web3.PublicKey
279
+ }) {
280
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
281
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
282
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
283
+ const impliedRate = priceToImpliedRate(maxPriceApy)
284
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
285
+ const remainingAccounts = uniqueRemainingAccounts([
286
+ ...this.syCpiAccounts.getSyState,
287
+ ...this.exponentCoreCpiAccounts.mergeSy,
288
+ ...this.exponentCoreCpiAccounts.stripSy,
289
+ ...this.exponentCoreCpiAccounts.depositYt,
290
+ ...this.exponentCoreCpiAccounts.withdrawYt,
291
+ ])
292
+ return this.orderbookProgram.methods
293
+ .marketOffer(impliedRate, amount, minAmountOut, offerType, virtualOffer)
294
+ .accountsStrict({
295
+ orderbook: this.selfAddress,
296
+ vault: this.state.vault,
297
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
298
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
299
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
300
+ yieldPosition: this.corePda.yieldPosition({ vault: this.state.vault, owner: this.selfAddress }),
301
+ systemProgram: web3.SystemProgram.programId,
302
+ syProgram: this.state.syProgram,
303
+ tokenProgram: TOKEN_PROGRAM_ID,
304
+ exponentCore: this.state.exponentCoreProgram,
305
+ addressLookupTable: this.state.addressLookupTable,
306
+ trader,
307
+ tokenSyTrader: sySrc,
308
+ tokenYtTrader: ytSrc,
309
+ tokenPtTrader: ptSrc,
310
+ eventAuthority: this.eventAuthority,
311
+ program: this.orderbookProgram.programId,
312
+ cpiAccountOrderbook,
313
+ })
314
+ .remainingAccounts(remainingAccounts)
315
+ .instruction()
316
+ }
317
+
318
+ /** High trust set configuration options instruction */
319
+ ixSetConfigurationOptions({
320
+ admin,
321
+ configurationOptions,
322
+ }: {
323
+ admin: web3.PublicKey
324
+ configurationOptions: ConfigurationOptions
325
+ }) {
326
+ return this.orderbookProgram.methods
327
+ .setConfigurationOptions({ thresholdAmount: { 0: new BN(configurationOptions.thresholdAmount.toString()) } })
328
+ .accountsStrict({
329
+ orderbook: this.selfAddress,
330
+ adminSigner: admin,
331
+ })
332
+ .instruction()
333
+ }
334
+
335
+ getOffers(): Offer[] {
336
+ const { offers, prices, userEscrows } = this.state
337
+
338
+ return offers.map((o) => {
339
+ //? pricePointer - 1 because of TreeNode allocator specifics
340
+ const priceApy = prices[o.pricePointer - 1]!.key / PRICE_BASE_POINTS
341
+ const userEscrow = userEscrows[o.userVaultPointer - 1]!.user
342
+
343
+ const type = getOfferType(o.orderTypeFlag)
344
+
345
+ return {
346
+ type,
347
+ priceApy,
348
+ amount: Number(o.amount.toString()),
349
+ userEscrow: userEscrow,
350
+ expiryAt: o.expiryAt,
351
+ createdAt: o.createdAt,
352
+ isVirtual: o.virtualOffer,
353
+ }
354
+ })
355
+ }
356
+
357
+ /** Remove offer instruction */
358
+ ixRemoveOffer({
359
+ trader,
360
+ offerIdx,
361
+ mintSy,
362
+ ptSrc: ptSrcParam,
363
+ ytSrc: ytSrcParam,
364
+ sySrc: sySrcParam,
365
+ }: {
366
+ trader: web3.PublicKey
367
+ offerIdx: number
368
+ mintSy: web3.PublicKey
369
+ ptSrc?: web3.PublicKey
370
+ ytSrc?: web3.PublicKey
371
+ sySrc?: web3.PublicKey
372
+ }) {
373
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
374
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
375
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
376
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
377
+ return this.orderbookProgram.methods
378
+ .removeOffer(offerIdx)
379
+ .accountsStrict({
380
+ orderbook: this.selfAddress,
381
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
382
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
383
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
384
+ systemProgram: web3.SystemProgram.programId,
385
+ tokenProgram: TOKEN_PROGRAM_ID,
386
+ trader,
387
+ tokenSyTrader: sySrc,
388
+ tokenYtTrader: ytSrc,
389
+ tokenPtTrader: ptSrc,
390
+ eventAuthority: this.eventAuthority,
391
+ program: this.orderbookProgram.programId,
392
+ syProgram: this.state.syProgram,
393
+ addressLookupTable: this.state.addressLookupTable,
394
+ cpiAccountOrderbook: cpiAccountOrderbook,
395
+ exponentCore: this.state.exponentCoreProgram,
396
+ })
397
+ .remainingAccounts(this.syCpiAccounts.getSyState)
398
+ .instruction()
399
+ }
400
+
401
+ /** Post offer instruction */
402
+ async ixWrapperPostOffer({
403
+ trader,
404
+ price,
405
+ amount,
406
+ offerType,
407
+ offerOption,
408
+ virtualOffer,
409
+ expirySeconds,
410
+ mintSy,
411
+ ptSrc: ptSrcParam,
412
+ ytSrc: ytSrcParam,
413
+ sySrc: sySrcParam,
414
+ tokenBaseTrader: tokenBaseTraderParam,
415
+ }: {
416
+ trader: web3.PublicKey
417
+ price: number
418
+ amount: BN
419
+ offerType: OfferTypeAnchor
420
+ offerOption: OfferOptionsAnchor
421
+ virtualOffer: boolean
422
+ expirySeconds: number
423
+ mintSy: web3.PublicKey
424
+ ptSrc?: web3.PublicKey
425
+ ytSrc?: web3.PublicKey
426
+ sySrc?: web3.PublicKey
427
+ tokenBaseTrader?: web3.PublicKey
428
+ }) {
429
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
430
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
431
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
432
+ const tokenBaseTrader =
433
+ tokenBaseTraderParam ||
434
+ getAssociatedTokenAddressSync(this.flavor.mintBase, trader, true, this.flavor.baseTokenProgram)
435
+ const impliedRate = priceToImpliedRate(price)
436
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
437
+ const remainingAccounts = uniqueRemainingAccounts([
438
+ ...this.syCpiAccounts.getSyState,
439
+ ...this.exponentCoreCpiAccounts.mergeSy,
440
+ ...this.exponentCoreCpiAccounts.stripSy,
441
+ ...this.exponentCoreCpiAccounts.depositYt,
442
+ ...this.exponentCoreCpiAccounts.withdrawYt,
443
+ ])
444
+
445
+ const mintSyIx = await this.flavor.ixMintSy({
446
+ amountBase: "0",
447
+ depositor: trader,
448
+ depositorBaseTokenAccount: tokenBaseTrader,
449
+ depositorSyTokenAccount: sySrc,
450
+ })
451
+
452
+ const mintSyRemAccounts = mintSyIx.keys
453
+ return this.orderbookProgram.methods
454
+ .wrapperPostOffer(
455
+ impliedRate,
456
+ amount,
457
+ offerType,
458
+ virtualOffer,
459
+ expirySeconds,
460
+ offerOption,
461
+ mintSyRemAccounts.length - 1,
462
+ )
463
+ .accountsStrict({
464
+ orderbook: this.selfAddress,
465
+ vault: this.state.vault,
466
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
467
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
468
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
469
+ yieldPosition: this.corePda.yieldPosition({ vault: this.state.vault, owner: this.selfAddress }),
470
+ systemProgram: web3.SystemProgram.programId,
471
+ syProgram: this.state.syProgram,
472
+ tokenProgram: TOKEN_PROGRAM_ID,
473
+ exponentCore: this.state.exponentCoreProgram,
474
+ addressLookupTable: this.state.addressLookupTable,
475
+ trader,
476
+ tokenSyTrader: sySrc,
477
+ tokenYtTrader: ytSrc,
478
+ tokenPtTrader: ptSrc,
479
+ eventAuthority: this.eventAuthority,
480
+ program: this.orderbookProgram.programId,
481
+ cpiAccountOrderbook,
482
+ })
483
+ .remainingAccounts([...mintSyRemAccounts, ...remainingAccounts])
484
+ .instruction()
485
+ }
486
+
487
+ /** Market offer instruction */
488
+ async ixWrapperMarketOffer({
489
+ trader,
490
+ maxPriceApy,
491
+ amount,
492
+ offerType,
493
+ minAmountOut,
494
+ virtualOffer,
495
+ mintSy,
496
+ ptSrc: ptSrcParam,
497
+ ytSrc: ytSrcParam,
498
+ sySrc: sySrcParam,
499
+ tokenBaseTrader: tokenBaseTraderParam,
500
+ }: {
501
+ trader: web3.PublicKey
502
+ maxPriceApy: number
503
+ amount: BN
504
+ offerType: OfferTypeAnchor
505
+ minAmountOut: BN
506
+ virtualOffer: boolean
507
+ mintSy: web3.PublicKey
508
+ ptSrc?: web3.PublicKey
509
+ ytSrc?: web3.PublicKey
510
+ sySrc?: web3.PublicKey
511
+ tokenBaseTrader?: web3.PublicKey
512
+ }) {
513
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
514
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
515
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
516
+ const tokenBaseTrader =
517
+ tokenBaseTraderParam ||
518
+ getAssociatedTokenAddressSync(this.flavor.mintBase, trader, true, this.flavor.baseTokenProgram)
519
+ const impliedRate = priceToImpliedRate(maxPriceApy)
520
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
521
+ const remainingAccounts = uniqueRemainingAccounts([
522
+ ...this.syCpiAccounts.getSyState,
523
+ ...this.exponentCoreCpiAccounts.mergeSy,
524
+ ...this.exponentCoreCpiAccounts.stripSy,
525
+ ...this.exponentCoreCpiAccounts.depositYt,
526
+ ...this.exponentCoreCpiAccounts.withdrawYt,
527
+ ])
528
+
529
+ const mintSyIx = await this.flavor.ixMintSy({
530
+ amountBase: "0",
531
+ depositor: trader,
532
+ depositorBaseTokenAccount: tokenBaseTrader,
533
+ depositorSyTokenAccount: sySrc,
534
+ })
535
+
536
+ const redeemSyIx = await this.flavor.ixRedeemSy({
537
+ amountSy: "0",
538
+ redeemer: trader,
539
+ redeemerBaseTokenAccount: tokenBaseTrader,
540
+ redeemerSyTokenAccount: sySrc,
541
+ })
542
+
543
+ const depositYtAccounts = await this.depositYtAccounts({
544
+ owner: trader,
545
+ ytSrc: ytSrc,
546
+ })
547
+ const offerTypeEnum = offerType.sellYt ? OfferType.SellYT : OfferType.BuyYT
548
+ const redeem_sy_or_deposit_yt_accounts =
549
+ (!virtualOffer && offerTypeEnum == OfferType.SellYT) || (virtualOffer && offerTypeEnum == OfferType.BuyYT)
550
+ ? redeemSyIx.keys
551
+ : depositYtAccounts.keys;
552
+
553
+
554
+
555
+ const mintSyRemAccounts = mintSyIx.keys
556
+ const redeem_sy_or_deposit_yt_accounts_untill = mintSyRemAccounts.length + redeem_sy_or_deposit_yt_accounts.length;
557
+ return this.orderbookProgram.methods
558
+ .wrapperMarketOffer(
559
+ impliedRate,
560
+ amount,
561
+ minAmountOut,
562
+ offerType,
563
+ virtualOffer,
564
+ mintSyRemAccounts.length,
565
+ redeem_sy_or_deposit_yt_accounts_untill,
566
+ )
567
+ .accountsStrict({
568
+ orderbook: this.selfAddress,
569
+ vault: this.state.vault,
570
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
571
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
572
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
573
+ yieldPosition: this.corePda.yieldPosition({ vault: this.state.vault, owner: this.selfAddress }),
574
+ systemProgram: web3.SystemProgram.programId,
575
+ syProgram: this.state.syProgram,
576
+ tokenProgram: TOKEN_PROGRAM_ID,
577
+ exponentCore: this.state.exponentCoreProgram,
578
+ addressLookupTable: this.state.addressLookupTable,
579
+ trader,
580
+ tokenSyTrader: sySrc,
581
+ tokenYtTrader: ytSrc,
582
+ tokenPtTrader: ptSrc,
583
+ eventAuthority: this.eventAuthority,
584
+ program: this.orderbookProgram.programId,
585
+ cpiAccountOrderbook,
586
+ })
587
+ .remainingAccounts(mintSyRemAccounts.concat(redeem_sy_or_deposit_yt_accounts).concat(remainingAccounts))
588
+ .instruction()
589
+ }
590
+
591
+ /** Wrapper remove offer instruction */
592
+ async ixWrapperRemoveOffer({
593
+ trader,
594
+ offerIdx,
595
+ mintSy,
596
+ ptSrc: ptSrcParam,
597
+ ytSrc: ytSrcParam,
598
+ sySrc: sySrcParam,
599
+ tokenBaseTrader: tokenBaseTraderParam,
600
+ }: {
601
+ trader: web3.PublicKey
602
+ offerIdx: number
603
+ mintSy: web3.PublicKey
604
+ ptSrc?: web3.PublicKey
605
+ ytSrc?: web3.PublicKey
606
+ sySrc?: web3.PublicKey
607
+ tokenBaseTrader?: web3.PublicKey
608
+ }) {
609
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
610
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
611
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
612
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
613
+ const tokenBaseTrader =
614
+ tokenBaseTraderParam ||
615
+ getAssociatedTokenAddressSync(this.flavor.mintBase, trader, true, this.flavor.baseTokenProgram)
616
+
617
+ const redeemSyIx = await this.flavor.ixRedeemSy({
618
+ amountSy: "0",
619
+ redeemer: trader,
620
+ redeemerBaseTokenAccount: tokenBaseTrader,
621
+ redeemerSyTokenAccount: sySrc,
622
+ })
623
+
624
+ const remainingAccounts = uniqueRemainingAccounts([
625
+ ...this.syCpiAccounts.getSyState,
626
+ ...this.exponentCoreCpiAccounts.withdrawYt,
627
+ ])
628
+
629
+ const redeemSyRemAccounts = redeemSyIx.keys
630
+ return this.orderbookProgram.methods
631
+ .wrapperRemoveOffer(offerIdx, redeemSyIx.keys.length - 1)
632
+ .accountsStrict({
633
+ orderbook: this.selfAddress,
634
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
635
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
636
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
637
+ systemProgram: web3.SystemProgram.programId,
638
+ tokenProgram: TOKEN_PROGRAM_ID,
639
+ trader,
640
+ tokenSyTrader: sySrc,
641
+ tokenYtTrader: ytSrc,
642
+ tokenPtTrader: ptSrc,
643
+ eventAuthority: this.eventAuthority,
644
+ program: this.orderbookProgram.programId,
645
+ syProgram: this.state.syProgram,
646
+ addressLookupTable: this.state.addressLookupTable,
647
+ cpiAccountOrderbook: cpiAccountOrderbook,
648
+ exponentCore: this.state.exponentCoreProgram,
649
+ vault: this.state.vault,
650
+ })
651
+ .remainingAccounts([...redeemSyRemAccounts, ...remainingAccounts])
652
+ .instruction()
653
+ }
654
+
655
+ /** Wrapper collect interest instruction */
656
+ async ixWrapperCollectInterest({
657
+ trader,
658
+ mintSy,
659
+ sySrc: sySrcParam,
660
+ tokenBaseTrader: tokenBaseTraderParam,
661
+ }: {
662
+ trader: web3.PublicKey
663
+ mintSy: web3.PublicKey
664
+ sySrc?: web3.PublicKey
665
+ tokenBaseTrader?: web3.PublicKey
666
+ }) {
667
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
668
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
669
+ const tokenBaseTrader =
670
+ tokenBaseTraderParam ||
671
+ getAssociatedTokenAddressSync(this.flavor.mintBase, trader, true, this.flavor.baseTokenProgram)
672
+
673
+ const redeemSyIx = await this.flavor.ixRedeemSy({
674
+ amountSy: "0",
675
+ redeemer: trader,
676
+ redeemerBaseTokenAccount: tokenBaseTrader,
677
+ redeemerSyTokenAccount: sySrc,
678
+ })
679
+ const remainingAccounts = uniqueRemainingAccounts([
680
+ ...this.syCpiAccounts.getSyState,
681
+ ...this.exponentCoreCpiAccounts.collectInterest,
682
+ ...this.syCpiAccounts.withdrawSy,
683
+ ])
684
+ const redeemSyRemAccounts = redeemSyIx.keys
685
+ return this.orderbookProgram.methods
686
+ .wrapperCollectInterest(redeemSyIx.keys.length - 1)
687
+ .accountsStrict({
688
+ orderbook: this.selfAddress,
689
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
690
+ systemProgram: web3.SystemProgram.programId,
691
+ tokenProgram: TOKEN_PROGRAM_ID,
692
+ trader,
693
+ tokenSyTrader: sySrc,
694
+ eventAuthority: this.eventAuthority,
695
+ program: this.orderbookProgram.programId,
696
+ syProgram: this.state.syProgram,
697
+ addressLookupTable: this.state.addressLookupTable,
698
+ cpiAccountOrderbook: cpiAccountOrderbook,
699
+ exponentCore: this.state.exponentCoreProgram,
700
+ vault: this.state.vault,
701
+ })
702
+ .remainingAccounts([...redeemSyRemAccounts, ...remainingAccounts])
703
+ .instruction()
704
+ }
705
+
706
+ /** Wrapper withdraw funds instruction */
707
+ async ixWrapperWithdrawFunds({
708
+ trader,
709
+ mintSy,
710
+ ptAmount,
711
+ ytAmount,
712
+ syAmount,
713
+ ptSrc: ptSrcParam,
714
+ ytSrc: ytSrcParam,
715
+ sySrc: sySrcParam,
716
+ tokenBaseTrader: tokenBaseTraderParam,
717
+ }: {
718
+ trader: web3.PublicKey
719
+ mintSy: web3.PublicKey
720
+ ptAmount: ClaimAmount
721
+ ytAmount: ClaimAmount
722
+ syAmount: ClaimAmount
723
+ ptSrc?: web3.PublicKey
724
+ ytSrc?: web3.PublicKey
725
+ sySrc?: web3.PublicKey
726
+ tokenBaseTrader?: web3.PublicKey
727
+ }) {
728
+ const ptSrc = ptSrcParam || getAssociatedTokenAddressSync(this.mintPt, trader, true, TOKEN_PROGRAM_ID)
729
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, trader, true, TOKEN_PROGRAM_ID)
730
+ const sySrc = sySrcParam || getAssociatedTokenAddressSync(mintSy, trader, true, TOKEN_PROGRAM_ID)
731
+
732
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
733
+ const tokenBaseTrader =
734
+ tokenBaseTraderParam ||
735
+ getAssociatedTokenAddressSync(this.flavor.mintBase, trader, true, this.flavor.baseTokenProgram)
736
+
737
+ const redeemSyIx = await this.flavor.ixRedeemSy({
738
+ amountSy: "0",
739
+ redeemer: trader,
740
+ redeemerBaseTokenAccount: tokenBaseTrader,
741
+ redeemerSyTokenAccount: sySrc,
742
+ })
743
+
744
+ const redeemSyRemAccounts = redeemSyIx.keys
745
+
746
+ const remainingAccounts = uniqueRemainingAccounts([
747
+ ...this.syCpiAccounts.getSyState,
748
+ ...this.exponentCoreCpiAccounts.withdrawYt,
749
+ ])
750
+
751
+ return this.orderbookProgram.methods
752
+ .wrapperWithdrawFunds(
753
+ ptAmount,
754
+ ytAmount,
755
+ syAmount,
756
+ redeemSyIx.keys.length - 1
757
+ )
758
+ .accountsStrict({
759
+ orderbook: this.selfAddress,
760
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
761
+ systemProgram: web3.SystemProgram.programId,
762
+ tokenProgram: TOKEN_PROGRAM_ID,
763
+ trader,
764
+ tokenSyTrader: sySrc,
765
+ eventAuthority: this.eventAuthority,
766
+ program: this.orderbookProgram.programId,
767
+ syProgram: this.state.syProgram,
768
+ addressLookupTable: this.state.addressLookupTable,
769
+ cpiAccountOrderbook: cpiAccountOrderbook,
770
+ exponentCore: this.state.exponentCoreProgram,
771
+ vault: this.state.vault,
772
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
773
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
774
+ tokenYtTrader: ytSrc,
775
+ tokenPtTrader: ptSrc,
776
+ })
777
+ .remainingAccounts(redeemSyRemAccounts.concat(remainingAccounts))
778
+ .instruction()
779
+ }
780
+
781
+ /** Wrapper collect admin fee instruction */
782
+ async ixWrapperCollectAdminFee({ admin, mintSy }: { admin: web3.PublicKey; mintSy: web3.PublicKey }) {
783
+ const ptSrc = getAssociatedTokenAddressSync(this.mintPt, admin, true, TOKEN_PROGRAM_ID)
784
+ const ytSrc = getAssociatedTokenAddressSync(this.mintYt, admin, true, TOKEN_PROGRAM_ID)
785
+ const sySrc = getAssociatedTokenAddressSync(mintSy, admin, true, TOKEN_PROGRAM_ID)
786
+
787
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
788
+ const tokenBaseTrader = getAssociatedTokenAddressSync(
789
+ this.flavor.mintBase,
790
+ admin,
791
+ true,
792
+ this.flavor.baseTokenProgram,
793
+ )
794
+
795
+ const redeemSyIx = await this.flavor.ixRedeemSy({
796
+ amountSy: "0",
797
+ redeemer: admin,
798
+ redeemerBaseTokenAccount: tokenBaseTrader,
799
+ redeemerSyTokenAccount: sySrc,
800
+ })
801
+
802
+ const redeemSyRemAccounts = redeemSyIx.keys
803
+
804
+ const remainingAccounts = uniqueRemainingAccounts([
805
+ ...this.syCpiAccounts.getSyState,
806
+ ...this.exponentCoreCpiAccounts.collectInterest,
807
+ ...this.exponentCoreCpiAccounts.withdrawYt,
808
+ ])
809
+
810
+ return this.orderbookProgram.methods
811
+ .wrapperCollectAdminFee(redeemSyIx.keys.length - 1)
812
+ .accountsStrict({
813
+ orderbook: this.selfAddress,
814
+ tokenEscrowSy: this.pda.orderbookEscrowSy({ orderbook: this.selfAddress }),
815
+ systemProgram: web3.SystemProgram.programId,
816
+ tokenProgram: TOKEN_PROGRAM_ID,
817
+ admin,
818
+ tokenSyAdmin: sySrc,
819
+ eventAuthority: this.eventAuthority,
820
+ program: this.orderbookProgram.programId,
821
+ syProgram: this.state.syProgram,
822
+ addressLookupTable: this.state.addressLookupTable,
823
+ cpiAccountOrderbook: cpiAccountOrderbook,
824
+ exponentCore: this.state.exponentCoreProgram,
825
+ vault: this.state.vault,
826
+ tokenEscrowYt: this.pda.orderbookEscrowYt({ orderbook: this.selfAddress }),
827
+ tokenEscrowPt: this.pda.orderbookEscrowPt({ orderbook: this.selfAddress }),
828
+ tokenYtAdmin: ytSrc,
829
+ tokenPtAdmin: ptSrc,
830
+ })
831
+ .remainingAccounts(redeemSyRemAccounts.concat(remainingAccounts))
832
+ .instruction()
833
+ }
834
+
835
+ /** Wrapper collect admin emission instruction */
836
+ async ixCollectAdminEmission({
837
+ emissionEscrow,
838
+ amount,
839
+ index,
840
+ treasuryEmissionTokenAccount,
841
+ tokenEmissionAdmin,
842
+ }: {
843
+ emissionEscrow: web3.PublicKey
844
+ index: number
845
+ amount: ClaimAmount
846
+ treasuryEmissionTokenAccount: web3.PublicKey
847
+ tokenEmissionAdmin: web3.PublicKey
848
+ }) {
849
+ const claimEmissionAccounts = this.collectAdminEmissionCoreAccounts({
850
+ emissionDst: tokenEmissionAdmin,
851
+ emissionEscrow,
852
+ treasuryEmissionTokenAccount,
853
+ })
854
+ const remainingAccounts = [...claimEmissionAccounts, ...this.syCpiAccounts.claimEmission[index]]
855
+
856
+ return this.orderbookProgram.methods
857
+ .collectAdminEmission(amount, index)
858
+ .accountsStrict({
859
+ orderbook: this.selfAddress,
860
+ eventAuthority: this.eventAuthority,
861
+ program: this.orderbookProgram.programId,
862
+ exponentCore: this.state.exponentCoreProgram,
863
+ admin: this.state.admin,
864
+ })
865
+ .remainingAccounts(remainingAccounts)
866
+ .instruction()
867
+ }
868
+
869
+ collectAdminEmissionCoreAccounts({
870
+ emissionDst,
871
+ emissionEscrow,
872
+ treasuryEmissionTokenAccount,
873
+ }: {
874
+ emissionDst: web3.PublicKey
875
+ emissionEscrow: web3.PublicKey
876
+ treasuryEmissionTokenAccount: web3.PublicKey
877
+ }): AccountInfo[] {
878
+ return [
879
+ {
880
+ pubkey: this.selfAddress,
881
+ isSigner: false,
882
+ isWritable: true,
883
+ },
884
+ {
885
+ pubkey: this.state.vault,
886
+ isSigner: false,
887
+ isWritable: true,
888
+ },
889
+ {
890
+ pubkey: this.state.yieldPosition,
891
+ isSigner: false,
892
+ isWritable: true,
893
+ },
894
+ {
895
+ pubkey: this.state.syProgram,
896
+ isSigner: false,
897
+ isWritable: false,
898
+ },
899
+ {
900
+ pubkey: emissionEscrow,
901
+ isSigner: false,
902
+ isWritable: true,
903
+ },
904
+ {
905
+ pubkey: emissionDst,
906
+ isSigner: false,
907
+ isWritable: true,
908
+ },
909
+ {
910
+ pubkey: treasuryEmissionTokenAccount,
911
+ isSigner: false,
912
+ isWritable: true,
913
+ },
914
+ {
915
+ pubkey: TOKEN_PROGRAM_ID,
916
+ isSigner: false,
917
+ isWritable: false,
918
+ },
919
+ {
920
+ pubkey: this.coreEventAuthority,
921
+ isSigner: false,
922
+ isWritable: false,
923
+ },
924
+ {
925
+ pubkey: this.state.exponentCoreProgram,
926
+ isSigner: false,
927
+ isWritable: false,
928
+ },
929
+ ]
930
+ }
931
+
932
+ /** Wrapper collect admin fee instruction */
933
+ async ixRemoveExpiredOffers({ admin }: { admin: web3.PublicKey }) {
934
+ const cpiAccountOrderbook = this.pda.orderbookCpiAccounts({ orderbook: this.selfAddress })
935
+
936
+ const remainingAccounts = uniqueRemainingAccounts([...this.syCpiAccounts.getSyState])
937
+
938
+ return this.orderbookProgram.methods
939
+ .removeExpiredOffers()
940
+ .accountsStrict({
941
+ orderbook: this.selfAddress,
942
+ admin,
943
+ eventAuthority: this.eventAuthority,
944
+ program: this.orderbookProgram.programId,
945
+ syProgram: this.state.syProgram,
946
+ addressLookupTable: this.state.addressLookupTable,
947
+ cpiAccountOrderbook: cpiAccountOrderbook,
948
+ })
949
+ .remainingAccounts(remainingAccounts)
950
+ .instruction()
951
+ }
952
+
953
+ getQuote({
954
+ priceApy: rawPriceApy,
955
+ inAmount: inAmountRaw,
956
+ direction,
957
+ unixNow,
958
+ syExchangeRate,
959
+ }: {
960
+ priceApy?: number //? In percents!!!
961
+ inAmount: number
962
+ unixNow: number //? Time is very important for calculations. Better to avoid using Date.now()
963
+ direction: QuoteDirection
964
+ syExchangeRate: number //? E.g. 1.000009210084
965
+ }) {
966
+ const offerDirection = getOfferDirectionFromQuoteDirection(direction)
967
+ const { isVirtual: isQuoteVirtualOffer, offerType: quoteOfferType } = getOfferTypeFromTradeDirection(offerDirection)
968
+
969
+ //? If inAmount is in base, convert Base to SY
970
+ const inAmount = isQuoteInputTokenBase(direction) ? inAmountRaw / syExchangeRate : inAmountRaw
971
+ //? Offer on contract stores its APY price in ln(1+ apy) view. Convert it before all calculations
972
+ const priceApy =
973
+ rawPriceApy &&
974
+ roundPriceApy(priceToImpliedRate(rawPriceApy), this.state.configurationOptions.priceDecimals) / PRICE_BASE_POINTS
975
+
976
+ const secUntilMaturity = this.state.financials.expirationTs - unixNow
977
+
978
+ //? If offerType === BuyYT, sort by priceApy asc, otherwise by priceApy desc
979
+ const suitableOffersByType = this.getOffers()
980
+ .filter(({ type, expiryAt, priceApy: offerPriceApy }) => {
981
+ const isExpired = expiryAt < unixNow
982
+ const satisfyPriceApy = (() => {
983
+ if (!priceApy) return true
984
+ if (quoteOfferType === OfferType.BuyYT) return offerPriceApy <= priceApy
985
+ return offerPriceApy >= priceApy
986
+ })()
987
+ return type !== quoteOfferType && !isExpired && satisfyPriceApy
988
+ })
989
+ .sort((a, b) => {
990
+ const expiryCompare = a.expiryAt - b.expiryAt
991
+ //? If we buyYT -- sort priceApy ascending, otherwise descending
992
+ if (quoteOfferType === OfferType.BuyYT) {
993
+ return a.priceApy - b.priceApy || expiryCompare
994
+ }
995
+ return b.priceApy - a.priceApy || expiryCompare
996
+ })
997
+
998
+ let remainingAmount = inAmount
999
+ let outAmount = 0
1000
+ let offersUsed = 0
1001
+ let makerFees = 0;
1002
+ let takerFees = 0;
1003
+ suitableOffersByType.forEach((counterOffer) => {
1004
+ if (remainingAmount <= 0) return
1005
+
1006
+ if (offersUsed > MAX_FILLED_OFFERS) return
1007
+
1008
+ //? How much counter type tokens we request using current counter offer price+type
1009
+ //? Returns YT amount for SY->YT quote
1010
+ //? Returns SY amount for quote YT->SY quote
1011
+ //? Returns SY amount for SY->PT quote. How much SY should be (in theory) in counter offer to satisfy strip: SY_get->PT+YT
1012
+ //? Returns YT amount for PT->SY quote. YT amount in merge operation: PT+YT->SY
1013
+ const remainingAmountInCounterOfferToken = getOfferAmountToGet(
1014
+ {
1015
+ type: quoteOfferType,
1016
+ amount: remainingAmount,
1017
+ priceApy: counterOffer.priceApy,
1018
+ isVirtual: isQuoteVirtualOffer,
1019
+ userEscrow: web3.PublicKey.default,
1020
+ expiryAt: Infinity,
1021
+ createdAt: unixNow,
1022
+ },
1023
+ syExchangeRate,
1024
+ secUntilMaturity,
1025
+ )
1026
+
1027
+ //? YT amount for SY->YT quote
1028
+ //? SY amount for quote YT->SY quote
1029
+ //? SY amount for SY->PT quote
1030
+ //? YT amount for PT->SY quote
1031
+ const offerSize = getOfferSize(counterOffer, secUntilMaturity, syExchangeRate)
1032
+
1033
+ if (remainingAmountInCounterOfferToken > offerSize) {
1034
+ //? How much token you can sell into this offer. To extract all the liquidity (offer.amount)
1035
+ const offerToGet = getOfferAmountToGetNoVirtual(
1036
+ {
1037
+ ...counterOffer,
1038
+ amount: offerSize,
1039
+ },
1040
+ syExchangeRate,
1041
+ secUntilMaturity,
1042
+ )
1043
+
1044
+ const remainingAmountFromCounterOffer = calcRemainingAmountOnCounterOfferFilling(
1045
+ offerToGet,
1046
+ offerSize,
1047
+ isQuoteVirtualOffer,
1048
+ quoteOfferType,
1049
+ syExchangeRate,
1050
+ )
1051
+
1052
+ const outAmountFromCounterOffer = calcOutAmountOnCounterOfferFilling(
1053
+ offerToGet,
1054
+ offerSize,
1055
+ isQuoteVirtualOffer,
1056
+ quoteOfferType,
1057
+ syExchangeRate,
1058
+ this.makerFeeRate,
1059
+ )
1060
+
1061
+ remainingAmount -= remainingAmountFromCounterOffer
1062
+ outAmount += outAmountFromCounterOffer.outAmount
1063
+ makerFees += outAmountFromCounterOffer.tradeFee
1064
+ } else {
1065
+ //? How much token you can sell into this offer. To extract all the liquidity (offer.amount)
1066
+ const offerToGet = getOfferAmountToGetNoVirtual(
1067
+ {
1068
+ ...counterOffer,
1069
+ amount: remainingAmountInCounterOfferToken,
1070
+ },
1071
+ syExchangeRate,
1072
+ secUntilMaturity,
1073
+ )
1074
+
1075
+ const outAmountFromCounterOffer = calcOutAmountOnCounterOfferFilling(
1076
+ offerToGet,
1077
+ remainingAmountInCounterOfferToken,
1078
+ isQuoteVirtualOffer,
1079
+ quoteOfferType,
1080
+ syExchangeRate,
1081
+ this.makerFeeRate,
1082
+ )
1083
+
1084
+ remainingAmount = 0
1085
+ outAmount += outAmountFromCounterOffer.outAmount
1086
+ makerFees += outAmountFromCounterOffer.tradeFee
1087
+ }
1088
+
1089
+ offersUsed++
1090
+ })
1091
+
1092
+ //? If output is in base, convert SY to Base
1093
+ const outAmountAdjusted = isQuoteOutputTokenBase(direction) ? outAmount * syExchangeRate : outAmount
1094
+
1095
+ return {
1096
+ outAmount: Math.floor(outAmountAdjusted),
1097
+ makerFees: Math.floor(makerFees),
1098
+ takerFees: Math.floor(takerFees),
1099
+ }
1100
+ }
1101
+
1102
+ async depositYtAccounts({
1103
+ owner,
1104
+ ytSrc: ytSrcParam,
1105
+ }: {
1106
+ owner: web3.PublicKey
1107
+ ytSrc?: web3.PublicKey
1108
+ }): Promise<web3.TransactionInstruction> {
1109
+ const ytSrc = ytSrcParam || getAssociatedTokenAddressSync(this.mintYt, owner, true, TOKEN_PROGRAM_ID)
1110
+ const userYieldPosition = this.corePda.yieldPosition({ vault: this.state.vault, owner })
1111
+ const yieldPosition = this.corePda.vaultYieldPosition({ vault: this.state.vault })
1112
+ const escrowYt = this.corePda.escrowYt({ vault: this.state.vault })
1113
+ const mainAccounts = {
1114
+ depositor: owner,
1115
+ ytSrc,
1116
+ vault: this.state.vault,
1117
+ userYieldPosition: userYieldPosition,
1118
+ escrowYt: escrowYt,
1119
+ tokenProgram: TOKEN_PROGRAM_ID,
1120
+ syProgram: this.state.syProgram,
1121
+ addressLookupTable: this.vaulLookupTable,
1122
+ yieldPosition,
1123
+ systemProgram: web3.SystemProgram.programId,
1124
+ eventAuthority: this.coreEventAuthority,
1125
+ program: this.state.exponentCoreProgram,
1126
+ }
1127
+ const remainingAccounts = this.syCpiAccounts.getSyState
1128
+
1129
+ const depositIx = await this.coreProgram.methods
1130
+ .depositYt(new BN(0))
1131
+ .accountsStrict(mainAccounts)
1132
+ .remainingAccounts(remainingAccounts)
1133
+ .instruction();
1134
+
1135
+ return depositIx
1136
+ }
1137
+ }
1138
+
1139
+ type DepositYtAccounts = {
1140
+ [K in
1141
+ | "depositor"
1142
+ | "vault"
1143
+ | "userYieldPosition"
1144
+ | "ytSrc"
1145
+ | "escrowYt"
1146
+ | "tokenProgram"
1147
+ | "syProgram"
1148
+ | "addressLookupTable"
1149
+ | "yieldPosition"
1150
+ | "systemProgram"
1151
+ | "eventAuthority"
1152
+ | "program"]: web3.PublicKey
1153
+ }