@zebec-network/zebec-vault-sdk 1.1.0 → 3.0.0

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.
package/dist/service.js CHANGED
@@ -5,101 +5,104 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.ZebecVaultService = void 0;
7
7
  const assert_1 = __importDefault(require("assert"));
8
+ const bignumber_js_1 = require("bignumber.js");
8
9
  const anchor_1 = require("@coral-xyz/anchor");
9
10
  const web3_js_1 = require("@solana/web3.js");
11
+ const core_utils_1 = require("@zebec-network/core-utils");
10
12
  const solana_common_1 = require("@zebec-network/solana-common");
11
13
  const artifacts_1 = require("./artifacts");
14
+ const constants_1 = require("./constants");
12
15
  const pda_1 = require("./pda");
13
16
  const utils_1 = require("./utils");
14
17
  class ZebecVaultService {
15
18
  provider;
16
- program;
19
+ vaultV1Program;
20
+ cardV2Program;
21
+ streamProgram;
17
22
  network;
18
- constructor(provider, program, network) {
23
+ constructor(provider, vaultV1Program, cardV2Program, streamProgram, network) {
19
24
  this.provider = provider;
20
- this.program = program;
25
+ this.vaultV1Program = vaultV1Program;
26
+ this.cardV2Program = cardV2Program;
27
+ this.streamProgram = streamProgram;
21
28
  this.network = network;
22
29
  }
23
- static async create(provider, network, program) {
24
- program = program ?? new anchor_1.Program(artifacts_1.ZEBEC_VAULT_IDL_V1, provider);
25
- return new ZebecVaultService(provider, program, network);
30
+ static create(provider, network) {
31
+ const vaultV1Program = new anchor_1.Program(artifacts_1.ZEBEC_VAULT_V1_IDL, provider);
32
+ const cardV2Program = new anchor_1.Program(artifacts_1.ZEBEC_CARD_V2_IDL, provider);
33
+ const streamProgram = new anchor_1.Program(artifacts_1.ZEBEC_STREAM_IDL, provider);
34
+ return new ZebecVaultService(provider, vaultV1Program, cardV2Program, streamProgram, network);
26
35
  }
27
- async getCreateVaultInstruction(payer, vault, owner, signerBump) {
28
- return this.program.methods
36
+ async getCreateVaultInstruction(payer, owner, signerBump) {
37
+ return this.vaultV1Program.methods
29
38
  .createVault({
30
39
  owner,
31
40
  signerBump,
32
41
  })
33
42
  .accounts({
34
43
  payer,
35
- vault,
36
44
  })
37
45
  .instruction();
38
46
  }
39
- async getDepositSolInstruction(depositor, vault, amount) {
40
- return this.program.methods
47
+ async getDepositSolInstruction(depositor, amount) {
48
+ return this.vaultV1Program.methods
41
49
  .depositSol({
42
50
  amount,
43
51
  })
44
52
  .accounts({
45
- vault,
46
53
  depositor,
47
54
  })
48
55
  .instruction();
49
56
  }
50
- async getWithdrawSolInstruction(withdrawer, vault, amount) {
51
- return this.program.methods
57
+ async getWithdrawSolInstruction(withdrawer, amount) {
58
+ return this.vaultV1Program.methods
52
59
  .withdrawSol({
53
60
  amount,
54
61
  })
55
62
  .accounts({
56
- vault,
57
63
  withdrawer,
58
64
  })
59
65
  .instruction();
60
66
  }
61
- async getDepositTokenInstruction(depositor, vault, tokenMint, amount, decimals) {
62
- return this.program.methods
67
+ async getDepositTokenInstruction(depositor, tokenMint, amount, decimals) {
68
+ return this.vaultV1Program.methods
63
69
  .depositToken({
64
70
  amount,
65
71
  decimals,
66
72
  })
67
73
  .accounts({
68
- vault,
69
74
  depositor,
70
75
  tokenMint,
71
76
  })
72
77
  .instruction();
73
78
  }
74
- async getWithdrawTokenInstruction(withdrawer, vault, tokenMint, amount, decimals) {
75
- return this.program.methods
79
+ async getWithdrawTokenInstruction(withdrawer, tokenMint, amount, decimals) {
80
+ return this.vaultV1Program.methods
76
81
  .withdrawToken({
77
82
  amount,
78
83
  decimals,
79
84
  })
80
85
  .accounts({
81
- vault,
82
86
  withdrawer,
83
87
  tokenMint,
84
88
  })
85
89
  .instruction();
86
90
  }
87
- async getCreateProposalInstruction(proposer, vault, proposal, name, actions, proposalAccountSize) {
88
- return this.program.methods
91
+ async getCreateProposalInstruction(proposer, proposal, name, actions, proposalAccountSize) {
92
+ return this.vaultV1Program.methods
89
93
  .createProposal({
90
94
  actions,
91
95
  name,
92
96
  proposalAccountSize,
93
97
  })
94
98
  .accounts({
95
- vault,
96
99
  proposal,
97
100
  proposer,
98
101
  })
99
102
  .instruction();
100
103
  }
101
104
  async getAppendActionInstruction(proposer, proposal, actions, newProposalAccountSize) {
102
- return this.program.methods
105
+ return this.vaultV1Program.methods
103
106
  .appendActions({
104
107
  actions,
105
108
  proposalAccountSize: newProposalAccountSize,
@@ -111,7 +114,7 @@ class ZebecVaultService {
111
114
  .instruction();
112
115
  }
113
116
  async getDeleteProposalInstruction(proposal) {
114
- return this.program.methods
117
+ return this.vaultV1Program.methods
115
118
  .deleteProposal()
116
119
  .accounts({
117
120
  proposal,
@@ -119,7 +122,7 @@ class ZebecVaultService {
119
122
  .instruction();
120
123
  }
121
124
  async getExecuteProposalInstruction(caller, proposal, remainingAccounts) {
122
- return this.program.methods
125
+ return this.vaultV1Program.methods
123
126
  .executeProposal()
124
127
  .accounts({
125
128
  proposal,
@@ -128,36 +131,117 @@ class ZebecVaultService {
128
131
  .remainingAccounts(remainingAccounts)
129
132
  .instruction();
130
133
  }
131
- async getExecuteProposalDirectInstruction(vault, proposer, actions, remainingAccounts) {
132
- return this.program.methods
134
+ async getExecuteProposalDirectInstruction(proposer, actions, remainingAccounts) {
135
+ return this.vaultV1Program.methods
133
136
  .executeProposalDirect({
134
137
  actions,
135
138
  })
136
139
  .accounts({
137
- vault,
138
140
  proposer,
139
141
  })
140
142
  .remainingAccounts(remainingAccounts)
141
143
  .instruction();
142
144
  }
145
+ async getSwapAndCreateSilverCardInstruction(cardVault, cardVaultAta, inputMint, inputMintProgram, outputMint, revenueVault, revenueVaultAta, vaultOwner, data, remainingAccounts) {
146
+ const { currency, emailHash, index, swapData } = data;
147
+ return this.vaultV1Program.methods
148
+ .swapAndCreateSilverCard({
149
+ currency,
150
+ emailHash,
151
+ index,
152
+ swapData,
153
+ })
154
+ .accounts({
155
+ cardVault,
156
+ cardVaultAta,
157
+ inputMint,
158
+ inputMintProgram,
159
+ outputMint,
160
+ outputMintProgram: solana_common_1.TOKEN_PROGRAM_ID,
161
+ revenueVault,
162
+ revenueVaultAta,
163
+ vaultOwner,
164
+ })
165
+ .remainingAccounts(remainingAccounts)
166
+ .instruction();
167
+ }
168
+ async getSwapAndLoadCarbonCardInstruction(cardVault, cardVaultAta, inputMint, inputMintProgram, outputMint, revenueVault, revenueVaultAta, vaultOwner, data, remainingAccounts) {
169
+ const { currency, emailHash, index, swapData, reloadCardId } = data;
170
+ return this.vaultV1Program.methods
171
+ .swapAndLoadCarbonCard({
172
+ currency,
173
+ emailHash,
174
+ index,
175
+ reloadCardId,
176
+ swapData,
177
+ })
178
+ .accounts({
179
+ cardVault,
180
+ cardVaultAta,
181
+ inputMint,
182
+ inputMintProgram,
183
+ outputMint,
184
+ outputMintProgram: solana_common_1.TOKEN_PROGRAM_ID,
185
+ revenueVault,
186
+ revenueVaultAta,
187
+ vaultOwner,
188
+ })
189
+ .remainingAccounts(remainingAccounts)
190
+ .instruction();
191
+ }
192
+ async getCreateStreamFromVaultInstruction(vaultOwner, vault, vaultSigner, vaultSignerAta, receiver, receiverAta, streamToken, streamMetadata, streamConfig, withdrawAccount, streamVault, streamVaultAta, zebecStreamProgram, streamData) {
193
+ return this.vaultV1Program.methods
194
+ .createStream({
195
+ amount: streamData.amount,
196
+ automaticWithdrawal: Number(streamData.automaticWithdrawal),
197
+ cancelableByRecipient: Number(streamData.cancelableByRecipient),
198
+ cancelableBySender: Number(streamData.cancelableBySender),
199
+ canTopup: Number(streamData.canTopup),
200
+ cliffPercentage: streamData.cliffPercentage,
201
+ duration: streamData.duration,
202
+ isPausable: Number(streamData.isPausable),
203
+ rateUpdatable: Number(streamData.rateUpdatable),
204
+ startNow: Number(streamData.startNow),
205
+ startTime: streamData.startTime,
206
+ streamFrequency: streamData.autoWithdrawFrequency,
207
+ streamName: Array.from(streamData.streamName),
208
+ transferableByRecipient: Number(streamData.transferableByRecipient),
209
+ transferableBySender: Number(streamData.transferableBySender),
210
+ })
211
+ .accountsPartial({
212
+ receiver,
213
+ streamToken,
214
+ vaultSignerAta,
215
+ withdrawAccount,
216
+ streamMetadata,
217
+ vaultOwner,
218
+ vault,
219
+ vaultSigner,
220
+ receiverAta,
221
+ streamConfig,
222
+ streamVault,
223
+ streamVaultAta,
224
+ zebecStreamProgram,
225
+ })
226
+ .instruction();
227
+ }
143
228
  async createVault(params) {
144
229
  const payer = params.payer ? (0, anchor_1.translateAddress)(params.payer) : this.provider.publicKey;
145
230
  if (!payer) {
146
231
  throw new Error("Either provide a payer or use AnchorProvider for provider in the service");
147
232
  }
148
- const vaultKeypair = params.vaultKeypair ?? web3_js_1.Keypair.generate();
149
- const [, signerBump] = (0, pda_1.deriveVaultSigner)(vaultKeypair.publicKey, this.programId);
150
- const ix = await this.getCreateVaultInstruction(payer, vaultKeypair.publicKey, payer, signerBump);
151
- return this._createTransactionPayload(payer, [ix], [vaultKeypair]);
233
+ const [vault] = (0, pda_1.deriveUserVault)(payer, this.vaultV1ProgramId);
234
+ const [, signerBump] = (0, pda_1.deriveVaultSigner)(vault, this.vaultV1ProgramId);
235
+ const ix = await this.getCreateVaultInstruction(payer, payer, signerBump);
236
+ return this._createTransactionPayload(payer, [ix]);
152
237
  }
153
238
  async depositSol(params) {
154
239
  const depositor = params.depositor ? (0, anchor_1.translateAddress)(params.depositor) : this.provider.publicKey;
155
240
  if (!depositor) {
156
241
  throw new Error("Either provide a depositor or use AnchorProvider for provider in the service");
157
242
  }
158
- const vault = (0, anchor_1.translateAddress)(params.vault);
159
243
  const amount = new anchor_1.BN((0, solana_common_1.parseSol)(params.amount).toString());
160
- const ix = await this.getDepositSolInstruction(depositor, vault, amount);
244
+ const ix = await this.getDepositSolInstruction(depositor, amount);
161
245
  return this._createTransactionPayload(depositor, [ix]);
162
246
  }
163
247
  async withdrawSol(params) {
@@ -165,9 +249,8 @@ class ZebecVaultService {
165
249
  if (!withdrawer) {
166
250
  throw new Error("Either provide a withdrawer or use AnchorProvider for provider in the service");
167
251
  }
168
- const vault = (0, anchor_1.translateAddress)(params.vault);
169
252
  const amount = new anchor_1.BN((0, solana_common_1.parseSol)(params.amount).toString());
170
- const ix = await this.getWithdrawSolInstruction(withdrawer, vault, amount);
253
+ const ix = await this.getWithdrawSolInstruction(withdrawer, amount);
171
254
  return this._createTransactionPayload(withdrawer, [ix]);
172
255
  }
173
256
  async depositToken(params) {
@@ -175,11 +258,10 @@ class ZebecVaultService {
175
258
  if (!depositor) {
176
259
  throw new Error("Either provide a depositor or use AnchorProvider for provider in the service");
177
260
  }
178
- const vault = (0, anchor_1.translateAddress)(params.vault);
179
261
  const tokenMint = (0, anchor_1.translateAddress)(params.tokenMint);
180
262
  const decimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, tokenMint);
181
263
  const amount = new anchor_1.BN((0, solana_common_1.parseToken)(params.amount, decimals).toString());
182
- const ix = await this.getDepositTokenInstruction(depositor, vault, tokenMint, amount, decimals);
264
+ const ix = await this.getDepositTokenInstruction(depositor, tokenMint, amount, decimals);
183
265
  return this._createTransactionPayload(depositor, [ix]);
184
266
  }
185
267
  async withdrawToken(params) {
@@ -187,11 +269,10 @@ class ZebecVaultService {
187
269
  if (!withdrawer) {
188
270
  throw new Error("Either provide a withdrawer or use AnchorProvider for provider in the service");
189
271
  }
190
- const vault = (0, anchor_1.translateAddress)(params.vault);
191
272
  const tokenMint = (0, anchor_1.translateAddress)(params.tokenMint);
192
273
  const decimals = await (0, solana_common_1.getMintDecimals)(this.provider.connection, tokenMint);
193
274
  const amount = new anchor_1.BN((0, solana_common_1.parseToken)(params.amount, decimals).toString());
194
- const ix = await this.getWithdrawTokenInstruction(withdrawer, vault, tokenMint, amount, decimals);
275
+ const ix = await this.getWithdrawTokenInstruction(withdrawer, tokenMint, amount, decimals);
195
276
  return this._createTransactionPayload(withdrawer, [ix]);
196
277
  }
197
278
  async createProposal(params) {
@@ -199,7 +280,6 @@ class ZebecVaultService {
199
280
  if (!proposer) {
200
281
  throw new Error("Either provide a proposer or use AnchorProvider for provider in the service");
201
282
  }
202
- const vault = (0, anchor_1.translateAddress)(params.vault);
203
283
  const proposalKeypair = params.proposalKeypair ?? web3_js_1.Keypair.generate();
204
284
  const actions = params.actions.map((ix) => ({
205
285
  accountSpecs: ix.keys,
@@ -210,7 +290,7 @@ class ZebecVaultService {
210
290
  if (proposalAccountSize > 10_000) {
211
291
  throw new Error("Proposal size exceeds maximum allowed size of 10,000 bytes");
212
292
  }
213
- const ix = await this.getCreateProposalInstruction(proposer, vault, proposalKeypair.publicKey, params.name, actions, proposalAccountSize);
293
+ const ix = await this.getCreateProposalInstruction(proposer, proposalKeypair.publicKey, params.name, actions, proposalAccountSize);
214
294
  return this._createTransactionPayload(proposer, [ix], [proposalKeypair]);
215
295
  }
216
296
  async appendActions(params) {
@@ -219,7 +299,7 @@ class ZebecVaultService {
219
299
  throw new Error("Either provide a proposer or use AnchorProvider for provider in the service");
220
300
  }
221
301
  const proposal = (0, anchor_1.translateAddress)(params.proposal);
222
- const proposalAccount = await this.program.account.proposal.fetchNullable(proposal, this.connection.commitment);
302
+ const proposalAccount = await this.vaultV1Program.account.proposal.fetchNullable(proposal, this.connection.commitment);
223
303
  if (!proposalAccount) {
224
304
  throw new Error("Proposal account not found");
225
305
  }
@@ -252,12 +332,12 @@ class ZebecVaultService {
252
332
  throw new Error("Either provide a caller or use AnchorProvider for provider in the service");
253
333
  }
254
334
  const proposal = (0, anchor_1.translateAddress)(params.proposal);
255
- const proposalAccount = await this.program.account.proposal.fetchNullable(proposal, this.connection.commitment);
335
+ const proposalAccount = await this.vaultV1Program.account.proposal.fetchNullable(proposal, this.connection.commitment);
256
336
  if (!proposalAccount) {
257
337
  throw new Error("Proposal account not found");
258
338
  }
259
339
  const vault = proposalAccount.vault;
260
- const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.programId);
340
+ const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.vaultV1ProgramId);
261
341
  const remainingAccounts = proposalAccount.actions.reduce((acc, current) => {
262
342
  const accounts = current.accountSpecs.map((spec) => ({
263
343
  pubkey: spec.pubkey,
@@ -291,8 +371,8 @@ class ZebecVaultService {
291
371
  if (!proposer) {
292
372
  throw new Error("Either provide a caller or use AnchorProvider for provider in the service");
293
373
  }
294
- const vault = (0, anchor_1.translateAddress)(params.vault);
295
- const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.programId);
374
+ const [vault] = (0, pda_1.deriveUserVault)(proposer, this.vaultV1ProgramId);
375
+ const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.vaultV1ProgramId);
296
376
  const actions = params.actions.map((ix) => ({
297
377
  accountSpecs: ix.keys,
298
378
  data: ix.data,
@@ -311,7 +391,7 @@ class ZebecVaultService {
311
391
  });
312
392
  return acc;
313
393
  }, []);
314
- const ix = await this.getExecuteProposalDirectInstruction(vault, proposer, actions, remainingAccounts);
394
+ const ix = await this.getExecuteProposalDirectInstruction(proposer, actions, remainingAccounts);
315
395
  const addressLookupTableAccounts = [];
316
396
  if (params.addressLookupTables) {
317
397
  const promises = params.addressLookupTables.map(async (lookupTable) => {
@@ -325,9 +405,206 @@ class ZebecVaultService {
325
405
  }
326
406
  return this._createTransactionPayload(proposer, [ix], params.partialSigners, addressLookupTableAccounts);
327
407
  }
408
+ async swapAndCreateSilverCard(params) {
409
+ const { vaultOwnerAddress, quoteInfo, emailHash, wrapAndUnwrapSol } = params;
410
+ if ("error" in quoteInfo) {
411
+ throw new Error(quoteInfo.error);
412
+ }
413
+ (0, core_utils_1.assertBufferSize)(emailHash, 32);
414
+ // const [cardConfig] = deriveCardConfigPda(this.cardV2ProgramId);
415
+ // console.log("cardConfig:", cardConfig.toString());
416
+ // const cardConfigInfo = await this.cardV2Program.account.card.fetch(cardConfig, this.connection.commitment);
417
+ const vaultOwner = (0, anchor_1.translateAddress)(vaultOwnerAddress);
418
+ const [vault] = (0, pda_1.deriveUserVault)(vaultOwner, this.vaultV1ProgramId);
419
+ const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.vaultV1ProgramId);
420
+ const inputMint = (0, anchor_1.translateAddress)(quoteInfo.inputMint);
421
+ const usdc = (0, anchor_1.translateAddress)(quoteInfo.outputMint);
422
+ // const [userPurchaseRecord] = deriveUserPurchaseRecordPda(user, this.vaultV1ProgramId);
423
+ // const revenueVault = cardConfigInfo.revenueVault;
424
+ const revenueVault = web3_js_1.Keypair.generate().publicKey;
425
+ // const cardVault = cardConfigInfo.cardVault;
426
+ const cardVault = web3_js_1.Keypair.generate().publicKey;
427
+ const cardVaultAta = (0, solana_common_1.getAssociatedTokenAddressSync)(usdc, cardVault, true);
428
+ const revenueVaultAta = (0, solana_common_1.getAssociatedTokenAddressSync)(usdc, revenueVault, true);
429
+ // const amount =
430
+ // quoteInfo.swapMode === "ExactIn"
431
+ // ? new BigNumber(quoteInfo.otherAmountThreshold)
432
+ // : new BigNumber(quoteInfo.outAmount);
433
+ // if (!usdc.equals(cardConfigInfo.usdcMint)) {
434
+ // throw new Error(`Invalid usdc: ${usdc.toString()}`);
435
+ // }
436
+ // const userInputMintAta = getAssociatedTokenAddressSync(inputMint, user);
437
+ const { swapTransaction } = await (await fetch("https://lite-api.jup.ag/swap/v1/swap", {
438
+ method: "POST",
439
+ headers: {
440
+ "Content-Type": "application/json",
441
+ },
442
+ body: JSON.stringify({
443
+ // quoteResponse from /quote api
444
+ quoteResponse: quoteInfo,
445
+ // user public key to be used for the swap
446
+ userPublicKey: vaultSigner.toString(),
447
+ // auto wrap and unwrap SOL. default is true
448
+ wrapAndUnwrapSol: wrapAndUnwrapSol ?? false,
449
+ // feeAccount is optional. Use if you want to charge a fee. feeBps must have been passed in /quote API.
450
+ // feeAccount: "fee_account_public_key"
451
+ }),
452
+ })).json();
453
+ // deserialize the transaction
454
+ const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
455
+ const transaction = web3_js_1.VersionedTransaction.deserialize(swapTransactionBuf);
456
+ // get address lookup table accounts
457
+ const addressLookupTableAccounts = await Promise.all(transaction.message.addressTableLookups.map(async (lookup) => {
458
+ const data = await this.connection.getAccountInfo(lookup.accountKey).then((res) => res.data);
459
+ return new web3_js_1.AddressLookupTableAccount({
460
+ key: lookup.accountKey,
461
+ state: web3_js_1.AddressLookupTableAccount.deserialize(data),
462
+ });
463
+ }));
464
+ const lookupTableData = await new web3_js_1.Connection((0, web3_js_1.clusterApiUrl)("devnet"))
465
+ .getAccountInfo((0, anchor_1.translateAddress)(constants_1.CARD_LOOKUP_TABLE_ADDRESS))
466
+ .then((res) => res.data);
467
+ addressLookupTableAccounts.push(new web3_js_1.AddressLookupTableAccount({
468
+ key: (0, anchor_1.translateAddress)(constants_1.CARD_LOOKUP_TABLE_ADDRESS),
469
+ state: web3_js_1.AddressLookupTableAccount.deserialize(lookupTableData),
470
+ }));
471
+ // console.log("address lookup table:\n", addressLookupTableAccounts);
472
+ // decompile transaction message and add transfer instruction
473
+ const message = web3_js_1.TransactionMessage.decompile(transaction.message, {
474
+ addressLookupTableAccounts: addressLookupTableAccounts,
475
+ });
476
+ const swapInstruction = message.instructions.find((ix) => ix.programId.equals((0, anchor_1.translateAddress)(constants_1.JUPITER_AGGREGATOR_PROGRAM_ID)));
477
+ (0, assert_1.default)(swapInstruction, "Swap instruction not found in the transaction message");
478
+ const otherIxs = message.instructions.filter((ix) => !ix.programId.equals((0, anchor_1.translateAddress)(constants_1.JUPITER_AGGREGATOR_PROGRAM_ID)));
479
+ const index = new anchor_1.BN(params.nextCardCounter.toString());
480
+ const swapAndCreateSilverCardIx = await this.getSwapAndCreateSilverCardInstruction(cardVault, cardVaultAta, inputMint, solana_common_1.TOKEN_PROGRAM_ID, usdc, revenueVault, revenueVaultAta, vaultOwner, {
481
+ index,
482
+ currency: params.currency,
483
+ emailHash: Array.from(emailHash),
484
+ swapData: swapInstruction.data,
485
+ }, swapInstruction.keys);
486
+ otherIxs.push(swapAndCreateSilverCardIx);
487
+ return this._createTransactionPayload(vaultOwner, otherIxs, [], addressLookupTableAccounts);
488
+ }
489
+ async swapAndLoadCarbonCard(params) {
490
+ const { vaultOwnerAddress, quoteInfo, emailHash, reloadCardId } = params;
491
+ if ("error" in quoteInfo) {
492
+ throw new Error(quoteInfo.error);
493
+ }
494
+ (0, core_utils_1.assertBufferSize)(emailHash, 32);
495
+ const [cardConfig] = (0, pda_1.deriveCardConfigPda)(this.cardV2ProgramId);
496
+ console.log("cardConfig:", cardConfig.toString());
497
+ const cardConfigInfo = await this.cardV2Program.account.card.fetch(cardConfig, this.connection.commitment);
498
+ const vaultOwner = (0, anchor_1.translateAddress)(vaultOwnerAddress);
499
+ const [vault] = (0, pda_1.deriveUserVault)(vaultOwner, this.vaultV1ProgramId);
500
+ const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.vaultV1ProgramId);
501
+ // const feePayer = user;
502
+ const inputMint = (0, anchor_1.translateAddress)(quoteInfo.inputMint);
503
+ const usdc = (0, anchor_1.translateAddress)(quoteInfo.outputMint);
504
+ // const [userPurchaseRecord] = deriveUserPurchaseRecordPda(user, this.vaultV1ProgramId);
505
+ const revenueVault = cardConfigInfo.revenueVault;
506
+ const cardVault = cardConfigInfo.cardVault;
507
+ const cardVaultAta = (0, solana_common_1.getAssociatedTokenAddressSync)(usdc, cardVault, true);
508
+ const revenueVaultAta = (0, solana_common_1.getAssociatedTokenAddressSync)(usdc, revenueVault, true);
509
+ const { swapTransaction } = await (await fetch("https://lite-api.jup.ag/swap/v1/swap", {
510
+ method: "POST",
511
+ headers: {
512
+ "Content-Type": "application/json",
513
+ },
514
+ body: JSON.stringify({
515
+ // quoteResponse from /quote api
516
+ quoteResponse: quoteInfo,
517
+ // user public key to be used for the swap
518
+ userPublicKey: vaultSigner.toString(),
519
+ // auto wrap and unwrap SOL. default is true
520
+ wrapAndUnwrapSol: false,
521
+ // feeAccount is optional. Use if you want to charge a fee. feeBps must have been passed in /quote API.
522
+ // feeAccount: "fee_account_public_key"
523
+ }),
524
+ })).json();
525
+ // deserialize the transaction
526
+ const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
527
+ const transaction = web3_js_1.VersionedTransaction.deserialize(swapTransactionBuf);
528
+ // get address lookup table accounts
529
+ const addressLookupTableAccounts = await Promise.all(transaction.message.addressTableLookups.map(async (lookup) => {
530
+ const data = await this.connection.getAccountInfo(lookup.accountKey).then((res) => res.data);
531
+ return new web3_js_1.AddressLookupTableAccount({
532
+ key: lookup.accountKey,
533
+ state: web3_js_1.AddressLookupTableAccount.deserialize(data),
534
+ });
535
+ }));
536
+ const lookupTableData = await new web3_js_1.Connection((0, web3_js_1.clusterApiUrl)("devnet"))
537
+ .getAccountInfo((0, anchor_1.translateAddress)(constants_1.CARD_LOOKUP_TABLE_ADDRESS))
538
+ .then((res) => res.data);
539
+ addressLookupTableAccounts.push(new web3_js_1.AddressLookupTableAccount({
540
+ key: (0, anchor_1.translateAddress)(constants_1.CARD_LOOKUP_TABLE_ADDRESS),
541
+ state: web3_js_1.AddressLookupTableAccount.deserialize(lookupTableData),
542
+ }));
543
+ // console.log("address lookup table:\n", addressLookupTableAccounts);
544
+ // decompile transaction message and add transfer instruction
545
+ const message = web3_js_1.TransactionMessage.decompile(transaction.message, {
546
+ addressLookupTableAccounts: addressLookupTableAccounts,
547
+ });
548
+ const swapInstruction = message.instructions.find((ix) => ix.programId.equals((0, anchor_1.translateAddress)(constants_1.JUPITER_AGGREGATOR_PROGRAM_ID)));
549
+ (0, assert_1.default)(swapInstruction, "Swap instruction not found in the transaction message");
550
+ const otherIxs = message.instructions.filter((ix) => !ix.programId.equals((0, anchor_1.translateAddress)(constants_1.JUPITER_AGGREGATOR_PROGRAM_ID)));
551
+ const index = new anchor_1.BN(params.nextCardCounter.toString());
552
+ const swapAndCreateSilverCardIx = await this.getSwapAndLoadCarbonCardInstruction(cardVault, cardVaultAta, inputMint, solana_common_1.TOKEN_PROGRAM_ID, usdc, revenueVault, revenueVaultAta, vaultOwner, {
553
+ index,
554
+ currency: params.currency,
555
+ emailHash: Array.from(emailHash),
556
+ swapData: swapInstruction.data,
557
+ reloadCardId,
558
+ }, swapInstruction.keys);
559
+ otherIxs.push(swapAndCreateSilverCardIx);
560
+ return this._createTransactionPayload(vaultOwner, otherIxs, [], addressLookupTableAccounts);
561
+ }
562
+ async createstreamFromVault(params) {
563
+ const vaultOwner = (0, anchor_1.translateAddress)(params.sender);
564
+ const [vault] = (0, pda_1.deriveUserVault)(vaultOwner, this.vaultV1ProgramId);
565
+ const [vaultSigner] = (0, pda_1.deriveVaultSigner)(vault, this.vaultV1ProgramId);
566
+ const receiver = (0, anchor_1.translateAddress)(params.receiver);
567
+ const [receiverVault] = (0, pda_1.deriveUserVault)(receiver, this.vaultV1ProgramId);
568
+ const [receiverVaultSigner] = (0, pda_1.deriveVaultSigner)(receiverVault, this.vaultV1ProgramId);
569
+ const streamToken = (0, anchor_1.translateAddress)(params.streamToken);
570
+ const vaultSignerAta = (0, solana_common_1.getAssociatedTokenAddressSync)(streamToken, vaultSigner, true);
571
+ const receiverVaultSignerAta = (0, solana_common_1.getAssociatedTokenAddressSync)(streamToken, receiverVaultSigner, true);
572
+ const [streamConfig] = (0, pda_1.deriveStreamConfigPda)(this.streamProgramId);
573
+ const streamConfigInfo = await this.streamProgram.account.streamConfig.fetch(streamConfig, this.connection.commitment);
574
+ const withdrawAccount = streamConfigInfo.withdrawAccount;
575
+ const streamMetatdataKeypair = params.streamMetadataKeypair ?? web3_js_1.Keypair.generate();
576
+ const streamMetadata = streamMetatdataKeypair.publicKey;
577
+ const [streamVault] = (0, pda_1.deriveStreamVaultPda)(streamMetadata, this.streamProgramId);
578
+ const streamVaultAta = (0, solana_common_1.getAssociatedTokenAddressSync)(streamToken, streamVault, true);
579
+ const streamTokenDecimals = await (0, solana_common_1.getMintDecimals)(this.connection, streamToken);
580
+ const amount = new anchor_1.BN((0, bignumber_js_1.BigNumber)(params.amount).times(constants_1.TEN_BIGNUM.pow(streamTokenDecimals)).toFixed(0));
581
+ const cliffPercentage = new anchor_1.BN((0, core_utils_1.percentToBps)(params.cliffPercentage));
582
+ const STREAM_NAME_BUFFER_SIZE = 128;
583
+ const streamNameBuffer = Buffer.alloc(STREAM_NAME_BUFFER_SIZE);
584
+ streamNameBuffer.fill(anchor_1.utils.bytes.utf8.encode(params.streamName), 0);
585
+ const ix = await this.getCreateStreamFromVaultInstruction(vaultOwner, vault, vaultSigner, vaultSignerAta, receiverVaultSigner, receiverVaultSignerAta, streamToken, streamMetadata, streamConfig, withdrawAccount, streamVault, streamVaultAta, this.streamProgramId, {
586
+ amount,
587
+ automaticWithdrawal: params.automaticWithdrawal,
588
+ autoWithdrawFrequency: new anchor_1.BN(params.autoWithdrawFrequency),
589
+ cancelableByRecipient: params.cancelableByRecipient,
590
+ cancelableBySender: params.cancelableBySender,
591
+ canTopup: params.canTopup,
592
+ cliffPercentage,
593
+ duration: new anchor_1.BN(params.duration),
594
+ isPausable: params.isPausable,
595
+ numberOfWithdrawls: new anchor_1.BN(Math.floor(params.duration / params.autoWithdrawFrequency)),
596
+ rateUpdatable: params.rateUpdatable,
597
+ startNow: params.startNow,
598
+ startTime: new anchor_1.BN(params.startTime),
599
+ streamName: streamNameBuffer,
600
+ transferableByRecipient: params.transferableByRecipient,
601
+ transferableBySender: params.transferableBySender,
602
+ });
603
+ return this._createTransactionPayload(vaultOwner, [ix], [streamMetatdataKeypair]);
604
+ }
328
605
  async _createTransactionPayload(payerKey, instructions, signers, addressLookupTableAccounts) {
329
606
  const errorMap = new Map();
330
- this.program.idl.errors.forEach((error) => errorMap.set(error.code, error.msg));
607
+ this.vaultV1Program.idl.errors.forEach((error) => errorMap.set(error.code, error.msg));
331
608
  let signTransaction = undefined;
332
609
  const provider = this.provider;
333
610
  if (provider instanceof anchor_1.AnchorProvider) {
@@ -337,56 +614,38 @@ class ZebecVaultService {
337
614
  }
338
615
  return new solana_common_1.TransactionPayload(this.provider.connection, errorMap, instructions, payerKey, signers, addressLookupTableAccounts, signTransaction);
339
616
  }
340
- async getVaultsInfoOfUser(user) {
617
+ async getVaultInfoOfUser(user) {
341
618
  user = user ? (0, anchor_1.translateAddress)(user) : this.provider.publicKey;
342
619
  if (!user) {
343
620
  throw new Error("Either provide a user or use AnchorProvider for provider in the service");
344
621
  }
345
- const accountInfos = await this.connection.getProgramAccounts(this.programId, {
346
- commitment: this.connection.commitment,
347
- filters: [
348
- {
349
- memcmp: {
350
- offset: 0, // offset for discriminator in Vault
351
- bytes: anchor_1.utils.bytes.bs58.encode(this.program.idl.accounts[1].discriminator),
352
- encoding: "base58",
353
- },
354
- },
355
- {
356
- memcmp: {
357
- offset: 8, // offset for owner field in Vault
358
- bytes: user.toBase58(),
359
- encoding: "base58",
360
- },
361
- },
362
- ],
363
- });
364
- const vaults = accountInfos.map((accountInfo) => {
365
- const vaultAccount = this.program.coder.accounts.decode(this.program.idl.accounts[1].name, accountInfo.account.data);
366
- return {
367
- vault: accountInfo.pubkey,
368
- owner: vaultAccount.owner,
369
- createdDate: vaultAccount.createdDate.toNumber(),
370
- signerBump: vaultAccount.signerBump,
371
- };
372
- });
373
- return vaults;
622
+ const [vault] = (0, pda_1.deriveUserVault)(user, this.vaultV1ProgramId);
623
+ const vaultAccount = await this.vaultV1Program.account.vault.fetchNullable(vault, this.connection.commitment);
624
+ if (!vaultAccount) {
625
+ return null;
626
+ }
627
+ return {
628
+ createdDate: vaultAccount.createdDate.toNumber(),
629
+ owner: vaultAccount.owner,
630
+ signerBump: vaultAccount.signerBump,
631
+ vault,
632
+ };
374
633
  }
375
634
  async getAllVaultsInfo() {
376
- const accountInfos = await this.connection.getProgramAccounts(this.programId, {
635
+ const accountInfos = await this.connection.getProgramAccounts(this.vaultV1ProgramId, {
377
636
  commitment: this.connection.commitment,
378
637
  filters: [
379
638
  {
380
639
  memcmp: {
381
640
  offset: 0, // offset for discriminator in Vault
382
- bytes: anchor_1.utils.bytes.bs58.encode(this.program.idl.accounts[1].discriminator),
641
+ bytes: anchor_1.utils.bytes.bs58.encode(this.vaultV1Program.idl.accounts[1].discriminator),
383
642
  encoding: "base58",
384
643
  },
385
644
  },
386
645
  ],
387
646
  });
388
647
  const vaults = accountInfos.map((accountInfo) => {
389
- const vaultAccount = this.program.coder.accounts.decode(this.program.idl.accounts[1].name, accountInfo.account.data);
648
+ const vaultAccount = this.vaultV1Program.coder.accounts.decode(this.vaultV1Program.idl.accounts[1].name, accountInfo.account.data);
390
649
  return {
391
650
  vault: accountInfo.pubkey,
392
651
  owner: vaultAccount.owner,
@@ -398,13 +657,13 @@ class ZebecVaultService {
398
657
  }
399
658
  async getProposalsInfoOfVault(vault) {
400
659
  const _vault = (0, anchor_1.translateAddress)(vault);
401
- const accountInfos = await this.connection.getProgramAccounts(this.programId, {
660
+ const accountInfos = await this.connection.getProgramAccounts(this.vaultV1ProgramId, {
402
661
  commitment: this.connection.commitment,
403
662
  filters: [
404
663
  {
405
664
  memcmp: {
406
665
  offset: 0, // offset for discriminator in Proposal
407
- bytes: anchor_1.utils.bytes.bs58.encode(this.program.idl.accounts[0].discriminator),
666
+ bytes: anchor_1.utils.bytes.bs58.encode(this.vaultV1Program.idl.accounts[0].discriminator),
408
667
  encoding: "base58",
409
668
  },
410
669
  },
@@ -418,7 +677,7 @@ class ZebecVaultService {
418
677
  ],
419
678
  });
420
679
  const proposals = accountInfos.map((accountInfo) => {
421
- const proposalAccount = this.program.coder.accounts.decode(this.program.idl.accounts[0].name, accountInfo.account.data);
680
+ const proposalAccount = this.vaultV1Program.coder.accounts.decode(this.vaultV1Program.idl.accounts[0].name, accountInfo.account.data);
422
681
  return {
423
682
  proposal: accountInfo.pubkey,
424
683
  vault: proposalAccount.vault,
@@ -432,8 +691,14 @@ class ZebecVaultService {
432
691
  });
433
692
  return proposals;
434
693
  }
435
- get programId() {
436
- return this.program.programId;
694
+ get vaultV1ProgramId() {
695
+ return this.vaultV1Program.programId;
696
+ }
697
+ get cardV2ProgramId() {
698
+ return this.cardV2Program.programId;
699
+ }
700
+ get streamProgramId() {
701
+ return this.streamProgram.programId;
437
702
  }
438
703
  get connection() {
439
704
  return this.provider.connection;