@exponent-labs/exponent-sdk 0.9.1 → 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 (26) hide show
  1. package/build/client/vaults/types/kaminoObligationEntry.d.ts +21 -21
  2. package/build/client/vaults/types/obligationType.d.ts +1 -1
  3. package/build/client/vaults/types/proposalAction.d.ts +54 -54
  4. package/build/client/vaults/types/reserveFarmMapping.d.ts +3 -3
  5. package/build/client/vaults/types/strategyPosition.d.ts +1 -1
  6. package/build/exponentVaults/index.d.ts +1 -1
  7. package/build/exponentVaults/index.js +3 -2
  8. package/build/exponentVaults/index.js.map +1 -1
  9. package/build/exponentVaults/vault-instruction-types.d.ts +1 -1
  10. package/build/exponentVaults/vault-interaction.d.ts +58 -41
  11. package/build/exponentVaults/vault-interaction.js +294 -54
  12. package/build/exponentVaults/vault-interaction.js.map +1 -1
  13. package/build/exponentVaults/vault-interaction.kamino-vault.test.d.ts +1 -0
  14. package/build/exponentVaults/vault-interaction.kamino-vault.test.js +143 -0
  15. package/build/exponentVaults/vault-interaction.kamino-vault.test.js.map +1 -0
  16. package/build/exponentVaults/vaultTransactionBuilder.js +35 -30
  17. package/build/exponentVaults/vaultTransactionBuilder.js.map +1 -1
  18. package/build/exponentVaults/vaultTransactionBuilder.test.js +84 -1
  19. package/build/exponentVaults/vaultTransactionBuilder.test.js.map +1 -1
  20. package/package.json +34 -32
  21. package/src/exponentVaults/index.ts +1 -0
  22. package/src/exponentVaults/vault-instruction-types.ts +1 -1
  23. package/src/exponentVaults/vault-interaction.kamino-vault.test.ts +149 -0
  24. package/src/exponentVaults/vault-interaction.ts +514 -86
  25. package/src/exponentVaults/vaultTransactionBuilder.test.ts +93 -0
  26. package/src/exponentVaults/vaultTransactionBuilder.ts +47 -41
@@ -17,6 +17,7 @@ jest.mock("./loopscale", () => ({
17
17
 
18
18
  jest.mock("./vault-interaction", () => ({
19
19
  buildSetupStatePriceRefreshInstructions: jest.fn(),
20
+ createVaultSyncTransactions: jest.fn(),
20
21
  createVaultSyncTransaction: jest.fn(),
21
22
  createStrategySetupContext: jest.fn(),
22
23
  }))
@@ -26,10 +27,12 @@ const { LoopscaleClient: mockLoopscaleClient } = jest.requireMock("./loopscale")
26
27
  }
27
28
  const {
28
29
  buildSetupStatePriceRefreshInstructions: mockBuildSetupStatePriceRefreshInstructions,
30
+ createVaultSyncTransactions: mockCreateVaultSyncTransactions,
29
31
  createVaultSyncTransaction: mockCreateVaultSyncTransaction,
30
32
  createStrategySetupContext: mockCreateStrategySetupContext,
31
33
  } = jest.requireMock("./vault-interaction") as {
32
34
  buildSetupStatePriceRefreshInstructions: jest.Mock
35
+ createVaultSyncTransactions: jest.Mock
33
36
  createVaultSyncTransaction: jest.Mock
34
37
  createStrategySetupContext: jest.Mock
35
38
  }
@@ -92,6 +95,7 @@ describe("VaultTransactionBuilder Loopscale integration", () => {
92
95
  ;(mockLoopscaleClient as any).mockPrepareVaultTransactions = mockPrepareVaultTransactions
93
96
  ;(mockLoopscaleClient as any).mockCoSign = mockCoSign
94
97
  mockBuildSetupStatePriceRefreshInstructions.mockReset()
98
+ mockCreateVaultSyncTransactions.mockReset()
95
99
  mockCreateVaultSyncTransaction.mockReset()
96
100
  mockCreateStrategySetupContext.mockReset()
97
101
  mockCreateStrategySetupContext.mockReturnValue({ kind: "shared-setup-context" })
@@ -254,3 +258,92 @@ describe("VaultTransactionBuilder Loopscale integration", () => {
254
258
  expect(sendResult.ephemeralAlt).toBeNull()
255
259
  })
256
260
  })
261
+
262
+ describe("VaultTransactionBuilder smart Kamino Vault withdraw fan-out", () => {
263
+ beforeEach(() => {
264
+ mockBuildSetupStatePriceRefreshInstructions.mockReset()
265
+ mockCreateVaultSyncTransactions.mockReset()
266
+ mockCreateStrategySetupContext.mockReset()
267
+ mockCreateStrategySetupContext.mockReturnValue({ kind: "shared-setup-context" })
268
+ })
269
+
270
+ it("splits a single instruction step into multiple sequential transaction sets when the sync helper returns chunks", async () => {
271
+ const config = createVault()
272
+ const refreshIx = ix(config.vault.programId, 90)
273
+ const setupIx = ix(config.vault.programId, 91)
274
+ const firstPreIx = ix(pk(60), 92)
275
+ const firstSyncIx = ix(pk(61), 93)
276
+ const secondSyncIx = ix(pk(62), 94)
277
+ const secondPostIx = ix(pk(63), 95)
278
+ const firstAlt = pk(64)
279
+ const secondAlt = pk(65)
280
+
281
+ mockBuildSetupStatePriceRefreshInstructions.mockImplementation(async () => [refreshIx])
282
+ mockCreateVaultSyncTransactions.mockImplementation(async () => [
283
+ {
284
+ setupInstructions: [setupIx],
285
+ preInstructions: [firstPreIx],
286
+ instruction: firstSyncIx,
287
+ postInstructions: [],
288
+ signers: [],
289
+ addressLookupTableAddresses: [firstAlt],
290
+ },
291
+ {
292
+ setupInstructions: [],
293
+ preInstructions: [],
294
+ instruction: secondSyncIx,
295
+ postInstructions: [secondPostIx],
296
+ signers: [],
297
+ addressLookupTableAddresses: [secondAlt],
298
+ },
299
+ ])
300
+
301
+ const result = await VaultTransactionBuilder
302
+ .create(config)
303
+ .addActions([{ action: "KAMINO_VAULT_WITHDRAW" } as any], { label: "withdraw" })
304
+ .build()
305
+
306
+ expect(mockCreateVaultSyncTransactions).toHaveBeenCalledTimes(1)
307
+ expect(result.labels).toEqual(["withdraw-1-setup", "withdraw-1", "withdraw-2"])
308
+
309
+ expect(result.transactionSets[0]).toEqual({
310
+ label: "withdraw-1-setup",
311
+ instructions: [
312
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 987_654 }),
313
+ refreshIx,
314
+ setupIx,
315
+ ],
316
+ signers: [],
317
+ addressLookupTableAddresses: [firstAlt, config.vault.state.addressLookupTable],
318
+ coSignWithLoopscale: false,
319
+ })
320
+
321
+ expect(result.transactionSets[1]).toEqual({
322
+ label: "withdraw-1",
323
+ instructions: [
324
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 987_654 }),
325
+ ComputeBudgetProgram.requestHeapFrame({ bytes: 256 * 1024 }),
326
+ refreshIx,
327
+ firstPreIx,
328
+ firstSyncIx,
329
+ ],
330
+ signers: [],
331
+ addressLookupTableAddresses: [firstAlt, config.vault.state.addressLookupTable],
332
+ coSignWithLoopscale: false,
333
+ })
334
+
335
+ expect(result.transactionSets[2]).toEqual({
336
+ label: "withdraw-2",
337
+ instructions: [
338
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 987_654 }),
339
+ ComputeBudgetProgram.requestHeapFrame({ bytes: 256 * 1024 }),
340
+ refreshIx,
341
+ secondSyncIx,
342
+ secondPostIx,
343
+ ],
344
+ signers: [],
345
+ addressLookupTableAddresses: [secondAlt, config.vault.state.addressLookupTable],
346
+ coSignWithLoopscale: false,
347
+ })
348
+ })
349
+ })
@@ -15,7 +15,7 @@ import { LoopscaleClient } from "./loopscale"
15
15
  import type { LoopscaleTransactionResponse } from "./loopscale"
16
16
  import {
17
17
  buildSetupStatePriceRefreshInstructions,
18
- createVaultSyncTransaction,
18
+ createVaultSyncTransactions,
19
19
  createStrategySetupContext,
20
20
  type VaultInstruction,
21
21
  } from "./vault-interaction"
@@ -473,7 +473,7 @@ export class VaultTransactionBuilder {
473
473
 
474
474
  const stepCU = step.options.computeUnitLimit ?? defaultCU
475
475
  const stepHeap = step.options.heapFrameBytes ?? defaultHeap
476
- const syncResult = await createVaultSyncTransaction({
476
+ const syncResults = await createVaultSyncTransactions({
477
477
  instructions: step.instructions,
478
478
  owner: vaultPda,
479
479
  connection,
@@ -487,14 +487,47 @@ export class VaultTransactionBuilder {
487
487
 
488
488
  const stepPriceRefreshIxs = await buildSetupStatePriceRefreshInstructions(sharedSetupContext)
489
489
 
490
- if (syncResult.setupInstructions.length > 0) {
491
- const setupSet: TransactionSet = {
492
- label: `${step.label}-setup`,
490
+ for (const [syncIndex, syncResult] of syncResults.entries()) {
491
+ const txLabel = syncResults.length === 1
492
+ ? step.label
493
+ : `${step.label}-${syncIndex + 1}`
494
+
495
+ if (syncResult.setupInstructions.length > 0) {
496
+ const setupSet: TransactionSet = {
497
+ label: `${txLabel}-setup`,
498
+ instructions: [
499
+ ComputeBudgetProgram.setComputeUnitLimit({ units: defaultCU }),
500
+ ...syncResult.setupInstructions,
501
+ ],
502
+ signers: [],
503
+ addressLookupTableAddresses: mergeAddressLookupTableAddresses(
504
+ syncResult.addressLookupTableAddresses,
505
+ extraLookupTableAddresses,
506
+ vault.state.addressLookupTable ? [vault.state.addressLookupTable] : [],
507
+ ),
508
+ coSignWithLoopscale: false,
509
+ }
510
+ if (shouldInjectPriceRefresh(setupSet, vault.programId, squadsProgram)) {
511
+ setupSet.instructions = insertAfterLeadingComputeBudgetAndScopeInstructions(
512
+ setupSet.instructions,
513
+ stepPriceRefreshIxs,
514
+ )
515
+ }
516
+ transactionSets.push(setupSet)
517
+ for (const alt of setupSet.addressLookupTableAddresses) {
518
+ allAltAddresses.add(alt.toBase58())
519
+ }
520
+ }
521
+
522
+ const syncSet: TransactionSet = {
523
+ label: txLabel,
493
524
  instructions: [
494
- ComputeBudgetProgram.setComputeUnitLimit({ units: defaultCU }),
495
- ...syncResult.setupInstructions,
525
+ ...buildComputeBudgetIxs(stepCU, stepHeap, step.options.priorityFee),
526
+ ...syncResult.preInstructions,
527
+ syncResult.instruction,
528
+ ...syncResult.postInstructions,
496
529
  ],
497
- signers: [],
530
+ signers: syncResult.signers,
498
531
  addressLookupTableAddresses: mergeAddressLookupTableAddresses(
499
532
  syncResult.addressLookupTableAddresses,
500
533
  extraLookupTableAddresses,
@@ -502,45 +535,18 @@ export class VaultTransactionBuilder {
502
535
  ),
503
536
  coSignWithLoopscale: false,
504
537
  }
505
- if (shouldInjectPriceRefresh(setupSet, vault.programId, squadsProgram)) {
506
- setupSet.instructions = insertAfterLeadingComputeBudgetAndScopeInstructions(
507
- setupSet.instructions,
538
+ if (shouldInjectPriceRefresh(syncSet, vault.programId, squadsProgram)) {
539
+ syncSet.instructions = insertAfterLeadingComputeBudgetAndScopeInstructions(
540
+ syncSet.instructions,
508
541
  stepPriceRefreshIxs,
509
542
  )
510
543
  }
511
- transactionSets.push(setupSet)
512
- for (const alt of setupSet.addressLookupTableAddresses) {
544
+ transactionSets.push(syncSet)
545
+
546
+ for (const alt of syncSet.addressLookupTableAddresses) {
513
547
  allAltAddresses.add(alt.toBase58())
514
548
  }
515
549
  }
516
-
517
- const syncSet: TransactionSet = {
518
- label: step.label,
519
- instructions: [
520
- ...buildComputeBudgetIxs(stepCU, stepHeap, step.options.priorityFee),
521
- ...syncResult.preInstructions,
522
- syncResult.instruction,
523
- ...syncResult.postInstructions,
524
- ],
525
- signers: syncResult.signers,
526
- addressLookupTableAddresses: mergeAddressLookupTableAddresses(
527
- syncResult.addressLookupTableAddresses,
528
- extraLookupTableAddresses,
529
- vault.state.addressLookupTable ? [vault.state.addressLookupTable] : [],
530
- ),
531
- coSignWithLoopscale: false,
532
- }
533
- if (shouldInjectPriceRefresh(syncSet, vault.programId, squadsProgram)) {
534
- syncSet.instructions = insertAfterLeadingComputeBudgetAndScopeInstructions(
535
- syncSet.instructions,
536
- stepPriceRefreshIxs,
537
- )
538
- }
539
- transactionSets.push(syncSet)
540
-
541
- for (const alt of syncSet.addressLookupTableAddresses) {
542
- allAltAddresses.add(alt.toBase58())
543
- }
544
550
  }
545
551
 
546
552
  const lookupTableAddresses = [...allAltAddresses].map((a) => new PublicKey(a))