@aspan/sdk
v0.1.8
Published
TypeScript SDK for Aspan Protocol - LST-backed stablecoin on BNB Chain
Downloads
311
Maintainers
Readme
@aspan/sdk
TypeScript SDK for Aspan Protocol - LST-backed stablecoin on BNB Chain.
Installation
npm install @aspan/sdk
# or
pnpm add @aspan/sdkContract Addresses (BSC Mainnet)
| Contract | Address |
|----------|---------|
| Diamond (Main Entry) | 0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f |
| ApUSD | 0x1977097E2E5697A6DD91b6732F368a14F50f6B3d |
| XBNB | 0xB78eB4d5928bAb158Eb23c3154544084cD2661d5 |
| SApUSD | 0xE2BE739C4aA4126ee72D612d9548C38B1B0e5A1b |
| SlisBNBAdapter | 0x1B0b8001624CC67031f1c30cCDC12fBdD5752376 |
Quick Start
Read-Only Client (Query Data)
import { createAspanReadClient, formatAmount, formatCR } from "@aspan/sdk";
const DIAMOND = "0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f";
const client = createAspanReadClient(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 } from "@aspan/sdk";
import { useWalletClient } from "wagmi";
const DIAMOND = "0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f";
function MyComponent() {
const { data: walletClient } = useWalletClient();
const getClient = () => {
if (!walletClient) return null;
return new AspanClient({
diamondAddress: DIAMOND,
walletClient: walletClient, // Pass wagmi's walletClient
});
};
const handleMint = async () => {
const client = getClient();
if (!client) return;
const hash = await client.mintApUSD({
lstToken: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B",
lstAmount: parseAmount("1"),
});
console.log("Tx hash:", hash);
};
}Write Client - Node.js / Server
import { createAspanClient, parseAmount } from "@aspan/sdk";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount("0x...");
const client = createAspanClient(DIAMOND, account);
const hash = await client.mintApUSD({
lstToken: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B",
lstAmount: parseAmount("1"),
});User Flows
Flow 1: Mint apUSD (Stablecoin)
User deposits LST (e.g., slisBNB) to mint apUSD stablecoin.
Browser (React/wagmi)
import { AspanClient, parseAmount } from "@aspan/sdk";
import { useWalletClient } from "wagmi";
const DIAMOND = "0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f";
const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B";
function MintComponent() {
const { data: walletClient } = useWalletClient();
const handleMint = async () => {
if (!walletClient) return;
const client = new AspanClient({
diamondAddress: DIAMOND,
walletClient,
});
const lstAmount = parseAmount("10"); // 10 slisBNB
// Step 1: Check LST is supported
const isSupported = await client.isLSTSupported(SLISBNB);
if (!isSupported) throw new Error("LST not supported");
// Step 2: Check current fees
const fees = await client.getCurrentFees();
if (fees.apUSDMintDisabled) throw new Error("Minting disabled");
// Step 3: Approve LST (use wagmi's useWriteContract or viem)
// ...
// Step 4: Calculate minOut for slippage protection (e.g., 0.5% slippage)
const expectedApUSD = lstAmount; // Simplified, use actual calculation
const minOut = expectedApUSD * 995n / 1000n; // 0.5% slippage
// Step 5: Mint apUSD
const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount, minOut });
const receipt = await client.waitForTransaction(hash);
console.log("Minted apUSD:", receipt.status);
};
}Node.js / Server
import { createAspanClient, parseAmount } from "@aspan/sdk";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount("0x...");
const client = createAspanClient(DIAMOND, account);
const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B";
const lstAmount = parseAmount("10"); // 10 slisBNB
// Step 1: Check LST is supported
const isSupported = await client.isLSTSupported(SLISBNB);
if (!isSupported) throw new Error("LST not supported");
// Step 2: Check current fees
const fees = await client.getCurrentFees();
console.log("Mint fee:", fees.apUSDMintFee / 100, "%");
if (fees.apUSDMintDisabled) throw new Error("Minting disabled in current CR");
// Step 3: Approve LST spending (use viem directly)
// await walletClient.writeContract({
// address: SLISBNB,
// abi: erc20Abi,
// functionName: "approve",
// args: [DIAMOND, lstAmount],
// });
// Step 4: Mint apUSD with slippage protection
const minOut = lstAmount * 995n / 1000n; // 0.5% slippage tolerance
const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount, minOut });
const receipt = await client.waitForTransaction(hash);
console.log("Minted apUSD:", receipt.status);Flow 2: Redeem apUSD for LST
User burns apUSD to get back LST.
const apUSDAmount = parseAmount("5000"); // 5000 apUSD
// Step 1: Check available LST liquidity
const collateral = await client.getLSTCollateral(SLISBNB);
const lstPrice = await client.getLSTPriceUSD(SLISBNB);
const maxRedeemable = (collateral * lstPrice) / parseAmount("1");
console.log("Max redeemable:", formatAmount(maxRedeemable), "USD");
// Step 2: Approve apUSD spending (use viem directly)
// Step 3: Calculate expected LST output and set minOut
const expectedLST = (apUSDAmount * parseAmount("1")) / lstPrice;
const minOut = expectedLST * 995n / 1000n; // 0.5% slippage
// Step 4: Redeem with slippage protection
const hash = await client.redeemApUSD({ lstToken: SLISBNB, apUSDAmount, minOut });
await client.waitForTransaction(hash);Flow 3: Mint xBNB (Leveraged Long)
User deposits LST to mint xBNB, a leveraged long position on BNB.
// Step 1: Check xBNB price and leverage
const xBNBPrice = await client.getXBNBPriceBNB();
const leverage = await client.getEffectiveLeverage();
console.log("xBNB Price:", formatAmount(xBNBPrice), "BNB");
console.log("Effective Leverage:", formatAmount(leverage), "x");
// Step 2: Check if xBNB is underwater (price = 0)
if (xBNBPrice === 0n) {
throw new Error("xBNB underwater - cannot mint");
}
// Step 3: Approve LST, then mint xBNB with slippage protection
const minOut = 0n; // Set appropriate minOut based on expected xBNB output
const hash = await client.mintXBNB({ lstToken: SLISBNB, lstAmount, minOut });
await client.waitForTransaction(hash);Flow 4: Redeem xBNB for LST
User burns xBNB to get back LST.
const xBNBAmount = parseAmount("100"); // 100 xBNB
// Step 1: Check xBNB price (ensure not underwater)
const xBNBPrice = await client.getXBNBPriceBNB();
if (xBNBPrice === 0n) {
throw new Error("xBNB is underwater - redemption may result in 0 LST");
}
// Step 2: Check current fees
const fees = await client.getCurrentFees();
console.log("xBNB Redeem fee:", fees.xBNBRedeemFee / 100, "%");
// Step 3: Check available LST liquidity
const collateral = await client.getLSTCollateral(SLISBNB);
console.log("Available collateral:", formatAmount(collateral));
// Step 4: Approve xBNB spending (use viem directly)
// ...
// Step 5: Calculate expected LST and set minOut for slippage protection
const expectedLST = (xBNBAmount * xBNBPrice) / parseAmount("1");
const minOut = expectedLST * 995n / 1000n; // 0.5% slippage
// Step 6: Redeem xBNB
const hash = await client.redeemXBNB({ lstToken: SLISBNB, xBNBAmount, minOut });
await client.waitForTransaction(hash);Flow 5: Stake apUSD to Earn Yield (sApUSD)
User deposits apUSD to stability pool to earn LST yield.
// Step 1: Check stability pool stats
const poolStats = await client.getStabilityPoolStats();
console.log("Total Staked:", formatAmount(poolStats.totalStaked));
console.log("Exchange Rate:", formatAmount(poolStats.exchangeRate));
// Step 2: Preview deposit
const depositAmount = parseAmount("1000");
const expectedShares = await client.previewDeposit(depositAmount);
console.log("Expected shares:", formatAmount(expectedShares));
// Step 3: Approve apUSD, then deposit
const hash = await client.deposit({ apUSDAmount: depositAmount });
await client.waitForTransaction(hash);
// Step 4: Check position
const position = await client.getUserStabilityPoolPosition(account.address);
console.log("Shares:", formatAmount(position.shares));
console.log("Balance (incl. yield):", formatAmount(position.balance));Flow 6: Withdraw from Stability Pool
User withdraws their staked apUSD plus accumulated yield.
// Step 1: Get user's shares
const shares = await client.getShares(account.address);
// Step 2: Preview redemption
const expectedAssets = await client.previewRedeem(shares);
console.log("Expected apUSD:", formatAmount(expectedAssets));
// Step 3: Approve sApUSD shares transfer
// const sApUSD = await client.getSApUSD();
// Step 4: Withdraw all shares
const hash = await client.withdraw({ shares });
await client.waitForTransaction(hash);
// Or withdraw specific amount of apUSD:
// const hash = await client.withdrawAssets({ assets: parseAmount("500") });Flow 7: Manual Yield Harvest
Anyone can trigger yield harvest to distribute pending LST yield.
// Step 1: Check pending yield
const yieldStats = await client.getYieldStats();
console.log("Pending yield:", formatAmount(yieldStats.pendingYield), "USD");
console.log("Preview harvest:", formatAmount(yieldStats.previewedHarvest), "USD");
// Step 2: Harvest (if there's yield)
if (yieldStats.pendingYield + yieldStats.previewedHarvest > 0n) {
const hash = await client.harvestYield();
await client.waitForTransaction(hash);
}Protocol Metrics Guide
Based on protocol-analysis.md, here's how to read all key metrics:
Core Metrics (Section 3: Core Math Model)
| Metric | SDK Method | Description |
|--------|------------|-------------|
| TVL | getTVLInUSD() | Total Value Locked in USD |
| TVL (BNB) | getTVLInBNB() | TVL in BNB terms |
| apUSD Supply | getApUSDSupply() | Total apUSD minted |
| xBNB Supply | getXBNBSupply() | Total xBNB minted |
const stats = await client.getProtocolStats();
// stats.tvlInUSD - TVL = sum of all LST collateral value
// stats.apUSDSupply - stable portion of the pool
// stats.xBNBSupply - leveraged long portionxBNB Price (Section 3.3 & 4)
| Metric | SDK Method | Formula |
|--------|------------|---------|
| xBNB Price (BNB) | getXBNBPriceBNB() | (TVL_BNB - apUSD_value_BNB) / xBNB_supply |
| xBNB Price (USD) | getXBNBPriceUSD() | xBNB_price_BNB * BNB_price_USD |
const xBNBPriceBNB = await client.getXBNBPriceBNB();
const xBNBPriceUSD = await client.getXBNBPriceUSD();
// Price = 0 means xBNB is "underwater" (TVL <= apUSD value)Collateral Ratio (Section 7)
| Metric | SDK Method | Formula |
|--------|------------|---------|
| CR | getCollateralRatio() | (TVL_USD / apUSD_supply) * 10000 (BPS) |
const cr = await client.getCollateralRatio();
// CR in BPS: 15000 = 150%, 13000 = 130%, 10000 = 100%
console.log("CR:", Number(cr) / 100, "%");Effective Leverage (Section 5)
| Metric | SDK Method | Formula |
|--------|------------|---------|
| Leverage | getEffectiveLeverage() | TVL / xBNB_market_cap |
const leverage = await client.getEffectiveLeverage();
// 1e18 = 1x, 2e18 = 2x leverage
console.log("Leverage:", formatAmount(leverage), "x");Stability Mode (Section 8)
| Mode | CR Range | Description | |------|----------|-------------| | Normal (0) | CR >= 150% | Standard operations | | Mode 1 (1) | 130% <= CR < 150% | Fee adjustments active | | Mode 2 (2) | CR < 130% | Forced conversion possible |
const mode = await client.getStabilityMode();
// mode.mode: 0=Normal, 1=StabilityMode1, 2=StabilityMode2
// mode.currentCR: Current CR in BPS
const mode2Info = await client.canTriggerStabilityMode2();
// mode2Info.canTrigger: true if CR < 130%
// mode2Info.potentialConversion: apUSD that would be convertedFee Tiers (Section 8.2)
| Mode | apUSD Mint | apUSD Redeem | xBNB Mint | xBNB Redeem | |------|------------|--------------|-----------|-------------| | Normal | 0.2% | 0.2% | 1% | 1% | | Mode 1 | 0.3% | 0.1% | 0.25% | 4% | | Mode 2 | Disabled | 0% | 0% | 8% |
const fees = await client.getCurrentFees();
// fees.currentCR - Current CR
// fees.tierMinCR - Tier threshold
// fees.apUSDMintFee - in BPS (20 = 0.2%)
// fees.apUSDMintDisabled - true in Mode 2Stability Pool / Yield (Section 6)
| Metric | SDK Method | Description |
|--------|------------|-------------|
| Total Staked | getTotalStaked() | apUSD in stability pool |
| Exchange Rate | getExchangeRate() | sApUSD to apUSD ratio |
| Pending Yield | getPendingYield() | Yield waiting to be distributed |
| Total Generated | getTotalYieldGenerated() | All-time yield |
const poolStats = await client.getStabilityPoolStats();
const yieldStats = await client.getYieldStats();
// APY calculation (Section 6.2-6.3)
// APY = LST_yield_rate * (TVL / staked_apUSD)
const amplification = stats.tvlInUSD / poolStats.totalStaked;
const estimatedAPY = 0.08 * Number(amplification); // Assuming 8% LST yieldLST Information
// Get all supported LSTs
const lsts = await client.getSupportedLSTs();
for (const lst of lsts) {
const info = await client.getLSTInfo(lst);
const price = await client.getLSTPriceUSD(lst);
const collateral = await client.getLSTCollateral(lst);
const yieldInfo = await client.getLSTYieldInfo(lst);
console.log(`LST: ${lst}`);
console.log(` Accepted: ${info.isAccepted}`);
console.log(` Collateral: ${formatAmount(collateral)}`);
console.log(` Price: $${formatAmount(price)}`);
console.log(` Exchange Rate: ${formatAmount(yieldInfo.lastExchangeRate)}`);
}Oracle / Prices
const bnbPrice = await client.getBNBPriceUSD();
console.log("BNB Price:", formatPriceUSD(bnbPrice));
// Note: BNB price is 8 decimals (Chainlink format)
const lstPrice = await client.getLSTPriceUSD(SLISBNB);
console.log("LST Price:", formatAmount(lstPrice), "USD");
// Note: LST price is 18 decimalsComplete Dashboard Example
import {
createAspanReadClient,
formatAmount,
formatCR,
formatFeeBPS,
formatPriceUSD,
} from "@aspan/sdk";
const DIAMOND = "0xa67e91ebbb709516c563bcf1d9dae355aaf6d2ef";
const client = createAspanReadClient(DIAMOND);
async function displayDashboard() {
// === Protocol Overview ===
const stats = await client.getProtocolStats();
const mode = await client.getStabilityMode();
const fees = await client.getCurrentFees();
console.log("=== Aspan Protocol Dashboard ===");
console.log(`TVL: $${formatAmount(stats.tvlInUSD)}`);
console.log(`CR: ${formatCR(stats.collateralRatio)}`);
console.log(`Stability Mode: ${mode.mode === 0 ? "Normal" : `Mode ${mode.mode}`}`);
console.log(`Effective Leverage: ${formatAmount(stats.effectiveLeverage)}x`);
// === Token Stats ===
console.log("\n=== Tokens ===");
console.log(`apUSD Supply: ${formatAmount(stats.apUSDSupply)}`);
console.log(`xBNB Supply: ${formatAmount(stats.xBNBSupply)}`);
console.log(`xBNB Price: ${formatAmount(stats.xBNBPriceBNB)} BNB`);
// === Current Fees ===
console.log("\n=== Current Fees ===");
console.log(`apUSD Mint: ${formatFeeBPS(fees.apUSDMintFee)}${fees.apUSDMintDisabled ? " (DISABLED)" : ""}`);
console.log(`apUSD Redeem: ${formatFeeBPS(fees.apUSDRedeemFee)}`);
console.log(`xBNB Mint: ${formatFeeBPS(fees.xBNBMintFee)}`);
console.log(`xBNB Redeem: ${formatFeeBPS(fees.xBNBRedeemFee)}`);
// === Stability Pool ===
const poolStats = await client.getStabilityPoolStats();
const yieldStats = await client.getYieldStats();
console.log("\n=== Stability Pool (sApUSD) ===");
console.log(`Total Staked: ${formatAmount(poolStats.totalStaked)} apUSD`);
console.log(`Exchange Rate: ${formatAmount(poolStats.exchangeRate)}`);
console.log(`Pending Yield: $${formatAmount(yieldStats.pendingYield)}`);
console.log(`Total Yield Generated: $${formatAmount(yieldStats.totalYieldGenerated)}`);
// === LST Collateral ===
const lsts = await client.getSupportedLSTs();
console.log("\n=== LST Collateral ===");
for (const lst of lsts) {
const collateral = await client.getLSTCollateral(lst);
const price = await client.getLSTPriceUSD(lst);
const value = (collateral * price) / 10n ** 18n;
console.log(`${lst.slice(0, 10)}...: ${formatAmount(collateral)} ($${formatAmount(value)})`);
}
}
displayDashboard();API Reference
Client Configuration
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| diamondAddress | Address | ✅ | Diamond contract address |
| chain | Chain | ❌ | Chain config (default: BSC Mainnet) |
| rpcUrl | string | ❌ | RPC URL (default: BSC public RPC) |
| walletClient | WalletClient | ⚠️ | For browser/wagmi (required if no account) |
| account | Account | ⚠️ | For Node.js (required if no walletClient) |
⚠️ Write client requires either
walletClient(browser) oraccount(Node.js)
View Functions
| Category | Methods |
|----------|---------|
| Stats | getProtocolStats(), getStabilityPoolStats(), getYieldStats() |
| Pool | getTVLInBNB(), getTVLInUSD(), getCollateralRatio(), getXBNBPriceBNB(), getXBNBPriceUSD(), getEffectiveLeverage(), getApUSDSupply(), getXBNBSupply(), getLSTCollateral(), getCurrentFees() |
| Stability Pool | getShares(), getBalance(), getUserStabilityPoolPosition(), getExchangeRate(), getTotalStaked(), previewDeposit(), previewRedeem(), getPendingYield() |
| Yield | getTotalYieldGenerated(), getLSTYieldInfo(), getMinHarvestInterval(), getLastHarvestTimestamp(), previewHarvest() |
| Oracle | getBNBPriceUSD(), getLSTPriceUSD(), getLSTInfo(), getSupportedLSTs(), isLSTSupported(), getBNBPriceFeed(), getOracleBounds() |
| Config | getTokens(), getSApUSD(), getStabilityPool(), getTreasury(), getFeeTierCount(), getFeeTier(), getCurrentFeeTier(), getMaxPriceAge(), getMinDepositPeriod(), isPaused() |
| Stability Mode | getStabilityMode(), canTriggerStabilityMode2() |
| Ownership | getOwner() |
Write Functions
| Category | Methods |
|----------|---------|
| Pool | mintApUSD(), redeemApUSD(), mintXBNB(), redeemXBNB() |
| Stability Pool | deposit(), withdraw(), withdrawAssets(), harvestYield() |
Utility Functions
import {
formatAmount, // bigint -> "1234.5678"
parseAmount, // "1234.5678" -> bigint
formatFeeBPS, // 25 -> "0.25%"
formatCR, // 15000n -> "150%"
formatPriceUSD, // 58325000000n -> "$583.25"
calculateAPY, // (oldRate, newRate, days) -> APY%
PRECISION, // 10^18
BPS_PRECISION, // 10000
PRICE_PRECISION, // 10^8
} from "@aspan/sdk";Testnet
import {
createAspanTestnetReadClient,
createAspanTestnetClient,
} from "@aspan/sdk";
const client = createAspanTestnetReadClient("0x...");
const writeClient = createAspanTestnetClient("0x...", account);License
MIT
