npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zebec-network/zebec-vault-sdk

v5.2.4

Published

An SDK for zebec vault solana program

Readme

Introduction

A Typescript SDK for interacting with Zebec Vault on Solana, enabling secure multi operations, token streaming, staking, and virtual card management.

Features

  • Vault Management: Create and manage secure vaults with proposal-based execution
  • Token Operations: Deposit and withdraw SOL and SPL tokens
  • Streaming Payments: Create, manage, and cancel payment streams
  • Staking: Stake tokens with customizable lock periods
  • Virtual Cards: Create and load Zebec cards with automatic token swapping
  • Jupiter Integration: Built-in token swapping for card operations

Installation

npm install @zebec-network/zebec-vault-sdk
yarn add @zebec-network/zebec-vault-sdk

Quick Start

Setup

import { Connection, Keypair } from "@solana/web3.js";
import { createAnchorProvider, ZebecVaultService } from "@zebec-network/zebec-vault-sdk";

// Create connection
const connection = new Connection("https://api.mainnet-beta.solana.com"); // use a private dedicated RPC for production

// Create wallet adapter
// For a frontend application, use the wallet provided by the wallet adapter:
const wallet = useAnchorWallet();

// For a server-side app, use the Wallet class from @coral-xyz/anchor:
const wallet = new Wallet(keypair); // create keypair from secret key

// Create provider
const provider = createAnchorProvider(connection, wallet);

// Initialize service
const vaultService = ZebecVaultService.create(provider, "mainnet-beta");

Core Features

Vault Operations

Each user has a vault that is derived from a seed containing the user's wallet. A vault signer is then derived from the vault as a seed. The vault signer holds SPL token and SOL balances and signs transactions during CPI executions.

Create a vault

const payload = await vaultService.createVault({
  payer: wallet.publicKey, // optional if using AnchorProvider
});

const signature = await payload.execute();
console.log("Vault created:", signature);

Get Vault Information

// Get a specific user's vault (param is optional when using AnchorProvider)
const vaultInfo = await vaultService.getVaultInfoOfUser(userAddress);

if (vaultInfo) {
  console.log("Vault:", vaultInfo.vault.toString());
  console.log("Owner:", vaultInfo.owner.toString());
  console.log("Created:", new Date(vaultInfo.createdDate * 1000));
}

// Get all vaults
const allVaults = await vaultService.getAllVaultsInfo();
console.log(`Total vaults: ${allVaults.length}`);

Deposit SOL

const payload = await vaultService.depositSol({
  depositor: wallet.publicKey,
  amount: 1.5, // SOL amount
});

const signature = await payload.execute();

Deposit SPL Tokens

const payload = await vaultService.deposit({
  depositor: wallet.publicKey,
  tokenMint: "TOKEN_MINT_ADDRESS",
  amount: 100, // token amount
});

const signature = await payload.execute();

Note: If the WSOL address is given as tokenMint, SOL will be wrapped to WSOL and deposited as an SPL token.

Withdraw SOL

const payload = await vaultService.withdrawSol({
  withdrawer: wallet.publicKey,
  amount: 0.5,
});

const signature = await payload.execute();

Withdraw SPL Tokens

const payload = await vaultService.withdraw({
  withdrawer: wallet.publicKey,
  tokenMint: "TOKEN_MINT_ADDRESS",
  amount: 50,
});

const signature = await payload.execute();

Note: If the WSOL address is given as tokenMint, WSOL will be withdrawn and unwrapped into the withdrawer's wallet.

Proposal System

The Proposal System includes methods for creating proposals, appending actions, and executing proposals. A proposal is like a Solana transaction but with extra fields such as proposal stage, created date, expiry date, execution status, and name. Each proposal contains one or more ProposalAction, which is similar to a TransactionInstruction in Solana. During execution, proposal actions run in order. You can delete a proposal to reclaim the SOL rent used to create it. Each proposal belongs to a vault and only the vault signer can execute, delete, or append actions to it.

Create a Proposal

import { SystemProgram } from "@solana/web3.js";
import { parseSol } from "@zebec-network/solana-common";
import { deriveUserVault, deriveVaultSigner } from "@zebec-network/zebec-vault-sdk";

const [vault] = deriveUserVault(wallet.publicKey, vaultService.vaultV1ProgramId);
const [vaultSigner] = deriveVaultSigner(vault, vaultService.vaultV1ProgramId);
const recipient = "<Recipient PublicKey>";

// Create custom instructions. For example:
const instruction = SystemProgram.transfer({
  fromPubkey: vaultSigner,
  toPubkey: recipient,
  lamports: Number(parseSol(1)),
});

const payload = await vaultService.createProposal({
  proposer: wallet.publicKey,
  name: "Transfer SOL",
  actions: [instruction],
  // proposalKeypair: Keypair.generate(), // optional; auto-generated if omitted
});

const signature = await payload.execute();

Get Proposals

const proposals = await vaultService.getProposalsInfoOfVault(vaultAddress);

proposals.forEach((proposal) => {
  console.log("Proposal:", proposal.name);
  console.log("Status:", proposal.proposalStage);
  console.log("Actions:", proposal.actions.length);
  console.log("Executed:", proposal.isExecuted);
});

Append Actions

import { SystemProgram } from "@solana/web3.js";
import { parseSol } from "@zebec-network/solana-common";

const proposal = "<Proposal PublicKey>";

const instruction = SystemProgram.transfer({
  fromPubkey: vaultSigner,
  toPubkey: wallet.publicKey,
  lamports: Number(parseSol(0.01)),
});

const payload = await vaultService.appendActions({
  proposal,
  actions: [instruction],
});

const signature = await payload.execute();

Delete Proposal

const proposal = "<Proposal PublicKey>";
const payload = await vaultService.deleteProposal({ proposal });
const deleteProposalSignature = await payload.execute();

Execute a Proposal

const proposal = "<Proposal PublicKey>";
const lookupTableAddress = "<Lookup Table Address PublicKey>";

const payload = await vaultService.executeProposal({
  caller: wallet.publicKey,
  proposal,
  addressLookupTables: [lookupTableAddress], // optional
});

const signature = await payload.execute();

Execute Proposal Directly (Single Transaction)

Proposal actions can be executed directly without creating a persistent proposal. However, this may hit the transaction size limit; some cases can be mitigated using address lookup tables.

import { SystemProgram, TransactionInstruction } from "@solana/web3.js";
import { parseSol } from "@zebec-network/solana-common";
import { deriveUserVault, deriveVaultSigner } from "@zebec-network/zebec-vault-sdk";

const [vault] = deriveUserVault(wallet.publicKey, vaultService.vaultV1ProgramId);
const [vaultSigner] = deriveVaultSigner(vault, vaultService.vaultV1ProgramId);
const recipient = "<Recipient PublicKey>";

const instruction1 = SystemProgram.transfer({
  fromPubkey: vaultSigner,
  toPubkey: recipient,
  lamports: Number(parseSol(1)),
});

const instruction2 = new TransactionInstruction({
  keys: [],
  programId: MEMO_PROGRAM_ID,
  data: Buffer.from("Transfer 1 sol from vault signer to recipient", "utf8"),
});

const payload = await vaultService.executeProposalDirect({
  proposer: wallet.publicKey,
  actions: [instruction1, instruction2],
  addressLookupTables: [lookupTableAddress],
});

const signature = await payload.execute();

Payment Streaming

Create a Stream

const payload = await vaultService.createStreamFromVault({
  vaultOwner: wallet.publicKey,
  receiver: recipientAddress,
  streamToken: tokenMintAddress,
  streamConfigName: "Config-001", // name of the stream configuration to use
  amount: 1000, // total amount
  duration: 2592000, // 30 days in seconds
  startNow: true,
  startTime: Math.floor(Date.now() / 1000),
  automaticWithdrawal: false,
  cancelableByRecipient: true,
  cancelableBySender: true,
  isPausable: true,
  transferableByRecipient: false,
  transferableBySender: false,
  canTopup: true,
  rateUpdatable: false,
  cliffPercentage: 0, // 0-100
  autoWithdrawFrequency: 86400, // 1 day in seconds; required when automaticWithdrawal is true
  streamName: "Monthly Payment",
});

const signature = await payload.execute();

Create Multiple Streams

There is a difference in the payload returned for creating multiple streams. While other payloads are instances of TransactionPayload, the payload returned for multiple streams is an instance of MultiTransactionPayload. After calling execute(), it returns MultiTransactionPayloadExecuteReturn, which is an array of settled promise results — each containing either a transaction signature on success or a failure reason.

export type MultiTransactionPayloadExecuteReturn = (PromiseSettledResult<string> & {
  transactionData: {
    readonly instructions: web3.TransactionInstruction[];
    readonly feePayer: web3.PublicKey;
    readonly signers?: web3.Signer[];
    readonly addressLookupTableAccounts?: web3.AddressLookupTableAccount[];
  };
  transaction: web3.VersionedTransaction;
})[];
const payload = await vaultService.createMultipleStreamFromVault({
  vaultOwner: wallet.publicKey,
  streamConfigName: "Config-001", // applies to all streams
  streamInfo: [
    {
      receiver: recipient1,
      streamToken: tokenMint,
      amount: 500,
      duration: 2592000,
      startNow: false,
      startTime: Math.floor(Date.now() / 1000) + 30,
      automaticWithdrawal: false,
      cancelableByRecipient: false,
      cancelableBySender: false,
      isPausable: false,
      transferableByRecipient: false,
      transferableBySender: false,
      canTopup: false,
      rateUpdatable: false,
      cliffPercentage: 0,
      streamName: "Stream 1",
    },
    {
      receiver: recipient2,
      streamToken: tokenMint,
      amount: 1000,
      duration: 2592000,
      startNow: false,
      startTime: Math.floor(Date.now() / 1000) + 30,
      automaticWithdrawal: false,
      cancelableByRecipient: false,
      cancelableBySender: false,
      isPausable: false,
      transferableByRecipient: false,
      transferableBySender: false,
      canTopup: false,
      rateUpdatable: false,
      cliffPercentage: 0,
      streamName: "Stream 2",
    },
  ],
});

// Execute all streams in separate transactions
const results = await payload.execute();

Pause/Resume a Stream

const payload = await vaultService.pauseResumeStream({
  vaultOwner: wallet.publicKey,
  streamMetadata: streamAddress,
});

const signature = await payload.execute();

Cancel a Stream

const payload = await vaultService.cancelStream({
  vaultOwner: wallet.publicKey,
  streamMetadata: streamAddress,
});

await payload.execute();

Withdraw from Stream

const payload = await vaultService.withdrawStream({
  vaultOwner: wallet.publicKey,
  streamMetadata: streamAddress,
});

await payload.execute();

Change Stream Receiver

const payload = await vaultService.changeStreamReceiver({
  vaultOwner: wallet.publicKey,
  streamMetadata: streamAddress,
  newRecipient: newRecipientAddress,
});

await payload.execute();

Get Stream Information

const streamInfo = await vaultService.getStreamMetadataInfo(streamAddress);

console.log("Stream details:", {
  sender: streamInfo.parties.sender,
  receiver: streamInfo.parties.receiver,
  token: streamInfo.financials.streamToken,
  deposited: streamInfo.financials.depositedAmount,
  withdrawn: streamInfo.financials.withdrawnAmount,
  startTime: new Date(streamInfo.schedule.startTime * 1000),
  endTime: new Date(streamInfo.schedule.endTime * 1000),
  isPaused: streamInfo.schedule.pausedTimestamp > 0,
});

Staking

Stake Tokens

const payload = await vaultService.stake({
  lockupName: "main-lockup",
  vaultOwner: wallet.publicKey,
  amount: 1000,
  lockPeriod: 7776000, // 90 days in seconds; must be one of the lockup's valid periods
  nonce: 0n,
});

await payload.execute();

Unstake Tokens

const payload = await vaultService.unstake({
  lockupName: "main-lockup",
  vaultOwner: wallet.publicKey,
  nonce: 0n,
});

await payload.execute();

Get Stake Nonce Information

const nonceInfo = await vaultService.getStakeUserNonceInfo("main-lockup", wallet.publicKey);

console.log("Current nonce:", nonceInfo ? nonceInfo.nonce : 0n);

Zebec Cards

Create a Silver Card

const nextIndex = await vaultService.getNextCardIndex();

const payload = await vaultService.createSilverCard({
  vaultOwnerAddress: wallet.publicKey,
  nextCardIndex: nextIndex,
  amount: 100, // USDC amount
  usdcAddress: USDC_MINT_ADDRESS,
  emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
  currency: "USD",
});

await payload.execute();

Load a Carbon Card

const nextIndex = await vaultService.getNextCardIndex();

const payload = await vaultService.loadCarbonCard({
  vaultOwnerAddress: wallet.publicKey,
  nextCardIndex: nextIndex,
  amount: 50,
  usdcAddress: USDC_MINT_ADDRESS,
  emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
  currency: "USD",
  reloadCardId: "CARD_ID",
});

await payload.execute();

Swap and Create Silver Card

// First, get a Jupiter quote
const quoteParams = new URLSearchParams({
  inputMint: inputMint,
  outputMint: USDC_MINT_ADDRESS,
  amount: parsedAmount, // in smallest units
  slippageBps: "50",
  swapMode: "ExactIn",
});
const quoteResponse = await fetch(
  `https://lite-api.jup.ag/swap/v1/quote?${quoteParams}`,
);
const quoteInfo = await quoteResponse.json();

const nextIndex = await vaultService.getNextCardIndex();

const payload = await vaultService.swapAndCreateSilverCard({
  vaultOwnerAddress: wallet.publicKey,
  quoteInfo: quoteInfo,
  nextCardCounter: nextIndex,
  emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
  currency: "USD",
  wrapAndUnwrapSol: true, // set to true when swapping SOL
});

await payload.execute();

Swap and Load Carbon Card

const payload = await vaultService.swapAndLoadCarbonCard({
  vaultOwnerAddress: wallet.publicKey,
  quoteInfo: quoteInfo,
  nextCardCounter: nextIndex,
  emailHash: Buffer.from("your-32-byte-hash"), // must be exactly 32 bytes
  currency: "USD",
  reloadCardId: "CARD_ID",
  wrapAndUnwrapSol: true,
});

await payload.execute();

Get Card Custom Token Fees

const tokenFees = await vaultService.getCardCustomTokenFees();

tokenFees.forEach((fee) => {
  console.log(`Token: ${fee.tokenAddress}, Fee: ${fee.fee}%`);
});

Read-only Provider

For read-only operations without a wallet:

import { createReadonlyProvider } from "@zebec-network/zebec-vault-sdk";

const readonlyProvider = createReadonlyProvider(connection, optionalWalletAddress);

const service = ZebecVaultService.create(readonlyProvider, "mainnet-beta");

// Can only call query methods
const vaultInfo = await service.getVaultInfoOfUser(someAddress);

Advanced Features

Program Derived Addresses (PDAs)

import {
  deriveUserVault,
  deriveVaultSigner,
} from "@zebec-network/zebec-vault-sdk";

const [vaultAddress, vaultBump] = deriveUserVault(userAddress, vaultProgramId);

const [signerAddress, signerBump] = deriveVaultSigner(vaultAddress, vaultProgramId);

Transaction Utilities

import { calculateProposalSize, transactionInstructionToProposalAction } from "@zebec-network/zebec-vault-sdk";

// Calculate proposal size (in bytes)
const size = calculateProposalSize("proposal-name", actions);

// Convert a TransactionInstruction to a ProposalAction
const action = transactionInstructionToProposalAction(instruction);

Network Configuration

// Mainnet
const mainnetService = ZebecVaultService.create(provider, "mainnet-beta");

// Devnet
const devnetService = ZebecVaultService.create(provider, "devnet");

Constants

import {
  ZEBEC_VAULT_PROGRAM_ID,
  JUPITER_AGGREGATOR_PROGRAM_ID,
  CARD_LOOKUP_TABLE_ADDRESS,
  STAKE_LOOKUP_TABLE_ADDRESS,
} from "@zebec-network/zebec-vault-sdk";

console.log("Vault Program:", ZEBEC_VAULT_PROGRAM_ID["mainnet-beta"]);

Error Types

The SDK throws typed errors you can catch and inspect:

import {
  AmountOutOfRangeError,
  DailyCardLimitReachedError,
  InvalidUsdcAddressError,
  NotEnoughBalanceError,
  QuoteResponseError,
  AssociatedTokenAccountDoesNotExistsError,
} from "@zebec-network/zebec-vault-sdk";

try {
  await payload.execute();
} catch (err) {
  if (err instanceof AmountOutOfRangeError) {
    console.error(`Amount must be between ${err.minRange} and ${err.maxRange}`);
  } else if (err instanceof DailyCardLimitReachedError) {
    console.error(`Daily limit: ${err.dailyCardLimit}, requested: ${err.requestedAmount}`);
  } else if (err instanceof NotEnoughBalanceError) {
    console.error("Insufficient balance");
  } else if (err instanceof AssociatedTokenAccountDoesNotExistsError) {
    console.error("Token account does not exist");
  }
}

Types

The SDK exports comprehensive TypeScript types:

import type {
  VaultInfo,
  ProposalInfo,
  ProposalAction,
  ProposalStage,
  CreateStreamFromVaultParams,
  createMultipleStreamFromVaultParams,
  StreamMetadataInfo,
  TokenFeeRecord,
  QuoteInfo,
  RouteInfo,
  StakeUserNonceInfo,
  CreateSilverCardParams,
  LoadCarbonCardParams,
  SwapAndCreateSilverCardParams,
  SwapAndLoadCarbonCardParams,
  CancelStreamParams,
  PauseResumeStreamParams,
  ChangeStreamReceiverParams,
  WithdrawStreamParams,
  ParsedCardConfigInfo,
  WhitelistInfo,
  Numeric,
} from "@zebec-network/zebec-vault-sdk";

Best Practices

  1. Always check balances before operations
  2. Use proposals for critical operations that require multiple instructions and cannot be executed in a single transaction
  3. Handle errors appropriately with the provided error types
  4. Verify stream parameters before creation (duration, amounts, permissions)
  5. Test on devnet before deploying to mainnet
  6. Use address lookup tables for complex transactions to reduce transaction size
  7. Use a private dedicated RPC for production workloads