@zebec-network/solana-payroll-sdk 2.6.0-dev.1 → 2.6.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.
@@ -4,3 +4,8 @@ export declare const PAYROLL_PROGRAM_ID: Record<RpcNetwork, string>;
4
4
  export declare const USX_DECIMALS = 6;
5
5
  export declare const DEFAULT_FEE_RATE_IN_BPS = 500;
6
6
  export declare const BPS_DENOMINATOR = 10000;
7
+ export declare const JUPITER_SWAP_API = "https://lite-api.jup.ag/swap/v1/swap";
8
+ export declare const CARD_LOOKUP_TABLE_ADDRESS: Record<"mainnet-beta" | "devnet", string>;
9
+ export declare const JUPITER_AGGREGATOR_PROGRAM_ID = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
10
+ export declare const PAYROLL_TOKEN_PRICE_MESSAGE_SIZE = 48;
11
+ export declare const ED25519_SIGNATURE_SIZE = 64;
package/dist/constants.js CHANGED
@@ -6,3 +6,11 @@ export const PAYROLL_PROGRAM_ID = {
6
6
  export const USX_DECIMALS = 6;
7
7
  export const DEFAULT_FEE_RATE_IN_BPS = 500;
8
8
  export const BPS_DENOMINATOR = 10000;
9
+ export const JUPITER_SWAP_API = "https://lite-api.jup.ag/swap/v1/swap";
10
+ export const CARD_LOOKUP_TABLE_ADDRESS = {
11
+ "mainnet-beta": "9BSK7XgPgAZJK6BEdiFDV8WKGye31uffvGjhQ1Zxob7F",
12
+ devnet: "CgPARkLEbygMJ8C9Z1u6MP57gvdnUERCxdhmR9bTFUSJ",
13
+ };
14
+ export const JUPITER_AGGREGATOR_PROGRAM_ID = "JUP6LkbZbjS1jKKwapdHNy74zcZ3tLUZoi5QNyVTaV4";
15
+ export const PAYROLL_TOKEN_PRICE_MESSAGE_SIZE = 48;
16
+ export const ED25519_SIGNATURE_SIZE = 64;
@@ -1,5 +1,5 @@
1
1
  import type { BN, Program } from "@coral-xyz/anchor";
2
- import type { AccountMeta, PublicKey, TransactionInstruction } from "@solana/web3.js";
2
+ import { type AccountMeta, type PublicKey, type TransactionInstruction } from "@solana/web3.js";
3
3
  import type { ZebecPayroll as ZebecPayrollIdl } from "@zebec-network/zebec_payroll";
4
4
  export declare function createCreatePayrollInstruction(program: Program<ZebecPayrollIdl>, accounts: {
5
5
  sender: PublicKey;
@@ -13,6 +13,8 @@ export declare function createCreatePayrollInstruction(program: Program<ZebecPay
13
13
  payrollConfig: PublicKey;
14
14
  withdrawAccount: PublicKey;
15
15
  payrollToken: PublicKey;
16
+ feeVault: PublicKey;
17
+ feeVaultTokenAccount: PublicKey;
16
18
  }, data: {
17
19
  amount: BN;
18
20
  startTime: BN;
@@ -33,6 +35,8 @@ export declare function createCreatePayrollInstruction(program: Program<ZebecPay
33
35
  autoTopupDelegate: number;
34
36
  senderId: number[];
35
37
  receiverId: number[];
38
+ priceExpiry: BN;
39
+ tokenPrice: BN;
36
40
  }): Promise<TransactionInstruction>;
37
41
  export declare function createCancelPayrollInstruction(program: Program<ZebecPayrollIdl>, accounts: {
38
42
  signer: PublicKey;
@@ -183,7 +187,6 @@ export declare function createSwapAndCreateCardInstruction(payrollProgram: Progr
183
187
  enterpriseCardConfig: PublicKey;
184
188
  enterpriseCardIndex: PublicKey;
185
189
  feePayer: PublicKey;
186
- jupiterProgram: PublicKey;
187
190
  revenueVault: PublicKey;
188
191
  revenueVaultAta: PublicKey;
189
192
  sourceToken: PublicKey;
@@ -1,6 +1,9 @@
1
+ import { SYSVAR_INSTRUCTIONS_PUBKEY, } from "@solana/web3.js";
1
2
  export async function createCreatePayrollInstruction(program, accounts, data) {
2
3
  return program.methods
3
4
  .createStream({
5
+ priceExpiry: data.priceExpiry,
6
+ tokenPrice: data.tokenPrice,
4
7
  amount: data.amount,
5
8
  startTime: data.startTime,
6
9
  duration: data.duration,
@@ -33,6 +36,9 @@ export async function createCreatePayrollInstruction(program, accounts, data) {
33
36
  payrollConfig: accounts.payrollConfig,
34
37
  withdrawAccount: accounts.withdrawAccount,
35
38
  streamToken: accounts.payrollToken,
39
+ feeVault: accounts.feeVault,
40
+ feeVaultTokenAccount: accounts.feeVaultTokenAccount,
41
+ instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
36
42
  })
37
43
  .instruction();
38
44
  }
package/dist/pda.js CHANGED
@@ -48,7 +48,7 @@ export function deriveEnterpriseCardPurchasePda(userAddress, entCardConfigName,
48
48
  PAYROLL_PROGRAM_SEEDS.ENT_USER_CARD_PURCHASE,
49
49
  translateAddress(userAddress).toBuffer(),
50
50
  utils.bytes.utf8.encode(entCardConfigName),
51
- new BN(cardIndex).toArrayLike(Buffer, "le"),
51
+ new BN(cardIndex).toArrayLike(Buffer, "le", 8),
52
52
  ], translateAddress(payrollProgramId));
53
53
  }
54
54
  export function deriveEnterpriseUserPurchaseRecordPda(userAddress, entCardConfigName, payrollProgramId) {
@@ -3,12 +3,12 @@ import { type Commitment } from "@solana/web3.js";
3
3
  import { MultiTransactionPayload, TransactionPayload } from "@zebec-network/solana-common";
4
4
  import type { ZebecConfigs as ZebecConfigsIdl } from "@zebec-network/zebec_configs";
5
5
  import type { ZebecPayroll as ZebecPayrollIdl } from "@zebec-network/zebec_payroll";
6
- import type { CancelMultiplePayrollParams, CancelPayrollParams, CancelUnlockParams, ChangePayrollReceiverParams, CompanyDepositInfo, CompanyNonceInfo, CompleteUnlockParams, CreateMultiplePayrollParams, CreatePayrollParams, DistributeRewardsParams, Numeric, PauseResumeMultiplePayrollParams, PauseResumePayrollParams, PayrollConfigInfo, PayrollMetadataInfo, RequestUnlockParams, SetMultipleTopupDelegateParams, SetTopupDelegateParams, TokenMetadata, TopupMultiplePayrollParams, TopupPayrollParams, WithdrawMultiplePayrollParams, WithdrawPayrollParams, YieldDepositParams } from "./types.js";
6
+ import type { CancelMultiplePayrollParams, CancelPayrollParams, CancelUnlockParams, CardPurchaseInfo, ChangePayrollReceiverParams, CompanyDepositInfo, CompanyNonceInfo, CompleteUnlockParams, CreateCardParams, CreateMultiplePayrollParams, CreatePayrollParams, DistributeRewardsParams, PauseResumeMultiplePayrollParams, PauseResumePayrollParams, PayrollConfigInfo, PayrollMetadataInfo, RequestUnlockParams, SetMultipleTopupDelegateParams, SetTopupDelegateParams, SwapAndCreateCardParams, TokenMetadata, TopupMultiplePayrollParams, TopupPayrollParams, UserPurchaseRecordInfo, WithdrawMultiplePayrollParams, WithdrawPayrollParams, YieldDepositParams } from "./types.js";
7
7
  export declare function getPayrollConfig(configProgram: Program<ZebecConfigsIdl>, configName: string): Promise<PayrollConfigInfo>;
8
8
  export declare function getWhitelistedTokens(configProgram: Program<ZebecConfigsIdl>, configName: string, commitment?: "processed" | "confirmed" | "finalized"): Promise<TokenMetadata[]>;
9
9
  export declare function getPayrollMetadataInfo(program: Program<ZebecPayrollIdl>, payrollMetadata: Address, commitment?: Commitment): Promise<PayrollMetadataInfo>;
10
- export declare function createPayroll(payrollProgram: Program<ZebecPayrollIdl>, configProgram: Program<ZebecConfigsIdl>, params: CreatePayrollParams, _payrollFeeBaseUrl: string): Promise<TransactionPayload>;
11
- export declare function createMultiplePayroll(payrollProgram: Program<ZebecPayrollIdl>, configProgram: Program<ZebecConfigsIdl>, params: CreateMultiplePayrollParams, _payrollFeeBaseUrl: string): Promise<MultiTransactionPayload>;
10
+ export declare function createPayroll(payrollProgram: Program<ZebecPayrollIdl>, configProgram: Program<ZebecConfigsIdl>, params: CreatePayrollParams): Promise<TransactionPayload>;
11
+ export declare function createMultiplePayroll(payrollProgram: Program<ZebecPayrollIdl>, configProgram: Program<ZebecConfigsIdl>, params: CreateMultiplePayrollParams): Promise<MultiTransactionPayload>;
12
12
  export declare function cancelPayroll(program: Program<ZebecPayrollIdl>, params: CancelPayrollParams): Promise<TransactionPayload>;
13
13
  export declare function cancelMultiplePayroll(program: Program<ZebecPayrollIdl>, params: CancelMultiplePayrollParams): Promise<MultiTransactionPayload>;
14
14
  export declare function pauseResumePayroll(program: Program<ZebecPayrollIdl>, params: PauseResumePayrollParams): Promise<TransactionPayload>;
@@ -27,13 +27,12 @@ export declare function cancelUnlock(payrollProgram: Program<ZebecPayrollIdl>, p
27
27
  export declare function completeUnlock(payrollProgram: Program<ZebecPayrollIdl>, configsProgram: Program<ZebecConfigsIdl>, params: CompleteUnlockParams, commitment?: Commitment): Promise<TransactionPayload>;
28
28
  export declare function distributeRewards(payrollProgram: Program<ZebecPayrollIdl>, configsProgram: Program<ZebecConfigsIdl>, params: DistributeRewardsParams): Promise<TransactionPayload>;
29
29
  export declare function getCompanyDeposit(payrollProgram: Program<ZebecPayrollIdl>, company: Address): Promise<CompanyDepositInfo | null>;
30
- export declare function createCard(payrollProgram: Program<ZebecPayrollIdl>, configsProgram: Program<ZebecConfigsIdl>, params: {
31
- currency: string;
32
- reloadCardId: string;
33
- nextCardIndex: bigint;
34
- user: Address;
35
- feePayer: Address;
36
- emailHash: Buffer | Uint8Array;
37
- amount: Numeric;
38
- entCardConfigName: string;
39
- }): Promise<TransactionPayload>;
30
+ export declare function createCard(payrollProgram: Program<ZebecPayrollIdl>, configsProgram: Program<ZebecConfigsIdl>, params: CreateCardParams): Promise<TransactionPayload>;
31
+ export declare function swapAndCreateCard(payrollProgram: Program<ZebecPayrollIdl>, configsProgram: Program<ZebecConfigsIdl>, params: SwapAndCreateCardParams): Promise<TransactionPayload>;
32
+ export declare function getCardIndexInfo(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, commitment?: Commitment): Promise<{
33
+ index: bigint;
34
+ totoalCardSold: string;
35
+ } | null>;
36
+ export declare function getNextCardIndex(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, commitment?: Commitment): Promise<bigint>;
37
+ export declare function getUserPurchaseRecordInfo(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, user: Address, commitment?: Commitment): Promise<UserPurchaseRecordInfo | null>;
38
+ export declare function getCardPurchaseInfo(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, user: Address, cardIndex: bigint, commitment?: Commitment): Promise<CardPurchaseInfo | null>;
package/dist/services.js CHANGED
@@ -2,13 +2,14 @@ import { AnchorProvider, translateAddress, utils, } from "@coral-xyz/anchor";
2
2
  import { fetchMetadata, MPL_TOKEN_METADATA_PROGRAM_ID, } from "@metaplex-foundation/mpl-token-metadata";
3
3
  import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
4
4
  import { fromWeb3JsPublicKey, toWeb3JsPublicKey, } from "@metaplex-foundation/umi-web3js-adapters";
5
- import { Keypair, PublicKey, } from "@solana/web3.js";
5
+ import { createCloseAccountInstruction, createSyncNativeInstruction, } from "@solana/spl-token";
6
+ import { AddressLookupTableAccount, ComputeBudgetProgram, Ed25519Program, Keypair, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
6
7
  import { assertBufferSize, bpsToPercent, percentToBps, } from "@zebec-network/core-utils";
7
- import { getAssociatedTokenAddressSync, getMintDecimals, MultiTransactionPayload, TEN_BIGNUM, TransactionPayload, UNITS_PER_USDC, USDC_DECIMALS, } from "@zebec-network/solana-common";
8
+ import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddressSync, getMintDecimals, MultiTransactionPayload, TEN_BIGNUM, TransactionPayload, UNITS_PER_USDC, USDC_DECIMALS, WSOL, } from "@zebec-network/solana-common";
8
9
  import { BigNumber } from "bignumber.js";
9
10
  import { BN } from "bn.js";
10
- import { PAYROLL_NAME_BUFFER_SIZE, USX_DECIMALS } from "./constants.js";
11
- import { createCancelPayrollInstruction, createCancelUnlockInstruction, createChangeRecipientInstruction, createCompleteUnlockInstruction, createCreateCardInstruction, createCreatePayrollInstruction, createDistributeRewardsInstruction, createPauseResumePayrollInstruction, createRequestUnlockInstruction, createSetTopupDelegateInstruction, createTopupPayrollInstruction, createWithdrawPayrollInstruction, createYieldDepositInstruction, } from "./instructions.js";
11
+ import { CARD_LOOKUP_TABLE_ADDRESS, ED25519_SIGNATURE_SIZE, JUPITER_AGGREGATOR_PROGRAM_ID, JUPITER_SWAP_API, PAYROLL_NAME_BUFFER_SIZE, PAYROLL_TOKEN_PRICE_MESSAGE_SIZE, USX_DECIMALS, } from "./constants.js";
12
+ import { createCancelPayrollInstruction, createCancelUnlockInstruction, createChangeRecipientInstruction, createCompleteUnlockInstruction, createCreateCardInstruction, createCreatePayrollInstruction, createDistributeRewardsInstruction, createPauseResumePayrollInstruction, createRequestUnlockInstruction, createSetTopupDelegateInstruction, createSwapAndCreateCardInstruction, createTopupPayrollInstruction, createWithdrawPayrollInstruction, createYieldDepositInstruction, } from "./instructions.js";
12
13
  import { deriveCheckAccountPda, deriveCompanyDepositPda, deriveCompanyNoncePda, deriveEnterpriseCardConfigPda, deriveEnterpriseCardIndexPda, deriveEnterpriseCardPurchasePda, deriveEnterpriseUserPurchaseRecordPda, derivePayrollConfigPda, derivePayrollVaultPda, deriveYieldConfigPda, } from "./pda.js";
13
14
  import { deductFeeFromAmount, getConnectionFromProgram,
14
15
  // getFeeInfoForPayroll,
@@ -204,7 +205,7 @@ function createMultiTransactionPayload(program, feePayer, transactionData) {
204
205
  feePayer,
205
206
  })), signAllTransactions);
206
207
  }
207
- export async function createPayroll(payrollProgram, configProgram, params, _payrollFeeBaseUrl) {
208
+ export async function createPayroll(payrollProgram, configProgram, params) {
208
209
  const receiver = translateAddress(params.receiver);
209
210
  const sender = translateAddress(params.sender);
210
211
  const feePayer = params.feePayer ? translateAddress(params.feePayer) : sender;
@@ -235,57 +236,21 @@ export async function createPayroll(payrollProgram, configProgram, params, _payr
235
236
  const cliffPercentage = new BN(percentToBps(params.cliffPercentage));
236
237
  const payrollRunId = new Uint8Array(PAYROLL_NAME_BUFFER_SIZE);
237
238
  payrollRunId.set(utils.bytes.utf8.encode(params.payrollRunId));
238
- // const feeInfo = await getFeeInfoForPayroll(
239
- // payrollFeeBaseUrl,
240
- // payrollToken,
241
- // amount,
242
- // );
243
- // const feeTokenDecimals = await getMintDecimals(
244
- // payrollProgram.provider.connection,
245
- // payrollConfigAccount.feeToken,
246
- // );
247
- // const parsedFeeAmount = feeInfo.feeAmountRaw;
248
- // const feeVault = payrollConfigAccount.feeVault;
249
- // const feeVaultAta = getAssociatedTokenAddressSync(
250
- // payrollConfigAccount.feeToken,
251
- // feeVault,
252
- // true,
253
- // );
254
- // const senderFeeTokenAta = getAssociatedTokenAddressSync(
255
- // payrollConfigAccount.feeToken,
256
- // sender,
257
- // true,
258
- // );
259
- // const feeVaultAtaInfo =
260
- // await payrollProgram.provider.connection.getAccountInfo(feeVaultAta);
239
+ const feeVault = payrollConfigAccount.feeVault;
240
+ const feeVaultTokenAccount = getAssociatedTokenAddressSync(payrollToken, feeVault, true);
241
+ const priceExpiry = new BN(params.priceData.priceExpiryUnixTimestamp);
242
+ const tokenPrice = new BN(params.priceData.tokenPrice);
243
+ assertBufferSize(params.priceData.signature, ED25519_SIGNATURE_SIZE);
244
+ assertBufferSize(params.priceData.message, PAYROLL_TOKEN_PRICE_MESSAGE_SIZE);
245
+ const message = Uint8Array.from(params.priceData.message);
246
+ const signature = Uint8Array.from(params.priceData.signature);
261
247
  const ixs = [];
262
- // // add instruction to create fee vault ATA if it does not exist
263
- // if (!feeVaultAtaInfo) {
264
- // const createFeeVaultAtaIx = createAssociatedTokenAccountInstruction(
265
- // feePayer,
266
- // feeVaultAta,
267
- // feeVault,
268
- // payrollConfigAccount.feeToken,
269
- // );
270
- // ixs.push(createFeeVaultAtaIx);
271
- // }
272
- // add instruction to transfer fee to fee vault
273
- // const transferFeeIx = await createTransferFeesInstruction(
274
- // payrollProgram,
275
- // {
276
- // feeVault,
277
- // feeVaultTokenAccount: feeVaultAta,
278
- // payrollConfig,
279
- // sender,
280
- // senderTokenAccount: senderFeeTokenAta,
281
- // tokenMint: payrollConfigAccount.feeToken,
282
- // },
283
- // {
284
- // decimals: feeTokenDecimals,
285
- // feeAmount: new BN(parsedFeeAmount),
286
- // },
287
- // );
288
- // ixs.push(transferFeeIx);
248
+ const ed25519Ix = Ed25519Program.createInstructionWithPublicKey({
249
+ publicKey: payrollConfigAccount.admin.toBytes(), // admin pubkey (32 bytes)
250
+ signature, // backend signature (64 bytes),
251
+ message, // 48-byte price message
252
+ });
253
+ ixs.push(ed25519Ix);
289
254
  const createpayrollIx = await createCreatePayrollInstruction(payrollProgram, {
290
255
  payrollConfig,
291
256
  feePayer,
@@ -298,6 +263,8 @@ export async function createPayroll(payrollProgram, configProgram, params, _payr
298
263
  payrollVault,
299
264
  payrollVaultAta,
300
265
  withdrawAccount: withdrawer,
266
+ feeVault,
267
+ feeVaultTokenAccount,
301
268
  }, {
302
269
  autoTopupDelegate: Number(params.delegateAutoTopup),
303
270
  initialBufferAmount: new BN(initialBufferAmount),
@@ -318,13 +285,15 @@ export async function createPayroll(payrollProgram, configProgram, params, _payr
318
285
  transferableBySender: Number(params.transferableBySender),
319
286
  receiverId: Array.from(params.receiverId),
320
287
  senderId: Array.from(params.senderId),
288
+ priceExpiry,
289
+ tokenPrice,
321
290
  });
322
291
  ixs.push(createpayrollIx);
323
292
  return createTransactionPayload(payrollProgram, feePayer, ixs, [
324
293
  payrollMetadataKeypair,
325
294
  ]);
326
295
  }
327
- export async function createMultiplePayroll(payrollProgram, configProgram, params, _payrollFeeBaseUrl) {
296
+ export async function createMultiplePayroll(payrollProgram, configProgram, params) {
328
297
  const sender = translateAddress(params.sender);
329
298
  const feePayer = params.feePayer ? translateAddress(params.feePayer) : sender;
330
299
  const senderId = Array.from(params.senderId);
@@ -357,57 +326,21 @@ export async function createMultiplePayroll(payrollProgram, configProgram, param
357
326
  const cliffPercentage = new BN(percentToBps(payroll.cliffPercentage));
358
327
  const payrollRunId = new Uint8Array(PAYROLL_NAME_BUFFER_SIZE);
359
328
  payrollRunId.set(utils.bytes.utf8.encode(payroll.payrollRunId));
360
- // const feeInfo = await getFeeInfoForPayroll(
361
- // payrollFeeBaseUrl,
362
- // payrollToken,
363
- // amount,
364
- // );
365
- // const feeTokenDecimals = await getMintDecimals(
366
- // payrollProgram.provider.connection,
367
- // payrollConfigAccount.feeToken,
368
- // );
369
- // const parsedFeeAmount = feeInfo.feeAmountRaw;
370
- // const feeVault = payrollConfigAccount.feeVault;
371
- // const feeVaultAta = getAssociatedTokenAddressSync(
372
- // payrollConfigAccount.feeToken,
373
- // feeVault,
374
- // true,
375
- // );
376
- // const senderFeeTokenAta = getAssociatedTokenAddressSync(
377
- // payrollConfigAccount.feeToken,
378
- // sender,
379
- // true,
380
- // );
381
- // const feeVaultAtaInfo =
382
- // await payrollProgram.provider.connection.getAccountInfo(feeVaultAta);
329
+ const feeVault = payrollConfigAccount.feeVault;
330
+ const feeVaultTokenAccount = getAssociatedTokenAddressSync(payrollToken, feeVault, true);
331
+ const priceExpiry = new BN(payroll.priceData.priceExpiryUnixTimestamp);
332
+ const tokenPrice = new BN(payroll.priceData.tokenPrice);
333
+ const message = Uint8Array.from(payroll.priceData.message);
334
+ const signature = Uint8Array.from(payroll.priceData.signature);
335
+ assertBufferSize(payroll.priceData.signature, ED25519_SIGNATURE_SIZE);
336
+ assertBufferSize(payroll.priceData.message, PAYROLL_TOKEN_PRICE_MESSAGE_SIZE);
383
337
  const instructions = [];
384
- // add instruction to create fee vault ATA if it does not exist
385
- // if (!feeVaultAtaInfo) {
386
- // const createFeeVaultAtaIx = createAssociatedTokenAccountInstruction(
387
- // feePayer,
388
- // feeVaultAta,
389
- // feeVault,
390
- // payrollConfigAccount.feeToken,
391
- // );
392
- // instructions.push(createFeeVaultAtaIx);
393
- // }
394
- // add instruction to transfer fee to fee vault
395
- // const transferFeeIx = await createTransferFeesInstruction(
396
- // payrollProgram,
397
- // {
398
- // feeVault,
399
- // feeVaultTokenAccount: feeVaultAta,
400
- // payrollConfig,
401
- // sender,
402
- // senderTokenAccount: senderFeeTokenAta,
403
- // tokenMint: payrollConfigAccount.feeToken,
404
- // },
405
- // {
406
- // decimals: feeTokenDecimals,
407
- // feeAmount: new BN(parsedFeeAmount),
408
- // },
409
- // );
410
- // instructions.push(transferFeeIx);
338
+ const ed25519Ix = Ed25519Program.createInstructionWithPublicKey({
339
+ publicKey: payrollConfigAccount.admin.toBytes(), // admin pubkey (32 bytes)
340
+ signature, // backend signature (64 bytes),
341
+ message, // 48-byte price message
342
+ });
343
+ instructions.push(ed25519Ix);
411
344
  const createpayrollIx = await createCreatePayrollInstruction(payrollProgram, {
412
345
  payrollConfig,
413
346
  feePayer,
@@ -420,6 +353,8 @@ export async function createMultiplePayroll(payrollProgram, configProgram, param
420
353
  payrollVault,
421
354
  payrollVaultAta,
422
355
  withdrawAccount: withdrawer,
356
+ feeVault,
357
+ feeVaultTokenAccount,
423
358
  }, {
424
359
  autoTopupDelegate: Number(payroll.delegateAutoTopup),
425
360
  initialBufferAmount: new BN(initialBufferAmount),
@@ -440,6 +375,8 @@ export async function createMultiplePayroll(payrollProgram, configProgram, param
440
375
  transferableBySender: Number(payroll.transferableBySender),
441
376
  receiverId: Array.from(payroll.receiverId),
442
377
  senderId,
378
+ priceExpiry,
379
+ tokenPrice,
443
380
  });
444
381
  instructions.push(createpayrollIx);
445
382
  return {
@@ -931,10 +868,10 @@ export async function createCard(payrollProgram, configsProgram, params) {
931
868
  throw new Error(`CardConfigAccountNotFound: Enterprise Card Config Account does not exits for config name: ${params.entCardConfigName}`);
932
869
  }
933
870
  const usdcMint = cardConfigAccount.usdcMint;
934
- const userAta = getAssociatedTokenAddressSync(usdcMint, user, true);
935
871
  const cardVault = cardConfigAccount.cardVault;
936
- const cardVaultAta = getAssociatedTokenAddressSync(usdcMint, cardVault, true);
937
872
  const revenueVault = cardConfigAccount.revenueVault;
873
+ const userAta = getAssociatedTokenAddressSync(usdcMint, user, true);
874
+ const cardVaultAta = getAssociatedTokenAddressSync(usdcMint, cardVault, true);
938
875
  const revenueVaultAta = getAssociatedTokenAddressSync(usdcMint, revenueVault, true);
939
876
  const [enterpriseCardIndex] = deriveEnterpriseCardIndexPda(params.entCardConfigName, payrollProgram.programId);
940
877
  const [cardPurchasePda] = deriveEnterpriseCardPurchasePda(user, params.entCardConfigName, params.nextCardIndex, payrollProgram.programId);
@@ -991,49 +928,227 @@ export async function createCard(payrollProgram, configsProgram, params) {
991
928
  });
992
929
  return createTransactionPayload(payrollProgram, feePayer, [instruction]);
993
930
  }
994
- // export async function swapAndCreateCard(
995
- // payrollProgram: Program<ZebecPayrollIdl>,
996
- // configsProgram: Program<ZebecConfigsIdl>,
997
- // params: {
998
- // currency: string;
999
- // reloadCardId: string;
1000
- // nextCardIndex: bigint;
1001
- // user: Address;
1002
- // feePayer: Address;
1003
- // emailHash: Buffer | Uint8Array;
1004
- // amount: Numeric;
1005
- // entCardConfigName: string;
1006
- // quoteInfo: QuoteInfo;
1007
- // }
1008
- // ) {
1009
- // const connection = getConnectionFromProgram(payrollProgram);
1010
- // const user = translateAddress(params.user);
1011
- // const feePayer = translateAddress(params.feePayer);
1012
- // const quoteInfo = params.quoteInfo;
1013
- // if ("error" in quoteInfo) {
1014
- // throw new Error(quoteInfo.error);
1015
- // }
1016
- // assertBufferSize(params.emailHash, 32);
1017
- // const [enterpriseCardConfig] = deriveEnterpriseCardConfigPda(
1018
- // params.entCardConfigName,
1019
- // configsProgram.programId,
1020
- // );
1021
- // const cardConfigAccount =
1022
- // await configsProgram.account.enterpriseCardConfig.fetchNullable(
1023
- // enterpriseCardConfig,
1024
- // connection.commitment,
1025
- // );
1026
- // if (!cardConfigAccount) {
1027
- // throw new Error(
1028
- // `CardConfigAccountNotFound: Enterprise Card Config Account does not exits for config name: ${params.entCardConfigName}`,
1029
- // );
1030
- // }
1031
- // const revenueVault = cardConfigAccount.revenueVault;
1032
- // const cardVault = cardConfigAccount.cardVault;
1033
- // const usdcMint = translateAddress(quoteInfo.outputMint);
1034
- // if (!usdcMint.equals(cardConfigAccount.usdcMint)) {
1035
- // throw new Error("InvalidUSDCMint: Output mint in quoteInfo in is not a usdc")
1036
- // }
1037
- // const inputMint = translateAddress(quoteInfo.inputMint);
1038
- // // const
1039
- // }
931
+ export async function swapAndCreateCard(payrollProgram, configsProgram, params) {
932
+ const connection = getConnectionFromProgram(payrollProgram);
933
+ const user = translateAddress(params.user);
934
+ const feePayer = translateAddress(params.feePayer);
935
+ const quoteInfo = params.quoteInfo;
936
+ if ("error" in quoteInfo) {
937
+ throw new Error(quoteInfo.error);
938
+ }
939
+ assertBufferSize(params.emailHash, 32);
940
+ const [enterpriseCardConfig] = deriveEnterpriseCardConfigPda(params.entCardConfigName, configsProgram.programId);
941
+ const cardConfigAccount = await configsProgram.account.enterpriseCardConfig.fetchNullable(enterpriseCardConfig, connection.commitment);
942
+ if (!cardConfigAccount) {
943
+ throw new Error(`CardConfigAccountNotFound: Enterprise Card Config Account does not exits for config name: ${params.entCardConfigName}`);
944
+ }
945
+ const inputMint = translateAddress(quoteInfo.inputMint);
946
+ const usdcMint = translateAddress(quoteInfo.outputMint);
947
+ if (!usdcMint.equals(cardConfigAccount.usdcMint)) {
948
+ throw new Error("InvalidUSDCMint: Output mint in quoteInfo in is not a usdc");
949
+ }
950
+ const revenueVault = cardConfigAccount.revenueVault;
951
+ const cardVault = cardConfigAccount.cardVault;
952
+ const userAta = getAssociatedTokenAddressSync(usdcMint, user, true);
953
+ const cardVaultAta = getAssociatedTokenAddressSync(usdcMint, cardVault, true);
954
+ const revenueVaultAta = getAssociatedTokenAddressSync(usdcMint, revenueVault, true);
955
+ const [enterpriseCardIndex] = deriveEnterpriseCardIndexPda(params.entCardConfigName, payrollProgram.programId);
956
+ const [cardPurchasePda] = deriveEnterpriseCardPurchasePda(user, params.entCardConfigName, params.nextCardIndex, payrollProgram.programId);
957
+ const [userPurchaseRecordPda] = deriveEnterpriseUserPurchaseRecordPda(user, params.entCardConfigName, payrollProgram.programId);
958
+ const unitsPerUSDC = BigNumber(10).pow(USDC_DECIMALS);
959
+ const amount = quoteInfo.swapMode === "ExactIn"
960
+ ? new BigNumber(quoteInfo.otherAmountThreshold)
961
+ : new BigNumber(quoteInfo.outAmount);
962
+ const feeRateInBps = BigNumber(getFeeRateForMint(cardConfigAccount.customFees.feeMap, inputMint));
963
+ const amountWithoutFee = deductFeeFromAmount(amount, feeRateInBps);
964
+ const userPurchaseRecord = await payrollProgram.account.userPurchaseRecord.fetchNullable(userPurchaseRecordPda, "confirmed");
965
+ if (userPurchaseRecord &&
966
+ !isAmountWithinDailyCardLimit(userPurchaseRecord.dateTimeInUnix.toNumber(), userPurchaseRecord.totalBoughtPerDay.toString(), cardConfigAccount.dailyCardBuyLimit.toString(), amountWithoutFee)) {
967
+ throw new Error("DailyCardLimitReachedError: " +
968
+ "Daily card limit reached. Limit: " +
969
+ BigNumber(cardConfigAccount.dailyCardBuyLimit.toString())
970
+ .div(unitsPerUSDC)
971
+ .toFixed() +
972
+ " Requested (Fee Deducted): " +
973
+ BigNumber(amountWithoutFee).div(unitsPerUSDC).toFixed());
974
+ }
975
+ if (!isAmountWithInProviderCardPurchaseRange(cardConfigAccount.providerConfig.minCardAmount.toString(), cardConfigAccount.providerConfig.maxCardAmount.toString(), amountWithoutFee)) {
976
+ throw new Error("AmountOfProviderCardPurchaseRange:" +
977
+ "Amount out of range: " +
978
+ BigNumber(amountWithoutFee).div(unitsPerUSDC).toFixed() +
979
+ "(Fee Deducted); Must be within " +
980
+ BigNumber(cardConfigAccount.providerConfig.minCardAmount.toString())
981
+ .div(unitsPerUSDC)
982
+ .toFixed() +
983
+ "-" +
984
+ BigNumber(cardConfigAccount.providerConfig.maxCardAmount.toString())
985
+ .div(unitsPerUSDC)
986
+ .toFixed());
987
+ }
988
+ // get serialized transactions for the swap
989
+ const { swapTransaction } = await (await fetch(JUPITER_SWAP_API, {
990
+ method: "POST",
991
+ headers: {
992
+ "Content-Type": "application/json",
993
+ },
994
+ body: JSON.stringify({
995
+ // quoteResponse from /quote api
996
+ quoteResponse: quoteInfo,
997
+ // user public key to be used for the swap
998
+ userPublicKey: user.toString(),
999
+ // auto wrap and unwrap SOL. default is true
1000
+ wrapAndUnwrapSol: false,
1001
+ }),
1002
+ })).json();
1003
+ // deserialize the transaction
1004
+ const swapTransactionBuf = Buffer.from(swapTransaction, "base64");
1005
+ const transaction = VersionedTransaction.deserialize(swapTransactionBuf);
1006
+ // get address lookup table accounts
1007
+ const addressLookupTableAccounts = await Promise.all(transaction.message.addressTableLookups.map(async (lookup) => {
1008
+ const data = await connection
1009
+ .getAccountInfo(lookup.accountKey)
1010
+ .then((res) => {
1011
+ if (!res) {
1012
+ throw new Error(`Address lookup table account not found: ${lookup.accountKey.toString()}`);
1013
+ }
1014
+ return res.data;
1015
+ });
1016
+ return new AddressLookupTableAccount({
1017
+ key: lookup.accountKey,
1018
+ state: AddressLookupTableAccount.deserialize(data),
1019
+ });
1020
+ }));
1021
+ const lookupTableData = await connection
1022
+ .getAccountInfo(translateAddress(CARD_LOOKUP_TABLE_ADDRESS["mainnet-beta"]))
1023
+ .then((res) => {
1024
+ if (!res) {
1025
+ throw new Error(`Address lookup table account not found: ${CARD_LOOKUP_TABLE_ADDRESS}`);
1026
+ }
1027
+ return res.data;
1028
+ });
1029
+ addressLookupTableAccounts.push(new AddressLookupTableAccount({
1030
+ key: translateAddress(CARD_LOOKUP_TABLE_ADDRESS["mainnet-beta"]),
1031
+ state: AddressLookupTableAccount.deserialize(lookupTableData),
1032
+ }));
1033
+ // decompile transaction message and add transfer instruction
1034
+ const message = TransactionMessage.decompile(transaction.message, {
1035
+ addressLookupTableAccounts: addressLookupTableAccounts,
1036
+ });
1037
+ const swapInstruction = message.instructions.find((ix) => ix.programId.equals(translateAddress(JUPITER_AGGREGATOR_PROGRAM_ID)));
1038
+ if (!swapInstruction) {
1039
+ throw new Error("Swap instruction not found in the transaction message");
1040
+ }
1041
+ const otherIxs = message.instructions.filter((ix) => !ix.programId.equals(translateAddress(JUPITER_AGGREGATOR_PROGRAM_ID)) &&
1042
+ !ix.programId.equals(ComputeBudgetProgram.programId));
1043
+ const isSolWrapUnwrapNeeded = inputMint.equals(WSOL);
1044
+ const wsolTokenAccount = getAssociatedTokenAddressSync(WSOL, // mint (Wrapped SOL)
1045
+ user, // owner
1046
+ true);
1047
+ if (params.wrapAndUnwrapWsol && isSolWrapUnwrapNeeded) {
1048
+ const wrapIxns = [];
1049
+ // Get the associated token account address for WSOL
1050
+ const wsolTokenAccountInfo = await connection.getAccountInfo(wsolTokenAccount, connection.commitment);
1051
+ if (!wsolTokenAccountInfo) {
1052
+ // create and push unwrap instructions
1053
+ const createWsolTokenAccountIx = createAssociatedTokenAccountInstruction(feePayer, // payer
1054
+ wsolTokenAccount, // associated token account address
1055
+ user, // owner
1056
+ WSOL);
1057
+ wrapIxns.push(createWsolTokenAccountIx);
1058
+ }
1059
+ const amountToSync = quoteInfo.inAmount;
1060
+ const transferSolToWsolIx = SystemProgram.transfer({
1061
+ fromPubkey: user,
1062
+ toPubkey: wsolTokenAccount,
1063
+ lamports: BigInt(amountToSync),
1064
+ });
1065
+ wrapIxns.push(transferSolToWsolIx);
1066
+ // create and push wrap instructions
1067
+ const wrapIx = createSyncNativeInstruction(wsolTokenAccount);
1068
+ wrapIxns.push(wrapIx);
1069
+ otherIxs.unshift(...wrapIxns);
1070
+ }
1071
+ const instruction = await createSwapAndCreateCardInstruction(payrollProgram, {
1072
+ cardPurchasePda,
1073
+ cardVault,
1074
+ cardVaultAta,
1075
+ enterpriseCardConfig,
1076
+ enterpriseCardIndex,
1077
+ feePayer,
1078
+ revenueVault,
1079
+ revenueVaultAta,
1080
+ sourceToken: inputMint,
1081
+ usdcMint,
1082
+ user,
1083
+ userAta,
1084
+ userPurchaseRecordPda,
1085
+ }, {
1086
+ currency: params.currency,
1087
+ emailHash: Array.from(params.emailHash),
1088
+ index: new BN(params.nextCardIndex),
1089
+ reloadCardId: params.reloadCardId,
1090
+ swapData: swapInstruction.data,
1091
+ }, swapInstruction.keys);
1092
+ otherIxs.push(instruction);
1093
+ if (params.wrapAndUnwrapWsol && isSolWrapUnwrapNeeded) {
1094
+ // create and push unwrap instructions
1095
+ const closeWsolAccountIx = createCloseAccountInstruction(wsolTokenAccount, // account to be closed
1096
+ user, // destination
1097
+ user);
1098
+ otherIxs.push(closeWsolAccountIx);
1099
+ }
1100
+ return createTransactionPayload(payrollProgram, feePayer, otherIxs, [], addressLookupTableAccounts);
1101
+ }
1102
+ export async function getCardIndexInfo(payrollProgram, entCardConfigName, commitment) {
1103
+ const connection = getConnectionFromProgram(payrollProgram);
1104
+ commitment = commitment ?? connection.commitment;
1105
+ const [enterpriseCardIndex] = deriveEnterpriseCardIndexPda(entCardConfigName, payrollProgram.programId);
1106
+ const info = await payrollProgram.account.enterpriseCardIndex.fetchNullable(enterpriseCardIndex, commitment);
1107
+ if (!info) {
1108
+ return null;
1109
+ }
1110
+ return {
1111
+ index: BigInt(info.index.toString()),
1112
+ totoalCardSold: BigNumber(info.totalBought.toString())
1113
+ .div(BigNumber(10).pow(USDC_DECIMALS))
1114
+ .toFixed(),
1115
+ };
1116
+ }
1117
+ export async function getNextCardIndex(payrollProgram, entCardConfigName, commitment) {
1118
+ const info = await getCardIndexInfo(payrollProgram, entCardConfigName, commitment);
1119
+ const currentIndex = info ? info.index : BigInt(0);
1120
+ return currentIndex + BigInt(1);
1121
+ }
1122
+ export async function getUserPurchaseRecordInfo(payrollProgram, entCardConfigName, user, commitment) {
1123
+ const connection = getConnectionFromProgram(payrollProgram);
1124
+ commitment = commitment ?? connection.commitment;
1125
+ const [userPurchaseRecordPda] = deriveEnterpriseUserPurchaseRecordPda(user, entCardConfigName, payrollProgram.programId);
1126
+ const info = await payrollProgram.account.userPurchaseRecord.fetchNullable(userPurchaseRecordPda, commitment);
1127
+ if (!info) {
1128
+ return null;
1129
+ }
1130
+ return {
1131
+ user: info.userAddress,
1132
+ lastCardBoughtPerDay: BigNumber(info.totalBoughtPerDay.toString())
1133
+ .div(BigNumber(10).pow(USDC_DECIMALS))
1134
+ .toFixed(),
1135
+ lastCardBoughtTimestamp: info.dateTimeInUnix.toNumber(),
1136
+ };
1137
+ }
1138
+ export async function getCardPurchaseInfo(payrollProgram, entCardConfigName, user, cardIndex, commitment) {
1139
+ const connection = getConnectionFromProgram(payrollProgram);
1140
+ commitment = commitment ?? connection.commitment;
1141
+ const [cardPurchasePda] = deriveEnterpriseCardPurchasePda(user, entCardConfigName, cardIndex, payrollProgram.programId);
1142
+ const info = await payrollProgram.account.cardPurchase.fetchNullable(cardPurchasePda, commitment);
1143
+ if (!info) {
1144
+ return null;
1145
+ }
1146
+ return {
1147
+ index: BigInt(info.index.toString()),
1148
+ buyer: info.buyerAddress,
1149
+ amount: BigNumber(info.amount.toString())
1150
+ .div(BigNumber(10).pow(USDC_DECIMALS))
1151
+ .toFixed(),
1152
+ purchasedAt: info.purchaseAt.toNumber(),
1153
+ };
1154
+ }
package/dist/types.d.ts CHANGED
@@ -72,6 +72,12 @@ export type TokenMetadata = {
72
72
  uri: string;
73
73
  } | null;
74
74
  };
75
+ export type PayrollTokenPriceData = {
76
+ priceExpiryUnixTimestamp: bigint;
77
+ tokenPrice: bigint;
78
+ signature: Buffer | Uint8Array;
79
+ message: Buffer | Uint8Array;
80
+ };
75
81
  export type CreatePayrollParams = {
76
82
  payrollConfigName: string;
77
83
  feePayer?: Address;
@@ -98,6 +104,7 @@ export type CreatePayrollParams = {
98
104
  payrollMetadataKeypair?: Keypair;
99
105
  senderId: number[] | Uint8Array | Buffer;
100
106
  receiverId: number[] | Uint8Array | Buffer;
107
+ priceData: PayrollTokenPriceData;
101
108
  };
102
109
  export type CreateMultiplePayrollParams = {
103
110
  payrollConfigName: string;
@@ -126,6 +133,7 @@ export type CreateMultiplePayrollParams = {
126
133
  initialBufferAmount: number;
127
134
  payrollMetadataKeypair?: Keypair;
128
135
  receiverId: number[] | Uint8Array | Buffer;
136
+ priceData: PayrollTokenPriceData;
129
137
  }[];
130
138
  };
131
139
  export type FeeTier = {
@@ -318,3 +326,35 @@ export type QuoteInfo = {
318
326
  } | {
319
327
  error: string;
320
328
  };
329
+ export type CreateCardParams = {
330
+ currency: string;
331
+ reloadCardId: string;
332
+ nextCardIndex: bigint;
333
+ user: Address;
334
+ feePayer: Address;
335
+ emailHash: Buffer | Uint8Array;
336
+ amount: Numeric;
337
+ entCardConfigName: string;
338
+ };
339
+ export type SwapAndCreateCardParams = {
340
+ currency: string;
341
+ reloadCardId: string;
342
+ nextCardIndex: bigint;
343
+ user: Address;
344
+ feePayer: Address;
345
+ emailHash: Buffer | Uint8Array;
346
+ entCardConfigName: string;
347
+ quoteInfo: QuoteInfo;
348
+ wrapAndUnwrapWsol?: boolean;
349
+ };
350
+ export type CardPurchaseInfo = {
351
+ index: bigint;
352
+ buyer: Address;
353
+ amount: Numeric;
354
+ purchasedAt: number;
355
+ };
356
+ export type UserPurchaseRecordInfo = {
357
+ user: Address;
358
+ lastCardBoughtPerDay: Numeric;
359
+ lastCardBoughtTimestamp: number;
360
+ };
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "@zebec-network/core-utils": "^1.3.1",
12
12
  "@zebec-network/solana-common": "^2.6.1",
13
13
  "@zebec-network/zebec_configs": "^1.2.6",
14
- "@zebec-network/zebec_payroll": "^1.5.2",
14
+ "@zebec-network/zebec_payroll": "1.5.4",
15
15
  "bignumber.js": "^11.1.1",
16
16
  "bn.js": "^5.2.3"
17
17
  },
@@ -24,6 +24,7 @@
24
24
  "rimraf": "^6.1.3",
25
25
  "ts-mocha": "^11.1.0",
26
26
  "ts-node": "^10.9.2",
27
+ "tweetnacl": "^1.0.3",
27
28
  "typescript": "^6.0.3"
28
29
  },
29
30
  "files": [
@@ -44,5 +45,5 @@
44
45
  },
45
46
  "type": "module",
46
47
  "types": "dist/index.d.ts",
47
- "version": "2.6.0-dev.1"
48
+ "version": "2.6.0"
48
49
  }