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

@aspan/sdk

v0.5.3

Published

TypeScript SDK for Aspan Protocol - LST-backed stablecoin on BNB Chain

Readme

@aspan/sdk

TypeScript SDK for Aspan Protocol - LST-backed stablecoin on BNB Chain.

Installation

npm install @aspan/sdk
# or
pnpm add @aspan/sdk

Contract Addresses (BSC Mainnet)

import { BSC_ADDRESSES } from "@aspan/sdk";

// Or use directly:
// BSC_ADDRESSES.diamond, BSC_ADDRESSES.router, etc.

| Contract | Address | |----------|---------| | Diamond (Main Entry) | 0x6a11B30d3a70727d5477D6d8090e144443fA1c78 | | Router | 0xb8a90CD2811d6DDbB4B7969d30B036574842cb6E | | ApUSD | 0x4570047eeB5aDb4081c5d470494EB5134e34A287 | | XBNB | 0x0A0c9CD826e747D99F90D63e780B3727Da4D0d43 | | SApUSD | 0xE2BE739C4aA4126ee72D612d9548C38B1B0e5A1b | | wclisBNB | 0xb2A0631bF0aC326fEefc201E7337E13C63Bbed07 |

Quick Start

Read-Only Client (Query Data)

import { createAspanReadClient, formatAmount, formatCR, BSC_ADDRESSES } from "@aspan/sdk";

const client = createAspanReadClient(BSC_ADDRESSES.diamond, "https://bsc-dataseed.binance.org/");

const stats = await client.getProtocolStats();
console.log("TVL:", formatAmount(stats.tvlInUSD), "USD");
console.log("CR:", formatCR(stats.collateralRatio));

Write Client - Browser (React/wagmi)

import { AspanClient, BSC_ADDRESSES } from "@aspan/sdk";
import { useWalletClient } from "wagmi";

function MyComponent() {
  const { data: walletClient } = useWalletClient();

  const getClient = () => {
    if (!walletClient) return null;
    return new AspanClient({
      diamondAddress: BSC_ADDRESSES.diamond,
      walletClient: walletClient,
    });
  };

  const handleMint = async () => {
    const client = getClient();
    if (!client) return;
    
    const hash = await client.mintApUSD({
      lstToken: BSC_ADDRESSES.slisBNB,
      lstAmount: parseAmount("1"),
    });
    console.log("Tx hash:", hash);
  };
}

Write Client - Node.js / Server

import { createAspanClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount("0x...");
const client = createAspanClient(BSC_ADDRESSES.diamond, account);

const hash = await client.mintApUSD({
  lstToken: BSC_ADDRESSES.slisBNB,
  lstAmount: parseAmount("1"),
});

Router (One-Click Operations)

AspanRouter is a periphery contract that enables users to mint/redeem apUSD or xBNB in a single transaction using common tokens like USDT, USDC, BNB, or WBNB. The router automatically handles DEX swaps, LST staking, and minting.

Router Client Setup

import { createRouterClient, AspanRouterClient, BSC_ADDRESSES } from "@aspan/sdk";
import { privateKeyToAccount } from "viem/accounts";

// Node.js
const account = privateKeyToAccount("0x...");
const router = createRouterClient(BSC_ADDRESSES.router, account);

// Browser (wagmi)
const router = new AspanRouterClient({
  routerAddress: BSC_ADDRESSES.router,
  walletClient,  // from useWalletClient()
});

Swap USDT/USDC → apUSD or xBNB (One-Click)

import { parseAmount, BSC_ADDRESSES, type SwapAndMintParams } from "@aspan/sdk";
import { zeroAddress } from "viem";

// Full control with SwapParams + MintParams
const params: SwapAndMintParams = {
  swapParams: {
    inputToken: BSC_ADDRESSES.USDT,
    inputAmount: parseAmount("100"),  // 100 USDT
    targetLST: zeroAddress,           // Use default LST
    minLSTOut: 0n,                    // Or set slippage protection
    poolFee: 2500,                    // 0.25% V3 pool fee
  },
  mintParams: {
    mintXBNB: false,                  // false = apUSD, true = xBNB
    minMintOut: parseAmount("99"),    // Min 99 apUSD (1% slippage)
    recipient: zeroAddress,           // Send to msg.sender
    deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  },
};

// Approve USDT first, then swap+mint
const hash = await router.swapAndMint(params);
await router.waitForTransaction(hash);

Simplified: Swap → apUSD/xBNB (Default LST)

// Simpler API using default LST
const hash = await router.swapAndMintDefault({
  inputToken: BSC_ADDRESSES.USDT,
  inputAmount: parseAmount("100"),
  mintXBNB: false,                    // false = apUSD, true = xBNB
  minMintOut: parseAmount("99"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
});

Stake Native BNB → apUSD/xBNB (Bypasses DEX)

Direct BNB staking gets better rates for large amounts by bypassing DEX.

// Stake BNB directly to Lista/Astherus → mint apUSD or xBNB
const hash = await router.stakeAndMint({
  targetLST: BSC_ADDRESSES.slisBNB,
  isXBNB: false,                      // false = apUSD, true = xBNB
  minMintOut: parseAmount("99"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  value: parseAmount("1"),            // 1 BNB
});

Direct Mint/Redeem via Router

If you already have LST, use direct functions:

// Mint apUSD or xBNB with LST
const hash = await router.mint({
  lst: BSC_ADDRESSES.slisBNB,
  lstAmount: parseAmount("10"),
  mintXBNB: false,                    // false = apUSD, true = xBNB
  minOut: parseAmount("99"),
});

// Redeem apUSD or xBNB for LST
const hash = await router.redeem({
  lst: BSC_ADDRESSES.slisBNB,
  redeemXBNB: false,                  // false = redeem apUSD, true = redeem xBNB
  amount: parseAmount("100"),
  minOut: parseAmount("0.9"),
});

Redeem + Swap to USDT/BNB (V3 Path)

import { encodeV3Path, BSC_ADDRESSES } from "@aspan/sdk";

// Encode V3 swap path: slisBNB → WBNB → USDT
const path = encodeV3Path(
  [BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB, BSC_ADDRESSES.USDT],
  [500, 500]              // pool fees (0.05% each hop)
);

// Redeem apUSD/xBNB and swap LST to output token via V3 path
const hash = await router.redeemAndSwap({
  lst: BSC_ADDRESSES.slisBNB,
  redeemXBNB: false,                  // false = redeem apUSD, true = redeem xBNB
  amount: parseAmount("100"),
  path,
  minOut: parseAmount("99"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  unwrapBNB: false,                   // true to unwrap WBNB → native BNB
});

Get Native BNB (Auto-unwrap)

// Redeem and get native BNB (auto-unwrap WBNB)
const path = encodeV3Path(
  [BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB],
  [2500]  // 0.25% pool fee
);

const hash = await router.redeemAndSwap({
  lst: BSC_ADDRESSES.slisBNB,
  redeemXBNB: false,
  amount: parseAmount("100"),
  path,
  minOut: parseAmount("0.15"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  unwrapBNB: true,                    // Auto-unwrap to native BNB!
});

Native Unstake (7-15 Day Unbonding)

For no-slippage BNB redemption, use Lista's native unstake:

// Request unstake (starts 7-15 day unbonding period)
const hash = await router.redeemAndRequestUnstake({
  redeemXBNB: false,                  // false = redeem apUSD, true = redeem xBNB
  amount: parseAmount("100"),
});
const receipt = await router.waitForTransaction(hash);

// Check withdrawal status
const indices = await router.getUserWithdrawalIndices(account.address);
for (const idx of indices) {
  const status = await router.getWithdrawalStatus(idx);
  console.log(`Request ${idx}: claimable=${status.isClaimable}, amount=${status.bnbAmount}`);
}

// Claim BNB after unbonding
const claimHash = await router.claimUnstake(requestIndex);

Router View Functions

// Check supported tokens
const defaultLST = await router.getDefaultLST();
const isSupported = await router.isSupportedInputToken(BSC_ADDRESSES.USDT);
const isLSTSupported = await router.isSupportedLST(BSC_ADDRESSES.slisBNB);

// Preview mint/redeem (accurate with fees)
const apUSDOut = await router.previewMint(BSC_ADDRESSES.slisBNB, parseAmount("1"), false);
const xBNBOut = await router.previewMint(BSC_ADDRESSES.slisBNB, parseAmount("1"), true);
const lstFromApUSD = await router.previewRedeem(BSC_ADDRESSES.slisBNB, false, parseAmount("100"));
const lstFromXBNB = await router.previewRedeem(BSC_ADDRESSES.slisBNB, true, parseAmount("10"));

// Get token addresses
const wbnb = await router.getWBNB();
const usdt = await router.getUSDT();
const slisBNB = await router.getSlisBNB();

Use Cases

1. New User: USDT → apUSD (One-Click)

The simplest way to mint apUSD stablecoin with USDT.

import { createRouterClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";

const router = createRouterClient(BSC_ADDRESSES.router, account);

// 100 USDT → apUSD (auto DEX swap + mint)
const hash = await router.swapAndMintDefault({
  inputToken: BSC_ADDRESSES.USDT,
  inputAmount: parseAmount("100"),
  mintXBNB: false,  // apUSD
  minMintOut: parseAmount("99"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
});

2. BNB Holder: BNB → apUSD/xBNB (Direct Stake)

For large BNB amounts, stake directly to Lista to avoid DEX slippage.

// 1 BNB → apUSD (direct stake, no DEX slippage)
const hash = await router.stakeAndMint({
  targetLST: BSC_ADDRESSES.slisBNB,
  isXBNB: false,  // false = apUSD, true = xBNB
  minMintOut: parseAmount("750"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  value: parseAmount("1"),  // 1 BNB
});

3. Leverage Trader: BNB → xBNB (Long BNB)

xBNB is leveraged BNB exposure, ideal for bullish BNB traders.

// 1 BNB → xBNB (~1.2x leverage)
const hash = await router.stakeAndMint({
  targetLST: BSC_ADDRESSES.slisBNB,
  isXBNB: true,  // xBNB
  minMintOut: parseAmount("0.001"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  value: parseAmount("1"),
});

// Check current leverage
const stats = await client.getProtocolStats();
console.log("xBNB Leverage:", formatAmount(stats.effectiveLeverage), "x");

4. Yield Farming: apUSD → sApUSD (Stability Pool)

Deposit apUSD into the Stability Pool to earn protocol yield.

import { createAspanClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";

const client = createAspanClient(BSC_ADDRESSES.diamond, account);

// Deposit apUSD
const hash = await client.deposit({ apUSDAmount: parseAmount("1000") });

// Check earnings
const position = await client.getUserStabilityPoolPosition(account.address);
console.log("sApUSD Balance:", formatAmount(position.balance));
console.log("Earned:", formatAmount(position.balance - position.deposited));

// Preview withdrawal (supports dirty pools with apUSD + xBNB)
const preview = await client.previewRedeemMulti(position.shares);
console.log("Will receive apUSD:", formatAmount(preview.apUSD));
if (preview.hasXBNB) {
  console.log("Will also receive xBNB:", formatAmount(preview.xBNB));
}

5. Quick Exit: apUSD/xBNB → USDT

Exit to USDT via DEX swap when you need liquidity fast.

import { encodeV3Path, BSC_ADDRESSES } from "@aspan/sdk";

// Path: slisBNB → WBNB → USDT (PancakeSwap V3)
const path = encodeV3Path(
  [BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB, BSC_ADDRESSES.USDT],
  [500, 500]
);

// 100 apUSD → USDT
const hash = await router.redeemAndSwap({
  lst: BSC_ADDRESSES.slisBNB,
  redeemXBNB: false,  // apUSD
  amount: parseAmount("100"),
  path,
  minOut: parseAmount("99"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  unwrapBNB: false,
});

6. Quick Exit: apUSD/xBNB → Native BNB (Lista StableSwap)

Exit to native BNB using Lista StableSwap for better rates on slisBNB → WBNB.

// For slisBNB → WBNB, Router auto-routes through Lista StableSwap
// Just use a single-hop path
const path = encodeV3Path(
  [BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB],
  [100]  // Fee tier ignored for Lista StableSwap route
);

// xBNB → Native BNB
const hash = await router.redeemAndSwap({
  lst: BSC_ADDRESSES.slisBNB,
  redeemXBNB: true,  // xBNB
  amount: parseAmount("0.001"),
  path,
  minOut: parseAmount("0.8"),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
  unwrapBNB: true,  // Auto-unwrap WBNB to native BNB
});

7. Zero-Slippage Exit: Lista Native Unstake (7 Days)

Don't want to pay DEX slippage? Use Lista native unstake for 1:1 BNB redemption after 7 days.

// Step 1: Request unstake
const hash = await router.redeemAndRequestUnstake({
  redeemXBNB: false,  // apUSD
  amount: parseAmount("100"),
});
await router.waitForTransaction(hash);

// Step 2: Check status
const indices = await router.getUserWithdrawalIndices(account.address);
for (const idx of indices) {
  const status = await router.getWithdrawalStatus(idx);
  console.log(`#${idx}: ${status.isClaimable ? "Claimable" : "Pending"}, ${formatAmount(status.bnbAmount)} BNB`);
}

// Step 3: Claim BNB after 7 days
const claimHash = await router.claimUnstake(requestIndex);

User Flows

Flow 1: Mint apUSD (Stablecoin)

User deposits LST (e.g., slisBNB) to mint apUSD stablecoin.

import { createAspanClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount("0x...");
const client = createAspanClient(BSC_ADDRESSES.diamond, account);

const lstAmount = parseAmount("10"); // 10 slisBNB

// Check fees
const fees = await client.getCurrentFees();
if (fees.apUSDMintDisabled) throw new Error("Minting disabled in current CR");

// Approve LST, then mint with slippage protection
const minOut = lstAmount * 995n / 1000n; // 0.5% slippage tolerance
const hash = await client.mintApUSD({
  lstToken: BSC_ADDRESSES.slisBNB,
  lstAmount,
  minOut,
});
await client.waitForTransaction(hash);

Flow 2: Redeem apUSD for LST

const apUSDAmount = parseAmount("5000");

// Calculate expected LST and set minOut
const lstPrice = await client.getLSTPriceUSD(BSC_ADDRESSES.slisBNB);
const expectedLST = (apUSDAmount * parseAmount("1")) / lstPrice;
const minOut = expectedLST * 995n / 1000n;

const hash = await client.redeemApUSD({
  lstToken: BSC_ADDRESSES.slisBNB,
  apUSDAmount,
  minOut,
});

Flow 3: Stake apUSD to Earn Yield (sApUSD)

// Check pool stats
const poolStats = await client.getStabilityPoolStats();
console.log("Exchange Rate:", formatAmount(poolStats.exchangeRate));

// Deposit apUSD
const hash = await client.deposit({ apUSDAmount: parseAmount("1000") });

// Check position
const position = await client.getUserStabilityPoolPosition(account.address);
console.log("Balance (incl. yield):", formatAmount(position.balance));

Protocol Metrics

const stats = await client.getProtocolStats();
const fees = await client.getCurrentFees();
const mode = await client.getStabilityMode();

console.log("TVL:", formatAmount(stats.tvlInUSD), "USD");
console.log("CR:", formatCR(stats.collateralRatio));
console.log("Stability Mode:", mode.mode);
console.log("xBNB Price:", formatAmount(stats.xBNBPriceBNB), "BNB");
console.log("Leverage:", formatAmount(stats.effectiveLeverage), "x");

API Reference

Router Write Functions (v2.0.0)

| Function | Description | |----------|-------------| | swapAndMint(params) | Swap input token → LST → mint apUSD/xBNB | | swapAndMintDefault(params) | Simplified swap+mint using default LST | | stakeAndMint(params) | Stake BNB directly → LST → mint apUSD/xBNB | | mint(params) | Direct mint apUSD/xBNB with LST | | redeem(params) | Direct redeem apUSD/xBNB for LST | | redeemAndSwap(params) | Redeem + swap LST to output token (V3 path, optional unwrapBNB) | | redeemAndRequestUnstake(params) | Redeem + request native unstake from Lista | | claimUnstake(requestIndex) | Claim BNB after unbonding period |

Router View Functions

| Function | Description | |----------|-------------| | previewMint(lst, amount, mintXBNB) | Preview mint output | | previewRedeem(lst, redeemXBNB, amount) | Preview redeem output | | getDefaultLST() | Get default LST address | | isSupportedInputToken(token) | Check if input token supported | | isSupportedLST(lst) | Check if LST supported | | getUserWithdrawalIndices(user) | Get user's unstake request indices | | getWithdrawalStatus(index) | Check unstake request status |

Diamond Write Functions

| Function | Description | |----------|-------------| | mintApUSD(params) | Mint apUSD with LST | | redeemApUSD(params) | Redeem apUSD for LST | | mintXBNB(params) | Mint xBNB with LST | | redeemXBNB(params) | Redeem xBNB for LST | | deposit(params) | Deposit apUSD to stability pool | | withdraw(params) | Withdraw from stability pool | | previewRedeemMulti(shares) | Preview multi-asset withdrawal (apUSD + xBNB) | | harvestYield() | Trigger yield distribution |


Utility Functions

import {
  formatAmount,     // bigint -> "1234.5678"
  parseAmount,      // "1234.5678" -> bigint
  formatFeeBPS,     // 25 -> "0.25%"
  formatCR,         // 15000n -> "150%"
  formatPriceUSD,   // 58325000000n -> "$583.25"
  encodeV3Path,     // Encode PancakeSwap V3 swap path
  BSC_ADDRESSES,    // All contract addresses
  PRECISION,        // 10^18
  BPS_PRECISION,    // 10000
  PRICE_PRECISION,  // 10^8
} from "@aspan/sdk";

Testnet

import {
  createAspanTestnetReadClient,
  createAspanTestnetClient,
  createRouterTestnetReadClient,
  createRouterTestnetClient,
} from "@aspan/sdk";

const client = createAspanTestnetReadClient("0x...");
const router = createRouterTestnetClient("0x...", account);

Risk Keeper Bot

The SDK includes a Risk Keeper service for automated risk management:

Features

  1. Stability Mode 2 Trigger - Automatically triggers SM2 when CR < 130%
  2. TWAP Vault Cleaning - Cleans xBNB from sApUSD vault after SM2

Environment Variables

# Required for Risk Keeper
RISK_KEEPER_ENABLED=true
KEEPER_PRIVATE_KEY=0x...
SAPUSD_ADDRESS=0xE2BE739C4aA4126ee72D612d9548C38B1B0e5A1b

# Optional (with defaults)
ROUTER_ADDRESS=0x10ED43C718714eb63d5aA57B78B54704E256024E  # PancakeSwap V2
WBNB_ADDRESS=0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c
SM2_COOLDOWN_MS=1800000     # 30 min
TWAP_INTERVAL_MS=600000     # 10 min
TWAP_PERCENTAGE=5           # 5% per batch
MAX_SLIPPAGE_BPS=50         # 0.5%
TWAP_START_CR=13500         # 135%

Risk Management Functions

| Function | Description | |----------|-------------| | triggerStabilityMode2(targetCR) | Trigger SM2 forced conversion | | cleanXbnb(amount) | Clean underwater xBNB (user burn) | | canTriggerStabilityMode2() | Check if SM2 can be triggered | | getStabilityMode() | Get current stability mode (0/1/2) |


License

MIT