@zebec-network/zebec-vault-sdk 5.2.1 → 5.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +294 -215
  2. package/package.json +3 -3
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A Typescript SDK for interacting with Zebec Vault on Solana, enabling secure multi operations, token streaming, staking, and virtual card management.
4
4
 
5
- # **Features**
5
+ ## **Features**
6
6
 
7
7
  - **Vault Management**: Create and manage secure vaults with proposal-based execution
8
8
  - **Token Operations**: Deposit and withdraw SOL and SPL tokens
@@ -11,7 +11,7 @@ A Typescript SDK for interacting with Zebec Vault on Solana, enabling secure mul
11
11
  - **Virtual Cards**: Create and load Zebec cards with automatic token swapping
12
12
  - **Jupiter Integration**: Built-in token swapping for card operations
13
13
 
14
- # **Installation**
14
+ ## **Installation**
15
15
 
16
16
  ```jsx
17
17
  npm install @zebec-network/zebec-vault-sdk
@@ -21,23 +21,22 @@ npm install @zebec-network/zebec-vault-sdk
21
21
  yarn add @zebec-network/zebec-vault-sdk
22
22
  ```
23
23
 
24
- # **Quick Start**
24
+ ## **Quick Start**
25
25
 
26
- ## **Setup**
26
+ ### **Setup**
27
27
 
28
28
  ```tsx
29
29
  import { Connection, Keypair } from "@solana/web3.js";
30
30
  import { createAnchorProvider, ZebecVaultService } from "@zebec-network/zebec-vault-sdk";
31
31
 
32
32
  // Create connection
33
- const connection = new Connection("https://api.mainnet-beta.solana.com"); // use private dedicatd rpc for production
33
+ const connection = new Connection("https://api.mainnet-beta.solana.com"); // use a private dedicated RPC for production
34
34
 
35
35
  // Create wallet adapter
36
- // for frontend application you can use wallet provided by the wallet provider
37
- // for example:
36
+ // For a frontend application, use the wallet provided by the wallet adapter:
38
37
  const wallet = useAnchorWallet();
39
38
 
40
- // for server side app you can use Wallet class provided by @coral-xyz/anchor
39
+ // For a server-side app, use the Wallet class from @coral-xyz/anchor:
41
40
  const wallet = new Wallet(keypair); // create keypair from secret key
42
41
 
43
42
  // Create provider
@@ -51,29 +50,29 @@ const vaultService = ZebecVaultService.create(provider, "mainnet-beta");
51
50
 
52
51
  ### **Vault Operations**
53
52
 
54
- Each user has a vault that is derived from the seed containing users wallet. Then a vault signer is derived from the vault taking it as a seed. The vault signer is responsible for holding SPL Tokens and Sol balances and signing the transaction during CPI executions.
53
+ Each user has a vault that is derived from a seed containing the user's wallet. A vault signer is then derived from the vault as a seed. The vault signer holds SPL token and SOL balances and signs transactions during CPI executions.
55
54
 
56
- **Create a vault**
55
+ #### Create a vault
57
56
 
58
- ```jsx
57
+ ```tsx
59
58
  const payload = await vaultService.createVault({
60
- payer: wallet.publicKey, // optional if using AnchorProvider
59
+ payer: wallet.publicKey, // optional if using AnchorProvider
61
60
  });
62
61
 
63
62
  const signature = await payload.execute();
64
63
  console.log("Vault created:", signature);
65
64
  ```
66
65
 
67
- **Get Vault Information**
66
+ #### Get Vault Information
68
67
 
69
68
  ```tsx
70
- // Get specific user's vault
69
+ // Get a specific user's vault (param is optional when using AnchorProvider)
71
70
  const vaultInfo = await vaultService.getVaultInfoOfUser(userAddress);
72
71
 
73
72
  if (vaultInfo) {
74
- console.log("Vault:", vaultInfo.vault.toString());
75
- console.log("Owner:", vaultInfo.owner.toString());
76
- console.log("Created:", new Date(vaultInfo.createdDate * 1000));
73
+ console.log("Vault:", vaultInfo.vault.toString());
74
+ console.log("Owner:", vaultInfo.owner.toString());
75
+ console.log("Created:", new Date(vaultInfo.createdDate * 1000));
77
76
  }
78
77
 
79
78
  // Get all vaults
@@ -81,101 +80,102 @@ const allVaults = await vaultService.getAllVaultsInfo();
81
80
  console.log(`Total vaults: ${allVaults.length}`);
82
81
  ```
83
82
 
84
- **Deposit SOL**
83
+ #### Deposit SOL
85
84
 
86
85
  ```tsx
87
86
  const payload = await vaultService.depositSol({
88
- depositor: wallet.publicKey,
89
- amount: 1.5, // SOL amount
87
+ depositor: wallet.publicKey,
88
+ amount: 1.5, // SOL amount
90
89
  });
90
+
91
+ const signature = await payload.execute();
91
92
  ```
92
93
 
93
- **Deposit SPL Tokens**
94
+ #### Deposit SPL Tokens
94
95
 
95
96
  ```tsx
96
97
  const payload = await vaultService.deposit({
97
- depositor: wallet.publicKey,
98
- tokenMint: "TOKEN_MINT_ADDRESS",
99
- amount: 100, // token amount
98
+ depositor: wallet.publicKey,
99
+ tokenMint: "TOKEN_MINT_ADDRESS",
100
+ amount: 100, // token amount
100
101
  });
101
102
 
102
103
  const signature = await payload.execute();
103
104
  ```
104
105
 
105
- > **_Note: If WSOL address is given in tokenMint, it will wrap SOL to WSOL and deposit as spl token._**
106
+ > **_Note: If the WSOL address is given as `tokenMint`, SOL will be wrapped to WSOL and deposited as an SPL token._**
106
107
 
107
- **Withdraw SOL**
108
+ #### Withdraw SOL
108
109
 
109
110
  ```tsx
110
111
  const payload = await vaultService.withdrawSol({
111
- withdrawer: wallet.publicKey,
112
- amount: 0.5,
112
+ withdrawer: wallet.publicKey,
113
+ amount: 0.5,
113
114
  });
114
115
 
115
116
  const signature = await payload.execute();
116
117
  ```
117
118
 
118
- **Withdraw SPL Tokens**
119
+ #### Withdraw SPL Tokens
119
120
 
120
121
  ```tsx
121
122
  const payload = await vaultService.withdraw({
122
- withdrawer: wallet.publicKey,
123
- tokenMint: "TOKEN_MINT_ADDRESS",
124
- amount: 50,
123
+ withdrawer: wallet.publicKey,
124
+ tokenMint: "TOKEN_MINT_ADDRESS",
125
+ amount: 50,
125
126
  });
126
127
 
127
128
  const signature = await payload.execute();
128
129
  ```
129
130
 
130
- > **_Note: If WSOL is address in given in tokenMint, it will with withdraw WSOL and unwrap into withdrawer wallet._**
131
+ > **_Note: If the WSOL address is given as `tokenMint`, WSOL will be withdrawn and unwrapped into the withdrawer's wallet._**
131
132
 
132
133
  ### Proposal System
133
134
 
134
- Proposal System includes methods like creating proposal, appending actions and executing proposal. A proposal is like a transaction in Solana but with extra fields like proposal stage, created date, expiry dates, execution status, name, etc. Each Proposal contains one or more Proposal Action which is similar to Transaction Instruction in Solana. While executing the proposal, the Proposal Actions get executed in order in which its resides inside a Proposal. You can delete the Proposal and claim SOLs used in creating the Proposal. Each Proposal belongs to a vault and only signer of that vault can execute the Proposal, delete or append any Proposal Actions in the Proposal.
135
+ The Proposal System includes methods for creating proposals, appending actions, and executing proposals. A proposal is like a Solana transaction but with extra fields such as proposal stage, created date, expiry date, execution status, and name. Each proposal contains one or more `ProposalAction`, which is similar to a `TransactionInstruction` in Solana. During execution, proposal actions run in order. You can delete a proposal to reclaim the SOL rent used to create it. Each proposal belongs to a vault and only the vault signer can execute, delete, or append actions to it.
135
136
 
136
- **Create a Proposal**
137
+ #### Create a Proposal
137
138
 
138
139
  ```tsx
139
- import { SystemProgram, Keypair } from "@solana/web3.js";
140
+ import { SystemProgram } from "@solana/web3.js";
140
141
  import { parseSol } from "@zebec-network/solana-common";
142
+ import { deriveUserVault, deriveVaultSigner } from "@zebec-network/zebec-vault-sdk";
141
143
 
142
- const [vault] = deriveUserVault(wallet.publicKey, service.vaultV1ProgramId);
143
- const [vaultSigner] = deriveVaultSigner(vault, service.vaultV1ProgramId);
144
+ const [vault] = deriveUserVault(wallet.publicKey, vaultService.vaultV1ProgramId);
145
+ const [vaultSigner] = deriveVaultSigner(vault, vaultService.vaultV1ProgramId);
144
146
  const recipient = "<Recipient PublicKey>";
145
147
 
146
148
  // Create custom instructions. For example:
147
149
  const instruction = SystemProgram.transfer({
148
- fromPubkey: vaultSigner,
149
- toPubkey: recipient,
150
- lamports: Number(parseSol(1)),
150
+ fromPubkey: vaultSigner,
151
+ toPubkey: recipient,
152
+ lamports: Number(parseSol(1)),
151
153
  });
152
154
 
153
- const proposalKeypair = Keypair.generate();
154
- console.log("Proposal:", proposalKeypair.publicKey.toString());
155
-
156
155
  const payload = await vaultService.createProposal({
157
- proposer: wallet.publicKey,
158
- name: "Transfer SOL",
159
- actions: [instruction],
156
+ proposer: wallet.publicKey,
157
+ name: "Transfer SOL",
158
+ actions: [instruction],
159
+ // proposalKeypair: Keypair.generate(), // optional; auto-generated if omitted
160
160
  });
161
161
 
162
162
  const signature = await payload.execute();
163
163
  ```
164
164
 
165
- ### **Get Proposals**
165
+ #### Get Proposals
166
166
 
167
167
  ```tsx
168
168
  const proposals = await vaultService.getProposalsInfoOfVault(vaultAddress);
169
169
 
170
170
  proposals.forEach((proposal) => {
171
- console.log("Proposal:", proposal.name);
172
- console.log("Status:", proposal.proposalStage);
173
- console.log("Actions:", proposal.actions.length);
174
- console.log("Executed:", proposal.isExecuted);
171
+ console.log("Proposal:", proposal.name);
172
+ console.log("Status:", proposal.proposalStage);
173
+ console.log("Actions:", proposal.actions.length);
174
+ console.log("Executed:", proposal.isExecuted);
175
175
  });
176
176
  ```
177
177
 
178
- **Append Actions**
178
+ #### Append Actions
179
179
 
180
180
  ```tsx
181
181
  import { SystemProgram } from "@solana/web3.js";
@@ -184,66 +184,71 @@ import { parseSol } from "@zebec-network/solana-common";
184
184
  const proposal = "<Proposal PublicKey>";
185
185
 
186
186
  const instruction = SystemProgram.transfer({
187
- fromPubkey: vaultSigner,
188
- toPubkey: wallet.publicKey,
189
- lamports: Number(parseSol(0.01)),
187
+ fromPubkey: vaultSigner,
188
+ toPubkey: wallet.publicKey,
189
+ lamports: Number(parseSol(0.01)),
190
190
  });
191
191
 
192
- const payload = await service.appendActions({
193
- actions: actionsB,
194
- proposal,
192
+ const payload = await vaultService.appendActions({
193
+ proposal,
194
+ actions: [instruction],
195
195
  });
196
196
 
197
197
  const signature = await payload.execute();
198
198
  ```
199
199
 
200
- **Delete Proposal**
200
+ #### Delete Proposal
201
201
 
202
202
  ```tsx
203
203
  const proposal = "<Proposal PublicKey>";
204
- const payload = await service.deleteProposal({ proposal });
204
+ const payload = await vaultService.deleteProposal({ proposal });
205
205
  const deleteProposalSignature = await payload.execute();
206
206
  ```
207
207
 
208
- **Execute a Proposal**
208
+ #### Execute a Proposal
209
209
 
210
210
  ```tsx
211
211
  const proposal = "<Proposal PublicKey>";
212
212
  const lookupTableAddress = "<Lookup Table Address PublicKey>";
213
213
 
214
214
  const payload = await vaultService.executeProposal({
215
- caller: wallet.publicKey,
216
- proposal,
217
- addressLookupTables: [lookupTableAddress], // optional
215
+ caller: wallet.publicKey,
216
+ proposal,
217
+ addressLookupTables: [lookupTableAddress], // optional
218
218
  });
219
219
 
220
220
  const signature = await payload.execute();
221
221
  ```
222
222
 
223
- **Execute Proposal Directly (Single Transaction)**
224
- Proposal Action can be directly executed without creating Proposal. However, it may cause transaction size limit while some size limit can be mitigated using address lookup table.
223
+ #### Execute Proposal Directly (Single Transaction)
224
+
225
+ Proposal actions can be executed directly without creating a persistent proposal. However, this may hit the transaction size limit; some cases can be mitigated using address lookup tables.
225
226
 
226
227
  ```tsx
227
- const [vault] = deriveUserVault(wallet.publicKey, service.vaultV1ProgramId);
228
- const [vaultSigner] = deriveVaultSigner(vault, service.vaultV1ProgramId);
228
+ import { SystemProgram, TransactionInstruction } from "@solana/web3.js";
229
+ import { parseSol } from "@zebec-network/solana-common";
230
+ import { deriveUserVault, deriveVaultSigner } from "@zebec-network/zebec-vault-sdk";
231
+
232
+ const [vault] = deriveUserVault(wallet.publicKey, vaultService.vaultV1ProgramId);
233
+ const [vaultSigner] = deriveVaultSigner(vault, vaultService.vaultV1ProgramId);
229
234
  const recipient = "<Recipient PublicKey>";
230
235
 
231
236
  const instruction1 = SystemProgram.transfer({
232
- fromPubkey: vaultSigner,
233
- toPubkey: recipient,
234
- lamports: Number(parseSol(1)),
237
+ fromPubkey: vaultSigner,
238
+ toPubkey: recipient,
239
+ lamports: Number(parseSol(1)),
235
240
  });
236
241
 
237
242
  const instruction2 = new TransactionInstruction({
238
- keys: [],
239
- programId: MEMO_PROGRAM_ID,
240
- data: Buffer.from("Transfer 1 sol from vault signer to recipient", "utf8"),
243
+ keys: [],
244
+ programId: MEMO_PROGRAM_ID,
245
+ data: Buffer.from("Transfer 1 sol from vault signer to recipient", "utf8"),
241
246
  });
242
247
 
243
248
  const payload = await vaultService.executeProposalDirect({
244
- proposer: wallet.publicKey,
245
- actions: [instruction1, instruction2],
246
- addressLookupTables: [lookupTableAddress],
249
+ proposer: wallet.publicKey,
250
+ actions: [instruction1, instruction2],
251
+ addressLookupTables: [lookupTableAddress],
247
252
  });
248
253
 
249
254
  const signature = await payload.execute();
@@ -251,80 +256,104 @@ const signature = await payload.execute();
251
256
 
252
257
  ### **Payment Streaming**
253
258
 
254
- **Create a Stream**
259
+ #### Create a Stream
255
260
 
256
261
  ```tsx
257
262
  const payload = await vaultService.createStreamFromVault({
258
- vaultOwner: wallet.publicKey,
259
- receiver: recipientAddress,
260
- streamToken: tokenMintAddress,
261
- amount: 1000, // total amount
262
- duration: 2592000, // 30 days in seconds
263
- startNow: true,
264
- startTime: Math.floor(Date.now() / 1000),
265
- automaticWithdrawal: false,
266
- cancelableByRecipient: true,
267
- cancelableBySender: true,
268
- isPausable: true,
269
- transferableByRecipient: false,
270
- transferableBySender: false,
271
- canTopup: true,
272
- rateUpdatable: false,
273
- cliffPercentage: 0, // 0-100
274
- autoWithdrawFrequency: 86400, // 1 day
275
- streamName: "Monthly Payment",
263
+ vaultOwner: wallet.publicKey,
264
+ receiver: recipientAddress,
265
+ streamToken: tokenMintAddress,
266
+ streamConfigName: "Config-001", // name of the stream configuration to use
267
+ amount: 1000, // total amount
268
+ duration: 2592000, // 30 days in seconds
269
+ startNow: true,
270
+ startTime: Math.floor(Date.now() / 1000),
271
+ automaticWithdrawal: false,
272
+ cancelableByRecipient: true,
273
+ cancelableBySender: true,
274
+ isPausable: true,
275
+ transferableByRecipient: false,
276
+ transferableBySender: false,
277
+ canTopup: true,
278
+ rateUpdatable: false,
279
+ cliffPercentage: 0, // 0-100
280
+ autoWithdrawFrequency: 86400, // 1 day in seconds; required when automaticWithdrawal is true
281
+ streamName: "Monthly Payment",
276
282
  });
277
283
 
278
- const await payload.execute();
284
+ const signature = await payload.execute();
279
285
  ```
280
286
 
281
- **Create Multiple Streams**
287
+ #### Create Multiple Streams
282
288
 
283
- There is a difference in payload that is return for creating multiple stream. While other payload is an instance of `TransactionPayload` class, the payload returned for creating multiple stream is an instance of `MultiTransactionPayload`. After invoking execute method in payload, it returns `MultiTransactionPayloadExecuteReturn` type which is an Array of union of `PromiseSettledResult<*string*>` and an object consisting of transactions data and transactions. The `PromiseSettledResult<*string*>` contains signature string as a value if the execution is success otherwise it it contains reason for the failure.
289
+ There is a difference in the payload returned for creating multiple streams. While other payloads are instances of `TransactionPayload`, the payload returned for multiple streams is an instance of `MultiTransactionPayload`. After calling `execute()`, it returns `MultiTransactionPayloadExecuteReturn`, which is an array of settled promise results each containing either a transaction signature on success or a failure reason.
284
290
 
285
291
  ```tsx
286
292
  export type MultiTransactionPayloadExecuteReturn = (PromiseSettledResult<string> & {
287
- transactionData: {
288
- readonly instructions: web3.TransactionInstruction[];
289
- readonly feePayer: web3.PublicKey;
290
- readonly signers?: web3.Signer[];
291
- readonly addressLookupTableAccounts?: web3.AddressLookupTableAccount[];
292
- };
293
- transaction: web3.VersionedTransaction;
293
+ transactionData: {
294
+ readonly instructions: web3.TransactionInstruction[];
295
+ readonly feePayer: web3.PublicKey;
296
+ readonly signers?: web3.Signer[];
297
+ readonly addressLookupTableAccounts?: web3.AddressLookupTableAccount[];
298
+ };
299
+ transaction: web3.VersionedTransaction;
294
300
  })[];
295
301
  ```
296
302
 
297
303
  ```tsx
298
304
  const payload = await vaultService.createMultipleStreamFromVault({
299
- vaultOwner: wallet.publicKey,
300
- streamInfo: [
301
- {
302
- receiver: recipient1,
303
- streamToken: tokenMint,
304
- amount: 500,
305
- duration: 2592000,
306
- // ... other stream parameters
307
- },
308
- {
309
- receiver: recipient2,
310
- streamToken: tokenMint,
311
- amount: 1000,
312
- duration: 2592000,
313
- // ... other stream parameters
314
- },
315
- ],
305
+ vaultOwner: wallet.publicKey,
306
+ streamConfigName: "Config-001", // applies to all streams
307
+ streamInfo: [
308
+ {
309
+ receiver: recipient1,
310
+ streamToken: tokenMint,
311
+ amount: 500,
312
+ duration: 2592000,
313
+ startNow: false,
314
+ startTime: Math.floor(Date.now() / 1000) + 30,
315
+ automaticWithdrawal: false,
316
+ cancelableByRecipient: false,
317
+ cancelableBySender: false,
318
+ isPausable: false,
319
+ transferableByRecipient: false,
320
+ transferableBySender: false,
321
+ canTopup: false,
322
+ rateUpdatable: false,
323
+ cliffPercentage: 0,
324
+ streamName: "Stream 1",
325
+ },
326
+ {
327
+ receiver: recipient2,
328
+ streamToken: tokenMint,
329
+ amount: 1000,
330
+ duration: 2592000,
331
+ startNow: false,
332
+ startTime: Math.floor(Date.now() / 1000) + 30,
333
+ automaticWithdrawal: false,
334
+ cancelableByRecipient: false,
335
+ cancelableBySender: false,
336
+ isPausable: false,
337
+ transferableByRecipient: false,
338
+ transferableBySender: false,
339
+ canTopup: false,
340
+ rateUpdatable: false,
341
+ cliffPercentage: 0,
342
+ streamName: "Stream 2",
343
+ },
344
+ ],
316
345
  });
317
346
 
318
- // Execute all streams in multiple transactions
319
- const result = await payload.execute();
347
+ // Execute all streams in separate transactions
348
+ const results = await payload.execute();
320
349
  ```
321
350
 
322
351
  ### **Pause/Resume a Stream**
323
352
 
324
353
  ```tsx
325
354
  const payload = await vaultService.pauseResumeStream({
326
- vaultOwner: wallet.publicKey,
327
- streamMetadata: streamAddress,
355
+ vaultOwner: wallet.publicKey,
356
+ streamMetadata: streamAddress,
328
357
  });
329
358
 
330
359
  const signature = await payload.execute();
@@ -334,8 +363,8 @@ const signature = await payload.execute();
334
363
 
335
364
  ```tsx
336
365
  const payload = await vaultService.cancelStream({
337
- vaultOwner: wallet.publicKey,
338
- streamMetadata: streamAddress,
366
+ vaultOwner: wallet.publicKey,
367
+ streamMetadata: streamAddress,
339
368
  });
340
369
 
341
370
  await payload.execute();
@@ -345,8 +374,8 @@ await payload.execute();
345
374
 
346
375
  ```tsx
347
376
  const payload = await vaultService.withdrawStream({
348
- vaultOwner: wallet.publicKey,
349
- streamMetadata: streamAddress,
377
+ vaultOwner: wallet.publicKey,
378
+ streamMetadata: streamAddress,
350
379
  });
351
380
 
352
381
  await payload.execute();
@@ -356,9 +385,9 @@ await payload.execute();
356
385
 
357
386
  ```tsx
358
387
  const payload = await vaultService.changeStreamReceiver({
359
- vaultOwner: wallet.publicKey,
360
- streamMetadata: streamAddress,
361
- newRecipient: newRecipientAddress,
388
+ vaultOwner: wallet.publicKey,
389
+ streamMetadata: streamAddress,
390
+ newRecipient: newRecipientAddress,
362
391
  });
363
392
 
364
393
  await payload.execute();
@@ -370,46 +399,46 @@ await payload.execute();
370
399
  const streamInfo = await vaultService.getStreamMetadataInfo(streamAddress);
371
400
 
372
401
  console.log("Stream details:", {
373
- sender: streamInfo.parties.sender,
374
- receiver: streamInfo.parties.receiver,
375
- token: streamInfo.financials.streamToken,
376
- deposited: streamInfo.financials.depositedAmount,
377
- withdrawn: streamInfo.financials.withdrawnAmount,
378
- startTime: new Date(streamInfo.schedule.startTime * 1000),
379
- endTime: new Date(streamInfo.schedule.endTime * 1000),
380
- isPaused: streamInfo.schedule.pausedTimestamp > 0,
402
+ sender: streamInfo.parties.sender,
403
+ receiver: streamInfo.parties.receiver,
404
+ token: streamInfo.financials.streamToken,
405
+ deposited: streamInfo.financials.depositedAmount,
406
+ withdrawn: streamInfo.financials.withdrawnAmount,
407
+ startTime: new Date(streamInfo.schedule.startTime * 1000),
408
+ endTime: new Date(streamInfo.schedule.endTime * 1000),
409
+ isPaused: streamInfo.schedule.pausedTimestamp > 0,
381
410
  });
382
411
  ```
383
412
 
384
413
  ### Staking
385
414
 
386
- **Stake Tokens**
415
+ #### Stake Tokens
387
416
 
388
417
  ```tsx
389
418
  const payload = await vaultService.stake({
390
- lockupName: "main-lockup",
391
- vaultOwner: wallet.publicKey,
392
- amount: 1000,
393
- lockPeriod: 7776000, // 90 days in seconds
394
- nonce: 0n,
419
+ lockupName: "main-lockup",
420
+ vaultOwner: wallet.publicKey,
421
+ amount: 1000,
422
+ lockPeriod: 7776000, // 90 days in seconds; must be one of the lockup's valid periods
423
+ nonce: 0n,
395
424
  });
396
425
 
397
426
  await payload.execute();
398
427
  ```
399
428
 
400
- **Unstake Tokens**
429
+ #### Unstake Tokens
401
430
 
402
431
  ```tsx
403
432
  const payload = await vaultService.unstake({
404
- lockupName: "main-lockup",
405
- vaultOwner: wallet.publicKey,
406
- nonce: 0n,
433
+ lockupName: "main-lockup",
434
+ vaultOwner: wallet.publicKey,
435
+ nonce: 0n,
407
436
  });
408
437
 
409
438
  await payload.execute();
410
439
  ```
411
440
 
412
- **Get Stake Nonce Information**
441
+ #### Get Stake Nonce Information
413
442
 
414
443
  ```tsx
415
444
  const nonceInfo = await vaultService.getStakeUserNonceInfo("main-lockup", wallet.publicKey);
@@ -419,85 +448,94 @@ console.log("Current nonce:", nonceInfo ? nonceInfo.nonce : 0n);
419
448
 
420
449
  ### Zebec Cards
421
450
 
422
- **Create a Silver Card**
451
+ #### Create a Silver Card
423
452
 
424
453
  ```tsx
425
454
  const nextIndex = await vaultService.getNextCardIndex();
426
455
 
427
456
  const payload = await vaultService.createSilverCard({
428
- vaultOwnerAddress: wallet.publicKey,
429
- nextCardIndex: nextIndex,
430
- amount: 100, // USDC amount
431
- usdcAddress: USDC_MINT_ADDRESS,
432
- emailHash: Buffer.from("your-32-byte-hash"),
433
- currency: "USD",
457
+ vaultOwnerAddress: wallet.publicKey,
458
+ nextCardIndex: nextIndex,
459
+ amount: 100, // USDC amount
460
+ usdcAddress: USDC_MINT_ADDRESS,
461
+ emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
462
+ currency: "USD",
434
463
  });
435
464
 
436
465
  await payload.execute();
437
466
  ```
438
467
 
439
- **Load a Carbon Card**
468
+ #### Load a Carbon Card
440
469
 
441
470
  ```tsx
442
471
  const nextIndex = await vaultService.getNextCardIndex();
443
472
 
444
473
  const payload = await vaultService.loadCarbonCard({
445
- vaultOwnerAddress: wallet.publicKey,
446
- nextCardIndex: nextIndex,
447
- amount: 50,
448
- usdcAddress: USDC_MINT_ADDRESS,
449
- emailHash: Buffer.from("your-32-byte-hash"),
450
- currency: "USD",
451
- reloadCardId: "CARD_ID",
474
+ vaultOwnerAddress: wallet.publicKey,
475
+ nextCardIndex: nextIndex,
476
+ amount: 50,
477
+ usdcAddress: USDC_MINT_ADDRESS,
478
+ emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
479
+ currency: "USD",
480
+ reloadCardId: "CARD_ID",
452
481
  });
453
482
 
454
483
  await payload.execute();
455
484
  ```
456
485
 
457
- **Swap and Create Silver Card**
486
+ #### Swap and Create Silver Card
458
487
 
459
488
  ```tsx
460
489
  // First, get a Jupiter quote
490
+ const quoteParams = new URLSearchParams({
491
+ inputMint: inputMint,
492
+ outputMint: USDC_MINT_ADDRESS,
493
+ amount: parsedAmount, // in smallest units
494
+ slippageBps: "50",
495
+ swapMode: "ExactIn",
496
+ });
461
497
  const quoteResponse = await fetch(
462
- `https://quote-api.jup.ag/v6/quote?inputMint=${inputMint}&outputMint=${USDC}&amount=${amount}&slippageBps=50`,
498
+ `https://lite-api.jup.ag/swap/v1/quote?${quoteParams}`,
463
499
  );
464
500
  const quoteInfo = await quoteResponse.json();
465
501
 
502
+ const nextIndex = await vaultService.getNextCardIndex();
503
+
466
504
  const payload = await vaultService.swapAndCreateSilverCard({
467
- vaultOwnerAddress: wallet.publicKey,
468
- quoteInfo: quoteInfo,
469
- nextCardCounter: nextIndex,
470
- emailHash: Buffer.from("your-32-byte-hash"),
471
- currency: "USD",
472
- wrapAndUnwrapSol: true, // if swapping SOL
505
+ vaultOwnerAddress: wallet.publicKey,
506
+ quoteInfo: quoteInfo,
507
+ nextCardCounter: nextIndex,
508
+ emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
509
+ currency: "USD",
510
+ wrapAndUnwrapSol: true, // set to true when swapping SOL
473
511
  });
474
512
 
475
513
  await payload.execute();
476
514
  ```
477
515
 
478
- **Swap and Load Carbon Card**
516
+ #### Swap and Load Carbon Card
479
517
 
480
518
  ```tsx
481
519
  const payload = await vaultService.swapAndLoadCarbonCard({
482
- vaultOwnerAddress: wallet.publicKey,
483
- quoteInfo: quoteInfo,
484
- nextCardCounter: nextIndex,
485
- emailHash: Buffer.from("your-32-byte-hash"),
486
- currency: "USD",
487
- reloadCardId: "CARD_ID",
488
- wrapAndUnwrapSol: true,
520
+ vaultOwnerAddress: wallet.publicKey,
521
+ quoteInfo: quoteInfo,
522
+ nextCardCounter: nextIndex,
523
+ emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
524
+ currency: "USD",
525
+ reloadCardId: "CARD_ID",
526
+ wrapAndUnwrapSol: true,
489
527
  });
490
528
 
491
529
  await payload.execute();
492
530
  ```
493
531
 
494
- **Get Card Custom Token Fees**
532
+ #### Get Card Custom Token Fees
495
533
 
496
534
  ```tsx
497
535
  const tokenFees = await vaultService.getCardCustomTokenFees();
498
536
 
499
537
  tokenFees.forEach((fee) => {
500
- console.log(`Token: ${fee.tokenAddress}, Fee: ${fee.fee}%`);
538
+ console.log(`Token: ${fee.tokenAddress}, Fee: ${fee.fee}%`);
501
539
  });
502
540
  ```
503
541
 
@@ -518,15 +556,12 @@ const vaultInfo = await service.getVaultInfoOfUser(someAddress);
518
556
 
519
557
  ### **Advanced Features**
520
558
 
521
- **Program Derived Addresses (PDAs)**
559
+ #### Program Derived Addresses (PDAs)
522
560
 
523
561
  ```tsx
524
562
  import {
525
- deriveUserVault,
526
- deriveVaultSigner,
527
- deriveStreamConfigPda,
528
- deriveCardConfigPda,
529
- deriveLockupAddress,
563
+ deriveUserVault,
564
+ deriveVaultSigner,
530
565
  } from "@zebec-network/zebec-vault-sdk";
531
566
 
532
567
  const [vaultAddress, vaultBump] = deriveUserVault(userAddress, vaultProgramId);
@@ -534,19 +569,19 @@ const [vaultAddress, vaultBump] = deriveUserVault(userAddress, vaultProgramId);
534
569
  const [signerAddress, signerBump] = deriveVaultSigner(vaultAddress, vaultProgramId);
535
570
  ```
536
571
 
537
- **Transaction Utilities**
572
+ #### Transaction Utilities
538
573
 
539
574
  ```tsx
540
575
  import { calculateProposalSize, transactionInstructionToProposalAction } from "@zebec-network/zebec-vault-sdk";
541
576
 
542
- // Calculate proposal size
577
+ // Calculate proposal size (in bytes)
543
578
  const size = calculateProposalSize("proposal-name", actions);
544
579
 
545
- // Convert instruction to proposal action
580
+ // Convert a TransactionInstruction to a ProposalAction
546
581
  const action = transactionInstructionToProposalAction(instruction);
547
582
  ```
548
583
 
549
- **Network Configuration**
584
+ #### Network Configuration
550
585
 
551
586
  ```tsx
552
587
  // Mainnet
@@ -560,37 +595,81 @@ const devnetService = ZebecVaultService.create(provider, "devnet");
560
595
 
561
596
  ```tsx
562
597
  import {
563
- ZEBEC_VAULT_PROGRAM_ID,
564
- JUPITER_AGGREGATOR_PROGRAM_ID,
565
- CARD_LOOKUP_TABLE_ADDRESS,
566
- STAKE_LOOKUP_TABLE_ADDRESS,
598
+ ZEBEC_VAULT_PROGRAM_ID,
599
+ JUPITER_AGGREGATOR_PROGRAM_ID,
600
+ CARD_LOOKUP_TABLE_ADDRESS,
601
+ STAKE_LOOKUP_TABLE_ADDRESS,
567
602
  } from "@zebec-network/zebec-vault-sdk";
568
603
 
569
604
  console.log("Vault Program:", ZEBEC_VAULT_PROGRAM_ID["mainnet-beta"]);
570
605
  ```
571
606
 
607
+ ### **Error Types**
608
+
609
+ The SDK throws typed errors you can catch and inspect:
610
+
611
+ ```tsx
612
+ import {
613
+ AmountOutOfRangeError,
614
+ DailyCardLimitReachedError,
615
+ InvalidUsdcAddressError,
616
+ NotEnoughBalanceError,
617
+ QuoteResponseError,
618
+ AssociatedTokenAccountDoesNotExistsError,
619
+ } from "@zebec-network/zebec-vault-sdk";
620
+
621
+ try {
622
+ await payload.execute();
623
+ } catch (err) {
624
+ if (err instanceof AmountOutOfRangeError) {
625
+ console.error(`Amount must be between ${err.minRange} and ${err.maxRange}`);
626
+ } else if (err instanceof DailyCardLimitReachedError) {
627
+ console.error(`Daily limit: ${err.dailyCardLimit}, requested: ${err.requestedAmount}`);
628
+ } else if (err instanceof NotEnoughBalanceError) {
629
+ console.error("Insufficient balance");
630
+ } else if (err instanceof AssociatedTokenAccountDoesNotExistsError) {
631
+ console.error("Token account does not exist");
632
+ }
633
+ }
634
+ ```
635
+
572
636
  ### **Types**
573
637
 
574
638
  The SDK exports comprehensive TypeScript types:
575
639
 
576
640
  ```tsx
577
641
  import type {
578
- VaultInfo,
579
- ProposalInfo,
580
- ProposalAction,
581
- CreateStreamFromVaultParams,
582
- StreamMetadataInfo,
583
- TokenFeeRecord,
584
- QuoteInfo,
585
- StakeUserNonceInfo,
642
+ VaultInfo,
643
+ ProposalInfo,
644
+ ProposalAction,
645
+ ProposalStage,
646
+ CreateStreamFromVaultParams,
647
+ createMultipleStreamFromVaultParams,
648
+ StreamMetadataInfo,
649
+ TokenFeeRecord,
650
+ QuoteInfo,
651
+ RouteInfo,
652
+ StakeUserNonceInfo,
653
+ CreateSilverCardParams,
654
+ LoadCarbonCardParams,
655
+ SwapAndCreateSilverCardParams,
656
+ SwapAndLoadCarbonCardParams,
657
+ CancelStreamParams,
658
+ PauseResumeStreamParams,
659
+ ChangeStreamReceiverParams,
660
+ WithdrawStreamParams,
661
+ ParsedCardConfigInfo,
662
+ WhitelistInfo,
663
+ Numeric,
586
664
  } from "@zebec-network/zebec-vault-sdk";
587
665
  ```
588
666
 
589
667
  ## **Best Practices**
590
668
 
591
- 1. **Always check balances** before operations
592
- 2. **Use proposals** for critical operations that require multiple instructions and cannot be executed in a single transaction.
593
- 3. **Handle errors** appropriately with the provided error types
594
- 4. **Verify stream parameters** before creation (duration, amounts, permissions)
595
- 5. **Test on `devnet`** before deploying to `mainnet`
596
- 6. **Use address lookup tables** for complex transactions to reduce size
669
+ 1. **Always check balances** before operations
670
+ 2. **Use proposals** for critical operations that require multiple instructions and cannot be executed in a single transaction
671
+ 3. **Handle errors** appropriately with the provided error types
672
+ 4. **Verify stream parameters** before creation (duration, amounts, permissions)
673
+ 5. **Test on `devnet`** before deploying to `mainnet`
674
+ 6. **Use address lookup tables** for complex transactions to reduce transaction size
675
+ 7. **Use a private dedicated RPC** for production workloads
package/package.json CHANGED
@@ -8,8 +8,8 @@
8
8
  "@zebec-network/core-utils": "^1.1.1",
9
9
  "@zebec-network/solana-common": "^2.3.1",
10
10
  "@zebec-network/zebec-card-v2-sdk": "^2.6.0",
11
- "@zebec-network/zebec-stake-sdk": "^1.3.0",
12
- "@zebec-network/zebec-stream-sdk": "^3.1.1",
11
+ "@zebec-network/zebec-stake-sdk": "^1.3.1",
12
+ "@zebec-network/zebec-stream-sdk": "^3.2.0",
13
13
  "bignumber.js": "^9.3.1",
14
14
  "buffer": "^6.0.3"
15
15
  },
@@ -47,5 +47,5 @@
47
47
  "test:single": "ts-mocha -p ./tsconfig.json -t 1000000000"
48
48
  },
49
49
  "types": "dist/index.d.ts",
50
- "version": "5.2.1"
50
+ "version": "5.2.3"
51
51
  }