@aspan/sdk 0.4.4 → 0.4.6
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 +8 -0
- package/dist/index.d.mts +116 -1
- package/dist/index.d.ts +116 -1
- package/dist/index.js +289 -14
- package/dist/index.mjs +289 -14
- package/package.json +1 -1
- package/src/__tests__/read-client.test.ts +212 -0
- package/src/abi/diamond.ts +36 -0
- package/src/abi/sApUSD.ts +36 -0
- package/src/client.ts +160 -14
package/dist/index.mjs
CHANGED
|
@@ -305,6 +305,16 @@ var DiamondABI = [
|
|
|
305
305
|
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
306
306
|
stateMutability: "view"
|
|
307
307
|
},
|
|
308
|
+
{
|
|
309
|
+
type: "function",
|
|
310
|
+
name: "previewRedeemMulti",
|
|
311
|
+
inputs: [{ name: "_shares", type: "uint256", internalType: "uint256" }],
|
|
312
|
+
outputs: [
|
|
313
|
+
{ name: "assets", type: "address[]", internalType: "address[]" },
|
|
314
|
+
{ name: "amounts", type: "uint256[]", internalType: "uint256[]" }
|
|
315
|
+
],
|
|
316
|
+
stateMutability: "view"
|
|
317
|
+
},
|
|
308
318
|
{
|
|
309
319
|
type: "function",
|
|
310
320
|
name: "getPendingYield",
|
|
@@ -405,6 +415,13 @@ var DiamondABI = [
|
|
|
405
415
|
outputs: [{ name: "", type: "address", internalType: "address" }],
|
|
406
416
|
stateMutability: "view"
|
|
407
417
|
},
|
|
418
|
+
{
|
|
419
|
+
type: "function",
|
|
420
|
+
name: "setSApUSD",
|
|
421
|
+
inputs: [{ name: "_sApUSD", type: "address", internalType: "address" }],
|
|
422
|
+
outputs: [],
|
|
423
|
+
stateMutability: "nonpayable"
|
|
424
|
+
},
|
|
408
425
|
{
|
|
409
426
|
type: "function",
|
|
410
427
|
name: "getStabilityPool",
|
|
@@ -426,6 +443,25 @@ var DiamondABI = [
|
|
|
426
443
|
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
427
444
|
stateMutability: "view"
|
|
428
445
|
},
|
|
446
|
+
{
|
|
447
|
+
type: "function",
|
|
448
|
+
name: "getAllFeeTiers",
|
|
449
|
+
inputs: [],
|
|
450
|
+
outputs: [{
|
|
451
|
+
name: "",
|
|
452
|
+
type: "tuple[]",
|
|
453
|
+
internalType: "struct LibAppStorage.FeeTier[]",
|
|
454
|
+
components: [
|
|
455
|
+
{ name: "minCR", type: "uint256", internalType: "uint256" },
|
|
456
|
+
{ name: "apUSDMintFee", type: "uint16", internalType: "uint16" },
|
|
457
|
+
{ name: "apUSDRedeemFee", type: "uint16", internalType: "uint16" },
|
|
458
|
+
{ name: "xBNBMintFee", type: "uint16", internalType: "uint16" },
|
|
459
|
+
{ name: "xBNBRedeemFee", type: "uint16", internalType: "uint16" },
|
|
460
|
+
{ name: "apUSDMintDisabled", type: "bool", internalType: "bool" }
|
|
461
|
+
]
|
|
462
|
+
}],
|
|
463
|
+
stateMutability: "view"
|
|
464
|
+
},
|
|
429
465
|
{
|
|
430
466
|
type: "function",
|
|
431
467
|
name: "getFeeTier",
|
|
@@ -619,6 +655,138 @@ var DiamondABI = [
|
|
|
619
655
|
}
|
|
620
656
|
];
|
|
621
657
|
|
|
658
|
+
// src/abi/sApUSD.ts
|
|
659
|
+
var SApUSDABI = [
|
|
660
|
+
// ============ View Functions ============
|
|
661
|
+
{
|
|
662
|
+
type: "function",
|
|
663
|
+
name: "totalAssets",
|
|
664
|
+
inputs: [],
|
|
665
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
666
|
+
stateMutability: "view"
|
|
667
|
+
},
|
|
668
|
+
{
|
|
669
|
+
type: "function",
|
|
670
|
+
name: "totalSupply",
|
|
671
|
+
inputs: [],
|
|
672
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
673
|
+
stateMutability: "view"
|
|
674
|
+
},
|
|
675
|
+
{
|
|
676
|
+
type: "function",
|
|
677
|
+
name: "balanceOf",
|
|
678
|
+
inputs: [{ name: "account", type: "address", internalType: "address" }],
|
|
679
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
680
|
+
stateMutability: "view"
|
|
681
|
+
},
|
|
682
|
+
{
|
|
683
|
+
type: "function",
|
|
684
|
+
name: "previewRedeemMulti",
|
|
685
|
+
inputs: [
|
|
686
|
+
{ name: "shares", type: "uint256", internalType: "uint256" }
|
|
687
|
+
],
|
|
688
|
+
outputs: [
|
|
689
|
+
{ name: "assets", type: "address[]", internalType: "address[]" },
|
|
690
|
+
{ name: "amounts", type: "uint256[]", internalType: "uint256[]" }
|
|
691
|
+
],
|
|
692
|
+
stateMutability: "view"
|
|
693
|
+
},
|
|
694
|
+
{
|
|
695
|
+
type: "function",
|
|
696
|
+
name: "hasStabilityConversion",
|
|
697
|
+
inputs: [],
|
|
698
|
+
outputs: [
|
|
699
|
+
{ name: "hasXBNB", type: "bool", internalType: "bool" },
|
|
700
|
+
{ name: "xBNBAmount", type: "uint256", internalType: "uint256" }
|
|
701
|
+
],
|
|
702
|
+
stateMutability: "view"
|
|
703
|
+
},
|
|
704
|
+
{
|
|
705
|
+
type: "function",
|
|
706
|
+
name: "totalValue",
|
|
707
|
+
inputs: [],
|
|
708
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
709
|
+
stateMutability: "view"
|
|
710
|
+
},
|
|
711
|
+
{
|
|
712
|
+
type: "function",
|
|
713
|
+
name: "underlyingBalances",
|
|
714
|
+
inputs: [{ name: "_user", type: "address", internalType: "address" }],
|
|
715
|
+
outputs: [
|
|
716
|
+
{ name: "apUSDBalance", type: "uint256", internalType: "uint256" },
|
|
717
|
+
{ name: "xBNBBalance", type: "uint256", internalType: "uint256" }
|
|
718
|
+
],
|
|
719
|
+
stateMutability: "view"
|
|
720
|
+
},
|
|
721
|
+
{
|
|
722
|
+
type: "function",
|
|
723
|
+
name: "xBNBToApUSDRate",
|
|
724
|
+
inputs: [],
|
|
725
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
726
|
+
stateMutability: "view"
|
|
727
|
+
},
|
|
728
|
+
{
|
|
729
|
+
type: "function",
|
|
730
|
+
name: "exchangeRate",
|
|
731
|
+
inputs: [],
|
|
732
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
733
|
+
stateMutability: "view"
|
|
734
|
+
},
|
|
735
|
+
{
|
|
736
|
+
type: "function",
|
|
737
|
+
name: "previewCleanXBNB",
|
|
738
|
+
inputs: [
|
|
739
|
+
{ name: "_xBNBAmount", type: "uint256", internalType: "uint256" },
|
|
740
|
+
{ name: "_router", type: "address", internalType: "address" },
|
|
741
|
+
{ name: "_path", type: "address[]", internalType: "address[]" }
|
|
742
|
+
],
|
|
743
|
+
outputs: [{ name: "expectedApUSD", type: "uint256", internalType: "uint256" }],
|
|
744
|
+
stateMutability: "view"
|
|
745
|
+
},
|
|
746
|
+
{
|
|
747
|
+
type: "function",
|
|
748
|
+
name: "KEEPER_ROLE",
|
|
749
|
+
inputs: [],
|
|
750
|
+
outputs: [{ name: "", type: "bytes32", internalType: "bytes32" }],
|
|
751
|
+
stateMutability: "view"
|
|
752
|
+
},
|
|
753
|
+
{
|
|
754
|
+
type: "function",
|
|
755
|
+
name: "hasRole",
|
|
756
|
+
inputs: [
|
|
757
|
+
{ name: "role", type: "bytes32", internalType: "bytes32" },
|
|
758
|
+
{ name: "account", type: "address", internalType: "address" }
|
|
759
|
+
],
|
|
760
|
+
outputs: [{ name: "", type: "bool", internalType: "bool" }],
|
|
761
|
+
stateMutability: "view"
|
|
762
|
+
},
|
|
763
|
+
// ============ Keeper Functions ============
|
|
764
|
+
{
|
|
765
|
+
type: "function",
|
|
766
|
+
name: "cleanXBNB",
|
|
767
|
+
inputs: [
|
|
768
|
+
{ name: "_xBNBAmount", type: "uint256", internalType: "uint256" },
|
|
769
|
+
{ name: "_minApUSDOut", type: "uint256", internalType: "uint256" },
|
|
770
|
+
{ name: "_router", type: "address", internalType: "address" },
|
|
771
|
+
{ name: "_path", type: "address[]", internalType: "address[]" },
|
|
772
|
+
{ name: "_deadline", type: "uint256", internalType: "uint256" }
|
|
773
|
+
],
|
|
774
|
+
outputs: [{ name: "apUSDReceived", type: "uint256", internalType: "uint256" }],
|
|
775
|
+
stateMutability: "nonpayable"
|
|
776
|
+
},
|
|
777
|
+
// ============ Events ============
|
|
778
|
+
{
|
|
779
|
+
type: "event",
|
|
780
|
+
name: "VaultCleaned",
|
|
781
|
+
inputs: [
|
|
782
|
+
{ name: "xBNBSold", type: "uint256", indexed: false, internalType: "uint256" },
|
|
783
|
+
{ name: "apUSDReceived", type: "uint256", indexed: false, internalType: "uint256" },
|
|
784
|
+
{ name: "keeper", type: "address", indexed: true, internalType: "address" }
|
|
785
|
+
],
|
|
786
|
+
anonymous: false
|
|
787
|
+
}
|
|
788
|
+
];
|
|
789
|
+
|
|
622
790
|
// src/client.ts
|
|
623
791
|
var pharosTestnet = {
|
|
624
792
|
id: 688689,
|
|
@@ -1012,6 +1180,19 @@ var AspanReadClient = class _AspanReadClient {
|
|
|
1012
1180
|
args: [user]
|
|
1013
1181
|
});
|
|
1014
1182
|
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Get user's underlying balances (apUSD + xBNB) from sApUSD vault
|
|
1185
|
+
*/
|
|
1186
|
+
async getBalanceMulti(user) {
|
|
1187
|
+
const sApUSDAddress = await this.getSApUSD();
|
|
1188
|
+
const [apUSDBalance, xBNBBalance] = await this.publicClient.readContract({
|
|
1189
|
+
address: sApUSDAddress,
|
|
1190
|
+
abi: SApUSDABI,
|
|
1191
|
+
functionName: "underlyingBalances",
|
|
1192
|
+
args: [user]
|
|
1193
|
+
});
|
|
1194
|
+
return { apUSDBalance, xBNBBalance };
|
|
1195
|
+
}
|
|
1015
1196
|
async getUserStabilityPoolPosition(user) {
|
|
1016
1197
|
const [shares, balance] = await Promise.all([
|
|
1017
1198
|
this.getShares(user),
|
|
@@ -1062,20 +1243,27 @@ var AspanReadClient = class _AspanReadClient {
|
|
|
1062
1243
|
throw error;
|
|
1063
1244
|
}
|
|
1064
1245
|
}
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1246
|
+
/**
|
|
1247
|
+
* Preview withdraw with multi-asset support (apUSD + xBNB)
|
|
1248
|
+
* Replaces previewRedeem — works for both clean and dirty pools.
|
|
1249
|
+
* @param shares Amount of sApUSD shares to redeem
|
|
1250
|
+
* @returns Object with apUSD and xBNB amounts, plus whether vault has xBNB
|
|
1251
|
+
*/
|
|
1252
|
+
async previewRedeemMulti(shares) {
|
|
1253
|
+
const [assets, amounts] = await this.publicClient.readContract({
|
|
1254
|
+
address: this.diamondAddress,
|
|
1255
|
+
abi: DiamondABI,
|
|
1256
|
+
functionName: "previewRedeemMulti",
|
|
1257
|
+
args: [shares]
|
|
1258
|
+
});
|
|
1259
|
+
const hasXBNB = amounts.length > 1 && amounts[1] > 0n;
|
|
1260
|
+
return {
|
|
1261
|
+
apUSD: amounts[0] ?? 0n,
|
|
1262
|
+
xBNB: amounts[1] ?? 0n,
|
|
1263
|
+
hasXBNB,
|
|
1264
|
+
assets,
|
|
1265
|
+
amounts
|
|
1266
|
+
};
|
|
1079
1267
|
}
|
|
1080
1268
|
async getPendingYield() {
|
|
1081
1269
|
try {
|
|
@@ -1230,6 +1418,93 @@ var AspanReadClient = class _AspanReadClient {
|
|
|
1230
1418
|
apUSDMintDisabled: result[5]
|
|
1231
1419
|
};
|
|
1232
1420
|
}
|
|
1421
|
+
/**
|
|
1422
|
+
* Get all fee tiers
|
|
1423
|
+
* @returns Array of fee tiers sorted by minCR descending
|
|
1424
|
+
*/
|
|
1425
|
+
async getAllFeeTiers() {
|
|
1426
|
+
const result = await this.publicClient.readContract({
|
|
1427
|
+
address: this.diamondAddress,
|
|
1428
|
+
abi: DiamondABI,
|
|
1429
|
+
functionName: "getAllFeeTiers"
|
|
1430
|
+
});
|
|
1431
|
+
return result.map((tier) => ({
|
|
1432
|
+
minCR: tier.minCR,
|
|
1433
|
+
apUSDMintFee: tier.apUSDMintFee,
|
|
1434
|
+
apUSDRedeemFee: tier.apUSDRedeemFee,
|
|
1435
|
+
xBNBMintFee: tier.xBNBMintFee,
|
|
1436
|
+
xBNBRedeemFee: tier.xBNBRedeemFee,
|
|
1437
|
+
apUSDMintDisabled: tier.apUSDMintDisabled
|
|
1438
|
+
}));
|
|
1439
|
+
}
|
|
1440
|
+
/**
|
|
1441
|
+
* Get comprehensive vault (sApUSD) info for frontend display
|
|
1442
|
+
* @returns Vault state including TVL, exchange rate, xBNB status
|
|
1443
|
+
*/
|
|
1444
|
+
async getVaultInfo() {
|
|
1445
|
+
const sApUSDAddress = await this.getSApUSD();
|
|
1446
|
+
const [totalSupply, totalAssets, exchangeRate, conversion] = await Promise.all([
|
|
1447
|
+
this.publicClient.readContract({
|
|
1448
|
+
address: sApUSDAddress,
|
|
1449
|
+
abi: SApUSDABI,
|
|
1450
|
+
functionName: "totalSupply"
|
|
1451
|
+
}),
|
|
1452
|
+
this.publicClient.readContract({
|
|
1453
|
+
address: sApUSDAddress,
|
|
1454
|
+
abi: SApUSDABI,
|
|
1455
|
+
functionName: "totalAssets"
|
|
1456
|
+
}),
|
|
1457
|
+
this.publicClient.readContract({
|
|
1458
|
+
address: sApUSDAddress,
|
|
1459
|
+
abi: SApUSDABI,
|
|
1460
|
+
functionName: "exchangeRate"
|
|
1461
|
+
}),
|
|
1462
|
+
this.publicClient.readContract({
|
|
1463
|
+
address: sApUSDAddress,
|
|
1464
|
+
abi: SApUSDABI,
|
|
1465
|
+
functionName: "hasStabilityConversion"
|
|
1466
|
+
})
|
|
1467
|
+
]);
|
|
1468
|
+
return {
|
|
1469
|
+
totalSupply,
|
|
1470
|
+
totalAssets,
|
|
1471
|
+
exchangeRate,
|
|
1472
|
+
hasXBNB: conversion[0],
|
|
1473
|
+
xBNBAmount: conversion[1]
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Get full protocol dashboard data in one call (for frontend overview page)
|
|
1478
|
+
* Batches all key metrics into a single multicall
|
|
1479
|
+
*/
|
|
1480
|
+
async getProtocolOverview() {
|
|
1481
|
+
const [cr, tvlBNB, tvlUSD, apUSD, xBNB, xPriceUSD, xPriceBNB, bnbPrice, fees, sm, staked] = await Promise.all([
|
|
1482
|
+
this.getCollateralRatio(),
|
|
1483
|
+
this.getTVLInBNB(),
|
|
1484
|
+
this.getTVLInUSD(),
|
|
1485
|
+
this.getApUSDSupply(),
|
|
1486
|
+
this.getXBNBSupply(),
|
|
1487
|
+
this.getXBNBPriceUSD(),
|
|
1488
|
+
this.getXBNBPriceBNB(),
|
|
1489
|
+
this.getBNBPriceUSD(),
|
|
1490
|
+
this.getCurrentFeeTier(),
|
|
1491
|
+
this.getStabilityMode(),
|
|
1492
|
+
this.getTotalStaked()
|
|
1493
|
+
]);
|
|
1494
|
+
return {
|
|
1495
|
+
collateralRatio: cr,
|
|
1496
|
+
tvlBNB,
|
|
1497
|
+
tvlUSD,
|
|
1498
|
+
apUSDSupply: apUSD,
|
|
1499
|
+
xBNBSupply: xBNB,
|
|
1500
|
+
xBNBPriceUSD: xPriceUSD,
|
|
1501
|
+
xBNBPriceBNB: xPriceBNB,
|
|
1502
|
+
bnbPriceUSD: bnbPrice,
|
|
1503
|
+
currentFees: fees,
|
|
1504
|
+
stabilityMode: sm,
|
|
1505
|
+
totalStaked: staked
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1233
1508
|
async getCurrentFeeTier() {
|
|
1234
1509
|
try {
|
|
1235
1510
|
const result = await this.publicClient.readContract({
|
package/package.json
CHANGED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AspanReadClient Tests - Read-only queries against BSC mainnet
|
|
3
|
+
*
|
|
4
|
+
* Tests new SDK methods: previewRedeemMulti, getVaultInfo, getAllFeeTiers, getProtocolOverview
|
|
5
|
+
* No wallet/private key needed — pure view calls.
|
|
6
|
+
*
|
|
7
|
+
* Run with: npm test -- read-client
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeAll } from "vitest";
|
|
11
|
+
import { parseEther, zeroAddress, type Address } from "viem";
|
|
12
|
+
import { bsc } from "viem/chains";
|
|
13
|
+
import { AspanReadClient, BSC_ADDRESSES } from "../index";
|
|
14
|
+
|
|
15
|
+
// ============ Configuration ============
|
|
16
|
+
|
|
17
|
+
const DIAMOND = BSC_ADDRESSES.diamond;
|
|
18
|
+
const RPC_URL = process.env.BSC_RPC_URL || "https://bsc-dataseed.binance.org";
|
|
19
|
+
|
|
20
|
+
describe("AspanReadClient - View Functions", () => {
|
|
21
|
+
let client: AspanReadClient;
|
|
22
|
+
|
|
23
|
+
beforeAll(() => {
|
|
24
|
+
client = new AspanReadClient({
|
|
25
|
+
diamondAddress: DIAMOND,
|
|
26
|
+
chain: bsc,
|
|
27
|
+
rpcUrl: RPC_URL,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
// ============ Vault Info ============
|
|
32
|
+
|
|
33
|
+
describe("getVaultInfo", () => {
|
|
34
|
+
it("should return vault state with all fields", async () => {
|
|
35
|
+
const info = await client.getVaultInfo();
|
|
36
|
+
|
|
37
|
+
expect(info).toHaveProperty("totalSupply");
|
|
38
|
+
expect(info).toHaveProperty("totalAssets");
|
|
39
|
+
expect(info).toHaveProperty("exchangeRate");
|
|
40
|
+
expect(info).toHaveProperty("hasXBNB");
|
|
41
|
+
expect(info).toHaveProperty("xBNBAmount");
|
|
42
|
+
|
|
43
|
+
expect(typeof info.totalSupply).toBe("bigint");
|
|
44
|
+
expect(typeof info.totalAssets).toBe("bigint");
|
|
45
|
+
expect(typeof info.exchangeRate).toBe("bigint");
|
|
46
|
+
expect(typeof info.hasXBNB).toBe("boolean");
|
|
47
|
+
expect(typeof info.xBNBAmount).toBe("bigint");
|
|
48
|
+
|
|
49
|
+
// Exchange rate should be > 0 (at least 1e18 for 1:1)
|
|
50
|
+
expect(info.exchangeRate).toBeGreaterThan(0n);
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// ============ Preview Redeem Multi ============
|
|
55
|
+
|
|
56
|
+
describe("previewRedeemMulti", () => {
|
|
57
|
+
it("should return apUSD and xBNB amounts for given shares", async () => {
|
|
58
|
+
const shares = parseEther("1"); // 1 share
|
|
59
|
+
const preview = await client.previewRedeemMulti(shares);
|
|
60
|
+
|
|
61
|
+
expect(preview).toHaveProperty("apUSD");
|
|
62
|
+
expect(preview).toHaveProperty("xBNB");
|
|
63
|
+
expect(preview).toHaveProperty("hasXBNB");
|
|
64
|
+
|
|
65
|
+
expect(typeof preview.apUSD).toBe("bigint");
|
|
66
|
+
expect(typeof preview.xBNB).toBe("bigint");
|
|
67
|
+
expect(typeof preview.hasXBNB).toBe("boolean");
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should return zero for zero shares", async () => {
|
|
71
|
+
const preview = await client.previewRedeemMulti(0n);
|
|
72
|
+
|
|
73
|
+
expect(preview.apUSD).toBe(0n);
|
|
74
|
+
expect(preview.xBNB).toBe(0n);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("should have consistent hasXBNB with getVaultInfo", async () => {
|
|
78
|
+
const shares = parseEther("1");
|
|
79
|
+
const [preview, vault] = await Promise.all([
|
|
80
|
+
client.previewRedeemMulti(shares),
|
|
81
|
+
client.getVaultInfo(),
|
|
82
|
+
]);
|
|
83
|
+
|
|
84
|
+
expect(preview.hasXBNB).toBe(vault.hasXBNB);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
// ============ Fee Tiers ============
|
|
89
|
+
|
|
90
|
+
describe("getAllFeeTiers", () => {
|
|
91
|
+
it("should return non-empty array of fee tiers", async () => {
|
|
92
|
+
const tiers = await client.getAllFeeTiers();
|
|
93
|
+
|
|
94
|
+
expect(Array.isArray(tiers)).toBe(true);
|
|
95
|
+
expect(tiers.length).toBeGreaterThan(0);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should have correct fee tier structure", async () => {
|
|
99
|
+
const tiers = await client.getAllFeeTiers();
|
|
100
|
+
const tier = tiers[0];
|
|
101
|
+
|
|
102
|
+
expect(tier).toHaveProperty("minCR");
|
|
103
|
+
expect(tier).toHaveProperty("apUSDMintFee");
|
|
104
|
+
expect(tier).toHaveProperty("apUSDRedeemFee");
|
|
105
|
+
expect(tier).toHaveProperty("xBNBMintFee");
|
|
106
|
+
expect(tier).toHaveProperty("xBNBRedeemFee");
|
|
107
|
+
expect(tier).toHaveProperty("apUSDMintDisabled");
|
|
108
|
+
|
|
109
|
+
expect(typeof tier.minCR).toBe("bigint");
|
|
110
|
+
expect(typeof tier.apUSDMintDisabled).toBe("boolean");
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should be sorted by minCR descending", async () => {
|
|
114
|
+
const tiers = await client.getAllFeeTiers();
|
|
115
|
+
|
|
116
|
+
for (let i = 1; i < tiers.length; i++) {
|
|
117
|
+
expect(tiers[i - 1].minCR).toBeGreaterThanOrEqual(tiers[i].minCR);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should match getFeeTierCount", async () => {
|
|
122
|
+
const [tiers, count] = await Promise.all([
|
|
123
|
+
client.getAllFeeTiers(),
|
|
124
|
+
client.getFeeTierCount(),
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
expect(BigInt(tiers.length)).toBe(count);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ============ Protocol Overview ============
|
|
132
|
+
|
|
133
|
+
describe("getProtocolOverview", () => {
|
|
134
|
+
it("should return all protocol metrics", async () => {
|
|
135
|
+
const overview = await client.getProtocolOverview();
|
|
136
|
+
|
|
137
|
+
expect(overview).toHaveProperty("collateralRatio");
|
|
138
|
+
expect(overview).toHaveProperty("tvlBNB");
|
|
139
|
+
expect(overview).toHaveProperty("tvlUSD");
|
|
140
|
+
expect(overview).toHaveProperty("apUSDSupply");
|
|
141
|
+
expect(overview).toHaveProperty("xBNBSupply");
|
|
142
|
+
expect(overview).toHaveProperty("xBNBPriceUSD");
|
|
143
|
+
expect(overview).toHaveProperty("xBNBPriceBNB");
|
|
144
|
+
expect(overview).toHaveProperty("bnbPriceUSD");
|
|
145
|
+
expect(overview).toHaveProperty("currentFees");
|
|
146
|
+
expect(overview).toHaveProperty("stabilityMode");
|
|
147
|
+
expect(overview).toHaveProperty("totalStaked");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("should have positive TVL and prices", async () => {
|
|
151
|
+
const overview = await client.getProtocolOverview();
|
|
152
|
+
|
|
153
|
+
expect(overview.tvlBNB).toBeGreaterThan(0n);
|
|
154
|
+
expect(overview.tvlUSD).toBeGreaterThan(0n);
|
|
155
|
+
expect(overview.bnbPriceUSD).toBeGreaterThan(0n);
|
|
156
|
+
expect(overview.collateralRatio).toBeGreaterThan(0n);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should have valid currentFees structure", async () => {
|
|
160
|
+
const overview = await client.getProtocolOverview();
|
|
161
|
+
const fees = overview.currentFees;
|
|
162
|
+
|
|
163
|
+
expect(fees).toHaveProperty("minCR");
|
|
164
|
+
expect(fees).toHaveProperty("apUSDMintFee");
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should have valid stabilityMode structure", async () => {
|
|
168
|
+
const overview = await client.getProtocolOverview();
|
|
169
|
+
const sm = overview.stabilityMode;
|
|
170
|
+
|
|
171
|
+
expect(sm).toHaveProperty("mode");
|
|
172
|
+
// mode should be 0 (normal), 1, or 2
|
|
173
|
+
expect([0, 1, 2]).toContain(sm.mode);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
// ============ Existing view methods consistency ============
|
|
178
|
+
|
|
179
|
+
describe("cross-method consistency", () => {
|
|
180
|
+
it("vault totalStaked should match getVaultInfo totalSupply context", async () => {
|
|
181
|
+
const [staked, vault] = await Promise.all([
|
|
182
|
+
client.getTotalStaked(),
|
|
183
|
+
client.getVaultInfo(),
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
// totalStaked from Diamond should relate to vault totalAssets
|
|
187
|
+
expect(typeof staked).toBe("bigint");
|
|
188
|
+
expect(typeof vault.totalAssets).toBe("bigint");
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it("exchangeRate from getVaultInfo should match getExchangeRate", async () => {
|
|
192
|
+
const [vault, rate] = await Promise.all([
|
|
193
|
+
client.getVaultInfo(),
|
|
194
|
+
client.getExchangeRate(),
|
|
195
|
+
]);
|
|
196
|
+
|
|
197
|
+
expect(vault.exchangeRate).toBe(rate);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
describe("getBalanceMulti", () => {
|
|
202
|
+
it("should return apUSD and xBNB balances for a user", async () => {
|
|
203
|
+
const testUser = zeroAddress; // zero address will have 0 balances
|
|
204
|
+
const result = await client.getBalanceMulti(testUser);
|
|
205
|
+
|
|
206
|
+
expect(typeof result.apUSDBalance).toBe("bigint");
|
|
207
|
+
expect(typeof result.xBNBBalance).toBe("bigint");
|
|
208
|
+
expect(result.apUSDBalance).toBe(0n);
|
|
209
|
+
expect(result.xBNBBalance).toBe(0n);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
});
|
package/src/abi/diamond.ts
CHANGED
|
@@ -303,6 +303,16 @@ export const DiamondABI = [
|
|
|
303
303
|
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
304
304
|
stateMutability: "view"
|
|
305
305
|
},
|
|
306
|
+
{
|
|
307
|
+
type: "function",
|
|
308
|
+
name: "previewRedeemMulti",
|
|
309
|
+
inputs: [{ name: "_shares", type: "uint256", internalType: "uint256" }],
|
|
310
|
+
outputs: [
|
|
311
|
+
{ name: "assets", type: "address[]", internalType: "address[]" },
|
|
312
|
+
{ name: "amounts", type: "uint256[]", internalType: "uint256[]" }
|
|
313
|
+
],
|
|
314
|
+
stateMutability: "view"
|
|
315
|
+
},
|
|
306
316
|
{
|
|
307
317
|
type: "function",
|
|
308
318
|
name: "getPendingYield",
|
|
@@ -406,6 +416,13 @@ export const DiamondABI = [
|
|
|
406
416
|
outputs: [{ name: "", type: "address", internalType: "address" }],
|
|
407
417
|
stateMutability: "view"
|
|
408
418
|
},
|
|
419
|
+
{
|
|
420
|
+
type: "function",
|
|
421
|
+
name: "setSApUSD",
|
|
422
|
+
inputs: [{ name: "_sApUSD", type: "address", internalType: "address" }],
|
|
423
|
+
outputs: [],
|
|
424
|
+
stateMutability: "nonpayable"
|
|
425
|
+
},
|
|
409
426
|
{
|
|
410
427
|
type: "function",
|
|
411
428
|
name: "getStabilityPool",
|
|
@@ -427,6 +444,25 @@ export const DiamondABI = [
|
|
|
427
444
|
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
428
445
|
stateMutability: "view"
|
|
429
446
|
},
|
|
447
|
+
{
|
|
448
|
+
type: "function",
|
|
449
|
+
name: "getAllFeeTiers",
|
|
450
|
+
inputs: [],
|
|
451
|
+
outputs: [{
|
|
452
|
+
name: "",
|
|
453
|
+
type: "tuple[]",
|
|
454
|
+
internalType: "struct LibAppStorage.FeeTier[]",
|
|
455
|
+
components: [
|
|
456
|
+
{ name: "minCR", type: "uint256", internalType: "uint256" },
|
|
457
|
+
{ name: "apUSDMintFee", type: "uint16", internalType: "uint16" },
|
|
458
|
+
{ name: "apUSDRedeemFee", type: "uint16", internalType: "uint16" },
|
|
459
|
+
{ name: "xBNBMintFee", type: "uint16", internalType: "uint16" },
|
|
460
|
+
{ name: "xBNBRedeemFee", type: "uint16", internalType: "uint16" },
|
|
461
|
+
{ name: "apUSDMintDisabled", type: "bool", internalType: "bool" },
|
|
462
|
+
],
|
|
463
|
+
}],
|
|
464
|
+
stateMutability: "view"
|
|
465
|
+
},
|
|
430
466
|
{
|
|
431
467
|
type: "function",
|
|
432
468
|
name: "getFeeTier",
|
package/src/abi/sApUSD.ts
CHANGED
|
@@ -25,6 +25,18 @@ export const SApUSDABI = [
|
|
|
25
25
|
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
26
26
|
stateMutability: "view"
|
|
27
27
|
},
|
|
28
|
+
{
|
|
29
|
+
type: "function",
|
|
30
|
+
name: "previewRedeemMulti",
|
|
31
|
+
inputs: [
|
|
32
|
+
{ name: "shares", type: "uint256", internalType: "uint256" }
|
|
33
|
+
],
|
|
34
|
+
outputs: [
|
|
35
|
+
{ name: "assets", type: "address[]", internalType: "address[]" },
|
|
36
|
+
{ name: "amounts", type: "uint256[]", internalType: "uint256[]" }
|
|
37
|
+
],
|
|
38
|
+
stateMutability: "view"
|
|
39
|
+
},
|
|
28
40
|
{
|
|
29
41
|
type: "function",
|
|
30
42
|
name: "hasStabilityConversion",
|
|
@@ -35,6 +47,30 @@ export const SApUSDABI = [
|
|
|
35
47
|
],
|
|
36
48
|
stateMutability: "view"
|
|
37
49
|
},
|
|
50
|
+
{
|
|
51
|
+
type: "function",
|
|
52
|
+
name: "totalValue",
|
|
53
|
+
inputs: [],
|
|
54
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
55
|
+
stateMutability: "view"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
type: "function",
|
|
59
|
+
name: "underlyingBalances",
|
|
60
|
+
inputs: [{ name: "_user", type: "address", internalType: "address" }],
|
|
61
|
+
outputs: [
|
|
62
|
+
{ name: "apUSDBalance", type: "uint256", internalType: "uint256" },
|
|
63
|
+
{ name: "xBNBBalance", type: "uint256", internalType: "uint256" }
|
|
64
|
+
],
|
|
65
|
+
stateMutability: "view"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
type: "function",
|
|
69
|
+
name: "xBNBToApUSDRate",
|
|
70
|
+
inputs: [],
|
|
71
|
+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
|
|
72
|
+
stateMutability: "view"
|
|
73
|
+
},
|
|
38
74
|
{
|
|
39
75
|
type: "function",
|
|
40
76
|
name: "exchangeRate",
|