@zebec-network/solana-payroll-sdk 1.0.0-dev.1

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/README.md ADDED
Binary file
@@ -0,0 +1,5 @@
1
+ import type { RpcNetwork } from "./types.js";
2
+ export declare const PAYROLL_NAME_BUFFER_SIZE = 128;
3
+ export declare const PAYROLL_PROGRAM_ID: Record<RpcNetwork, string>;
4
+ export declare const PAYROLL_PROGRAM_LOOKUP_TABLE_ADDRESS: Record<RpcNetwork, string>;
5
+ export declare const SUPERAPP_BACKEND_URL: Record<RpcNetwork, string>;
@@ -0,0 +1,14 @@
1
+ export const PAYROLL_NAME_BUFFER_SIZE = 128;
2
+ export const PAYROLL_PROGRAM_ID = {
3
+ "mainnet-beta": "zPAY457TttFCcaCoA3imYyEHc2sPvLMTQgVxjAfodSM",
4
+ devnet: "zPAY457TttFCcaCoA3imYyEHc2sPvLMTQgVxjAfodSM",
5
+ };
6
+ export const PAYROLL_PROGRAM_LOOKUP_TABLE_ADDRESS = {
7
+ devnet: "HJmEzSXzJrtSdgBZSaedQ51WaD4LkT1r5zR2yT1QERqv",
8
+ "mainnet-beta": "43N5otEu7k7TzkKsdhkwiYGrdKjBejetWQbF9cJPtY6i",
9
+ };
10
+ export const SUPERAPP_BACKEND_URL = {
11
+ // "mainnet-beta": "https://uat-super.api.zebec.io",
12
+ "mainnet-beta": "https://api.superapp.zebec.io",
13
+ devnet: "https://dev-super.api.zebec.io",
14
+ };
@@ -0,0 +1,8 @@
1
+ export * from "./constants.js";
2
+ export * from "./instructions.js";
3
+ export * from "./pda.js";
4
+ export * from "./program.js";
5
+ export * from "./providers.js";
6
+ export * from "./services.js";
7
+ export * from "./types.js";
8
+ export * from "./utils.js";
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./constants.js";
2
+ export * from "./instructions.js";
3
+ export * from "./pda.js";
4
+ export * from "./program.js";
5
+ export * from "./providers.js";
6
+ export * from "./services.js";
7
+ export * from "./types.js";
8
+ export * from "./utils.js";
@@ -0,0 +1,132 @@
1
+ import type { BN, Program } from "@coral-xyz/anchor";
2
+ import type { PublicKey, TransactionInstruction } from "@solana/web3.js";
3
+ import type { ZebecPayroll as ZebecPayrollIdl } from "@zebec-network/zebec_payroll";
4
+ import type { ParsedFeeTier } from "./types.js";
5
+ export declare function createInitializeConfigInstruction(program: Program<ZebecPayrollIdl>, accounts: {
6
+ streamConfig: PublicKey;
7
+ admin: PublicKey;
8
+ }, data: {
9
+ baseFee: BN;
10
+ configName: string;
11
+ feeTiers: ParsedFeeTier[];
12
+ feeVault: PublicKey;
13
+ frequencies: BN[];
14
+ platformFee: BN;
15
+ withdrawAccount: PublicKey;
16
+ }): Promise<TransactionInstruction>;
17
+ export declare function createUpdateConfigInstruction(program: Program<ZebecPayrollIdl>, accounts: {
18
+ streamConfig: PublicKey;
19
+ admin: PublicKey;
20
+ }, data: {
21
+ baseFee: BN;
22
+ configName: string;
23
+ feeTiers: ParsedFeeTier[];
24
+ feeVault: PublicKey;
25
+ frequencies: BN[];
26
+ platformFee: BN;
27
+ withdrawAccount: PublicKey;
28
+ }): Promise<TransactionInstruction>;
29
+ export declare function createAddFeeTokenInstruction(program: Program<ZebecPayrollIdl>, accounts: {
30
+ streamConfig: PublicKey;
31
+ admin: PublicKey;
32
+ }, data: {
33
+ token: PublicKey;
34
+ }): Promise<TransactionInstruction>;
35
+ export declare function createWhitelistTokensInstruction(program: Program<ZebecPayrollIdl>, accounts: {
36
+ streamConfig: PublicKey;
37
+ admin: PublicKey;
38
+ }, data: {
39
+ tokens: PublicKey[];
40
+ }): Promise<TransactionInstruction>;
41
+ export declare function createRemoveWhitelistInstruction(program: Program<ZebecPayrollIdl>, accounts: {
42
+ streamConfig: PublicKey;
43
+ admin: PublicKey;
44
+ }, data: {
45
+ tokens: PublicKey[];
46
+ }): Promise<TransactionInstruction>;
47
+ export declare function createCreateStreamInstruction(program: Program<ZebecPayrollIdl>, accounts: {
48
+ sender: PublicKey;
49
+ feePayer: PublicKey;
50
+ senderAta: PublicKey;
51
+ receiver: PublicKey;
52
+ receiverAta: PublicKey;
53
+ streamMetadata: PublicKey;
54
+ streamVault: PublicKey;
55
+ streamVaultAta: PublicKey;
56
+ streamConfig: PublicKey;
57
+ withdrawAccount: PublicKey;
58
+ streamToken: PublicKey;
59
+ }, data: {
60
+ amount: BN;
61
+ startTime: BN;
62
+ duration: BN;
63
+ autoWithdrawFrequency: BN;
64
+ cliffPercentage: BN;
65
+ cancelableBySender: number;
66
+ cancelableByRecipient: number;
67
+ automaticWithdrawal: number;
68
+ transferableBySender: number;
69
+ transferableByRecipient: number;
70
+ canTopup: number;
71
+ isPausable: number;
72
+ rateUpdatable: number;
73
+ startNow: number;
74
+ streamName: number[];
75
+ initialBufferDuration: BN;
76
+ autoTopupDelegate: number;
77
+ senderId: number[];
78
+ receiverId: number[];
79
+ }): Promise<TransactionInstruction>;
80
+ export declare function createCancelStreamInstruction(program: Program<ZebecPayrollIdl>, accounts: {
81
+ signer: PublicKey;
82
+ feePayer: PublicKey;
83
+ otherPartyAta: PublicKey;
84
+ otherParty: PublicKey;
85
+ streamMetadata: PublicKey;
86
+ streamVault: PublicKey;
87
+ streamVaultAta: PublicKey;
88
+ signerAta: PublicKey;
89
+ streamToken: PublicKey;
90
+ }): Promise<TransactionInstruction>;
91
+ export declare function createWithdrawStreamInstruction(program: Program<ZebecPayrollIdl>, accounts: {
92
+ withdrawer: PublicKey;
93
+ feePayer: PublicKey;
94
+ receiver: PublicKey;
95
+ receiverAta: PublicKey;
96
+ streamMetadata: PublicKey;
97
+ streamVault: PublicKey;
98
+ streamVaultAta: PublicKey;
99
+ streamConfig: PublicKey;
100
+ streamToken: PublicKey;
101
+ }): Promise<TransactionInstruction>;
102
+ export declare function createPauseResumeStreamInstruction(program: Program<ZebecPayrollIdl>, accounts: {
103
+ user: PublicKey;
104
+ streamMetadata: PublicKey;
105
+ }): Promise<TransactionInstruction>;
106
+ export declare function createChangeRecipientInstruction(program: Program<ZebecPayrollIdl>, accounts: {
107
+ signer: PublicKey;
108
+ stream: PublicKey;
109
+ newRecipient: PublicKey;
110
+ }): Promise<TransactionInstruction>;
111
+ export declare function createTopupStreamInstruction(program: Program<ZebecPayrollIdl>, accounts: {
112
+ caller: PublicKey;
113
+ sender: PublicKey;
114
+ senderAta: PublicKey;
115
+ streamMetadata: PublicKey;
116
+ streamVault: PublicKey;
117
+ streamVaultAta: PublicKey;
118
+ streamConfig: PublicKey;
119
+ streamToken: PublicKey;
120
+ }, data: {
121
+ extra: BN;
122
+ }): Promise<TransactionInstruction>;
123
+ export declare function createSetTopupDelegateInstruction(program: Program<ZebecPayrollIdl>, accounts: {
124
+ sender: PublicKey;
125
+ senderAta: PublicKey;
126
+ streamMetadata: PublicKey;
127
+ streamVault: PublicKey;
128
+ streamConfig: PublicKey;
129
+ streamToken: PublicKey;
130
+ }, data: {
131
+ amount: BN;
132
+ }): Promise<TransactionInstruction>;
@@ -0,0 +1,178 @@
1
+ export async function createInitializeConfigInstruction(program, accounts, data) {
2
+ return program.methods
3
+ .initializeConfig({
4
+ baseFee: data.baseFee,
5
+ configName: data.configName,
6
+ feeTier: data.feeTiers,
7
+ feeVault: data.feeVault,
8
+ frequencies: data.frequencies,
9
+ platformFee: data.platformFee,
10
+ withdrawAccount: data.withdrawAccount,
11
+ })
12
+ .accountsPartial({
13
+ admin: accounts.admin,
14
+ streamConfig: accounts.streamConfig,
15
+ })
16
+ .instruction();
17
+ }
18
+ export async function createUpdateConfigInstruction(program, accounts, data) {
19
+ return program.methods
20
+ .updateConfig({
21
+ baseFee: data.baseFee,
22
+ configName: data.configName,
23
+ feeTier: data.feeTiers,
24
+ feeVault: data.feeVault,
25
+ frequencies: data.frequencies,
26
+ platformFee: data.platformFee,
27
+ withdrawAccount: data.withdrawAccount,
28
+ })
29
+ .accountsPartial({
30
+ admin: accounts.admin,
31
+ streamConfig: accounts.streamConfig,
32
+ })
33
+ .instruction();
34
+ }
35
+ export async function createAddFeeTokenInstruction(program, accounts, data) {
36
+ return program.methods
37
+ .addFeeToken({ token: data.token })
38
+ .accountsPartial({
39
+ admin: accounts.admin,
40
+ streamConfig: accounts.streamConfig,
41
+ })
42
+ .instruction();
43
+ }
44
+ export async function createWhitelistTokensInstruction(program, accounts, data) {
45
+ return program.methods
46
+ .whitelistTokens({ tokens: data.tokens })
47
+ .accountsPartial({
48
+ admin: accounts.admin,
49
+ streamConfig: accounts.streamConfig,
50
+ })
51
+ .instruction();
52
+ }
53
+ export async function createRemoveWhitelistInstruction(program, accounts, data) {
54
+ return program.methods
55
+ .removeWhitelist({ tokens: data.tokens })
56
+ .accountsPartial({
57
+ admin: accounts.admin,
58
+ streamConfig: accounts.streamConfig,
59
+ })
60
+ .instruction();
61
+ }
62
+ export async function createCreateStreamInstruction(program, accounts, data) {
63
+ return program.methods
64
+ .createStream({
65
+ amount: data.amount,
66
+ startTime: data.startTime,
67
+ duration: data.duration,
68
+ streamFrequency: data.autoWithdrawFrequency,
69
+ cliffPercentage: data.cliffPercentage,
70
+ cancelableBySender: data.cancelableBySender,
71
+ cancelableByRecipient: data.cancelableByRecipient,
72
+ automaticWithdrawal: data.automaticWithdrawal,
73
+ transferableBySender: data.transferableBySender,
74
+ transferableByRecipient: data.transferableByRecipient,
75
+ canTopup: data.canTopup,
76
+ isPausable: data.isPausable,
77
+ rateUpdatable: data.rateUpdatable,
78
+ startNow: data.startNow,
79
+ streamName: data.streamName,
80
+ initialBufferDuration: data.initialBufferDuration,
81
+ autoTopupDelegate: data.autoTopupDelegate,
82
+ senderId: data.senderId,
83
+ receiverId: data.receiverId,
84
+ })
85
+ .accountsPartial({
86
+ sender: accounts.sender,
87
+ feePayer: accounts.feePayer,
88
+ senderAta: accounts.senderAta,
89
+ receiver: accounts.receiver,
90
+ receiverAta: accounts.receiverAta,
91
+ streamMetadata: accounts.streamMetadata,
92
+ streamVault: accounts.streamVault,
93
+ streamVaultAta: accounts.streamVaultAta,
94
+ streamConfig: accounts.streamConfig,
95
+ withdrawAccount: accounts.withdrawAccount,
96
+ streamToken: accounts.streamToken,
97
+ })
98
+ .instruction();
99
+ }
100
+ export async function createCancelStreamInstruction(program, accounts) {
101
+ return program.methods
102
+ .cancelStream()
103
+ .accountsPartial({
104
+ signer: accounts.signer,
105
+ feePayer: accounts.feePayer,
106
+ otherPartyAta: accounts.otherPartyAta,
107
+ otherParty: accounts.otherParty,
108
+ streamMetadata: accounts.streamMetadata,
109
+ streamVault: accounts.streamVault,
110
+ streamVaultAta: accounts.streamVaultAta,
111
+ signerAta: accounts.signerAta,
112
+ streamToken: accounts.streamToken,
113
+ })
114
+ .instruction();
115
+ }
116
+ export async function createWithdrawStreamInstruction(program, accounts) {
117
+ return program.methods
118
+ .withdrawStream()
119
+ .accountsPartial({
120
+ withdrawer: accounts.withdrawer,
121
+ feePayer: accounts.feePayer,
122
+ receiver: accounts.receiver,
123
+ receiverAta: accounts.receiverAta,
124
+ streamMetadata: accounts.streamMetadata,
125
+ streamVault: accounts.streamVault,
126
+ streamVaultAta: accounts.streamVaultAta,
127
+ streamConfig: accounts.streamConfig,
128
+ streamToken: accounts.streamToken,
129
+ })
130
+ .instruction();
131
+ }
132
+ export async function createPauseResumeStreamInstruction(program, accounts) {
133
+ return program.methods
134
+ .pauseResumeStream()
135
+ .accountsPartial({
136
+ user: accounts.user,
137
+ streamMetadata: accounts.streamMetadata,
138
+ })
139
+ .instruction();
140
+ }
141
+ export async function createChangeRecipientInstruction(program, accounts) {
142
+ return program.methods
143
+ .changeRecipient()
144
+ .accountsPartial({
145
+ signer: accounts.signer,
146
+ stream: accounts.stream,
147
+ newRecipient: accounts.newRecipient,
148
+ })
149
+ .instruction();
150
+ }
151
+ export async function createTopupStreamInstruction(program, accounts, data) {
152
+ return program.methods
153
+ .topupStream(data.extra)
154
+ .accountsPartial({
155
+ caller: accounts.caller,
156
+ sender: accounts.sender,
157
+ senderAta: accounts.senderAta,
158
+ streamMetadata: accounts.streamMetadata,
159
+ streamVault: accounts.streamVault,
160
+ streamVaultAta: accounts.streamVaultAta,
161
+ streamConfig: accounts.streamConfig,
162
+ streamToken: accounts.streamToken,
163
+ })
164
+ .instruction();
165
+ }
166
+ export async function createSetTopupDelegateInstruction(program, accounts, data) {
167
+ return program.methods
168
+ .setTopupDelegate(data.amount)
169
+ .accountsPartial({
170
+ sender: accounts.sender,
171
+ senderAta: accounts.senderAta,
172
+ streamMetadata: accounts.streamMetadata,
173
+ streamVault: accounts.streamVault,
174
+ streamConfig: accounts.streamConfig,
175
+ streamToken: accounts.streamToken,
176
+ })
177
+ .instruction();
178
+ }
package/dist/pda.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { type Address } from "@coral-xyz/anchor";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ export declare function deriveStreamConfigPda(configName: string, programId: Address): [PublicKey, number];
4
+ export declare function deriveStreamVaultPda(metatadata: Address, programId: Address): [PublicKey, number];
package/dist/pda.js ADDED
@@ -0,0 +1,11 @@
1
+ import { translateAddress, utils } from "@coral-xyz/anchor";
2
+ import { PublicKey } from "@solana/web3.js";
3
+ const SEEDS = {
4
+ STREAM_CONFIG: utils.bytes.utf8.encode("config"),
5
+ };
6
+ export function deriveStreamConfigPda(configName, programId) {
7
+ return PublicKey.findProgramAddressSync([SEEDS.STREAM_CONFIG, utils.bytes.utf8.encode(configName)], translateAddress(programId));
8
+ }
9
+ export function deriveStreamVaultPda(metatadata, programId) {
10
+ return PublicKey.findProgramAddressSync([translateAddress(metatadata).toBuffer()], translateAddress(programId));
11
+ }
@@ -0,0 +1,3 @@
1
+ import { Program, type Provider } from "@coral-xyz/anchor";
2
+ import { type ZebecPayroll as ZebecPayrollIdl } from "@zebec-network/zebec_payroll";
3
+ export declare function createPayrollProgram(provider: Provider): Program<ZebecPayrollIdl>;
@@ -0,0 +1,5 @@
1
+ import { Program } from "@coral-xyz/anchor";
2
+ import { zebecPayroll as ZEBEC_PAYROLL, } from "@zebec-network/zebec_payroll";
3
+ export function createPayrollProgram(provider) {
4
+ return new Program(ZEBEC_PAYROLL.idl, provider);
5
+ }
@@ -0,0 +1,17 @@
1
+ import { type Address, AnchorProvider } from "@coral-xyz/anchor";
2
+ import type { ConfirmOptions, Connection, PublicKey, Transaction, VersionedTransaction } from "@solana/web3.js";
3
+ export declare class ReadonlyProvider {
4
+ readonly connection: Connection;
5
+ readonly walletAddress?: PublicKey;
6
+ constructor(connection: Connection, walletAddress?: Address);
7
+ }
8
+ export declare function createReadonlyProvider(connection: Connection, walletAddress?: Address): ReadonlyProvider;
9
+ /**
10
+ * Wallet interface used by Anchor Framework
11
+ */
12
+ export interface AnchorWallet {
13
+ signTransaction: <T extends Transaction | VersionedTransaction>(tx: T) => Promise<T>;
14
+ signAllTransactions: <T extends Transaction | VersionedTransaction>(txs: T[]) => Promise<T[]>;
15
+ publicKey: PublicKey;
16
+ }
17
+ export declare function createAnchorProvider(connection: Connection, wallet: AnchorWallet, options?: ConfirmOptions): AnchorProvider;
@@ -0,0 +1,20 @@
1
+ import { AnchorProvider, translateAddress, } from "@coral-xyz/anchor";
2
+ export class ReadonlyProvider {
3
+ connection;
4
+ walletAddress;
5
+ constructor(connection, walletAddress) {
6
+ this.connection = connection;
7
+ if (walletAddress) {
8
+ this.walletAddress = translateAddress(walletAddress);
9
+ }
10
+ }
11
+ }
12
+ export function createReadonlyProvider(connection, walletAddress) {
13
+ return new ReadonlyProvider(connection, walletAddress);
14
+ }
15
+ export function createAnchorProvider(connection, wallet, options) {
16
+ return new AnchorProvider(connection, wallet, {
17
+ ...AnchorProvider.defaultOptions(),
18
+ ...options,
19
+ });
20
+ }
@@ -0,0 +1,20 @@
1
+ import { type Address, type Program } from "@coral-xyz/anchor";
2
+ import { type Commitment } from "@solana/web3.js";
3
+ import { TransactionPayload } from "@zebec-network/solana-common";
4
+ import type { ZebecPayroll as ZebecPayrollIdl } from "@zebec-network/zebec_payroll";
5
+ import type { CancelStreamParams, ChangeStreamReceiverParams, CreateStreamParams, InitializeStreamConfigParams, PayrollConfigInfo, PayrollMetadataInfo, SetTopupDelegateParams, TokenMetadata, TopupStreamParams, UpdateStreamConfigParams, WhiteListTokensParams, WithdrawStreamParams } from "./types.js";
6
+ export declare function getPayrollConfig(program: Program<ZebecPayrollIdl>, configName: string): Promise<PayrollConfigInfo>;
7
+ export declare function getWhitelistedTokens(program: Program<ZebecPayrollIdl>, configName: string, commitment?: "processed" | "confirmed" | "finalized"): Promise<TokenMetadata[]>;
8
+ export declare function getStreamMetadataInfo(program: Program<ZebecPayrollIdl>, streamMetadata: Address, commitment?: Commitment): Promise<PayrollMetadataInfo>;
9
+ export declare function initializePayrollConfig(program: Program<ZebecPayrollIdl>, params: InitializeStreamConfigParams): Promise<TransactionPayload>;
10
+ export declare function updatePayrollConfig(program: Program<ZebecPayrollIdl>, params: UpdateStreamConfigParams): Promise<TransactionPayload>;
11
+ export declare function whiteListTokens(program: Program<ZebecPayrollIdl>, params: WhiteListTokensParams): Promise<TransactionPayload>;
12
+ export declare function createStream(program: Program<ZebecPayrollIdl>, params: CreateStreamParams): Promise<TransactionPayload>;
13
+ export declare function cancelStream(program: Program<ZebecPayrollIdl>, params: CancelStreamParams): Promise<TransactionPayload>;
14
+ export declare function pauseResumeStream(program: Program<ZebecPayrollIdl>, params: {
15
+ streamMetadata: Address;
16
+ }): Promise<TransactionPayload>;
17
+ export declare function withdrawStream(program: Program<ZebecPayrollIdl>, params: WithdrawStreamParams): Promise<TransactionPayload>;
18
+ export declare function changeStreamReceiver(program: Program<ZebecPayrollIdl>, params: ChangeStreamReceiverParams): Promise<TransactionPayload>;
19
+ export declare function setTopupDelegate(program: Program<ZebecPayrollIdl>, params: SetTopupDelegateParams): Promise<TransactionPayload>;
20
+ export declare function topupStream(program: Program<ZebecPayrollIdl>, params: TopupStreamParams): Promise<TransactionPayload>;
@@ -0,0 +1,472 @@
1
+ import { AnchorProvider, translateAddress, utils, } from "@coral-xyz/anchor";
2
+ import { fetchMetadata, MPL_TOKEN_METADATA_PROGRAM_ID, } from "@metaplex-foundation/mpl-token-metadata";
3
+ import { createUmi } from "@metaplex-foundation/umi-bundle-defaults";
4
+ import { fromWeb3JsPublicKey, toWeb3JsPublicKey, } from "@metaplex-foundation/umi-web3js-adapters";
5
+ import { createTransferInstruction } from "@solana/spl-token";
6
+ import { Keypair, PublicKey, } from "@solana/web3.js";
7
+ import { bpsToPercent, percentToBps } from "@zebec-network/core-utils";
8
+ import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddressSync, getMintDecimals, TEN_BIGNUM, TransactionPayload, UNITS_PER_USDC, USDC_DECIMALS, } from "@zebec-network/solana-common";
9
+ import BigNumber from "bignumber.js";
10
+ import { BN } from "bn.js";
11
+ import { PAYROLL_NAME_BUFFER_SIZE } from "./constants.js";
12
+ import { createCancelStreamInstruction, createChangeRecipientInstruction, createCreateStreamInstruction, createInitializeConfigInstruction, createPauseResumeStreamInstruction, createSetTopupDelegateInstruction, createTopupStreamInstruction, createUpdateConfigInstruction, createWhitelistTokensInstruction, createWithdrawStreamInstruction, } from "./instructions.js";
13
+ import { deriveStreamConfigPda, deriveStreamVaultPda } from "./pda.js";
14
+ import { getFeeInfoForStream, getNetworkFromConnection } from "./utils.js";
15
+ export async function getPayrollConfig(program, configName) {
16
+ const [streamConfigPda] = deriveStreamConfigPda(configName, program.programId);
17
+ const streamConfig = await program.account.streamConfig.fetchNullable(streamConfigPda);
18
+ if (!streamConfig) {
19
+ throw new Error(`Stream config not found for name: ${configName}`);
20
+ }
21
+ return {
22
+ configName,
23
+ address: streamConfigPda,
24
+ admin: streamConfig.admin,
25
+ withdrawerAccount: streamConfig.withdrawAccount,
26
+ whitelistedTokens: streamConfig.whitelistedTokens,
27
+ platformFee: Number(bpsToPercent(streamConfig.platformFee.toNumber())),
28
+ baseFee: Number(bpsToPercent(streamConfig.baseFee.toNumber())),
29
+ frequencies: streamConfig.frequencies.map((f) => f.toNumber()),
30
+ feeTiers: streamConfig.feeTiers.tiers.map((t) => ({
31
+ minThreshold: BigNumber(t.minAmount.toString())
32
+ .div(UNITS_PER_USDC)
33
+ .toFixed(),
34
+ maxThreshold: BigNumber(t.maxAmount.toString())
35
+ .div(UNITS_PER_USDC)
36
+ .toFixed(),
37
+ feeRateInPercent: Number(bpsToPercent(t.fee.toNumber())),
38
+ })),
39
+ feeVault: streamConfig.feeVault,
40
+ };
41
+ }
42
+ export async function getWhitelistedTokens(program, configName, commitment) {
43
+ const [config] = deriveStreamConfigPda(configName, program.programId);
44
+ const configInfo = await program.account.streamConfig.fetch(config, commitment ?? program.provider.connection.commitment);
45
+ const whitelistedTokens = configInfo.whitelistedTokens;
46
+ const umi = createUmi(program.provider.connection.rpcEndpoint, commitment);
47
+ return Promise.all(whitelistedTokens.map(async (mint) => {
48
+ const mplProgramId = toWeb3JsPublicKey(MPL_TOKEN_METADATA_PROGRAM_ID);
49
+ const [metadata] = PublicKey.findProgramAddressSync([Buffer.from("metadata"), mplProgramId.toBytes(), mint.toBytes()], mplProgramId);
50
+ const mintInfo = await program.provider.connection.getParsedAccountInfo(mint, commitment);
51
+ if (!mintInfo.value) {
52
+ throw new Error(`Failed to fetch mint account: ${mint.toString()}`);
53
+ }
54
+ // Check if the account is a valid mint account
55
+ const mintData = mintInfo.value.data;
56
+ if (Buffer.isBuffer(mintData) || mintData.parsed.type !== "mint") {
57
+ throw new Error(`The provided address is not a valid mint account: ${mint.toString()}`);
58
+ }
59
+ try {
60
+ const metadataInfo = await fetchMetadata(umi, fromWeb3JsPublicKey(metadata));
61
+ return {
62
+ mint,
63
+ decimals: Number(mintData.parsed.info.decimals),
64
+ freezeAuthority: mintData.parsed.info.freezeAuthority
65
+ ? new PublicKey(mintData.parsed.info.freezeAuthority)
66
+ : null,
67
+ supply: BigNumber(mintData.parsed.info.supply)
68
+ .div(TEN_BIGNUM.pow(mintData.parsed.info.decimals))
69
+ .toFixed(),
70
+ isInitialized: Boolean(mintData.parsed.info.isInitialized),
71
+ mintAuthority: mintData.parsed.info.mintAuthority
72
+ ? new PublicKey(mintData.parsed.info.mintAuthority)
73
+ : null,
74
+ metadata: {
75
+ address: metadata,
76
+ updateAuthority: toWeb3JsPublicKey(metadataInfo.updateAuthority),
77
+ name: metadataInfo.name,
78
+ symbol: metadataInfo.symbol,
79
+ uri: metadataInfo.uri,
80
+ },
81
+ };
82
+ }
83
+ catch (error) {
84
+ if (error instanceof Error &&
85
+ error.message.includes("The account of type [Metadata] was not found at the provided address")) {
86
+ console.warn(`Failed to fetch metadata for mint: ${mint.toBase58()}`, error);
87
+ return {
88
+ mint,
89
+ decimals: Number(mintData.parsed.info.decimals),
90
+ freezeAuthority: mintData.parsed.info.freezeAuthority
91
+ ? new PublicKey(mintData.parsed.info.freezeAuthority)
92
+ : null,
93
+ supply: BigNumber(mintData.parsed.info.supply)
94
+ .div(TEN_BIGNUM.pow(mintData.parsed.info.decimals))
95
+ .toFixed(),
96
+ isInitialized: Boolean(mintData.parsed.info.isInitialized),
97
+ mintAuthority: mintData.parsed.info.mintAuthority
98
+ ? new PublicKey(mintData.parsed.info.mintAuthority)
99
+ : null,
100
+ metadata: null,
101
+ };
102
+ }
103
+ throw error;
104
+ }
105
+ }));
106
+ }
107
+ export async function getStreamMetadataInfo(program, streamMetadata, commitment) {
108
+ const metadataInfo = await program.account.paymentStream.fetch(translateAddress(streamMetadata), commitment ?? program.provider.connection.commitment);
109
+ const streamToken = metadataInfo.financials.streamToken;
110
+ const streamTokenDecimals = await getMintDecimals(program.provider.connection, streamToken);
111
+ const unitsPerStreamToken = TEN_BIGNUM.pow(streamTokenDecimals);
112
+ const depositedAmount = BigNumber(metadataInfo.financials.depositedAmount.toString())
113
+ .div(unitsPerStreamToken)
114
+ .toFixed();
115
+ const withdrawnAmount = BigNumber(metadataInfo.financials.withdrawnAmount.toString())
116
+ .div(unitsPerStreamToken)
117
+ .toFixed();
118
+ const cliffPercentage = Number(bpsToPercent(metadataInfo.financials.cliffPercentage.toNumber()));
119
+ return {
120
+ address: translateAddress(streamMetadata),
121
+ parties: {
122
+ sender: metadataInfo.parties.sender,
123
+ receiver: metadataInfo.parties.receiver,
124
+ },
125
+ financials: {
126
+ streamToken,
127
+ cliffPercentage,
128
+ depositedAmount,
129
+ withdrawnAmount,
130
+ },
131
+ schedule: {
132
+ startTime: metadataInfo.schedule.startTime.toNumber(),
133
+ endTime: metadataInfo.schedule.endTime.toNumber(),
134
+ lastWithdrawTime: metadataInfo.schedule.lastWithdrawTime.toNumber(),
135
+ frequency: metadataInfo.schedule.frequency.toNumber(),
136
+ duration: metadataInfo.schedule.duration.toNumber(),
137
+ pausedTimestamp: metadataInfo.schedule.pausedTimestamp.toNumber(),
138
+ pausedInterval: metadataInfo.schedule.pausedInterval.toNumber(),
139
+ canceledTimestamp: metadataInfo.schedule.canceledTimestamp.toNumber(),
140
+ },
141
+ topupState: {
142
+ coveredUntill: metadataInfo.topupState.coveredUntil.toNumber(),
143
+ initialBufferDuration: metadataInfo.topupState.initialBufferDuration.toNumber(),
144
+ topupCount: metadataInfo.topupState.topupCount.toNumber(),
145
+ },
146
+ permissions: {
147
+ cancelableBySender: Boolean(metadataInfo.permissions.cancelableBySender),
148
+ cancelableByRecipient: Boolean(metadataInfo.permissions.cancelableByRecipient),
149
+ automaticWithdrawal: Boolean(metadataInfo.permissions.automaticWithdrawal),
150
+ transferableBySender: Boolean(metadataInfo.permissions.transferableBySender),
151
+ transferableByRecipient: Boolean(metadataInfo.permissions.transferableByRecipient),
152
+ canTopup: Boolean(metadataInfo.permissions.canTopup),
153
+ isPausable: Boolean(metadataInfo.permissions.isPausable),
154
+ rateUpdatable: Boolean(metadataInfo.permissions.rateUpdatable),
155
+ },
156
+ streamName: utils.bytes.utf8.decode(Uint8Array.from(metadataInfo.streamName).filter((byte) => byte !== 0)), // Remove padding zeros
157
+ };
158
+ }
159
+ async function createPayload(program, payerKey, instructions, signers, addressLookupTableAccounts) {
160
+ const errorMap = new Map();
161
+ program.idl.errors.map((error) => errorMap.set(error.code, error.msg));
162
+ const provider = program.provider;
163
+ let signTransaction;
164
+ if (provider instanceof AnchorProvider) {
165
+ signTransaction = async (tx) => {
166
+ return provider.wallet.signTransaction(tx);
167
+ };
168
+ }
169
+ return new TransactionPayload(program.provider.connection, errorMap, {
170
+ instructions,
171
+ feePayer: payerKey,
172
+ signers: signers ?? [],
173
+ addressLookupTableAccounts: addressLookupTableAccounts ?? [],
174
+ }, signTransaction);
175
+ }
176
+ export async function initializePayrollConfig(program, params) {
177
+ const admin = params.admin
178
+ ? translateAddress(params.admin)
179
+ : program.provider.publicKey;
180
+ if (!admin) {
181
+ throw new Error("Either provide admin or create provider with public key");
182
+ }
183
+ const [streamConfig] = deriveStreamConfigPda(params.config.streamConfigName, program.programId);
184
+ const baseFee = new BN(percentToBps(params.config.baseFeePercent));
185
+ const frequencies = params.config.frequencies.map((frequency) => new BN(frequency));
186
+ const platformFee = new BN(percentToBps(params.config.platformFeePercent));
187
+ const withdrawAccount = translateAddress(params.config.withdrawAccount);
188
+ const feeVault = translateAddress(params.config.feeVault);
189
+ const feeTiers = params.config.feeTiers.map((tier) => {
190
+ return {
191
+ minAmount: new BN(BigNumber(tier.minThreshold)
192
+ .times(TEN_BIGNUM.pow(USDC_DECIMALS))
193
+ .toFixed(0)),
194
+ maxAmount: new BN(BigNumber(tier.maxThreshold)
195
+ .times(TEN_BIGNUM.pow(USDC_DECIMALS))
196
+ .toFixed(0)),
197
+ fee: new BN(percentToBps(tier.feeRateInPercent)),
198
+ };
199
+ });
200
+ const ix = await createInitializeConfigInstruction(program, { admin, streamConfig }, {
201
+ baseFee,
202
+ frequencies,
203
+ platformFee,
204
+ withdrawAccount,
205
+ feeTiers,
206
+ configName: params.config.streamConfigName,
207
+ feeVault,
208
+ });
209
+ return createPayload(program, admin, [ix]);
210
+ }
211
+ export async function updatePayrollConfig(program, params) {
212
+ const admin = params.admin
213
+ ? translateAddress(params.admin)
214
+ : program.provider.publicKey;
215
+ if (!admin) {
216
+ throw new Error("Either provide admin or create provider with public key");
217
+ }
218
+ const [streamConfig] = deriveStreamConfigPda(params.config.streamConfigName, program.programId);
219
+ const baseFee = new BN(percentToBps(params.config.baseFeePercent));
220
+ const frequencies = params.config.frequencies.map((frequency) => new BN(frequency));
221
+ const platformFee = new BN(percentToBps(params.config.platformFeePercent));
222
+ const withdrawAccount = translateAddress(params.config.withdrawAccount);
223
+ const feeVault = translateAddress(params.config.feeVault);
224
+ const feeTiers = params.config.feeTiers.map((tier) => {
225
+ return {
226
+ minAmount: new BN(BigNumber(tier.minThreshold)
227
+ .times(TEN_BIGNUM.pow(USDC_DECIMALS))
228
+ .toFixed(0)),
229
+ maxAmount: new BN(BigNumber(tier.maxThreshold)
230
+ .times(TEN_BIGNUM.pow(USDC_DECIMALS))
231
+ .toFixed(0)),
232
+ fee: new BN(percentToBps(tier.feeRateInPercent)),
233
+ };
234
+ });
235
+ const ix = await createUpdateConfigInstruction(program, { admin, streamConfig }, {
236
+ baseFee,
237
+ frequencies,
238
+ platformFee,
239
+ withdrawAccount,
240
+ feeTiers,
241
+ configName: params.config.streamConfigName,
242
+ feeVault,
243
+ });
244
+ return createPayload(program, admin, [ix]);
245
+ }
246
+ export async function whiteListTokens(program, params) {
247
+ const admin = translateAddress(params.admin);
248
+ const [streamConfig] = deriveStreamConfigPda(params.streamConfigName, program.programId);
249
+ const tokens = params.tokens.map((token) => translateAddress(token));
250
+ const ix = await createWhitelistTokensInstruction(program, {
251
+ admin,
252
+ streamConfig,
253
+ }, { tokens });
254
+ return createPayload(program, admin, [ix]);
255
+ }
256
+ export async function createStream(program, params) {
257
+ const receiver = translateAddress(params.receiver);
258
+ const sender = translateAddress(params.sender);
259
+ const feePayer = params.feePayer ? translateAddress(params.feePayer) : sender;
260
+ const streamToken = translateAddress(params.streamToken);
261
+ const [streamConfig] = deriveStreamConfigPda(params.streamConfigName, program.programId);
262
+ const streamConfigAccount = await program.account.streamConfig.fetch(streamConfig);
263
+ const withdrawer = streamConfigAccount.withdrawAccount;
264
+ const autoWithdrawFrequencies = new Set(Array.from(streamConfigAccount.frequencies.map((f) => f.toNumber())));
265
+ if (params.automaticWithdrawal &&
266
+ !autoWithdrawFrequencies.has(params.autoWithdrawFrequency)) {
267
+ throw new Error("Invalid stream frequency");
268
+ }
269
+ const senderAta = getAssociatedTokenAddressSync(streamToken, sender, true);
270
+ const receiverAta = getAssociatedTokenAddressSync(streamToken, receiver, true);
271
+ const streamMetadataKeypair = params.streamMetadataKeypair ?? Keypair.generate();
272
+ const [streamVault] = deriveStreamVaultPda(streamMetadataKeypair.publicKey, program.programId);
273
+ const streamVaultAta = getAssociatedTokenAddressSync(streamToken, streamVault, true);
274
+ const streamTokenDecimals = await getMintDecimals(program.provider.connection, streamToken);
275
+ const amount = BigNumber(params.amount)
276
+ .times(TEN_BIGNUM.pow(streamTokenDecimals))
277
+ .toFixed(0);
278
+ const cliffPercentage = new BN(percentToBps(params.cliffPercentage));
279
+ const streamName = new Uint8Array(PAYROLL_NAME_BUFFER_SIZE);
280
+ streamName.set(utils.bytes.utf8.encode(params.streamName));
281
+ const configAccount = await program.account.streamConfig.fetch(streamConfig);
282
+ const network = getNetworkFromConnection(program.provider.connection);
283
+ const feeInfo = await getFeeInfoForStream(streamToken, amount, streamTokenDecimals, network);
284
+ const feeToken = translateAddress(feeInfo.feeToken.mintAddress);
285
+ const parsedFeeAmount = feeInfo.feeAmountRaw;
286
+ const feeVault = configAccount.feeVault;
287
+ const feeVaultAta = getAssociatedTokenAddressSync(feeToken, feeVault, true);
288
+ const senderFeeTokenAta = getAssociatedTokenAddressSync(feeToken, sender, true);
289
+ const feeVaultAtaInfo = await program.provider.connection.getAccountInfo(feeVaultAta);
290
+ const ixs = [];
291
+ // add instruction to create fee vault ATA if it does not exist
292
+ if (!feeVaultAtaInfo) {
293
+ const createFeeVaultAtaIx = createAssociatedTokenAccountInstruction(feePayer, feeVaultAta, feeVault, feeToken);
294
+ ixs.push(createFeeVaultAtaIx);
295
+ }
296
+ // add instruction to transfer fee to fee vault
297
+ const transferFeeToVaultIx = createTransferInstruction(senderFeeTokenAta, feeVaultAta, sender, BigInt(parsedFeeAmount));
298
+ ixs.push(transferFeeToVaultIx);
299
+ const createStreamIx = await createCreateStreamInstruction(program, {
300
+ streamConfig,
301
+ feePayer,
302
+ receiver,
303
+ senderAta,
304
+ streamToken,
305
+ sender,
306
+ receiverAta,
307
+ streamMetadata: streamMetadataKeypair.publicKey,
308
+ streamVault,
309
+ streamVaultAta,
310
+ withdrawAccount: withdrawer,
311
+ }, {
312
+ autoTopupDelegate: Number(params.delegateAutoTopup),
313
+ initialBufferDuration: new BN(params.initialBufferDuration),
314
+ amount: new BN(amount),
315
+ automaticWithdrawal: Number(params.automaticWithdrawal),
316
+ cancelableByRecipient: Number(params.cancelableByRecipient),
317
+ cancelableBySender: Number(params.cancelableBySender),
318
+ canTopup: Number(params.canTopup),
319
+ cliffPercentage,
320
+ duration: new BN(params.duration),
321
+ isPausable: Number(params.isPausable),
322
+ rateUpdatable: Number(params.rateUpdatable),
323
+ startNow: Number(params.startNow),
324
+ startTime: new BN(params.startTime),
325
+ autoWithdrawFrequency: new BN(params.autoWithdrawFrequency),
326
+ streamName: Array.from(streamName),
327
+ transferableByRecipient: Number(params.transferableByRecipient),
328
+ transferableBySender: Number(params.transferableBySender),
329
+ receiverId: Array.from(params.receiverId),
330
+ senderId: Array.from(params.senderId),
331
+ });
332
+ ixs.push(createStreamIx);
333
+ return createPayload(program, feePayer, ixs, [streamMetadataKeypair]);
334
+ }
335
+ export async function cancelStream(program, params) {
336
+ const user = translateAddress(params.user);
337
+ const streamMetadata = translateAddress(params.streamMetadata);
338
+ const streamMetadataAccount = await program.account.paymentStream.fetch(streamMetadata);
339
+ const streamToken = streamMetadataAccount.financials.streamToken;
340
+ const streamer = streamMetadataAccount.parties.sender;
341
+ const receiver = streamMetadataAccount.parties.receiver;
342
+ let otherParty;
343
+ if (user.equals(streamer)) {
344
+ otherParty = receiver;
345
+ }
346
+ else if (user.equals(receiver)) {
347
+ otherParty = streamer;
348
+ }
349
+ else {
350
+ throw new Error("User must be either streamer or receiver");
351
+ }
352
+ const feePayer = params.feePayer ? translateAddress(params.feePayer) : user;
353
+ const userAta = getAssociatedTokenAddressSync(streamToken, user, true);
354
+ const otherPartyAta = getAssociatedTokenAddressSync(streamToken, otherParty, true);
355
+ const [streamVault] = deriveStreamVaultPda(streamMetadata, program.programId);
356
+ const streamVaultAta = getAssociatedTokenAddressSync(streamToken, streamVault, true);
357
+ const ix = await createCancelStreamInstruction(program, {
358
+ feePayer,
359
+ otherParty,
360
+ otherPartyAta,
361
+ signer: user,
362
+ signerAta: userAta,
363
+ streamMetadata,
364
+ streamToken,
365
+ streamVault,
366
+ streamVaultAta,
367
+ });
368
+ return createPayload(program, feePayer, [ix]);
369
+ }
370
+ export async function pauseResumeStream(program, params) {
371
+ const streamMetadata = translateAddress(params.streamMetadata);
372
+ const streamMetadataAccount = await program.account.paymentStream.fetch(streamMetadata);
373
+ const user = streamMetadataAccount.parties.sender;
374
+ const ix = await createPauseResumeStreamInstruction(program, {
375
+ streamMetadata,
376
+ user,
377
+ });
378
+ return createPayload(program, user, [ix]);
379
+ }
380
+ export async function withdrawStream(program, params) {
381
+ const [streamConfig] = deriveStreamConfigPda(params.streamConfigName, program.programId);
382
+ const receiver = translateAddress(params.receiver);
383
+ const withdrawer = params.withdrawer
384
+ ? translateAddress(params.withdrawer)
385
+ : receiver;
386
+ const feePayer = params.feePayer
387
+ ? translateAddress(params.feePayer)
388
+ : params.withdrawer
389
+ ? withdrawer
390
+ : receiver;
391
+ const streamMetadata = translateAddress(params.streamMetadata);
392
+ const streamMetadataAccount = await program.account.paymentStream.fetch(streamMetadata);
393
+ const streamToken = streamMetadataAccount.financials.streamToken;
394
+ const receiverAta = getAssociatedTokenAddressSync(streamToken, receiver, true);
395
+ const [streamVault] = deriveStreamVaultPda(streamMetadata, program.programId);
396
+ const streamVaultAta = getAssociatedTokenAddressSync(streamToken, streamVault, true);
397
+ const ix = await createWithdrawStreamInstruction(program, {
398
+ receiver,
399
+ receiverAta,
400
+ streamConfig,
401
+ streamMetadata,
402
+ streamToken,
403
+ streamVault,
404
+ streamVaultAta,
405
+ withdrawer,
406
+ feePayer,
407
+ });
408
+ return createPayload(program, withdrawer, [ix]);
409
+ }
410
+ export async function changeStreamReceiver(program, params) {
411
+ const streamMetadata = translateAddress(params.streamMetadata);
412
+ const newRecipient = translateAddress(params.newRecipient);
413
+ const signer = translateAddress(params.signer);
414
+ const ix = await createChangeRecipientInstruction(program, {
415
+ stream: streamMetadata,
416
+ newRecipient,
417
+ signer,
418
+ });
419
+ return createPayload(program, signer, [ix]);
420
+ }
421
+ export async function setTopupDelegate(program, params) {
422
+ const sender = translateAddress(params.sender);
423
+ const streamMetadata = translateAddress(params.streamMetadata);
424
+ const streamMetadataAccount = await program.account.paymentStream.fetch(streamMetadata);
425
+ const streamToken = streamMetadataAccount.financials.streamToken;
426
+ const senderAta = getAssociatedTokenAddressSync(streamToken, sender, true);
427
+ const [streamVault] = deriveStreamVaultPda(streamMetadata, program.programId);
428
+ const [streamConfig] = deriveStreamConfigPda(params.streamConfigName, program.programId);
429
+ const streamTokenDecimals = await getMintDecimals(program.provider.connection, streamToken);
430
+ const amount = new BN(BigNumber(params.amount)
431
+ .multipliedBy(BigNumber(10).pow(streamTokenDecimals))
432
+ .toFixed(0));
433
+ const ix = await createSetTopupDelegateInstruction(program, {
434
+ sender,
435
+ senderAta,
436
+ streamConfig,
437
+ streamMetadata,
438
+ streamToken,
439
+ streamVault,
440
+ }, {
441
+ amount,
442
+ });
443
+ return createPayload(program, sender, [ix]);
444
+ }
445
+ export async function topupStream(program, params) {
446
+ const sender = translateAddress(params.sender);
447
+ const streamMetadata = translateAddress(params.streamMetadata);
448
+ const caller = params.caller ? translateAddress(params.caller) : sender;
449
+ const streamMetadataAccount = await program.account.paymentStream.fetch(streamMetadata);
450
+ const streamToken = streamMetadataAccount.financials.streamToken;
451
+ const senderAta = getAssociatedTokenAddressSync(streamToken, sender, true);
452
+ const [streamVault] = deriveStreamVaultPda(streamMetadata, program.programId);
453
+ const [streamConfig] = deriveStreamConfigPda(params.streamConfigName, program.programId);
454
+ const streamTokenDecimals = await getMintDecimals(program.provider.connection, streamToken);
455
+ const amount = new BN(BigNumber(params.extra)
456
+ .multipliedBy(BigNumber(10).pow(streamTokenDecimals))
457
+ .toFixed(0));
458
+ const streamVaultAta = getAssociatedTokenAddressSync(streamToken, streamVault, true);
459
+ const ix = await createTopupStreamInstruction(program, {
460
+ caller,
461
+ sender,
462
+ senderAta,
463
+ streamConfig,
464
+ streamMetadata,
465
+ streamToken,
466
+ streamVault,
467
+ streamVaultAta,
468
+ }, {
469
+ extra: amount,
470
+ });
471
+ return createPayload(program, caller, [ix]);
472
+ }
@@ -0,0 +1,194 @@
1
+ import type { Address } from "@coral-xyz/anchor";
2
+ import type { Keypair, PublicKey } from "@solana/web3.js";
3
+ import type BN from "bn.js";
4
+ export type RpcNetwork = "mainnet-beta" | "devnet";
5
+ export type Numeric = string | number;
6
+ export type PayrollConfigInfo = {
7
+ configName: string;
8
+ address: PublicKey;
9
+ admin: PublicKey;
10
+ withdrawerAccount: PublicKey;
11
+ whitelistedTokens: PublicKey[];
12
+ platformFee: number;
13
+ baseFee: number;
14
+ frequencies: number[];
15
+ feeTiers: FeeTier[];
16
+ feeVault: PublicKey;
17
+ };
18
+ export type PayrollMetadataInfo = {
19
+ address: PublicKey;
20
+ parties: {
21
+ sender: PublicKey;
22
+ receiver: PublicKey;
23
+ };
24
+ financials: {
25
+ streamToken: PublicKey;
26
+ cliffPercentage: number;
27
+ depositedAmount: string;
28
+ withdrawnAmount: string;
29
+ };
30
+ schedule: {
31
+ startTime: number;
32
+ endTime: number;
33
+ lastWithdrawTime: number;
34
+ frequency: number;
35
+ duration: number;
36
+ pausedTimestamp: number;
37
+ pausedInterval: number;
38
+ canceledTimestamp: number;
39
+ };
40
+ permissions: {
41
+ cancelableBySender: boolean;
42
+ cancelableByRecipient: boolean;
43
+ automaticWithdrawal: boolean;
44
+ transferableBySender: boolean;
45
+ transferableByRecipient: boolean;
46
+ canTopup: boolean;
47
+ isPausable: boolean;
48
+ rateUpdatable: boolean;
49
+ };
50
+ topupState: {
51
+ coveredUntill: number;
52
+ initialBufferDuration: number;
53
+ topupCount: number;
54
+ };
55
+ streamName: string;
56
+ };
57
+ export type TokenMetadata = {
58
+ mint: PublicKey;
59
+ decimals: number;
60
+ freezeAuthority: PublicKey | null;
61
+ supply: string;
62
+ isInitialized: boolean;
63
+ mintAuthority: PublicKey | null;
64
+ metadata: {
65
+ address: PublicKey;
66
+ updateAuthority: PublicKey;
67
+ name: string;
68
+ symbol: string;
69
+ uri: string;
70
+ } | null;
71
+ };
72
+ export type CreateStreamParams = {
73
+ streamConfigName: string;
74
+ feePayer?: Address;
75
+ receiver: Address;
76
+ sender: Address;
77
+ streamToken: Address;
78
+ amount: Numeric;
79
+ automaticWithdrawal: boolean;
80
+ cancelableByRecipient: boolean;
81
+ cancelableBySender: boolean;
82
+ cliffPercentage: Numeric;
83
+ duration: number;
84
+ isPausable: boolean;
85
+ startNow: boolean;
86
+ startTime: number;
87
+ autoWithdrawFrequency: number;
88
+ streamName: string;
89
+ transferableByRecipient: boolean;
90
+ transferableBySender: boolean;
91
+ canTopup: boolean;
92
+ rateUpdatable: boolean;
93
+ delegateAutoTopup: boolean;
94
+ initialBufferDuration: number;
95
+ streamMetadataKeypair?: Keypair;
96
+ senderId: number[] | Uint8Array | Buffer;
97
+ receiverId: number[] | Uint8Array | Buffer;
98
+ };
99
+ export type InitializeStreamConfigParams = {
100
+ admin?: Address;
101
+ config: {
102
+ streamConfigName: string;
103
+ baseFeePercent: Numeric;
104
+ frequencies: number[];
105
+ platformFeePercent: Numeric;
106
+ withdrawAccount: Address;
107
+ feeTiers: FeeTier[];
108
+ feeVault: Address;
109
+ };
110
+ };
111
+ export type FeeTier = {
112
+ minThreshold: Numeric;
113
+ maxThreshold: Numeric;
114
+ feeRateInPercent: Numeric;
115
+ };
116
+ export type UpdateStreamConfigParams = {
117
+ admin?: Address;
118
+ config: {
119
+ streamConfigName: string;
120
+ baseFeePercent: Numeric;
121
+ frequencies: number[];
122
+ platformFeePercent: Numeric;
123
+ withdrawAccount: Address;
124
+ feeTiers: FeeTier[];
125
+ feeVault: Address;
126
+ };
127
+ };
128
+ export type CancelStreamParams = {
129
+ feePayer?: Address;
130
+ streamMetadata: Address;
131
+ user: Address;
132
+ };
133
+ export type PauseResumeStreamParams = {
134
+ streamMetadata: Address;
135
+ };
136
+ export type WithdrawStreamParams = {
137
+ streamConfigName: string;
138
+ streamMetadata: Address;
139
+ withdrawer?: Address;
140
+ feePayer?: Address;
141
+ receiver: Address;
142
+ };
143
+ export type WhiteListTokensParams = {
144
+ streamConfigName: string;
145
+ admin: Address;
146
+ tokens: Address[];
147
+ };
148
+ export type ChangeStreamReceiverParams = {
149
+ streamMetadata: Address;
150
+ newRecipient: Address;
151
+ signer: Address;
152
+ };
153
+ export type TopupStreamParams = {
154
+ streamConfigName: string;
155
+ caller?: Address;
156
+ sender: Address;
157
+ streamMetadata: Address;
158
+ extra: Numeric;
159
+ };
160
+ export type SetTopupDelegateParams = {
161
+ streamConfigName: string;
162
+ sender: Address;
163
+ streamMetadata: Address;
164
+ amount: Numeric;
165
+ };
166
+ export type StreamFeeInfo = {
167
+ tokenSymbol: string;
168
+ mintAddress: string;
169
+ chain: string;
170
+ streamAmount: string;
171
+ streamAmountUi: string;
172
+ tokenPriceUsd: number;
173
+ streamAmountUsd: number;
174
+ feeTier: {
175
+ tier: number;
176
+ range: string;
177
+ feeRatePercent: number;
178
+ };
179
+ feeRatePercent: number;
180
+ feeAmountUsd: number;
181
+ feeToken: {
182
+ symbol: string;
183
+ decimals: number;
184
+ priceUsd: number;
185
+ mintAddress: string;
186
+ };
187
+ feeAmount: number;
188
+ feeAmountRaw: string;
189
+ };
190
+ export type ParsedFeeTier = {
191
+ minAmount: BN;
192
+ maxAmount: BN;
193
+ fee: BN;
194
+ };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import type { Connection, PublicKey } from "@solana/web3.js";
2
+ import { BigNumber } from "bignumber.js";
3
+ import type { FeeTier, RpcNetwork, StreamFeeInfo } from "./types.js";
4
+ export declare function getFeeInfoForStream(streamToken: PublicKey, parsedStreamTokenAmount: BigNumber.Value, streamTokenDecimals: number, network: RpcNetwork): Promise<StreamFeeInfo>;
5
+ export declare function getFeeRateForUsdAmount(amount: BigNumber.Value, feeTiers: FeeTier[]): string;
6
+ export declare function getNetworkFromConnection(connection: Connection): RpcNetwork;
package/dist/utils.js ADDED
@@ -0,0 +1,41 @@
1
+ import { percentToBps } from "@zebec-network/core-utils";
2
+ import { BigNumber } from "bignumber.js";
3
+ import { SUPERAPP_BACKEND_URL } from "./constants.js";
4
+ export async function getFeeInfoForStream(streamToken, parsedStreamTokenAmount, streamTokenDecimals, network) {
5
+ const urlsParams = new URLSearchParams({
6
+ mintAddress: streamToken.toBase58(),
7
+ chain: "SOLANA",
8
+ amount: BigNumber(parsedStreamTokenAmount).toFixed(0),
9
+ decimals: streamTokenDecimals.toString(),
10
+ });
11
+ const url = `${SUPERAPP_BACKEND_URL[network]}/l1-stream/fees/stream-quote?${urlsParams}`;
12
+ const response = await fetch(url);
13
+ if (!response.ok) {
14
+ const body = await response.json().catch(() => null);
15
+ if (body && "message" in body) {
16
+ throw new Error(`Failed to fetch fee token amount: ${body.message}`);
17
+ }
18
+ throw new Error(`Failed to fetch fee token amount: ${response.status} ${response.statusText} ${body}`.trim());
19
+ }
20
+ const data = await response.json();
21
+ return data;
22
+ }
23
+ export function getFeeRateForUsdAmount(amount, feeTiers) {
24
+ feeTiers.sort((a, b) => BigNumber(a.minThreshold).comparedTo(BigNumber(b.minThreshold)) ?? 0);
25
+ const tier = feeTiers.find((tier) => BigNumber(amount).gte(tier.minThreshold) &&
26
+ BigNumber(amount).lt(tier.maxThreshold));
27
+ if (!tier) {
28
+ throw new Error(`No fee tier found for amount: ${amount}`);
29
+ }
30
+ return percentToBps(tier.feeRateInPercent);
31
+ }
32
+ export function getNetworkFromConnection(connection) {
33
+ const rpcEndpoint = connection.rpcEndpoint;
34
+ if (rpcEndpoint.includes("devnet")) {
35
+ return "devnet";
36
+ }
37
+ if (rpcEndpoint.includes("testnet")) {
38
+ throw new Error("Testnet is not supported");
39
+ }
40
+ return "mainnet-beta";
41
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "author": "Zebec Network",
3
+ "dependencies": {
4
+ "@coral-xyz/anchor": "^0.31.1",
5
+ "@metaplex-foundation/mpl-token-metadata": "^3.4.0",
6
+ "@metaplex-foundation/umi": "^1.5.1",
7
+ "@metaplex-foundation/umi-bundle-defaults": "^1.5.1",
8
+ "@metaplex-foundation/umi-web3js-adapters": "^1.5.1",
9
+ "@solana/spl-token": "^0.4.14",
10
+ "@solana/web3.js": "^1.98.2",
11
+ "@zebec-network/core-utils": "^1.1.1",
12
+ "@zebec-network/solana-common": "^2.3.1",
13
+ "@zebec-network/zebec_payroll": "^1.1.0",
14
+ "bignumber.js": "^11.0.0"
15
+ },
16
+ "devDependencies": {
17
+ "@types/bn.js": "^5.2.0",
18
+ "@types/mocha": "^10.0.10",
19
+ "@types/node": "^25.6.0",
20
+ "dotenv": "^17.4.2",
21
+ "mocha": "^11.7.5",
22
+ "rimraf": "^6.1.3",
23
+ "ts-mocha": "^11.1.0",
24
+ "ts-node": "^10.9.2",
25
+ "typescript": "^6.0.3"
26
+ },
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "license": "MIT",
31
+ "main": "dist/index.js",
32
+ "name": "@zebec-network/solana-payroll-sdk",
33
+ "private": false,
34
+ "scripts": {
35
+ "build": "npm run clean && tsc",
36
+ "clean": "rimraf ./dist",
37
+ "format": "npx @biomejs/biome format --write",
38
+ "prepare": "npm run build",
39
+ "test": "ts-mocha -p ./tsconfig.json -t 1000000000 test/**/*.test.ts",
40
+ "test:single": "ts-mocha -p ./tsconfig.json -t 1000000000"
41
+ },
42
+ "type": "module",
43
+ "types": "dist/index.d.ts",
44
+ "version": "1.0.0-dev.1"
45
+ }