@exponent-labs/exponent-sdk 0.9.0 → 0.9.2

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 (155) hide show
  1. package/build/client/vaults/index.d.ts +2 -0
  2. package/build/client/vaults/index.js +2 -0
  3. package/build/client/vaults/index.js.map +1 -1
  4. package/build/client/vaults/types/index.d.ts +2 -0
  5. package/build/client/vaults/types/index.js +2 -0
  6. package/build/client/vaults/types/index.js.map +1 -1
  7. package/build/client/vaults/types/kaminoFarmEntry.d.ts +15 -0
  8. package/build/client/vaults/types/kaminoFarmEntry.js +17 -0
  9. package/build/client/vaults/types/kaminoFarmEntry.js.map +1 -0
  10. package/build/client/vaults/types/kaminoObligationEntry.d.ts +21 -4
  11. package/build/client/vaults/types/kaminoObligationEntry.js +2 -1
  12. package/build/client/vaults/types/kaminoObligationEntry.js.map +1 -1
  13. package/build/client/vaults/types/positionUpdate.d.ts +9 -0
  14. package/build/client/vaults/types/positionUpdate.js +23 -0
  15. package/build/client/vaults/types/positionUpdate.js.map +1 -1
  16. package/build/client/vaults/types/proposalAction.js +0 -3
  17. package/build/client/vaults/types/proposalAction.js.map +1 -1
  18. package/build/client/vaults/types/reserveFarmMapping.d.ts +19 -0
  19. package/build/client/vaults/types/reserveFarmMapping.js +18 -0
  20. package/build/client/vaults/types/reserveFarmMapping.js.map +1 -0
  21. package/build/client/vaults/types/strategyPosition.d.ts +5 -0
  22. package/build/client/vaults/types/strategyPosition.js +5 -0
  23. package/build/client/vaults/types/strategyPosition.js.map +1 -1
  24. package/build/exponentVaults/aumCalculator.d.ts +25 -4
  25. package/build/exponentVaults/aumCalculator.js +236 -15
  26. package/build/exponentVaults/aumCalculator.js.map +1 -1
  27. package/build/exponentVaults/fetcher.d.ts +52 -0
  28. package/build/exponentVaults/fetcher.js +199 -0
  29. package/build/exponentVaults/fetcher.js.map +1 -0
  30. package/build/exponentVaults/index.d.ts +10 -9
  31. package/build/exponentVaults/index.js +26 -8
  32. package/build/exponentVaults/index.js.map +1 -1
  33. package/build/exponentVaults/kamino-farms.d.ts +144 -0
  34. package/build/exponentVaults/kamino-farms.js +396 -0
  35. package/build/exponentVaults/kamino-farms.js.map +1 -0
  36. package/build/exponentVaults/loopscale/client.d.ts +240 -0
  37. package/build/exponentVaults/loopscale/client.js +590 -0
  38. package/build/exponentVaults/loopscale/client.js.map +1 -0
  39. package/build/exponentVaults/loopscale/client.test.d.ts +1 -0
  40. package/build/exponentVaults/loopscale/client.test.js +183 -0
  41. package/build/exponentVaults/loopscale/client.test.js.map +1 -0
  42. package/build/exponentVaults/loopscale/helpers.d.ts +29 -0
  43. package/build/exponentVaults/loopscale/helpers.js +119 -0
  44. package/build/exponentVaults/loopscale/helpers.js.map +1 -0
  45. package/build/exponentVaults/loopscale/index.d.ts +3 -0
  46. package/build/exponentVaults/loopscale/index.js +12 -0
  47. package/build/exponentVaults/loopscale/index.js.map +1 -0
  48. package/build/exponentVaults/loopscale/prepared-transactions.d.ts +13 -0
  49. package/build/exponentVaults/loopscale/prepared-transactions.js +271 -0
  50. package/build/exponentVaults/loopscale/prepared-transactions.js.map +1 -0
  51. package/build/exponentVaults/loopscale/prepared-transactions.test.d.ts +1 -0
  52. package/build/exponentVaults/loopscale/prepared-transactions.test.js +400 -0
  53. package/build/exponentVaults/loopscale/prepared-transactions.test.js.map +1 -0
  54. package/build/exponentVaults/loopscale/prepared-types.d.ts +62 -0
  55. package/build/exponentVaults/loopscale/prepared-types.js +3 -0
  56. package/build/exponentVaults/loopscale/prepared-types.js.map +1 -0
  57. package/build/exponentVaults/loopscale/response-plan.d.ts +69 -0
  58. package/build/exponentVaults/loopscale/response-plan.js +141 -0
  59. package/build/exponentVaults/loopscale/response-plan.js.map +1 -0
  60. package/build/exponentVaults/loopscale/response-plan.test.d.ts +1 -0
  61. package/build/exponentVaults/loopscale/response-plan.test.js +139 -0
  62. package/build/exponentVaults/loopscale/response-plan.test.js.map +1 -0
  63. package/build/exponentVaults/loopscale/send-plan.d.ts +75 -0
  64. package/build/exponentVaults/loopscale/send-plan.js +235 -0
  65. package/build/exponentVaults/loopscale/send-plan.js.map +1 -0
  66. package/build/exponentVaults/loopscale/types.d.ts +443 -0
  67. package/build/exponentVaults/loopscale/types.js +3 -0
  68. package/build/exponentVaults/loopscale/types.js.map +1 -0
  69. package/build/exponentVaults/loopscale-client.d.ts +113 -524
  70. package/build/exponentVaults/loopscale-client.js +296 -539
  71. package/build/exponentVaults/loopscale-client.js.map +1 -1
  72. package/build/exponentVaults/loopscale-client.test.d.ts +1 -0
  73. package/build/exponentVaults/loopscale-client.test.js +162 -0
  74. package/build/exponentVaults/loopscale-client.test.js.map +1 -0
  75. package/build/exponentVaults/loopscale-client.types.d.ts +425 -0
  76. package/build/exponentVaults/loopscale-client.types.js +3 -0
  77. package/build/exponentVaults/loopscale-client.types.js.map +1 -0
  78. package/build/exponentVaults/loopscale-execution.d.ts +125 -0
  79. package/build/exponentVaults/loopscale-execution.js +341 -0
  80. package/build/exponentVaults/loopscale-execution.js.map +1 -0
  81. package/build/exponentVaults/loopscale-execution.test.d.ts +1 -0
  82. package/build/exponentVaults/loopscale-execution.test.js +139 -0
  83. package/build/exponentVaults/loopscale-execution.test.js.map +1 -0
  84. package/build/exponentVaults/loopscale-vault.d.ts +115 -0
  85. package/build/exponentVaults/loopscale-vault.js +275 -0
  86. package/build/exponentVaults/loopscale-vault.js.map +1 -0
  87. package/build/exponentVaults/loopscale-vault.test.d.ts +1 -0
  88. package/build/exponentVaults/loopscale-vault.test.js +102 -0
  89. package/build/exponentVaults/loopscale-vault.test.js.map +1 -0
  90. package/build/exponentVaults/policyBuilders.d.ts +62 -0
  91. package/build/exponentVaults/policyBuilders.js +119 -2
  92. package/build/exponentVaults/policyBuilders.js.map +1 -1
  93. package/build/exponentVaults/pricePathResolver.d.ts +45 -0
  94. package/build/exponentVaults/pricePathResolver.js +198 -0
  95. package/build/exponentVaults/pricePathResolver.js.map +1 -0
  96. package/build/exponentVaults/pricePathResolver.test.d.ts +1 -0
  97. package/build/exponentVaults/pricePathResolver.test.js +369 -0
  98. package/build/exponentVaults/pricePathResolver.test.js.map +1 -0
  99. package/build/exponentVaults/syncTransaction.js +4 -1
  100. package/build/exponentVaults/syncTransaction.js.map +1 -1
  101. package/build/exponentVaults/titan-quote.js +170 -36
  102. package/build/exponentVaults/titan-quote.js.map +1 -1
  103. package/build/exponentVaults/vault-instruction-types.d.ts +363 -0
  104. package/build/exponentVaults/vault-instruction-types.js +128 -0
  105. package/build/exponentVaults/vault-instruction-types.js.map +1 -0
  106. package/build/exponentVaults/vault-interaction.d.ts +203 -343
  107. package/build/exponentVaults/vault-interaction.js +1894 -426
  108. package/build/exponentVaults/vault-interaction.js.map +1 -1
  109. package/build/exponentVaults/vault-interaction.kamino-vault.test.d.ts +1 -0
  110. package/build/exponentVaults/vault-interaction.kamino-vault.test.js +143 -0
  111. package/build/exponentVaults/vault-interaction.kamino-vault.test.js.map +1 -0
  112. package/build/exponentVaults/vault.d.ts +51 -2
  113. package/build/exponentVaults/vault.js +324 -48
  114. package/build/exponentVaults/vault.js.map +1 -1
  115. package/build/exponentVaults/vaultTransactionBuilder.d.ts +100 -134
  116. package/build/exponentVaults/vaultTransactionBuilder.js +383 -285
  117. package/build/exponentVaults/vaultTransactionBuilder.js.map +1 -1
  118. package/build/exponentVaults/vaultTransactionBuilder.test.d.ts +1 -0
  119. package/build/exponentVaults/vaultTransactionBuilder.test.js +297 -0
  120. package/build/exponentVaults/vaultTransactionBuilder.test.js.map +1 -0
  121. package/build/marketThree.d.ts +6 -2
  122. package/build/marketThree.js +10 -8
  123. package/build/marketThree.js.map +1 -1
  124. package/package.json +34 -32
  125. package/src/client/vaults/index.ts +2 -0
  126. package/src/client/vaults/types/index.ts +2 -0
  127. package/src/client/vaults/types/kaminoFarmEntry.ts +32 -0
  128. package/src/client/vaults/types/kaminoObligationEntry.ts +6 -3
  129. package/src/client/vaults/types/positionUpdate.ts +62 -0
  130. package/src/client/vaults/types/proposalAction.ts +0 -3
  131. package/src/client/vaults/types/reserveFarmMapping.ts +35 -0
  132. package/src/client/vaults/types/strategyPosition.ts +18 -1
  133. package/src/exponentVaults/aumCalculator.ts +353 -16
  134. package/src/exponentVaults/fetcher.ts +257 -0
  135. package/src/exponentVaults/index.ts +65 -40
  136. package/src/exponentVaults/kamino-farms.ts +538 -0
  137. package/src/exponentVaults/loopscale/client.ts +808 -0
  138. package/src/exponentVaults/loopscale/helpers.ts +172 -0
  139. package/src/exponentVaults/loopscale/index.ts +57 -0
  140. package/src/exponentVaults/loopscale/prepared-transactions.ts +435 -0
  141. package/src/exponentVaults/loopscale/prepared-types.ts +73 -0
  142. package/src/exponentVaults/loopscale/types.ts +466 -0
  143. package/src/exponentVaults/policyBuilders.ts +170 -0
  144. package/src/exponentVaults/pricePathResolver.test.ts +466 -0
  145. package/src/exponentVaults/pricePathResolver.ts +273 -0
  146. package/src/exponentVaults/syncTransaction.ts +6 -1
  147. package/src/exponentVaults/titan-quote.ts +231 -45
  148. package/src/exponentVaults/vault-instruction-types.ts +493 -0
  149. package/src/exponentVaults/vault-interaction.kamino-vault.test.ts +149 -0
  150. package/src/exponentVaults/vault-interaction.ts +2818 -799
  151. package/src/exponentVaults/vault.ts +474 -63
  152. package/src/exponentVaults/vaultTransactionBuilder.test.ts +349 -0
  153. package/src/exponentVaults/vaultTransactionBuilder.ts +581 -433
  154. package/src/marketThree.ts +14 -6
  155. package/src/exponentVaults/loopscale-client.ts +0 -1373
@@ -0,0 +1,493 @@
1
+ import { PublicKey, TransactionInstruction } from "@solana/web3.js"
2
+ import { SwapDirection } from "../client/clmm"
3
+ import { KAMINO_RESERVES, KaminoMarket } from "./kamino-markets"
4
+ import BN from "bn.js"
5
+
6
+ // ============================================================================
7
+ // Vault Instruction Types
8
+ // ============================================================================
9
+
10
+ type KaminoReserves = typeof KAMINO_RESERVES
11
+
12
+ /** Actions that can be performed through the vault instruction builder. */
13
+ export enum VaultAction {
14
+ INIT_USER_METADATA = "INIT_USER_METADATA",
15
+ INIT_OBLIGATION = "INIT_OBLIGATION",
16
+ DEPOSIT = "DEPOSIT",
17
+ WITHDRAW = "WITHDRAW",
18
+ BORROW = "BORROW",
19
+ REPAY = "REPAY",
20
+ }
21
+
22
+ /** A market-level instruction (no specific reserve needed). */
23
+ export type MarketInstruction = {
24
+ action: VaultAction.INIT_USER_METADATA | VaultAction.INIT_OBLIGATION
25
+ market: KaminoMarket
26
+ }
27
+
28
+ /** A reserve-level instruction with an amount. */
29
+ export type ReserveInstruction = {
30
+ action: VaultAction.DEPOSIT | VaultAction.WITHDRAW | VaultAction.BORROW | VaultAction.REPAY
31
+ market: KaminoMarket
32
+ asset: string
33
+ amount: BN
34
+ }
35
+
36
+ // ============================================================================
37
+ // Kamino Vault Instruction Types
38
+ // ============================================================================
39
+
40
+ /** Actions that can be performed on a direct Kamino Vault position. */
41
+ export enum KaminoVaultAction {
42
+ DEPOSIT = "KAMINO_VAULT_DEPOSIT",
43
+ WITHDRAW = "KAMINO_VAULT_WITHDRAW",
44
+ }
45
+
46
+ type KaminoVaultInstructionBase = {
47
+ action: KaminoVaultAction
48
+ vault: PublicKey
49
+ }
50
+
51
+ /** Deposit the vault-owned token account into a Kamino Vault and mint shares. */
52
+ export type KaminoVaultDepositInstruction = KaminoVaultInstructionBase & {
53
+ action: KaminoVaultAction.DEPOSIT
54
+ amount: BN
55
+ }
56
+
57
+ /** Withdraw Kamino Vault shares back into the vault-owned token account. */
58
+ export type KaminoVaultWithdrawInstruction = KaminoVaultInstructionBase & {
59
+ action: KaminoVaultAction.WITHDRAW
60
+ sharesAmount: BN
61
+ /** Optional reserve override. Omit it to let the SDK plan the withdraw across the vault's active reserves. */
62
+ reserve?: PublicKey
63
+ }
64
+
65
+ export type KaminoVaultInstruction =
66
+ | KaminoVaultDepositInstruction
67
+ | KaminoVaultWithdrawInstruction
68
+
69
+ // ============================================================================
70
+ // Kamino Farm Instruction Types
71
+ // ============================================================================
72
+
73
+ /** Actions that can be performed on a direct Kamino Farm position. */
74
+ export enum KaminoFarmAction {
75
+ INITIALIZE_USER = "KAMINO_FARM_INITIALIZE_USER",
76
+ STAKE = "KAMINO_FARM_STAKE",
77
+ UNSTAKE = "KAMINO_FARM_UNSTAKE",
78
+ WITHDRAW_UNSTAKED_DEPOSITS = "KAMINO_FARM_WITHDRAW_UNSTAKED_DEPOSITS",
79
+ HARVEST_REWARD = "KAMINO_FARM_HARVEST_REWARD",
80
+ }
81
+
82
+ type KaminoFarmInstructionBase = {
83
+ action: KaminoFarmAction
84
+ farmState: PublicKey
85
+ /**
86
+ * Optional delegatee used to derive the Farm `user_state`.
87
+ * Defaults to the managed vault owner when omitted.
88
+ */
89
+ delegatee?: PublicKey
90
+ }
91
+
92
+ /** Initialize the Farm `user_state` PDA for the vault owner or delegatee. */
93
+ export type KaminoFarmInitializeUserInstruction = KaminoFarmInstructionBase & {
94
+ action: KaminoFarmAction.INITIALIZE_USER
95
+ }
96
+
97
+ /** Stake tokens from the vault-owned ATA into the Farm. */
98
+ export type KaminoFarmStakeInstruction = KaminoFarmInstructionBase & {
99
+ action: KaminoFarmAction.STAKE
100
+ amount: BN | "ALL"
101
+ }
102
+
103
+ /** Unstake a scaled share amount from the Farm. */
104
+ export type KaminoFarmUnstakeInstruction = KaminoFarmInstructionBase & {
105
+ action: KaminoFarmAction.UNSTAKE
106
+ stakeSharesScaled: BN
107
+ }
108
+
109
+ /** Withdraw matured unstaked deposits back into the vault-owned ATA. */
110
+ export type KaminoFarmWithdrawUnstakedDepositsInstruction = KaminoFarmInstructionBase & {
111
+ action: KaminoFarmAction.WITHDRAW_UNSTAKED_DEPOSITS
112
+ }
113
+
114
+ /** Harvest a single Farm reward into a vault-owned reward ATA. */
115
+ export type KaminoFarmHarvestRewardInstruction = KaminoFarmInstructionBase & {
116
+ action: KaminoFarmAction.HARVEST_REWARD
117
+ rewardIndex: number
118
+ }
119
+
120
+ export type KaminoFarmInstruction =
121
+ | KaminoFarmInitializeUserInstruction
122
+ | KaminoFarmStakeInstruction
123
+ | KaminoFarmUnstakeInstruction
124
+ | KaminoFarmWithdrawUnstakedDepositsInstruction
125
+ | KaminoFarmHarvestRewardInstruction
126
+
127
+ // ============================================================================
128
+ // Orderbook Instruction Types
129
+ // ============================================================================
130
+
131
+ /** Orderbook trade direction */
132
+ export enum OrderbookTradeDirection {
133
+ BUY_PT = "BUY_PT",
134
+ SELL_PT = "SELL_PT",
135
+ BUY_YT = "BUY_YT",
136
+ SELL_YT = "SELL_YT",
137
+ }
138
+
139
+ /** Offer options for limit orders (currently only FillOrKill supported) */
140
+ export type OrderbookOfferOption = "FillOrKill"
141
+
142
+ /** Actions that can be performed on the Exponent Orderbook */
143
+ export enum OrderbookAction {
144
+ POST_OFFER = "POST_OFFER",
145
+ MARKET_OFFER = "MARKET_OFFER",
146
+ REMOVE_OFFER = "REMOVE_OFFER",
147
+ WITHDRAW_FUNDS = "WITHDRAW_FUNDS",
148
+ }
149
+
150
+ export type OrderbookInstructionMode = "wrapper" | "raw"
151
+
152
+ /** Base instruction type for all orderbook operations */
153
+ interface OrderbookInstructionBase {
154
+ action: OrderbookAction
155
+ orderbook: PublicKey
156
+ mode?: OrderbookInstructionMode
157
+ }
158
+
159
+ /** Post a limit order on the orderbook */
160
+ export interface OrderbookPostOfferInstruction extends OrderbookInstructionBase {
161
+ action: OrderbookAction.POST_OFFER
162
+ direction: OrderbookTradeDirection
163
+ priceApy: number
164
+ amount: bigint
165
+ offerOption?: OrderbookOfferOption
166
+ expirySeconds?: number
167
+ }
168
+
169
+ /** Execute a market order on the orderbook */
170
+ export interface OrderbookMarketOfferInstruction extends OrderbookInstructionBase {
171
+ action: OrderbookAction.MARKET_OFFER
172
+ direction: OrderbookTradeDirection
173
+ maxPriceApy: number
174
+ amount: bigint
175
+ minAmountOut: bigint
176
+ virtualOffer?: boolean
177
+ }
178
+
179
+ /** Cancel an existing limit order */
180
+ export interface OrderbookRemoveOfferInstruction extends OrderbookInstructionBase {
181
+ action: OrderbookAction.REMOVE_OFFER
182
+ offerIdx: number
183
+ }
184
+
185
+ /** Withdraw funds from user escrow */
186
+ export interface OrderbookWithdrawFundsInstruction extends OrderbookInstructionBase {
187
+ action: OrderbookAction.WITHDRAW_FUNDS
188
+ ptAmount?: bigint | null
189
+ ytAmount?: bigint | null
190
+ syAmount?: bigint | null
191
+ }
192
+
193
+ /** A single orderbook instruction */
194
+ export type OrderbookInstruction =
195
+ | OrderbookPostOfferInstruction
196
+ | OrderbookMarketOfferInstruction
197
+ | OrderbookRemoveOfferInstruction
198
+ | OrderbookWithdrawFundsInstruction
199
+
200
+ // ============================================================================
201
+ // Core Instruction Types (Strip/Merge)
202
+ // ============================================================================
203
+
204
+ /** Actions that can be performed on Exponent Core */
205
+ export enum CoreAction {
206
+ STRIP = "STRIP",
207
+ MERGE = "MERGE",
208
+ WITHDRAW_YT = "WITHDRAW_YT",
209
+ DEPOSIT_YT = "DEPOSIT_YT",
210
+ INITIALIZE_YIELD_POSITION = "INITIALIZE_YIELD_POSITION",
211
+ }
212
+
213
+ /** Base instruction type for all core operations */
214
+ interface CoreInstructionBase {
215
+ action: CoreAction
216
+ vault: PublicKey
217
+ }
218
+
219
+ /** Strip LST into PT + YT */
220
+ export interface CoreStripInstruction extends CoreInstructionBase {
221
+ action: CoreAction.STRIP
222
+ /** Amount of base token (LST) to strip */
223
+ amountBase: bigint
224
+ }
225
+
226
+ /** Merge PT + YT into LST */
227
+ export interface CoreMergeInstruction extends CoreInstructionBase {
228
+ action: CoreAction.MERGE
229
+ /** Amount of PT/YT to merge (must have equal amounts of both) */
230
+ amountPy: bigint
231
+ }
232
+
233
+ /** Withdraw YT from the tracked yield position back into the YT token account */
234
+ export interface CoreWithdrawYtInstruction extends CoreInstructionBase {
235
+ action: CoreAction.WITHDRAW_YT
236
+ amountYt: bigint
237
+ }
238
+
239
+ /** Deposit YT from the YT token account back into the tracked yield position */
240
+ export interface CoreDepositYtInstruction extends CoreInstructionBase {
241
+ action: CoreAction.DEPOSIT_YT
242
+ amountYt: bigint
243
+ }
244
+
245
+ /** Initialize yield position for a vault (owner = Squads vault) */
246
+ export interface CoreInitializeYieldPositionInstruction extends CoreInstructionBase {
247
+ action: CoreAction.INITIALIZE_YIELD_POSITION
248
+ }
249
+
250
+ /** A single core instruction */
251
+ export type CoreInstruction =
252
+ | CoreStripInstruction
253
+ | CoreMergeInstruction
254
+ | CoreWithdrawYtInstruction
255
+ | CoreDepositYtInstruction
256
+ | CoreInitializeYieldPositionInstruction
257
+
258
+ // ============================================================================
259
+ // Standard Program Instruction Types (mint_sy / redeem_sy)
260
+ // ============================================================================
261
+
262
+ export enum SyAction {
263
+ MINT = "MINT_SY",
264
+ REDEEM = "REDEEM_SY",
265
+ }
266
+
267
+ interface SyInstructionBase {
268
+ action: SyAction
269
+ vault: PublicKey
270
+ }
271
+
272
+ export interface SyMintInstruction extends SyInstructionBase {
273
+ action: SyAction.MINT
274
+ amountBase: bigint
275
+ }
276
+
277
+ export interface SyRedeemInstruction extends SyInstructionBase {
278
+ action: SyAction.REDEEM
279
+ amountSy: bigint
280
+ }
281
+
282
+ export type SyInstruction = SyMintInstruction | SyRedeemInstruction
283
+
284
+ // ============================================================================
285
+ // Titan Instruction Types
286
+ // ============================================================================
287
+
288
+ export enum TitanAction {
289
+ SWAP = "SWAP",
290
+ }
291
+
292
+ /** A pre-built Titan swap instruction to wrap in a sync transaction. */
293
+ export interface TitanSwapInstruction {
294
+ action: TitanAction.SWAP
295
+ /** The raw Titan SwapRouteV2 TransactionInstruction (from Titan's router API) */
296
+ instruction: TransactionInstruction
297
+ /** ALT addresses returned by Titan's router for this route. */
298
+ addressLookupTableAddresses?: PublicKey[]
299
+ }
300
+
301
+ // ============================================================================
302
+ // Loopscale Instruction Types
303
+ // ============================================================================
304
+
305
+ /** Actions for Loopscale interactions (loans = borrower side, strategies = lender side). */
306
+ export enum LoopscaleAction {
307
+ CREATE_LOAN = "LOOPSCALE_CREATE_LOAN",
308
+ DEPOSIT_COLLATERAL = "LOOPSCALE_DEPOSIT_COLLATERAL",
309
+ BORROW_PRINCIPAL = "LOOPSCALE_BORROW_PRINCIPAL",
310
+ REPAY_PRINCIPAL = "LOOPSCALE_REPAY_PRINCIPAL",
311
+ WITHDRAW_COLLATERAL = "LOOPSCALE_WITHDRAW_COLLATERAL",
312
+ CLOSE_LOAN = "LOOPSCALE_CLOSE_LOAN",
313
+ UPDATE_WEIGHT_MATRIX = "LOOPSCALE_UPDATE_WEIGHT_MATRIX",
314
+ CREATE_STRATEGY = "LOOPSCALE_CREATE_STRATEGY",
315
+ DEPOSIT_STRATEGY = "LOOPSCALE_DEPOSIT_STRATEGY",
316
+ WITHDRAW_STRATEGY = "LOOPSCALE_WITHDRAW_STRATEGY",
317
+ CLOSE_STRATEGY = "LOOPSCALE_CLOSE_STRATEGY",
318
+ UPDATE_STRATEGY = "LOOPSCALE_UPDATE_STRATEGY",
319
+ LOCK_LOAN = "LOOPSCALE_LOCK_LOAN",
320
+ UNLOCK_LOAN = "LOOPSCALE_UNLOCK_LOAN",
321
+ REFINANCE_LEDGER = "LOOPSCALE_REFINANCE_LEDGER",
322
+ }
323
+
324
+ /** A pre-built Loopscale instruction (loan or strategy) to wrap in a sync transaction. */
325
+ export interface LoopscaleInstruction {
326
+ action: LoopscaleAction
327
+ /** The raw Loopscale TransactionInstruction (from Loopscale API or local builder) */
328
+ instruction: TransactionInstruction
329
+ }
330
+
331
+ // ============================================================================
332
+ // CLMM Instruction Types
333
+ // ============================================================================
334
+
335
+ /** Actions that can be performed on the Exponent CLMM (Concentrated Liquidity Market Maker). */
336
+ export enum ClmmAction {
337
+ /** Create a new LP position with a specified tick range. Generates keypair internally. */
338
+ DEPOSIT_LIQUIDITY = "CLMM_DEPOSIT_LIQUIDITY",
339
+ /** Add more liquidity to an existing LP position. */
340
+ ADD_LIQUIDITY = "CLMM_ADD_LIQUIDITY",
341
+ /** Remove liquidity from an LP position and receive PT + SY. */
342
+ WITHDRAW_LIQUIDITY = "CLMM_WITHDRAW_LIQUIDITY",
343
+ /** Low-level PT/SY swap. Prefer buyPt/sellPt for directional trades. */
344
+ TRADE_PT = "CLMM_TRADE_PT",
345
+ /** Buy PT with SY on the CLMM. */
346
+ BUY_PT = "CLMM_BUY_PT",
347
+ /** Sell PT for SY on the CLMM. */
348
+ SELL_PT = "CLMM_SELL_PT",
349
+ /** Buy YT with SY on the CLMM. */
350
+ BUY_YT = "CLMM_BUY_YT",
351
+ /** Sell YT for SY on the CLMM. */
352
+ SELL_YT = "CLMM_SELL_YT",
353
+ /** Claim farm emissions from an LP position. */
354
+ CLAIM_FARM_EMISSION = "CLMM_CLAIM_FARM_EMISSION",
355
+ }
356
+
357
+ /** Base type for all CLMM instructions. */
358
+ interface ClmmInstructionBase {
359
+ action: ClmmAction
360
+ /** The CLMM MarketThree account address. */
361
+ market: PublicKey
362
+ }
363
+
364
+ /** Create a new LP position on the CLMM. The lpPosition keypair is generated internally for good UX. */
365
+ export interface ClmmDepositLiquidityInstruction extends ClmmInstructionBase {
366
+ action: ClmmAction.DEPOSIT_LIQUIDITY
367
+ /** Maximum amount of PT to deposit. */
368
+ ptInIntent: bigint
369
+ /** Maximum amount of SY to deposit. */
370
+ syInIntent: bigint
371
+ /** Lower tick boundary (APY value). */
372
+ lowerTickKey: number
373
+ /** Upper tick boundary (APY value). */
374
+ upperTickKey: number
375
+ }
376
+
377
+ /** Add liquidity to an existing LP position. */
378
+ export interface ClmmAddLiquidityInstruction extends ClmmInstructionBase {
379
+ action: ClmmAction.ADD_LIQUIDITY
380
+ /** The existing LpPosition account public key. */
381
+ lpPosition: PublicKey
382
+ /** Maximum amount of PT to add. */
383
+ ptInIntent: bigint
384
+ /** Maximum amount of SY to add. */
385
+ syInIntent: bigint
386
+ }
387
+
388
+ /** Withdraw liquidity from an LP position. */
389
+ export interface ClmmWithdrawLiquidityInstruction extends ClmmInstructionBase {
390
+ action: ClmmAction.WITHDRAW_LIQUIDITY
391
+ /** The LpPosition account to withdraw from. */
392
+ lpPosition: PublicKey
393
+ /** Amount of liquidity (LP units) to remove. */
394
+ lpIn: bigint
395
+ /** Minimum PT to receive (slippage protection). */
396
+ minPtOut: bigint
397
+ /** Minimum SY to receive (slippage protection). */
398
+ minSyOut: bigint
399
+ }
400
+
401
+ /** Low-level PT/SY swap on the CLMM. Prefer buyPt/sellPt for directional trades. */
402
+ export interface ClmmTradePtInstruction extends ClmmInstructionBase {
403
+ action: ClmmAction.TRADE_PT
404
+ /** Amount of the input token. */
405
+ traderAmount: bigint
406
+ /** Minimum output amount (slippage protection). */
407
+ outConstraint: bigint
408
+ /** Swap direction: SyToPt or PtToSy. */
409
+ swapDirection: SwapDirection
410
+ /** Optional price limit (ln implied APY). */
411
+ lnImpliedApyLimit?: number
412
+ }
413
+
414
+ /** Buy PT with SY on the CLMM. */
415
+ export interface ClmmBuyPtInstruction extends ClmmInstructionBase {
416
+ action: ClmmAction.BUY_PT
417
+ /** Amount of SY to spend. */
418
+ amountSy: bigint
419
+ /** Minimum PT to receive (slippage protection). */
420
+ outConstraint: bigint
421
+ /** Optional price limit (ln implied APY). */
422
+ lnImpliedApyLimit?: number
423
+ }
424
+
425
+ /** Sell PT for SY on the CLMM. */
426
+ export interface ClmmSellPtInstruction extends ClmmInstructionBase {
427
+ action: ClmmAction.SELL_PT
428
+ /** Amount of PT to sell. */
429
+ amountPt: bigint
430
+ /** Minimum SY to receive (slippage protection). */
431
+ outConstraint: bigint
432
+ /** Optional price limit (ln implied APY). */
433
+ lnImpliedApyLimit?: number
434
+ }
435
+
436
+ /** Buy YT with SY on the CLMM. */
437
+ export interface ClmmBuyYtInstruction extends ClmmInstructionBase {
438
+ action: ClmmAction.BUY_YT
439
+ /** Minimum amount of YT to receive. */
440
+ ytOut: bigint
441
+ /** Maximum amount of SY to spend. */
442
+ maxSyIn: bigint
443
+ /** Optional price limit (ln implied APY). */
444
+ lnImpliedApyLimit?: number
445
+ }
446
+
447
+ /** Sell YT for SY on the CLMM. */
448
+ export interface ClmmSellYtInstruction extends ClmmInstructionBase {
449
+ action: ClmmAction.SELL_YT
450
+ /** Amount of YT to sell. */
451
+ ytIn: bigint
452
+ /** Minimum SY to receive (slippage protection). */
453
+ minSyOut: bigint
454
+ /** Optional price limit (ln implied APY). */
455
+ lnImpliedApyLimit?: number
456
+ }
457
+
458
+ /** Claim farm emissions from an LP position. */
459
+ export interface ClmmClaimFarmEmissionInstruction extends ClmmInstructionBase {
460
+ action: ClmmAction.CLAIM_FARM_EMISSION
461
+ /** The LpPosition account to claim from. */
462
+ lpPosition: PublicKey
463
+ /** Index of the farm to claim from. */
464
+ farmIndex: number
465
+ }
466
+
467
+ /** A single CLMM instruction. */
468
+ export type ClmmInstruction =
469
+ | ClmmDepositLiquidityInstruction
470
+ | ClmmAddLiquidityInstruction
471
+ | ClmmWithdrawLiquidityInstruction
472
+ | ClmmTradePtInstruction
473
+ | ClmmBuyPtInstruction
474
+ | ClmmSellPtInstruction
475
+ | ClmmBuyYtInstruction
476
+ | ClmmSellYtInstruction
477
+ | ClmmClaimFarmEmissionInstruction
478
+
479
+ /** A single vault instruction — pass an array of these to `createVaultSyncTransaction`. */
480
+ export type VaultInstruction =
481
+ | MarketInstruction
482
+ | ReserveInstruction
483
+ | KaminoVaultInstruction
484
+ | KaminoFarmInstruction
485
+ | OrderbookInstruction
486
+ | CoreInstruction
487
+ | SyInstruction
488
+ | TitanSwapInstruction
489
+ | ClmmInstruction
490
+ | LoopscaleInstruction
491
+
492
+ // Re-export KaminoReserves for use in action builders
493
+ export type { KaminoReserves }
@@ -0,0 +1,149 @@
1
+ import { describe, expect, it } from "@jest/globals"
2
+ import BN from "bn.js"
3
+ import Decimal from "decimal.js"
4
+ import { PublicKey } from "@solana/web3.js"
5
+
6
+ import { __kaminoVaultTesting } from "./vault-interaction"
7
+
8
+ function pk(seed: number): PublicKey {
9
+ return new PublicKey(Uint8Array.from({ length: 32 }, () => seed))
10
+ }
11
+
12
+ describe("Kamino Vault withdraw planning", () => {
13
+ it("computes tokens per share from available liquidity, invested liquidity, and pending fees", () => {
14
+ const tokensPerShare = __kaminoVaultTesting.calculateKaminoVaultTokensPerShareFromSnapshot({
15
+ sharesBalance: new BN(50),
16
+ tokenAvailable: new BN(50),
17
+ sharesIssued: new BN(100),
18
+ pendingFeesSf: new BN("11529215046068469760"), // 10.0 in Fraction fixed-point
19
+ reserves: [
20
+ {
21
+ reserveAddress: pk(1),
22
+ investedLiquidityAmount: new Decimal(60),
23
+ availableLiquidityToWithdraw: new Decimal(40),
24
+ },
25
+ {
26
+ reserveAddress: pk(2),
27
+ investedLiquidityAmount: new Decimal(40),
28
+ availableLiquidityToWithdraw: new Decimal(20),
29
+ },
30
+ ],
31
+ })
32
+
33
+ expect(tokensPerShare.toFixed(6)).toBe("1.400000")
34
+ })
35
+
36
+ it("uses the first active reserve when vault-side available liquidity already covers the withdraw", () => {
37
+ const reserveOne = pk(10)
38
+ const reserveTwo = pk(11)
39
+ const legs = __kaminoVaultTesting.planKaminoVaultWithdrawLegsFromSnapshot({
40
+ sharesAmount: new BN(10),
41
+ snapshot: {
42
+ sharesBalance: new BN(100),
43
+ tokenAvailable: new BN(20),
44
+ sharesIssued: new BN(100),
45
+ pendingFeesSf: new BN(0),
46
+ reserves: [
47
+ {
48
+ reserveAddress: reserveOne,
49
+ investedLiquidityAmount: new Decimal(40),
50
+ availableLiquidityToWithdraw: new Decimal(25),
51
+ },
52
+ {
53
+ reserveAddress: reserveTwo,
54
+ investedLiquidityAmount: new Decimal(40),
55
+ availableLiquidityToWithdraw: new Decimal(30),
56
+ },
57
+ ],
58
+ },
59
+ })
60
+
61
+ expect(legs).toHaveLength(1)
62
+ expect(legs[0]?.reserveAddress.equals(reserveOne)).toBe(true)
63
+ expect(legs[0]?.sharesAmount.toString()).toBe("10")
64
+ })
65
+
66
+ it("keeps a single-reserve invested withdraw on that reserve when reserve is omitted", () => {
67
+ const reserve = pk(20)
68
+ const legs = __kaminoVaultTesting.planKaminoVaultWithdrawLegsFromSnapshot({
69
+ sharesAmount: new BN(50),
70
+ snapshot: {
71
+ sharesBalance: new BN(80),
72
+ tokenAvailable: new BN(10),
73
+ sharesIssued: new BN(100),
74
+ pendingFeesSf: new BN(0),
75
+ reserves: [{
76
+ reserveAddress: reserve,
77
+ investedLiquidityAmount: new Decimal(90),
78
+ availableLiquidityToWithdraw: new Decimal(90),
79
+ }],
80
+ },
81
+ })
82
+
83
+ expect(legs).toHaveLength(1)
84
+ expect(legs[0]?.reserveAddress.equals(reserve)).toBe(true)
85
+ expect(legs[0]?.sharesAmount.toString()).toBe("50")
86
+ })
87
+
88
+ it("orders multi-reserve withdraw legs by withdrawable liquidity when invested liquidity must be unwound", () => {
89
+ const reserveOne = pk(30)
90
+ const reserveTwo = pk(31)
91
+ const reserveThree = pk(32)
92
+ const legs = __kaminoVaultTesting.planKaminoVaultWithdrawLegsFromSnapshot({
93
+ sharesAmount: new BN(50),
94
+ snapshot: {
95
+ sharesBalance: new BN(80),
96
+ tokenAvailable: new BN(10),
97
+ sharesIssued: new BN(100),
98
+ pendingFeesSf: new BN(0),
99
+ reserves: [
100
+ {
101
+ reserveAddress: reserveOne,
102
+ investedLiquidityAmount: new Decimal(50),
103
+ availableLiquidityToWithdraw: new Decimal(15),
104
+ },
105
+ {
106
+ reserveAddress: reserveTwo,
107
+ investedLiquidityAmount: new Decimal(40),
108
+ availableLiquidityToWithdraw: new Decimal(30),
109
+ },
110
+ {
111
+ reserveAddress: reserveThree,
112
+ investedLiquidityAmount: new Decimal(20),
113
+ availableLiquidityToWithdraw: new Decimal(5),
114
+ },
115
+ ],
116
+ },
117
+ })
118
+
119
+ expect(legs.map((leg) => leg.reserveAddress.toBase58())).toEqual([
120
+ reserveTwo.toBase58(),
121
+ reserveOne.toBase58(),
122
+ reserveThree.toBase58(),
123
+ ])
124
+ expect(legs.map((leg) => leg.sharesAmount.toString())).toEqual(["33", "12", "4"])
125
+ })
126
+
127
+ it("preserves an explicit reserve override", () => {
128
+ const reserve = pk(40)
129
+ const legs = __kaminoVaultTesting.planKaminoVaultWithdrawLegsFromSnapshot({
130
+ sharesAmount: new BN(25),
131
+ reserve,
132
+ snapshot: {
133
+ sharesBalance: new BN(80),
134
+ tokenAvailable: new BN(0),
135
+ sharesIssued: new BN(80),
136
+ pendingFeesSf: new BN(0),
137
+ reserves: [{
138
+ reserveAddress: reserve,
139
+ investedLiquidityAmount: new Decimal(80),
140
+ availableLiquidityToWithdraw: new Decimal(80),
141
+ }],
142
+ },
143
+ })
144
+
145
+ expect(legs).toHaveLength(1)
146
+ expect(legs[0]?.reserveAddress.equals(reserve)).toBe(true)
147
+ expect(legs[0]?.sharesAmount.toString()).toBe("25")
148
+ })
149
+ })