@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.
- package/README.md +9 -63
- package/dist/index.d.ts +11 -4
- package/dist/index.mjs +3 -6
- package/package.json +31 -19
- package/src/providers/SodaxProvider.tsx +15 -11
- package/ai-exported/AGENTS.md +0 -134
- package/ai-exported/integration/README.md +0 -49
- package/ai-exported/integration/ai-rules.md +0 -79
- package/ai-exported/integration/architecture.md +0 -274
- package/ai-exported/integration/features/README.md +0 -29
- package/ai-exported/integration/features/auxiliary-services.md +0 -169
- package/ai-exported/integration/features/bitcoin.md +0 -87
- package/ai-exported/integration/features/bridge.md +0 -91
- package/ai-exported/integration/features/dex.md +0 -152
- package/ai-exported/integration/features/migration.md +0 -118
- package/ai-exported/integration/features/money-market.md +0 -116
- package/ai-exported/integration/features/staking.md +0 -123
- package/ai-exported/integration/features/swap.md +0 -101
- package/ai-exported/integration/quickstart.md +0 -187
- package/ai-exported/integration/recipes/README.md +0 -136
- package/ai-exported/integration/recipes/backend-queries.md +0 -157
- package/ai-exported/integration/recipes/bitcoin.md +0 -193
- package/ai-exported/integration/recipes/bridge.md +0 -174
- package/ai-exported/integration/recipes/dex.md +0 -204
- package/ai-exported/integration/recipes/invalidations.md +0 -115
- package/ai-exported/integration/recipes/migration.md +0 -212
- package/ai-exported/integration/recipes/money-market.md +0 -206
- package/ai-exported/integration/recipes/mutation-error-handling.md +0 -118
- package/ai-exported/integration/recipes/observability.md +0 -93
- package/ai-exported/integration/recipes/setup.md +0 -144
- package/ai-exported/integration/recipes/staking.md +0 -202
- package/ai-exported/integration/recipes/swap.md +0 -272
- package/ai-exported/integration/recipes/wallet-connectivity.md +0 -101
- package/ai-exported/integration/reference/README.md +0 -12
- package/ai-exported/integration/reference/glossary.md +0 -188
- package/ai-exported/integration/reference/hooks-index.md +0 -190
- package/ai-exported/integration/reference/public-api.md +0 -110
- package/ai-exported/integration/reference/querykey-conventions.md +0 -179
- package/ai-exported/migration/README.md +0 -60
- package/ai-exported/migration/ai-rules.md +0 -81
- package/ai-exported/migration/breaking-changes/hook-signatures.md +0 -233
- package/ai-exported/migration/breaking-changes/querykey-conventions.md +0 -108
- package/ai-exported/migration/breaking-changes/result-handling.md +0 -211
- package/ai-exported/migration/breaking-changes/sdk-leakage.md +0 -165
- package/ai-exported/migration/checklist.md +0 -89
- package/ai-exported/migration/features/README.md +0 -34
- package/ai-exported/migration/features/auxiliary-services.md +0 -114
- package/ai-exported/migration/features/bitcoin.md +0 -88
- package/ai-exported/migration/features/bridge.md +0 -123
- package/ai-exported/migration/features/dex.md +0 -101
- package/ai-exported/migration/features/migration.md +0 -120
- package/ai-exported/migration/features/money-market.md +0 -97
- package/ai-exported/migration/features/staking.md +0 -109
- package/ai-exported/migration/features/swap.md +0 -118
- package/ai-exported/migration/recipes.md +0 -188
- package/ai-exported/migration/reference/README.md +0 -15
- package/ai-exported/migration/reference/deleted-hooks.md +0 -110
- package/ai-exported/migration/reference/error-shape-crosswalk.md +0 -144
- package/ai-exported/migration/reference/renamed-hooks.md +0 -66
- package/dist/index.cjs +0 -2642
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -1550
- package/dist/index.mjs.map +0 -1
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
# queryKey conventions — v1 → v2
|
|
2
|
-
|
|
3
|
-
This is a low-priority migration item — it only matters if your code grafts onto dapp-kit's cache invalidation (e.g. you fetch a related query and want it to be invalidated when dapp-kit's mutation fires).
|
|
4
|
-
|
|
5
|
-
If your app doesn't share queryKey shapes with dapp-kit, skip this file. The shape changes are a nicety, not a blocker — your existing keys still work for your own queries.
|
|
6
|
-
|
|
7
|
-
## What changed
|
|
8
|
-
|
|
9
|
-
v1 was ad-hoc; v2 is canonical.
|
|
10
|
-
|
|
11
|
-
| Aspect | v1 | v2 |
|
|
12
|
-
|---|---|---|
|
|
13
|
-
| First segment | Free-form (`'xBalances'`, `'btc-balance'`, `'api'`) | Feature directory name (`'shared'`, `'bitcoin'`, `'backend'`) |
|
|
14
|
-
| Casing | Mixed (kebab-case in places) | camelCase exclusively |
|
|
15
|
-
| Bigint values | Inconsistent | Always `.toString()` before going into a key |
|
|
16
|
-
| Default `mutationKey` | Many hooks had none | Every hook has a default; consumer can override |
|
|
17
|
-
|
|
18
|
-
## Why align?
|
|
19
|
-
|
|
20
|
-
Your custom queries can be invalidated by dapp-kit's mutations if they share the prefix:
|
|
21
|
-
|
|
22
|
-
```ts
|
|
23
|
-
// @ai-snippets-skip — illustrative; `queryFn` is shown as `...` placeholder
|
|
24
|
-
// Your custom query
|
|
25
|
-
const { data: customAnalytics } = useQuery({
|
|
26
|
-
queryKey: ['shared', 'xBalances', xChainId, address, 'with-analytics'],
|
|
27
|
-
queryFn: ...,
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
// Dapp-kit's `useSwap` invalidates `['shared', 'xBalances', srcChainKey]`,
|
|
31
|
-
// which is a PREFIX of your key — your query gets invalidated automatically.
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
If your key starts with something else (e.g. `['my-app', 'xBalances', ...]`), dapp-kit's invalidation won't touch it — you'd need to wire your own invalidation in `mutationOptions.onSuccess`.
|
|
35
|
-
|
|
36
|
-
## Migration patterns
|
|
37
|
-
|
|
38
|
-
### Sweep your custom queryKeys
|
|
39
|
-
|
|
40
|
-
If your app has custom queries that overlap with dapp-kit's domains, rename them to match v2 conventions:
|
|
41
|
-
|
|
42
|
-
<!-- ai-keys-allow — v1 keys shown for migration context; the `-` lines are v1 shapes, not real v2 source keys -->
|
|
43
|
-
|
|
44
|
-
```diff
|
|
45
|
-
const { data } = useQuery({
|
|
46
|
-
- queryKey: ['xBalances', address, ...],
|
|
47
|
-
+ queryKey: ['shared', 'xBalances', xChainId, [token], address],
|
|
48
|
-
queryFn: ...,
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
const { data } = useQuery({
|
|
52
|
-
- queryKey: ['btc-balance', address],
|
|
53
|
-
+ queryKey: ['bitcoin', 'balance', address],
|
|
54
|
-
queryFn: ...,
|
|
55
|
-
});
|
|
56
|
-
<!-- ai-keys-allow -->
|
|
57
|
-
|
|
58
|
-
const { data } = useQuery({
|
|
59
|
-
- queryKey: ['api', 'mm', userAddress],
|
|
60
|
-
+ queryKey: ['backend', 'mm', userAddress],
|
|
61
|
-
queryFn: ...,
|
|
62
|
-
});
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### If you previously overrode dapp-kit's queryKeys
|
|
66
|
-
|
|
67
|
-
v1 query hooks accepted `queryKey` overrides. v2 hooks own their queryKeys — the option is gone.
|
|
68
|
-
|
|
69
|
-
```diff
|
|
70
|
-
- const { data } = useUserReservesData({
|
|
71
|
-
- spokeProvider,
|
|
72
|
-
- address,
|
|
73
|
-
- queryKey: ['my-app-mm-positions'], // v1
|
|
74
|
-
- });
|
|
75
|
-
+ // v2 — drop the queryKey override; if you needed an alias, write your own useQuery.
|
|
76
|
-
+ const { data } = useUserReservesData({
|
|
77
|
-
+ params: { spokeChainKey, userAddress: address },
|
|
78
|
-
+ });
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### If you had your own `mutationKey` defaults
|
|
82
|
-
|
|
83
|
-
v1 mutation hooks often had no default `mutationKey` — consumers set one in `mutationOptions`. v2 hooks set a sensible default (e.g. `['swap']`, `['mm', 'supply']`) — drop redundant overrides:
|
|
84
|
-
|
|
85
|
-
```diff
|
|
86
|
-
const { mutateAsync: swap } = useSwap({
|
|
87
|
-
mutationOptions: {
|
|
88
|
-
- mutationKey: ['swap'], // already the default in v2
|
|
89
|
-
retry: 5,
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Per-feature conventions
|
|
95
|
-
|
|
96
|
-
See [`../../integration/reference/querykey-conventions.md`](../../integration/reference/querykey-conventions.md) for the full per-feature key tables. Use that as the reference when aligning your own keys.
|
|
97
|
-
|
|
98
|
-
## Done criteria
|
|
99
|
-
|
|
100
|
-
<!-- ai-keys-allow — the bare xBalances key below is shown as a v1-style anti-example -->
|
|
101
|
-
- [ ] No custom queryKeys overlapping with dapp-kit's domains using non-canonical first segments (e.g. `['xBalances', ...]` should become `['shared', 'xBalances', ...]`).
|
|
102
|
-
- [ ] No `queryKey` overrides in `useFooQuery({ ..., queryKey: [...] })` patterns (the option is gone).
|
|
103
|
-
- [ ] Optional: drop redundant default-`mutationKey` overrides in `mutationOptions`.
|
|
104
|
-
|
|
105
|
-
## Cross-references
|
|
106
|
-
|
|
107
|
-
- [`../../integration/reference/querykey-conventions.md`](../../integration/reference/querykey-conventions.md) — full canonical conventions + per-feature key tables.
|
|
108
|
-
- [`hook-signatures.md`](hook-signatures.md) — broader hook-shape changes.
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
# Result<T> handling — v1 → v2
|
|
2
|
-
|
|
3
|
-
The most subtle breakage: `Result<T>` semantics inside dapp-kit's mutation pipeline inverted in v2.
|
|
4
|
-
|
|
5
|
-
## The semantic shift
|
|
6
|
-
|
|
7
|
-
| | v1 | v2 |
|
|
8
|
-
|---|---|---|
|
|
9
|
-
| `mutationFn` return | `Result<T>` | unwrapped `T`; throws on `!ok` |
|
|
10
|
-
| `mutation.data` shape | `Result<T>` (`{ ok, value }` or `{ ok, error }`) | unwrapped `T` (e.g. `SwapResponse`, `TxHashPair`) |
|
|
11
|
-
| Where to branch | Inside `onSuccess`: `if (data.ok) ...` | Branch on `mutation.error` / `mutation.isError`, OR use `mutateAsyncSafe` |
|
|
12
|
-
| `onSuccess` fires on SDK `!ok`? | **Yes** (success path) — required `data.ok` check inside | **No** — only on actual success |
|
|
13
|
-
| `onError` fires on SDK `!ok`? | No | **Yes** — engages React Query's native error model |
|
|
14
|
-
| `retry` config | Ignored on SDK `!ok` | Engages on SDK `!ok` |
|
|
15
|
-
| Devtools error display | Empty | Shows the SDK error |
|
|
16
|
-
|
|
17
|
-
The shift makes React Query's native error model engage for SDK failures, instead of treating every SDK call as "successful but maybe with an error inside."
|
|
18
|
-
|
|
19
|
-
## Why the change
|
|
20
|
-
|
|
21
|
-
In v1:
|
|
22
|
-
- Consumers had to remember to branch on `data.ok` inside every `onSuccess`. Forgetting was easy and silent (success logic ran on a failed swap).
|
|
23
|
-
- Hook-owned invalidations fired on SDK failure too, burning RPC traffic on every failed click.
|
|
24
|
-
- Devtools showed every mutation as "success" even when the SDK returned `{ ok: false }`.
|
|
25
|
-
- `retry` config didn't engage (the request didn't "fail" from React Query's perspective).
|
|
26
|
-
|
|
27
|
-
v2's `mutationFn` calls `unwrapResult(await sodax.<feature>.<method>(vars))`:
|
|
28
|
-
- `Result<T>` `{ ok: true; value }` → returns `value` (the unwrapped success type).
|
|
29
|
-
- `Result<T>` `{ ok: false; error }` → throws `error`.
|
|
30
|
-
|
|
31
|
-
This makes `isError`, `error`, `onError`, `retry`, devtools all work correctly out of the box.
|
|
32
|
-
|
|
33
|
-
## Migration patterns
|
|
34
|
-
|
|
35
|
-
### Pattern 1: success-path branching → drop the check
|
|
36
|
-
|
|
37
|
-
```diff
|
|
38
|
-
const { mutateAsync: swap } = useSwap({
|
|
39
|
-
mutationOptions: {
|
|
40
|
-
- onSuccess: (data, vars) => {
|
|
41
|
-
- if (data.ok) {
|
|
42
|
-
- showSuccess(data.value.intent);
|
|
43
|
-
- } else {
|
|
44
|
-
- showError(data.error);
|
|
45
|
-
- }
|
|
46
|
-
- },
|
|
47
|
-
+ onSuccess: (data, vars) => {
|
|
48
|
-
+ // data is now SwapResponse — already-unwrapped success value.
|
|
49
|
-
+ showSuccess(data.intent);
|
|
50
|
-
+ },
|
|
51
|
-
+ onError: (error) => {
|
|
52
|
-
+ showError(error);
|
|
53
|
-
+ },
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
`onSuccess` only fires on actual success now; `onError` fires on SDK failure. Move the failure logic to `onError`.
|
|
59
|
-
|
|
60
|
-
### Pattern 2: imperative `mutateAsync` → wrap in try/catch
|
|
61
|
-
|
|
62
|
-
```diff
|
|
63
|
-
const { mutateAsync: swap } = useSwap();
|
|
64
|
-
- const result = await swap({ params, spokeProvider });
|
|
65
|
-
- if (result.ok) {
|
|
66
|
-
- navigate('/done');
|
|
67
|
-
- } else {
|
|
68
|
-
- toast.error(result.error.message);
|
|
69
|
-
- }
|
|
70
|
-
+ try {
|
|
71
|
-
+ const result = await swap({ params, walletProvider });
|
|
72
|
-
+ navigate('/done');
|
|
73
|
-
+ } catch (e) {
|
|
74
|
-
+ toast.error(e instanceof Error ? e.message : 'Swap failed');
|
|
75
|
-
+ }
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
v2's `mutateAsync` rejects on SDK `!ok` — `try/catch` is mandatory. If you forget `try/catch`, an unhandled rejection lands in the global handler.
|
|
79
|
-
|
|
80
|
-
### Pattern 3: imperative `mutateAsync` → use `mutateAsyncSafe` (recommended)
|
|
81
|
-
|
|
82
|
-
If you prefer the v1 `Result<T>` ergonomics without exception flow, use `mutateAsyncSafe` — it never rejects:
|
|
83
|
-
|
|
84
|
-
```diff
|
|
85
|
-
- const { mutateAsync: swap } = useSwap();
|
|
86
|
-
- const result = await swap({ params, spokeProvider });
|
|
87
|
-
- if (result.ok) {
|
|
88
|
-
- navigate('/done');
|
|
89
|
-
- } else {
|
|
90
|
-
- toast.error(result.error.message);
|
|
91
|
-
- }
|
|
92
|
-
+ const { mutateAsyncSafe: swap } = useSwap();
|
|
93
|
-
+ const result = await swap({ params, walletProvider });
|
|
94
|
-
+ if (!result.ok) {
|
|
95
|
-
+ toast.error(result.error instanceof Error ? result.error.message : 'Swap failed');
|
|
96
|
-
+ return;
|
|
97
|
-
+ }
|
|
98
|
-
+ navigate('/done');
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
`mutateAsyncSafe` re-packs the throw inside `mutationFn` back into `Result<TData>`. Same React Query state under the hood (`isError`, `error`, devtools all work). Recommended for sequenced flows.
|
|
102
|
-
|
|
103
|
-
### Pattern 4: sequenced flow (approve + execute)
|
|
104
|
-
|
|
105
|
-
```diff
|
|
106
|
-
- // v1: branch on every step
|
|
107
|
-
- const result1 = await approve({ params, spokeProvider });
|
|
108
|
-
- if (!result1.ok) { toast(result1.error); return; }
|
|
109
|
-
- const result2 = await action({ params, spokeProvider });
|
|
110
|
-
- if (!result2.ok) { toast(result2.error); return; }
|
|
111
|
-
- navigate('/done');
|
|
112
|
-
|
|
113
|
-
+ // v2: same shape, but Result is from mutateAsyncSafe; walletProvider in mutate(vars)
|
|
114
|
-
+ const result1 = await approve({ params, walletProvider });
|
|
115
|
-
+ if (!result1.ok) { toast(result1.error.message); return; }
|
|
116
|
-
+ const result2 = await action({ params, walletProvider });
|
|
117
|
-
+ if (!result2.ok) { toast(result2.error.message); return; }
|
|
118
|
-
+ navigate('/done');
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
Just swap `mutateAsync` → `mutateAsyncSafe` and `spokeProvider` → `walletProvider`. The branching pattern stays nearly identical — same `result.ok` check.
|
|
122
|
-
|
|
123
|
-
## Edge case: `data` consumed in render
|
|
124
|
-
|
|
125
|
-
```diff
|
|
126
|
-
function SwapResult() {
|
|
127
|
-
const { data, isError } = useSwap();
|
|
128
|
-
- if (data?.ok) return <p>Success: {data.value.intent.intentHash}</p>;
|
|
129
|
-
- if (data && !data.ok) return <p>Error: {data.error.message}</p>;
|
|
130
|
-
+ const { data, error, isError } = useSwap();
|
|
131
|
-
+ if (data) return <p>Success: {data.intent.intentHash}</p>;
|
|
132
|
-
+ if (isError && error) return <p>Error: {error.message}</p>;
|
|
133
|
-
return null;
|
|
134
|
-
}
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
`data` is the unwrapped success value or `undefined`. `error` is the SDK error (or `null`). `isError` is the React Query flag.
|
|
138
|
-
|
|
139
|
-
## Edge case: `mutation.error` consumers
|
|
140
|
-
|
|
141
|
-
In v1, `mutation.error` only fired for actual exceptions (e.g. missing `walletProvider`, invalid input). In v2, it ALSO fires for SDK `!ok`. Audit all places that read `mutation.error` to ensure the new firings are appropriate.
|
|
142
|
-
|
|
143
|
-
```ts
|
|
144
|
-
// @ai-snippets-skip
|
|
145
|
-
// v1: error was rare (only thrown exceptions)
|
|
146
|
-
{mutation.error && <p>Unexpected error: {mutation.error.message}</p>}
|
|
147
|
-
|
|
148
|
-
// v2: error includes SDK !ok
|
|
149
|
-
// You may want to distinguish, e.g. check isSodaxError(error)
|
|
150
|
-
{mutation.error && (
|
|
151
|
-
isSodaxError(mutation.error)
|
|
152
|
-
? <p>SDK error ({mutation.error.code}): {mutation.error.message}</p>
|
|
153
|
-
: <p>Unexpected error: {mutation.error.message}</p>
|
|
154
|
-
)}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
`isSodaxError` is exported from `@sodax/dapp-kit` (re-exported from `@sodax/sdk`).
|
|
158
|
-
|
|
159
|
-
## Edge case: query hooks returning `Result<T>` as data
|
|
160
|
-
|
|
161
|
-
A small set of query hooks for SDK methods that can fail in expected ways (e.g. quote unavailable, status not yet known) surface the `Result<T>` directly to the consumer as `data` rather than unwrapping. This is intentional — read failures are part of the data flow, not exception flow.
|
|
162
|
-
|
|
163
|
-
**Result-wrapped query hooks** (data is `Result<T> | undefined` — branch on `data?.ok`):
|
|
164
|
-
|
|
165
|
-
```tsx
|
|
166
|
-
// @ai-snippets-skip
|
|
167
|
-
// useQuote — SDK request goes under params.payload
|
|
168
|
-
const { data: quoteResult } = useQuote({ params: { payload: quotePayload } });
|
|
169
|
-
if (quoteResult?.ok) {
|
|
170
|
-
const quote = quoteResult.value;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// useStatus — key is `intentTxHash`, NOT `intentHash`
|
|
174
|
-
const { data: statusResult } = useStatus({ params: { intentTxHash } });
|
|
175
|
-
if (statusResult?.ok) {
|
|
176
|
-
const status = statusResult.value;
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
**Most other query hooks unwrap** the SDK Result inside the hook (`if (!result.ok) throw result.error`), so `data` is the success value directly and React Query's native error model (`isError`/`error`/`onError`/`retry`) engages on SDK failure. Examples:
|
|
181
|
-
|
|
182
|
-
```tsx
|
|
183
|
-
// @ai-snippets-skip
|
|
184
|
-
// useStakingInfo, useUnstakingInfo, useUnstakingInfoWithPenalty,
|
|
185
|
-
// useStakingConfig, useStakeRatio, useInstantUnstakeRatio, useConvertedAssets,
|
|
186
|
-
// all three staking allowance hooks (useStakeAllowance/useUnstakeAllowance/useInstantUnstakeAllowance),
|
|
187
|
-
// useMMAllowance, useSwapAllowance, useDexAllowance,
|
|
188
|
-
// all MM reserves + position hooks, all DEX read hooks except where noted —
|
|
189
|
-
// data is the unwrapped value. NO `.ok` / `.value` branching.
|
|
190
|
-
const { data: info, isError, error } = useStakingInfo({ params: { srcAddress, srcChainKey } });
|
|
191
|
-
// info is StakingInfo | undefined — read fields directly: info?.totalStaked
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
**`useBridgeAllowance` is special** — it returns `false` on SDK `!ok` (does NOT throw). The data is still `boolean | undefined`, just biased toward "not approved" on lookup error.
|
|
195
|
-
|
|
196
|
-
For per-hook truth, check the per-feature reference (`integration/features/<x>.md`).
|
|
197
|
-
|
|
198
|
-
## Done criteria for this category
|
|
199
|
-
|
|
200
|
-
- [ ] No `data.ok` checks inside mutation `onSuccess` callbacks.
|
|
201
|
-
- [ ] No `result.ok` branching after `mutateAsync(...)` (it now throws — either `try/catch` or use `mutateAsyncSafe`).
|
|
202
|
-
- [ ] All `mutateAsync` calls are wrapped in `try/catch` OR replaced with `mutateAsyncSafe`.
|
|
203
|
-
- [ ] `onError` callbacks audit — they now fire for SDK `!ok` (which they didn't before).
|
|
204
|
-
- [ ] Mutation `mutation.error` reads — same audit.
|
|
205
|
-
|
|
206
|
-
## Cross-references
|
|
207
|
-
|
|
208
|
-
- [`hook-signatures.md`](hook-signatures.md) — the structural changes (provider stack, hook shapes, approve returns).
|
|
209
|
-
- [`../../integration/recipes/mutation-error-handling.md`](../../integration/recipes/mutation-error-handling.md) — full v2 patterns for picking call shapes.
|
|
210
|
-
- [`../../integration/architecture.md`](../../integration/architecture.md) § "SDK Result handling" — full design rationale.
|
|
211
|
-
- [`../../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md`](../../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md) — SDK-side `Result<T>` migration (the underlying contract that dapp-kit translates).
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
# SDK leakage — v1 → v2
|
|
2
|
-
|
|
3
|
-
Some v1 dapp-kit migration items are really *SDK* migrations that surface through dapp-kit's hook signatures. Each is documented in detail in the SDK's migration tree — this file summarizes what you'll see at the dapp-kit layer and links out for the full picture.
|
|
4
|
-
|
|
5
|
-
## chain-key terminology
|
|
6
|
-
|
|
7
|
-
The SDK renamed `xChainId` / `srcChainId` / `dstChainId` to `chainKey` / `srcChainKey` / `dstChainKey` on token shapes and request params. In dapp-kit, this surfaces in:
|
|
8
|
-
|
|
9
|
-
```diff
|
|
10
|
-
- // useGetBridgeableTokens — v1 took chain ids
|
|
11
|
-
- useGetBridgeableTokens(BASE_MAINNET_CHAIN_ID, POLYGON_MAINNET_CHAIN_ID, '0x...');
|
|
12
|
-
+ // v2 takes chain keys via the canonical query shape
|
|
13
|
-
+ useGetBridgeableTokens({ params: { from: ChainKeys.BASE_MAINNET, to: ChainKeys.POLYGON_MAINNET, token: '0x...' } });
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```diff
|
|
17
|
-
- // bridge params — v1
|
|
18
|
-
- await bridge({ params: { srcChainId: BASE_MAINNET_CHAIN_ID, dstChainId: POLYGON_MAINNET_CHAIN_ID, /* ... */ } });
|
|
19
|
-
+ // v2
|
|
20
|
-
+ await bridge({ params: { srcChainKey: ChainKeys.BASE_MAINNET, dstChainKey: ChainKeys.POLYGON_MAINNET, /* ... */ }, walletProvider });
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
```diff
|
|
24
|
-
- // XToken read shape — v1
|
|
25
|
-
- const chainId = token.xChainId;
|
|
26
|
-
+ // v2
|
|
27
|
-
+ const chainKey = token.chainKey;
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Note:** `useXBalances` request params still take `xChainId` (the field name stayed for the cross-chain abstraction it overlays). This is distinct from the renamed token-side `chainKey`. Don't conflate them.
|
|
31
|
-
|
|
32
|
-
**Note:** `Intent.srcChain` / `Intent.dstChain` (read shape) kept their names. They're `IntentRelayChainId` (bigints), distinct from request-side `srcChainKey` / `dstChainKey`. Don't blanket grep-replace.
|
|
33
|
-
|
|
34
|
-
Full SDK-level detail: [`../../../../sdk/ai-exported/migration/breaking-changes/type-system.md`](../../../../sdk/ai-exported/migration/breaking-changes/type-system.md).
|
|
35
|
-
|
|
36
|
-
## Required `srcChainKey` + `srcAddress` on action params
|
|
37
|
-
|
|
38
|
-
v1 mutation params were minimal (`{ token, amount, action }`). v2 added required `srcChainKey` + `srcAddress` to every feature's action params. The chain key drives spoke routing internally; the address is the user's spoke-side address.
|
|
39
|
-
|
|
40
|
-
```diff
|
|
41
|
-
- // v1
|
|
42
|
-
- await supply({ params: { token, amount, action: 'supply' } });
|
|
43
|
-
+ // v2
|
|
44
|
-
+ await supply({
|
|
45
|
-
+ params: {
|
|
46
|
-
+ srcChainKey: ChainKeys.BASE_MAINNET,
|
|
47
|
-
+ srcAddress: '0x...', // NEW: required
|
|
48
|
-
+ token,
|
|
49
|
-
+ amount,
|
|
50
|
-
+ action: 'supply',
|
|
51
|
-
+ },
|
|
52
|
-
+ walletProvider,
|
|
53
|
-
+ });
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Same applies to `useBorrow`, `useWithdraw`, `useRepay`, `useStake`, `useUnstake`, `useBridge`, `useDexDeposit`, `useDexWithdraw`, etc. — anywhere the SDK now requires it.
|
|
57
|
-
|
|
58
|
-
Full SDK-level detail: [`../../../../sdk/ai-exported/migration/features/`](../../../../sdk/ai-exported/migration/features/) — each feature's migration file lists the required new fields.
|
|
59
|
-
|
|
60
|
-
## `*_MAINNET_CHAIN_ID` constants gone
|
|
61
|
-
|
|
62
|
-
v1 exported individual constants (`BSC_MAINNET_CHAIN_ID`, `BASE_MAINNET_CHAIN_ID`, etc.). v2 replaces them with the `ChainKeys.*` namespace.
|
|
63
|
-
|
|
64
|
-
```diff
|
|
65
|
-
- import { BSC_MAINNET_CHAIN_ID, BASE_MAINNET_CHAIN_ID } from '@sodax/sdk';
|
|
66
|
-
+ import { ChainKeys } from '@sodax/sdk';
|
|
67
|
-
|
|
68
|
-
- const chainKey = BSC_MAINNET_CHAIN_ID;
|
|
69
|
-
+ const chainKey = ChainKeys.BSC_MAINNET;
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
Codemod with sed:
|
|
73
|
-
|
|
74
|
-
```bash
|
|
75
|
-
find src -type f \( -name '*.ts' -o -name '*.tsx' \) | xargs sed -i '' -E 's/\b([A-Z_]+)_MAINNET_CHAIN_ID\b/ChainKeys.\1_MAINNET/g'
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
Then add `import { ChainKeys } from '@sodax/sdk'` (or `@sodax/dapp-kit`) where needed.
|
|
79
|
-
|
|
80
|
-
Full SDK-level detail: [`../../../../sdk/ai-exported/migration/breaking-changes/type-system.md`](../../../../sdk/ai-exported/migration/breaking-changes/type-system.md).
|
|
81
|
-
|
|
82
|
-
## `SodaxConfig` reshape — `rpcConfig` → `chains`
|
|
83
|
-
|
|
84
|
-
`SodaxProvider`'s config prop is `DeepPartial<SodaxConfig>`. The SDK renamed/restructured the config:
|
|
85
|
-
|
|
86
|
-
```diff
|
|
87
|
-
- <SodaxProvider rpcConfig={{
|
|
88
|
-
- sonic: 'https://sonic-rpc.publicnode.com',
|
|
89
|
-
- '0xa86a.avax': 'https://...',
|
|
90
|
-
- }}>
|
|
91
|
-
+ <SodaxProvider config={{
|
|
92
|
-
+ chains: {
|
|
93
|
-
+ [ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://sonic-rpc.publicnode.com' },
|
|
94
|
-
+ [ChainKeys.AVALANCHE_MAINNET]: { rpcUrl: 'https://...' },
|
|
95
|
-
+ },
|
|
96
|
-
+ }}>
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
Other v1 fields renamed or restructured:
|
|
100
|
-
|
|
101
|
-
| v1 | v2 |
|
|
102
|
-
|---|---|
|
|
103
|
-
| `rpcConfig` | `chains[ChainKeys.X]: { rpcUrl }` |
|
|
104
|
-
| `backendApi: { url }` | `api: { baseURL }` |
|
|
105
|
-
| `swaps: { intentsContract, ... }` | Split: `solver: { intentsContract, ... }` for endpoints; `swaps: SwapsConfig` for supported tokens |
|
|
106
|
-
| `hubProviderConfig` | `hub: HubConfig` |
|
|
107
|
-
|
|
108
|
-
Full SDK-level detail: [`../../../../sdk/ai-exported/migration/breaking-changes/architecture.md`](../../../../sdk/ai-exported/migration/breaking-changes/architecture.md) (Appendix B).
|
|
109
|
-
|
|
110
|
-
## Error class
|
|
111
|
-
|
|
112
|
-
The SDK consolidated 7+ per-feature error classes (`MoneyMarketError<Code>`, `IntentError<Code>`, `StakingError<Code>`, `BridgeError<Code>`, `MigrationError<Code>`, etc.) into a single canonical `SodaxError<C>`.
|
|
113
|
-
|
|
114
|
-
If your dapp-kit consumer code catches errors from mutations and uses `instanceof XxxError`, those checks are now broken:
|
|
115
|
-
|
|
116
|
-
```diff
|
|
117
|
-
- // v1
|
|
118
|
-
- catch (e) {
|
|
119
|
-
- if (e instanceof MoneyMarketError) {
|
|
120
|
-
- console.error('MM-specific:', e.code);
|
|
121
|
-
- }
|
|
122
|
-
- }
|
|
123
|
-
|
|
124
|
-
+ // v2
|
|
125
|
-
+ catch (e) {
|
|
126
|
-
+ if (isSodaxError(e) && e.feature === 'moneyMarket') {
|
|
127
|
-
+ console.error('MM-specific:', e.code);
|
|
128
|
-
+ }
|
|
129
|
-
+ }
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
`isSodaxError` is re-exported from `@sodax/dapp-kit`. Discriminate via `(error.feature, error.code)` — the feature is now a first-class field, and the code vocabulary is unified to 13 reason-only codes.
|
|
133
|
-
|
|
134
|
-
Full SDK-level detail: [`../../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md`](../../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md).
|
|
135
|
-
|
|
136
|
-
## `Result<T>` type and propagation
|
|
137
|
-
|
|
138
|
-
The SDK's `Result<T>` type is the same in v1 and v2. What changed is **where it's returned vs unwrapped**:
|
|
139
|
-
|
|
140
|
-
| | v1 | v2 |
|
|
141
|
-
|---|---|---|
|
|
142
|
-
| SDK service method return | `Result<T>` | `Result<T>` (unchanged) |
|
|
143
|
-
| dapp-kit `mutationFn` return | `Result<T>` | unwrapped `T` (throws on `!ok`) |
|
|
144
|
-
| Consumer's `mutation.data` | `Result<T>` | unwrapped `T` |
|
|
145
|
-
|
|
146
|
-
So at the SDK level, `Result<T>` semantics didn't change. But at the dapp-kit level, the unwrap point moved into the hook. See [`result-handling.md`](result-handling.md) for the full picture.
|
|
147
|
-
|
|
148
|
-
## Other SDK-level migrations
|
|
149
|
-
|
|
150
|
-
These are unlikely to leak through hook signatures unless your app reaches into the SDK directly via `useSodaxContext()`:
|
|
151
|
-
|
|
152
|
-
- **`*SpokeProvider` classes deleted** — the chain key drives spoke routing; no provider classes to construct. dapp-kit consumers never see these (you'd already be using `useSpokeProvider` which is gone).
|
|
153
|
-
- **`ConfigService` replaces static lookup tables** — `hubAssets`, `moneyMarketSupportedTokens`, `SodaTokens` globals are gone. Use `sodax.config.*` (which dapp-kit's hooks already do internally).
|
|
154
|
-
- **`WalletProviderSlot<K, Raw>` discriminated union** — a TypeScript-level construct; `walletProvider` is the typical consumer-facing shape.
|
|
155
|
-
|
|
156
|
-
For the full SDK migration playbook, start at [`../../../../sdk/ai-exported/migration/README.md`](../../../../sdk/ai-exported/migration/README.md).
|
|
157
|
-
|
|
158
|
-
## Cross-references
|
|
159
|
-
|
|
160
|
-
- [`../../../../sdk/ai-exported/migration/README.md`](../../../../sdk/ai-exported/migration/README.md) — full SDK migration overview.
|
|
161
|
-
- [`../../../../sdk/ai-exported/migration/breaking-changes/type-system.md`](../../../../sdk/ai-exported/migration/breaking-changes/type-system.md) — type renames + ChainKeys.
|
|
162
|
-
- [`../../../../sdk/ai-exported/migration/breaking-changes/architecture.md`](../../../../sdk/ai-exported/migration/breaking-changes/architecture.md) — `*SpokeProvider`, ConfigService, SodaxConfig reshape.
|
|
163
|
-
- [`../../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md`](../../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md) — `Result<T>` + error class consolidation.
|
|
164
|
-
- [`hook-signatures.md`](hook-signatures.md) — dapp-kit-only hook-shape changes.
|
|
165
|
-
- [`result-handling.md`](result-handling.md) — dapp-kit-only `Result<T>` unwrap-point shift.
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# Migration checklist — `@sodax/dapp-kit` v1 → v2
|
|
2
|
-
|
|
3
|
-
Top-down cross-cutting checklist. Walk it in order — each step makes later ones tractable.
|
|
4
|
-
|
|
5
|
-
## Phase 1 — provider stack and imports
|
|
6
|
-
|
|
7
|
-
- [ ] **Update `SodaxProvider` config shape.** `rpcConfig: { sonic: '...', ... }` → `chains: { [ChainKeys.SONIC_MAINNET]: { rpcUrl: '...' } }`. See [`breaking-changes/hook-signatures.md`](breaking-changes/hook-signatures.md) § Provider stack.
|
|
8
|
-
- [ ] **Replace `new QueryClient()` with `createSodaxQueryClient()`** (optional but recommended — gives you global mutation observability).
|
|
9
|
-
- [ ] **Drop any `@sodax/types` dependency** from `package.json`. Re-exported via `@sodax/sdk` (which dapp-kit re-exports). Run `pnpm install` after.
|
|
10
|
-
- [ ] **Import statement codemod.**
|
|
11
|
-
- `useSpokeProvider` import → delete the import line.
|
|
12
|
-
- `BSC_MAINNET_CHAIN_ID` (and the 14 other `*_MAINNET_CHAIN_ID` constants) → `ChainKeys.X_MAINNET`.
|
|
13
|
-
- Any deep-import from `@sodax/dapp-kit/dist/...` → import from `@sodax/dapp-kit` root.
|
|
14
|
-
|
|
15
|
-
## Phase 2 — mechanical sweeps
|
|
16
|
-
|
|
17
|
-
- [ ] **Delete every `useSpokeProvider(...)` call.** The `walletProvider` from `useWalletProvider({ xChainId: chainKey })` flows directly into `mutate(vars)`. See [`reference/deleted-hooks.md`](reference/deleted-hooks.md).
|
|
18
|
-
- [ ] **`*_MAINNET_CHAIN_ID` → `ChainKeys.X_MAINNET`.** Codemod with sed:
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
find src -type f \( -name '*.ts' -o -name '*.tsx' \) | xargs sed -i '' -E 's/\b([A-Z_]+)_MAINNET_CHAIN_ID\b/ChainKeys.\1_MAINNET/g'
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
- [ ] **`xChainId` → `chainKey` on `XToken`.** Be careful — only on the read shape. The `useXBalances` hook still takes `xChainId` as a request param (intentional naming for the cross-chain abstraction). See [`breaking-changes/sdk-leakage.md`](breaking-changes/sdk-leakage.md).
|
|
25
|
-
|
|
26
|
-
## Phase 3 — hook-call-site rewrites (per feature)
|
|
27
|
-
|
|
28
|
-
For each feature your app uses, walk the matching `migration/features/<feature>.md`:
|
|
29
|
-
|
|
30
|
-
- [ ] [`features/swap.md`](features/swap.md) — swap call sites.
|
|
31
|
-
- [ ] [`features/money-market.md`](features/money-market.md) — supply / borrow / withdraw / repay.
|
|
32
|
-
- [ ] [`features/staking.md`](features/staking.md) — stake / unstake / claim.
|
|
33
|
-
- [ ] [`features/bridge.md`](features/bridge.md) — bridge.
|
|
34
|
-
- [ ] [`features/dex.md`](features/dex.md) — deposit / supply liquidity / etc.
|
|
35
|
-
- [ ] [`features/migration.md`](features/migration.md) — ICX / bnUSD / BALN. **Note:** v1's `useMigrate(spokeProvider)` is gone; v2 has 6 per-action hooks.
|
|
36
|
-
- [ ] [`features/bitcoin.md`](features/bitcoin.md) — Radfi.
|
|
37
|
-
- [ ] [`features/auxiliary-services.md`](features/auxiliary-services.md) — partner, recovery, backend queries, shared utilities.
|
|
38
|
-
|
|
39
|
-
The cross-cutting pattern at every call site:
|
|
40
|
-
|
|
41
|
-
1. **Hook init**: `useFoo(spokeProvider, params)` → `useFoo()` or `useFoo({ mutationOptions })`. No domain inputs at hook init.
|
|
42
|
-
2. **Mutation invocation**: `mutate(spokeProvider)` or `mutate()` → `mutate({ params, walletProvider })`. ALL domain inputs flow through here.
|
|
43
|
-
3. **Approve hooks**: `const { approve, isLoading } = useFooApprove(spokeProvider)` → `const { mutateAsync: approve, isPending } = useFooApprove()`.
|
|
44
|
-
4. **Query hooks**: `useFoo(arg1, arg2)` → `useFoo({ params: { ... }, queryOptions: { ... } })`.
|
|
45
|
-
|
|
46
|
-
## Phase 4 — Result<T> handling
|
|
47
|
-
|
|
48
|
-
- [ ] **Mutation success-path branching.** v1: `onSuccess: (data) => { if (data.ok) ... }`. v2: drop the `.ok` check; `data` is unwrapped success (e.g. `SwapResponse`, `TxHashPair`).
|
|
49
|
-
- [ ] **Convert imperative `mutateAsync` calls.** Wrap in `try/catch` (v2 throws on `!ok`) OR switch to `mutateAsyncSafe` and branch on `result.ok`. See [`breaking-changes/result-handling.md`](breaking-changes/result-handling.md).
|
|
50
|
-
- [ ] **Audit `onError` callbacks.** They now fire for SDK `!ok` (didn't in v1). Check that any error-toast logic is appropriate.
|
|
51
|
-
|
|
52
|
-
## Phase 5 — invalidations
|
|
53
|
-
|
|
54
|
-
- [ ] **Delete `invalidate*Queries` utility files.** Hook-owned in v2; no consumer-side invalidation needed.
|
|
55
|
-
- [ ] **Drop manual `queryClient.invalidateQueries(...)` calls** that mirror what dapp-kit hooks already do (e.g. `xBalances` after a swap).
|
|
56
|
-
- [ ] **Keep ONLY the cross-feature invalidations** that dapp-kit hooks don't know about (e.g. your custom analytics view query).
|
|
57
|
-
- [ ] **If you have consumer wrappers around dapp-kit mutations**, ensure they don't double-invalidate. Move custom invalidations to the wrapper's `mutationOptions.onSuccess`.
|
|
58
|
-
|
|
59
|
-
## Phase 6 — queryKey alignment (optional but recommended)
|
|
60
|
-
|
|
61
|
-
If your code grafts onto dapp-kit's cache invalidation (e.g. you fetch a related query and want it to be invalidated by dapp-kit's mutation), align your queryKeys with dapp-kit conventions:
|
|
62
|
-
|
|
63
|
-
- [ ] **First segment = feature directory name.** `'swap'`, `'mm'`, `'bridge'`, etc. See [`../integration/reference/querykey-conventions.md`](../integration/reference/querykey-conventions.md).
|
|
64
|
-
- [ ] **camelCase segments.** No kebab-case.
|
|
65
|
-
- [ ] **Bigints stringified** in keys.
|
|
66
|
-
|
|
67
|
-
## Phase 7 — SDK-level migrations leaking through
|
|
68
|
-
|
|
69
|
-
These are SDK-level changes that surface in dapp-kit hook signatures or types. Refer to the SDK migration tree for full detail:
|
|
70
|
-
|
|
71
|
-
- [ ] **Chain-key terminology** — `xChainId` / `srcChainId` / `dstChainId` on action params → `chainKey` / `srcChainKey` / `dstChainKey`. See [`../../../sdk/ai-exported/migration/breaking-changes/type-system.md`](../../../sdk/ai-exported/migration/breaking-changes/type-system.md).
|
|
72
|
-
- [ ] **SodaxConfig reshape** — flat `rpcConfig` → nested `chains[ChainKeys.X]: { rpcUrl }`. See [`../../../sdk/ai-exported/migration/breaking-changes/architecture.md`](../../../sdk/ai-exported/migration/breaking-changes/architecture.md).
|
|
73
|
-
- [ ] **Error class** — `MoneyMarketError<Code>` etc. → single `SodaxError<C>`. See [`../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md`](../../../sdk/ai-exported/migration/breaking-changes/result-and-errors.md). dapp-kit consumers see this only if they directly reference SDK error classes.
|
|
74
|
-
|
|
75
|
-
## Phase 8 — verification
|
|
76
|
-
|
|
77
|
-
- [ ] `pnpm tsc --noEmit` is clean.
|
|
78
|
-
- [ ] Smoke-test each feature your app uses: connect wallet, run one mutation, observe success + state updates.
|
|
79
|
-
- [ ] Search for v1 leftovers: `grep -rE '\buseSpokeProvider\b|\binvalidateMmQueries\b|_MAINNET_CHAIN_ID\b'` returns zero hits.
|
|
80
|
-
- [ ] Confirm `mutateAsync` calls are wrapped in `try/catch` OR replaced with `mutateAsyncSafe`.
|
|
81
|
-
- [ ] Confirm provider stack uses `chains: ...` not `rpcConfig: ...`.
|
|
82
|
-
|
|
83
|
-
## Cross-references
|
|
84
|
-
|
|
85
|
-
- [`README.md`](README.md) — overview and v1↔v2 glossary.
|
|
86
|
-
- [`ai-rules.md`](ai-rules.md) — DO / DO NOT for the agent doing the migration.
|
|
87
|
-
- [`breaking-changes/`](breaking-changes/) — cross-cutting v1→v2 deltas (hook signatures, result handling, queryKey, SDK leakage).
|
|
88
|
-
- [`recipes.md`](recipes.md) — codemods and adapters.
|
|
89
|
-
- [`features/`](features/) — per-feature porting playbooks.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Migration features — `@sodax/dapp-kit` v1 → v2
|
|
2
|
-
|
|
3
|
-
Per-feature porting playbooks. Each file shows the v1 → v2 delta for one feature's hook surface, with concrete code diffs.
|
|
4
|
-
|
|
5
|
-
| File | What's covered |
|
|
6
|
-
|---|---|
|
|
7
|
-
| [`swap.md`](swap.md) | v1 `useSwap(spokeProvider)`-style call sites → v2 `mutate({ params, walletProvider })`. Approve return shape change. Result handling. |
|
|
8
|
-
| [`money-market.md`](money-market.md) | v1 supply/borrow/withdraw/repay → v2 same with `srcChainKey`/`srcAddress` required. Allowance auto-skip for borrow/withdraw. |
|
|
9
|
-
| [`staking.md`](staking.md) | All five mutations + their dedicated approve hooks. `useStakeRatio` returns a tuple in v2. |
|
|
10
|
-
| [`bridge.md`](bridge.md) | Field renames in `useBridge` params (`srcChainId` → `srcChainKey`, `recipient` → `dstAddress`). `useGetBridgeableAmount` shape change. |
|
|
11
|
-
| [`dex.md`](dex.md) | Two-step flow stayed the same; field renames + `srcChainKey` requirement. `useSupplyLiquidity` mint/increase routing. |
|
|
12
|
-
| [`migration.md`](migration.md) | **Biggest change**: v1's `useMigrate(spokeProvider)` → 6 per-action hooks. |
|
|
13
|
-
| [`bitcoin.md`](bitcoin.md) | Radfi flow shapes are mostly unchanged; provider/session lifecycle hooks tightened. |
|
|
14
|
-
| [`auxiliary-services.md`](auxiliary-services.md) | Partner / recovery / backend queries / shared utilities — small per-hook changes. |
|
|
15
|
-
|
|
16
|
-
## Pair-completeness
|
|
17
|
-
|
|
18
|
-
Every file in this directory has a sibling in [`../../integration/features/`](../../integration/features/) with the same filename — the v2 design context for that feature. When you're stuck in one, the other is one path-swap away.
|
|
19
|
-
|
|
20
|
-
## Cross-cutting prerequisites
|
|
21
|
-
|
|
22
|
-
Before reading a feature playbook, make sure you've already read the cross-cutting deltas:
|
|
23
|
-
|
|
24
|
-
- [`../breaking-changes/hook-signatures.md`](../breaking-changes/hook-signatures.md) — provider stack, hook init shapes, approve return.
|
|
25
|
-
- [`../breaking-changes/result-handling.md`](../breaking-changes/result-handling.md) — `Result<T>` semantic shift.
|
|
26
|
-
- [`../breaking-changes/sdk-leakage.md`](../breaking-changes/sdk-leakage.md) — `srcChainKey`/`srcAddress` required, chain-key terminology, etc.
|
|
27
|
-
|
|
28
|
-
The per-feature files below are about the *feature-specific* delta on top of those cross-cutting changes.
|
|
29
|
-
|
|
30
|
-
## Cross-references
|
|
31
|
-
|
|
32
|
-
- [`../README.md`](../README.md) — migration overview + glossary.
|
|
33
|
-
- [`../checklist.md`](../checklist.md) — top-down checklist.
|
|
34
|
-
- [`../ai-rules.md`](../ai-rules.md) — DO / DO NOT for the porting agent.
|