@aspan/sdk 0.3.0 → 0.4.0
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 +267 -509
- package/dist/index.d.mts +148 -328
- package/dist/index.d.ts +148 -328
- package/dist/index.js +133 -381
- package/dist/index.mjs +132 -381
- package/package.json +3 -1
- package/src/__tests__/fork.test.ts +206 -0
- package/src/__tests__/router.test.ts +456 -27
- package/src/abi/router.ts +60 -191
- package/src/index.ts +22 -5
- package/src/router.ts +58 -216
- package/src/types.ts +60 -43
package/README.md
CHANGED
|
@@ -12,26 +12,30 @@ pnpm add @aspan/sdk
|
|
|
12
12
|
|
|
13
13
|
## Contract Addresses (BSC Mainnet)
|
|
14
14
|
|
|
15
|
+
```typescript
|
|
16
|
+
import { BSC_ADDRESSES } from "@aspan/sdk";
|
|
17
|
+
|
|
18
|
+
// Or use directly:
|
|
19
|
+
// BSC_ADDRESSES.diamond, BSC_ADDRESSES.router, etc.
|
|
20
|
+
```
|
|
15
21
|
|
|
16
22
|
| Contract | Address |
|
|
17
23
|
|----------|---------|
|
|
18
24
|
| **Diamond (Main Entry)** | `0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f` |
|
|
19
|
-
| **Router** | `
|
|
20
|
-
| **wclisBNB** | `0x439faaC2229559121C4Ad4fd8B3FE13Dff038046` |
|
|
25
|
+
| **Router** | `0x813d3D1A3154950E2f1d8718305426a335A974A9` |
|
|
21
26
|
| **ApUSD** | `0x1977097E2E5697A6DD91b6732F368a14F50f6B3d` |
|
|
22
27
|
| **XBNB** | `0xB78eB4d5928bAb158Eb23c3154544084cD2661d5` |
|
|
23
28
|
| **SApUSD** | `0xE2BE739C4aA4126ee72D612d9548C38B1B0e5A1b` |
|
|
24
|
-
| **
|
|
29
|
+
| **wclisBNB** | `0x439faaC2229559121C4Ad4fd8B3FE13Dff038046` |
|
|
25
30
|
|
|
26
31
|
## Quick Start
|
|
27
32
|
|
|
28
33
|
### Read-Only Client (Query Data)
|
|
29
34
|
|
|
30
35
|
```typescript
|
|
31
|
-
import { createAspanReadClient, formatAmount, formatCR } from "@aspan/sdk";
|
|
36
|
+
import { createAspanReadClient, formatAmount, formatCR, BSC_ADDRESSES } from "@aspan/sdk";
|
|
32
37
|
|
|
33
|
-
const
|
|
34
|
-
const client = createAspanReadClient(DIAMOND, "https://bsc-dataseed.binance.org/");
|
|
38
|
+
const client = createAspanReadClient(BSC_ADDRESSES.diamond, "https://bsc-dataseed.binance.org/");
|
|
35
39
|
|
|
36
40
|
const stats = await client.getProtocolStats();
|
|
37
41
|
console.log("TVL:", formatAmount(stats.tvlInUSD), "USD");
|
|
@@ -41,19 +45,17 @@ console.log("CR:", formatCR(stats.collateralRatio));
|
|
|
41
45
|
### Write Client - Browser (React/wagmi)
|
|
42
46
|
|
|
43
47
|
```typescript
|
|
44
|
-
import { AspanClient } from "@aspan/sdk";
|
|
48
|
+
import { AspanClient, BSC_ADDRESSES } from "@aspan/sdk";
|
|
45
49
|
import { useWalletClient } from "wagmi";
|
|
46
50
|
|
|
47
|
-
const DIAMOND = "0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f";
|
|
48
|
-
|
|
49
51
|
function MyComponent() {
|
|
50
52
|
const { data: walletClient } = useWalletClient();
|
|
51
53
|
|
|
52
54
|
const getClient = () => {
|
|
53
55
|
if (!walletClient) return null;
|
|
54
56
|
return new AspanClient({
|
|
55
|
-
diamondAddress:
|
|
56
|
-
walletClient: walletClient,
|
|
57
|
+
diamondAddress: BSC_ADDRESSES.diamond,
|
|
58
|
+
walletClient: walletClient,
|
|
57
59
|
});
|
|
58
60
|
};
|
|
59
61
|
|
|
@@ -62,7 +64,7 @@ function MyComponent() {
|
|
|
62
64
|
if (!client) return;
|
|
63
65
|
|
|
64
66
|
const hash = await client.mintApUSD({
|
|
65
|
-
lstToken:
|
|
67
|
+
lstToken: BSC_ADDRESSES.slisBNB,
|
|
66
68
|
lstAmount: parseAmount("1"),
|
|
67
69
|
});
|
|
68
70
|
console.log("Tx hash:", hash);
|
|
@@ -73,14 +75,14 @@ function MyComponent() {
|
|
|
73
75
|
### Write Client - Node.js / Server
|
|
74
76
|
|
|
75
77
|
```typescript
|
|
76
|
-
import { createAspanClient, parseAmount } from "@aspan/sdk";
|
|
78
|
+
import { createAspanClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";
|
|
77
79
|
import { privateKeyToAccount } from "viem/accounts";
|
|
78
80
|
|
|
79
81
|
const account = privateKeyToAccount("0x...");
|
|
80
|
-
const client = createAspanClient(
|
|
82
|
+
const client = createAspanClient(BSC_ADDRESSES.diamond, account);
|
|
81
83
|
|
|
82
84
|
const hash = await client.mintApUSD({
|
|
83
|
-
lstToken:
|
|
85
|
+
lstToken: BSC_ADDRESSES.slisBNB,
|
|
84
86
|
lstAmount: parseAmount("1"),
|
|
85
87
|
});
|
|
86
88
|
```
|
|
@@ -94,41 +96,37 @@ AspanRouter is a periphery contract that enables users to mint/redeem apUSD or x
|
|
|
94
96
|
### Router Client Setup
|
|
95
97
|
|
|
96
98
|
```typescript
|
|
97
|
-
import { createRouterClient, AspanRouterClient } from "@aspan/sdk";
|
|
99
|
+
import { createRouterClient, AspanRouterClient, BSC_ADDRESSES } from "@aspan/sdk";
|
|
98
100
|
import { privateKeyToAccount } from "viem/accounts";
|
|
99
|
-
import { zeroAddress } from "viem";
|
|
100
|
-
|
|
101
|
-
const ROUTER = "0xf63f34f7e9608ae7d3a6f5b06ce423d9f9043648";
|
|
102
101
|
|
|
103
102
|
// Node.js
|
|
104
103
|
const account = privateKeyToAccount("0x...");
|
|
105
|
-
const router = createRouterClient(
|
|
104
|
+
const router = createRouterClient(BSC_ADDRESSES.router, account);
|
|
106
105
|
|
|
107
106
|
// Browser (wagmi)
|
|
108
107
|
const router = new AspanRouterClient({
|
|
109
|
-
routerAddress:
|
|
108
|
+
routerAddress: BSC_ADDRESSES.router,
|
|
110
109
|
walletClient, // from useWalletClient()
|
|
111
110
|
});
|
|
112
111
|
```
|
|
113
112
|
|
|
114
|
-
### Swap USDT/USDC → apUSD (One-Click)
|
|
113
|
+
### Swap USDT/USDC → apUSD or xBNB (One-Click)
|
|
115
114
|
|
|
116
115
|
```typescript
|
|
117
|
-
import { parseAmount, type SwapAndMintParams } from "@aspan/sdk";
|
|
116
|
+
import { parseAmount, BSC_ADDRESSES, type SwapAndMintParams } from "@aspan/sdk";
|
|
118
117
|
import { zeroAddress } from "viem";
|
|
119
118
|
|
|
120
|
-
const USDT = "0x55d398326f99059fF775485246999027B3197955";
|
|
121
|
-
|
|
122
119
|
// Full control with SwapParams + MintParams
|
|
123
120
|
const params: SwapAndMintParams = {
|
|
124
121
|
swapParams: {
|
|
125
|
-
inputToken: USDT,
|
|
122
|
+
inputToken: BSC_ADDRESSES.USDT,
|
|
126
123
|
inputAmount: parseAmount("100"), // 100 USDT
|
|
127
124
|
targetLST: zeroAddress, // Use default LST
|
|
128
125
|
minLSTOut: 0n, // Or set slippage protection
|
|
129
126
|
poolFee: 2500, // 0.25% V3 pool fee
|
|
130
127
|
},
|
|
131
128
|
mintParams: {
|
|
129
|
+
mintXBNB: false, // false = apUSD, true = xBNB
|
|
132
130
|
minMintOut: parseAmount("99"), // Min 99 apUSD (1% slippage)
|
|
133
131
|
recipient: zeroAddress, // Send to msg.sender
|
|
134
132
|
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
@@ -136,77 +134,56 @@ const params: SwapAndMintParams = {
|
|
|
136
134
|
};
|
|
137
135
|
|
|
138
136
|
// Approve USDT first, then swap+mint
|
|
139
|
-
const hash = await router.
|
|
137
|
+
const hash = await router.swapAndMint(params);
|
|
140
138
|
await router.waitForTransaction(hash);
|
|
141
139
|
```
|
|
142
140
|
|
|
143
|
-
### Simplified: Swap → apUSD (Default LST)
|
|
141
|
+
### Simplified: Swap → apUSD/xBNB (Default LST)
|
|
144
142
|
|
|
145
143
|
```typescript
|
|
146
|
-
// Simpler API using default LST
|
|
147
|
-
const hash = await router.
|
|
148
|
-
inputToken: USDT,
|
|
144
|
+
// Simpler API using default LST
|
|
145
|
+
const hash = await router.swapAndMintDefault({
|
|
146
|
+
inputToken: BSC_ADDRESSES.USDT,
|
|
149
147
|
inputAmount: parseAmount("100"),
|
|
148
|
+
mintXBNB: false, // false = apUSD, true = xBNB
|
|
150
149
|
minMintOut: parseAmount("99"),
|
|
151
150
|
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
152
151
|
});
|
|
153
152
|
```
|
|
154
153
|
|
|
155
|
-
### Stake Native BNB → apUSD (Bypasses DEX)
|
|
154
|
+
### Stake Native BNB → apUSD/xBNB (Bypasses DEX)
|
|
156
155
|
|
|
157
156
|
Direct BNB staking gets better rates for large amounts by bypassing DEX.
|
|
158
157
|
|
|
159
158
|
```typescript
|
|
160
|
-
// Stake BNB directly to Lista/Astherus → mint apUSD
|
|
161
|
-
const hash = await router.stakeAndMintApUSD(
|
|
162
|
-
parseAmount("99"), // minMintOut
|
|
163
|
-
parseAmount("1"), // 1 BNB to stake (sent as value)
|
|
164
|
-
);
|
|
165
|
-
|
|
166
|
-
// Or with full control
|
|
159
|
+
// Stake BNB directly to Lista/Astherus → mint apUSD or xBNB
|
|
167
160
|
const hash = await router.stakeAndMint({
|
|
168
|
-
targetLST:
|
|
169
|
-
isXBNB: false,
|
|
161
|
+
targetLST: BSC_ADDRESSES.slisBNB,
|
|
162
|
+
isXBNB: false, // false = apUSD, true = xBNB
|
|
170
163
|
minMintOut: parseAmount("99"),
|
|
171
164
|
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
172
|
-
value: parseAmount("1"),
|
|
173
|
-
});
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
### Swap → xBNB (Leveraged Long)
|
|
177
|
-
|
|
178
|
-
```typescript
|
|
179
|
-
// Full params
|
|
180
|
-
const hash = await router.swapAndMintXBNB(params);
|
|
181
|
-
|
|
182
|
-
// Or simplified
|
|
183
|
-
const hash = await router.swapAndMintXBNBDefault({
|
|
184
|
-
inputToken: USDT,
|
|
185
|
-
inputAmount: parseAmount("1000"),
|
|
186
|
-
minMintOut: parseAmount("1"), // Min 1 xBNB
|
|
187
|
-
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
165
|
+
value: parseAmount("1"), // 1 BNB
|
|
188
166
|
});
|
|
189
|
-
|
|
190
|
-
// Or stake BNB directly
|
|
191
|
-
const hash = await router.stakeAndMintXBNB(parseAmount("1"), parseAmount("10"));
|
|
192
167
|
```
|
|
193
168
|
|
|
194
169
|
### Direct Mint/Redeem via Router
|
|
195
170
|
|
|
196
|
-
If you already have LST, use direct functions
|
|
171
|
+
If you already have LST, use direct functions:
|
|
197
172
|
|
|
198
173
|
```typescript
|
|
199
|
-
// Mint apUSD with LST
|
|
200
|
-
const hash = await router.
|
|
201
|
-
lst:
|
|
174
|
+
// Mint apUSD or xBNB with LST
|
|
175
|
+
const hash = await router.mint({
|
|
176
|
+
lst: BSC_ADDRESSES.slisBNB,
|
|
202
177
|
lstAmount: parseAmount("10"),
|
|
178
|
+
mintXBNB: false, // false = apUSD, true = xBNB
|
|
203
179
|
minOut: parseAmount("99"),
|
|
204
180
|
});
|
|
205
181
|
|
|
206
|
-
// Redeem apUSD for LST
|
|
207
|
-
const hash = await router.
|
|
208
|
-
lst:
|
|
209
|
-
|
|
182
|
+
// Redeem apUSD or xBNB for LST
|
|
183
|
+
const hash = await router.redeem({
|
|
184
|
+
lst: BSC_ADDRESSES.slisBNB,
|
|
185
|
+
redeemXBNB: false, // false = redeem apUSD, true = redeem xBNB
|
|
186
|
+
amount: parseAmount("100"),
|
|
210
187
|
minOut: parseAmount("0.9"),
|
|
211
188
|
});
|
|
212
189
|
```
|
|
@@ -214,31 +191,45 @@ const hash = await router.redeemApUSD({
|
|
|
214
191
|
### Redeem + Swap to USDT/BNB (V3 Path)
|
|
215
192
|
|
|
216
193
|
```typescript
|
|
217
|
-
import { encodeV3Path } from "@aspan/sdk";
|
|
218
|
-
|
|
219
|
-
const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B";
|
|
220
|
-
const WBNB = "0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c";
|
|
221
|
-
const USDT = "0x55d398326f99059fF775485246999027B3197955";
|
|
194
|
+
import { encodeV3Path, BSC_ADDRESSES } from "@aspan/sdk";
|
|
222
195
|
|
|
223
196
|
// Encode V3 swap path: slisBNB → WBNB → USDT
|
|
224
|
-
// Use encodeV3Path helper or get optimal path from PancakeSwap Quoter
|
|
225
197
|
const path = encodeV3Path(
|
|
226
|
-
[
|
|
198
|
+
[BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB, BSC_ADDRESSES.USDT],
|
|
227
199
|
[500, 500] // pool fees (0.05% each hop)
|
|
228
200
|
);
|
|
229
201
|
|
|
230
|
-
// Redeem apUSD and swap LST to
|
|
231
|
-
const hash = await router.
|
|
232
|
-
lst:
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
202
|
+
// Redeem apUSD/xBNB and swap LST to output token via V3 path
|
|
203
|
+
const hash = await router.redeemAndSwap({
|
|
204
|
+
lst: BSC_ADDRESSES.slisBNB,
|
|
205
|
+
redeemXBNB: false, // false = redeem apUSD, true = redeem xBNB
|
|
206
|
+
amount: parseAmount("100"),
|
|
207
|
+
path,
|
|
208
|
+
minOut: parseAmount("99"),
|
|
236
209
|
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
210
|
+
unwrapBNB: false, // true to unwrap WBNB → native BNB
|
|
237
211
|
});
|
|
238
212
|
```
|
|
239
213
|
|
|
240
|
-
|
|
241
|
-
|
|
214
|
+
### Get Native BNB (Auto-unwrap)
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
// Redeem and get native BNB (auto-unwrap WBNB)
|
|
218
|
+
const path = encodeV3Path(
|
|
219
|
+
[BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB],
|
|
220
|
+
[2500] // 0.25% pool fee
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const hash = await router.redeemAndSwap({
|
|
224
|
+
lst: BSC_ADDRESSES.slisBNB,
|
|
225
|
+
redeemXBNB: false,
|
|
226
|
+
amount: parseAmount("100"),
|
|
227
|
+
path,
|
|
228
|
+
minOut: parseAmount("0.15"),
|
|
229
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
230
|
+
unwrapBNB: true, // Auto-unwrap to native BNB!
|
|
231
|
+
});
|
|
232
|
+
```
|
|
242
233
|
|
|
243
234
|
### Native Unstake (7-15 Day Unbonding)
|
|
244
235
|
|
|
@@ -246,9 +237,11 @@ For no-slippage BNB redemption, use Lista's native unstake:
|
|
|
246
237
|
|
|
247
238
|
```typescript
|
|
248
239
|
// Request unstake (starts 7-15 day unbonding period)
|
|
249
|
-
const hash = await router.
|
|
240
|
+
const hash = await router.redeemAndRequestUnstake({
|
|
241
|
+
redeemXBNB: false, // false = redeem apUSD, true = redeem xBNB
|
|
242
|
+
amount: parseAmount("100"),
|
|
243
|
+
});
|
|
250
244
|
const receipt = await router.waitForTransaction(hash);
|
|
251
|
-
// Parse event to get requestIndex...
|
|
252
245
|
|
|
253
246
|
// Check withdrawal status
|
|
254
247
|
const indices = await router.getUserWithdrawalIndices(account.address);
|
|
@@ -258,7 +251,7 @@ for (const idx of indices) {
|
|
|
258
251
|
}
|
|
259
252
|
|
|
260
253
|
// Claim BNB after unbonding
|
|
261
|
-
const
|
|
254
|
+
const claimHash = await router.claimUnstake(requestIndex);
|
|
262
255
|
```
|
|
263
256
|
|
|
264
257
|
### Router View Functions
|
|
@@ -266,518 +259,287 @@ const hash = await router.claimUnstake(requestIndex);
|
|
|
266
259
|
```typescript
|
|
267
260
|
// Check supported tokens
|
|
268
261
|
const defaultLST = await router.getDefaultLST();
|
|
269
|
-
const isSupported = await router.isSupportedInputToken(USDT);
|
|
270
|
-
const isLSTSupported = await router.isSupportedLST(slisBNB);
|
|
262
|
+
const isSupported = await router.isSupportedInputToken(BSC_ADDRESSES.USDT);
|
|
263
|
+
const isLSTSupported = await router.isSupportedLST(BSC_ADDRESSES.slisBNB);
|
|
271
264
|
|
|
272
|
-
// Preview mint/redeem
|
|
273
|
-
const apUSDOut = await router.
|
|
274
|
-
const xBNBOut = await router.
|
|
275
|
-
const lstFromApUSD = await router.
|
|
276
|
-
const lstFromXBNB = await router.
|
|
265
|
+
// Preview mint/redeem (accurate with fees)
|
|
266
|
+
const apUSDOut = await router.previewMint(BSC_ADDRESSES.slisBNB, parseAmount("1"), false);
|
|
267
|
+
const xBNBOut = await router.previewMint(BSC_ADDRESSES.slisBNB, parseAmount("1"), true);
|
|
268
|
+
const lstFromApUSD = await router.previewRedeem(BSC_ADDRESSES.slisBNB, false, parseAmount("100"));
|
|
269
|
+
const lstFromXBNB = await router.previewRedeem(BSC_ADDRESSES.slisBNB, true, parseAmount("10"));
|
|
277
270
|
|
|
278
271
|
// Get token addresses
|
|
279
272
|
const wbnb = await router.getWBNB();
|
|
280
273
|
const usdt = await router.getUSDT();
|
|
281
274
|
const slisBNB = await router.getSlisBNB();
|
|
282
|
-
const wclisBNB = await router.getWclisBNB();
|
|
283
275
|
```
|
|
284
276
|
|
|
285
277
|
---
|
|
286
278
|
|
|
287
|
-
##
|
|
288
|
-
|
|
289
|
-
### Flow 1: Mint apUSD (Stablecoin)
|
|
279
|
+
## Use Cases
|
|
290
280
|
|
|
291
|
-
|
|
281
|
+
### 1. New User: USDT → apUSD (One-Click)
|
|
292
282
|
|
|
293
|
-
|
|
283
|
+
The simplest way to mint apUSD stablecoin with USDT.
|
|
294
284
|
|
|
295
285
|
```typescript
|
|
296
|
-
import {
|
|
297
|
-
import { useWalletClient } from "wagmi";
|
|
286
|
+
import { createRouterClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";
|
|
298
287
|
|
|
299
|
-
const
|
|
300
|
-
const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B";
|
|
288
|
+
const router = createRouterClient(BSC_ADDRESSES.router, account);
|
|
301
289
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
walletClient,
|
|
311
|
-
});
|
|
312
|
-
|
|
313
|
-
const lstAmount = parseAmount("10"); // 10 slisBNB
|
|
314
|
-
|
|
315
|
-
// Step 1: Check LST is supported
|
|
316
|
-
const isSupported = await client.isLSTSupported(SLISBNB);
|
|
317
|
-
if (!isSupported) throw new Error("LST not supported");
|
|
318
|
-
|
|
319
|
-
// Step 2: Check current fees
|
|
320
|
-
const fees = await client.getCurrentFees();
|
|
321
|
-
if (fees.apUSDMintDisabled) throw new Error("Minting disabled");
|
|
322
|
-
|
|
323
|
-
// Step 3: Approve LST (use wagmi's useWriteContract or viem)
|
|
324
|
-
// ...
|
|
325
|
-
|
|
326
|
-
// Step 4: Calculate minOut for slippage protection (e.g., 0.5% slippage)
|
|
327
|
-
const expectedApUSD = lstAmount; // Simplified, use actual calculation
|
|
328
|
-
const minOut = expectedApUSD * 995n / 1000n; // 0.5% slippage
|
|
329
|
-
|
|
330
|
-
// Step 5: Mint apUSD
|
|
331
|
-
const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount, minOut });
|
|
332
|
-
const receipt = await client.waitForTransaction(hash);
|
|
333
|
-
console.log("Minted apUSD:", receipt.status);
|
|
334
|
-
};
|
|
335
|
-
}
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
#### Node.js / Server
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
import { createAspanClient, parseAmount } from "@aspan/sdk";
|
|
342
|
-
import { privateKeyToAccount } from "viem/accounts";
|
|
343
|
-
|
|
344
|
-
const account = privateKeyToAccount("0x...");
|
|
345
|
-
const client = createAspanClient(DIAMOND, account);
|
|
346
|
-
|
|
347
|
-
const SLISBNB = "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B";
|
|
348
|
-
const lstAmount = parseAmount("10"); // 10 slisBNB
|
|
349
|
-
|
|
350
|
-
// Step 1: Check LST is supported
|
|
351
|
-
const isSupported = await client.isLSTSupported(SLISBNB);
|
|
352
|
-
if (!isSupported) throw new Error("LST not supported");
|
|
353
|
-
|
|
354
|
-
// Step 2: Check current fees
|
|
355
|
-
const fees = await client.getCurrentFees();
|
|
356
|
-
console.log("Mint fee:", fees.apUSDMintFee / 100, "%");
|
|
357
|
-
if (fees.apUSDMintDisabled) throw new Error("Minting disabled in current CR");
|
|
358
|
-
|
|
359
|
-
// Step 3: Approve LST spending (use viem directly)
|
|
360
|
-
// await walletClient.writeContract({
|
|
361
|
-
// address: SLISBNB,
|
|
362
|
-
// abi: erc20Abi,
|
|
363
|
-
// functionName: "approve",
|
|
364
|
-
// args: [DIAMOND, lstAmount],
|
|
365
|
-
// });
|
|
366
|
-
|
|
367
|
-
// Step 4: Mint apUSD with slippage protection
|
|
368
|
-
const minOut = lstAmount * 995n / 1000n; // 0.5% slippage tolerance
|
|
369
|
-
const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount, minOut });
|
|
370
|
-
const receipt = await client.waitForTransaction(hash);
|
|
371
|
-
console.log("Minted apUSD:", receipt.status);
|
|
290
|
+
// 100 USDT → apUSD (auto DEX swap + mint)
|
|
291
|
+
const hash = await router.swapAndMintDefault({
|
|
292
|
+
inputToken: BSC_ADDRESSES.USDT,
|
|
293
|
+
inputAmount: parseAmount("100"),
|
|
294
|
+
mintXBNB: false, // apUSD
|
|
295
|
+
minMintOut: parseAmount("99"),
|
|
296
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
297
|
+
});
|
|
372
298
|
```
|
|
373
299
|
|
|
374
|
-
###
|
|
300
|
+
### 2. BNB Holder: BNB → apUSD/xBNB (Direct Stake)
|
|
375
301
|
|
|
376
|
-
|
|
302
|
+
For large BNB amounts, stake directly to Lista to avoid DEX slippage.
|
|
377
303
|
|
|
378
304
|
```typescript
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
// Step 2: Approve apUSD spending (use viem directly)
|
|
388
|
-
|
|
389
|
-
// Step 3: Calculate expected LST output and set minOut
|
|
390
|
-
const expectedLST = (apUSDAmount * parseAmount("1")) / lstPrice;
|
|
391
|
-
const minOut = expectedLST * 995n / 1000n; // 0.5% slippage
|
|
392
|
-
|
|
393
|
-
// Step 4: Redeem with slippage protection
|
|
394
|
-
const hash = await client.redeemApUSD({ lstToken: SLISBNB, apUSDAmount, minOut });
|
|
395
|
-
await client.waitForTransaction(hash);
|
|
305
|
+
// 1 BNB → apUSD (direct stake, no DEX slippage)
|
|
306
|
+
const hash = await router.stakeAndMint({
|
|
307
|
+
targetLST: BSC_ADDRESSES.slisBNB,
|
|
308
|
+
isXBNB: false, // false = apUSD, true = xBNB
|
|
309
|
+
minMintOut: parseAmount("750"),
|
|
310
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
311
|
+
value: parseAmount("1"), // 1 BNB
|
|
312
|
+
});
|
|
396
313
|
```
|
|
397
314
|
|
|
398
|
-
###
|
|
315
|
+
### 3. Leverage Trader: BNB → xBNB (Long BNB)
|
|
399
316
|
|
|
400
|
-
|
|
317
|
+
xBNB is leveraged BNB exposure, ideal for bullish BNB traders.
|
|
401
318
|
|
|
402
319
|
```typescript
|
|
403
|
-
//
|
|
404
|
-
const
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
throw new Error("xBNB underwater - cannot mint");
|
|
412
|
-
}
|
|
320
|
+
// 1 BNB → xBNB (~1.2x leverage)
|
|
321
|
+
const hash = await router.stakeAndMint({
|
|
322
|
+
targetLST: BSC_ADDRESSES.slisBNB,
|
|
323
|
+
isXBNB: true, // xBNB
|
|
324
|
+
minMintOut: parseAmount("0.001"),
|
|
325
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
326
|
+
value: parseAmount("1"),
|
|
327
|
+
});
|
|
413
328
|
|
|
414
|
-
//
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
await client.waitForTransaction(hash);
|
|
329
|
+
// Check current leverage
|
|
330
|
+
const stats = await client.getProtocolStats();
|
|
331
|
+
console.log("xBNB Leverage:", formatAmount(stats.effectiveLeverage), "x");
|
|
418
332
|
```
|
|
419
333
|
|
|
420
|
-
###
|
|
334
|
+
### 4. Yield Farming: apUSD → sApUSD (Stability Pool)
|
|
421
335
|
|
|
422
|
-
|
|
336
|
+
Deposit apUSD into the Stability Pool to earn protocol yield.
|
|
423
337
|
|
|
424
338
|
```typescript
|
|
425
|
-
|
|
339
|
+
import { createAspanClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";
|
|
426
340
|
|
|
427
|
-
|
|
428
|
-
const xBNBPrice = await client.getXBNBPriceBNB();
|
|
429
|
-
if (xBNBPrice === 0n) {
|
|
430
|
-
throw new Error("xBNB is underwater - redemption may result in 0 LST");
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
// Step 2: Check current fees
|
|
434
|
-
const fees = await client.getCurrentFees();
|
|
435
|
-
console.log("xBNB Redeem fee:", fees.xBNBRedeemFee / 100, "%");
|
|
341
|
+
const client = createAspanClient(BSC_ADDRESSES.diamond, account);
|
|
436
342
|
|
|
437
|
-
//
|
|
438
|
-
const
|
|
439
|
-
console.log("Available collateral:", formatAmount(collateral));
|
|
343
|
+
// Deposit apUSD
|
|
344
|
+
const hash = await client.deposit({ apUSDAmount: parseAmount("1000") });
|
|
440
345
|
|
|
441
|
-
//
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
const expectedLST = (xBNBAmount * xBNBPrice) / parseAmount("1");
|
|
446
|
-
const minOut = expectedLST * 995n / 1000n; // 0.5% slippage
|
|
447
|
-
|
|
448
|
-
// Step 6: Redeem xBNB
|
|
449
|
-
const hash = await client.redeemXBNB({ lstToken: SLISBNB, xBNBAmount, minOut });
|
|
450
|
-
await client.waitForTransaction(hash);
|
|
346
|
+
// Check earnings
|
|
347
|
+
const position = await client.getUserStabilityPoolPosition(account.address);
|
|
348
|
+
console.log("sApUSD Balance:", formatAmount(position.balance));
|
|
349
|
+
console.log("Earned:", formatAmount(position.balance - position.deposited));
|
|
451
350
|
```
|
|
452
351
|
|
|
453
|
-
###
|
|
352
|
+
### 5. Quick Exit: apUSD/xBNB → USDT
|
|
454
353
|
|
|
455
|
-
|
|
354
|
+
Exit to USDT via DEX swap when you need liquidity fast.
|
|
456
355
|
|
|
457
356
|
```typescript
|
|
458
|
-
|
|
459
|
-
const poolStats = await client.getStabilityPoolStats();
|
|
460
|
-
console.log("Total Staked:", formatAmount(poolStats.totalStaked));
|
|
461
|
-
console.log("Exchange Rate:", formatAmount(poolStats.exchangeRate));
|
|
462
|
-
|
|
463
|
-
// Step 2: Preview deposit
|
|
464
|
-
const depositAmount = parseAmount("1000");
|
|
465
|
-
const expectedShares = await client.previewDeposit(depositAmount);
|
|
466
|
-
console.log("Expected shares:", formatAmount(expectedShares));
|
|
357
|
+
import { encodeV3Path, BSC_ADDRESSES } from "@aspan/sdk";
|
|
467
358
|
|
|
468
|
-
//
|
|
469
|
-
const
|
|
470
|
-
|
|
359
|
+
// Path: slisBNB → WBNB → USDT (PancakeSwap V3)
|
|
360
|
+
const path = encodeV3Path(
|
|
361
|
+
[BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB, BSC_ADDRESSES.USDT],
|
|
362
|
+
[500, 500]
|
|
363
|
+
);
|
|
471
364
|
|
|
472
|
-
//
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
365
|
+
// 100 apUSD → USDT
|
|
366
|
+
const hash = await router.redeemAndSwap({
|
|
367
|
+
lst: BSC_ADDRESSES.slisBNB,
|
|
368
|
+
redeemXBNB: false, // apUSD
|
|
369
|
+
amount: parseAmount("100"),
|
|
370
|
+
path,
|
|
371
|
+
minOut: parseAmount("99"),
|
|
372
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
373
|
+
unwrapBNB: false,
|
|
374
|
+
});
|
|
476
375
|
```
|
|
477
376
|
|
|
478
|
-
###
|
|
377
|
+
### 6. Quick Exit: apUSD/xBNB → Native BNB (Lista StableSwap)
|
|
479
378
|
|
|
480
|
-
|
|
379
|
+
Exit to native BNB using Lista StableSwap for better rates on slisBNB → WBNB.
|
|
481
380
|
|
|
482
381
|
```typescript
|
|
483
|
-
//
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
// Step 3: Approve sApUSD shares transfer
|
|
491
|
-
// const sApUSD = await client.getSApUSD();
|
|
492
|
-
|
|
493
|
-
// Step 4: Withdraw all shares
|
|
494
|
-
const hash = await client.withdraw({ shares });
|
|
495
|
-
await client.waitForTransaction(hash);
|
|
382
|
+
// For slisBNB → WBNB, Router auto-routes through Lista StableSwap
|
|
383
|
+
// Just use a single-hop path
|
|
384
|
+
const path = encodeV3Path(
|
|
385
|
+
[BSC_ADDRESSES.slisBNB, BSC_ADDRESSES.WBNB],
|
|
386
|
+
[100] // Fee tier ignored for Lista StableSwap route
|
|
387
|
+
);
|
|
496
388
|
|
|
497
|
-
//
|
|
498
|
-
|
|
389
|
+
// xBNB → Native BNB
|
|
390
|
+
const hash = await router.redeemAndSwap({
|
|
391
|
+
lst: BSC_ADDRESSES.slisBNB,
|
|
392
|
+
redeemXBNB: true, // xBNB
|
|
393
|
+
amount: parseAmount("0.001"),
|
|
394
|
+
path,
|
|
395
|
+
minOut: parseAmount("0.8"),
|
|
396
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
397
|
+
unwrapBNB: true, // Auto-unwrap WBNB to native BNB
|
|
398
|
+
});
|
|
499
399
|
```
|
|
500
400
|
|
|
501
|
-
###
|
|
401
|
+
### 7. Zero-Slippage Exit: Lista Native Unstake (7 Days)
|
|
502
402
|
|
|
503
|
-
|
|
403
|
+
Don't want to pay DEX slippage? Use Lista native unstake for 1:1 BNB redemption after 7 days.
|
|
504
404
|
|
|
505
405
|
```typescript
|
|
506
|
-
// Step 1:
|
|
507
|
-
const
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
406
|
+
// Step 1: Request unstake
|
|
407
|
+
const hash = await router.redeemAndRequestUnstake({
|
|
408
|
+
redeemXBNB: false, // apUSD
|
|
409
|
+
amount: parseAmount("100"),
|
|
410
|
+
});
|
|
411
|
+
await router.waitForTransaction(hash);
|
|
412
|
+
|
|
413
|
+
// Step 2: Check status
|
|
414
|
+
const indices = await router.getUserWithdrawalIndices(account.address);
|
|
415
|
+
for (const idx of indices) {
|
|
416
|
+
const status = await router.getWithdrawalStatus(idx);
|
|
417
|
+
console.log(`#${idx}: ${status.isClaimable ? "Claimable" : "Pending"}, ${formatAmount(status.bnbAmount)} BNB`);
|
|
515
418
|
}
|
|
419
|
+
|
|
420
|
+
// Step 3: Claim BNB after 7 days
|
|
421
|
+
const claimHash = await router.claimUnstake(requestIndex);
|
|
516
422
|
```
|
|
517
423
|
|
|
518
424
|
---
|
|
519
425
|
|
|
520
|
-
##
|
|
521
|
-
|
|
522
|
-
Based on protocol-analysis.md, here's how to read all key metrics:
|
|
523
|
-
|
|
524
|
-
### Core Metrics (Section 3: Core Math Model)
|
|
525
|
-
|
|
526
|
-
| Metric | SDK Method | Description |
|
|
527
|
-
|--------|------------|-------------|
|
|
528
|
-
| **TVL** | `getTVLInUSD()` | Total Value Locked in USD |
|
|
529
|
-
| **TVL (BNB)** | `getTVLInBNB()` | TVL in BNB terms |
|
|
530
|
-
| **apUSD Supply** | `getApUSDSupply()` | Total apUSD minted |
|
|
531
|
-
| **xBNB Supply** | `getXBNBSupply()` | Total xBNB minted |
|
|
532
|
-
|
|
533
|
-
```typescript
|
|
534
|
-
const stats = await client.getProtocolStats();
|
|
535
|
-
// stats.tvlInUSD - TVL = sum of all LST collateral value
|
|
536
|
-
// stats.apUSDSupply - stable portion of the pool
|
|
537
|
-
// stats.xBNBSupply - leveraged long portion
|
|
538
|
-
```
|
|
426
|
+
## User Flows
|
|
539
427
|
|
|
540
|
-
###
|
|
428
|
+
### Flow 1: Mint apUSD (Stablecoin)
|
|
541
429
|
|
|
542
|
-
|
|
543
|
-
|--------|------------|---------|
|
|
544
|
-
| **xBNB Price (BNB)** | `getXBNBPriceBNB()` | `(TVL_BNB - apUSD_value_BNB) / xBNB_supply` |
|
|
545
|
-
| **xBNB Price (USD)** | `getXBNBPriceUSD()` | `xBNB_price_BNB * BNB_price_USD` |
|
|
430
|
+
User deposits LST (e.g., slisBNB) to mint apUSD stablecoin.
|
|
546
431
|
|
|
547
432
|
```typescript
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
// Price = 0 means xBNB is "underwater" (TVL <= apUSD value)
|
|
551
|
-
```
|
|
552
|
-
|
|
553
|
-
### Collateral Ratio (Section 7)
|
|
554
|
-
|
|
555
|
-
| Metric | SDK Method | Formula |
|
|
556
|
-
|--------|------------|---------|
|
|
557
|
-
| **CR** | `getCollateralRatio()` | `(TVL_USD / apUSD_supply) * 10000` (BPS) |
|
|
433
|
+
import { createAspanClient, parseAmount, BSC_ADDRESSES } from "@aspan/sdk";
|
|
434
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
558
435
|
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
// CR in BPS: 15000 = 150%, 13000 = 130%, 10000 = 100%
|
|
562
|
-
console.log("CR:", Number(cr) / 100, "%");
|
|
563
|
-
```
|
|
436
|
+
const account = privateKeyToAccount("0x...");
|
|
437
|
+
const client = createAspanClient(BSC_ADDRESSES.diamond, account);
|
|
564
438
|
|
|
565
|
-
|
|
439
|
+
const lstAmount = parseAmount("10"); // 10 slisBNB
|
|
566
440
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
441
|
+
// Check fees
|
|
442
|
+
const fees = await client.getCurrentFees();
|
|
443
|
+
if (fees.apUSDMintDisabled) throw new Error("Minting disabled in current CR");
|
|
570
444
|
|
|
571
|
-
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
445
|
+
// Approve LST, then mint with slippage protection
|
|
446
|
+
const minOut = lstAmount * 995n / 1000n; // 0.5% slippage tolerance
|
|
447
|
+
const hash = await client.mintApUSD({
|
|
448
|
+
lstToken: BSC_ADDRESSES.slisBNB,
|
|
449
|
+
lstAmount,
|
|
450
|
+
minOut,
|
|
451
|
+
});
|
|
452
|
+
await client.waitForTransaction(hash);
|
|
575
453
|
```
|
|
576
454
|
|
|
577
|
-
###
|
|
578
|
-
|
|
579
|
-
| Mode | CR Range | Description |
|
|
580
|
-
|------|----------|-------------|
|
|
581
|
-
| **Normal (0)** | CR >= 150% | Standard operations |
|
|
582
|
-
| **Mode 1 (1)** | 130% <= CR < 150% | Fee adjustments active |
|
|
583
|
-
| **Mode 2 (2)** | CR < 130% | Forced conversion possible |
|
|
455
|
+
### Flow 2: Redeem apUSD for LST
|
|
584
456
|
|
|
585
457
|
```typescript
|
|
586
|
-
const
|
|
587
|
-
// mode.mode: 0=Normal, 1=StabilityMode1, 2=StabilityMode2
|
|
588
|
-
// mode.currentCR: Current CR in BPS
|
|
589
|
-
|
|
590
|
-
const mode2Info = await client.canTriggerStabilityMode2();
|
|
591
|
-
// mode2Info.canTrigger: true if CR < 130%
|
|
592
|
-
// mode2Info.potentialConversion: apUSD that would be converted
|
|
593
|
-
```
|
|
458
|
+
const apUSDAmount = parseAmount("5000");
|
|
594
459
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
| Normal | 0.2% | 0.2% | 1% | 1% |
|
|
600
|
-
| Mode 1 | 0.3% | 0.1% | 0.25% | 4% |
|
|
601
|
-
| Mode 2 | **Disabled** | 0% | 0% | 8% |
|
|
460
|
+
// Calculate expected LST and set minOut
|
|
461
|
+
const lstPrice = await client.getLSTPriceUSD(BSC_ADDRESSES.slisBNB);
|
|
462
|
+
const expectedLST = (apUSDAmount * parseAmount("1")) / lstPrice;
|
|
463
|
+
const minOut = expectedLST * 995n / 1000n;
|
|
602
464
|
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
// fees.apUSDMintDisabled - true in Mode 2
|
|
465
|
+
const hash = await client.redeemApUSD({
|
|
466
|
+
lstToken: BSC_ADDRESSES.slisBNB,
|
|
467
|
+
apUSDAmount,
|
|
468
|
+
minOut,
|
|
469
|
+
});
|
|
609
470
|
```
|
|
610
471
|
|
|
611
|
-
###
|
|
612
|
-
|
|
613
|
-
| Metric | SDK Method | Description |
|
|
614
|
-
|--------|------------|-------------|
|
|
615
|
-
| **Total Staked** | `getTotalStaked()` | apUSD in stability pool |
|
|
616
|
-
| **Exchange Rate** | `getExchangeRate()` | sApUSD to apUSD ratio |
|
|
617
|
-
| **Pending Yield** | `getPendingYield()` | Yield waiting to be distributed |
|
|
618
|
-
| **Total Generated** | `getTotalYieldGenerated()` | All-time yield |
|
|
472
|
+
### Flow 3: Stake apUSD to Earn Yield (sApUSD)
|
|
619
473
|
|
|
620
474
|
```typescript
|
|
475
|
+
// Check pool stats
|
|
621
476
|
const poolStats = await client.getStabilityPoolStats();
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
// APY calculation (Section 6.2-6.3)
|
|
625
|
-
// APY = LST_yield_rate * (TVL / staked_apUSD)
|
|
626
|
-
const amplification = stats.tvlInUSD / poolStats.totalStaked;
|
|
627
|
-
const estimatedAPY = 0.08 * Number(amplification); // Assuming 8% LST yield
|
|
628
|
-
```
|
|
629
|
-
|
|
630
|
-
### LST Information
|
|
631
|
-
|
|
632
|
-
```typescript
|
|
633
|
-
// Get all supported LSTs
|
|
634
|
-
const lsts = await client.getSupportedLSTs();
|
|
635
|
-
|
|
636
|
-
for (const lst of lsts) {
|
|
637
|
-
const info = await client.getLSTInfo(lst);
|
|
638
|
-
const price = await client.getLSTPriceUSD(lst);
|
|
639
|
-
const collateral = await client.getLSTCollateral(lst);
|
|
640
|
-
const yieldInfo = await client.getLSTYieldInfo(lst);
|
|
641
|
-
|
|
642
|
-
console.log(`LST: ${lst}`);
|
|
643
|
-
console.log(` Accepted: ${info.isAccepted}`);
|
|
644
|
-
console.log(` Collateral: ${formatAmount(collateral)}`);
|
|
645
|
-
console.log(` Price: $${formatAmount(price)}`);
|
|
646
|
-
console.log(` Exchange Rate: ${formatAmount(yieldInfo.lastExchangeRate)}`);
|
|
647
|
-
}
|
|
648
|
-
```
|
|
649
|
-
|
|
650
|
-
### Oracle / Prices
|
|
477
|
+
console.log("Exchange Rate:", formatAmount(poolStats.exchangeRate));
|
|
651
478
|
|
|
652
|
-
|
|
653
|
-
const
|
|
654
|
-
console.log("BNB Price:", formatPriceUSD(bnbPrice));
|
|
655
|
-
// Note: BNB price is 8 decimals (Chainlink format)
|
|
479
|
+
// Deposit apUSD
|
|
480
|
+
const hash = await client.deposit({ apUSDAmount: parseAmount("1000") });
|
|
656
481
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
482
|
+
// Check position
|
|
483
|
+
const position = await client.getUserStabilityPoolPosition(account.address);
|
|
484
|
+
console.log("Balance (incl. yield):", formatAmount(position.balance));
|
|
660
485
|
```
|
|
661
486
|
|
|
662
487
|
---
|
|
663
488
|
|
|
664
|
-
##
|
|
489
|
+
## Protocol Metrics
|
|
665
490
|
|
|
666
491
|
```typescript
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
formatCR,
|
|
671
|
-
formatFeeBPS,
|
|
672
|
-
formatPriceUSD,
|
|
673
|
-
} from "@aspan/sdk";
|
|
674
|
-
|
|
675
|
-
const DIAMOND = "0xa67e91ebbb709516c563bcf1d9dae355aaf6d2ef";
|
|
676
|
-
const client = createAspanReadClient(DIAMOND);
|
|
677
|
-
|
|
678
|
-
async function displayDashboard() {
|
|
679
|
-
// === Protocol Overview ===
|
|
680
|
-
const stats = await client.getProtocolStats();
|
|
681
|
-
const mode = await client.getStabilityMode();
|
|
682
|
-
const fees = await client.getCurrentFees();
|
|
683
|
-
|
|
684
|
-
console.log("=== Aspan Protocol Dashboard ===");
|
|
685
|
-
console.log(`TVL: $${formatAmount(stats.tvlInUSD)}`);
|
|
686
|
-
console.log(`CR: ${formatCR(stats.collateralRatio)}`);
|
|
687
|
-
console.log(`Stability Mode: ${mode.mode === 0 ? "Normal" : `Mode ${mode.mode}`}`);
|
|
688
|
-
console.log(`Effective Leverage: ${formatAmount(stats.effectiveLeverage)}x`);
|
|
689
|
-
|
|
690
|
-
// === Token Stats ===
|
|
691
|
-
console.log("\n=== Tokens ===");
|
|
692
|
-
console.log(`apUSD Supply: ${formatAmount(stats.apUSDSupply)}`);
|
|
693
|
-
console.log(`xBNB Supply: ${formatAmount(stats.xBNBSupply)}`);
|
|
694
|
-
console.log(`xBNB Price: ${formatAmount(stats.xBNBPriceBNB)} BNB`);
|
|
695
|
-
|
|
696
|
-
// === Current Fees ===
|
|
697
|
-
console.log("\n=== Current Fees ===");
|
|
698
|
-
console.log(`apUSD Mint: ${formatFeeBPS(fees.apUSDMintFee)}${fees.apUSDMintDisabled ? " (DISABLED)" : ""}`);
|
|
699
|
-
console.log(`apUSD Redeem: ${formatFeeBPS(fees.apUSDRedeemFee)}`);
|
|
700
|
-
console.log(`xBNB Mint: ${formatFeeBPS(fees.xBNBMintFee)}`);
|
|
701
|
-
console.log(`xBNB Redeem: ${formatFeeBPS(fees.xBNBRedeemFee)}`);
|
|
702
|
-
|
|
703
|
-
// === Stability Pool ===
|
|
704
|
-
const poolStats = await client.getStabilityPoolStats();
|
|
705
|
-
const yieldStats = await client.getYieldStats();
|
|
706
|
-
|
|
707
|
-
console.log("\n=== Stability Pool (sApUSD) ===");
|
|
708
|
-
console.log(`Total Staked: ${formatAmount(poolStats.totalStaked)} apUSD`);
|
|
709
|
-
console.log(`Exchange Rate: ${formatAmount(poolStats.exchangeRate)}`);
|
|
710
|
-
console.log(`Pending Yield: $${formatAmount(yieldStats.pendingYield)}`);
|
|
711
|
-
console.log(`Total Yield Generated: $${formatAmount(yieldStats.totalYieldGenerated)}`);
|
|
712
|
-
|
|
713
|
-
// === LST Collateral ===
|
|
714
|
-
const lsts = await client.getSupportedLSTs();
|
|
715
|
-
console.log("\n=== LST Collateral ===");
|
|
716
|
-
for (const lst of lsts) {
|
|
717
|
-
const collateral = await client.getLSTCollateral(lst);
|
|
718
|
-
const price = await client.getLSTPriceUSD(lst);
|
|
719
|
-
const value = (collateral * price) / 10n ** 18n;
|
|
720
|
-
console.log(`${lst.slice(0, 10)}...: ${formatAmount(collateral)} ($${formatAmount(value)})`);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
492
|
+
const stats = await client.getProtocolStats();
|
|
493
|
+
const fees = await client.getCurrentFees();
|
|
494
|
+
const mode = await client.getStabilityMode();
|
|
723
495
|
|
|
724
|
-
|
|
496
|
+
console.log("TVL:", formatAmount(stats.tvlInUSD), "USD");
|
|
497
|
+
console.log("CR:", formatCR(stats.collateralRatio));
|
|
498
|
+
console.log("Stability Mode:", mode.mode);
|
|
499
|
+
console.log("xBNB Price:", formatAmount(stats.xBNBPriceBNB), "BNB");
|
|
500
|
+
console.log("Leverage:", formatAmount(stats.effectiveLeverage), "x");
|
|
725
501
|
```
|
|
726
502
|
|
|
727
503
|
---
|
|
728
504
|
|
|
729
505
|
## API Reference
|
|
730
506
|
|
|
731
|
-
###
|
|
732
|
-
|
|
733
|
-
| Option | Type | Required | Description |
|
|
734
|
-
|--------|------|----------|-------------|
|
|
735
|
-
| `diamondAddress` | `Address` | ✅ | Diamond contract address |
|
|
736
|
-
| `chain` | `Chain` | ❌ | Chain config (default: BSC Mainnet) |
|
|
737
|
-
| `rpcUrl` | `string` | ❌ | RPC URL (default: BSC public RPC) |
|
|
738
|
-
| `walletClient` | `WalletClient` | ⚠️ | For browser/wagmi (required if no account) |
|
|
739
|
-
| `account` | `Account` | ⚠️ | For Node.js (required if no walletClient) |
|
|
740
|
-
|
|
741
|
-
> ⚠️ Write client requires either `walletClient` (browser) or `account` (Node.js)
|
|
507
|
+
### Router Write Functions (v2.0.0)
|
|
742
508
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
|
746
|
-
|
|
747
|
-
|
|
|
748
|
-
|
|
|
749
|
-
|
|
|
750
|
-
|
|
|
751
|
-
|
|
|
752
|
-
|
|
|
753
|
-
| **Stability Mode** | `getStabilityMode()`, `canTriggerStabilityMode2()` |
|
|
754
|
-
| **Ownership** | `getOwner()` |
|
|
755
|
-
|
|
756
|
-
### Write Functions
|
|
757
|
-
|
|
758
|
-
| Category | Methods |
|
|
759
|
-
|----------|---------|
|
|
760
|
-
| **Pool** | `mintApUSD()`, `redeemApUSD()`, `mintXBNB()`, `redeemXBNB()` |
|
|
761
|
-
| **Stability Pool** | `deposit()`, `withdraw()`, `withdrawAssets()`, `harvestYield()` |
|
|
509
|
+
| Function | Description |
|
|
510
|
+
|----------|-------------|
|
|
511
|
+
| `swapAndMint(params)` | Swap input token → LST → mint apUSD/xBNB |
|
|
512
|
+
| `swapAndMintDefault(params)` | Simplified swap+mint using default LST |
|
|
513
|
+
| `stakeAndMint(params)` | Stake BNB directly → LST → mint apUSD/xBNB |
|
|
514
|
+
| `mint(params)` | Direct mint apUSD/xBNB with LST |
|
|
515
|
+
| `redeem(params)` | Direct redeem apUSD/xBNB for LST |
|
|
516
|
+
| `redeemAndSwap(params)` | Redeem + swap LST to output token (V3 path, optional unwrapBNB) |
|
|
517
|
+
| `redeemAndRequestUnstake(params)` | Redeem + request native unstake from Lista |
|
|
518
|
+
| `claimUnstake(requestIndex)` | Claim BNB after unbonding period |
|
|
762
519
|
|
|
763
520
|
### Router View Functions
|
|
764
521
|
|
|
765
|
-
|
|
|
766
|
-
|
|
767
|
-
|
|
|
768
|
-
|
|
|
769
|
-
|
|
|
770
|
-
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
|
778
|
-
|
|
779
|
-
|
|
|
780
|
-
|
|
|
522
|
+
| Function | Description |
|
|
523
|
+
|----------|-------------|
|
|
524
|
+
| `previewMint(lst, amount, mintXBNB)` | Preview mint output |
|
|
525
|
+
| `previewRedeem(lst, redeemXBNB, amount)` | Preview redeem output |
|
|
526
|
+
| `getDefaultLST()` | Get default LST address |
|
|
527
|
+
| `isSupportedInputToken(token)` | Check if input token supported |
|
|
528
|
+
| `isSupportedLST(lst)` | Check if LST supported |
|
|
529
|
+
| `getUserWithdrawalIndices(user)` | Get user's unstake request indices |
|
|
530
|
+
| `getWithdrawalStatus(index)` | Check unstake request status |
|
|
531
|
+
|
|
532
|
+
### Diamond Write Functions
|
|
533
|
+
|
|
534
|
+
| Function | Description |
|
|
535
|
+
|----------|-------------|
|
|
536
|
+
| `mintApUSD(params)` | Mint apUSD with LST |
|
|
537
|
+
| `redeemApUSD(params)` | Redeem apUSD for LST |
|
|
538
|
+
| `mintXBNB(params)` | Mint xBNB with LST |
|
|
539
|
+
| `redeemXBNB(params)` | Redeem xBNB for LST |
|
|
540
|
+
| `deposit(params)` | Deposit apUSD to stability pool |
|
|
541
|
+
| `withdraw(params)` | Withdraw from stability pool |
|
|
542
|
+
| `harvestYield()` | Trigger yield distribution |
|
|
781
543
|
|
|
782
544
|
---
|
|
783
545
|
|
|
@@ -790,7 +552,8 @@ import {
|
|
|
790
552
|
formatFeeBPS, // 25 -> "0.25%"
|
|
791
553
|
formatCR, // 15000n -> "150%"
|
|
792
554
|
formatPriceUSD, // 58325000000n -> "$583.25"
|
|
793
|
-
|
|
555
|
+
encodeV3Path, // Encode PancakeSwap V3 swap path
|
|
556
|
+
BSC_ADDRESSES, // All contract addresses
|
|
794
557
|
PRECISION, // 10^18
|
|
795
558
|
BPS_PRECISION, // 10000
|
|
796
559
|
PRICE_PRECISION, // 10^8
|
|
@@ -809,13 +572,8 @@ import {
|
|
|
809
572
|
createRouterTestnetClient,
|
|
810
573
|
} from "@aspan/sdk";
|
|
811
574
|
|
|
812
|
-
// Diamond client (testnet)
|
|
813
575
|
const client = createAspanTestnetReadClient("0x...");
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
// Router client (testnet)
|
|
817
|
-
const routerRead = createRouterTestnetReadClient("0x...");
|
|
818
|
-
const routerWrite = createRouterTestnetClient("0x...", account);
|
|
576
|
+
const router = createRouterTestnetClient("0x...", account);
|
|
819
577
|
```
|
|
820
578
|
|
|
821
579
|
## License
|