@zebec-network/solana-payroll-sdk 2.5.0 → 2.6.0-dev.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,3 +2,10 @@ import type { RpcNetwork } from "./types.js";
2
2
  export declare const PAYROLL_NAME_BUFFER_SIZE = 128;
3
3
  export declare const PAYROLL_PROGRAM_ID: Record<RpcNetwork, string>;
4
4
  export declare const USX_DECIMALS = 6;
5
+ export declare const DEFAULT_FEE_RATE_IN_BPS = 500;
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
@@ -4,3 +4,13 @@ export const PAYROLL_PROGRAM_ID = {
4
4
  devnet: "zPAY457TttFCcaCoA3imYyEHc2sPvLMTQgVxjAfodSM",
5
5
  };
6
6
  export const USX_DECIMALS = 6;
7
+ export const DEFAULT_FEE_RATE_IN_BPS = 500;
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;
@@ -156,3 +160,44 @@ export declare function createDistributeRewardsInstruction(program: Program<Zebe
156
160
  }[];
157
161
  checkId: number[];
158
162
  }, remainingAccounts: AccountMeta[]): Promise<TransactionInstruction>;
163
+ export declare function createCreateCardInstruction(payrollProgram: Program<ZebecPayrollIdl>, accounts: {
164
+ cardPurchasePda: PublicKey;
165
+ cardVault: PublicKey;
166
+ cardVaultAta: PublicKey;
167
+ enterpriseCardConfig: PublicKey;
168
+ enterpriseCardIndex: PublicKey;
169
+ feePayer: PublicKey;
170
+ revenueVault: PublicKey;
171
+ revenueVaultAta: PublicKey;
172
+ usdcMint: PublicKey;
173
+ user: PublicKey;
174
+ userAta: PublicKey;
175
+ userPurchaseRecordPda: PublicKey;
176
+ }, data: {
177
+ amount: BN;
178
+ currency: string;
179
+ emailHash: number[];
180
+ index: BN;
181
+ reloadCardId: string;
182
+ }): Promise<TransactionInstruction>;
183
+ export declare function createSwapAndCreateCardInstruction(payrollProgram: Program<ZebecPayrollIdl>, accounts: {
184
+ cardPurchasePda: PublicKey;
185
+ cardVault: PublicKey;
186
+ cardVaultAta: PublicKey;
187
+ enterpriseCardConfig: PublicKey;
188
+ enterpriseCardIndex: PublicKey;
189
+ feePayer: PublicKey;
190
+ revenueVault: PublicKey;
191
+ revenueVaultAta: PublicKey;
192
+ sourceToken: PublicKey;
193
+ usdcMint: PublicKey;
194
+ user: PublicKey;
195
+ userAta: PublicKey;
196
+ userPurchaseRecordPda: PublicKey;
197
+ }, data: {
198
+ currency: string;
199
+ emailHash: number[];
200
+ index: BN;
201
+ reloadCardId: string;
202
+ swapData: Buffer;
203
+ }, remainingAccounts: AccountMeta[]): Promise<TransactionInstruction>;
@@ -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
  }
@@ -195,3 +201,55 @@ export async function createDistributeRewardsInstruction(program, accounts, data
195
201
  .remainingAccounts(remainingAccounts)
196
202
  .instruction();
197
203
  }
204
+ export async function createCreateCardInstruction(payrollProgram, accounts, data) {
205
+ return payrollProgram.methods
206
+ .enterpriseCreateCard({
207
+ amount: data.amount,
208
+ currency: data.currency,
209
+ emailHash: data.emailHash,
210
+ index: data.index,
211
+ reloadCardId: data.reloadCardId,
212
+ })
213
+ .accountsPartial({
214
+ cardPurchasePda: accounts.cardPurchasePda,
215
+ cardVault: accounts.cardVault,
216
+ cardVaultAta: accounts.cardVaultAta,
217
+ enterpriseCardConfig: accounts.enterpriseCardConfig,
218
+ enterpriseCardIndex: accounts.enterpriseCardIndex,
219
+ feePayer: accounts.feePayer,
220
+ revenueVault: accounts.revenueVault,
221
+ revenueVaultAta: accounts.revenueVaultAta,
222
+ usdcMint: accounts.usdcMint,
223
+ user: accounts.user,
224
+ userAta: accounts.userAta,
225
+ userPurchaseRecordPda: accounts.userPurchaseRecordPda,
226
+ })
227
+ .instruction();
228
+ }
229
+ export async function createSwapAndCreateCardInstruction(payrollProgram, accounts, data, remainingAccounts) {
230
+ return payrollProgram.methods
231
+ .swapAndCreateCard({
232
+ currency: data.currency,
233
+ emailHash: data.emailHash,
234
+ index: data.index,
235
+ reloadCardId: data.reloadCardId,
236
+ swapData: data.swapData,
237
+ })
238
+ .accountsPartial({
239
+ cardPurchasePda: accounts.cardPurchasePda,
240
+ cardVault: accounts.cardVault,
241
+ cardVaultAta: accounts.cardVaultAta,
242
+ enterpriseCardConfig: accounts.enterpriseCardConfig,
243
+ enterpriseCardIndex: accounts.enterpriseCardIndex,
244
+ feePayer: accounts.feePayer,
245
+ revenueVault: accounts.revenueVault,
246
+ revenueVaultAta: accounts.revenueVaultAta,
247
+ sourceToken: accounts.sourceToken,
248
+ usdcMint: accounts.usdcMint,
249
+ user: accounts.user,
250
+ userAta: accounts.userAta,
251
+ userPurchaseRecordPda: accounts.userPurchaseRecordPda,
252
+ })
253
+ .remainingAccounts(remainingAccounts)
254
+ .instruction();
255
+ }
package/dist/pda.d.ts CHANGED
@@ -6,3 +6,7 @@ export declare function deriveYieldConfigPda(configProgramId: Address): [PublicK
6
6
  export declare function deriveCompanyDepositPda(companyId: Buffer, nonce: bigint, payrollProgramId: Address): [PublicKey, number];
7
7
  export declare function deriveCompanyNoncePda(companyId: Buffer, payrollProgramId: Address): [PublicKey, number];
8
8
  export declare function deriveCheckAccountPda(checkId: Buffer | Uint8Array, payrollProgramId: Address): [PublicKey, number];
9
+ export declare function deriveEnterpriseCardIndexPda(entCardConfigName: string, payrollProgramId: Address): [PublicKey, number];
10
+ export declare function deriveEnterpriseCardPurchasePda(userAddress: Address, entCardConfigName: string, cardIndex: bigint, payrollProgramId: Address): [PublicKey, number];
11
+ export declare function deriveEnterpriseUserPurchaseRecordPda(userAddress: Address, entCardConfigName: string, payrollProgramId: Address): [PublicKey, number];
12
+ export declare function deriveEnterpriseCardConfigPda(entCardConfigName: string, zebecConfigProgramId: Address): [PublicKey, number];
package/dist/pda.js CHANGED
@@ -4,9 +4,13 @@ import BN from "bn.js";
4
4
  const ZEBEC_CONFIG_PROGRAM_SEEDS = {
5
5
  PAYROLL_CONFIG: utils.bytes.utf8.encode("payroll_config"),
6
6
  YIELD_CONFIG: utils.bytes.utf8.encode("yield_config"),
7
+ ENTERPRISE_CARD_CONFIG: utils.bytes.utf8.encode("enterprise_card_config"),
7
8
  };
8
9
  const PAYROLL_PROGRAM_SEEDS = {
9
- COMPANY_DEPOSIT: utils.bytes.utf8.encode("Yield"),
10
+ YIELD_COMPANY_DEPOSIT: utils.bytes.utf8.encode("Yield"),
11
+ ENT_USER_PURCHASE_RECORD: utils.bytes.utf8.encode("UserPurchaseRecord"),
12
+ ENT_USER_CARD_PURCHASE: utils.bytes.utf8.encode("CardPurchase"),
13
+ ENT_CARD_INDEX: utils.bytes.utf8.encode("EnterpriseCardIndex"),
10
14
  };
11
15
  export function derivePayrollConfigPda(configName, configProgramId) {
12
16
  return PublicKey.findProgramAddressSync([
@@ -24,7 +28,7 @@ export function deriveCompanyDepositPda(companyId, nonce, payrollProgramId) {
24
28
  return PublicKey.findProgramAddressSync([
25
29
  companyId,
26
30
  new BN(nonce).toArrayLike(Buffer, "le", 8),
27
- PAYROLL_PROGRAM_SEEDS.COMPANY_DEPOSIT,
31
+ PAYROLL_PROGRAM_SEEDS.YIELD_COMPANY_DEPOSIT,
28
32
  ], translateAddress(payrollProgramId));
29
33
  }
30
34
  export function deriveCompanyNoncePda(companyId, payrollProgramId) {
@@ -33,3 +37,30 @@ export function deriveCompanyNoncePda(companyId, payrollProgramId) {
33
37
  export function deriveCheckAccountPda(checkId, payrollProgramId) {
34
38
  return PublicKey.findProgramAddressSync([checkId], translateAddress(payrollProgramId));
35
39
  }
40
+ export function deriveEnterpriseCardIndexPda(entCardConfigName, payrollProgramId) {
41
+ return PublicKey.findProgramAddressSync([
42
+ PAYROLL_PROGRAM_SEEDS.ENT_CARD_INDEX,
43
+ utils.bytes.utf8.encode(entCardConfigName),
44
+ ], translateAddress(payrollProgramId));
45
+ }
46
+ export function deriveEnterpriseCardPurchasePda(userAddress, entCardConfigName, cardIndex, payrollProgramId) {
47
+ return PublicKey.findProgramAddressSync([
48
+ PAYROLL_PROGRAM_SEEDS.ENT_USER_CARD_PURCHASE,
49
+ translateAddress(userAddress).toBuffer(),
50
+ utils.bytes.utf8.encode(entCardConfigName),
51
+ new BN(cardIndex).toArrayLike(Buffer, "le", 8),
52
+ ], translateAddress(payrollProgramId));
53
+ }
54
+ export function deriveEnterpriseUserPurchaseRecordPda(userAddress, entCardConfigName, payrollProgramId) {
55
+ return PublicKey.findProgramAddressSync([
56
+ PAYROLL_PROGRAM_SEEDS.ENT_USER_PURCHASE_RECORD,
57
+ translateAddress(userAddress).toBuffer(),
58
+ utils.bytes.utf8.encode(entCardConfigName),
59
+ ], translateAddress(payrollProgramId));
60
+ }
61
+ export function deriveEnterpriseCardConfigPda(entCardConfigName, zebecConfigProgramId) {
62
+ return PublicKey.findProgramAddressSync([
63
+ ZEBEC_CONFIG_PROGRAM_SEEDS.ENTERPRISE_CARD_CONFIG,
64
+ utils.bytes.utf8.encode(entCardConfigName),
65
+ ], translateAddress(zebecConfigProgramId));
66
+ }
@@ -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, 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,3 +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: 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,15 +2,18 @@ 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";
6
- import { bpsToPercent, percentToBps } from "@zebec-network/core-utils";
7
- import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddressSync, getMintDecimals, MultiTransactionPayload, TEN_BIGNUM, TransactionPayload, UNITS_PER_USDC, } from "@zebec-network/solana-common";
5
+ import { createCloseAccountInstruction, createSyncNativeInstruction, } from "@solana/spl-token";
6
+ import { AddressLookupTableAccount, ComputeBudgetProgram, Ed25519Program, Keypair, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
7
+ import { assertBufferSize, bpsToPercent, percentToBps, } from "@zebec-network/core-utils";
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, createCreatePayrollInstruction, createDistributeRewardsInstruction, createPauseResumePayrollInstruction, createRequestUnlockInstruction, createSetTopupDelegateInstruction, createTopupPayrollInstruction, createTransferFeesInstruction, createWithdrawPayrollInstruction, createYieldDepositInstruction, } from "./instructions.js";
12
- import { deriveCheckAccountPda, deriveCompanyDepositPda, deriveCompanyNoncePda, derivePayrollConfigPda, derivePayrollVaultPda, deriveYieldConfigPda, } from "./pda.js";
13
- import { getFeeInfoForPayroll } from "./utils.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";
13
+ import { deriveCheckAccountPda, deriveCompanyDepositPda, deriveCompanyNoncePda, deriveEnterpriseCardConfigPda, deriveEnterpriseCardIndexPda, deriveEnterpriseCardPurchasePda, deriveEnterpriseUserPurchaseRecordPda, derivePayrollConfigPda, derivePayrollVaultPda, deriveYieldConfigPda, } from "./pda.js";
14
+ import { deductFeeFromAmount, getConnectionFromProgram,
15
+ // getFeeInfoForPayroll,
16
+ getFeeRateForMint, isAmountWithInProviderCardPurchaseRange, isAmountWithinDailyCardLimit, } from "./utils.js";
14
17
  export async function getPayrollConfig(configProgram, configName) {
15
18
  const [payrollConfigPda] = derivePayrollConfigPda(configName, configProgram.programId);
16
19
  const payrollConfig = await configProgram.account.payrollConfig.fetchNullable(payrollConfigPda);
@@ -202,7 +205,7 @@ function createMultiTransactionPayload(program, feePayer, transactionData) {
202
205
  feePayer,
203
206
  })), signAllTransactions);
204
207
  }
205
- export async function createPayroll(payrollProgram, configProgram, params, payrollFeeBaseUrl) {
208
+ export async function createPayroll(payrollProgram, configProgram, params) {
206
209
  const receiver = translateAddress(params.receiver);
207
210
  const sender = translateAddress(params.sender);
208
211
  const feePayer = params.feePayer ? translateAddress(params.feePayer) : sender;
@@ -233,32 +236,21 @@ export async function createPayroll(payrollProgram, configProgram, params, payro
233
236
  const cliffPercentage = new BN(percentToBps(params.cliffPercentage));
234
237
  const payrollRunId = new Uint8Array(PAYROLL_NAME_BUFFER_SIZE);
235
238
  payrollRunId.set(utils.bytes.utf8.encode(params.payrollRunId));
236
- const feeInfo = await getFeeInfoForPayroll(payrollFeeBaseUrl, payrollToken, amount);
237
- const feeTokenDecimals = await getMintDecimals(payrollProgram.provider.connection, payrollConfigAccount.feeToken);
238
- const parsedFeeAmount = feeInfo.feeAmountRaw;
239
239
  const feeVault = payrollConfigAccount.feeVault;
240
- const feeVaultAta = getAssociatedTokenAddressSync(payrollConfigAccount.feeToken, feeVault, true);
241
- const senderFeeTokenAta = getAssociatedTokenAddressSync(payrollConfigAccount.feeToken, sender, true);
242
- const feeVaultAtaInfo = await payrollProgram.provider.connection.getAccountInfo(feeVaultAta);
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);
243
247
  const ixs = [];
244
- // add instruction to create fee vault ATA if it does not exist
245
- if (!feeVaultAtaInfo) {
246
- const createFeeVaultAtaIx = createAssociatedTokenAccountInstruction(feePayer, feeVaultAta, feeVault, payrollConfigAccount.feeToken);
247
- ixs.push(createFeeVaultAtaIx);
248
- }
249
- // add instruction to transfer fee to fee vault
250
- const transferFeeIx = await createTransferFeesInstruction(payrollProgram, {
251
- feeVault,
252
- feeVaultTokenAccount: feeVaultAta,
253
- payrollConfig,
254
- sender,
255
- senderTokenAccount: senderFeeTokenAta,
256
- tokenMint: payrollConfigAccount.feeToken,
257
- }, {
258
- decimals: feeTokenDecimals,
259
- feeAmount: new BN(parsedFeeAmount),
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
260
252
  });
261
- ixs.push(transferFeeIx);
253
+ ixs.push(ed25519Ix);
262
254
  const createpayrollIx = await createCreatePayrollInstruction(payrollProgram, {
263
255
  payrollConfig,
264
256
  feePayer,
@@ -271,6 +263,8 @@ export async function createPayroll(payrollProgram, configProgram, params, payro
271
263
  payrollVault,
272
264
  payrollVaultAta,
273
265
  withdrawAccount: withdrawer,
266
+ feeVault,
267
+ feeVaultTokenAccount,
274
268
  }, {
275
269
  autoTopupDelegate: Number(params.delegateAutoTopup),
276
270
  initialBufferAmount: new BN(initialBufferAmount),
@@ -291,13 +285,15 @@ export async function createPayroll(payrollProgram, configProgram, params, payro
291
285
  transferableBySender: Number(params.transferableBySender),
292
286
  receiverId: Array.from(params.receiverId),
293
287
  senderId: Array.from(params.senderId),
288
+ priceExpiry,
289
+ tokenPrice,
294
290
  });
295
291
  ixs.push(createpayrollIx);
296
292
  return createTransactionPayload(payrollProgram, feePayer, ixs, [
297
293
  payrollMetadataKeypair,
298
294
  ]);
299
295
  }
300
- export async function createMultiplePayroll(payrollProgram, configProgram, params, payrollFeeBaseUrl) {
296
+ export async function createMultiplePayroll(payrollProgram, configProgram, params) {
301
297
  const sender = translateAddress(params.sender);
302
298
  const feePayer = params.feePayer ? translateAddress(params.feePayer) : sender;
303
299
  const senderId = Array.from(params.senderId);
@@ -330,32 +326,21 @@ export async function createMultiplePayroll(payrollProgram, configProgram, param
330
326
  const cliffPercentage = new BN(percentToBps(payroll.cliffPercentage));
331
327
  const payrollRunId = new Uint8Array(PAYROLL_NAME_BUFFER_SIZE);
332
328
  payrollRunId.set(utils.bytes.utf8.encode(payroll.payrollRunId));
333
- const feeInfo = await getFeeInfoForPayroll(payrollFeeBaseUrl, payrollToken, amount);
334
- const feeTokenDecimals = await getMintDecimals(payrollProgram.provider.connection, payrollConfigAccount.feeToken);
335
- const parsedFeeAmount = feeInfo.feeAmountRaw;
336
329
  const feeVault = payrollConfigAccount.feeVault;
337
- const feeVaultAta = getAssociatedTokenAddressSync(payrollConfigAccount.feeToken, feeVault, true);
338
- const senderFeeTokenAta = getAssociatedTokenAddressSync(payrollConfigAccount.feeToken, sender, true);
339
- const feeVaultAtaInfo = await payrollProgram.provider.connection.getAccountInfo(feeVaultAta);
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);
340
337
  const instructions = [];
341
- // add instruction to create fee vault ATA if it does not exist
342
- if (!feeVaultAtaInfo) {
343
- const createFeeVaultAtaIx = createAssociatedTokenAccountInstruction(feePayer, feeVaultAta, feeVault, payrollConfigAccount.feeToken);
344
- instructions.push(createFeeVaultAtaIx);
345
- }
346
- // add instruction to transfer fee to fee vault
347
- const transferFeeIx = await createTransferFeesInstruction(payrollProgram, {
348
- feeVault,
349
- feeVaultTokenAccount: feeVaultAta,
350
- payrollConfig,
351
- sender,
352
- senderTokenAccount: senderFeeTokenAta,
353
- tokenMint: payrollConfigAccount.feeToken,
354
- }, {
355
- decimals: feeTokenDecimals,
356
- feeAmount: new BN(parsedFeeAmount),
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
357
342
  });
358
- instructions.push(transferFeeIx);
343
+ instructions.push(ed25519Ix);
359
344
  const createpayrollIx = await createCreatePayrollInstruction(payrollProgram, {
360
345
  payrollConfig,
361
346
  feePayer,
@@ -368,6 +353,8 @@ export async function createMultiplePayroll(payrollProgram, configProgram, param
368
353
  payrollVault,
369
354
  payrollVaultAta,
370
355
  withdrawAccount: withdrawer,
356
+ feeVault,
357
+ feeVaultTokenAccount,
371
358
  }, {
372
359
  autoTopupDelegate: Number(payroll.delegateAutoTopup),
373
360
  initialBufferAmount: new BN(initialBufferAmount),
@@ -388,6 +375,8 @@ export async function createMultiplePayroll(payrollProgram, configProgram, param
388
375
  transferableBySender: Number(payroll.transferableBySender),
389
376
  receiverId: Array.from(payroll.receiverId),
390
377
  senderId,
378
+ priceExpiry,
379
+ tokenPrice,
391
380
  });
392
381
  instructions.push(createpayrollIx);
393
382
  return {
@@ -868,3 +857,298 @@ export async function getCompanyDeposit(payrollProgram, company) {
868
857
  : null,
869
858
  };
870
859
  }
860
+ export async function createCard(payrollProgram, configsProgram, params) {
861
+ const connection = getConnectionFromProgram(payrollProgram);
862
+ const user = translateAddress(params.user);
863
+ const feePayer = translateAddress(params.feePayer);
864
+ assertBufferSize(params.emailHash, 32);
865
+ const [enterpriseCardConfig] = deriveEnterpriseCardConfigPda(params.entCardConfigName, configsProgram.programId);
866
+ const cardConfigAccount = await configsProgram.account.enterpriseCardConfig.fetchNullable(enterpriseCardConfig, connection.commitment);
867
+ if (!cardConfigAccount) {
868
+ throw new Error(`CardConfigAccountNotFound: Enterprise Card Config Account does not exits for config name: ${params.entCardConfigName}`);
869
+ }
870
+ const usdcMint = cardConfigAccount.usdcMint;
871
+ const cardVault = cardConfigAccount.cardVault;
872
+ const revenueVault = cardConfigAccount.revenueVault;
873
+ const userAta = getAssociatedTokenAddressSync(usdcMint, user, true);
874
+ const cardVaultAta = getAssociatedTokenAddressSync(usdcMint, cardVault, true);
875
+ const revenueVaultAta = getAssociatedTokenAddressSync(usdcMint, revenueVault, true);
876
+ const [enterpriseCardIndex] = deriveEnterpriseCardIndexPda(params.entCardConfigName, payrollProgram.programId);
877
+ const [cardPurchasePda] = deriveEnterpriseCardPurchasePda(user, params.entCardConfigName, params.nextCardIndex, payrollProgram.programId);
878
+ const [userPurchaseRecordPda] = deriveEnterpriseUserPurchaseRecordPda(user, params.entCardConfigName, payrollProgram.programId);
879
+ const unitsPerUSDC = BigNumber(10).pow(USDC_DECIMALS);
880
+ const amount = BigNumber(params.amount)
881
+ .times(unitsPerUSDC)
882
+ .toFixed(0, BigNumber.ROUND_FLOOR);
883
+ const feeRateInBps = BigNumber(getFeeRateForMint(cardConfigAccount.customFees.feeMap, usdcMint));
884
+ const amountWithoutFee = deductFeeFromAmount(amount, feeRateInBps);
885
+ const userPurchaseRecord = await payrollProgram.account.userPurchaseRecord.fetchNullable(userPurchaseRecordPda, "confirmed");
886
+ if (userPurchaseRecord &&
887
+ !isAmountWithinDailyCardLimit(userPurchaseRecord.dateTimeInUnix.toNumber(), userPurchaseRecord.totalBoughtPerDay.toString(), cardConfigAccount.dailyCardBuyLimit.toString(), amountWithoutFee)) {
888
+ throw new Error("DailyCardLimitReachedError: " +
889
+ "Daily card limit reached. Limit: " +
890
+ BigNumber(cardConfigAccount.dailyCardBuyLimit.toString())
891
+ .div(unitsPerUSDC)
892
+ .toFixed() +
893
+ " Requested (Fee Deducted): " +
894
+ BigNumber(amountWithoutFee).div(unitsPerUSDC).toFixed());
895
+ }
896
+ if (!isAmountWithInProviderCardPurchaseRange(cardConfigAccount.providerConfig.minCardAmount.toString(), cardConfigAccount.providerConfig.maxCardAmount.toString(), amountWithoutFee)) {
897
+ throw new Error("AmountOfProviderCardPurchaseRange:" +
898
+ "Amount out of range: " +
899
+ BigNumber(amountWithoutFee).div(unitsPerUSDC).toFixed() +
900
+ "(Fee Deducted); Must be within " +
901
+ BigNumber(cardConfigAccount.providerConfig.minCardAmount.toString())
902
+ .div(unitsPerUSDC)
903
+ .toFixed() +
904
+ "-" +
905
+ BigNumber(cardConfigAccount.providerConfig.maxCardAmount.toString())
906
+ .div(unitsPerUSDC)
907
+ .toFixed());
908
+ }
909
+ const instruction = await createCreateCardInstruction(payrollProgram, {
910
+ cardPurchasePda,
911
+ cardVault,
912
+ cardVaultAta,
913
+ enterpriseCardConfig,
914
+ enterpriseCardIndex,
915
+ feePayer,
916
+ revenueVault,
917
+ revenueVaultAta,
918
+ usdcMint,
919
+ user,
920
+ userAta,
921
+ userPurchaseRecordPda,
922
+ }, {
923
+ amount: new BN(amount),
924
+ currency: params.currency,
925
+ emailHash: Array.from(params.emailHash),
926
+ index: new BN(params.nextCardIndex),
927
+ reloadCardId: params.reloadCardId,
928
+ });
929
+ return createTransactionPayload(payrollProgram, feePayer, [instruction]);
930
+ }
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 = {
@@ -274,3 +282,79 @@ export type CompanyDepositInfo = {
274
282
  requestTime: number;
275
283
  } | null;
276
284
  };
285
+ /**
286
+ * Jupiter quote routes info
287
+ */
288
+ export type RouteInfo = {
289
+ swapInfo: {
290
+ ammKey: string;
291
+ label: string;
292
+ inputMint: string;
293
+ outputMint: string;
294
+ inAmount: string;
295
+ outAmount: string;
296
+ feeAmount: string;
297
+ feeMint: string;
298
+ };
299
+ percent: number;
300
+ bps: number;
301
+ };
302
+ /**
303
+ * Jupiter quote info
304
+ */
305
+ export type QuoteInfo = {
306
+ inputMint: string;
307
+ inAmount: string;
308
+ outputMint: string;
309
+ outAmount: string;
310
+ otherAmountThreshold: string;
311
+ swapMode: "ExactIn" | "ExactOut";
312
+ slippageBps: number;
313
+ platformFee: {
314
+ amount: string;
315
+ feeBps: number;
316
+ } | null;
317
+ priceImpactPct: string;
318
+ routePlan: RouteInfo[];
319
+ contextSlot: number;
320
+ timeTaken: number;
321
+ swapUsdValue: string;
322
+ simplerRouteUsed: boolean;
323
+ mostReliableAmmsQuoteReport: {
324
+ info: Record<string, string>;
325
+ };
326
+ } | {
327
+ error: string;
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/dist/utils.d.ts CHANGED
@@ -1,5 +1,16 @@
1
- import type { Address } from "@coral-xyz/anchor";
1
+ import type { Address, Idl, Program } from "@coral-xyz/anchor";
2
+ import type { PublicKey } from "@solana/web3.js";
2
3
  import { BigNumber } from "bignumber.js";
4
+ import type BN from "bn.js";
3
5
  import type { FeeTier, PayrollFeeInfo } from "./types.js";
4
6
  export declare function getFeeInfoForPayroll(baseUrl: string, payrollToken: Address, parsedStreamTokenAmount: BigNumber.Value): Promise<PayrollFeeInfo>;
5
7
  export declare function getFeeRateForUsdAmount(amount: BigNumber.Value, feeTiers: FeeTier[]): string;
8
+ export declare function getConnectionFromProgram<T extends Idl>(program: Program<T>): import("@solana/web3.js").Connection;
9
+ export declare function isAmountWithinDailyCardLimit(lastCardBoughtUnixTimestamp: number, lastCardBoughtRawAmountPerDay: BigNumber.Value, rawDailyCardBuyLimit: BigNumber.Value, rawAmount: BigNumber.Value): boolean;
10
+ export declare function isAmountWithInProviderCardPurchaseRange(rawMinCardAmount: BigNumber.Value, rawMaxCardAmount: BigNumber.Value, rawAmount: BigNumber.Value): boolean;
11
+ export type ParsedTokenFeeItem = {
12
+ tokenAddress: PublicKey;
13
+ fee: BN;
14
+ };
15
+ export declare function getFeeRateForMint(feeRateList: ParsedTokenFeeItem[], mint: PublicKey): number;
16
+ export declare function deductFeeFromAmount(rawAmount: BigNumber.Value, feeRateInBps: BigNumber.Value): string;
package/dist/utils.js CHANGED
@@ -1,5 +1,6 @@
1
- import { percentToBps } from "@zebec-network/core-utils";
1
+ import { areDatesOfSameDay, percentToBps } from "@zebec-network/core-utils";
2
2
  import { BigNumber } from "bignumber.js";
3
+ import { BPS_DENOMINATOR, DEFAULT_FEE_RATE_IN_BPS } from "./constants.js";
3
4
  export async function getFeeInfoForPayroll(baseUrl, payrollToken, parsedStreamTokenAmount) {
4
5
  const urlsParams = new URLSearchParams({
5
6
  tokenMint: payrollToken.toString(),
@@ -60,3 +61,41 @@ export function getFeeRateForUsdAmount(amount, feeTiers) {
60
61
  }
61
62
  return percentToBps(tier.feeRateInPercent);
62
63
  }
64
+ export function getConnectionFromProgram(program) {
65
+ return program.provider.connection;
66
+ }
67
+ export function isAmountWithinDailyCardLimit(lastCardBoughtUnixTimestamp, lastCardBoughtRawAmountPerDay, rawDailyCardBuyLimit, rawAmount) {
68
+ const dailyCardBuyLimit = BigNumber(rawDailyCardBuyLimit);
69
+ const amount = BigNumber(rawAmount);
70
+ const today = new Date();
71
+ const lastCardBoughtDate = new Date(lastCardBoughtUnixTimestamp * 1000);
72
+ let cardBoughtInADay = BigNumber(0);
73
+ if (areDatesOfSameDay(today, lastCardBoughtDate)) {
74
+ cardBoughtInADay = BigNumber(lastCardBoughtRawAmountPerDay).plus(amount);
75
+ }
76
+ else {
77
+ cardBoughtInADay = amount;
78
+ }
79
+ if (cardBoughtInADay.isGreaterThan(dailyCardBuyLimit)) {
80
+ return false;
81
+ }
82
+ return true;
83
+ }
84
+ export function isAmountWithInProviderCardPurchaseRange(rawMinCardAmount, rawMaxCardAmount, rawAmount) {
85
+ const minRange = BigNumber(rawMinCardAmount);
86
+ const maxRange = BigNumber(rawMaxCardAmount);
87
+ const amount = BigNumber(rawAmount);
88
+ if (amount.isLessThan(minRange) || amount.isGreaterThan(maxRange)) {
89
+ return false;
90
+ }
91
+ return true;
92
+ }
93
+ export function getFeeRateForMint(feeRateList, mint) {
94
+ return (feeRateList.find((fr) => fr.tokenAddress.equals(mint))?.fee.toNumber() ||
95
+ DEFAULT_FEE_RATE_IN_BPS);
96
+ }
97
+ export function deductFeeFromAmount(rawAmount, feeRateInBps) {
98
+ const amount = BigNumber(rawAmount);
99
+ const fee = amount.times(feeRateInBps).div(BPS_DENOMINATOR);
100
+ return amount.minus(fee).toFixed(0, BigNumber.ROUND_FLOOR);
101
+ }
package/package.json CHANGED
@@ -9,10 +9,11 @@
9
9
  "@solana/spl-token": "^0.4.14",
10
10
  "@solana/web3.js": "^1.98.2",
11
11
  "@zebec-network/core-utils": "^1.3.1",
12
- "@zebec-network/solana-common": "^2.6.0",
13
- "@zebec-network/zebec_configs": "^1.2.3",
14
- "@zebec-network/zebec_payroll": "^1.5.0",
15
- "bignumber.js": "^11.1.1"
12
+ "@zebec-network/solana-common": "^2.6.1",
13
+ "@zebec-network/zebec_configs": "^1.2.6",
14
+ "@zebec-network/zebec_payroll": "^1.5.4",
15
+ "bignumber.js": "^11.1.1",
16
+ "bn.js": "^5.2.3"
16
17
  },
17
18
  "devDependencies": {
18
19
  "@types/bn.js": "^5.2.0",
@@ -23,6 +24,7 @@
23
24
  "rimraf": "^6.1.3",
24
25
  "ts-mocha": "^11.1.0",
25
26
  "ts-node": "^10.9.2",
27
+ "tweetnacl": "^1.0.3",
26
28
  "typescript": "^6.0.3"
27
29
  },
28
30
  "files": [
@@ -43,5 +45,5 @@
43
45
  },
44
46
  "type": "module",
45
47
  "types": "dist/index.d.ts",
46
- "version": "2.5.0"
48
+ "version": "2.6.0-dev.2"
47
49
  }