@sodax/dapp-kit 1.5.7-beta → 2.0.0-rc.2

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 +190 -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 +1581 -1531
  61. package/dist/index.mjs.map +1 -1
  62. package/package.json +21 -11
  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 +13 -82
  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 -2574
  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
@@ -0,0 +1,169 @@
1
+ # Auxiliary services — `@sodax/dapp-kit`
2
+
3
+ Smaller surfaces grouped together: partner fee claiming, recovery, backend queries (read-only data hooks), and shared utilities.
4
+
5
+ Pair: [`../../migration/features/auxiliary-services.md`](../../migration/features/auxiliary-services.md).
6
+
7
+ ## Partner
8
+
9
+ Partner fee claiming and auto-swap preferences.
10
+
11
+ ```ts
12
+ // @ai-snippets-skip
13
+ useFetchAssetsBalances({ params, queryOptions }); // Partner asset balances
14
+ useGetAutoSwapPreferences({ params, queryOptions });
15
+ useIsTokenApproved({ params: { payload: FeeTokenApproveParams }, queryOptions });
16
+ useApproveToken({ mutationOptions });
17
+ useSetSwapPreference({ mutationOptions });
18
+ useFeeClaimSwap({ mutationOptions }); // Claim partner fees via swap
19
+ ```
20
+
21
+ `useFeeClaimSwap` returns `SafeUseMutationResult<IntentAutoSwapResult, Error, UseFeeClaimSwapVars>` — the success value is `IntentAutoSwapResult` (NOT `SwapResponse`). TVars are `Omit<PartnerFeeClaimSwapAction<HubChainKey, false>, 'raw'>`.
22
+
23
+ ## Recovery
24
+
25
+ Withdraw stuck hub-wallet assets back to a spoke chain.
26
+
27
+ ```ts
28
+ // @ai-snippets-skip
29
+ useHubAssetBalances({ params, queryOptions }); // List assets stuck on hub
30
+ useWithdrawHubAsset({ mutationOptions });
31
+ ```
32
+
33
+ ## Backend queries (read-only data)
34
+
35
+ No wallet connection required.
36
+
37
+ ### Intent tracking
38
+
39
+ ```ts
40
+ // @ai-snippets-skip
41
+ useBackendIntentByTxHash({ params, queryOptions }); // Polls 1s once a txHash is supplied
42
+ useBackendIntentByHash({ params, queryOptions });
43
+ useBackendUserIntents({ params, queryOptions }); // Date-filtered user history; data is { items: IntentResponse[], total, offset, limit }
44
+ ```
45
+
46
+ ### Orderbook
47
+
48
+ ```ts
49
+ // @ai-snippets-skip
50
+ // `pagination` MUST be nested under `params` — top-level pagination is invalid.
51
+ useBackendOrderbook({ params: { pagination: { offset, limit } }, queryOptions }); // staleTime 30s; no auto-refresh
52
+ ```
53
+
54
+ ### Money market data
55
+
56
+ ```ts
57
+ // @ai-snippets-skip
58
+ useBackendMoneyMarketPosition({ params, queryOptions });
59
+ useBackendMoneyMarketAsset({ params, queryOptions });
60
+ useBackendAllMoneyMarketAssets({ queryOptions });
61
+ useBackendMoneyMarketAssetSuppliers({ params, queryOptions });
62
+ useBackendMoneyMarketAssetBorrowers({ params, queryOptions });
63
+ // Pagination required — without it the query is disabled.
64
+ useBackendAllMoneyMarketBorrowers({ params: { pagination: { offset, limit } }, queryOptions });
65
+ ```
66
+
67
+ ### Swap submission
68
+
69
+ ```ts
70
+ // @ai-snippets-skip
71
+ useBackendSubmitSwapTx({ mutationOptions }); // Mutation
72
+ useBackendSubmitSwapTxStatus({ params, queryOptions }); // Query — check submitted status
73
+ ```
74
+
75
+ `useBackendSubmitSwapTx` is a mutation hook — per-call config (e.g. backend base URL) flows through `mutate(vars)`:
76
+
77
+ ```ts
78
+ // @ai-snippets-skip
79
+ const { mutateAsync: submitSwapTx } = useBackendSubmitSwapTx();
80
+ await submitSwapTx({ request: swapPayload, apiConfig: { baseURL: 'https://...' } });
81
+ ```
82
+
83
+ ## Shared utilities
84
+
85
+ Cross-cutting hooks used by other features.
86
+
87
+ ```ts
88
+ // @ai-snippets-skip
89
+ useSodaxContext(); // Access the Sodax SDK instance
90
+ useHubProvider(); // Hub chain (Sonic) provider
91
+ useXBalances({ params, queryOptions }); // Cross-chain token balances
92
+ useDeriveUserWalletAddress({ params, queryOptions }); // Hub wallet address (CREATE3)
93
+ useGetUserHubWalletAddress({ params, queryOptions }); // Hub wallet via wallet router
94
+ useEstimateGas({ mutationOptions }); // Gas estimation for raw tx
95
+ useStellarTrustlineCheck({ params, queryOptions });
96
+ useRequestTrustline({ mutationOptions });
97
+ ```
98
+
99
+ ### `useXBalances` shape
100
+
101
+ ```ts
102
+ // @ai-snippets-skip
103
+ type UseXBalancesParams = ReadHookParams<Record<string, bigint>, {
104
+ xService: IXServiceBase | undefined; // From @sodax/wallet-sdk-react's useXService
105
+ xChainId: SpokeChainKey | undefined;
106
+ xTokens: readonly XToken[]; // Tokens to fetch balances for
107
+ address: string | undefined;
108
+ }>;
109
+ ```
110
+
111
+ Note: the **request-side** field is `xChainId` (kept for the cross-chain abstraction it overlays). This is distinct from the v2-renamed token-side `chainKey` — don't conflate them.
112
+
113
+ Consumer must supply `xService` from `@sodax/wallet-sdk-react`:
114
+
115
+ ```tsx
116
+ // @ai-snippets-skip
117
+ import { useXService, getXChainType } from '@sodax/wallet-sdk-react';
118
+ const xService = useXService({ xChainType: getXChainType(xChainId) });
119
+ const { data: balances } = useXBalances({ params: { xService, xChainId, xTokens, address } });
120
+ ```
121
+
122
+ ### Stellar trustlines
123
+
124
+ Stellar accounts that have never held an asset have no trustline — receiving will fail. Pre-flight with `useStellarTrustlineCheck`; fix with `useRequestTrustline`:
125
+
126
+ ```ts
127
+ // @ai-snippets-skip — illustrative only; real types pulled into agents below.
128
+ // useStellarTrustlineCheck takes { token, amount, chainId, walletProvider } under params.
129
+ // `chainId` here is a `SpokeChainKey` (typed loosely so consumers can pass any chain key —
130
+ // the hook returns `true` for non-Stellar chains, making it safe to gate on conditionally).
131
+ const { data: hasTrustline } = useStellarTrustlineCheck({
132
+ params: { token, amount, chainId: ChainKeys.STELLAR_MAINNET, walletProvider },
133
+ });
134
+
135
+ // useRequestTrustline is NOT a canonical mutation hook — it takes a single positional
136
+ // `token` arg and returns { requestTrustline, isLoading, isRequested, error, data }.
137
+ // The `requestTrustline` callback signature is:
138
+ // ({ token, amount, srcChainKey, walletProvider }) => Promise<string>
139
+ // NOTE: fields are `token` / `amount` / `srcChainKey` / `walletProvider` — NOT
140
+ // `account` / `asset`. Pass a StellarChainKey for srcChainKey.
141
+ const { requestTrustline, isLoading } = useRequestTrustline(token);
142
+ if (hasTrustline === false) {
143
+ await requestTrustline({ token, amount, srcChainKey: ChainKeys.STELLAR_MAINNET, walletProvider });
144
+ }
145
+ ```
146
+
147
+ ## Default polling intervals
148
+
149
+ | Hook | Polling | Notes |
150
+ |---|---|---|
151
+ | `useBackendIntentByTxHash` | 1s | once a `txHash` is supplied (refetch is unconditional, not "while pending") |
152
+ | `useBackendSubmitSwapTxStatus` | varies | poll stops on `executed` / `failed` |
153
+ | `useBackendOrderbook` | none | `staleTime: 30s` — fresh-window, no background refetch |
154
+ | `useExpiredUtxos` (bitcoin) | 60s | refetchInterval |
155
+ | `useQuote` (swap) | 3s | refetchInterval |
156
+ | `useStatus` (swap) | 3s | refetchInterval |
157
+ | `useSwapAllowance` (swap) | 2s | refetchInterval |
158
+ | `useMMAllowance` (mm) | 5s | refetchInterval; `enabled: false` for borrow/withdraw actions |
159
+ | Reserves data (mm) | 5s | `useReservesData` / `useReservesHumanized` / user position hooks |
160
+ | Most others | None | |
161
+
162
+ All overridable via `queryOptions.refetchInterval`.
163
+
164
+ ## Cross-references
165
+
166
+ - [`../recipes/backend-queries.md`](../recipes/backend-queries.md) — worked examples for intent tracking, orderbook, MM data.
167
+ - [`../recipes/wallet-connectivity.md`](../recipes/wallet-connectivity.md) — `useXBalances` worked example.
168
+ - [`../../migration/features/auxiliary-services.md`](../../migration/features/auxiliary-services.md) — v1 → v2 porting.
169
+ - [`../../../../sdk/ai-exported/integration/features/auxiliary-services.md`](../../../../sdk/ai-exported/integration/features/auxiliary-services.md) — underlying SDK auxiliary surfaces (partner, recovery, backendApi).
@@ -0,0 +1,87 @@
1
+ # Bitcoin (Radfi) — `@sodax/dapp-kit`
2
+
3
+ Bitcoin trading via the Radfi protocol — authenticate, fund a trading wallet, withdraw, manage UTXOs. **Dapp-kit-unique surface** (no SDK equivalent — these flows are React-shaped).
4
+
5
+ Pair: [`../../migration/features/bitcoin.md`](../../migration/features/bitcoin.md).
6
+
7
+ ## Hook surface
8
+
9
+ ```ts
10
+ // @ai-snippets-skip
11
+ // Session lifecycle
12
+ useRadfiAuth({ mutationOptions }); // Authenticate via BIP322 signing
13
+ useRadfiSession(walletProvider); // Manage full lifecycle (login, refresh, auto-refresh)
14
+ useTradingWallet(walletAddress); // Synchronous: read persisted session
15
+
16
+ // Balances
17
+ useBitcoinBalance({ params: { address, rpcUrl? }, queryOptions }); // Personal wallet (default mempool.space)
18
+ useTradingWalletBalance({ params: { walletProvider, tradingAddress }, queryOptions }); // Radfi API
19
+
20
+ // Operations
21
+ useFundTradingWallet({ mutationOptions });
22
+ useRadfiWithdraw({ mutationOptions });
23
+ useExpiredUtxos({ params: { walletProvider, tradingAddress }, queryOptions }); // Polls 60s
24
+ useRenewUtxos({ mutationOptions });
25
+ ```
26
+
27
+ ## Session flow
28
+
29
+ Radfi requires authentication before trading operations. `useRadfiSession` handles the full lifecycle:
30
+
31
+ ```ts
32
+ // @ai-snippets-skip
33
+ const { walletAddress, isAuthed, tradingAddress, login, isLoginPending } = useRadfiSession(walletProvider);
34
+ ```
35
+
36
+ Lifecycle behavior:
37
+ - On mount: refreshes token to validate existing session
38
+ - Every 5 min: auto-refreshes access token
39
+ - If refresh fails: clears session, sets `isAuthed = false`
40
+ - Session persisted in localStorage (keyed by wallet address)
41
+
42
+ ## Mutation TVars
43
+
44
+ ```ts
45
+ // @ai-snippets-skip
46
+ // useFundTradingWallet
47
+ type FundTradingWalletVars = { amount: bigint; walletProvider: IBitcoinWalletProvider };
48
+
49
+ // useRadfiWithdraw
50
+ type RadfiWithdrawVars = {
51
+ amount: string;
52
+ tokenId: string; // e.g. '0:0'
53
+ withdrawTo: string; // user's personal BTC address
54
+ walletProvider: IBitcoinWalletProvider;
55
+ };
56
+
57
+ // useRenewUtxos
58
+ type RenewUtxosVars = { txIdVouts: string[]; walletProvider: IBitcoinWalletProvider };
59
+ ```
60
+
61
+ ## Return shapes
62
+
63
+ | Hook | Returns |
64
+ |---|---|
65
+ | `useRadfiAuth` | `SafeUseMutationResult<RadfiAuthResult, Error, UseRadfiAuthVars>` where `RadfiAuthResult = { accessToken, refreshToken, tradingAddress }` (3 fields, NOT `RadfiSession` — the hook persists `publicKey` to localStorage internally but doesn't return it) |
66
+ | `useFundTradingWallet` | `SafeUseMutationResult<TxId, Error, ...>` |
67
+ | `useRadfiWithdraw` | `SafeUseMutationResult<{ txId, fee }, Error, ...>` |
68
+ | `useRenewUtxos` | `SafeUseMutationResult<TxId, Error, ...>` |
69
+ | `useRadfiSession` | `{ walletAddress, isAuthed, tradingAddress, login, isLoginPending }` (utility, not Query/Mutation) |
70
+ | `useTradingWallet` | `{ tradingAddress: string \| undefined }` (synchronous from localStorage) |
71
+ | `useBitcoinBalance` | `UseQueryResult<bigint, Error>` (BTC balance in sats; default Esplora is mempool.space, override via `rpcUrl`) |
72
+ | `useTradingWalletBalance` | `UseQueryResult<RadfiWalletBalance, Error>` where `RadfiWalletBalance = { btcSatoshi: bigint; pendingSatoshi: bigint; externalPendingSatoshi: bigint; totalUtxos: number }` |
73
+ | `useExpiredUtxos` | `UseQueryResult<RadfiUtxo[], Error>` where `RadfiUtxo = { _id, txid, vout, txidVout, satoshi, amount, address, isSpent, status, source, runes? }` |
74
+
75
+ ## Gotchas
76
+
77
+ 1. **Authentication required before any trading operation.** `useRadfiSession` manages this automatically — gate buttons on `isAuthed`.
78
+ 2. **Trading wallet is created during first authentication** — not a separate step.
79
+ 3. **`useTradingWallet(walletAddress)` is synchronous** (no network call). It reads persisted Radfi session from localStorage. Use it when you don't have a `walletProvider` available yet but need the trading address.
80
+ 4. **PSBT signing flow for withdrawals.** Radfi server builds an unsigned PSBT, the user signs locally via the wallet provider, then submits back for co-signing and broadcast. The dapp-kit hook orchestrates this — consumers don't see PSBTs directly.
81
+ 5. **Session tokens are for API rate-limiting, not asset access.** Stored in localStorage keyed by wallet address. Compromise of localStorage data doesn't affect funds.
82
+ 6. **`useExpiredUtxos` polls every 60s** — set `queryOptions.refetchInterval: false` to disable while UI is hidden.
83
+
84
+ ## Cross-references
85
+
86
+ - [`../recipes/bitcoin.md`](../recipes/bitcoin.md) — full worked examples (session, fund, withdraw, UTXO management).
87
+ - [`../../migration/features/bitcoin.md`](../../migration/features/bitcoin.md) — v1 → v2 porting (mostly hook signature shape changes; flow stays the same).
@@ -0,0 +1,91 @@
1
+ # Bridge — `@sodax/dapp-kit`
2
+
3
+ Cross-chain token transfers via the hub-and-spoke vault architecture.
4
+
5
+ Pair: [`../../migration/features/bridge.md`](../../migration/features/bridge.md).
6
+
7
+ ## Hook surface
8
+
9
+ ```ts
10
+ // @ai-snippets-skip
11
+ // Mutation
12
+ useBridge({ mutationOptions });
13
+ useBridgeApprove({ mutationOptions });
14
+
15
+ // Queries
16
+ // useBridgeAllowance nests payload + walletProvider under params (NOT at top level)
17
+ useBridgeAllowance({ params: { payload: CreateBridgeIntentParams<K>, walletProvider }, queryOptions });
18
+ useGetBridgeableAmount({ params: { from: XToken, to: XToken }, queryOptions });
19
+ useGetBridgeableTokens({ params: { from: SpokeChainKey, to: SpokeChainKey, token: string }, queryOptions });
20
+ ```
21
+
22
+ ## Mutation params
23
+
24
+ ```ts
25
+ // @ai-snippets-skip
26
+ type CreateBridgeIntentParams<K extends SpokeChainKey = SpokeChainKey> = {
27
+ srcChainKey: K;
28
+ srcAddress: string;
29
+ srcToken: string;
30
+ amount: bigint;
31
+ dstChainKey: SpokeChainKey;
32
+ dstToken: string;
33
+ recipient: string; // non-encoded recipient address on the destination chain
34
+ };
35
+
36
+ const { mutateAsyncSafe: bridge } = useBridge();
37
+ const result = await bridge({ params, walletProvider });
38
+ if (!result.ok) return;
39
+ const { srcChainTxHash, dstChainTxHash } = result.value; // TxHashPair
40
+ ```
41
+
42
+ ## Query params
43
+
44
+ ```ts
45
+ // @ai-snippets-skip
46
+ // useBridgeAllowance — payload + walletProvider nested under params
47
+ type UseBridgeAllowanceParams<K extends SpokeChainKey> = ReadHookParams<
48
+ boolean,
49
+ {
50
+ payload: CreateBridgeIntentParams<K> | undefined;
51
+ walletProvider: GetWalletProviderType<K> | undefined;
52
+ }
53
+ >;
54
+
55
+ // useGetBridgeableAmount — flat: pair of XToken objects
56
+ type UseGetBridgeableAmountParams = ReadHookParams<BridgeLimit, {
57
+ from: XToken | undefined;
58
+ to: XToken | undefined;
59
+ }>;
60
+ // BridgeLimit = { amount: bigint; decimals: number; type: 'DEPOSIT_LIMIT' | 'WITHDRAWAL_LIMIT' }
61
+
62
+ // useGetBridgeableTokens — flat: (from, to, token)
63
+ type UseGetBridgeableTokensParams = ReadHookParams<XToken[], {
64
+ from: SpokeChainKey | undefined;
65
+ to: SpokeChainKey | undefined;
66
+ token: string | undefined;
67
+ }>;
68
+ ```
69
+
70
+ ## Return shapes
71
+
72
+ | Hook | Returns |
73
+ |---|---|
74
+ | `useBridge` | `SafeUseMutationResult<TxHashPair, Error, ...>` (`{ srcChainTxHash, dstChainTxHash }`) |
75
+ | `useBridgeApprove` | `SafeUseMutationResult<TxReturnType<K, false>, Error, UseBridgeApproveVars<K>>` — chain-keyed receipt union (EVM/Stellar/Sui differ) |
76
+ | `useBridgeAllowance` | `UseQueryResult<boolean, Error>` — already unwrapped; on SDK `!ok` the queryFn returns `false` (does NOT throw), so `isError` stays clean |
77
+ | `useGetBridgeableAmount` | `UseQueryResult<BridgeLimit, Error>` (richer than v1's bare `bigint`) |
78
+ | `useGetBridgeableTokens` | `UseQueryResult<XToken[], Error>` |
79
+
80
+ ## Gotchas
81
+
82
+ 1. **`useGetBridgeableAmount` takes XToken objects, not addresses + chain ids.** Each `XToken` carries its own `chainKey`. v1 took 4 separate args; v2 takes 2 objects.
83
+ 2. **`useGetBridgeableAmount` value is `BridgeLimit`, not a bare bigint.** Access `result.value.amount` and `result.value.decimals` for the limit + scale.
84
+ 3. **Tokens are bridgeable iff they share the same vault on the hub.** Use `useGetBridgeableTokens` to enumerate compatible destinations for a given source — passing an incompatible pair to `bridge()` rejects with `VALIDATION_FAILED`.
85
+ 4. **`bridge()` returns `TxHashPair`, not a tuple.** Destructure as `{ srcChainTxHash, dstChainTxHash }` — never `[a, b]`.
86
+
87
+ ## Cross-references
88
+
89
+ - [`../recipes/bridge.md`](../recipes/bridge.md) — full worked example.
90
+ - [`../../migration/features/bridge.md`](../../migration/features/bridge.md) — v1 → v2 porting.
91
+ - [`../../../../sdk/ai-exported/integration/features/bridge.md`](../../../../sdk/ai-exported/integration/features/bridge.md) — underlying SDK bridge surface.
@@ -0,0 +1,152 @@
1
+ # DEX — `@sodax/dapp-kit`
2
+
3
+ Concentrated-liquidity DEX (similar to Uniswap V3). Two-step flow: deposit assets to mint pool tokens, then supply liquidity to a position.
4
+
5
+ Pair: [`../../migration/features/dex.md`](../../migration/features/dex.md).
6
+
7
+ ## Hook surface
8
+
9
+ ```ts
10
+ // @ai-snippets-skip
11
+ // Asset deposit / withdraw (spoke ↔ hub pool tokens)
12
+ useDexDeposit({ mutationOptions });
13
+ useDexWithdraw({ mutationOptions });
14
+ useDexAllowance({ params: { payload: CreateAssetDepositParams<K> }, queryOptions });
15
+ useDexApprove({ mutationOptions });
16
+ usePoolBalances({ params, queryOptions });
17
+
18
+ // Liquidity (pool tokens ↔ position)
19
+ useSupplyLiquidity({ mutationOptions }); // Mint new or increase existing
20
+ useDecreaseLiquidity({ mutationOptions });
21
+ useClaimRewards({ mutationOptions });
22
+
23
+ // Reads
24
+ usePools({ queryOptions });
25
+ usePoolData({ params, queryOptions });
26
+ usePositionInfo({ params, queryOptions });
27
+ useLiquidityAmounts({ params, queryOptions });
28
+
29
+ // Param builders (compute derived params client-side) — these take a FLAT props object,
30
+ // NOT a `{ params }` wrapper. They return memoized derived params that the consumer adds
31
+ // `srcChainKey` + `srcAddress` to at the mutation call site.
32
+ useCreateDepositParams({ tokenIndex, amount, poolData, poolSpokeAssets, dst? });
33
+ useCreateWithdrawParams({ tokenIndex, amount, poolData, poolSpokeAssets, dst? });
34
+ useCreateSupplyLiquidityParams({ poolData, poolKey, minPrice, maxPrice, liquidityToken0Amount, liquidityToken1Amount, slippageTolerance, positionId?, isValidPosition? });
35
+ useCreateDecreaseLiquidityParams({ /* see source for fields */ });
36
+ ```
37
+
38
+ ## SDK param types (passed via `mutate({ params, walletProvider })`)
39
+
40
+ Each dex mutation hook's TVars is `{ params: <SDKParamsType>, walletProvider, timeout? }`. The SDK param types below are what goes INSIDE `params` — they are not the TVars themselves.
41
+
42
+ ```ts
43
+ // @ai-snippets-skip
44
+ // Deposit / withdraw — spoke chain assets → hub pool tokens (or vice versa)
45
+ type CreateAssetDepositParams<K> = {
46
+ srcChainKey: K;
47
+ srcAddress: GetAddressType<K>;
48
+ asset: string; // spoke-chain asset address
49
+ amount: bigint;
50
+ poolToken: string; // hub-side pool token (vault) address
51
+ dst?: { chainKey: SpokeChainKey; address: string };
52
+ };
53
+
54
+ // Supply liquidity — `useSupplyLiquidity` fans out internally to mint-new vs
55
+ // increase-existing based on params.tokenId + params.isValidPosition.
56
+ // The TVars `params` field is `UseCreateSupplyLiquidityParamsResult & { srcChainKey, srcAddress }`
57
+ // (the memoized output of `useCreateSupplyLiquidityParams` + the chain/address pair).
58
+ // Underlying SDK type ClSupplyParams<K> (for mint-new) has NO tokenId field:
59
+ type ClSupplyParams<K> = {
60
+ srcChainKey: K;
61
+ srcAddress: GetAddressType<K>;
62
+ poolKey: PoolKey;
63
+ tickLower: bigint;
64
+ tickUpper: bigint;
65
+ liquidity: bigint;
66
+ amount0Max: bigint;
67
+ amount1Max: bigint;
68
+ sqrtPriceX96: bigint;
69
+ };
70
+ // And ClIncreaseLiquidityParams<K> = ClSupplyParams<K> & { tokenId: bigint }
71
+ // for the increase-existing branch.
72
+
73
+ // Decrease liquidity
74
+ type ClDecreaseLiquidityParams<K> = {
75
+ srcChainKey: K;
76
+ srcAddress: GetAddressType<K>;
77
+ poolKey: PoolKey;
78
+ tokenId: bigint;
79
+ liquidity: bigint;
80
+ amount0Min: bigint;
81
+ amount1Min: bigint;
82
+ };
83
+
84
+ // Claim rewards
85
+ type ClClaimRewardsParams<K> = {
86
+ srcChainKey: K;
87
+ srcAddress: GetAddressType<K>;
88
+ poolKey: PoolKey;
89
+ tokenId: bigint;
90
+ tickLower: bigint;
91
+ tickUpper: bigint;
92
+ };
93
+ ```
94
+
95
+ ## Param builders
96
+
97
+ The `useCreate*Params` hooks compute the right derived params client-side (e.g. ERC-4626 share conversions for deposit, current tick range for liquidity). Spread the result into the mutation:
98
+
99
+ ```ts
100
+ // @ai-snippets-skip — illustrative; `useCreateSupplyLiquidityParams` takes a FLAT props
101
+ // object (not `{ params }`-wrapped). The consumer adds `srcChainKey` + `srcAddress` at
102
+ // the mutation call site.
103
+ const supplyResult = useCreateSupplyLiquidityParams({
104
+ poolData,
105
+ poolKey,
106
+ minPrice,
107
+ maxPrice,
108
+ liquidityToken0Amount,
109
+ liquidityToken1Amount,
110
+ slippageTolerance,
111
+ positionId, // optional, for increase-existing
112
+ isValidPosition, // optional, gates the increase-existing branch
113
+ });
114
+
115
+ const { mutateAsync: supply } = useSupplyLiquidity();
116
+ if (supplyResult && walletProvider) {
117
+ await supply({
118
+ params: { ...supplyResult, srcChainKey, srcAddress },
119
+ walletProvider,
120
+ });
121
+ }
122
+ ```
123
+
124
+ ## Return shapes
125
+
126
+ | Hook | Returns |
127
+ |---|---|
128
+ | `useDexDeposit` / `useDexWithdraw` | `SafeUseMutationResult<TxHashPair, Error, UseDex(Deposit\|Withdraw)Vars<K>>` (TVars = `{ params, walletProvider, ...optional }`) |
129
+ | `useDexApprove` | `SafeUseMutationResult<TxReturnType<K, false>, Error, UseDexApproveVars<K>>` — chain-keyed receipt union |
130
+ | `useSupplyLiquidity` (mint or increase) | `SafeUseMutationResult<TxHashPair, Error, UseSupplyLiquidityVars<K>>` — single shape for both branches; fan-out happens inside the hook |
131
+ | `useDecreaseLiquidity` / `useClaimRewards` | `SafeUseMutationResult<TxHashPair, Error, ...>` |
132
+ | `useDexAllowance` | `UseQueryResult<boolean, Error>` (already unwrapped; throws on SDK `!ok`) |
133
+ | `usePools` | `UseQueryResult<PoolKey[], Error>` — `staleTime: Infinity` (no auto-refresh; pools are static config) |
134
+ | `usePoolData` | `UseQueryResult<PoolData, Error>` |
135
+ | `usePositionInfo` | `UseQueryResult<{ positionInfo: ClPositionInfo, isValid: boolean }, Error>` — `tokenId` param is `string \| null` (NOT bigint) |
136
+ | `usePoolBalances` | `UseQueryResult<{ token0Balance: bigint; token1Balance: bigint }, Error>` |
137
+ | `useLiquidityAmounts` | Direct synchronous calculation (memoized via `useMemo`) — not a React Query hook |
138
+
139
+ ## Gotchas
140
+
141
+ 1. **Two-step flow: deposit, then supply.** First `useDexDeposit` brings the spoke asset to the hub as pool-token shares (ERC-4626). Then `useSupplyLiquidity` uses those shares to mint or grow a position. UI flows usually combine them.
142
+ 2. **`useSupplyLiquidity` handles both mint-new and increase-existing.** If `params.tokenId` is provided AND that position is valid for the pool, it increases. Otherwise it mints a new position. Use `useCreateSupplyLiquidityParams` to handle the routing.
143
+ 3. **Ticks are logarithmic.** `tickLower` / `tickUpper` are not prices — they're indices. Convert with viem's `Q96` math or the SDK's helpers.
144
+ 4. **`usePools` never auto-refreshes.** Pools are static config — fetch once. Override `queryOptions.refetchInterval` only if you really know your config changed.
145
+ 5. **`useDexAllowance` doesn't take `walletProvider`.** Read-only — derives the user from `srcAddress` in `params`.
146
+ 6. **`useClaimRewards` operates per-position.** If you need to claim across multiple positions, call it once per `tokenId`. The hook invalidates the corresponding `usePositionInfo` after success.
147
+
148
+ ## Cross-references
149
+
150
+ - [`../recipes/dex.md`](../recipes/dex.md) — full worked examples.
151
+ - [`../../migration/features/dex.md`](../../migration/features/dex.md) — v1 → v2 porting.
152
+ - [`../../../../sdk/ai-exported/integration/features/dex.md`](../../../../sdk/ai-exported/integration/features/dex.md) — underlying SDK DEX surface.
@@ -0,0 +1,118 @@
1
+ # Migration — `@sodax/dapp-kit`
2
+
3
+ Token migration: ICX/wICX → SODA, BALN → SODA, legacy bnUSD ↔ new bnUSD. Six per-action hooks plus shared allowance/approve.
4
+
5
+ Pair: [`../../migration/features/migration.md`](../../migration/features/migration.md).
6
+
7
+ ## Hook surface
8
+
9
+ ```ts
10
+ // @ai-snippets-skip — hook-surface listing; `<inner>` is a type placeholder, not real code
11
+ // Mutations (one per action)
12
+ useMigrateIcxToSoda({ mutationOptions });
13
+ useRevertMigrateSodaToIcx({ mutationOptions });
14
+ useMigratebnUSD({ mutationOptions }); // Bidirectional (auto-detects direction)
15
+ useMigrateBaln({ mutationOptions });
16
+
17
+ // Allowance + approve (action-discriminated)
18
+ useMigrationApprove({ mutationOptions });
19
+ // useMigrationAllowance — params nest `{ params: <inner-migration-params>, action }` under the outer `params`
20
+ useMigrationAllowance({ params: { params: <inner>, action: 'migrate' | 'revert' }, queryOptions });
21
+ ```
22
+
23
+ ## Mutation params
24
+
25
+ ```ts
26
+ // @ai-snippets-skip
27
+ // useMigrateIcxToSoda — wICX (ICON) → SODA (Sonic)
28
+ type IcxMigrateParams = {
29
+ srcChainKey: IconChainKey; // typeof ChainKeys.ICON_MAINNET
30
+ srcAddress: IconAddress; // `hx${string}` | `cx${string}`
31
+ address: IcxTokenType; // narrow union: wICX address OR native-ICX address
32
+ amount: bigint;
33
+ dstAddress: Address; // `0x${string}` — Sonic recipient
34
+ };
35
+
36
+ // useRevertMigrateSodaToIcx — SODA (Sonic) → wICX (ICON)
37
+ type IcxCreateRevertMigrationParams = {
38
+ srcChainKey: SonicChainKey; // typeof ChainKeys.SONIC_MAINNET
39
+ srcAddress: Address; // `0x${string}` — Sonic
40
+ amount: bigint;
41
+ dstAddress: IconEoaAddress; // `hx${string}` — ICON recipient
42
+ };
43
+
44
+ // useMigratebnUSD — bidirectional, swap srcbnUSD/dstbnUSD + chains for the other direction
45
+ type UnifiedBnUSDMigrateParams<K extends SpokeChainKey> = {
46
+ srcChainKey: K;
47
+ srcAddress: string; // SDK keeps this loose (cross-chain)
48
+ srcbnUSD: string; // legacy or new bnUSD
49
+ dstChainKey: SpokeChainKey;
50
+ dstbnUSD: string; // the other one
51
+ amount: bigint;
52
+ dstAddress: string;
53
+ };
54
+
55
+ // useMigrateBaln — BALN (ICON) → SODA with optional lock
56
+ type BalnMigrateParams = {
57
+ srcChainKey: IconChainKey;
58
+ srcAddress: IconAddress;
59
+ amount: bigint;
60
+ lockupPeriod: LockupPeriod; // enum (values in SECONDS), see below
61
+ dstAddress: Address;
62
+ stake: boolean; // REQUIRED — auto-stake migrated SODA into xSODA vault
63
+ };
64
+
65
+ // `LockupPeriod` is an enum with 5 members (values are in seconds, NOT months):
66
+ // NO_LOCKUP = 0 (0.5x reward multiplier)
67
+ // SIX_MONTHS = 6 * 30 * 24 * 60 * 60 (0.75x)
68
+ // TWELVE_MONTHS = 12 * 30 * 24 * 60 * 60 (1.0x)
69
+ // EIGHTEEN_MONTHS = 18 * 30 * 24 * 60 * 60 (1.25x)
70
+ // TWENTY_FOUR_MONTHS = 24 * 30 * 24 * 60 * 60 (1.5x)
71
+
72
+ // All wrapped as TVars: { params: <ParamsType>, walletProvider }
73
+ ```
74
+
75
+ ## Allowance / approve
76
+
77
+ The migration approve/allowance hooks are **action-discriminated** — same hook handles all migrations, with `action` disambiguating which token is being approved:
78
+
79
+ ```ts
80
+ // @ai-snippets-skip
81
+ const { data: isApproved } = useMigrationAllowance({
82
+ params: { params: bnUSDParams, action: 'migrate' }, // 'migrate' | 'revert'
83
+ });
84
+ const { mutateAsync: approve } = useMigrationApprove();
85
+ await approve({ params: bnUSDParams, walletProvider, action: 'migrate' });
86
+ ```
87
+
88
+ ## Migration paths summary
89
+
90
+ | Migration | Approval needed? | Hook |
91
+ |---|---|---|
92
+ | ICX/wICX (ICON) → SODA | No (ICON has no ERC-20 allowance) | `useMigrateIcxToSoda` |
93
+ | SODA → wICX (revert) | Yes | `useRevertMigrateSodaToIcx` + `useMigrationApprove({ action: 'revert' })` |
94
+ | Legacy bnUSD ↔ new bnUSD (EVM) | Yes | `useMigratebnUSD` + `useMigrationApprove({ action: 'migrate' })` |
95
+ | Legacy bnUSD (Stellar/Sui) ↔ new bnUSD | Maybe (depends on chain) | Same as above |
96
+ | BALN (ICON) → SODA | No | `useMigrateBaln` |
97
+
98
+ ## Return shapes
99
+
100
+ | Hook | Returns |
101
+ |---|---|
102
+ | `useMigrateIcxToSoda` / `useRevertMigrateSodaToIcx` / `useMigratebnUSD` / `useMigrateBaln` | `SafeUseMutationResult<TxHashPair, Error, ...>` |
103
+ | `useMigrationApprove` | `SafeUseMutationResult<TxReturnType<K, false>, Error, ...>` — chain-keyed receipt union (EVM/Stellar differ) |
104
+ | `useMigrationAllowance` | `UseQueryResult<boolean, Error>` (already unwrapped) |
105
+
106
+ ## Gotchas
107
+
108
+ 1. **`useMigratebnUSD` is bidirectional.** v2 detects direction from `(srcbnUSD, dstbnUSD)` token addresses. To go the other direction, swap the params; no separate hook.
109
+ 2. **BALN `lockupPeriod` is the `LockupPeriod` enum, NOT a literal number union.** Use `LockupPeriod.NO_LOCKUP`, `LockupPeriod.SIX_MONTHS`, `LockupPeriod.TWELVE_MONTHS`, `LockupPeriod.EIGHTEEN_MONTHS`, or `LockupPeriod.TWENTY_FOUR_MONTHS`. Enum values are in **seconds** (e.g. `TWELVE_MONTHS = 12 * 30 * 24 * 60 * 60`), not months. Reward multiplier ranges 0.5x (no lockup) → 1.5x (24 months). Also note: `BalnMigrateParams` requires `stake: boolean` — set `true` to auto-stake migrated SODA into the xSODA vault.
110
+ 3. **ICON-side migrations don't need approval.** ICON has no ERC-20 allowance mechanism.
111
+ 4. **`useRevertMigrateSodaToIcx` requires SODA approval on Sonic.** Use `useMigrationAllowance` + `useMigrationApprove` with `action: 'revert'`.
112
+ 5. **`useMigratebnUSD` errors include `direction: 'forward' | 'reverse'` on context.** When surfacing errors, distinguish forward vs reverse for clearer messaging.
113
+
114
+ ## Cross-references
115
+
116
+ - [`../recipes/migration.md`](../recipes/migration.md) — full worked examples.
117
+ - [`../../migration/features/migration.md`](../../migration/features/migration.md) — v1 → v2 porting (the v1 dapp-kit had a single `useMigrate(spokeProvider)`-style hook; v2 split into 6).
118
+ - [`../../../../sdk/ai-exported/integration/features/icx-bnusd-baln.md`](../../../../sdk/ai-exported/integration/features/icx-bnusd-baln.md) — underlying SDK migration surface.