@sodax/dapp-kit 2.0.0-rc.11 → 2.0.0-rc.13

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.
Files changed (35) hide show
  1. package/README.md +5 -5
  2. package/dist/index.d.ts +282 -8
  3. package/dist/index.mjs +290 -47
  4. package/package.json +2 -2
  5. package/src/hooks/_mutationContract.test.ts +6 -1
  6. package/src/hooks/bitcoin/resolveBtcReadAddress.test.ts +54 -0
  7. package/src/hooks/bitcoin/resolveBtcReadAddress.ts +21 -0
  8. package/src/hooks/bitcoin/useFundTradingWallet.ts +1 -1
  9. package/src/hooks/bitcoin/useRadfiAuth.ts +2 -2
  10. package/src/hooks/bitcoin/useRadfiWithdraw.ts +2 -2
  11. package/src/hooks/bitcoin/useRenewUtxos.ts +2 -2
  12. package/src/hooks/bitcoin/useTradingWallet.ts +1 -1
  13. package/src/hooks/index.ts +1 -0
  14. package/src/hooks/leverageYield/index.ts +9 -0
  15. package/src/hooks/leverageYield/useLeverageYieldDeposit.ts +40 -0
  16. package/src/hooks/leverageYield/useLeverageYieldEffectiveApr.ts +42 -0
  17. package/src/hooks/leverageYield/useLeverageYieldNotifySolver.ts +34 -0
  18. package/src/hooks/leverageYield/useLeverageYieldPosition.ts +40 -0
  19. package/src/hooks/leverageYield/useLeverageYieldPreviewRedeem.ts +43 -0
  20. package/src/hooks/leverageYield/useLeverageYieldShareBalances.ts +74 -0
  21. package/src/hooks/leverageYield/useLeverageYieldTotalAssets.ts +36 -0
  22. package/src/hooks/leverageYield/useLeverageYieldVaultSwap.ts +50 -0
  23. package/src/hooks/leverageYield/useLeverageYieldWithdraw.ts +40 -0
  24. package/src/hooks/mm/useATokensBalances.ts +7 -1
  25. package/src/hooks/mm/useUserFormattedSummary.ts +5 -1
  26. package/src/hooks/mm/useUserReservesData.ts +5 -1
  27. package/src/hooks/shared/index.ts +3 -0
  28. package/src/hooks/shared/useGetUserHubWalletAddress.ts +5 -1
  29. package/src/hooks/shared/useNearStorageCheck.ts +45 -0
  30. package/src/hooks/shared/useNearStorageGate.ts +60 -0
  31. package/src/hooks/shared/useRegisterNearStorage.ts +46 -0
  32. package/src/providers/SodaxProvider.tsx +2 -3
  33. package/src/utils/index.ts +1 -0
  34. package/src/utils/nearStorageGate.test.ts +46 -0
  35. package/src/utils/nearStorageGate.ts +39 -0
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useMutation, useQuery, useQueryClient, QueryClient, MutationCache } from '@tanstack/react-query';
1
+ import { useMutation, useQuery, useQueryClient, useQueries, QueryClient, MutationCache } from '@tanstack/react-query';
2
2
  import { createContext, useCallback, useContext, useState, useRef, useEffect, useMemo } from 'react';
3
3
  import { ChainKeys, RadfiApiError, normalizePsbtToBase64, ClService, Sodax } from '@sodax/sdk';
4
4
  export * from '@sodax/sdk';
@@ -140,59 +140,76 @@ function useRequestTrustline(token) {
140
140
  );
141
141
  return { requestTrustline, isLoading, isRequested, error, data };
142
142
  }
143
- function useGetUserHubWalletAddress({
143
+ function useNearStorageCheck({
144
144
  params,
145
145
  queryOptions
146
146
  } = {}) {
147
147
  const { sodax } = useSodaxContext();
148
- const spokeChainId = params?.spokeChainId;
149
- const spokeAddress = params?.spokeAddress;
148
+ const token = params?.token;
149
+ const accountId = params?.accountId;
150
+ const chainId = params?.chainId;
150
151
  return useQuery({
151
- queryKey: ["shared", "userHubWalletAddress", spokeChainId, spokeAddress],
152
+ queryKey: ["shared", "nearStorageCheck", chainId, token, accountId],
152
153
  queryFn: async () => {
153
- if (!spokeChainId || !spokeAddress) {
154
- throw new Error("Spoke chain id and address are required");
155
- }
156
- return await sodax.hubProvider.getUserHubWalletAddress(spokeAddress, spokeChainId);
154
+ if (chainId !== ChainKeys.NEAR_MAINNET) return true;
155
+ if (!token || !accountId) return false;
156
+ return sodax.spoke.near.isStorageRegistered(token, accountId);
157
157
  },
158
- enabled: !!spokeChainId && !!spokeAddress,
159
- refetchInterval: false,
158
+ enabled: !!token && !!accountId,
160
159
  ...queryOptions
161
160
  });
162
161
  }
163
- var REFETCH_INTERVAL_MS = 5e3;
164
- function getXBalancesQueryOptions({ xService, xChainId, xTokens, address }) {
165
- return {
166
- // Pair symbol + address: readable in devtools, unique on-chain (symbol alone
167
- // can collide — e.g. scam tokens copying legitimate ticker).
168
- queryKey: ["shared", "xBalances", xChainId, xTokens.map((x) => [x.symbol, x.address]), address],
169
- queryFn: async () => {
170
- if (!xService) return {};
171
- return xService.getBalances(address, xTokens);
172
- },
173
- enabled: !!xService && !!address && xTokens.length > 0,
174
- refetchInterval: REFETCH_INTERVAL_MS
175
- };
176
- }
177
- function useXBalances({
178
- params,
179
- queryOptions
162
+ function useRegisterNearStorage({
163
+ mutationOptions
180
164
  } = {}) {
181
- return useQuery({
182
- ...getXBalancesQueryOptions({
183
- xService: params?.xService,
184
- xChainId: params?.xChainId,
185
- xTokens: params?.xTokens ?? [],
186
- address: params?.address
187
- }),
188
- ...queryOptions
165
+ const { sodax } = useSodaxContext();
166
+ const queryClient = useQueryClient();
167
+ return useSafeMutation({
168
+ mutationKey: ["shared", "registerNearStorage"],
169
+ ...mutationOptions,
170
+ mutationFn: async ({ token, accountId, walletProvider, deposit }) => sodax.spoke.near.registerStorage({ token, accountId, walletProvider, deposit, raw: false }),
171
+ onSuccess: async (data, vars, ctx) => {
172
+ queryClient.invalidateQueries({
173
+ queryKey: ["shared", "nearStorageCheck", ChainKeys.NEAR_MAINNET, vars.token, vars.accountId]
174
+ });
175
+ await mutationOptions?.onSuccess?.(data, vars, ctx);
176
+ }
189
177
  });
190
178
  }
179
+ function resolveNearStorageGate(chainKey, check) {
180
+ const isNear = chainKey === ChainKeys.NEAR_MAINNET;
181
+ const isChecking = check.isLoading;
182
+ const isRegistered = check.data;
183
+ return {
184
+ isNear,
185
+ needsRegistration: isNear && !isChecking && isRegistered === false,
186
+ blocksAction: isNear && (isChecking || isRegistered === false)
187
+ };
188
+ }
191
189
 
192
- // src/hooks/provider/useHubProvider.ts
193
- function useHubProvider() {
194
- const { sodax } = useSodaxContext();
195
- return sodax.hubProvider;
190
+ // src/hooks/shared/useNearStorageGate.ts
191
+ function useNearStorageGate({
192
+ dstChainKey,
193
+ token,
194
+ accountId,
195
+ walletProvider
196
+ }) {
197
+ const nearWalletProvider = walletProvider?.chainType === "NEAR" ? walletProvider : void 0;
198
+ const storageCheck = useNearStorageCheck({ params: { token, accountId, chainId: dstChainKey } });
199
+ const { mutateAsyncSafe: register, isPending: isRegistering } = useRegisterNearStorage();
200
+ const { isNear, needsRegistration, blocksAction } = resolveNearStorageGate(dstChainKey, storageCheck);
201
+ const registerStorage = async () => {
202
+ if (!nearWalletProvider || !token || !accountId) return void 0;
203
+ return register({ token, accountId, walletProvider: nearWalletProvider });
204
+ };
205
+ return {
206
+ isNear,
207
+ needsRegistration,
208
+ blocksAction,
209
+ isChecking: storageCheck.isLoading,
210
+ isRegistering,
211
+ registerStorage
212
+ };
196
213
  }
197
214
  var SESSION_KEY = (address) => `radfi_session_${address}`;
198
215
  function saveRadfiSession(address, session) {
@@ -254,7 +271,7 @@ function useRadfiAuth({
254
271
  clearRadfiSession(walletAddress);
255
272
  }
256
273
  throw new Error(
257
- "This wallet is already registered with Radfi from another session. Please clear your browser storage for this site and try again, or wait for the previous session to expire."
274
+ "This wallet is already registered with Bound Exchange from another session. Please clear your browser storage for this site and try again, or wait for the previous session to expire."
258
275
  );
259
276
  }
260
277
  throw err;
@@ -262,6 +279,71 @@ function useRadfiAuth({
262
279
  }
263
280
  });
264
281
  }
282
+
283
+ // src/hooks/bitcoin/resolveBtcReadAddress.ts
284
+ function resolveBtcReadAddress(chainKey, address) {
285
+ if (chainKey !== ChainKeys.BITCOIN_MAINNET) return address;
286
+ return loadRadfiSession(address)?.tradingAddress ?? address;
287
+ }
288
+
289
+ // src/hooks/shared/useGetUserHubWalletAddress.ts
290
+ function useGetUserHubWalletAddress({
291
+ params,
292
+ queryOptions
293
+ } = {}) {
294
+ const { sodax } = useSodaxContext();
295
+ const spokeChainId = params?.spokeChainId;
296
+ const spokeAddress = params?.spokeAddress;
297
+ return useQuery({
298
+ queryKey: ["shared", "userHubWalletAddress", spokeChainId, spokeAddress],
299
+ queryFn: async () => {
300
+ if (!spokeChainId || !spokeAddress) {
301
+ throw new Error("Spoke chain id and address are required");
302
+ }
303
+ return await sodax.hubProvider.getUserHubWalletAddress(
304
+ resolveBtcReadAddress(spokeChainId, spokeAddress),
305
+ spokeChainId
306
+ );
307
+ },
308
+ enabled: !!spokeChainId && !!spokeAddress,
309
+ refetchInterval: false,
310
+ ...queryOptions
311
+ });
312
+ }
313
+ var REFETCH_INTERVAL_MS = 5e3;
314
+ function getXBalancesQueryOptions({ xService, xChainId, xTokens, address }) {
315
+ return {
316
+ // Pair symbol + address: readable in devtools, unique on-chain (symbol alone
317
+ // can collide — e.g. scam tokens copying legitimate ticker).
318
+ queryKey: ["shared", "xBalances", xChainId, xTokens.map((x) => [x.symbol, x.address]), address],
319
+ queryFn: async () => {
320
+ if (!xService) return {};
321
+ return xService.getBalances(address, xTokens);
322
+ },
323
+ enabled: !!xService && !!address && xTokens.length > 0,
324
+ refetchInterval: REFETCH_INTERVAL_MS
325
+ };
326
+ }
327
+ function useXBalances({
328
+ params,
329
+ queryOptions
330
+ } = {}) {
331
+ return useQuery({
332
+ ...getXBalancesQueryOptions({
333
+ xService: params?.xService,
334
+ xChainId: params?.xChainId,
335
+ xTokens: params?.xTokens ?? [],
336
+ address: params?.address
337
+ }),
338
+ ...queryOptions
339
+ });
340
+ }
341
+
342
+ // src/hooks/provider/useHubProvider.ts
343
+ function useHubProvider() {
344
+ const { sodax } = useSodaxContext();
345
+ return sodax.hubProvider;
346
+ }
265
347
  var REFRESH_INTERVAL = 5 * 60 * 1e3;
266
348
  function useRadfiSession(walletProvider) {
267
349
  const { sodax } = useSodaxContext();
@@ -432,7 +514,7 @@ function useRenewUtxos({
432
514
  const session = loadRadfiSession(userAddress);
433
515
  const accessToken = session?.accessToken || radfi.accessToken;
434
516
  if (!accessToken) {
435
- throw new Error("Radfi authentication required. Please login first.");
517
+ throw new Error("Bound Exchange authentication required. Please login first.");
436
518
  }
437
519
  const buildResult = await radfi.buildRenewUtxoTransaction({ userAddress, txIdVouts }, accessToken);
438
520
  const signedTx = await walletProvider.signTransaction(buildResult.base64Psbt, false);
@@ -460,7 +542,7 @@ function useRadfiWithdraw({
460
542
  const session = loadRadfiSession(userAddress);
461
543
  const accessToken = session?.accessToken || radfi.accessToken;
462
544
  if (!accessToken) {
463
- throw new Error("Radfi authentication required. Please login first.");
545
+ throw new Error("Bound Exchange authentication required. Please login first.");
464
546
  }
465
547
  const buildResult = await radfi.withdrawToUser({ userAddress, amount, tokenId, withdrawTo }, accessToken);
466
548
  const signedTx = await walletProvider.signTransaction(buildResult.base64Psbt, false);
@@ -581,7 +663,10 @@ function useUserReservesData({
581
663
  if (!spokeChainKey || !userAddress) {
582
664
  throw new Error("spokeChainKey and userAddress are required");
583
665
  }
584
- return sodax.moneyMarket.data.getUserReservesData(spokeChainKey, userAddress);
666
+ return sodax.moneyMarket.data.getUserReservesData(
667
+ spokeChainKey,
668
+ resolveBtcReadAddress(spokeChainKey, userAddress)
669
+ );
585
670
  },
586
671
  enabled: !!spokeChainKey && !!userAddress,
587
672
  refetchInterval: 5e3,
@@ -707,7 +792,10 @@ function useATokensBalances({
707
792
  throw new Error(`Invalid aToken address: ${aToken}`);
708
793
  }
709
794
  }
710
- const hubWalletAddress = await sodax.hubProvider.getUserHubWalletAddress(userAddress, spokeChainKey);
795
+ const hubWalletAddress = await sodax.hubProvider.getUserHubWalletAddress(
796
+ resolveBtcReadAddress(spokeChainKey, userAddress),
797
+ spokeChainKey
798
+ );
711
799
  return sodax.moneyMarket.data.getATokensBalances(aTokens, hubWalletAddress);
712
800
  },
713
801
  enabled: aTokens.length > 0 && !!spokeChainKey && !!userAddress,
@@ -742,7 +830,10 @@ function useUserFormattedSummary({
742
830
  }
743
831
  const [reserves, userReserves] = await Promise.all([
744
832
  sodax.moneyMarket.data.getReservesHumanized(),
745
- sodax.moneyMarket.data.getUserReservesHumanized(spokeChainKey, userAddress)
833
+ sodax.moneyMarket.data.getUserReservesHumanized(
834
+ spokeChainKey,
835
+ resolveBtcReadAddress(spokeChainKey, userAddress)
836
+ )
746
837
  ]);
747
838
  const formattedReserves = sodax.moneyMarket.data.formatReservesUSD(
748
839
  sodax.moneyMarket.data.buildReserveDataWithPrice(reserves)
@@ -2482,6 +2573,158 @@ function useClaimRewards({
2482
2573
  }
2483
2574
  });
2484
2575
  }
2576
+ function useLeverageYieldEffectiveApr({
2577
+ params,
2578
+ queryOptions
2579
+ } = {}) {
2580
+ const { sodax } = useSodaxContext();
2581
+ const vault = params?.vault;
2582
+ return useQuery({
2583
+ queryKey: ["leverageYield", "effectiveApr", vault],
2584
+ queryFn: async () => {
2585
+ if (!vault) throw new Error("vault is required");
2586
+ const result = await sodax.leverageYield.getEffectiveApr(vault);
2587
+ if (!result.ok) throw result.error;
2588
+ return result.value;
2589
+ },
2590
+ enabled: !!vault,
2591
+ refetchInterval: 6e4,
2592
+ ...queryOptions
2593
+ });
2594
+ }
2595
+ function useLeverageYieldPosition({
2596
+ params,
2597
+ queryOptions
2598
+ } = {}) {
2599
+ const { sodax } = useSodaxContext();
2600
+ const vault = params?.vault;
2601
+ return useQuery({
2602
+ queryKey: ["leverageYield", "position", vault],
2603
+ queryFn: async () => {
2604
+ if (!vault) throw new Error("vault is required");
2605
+ const result = await sodax.leverageYield.getPosition(vault);
2606
+ if (!result.ok) throw result.error;
2607
+ return result.value;
2608
+ },
2609
+ enabled: !!vault,
2610
+ refetchInterval: 3e4,
2611
+ ...queryOptions
2612
+ });
2613
+ }
2614
+ function useLeverageYieldTotalAssets({
2615
+ params,
2616
+ queryOptions
2617
+ } = {}) {
2618
+ const { sodax } = useSodaxContext();
2619
+ const vault = params?.vault;
2620
+ return useQuery({
2621
+ queryKey: ["leverageYield", "totalAssets", vault],
2622
+ queryFn: async () => {
2623
+ if (!vault) throw new Error("vault is required");
2624
+ const result = await sodax.leverageYield.getTotalAssets(vault);
2625
+ if (!result.ok) throw result.error;
2626
+ return result.value;
2627
+ },
2628
+ enabled: !!vault,
2629
+ refetchInterval: 6e4,
2630
+ ...queryOptions
2631
+ });
2632
+ }
2633
+ function useLeverageYieldPreviewRedeem({
2634
+ params,
2635
+ queryOptions
2636
+ } = {}) {
2637
+ const { sodax } = useSodaxContext();
2638
+ const vault = params?.vault;
2639
+ const shares = params?.shares;
2640
+ return useQuery({
2641
+ queryKey: ["leverageYield", "previewRedeem", vault, shares?.toString()],
2642
+ queryFn: async () => {
2643
+ if (!vault || shares === void 0) throw new Error("vault and shares are required");
2644
+ const result = await sodax.leverageYield.previewRedeem(vault, shares);
2645
+ if (!result.ok) throw result.error;
2646
+ return result.value;
2647
+ },
2648
+ enabled: !!vault && shares !== void 0,
2649
+ refetchInterval: 6e4,
2650
+ ...queryOptions
2651
+ });
2652
+ }
2653
+ function useLeverageYieldShareBalances({
2654
+ params,
2655
+ queryOptions
2656
+ } = {}) {
2657
+ const { sodax } = useSodaxContext();
2658
+ const vault = params?.vault;
2659
+ const holders = params?.holders;
2660
+ return useQueries({
2661
+ queries: (holders ?? []).map(({ chainKey, address }) => ({
2662
+ queryKey: ["leverageYield", "shareBalance", vault, chainKey, address],
2663
+ refetchInterval: 15e3,
2664
+ ...queryOptions,
2665
+ enabled: !!vault,
2666
+ queryFn: async () => {
2667
+ if (!vault) throw new Error("vault is required");
2668
+ const holder = await sodax.hubProvider.getUserHubWalletAddress(address, chainKey);
2669
+ const result = await sodax.leverageYield.getShareBalance(vault, holder);
2670
+ if (!result.ok) throw result.error;
2671
+ return { chainKey, holder, shares: result.value };
2672
+ }
2673
+ }))
2674
+ });
2675
+ }
2676
+
2677
+ // src/hooks/leverageYield/useLeverageYieldDeposit.ts
2678
+ function useLeverageYieldDeposit({
2679
+ mutationOptions
2680
+ } = {}) {
2681
+ const { sodax } = useSodaxContext();
2682
+ return useSafeMutation({
2683
+ mutationKey: ["leverageYield", "deposit"],
2684
+ ...mutationOptions,
2685
+ mutationFn: async (vars) => unwrapResult(await sodax.leverageYield.deposit(vars))
2686
+ });
2687
+ }
2688
+
2689
+ // src/hooks/leverageYield/useLeverageYieldNotifySolver.ts
2690
+ function useLeverageYieldNotifySolver({
2691
+ mutationOptions
2692
+ } = {}) {
2693
+ const { sodax } = useSodaxContext();
2694
+ return useSafeMutation({
2695
+ mutationKey: ["leverageYield", "notifySolver"],
2696
+ ...mutationOptions,
2697
+ mutationFn: async (vars) => unwrapResult(await sodax.leverageYield.notifySolver(vars))
2698
+ });
2699
+ }
2700
+ function useLeverageYieldVaultSwap({
2701
+ mutationOptions
2702
+ } = {}) {
2703
+ const { sodax } = useSodaxContext();
2704
+ const queryClient = useQueryClient();
2705
+ return useSafeMutation({
2706
+ mutationKey: ["leverageYield", "vaultSwap"],
2707
+ ...mutationOptions,
2708
+ mutationFn: async (vars) => unwrapResult(await sodax.leverageYield.vaultSwap({ ...vars, raw: false })),
2709
+ onSuccess: async (data, vars, ctx) => {
2710
+ queryClient.invalidateQueries({ queryKey: ["shared", "xBalances", vars.params.srcChainKey] });
2711
+ queryClient.invalidateQueries({ queryKey: ["shared", "xBalances", vars.params.dstChainKey] });
2712
+ await mutationOptions?.onSuccess?.(data, vars, ctx);
2713
+ }
2714
+ });
2715
+ }
2716
+
2717
+ // src/hooks/leverageYield/useLeverageYieldWithdraw.ts
2718
+ function useLeverageYieldWithdraw({
2719
+ mutationOptions
2720
+ } = {}) {
2721
+ const { sodax } = useSodaxContext();
2722
+ return useSafeMutation({
2723
+ mutationKey: ["leverageYield", "withdraw"],
2724
+ ...mutationOptions,
2725
+ mutationFn: async (vars) => unwrapResult(await sodax.leverageYield.withdraw(vars))
2726
+ });
2727
+ }
2485
2728
  var SodaxProvider = ({ children, config }) => {
2486
2729
  const sodax = useMemo(() => new Sodax(config), [config]);
2487
2730
  const contextValue = useMemo(() => ({ sodax }), [sodax]);
@@ -2513,4 +2756,4 @@ function createSodaxQueryClient({
2513
2756
  });
2514
2757
  }
2515
2758
 
2516
- export { SodaxProvider, clearRadfiSession, createDecreaseLiquidityParamsProps, createDepositParamsProps, createSodaxQueryClient, createSupplyLiquidityParamsProps, createWithdrawParamsProps, getXBalancesQueryOptions, loadRadfiSession, saveRadfiSession, toResult, unwrapResult, useAToken, useATokensBalances, useApproveToken, useBackendAllMoneyMarketAssets, useBackendAllMoneyMarketBorrowers, useBackendIntentByHash, useBackendIntentByTxHash, useBackendMoneyMarketAsset, useBackendMoneyMarketAssetBorrowers, useBackendMoneyMarketAssetSuppliers, useBackendMoneyMarketPosition, useBackendOrderbook, useBackendSubmitSwapTx, useBackendSubmitSwapTxStatus, useBackendUserIntents, useBitcoinBalance, useBorrow, useBridge, useBridgeAllowance, useBridgeApprove, useCancelLimitOrder, useCancelSwap, useCancelUnstake, useClaim, useClaimRewards, useConvertedAssets, useCreateDecreaseLiquidityParams, useCreateDepositParams, useCreateLimitOrder, useCreateSupplyLiquidityParams, useCreateWithdrawParams, useDecreaseLiquidity, useDeriveUserWalletAddress, useDexAllowance, useDexApprove, useDexDeposit, useDexWithdraw, useEstimateGas, useExpiredUtxos, useFeeClaimSwap, useFetchAssetsBalances, useFundTradingWallet, useGetAutoSwapPreferences, useGetBridgeableAmount, useGetBridgeableTokens, useGetUserHubWalletAddress, useHubAssetBalances, useHubProvider, useInstantUnstake, useInstantUnstakeAllowance, useInstantUnstakeApprove, useInstantUnstakeRatio, useIsTokenApproved, useLiquidityAmounts, useMMAllowance, useMMApprove, useMigrateBaln, useMigrateIcxToSoda, useMigratebnUSD, useMigrationAllowance, useMigrationApprove, usePoolBalances, usePoolData, usePools, usePositionInfo, useQuote, useRadfiAuth, useRadfiSession, useRadfiWithdraw, useRenewUtxos, useRepay, useRequestTrustline, useReservesData, useReservesHumanized, useReservesList, useReservesUsdFormat, useRevertMigrateSodaToIcx, useSafeMutation, useSetSwapPreference, useSodaxContext, useStake, useStakeAllowance, useStakeApprove, useStakeRatio, useStakingConfig, useStakingInfo, useStatus, useStellarTrustlineCheck, useSupply, useSupplyLiquidity, useSwap, useSwapAllowance, useSwapApprove, useTradingWallet, useTradingWalletBalance, useUnstake, useUnstakeAllowance, useUnstakeApprove, useUnstakingInfo, useUnstakingInfoWithPenalty, useUserFormattedSummary, useUserReservesData, useWithdraw, useWithdrawHubAsset, useXBalances };
2759
+ export { SodaxProvider, clearRadfiSession, createDecreaseLiquidityParamsProps, createDepositParamsProps, createSodaxQueryClient, createSupplyLiquidityParamsProps, createWithdrawParamsProps, getXBalancesQueryOptions, loadRadfiSession, resolveNearStorageGate, saveRadfiSession, toResult, unwrapResult, useAToken, useATokensBalances, useApproveToken, useBackendAllMoneyMarketAssets, useBackendAllMoneyMarketBorrowers, useBackendIntentByHash, useBackendIntentByTxHash, useBackendMoneyMarketAsset, useBackendMoneyMarketAssetBorrowers, useBackendMoneyMarketAssetSuppliers, useBackendMoneyMarketPosition, useBackendOrderbook, useBackendSubmitSwapTx, useBackendSubmitSwapTxStatus, useBackendUserIntents, useBitcoinBalance, useBorrow, useBridge, useBridgeAllowance, useBridgeApprove, useCancelLimitOrder, useCancelSwap, useCancelUnstake, useClaim, useClaimRewards, useConvertedAssets, useCreateDecreaseLiquidityParams, useCreateDepositParams, useCreateLimitOrder, useCreateSupplyLiquidityParams, useCreateWithdrawParams, useDecreaseLiquidity, useDeriveUserWalletAddress, useDexAllowance, useDexApprove, useDexDeposit, useDexWithdraw, useEstimateGas, useExpiredUtxos, useFeeClaimSwap, useFetchAssetsBalances, useFundTradingWallet, useGetAutoSwapPreferences, useGetBridgeableAmount, useGetBridgeableTokens, useGetUserHubWalletAddress, useHubAssetBalances, useHubProvider, useInstantUnstake, useInstantUnstakeAllowance, useInstantUnstakeApprove, useInstantUnstakeRatio, useIsTokenApproved, useLeverageYieldDeposit, useLeverageYieldEffectiveApr, useLeverageYieldNotifySolver, useLeverageYieldPosition, useLeverageYieldPreviewRedeem, useLeverageYieldShareBalances, useLeverageYieldTotalAssets, useLeverageYieldVaultSwap, useLeverageYieldWithdraw, useLiquidityAmounts, useMMAllowance, useMMApprove, useMigrateBaln, useMigrateIcxToSoda, useMigratebnUSD, useMigrationAllowance, useMigrationApprove, useNearStorageCheck, useNearStorageGate, usePoolBalances, usePoolData, usePools, usePositionInfo, useQuote, useRadfiAuth, useRadfiSession, useRadfiWithdraw, useRegisterNearStorage, useRenewUtxos, useRepay, useRequestTrustline, useReservesData, useReservesHumanized, useReservesList, useReservesUsdFormat, useRevertMigrateSodaToIcx, useSafeMutation, useSetSwapPreference, useSodaxContext, useStake, useStakeAllowance, useStakeApprove, useStakeRatio, useStakingConfig, useStakingInfo, useStatus, useStellarTrustlineCheck, useSupply, useSupplyLiquidity, useSwap, useSwapAllowance, useSwapApprove, useTradingWallet, useTradingWalletBalance, useUnstake, useUnstakeAllowance, useUnstakeApprove, useUnstakingInfo, useUnstakingInfoWithPenalty, useUserFormattedSummary, useUserReservesData, useWithdraw, useWithdrawHubAsset, useXBalances };
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "access": "public"
6
6
  },
7
7
  "license": "MIT",
8
- "version": "2.0.0-rc.11",
8
+ "version": "2.0.0-rc.13",
9
9
  "description": "React hooks for building dApps on the SODAX cross-chain DeFi platform",
10
10
  "keywords": [
11
11
  "sodax",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {
36
36
  "viem": "2.29.2",
37
- "@sodax/sdk": "2.0.0-rc.11"
37
+ "@sodax/sdk": "2.0.0-rc.13"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@arethetypeswrong/cli": "0.17.4",
@@ -7,7 +7,7 @@ const HOOKS_DIR = resolve(fileURLToPath(import.meta.url), '..');
7
7
 
8
8
  /**
9
9
  * Manifest of every mutation hook. `nativeThrow: true` marks hooks whose underlying SDK methods
10
- * throw natively (Radfi APIs) and so don't need `unwrapResult`.
10
+ * throw natively (Bound Exchange APIs) and so don't need `unwrapResult`.
11
11
  *
12
12
  * To add a new mutation hook, add its path here. The friction is intentional — it forces explicit
13
13
  * registration so the contract is enforced from day one.
@@ -26,6 +26,10 @@ const HOOKS: Array<{ path: string; nativeThrow?: true }> = [
26
26
  { path: 'dex/useDexDeposit.ts' },
27
27
  { path: 'dex/useDexWithdraw.ts' },
28
28
  { path: 'dex/useSupplyLiquidity.ts' },
29
+ { path: 'leverageYield/useLeverageYieldDeposit.ts' },
30
+ { path: 'leverageYield/useLeverageYieldNotifySolver.ts' },
31
+ { path: 'leverageYield/useLeverageYieldVaultSwap.ts' },
32
+ { path: 'leverageYield/useLeverageYieldWithdraw.ts' },
29
33
  { path: 'migrate/useMigrateBaln.ts' },
30
34
  { path: 'migrate/useMigrateIcxToSoda.ts' },
31
35
  { path: 'migrate/useMigratebnUSD.ts' },
@@ -41,6 +45,7 @@ const HOOKS: Array<{ path: string; nativeThrow?: true }> = [
41
45
  { path: 'partner/useSetSwapPreference.ts' },
42
46
  { path: 'recovery/useWithdrawHubAsset.ts' },
43
47
  { path: 'shared/useEstimateGas.ts' },
48
+ { path: 'shared/useRegisterNearStorage.ts', nativeThrow: true },
44
49
  { path: 'staking/useCancelUnstake.ts' },
45
50
  { path: 'staking/useClaim.ts' },
46
51
  { path: 'staking/useInstantUnstake.ts' },
@@ -0,0 +1,54 @@
1
+ import { ChainKeys } from '@sodax/sdk';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import type { RadfiSession } from './useRadfiAuth.js';
4
+ import { loadRadfiSession } from './useRadfiAuth.js';
5
+ import { resolveBtcReadAddress } from './resolveBtcReadAddress.js';
6
+
7
+ // resolveBtcReadAddress reads the Bound Exchange session via loadRadfiSession (localStorage-backed).
8
+ // The dapp-kit test env is `node` (no localStorage), so mock the session lookup to drive each branch.
9
+ vi.mock('./useRadfiAuth.js', () => ({
10
+ loadRadfiSession: vi.fn(),
11
+ }));
12
+
13
+ const mockLoadRadfiSession = vi.mocked(loadRadfiSession);
14
+
15
+ const PERSONAL_ADDRESS = 'bc1qpersonal00000000000000000000000000000';
16
+ const TRADING_ADDRESS = 'bc1qtrading000000000000000000000000000000';
17
+
18
+ const session = (tradingAddress: string): RadfiSession => ({
19
+ accessToken: 'access',
20
+ refreshToken: 'refresh',
21
+ tradingAddress,
22
+ publicKey: 'pub',
23
+ });
24
+
25
+ describe('resolveBtcReadAddress', () => {
26
+ beforeEach(() => {
27
+ mockLoadRadfiSession.mockReset();
28
+ });
29
+
30
+ it('passes the address through unchanged for non-Bitcoin chains (no session lookup)', () => {
31
+ const result = resolveBtcReadAddress(ChainKeys.ARBITRUM_MAINNET, PERSONAL_ADDRESS);
32
+
33
+ expect(result).toBe(PERSONAL_ADDRESS);
34
+ expect(mockLoadRadfiSession).not.toHaveBeenCalled();
35
+ });
36
+
37
+ it('returns the trading address from the local session for Bitcoin', () => {
38
+ mockLoadRadfiSession.mockReturnValue(session(TRADING_ADDRESS));
39
+
40
+ const result = resolveBtcReadAddress(ChainKeys.BITCOIN_MAINNET, PERSONAL_ADDRESS);
41
+
42
+ expect(result).toBe(TRADING_ADDRESS);
43
+ // The session is keyed by the personal address.
44
+ expect(mockLoadRadfiSession).toHaveBeenCalledWith(PERSONAL_ADDRESS);
45
+ });
46
+
47
+ it('falls back to the personal address for Bitcoin when there is no session', () => {
48
+ mockLoadRadfiSession.mockReturnValue(null);
49
+
50
+ const result = resolveBtcReadAddress(ChainKeys.BITCOIN_MAINNET, PERSONAL_ADDRESS);
51
+
52
+ expect(result).toBe(PERSONAL_ADDRESS);
53
+ });
54
+ });
@@ -0,0 +1,21 @@
1
+ import { ChainKeys, type SpokeChainKey } from '@sodax/sdk';
2
+ import { loadRadfiSession } from './useRadfiAuth.js';
3
+
4
+ /**
5
+ * Resolve a spoke address for READ queries (positions, balances, hub-wallet display).
6
+ *
7
+ * Bitcoin positions live under the Bound Exchange trading-wallet-derived hub wallet, so for Bitcoin we
8
+ * resolve to the trading address from the locally-persisted Bound Exchange session. This is intentionally
9
+ * a LOCAL lookup (no network call): a transient Bound Exchange API outage can never make a real position
10
+ * read as empty, and reads never throw "Trading wallet not found". When there is no session, the
11
+ * user has no Bitcoin position to show, so the original (personal) address is returned — deriving
12
+ * an empty hub wallet, which is correct. Non-Bitcoin chains pass through unchanged.
13
+ *
14
+ * The WRITE path resolves the trading address authoritatively in the SDK
15
+ * (`getEffectiveWalletAddress`, called from the money-market create*Intent flows); reads
16
+ * deliberately use this lighter, fail-safe path.
17
+ */
18
+ export function resolveBtcReadAddress(chainKey: SpokeChainKey, address: string): string {
19
+ if (chainKey !== ChainKeys.BITCOIN_MAINNET) return address;
20
+ return loadRadfiSession(address)?.tradingAddress ?? address;
21
+ }
@@ -11,7 +11,7 @@ export type UseFundTradingWalletVars = {
11
11
  };
12
12
 
13
13
  /**
14
- * React hook for funding the user's Radfi trading wallet from their personal Bitcoin wallet.
14
+ * React hook for funding the user's Bound Exchange trading wallet from their personal Bitcoin wallet.
15
15
  * Pure mutation: pass `{ amount, walletProvider }` to `mutate({...})`. Returns the broadcast tx
16
16
  * id on success.
17
17
  */
@@ -45,7 +45,7 @@ export function clearRadfiSession(address: string): void {
45
45
  }
46
46
 
47
47
  /**
48
- * React hook for authenticating with Radfi via BIP322-signed message. Pure mutation: pass
48
+ * React hook for authenticating with Bound Exchange via BIP322-signed message. Pure mutation: pass
49
49
  * `{ walletProvider }` to `mutate({...})`. The hook itself takes no arguments other than the
50
50
  * structural `mutationOptions` slot.
51
51
  */
@@ -95,7 +95,7 @@ export function useRadfiAuth({
95
95
  }
96
96
 
97
97
  throw new Error(
98
- 'This wallet is already registered with Radfi from another session. ' +
98
+ 'This wallet is already registered with Bound Exchange from another session. ' +
99
99
  'Please clear your browser storage for this site and try again, ' +
100
100
  'or wait for the previous session to expire.',
101
101
  );
@@ -19,7 +19,7 @@ type WithdrawResult = {
19
19
  };
20
20
 
21
21
  /**
22
- * React hook for withdrawing BTC from the user's Radfi trading wallet back to their personal
22
+ * React hook for withdrawing BTC from the user's Bound Exchange trading wallet back to their personal
23
23
  * Bitcoin wallet. Pure mutation: pass all inputs (including the wallet provider) to
24
24
  * `mutate({...})`.
25
25
  */
@@ -44,7 +44,7 @@ export function useRadfiWithdraw({
44
44
  const accessToken = session?.accessToken || radfi.accessToken;
45
45
 
46
46
  if (!accessToken) {
47
- throw new Error('Radfi authentication required. Please login first.');
47
+ throw new Error('Bound Exchange authentication required. Please login first.');
48
48
  }
49
49
 
50
50
  const buildResult = await radfi.withdrawToUser({ userAddress, amount, tokenId, withdrawTo }, accessToken);
@@ -12,7 +12,7 @@ export type UseRenewUtxosVars = {
12
12
  };
13
13
 
14
14
  /**
15
- * React hook for renewing expired UTXOs in the user's Radfi trading wallet. Pure mutation: pass
15
+ * React hook for renewing expired UTXOs in the user's Bound Exchange trading wallet. Pure mutation: pass
16
16
  * `{ txIdVouts, walletProvider }` to `mutate({...})`.
17
17
  */
18
18
  export function useRenewUtxos({
@@ -32,7 +32,7 @@ export function useRenewUtxos({
32
32
  const accessToken = session?.accessToken || radfi.accessToken;
33
33
 
34
34
  if (!accessToken) {
35
- throw new Error('Radfi authentication required. Please login first.');
35
+ throw new Error('Bound Exchange authentication required. Please login first.');
36
36
  }
37
37
 
38
38
  const buildResult = await radfi.buildRenewUtxoTransaction({ userAddress, txIdVouts }, accessToken);
@@ -5,7 +5,7 @@ type UseTradingWalletReturn = {
5
5
  };
6
6
 
7
7
  /**
8
- * Returns the Radfi trading wallet address from the persisted session.
8
+ * Returns the Bound Exchange trading wallet address from the persisted session.
9
9
  * Trading wallet is created automatically during authentication — no API call needed.
10
10
  */
11
11
  export function useTradingWallet(walletAddress: string | undefined): UseTradingWalletReturn {
@@ -10,3 +10,4 @@ export * from './partner/index.js';
10
10
  export * from './recovery/index.js';
11
11
  export * from './migrate/index.js';
12
12
  export * from './dex/index.js';
13
+ export * from './leverageYield/index.js';
@@ -0,0 +1,9 @@
1
+ export * from './useLeverageYieldEffectiveApr.js';
2
+ export * from './useLeverageYieldPosition.js';
3
+ export * from './useLeverageYieldTotalAssets.js';
4
+ export * from './useLeverageYieldPreviewRedeem.js';
5
+ export * from './useLeverageYieldShareBalances.js';
6
+ export * from './useLeverageYieldDeposit.js';
7
+ export * from './useLeverageYieldNotifySolver.js';
8
+ export * from './useLeverageYieldVaultSwap.js';
9
+ export * from './useLeverageYieldWithdraw.js';