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

shadowlend-sdk

v1.0.1

Published

TypeScript SDK for ShadowLend - Privacy-preserving lending protocol on Solana

Readme

ShadowLend SDK

TypeScript SDK for interacting with the ShadowLend privacy-preserving lending protocol on Solana

npm version License: MIT

Features

  • Privacy-First: Generate ZK proofs client-side to keep your financial data private
  • Full Protocol Support: Deposit, borrow, repay, withdraw, and liquidate
  • Merkle Tree Management: Built-in incremental Merkle tree for commitment tracking
  • Type-Safe: Full TypeScript support with comprehensive type definitions
  • Flexible: Works with any Solana wallet adapter

Installation

npm install shadowlend-sdk
# or
yarn add shadowlend-sdk
# or
pnpm add shadowlend-sdk

Quick Start

import { createShadowLendDevnet, Asset, BN } from 'shadowlend-sdk';

async function main() {
  // Create SDK instance for devnet
  const shadowlend = createShadowLendDevnet();

  // Initialize (loads Poseidon, Merkle tree, ZK circuits)
  await shadowlend.initialize();

  // Connect your wallet
  shadowlend.connect(wallet);

  // Deposit 1 SOL as collateral
  const deposit = await shadowlend.depositCollateral(
    Asset.SOL,
    new BN(1_000_000_000) // 1 SOL in lamports
  );

  // Sign and send transaction
  const signature = await shadowlend.sendTransaction(deposit.transaction);

  console.log('Deposit successful:', signature);
  console.log('Commitment:', deposit.commitment);

  // IMPORTANT: Save these - needed for withdrawal!
  console.log('Secret:', deposit.secret);
  console.log('Leaf Index:', deposit.leafIndex);
}

API Reference

Creating an Instance

import {
  ShadowLend,
  createShadowLend,
  createShadowLendDevnet,
  createShadowLendMainnet
} from 'shadowlend-sdk';
import { Connection } from '@solana/web3.js';

// Option 1: Quick setup for devnet
const sdk = createShadowLendDevnet();

// Option 2: Quick setup for mainnet
const sdk = createShadowLendMainnet();

// Option 3: Custom configuration
const connection = new Connection('https://api.devnet.solana.com');
const sdk = createShadowLend(connection, {
  programId: new PublicKey('BzabuYsVF1mkW2oEiAb7gyG8euJWkr4zZjsgRDZNSdGG'),
  merkleTreeDepth: 20,
  minCollateralRatio: 150,
  liquidationThreshold: 125,
});

// Always initialize before use
await sdk.initialize();

Wallet Connection

// Connect wallet (compatible with @solana/wallet-adapter)
sdk.connect(wallet);

// Get connected wallet
const wallet = sdk.getWallet();

// Disconnect
sdk.disconnect();

Depositing Collateral

import { Asset, BN } from 'shadowlend-sdk';

// Deposit SOL
const deposit = await sdk.depositCollateral(
  Asset.SOL,
  new BN(5_000_000_000) // 5 SOL
);

// Transaction ready to sign
const signature = await sdk.sendTransaction(deposit.transaction);

// Save these for later operations!
const { commitment, secret, nullifierHash, leafIndex } = deposit;

What happens under the hood:

  1. Generates random secret and nullifier
  2. Computes commitment = Poseidon(nullifier, amount)
  3. Inserts commitment into local Merkle tree
  4. Builds transaction with encrypted amount

Borrowing Against Collateral

// Borrow USDC against your deposited collateral
const borrow = await sdk.borrow(
  Asset.USDC,
  new BN(500_000_000), // 500 USDC (6 decimals)
  deposit.commitment,
  {
    secret: deposit.secret,
    nullifier: deposit.nullifierHash,
    collateralAmount: BigInt(5_000_000_000), // 5 SOL
    collateralAsset: Asset.SOL,
  }
);

const signature = await sdk.sendTransaction(borrow.transaction);

console.log('Position ID:', borrow.positionId);
console.log('Interest Rate:', borrow.interestRate);

ZK Proof Generation: The SDK automatically generates a Groth16 proof that verifies:

  • You own the collateral (know the secret)
  • Collateral is in the Merkle tree
  • collateralValue * LTV >= loanAmount

Without revealing the actual collateral amount!

Repaying a Loan

const repay = await sdk.repay(
  new BN(250_000_000), // Repay 250 USDC
  borrow.positionId
);

const signature = await sdk.sendTransaction(repay.transaction);

console.log('Remaining Debt:', repay.remainingDebt.toString());
console.log('Interest Paid:', repay.interestPaid.toString());

Withdrawing Collateral

// After repaying your loan, withdraw collateral
const withdraw = await sdk.generateAndWithdraw({
  commitment: deposit.commitment,
  secret: deposit.secret,
  nullifier: deposit.nullifierHash,
  amount: BigInt(5_000_000_000), // Full amount
  recipientAddress: wallet.publicKey,
});

const signature = await sdk.sendTransaction(withdraw.transaction);

console.log('Withdrawn:', withdraw.withdrawnAmount.toString());

Checking Health Factor

const health = await sdk.getHealthFactor(deposit.commitment);

console.log('Health Factor:', health.healthFactor);
console.log('Collateral Value:', health.collateralValue.toString());
console.log('Debt Value:', health.debtValue.toString());
console.log('Liquidation Price:', health.liquidationPrice.toString());
console.log('Is Liquidatable:', health.isLiquidatable);

Getting Pool State

const poolState = await sdk.getPoolState(Asset.SOL);

console.log('Total Deposits:', poolState.totalDeposits.toString());
console.log('Total Borrows:', poolState.totalBorrows.toString());
console.log('Utilization:', poolState.utilizationRate);
console.log('Supply APY:', poolState.supplyAPY);
console.log('Borrow APY:', poolState.borrowAPY);

Getting Asset Prices

const price = await sdk.getAssetPrice(Asset.SOL);

console.log('Price:', price.price.toString());
console.log('Confidence:', price.confidence.toString());
console.log('Source:', price.source);

Merkle Tree Operations

// Get current Merkle root
const root = sdk.getMerkleRoot();

// Get proof for a commitment
const proof = await sdk.getMerkleProof(commitment);
console.log('Path Elements:', proof.pathElements);
console.log('Path Indices:', proof.pathIndices);

// Restore commitments after page reload
await sdk.restoreCommitments([commitment1, commitment2]);

// Check if commitment exists
const exists = sdk.hasCommitment(commitment);

Types

Supported Assets

enum Asset {
  SOL = 'SOL',
  USDC = 'USDC',
  USDT = 'USDT',
  mSOL = 'mSOL',
  stSOL = 'stSOL',
  ETH = 'ETH',
  BTC = 'BTC',
}

Position Interface

interface Position {
  commitment: string;
  collateralAsset: Asset;
  collateralAmount: BN;
  borrowedAsset: Asset;
  borrowedAmount: BN;
  interestAccrued: BN;
  healthFactor: number;
  status: LoanStatus;
  createdAt: number;
  lastUpdated: number;
}

Loan Status

enum LoanStatus {
  Active = 'Active',
  Repaid = 'Repaid',
  Liquidated = 'Liquidated',
}

Cryptographic Utilities

The SDK exports cryptographic utilities for advanced use cases:

import {
  initPoseidon,
  poseidonHash,
  generateSecret,
  generateNullifier,
  computeCommitment,
  computeNullifierHash,
  encryptNote,
  decryptNote,
} from 'shadowlend-sdk';

// Initialize Poseidon (required before hashing)
await initPoseidon();

// Generate cryptographic secrets
const secret = generateSecret();
const nullifier = generateNullifier();

// Compute commitment
const commitment = await computeCommitment(
  secret,
  nullifier,
  BigInt(1_000_000_000), // amount
  0 // asset ID
);

// Hash arbitrary inputs
const hash = await poseidonHash([BigInt(123), BigInt(456)]);

ZK Prover

Generate proofs manually for advanced use cases:

import { ZKProver, createProver } from 'shadowlend-sdk';

const prover = createProver();

// Preload circuits for faster proof generation
await prover.preloadCircuits();

// Generate collateral proof
const proof = await prover.generateCollateralProof(
  secret,
  nullifier,
  collateralAmount,
  minCollateralRequired,
  oraclePrice,
  merkleProof,
  leafIndex
);

// Export for Solana transaction
const solanaProof = prover.exportProofForSolana(proof.proof);

Constants

import {
  SHADOWLEND_PROGRAM_ID,
  MERKLE_TREE_DEPTH,
  MIN_COLLATERAL_RATIO,
  LIQUIDATION_THRESHOLD,
  TOKEN_MINTS,
  TOKEN_DECIMALS,
  PYTH_ORACLES,
} from 'shadowlend-sdk';

// Program ID
console.log(SHADOWLEND_PROGRAM_ID.toBase58());
// BzabuYsVF1mkW2oEiAb7gyG8euJWkr4zZjsgRDZNSdGG

// Merkle tree supports 2^20 = 1,048,576 deposits
console.log(MERKLE_TREE_DEPTH); // 20

// Risk parameters
console.log(MIN_COLLATERAL_RATIO);    // 150 (150%)
console.log(LIQUIDATION_THRESHOLD);   // 125 (125%)

// Token mints (devnet)
console.log(TOKEN_MINTS[Asset.SOL].toBase58());
console.log(TOKEN_MINTS[Asset.USDC].toBase58());

Error Handling

try {
  await sdk.depositCollateral(Asset.SOL, new BN(100));
} catch (error) {
  if (error.message.includes('not initialized')) {
    await sdk.initialize();
    // Retry
  } else if (error.message.includes('Wallet not connected')) {
    // Prompt user to connect wallet
  } else if (error.message.includes('insufficient funds')) {
    // User doesn't have enough SOL
  }
}

Session Recovery

After page reload, restore your local state:

// Save to localStorage after deposit
localStorage.setItem('shadowlend_positions', JSON.stringify([{
  commitment: deposit.commitment,
  secret: deposit.secret,
  nullifier: deposit.nullifierHash,
  leafIndex: deposit.leafIndex,
  amount: '5000000000',
  asset: 'SOL',
}]));

// Restore on page load
const saved = JSON.parse(localStorage.getItem('shadowlend_positions') || '[]');
const commitments = saved.map(p => p.commitment);
await sdk.restoreCommitments(commitments);

Advanced: Direct Transaction Building

For advanced integrations, you can use lower-level methods:

// Get PDAs
const programId = sdk.getProgramId();
const connection = sdk.getConnection();

// Get supported assets
const assets = sdk.getSupportedAssets();
const solConfig = sdk.getAssetConfig(Asset.SOL);

// Sync with on-chain state
await sdk.syncMerkleTree();
const onChainRoot = await sdk.getOnChainMerkleRoot();

Security Considerations

Secret Management

CRITICAL: The secret returned from depositCollateral() is required to withdraw your funds. If lost, your collateral is permanently locked.

Recommendations:

  • Store secrets securely (encrypted local storage, hardware wallet derivation)
  • Never expose secrets in logs or error messages
  • Consider implementing secret recovery mechanisms

Transaction Simulation

Always simulate transactions before sending in production:

const signature = await sdk.sendTransaction(tx, {
  skipPreflight: false, // Enable simulation
  commitment: 'confirmed',
  maxRetries: 3,
});

Devnet vs Mainnet

The SDK uses fallback prices on devnet when oracles aren't available. In production:

  • Ensure Pyth oracles are properly configured
  • Monitor price staleness
  • Implement circuit breakers for extreme price movements

Building from Source

# Clone repository
git clone https://github.com/kamalbuilds/shadowlend
cd shadowlend/sdk

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Lint
npm run lint

# Format
npm run format

Requirements

  • Node.js >= 18.0.0
  • npm >= 8.0.0

Dependencies

| Package | Version | Purpose | |---------|---------|---------| | @coral-xyz/anchor | ^0.29.0 | Solana program interaction | | @solana/web3.js | ^1.91.0 | Solana blockchain connection | | @solana/spl-token | ^0.4.14 | SPL token operations | | snarkjs | ^0.7.3 | ZK proof generation | | circomlibjs | ^0.1.7 | Poseidon hashing | | ffjavascript | ^0.3.0 | Finite field arithmetic |

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Push to branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

MIT License - see LICENSE for details.

Links


Built for the Solana Privacy Hackathon 2026