@aspan/sdk 0.4.3 → 0.4.5

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/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",
package/src/client.ts CHANGED
@@ -54,6 +54,7 @@ export function getChainById(chainId: number): Chain {
54
54
  return chain;
55
55
  }
56
56
  import { DiamondABI } from "./abi/diamond";
57
+ import { SApUSDABI } from "./abi/sApUSD";
57
58
  import type {
58
59
  LSTInfo,
59
60
  LSTYieldInfo,
@@ -525,6 +526,20 @@ export class AspanReadClient {
525
526
  });
526
527
  }
527
528
 
529
+ /**
530
+ * Get user's underlying balances (apUSD + xBNB) from sApUSD vault
531
+ */
532
+ async getBalanceMulti(user: Address): Promise<{ apUSDBalance: bigint; xBNBBalance: bigint }> {
533
+ const sApUSDAddress = await this.getSApUSD();
534
+ const [apUSDBalance, xBNBBalance] = await this.publicClient.readContract({
535
+ address: sApUSDAddress,
536
+ abi: SApUSDABI,
537
+ functionName: "underlyingBalances",
538
+ args: [user],
539
+ });
540
+ return { apUSDBalance, xBNBBalance };
541
+ }
542
+
528
543
  async getUserStabilityPoolPosition(
529
544
  user: Address
530
545
  ): Promise<UserStabilityPoolPosition> {
@@ -599,6 +614,37 @@ export class AspanReadClient {
599
614
  }
600
615
  }
601
616
 
617
+ /**
618
+ * Preview withdraw with multi-asset support (apUSD + xBNB)
619
+ * @param shares Amount of sApUSD shares to redeem
620
+ * @returns Object with apUSD and xBNB amounts, plus whether vault has xBNB
621
+ */
622
+ async previewRedeemMulti(shares: bigint): Promise<{
623
+ apUSD: bigint;
624
+ xBNB: bigint;
625
+ hasXBNB: boolean;
626
+ }> {
627
+ const sApUSDAddress = await this.getSApUSD();
628
+ const [result, conversion] = await Promise.all([
629
+ this.publicClient.readContract({
630
+ address: sApUSDAddress,
631
+ abi: SApUSDABI,
632
+ functionName: "previewRedeemMulti",
633
+ args: [shares],
634
+ }) as Promise<[Address[], bigint[]]>,
635
+ this.publicClient.readContract({
636
+ address: sApUSDAddress,
637
+ abi: SApUSDABI,
638
+ functionName: "hasStabilityConversion",
639
+ }) as Promise<[boolean, bigint]>,
640
+ ]);
641
+ return {
642
+ apUSD: result[1][0],
643
+ xBNB: result[1][1],
644
+ hasXBNB: conversion[0],
645
+ };
646
+ }
647
+
602
648
  async getPendingYield(): Promise<bigint> {
603
649
  try {
604
650
  return await this.publicClient.readContract({
@@ -770,6 +816,122 @@ export class AspanReadClient {
770
816
  };
771
817
  }
772
818
 
819
+ /**
820
+ * Get all fee tiers
821
+ * @returns Array of fee tiers sorted by minCR descending
822
+ */
823
+ async getAllFeeTiers(): Promise<FeeTier[]> {
824
+ const result = await this.publicClient.readContract({
825
+ address: this.diamondAddress,
826
+ abi: DiamondABI,
827
+ functionName: "getAllFeeTiers",
828
+ }) as unknown as Array<{
829
+ minCR: bigint;
830
+ apUSDMintFee: number;
831
+ apUSDRedeemFee: number;
832
+ xBNBMintFee: number;
833
+ xBNBRedeemFee: number;
834
+ apUSDMintDisabled: boolean;
835
+ }>;
836
+ return result.map((tier) => ({
837
+ minCR: tier.minCR,
838
+ apUSDMintFee: tier.apUSDMintFee,
839
+ apUSDRedeemFee: tier.apUSDRedeemFee,
840
+ xBNBMintFee: tier.xBNBMintFee,
841
+ xBNBRedeemFee: tier.xBNBRedeemFee,
842
+ apUSDMintDisabled: tier.apUSDMintDisabled,
843
+ }));
844
+ }
845
+
846
+ /**
847
+ * Get comprehensive vault (sApUSD) info for frontend display
848
+ * @returns Vault state including TVL, exchange rate, xBNB status
849
+ */
850
+ async getVaultInfo(): Promise<{
851
+ totalSupply: bigint;
852
+ totalAssets: bigint;
853
+ exchangeRate: bigint;
854
+ hasXBNB: boolean;
855
+ xBNBAmount: bigint;
856
+ }> {
857
+ const sApUSDAddress = await this.getSApUSD();
858
+ const [totalSupply, totalAssets, exchangeRate, conversion] = await Promise.all([
859
+ this.publicClient.readContract({
860
+ address: sApUSDAddress,
861
+ abi: SApUSDABI,
862
+ functionName: "totalSupply",
863
+ }) as Promise<bigint>,
864
+ this.publicClient.readContract({
865
+ address: sApUSDAddress,
866
+ abi: SApUSDABI,
867
+ functionName: "totalAssets",
868
+ }) as Promise<bigint>,
869
+ this.publicClient.readContract({
870
+ address: sApUSDAddress,
871
+ abi: SApUSDABI,
872
+ functionName: "exchangeRate",
873
+ }) as Promise<bigint>,
874
+ this.publicClient.readContract({
875
+ address: sApUSDAddress,
876
+ abi: SApUSDABI,
877
+ functionName: "hasStabilityConversion",
878
+ }) as Promise<[boolean, bigint]>,
879
+ ]);
880
+ return {
881
+ totalSupply,
882
+ totalAssets,
883
+ exchangeRate,
884
+ hasXBNB: conversion[0],
885
+ xBNBAmount: conversion[1],
886
+ };
887
+ }
888
+
889
+ /**
890
+ * Get full protocol dashboard data in one call (for frontend overview page)
891
+ * Batches all key metrics into a single multicall
892
+ */
893
+ async getProtocolOverview(): Promise<{
894
+ collateralRatio: bigint;
895
+ tvlBNB: bigint;
896
+ tvlUSD: bigint;
897
+ apUSDSupply: bigint;
898
+ xBNBSupply: bigint;
899
+ xBNBPriceUSD: bigint;
900
+ xBNBPriceBNB: bigint;
901
+ bnbPriceUSD: bigint;
902
+ currentFees: CurrentFeeTier;
903
+ stabilityMode: StabilityModeInfo;
904
+ totalStaked: bigint;
905
+ }> {
906
+ const [cr, tvlBNB, tvlUSD, apUSD, xBNB, xPriceUSD, xPriceBNB, bnbPrice, fees, sm, staked] =
907
+ await Promise.all([
908
+ this.getCollateralRatio(),
909
+ this.getTVLInBNB(),
910
+ this.getTVLInUSD(),
911
+ this.getApUSDSupply(),
912
+ this.getXBNBSupply(),
913
+ this.getXBNBPriceUSD(),
914
+ this.getXBNBPriceBNB(),
915
+ this.getBNBPriceUSD(),
916
+ this.getCurrentFeeTier(),
917
+ this.getStabilityMode(),
918
+ this.getTotalStaked(),
919
+ ]);
920
+ return {
921
+ collateralRatio: cr,
922
+ tvlBNB,
923
+ tvlUSD,
924
+ apUSDSupply: apUSD,
925
+ xBNBSupply: xBNB,
926
+ xBNBPriceUSD: xPriceUSD,
927
+ xBNBPriceBNB: xPriceBNB,
928
+ bnbPriceUSD: bnbPrice,
929
+ currentFees: fees,
930
+ stabilityMode: sm,
931
+ totalStaked: staked,
932
+ };
933
+ }
934
+
773
935
  async getCurrentFeeTier(): Promise<CurrentFeeTier> {
774
936
  try {
775
937
  const result = await this.publicClient.readContract({
@@ -1115,22 +1277,36 @@ export class AspanClient extends AspanReadClient {
1115
1277
  }
1116
1278
 
1117
1279
  /**
1118
- * Clean underwater xBNB (burn without getting LST back)
1119
- * @description Only works when xBNB is underwater (price = 0)
1120
- * @param xBNBAmount Amount of xBNB to clean (burn)
1280
+ * Clean xBNB from sApUSD vault by converting back to apUSD
1281
+ * @param xBNBAmount Amount of xBNB to clean
1282
+ * @param minApUSDOut Minimum apUSD to receive (slippage protection)
1121
1283
  * @returns Transaction hash
1122
1284
  */
1123
- async cleanXbnb(xBNBAmount: bigint): Promise<Hash> {
1285
+ async cleanVaultXBNB(xBNBAmount: bigint, minApUSDOut: bigint = 0n): Promise<Hash> {
1124
1286
  return this.walletClient.writeContract({
1125
1287
  chain: this.chain,
1126
1288
  account: this.walletClient.account!,
1127
1289
  address: this.diamondAddress,
1128
1290
  abi: DiamondABI,
1129
- functionName: "cleanXbnb",
1130
- args: [xBNBAmount],
1291
+ functionName: "cleanVaultXBNB",
1292
+ args: [xBNBAmount, minApUSDOut],
1131
1293
  });
1132
1294
  }
1133
1295
 
1296
+ /**
1297
+ * Preview how much apUSD would be minted from cleaning xBNB
1298
+ * @param xBNBAmount Amount of xBNB to preview
1299
+ * @returns apUSD amount that would be minted
1300
+ */
1301
+ async previewCleanVaultXBNB(xBNBAmount: bigint): Promise<bigint> {
1302
+ return this.publicClient.readContract({
1303
+ address: this.diamondAddress,
1304
+ abi: DiamondABI,
1305
+ functionName: "previewCleanVaultXBNB",
1306
+ args: [xBNBAmount],
1307
+ }) as Promise<bigint>;
1308
+ }
1309
+
1134
1310
  // ============ Fee Management Functions ============
1135
1311
 
1136
1312
  /**
package/src/index.ts CHANGED
@@ -120,7 +120,7 @@ export const BSC_ADDRESSES = {
120
120
  router: "0x29dd49b2e98674ee7531f17e4d40a7725918c3f6" as const,
121
121
  apUSD: "0x4570047eeB5aDb4081c5d470494EB5134e34A287" as const,
122
122
  xBNB: "0x0A0c9CD826e747D99F90D63e780B3727Da4D0d43" as const,
123
- sApUSD: "0x73407A291c007a47CC926EcD5CaC256A1E2d00cF" as const,
123
+ sApUSD: "0x896770Dba7c0481539E25aaB56bE285ECF6D65eB" as const,
124
124
  // LSTs
125
125
  slisBNB: "0xB0b84D294e0C75A6abe60171b70edEb2EFd14A1B" as const,
126
126
  asBNB: "0x77734e70b6E88b4d82fE632a168EDf6e700912b6" as const,