@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
@@ -0,0 +1,88 @@
1
+ # Bitcoin (Radfi) migration — v1 → v2 (dapp-kit)
2
+
3
+ Pair: [`../../integration/features/bitcoin.md`](../../integration/features/bitcoin.md).
4
+
5
+ Bitcoin / Radfi hook surface was new in v1 with limited adoption; v2 standardizes its shapes against the canonical hook conventions. Treat the v2 forms below as the canonical reference — if your v1 code used a different shape, swap to v2's directly.
6
+
7
+ ## TL;DR
8
+
9
+ > Cross-cutting conventions (drop `spokeProvider`, single-object hook init, `mutate(vars)` for domain inputs, `mutateAsyncSafe` ergonomics) — see [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) and [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md). Bitcoin-specific deltas:
10
+
11
+ 1. **`useRadfiSession` API unchanged** — still takes a `walletProvider` directly (not via `mutate(vars)`); it manages session lifecycle.
12
+ 2. **`useTradingWallet(walletAddress)` is synchronous** — no Query/Mutation; reads localStorage. Unchanged.
13
+ 3. **`useBitcoinBalance` / `useTradingWalletBalance`** use single-object query shape `{ params, queryOptions }`.
14
+ 4. **Withdrawal/funding mutations** follow the canonical mutation hook shape — only `{ mutationOptions }` at hook init; `walletProvider` and per-call config flow through `mutate(vars)`.
15
+
16
+ ## v2 canonical shapes
17
+
18
+ ### `useFundTradingWallet`
19
+
20
+ ```ts
21
+ // @ai-snippets-skip
22
+ const walletProvider = useWalletProvider({ xChainId: ChainKeys.BITCOIN_MAINNET });
23
+ const { mutateAsyncSafe: fund } = useFundTradingWallet();
24
+ const result = await fund({ amount: 100_000n, walletProvider });
25
+ if (!result.ok) return;
26
+ const txId = result.value;
27
+ ```
28
+
29
+ ### `useRadfiWithdraw`
30
+
31
+ ```ts
32
+ // @ai-snippets-skip
33
+ const { mutateAsyncSafe: withdraw } = useRadfiWithdraw();
34
+ const result = await withdraw({
35
+ amount: '10000',
36
+ tokenId: '0:0',
37
+ withdrawTo,
38
+ walletProvider,
39
+ });
40
+ ```
41
+
42
+ ### `useRenewUtxos`
43
+
44
+ ```ts
45
+ // @ai-snippets-skip
46
+ await renewUtxos({ txIdVouts, walletProvider });
47
+ ```
48
+
49
+ ### `useRadfiSession`
50
+
51
+ ```ts
52
+ // @ai-snippets-skip
53
+ // Unchanged — still takes walletProvider directly (not via mutate vars).
54
+ const { isAuthed, tradingAddress, login, isLoginPending } = useRadfiSession(walletProvider);
55
+ ```
56
+
57
+ The session-management lifecycle hook needs constant access to the wallet provider for token refresh — it doesn't fit the `mutate(vars)` pattern.
58
+
59
+ ### `useBitcoinBalance` / `useTradingWalletBalance`
60
+
61
+ Single-object query shape:
62
+
63
+ ```diff
64
+ - const { data } = useBitcoinBalance(address);
65
+ + const { data } = useBitcoinBalance({ params: { address } });
66
+
67
+ - const { data } = useTradingWalletBalance(walletProvider, tradingAddress);
68
+ + const { data } = useTradingWalletBalance({ params: { walletProvider, tradingAddress } });
69
+ ```
70
+
71
+ ### `useExpiredUtxos`
72
+
73
+ ```diff
74
+ - const { data: expiredUtxos } = useExpiredUtxos(walletProvider, tradingAddress);
75
+ + const { data: expiredUtxos } = useExpiredUtxos({ params: { walletProvider, tradingAddress } });
76
+ ```
77
+
78
+ ## Pitfalls
79
+
80
+ 1. **`useRadfiSession` is the lifecycle owner.** Don't create your own `useRadfiAuth` ad-hoc handlers if you're using `useRadfiSession` — it manages auth + refresh + persistence.
81
+ 2. **Session tokens in localStorage are NOT for asset access.** They're API rate-limit tokens. Compromise of localStorage data doesn't let an attacker move funds.
82
+ 3. **Trading wallet is auto-created** during first authentication — don't add a separate "create wallet" step in your UI.
83
+ 4. **PSBT signing flow is internal.** v1 may have surfaced the unsigned PSBT for explicit consumer signing; v2 hooks orchestrate the full flow (build → sign → co-sign → broadcast) inside `mutationFn`.
84
+
85
+ ## Cross-references
86
+
87
+ - [`../../integration/features/bitcoin.md`](../../integration/features/bitcoin.md) — v2 reference.
88
+ - [`../../integration/recipes/bitcoin.md`](../../integration/recipes/bitcoin.md) — full v2 worked examples.
@@ -0,0 +1,123 @@
1
+ # Bridge migration — v1 → v2 (dapp-kit)
2
+
3
+ Pair: [`../../integration/features/bridge.md`](../../integration/features/bridge.md).
4
+
5
+ ## TL;DR
6
+
7
+ > Cross-cutting conventions (drop `spokeProvider`, single-object hook init, `mutate(vars)` for domain inputs, `mutateAsyncSafe` ergonomics) — see [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) and [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md). Feature-specific deltas below:
8
+
9
+ 1. **`CreateBridgeIntentParams` field renames** (SDK-leakage):
10
+ - `srcChainId` → `srcChainKey`
11
+ - `dstChainId` → `dstChainKey`
12
+ - `recipient` → `dstAddress`
13
+ - **NEW required**: `srcAddress`
14
+ 2. **`useBridge` return is `TxHashPair`, not a tuple.** v1 may have returned `[spokeTxHash, hubTxHash]`; v2 returns `{ srcChainTxHash, dstChainTxHash }`. Don't destructure as array.
15
+ 3. **`useGetBridgeableAmount` reshape.** v1 took `(srcChainId, srcAsset, dstChainId, dstAsset)`. v2 takes `{ from: XToken, to: XToken }` — each `XToken` carries its own `chainKey`.
16
+ 4. **`useGetBridgeableAmount` return value is `BridgeLimit`, not bare `bigint`.** Access `.value.amount` and `.value.decimals`.
17
+ 5. **`useGetBridgeableTokens` is sync now** in the SDK. The hook still returns `UseQueryResult` but the underlying SDK call doesn't fire RPC — it's config-derived.
18
+ 6. **Allowance/approve** — same shape changes as every other feature.
19
+
20
+ ## Per-method delta
21
+
22
+ ### `useBridge` — params + return
23
+
24
+ ```diff
25
+ function BridgeButton({ srcAddress }) {
26
+ - const bridge = useBridge(spokeProvider);
27
+ + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
28
+ + const { mutateAsyncSafe: bridge } = useBridge();
29
+
30
+ const handleBridge = async () => {
31
+ + if (!walletProvider) return;
32
+ - const result = await bridge.mutateAsync({
33
+ - params: {
34
+ - srcChainId: BASE_MAINNET_CHAIN_ID,
35
+ - srcAsset: '0x...',
36
+ - amount: 1_000_000n,
37
+ - dstChainId: POLYGON_MAINNET_CHAIN_ID,
38
+ - dstAsset: '0x...',
39
+ - recipient: '0x...',
40
+ - },
41
+ - });
42
+ - if (result.ok) {
43
+ - const [spokeTxHash, hubTxHash] = result.value;
44
+ - /* ... */
45
+ - }
46
+ + const result = await bridge({
47
+ + params: {
48
+ + srcChainKey: ChainKeys.BASE_MAINNET,
49
+ + srcAddress, // NEW: required
50
+ + srcAsset: '0x...',
51
+ + amount: 1_000_000n,
52
+ + dstChainKey: ChainKeys.POLYGON_MAINNET,
53
+ + dstAsset: '0x...',
54
+ + dstAddress: '0x...', // RENAMED from `recipient`
55
+ + },
56
+ + walletProvider,
57
+ + });
58
+ + if (!result.ok) return;
59
+ + const { srcChainTxHash, dstChainTxHash } = result.value; // OBJECT, not tuple
60
+ };
61
+ }
62
+ ```
63
+
64
+ ### `useGetBridgeableAmount` — params + return reshape
65
+
66
+ ```diff
67
+ - const { data: amount } = useGetBridgeableAmount({
68
+ - params: {
69
+ - srcChainId: BASE_MAINNET_CHAIN_ID,
70
+ - srcAsset: '0x...',
71
+ - dstChainId: POLYGON_MAINNET_CHAIN_ID,
72
+ - dstAsset: '0x...',
73
+ - },
74
+ - });
75
+ - if (amount) {
76
+ - <p>Max: {formatUnits(amount, 6)}</p>; // v1 was bare bigint
77
+ - }
78
+ + const { data: result } = useGetBridgeableAmount({
79
+ + params: { from: srcXToken, to: dstXToken }, // each XToken carries chainKey
80
+ + });
81
+ + if (result?.ok) {
82
+ + <p>Max: {formatUnits(result.value.amount, result.value.decimals)}</p>;
83
+ + }
84
+ ```
85
+
86
+ ### `useGetBridgeableTokens`
87
+
88
+ ```diff
89
+ - const { data: tokens } = useGetBridgeableTokens(BASE_MAINNET_CHAIN_ID, POLYGON_MAINNET_CHAIN_ID, srcAsset);
90
+ + const { data: result } = useGetBridgeableTokens({
91
+ + params: { from: ChainKeys.BASE_MAINNET, to: ChainKeys.POLYGON_MAINNET, token: srcAsset },
92
+ + });
93
+ + if (result?.ok) {
94
+ + const tokens: XToken[] = result.value;
95
+ + }
96
+ ```
97
+
98
+ ### `useBridgeAllowance` / `useBridgeApprove`
99
+
100
+ `useBridgeAllowance` query inputs (payload + walletProvider) all nest under `params` in v2:
101
+
102
+ ```diff
103
+ - const { data: allowanceResult } = useBridgeAllowance({ params, spokeProvider });
104
+ + const { data: isApproved } = useBridgeAllowance({
105
+ + params: { payload: bridgeParams, walletProvider },
106
+ + });
107
+ + // `data` is `boolean | undefined` (already unwrapped).
108
+ ```
109
+
110
+ `useBridgeApprove` mutation drops `spokeProvider` from hook init; `mutate(vars)` takes `{ params, walletProvider }`.
111
+
112
+ ## Pitfalls
113
+
114
+ 1. **`useGetBridgeableAmount` data shape changed.** v1 returned bare `bigint`; v2 returns `Result<BridgeLimit>` where `BridgeLimit = { amount, decimals, type }`. UI code that displayed the bigint directly needs `.value.amount`.
115
+ 2. **Tokens must share the same vault** to be bridgeable. Use `useGetBridgeableTokens` to enumerate compatible destinations — passing an incompatible pair to `bridge()` rejects with `VALIDATION_FAILED`.
116
+ 3. **`useBridge` return is `TxHashPair`** — destructure as `{ srcChainTxHash, dstChainTxHash }`, not `[a, b]`.
117
+ 4. **`recipient` field renamed to `dstAddress`** for consistency with the rest of the SDK.
118
+
119
+ ## Cross-references
120
+
121
+ - [`../../integration/features/bridge.md`](../../integration/features/bridge.md) — v2 reference.
122
+ - [`../../integration/recipes/bridge.md`](../../integration/recipes/bridge.md) — full v2 worked example.
123
+ - [`../../../../sdk/ai-exported/migration/features/bridge.md`](../../../../sdk/ai-exported/migration/features/bridge.md) — underlying SDK bridge migration.
@@ -0,0 +1,101 @@
1
+ # DEX migration — v1 → v2 (dapp-kit)
2
+
3
+ Pair: [`../../integration/features/dex.md`](../../integration/features/dex.md).
4
+
5
+ ## TL;DR
6
+
7
+ > Cross-cutting conventions (drop `spokeProvider`, single-object hook init, `mutate(vars)` for domain inputs, `mutateAsyncSafe` ergonomics) — see [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) and [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md). Feature-specific deltas below:
8
+
9
+ 1. **All mutations** (`useDexDeposit`, `useDexWithdraw`, `useSupplyLiquidity`, `useDecreaseLiquidity`, `useClaimRewards`, `useDexApprove`) — single-object hook init + `mutate({ params, walletProvider })`. SDK-leakage adds required `srcChainKey` + `srcAddress` to all action params.
10
+ 2. **`useSupplyLiquidity` handles both mint-new and increase-existing** — pass `tokenId` in params for increase, omit for mint. Use `useCreateSupplyLiquidityParams` to handle the routing.
11
+ 3. **`usePools` returns synchronously** in the SDK. The hook still returns `UseQueryResult` but the underlying call is config-derived (no RPC) — `staleTime: Infinity`, no auto-refresh.
12
+ 4. **Param builders take a FLAT props object** — `useCreateDepositParams`, `useCreateWithdrawParams`, `useCreateSupplyLiquidityParams`, `useCreateDecreaseLiquidityParams` — NOT `{ params: { ... } }`-wrapped. Their inputs use `srcChainKey` (not `srcChainId`); the result is spread into the mutation's `params` field at the call site.
13
+
14
+ ## Per-method delta
15
+
16
+ ### `useDexDeposit` / `useDexWithdraw`
17
+
18
+ ```diff
19
+ - const deposit = useDexDeposit(spokeProvider);
20
+ - await deposit.mutateAsync({ params: { asset, amount, poolToken } });
21
+ + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
22
+ + const { mutateAsyncSafe: deposit } = useDexDeposit();
23
+ + const result = await deposit({
24
+ + params: {
25
+ + srcChainKey: ChainKeys.BASE_MAINNET,
26
+ + srcAddress, // NEW
27
+ + asset,
28
+ + amount,
29
+ + poolToken,
30
+ + },
31
+ + walletProvider,
32
+ + });
33
+ + if (!result.ok) return;
34
+ + const { srcChainTxHash, dstChainTxHash } = result.value;
35
+ ```
36
+
37
+ ### `useSupplyLiquidity` — mint vs increase routing
38
+
39
+ ```diff
40
+ - // v1: separate hooks for mint and increase
41
+ - const mint = useMintLiquidity(spokeProvider);
42
+ - const increase = useIncreaseLiquidity(spokeProvider);
43
+ - if (existingTokenId) {
44
+ - await increase.mutateAsync({ params: { tokenId, poolKey, ... } });
45
+ - } else {
46
+ - await mint.mutateAsync({ params: { poolKey, ... } });
47
+ - }
48
+
49
+ + // v2: single hook handles both via tokenId presence
50
+ + const { mutateAsyncSafe: supply } = useSupplyLiquidity();
51
+ + const supplyParams = useCreateSupplyLiquidityParams({
52
+ + params: { poolKey, tickLower, tickUpper, amount0, amount1, tokenId: existingTokenId },
53
+ + });
54
+ + if (supplyParams && walletProvider) {
55
+ + const result = await supply({ params: supplyParams, walletProvider });
56
+ + }
57
+ ```
58
+
59
+ ### `useDecreaseLiquidity` / `useClaimRewards`
60
+
61
+ Standard pattern — drop `spokeProvider` from hook init, add `srcChainKey` / `srcAddress` to params, pass `walletProvider` via `mutate(vars)`.
62
+
63
+ ### `useDexAllowance` / `useDexApprove`
64
+
65
+ `useDexAllowance` wraps the deposit params under `params.payload`. Read-only — no `walletProvider`:
66
+
67
+ ```diff
68
+ - const { data: allowance } = useDexAllowance({ params: depositParams, walletProvider });
69
+ + const { data: isApproved } = useDexAllowance({ params: { payload: depositParams } });
70
+ + // `data` is `boolean | undefined`; the hook calls `isAllowanceValid` with `raw: true`.
71
+ ```
72
+
73
+ `useDexApprove` mutation drops `spokeProvider` from hook init; `mutate(vars)` takes `{ params, walletProvider }`.
74
+
75
+ ### `usePoolData` / `usePositionInfo` / `usePools`
76
+
77
+ Convert to single-object query shape:
78
+
79
+ ```diff
80
+ - const { data } = usePoolData(poolKey);
81
+ + const { data } = usePoolData({ params: { poolKey } });
82
+
83
+ - const { data } = usePositionInfo(tokenId, poolKey);
84
+ + const { data } = usePositionInfo({ params: { tokenId, poolKey } });
85
+
86
+ - const { data: pools } = usePools();
87
+ + const { data: pools } = usePools({}); // single-object shape, even with no params
88
+ ```
89
+
90
+ ## Pitfalls
91
+
92
+ 1. **`useSupplyLiquidity` is now ONE hook for both mint and increase.** v1 may have had two separate hooks. Use `tokenId` presence in `params` to drive the routing — `useCreateSupplyLiquidityParams` handles this for you.
93
+ 2. **Two-step flow stays the same.** First `useDexDeposit` brings the spoke asset to the hub as pool-token shares. Then `useSupplyLiquidity` uses those shares to mint/grow a position. UI sequencing unchanged.
94
+ 3. **Ticks are logarithmic.** Calculation libraries unchanged; just be aware that `tickLower` / `tickUpper` are tick indices, not prices.
95
+ 4. **`usePools` never auto-refreshes** — pools are static config. Override `queryOptions.refetchInterval` only if you really know your config changed.
96
+
97
+ ## Cross-references
98
+
99
+ - [`../../integration/features/dex.md`](../../integration/features/dex.md) — v2 reference.
100
+ - [`../../integration/recipes/dex.md`](../../integration/recipes/dex.md) — full v2 worked example.
101
+ - [`../../../../sdk/ai-exported/migration/features/dex.md`](../../../../sdk/ai-exported/migration/features/dex.md) — underlying SDK DEX migration.
@@ -0,0 +1,120 @@
1
+ # Migration migration — v1 → v2 (dapp-kit)
2
+
3
+ Pair: [`../../integration/features/migration.md`](../../integration/features/migration.md).
4
+
5
+ The biggest single API change in dapp-kit v2: v1 had a single `useMigrate(spokeProvider)`-style hook (often commented out by the time consumers needed it); v2 split it into 6 dedicated hooks.
6
+
7
+ ## TL;DR
8
+
9
+ > Cross-cutting conventions (drop `spokeProvider`, single-object hook init, `mutate(vars)` for domain inputs, `mutateAsyncSafe` ergonomics) — see [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) and [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md). Feature-specific deltas below:
10
+
11
+ 1. **`useMigrate(spokeProvider)` is gone.** Replaced by **six per-action hooks**:
12
+ - `useMigrateIcxToSoda` — wICX (ICON) → SODA (Sonic)
13
+ - `useRevertMigrateSodaToIcx` — SODA → wICX (revert)
14
+ - `useMigratebnUSD` — legacy bnUSD ↔ new bnUSD (bidirectional)
15
+ - `useMigrateBaln` — BALN (ICON) → SODA with optional lock period
16
+ - `useMigrationApprove` — approve before migration (action-discriminated)
17
+ - `useMigrationAllowance` — check approval (action-discriminated)
18
+ 2. **`useMigratebnUSD` is bidirectional.** v2 detects direction from `(srcbnUSD, dstbnUSD)` token addresses — no separate forward/reverse hook.
19
+ 3. **All mutations** drop `spokeProvider`; `walletProvider` flows through `mutate(vars)`. SDK-leakage adds `srcChainKey` / `srcAddress` to all action params.
20
+ 4. **`useMigrationApprove` / `useMigrationAllowance` are action-discriminated.** Same hook handles all migration approvals; pass `action: 'migrate' | 'revert'` to disambiguate.
21
+ 5. **BALN `lockupPeriod` is a literal union, not arbitrary number.** `0 | 1 | 2 | 3 | 6 | 12 | 18 | 24` (months).
22
+
23
+ ## Per-method delta
24
+
25
+ ### v1 single hook → v2 six hooks
26
+
27
+ ```diff
28
+ - // v1 — single hook
29
+ - const migrate = useMigrate(spokeProvider);
30
+ - await migrate.mutateAsync({ params: { type: 'icxToSoda', amount, /* ... */ } });
31
+
32
+ + // v2 — pick the right hook
33
+ + const { mutateAsyncSafe: migrate } = useMigrateIcxToSoda();
34
+ + const result = await migrate({
35
+ + params: {
36
+ + srcChainKey: ChainKeys.ICON_MAINNET,
37
+ + srcAddress: 'hx...',
38
+ + address: 'cx88fd...', // wICX token address
39
+ + amount,
40
+ + dstAddress: '0x...', // Sonic recipient
41
+ + },
42
+ + walletProvider,
43
+ + });
44
+ + if (!result.ok) return;
45
+ + const { srcChainTxHash, dstChainTxHash } = result.value;
46
+ ```
47
+
48
+ ### `useMigratebnUSD` — bidirectional via token addresses
49
+
50
+ ```diff
51
+ - // v1 might have had separate forward/reverse hooks (or all-in-one)
52
+ + // v2: one hook; direction detected from (srcbnUSD, dstbnUSD)
53
+ + const { mutateAsyncSafe: migratebnUSD } = useMigratebnUSD();
54
+ + const result = await migratebnUSD({
55
+ + params: {
56
+ + srcChainKey: ChainKeys.BASE_MAINNET,
57
+ + srcAddress: '0x...',
58
+ + srcbnUSD: '0x... (legacy or new)',
59
+ + dstChainKey: ChainKeys.ARBITRUM_MAINNET,
60
+ + dstbnUSD: '0x... (the other one)',
61
+ + amount,
62
+ + dstAddress: '0x...',
63
+ + },
64
+ + walletProvider,
65
+ + });
66
+ + if (!result.ok) {
67
+ + const direction = result.error.context?.direction; // 'forward' | 'reverse'
68
+ + /* ... */
69
+ + }
70
+ ```
71
+
72
+ ### `useMigrateBaln` — lock period
73
+
74
+ ```diff
75
+ + const { mutateAsyncSafe: migrateBaln } = useMigrateBaln();
76
+ + await migrateBaln({
77
+ + params: {
78
+ + srcChainKey: ChainKeys.ICON_MAINNET,
79
+ + srcAddress: 'hx...',
80
+ + amount,
81
+ + lockupPeriod: 12, // 0 | 1 | 2 | 3 | 6 | 12 | 18 | 24
82
+ + dstAddress: '0x...',
83
+ + },
84
+ + walletProvider,
85
+ + });
86
+ ```
87
+
88
+ ### `useMigrationApprove` / `useMigrationAllowance` — action-discriminated
89
+
90
+ ```diff
91
+ - const { approve } = useMigrationApprove(spokeProvider);
92
+ - await approve(params);
93
+ + const { data: isApproved } = useMigrationAllowance({
94
+ + params: { params: revertParams, action: 'revert' },
95
+ + });
96
+ + const { mutateAsync: approve } = useMigrationApprove();
97
+ + await approve({ params: revertParams, walletProvider, action: 'revert' });
98
+ ```
99
+
100
+ ## Approval requirements
101
+
102
+ | Migration | Approval needed? |
103
+ |---|---|
104
+ | ICX/wICX (ICON) → SODA | No (ICON has no ERC-20 allowance) |
105
+ | SODA → wICX (revert) | Yes |
106
+ | Legacy bnUSD ↔ new bnUSD (EVM/Stellar source) | Yes |
107
+ | BALN (ICON) → SODA | No |
108
+
109
+ ## Pitfalls
110
+
111
+ 1. **The single `useMigrate` is gone.** Pick the per-action hook that matches your migration. The v1 one-size-fits-all approach doesn't have a v2 shim.
112
+ 2. **`useMigratebnUSD` direction detection.** v2 detects from token addresses. If both `srcbnUSD` and `dstbnUSD` are on the same side (both legacy or both new), the SDK rejects with `VALIDATION_FAILED`. Use `error.context?.direction` to disambiguate in error messaging.
113
+ 3. **`lockupPeriod` is a literal union.** TypeScript rejects `lockupPeriod: 7`. Allowed: `0 | 1 | 2 | 3 | 6 | 12 | 18 | 24`. Reward multiplier ranges 0.5x (0 months) → 1.5x (24 months).
114
+ 4. **ICON-side migrations don't need approval** — ICON has no ERC-20 allowance mechanism. Don't render an approve step for `useMigrateIcxToSoda` or `useMigrateBaln`.
115
+
116
+ ## Cross-references
117
+
118
+ - [`../../integration/features/migration.md`](../../integration/features/migration.md) — v2 reference.
119
+ - [`../../integration/recipes/migration.md`](../../integration/recipes/migration.md) — full v2 worked examples (ICX, BALN, bnUSD, revert).
120
+ - [`../../../../sdk/ai-exported/migration/features/icx-bnusd-baln.md`](../../../../sdk/ai-exported/migration/features/icx-bnusd-baln.md) — underlying SDK migration migration.
@@ -0,0 +1,97 @@
1
+ # Money Market migration — v1 → v2 (dapp-kit)
2
+
3
+ Pair: [`../../integration/features/money-market.md`](../../integration/features/money-market.md).
4
+
5
+ ## TL;DR
6
+
7
+ > Cross-cutting conventions (drop `spokeProvider`, single-object hook init, `mutate(vars)` for domain inputs, `mutateAsyncSafe` ergonomics) — see [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) and [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md). Feature-specific deltas below:
8
+
9
+ 1. **`useSupply` / `useBorrow` / `useWithdraw` / `useRepay`** all switch to single-object `{ mutationOptions }` hook init + `mutate({ params, walletProvider })`.
10
+ 2. **`MoneyMarketSupplyParams<K>` (and the four similar action-param types) gained required `srcChainKey` + `srcAddress`** — SDK-leakage.
11
+ 3. **`useMMAllowance` auto-skips on-chain checks for borrow/withdraw** — v1 may have had this too, but v2 returns `true` synchronously for those actions instead of issuing a no-op RPC.
12
+ 4. **`useMMApprove` returns standard `SafeUseMutationResult`** — `isLoading` → `isPending`.
13
+ 5. **Reserve data hooks renamed `address` → `userAddress`** in some queries (`useUserFormattedSummary`, `useUserReservesData`).
14
+
15
+ ## Per-method delta
16
+
17
+ ### `useSupply` (and `useBorrow` / `useWithdraw` / `useRepay`)
18
+
19
+ ```diff
20
+ function SupplyButton({ token, amount, srcAddress }) {
21
+ - const supply = useSupply(spokeProvider);
22
+ + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
23
+ + const { mutateAsyncSafe: supply, isPending } = useSupply();
24
+
25
+ const handleSupply = async () => {
26
+ + if (!walletProvider) return;
27
+ - const result = await supply.mutateAsync({ params: { token, amount, action: 'supply' } });
28
+ - if (result.ok) {
29
+ - const txHashPair = result.value;
30
+ - /* ... */
31
+ - }
32
+ + const result = await supply({
33
+ + params: {
34
+ + srcChainKey: ChainKeys.BASE_MAINNET, // NEW: required
35
+ + srcAddress, // NEW: required
36
+ + token,
37
+ + amount,
38
+ + action: 'supply',
39
+ + },
40
+ + walletProvider,
41
+ + });
42
+ + if (!result.ok) return;
43
+ + const { srcChainTxHash, dstChainTxHash } = result.value; // TxHashPair
44
+ };
45
+ }
46
+ ```
47
+
48
+ `useBorrow`, `useWithdraw`, `useRepay` follow the same pattern with their respective `action` literals (`'borrow'` / `'withdraw'` / `'repay'`). Borrow + repay can specify optional `dstChainKey` / `dstAddress` for cross-chain delivery.
49
+
50
+ ### `useMMAllowance` — auto-skip
51
+
52
+ ```diff
53
+ - const { data: isApproved } = useMMAllowance({ params, spokeProvider });
54
+ + const { data: isApproved } = useMMAllowance({ params: { payload: params } });
55
+ + // No walletProvider — read-only (SDK call uses `raw: true` internally).
56
+ + // For borrow/withdraw actions, returns `true` synchronously (no RPC call).
57
+ + // For supply/repay, reads on-chain allowance.
58
+ ```
59
+
60
+ ### `useMMApprove`
61
+
62
+ ```diff
63
+ - const { approve, isLoading } = useMMApprove(spokeProvider);
64
+ - await approve(params);
65
+ + const { mutateAsync: approve, isPending } = useMMApprove();
66
+ + await approve({ params, walletProvider });
67
+ ```
68
+
69
+ ### Reserve data hooks
70
+
71
+ Most got the single-object shape:
72
+
73
+ ```diff
74
+ - const { data } = useReservesData({ ...refetchOptions });
75
+ + const { data } = useReservesData({ queryOptions: { ...refetchOptions } });
76
+ ```
77
+
78
+ User-position hooks renamed param fields:
79
+
80
+ ```diff
81
+ - const { data } = useUserFormattedSummary({ spokeChainKey, address: userAddress });
82
+ + const { data } = useUserFormattedSummary({ params: { spokeChainKey, userAddress } });
83
+ ```
84
+
85
+ ## Pitfalls
86
+
87
+ 1. **`srcAddress` is the user's spoke-side address**, not the hub address. Hub wallet is derived internally.
88
+ 2. **`useMMAllowance` returns `true` instantly for borrow/withdraw** — don't wait on the query state. Branch on `isApproved` directly.
89
+ 3. **Cross-chain borrow/repay**: omit `dstChainKey` / `dstAddress` for same-chain. Don't pass `dstChainKey === srcChainKey` (let the default kick in).
90
+ 4. **`MoneyMarketSupplyParams<K>` is now generic.** Use `as const` on `srcChainKey` for narrowing: `srcChainKey: ChainKeys.BASE_MAINNET as const`.
91
+
92
+ ## Cross-references
93
+
94
+ - [`../../integration/features/money-market.md`](../../integration/features/money-market.md) — v2 reference.
95
+ - [`../../integration/recipes/money-market.md`](../../integration/recipes/money-market.md) — full v2 worked example.
96
+ - [`../breaking-changes/sdk-leakage.md`](../breaking-changes/sdk-leakage.md) — `srcChainKey`/`srcAddress` required.
97
+ - [`../../../../sdk/ai-exported/migration/features/money-market.md`](../../../../sdk/ai-exported/migration/features/money-market.md) — underlying SDK MM migration.
@@ -0,0 +1,109 @@
1
+ # Staking migration — v1 → v2 (dapp-kit)
2
+
3
+ Pair: [`../../integration/features/staking.md`](../../integration/features/staking.md).
4
+
5
+ ## TL;DR
6
+
7
+ > Cross-cutting conventions (drop `spokeProvider`, single-object hook init, `mutate(vars)` for domain inputs, `mutateAsyncSafe` ergonomics) — see [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) and [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md). Feature-specific deltas below:
8
+
9
+ 1. **All five mutations** (`useStake`, `useUnstake`, `useInstantUnstake`, `useClaim`, `useCancelUnstake`) drop `spokeProvider` from hook init; `walletProvider` flows through `mutate(vars)`.
10
+ 2. **Three approve hooks** (`useStakeApprove`, `useUnstakeApprove`, `useInstantUnstakeApprove`) — same shape change. Each approves a different token (SODA for stake; xSODA for unstake/instant).
11
+ 3. **`useStakeRatio` return changed.** v2: `Result<[xSodaAmount, previewDepositAmount]>` — a 2-tuple. v1 returned a single bigint.
12
+ 4. **`useUnstakingInfo` return shape changed.** v2: `Result<UnstakingInfo>` where `UnstakingInfo = { userUnstakeSodaRequests: UserUnstakeInfo[], totalUnstaking: bigint }`. v1 may have returned just the array — v2 wraps it in an object.
13
+ 5. **Action params gained `srcChainKey` + `srcAddress`.** Same SDK-leakage as MM.
14
+
15
+ ## Per-method delta
16
+
17
+ ### `useStake` (template for all five)
18
+
19
+ ```diff
20
+ function StakeButton({ amount, srcAddress }) {
21
+ - const stake = useStake(spokeProvider);
22
+ + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
23
+ + const { mutateAsyncSafe: stake } = useStake();
24
+
25
+ const handleStake = async () => {
26
+ + if (!walletProvider) return;
27
+ - await stake.mutateAsync({ params: { amount, minReceive, action: 'stake' } });
28
+ + const result = await stake({
29
+ + params: {
30
+ + srcChainKey: ChainKeys.BASE_MAINNET,
31
+ + srcAddress,
32
+ + amount,
33
+ + minReceive,
34
+ + action: 'stake',
35
+ + },
36
+ + walletProvider,
37
+ + });
38
+ + if (!result.ok) return;
39
+ + const { srcChainTxHash, dstChainTxHash } = result.value;
40
+ };
41
+ }
42
+ ```
43
+
44
+ `useUnstake` / `useInstantUnstake` / `useClaim` / `useCancelUnstake` follow the same pattern with their respective params types.
45
+
46
+ ### Approve hooks
47
+
48
+ Each of stake / unstake / instantUnstake has its OWN approve hook (different tokens):
49
+
50
+ ```diff
51
+ - const { approve, isLoading } = useStakeApprove(spokeProvider);
52
+ - await approve({ amount, action: 'stake' });
53
+ + const { mutateAsync: approve, isPending } = useStakeApprove();
54
+ + await approve({ params: { srcChainKey, srcAddress, amount, action: 'stake' }, walletProvider });
55
+ ```
56
+
57
+ `useUnstakeApprove`, `useInstantUnstakeApprove` — same pattern.
58
+
59
+ ### `useStakeRatio` — return type change
60
+
61
+ ```diff
62
+ - const { data: ratio } = useStakeRatio(amount);
63
+ - if (ratio) {
64
+ - const xSodaAmount = ratio; // v1 returned single bigint
65
+ - /* ... */
66
+ - }
67
+ + const { data: ratio } = useStakeRatio({ params: { amount } });
68
+ + if (ratio?.ok) {
69
+ + const [xSodaAmount, previewDepositAmount] = ratio.value; // v2 returns tuple
70
+ + }
71
+ ```
72
+
73
+ ### `useUnstakingInfo` — return shape change
74
+
75
+ ```diff
76
+ - const { data: requests } = useUnstakingInfo(spokeProvider);
77
+ - requests?.map((r) => /* ... */); // v1 was an array
78
+ + const { data: result } = useUnstakingInfo({ params: { srcAddress, srcChainKey } });
79
+ + if (result?.ok) {
80
+ + const { userUnstakeSodaRequests, totalUnstaking } = result.value; // v2 is object
81
+ + userUnstakeSodaRequests.map((r) => /* ... */);
82
+ + }
83
+ ```
84
+
85
+ ### `useUnstakingInfoWithPenalty`
86
+
87
+ New in v2 — wraps `useUnstakingInfo`'s base shape with a per-request penalty annotation. Skip this section if your v1 codebase didn't compute penalty client-side.
88
+
89
+ ```ts
90
+ // @ai-snippets-skip
91
+ const { data: result } = useUnstakingInfoWithPenalty({ params: { srcAddress, srcChainKey } });
92
+ if (result?.ok) {
93
+ const { requestsWithPenalty } = result.value; // each adds penalty, penaltyPercentage, claimableAmount
94
+ }
95
+ ```
96
+
97
+ ## Pitfalls
98
+
99
+ 1. **`useStakeRatio` returns a tuple, not a single bigint.** v1 was simpler; v2 returns `[xSodaAmount, previewDepositAmount]`. Adjust render code.
100
+ 2. **`useStakingInfo` is unwrapped (not Result), but `useUnstakingInfo` IS Result-wrapped.** Asymmetric — check the integration docs per hook.
101
+ 3. **`useUnstakingInfoWithPenalty` returns an object with `requestsWithPenalty` array embedded** — don't `.value.map(...)`, use `.value.requestsWithPenalty.map(...)`.
102
+ 4. **Unstake has a waiting period.** Display via `useStakingConfig().unstakingPeriod`. Shows up in v1 too, but the read shape may have changed.
103
+ 5. **Instant unstake bypasses the waiting period but pays slippage.** Use `useInstantUnstakeRatio` to preview; set `minAmount` in params for slippage protection.
104
+
105
+ ## Cross-references
106
+
107
+ - [`../../integration/features/staking.md`](../../integration/features/staking.md) — v2 reference.
108
+ - [`../../integration/recipes/staking.md`](../../integration/recipes/staking.md) — full v2 worked example.
109
+ - [`../../../../sdk/ai-exported/migration/features/staking.md`](../../../../sdk/ai-exported/migration/features/staking.md) — underlying SDK staking migration.