@zebec-network/solana-payroll-sdk 2.7.0 → 2.9.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/LICENSE CHANGED
@@ -1,9 +1,9 @@
1
- # The MIT License (MIT)
2
-
3
- Copyright © 2025 Zebec Network
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
-
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
-
9
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ # The MIT License (MIT)
2
+
3
+ Copyright © 2025 Zebec Network
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
Binary file
@@ -3,7 +3,7 @@ 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, CardPurchaseInfo, ChangePayrollReceiverParams, CompanyDepositInfo, CompanyNonceInfo, CompleteUnlockParams, CreateCardParams, CreateMultiplePayrollParams, CreatePayrollParams, DistributeRewardsParams, PauseResumeMultiplePayrollParams, PauseResumePayrollParams, PayrollConfigInfo, PayrollMetadataInfo, RequestUnlockParams, SetMultipleTopupDelegateParams, SetTopupDelegateParams, SwapAndCreateCardParams, TokenMetadata, TopupMultiplePayrollParams, TopupPayrollParams, UserPurchaseRecordInfo, WithdrawMultiplePayrollParams, WithdrawPayrollParams, WithdrawRewardsParams, YieldDepositParams } from "./types.js";
6
+ import type { CancelMultiplePayrollParams, CancelPayrollParams, CancelUnlockParams, CardPurchaseInfo, ChangePayrollReceiverParams, CompanyDepositInfo, CompanyNonceInfo, CompleteUnlockParams, CreateCardParams, CreateMultiplePayrollParams, CreatePayrollParams, DistributeRewardsParams, InstantDisbursementParams, PauseResumeMultiplePayrollParams, PauseResumePayrollParams, PayrollConfigInfo, PayrollMetadataInfo, RequestUnlockParams, SetMultipleTopupDelegateParams, SetTopupDelegateParams, SwapAndCreateCardParams, TokenMetadata, TopupMultiplePayrollParams, TopupPayrollParams, UserPurchaseRecordInfo, WithdrawMultiplePayrollParams, WithdrawPayrollAndYieldDepositParams, WithdrawPayrollParams, WithdrawRewardsParams, 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>;
@@ -37,3 +37,5 @@ export declare function getCardIndexInfo(payrollProgram: Program<ZebecPayrollIdl
37
37
  export declare function getNextCardIndex(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, commitment?: Commitment): Promise<bigint>;
38
38
  export declare function getUserPurchaseRecordInfo(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, user: Address, commitment?: Commitment): Promise<UserPurchaseRecordInfo | null>;
39
39
  export declare function getCardPurchaseInfo(payrollProgram: Program<ZebecPayrollIdl>, entCardConfigName: string, user: Address, cardIndex: bigint, commitment?: Commitment): Promise<CardPurchaseInfo | null>;
40
+ export declare function instantDisbursement(payrollProgram: Program<ZebecPayrollIdl>, params: InstantDisbursementParams): Promise<MultiTransactionPayload>;
41
+ export declare function withdrawPayrollAndYieldDeposit(payrollProgram: Program<ZebecPayrollIdl>, configsProgram: Program<ZebecConfigsIdl>, params: WithdrawPayrollAndYieldDepositParams): Promise<TransactionPayload>;
package/dist/services.js CHANGED
@@ -2,8 +2,8 @@ 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 { createCloseAccountInstruction, createSyncNativeInstruction, } from "@solana/spl-token";
6
- import { AddressLookupTableAccount, ComputeBudgetProgram, Ed25519Program, Keypair, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
5
+ import { createCloseAccountInstruction, createSyncNativeInstruction, createTransferInstruction, } from "@solana/spl-token";
6
+ import { AddressLookupTableAccount, ComputeBudgetProgram, Ed25519Program, Keypair, LAMPORTS_PER_SOL, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
7
7
  import { assertBufferSize, bpsToPercent, percentToBps, } from "@zebec-network/core-utils";
8
8
  import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddressSync, getMintDecimals, MultiTransactionPayload, TEN_BIGNUM, TransactionPayload, UNITS_PER_USDC, USDC_DECIMALS, WSOL, } from "@zebec-network/solana-common";
9
9
  import { BigNumber } from "bignumber.js";
@@ -11,7 +11,7 @@ import { BN } from "bn.js";
11
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
12
  import { createCancelPayrollInstruction, createCancelUnlockInstruction, createChangeRecipientInstruction, createCompleteUnlockInstruction, createCreateCardInstruction, createCreatePayrollInstruction, createDistributeRewardsInstruction, createPauseResumePayrollInstruction, createRequestUnlockInstruction, createSetTopupDelegateInstruction, createSwapAndCreateCardInstruction, createTopupPayrollInstruction, createWithdrawPayrollInstruction, createWithdrawRewardsInstruction, createYieldDepositInstruction, } from "./instructions.js";
13
13
  import { deriveCheckAccountPda, deriveCompanyDepositPda, deriveCompanyNoncePda, deriveEnterpriseCardConfigPda, deriveEnterpriseCardIndexPda, deriveEnterpriseCardPurchasePda, deriveEnterpriseUserPurchaseRecordPda, derivePayrollConfigPda, derivePayrollVaultPda, deriveYieldConfigPda, } from "./pda.js";
14
- import { deductFeeFromAmount, getConnectionFromProgram,
14
+ import { calculateTotalWithdrawableAmount, deductFeeFromAmount, getConnectionFromProgram,
15
15
  // getFeeInfoForPayroll,
16
16
  getFeeRateForMint, isAmountWithInProviderCardPurchaseRange, isAmountWithinDailyCardLimit, } from "./utils.js";
17
17
  export async function getPayrollConfig(configProgram, configName) {
@@ -694,7 +694,7 @@ export async function getCompanyNonceInfo(payrollProgram, companyIdBuffer, commi
694
694
  export async function yieldDeposit(payrollProgram, configsProgram, params, commitment) {
695
695
  commitment = commitment ?? payrollProgram.provider.connection.commitment;
696
696
  const company = translateAddress(params.company);
697
- const depositMint = translateAddress(params.depoistMint);
697
+ const depositMint = translateAddress(params.depositMint);
698
698
  const [yieldConfig] = deriveYieldConfigPda(configsProgram.programId);
699
699
  const configData = await configsProgram.account.yieldConfig.fetchNullable(yieldConfig, commitment);
700
700
  if (!configData) {
@@ -1182,3 +1182,128 @@ export async function getCardPurchaseInfo(payrollProgram, entCardConfigName, use
1182
1182
  purchasedAt: info.purchaseAt.toNumber(),
1183
1183
  };
1184
1184
  }
1185
+ export async function instantDisbursement(payrollProgram, params) {
1186
+ const sender = translateAddress(params.sender);
1187
+ const feePayer = params.feePayer ? translateAddress(params.feePayer) : sender;
1188
+ if (params.recipients.length === 0) {
1189
+ throw new Error("At least one recipient is required");
1190
+ }
1191
+ const chunkSize = params.chunkSize ?? (params.isNative ? 20 : 5);
1192
+ const chunks = [];
1193
+ for (let i = 0; i < params.recipients.length; i += chunkSize) {
1194
+ chunks.push(params.recipients.slice(i, i + chunkSize));
1195
+ }
1196
+ const transactionData = await Promise.all(chunks.map(async (chunk) => {
1197
+ const instructions = [];
1198
+ if (params.isNative) {
1199
+ for (const recipient of chunk) {
1200
+ const receiver = translateAddress(recipient.address);
1201
+ const amount = BigNumber(recipient.amount)
1202
+ .times(LAMPORTS_PER_SOL)
1203
+ .toFixed(0);
1204
+ instructions.push(SystemProgram.transfer({
1205
+ fromPubkey: sender,
1206
+ toPubkey: receiver,
1207
+ lamports: BigInt(amount),
1208
+ }));
1209
+ }
1210
+ }
1211
+ else {
1212
+ const token = translateAddress(params.token);
1213
+ const decimals = await getMintDecimals(payrollProgram.provider.connection, token);
1214
+ const senderAta = getAssociatedTokenAddressSync(token, sender, true);
1215
+ for (const recipient of chunk) {
1216
+ const receiver = translateAddress(recipient.address);
1217
+ const receiverAta = getAssociatedTokenAddressSync(token, receiver, true);
1218
+ const amount = BigNumber(recipient.amount)
1219
+ .times(BigNumber(10).pow(decimals))
1220
+ .toFixed(0);
1221
+ const receiverAtaInfo = await payrollProgram.provider.connection.getAccountInfo(receiverAta);
1222
+ if (!receiverAtaInfo) {
1223
+ instructions.push(createAssociatedTokenAccountInstruction(feePayer, receiverAta, receiver, token));
1224
+ }
1225
+ instructions.push(createTransferInstruction(senderAta, receiverAta, sender, BigInt(amount)));
1226
+ }
1227
+ }
1228
+ return { instructions };
1229
+ }));
1230
+ return createMultiTransactionPayload(payrollProgram, feePayer, transactionData);
1231
+ }
1232
+ export async function withdrawPayrollAndYieldDeposit(payrollProgram, configsProgram, params) {
1233
+ const connection = getConnectionFromProgram(payrollProgram);
1234
+ const [payrollConfig] = derivePayrollConfigPda(params.payrollConfigName, configsProgram.programId);
1235
+ const receiver = translateAddress(params.company);
1236
+ const withdrawer = params.withdrawer
1237
+ ? translateAddress(params.withdrawer)
1238
+ : receiver;
1239
+ const feePayer = params.feePayer
1240
+ ? translateAddress(params.feePayer)
1241
+ : params.withdrawer
1242
+ ? withdrawer
1243
+ : receiver;
1244
+ const payrollMetadata = translateAddress(params.payrollMetadata);
1245
+ const payrollMetadataAccount = await payrollProgram.account.paymentStream.fetch(payrollMetadata);
1246
+ const payrollToken = payrollMetadataAccount.financials.streamToken;
1247
+ const receiverAta = getAssociatedTokenAddressSync(payrollToken, receiver, true);
1248
+ const [payrollVault] = derivePayrollVaultPda(payrollMetadata, payrollProgram.programId);
1249
+ const payrollVaultAta = getAssociatedTokenAddressSync(payrollToken, payrollVault, true);
1250
+ const payrollTokenDecimals = await getMintDecimals(connection, payrollToken);
1251
+ const withdrawPayrollIx = await createWithdrawPayrollInstruction(payrollProgram, {
1252
+ receiver,
1253
+ receiverAta,
1254
+ payrollConfig,
1255
+ payrollMetadata,
1256
+ payrollToken,
1257
+ payrollVault,
1258
+ payrollVaultAta,
1259
+ withdrawer,
1260
+ feePayer,
1261
+ });
1262
+ const company = translateAddress(params.company);
1263
+ const [yieldConfig] = deriveYieldConfigPda(configsProgram.programId);
1264
+ const configData = await configsProgram.account.yieldConfig.fetchNullable(yieldConfig, connection.commitment);
1265
+ if (!configData) {
1266
+ throw new Error("Yield config is not initialized in Zebec Configs Program");
1267
+ }
1268
+ const centralVault = configData.centralVault;
1269
+ const [companyNonce] = deriveCompanyNoncePda(Buffer.from(params.companyId), payrollProgram.programId);
1270
+ const [companyDeposit] = deriveCompanyDepositPda(Buffer.from(params.companyId), params.nonce, payrollProgram.programId);
1271
+ const centralVaultTokenAta = getAssociatedTokenAddressSync(payrollToken, centralVault, true);
1272
+ const companyTokenAta = getAssociatedTokenAddressSync(payrollToken, company, true);
1273
+ const amount = new BN(BigNumber(params.depositAmount).shiftedBy(payrollTokenDecimals).toFixed(0));
1274
+ const createYieldDepositIx = await createYieldDepositInstruction(payrollProgram, {
1275
+ company,
1276
+ companyDeposit,
1277
+ yieldConfig,
1278
+ centralVault,
1279
+ centralVaultTokenAta,
1280
+ companyNonce,
1281
+ companyTokenAta,
1282
+ depositMint: payrollToken,
1283
+ }, {
1284
+ amount,
1285
+ companyId: Array.from(params.companyId),
1286
+ nonce: new BN(params.nonce),
1287
+ });
1288
+ let effectiveTime = BigNumber(0);
1289
+ if (payrollMetadataAccount.schedule.pausedTimestamp.gtn(0)) {
1290
+ effectiveTime = BigNumber(payrollMetadataAccount.schedule.pausedTimestamp.toString());
1291
+ }
1292
+ else {
1293
+ const slot = await connection.getSlot(connection.commitment);
1294
+ effectiveTime = BigNumber(await connection.getBlockTime(slot).then((blocktime) => {
1295
+ if (!blocktime) {
1296
+ throw new Error("Could not fetch block time");
1297
+ }
1298
+ return blocktime;
1299
+ }));
1300
+ }
1301
+ const withdrawableAmount = calculateTotalWithdrawableAmount(BigNumber(payrollMetadataAccount.schedule.startTime.toString()), BigNumber(payrollMetadataAccount.financials.fullAmount.toString()), BigNumber(payrollMetadataAccount.schedule.duration.toString()), effectiveTime, BigNumber(payrollMetadataAccount.schedule.pausedInterval.toString())).shiftedBy(payrollTokenDecimals * -1);
1302
+ if (withdrawableAmount.lt(params.depositAmount)) {
1303
+ throw new Error("Withdrawable payroll amount is less than asked Yield deposit amount");
1304
+ }
1305
+ return createTransactionPayload(payrollProgram, withdrawer, [
1306
+ withdrawPayrollIx,
1307
+ createYieldDepositIx,
1308
+ ]);
1309
+ }
package/dist/types.d.ts CHANGED
@@ -210,7 +210,7 @@ export type YieldDepositParams = {
210
210
  companyId: Buffer | Uint8Array;
211
211
  company: Address;
212
212
  nonce: bigint;
213
- depoistMint: Address;
213
+ depositMint: Address;
214
214
  amount: Numeric;
215
215
  };
216
216
  export type RequestUnlockParams = {
@@ -355,6 +355,20 @@ export type SwapAndCreateCardParams = {
355
355
  quoteInfo: QuoteInfo;
356
356
  wrapAndUnwrapWsol?: boolean;
357
357
  };
358
+ export type InstantDisbursementRecipient = {
359
+ address: Address;
360
+ amount: Numeric;
361
+ };
362
+ export type InstantDisbursementParams = {
363
+ sender: Address;
364
+ feePayer?: Address;
365
+ /** SPL token mint. Ignored when isNative is true (uses SOL). */
366
+ token: Address;
367
+ isNative: boolean;
368
+ recipients: InstantDisbursementRecipient[];
369
+ /** Max recipients per transaction. Defaults to 5 for SPL, 20 for native SOL. */
370
+ chunkSize?: number;
371
+ };
358
372
  export type CardPurchaseInfo = {
359
373
  index: bigint;
360
374
  buyer: Address;
@@ -366,3 +380,13 @@ export type UserPurchaseRecordInfo = {
366
380
  lastCardBoughtPerDay: Numeric;
367
381
  lastCardBoughtTimestamp: number;
368
382
  };
383
+ export type WithdrawPayrollAndYieldDepositParams = {
384
+ payrollConfigName: string;
385
+ payrollMetadata: Address;
386
+ withdrawer?: Address;
387
+ feePayer?: Address;
388
+ company: Address;
389
+ companyId: Buffer | Uint8Array;
390
+ nonce: bigint;
391
+ depositAmount: Numeric;
392
+ };
package/dist/utils.d.ts CHANGED
@@ -14,3 +14,4 @@ export type ParsedTokenFeeItem = {
14
14
  };
15
15
  export declare function getFeeRateForMint(feeRateList: ParsedTokenFeeItem[], mint: PublicKey): number;
16
16
  export declare function deductFeeFromAmount(rawAmount: BigNumber.Value, feeRateInBps: BigNumber.Value): string;
17
+ export declare function calculateTotalWithdrawableAmount(start_time: BigNumber, full_amount: BigNumber, duration: BigNumber, now: BigNumber, paused_interval: BigNumber): BigNumber;
package/dist/utils.js CHANGED
@@ -99,3 +99,14 @@ export function deductFeeFromAmount(rawAmount, feeRateInBps) {
99
99
  const fee = amount.times(feeRateInBps).div(BPS_DENOMINATOR);
100
100
  return amount.minus(fee).toFixed(0, BigNumber.ROUND_FLOOR);
101
101
  }
102
+ export function calculateTotalWithdrawableAmount(start_time, full_amount, duration, now, paused_interval) {
103
+ if (now.lte(start_time)) {
104
+ return BigNumber(0);
105
+ }
106
+ const elapsed = BigNumber.max(0, now.minus(start_time).minus(paused_interval));
107
+ const totalDuration = BigNumber.max(1, duration);
108
+ return BigNumber.min(elapsed
109
+ .times(full_amount)
110
+ .div(totalDuration)
111
+ .decimalPlaces(0, BigNumber.ROUND_FLOOR), full_amount);
112
+ }
package/package.json CHANGED
@@ -45,5 +45,5 @@
45
45
  },
46
46
  "type": "module",
47
47
  "types": "dist/index.d.ts",
48
- "version": "2.7.0"
48
+ "version": "2.9.0"
49
49
  }