@aspan/sdk 0.1.4

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
@@ -0,0 +1,451 @@
1
+ # @aspan/sdk
2
+
3
+ TypeScript SDK for Aspan Protocol - LST-backed stablecoin on BNB Chain.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @aspan/sdk
9
+ # or
10
+ pnpm add @aspan/sdk
11
+ ```
12
+
13
+ ## Contract Addresses (BSC Mainnet)
14
+
15
+
16
+ | Contract | Address |
17
+ |----------|---------|
18
+ | **Diamond (Main Entry)** | `0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f` |
19
+ | **ApUSD** | `0x1977097E2E5697A6DD91b6732F368a14F50f6B3d` |
20
+ | **XBNB** | `0xB78eB4d5928bAb158Eb23c3154544084cD2661d5` |
21
+ | **SApUSD** | `0xE2BE739C4aA4126ee72D612d9548C38B1B0e5A1b` |
22
+ | **SlisBNBAdapter** | `0x1B0b8001624CC67031f1c30cCDC12fBdD5752376` |
23
+
24
+ ## Quick Start
25
+
26
+ ```typescript
27
+ import { createAspanReadClient, formatAmount, formatCR } from "@aspan/sdk";
28
+
29
+ const DIAMOND = "0xa67e91ebbb709516c563bcf1d9dae355aaf6d2ef";
30
+ const client = createAspanReadClient(DIAMOND, "https://bsc-dataseed.binance.org/");
31
+
32
+ const stats = await client.getProtocolStats();
33
+ console.log("TVL:", formatAmount(stats.tvlInUSD), "USD");
34
+ console.log("CR:", formatCR(stats.collateralRatio));
35
+ ```
36
+
37
+ ---
38
+
39
+ ## User Flows
40
+
41
+ ### Flow 1: Mint apUSD (Stablecoin)
42
+
43
+ User deposits LST (e.g., slisBNB) to mint apUSD stablecoin.
44
+
45
+ ```typescript
46
+ import { createAspanClient, parseAmount } from "@aspan/sdk";
47
+ import { privateKeyToAccount } from "viem/accounts";
48
+ import { erc20Abi } from "viem";
49
+
50
+ const account = privateKeyToAccount("0x...");
51
+ const client = createAspanClient(DIAMOND, account);
52
+
53
+ const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B";
54
+ const lstAmount = parseAmount("10"); // 10 slisBNB
55
+
56
+ // Step 1: Check LST is supported
57
+ const isSupported = await client.isLSTSupported(SLISBNB);
58
+ if (!isSupported) throw new Error("LST not supported");
59
+
60
+ // Step 2: Check current fees
61
+ const fees = await client.getCurrentFees();
62
+ console.log("Mint fee:", fees.apUSDMintFee / 100, "%");
63
+ if (fees.apUSDMintDisabled) throw new Error("Minting disabled in current CR");
64
+
65
+ // Step 3: Approve LST spending (use viem directly)
66
+ // await walletClient.writeContract({
67
+ // address: SLISBNB,
68
+ // abi: erc20Abi,
69
+ // functionName: "approve",
70
+ // args: [DIAMOND, lstAmount],
71
+ // });
72
+
73
+ // Step 4: Mint apUSD
74
+ const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount });
75
+ const receipt = await client.waitForTransaction(hash);
76
+ console.log("Minted apUSD:", receipt.status);
77
+ ```
78
+
79
+ ### Flow 2: Redeem apUSD for LST
80
+
81
+ User burns apUSD to get back LST.
82
+
83
+ ```typescript
84
+ const apUSDAmount = parseAmount("5000"); // 5000 apUSD
85
+
86
+ // Step 1: Check available LST liquidity
87
+ const collateral = await client.getLSTCollateral(SLISBNB);
88
+ const lstPrice = await client.getLSTPriceUSD(SLISBNB);
89
+ const maxRedeemable = (collateral * lstPrice) / parseAmount("1");
90
+ console.log("Max redeemable:", formatAmount(maxRedeemable), "USD");
91
+
92
+ // Step 2: Approve apUSD spending (use viem directly)
93
+ // Step 3: Redeem
94
+ const hash = await client.redeemApUSD({ lstToken: SLISBNB, apUSDAmount });
95
+ await client.waitForTransaction(hash);
96
+ ```
97
+
98
+ ### Flow 3: Mint xBNB (Leveraged Long)
99
+
100
+ User deposits LST to mint xBNB, a leveraged long position on BNB.
101
+
102
+ ```typescript
103
+ // Step 1: Check xBNB price and leverage
104
+ const xBNBPrice = await client.getXBNBPriceBNB();
105
+ const leverage = await client.getEffectiveLeverage();
106
+ console.log("xBNB Price:", formatAmount(xBNBPrice), "BNB");
107
+ console.log("Effective Leverage:", formatAmount(leverage), "x");
108
+
109
+ // Step 2: Check if xBNB is underwater (price = 0)
110
+ if (xBNBPrice === 0n) {
111
+ throw new Error("xBNB underwater - cannot mint");
112
+ }
113
+
114
+ // Step 3: Approve LST, then mint xBNB
115
+ const hash = await client.mintXBNB({ lstToken: SLISBNB, lstAmount });
116
+ await client.waitForTransaction(hash);
117
+ ```
118
+
119
+ ### Flow 4: Stake apUSD to Earn Yield (sApUSD)
120
+
121
+ User deposits apUSD to stability pool to earn LST yield.
122
+
123
+ ```typescript
124
+ // Step 1: Check stability pool stats
125
+ const poolStats = await client.getStabilityPoolStats();
126
+ console.log("Total Staked:", formatAmount(poolStats.totalStaked));
127
+ console.log("Exchange Rate:", formatAmount(poolStats.exchangeRate));
128
+
129
+ // Step 2: Preview deposit
130
+ const depositAmount = parseAmount("1000");
131
+ const expectedShares = await client.previewDeposit(depositAmount);
132
+ console.log("Expected shares:", formatAmount(expectedShares));
133
+
134
+ // Step 3: Approve apUSD, then deposit
135
+ const hash = await client.deposit({ apUSDAmount: depositAmount });
136
+ await client.waitForTransaction(hash);
137
+
138
+ // Step 4: Check position
139
+ const position = await client.getUserStabilityPoolPosition(account.address);
140
+ console.log("Shares:", formatAmount(position.shares));
141
+ console.log("Balance (incl. yield):", formatAmount(position.balance));
142
+ ```
143
+
144
+ ### Flow 5: Withdraw from Stability Pool
145
+
146
+ User withdraws their staked apUSD plus accumulated yield.
147
+
148
+ ```typescript
149
+ // Step 1: Get user's shares
150
+ const shares = await client.getShares(account.address);
151
+
152
+ // Step 2: Preview redemption
153
+ const expectedAssets = await client.previewRedeem(shares);
154
+ console.log("Expected apUSD:", formatAmount(expectedAssets));
155
+
156
+ // Step 3: Approve sApUSD shares transfer
157
+ // const sApUSD = await client.getSApUSD();
158
+
159
+ // Step 4: Withdraw all shares
160
+ const hash = await client.withdraw({ shares });
161
+ await client.waitForTransaction(hash);
162
+
163
+ // Or withdraw specific amount of apUSD:
164
+ // const hash = await client.withdrawAssets({ assets: parseAmount("500") });
165
+ ```
166
+
167
+ ### Flow 6: Manual Yield Harvest
168
+
169
+ Anyone can trigger yield harvest to distribute pending LST yield.
170
+
171
+ ```typescript
172
+ // Step 1: Check pending yield
173
+ const yieldStats = await client.getYieldStats();
174
+ console.log("Pending yield:", formatAmount(yieldStats.pendingYield), "USD");
175
+ console.log("Preview harvest:", formatAmount(yieldStats.previewedHarvest), "USD");
176
+
177
+ // Step 2: Harvest (if there's yield)
178
+ if (yieldStats.pendingYield + yieldStats.previewedHarvest > 0n) {
179
+ const hash = await client.harvestYield();
180
+ await client.waitForTransaction(hash);
181
+ }
182
+ ```
183
+
184
+ ---
185
+
186
+ ## Protocol Metrics Guide
187
+
188
+ Based on protocol-analysis.md, here's how to read all key metrics:
189
+
190
+ ### Core Metrics (Section 3: Core Math Model)
191
+
192
+ | Metric | SDK Method | Description |
193
+ |--------|------------|-------------|
194
+ | **TVL** | `getTVLInUSD()` | Total Value Locked in USD |
195
+ | **TVL (BNB)** | `getTVLInBNB()` | TVL in BNB terms |
196
+ | **apUSD Supply** | `getApUSDSupply()` | Total apUSD minted |
197
+ | **xBNB Supply** | `getXBNBSupply()` | Total xBNB minted |
198
+
199
+ ```typescript
200
+ const stats = await client.getProtocolStats();
201
+ // stats.tvlInUSD - TVL = sum of all LST collateral value
202
+ // stats.apUSDSupply - stable portion of the pool
203
+ // stats.xBNBSupply - leveraged long portion
204
+ ```
205
+
206
+ ### xBNB Price (Section 3.3 & 4)
207
+
208
+ | Metric | SDK Method | Formula |
209
+ |--------|------------|---------|
210
+ | **xBNB Price (BNB)** | `getXBNBPriceBNB()` | `(TVL_BNB - apUSD_value_BNB) / xBNB_supply` |
211
+ | **xBNB Price (USD)** | `getXBNBPriceUSD()` | `xBNB_price_BNB * BNB_price_USD` |
212
+
213
+ ```typescript
214
+ const xBNBPriceBNB = await client.getXBNBPriceBNB();
215
+ const xBNBPriceUSD = await client.getXBNBPriceUSD();
216
+ // Price = 0 means xBNB is "underwater" (TVL <= apUSD value)
217
+ ```
218
+
219
+ ### Collateral Ratio (Section 7)
220
+
221
+ | Metric | SDK Method | Formula |
222
+ |--------|------------|---------|
223
+ | **CR** | `getCollateralRatio()` | `(TVL_USD / apUSD_supply) * 10000` (BPS) |
224
+
225
+ ```typescript
226
+ const cr = await client.getCollateralRatio();
227
+ // CR in BPS: 15000 = 150%, 13000 = 130%, 10000 = 100%
228
+ console.log("CR:", Number(cr) / 100, "%");
229
+ ```
230
+
231
+ ### Effective Leverage (Section 5)
232
+
233
+ | Metric | SDK Method | Formula |
234
+ |--------|------------|---------|
235
+ | **Leverage** | `getEffectiveLeverage()` | `TVL / xBNB_market_cap` |
236
+
237
+ ```typescript
238
+ const leverage = await client.getEffectiveLeverage();
239
+ // 1e18 = 1x, 2e18 = 2x leverage
240
+ console.log("Leverage:", formatAmount(leverage), "x");
241
+ ```
242
+
243
+ ### Stability Mode (Section 8)
244
+
245
+ | Mode | CR Range | Description |
246
+ |------|----------|-------------|
247
+ | **Normal (0)** | CR >= 150% | Standard operations |
248
+ | **Mode 1 (1)** | 130% <= CR < 150% | Fee adjustments active |
249
+ | **Mode 2 (2)** | CR < 130% | Forced conversion possible |
250
+
251
+ ```typescript
252
+ const mode = await client.getStabilityMode();
253
+ // mode.mode: 0=Normal, 1=StabilityMode1, 2=StabilityMode2
254
+ // mode.currentCR: Current CR in BPS
255
+
256
+ const mode2Info = await client.canTriggerStabilityMode2();
257
+ // mode2Info.canTrigger: true if CR < 130%
258
+ // mode2Info.potentialConversion: apUSD that would be converted
259
+ ```
260
+
261
+ ### Fee Tiers (Section 8.2)
262
+
263
+ | Mode | apUSD Mint | apUSD Redeem | xBNB Mint | xBNB Redeem |
264
+ |------|------------|--------------|-----------|-------------|
265
+ | Normal | 0.2% | 0.2% | 1% | 1% |
266
+ | Mode 1 | 0.3% | 0.1% | 0.25% | 4% |
267
+ | Mode 2 | **Disabled** | 0% | 0% | 8% |
268
+
269
+ ```typescript
270
+ const fees = await client.getCurrentFees();
271
+ // fees.currentCR - Current CR
272
+ // fees.tierMinCR - Tier threshold
273
+ // fees.apUSDMintFee - in BPS (20 = 0.2%)
274
+ // fees.apUSDMintDisabled - true in Mode 2
275
+ ```
276
+
277
+ ### Stability Pool / Yield (Section 6)
278
+
279
+ | Metric | SDK Method | Description |
280
+ |--------|------------|-------------|
281
+ | **Total Staked** | `getTotalStaked()` | apUSD in stability pool |
282
+ | **Exchange Rate** | `getExchangeRate()` | sApUSD to apUSD ratio |
283
+ | **Pending Yield** | `getPendingYield()` | Yield waiting to be distributed |
284
+ | **Total Generated** | `getTotalYieldGenerated()` | All-time yield |
285
+
286
+ ```typescript
287
+ const poolStats = await client.getStabilityPoolStats();
288
+ const yieldStats = await client.getYieldStats();
289
+
290
+ // APY calculation (Section 6.2-6.3)
291
+ // APY = LST_yield_rate * (TVL / staked_apUSD)
292
+ const amplification = stats.tvlInUSD / poolStats.totalStaked;
293
+ const estimatedAPY = 0.08 * Number(amplification); // Assuming 8% LST yield
294
+ ```
295
+
296
+ ### LST Information
297
+
298
+ ```typescript
299
+ // Get all supported LSTs
300
+ const lsts = await client.getSupportedLSTs();
301
+
302
+ for (const lst of lsts) {
303
+ const info = await client.getLSTInfo(lst);
304
+ const price = await client.getLSTPriceUSD(lst);
305
+ const collateral = await client.getLSTCollateral(lst);
306
+ const yieldInfo = await client.getLSTYieldInfo(lst);
307
+
308
+ console.log(`LST: ${lst}`);
309
+ console.log(` Accepted: ${info.isAccepted}`);
310
+ console.log(` Collateral: ${formatAmount(collateral)}`);
311
+ console.log(` Price: $${formatAmount(price)}`);
312
+ console.log(` Exchange Rate: ${formatAmount(yieldInfo.lastExchangeRate)}`);
313
+ }
314
+ ```
315
+
316
+ ### Oracle / Prices
317
+
318
+ ```typescript
319
+ const bnbPrice = await client.getBNBPriceUSD();
320
+ console.log("BNB Price:", formatPriceUSD(bnbPrice));
321
+ // Note: BNB price is 8 decimals (Chainlink format)
322
+
323
+ const lstPrice = await client.getLSTPriceUSD(SLISBNB);
324
+ console.log("LST Price:", formatAmount(lstPrice), "USD");
325
+ // Note: LST price is 18 decimals
326
+ ```
327
+
328
+ ---
329
+
330
+ ## Complete Dashboard Example
331
+
332
+ ```typescript
333
+ import {
334
+ createAspanReadClient,
335
+ formatAmount,
336
+ formatCR,
337
+ formatFeeBPS,
338
+ formatPriceUSD,
339
+ } from "@aspan/sdk";
340
+
341
+ const DIAMOND = "0xa67e91ebbb709516c563bcf1d9dae355aaf6d2ef";
342
+ const client = createAspanReadClient(DIAMOND);
343
+
344
+ async function displayDashboard() {
345
+ // === Protocol Overview ===
346
+ const stats = await client.getProtocolStats();
347
+ const mode = await client.getStabilityMode();
348
+ const fees = await client.getCurrentFees();
349
+
350
+ console.log("=== Aspan Protocol Dashboard ===");
351
+ console.log(`TVL: $${formatAmount(stats.tvlInUSD)}`);
352
+ console.log(`CR: ${formatCR(stats.collateralRatio)}`);
353
+ console.log(`Stability Mode: ${mode.mode === 0 ? "Normal" : `Mode ${mode.mode}`}`);
354
+ console.log(`Effective Leverage: ${formatAmount(stats.effectiveLeverage)}x`);
355
+
356
+ // === Token Stats ===
357
+ console.log("\n=== Tokens ===");
358
+ console.log(`apUSD Supply: ${formatAmount(stats.apUSDSupply)}`);
359
+ console.log(`xBNB Supply: ${formatAmount(stats.xBNBSupply)}`);
360
+ console.log(`xBNB Price: ${formatAmount(stats.xBNBPriceBNB)} BNB`);
361
+
362
+ // === Current Fees ===
363
+ console.log("\n=== Current Fees ===");
364
+ console.log(`apUSD Mint: ${formatFeeBPS(fees.apUSDMintFee)}${fees.apUSDMintDisabled ? " (DISABLED)" : ""}`);
365
+ console.log(`apUSD Redeem: ${formatFeeBPS(fees.apUSDRedeemFee)}`);
366
+ console.log(`xBNB Mint: ${formatFeeBPS(fees.xBNBMintFee)}`);
367
+ console.log(`xBNB Redeem: ${formatFeeBPS(fees.xBNBRedeemFee)}`);
368
+
369
+ // === Stability Pool ===
370
+ const poolStats = await client.getStabilityPoolStats();
371
+ const yieldStats = await client.getYieldStats();
372
+
373
+ console.log("\n=== Stability Pool (sApUSD) ===");
374
+ console.log(`Total Staked: ${formatAmount(poolStats.totalStaked)} apUSD`);
375
+ console.log(`Exchange Rate: ${formatAmount(poolStats.exchangeRate)}`);
376
+ console.log(`Pending Yield: $${formatAmount(yieldStats.pendingYield)}`);
377
+ console.log(`Total Yield Generated: $${formatAmount(yieldStats.totalYieldGenerated)}`);
378
+
379
+ // === LST Collateral ===
380
+ const lsts = await client.getSupportedLSTs();
381
+ console.log("\n=== LST Collateral ===");
382
+ for (const lst of lsts) {
383
+ const collateral = await client.getLSTCollateral(lst);
384
+ const price = await client.getLSTPriceUSD(lst);
385
+ const value = (collateral * price) / 10n ** 18n;
386
+ console.log(`${lst.slice(0, 10)}...: ${formatAmount(collateral)} ($${formatAmount(value)})`);
387
+ }
388
+ }
389
+
390
+ displayDashboard();
391
+ ```
392
+
393
+ ---
394
+
395
+ ## API Reference
396
+
397
+ ### View Functions
398
+
399
+ | Category | Methods |
400
+ |----------|---------|
401
+ | **Stats** | `getProtocolStats()`, `getStabilityPoolStats()`, `getYieldStats()` |
402
+ | **Pool** | `getTVLInBNB()`, `getTVLInUSD()`, `getCollateralRatio()`, `getXBNBPriceBNB()`, `getXBNBPriceUSD()`, `getEffectiveLeverage()`, `getApUSDSupply()`, `getXBNBSupply()`, `getLSTCollateral()`, `getCurrentFees()` |
403
+ | **Stability Pool** | `getShares()`, `getBalance()`, `getUserStabilityPoolPosition()`, `getExchangeRate()`, `getTotalStaked()`, `previewDeposit()`, `previewRedeem()`, `getPendingYield()` |
404
+ | **Yield** | `getTotalYieldGenerated()`, `getLSTYieldInfo()`, `getMinHarvestInterval()`, `getLastHarvestTimestamp()`, `previewHarvest()` |
405
+ | **Oracle** | `getBNBPriceUSD()`, `getLSTPriceUSD()`, `getLSTInfo()`, `getSupportedLSTs()`, `isLSTSupported()`, `getBNBPriceFeed()`, `getOracleBounds()` |
406
+ | **Config** | `getTokens()`, `getSApUSD()`, `getStabilityPool()`, `getTreasury()`, `getFeeTierCount()`, `getFeeTier()`, `getCurrentFeeTier()`, `getMaxPriceAge()`, `getMinDepositPeriod()`, `isPaused()` |
407
+ | **Stability Mode** | `getStabilityMode()`, `canTriggerStabilityMode2()` |
408
+ | **Ownership** | `getOwner()` |
409
+
410
+ ### Write Functions
411
+
412
+ | Category | Methods |
413
+ |----------|---------|
414
+ | **Pool** | `mintApUSD()`, `redeemApUSD()`, `mintXBNB()`, `redeemXBNB()` |
415
+ | **Stability Pool** | `deposit()`, `withdraw()`, `withdrawAssets()`, `harvestYield()` |
416
+
417
+ ---
418
+
419
+ ## Utility Functions
420
+
421
+ ```typescript
422
+ import {
423
+ formatAmount, // bigint -> "1234.5678"
424
+ parseAmount, // "1234.5678" -> bigint
425
+ formatFeeBPS, // 25 -> "0.25%"
426
+ formatCR, // 15000n -> "150%"
427
+ formatPriceUSD, // 58325000000n -> "$583.25"
428
+ calculateAPY, // (oldRate, newRate, days) -> APY%
429
+ PRECISION, // 10^18
430
+ BPS_PRECISION, // 10000
431
+ PRICE_PRECISION, // 10^8
432
+ } from "@aspan/sdk";
433
+ ```
434
+
435
+ ---
436
+
437
+ ## Testnet
438
+
439
+ ```typescript
440
+ import {
441
+ createAspanTestnetReadClient,
442
+ createAspanTestnetClient,
443
+ } from "@aspan/sdk";
444
+
445
+ const client = createAspanTestnetReadClient("0x...");
446
+ const writeClient = createAspanTestnetClient("0x...", account);
447
+ ```
448
+
449
+ ## License
450
+
451
+ MIT