@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,349 @@
1
+ import { describe, expect, it, jest, beforeEach } from "@jest/globals"
2
+ import {
3
+ AddressLookupTableAccount,
4
+ ComputeBudgetProgram,
5
+ Keypair,
6
+ PublicKey,
7
+ TransactionInstruction,
8
+ VersionedTransaction,
9
+ } from "@solana/web3.js"
10
+
11
+ import { VaultTransactionBuilder, type VaultTransactionBuilderConfig } from "./vaultTransactionBuilder"
12
+ import type { LoopscalePreparedTransaction } from "./loopscale"
13
+
14
+ jest.mock("./loopscale", () => ({
15
+ LoopscaleClient: jest.fn(),
16
+ }))
17
+
18
+ jest.mock("./vault-interaction", () => ({
19
+ buildSetupStatePriceRefreshInstructions: jest.fn(),
20
+ createVaultSyncTransactions: jest.fn(),
21
+ createVaultSyncTransaction: jest.fn(),
22
+ createStrategySetupContext: jest.fn(),
23
+ }))
24
+
25
+ const { LoopscaleClient: mockLoopscaleClient } = jest.requireMock("./loopscale") as {
26
+ LoopscaleClient: jest.Mock
27
+ }
28
+ const {
29
+ buildSetupStatePriceRefreshInstructions: mockBuildSetupStatePriceRefreshInstructions,
30
+ createVaultSyncTransactions: mockCreateVaultSyncTransactions,
31
+ createVaultSyncTransaction: mockCreateVaultSyncTransaction,
32
+ createStrategySetupContext: mockCreateStrategySetupContext,
33
+ } = jest.requireMock("./vault-interaction") as {
34
+ buildSetupStatePriceRefreshInstructions: jest.Mock
35
+ createVaultSyncTransactions: jest.Mock
36
+ createVaultSyncTransaction: jest.Mock
37
+ createStrategySetupContext: jest.Mock
38
+ }
39
+
40
+ type LoopscaleResponseOptions = Parameters<VaultTransactionBuilder["addLoopscaleResponse"]>[1]
41
+ const validLoopscaleOptions: LoopscaleResponseOptions = { label: "loopscale-step" }
42
+ // @ts-expect-error Loopscale builder steps only accept label metadata.
43
+ const invalidLoopscaleOptions: LoopscaleResponseOptions = { priorityFee: 123 }
44
+ void invalidLoopscaleOptions
45
+
46
+ function pk(seed: number): PublicKey {
47
+ return new PublicKey(Uint8Array.from({ length: 32 }, () => seed))
48
+ }
49
+
50
+ function ix(programId: PublicKey, dataSeed: number): TransactionInstruction {
51
+ return new TransactionInstruction({
52
+ programId,
53
+ keys: [],
54
+ data: Buffer.from([dataSeed]),
55
+ })
56
+ }
57
+
58
+ function createVault(overrides: Partial<VaultTransactionBuilderConfig> = {}): VaultTransactionBuilderConfig {
59
+ return {
60
+ vault: {
61
+ selfAddress: pk(10),
62
+ programId: pk(11),
63
+ state: {
64
+ addressLookupTable: pk(12),
65
+ squadsVault: pk(21),
66
+ },
67
+ } as any,
68
+ connection: {
69
+ getAddressLookupTable: jest.fn(async () => ({ value: null })),
70
+ getLatestBlockhash: jest.fn(async () => ({
71
+ blockhash: PublicKey.default.toBase58(),
72
+ lastValidBlockHeight: 123,
73
+ })),
74
+ sendTransaction: jest.fn(async () => "sig-123"),
75
+ confirmTransaction: jest.fn(async () => ({ value: { err: null } })),
76
+ getSlot: jest.fn(),
77
+ } as any,
78
+ signer: pk(20),
79
+ computeUnitLimit: 987_654,
80
+ heapFrameBytes: 256 * 1024,
81
+ ...overrides,
82
+ }
83
+ }
84
+
85
+ describe("VaultTransactionBuilder Loopscale integration", () => {
86
+ beforeEach(() => {
87
+ mockLoopscaleClient.mockClear()
88
+ const mockPrepareVaultTransactions = jest.fn()
89
+ const mockCoSign = jest.fn()
90
+ mockLoopscaleClient.mockImplementation((config) => ({
91
+ config,
92
+ prepareVaultTransactions: mockPrepareVaultTransactions,
93
+ coSign: mockCoSign,
94
+ }))
95
+ ;(mockLoopscaleClient as any).mockPrepareVaultTransactions = mockPrepareVaultTransactions
96
+ ;(mockLoopscaleClient as any).mockCoSign = mockCoSign
97
+ mockBuildSetupStatePriceRefreshInstructions.mockReset()
98
+ mockCreateVaultSyncTransactions.mockReset()
99
+ mockCreateVaultSyncTransaction.mockReset()
100
+ mockCreateStrategySetupContext.mockReset()
101
+ mockCreateStrategySetupContext.mockReturnValue({ kind: "shared-setup-context" })
102
+ })
103
+
104
+ it("narrows Loopscale step options to label-only metadata", () => {
105
+ expect(validLoopscaleOptions).toEqual({ label: "loopscale-step" })
106
+ })
107
+
108
+ it("uses builder defaults and injects price refresh only into local Loopscale-derived vault transactions", async () => {
109
+ const config = createVault()
110
+ const refreshIx = ix(config.vault.programId, 200)
111
+ const vaultSetupIx = ix(config.vault.programId, 1)
112
+ const localVaultIx = ix(config.vault.programId, 2)
113
+ const plainSetupIx = ix(pk(30), 3)
114
+ const coSignedIx = ix(pk(31), 4)
115
+ const rawAlt = pk(32)
116
+
117
+ const preparedTransactions: LoopscalePreparedTransaction[] = [
118
+ {
119
+ setupInstructions: [vaultSetupIx],
120
+ instructions: [localVaultIx],
121
+ signers: [],
122
+ addressLookupTableAddresses: [rawAlt],
123
+ requiresLoopscaleCoSign: false,
124
+ },
125
+ {
126
+ setupInstructions: [plainSetupIx],
127
+ instructions: [coSignedIx],
128
+ signers: [],
129
+ addressLookupTableAddresses: [rawAlt],
130
+ requiresLoopscaleCoSign: true,
131
+ },
132
+ ]
133
+
134
+ const mockPrepareVaultTransactions = (mockLoopscaleClient as any).mockPrepareVaultTransactions as jest.Mock
135
+ mockPrepareVaultTransactions.mockImplementation(async () => preparedTransactions)
136
+ mockBuildSetupStatePriceRefreshInstructions.mockImplementation(async () => [refreshIx])
137
+
138
+ const result = await VaultTransactionBuilder
139
+ .create(config)
140
+ .addLoopscaleResponse({ message: "", signatures: [] } as any, { label: "loop" })
141
+ .build()
142
+
143
+ expect(mockLoopscaleClient).toHaveBeenCalledTimes(1)
144
+ expect(mockLoopscaleClient).toHaveBeenCalledWith({
145
+ connection: config.connection,
146
+ userWallet: config.vault.state.squadsVault,
147
+ baseUrl: undefined,
148
+ debug: undefined,
149
+ })
150
+
151
+ expect(result.labels).toEqual(["loop-1-setup", "loop-1", "loop-2-setup", "loop-2"])
152
+
153
+ const firstSetup = result.transactionSets[0]!
154
+ expect(firstSetup.instructions).toEqual([
155
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 987_654 }),
156
+ refreshIx,
157
+ vaultSetupIx,
158
+ ])
159
+ expect(firstSetup.addressLookupTableAddresses).toEqual([config.vault.state.addressLookupTable])
160
+ expect(firstSetup.coSignWithLoopscale).toBe(false)
161
+
162
+ const firstMain = result.transactionSets[1]!
163
+ expect(firstMain.instructions).toEqual([refreshIx, localVaultIx])
164
+ expect(firstMain.addressLookupTableAddresses).toEqual([rawAlt, config.vault.state.addressLookupTable])
165
+ expect(firstMain.coSignWithLoopscale).toBe(false)
166
+
167
+ const secondSetup = result.transactionSets[2]!
168
+ expect(secondSetup.instructions).toEqual([
169
+ ComputeBudgetProgram.setComputeUnitLimit({ units: 987_654 }),
170
+ plainSetupIx,
171
+ ])
172
+ expect(secondSetup.addressLookupTableAddresses).toEqual([config.vault.state.addressLookupTable])
173
+ expect(secondSetup.coSignWithLoopscale).toBe(false)
174
+
175
+ const secondMain = result.transactionSets[3]!
176
+ expect(secondMain.instructions).toEqual([coSignedIx])
177
+ expect(secondMain.addressLookupTableAddresses).toEqual([rawAlt])
178
+ expect(secondMain.coSignWithLoopscale).toBe(true)
179
+ })
180
+
181
+ it("only co-signs flagged transactions and forwards loopscale client config to build and send paths", async () => {
182
+ const payer = Keypair.generate()
183
+ const persistentAlt = pk(50)
184
+ const config = createVault({
185
+ vault: {
186
+ selfAddress: pk(10),
187
+ programId: pk(11),
188
+ state: {
189
+ addressLookupTable: persistentAlt,
190
+ squadsVault: pk(51),
191
+ },
192
+ } as any,
193
+ loopscale: {
194
+ baseUrl: "https://loopscale.test",
195
+ debug: true,
196
+ },
197
+ })
198
+
199
+ const localIx = ix(pk(40), 1)
200
+ const coSignedIx = ix(pk(41), 2)
201
+ const persistentAltAccount = new AddressLookupTableAccount({
202
+ key: persistentAlt,
203
+ state: {
204
+ deactivationSlot: 0n,
205
+ lastExtendedSlot: 0,
206
+ lastExtendedSlotStartIndex: 0,
207
+ authority: payer.publicKey,
208
+ addresses: [config.signer, localIx.programId, coSignedIx.programId],
209
+ },
210
+ })
211
+ ;(config.connection.getAddressLookupTable as jest.Mock).mockImplementation(async (address: PublicKey) => ({
212
+ value: address.equals(persistentAlt) ? persistentAltAccount : null,
213
+ }))
214
+
215
+ const mockPrepareVaultTransactions = (mockLoopscaleClient as any).mockPrepareVaultTransactions as jest.Mock
216
+ const mockCoSign = (mockLoopscaleClient as any).mockCoSign as jest.Mock
217
+ mockPrepareVaultTransactions.mockImplementation(async () => [
218
+ {
219
+ setupInstructions: [],
220
+ instructions: [localIx],
221
+ signers: [],
222
+ addressLookupTableAddresses: [],
223
+ requiresLoopscaleCoSign: false,
224
+ },
225
+ {
226
+ setupInstructions: [],
227
+ instructions: [coSignedIx],
228
+ signers: [],
229
+ addressLookupTableAddresses: [],
230
+ requiresLoopscaleCoSign: true,
231
+ },
232
+ ] satisfies LoopscalePreparedTransaction[])
233
+ mockBuildSetupStatePriceRefreshInstructions.mockImplementation(async () => [])
234
+ mockCoSign.mockImplementation(async (transaction: VersionedTransaction) => transaction)
235
+
236
+ const result = await VaultTransactionBuilder
237
+ .create(config)
238
+ .addLoopscaleResponse({ message: "", signatures: [] } as any, { label: "loop" })
239
+ .build()
240
+
241
+ const sendResult = await result.send({ signers: [payer] })
242
+
243
+ expect(mockLoopscaleClient).toHaveBeenNthCalledWith(1, {
244
+ connection: config.connection,
245
+ userWallet: config.vault.state.squadsVault,
246
+ baseUrl: "https://loopscale.test",
247
+ debug: true,
248
+ })
249
+ expect(mockLoopscaleClient).toHaveBeenNthCalledWith(2, {
250
+ connection: config.connection,
251
+ userWallet: config.vault.state.squadsVault,
252
+ baseUrl: "https://loopscale.test",
253
+ debug: true,
254
+ })
255
+ expect(mockCoSign).toHaveBeenCalledTimes(1)
256
+ expect((config.connection.sendTransaction as jest.Mock)).toHaveBeenCalledTimes(2)
257
+ expect(sendResult.signatures).toEqual(["sig-123", "sig-123"])
258
+ expect(sendResult.ephemeralAlt).toBeNull()
259
+ })
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
+ })