@sodax/dapp-kit 2.0.0-rc.2 → 2.0.0-rc.20

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 (129) hide show
  1. package/README.md +29 -74
  2. package/dist/index.d.ts +780 -58
  3. package/dist/index.mjs +841 -143
  4. package/package.json +31 -19
  5. package/src/hooks/_mutationContract.test.ts +15 -2
  6. package/src/hooks/backend/index.ts +1 -5
  7. package/src/hooks/bitcoin/index.ts +2 -0
  8. package/src/hooks/bitcoin/resolveBtcReadAddress.test.ts +54 -0
  9. package/src/hooks/bitcoin/resolveBtcReadAddress.ts +21 -0
  10. package/src/hooks/bitcoin/useBitcoinTradingSetup.ts +45 -0
  11. package/src/hooks/bitcoin/useEnsureRadfiAccessToken.ts +57 -0
  12. package/src/hooks/bitcoin/useFundTradingWallet.ts +1 -1
  13. package/src/hooks/bitcoin/useRadfiAuth.ts +2 -2
  14. package/src/hooks/bitcoin/useRadfiWithdraw.ts +2 -2
  15. package/src/hooks/bitcoin/useRenewUtxos.ts +2 -2
  16. package/src/hooks/bitcoin/useTradingWallet.ts +1 -1
  17. package/src/hooks/index.ts +2 -0
  18. package/src/hooks/leverageYield/index.ts +9 -0
  19. package/src/hooks/leverageYield/useLeverageYieldDeposit.ts +40 -0
  20. package/src/hooks/leverageYield/useLeverageYieldEffectiveApr.ts +42 -0
  21. package/src/hooks/leverageYield/useLeverageYieldNotifySolver.ts +34 -0
  22. package/src/hooks/leverageYield/useLeverageYieldPosition.ts +40 -0
  23. package/src/hooks/leverageYield/useLeverageYieldPreviewRedeem.ts +43 -0
  24. package/src/hooks/leverageYield/useLeverageYieldShareBalances.ts +74 -0
  25. package/src/hooks/leverageYield/useLeverageYieldTotalAssets.ts +36 -0
  26. package/src/hooks/leverageYield/useLeverageYieldVaultSwap.ts +50 -0
  27. package/src/hooks/leverageYield/useLeverageYieldWithdraw.ts +40 -0
  28. package/src/hooks/mm/useATokensBalances.ts +7 -1
  29. package/src/hooks/mm/useUserFormattedSummary.ts +5 -1
  30. package/src/hooks/mm/useUserReservesData.ts +5 -1
  31. package/src/hooks/partner/index.ts +4 -0
  32. package/src/hooks/partner/useFeeClaimWithdraw.ts +88 -0
  33. package/src/hooks/partner/useGetIntentDetails.ts +39 -0
  34. package/src/hooks/partner/useGetUserIntent.ts +35 -0
  35. package/src/hooks/partner/usePartnerCancelIntent.ts +52 -0
  36. package/src/hooks/shared/index.ts +4 -0
  37. package/src/hooks/shared/isUserRejectedError.test.ts +42 -0
  38. package/src/hooks/shared/isUserRejectedError.ts +30 -0
  39. package/src/hooks/shared/useGetUserHubWalletAddress.ts +5 -1
  40. package/src/hooks/shared/useNearStorageCheck.ts +45 -0
  41. package/src/hooks/shared/useNearStorageGate.ts +60 -0
  42. package/src/hooks/shared/useRegisterNearStorage.ts +46 -0
  43. package/src/hooks/swapsApi/index.ts +41 -0
  44. package/src/hooks/swapsApi/isTerminalSwapIntentStatus.test.ts +24 -0
  45. package/src/hooks/swapsApi/isTerminalSwapIntentStatus.ts +11 -0
  46. package/src/hooks/swapsApi/useSwapsApiAllowance.ts +40 -0
  47. package/src/hooks/swapsApi/useSwapsApiApprove.ts +42 -0
  48. package/src/hooks/swapsApi/useSwapsApiCancelIntent.ts +41 -0
  49. package/src/hooks/swapsApi/useSwapsApiCreateIntent.ts +41 -0
  50. package/src/hooks/swapsApi/useSwapsApiCreateLimitOrder.ts +41 -0
  51. package/src/hooks/swapsApi/useSwapsApiDeadline.ts +36 -0
  52. package/src/hooks/swapsApi/useSwapsApiEstimateGas.ts +40 -0
  53. package/src/hooks/swapsApi/useSwapsApiFilledIntent.ts +41 -0
  54. package/src/hooks/swapsApi/useSwapsApiIntent.ts +40 -0
  55. package/src/hooks/swapsApi/useSwapsApiIntentExtraData.ts +41 -0
  56. package/src/hooks/swapsApi/useSwapsApiIntentHash.ts +40 -0
  57. package/src/hooks/swapsApi/useSwapsApiIntentPacket.ts +43 -0
  58. package/src/hooks/swapsApi/useSwapsApiPartnerFee.ts +40 -0
  59. package/src/hooks/swapsApi/useSwapsApiQuote.ts +55 -0
  60. package/src/hooks/swapsApi/useSwapsApiSolverFee.ts +40 -0
  61. package/src/hooks/swapsApi/useSwapsApiStatus.ts +45 -0
  62. package/src/hooks/swapsApi/useSwapsApiSubmitIntent.ts +43 -0
  63. package/src/hooks/{backend/useBackendSubmitSwapTx.ts → swapsApi/useSwapsApiSubmitTx.ts} +16 -17
  64. package/src/hooks/swapsApi/useSwapsApiSubmitTxStatus.ts +55 -0
  65. package/src/hooks/swapsApi/useSwapsApiTokens.ts +34 -0
  66. package/src/hooks/swapsApi/useSwapsApiTokensByChain.ts +40 -0
  67. package/src/providers/SodaxProvider.tsx +17 -14
  68. package/src/utils/index.ts +1 -0
  69. package/src/utils/nearStorageGate.test.ts +46 -0
  70. package/src/utils/nearStorageGate.ts +39 -0
  71. package/ai-exported/AGENTS.md +0 -134
  72. package/ai-exported/integration/README.md +0 -49
  73. package/ai-exported/integration/ai-rules.md +0 -79
  74. package/ai-exported/integration/architecture.md +0 -274
  75. package/ai-exported/integration/features/README.md +0 -29
  76. package/ai-exported/integration/features/auxiliary-services.md +0 -169
  77. package/ai-exported/integration/features/bitcoin.md +0 -87
  78. package/ai-exported/integration/features/bridge.md +0 -91
  79. package/ai-exported/integration/features/dex.md +0 -152
  80. package/ai-exported/integration/features/migration.md +0 -118
  81. package/ai-exported/integration/features/money-market.md +0 -116
  82. package/ai-exported/integration/features/staking.md +0 -123
  83. package/ai-exported/integration/features/swap.md +0 -101
  84. package/ai-exported/integration/quickstart.md +0 -187
  85. package/ai-exported/integration/recipes/README.md +0 -136
  86. package/ai-exported/integration/recipes/backend-queries.md +0 -157
  87. package/ai-exported/integration/recipes/bitcoin.md +0 -193
  88. package/ai-exported/integration/recipes/bridge.md +0 -174
  89. package/ai-exported/integration/recipes/dex.md +0 -204
  90. package/ai-exported/integration/recipes/invalidations.md +0 -115
  91. package/ai-exported/integration/recipes/migration.md +0 -212
  92. package/ai-exported/integration/recipes/money-market.md +0 -206
  93. package/ai-exported/integration/recipes/mutation-error-handling.md +0 -118
  94. package/ai-exported/integration/recipes/observability.md +0 -93
  95. package/ai-exported/integration/recipes/setup.md +0 -144
  96. package/ai-exported/integration/recipes/staking.md +0 -202
  97. package/ai-exported/integration/recipes/swap.md +0 -272
  98. package/ai-exported/integration/recipes/wallet-connectivity.md +0 -101
  99. package/ai-exported/integration/reference/README.md +0 -12
  100. package/ai-exported/integration/reference/glossary.md +0 -188
  101. package/ai-exported/integration/reference/hooks-index.md +0 -190
  102. package/ai-exported/integration/reference/public-api.md +0 -110
  103. package/ai-exported/integration/reference/querykey-conventions.md +0 -179
  104. package/ai-exported/migration/README.md +0 -60
  105. package/ai-exported/migration/ai-rules.md +0 -81
  106. package/ai-exported/migration/breaking-changes/hook-signatures.md +0 -233
  107. package/ai-exported/migration/breaking-changes/querykey-conventions.md +0 -108
  108. package/ai-exported/migration/breaking-changes/result-handling.md +0 -211
  109. package/ai-exported/migration/breaking-changes/sdk-leakage.md +0 -165
  110. package/ai-exported/migration/checklist.md +0 -89
  111. package/ai-exported/migration/features/README.md +0 -34
  112. package/ai-exported/migration/features/auxiliary-services.md +0 -114
  113. package/ai-exported/migration/features/bitcoin.md +0 -88
  114. package/ai-exported/migration/features/bridge.md +0 -123
  115. package/ai-exported/migration/features/dex.md +0 -101
  116. package/ai-exported/migration/features/migration.md +0 -120
  117. package/ai-exported/migration/features/money-market.md +0 -97
  118. package/ai-exported/migration/features/staking.md +0 -109
  119. package/ai-exported/migration/features/swap.md +0 -118
  120. package/ai-exported/migration/recipes.md +0 -188
  121. package/ai-exported/migration/reference/README.md +0 -15
  122. package/ai-exported/migration/reference/deleted-hooks.md +0 -110
  123. package/ai-exported/migration/reference/error-shape-crosswalk.md +0 -144
  124. package/ai-exported/migration/reference/renamed-hooks.md +0 -66
  125. package/dist/index.cjs +0 -2642
  126. package/dist/index.cjs.map +0 -1
  127. package/dist/index.d.cts +0 -1550
  128. package/dist/index.mjs.map +0 -1
  129. package/src/hooks/backend/useBackendSubmitSwapTxStatus.ts +0 -59
@@ -0,0 +1,45 @@
1
+ import { ChainKeys, type SpokeChainKey } from '@sodax/sdk';
2
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
3
+ import { useSodaxContext } from './useSodaxContext.js';
4
+ import type { ReadHookParams } from './types.js';
5
+
6
+ export type UseNearStorageCheckParams = ReadHookParams<
7
+ boolean,
8
+ {
9
+ token: string | undefined;
10
+ accountId: string | undefined;
11
+ chainId: SpokeChainKey | undefined;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * Whether `accountId` is NEP-141 storage-registered for `token` on NEAR — the receive-side
17
+ * prerequisite for any leg that delivers a token to the user on NEAR (swap output on NEAR, bridge
18
+ * into NEAR, money-market borrow/withdraw to NEAR). NEAR's analogue of a Stellar trustline.
19
+ *
20
+ * Returns `true` (no gate) when `chainId` is not NEAR, mirroring how the Stellar trustline check
21
+ * short-circuits off-chain. Native NEAR is not a NEP-141 token, so the SDK reports it as registered.
22
+ *
23
+ * Pair with {@link useRegisterNearStorage} to perform the one-time `storage_deposit` when this
24
+ * resolves to `false`.
25
+ */
26
+ export function useNearStorageCheck({
27
+ params,
28
+ queryOptions,
29
+ }: UseNearStorageCheckParams = {}): UseQueryResult<boolean, Error> {
30
+ const { sodax } = useSodaxContext();
31
+ const token = params?.token;
32
+ const accountId = params?.accountId;
33
+ const chainId = params?.chainId;
34
+
35
+ return useQuery<boolean, Error>({
36
+ queryKey: ['shared', 'nearStorageCheck', chainId, token, accountId],
37
+ queryFn: async () => {
38
+ if (chainId !== ChainKeys.NEAR_MAINNET) return true;
39
+ if (!token || !accountId) return false;
40
+ return sodax.spoke.near.isStorageRegistered(token, accountId);
41
+ },
42
+ enabled: !!token && !!accountId,
43
+ ...queryOptions,
44
+ });
45
+ }
@@ -0,0 +1,60 @@
1
+ import type { GetWalletProviderType, INearWalletProvider, Result, SpokeChainKey } from '@sodax/sdk';
2
+ import { resolveNearStorageGate } from '../../utils/nearStorageGate.js';
3
+ import { useNearStorageCheck } from './useNearStorageCheck.js';
4
+ import { useRegisterNearStorage } from './useRegisterNearStorage.js';
5
+
6
+ interface UseNearStorageGateParams {
7
+ /** Destination chain the token is delivered on. */
8
+ dstChainKey: SpokeChainKey;
9
+ /** Destination token address the recipient must be registered for. */
10
+ token: string | undefined;
11
+ /** Recipient NEAR account id. */
12
+ accountId: string | undefined;
13
+ /** Destination wallet provider; only consumed when it is the NEAR provider. */
14
+ walletProvider: GetWalletProviderType<SpokeChainKey> | undefined;
15
+ }
16
+
17
+ interface NearStorageGate {
18
+ /** Destination is NEAR. */
19
+ isNear: boolean;
20
+ /** Destination is NEAR and the recipient is not yet storage-registered for `token`. */
21
+ needsRegistration: boolean;
22
+ /** The downstream action must stay disabled while the gate is unresolved or unmet. */
23
+ blocksAction: boolean;
24
+ /** The registration-status query is actively fetching. */
25
+ isChecking: boolean;
26
+ /** A `storage_deposit` tx is in flight. */
27
+ isRegistering: boolean;
28
+ /** Submit the `storage_deposit`; resolves to the SDK `Result` or `undefined` if inputs are missing. */
29
+ registerStorage: () => Promise<Result<string> | undefined>;
30
+ }
31
+
32
+ /**
33
+ * NEP-141 storage-registration gate for flows that deliver a token to a user on NEAR.
34
+ */
35
+ export function useNearStorageGate({
36
+ dstChainKey,
37
+ token,
38
+ accountId,
39
+ walletProvider,
40
+ }: UseNearStorageGateParams): NearStorageGate {
41
+ const nearWalletProvider = walletProvider?.chainType === 'NEAR' ? (walletProvider as INearWalletProvider) : undefined;
42
+
43
+ const storageCheck = useNearStorageCheck({ params: { token, accountId, chainId: dstChainKey } });
44
+ const { mutateAsyncSafe: register, isPending: isRegistering } = useRegisterNearStorage();
45
+ const { isNear, needsRegistration, blocksAction } = resolveNearStorageGate(dstChainKey, storageCheck);
46
+
47
+ const registerStorage = async (): Promise<Result<string> | undefined> => {
48
+ if (!nearWalletProvider || !token || !accountId) return undefined;
49
+ return register({ token, accountId, walletProvider: nearWalletProvider });
50
+ };
51
+
52
+ return {
53
+ isNear,
54
+ needsRegistration,
55
+ blocksAction,
56
+ isChecking: storageCheck.isLoading,
57
+ isRegistering,
58
+ registerStorage,
59
+ };
60
+ }
@@ -0,0 +1,46 @@
1
+ import { ChainKeys, type INearWalletProvider } from '@sodax/sdk';
2
+ import { useQueryClient } from '@tanstack/react-query';
3
+ import { useSodaxContext } from './useSodaxContext.js';
4
+ import type { MutationHookParams } from './types.js';
5
+ import { useSafeMutation, type SafeUseMutationResult } from './useSafeMutation.js';
6
+
7
+ export type UseRegisterNearStorageVars = {
8
+ token: string;
9
+ accountId: string;
10
+ walletProvider: INearWalletProvider;
11
+ /** Storage bond override; defaults to the SDK's `NEAR_STORAGE_DEPOSIT` (0.00125 NEAR). */
12
+ deposit?: bigint;
13
+ };
14
+
15
+ /**
16
+ * Submit a NEP-141 `storage_deposit` so `accountId` can receive `token` on NEAR. NEAR's analogue of
17
+ * requesting a Stellar trustline; pair with {@link useNearStorageCheck} and call this when the check
18
+ * resolves to `false`. The recipient's NEAR wallet signs the registration tx.
19
+ *
20
+ * Pure mutation: pass `{ token, accountId, walletProvider }` to `mutate(...)`. The hook itself only
21
+ * takes the structural `mutationOptions` slot. `registerStorage` throws natively (no `Result<T>`),
22
+ * so this hook is registered as `nativeThrow` in the mutation contract. On success it invalidates
23
+ * the matching {@link useNearStorageCheck} query.
24
+ */
25
+ export function useRegisterNearStorage({
26
+ mutationOptions,
27
+ }: MutationHookParams<string, UseRegisterNearStorageVars> = {}): SafeUseMutationResult<
28
+ string,
29
+ Error,
30
+ UseRegisterNearStorageVars
31
+ > {
32
+ const { sodax } = useSodaxContext();
33
+ const queryClient = useQueryClient();
34
+ return useSafeMutation<string, Error, UseRegisterNearStorageVars>({
35
+ mutationKey: ['shared', 'registerNearStorage'],
36
+ ...mutationOptions,
37
+ mutationFn: async ({ token, accountId, walletProvider, deposit }) =>
38
+ sodax.spoke.near.registerStorage({ token, accountId, walletProvider, deposit, raw: false }),
39
+ onSuccess: async (data, vars, ctx) => {
40
+ queryClient.invalidateQueries({
41
+ queryKey: ['shared', 'nearStorageCheck', ChainKeys.NEAR_MAINNET, vars.token, vars.accountId],
42
+ });
43
+ await mutationOptions?.onSuccess?.(data, vars, ctx);
44
+ },
45
+ });
46
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Swaps API v2 hooks — typed React Query wrappers over `sodax.api.swaps.*` (the SwapsApiService
3
+ * HTTP client). One hook per endpoint of the backend Swaps API v2.
4
+ *
5
+ * Distinct from the on-chain `swap/` hooks (`useQuote`/`useStatus`/`useSwap`/…), which drive the
6
+ * `SwapService` path (wallet → hub chain). These hooks call the backend HTTP API instead.
7
+ */
8
+
9
+ // Tokens
10
+ export * from './useSwapsApiTokens.js';
11
+ export * from './useSwapsApiTokensByChain.js';
12
+
13
+ // Quote · deadline
14
+ export * from './useSwapsApiQuote.js';
15
+ export * from './useSwapsApiDeadline.js';
16
+
17
+ // Allowance · approve · create intent
18
+ export * from './useSwapsApiAllowance.js';
19
+ export * from './useSwapsApiApprove.js';
20
+ export * from './useSwapsApiCreateIntent.js';
21
+
22
+ // Intent lifecycle: submit · status · cancel · hash · packet · extra-data · lookup
23
+ export * from './useSwapsApiSubmitIntent.js';
24
+ export * from './useSwapsApiStatus.js';
25
+ export * from './isTerminalSwapIntentStatus.js'; // terminal-status predicate (drives the status hook's polling)
26
+ export * from './useSwapsApiCancelIntent.js';
27
+ export * from './useSwapsApiIntentHash.js';
28
+ export * from './useSwapsApiIntentPacket.js';
29
+ export * from './useSwapsApiIntentExtraData.js';
30
+ export * from './useSwapsApiFilledIntent.js';
31
+ export * from './useSwapsApiIntent.js';
32
+
33
+ // Limit orders · gas · fees
34
+ export * from './useSwapsApiCreateLimitOrder.js';
35
+ export * from './useSwapsApiEstimateGas.js';
36
+ export * from './useSwapsApiPartnerFee.js';
37
+ export * from './useSwapsApiSolverFee.js';
38
+
39
+ // Submit-tx state machine
40
+ export * from './useSwapsApiSubmitTx.js';
41
+ export * from './useSwapsApiSubmitTxStatus.js';
@@ -0,0 +1,24 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { isTerminalSwapIntentStatus } from './isTerminalSwapIntentStatus.js';
3
+
4
+ /**
5
+ * Guards the polling-stop invariant for `useSwapsApiStatus.refetchInterval`: the hook keeps polling
6
+ * (1s) until the solver reports a terminal status, then stops. Tested as a pure predicate because
7
+ * dapp-kit's vitest runs in the `node` environment (no hook rendering) — see nearStorageGate.test.ts.
8
+ */
9
+ describe('isTerminalSwapIntentStatus', () => {
10
+ it('is terminal for SOLVED (3) and FAILED (4)', () => {
11
+ expect(isTerminalSwapIntentStatus(3)).toBe(true);
12
+ expect(isTerminalSwapIntentStatus(4)).toBe(true);
13
+ });
14
+
15
+ it('is non-terminal for NOT_FOUND (-1), NOT_STARTED_YET (1), and STARTED_NOT_FINISHED (2)', () => {
16
+ expect(isTerminalSwapIntentStatus(-1)).toBe(false);
17
+ expect(isTerminalSwapIntentStatus(1)).toBe(false);
18
+ expect(isTerminalSwapIntentStatus(2)).toBe(false);
19
+ });
20
+
21
+ it('is non-terminal when no status has arrived yet (undefined) — keeps polling', () => {
22
+ expect(isTerminalSwapIntentStatus(undefined)).toBe(false);
23
+ });
24
+ });
@@ -0,0 +1,11 @@
1
+ import type { SwapIntentStatusCodeV2 } from '@sodax/sdk';
2
+
3
+ /**
4
+ * Terminal solver intent states: once reached, the intent is resolved and polling stops.
5
+ * `3` = SOLVED, `4` = FAILED (per `SwapIntentStatusCodeV2`); `-1` / `1` / `2` are non-terminal.
6
+ *
7
+ * Kept in its own pure module (no React/context imports) so it is unit-testable in dapp-kit's
8
+ * `node` test environment — importing the hook itself pulls in `useSodaxContext`.
9
+ */
10
+ export const isTerminalSwapIntentStatus = (status: SwapIntentStatusCodeV2 | undefined): boolean =>
11
+ status === 3 || status === 4;
@@ -0,0 +1,40 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import type { AllowanceCheckResponseV2, CreateIntentParamsV2, RequestOverrideConfig } from '@sodax/sdk';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseSwapsApiAllowanceParams = ReadHookParams<
8
+ AllowanceCheckResponseV2 | undefined,
9
+ {
10
+ body: CreateIntentParamsV2 | undefined;
11
+ apiConfig?: RequestOverrideConfig;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * React hook to check whether the source-token allowance is already sufficient for an intent via
17
+ * the swaps API — `sodax.api.swaps.checkAllowance`. Returns `{ valid }`.
18
+ *
19
+ * @example
20
+ * const { data: allowance } = useSwapsApiAllowance({ params: { body: createIntentParams } });
21
+ */
22
+ export const useSwapsApiAllowance = ({
23
+ params,
24
+ queryOptions,
25
+ }: UseSwapsApiAllowanceParams = {}): UseQueryResult<AllowanceCheckResponseV2 | undefined, Error> => {
26
+ const { sodax } = useSodaxContext();
27
+ const body = params?.body;
28
+ const apiConfig = params?.apiConfig;
29
+
30
+ return useQuery({
31
+ queryKey: ['swapsApi', 'allowance', body?.srcChainKey, body?.inputToken, body?.inputAmount, body?.srcAddress],
32
+ queryFn: async (): Promise<AllowanceCheckResponseV2 | undefined> => {
33
+ if (!body) return undefined;
34
+ return unwrapResult(await sodax.api.swaps.checkAllowance(body, apiConfig));
35
+ },
36
+ enabled: !!body,
37
+ retry: 3,
38
+ ...queryOptions,
39
+ });
40
+ };
@@ -0,0 +1,42 @@
1
+ import type { ApproveResponseV2, CreateIntentParamsV2, RequestOverrideConfig } from '@sodax/sdk';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import { unwrapResult } from '../shared/unwrapResult.js';
4
+ import type { MutationHookParams } from '../shared/types.js';
5
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
6
+
7
+ /**
8
+ * Mutation variables for {@link useSwapsApiApprove}. The per-request `apiConfig` override belongs
9
+ * here rather than at the hook level — different calls in the same component can target different
10
+ * endpoints without re-rendering.
11
+ */
12
+ export type UseSwapsApiApproveVars = {
13
+ body: CreateIntentParamsV2;
14
+ apiConfig?: RequestOverrideConfig;
15
+ };
16
+
17
+ /**
18
+ * React hook to build an unsigned token-approval transaction for the source token via the swaps
19
+ * API — `sodax.api.swaps.approve`. Returns `{ tx }` (chain-specific unsigned tx) to sign and
20
+ * broadcast yourself; it does not change state, so no queries are invalidated.
21
+ *
22
+ * @example
23
+ * const { mutateAsync: approve } = useSwapsApiApprove();
24
+ * const { tx } = await approve({ body: createIntentParams });
25
+ */
26
+ export const useSwapsApiApprove = ({
27
+ mutationOptions,
28
+ }: MutationHookParams<ApproveResponseV2, UseSwapsApiApproveVars> = {}): SafeUseMutationResult<
29
+ ApproveResponseV2,
30
+ Error,
31
+ UseSwapsApiApproveVars
32
+ > => {
33
+ const { sodax } = useSodaxContext();
34
+
35
+ return useSafeMutation<ApproveResponseV2, Error, UseSwapsApiApproveVars>({
36
+ mutationKey: ['swapsApi', 'approve'],
37
+ retry: 3,
38
+ ...mutationOptions,
39
+ mutationFn: async ({ body, apiConfig }): Promise<ApproveResponseV2> =>
40
+ unwrapResult(await sodax.api.swaps.approve(body, apiConfig)),
41
+ });
42
+ };
@@ -0,0 +1,41 @@
1
+ import type { CancelIntentRequestV2, CancelIntentResponseV2, RequestOverrideConfig } from '@sodax/sdk';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import { unwrapResult } from '../shared/unwrapResult.js';
4
+ import type { MutationHookParams } from '../shared/types.js';
5
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
6
+
7
+ /**
8
+ * Mutation variables for {@link useSwapsApiCancelIntent}. The per-request `apiConfig` override
9
+ * belongs here rather than at the hook level.
10
+ */
11
+ export type UseSwapsApiCancelIntentVars = {
12
+ body: CancelIntentRequestV2;
13
+ apiConfig?: RequestOverrideConfig;
14
+ };
15
+
16
+ /**
17
+ * React hook to build an unsigned cancel-intent transaction via the swaps API —
18
+ * `sodax.api.swaps.cancelIntent`. The `intent` carries `bigint` numerics. Returns `{ tx }` to sign
19
+ * and broadcast yourself; it does not change state, so no queries are invalidated.
20
+ *
21
+ * @example
22
+ * const { mutateAsync: cancelIntent } = useSwapsApiCancelIntent();
23
+ * const { tx } = await cancelIntent({ body: { srcChainKey: 'sonic', intent } });
24
+ */
25
+ export const useSwapsApiCancelIntent = ({
26
+ mutationOptions,
27
+ }: MutationHookParams<CancelIntentResponseV2, UseSwapsApiCancelIntentVars> = {}): SafeUseMutationResult<
28
+ CancelIntentResponseV2,
29
+ Error,
30
+ UseSwapsApiCancelIntentVars
31
+ > => {
32
+ const { sodax } = useSodaxContext();
33
+
34
+ return useSafeMutation<CancelIntentResponseV2, Error, UseSwapsApiCancelIntentVars>({
35
+ mutationKey: ['swapsApi', 'cancelIntent'],
36
+ retry: 3,
37
+ ...mutationOptions,
38
+ mutationFn: async ({ body, apiConfig }): Promise<CancelIntentResponseV2> =>
39
+ unwrapResult(await sodax.api.swaps.cancelIntent(body, apiConfig)),
40
+ });
41
+ };
@@ -0,0 +1,41 @@
1
+ import type { CreateIntentParamsV2, CreateIntentResponseV2, RequestOverrideConfig } from '@sodax/sdk';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import { unwrapResult } from '../shared/unwrapResult.js';
4
+ import type { MutationHookParams } from '../shared/types.js';
5
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
6
+
7
+ /**
8
+ * Mutation variables for {@link useSwapsApiCreateIntent}. The per-request `apiConfig` override
9
+ * belongs here rather than at the hook level.
10
+ */
11
+ export type UseSwapsApiCreateIntentVars = {
12
+ body: CreateIntentParamsV2;
13
+ apiConfig?: RequestOverrideConfig;
14
+ };
15
+
16
+ /**
17
+ * React hook to build an unsigned create-intent transaction via the swaps API —
18
+ * `sodax.api.swaps.createIntent`. Returns `{ tx, intent, relayData }` to sign and broadcast
19
+ * yourself; it does not change state, so no queries are invalidated.
20
+ *
21
+ * @example
22
+ * const { mutateAsync: createIntent } = useSwapsApiCreateIntent();
23
+ * const { tx, intent, relayData } = await createIntent({ body: createIntentParams });
24
+ */
25
+ export const useSwapsApiCreateIntent = ({
26
+ mutationOptions,
27
+ }: MutationHookParams<CreateIntentResponseV2, UseSwapsApiCreateIntentVars> = {}): SafeUseMutationResult<
28
+ CreateIntentResponseV2,
29
+ Error,
30
+ UseSwapsApiCreateIntentVars
31
+ > => {
32
+ const { sodax } = useSodaxContext();
33
+
34
+ return useSafeMutation<CreateIntentResponseV2, Error, UseSwapsApiCreateIntentVars>({
35
+ mutationKey: ['swapsApi', 'createIntent'],
36
+ retry: 3,
37
+ ...mutationOptions,
38
+ mutationFn: async ({ body, apiConfig }): Promise<CreateIntentResponseV2> =>
39
+ unwrapResult(await sodax.api.swaps.createIntent(body, apiConfig)),
40
+ });
41
+ };
@@ -0,0 +1,41 @@
1
+ import type { CreateLimitOrderParamsV2, CreateLimitOrderResponseV2, RequestOverrideConfig } from '@sodax/sdk';
2
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
3
+ import { unwrapResult } from '../shared/unwrapResult.js';
4
+ import type { MutationHookParams } from '../shared/types.js';
5
+ import { useSafeMutation, type SafeUseMutationResult } from '../shared/useSafeMutation.js';
6
+
7
+ /**
8
+ * Mutation variables for {@link useSwapsApiCreateLimitOrder}. The per-request `apiConfig` override
9
+ * belongs here rather than at the hook level.
10
+ */
11
+ export type UseSwapsApiCreateLimitOrderVars = {
12
+ body: CreateLimitOrderParamsV2;
13
+ apiConfig?: RequestOverrideConfig;
14
+ };
15
+
16
+ /**
17
+ * React hook to build an unsigned create-limit-order-intent transaction via the swaps API —
18
+ * `sodax.api.swaps.createLimitOrderIntent` (same as create-intent but `deadline` is optional).
19
+ * Returns `{ tx, intent, relayData }`; it does not change state, so no queries are invalidated.
20
+ *
21
+ * @example
22
+ * const { mutateAsync: createLimitOrder } = useSwapsApiCreateLimitOrder();
23
+ * const { tx, intent, relayData } = await createLimitOrder({ body: createLimitOrderParams });
24
+ */
25
+ export const useSwapsApiCreateLimitOrder = ({
26
+ mutationOptions,
27
+ }: MutationHookParams<CreateLimitOrderResponseV2, UseSwapsApiCreateLimitOrderVars> = {}): SafeUseMutationResult<
28
+ CreateLimitOrderResponseV2,
29
+ Error,
30
+ UseSwapsApiCreateLimitOrderVars
31
+ > => {
32
+ const { sodax } = useSodaxContext();
33
+
34
+ return useSafeMutation<CreateLimitOrderResponseV2, Error, UseSwapsApiCreateLimitOrderVars>({
35
+ mutationKey: ['swapsApi', 'createLimitOrder'],
36
+ retry: 3,
37
+ ...mutationOptions,
38
+ mutationFn: async ({ body, apiConfig }): Promise<CreateLimitOrderResponseV2> =>
39
+ unwrapResult(await sodax.api.swaps.createLimitOrderIntent(body, apiConfig)),
40
+ });
41
+ };
@@ -0,0 +1,36 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import type { DeadlineQueryV2, DeadlineResponseV2, RequestOverrideConfig } from '@sodax/sdk';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseSwapsApiDeadlineParams = ReadHookParams<
8
+ DeadlineResponseV2,
9
+ {
10
+ query?: DeadlineQueryV2;
11
+ apiConfig?: RequestOverrideConfig;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * React hook to compute a swap deadline (hub timestamp + `offsetSeconds`, default 300s) via the
17
+ * swaps API — `sodax.api.swaps.getDeadline`.
18
+ *
19
+ * @example
20
+ * const { data: deadline } = useSwapsApiDeadline({ params: { query: { offsetSeconds: 600 } } });
21
+ */
22
+ export const useSwapsApiDeadline = ({
23
+ params,
24
+ queryOptions,
25
+ }: UseSwapsApiDeadlineParams = {}): UseQueryResult<DeadlineResponseV2, Error> => {
26
+ const { sodax } = useSodaxContext();
27
+ const query = params?.query;
28
+ const apiConfig = params?.apiConfig;
29
+
30
+ return useQuery<DeadlineResponseV2, Error>({
31
+ queryKey: ['swapsApi', 'deadline', query?.offsetSeconds ?? null],
32
+ queryFn: async (): Promise<DeadlineResponseV2> => unwrapResult(await sodax.api.swaps.getDeadline(query, apiConfig)),
33
+ retry: 3,
34
+ ...queryOptions,
35
+ });
36
+ };
@@ -0,0 +1,40 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import type { GasEstimateRequestV2, GasEstimateResponseV2, RequestOverrideConfig } from '@sodax/sdk';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseSwapsApiEstimateGasParams = ReadHookParams<
8
+ GasEstimateResponseV2 | undefined,
9
+ {
10
+ body: GasEstimateRequestV2 | undefined;
11
+ apiConfig?: RequestOverrideConfig;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * React hook to estimate gas for a raw transaction on a spoke chain via the swaps API —
17
+ * `sodax.api.swaps.estimateGas`. Returns `{ gas }` (chain-specific shape).
18
+ *
19
+ * @example
20
+ * const { data } = useSwapsApiEstimateGas({ params: { body: { chainKey: 'sonic', tx } } });
21
+ */
22
+ export const useSwapsApiEstimateGas = ({
23
+ params,
24
+ queryOptions,
25
+ }: UseSwapsApiEstimateGasParams = {}): UseQueryResult<GasEstimateResponseV2 | undefined, Error> => {
26
+ const { sodax } = useSodaxContext();
27
+ const body = params?.body;
28
+ const apiConfig = params?.apiConfig;
29
+
30
+ return useQuery({
31
+ queryKey: ['swapsApi', 'estimateGas', body?.chainKey, body?.tx],
32
+ queryFn: async (): Promise<GasEstimateResponseV2 | undefined> => {
33
+ if (!body) return undefined;
34
+ return unwrapResult(await sodax.api.swaps.estimateGas(body, apiConfig));
35
+ },
36
+ enabled: !!body,
37
+ retry: 3,
38
+ ...queryOptions,
39
+ });
40
+ };
@@ -0,0 +1,41 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import type { IntentStateV2, RequestOverrideConfig } from '@sodax/sdk';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseSwapsApiFilledIntentParams = ReadHookParams<
8
+ IntentStateV2 | undefined,
9
+ {
10
+ txHash: string | undefined;
11
+ apiConfig?: RequestOverrideConfig;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * React hook to get the on-chain fill state for an intent by its hub-chain tx hash via the swaps
17
+ * API — `sodax.api.swaps.getFilledIntent`. Returns
18
+ * `{ exists, remainingInput, receivedOutput, pendingPayment }`.
19
+ *
20
+ * @example
21
+ * const { data: fill } = useSwapsApiFilledIntent({ params: { txHash: '0x123...' } });
22
+ */
23
+ export const useSwapsApiFilledIntent = ({
24
+ params,
25
+ queryOptions,
26
+ }: UseSwapsApiFilledIntentParams = {}): UseQueryResult<IntentStateV2 | undefined, Error> => {
27
+ const { sodax } = useSodaxContext();
28
+ const txHash = params?.txHash;
29
+ const apiConfig = params?.apiConfig;
30
+
31
+ return useQuery({
32
+ queryKey: ['swapsApi', 'filledIntent', txHash],
33
+ queryFn: async (): Promise<IntentStateV2 | undefined> => {
34
+ if (!txHash) return undefined;
35
+ return unwrapResult(await sodax.api.swaps.getFilledIntent(txHash, apiConfig));
36
+ },
37
+ enabled: !!txHash && txHash.length > 0,
38
+ retry: 3,
39
+ ...queryOptions,
40
+ });
41
+ };
@@ -0,0 +1,40 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import type { GetIntentResponseV2, RequestOverrideConfig } from '@sodax/sdk';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseSwapsApiIntentParams = ReadHookParams<
8
+ GetIntentResponseV2 | undefined,
9
+ {
10
+ txHash: string | undefined;
11
+ apiConfig?: RequestOverrideConfig;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * React hook to look up an Intent struct by its hub-chain creation tx hash via the swaps API —
17
+ * `sodax.api.swaps.getIntent`. The decoded intent's bigint fields are returned as decimal strings.
18
+ *
19
+ * @example
20
+ * const { data: intent } = useSwapsApiIntent({ params: { txHash: '0x123...' } });
21
+ */
22
+ export const useSwapsApiIntent = ({
23
+ params,
24
+ queryOptions,
25
+ }: UseSwapsApiIntentParams = {}): UseQueryResult<GetIntentResponseV2 | undefined, Error> => {
26
+ const { sodax } = useSodaxContext();
27
+ const txHash = params?.txHash;
28
+ const apiConfig = params?.apiConfig;
29
+
30
+ return useQuery({
31
+ queryKey: ['swapsApi', 'intent', txHash],
32
+ queryFn: async (): Promise<GetIntentResponseV2 | undefined> => {
33
+ if (!txHash) return undefined;
34
+ return unwrapResult(await sodax.api.swaps.getIntent(txHash, apiConfig));
35
+ },
36
+ enabled: !!txHash && txHash.length > 0,
37
+ retry: 3,
38
+ ...queryOptions,
39
+ });
40
+ };
@@ -0,0 +1,41 @@
1
+ import { useQuery, type UseQueryResult } from '@tanstack/react-query';
2
+ import type { IntentExtraDataRequestV2, IntentExtraDataResponseV2, RequestOverrideConfig } from '@sodax/sdk';
3
+ import { useSodaxContext } from '../shared/useSodaxContext.js';
4
+ import { unwrapResult } from '../shared/unwrapResult.js';
5
+ import type { ReadHookParams } from '../shared/types.js';
6
+
7
+ export type UseSwapsApiIntentExtraDataParams = ReadHookParams<
8
+ IntentExtraDataResponseV2 | undefined,
9
+ {
10
+ body: IntentExtraDataRequestV2 | undefined;
11
+ apiConfig?: RequestOverrideConfig;
12
+ }
13
+ >;
14
+
15
+ /**
16
+ * React hook to recover the relay extra data needed by `/swaps/intents/submit` via the swaps API —
17
+ * `sodax.api.swaps.getIntentSubmitTxExtraData`. Provide EITHER `txHash` OR `intent` in the body
18
+ * (whose `bigint` numerics are serialized by the SDK). Returns `{ address, payload }`.
19
+ *
20
+ * @example
21
+ * const { data } = useSwapsApiIntentExtraData({ params: { body: { txHash: '0x123...' } } });
22
+ */
23
+ export const useSwapsApiIntentExtraData = ({
24
+ params,
25
+ queryOptions,
26
+ }: UseSwapsApiIntentExtraDataParams = {}): UseQueryResult<IntentExtraDataResponseV2 | undefined, Error> => {
27
+ const { sodax } = useSodaxContext();
28
+ const body = params?.body;
29
+ const apiConfig = params?.apiConfig;
30
+
31
+ return useQuery({
32
+ queryKey: ['swapsApi', 'intentExtraData', body?.txHash ?? body?.intent?.intentId?.toString()],
33
+ queryFn: async (): Promise<IntentExtraDataResponseV2 | undefined> => {
34
+ if (!body || (!body.txHash && !body.intent)) return undefined;
35
+ return unwrapResult(await sodax.api.swaps.getIntentSubmitTxExtraData(body, apiConfig));
36
+ },
37
+ enabled: !!body && (!!body.txHash || !!body.intent),
38
+ retry: 3,
39
+ ...queryOptions,
40
+ });
41
+ };