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

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 (63) hide show
  1. package/README.md +9 -63
  2. package/dist/index.d.ts +11 -4
  3. package/dist/index.mjs +3 -6
  4. package/package.json +31 -19
  5. package/src/providers/SodaxProvider.tsx +15 -11
  6. package/ai-exported/AGENTS.md +0 -134
  7. package/ai-exported/integration/README.md +0 -49
  8. package/ai-exported/integration/ai-rules.md +0 -79
  9. package/ai-exported/integration/architecture.md +0 -274
  10. package/ai-exported/integration/features/README.md +0 -29
  11. package/ai-exported/integration/features/auxiliary-services.md +0 -169
  12. package/ai-exported/integration/features/bitcoin.md +0 -87
  13. package/ai-exported/integration/features/bridge.md +0 -91
  14. package/ai-exported/integration/features/dex.md +0 -152
  15. package/ai-exported/integration/features/migration.md +0 -118
  16. package/ai-exported/integration/features/money-market.md +0 -116
  17. package/ai-exported/integration/features/staking.md +0 -123
  18. package/ai-exported/integration/features/swap.md +0 -101
  19. package/ai-exported/integration/quickstart.md +0 -187
  20. package/ai-exported/integration/recipes/README.md +0 -136
  21. package/ai-exported/integration/recipes/backend-queries.md +0 -157
  22. package/ai-exported/integration/recipes/bitcoin.md +0 -193
  23. package/ai-exported/integration/recipes/bridge.md +0 -174
  24. package/ai-exported/integration/recipes/dex.md +0 -204
  25. package/ai-exported/integration/recipes/invalidations.md +0 -115
  26. package/ai-exported/integration/recipes/migration.md +0 -212
  27. package/ai-exported/integration/recipes/money-market.md +0 -206
  28. package/ai-exported/integration/recipes/mutation-error-handling.md +0 -118
  29. package/ai-exported/integration/recipes/observability.md +0 -93
  30. package/ai-exported/integration/recipes/setup.md +0 -144
  31. package/ai-exported/integration/recipes/staking.md +0 -202
  32. package/ai-exported/integration/recipes/swap.md +0 -272
  33. package/ai-exported/integration/recipes/wallet-connectivity.md +0 -101
  34. package/ai-exported/integration/reference/README.md +0 -12
  35. package/ai-exported/integration/reference/glossary.md +0 -188
  36. package/ai-exported/integration/reference/hooks-index.md +0 -190
  37. package/ai-exported/integration/reference/public-api.md +0 -110
  38. package/ai-exported/integration/reference/querykey-conventions.md +0 -179
  39. package/ai-exported/migration/README.md +0 -60
  40. package/ai-exported/migration/ai-rules.md +0 -81
  41. package/ai-exported/migration/breaking-changes/hook-signatures.md +0 -233
  42. package/ai-exported/migration/breaking-changes/querykey-conventions.md +0 -108
  43. package/ai-exported/migration/breaking-changes/result-handling.md +0 -211
  44. package/ai-exported/migration/breaking-changes/sdk-leakage.md +0 -165
  45. package/ai-exported/migration/checklist.md +0 -89
  46. package/ai-exported/migration/features/README.md +0 -34
  47. package/ai-exported/migration/features/auxiliary-services.md +0 -114
  48. package/ai-exported/migration/features/bitcoin.md +0 -88
  49. package/ai-exported/migration/features/bridge.md +0 -123
  50. package/ai-exported/migration/features/dex.md +0 -101
  51. package/ai-exported/migration/features/migration.md +0 -120
  52. package/ai-exported/migration/features/money-market.md +0 -97
  53. package/ai-exported/migration/features/staking.md +0 -109
  54. package/ai-exported/migration/features/swap.md +0 -118
  55. package/ai-exported/migration/recipes.md +0 -188
  56. package/ai-exported/migration/reference/README.md +0 -15
  57. package/ai-exported/migration/reference/deleted-hooks.md +0 -110
  58. package/ai-exported/migration/reference/error-shape-crosswalk.md +0 -144
  59. package/ai-exported/migration/reference/renamed-hooks.md +0 -66
  60. package/dist/index.cjs +0 -2642
  61. package/dist/index.cjs.map +0 -1
  62. package/dist/index.d.cts +0 -1550
  63. package/dist/index.mjs.map +0 -1
@@ -1,179 +0,0 @@
1
- # queryKey / mutationKey conventions — `@sodax/dapp-kit`
2
-
3
- Mandatory shape rules for every `queryKey` and `mutationKey`. Mechanically enforced on mutation keys by [`packages/dapp-kit/src/hooks/_mutationContract.test.ts`](../../../src/hooks/_mutationContract.test.ts); reviewer-enforced on query keys.
4
-
5
- ## The five rules
6
-
7
- ### Rule 1 — first segment is the feature directory name
8
-
9
- | Hook directory | First segment |
10
- |---|---|
11
- | `backend/` | `'backend'` |
12
- | `bitcoin/` | `'bitcoin'` |
13
- | `bridge/` | `'bridge'` |
14
- | `dex/` | `'dex'` |
15
- | `mm/` | `'mm'` |
16
- | `partner/` | `'partner'` |
17
- | `recovery/` | `'recovery'` |
18
- | `shared/` | `'shared'` |
19
- | `staking/` | `'staking'` |
20
- | `swap/` | `'swap'` |
21
- | `migrate/` | `'migrate'` |
22
-
23
- No exceptions. A hook in `swap/` whose key starts with `'intent'` is wrong.
24
-
25
- ### Rule 2 — camelCase for all segments
26
-
27
- No kebab-case (`'btc-balance'`), no ad-hoc casing, no `snake_case`. Identifiers are camelCase string literals (`'tradingWalletBalance'`, `'submitSwapTx'`).
28
-
29
- ### Rule 3 — shape is `[feature, action, ...identifiers]`
30
-
31
- Stable order: chain → token/asset → user → amount.
32
-
33
- ```ts
34
- // @ai-snippets-skip
35
- queryKey: ['mm', 'allowance', srcChainKey, token, action]
36
- // not ['mm', 'allowance', token, srcChainKey, action]
37
- ```
38
-
39
- ### Rule 4 — bigints stringify
40
-
41
- React Query's hash uses `JSON.stringify` which throws on raw bigints. Always coerce:
42
-
43
- ```ts
44
- queryKey: ['staking', 'stakeRatio', amount.toString()] // ✓
45
- queryKey: ['staking', 'stakeRatio', amount] // ✗ — runtime crash
46
- ```
47
-
48
- Exception: query keys that pass bigint via the read hook's typed params and the corresponding invalidations use the same raw value — match the read hook's shape exactly. New code should always stringify.
49
-
50
- ### Rule 5 — invalidate the narrowest key that could change
51
-
52
- If the mutation knows the affected `tokenId` / user / chain, scope the invalidation to it. Bare keys (no segments past the action) are reserved for "we don't know which variant changed" cases and should be commented.
53
-
54
- ```ts
55
- // Good — narrow scope
56
- queryClient.invalidateQueries({ queryKey: ['dex', 'positionInfo', tokenId, poolKey] });
57
-
58
- // Acceptable — when the mutation can't scope further
59
- queryClient.invalidateQueries({ queryKey: ['swap', 'allowance'] }); // wipe all allowance variants on approve
60
- ```
61
-
62
- ## Worked examples
63
-
64
- ```ts
65
- // @ai-snippets-skip
66
- // Cross-feature pattern: allowance reads. Shapes vary per feature (each carries
67
- // the inputs that actually scope the allowance). Match the read hook's shape exactly
68
- // from invalidations.
69
- queryKey: ['mm', 'allowance', srcChainKey, token, action]
70
- queryKey: ['swap', 'allowance', srcChainKey, srcAddress, inputToken, inputAmount.toString()]
71
- queryKey: ['bridge', 'allowance', srcChainKey, srcAddress, srcToken, amount.toString()]
72
- queryKey: ['dex', 'allowance', srcChainKey, asset, amount.toString()]
73
- queryKey: ['staking', 'allowance', srcChainKey, action, srcAddress, amount.toString()]
74
- // ^^ action is a fixed literal per hook: 'stake' / 'unstake' / 'instantUnstake'
75
-
76
- // User position reads
77
- queryKey: ['mm', 'userReservesData', spokeChainKey, userAddress]
78
- queryKey: ['staking', 'info', srcChainKey, srcAddress] // useStakingInfo — second segment is 'info', not 'stakingInfo'
79
- queryKey: ['shared', 'xBalances', xChainId, tokens, address]
80
-
81
- // Mutation default keys
82
- mutationKey: ['swap'] // useSwap
83
- mutationKey: ['swap', 'approve'] // useSwapApprove
84
- mutationKey: ['swap', 'cancel'] // useCancelSwap
85
- mutationKey: ['swap', 'limitOrder', 'create'] // useCreateLimitOrder
86
- mutationKey: ['swap', 'limitOrder', 'cancel'] // useCancelLimitOrder
87
- mutationKey: ['mm', 'supply']
88
- mutationKey: ['staking', 'stake']
89
- mutationKey: ['staking', 'approve', 'stake'] // useStakeApprove (action discriminator inside the key)
90
- mutationKey: ['bridge'] // useBridge — single segment (no 'execute' suffix)
91
- mutationKey: ['migrate', 'icxToSoda']
92
- mutationKey: ['dex', 'supplyLiquidity']
93
- ```
94
-
95
- ## Per-feature key tables
96
-
97
- Skip if you're writing a feature hook for the first time and want to align with existing conventions.
98
-
99
- ### Swap
100
-
101
- | Key | Hook |
102
- |---|---|
103
- | `['swap', 'quote', { ...payload, amount: payload.amount.toString() }]` | `useQuote` (object segment with bigint stringified) |
104
- | `['swap', 'allowance', srcChainKey, srcAddress, inputToken, inputAmount.toString()]` | `useSwapAllowance` |
105
- | `['swap', 'status', intentTxHash]` | `useStatus` |
106
- | `['swap']` | `useSwap` mutation key |
107
- | `['swap', 'approve']` | `useSwapApprove` |
108
- | `['swap', 'cancel']` | `useCancelSwap` |
109
- | `['swap', 'limitOrder', 'create']` | `useCreateLimitOrder` |
110
- | `['swap', 'limitOrder', 'cancel']` | `useCancelLimitOrder` |
111
-
112
- ### Money market
113
-
114
- | Key | Hook |
115
- |---|---|
116
- | `['mm', 'reservesData']` | `useReservesData` |
117
- | `['mm', 'reservesHumanized']` | `useReservesHumanized` |
118
- | `['mm', 'reservesList']` | `useReservesList` |
119
- | `['mm', 'reservesUsdFormat']` | `useReservesUsdFormat` |
120
- | `['mm', 'userReservesData', spokeChainKey, userAddress]` | `useUserReservesData` |
121
- | `['mm', 'userFormattedSummary', spokeChainKey, userAddress]` | `useUserFormattedSummary` |
122
- | `['mm', 'allowance', srcChainKey, token, action]` | `useMMAllowance` |
123
- | `['mm', 'aToken', aToken]` | `useAToken` |
124
- | `['mm', 'aTokensBalances', aTokens, spokeChainKey, userAddress]` | `useATokensBalances` |
125
- | `['mm', 'supply']` | `useSupply` mutation |
126
- | `['mm', 'borrow']` | `useBorrow` |
127
- | `['mm', 'withdraw']` | `useWithdraw` |
128
- | `['mm', 'repay']` | `useRepay` |
129
- | `['mm', 'approve']` | `useMMApprove` |
130
-
131
- ### Staking
132
-
133
- | Key | Hook |
134
- |---|---|
135
- | `['staking', 'info', srcChainKey, srcAddress]` | `useStakingInfo` (second segment is `'info'`, NOT `'stakingInfo'`) |
136
- | `['staking', 'unstakingInfo', srcChainKey, srcAddress]` | `useUnstakingInfo` |
137
- | `['staking', 'unstakingInfoWithPenalty', srcChainKey, srcAddress]` | `useUnstakingInfoWithPenalty` |
138
- | `['staking', 'config']` | `useStakingConfig` |
139
- | `['staking', 'stakeRatio', amount.toString()]` | `useStakeRatio` |
140
- | `['staking', 'instantUnstakeRatio', amount.toString()]` | `useInstantUnstakeRatio` |
141
- | `['staking', 'convertedAssets', amount.toString()]` | `useConvertedAssets` |
142
- | `['staking', 'allowance', srcChainKey, action, srcAddress, amount.toString()]` | `useStakeAllowance` / `useUnstakeAllowance` / `useInstantUnstakeAllowance` — `action` is a fixed literal per hook |
143
- | `['staking', 'stake']` | `useStake` mutation |
144
- | `['staking', 'unstake']` | `useUnstake` |
145
- | `['staking', 'instantUnstake']` | `useInstantUnstake` |
146
- | `['staking', 'claim']` | `useClaim` |
147
- | `['staking', 'cancelUnstake']` | `useCancelUnstake` |
148
- | `['staking', 'approve', 'stake' \| 'unstake' \| 'instantUnstake']` | `useStakeApprove` / `useUnstakeApprove` / `useInstantUnstakeApprove` |
149
-
150
- ### Bridge / DEX / Migration / Bitcoin / etc.
151
-
152
- Follow the same shape. See the source hook files (`packages/dapp-kit/src/hooks/<feature>/`) for current keys.
153
-
154
- ## v1 → v2
155
-
156
- In v1 dapp-kit, queryKey conventions were ad-hoc:
157
-
158
- ```ts
159
- // @ai-snippets-skip — queryKey-shape examples; `...` is a placeholder, not real code
160
- // ai-keys-allow — v1 keys shown for migration context; not real v2 source keys
161
- // v1 examples
162
- queryKey: ['xBalances', ...] // missing feature prefix
163
- queryKey: ['btc-balance', ...] // kebab-case
164
- queryKey: ['api', 'mm', ...] // wrong feature prefix
165
- mutationKey: undefined // many hooks had no default
166
-
167
- // v2
168
- queryKey: ['shared', 'xBalances', ...] // feature-prefixed
169
- queryKey: ['bitcoin', 'balance', ...] // camelCase
170
- queryKey: ['backend', 'mm', ...] // correctly nested under 'backend'
171
- mutationKey: ['mm', 'supply'] // every hook has a default; consumer can override via mutationOptions.mutationKey
172
- ```
173
-
174
- For migration code grafting onto dapp-kit's cache invalidation, see [`../../migration/breaking-changes/querykey-conventions.md`](../../migration/breaking-changes/querykey-conventions.md).
175
-
176
- ## Cross-references
177
-
178
- - [`../architecture.md`](../architecture.md) § "queryKey / mutationKey conventions" — full design rationale.
179
- - [`hooks-index.md`](hooks-index.md) — full hook table.
@@ -1,60 +0,0 @@
1
- # Migration — `@sodax/dapp-kit` v1 → v2
2
-
3
- This tree is the v1 → v2 migration playbook for **existing consumers** using v1 dapp-kit. If you're starting fresh on v2 with no v1 code to port, skip to [`../integration/README.md`](../integration/README.md).
4
-
5
- ## What v2 changes (the 30-second version)
6
-
7
- v2 was a deep canonicalization of dapp-kit's hook shapes plus an architectural reshape underneath in `@sodax/sdk`. Five orthogonal changes account for ~95% of the breakage your typecheck will surface:
8
-
9
- 1. **Single-object hook params.** Every hook accepts a single optional object. Mutation hooks take only `{ mutationOptions }` at hook-init; ALL domain inputs (`params`, `walletProvider`, per-call config) flow through `mutate(vars)`. Query hooks take `{ params, queryOptions }`. v1's positional args and hook-level `spokeProvider` / `params` are gone.
10
- 2. **`Result<T>` semantics inverted.** v1: `mutationFn` returned `Result<T>` as success; consumer branched on `data.ok` inside `onSuccess`. v2: `mutationFn` calls `unwrapResult` and **throws** on `!ok` — React Query's native `isError` / `error` / `onError` / `retry` engage. New `mutateAsyncSafe(vars): Promise<Result<TData>>` re-packs the throw for `Result<T>`-style branching when you want it.
11
- 3. **`useSpokeProvider` deleted.** Pass `walletProvider` (from `useWalletProvider({ xChainId: chainKey })`) directly into `mutate(vars)`. There is no provider class to derive.
12
- 4. **Approve-hook return shape standardized.** v1's `useFooApprove(spokeProvider)` returned a custom `{ approve, isLoading, error }` object. v2 returns the standard `SafeUseMutationResult` with `mutateAsync` / `mutateAsyncSafe` / `isPending`.
13
- 5. **Hook-owned invalidations.** Each mutation hook invalidates the relevant query keys in its own `onSuccess`. v1 utilities like `invalidateMmQueries` are deleted; consumer-provided `onSuccess` runs after the hook's invalidations.
14
-
15
- The remainder is per-feature shape diffs (return types, params field renames, new required params) and SDK-leakage (`xChainId` → `chainKey`, `*_MAINNET_CHAIN_ID` → `ChainKeys.*`, `Result<T>` propagation through hook signatures).
16
-
17
- ## Reading order
18
-
19
- Read in this order. Each step builds on the last.
20
-
21
- 1. **[`ai-rules.md`](ai-rules.md)** — DO / DO NOT / workflow / stop-conditions. Read first, then dive in.
22
- 2. **This file.** Cross-cutting glossary below + reference list of breaking-changes / features / checklist.
23
- 3. **[`checklist.md`](checklist.md)** — top-down cross-cutting migration checklist. Walk it, mark items off as you go.
24
- 4. **[`breaking-changes/hook-signatures.md`](breaking-changes/hook-signatures.md)** — fix every hook call site shape first (single-object params, `mutate(vars)`, approve return).
25
- 5. **[`breaking-changes/result-handling.md`](breaking-changes/result-handling.md)** — convert SDK-level error handling: success-path branching → `mutateAsyncSafe` (or `try/catch` on `mutateAsync`).
26
- 6. **[`breaking-changes/querykey-conventions.md`](breaking-changes/querykey-conventions.md)** — rename consumer query keys to match v2 conventions (where consumer code grafts onto dapp-kit cache invalidation).
27
- 7. **[`breaking-changes/sdk-leakage.md`](breaking-changes/sdk-leakage.md)** — SDK-level changes leaking through dapp-kit hook signatures. Cross-links to the SDK's migration tree.
28
- 8. **[`features/<x>.md`](features/)** — port the call sites for each feature you use. Pair with [`../integration/features/<x>.md`](../integration/features/) (same filename) when you need v2 design context.
29
- 9. **[`recipes.md`](recipes.md)** — codemods and adapters for incremental migration.
30
-
31
- ## v1 ↔ v2 glossary (terms that changed meaning)
32
-
33
- Same word, different concept across versions. Skim before reading the breaking-changes files — this dictionary prevents the most common porting confusions.
34
-
35
- | Term | v1 meaning | v2 meaning |
36
- |---|---|---|
37
- | **mutation hook arg** | Positional or first-arg `spokeProvider`; mutation called with minimal vars. | Optional `{ mutationOptions }` only. ALL domain inputs (`params`, `walletProvider`, per-call config) flow through `mutate(vars)`. |
38
- | **query hook arg** | Positional args (e.g. `useGetBridgeableTokens(srcChainId, dstChainId, addr)`). | Single object `{ params, queryOptions }`. |
39
- | **mutation `data`** | `Result<T>` — `{ ok: true; value: T } \| { ok: false; error }`. Branch on `data.ok` in `onSuccess`. | The unwrapped success type `T`. SDK failures throw inside `mutationFn` so React Query's `isError` / `error` engage. |
40
- | **approve hook return** | Custom object: `{ approve, isLoading, error }`. | Standard `SafeUseMutationResult`: `mutateAsync` / `mutateAsyncSafe`, `isPending`, `isError`, `error`. |
41
- | **`useSpokeProvider`** | Hook that derived a `SpokeProvider` from connected wallet state. | Deleted. Pass `walletProvider` (from `useWalletProvider`) directly into `mutate(vars)`. |
42
- | **invalidations** | Consumer-managed via `invalidateMmQueries(queryClient, ...)` utilities. | Hook-owned in composed `onSuccess`. Consumer `onSuccess` runs after the hook's. |
43
- | **`xChainId` / `srcChainId` / `dstChainId`** | Field names on tokens, intents, bridge params. (SDK-leakage.) | Renamed: `XToken.chainKey`, request-side `srcChainKey` / `dstChainKey`. **`Intent.srcChain` / `Intent.dstChain` (read shape) kept** — distinct from request-side. |
44
- | **`*_MAINNET_CHAIN_ID` constants** | Individual exports (`BSC_MAINNET_CHAIN_ID`, etc.). | Gone. Use `ChainKeys.X_MAINNET` namespace access. |
45
- | **`SodaxProvider`'s config** | Flat `rpcConfig: { sonic: '...', ... }`. | Nested under `chains`: `config.chains[ChainKeys.X]: { rpcUrl: '...' }`. |
46
- | **`useMigrate(spokeProvider)`** | Single hook (commented out in v1). | Six per-action hooks: `useMigrateIcxToSoda`, `useRevertMigrateSodaToIcx`, `useMigratebnUSD`, `useMigrateBaln`, `useMigrationApprove`, `useMigrationAllowance`. |
47
- | **error class** | Per-feature classes (`MoneyMarketError<Code>`, `IntentError<Code>`, etc.). (SDK-leakage.) | One canonical `SodaxError<C>` with `feature` + closed 13-code reason vocabulary. |
48
-
49
- ## Cross-references to integration
50
-
51
- Every breaking-change file in this tree has a v2-design counterpart in `../integration/`. Follow the link when "what does v2 expect instead?" comes up:
52
-
53
- - [`breaking-changes/hook-signatures.md`](breaking-changes/hook-signatures.md) ↔ [`../integration/architecture.md`](../integration/architecture.md) (§ Read hook shape, Mutation hook shape).
54
- - [`breaking-changes/result-handling.md`](breaking-changes/result-handling.md) ↔ [`../integration/recipes/mutation-error-handling.md`](../integration/recipes/mutation-error-handling.md).
55
- - [`breaking-changes/querykey-conventions.md`](breaking-changes/querykey-conventions.md) ↔ [`../integration/reference/querykey-conventions.md`](../integration/reference/querykey-conventions.md).
56
- - [`breaking-changes/sdk-leakage.md`](breaking-changes/sdk-leakage.md) ↔ [`../../../sdk/ai-exported/migration/`](../../../sdk/ai-exported/migration/) (the underlying SDK's migration tree).
57
- - [`features/<x>.md`](features/) ↔ [`../integration/features/<x>.md`](../integration/features/) (same filename).
58
- - [`recipes.md`](recipes.md) ↔ no integration counterpart (migration-only patterns).
59
-
60
- The pair-completeness rule: every file in `migration/features/` has a sibling in `integration/features/` with the same filename. Use this when you're stuck in one and want the other view.
@@ -1,81 +0,0 @@
1
- # AI rules — `@sodax/dapp-kit` migration v1 → v2
2
-
3
- DO / DO NOT / workflow / stop conditions for AI agents porting v1 dapp-kit code to v2. Read this **before** the per-feature migration playbooks.
4
-
5
- ## Workflow (do these in order)
6
-
7
- 1. **Survey the v1 surface area first.**
8
-
9
- ```bash
10
- pnpm tsc --noEmit # baseline (will produce hundreds of errors)
11
- grep -rE '\buseSpokeProvider\b|\binvalidateMmQueries\b' --include='*.tsx' --include='*.ts' src/ # hottest v1 patterns
12
- grep -rE '_MAINNET_CHAIN_ID\b|\bxChainId\b' --include='*.tsx' --include='*.ts' src/ # SDK leakage
13
- ```
14
-
15
- 2. **Read [`checklist.md`](checklist.md)** — top-down cross-cutting checklist. Walk it before touching code.
16
- 3. **Fix imports + provider-stack first** ([`breaking-changes/hook-signatures.md`](breaking-changes/hook-signatures.md) § Provider stack). The rest of the codebase won't typecheck without these.
17
- 4. **Mechanical sweeps next** — easier wins:
18
- - `*_MAINNET_CHAIN_ID` → `ChainKeys.X_MAINNET` (one codemod)
19
- - `useSpokeProvider` deletions
20
- - `xChainId` → `chainKey` on `XToken` (with care — read shape kept the field)
21
- 5. **Per-call-site rewrites:** mutation hook calls (move `params` + `walletProvider` from hook init to `mutate(vars)`), approve-hook returns (`{ approve, isLoading }` → `mutateAsync` + `isPending`), result handling (`data.ok` branching → `mutateAsyncSafe` or `try/catch`).
22
- 6. **Delete v1-managed invalidations** (`invalidateMmQueries`-style utilities). Hook-owned now.
23
- 7. **Verify with `pnpm tsc --noEmit`** until clean. Then run app smoke tests.
24
-
25
- ## DO
26
-
27
- - **DO** mechanical sweeps before per-call-site rewrites. Type renames and constant renames are codemod-friendly; result handling needs case-by-case attention.
28
- - **DO** prefer `mutateAsyncSafe` for sequenced flows. The user-reject case is modal, not exceptional.
29
- - **DO** `try/catch` `mutateAsync` calls if you keep that call shape. v2's `mutateAsync` rejects on SDK `!ok`.
30
- - **DO** delete consumer-side `invalidate*Queries` utility files. Hook-owned invalidations make them obsolete.
31
- - **DO** swap `BSC_MAINNET_CHAIN_ID` (and the other 14 v1 constants) for `ChainKeys.BSC_MAINNET` (or whichever chain). Codemod-friendly.
32
- - **DO** consult [`../integration/architecture.md`](../integration/architecture.md) when "what does v2 expect instead?" comes up.
33
- - **DO** consult [`../../../sdk/ai-exported/migration/`](../../../sdk/ai-exported/migration/) for any SDK-leakage migrations (chain-key terminology, `Result<T>` propagation, ConfigService).
34
-
35
- ## DO NOT
36
-
37
- - **DO NOT** convert `data.ok` branching mechanically. v1's `data` was `Result<T>`; v2's `data` is the unwrapped success value. The branching has to move from `onSuccess` to either `mutateAsyncSafe` (preferred) or `try/catch` on `mutateAsync`.
38
- - **DO NOT** keep the legacy `useFooApprove(spokeProvider)` call shape. v2's approve hooks return `SafeUseMutationResult` — call as `useFooApprove()` (no args), then `mutateAsync({ params, walletProvider })`.
39
- - **DO NOT** preserve `useSpokeProvider` "for compat." It's deleted; there's no shim. Pass `walletProvider` from `useWalletProvider({ xChainId: chainKey })` directly into `mutate(vars)`.
40
- - **DO NOT** blanket-replace `srcChain` → `srcChainKey`. The `Intent` *read shape* keeps `srcChain` / `dstChain` (those are `IntentRelayChainId`s). Only the *request-side* params (e.g. `MoneyMarketSupplyParams`) renamed to `srcChainKey` / `dstChainKey`.
41
- - **DO NOT** treat the v1 `useMigrate(spokeProvider)` API as still working. v2 split it into 6 per-action hooks (`useMigrateIcxToSoda`, etc.).
42
- - **DO NOT** add `@sodax/types` as an explicit dep during migration. It's transitively re-exported.
43
-
44
- ## Stop conditions (defer to user)
45
-
46
- | Signal | Why stop |
47
- |---|---|
48
- | User wants to keep v1 dapp-kit | Tell them the shapes are not compatible. They either upgrade or stay on v1. |
49
- | User wants to use React Server Components (RSC) | dapp-kit code goes in client components. Server Components can't run hooks. |
50
- | Codebase has consumer wrappers around dapp-kit hooks that look like dapp-kit's own internals | Examine each — they may be reasonable but check that they preserve `mutateAsyncSafe`. v1 wrappers often replaced React Query's `useMutation` directly. |
51
- | User expects approve hooks to look like before | Show them the new return shape. v2 standardized approve to `SafeUseMutationResult`; `{ approve, isLoading }` is gone. |
52
- | You hit an SDK-level migration item | Defer to [`../../../sdk/ai-exported/migration/`](../../../sdk/ai-exported/migration/). Don't try to re-explain SDK changes inside dapp-kit migration files — link them out. |
53
-
54
- ## Verification protocol
55
-
56
- ```bash
57
- # 1. Type-check the consumer (canonical pass).
58
- pnpm tsc --noEmit # zero errors expected
59
-
60
- # 2. Confirm no leftover v1 patterns.
61
- grep -rE '\buseSpokeProvider\b' src/ # zero hits
62
- grep -rE 'invalidateMmQueries\b' src/ # zero hits
63
- grep -rE '_MAINNET_CHAIN_ID\b' src/ # zero hits
64
- grep -rE 'data\?\.ok\b.*onSuccess' src/ # zero hits — v1 success-path branching is gone
65
-
66
- # 3. Confirm mutateAsync calls are properly wrapped.
67
- grep -rE 'mutateAsync\(' src/ | grep -v 'try\|catch\|mutateAsyncSafe' # zero hits or audit each
68
-
69
- # 4. Confirm dapp-kit imports come only from the package root.
70
- grep -rE "@sodax/dapp-kit/[a-z]" src/ # zero hits (no deep imports)
71
- ```
72
-
73
- ## Done criteria
74
-
75
- - [ ] Provider stack updated: `<SodaxProvider config={...}>` + `<QueryClientProvider>` (preferably `createSodaxQueryClient()`).
76
- - [ ] Every v1 hook call site rewritten to single-object params + `mutate(vars)` flow for domain inputs.
77
- - [ ] Every approve hook usage rewritten to `mutateAsync` / `mutateAsyncSafe` + `isPending`.
78
- - [ ] Every mutation result handler converted from `data.ok` branching to `mutateAsyncSafe`'s `result.ok` branching, or to `try/catch` on `mutateAsync`.
79
- - [ ] No `useSpokeProvider`, no `invalidateMmQueries`, no `*_MAINNET_CHAIN_ID` constants.
80
- - [ ] `pnpm tsc --noEmit` clean.
81
- - [ ] App smoke-tested: connect wallet, run one mutation per feature you use.
@@ -1,233 +0,0 @@
1
- # Hook signatures — v1 → v2
2
-
3
- The structural shape of every dapp-kit hook changed in v2. Five categories of breakage:
4
-
5
- 1. Provider stack config
6
- 2. Mutation hook signature (`{ mutationOptions }` only)
7
- 3. Query hook signature (`{ params, queryOptions }`)
8
- 4. Approve hook return shape
9
- 5. `useSpokeProvider` deletion + invalidation logic move
10
-
11
- ## 1. Provider stack
12
-
13
- `SodaxProvider`'s prop shape changed.
14
-
15
- ```diff
16
- - <SodaxProvider rpcConfig={{
17
- - sonic: 'https://sonic-rpc.publicnode.com',
18
- - '0xa86a.avax': 'https://...',
19
- - '0xa4b1.arbitrum': 'https://arb1.arbitrum.io/rpc',
20
- - }}>
21
- + <SodaxProvider config={{
22
- + chains: {
23
- + [ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://sonic-rpc.publicnode.com' },
24
- + [ChainKeys.AVALANCHE_MAINNET]: { rpcUrl: 'https://...' },
25
- + [ChainKeys.ARBITRUM_MAINNET]: { rpcUrl: 'https://arb1.arbitrum.io/rpc' },
26
- + },
27
- + }}>
28
- ```
29
-
30
- The `config` prop is `DeepPartial<SodaxConfig>` from `@sodax/sdk`. Other fields available: `api`, `solver`, `swaps`, `bridge`, `dex`, `moneyMarket`, `hub`, `relay`, `fee`. See [`../../../../sdk/ai-exported/migration/breaking-changes/architecture.md`](../../../../sdk/ai-exported/migration/breaking-changes/architecture.md) for the SDK-side reshape.
31
-
32
- **Recommended pairing**: replace `new QueryClient()` with `createSodaxQueryClient()` for global mutation observability.
33
-
34
- ```diff
35
- - import { QueryClient } from '@tanstack/react-query';
36
- - const queryClient = new QueryClient();
37
- + import { createSodaxQueryClient } from '@sodax/dapp-kit';
38
- + const queryClient = createSodaxQueryClient();
39
- ```
40
-
41
- ## 2. Mutation hook signature
42
-
43
- v1: hook took `spokeProvider` (or other domain inputs) at hook-init.
44
- v2: hook takes only `{ mutationOptions }`. ALL domain inputs flow through `mutate(vars)`.
45
-
46
- ```diff
47
- - // v1
48
- - function SwapButton({ intentParams, spokeProvider }) {
49
- - const swap = useSwap(spokeProvider);
50
- - await swap.mutateAsync({ params: intentParams });
51
- - }
52
-
53
- + // v2
54
- + function SwapButton({ intentParams }) {
55
- + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET }); // separate now
56
- + const { mutateAsync: swap } = useSwap();
57
- + if (!walletProvider) return;
58
- + await swap({ params: intentParams, walletProvider });
59
- + }
60
- ```
61
-
62
- This affects every mutation hook — `useSupply`, `useBorrow`, `useStake`, `useBridge`, etc. The mechanical recipe per call site:
63
-
64
- 1. Drop `spokeProvider` from the hook init.
65
- 2. Add `useWalletProvider({ xChainId: chainKey })` separately.
66
- 3. Move `params` and `walletProvider` from hook init to `mutate(vars)`.
67
- 4. Update the destructure: `const { mutateAsync: foo } = useFoo();` (or `mutateAsyncSafe`).
68
-
69
- ### Approve hooks (the most disruptive of the bunch)
70
-
71
- v1's approve hooks returned a custom object. v2 returns the standard `SafeUseMutationResult`.
72
-
73
- ```diff
74
- - // v1
75
- - const { approve, isLoading, error } = useSwapApprove(spokeProvider);
76
- - await approve(intentParams);
77
-
78
- + // v2
79
- + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
80
- + const { mutateAsync: approve, mutateAsyncSafe, isPending, error } = useSwapApprove();
81
- + if (!walletProvider) return;
82
- + await approve({ params: intentParams, walletProvider });
83
- ```
84
-
85
- Field rename: `isLoading` → `isPending` (React Query 5 convention; v2 dapp-kit follows it).
86
-
87
- ## 3. Query hook signature
88
-
89
- v1: positional args (`useFoo(arg1, arg2)`).
90
- v2: single object (`useFoo({ params, queryOptions })`).
91
-
92
- ```diff
93
- - // v1
94
- - const { data: tokens } = useGetBridgeableTokens(srcChainId, dstChainId, tokenAddress);
95
-
96
- + // v2
97
- + const { data: tokens } = useGetBridgeableTokens({
98
- + params: { from: ChainKeys.BASE_MAINNET, to: ChainKeys.POLYGON_MAINNET, token: tokenAddress },
99
- + });
100
- ```
101
-
102
- Hook owns `queryKey`, `queryFn`, `enabled`. The `queryOptions` slot is `Omit<UseQueryOptions, 'queryKey' | 'queryFn' | 'enabled'>`. Don't try to override those three fields — TypeScript rejects.
103
-
104
- ## 4. Wallet plumbing — `useSpokeProvider` deletion
105
-
106
- v1 had `useSpokeProvider(chainId, walletProvider)` to derive a `SpokeProvider` instance. v2 deleted this hook entirely.
107
-
108
- ```diff
109
- - // v1
110
- - import { useSpokeProvider } from '@sodax/dapp-kit';
111
- -
112
- - const spokeProvider = useSpokeProvider({ chainId: BSC_MAINNET_CHAIN_ID });
113
- - // ... pass spokeProvider into hooks
114
-
115
- + // v2
116
- + import { useWalletProvider } from '@sodax/wallet-sdk-react';
117
- + import { ChainKeys } from '@sodax/sdk';
118
- +
119
- + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
120
- + // ... pass walletProvider into mutate(vars)
121
- ```
122
-
123
- `SpokeProvider` was a v1 abstraction that v2 makes implicit (the chain key on action params drives spoke routing internally). There's no shim — drop the concept.
124
-
125
- ## 5. Invalidation logic
126
-
127
- v1 expected consumers to manage cache invalidation manually:
128
-
129
- ```ts
130
- // @ai-snippets-skip
131
- // v1 — consumer-managed
132
- import { useQueryClient } from '@tanstack/react-query';
133
- const queryClient = useQueryClient();
134
- await supply({ params, spokeProvider });
135
- invalidateMmQueries(queryClient, srcChainKey, userAddress, token);
136
- ```
137
-
138
- v2: each mutation hook invalidates its relevant keys in its own `onSuccess`. Delete consumer-side `invalidate*Queries` utilities.
139
-
140
- ```diff
141
- - // v1
142
- - await supply({ params, spokeProvider });
143
- - invalidateMmQueries(queryClient, srcChainKey, userAddress, token);
144
-
145
- + // v2
146
- + await supply({ params, walletProvider }); // hook invalidates xBalances + userReservesData automatically
147
- ```
148
-
149
- To run additional cross-feature invalidations (your own analytics view, etc.), pass `mutationOptions.onSuccess`:
150
-
151
- ```ts
152
- // @ai-snippets-skip
153
- const { mutateAsync: supply } = useSupply({
154
- mutationOptions: {
155
- onSuccess: async (data, vars) => {
156
- // Runs AFTER dapp-kit's invalidations.
157
- await queryClient.invalidateQueries({ queryKey: ['my-app', 'analytics'] });
158
- },
159
- },
160
- });
161
- ```
162
-
163
- See [`../../integration/recipes/invalidations.md`](../../integration/recipes/invalidations.md) for the full pattern.
164
-
165
- ## 6. Variable-shape changes inside `mutate(vars)`
166
-
167
- v1's mutation vars were scattered (some at hook init, some in `mutate`). v2 consolidates everything into `TVars`.
168
-
169
- ```diff
170
- - // v1
171
- - const supply = useSupply(spokeProvider);
172
- - await supply.mutateAsync({ params: { token, amount, action: 'supply' } });
173
-
174
- + // v2 — params now requires srcChainKey + srcAddress (SDK leakage)
175
- + const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
176
- + const { mutateAsync: supply } = useSupply();
177
- + await supply({
178
- + params: {
179
- + srcChainKey: ChainKeys.BASE_MAINNET,
180
- + srcAddress: '0x...', // NEW: required in v2
181
- + token,
182
- + amount,
183
- + action: 'supply',
184
- + },
185
- + walletProvider, // NEW: at mutate(vars), not hook init
186
- + });
187
- ```
188
-
189
- The added `srcChainKey` + `srcAddress` is SDK-leakage — see [`sdk-leakage.md`](sdk-leakage.md) for the full picture.
190
-
191
- ## 7. Query options shape
192
-
193
- v1 query hooks accepted ad-hoc option overrides (sometimes including `queryKey`). v2 typed the slot strictly:
194
-
195
- ```diff
196
- - // v1
197
- - const { data } = useUserReservesData({
198
- - spokeProvider,
199
- - address,
200
- - queryKey: ['my-custom-key'], // ⚠️ v2 forbids overriding queryKey
201
- - });
202
-
203
- + // v2
204
- + const { data } = useUserReservesData({
205
- + params: { spokeChainKey, userAddress: address },
206
- + queryOptions: { staleTime: 5000, refetchInterval: 10000 },
207
- + });
208
- ```
209
-
210
- If you were overriding `queryKey` in v1 to graft your own invalidations, that's not the v2 way. Either:
211
- - Use the hook's default queryKey + invalidate via your own `mutationOptions.onSuccess` after relevant mutations.
212
- - If you need a totally different query shape, write your own `useQuery` directly (don't shoehorn dapp-kit's hook).
213
-
214
- ## TypeScript fingerprints
215
-
216
- These error patterns indicate this category of breakage:
217
-
218
- | Error | What it means |
219
- |---|---|
220
- | `Module '"@sodax/dapp-kit"' has no exported member 'useSpokeProvider'` | Hook deleted; drop import. |
221
- | `Property 'approve' does not exist on type 'SafeUseMutationResult'` | v1 approve return shape; use `mutateAsync` / `mutateAsyncSafe`. |
222
- | `Property 'isLoading' does not exist on type 'SafeUseMutationResult'` | Renamed to `isPending`. |
223
- | `Object literal may only specify known properties, and 'spokeProvider' does not exist in type 'UseFooVars'` | Hook init or mutate vars still has v1 `spokeProvider`. Drop it. |
224
- | `Object literal may only specify known properties, and 'queryKey' does not exist in type 'ReadQueryOptions'` | v1 ad-hoc queryOptions; queryKey is hook-owned now. |
225
- | `Type '...' is missing the following properties from type 'MoneyMarketSupplyParams': srcChainKey, srcAddress` | SDK leakage — params shape gained required fields. |
226
- | `Expected 0-1 arguments, but got 3` (on a query hook) | v1 positional args; switch to `{ params, queryOptions }`. |
227
-
228
- ## Cross-references
229
-
230
- - [`result-handling.md`](result-handling.md) — `Result<T>` semantic shift (success-path → throws inside mutationFn).
231
- - [`querykey-conventions.md`](querykey-conventions.md) — queryKey/mutationKey rename rules.
232
- - [`sdk-leakage.md`](sdk-leakage.md) — SDK-side changes that surface here (chain-key terminology, etc.).
233
- - [`../../integration/architecture.md`](../../integration/architecture.md) — the canonical v2 hook shapes.