@sodax/dapp-kit 1.5.6-beta → 2.0.0-rc.1

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 (202) hide show
  1. package/README.md +300 -422
  2. package/ai-exported/AGENTS.md +134 -0
  3. package/ai-exported/integration/README.md +49 -0
  4. package/ai-exported/integration/ai-rules.md +79 -0
  5. package/ai-exported/integration/architecture.md +274 -0
  6. package/ai-exported/integration/features/README.md +29 -0
  7. package/ai-exported/integration/features/auxiliary-services.md +169 -0
  8. package/ai-exported/integration/features/bitcoin.md +87 -0
  9. package/ai-exported/integration/features/bridge.md +91 -0
  10. package/ai-exported/integration/features/dex.md +152 -0
  11. package/ai-exported/integration/features/migration.md +118 -0
  12. package/ai-exported/integration/features/money-market.md +116 -0
  13. package/ai-exported/integration/features/staking.md +123 -0
  14. package/ai-exported/integration/features/swap.md +101 -0
  15. package/ai-exported/integration/quickstart.md +187 -0
  16. package/ai-exported/integration/recipes/README.md +136 -0
  17. package/ai-exported/integration/recipes/backend-queries.md +157 -0
  18. package/ai-exported/integration/recipes/bitcoin.md +193 -0
  19. package/ai-exported/integration/recipes/bridge.md +174 -0
  20. package/ai-exported/integration/recipes/dex.md +204 -0
  21. package/ai-exported/integration/recipes/invalidations.md +115 -0
  22. package/ai-exported/integration/recipes/migration.md +212 -0
  23. package/ai-exported/integration/recipes/money-market.md +206 -0
  24. package/ai-exported/integration/recipes/mutation-error-handling.md +118 -0
  25. package/ai-exported/integration/recipes/observability.md +93 -0
  26. package/ai-exported/integration/recipes/setup.md +144 -0
  27. package/ai-exported/integration/recipes/staking.md +202 -0
  28. package/ai-exported/integration/recipes/swap.md +272 -0
  29. package/ai-exported/integration/recipes/wallet-connectivity.md +101 -0
  30. package/ai-exported/integration/reference/README.md +12 -0
  31. package/ai-exported/integration/reference/glossary.md +188 -0
  32. package/ai-exported/integration/reference/hooks-index.md +194 -0
  33. package/ai-exported/integration/reference/public-api.md +110 -0
  34. package/ai-exported/integration/reference/querykey-conventions.md +179 -0
  35. package/ai-exported/migration/README.md +60 -0
  36. package/ai-exported/migration/ai-rules.md +81 -0
  37. package/ai-exported/migration/breaking-changes/hook-signatures.md +233 -0
  38. package/ai-exported/migration/breaking-changes/querykey-conventions.md +108 -0
  39. package/ai-exported/migration/breaking-changes/result-handling.md +211 -0
  40. package/ai-exported/migration/breaking-changes/sdk-leakage.md +165 -0
  41. package/ai-exported/migration/checklist.md +89 -0
  42. package/ai-exported/migration/features/README.md +34 -0
  43. package/ai-exported/migration/features/auxiliary-services.md +114 -0
  44. package/ai-exported/migration/features/bitcoin.md +88 -0
  45. package/ai-exported/migration/features/bridge.md +123 -0
  46. package/ai-exported/migration/features/dex.md +101 -0
  47. package/ai-exported/migration/features/migration.md +120 -0
  48. package/ai-exported/migration/features/money-market.md +97 -0
  49. package/ai-exported/migration/features/staking.md +109 -0
  50. package/ai-exported/migration/features/swap.md +118 -0
  51. package/ai-exported/migration/recipes.md +188 -0
  52. package/ai-exported/migration/reference/README.md +15 -0
  53. package/ai-exported/migration/reference/deleted-hooks.md +110 -0
  54. package/ai-exported/migration/reference/error-shape-crosswalk.md +144 -0
  55. package/ai-exported/migration/reference/renamed-hooks.md +66 -0
  56. package/dist/index.cjs +2642 -0
  57. package/dist/index.cjs.map +1 -0
  58. package/dist/index.d.cts +1550 -0
  59. package/dist/index.d.ts +1020 -2051
  60. package/dist/index.mjs +1594 -1532
  61. package/dist/index.mjs.map +1 -1
  62. package/package.json +20 -10
  63. package/src/contexts/index.ts +0 -3
  64. package/src/hooks/_mutationContract.test.ts +99 -0
  65. package/src/hooks/backend/README.md +2 -2
  66. package/src/hooks/backend/index.ts +13 -13
  67. package/src/hooks/backend/unwrapResult.ts +1 -0
  68. package/src/hooks/backend/useBackendAllMoneyMarketAssets.ts +13 -45
  69. package/src/hooks/backend/useBackendAllMoneyMarketBorrowers.ts +29 -59
  70. package/src/hooks/backend/useBackendIntentByHash.ts +21 -47
  71. package/src/hooks/backend/useBackendIntentByTxHash.ts +23 -50
  72. package/src/hooks/backend/useBackendMoneyMarketAsset.ts +21 -54
  73. package/src/hooks/backend/useBackendMoneyMarketAssetBorrowers.ts +30 -57
  74. package/src/hooks/backend/useBackendMoneyMarketAssetSuppliers.ts +31 -58
  75. package/src/hooks/backend/useBackendMoneyMarketPosition.ts +22 -38
  76. package/src/hooks/backend/useBackendOrderbook.ts +27 -49
  77. package/src/hooks/backend/useBackendSubmitSwapTx.ts +30 -36
  78. package/src/hooks/backend/useBackendSubmitSwapTxStatus.ts +38 -58
  79. package/src/hooks/backend/useBackendUserIntents.ts +25 -63
  80. package/src/hooks/bitcoin/index.ts +9 -8
  81. package/src/hooks/bitcoin/useBitcoinBalance.ts +20 -5
  82. package/src/hooks/bitcoin/useExpiredUtxos.ts +26 -16
  83. package/src/hooks/bitcoin/useFundTradingWallet.ts +33 -30
  84. package/src/hooks/bitcoin/useRadfiAuth.ts +43 -40
  85. package/src/hooks/bitcoin/useRadfiSession.ts +53 -59
  86. package/src/hooks/bitcoin/useRadfiWithdraw.ts +35 -53
  87. package/src/hooks/bitcoin/useRenewUtxos.ts +30 -50
  88. package/src/hooks/bitcoin/useTradingWallet.ts +1 -1
  89. package/src/hooks/bitcoin/useTradingWalletBalance.ts +25 -14
  90. package/src/hooks/bridge/index.ts +5 -5
  91. package/src/hooks/bridge/useBridge.ts +29 -55
  92. package/src/hooks/bridge/useBridgeAllowance.ts +38 -38
  93. package/src/hooks/bridge/useBridgeApprove.ts +32 -57
  94. package/src/hooks/bridge/useGetBridgeableAmount.ts +23 -37
  95. package/src/hooks/bridge/useGetBridgeableTokens.ts +27 -50
  96. package/src/hooks/dex/index.ts +16 -16
  97. package/src/hooks/dex/useClaimRewards.ts +35 -54
  98. package/src/hooks/dex/useCreateDecreaseLiquidityParams.ts +7 -20
  99. package/src/hooks/dex/useCreateDepositParams.ts +7 -21
  100. package/src/hooks/dex/useCreateSupplyLiquidityParams.ts +13 -28
  101. package/src/hooks/dex/useCreateWithdrawParams.ts +7 -20
  102. package/src/hooks/dex/useDecreaseLiquidity.ts +40 -66
  103. package/src/hooks/dex/useDexAllowance.ts +29 -75
  104. package/src/hooks/dex/useDexApprove.ts +32 -43
  105. package/src/hooks/dex/useDexDeposit.ts +42 -49
  106. package/src/hooks/dex/useDexWithdraw.ts +32 -43
  107. package/src/hooks/dex/useLiquidityAmounts.ts +27 -84
  108. package/src/hooks/dex/usePoolBalances.ts +50 -72
  109. package/src/hooks/dex/usePoolData.ts +17 -43
  110. package/src/hooks/dex/usePools.ts +11 -38
  111. package/src/hooks/dex/usePositionInfo.ts +27 -62
  112. package/src/hooks/dex/useSupplyLiquidity.ts +80 -75
  113. package/src/hooks/index.ts +12 -10
  114. package/src/hooks/migrate/index.ts +13 -4
  115. package/src/hooks/migrate/useMigrateBaln.ts +42 -0
  116. package/src/hooks/migrate/useMigrateIcxToSoda.ts +44 -0
  117. package/src/hooks/migrate/useMigratebnUSD.ts +47 -0
  118. package/src/hooks/migrate/useMigrationAllowance.ts +76 -0
  119. package/src/hooks/migrate/useMigrationApprove.ts +66 -0
  120. package/src/hooks/migrate/useRevertMigrateSodaToIcx.ts +39 -0
  121. package/src/hooks/mm/index.ts +14 -12
  122. package/src/hooks/mm/useAToken.ts +25 -41
  123. package/src/hooks/mm/useATokensBalances.ts +29 -60
  124. package/src/hooks/mm/useBorrow.ts +38 -56
  125. package/src/hooks/mm/useMMAllowance.ts +37 -73
  126. package/src/hooks/mm/useMMApprove.ts +36 -43
  127. package/src/hooks/mm/useRepay.ts +33 -53
  128. package/src/hooks/mm/useReservesData.ts +12 -38
  129. package/src/hooks/mm/useReservesHumanized.ts +12 -31
  130. package/src/hooks/mm/useReservesList.ts +11 -31
  131. package/src/hooks/mm/useReservesUsdFormat.ts +15 -35
  132. package/src/hooks/mm/useSupply.ts +45 -51
  133. package/src/hooks/mm/useUserFormattedSummary.ts +32 -84
  134. package/src/hooks/mm/useUserReservesData.ts +27 -77
  135. package/src/hooks/mm/useWithdraw.ts +38 -54
  136. package/src/hooks/partner/index.ts +6 -0
  137. package/src/hooks/partner/useApproveToken.ts +42 -0
  138. package/src/hooks/partner/useFeeClaimSwap.ts +38 -0
  139. package/src/hooks/partner/useFetchAssetsBalances.ts +37 -0
  140. package/src/hooks/partner/useGetAutoSwapPreferences.ts +37 -0
  141. package/src/hooks/partner/useIsTokenApproved.ts +39 -0
  142. package/src/hooks/partner/useSetSwapPreference.ts +50 -0
  143. package/src/hooks/provider/index.ts +1 -2
  144. package/src/hooks/provider/useHubProvider.ts +1 -1
  145. package/src/hooks/recovery/index.ts +2 -0
  146. package/src/hooks/recovery/useHubAssetBalances.ts +43 -0
  147. package/src/hooks/recovery/useWithdrawHubAsset.ts +48 -0
  148. package/src/hooks/shared/index.ts +10 -6
  149. package/src/hooks/shared/types.ts +77 -0
  150. package/src/hooks/shared/unwrapResult.ts +19 -0
  151. package/src/hooks/shared/useDeriveUserWalletAddress.ts +22 -40
  152. package/src/hooks/shared/useEstimateGas.ts +18 -15
  153. package/src/hooks/shared/useGetUserHubWalletAddress.ts +25 -26
  154. package/src/hooks/shared/useRequestTrustline.ts +28 -61
  155. package/src/hooks/shared/useSafeMutation.test.ts +43 -0
  156. package/src/hooks/shared/useSafeMutation.ts +68 -0
  157. package/src/hooks/shared/useSodaxContext.ts +1 -1
  158. package/src/hooks/shared/useStellarTrustlineCheck.ts +30 -64
  159. package/src/hooks/shared/useXBalances.test.ts +113 -0
  160. package/src/hooks/shared/useXBalances.ts +61 -0
  161. package/src/hooks/staking/index.ts +18 -18
  162. package/src/hooks/staking/useCancelUnstake.ts +30 -41
  163. package/src/hooks/staking/useClaim.ts +27 -36
  164. package/src/hooks/staking/useConvertedAssets.ts +24 -34
  165. package/src/hooks/staking/useInstantUnstake.ts +33 -40
  166. package/src/hooks/staking/useInstantUnstakeAllowance.ts +37 -45
  167. package/src/hooks/staking/useInstantUnstakeApprove.ts +42 -42
  168. package/src/hooks/staking/useInstantUnstakeRatio.ts +24 -41
  169. package/src/hooks/staking/useStake.ts +32 -37
  170. package/src/hooks/staking/useStakeAllowance.ts +30 -43
  171. package/src/hooks/staking/useStakeApprove.ts +40 -40
  172. package/src/hooks/staking/useStakeRatio.ts +24 -40
  173. package/src/hooks/staking/useStakingConfig.ts +14 -27
  174. package/src/hooks/staking/useStakingInfo.ts +30 -38
  175. package/src/hooks/staking/useUnstake.ts +29 -43
  176. package/src/hooks/staking/useUnstakeAllowance.ts +37 -44
  177. package/src/hooks/staking/useUnstakeApprove.ts +40 -43
  178. package/src/hooks/staking/useUnstakingInfo.ts +29 -41
  179. package/src/hooks/staking/useUnstakingInfoWithPenalty.ts +31 -47
  180. package/src/hooks/swap/index.ts +8 -8
  181. package/src/hooks/swap/useCancelLimitOrder.ts +24 -41
  182. package/src/hooks/swap/useCancelSwap.ts +24 -33
  183. package/src/hooks/swap/useCreateLimitOrder.ts +29 -62
  184. package/src/hooks/swap/useQuote.ts +17 -43
  185. package/src/hooks/swap/useStatus.ts +22 -29
  186. package/src/hooks/swap/useSwap.ts +31 -49
  187. package/src/hooks/swap/useSwapAllowance.ts +38 -35
  188. package/src/hooks/swap/useSwapApprove.ts +48 -57
  189. package/src/index.ts +5 -3
  190. package/src/providers/SodaxProvider.tsx +17 -11
  191. package/src/providers/createSodaxQueryClient.ts +96 -0
  192. package/src/providers/index.ts +2 -1
  193. package/src/utils/dex-utils.ts +27 -5
  194. package/src/utils/index.ts +1 -1
  195. package/dist/index.d.mts +0 -2581
  196. package/dist/index.js +0 -2562
  197. package/dist/index.js.map +0 -1
  198. package/src/hooks/migrate/types.ts +0 -15
  199. package/src/hooks/migrate/useMigrate.tsx +0 -110
  200. package/src/hooks/migrate/useMigrationAllowance.tsx +0 -79
  201. package/src/hooks/migrate/useMigrationApprove.tsx +0 -129
  202. package/src/hooks/provider/useSpokeProvider.ts +0 -172
@@ -1,47 +1,42 @@
1
1
  // packages/dapp-kit/src/hooks/staking/useStake.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
- import type { StakeParams, SpokeTxHash, HubTxHash, SpokeProvider } from '@sodax/sdk';
4
- import { useMutation, type UseMutationResult } from '@tanstack/react-query';
2
+ import type { SpokeChainKey, StakeAction, TxHashPair } from '@sodax/sdk';
3
+ import { useQueryClient } from '@tanstack/react-query';
4
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
5
+ import type { MutationHookParams } from '../shared/types.js';
6
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
7
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
8
 
6
9
  /**
7
- * Hook for executing stake transactions to stake SODA tokens and receive xSODA shares.
8
- * Uses React Query's useMutation for better state management and caching.
9
- *
10
- * @param {SpokeProvider | undefined} spokeProvider - The spoke provider to use for the stake
11
- * @returns {UseMutationResult<[SpokeTxHash, HubTxHash], Error, StakeParams>} Mutation result object containing mutation function and state
12
- *
13
- * @example
14
- * ```typescript
15
- * const { mutateAsync: stake, isPending } = useStake(spokeProvider);
16
- *
17
- * const handleStake = async () => {
18
- * const result = await stake({
19
- * amount: 1000000000000000000n, // 1 SODA
20
- * account: '0x...'
21
- * });
10
+ * Mutation variables for {@link useStake}. Generic over `K extends SpokeChainKey` (defaults to
11
+ * the full union). Sophisticated callers can lock K at the hook call site to narrow the
12
+ * `walletProvider` and `params.srcChainKey` types.
13
+ */
14
+ export type UseStakeVars<K extends SpokeChainKey = SpokeChainKey> = Omit<StakeAction<K, false>, 'raw'>;
15
+
16
+ /**
17
+ * React hook for staking SODA tokens.
22
18
  *
23
- * console.log('Stake successful:', result);
24
- * };
25
- * ```
19
+ * Throws on SDK failure so React Query's native error model engages (`isError`, `error`,
20
+ * `onError`, `retry`). Returns the unwrapped `TxHashPair` on success.
26
21
  */
27
- export function useStake(
28
- spokeProvider: SpokeProvider | undefined,
29
- ): UseMutationResult<[SpokeTxHash, HubTxHash], Error, StakeParams> {
22
+ export function useStake<K extends SpokeChainKey = SpokeChainKey>({
23
+ mutationOptions,
24
+ }: MutationHookParams<TxHashPair, UseStakeVars<K>> = {}): SafeUseMutationResult<TxHashPair, Error, UseStakeVars<K>> {
30
25
  const { sodax } = useSodaxContext();
26
+ const queryClient = useQueryClient();
31
27
 
32
- return useMutation<[SpokeTxHash, HubTxHash], Error, StakeParams>({
33
- mutationFn: async (params: StakeParams) => {
34
- if (!spokeProvider) {
35
- throw new Error('Spoke provider not found');
36
- }
37
-
38
- const result = await sodax.staking.stake(params, spokeProvider);
39
-
40
- if (!result.ok) {
41
- throw new Error(`Stake failed: ${result.error.code}`);
42
- }
43
-
44
- return result.value;
28
+ return useSafeMutation<TxHashPair, Error, UseStakeVars<K>>({
29
+ mutationKey: ['staking', 'stake'],
30
+ ...mutationOptions,
31
+ mutationFn: async vars => unwrapResult(await sodax.staking.stake({ ...vars, raw: false })),
32
+ onSuccess: async (data, vars, ctx) => {
33
+ const { params } = vars;
34
+ queryClient.invalidateQueries({ queryKey: ['staking', 'info', params.srcChainKey, params.srcAddress] });
35
+ queryClient.invalidateQueries({ queryKey: ['staking', 'allowance', params.srcChainKey, 'stake'] });
36
+ queryClient.invalidateQueries({ queryKey: ['staking', 'stakeRatio'] });
37
+ queryClient.invalidateQueries({ queryKey: ['staking', 'convertedAssets'] });
38
+ queryClient.invalidateQueries({ queryKey: ['shared', 'xBalances', params.srcChainKey] });
39
+ await mutationOptions?.onSuccess?.(data, vars, ctx);
45
40
  },
46
41
  });
47
42
  }
@@ -1,57 +1,44 @@
1
- // packages/dapp-kit/src/hooks/staking/useStakeAllowance.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
- import type { StakeParams, SpokeProvider } from '@sodax/sdk';
1
+ import type { StakeParams } from '@sodax/sdk';
2
+ import type { SpokeChainKey } from '@sodax/sdk';
4
3
  import { useQuery, type UseQueryResult } from '@tanstack/react-query';
4
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseStakeAllowanceParams<K extends SpokeChainKey = SpokeChainKey> = ReadHookParams<
8
+ boolean,
9
+ {
10
+ payload: Omit<StakeParams<K>, 'action'> | undefined;
11
+ }
12
+ >;
5
13
 
6
14
  /**
7
- * Hook for checking SODA token allowance for staking operations.
8
- * Uses React Query for efficient caching and state management.
9
- *
10
- * @param {Omit<StakeParams, 'action'> | undefined} params - The staking parameters. If undefined, the query will be disabled.
11
- * @param {SpokeProvider | undefined} spokeProvider - The spoke provider to use for the allowance check
12
- * @returns {UseQueryResult<boolean, Error>} Query result object containing allowance data and state
13
- *
14
- * @example
15
- * ```typescript
16
- * const { data: hasAllowed, isLoading } = useStakeAllowance(
17
- * {
18
- * amount: 1000000000000000000n, // 1 SODA
19
- * account: '0x...'
20
- * },
21
- * spokeProvider
22
- * );
23
- *
24
- * if (isLoading) return <div>Checking allowance...</div>;
25
- * if (hasAllowed) {
26
- * console.log('Sufficient allowance for staking');
27
- * }
28
- * ```
15
+ * React hook to check whether the user has approved sufficient SODA spending for the stake
16
+ * action. Read-only calls `staking.isAllowanceValid` with `raw: true` so no `walletProvider`
17
+ * is required.
29
18
  */
30
- export function useStakeAllowance(
31
- params: Omit<StakeParams, 'action'> | undefined,
32
- spokeProvider: SpokeProvider | undefined,
33
- ): UseQueryResult<boolean, Error> {
19
+ export function useStakeAllowance<K extends SpokeChainKey = SpokeChainKey>({
20
+ params,
21
+ queryOptions,
22
+ }: UseStakeAllowanceParams<K> = {}): UseQueryResult<boolean, Error> {
34
23
  const { sodax } = useSodaxContext();
24
+ const payload = params?.payload;
35
25
 
36
- return useQuery({
37
- queryKey: ['soda', 'stakeAllowance', params, spokeProvider?.chainConfig.chain.id],
26
+ return useQuery<boolean, Error>({
27
+ queryKey: ['staking', 'allowance', payload?.srcChainKey, 'stake', payload?.srcAddress, payload?.amount?.toString()],
38
28
  queryFn: async () => {
39
- if (!params || !spokeProvider) {
40
- return false;
29
+ if (!payload) {
30
+ throw new Error('Params are required');
41
31
  }
42
-
43
32
  const result = await sodax.staking.isAllowanceValid({
44
- params: { ...params, action: 'stake' },
45
- spokeProvider,
33
+ params: { ...payload, action: 'stake' },
34
+ raw: true,
46
35
  });
47
-
48
- if (!result.ok) {
49
- throw new Error(`Allowance check failed: ${result.error.code}`);
50
- }
51
-
36
+ if (!result.ok) throw result.error;
52
37
  return result.value;
53
38
  },
54
- enabled: !!params && !!spokeProvider,
55
- refetchInterval: 5000, // Refetch every 5 seconds
39
+ enabled: !!payload,
40
+ refetchInterval: 5_000,
41
+ gcTime: 0,
42
+ ...queryOptions,
56
43
  });
57
44
  }
@@ -1,50 +1,50 @@
1
1
  // packages/dapp-kit/src/hooks/staking/useStakeApprove.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
- import type { StakeParams, TxReturnType, SpokeProvider } from '@sodax/sdk';
4
- import { useMutation, type UseMutationResult } from '@tanstack/react-query';
2
+ import type { GetWalletProviderType, SpokeChainKey, StakeParams, TxReturnType } from '@sodax/sdk';
3
+ import { useQueryClient } from '@tanstack/react-query';
4
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
5
+ import type { MutationHookParams } from '../shared/types.js';
6
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
7
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
8
 
6
9
  /**
7
- * Hook for approving SODA token spending for staking operations.
8
- * Uses React Query's useMutation for better state management and caching.
9
- *
10
- * @param {SpokeProvider | undefined} spokeProvider - The spoke provider to use for the approval
11
- * @returns {UseMutationResult<TxReturnType<SpokeProvider, false>, Error, Omit<StakeParams, 'action'>>} Mutation result object containing mutation function and state
12
- *
13
- * @example
14
- * ```typescript
15
- * const { mutateAsync: approve, isPending } = useStakeApprove(spokeProvider);
16
- *
17
- * const handleApprove = async () => {
18
- * const result = await approve({
19
- * amount: 1000000000000000000n, // 1 SODA
20
- * account: '0x...'
21
- * });
10
+ * Mutation variables for {@link useStakeApprove}. The `action` literal is injected by the hook —
11
+ * callers pass the stake-specific fields only.
12
+ */
13
+ export type UseStakeApproveVars<K extends SpokeChainKey = SpokeChainKey> = {
14
+ params: Omit<StakeParams<K>, 'action'>;
15
+ walletProvider: GetWalletProviderType<K>;
16
+ };
17
+
18
+ /**
19
+ * React hook for approving SODA spending on the stake action.
22
20
  *
23
- * console.log('Approval successful:', result);
24
- * };
25
- * ```
21
+ * Throws on SDK failure so React Query's native error model engages (`isError`, `error`,
22
+ * `onError`, `retry`). Returns the unwrapped tx return value on success.
26
23
  */
27
- export function useStakeApprove(
28
- spokeProvider: SpokeProvider | undefined,
29
- ): UseMutationResult<TxReturnType<SpokeProvider, false>, Error, Omit<StakeParams, 'action'>> {
24
+ export function useStakeApprove<K extends SpokeChainKey = SpokeChainKey>({
25
+ mutationOptions,
26
+ }: MutationHookParams<TxReturnType<K, false>, UseStakeApproveVars<K>> = {}): SafeUseMutationResult<
27
+ TxReturnType<K, false>,
28
+ Error,
29
+ UseStakeApproveVars<K>
30
+ > {
30
31
  const { sodax } = useSodaxContext();
32
+ const queryClient = useQueryClient();
31
33
 
32
- return useMutation<TxReturnType<SpokeProvider, false>, Error, Omit<StakeParams, 'action'>>({
33
- mutationFn: async (params: Omit<StakeParams, 'action'>) => {
34
- if (!spokeProvider) {
35
- throw new Error('Spoke provider not found');
36
- }
37
-
38
- const result = await sodax.staking.approve({
39
- params: { ...params, action: 'stake' },
40
- spokeProvider,
41
- });
42
-
43
- if (!result.ok) {
44
- throw new Error(`Stake approval failed: ${result.error.code}`);
45
- }
46
-
47
- return result.value;
34
+ return useSafeMutation<TxReturnType<K, false>, Error, UseStakeApproveVars<K>>({
35
+ mutationKey: ['staking', 'approve', 'stake'],
36
+ ...mutationOptions,
37
+ mutationFn: async ({ params, walletProvider }) =>
38
+ unwrapResult(
39
+ await sodax.staking.approve({
40
+ params: { ...params, action: 'stake' },
41
+ raw: false,
42
+ walletProvider,
43
+ }),
44
+ ),
45
+ onSuccess: async (data, vars, ctx) => {
46
+ queryClient.invalidateQueries({ queryKey: ['staking', 'allowance', vars.params.srcChainKey, 'stake'] });
47
+ await mutationOptions?.onSuccess?.(data, vars, ctx);
48
48
  },
49
49
  });
50
50
  }
@@ -1,53 +1,37 @@
1
- // packages/dapp-kit/src/hooks/staking/useStakeRatio.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
1
  import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import type { ReadHookParams } from '../shared/types.js';
4
+
5
+ export type UseStakeRatioParams = ReadHookParams<
6
+ [bigint, bigint],
7
+ {
8
+ amount: bigint | undefined;
9
+ }
10
+ >;
4
11
 
5
12
  /**
6
- * Hook for fetching stake ratio estimates (xSoda amount and preview deposit).
7
- * Uses React Query for efficient caching and state management.
8
- *
9
- * @param {bigint | undefined} amount - The amount of SODA to estimate stake for
10
- * @param {number} refetchInterval - The interval in milliseconds to refetch data (default: 10000)
11
- * @returns {UseQueryResult<[bigint, bigint], Error>} Query result object containing stake ratio estimates and state
12
- *
13
- * @example
14
- * ```typescript
15
- * const { data: stakeRatio, isLoading, error } = useStakeRatio(1000000000000000000n); // 1 SODA
16
- *
17
- * if (isLoading) return <div>Loading stake ratio...</div>;
18
- * if (stakeRatio) {
19
- * const [xSodaAmount, previewDepositAmount] = stakeRatio;
20
- * console.log('xSoda amount:', xSodaAmount);
21
- * console.log('Preview deposit:', previewDepositAmount);
22
- * }
23
- * ```
13
+ * React hook to estimate the SODA → xSODA stake ratio for a given amount. Hub-only read. Throws
14
+ * on `!ok`.
24
15
  */
25
- export function useStakeRatio(
26
- amount: bigint | undefined,
27
- refetchInterval = 10000,
28
- ): UseQueryResult<[bigint, bigint], Error> {
16
+ export function useStakeRatio({
17
+ params,
18
+ queryOptions,
19
+ }: UseStakeRatioParams = {}): UseQueryResult<[bigint, bigint], Error> {
29
20
  const { sodax } = useSodaxContext();
21
+ const amount = params?.amount;
30
22
 
31
- return useQuery({
32
- queryKey: ['soda', 'stakeRatio', amount?.toString()],
23
+ return useQuery<[bigint, bigint], Error>({
24
+ queryKey: ['staking', 'stakeRatio', amount?.toString()],
33
25
  queryFn: async () => {
34
- if (!amount || amount <= 0n) {
35
- throw new Error('Amount must be greater than 0');
36
- }
37
-
38
- if (!sodax?.staking) {
39
- throw new Error('Staking service not available');
26
+ if (amount === undefined) {
27
+ throw new Error('amount is required');
40
28
  }
41
-
42
29
  const result = await sodax.staking.getStakeRatio(amount);
43
-
44
- if (!result.ok) {
45
- throw new Error(`Failed to fetch stake ratio: ${result.error.code}`);
46
- }
47
-
30
+ if (!result.ok) throw result.error;
48
31
  return result.value;
49
32
  },
50
- enabled: !!amount && amount > 0n && !!sodax?.staking,
51
- refetchInterval,
33
+ enabled: amount !== undefined,
34
+ refetchInterval: 10_000,
35
+ ...queryOptions,
52
36
  });
53
37
  }
@@ -1,40 +1,27 @@
1
- // packages/dapp-kit/src/hooks/staking/useStakingConfig.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
1
  import type { StakingConfig } from '@sodax/sdk';
4
2
  import { useQuery, type UseQueryResult } from '@tanstack/react-query';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import type { ReadHookParams } from '../shared/types.js';
5
+
6
+ export type UseStakingConfigParams = ReadHookParams<StakingConfig>;
5
7
 
6
8
  /**
7
- * Hook for fetching staking configuration from the stakedSoda contract.
8
- * Uses React Query for efficient caching and state management.
9
- *
10
- * @param {number} refetchInterval - The interval in milliseconds to refetch data (default: 30000)
11
- * @returns {UseQueryResult<StakingConfig, Error>} Query result object containing staking config and state
12
- *
13
- * @example
14
- * ```typescript
15
- * const { data: stakingConfig, isLoading, error } = useStakingConfig();
16
- *
17
- * if (isLoading) return <div>Loading staking config...</div>;
18
- * if (stakingConfig) {
19
- * console.log('Unstaking period (days):', stakingConfig.unstakingPeriod / 86400n);
20
- * console.log('Max penalty (%):', stakingConfig.maxPenalty);
21
- * }
22
- * ```
9
+ * React hook to fetch the global staking config (unstaking period, min unstaking period, max
10
+ * penalty). Hub-only read; no chain context required. Throws on `!ok`.
23
11
  */
24
- export function useStakingConfig(refetchInterval = 30000): UseQueryResult<StakingConfig, Error> {
12
+ export function useStakingConfig({
13
+ queryOptions,
14
+ }: UseStakingConfigParams = {}): UseQueryResult<StakingConfig, Error> {
25
15
  const { sodax } = useSodaxContext();
26
16
 
27
- return useQuery({
28
- queryKey: ['soda', 'stakingConfig'],
17
+ return useQuery<StakingConfig, Error>({
18
+ queryKey: ['staking', 'config'],
29
19
  queryFn: async () => {
30
20
  const result = await sodax.staking.getStakingConfig();
31
-
32
- if (!result.ok) {
33
- throw new Error(`Failed to fetch staking config: ${result.error.code}`);
34
- }
35
-
21
+ if (!result.ok) throw result.error;
36
22
  return result.value;
37
23
  },
38
- refetchInterval,
24
+ staleTime: Number.POSITIVE_INFINITY,
25
+ ...queryOptions,
39
26
  });
40
27
  }
@@ -1,50 +1,42 @@
1
- // packages/dapp-kit/src/hooks/staking/useStakingInfo.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
- import type { StakingInfo, SpokeProvider } from '@sodax/sdk';
1
+ import type { StakingInfo } from '@sodax/sdk';
2
+ import type { SpokeChainKey } from '@sodax/sdk';
4
3
  import { useQuery, type UseQueryResult } from '@tanstack/react-query';
4
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseStakingInfoParams = ReadHookParams<
8
+ StakingInfo,
9
+ {
10
+ srcAddress: `0x${string}` | undefined;
11
+ srcChainKey: SpokeChainKey | undefined;
12
+ }
13
+ >;
5
14
 
6
15
  /**
7
- * Hook for fetching comprehensive staking information for a user.
8
- * Uses React Query for efficient caching and state management.
9
- *
10
- * @param {SpokeProvider | undefined} spokeProvider - The spoke provider to use for the query
11
- * @param {number} refetchInterval - The interval in milliseconds to refetch data (default: 5000)
12
- * @returns {UseQueryResult<StakingInfo, Error>} Query result object containing staking info and state
13
- *
14
- * @example
15
- * ```typescript
16
- * const { data: stakingInfo, isLoading, error } = useStakingInfo(spokeProvider);
17
- *
18
- * if (isLoading) return <div>Loading staking info...</div>;
19
- * if (stakingInfo) {
20
- * console.log('Total staked:', stakingInfo.totalStaked);
21
- * console.log('User staked:', stakingInfo.userStaked);
22
- * console.log('xSODA balance:', stakingInfo.userXSodaBalance);
23
- * }
24
- * ```
16
+ * React hook to fetch the user's staking info (xSODA balance, share value, underlying SODA) by
17
+ * deriving the hub wallet from the spoke `srcAddress` + `srcChainKey`. Throws on `!ok` so React
18
+ * Query lands in `error` state.
25
19
  */
26
- export function useStakingInfo(
27
- spokeProvider: SpokeProvider | undefined,
28
- refetchInterval = 5000,
29
- ): UseQueryResult<StakingInfo, Error> {
20
+ export function useStakingInfo({ params, queryOptions }: UseStakingInfoParams = {}): UseQueryResult<
21
+ StakingInfo,
22
+ Error
23
+ > {
30
24
  const { sodax } = useSodaxContext();
25
+ const srcAddress = params?.srcAddress;
26
+ const srcChainKey = params?.srcChainKey;
31
27
 
32
- return useQuery({
33
- queryKey: ['soda', 'stakingInfo', spokeProvider?.chainConfig.chain.id],
28
+ return useQuery<StakingInfo, Error>({
29
+ queryKey: ['staking', 'info', srcChainKey, srcAddress],
34
30
  queryFn: async () => {
35
- if (!spokeProvider) {
36
- throw new Error('Spoke provider not found');
31
+ if (!srcAddress || !srcChainKey) {
32
+ throw new Error('srcAddress and srcChainKey are required');
37
33
  }
38
-
39
- const result = await sodax.staking.getStakingInfoFromSpoke(spokeProvider);
40
-
41
- if (!result.ok) {
42
- throw new Error(`Failed to fetch staking info: ${result.error.code}`);
43
- }
44
-
34
+ const result = await sodax.staking.getStakingInfoFromSpoke(srcAddress, srcChainKey);
35
+ if (!result.ok) throw result.error;
45
36
  return result.value;
46
37
  },
47
- enabled: !!spokeProvider,
48
- refetchInterval,
38
+ enabled: !!srcAddress && !!srcChainKey,
39
+ refetchInterval: 5_000,
40
+ ...queryOptions,
49
41
  });
50
42
  }
@@ -1,54 +1,40 @@
1
1
  // packages/dapp-kit/src/hooks/staking/useUnstake.ts
2
- import { useSodaxContext } from '../shared/useSodaxContext';
3
- import type { UnstakeParams, SpokeTxHash, HubTxHash, SpokeProvider } from '@sodax/sdk';
4
- import { useMutation, useQueryClient, type UseMutationResult } from '@tanstack/react-query';
2
+ import type { SpokeChainKey, TxHashPair, UnstakeAction } from '@sodax/sdk';
3
+ import { useQueryClient } from '@tanstack/react-query';
4
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
5
+ import type { MutationHookParams } from '../shared/types.js';
6
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
7
+ import { unwrapResult } from '../shared/unwrapResult.js';
8
+
9
+ export type UseUnstakeVars<K extends SpokeChainKey = SpokeChainKey> = Omit<UnstakeAction<K, false>, 'raw'>;
5
10
 
6
11
  /**
7
- * Hook for executing unstake transactions to unstake xSODA shares.
8
- * Uses React Query's useMutation for better state management and caching.
9
- *
10
- * @param {SpokeProvider | undefined} spokeProvider - The spoke provider to use for the unstake
11
- * @returns {UseMutationResult<[SpokeTxHash, HubTxHash], Error, Omit<UnstakeParams, 'action'>>} Mutation result object containing mutation function and state
12
- *
13
- * @example
14
- * ```typescript
15
- * const { mutateAsync: unstake, isPending } = useUnstake(spokeProvider);
16
- *
17
- * const handleUnstake = async () => {
18
- * const result = await unstake({
19
- * amount: 1000000000000000000n, // 1 xSODA
20
- * account: '0x...'
21
- * });
12
+ * React hook for initiating an SODA unstake.
22
13
  *
23
- * console.log('Unstake successful:', result);
24
- * };
25
- * ```
14
+ * Throws on SDK failure so React Query's native error model engages (`isError`, `error`,
15
+ * `onError`, `retry`). Returns the unwrapped `TxHashPair` on success.
26
16
  */
27
- export function useUnstake(
28
- spokeProvider: SpokeProvider | undefined,
29
- ): UseMutationResult<[SpokeTxHash, HubTxHash], Error, Omit<UnstakeParams, 'action'>> {
17
+ export function useUnstake<K extends SpokeChainKey = SpokeChainKey>({
18
+ mutationOptions,
19
+ }: MutationHookParams<TxHashPair, UseUnstakeVars<K>> = {}): SafeUseMutationResult<TxHashPair, Error, UseUnstakeVars<K>> {
30
20
  const { sodax } = useSodaxContext();
31
21
  const queryClient = useQueryClient();
32
22
 
33
- return useMutation<[SpokeTxHash, HubTxHash], Error, Omit<UnstakeParams, 'action'>>({
34
- mutationFn: async (params: Omit<UnstakeParams, 'action'>) => {
35
- if (!spokeProvider) {
36
- throw new Error('Spoke provider not found');
37
- }
38
-
39
- const result = await sodax.staking.unstake({ ...params, action: 'unstake' }, spokeProvider);
40
-
41
- if (!result.ok) {
42
- throw new Error(`Unstake failed: ${result.error.code}`);
43
- }
44
-
45
- return result.value;
46
- },
47
- onSuccess: () => {
48
- // Invalidate relevant queries to refresh data
49
- queryClient.invalidateQueries({ queryKey: ['stakingInfo'] });
50
- queryClient.invalidateQueries({ queryKey: ['unstakingInfo'] });
51
- queryClient.invalidateQueries({ queryKey: ['unstakingInfoWithPenalty'] });
23
+ return useSafeMutation<TxHashPair, Error, UseUnstakeVars<K>>({
24
+ mutationKey: ['staking', 'unstake'],
25
+ ...mutationOptions,
26
+ mutationFn: async vars => unwrapResult(await sodax.staking.unstake({ ...vars, raw: false })),
27
+ onSuccess: async (data, vars, ctx) => {
28
+ const { params } = vars;
29
+ queryClient.invalidateQueries({ queryKey: ['staking', 'info', params.srcChainKey, params.srcAddress] });
30
+ // Scope to (srcChainKey, srcAddress) so a user's unstake doesn't refetch every other user's
31
+ // staking data. Matches `useUnstakingInfo` / `useUnstakingInfoWithPenalty` query keys.
32
+ queryClient.invalidateQueries({ queryKey: ['staking', 'unstakingInfo', params.srcChainKey, params.srcAddress] });
33
+ queryClient.invalidateQueries({
34
+ queryKey: ['staking', 'unstakingInfoWithPenalty', params.srcChainKey, params.srcAddress],
35
+ });
36
+ queryClient.invalidateQueries({ queryKey: ['staking', 'allowance', params.srcChainKey, 'unstake'] });
37
+ await mutationOptions?.onSuccess?.(data, vars, ctx);
52
38
  },
53
39
  });
54
40
  }