@aspan/sdk 0.1.7 → 0.2.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 +273 -11
- package/dist/index.d.mts +1209 -3
- package/dist/index.d.ts +1209 -3
- package/dist/index.js +1111 -32
- package/dist/index.mjs +1109 -32
- package/package.json +1 -1
- package/src/abi/diamond.ts +8 -4
- package/src/abi/router.ts +554 -0
- package/src/bot/config.ts +6 -6
- package/src/bot/monitors/cr-monitor.ts +8 -0
- package/src/bot/monitors/stats-monitor.ts +1 -1
- package/src/client.ts +81 -32
- package/src/index.ts +40 -4
- package/src/router.ts +686 -0
- package/src/types.ts +226 -0
package/README.md
CHANGED
|
@@ -16,6 +16,7 @@ pnpm add @aspan/sdk
|
|
|
16
16
|
| Contract | Address |
|
|
17
17
|
|----------|---------|
|
|
18
18
|
| **Diamond (Main Entry)** | `0x10d25Ae0690533e0BA9E64EC7ae77dbD4fE8A46f` |
|
|
19
|
+
| **Router** | `0x46d4Bb3bB2d0A0a85739A6d467eFB3025388AE2E` |
|
|
19
20
|
| **ApUSD** | `0x1977097E2E5697A6DD91b6732F368a14F50f6B3d` |
|
|
20
21
|
| **XBNB** | `0xB78eB4d5928bAb158Eb23c3154544084cD2661d5` |
|
|
21
22
|
| **SApUSD** | `0xE2BE739C4aA4126ee72D612d9548C38B1B0e5A1b` |
|
|
@@ -85,6 +86,197 @@ const hash = await client.mintApUSD({
|
|
|
85
86
|
|
|
86
87
|
---
|
|
87
88
|
|
|
89
|
+
## Router (One-Click Operations)
|
|
90
|
+
|
|
91
|
+
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.
|
|
92
|
+
|
|
93
|
+
### Router Client Setup
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
import { createRouterClient, AspanRouterClient } from "@aspan/sdk";
|
|
97
|
+
import { privateKeyToAccount } from "viem/accounts";
|
|
98
|
+
import { zeroAddress } from "viem";
|
|
99
|
+
|
|
100
|
+
const ROUTER = "0x46d4Bb3bB2d0A0a85739A6d467eFB3025388AE2E";
|
|
101
|
+
|
|
102
|
+
// Node.js
|
|
103
|
+
const account = privateKeyToAccount("0x...");
|
|
104
|
+
const router = createRouterClient(ROUTER, account);
|
|
105
|
+
|
|
106
|
+
// Browser (wagmi)
|
|
107
|
+
const router = new AspanRouterClient({
|
|
108
|
+
routerAddress: ROUTER,
|
|
109
|
+
walletClient, // from useWalletClient()
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Swap USDT/USDC → apUSD (One-Click)
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
import { parseAmount, type SwapAndMintParams } from "@aspan/sdk";
|
|
117
|
+
import { zeroAddress } from "viem";
|
|
118
|
+
|
|
119
|
+
const USDT = "0x55d398326f99059fF775485246999027B3197955";
|
|
120
|
+
|
|
121
|
+
// Full control with SwapParams + MintParams
|
|
122
|
+
const params: SwapAndMintParams = {
|
|
123
|
+
swapParams: {
|
|
124
|
+
inputToken: USDT,
|
|
125
|
+
inputAmount: parseAmount("100"), // 100 USDT
|
|
126
|
+
targetLST: zeroAddress, // Use default LST
|
|
127
|
+
minLSTOut: 0n, // Or set slippage protection
|
|
128
|
+
poolFee: 2500, // 0.25% V3 pool fee
|
|
129
|
+
useV2: true, // Use PancakeSwap V2
|
|
130
|
+
},
|
|
131
|
+
mintParams: {
|
|
132
|
+
mintXBNB: false, // Mint apUSD
|
|
133
|
+
minMintOut: parseAmount("99"), // Min 99 apUSD (1% slippage)
|
|
134
|
+
recipient: zeroAddress, // Send to msg.sender
|
|
135
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
// Approve USDT first, then swap+mint
|
|
140
|
+
const hash = await router.swapAndMintApUSD(params);
|
|
141
|
+
await router.waitForTransaction(hash);
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Simplified: Swap → apUSD (Default LST)
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Simpler API using default LST and V2
|
|
148
|
+
const hash = await router.swapAndMintApUSDDefault({
|
|
149
|
+
inputToken: USDT,
|
|
150
|
+
inputAmount: parseAmount("100"),
|
|
151
|
+
minMintOut: parseAmount("99"),
|
|
152
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### Stake Native BNB → apUSD (Bypasses DEX)
|
|
157
|
+
|
|
158
|
+
Direct BNB staking gets better rates for large amounts by bypassing DEX.
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
// Stake BNB directly to Lista/Astherus → mint apUSD
|
|
162
|
+
const hash = await router.stakeAndMintApUSD(
|
|
163
|
+
parseAmount("99"), // minMintOut
|
|
164
|
+
parseAmount("1"), // 1 BNB to stake (sent as value)
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
// Or with full control
|
|
168
|
+
const hash = await router.stakeAndMint({
|
|
169
|
+
targetLST: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B", // slisBNB
|
|
170
|
+
mintXBNB: false,
|
|
171
|
+
minMintOut: parseAmount("99"),
|
|
172
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
173
|
+
value: parseAmount("1"), // 1 BNB
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Swap → xBNB (Leveraged Long)
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
// Full params
|
|
181
|
+
const hash = await router.swapAndMintXBNB(params);
|
|
182
|
+
|
|
183
|
+
// Or simplified
|
|
184
|
+
const hash = await router.swapAndMintXBNBDefault({
|
|
185
|
+
inputToken: USDT,
|
|
186
|
+
inputAmount: parseAmount("1000"),
|
|
187
|
+
minMintOut: parseAmount("1"), // Min 1 xBNB
|
|
188
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
// Or stake BNB directly
|
|
192
|
+
const hash = await router.stakeAndMintXBNB(parseAmount("1"), parseAmount("10"));
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Direct Mint/Redeem via Router
|
|
196
|
+
|
|
197
|
+
If you already have LST, use direct functions (still routes through Diamond):
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
// Mint apUSD with LST
|
|
201
|
+
const hash = await router.mintApUSD({
|
|
202
|
+
lst: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B", // slisBNB
|
|
203
|
+
lstAmount: parseAmount("10"),
|
|
204
|
+
minOut: parseAmount("99"),
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
// Redeem apUSD for LST
|
|
208
|
+
const hash = await router.redeemApUSD({
|
|
209
|
+
lst: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B",
|
|
210
|
+
apUSDAmount: parseAmount("100"),
|
|
211
|
+
minOut: parseAmount("0.9"),
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Redeem + Swap to USDT/BNB
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
// Redeem apUSD and swap LST to USDT
|
|
219
|
+
const hash = await router.redeemApUSDAndSwap({
|
|
220
|
+
lst: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B",
|
|
221
|
+
amount: parseAmount("100"), // 100 apUSD
|
|
222
|
+
outputToken: USDT, // Get USDT
|
|
223
|
+
minOut: parseAmount("99"), // Min 99 USDT
|
|
224
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
225
|
+
useV2: true,
|
|
226
|
+
poolFee: 2500,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// Redeem and get native BNB instantly (via DEX swap)
|
|
230
|
+
const hash = await router.redeemApUSDAndUnstake({
|
|
231
|
+
lst: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B",
|
|
232
|
+
amount: parseAmount("100"),
|
|
233
|
+
minBNBOut: parseAmount("0.1"),
|
|
234
|
+
deadline: BigInt(Math.floor(Date.now() / 1000) + 3600),
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Native Unstake (7-15 Day Unbonding)
|
|
239
|
+
|
|
240
|
+
For no-slippage BNB redemption, use Lista's native unstake:
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Request unstake (starts 7-15 day unbonding period)
|
|
244
|
+
const hash = await router.redeemApUSDAndRequestUnstake(parseAmount("100"));
|
|
245
|
+
const receipt = await router.waitForTransaction(hash);
|
|
246
|
+
// Parse event to get requestIndex...
|
|
247
|
+
|
|
248
|
+
// Check withdrawal status
|
|
249
|
+
const indices = await router.getUserWithdrawalIndices(account.address);
|
|
250
|
+
for (const idx of indices) {
|
|
251
|
+
const status = await router.getWithdrawalStatus(idx);
|
|
252
|
+
console.log(`Request ${idx}: claimable=${status.isClaimable}, amount=${status.bnbAmount}`);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Claim BNB after unbonding
|
|
256
|
+
const hash = await router.claimUnstake(requestIndex);
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Router View Functions
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
// Check supported tokens
|
|
263
|
+
const defaultLST = await router.getDefaultLST();
|
|
264
|
+
const isSupported = await router.isSupportedInputToken(USDT);
|
|
265
|
+
const isLSTSupported = await router.isSupportedLST(slisBNB);
|
|
266
|
+
|
|
267
|
+
// Preview swap output
|
|
268
|
+
const output = await router.getExpectedOutput(USDT, parseAmount("100"), zeroAddress, false);
|
|
269
|
+
console.log("Expected LST:", output.expectedLST);
|
|
270
|
+
console.log("Expected apUSD:", output.expectedMint);
|
|
271
|
+
|
|
272
|
+
// Get token addresses
|
|
273
|
+
const wbnb = await router.getWBNB();
|
|
274
|
+
const usdt = await router.getUSDT();
|
|
275
|
+
const slisBNB = await router.getSlisBNB();
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
88
280
|
## User Flows
|
|
89
281
|
|
|
90
282
|
### Flow 1: Mint apUSD (Stablecoin)
|
|
@@ -124,8 +316,12 @@ function MintComponent() {
|
|
|
124
316
|
// Step 3: Approve LST (use wagmi's useWriteContract or viem)
|
|
125
317
|
// ...
|
|
126
318
|
|
|
127
|
-
// Step 4:
|
|
128
|
-
const
|
|
319
|
+
// Step 4: Calculate minOut for slippage protection (e.g., 0.5% slippage)
|
|
320
|
+
const expectedApUSD = lstAmount; // Simplified, use actual calculation
|
|
321
|
+
const minOut = expectedApUSD * 995n / 1000n; // 0.5% slippage
|
|
322
|
+
|
|
323
|
+
// Step 5: Mint apUSD
|
|
324
|
+
const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount, minOut });
|
|
129
325
|
const receipt = await client.waitForTransaction(hash);
|
|
130
326
|
console.log("Minted apUSD:", receipt.status);
|
|
131
327
|
};
|
|
@@ -161,8 +357,9 @@ if (fees.apUSDMintDisabled) throw new Error("Minting disabled in current CR");
|
|
|
161
357
|
// args: [DIAMOND, lstAmount],
|
|
162
358
|
// });
|
|
163
359
|
|
|
164
|
-
// Step 4: Mint apUSD
|
|
165
|
-
const
|
|
360
|
+
// Step 4: Mint apUSD with slippage protection
|
|
361
|
+
const minOut = lstAmount * 995n / 1000n; // 0.5% slippage tolerance
|
|
362
|
+
const hash = await client.mintApUSD({ lstToken: SLISBNB, lstAmount, minOut });
|
|
166
363
|
const receipt = await client.waitForTransaction(hash);
|
|
167
364
|
console.log("Minted apUSD:", receipt.status);
|
|
168
365
|
```
|
|
@@ -181,8 +378,13 @@ const maxRedeemable = (collateral * lstPrice) / parseAmount("1");
|
|
|
181
378
|
console.log("Max redeemable:", formatAmount(maxRedeemable), "USD");
|
|
182
379
|
|
|
183
380
|
// Step 2: Approve apUSD spending (use viem directly)
|
|
184
|
-
|
|
185
|
-
|
|
381
|
+
|
|
382
|
+
// Step 3: Calculate expected LST output and set minOut
|
|
383
|
+
const expectedLST = (apUSDAmount * parseAmount("1")) / lstPrice;
|
|
384
|
+
const minOut = expectedLST * 995n / 1000n; // 0.5% slippage
|
|
385
|
+
|
|
386
|
+
// Step 4: Redeem with slippage protection
|
|
387
|
+
const hash = await client.redeemApUSD({ lstToken: SLISBNB, apUSDAmount, minOut });
|
|
186
388
|
await client.waitForTransaction(hash);
|
|
187
389
|
```
|
|
188
390
|
|
|
@@ -202,12 +404,46 @@ if (xBNBPrice === 0n) {
|
|
|
202
404
|
throw new Error("xBNB underwater - cannot mint");
|
|
203
405
|
}
|
|
204
406
|
|
|
205
|
-
// Step 3: Approve LST, then mint xBNB
|
|
206
|
-
const
|
|
407
|
+
// Step 3: Approve LST, then mint xBNB with slippage protection
|
|
408
|
+
const minOut = 0n; // Set appropriate minOut based on expected xBNB output
|
|
409
|
+
const hash = await client.mintXBNB({ lstToken: SLISBNB, lstAmount, minOut });
|
|
207
410
|
await client.waitForTransaction(hash);
|
|
208
411
|
```
|
|
209
412
|
|
|
210
|
-
### Flow 4:
|
|
413
|
+
### Flow 4: Redeem xBNB for LST
|
|
414
|
+
|
|
415
|
+
User burns xBNB to get back LST.
|
|
416
|
+
|
|
417
|
+
```typescript
|
|
418
|
+
const xBNBAmount = parseAmount("100"); // 100 xBNB
|
|
419
|
+
|
|
420
|
+
// Step 1: Check xBNB price (ensure not underwater)
|
|
421
|
+
const xBNBPrice = await client.getXBNBPriceBNB();
|
|
422
|
+
if (xBNBPrice === 0n) {
|
|
423
|
+
throw new Error("xBNB is underwater - redemption may result in 0 LST");
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Step 2: Check current fees
|
|
427
|
+
const fees = await client.getCurrentFees();
|
|
428
|
+
console.log("xBNB Redeem fee:", fees.xBNBRedeemFee / 100, "%");
|
|
429
|
+
|
|
430
|
+
// Step 3: Check available LST liquidity
|
|
431
|
+
const collateral = await client.getLSTCollateral(SLISBNB);
|
|
432
|
+
console.log("Available collateral:", formatAmount(collateral));
|
|
433
|
+
|
|
434
|
+
// Step 4: Approve xBNB spending (use viem directly)
|
|
435
|
+
// ...
|
|
436
|
+
|
|
437
|
+
// Step 5: Calculate expected LST and set minOut for slippage protection
|
|
438
|
+
const expectedLST = (xBNBAmount * xBNBPrice) / parseAmount("1");
|
|
439
|
+
const minOut = expectedLST * 995n / 1000n; // 0.5% slippage
|
|
440
|
+
|
|
441
|
+
// Step 6: Redeem xBNB
|
|
442
|
+
const hash = await client.redeemXBNB({ lstToken: SLISBNB, xBNBAmount, minOut });
|
|
443
|
+
await client.waitForTransaction(hash);
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
### Flow 5: Stake apUSD to Earn Yield (sApUSD)
|
|
211
447
|
|
|
212
448
|
User deposits apUSD to stability pool to earn LST yield.
|
|
213
449
|
|
|
@@ -232,7 +468,7 @@ console.log("Shares:", formatAmount(position.shares));
|
|
|
232
468
|
console.log("Balance (incl. yield):", formatAmount(position.balance));
|
|
233
469
|
```
|
|
234
470
|
|
|
235
|
-
### Flow
|
|
471
|
+
### Flow 6: Withdraw from Stability Pool
|
|
236
472
|
|
|
237
473
|
User withdraws their staked apUSD plus accumulated yield.
|
|
238
474
|
|
|
@@ -255,7 +491,7 @@ await client.waitForTransaction(hash);
|
|
|
255
491
|
// const hash = await client.withdrawAssets({ assets: parseAmount("500") });
|
|
256
492
|
```
|
|
257
493
|
|
|
258
|
-
### Flow
|
|
494
|
+
### Flow 7: Manual Yield Harvest
|
|
259
495
|
|
|
260
496
|
Anyone can trigger yield harvest to distribute pending LST yield.
|
|
261
497
|
|
|
@@ -517,6 +753,25 @@ displayDashboard();
|
|
|
517
753
|
| **Pool** | `mintApUSD()`, `redeemApUSD()`, `mintXBNB()`, `redeemXBNB()` |
|
|
518
754
|
| **Stability Pool** | `deposit()`, `withdraw()`, `withdrawAssets()`, `harvestYield()` |
|
|
519
755
|
|
|
756
|
+
### Router View Functions
|
|
757
|
+
|
|
758
|
+
| Category | Methods |
|
|
759
|
+
|----------|---------|
|
|
760
|
+
| **Config** | `getDefaultLST()`, `isSupportedInputToken()`, `isSupportedLST()`, `getDiamond()` |
|
|
761
|
+
| **Preview** | `getExpectedOutput()` |
|
|
762
|
+
| **Unstake** | `getUserWithdrawalIndices()`, `getWithdrawalStatus()` |
|
|
763
|
+
| **Addresses** | `getWBNB()`, `getUSDT()`, `getUSDC()`, `getSlisBNB()`, `getAsBNB()`, `getWclisBNB()`, `getApUSD()`, `getXBNB()` |
|
|
764
|
+
|
|
765
|
+
### Router Write Functions
|
|
766
|
+
|
|
767
|
+
| Category | Methods |
|
|
768
|
+
|----------|---------|
|
|
769
|
+
| **Swap+Mint** | `swapAndMintApUSD()`, `swapAndMintXBNB()`, `swapAndMintApUSDDefault()`, `swapAndMintXBNBDefault()` |
|
|
770
|
+
| **Stake+Mint** | `stakeAndMint()`, `stakeAndMintApUSD()`, `stakeAndMintXBNB()` |
|
|
771
|
+
| **Direct** | `mintApUSD()`, `mintXBNB()`, `redeemApUSD()`, `redeemXBNB()` |
|
|
772
|
+
| **Redeem+Swap** | `redeemApUSDAndSwap()`, `redeemXBNBAndSwap()`, `redeemApUSDAndUnstake()`, `redeemXBNBAndUnstake()` |
|
|
773
|
+
| **Native Unstake** | `redeemApUSDAndRequestUnstake()`, `redeemXBNBAndRequestUnstake()`, `claimUnstake()` |
|
|
774
|
+
|
|
520
775
|
---
|
|
521
776
|
|
|
522
777
|
## Utility Functions
|
|
@@ -543,10 +798,17 @@ import {
|
|
|
543
798
|
import {
|
|
544
799
|
createAspanTestnetReadClient,
|
|
545
800
|
createAspanTestnetClient,
|
|
801
|
+
createRouterTestnetReadClient,
|
|
802
|
+
createRouterTestnetClient,
|
|
546
803
|
} from "@aspan/sdk";
|
|
547
804
|
|
|
805
|
+
// Diamond client (testnet)
|
|
548
806
|
const client = createAspanTestnetReadClient("0x...");
|
|
549
807
|
const writeClient = createAspanTestnetClient("0x...", account);
|
|
808
|
+
|
|
809
|
+
// Router client (testnet)
|
|
810
|
+
const routerRead = createRouterTestnetReadClient("0x...");
|
|
811
|
+
const routerWrite = createRouterTestnetClient("0x...", account);
|
|
550
812
|
```
|
|
551
813
|
|
|
552
814
|
## License
|