@sodax/dapp-kit 2.0.0-rc.3 → 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 (61) hide show
  1. package/README.md +9 -63
  2. package/dist/index.mjs +0 -2
  3. package/package.json +31 -20
  4. package/ai-exported/AGENTS.md +0 -134
  5. package/ai-exported/integration/README.md +0 -49
  6. package/ai-exported/integration/ai-rules.md +0 -80
  7. package/ai-exported/integration/architecture.md +0 -276
  8. package/ai-exported/integration/features/README.md +0 -29
  9. package/ai-exported/integration/features/auxiliary-services.md +0 -169
  10. package/ai-exported/integration/features/bitcoin.md +0 -87
  11. package/ai-exported/integration/features/bridge.md +0 -91
  12. package/ai-exported/integration/features/dex.md +0 -152
  13. package/ai-exported/integration/features/migration.md +0 -118
  14. package/ai-exported/integration/features/money-market.md +0 -144
  15. package/ai-exported/integration/features/staking.md +0 -123
  16. package/ai-exported/integration/features/swap.md +0 -101
  17. package/ai-exported/integration/quickstart.md +0 -187
  18. package/ai-exported/integration/recipes/README.md +0 -136
  19. package/ai-exported/integration/recipes/backend-queries.md +0 -157
  20. package/ai-exported/integration/recipes/bitcoin.md +0 -193
  21. package/ai-exported/integration/recipes/bridge.md +0 -174
  22. package/ai-exported/integration/recipes/dex.md +0 -204
  23. package/ai-exported/integration/recipes/invalidations.md +0 -115
  24. package/ai-exported/integration/recipes/migration.md +0 -212
  25. package/ai-exported/integration/recipes/money-market.md +0 -207
  26. package/ai-exported/integration/recipes/mutation-error-handling.md +0 -118
  27. package/ai-exported/integration/recipes/observability.md +0 -93
  28. package/ai-exported/integration/recipes/setup.md +0 -168
  29. package/ai-exported/integration/recipes/staking.md +0 -202
  30. package/ai-exported/integration/recipes/swap.md +0 -272
  31. package/ai-exported/integration/recipes/wallet-connectivity.md +0 -128
  32. package/ai-exported/integration/reference/README.md +0 -12
  33. package/ai-exported/integration/reference/glossary.md +0 -190
  34. package/ai-exported/integration/reference/hooks-index.md +0 -190
  35. package/ai-exported/integration/reference/public-api.md +0 -110
  36. package/ai-exported/integration/reference/querykey-conventions.md +0 -179
  37. package/ai-exported/migration/README.md +0 -60
  38. package/ai-exported/migration/ai-rules.md +0 -81
  39. package/ai-exported/migration/breaking-changes/hook-signatures.md +0 -233
  40. package/ai-exported/migration/breaking-changes/querykey-conventions.md +0 -108
  41. package/ai-exported/migration/breaking-changes/result-handling.md +0 -211
  42. package/ai-exported/migration/breaking-changes/sdk-leakage.md +0 -167
  43. package/ai-exported/migration/checklist.md +0 -89
  44. package/ai-exported/migration/features/README.md +0 -34
  45. package/ai-exported/migration/features/auxiliary-services.md +0 -114
  46. package/ai-exported/migration/features/bitcoin.md +0 -88
  47. package/ai-exported/migration/features/bridge.md +0 -160
  48. package/ai-exported/migration/features/dex.md +0 -101
  49. package/ai-exported/migration/features/migration.md +0 -120
  50. package/ai-exported/migration/features/money-market.md +0 -139
  51. package/ai-exported/migration/features/staking.md +0 -109
  52. package/ai-exported/migration/features/swap.md +0 -133
  53. package/ai-exported/migration/recipes.md +0 -185
  54. package/ai-exported/migration/reference/README.md +0 -15
  55. package/ai-exported/migration/reference/deleted-hooks.md +0 -110
  56. package/ai-exported/migration/reference/error-shape-crosswalk.md +0 -144
  57. package/ai-exported/migration/reference/renamed-hooks.md +0 -68
  58. package/dist/index.cjs +0 -2641
  59. package/dist/index.cjs.map +0 -1
  60. package/dist/index.d.cts +0 -1557
  61. package/dist/index.mjs.map +0 -1
@@ -1,174 +0,0 @@
1
- # Recipe: Bridge
2
-
3
- Cross-chain token transfers via the hub-and-spoke vault architecture.
4
-
5
- **Depends on:** [setup.md](setup.md), [wallet-connectivity.md](wallet-connectivity.md)
6
-
7
- ## Hooks
8
-
9
- | Hook | Type | Purpose |
10
- |------|------|---------|
11
- | `useBridge` | Mutation | Execute a cross-chain bridge transfer |
12
- | `useBridgeAllowance` | Query | Check if token approval is needed |
13
- | `useBridgeApprove` | Mutation | Approve tokens for bridge |
14
- | `useGetBridgeableAmount` | Query | Available bridgeable amount between two tokens |
15
- | `useGetBridgeableTokens` | Query | Tokens bridgeable to a destination chain |
16
-
17
- ## Check Bridgeable Tokens
18
-
19
- ```tsx
20
- import { useGetBridgeableTokens } from '@sodax/dapp-kit';
21
- import { ChainKeys } from '@sodax/sdk';
22
-
23
- function BridgeableTokensList() {
24
- // `data` is `XToken[] | undefined` — the hook throws on SDK `!ok` so we get the unwrapped value.
25
- const { data: tokens } = useGetBridgeableTokens({
26
- params: { from: ChainKeys.BASE_MAINNET, to: ChainKeys.POLYGON_MAINNET, token: '0x0000000000000000000000000000000000000000' },
27
- });
28
-
29
- if (tokens) {
30
- return <ul>{tokens.map((t) => <li key={t.address}>{t.symbol}</li>)}</ul>;
31
- }
32
- return null;
33
- }
34
- ```
35
-
36
- ## Check Allowance + Approve
37
-
38
- ```tsx
39
- import { useBridgeAllowance, useBridgeApprove } from '@sodax/dapp-kit';
40
- import { useWalletProvider } from '@sodax/wallet-sdk-react';
41
- import { ChainKeys } from '@sodax/sdk';
42
- import type { CreateBridgeIntentParams } from '@sodax/sdk';
43
-
44
- function BridgeApproval({ params }: { params: CreateBridgeIntentParams }) {
45
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
46
- // useBridgeAllowance wraps payload + walletProvider under params (not at top level).
47
- const { data: isApproved } = useBridgeAllowance({
48
- params: { payload: params, walletProvider },
49
- });
50
- const { mutateAsync: approve, isPending } = useBridgeApprove();
51
-
52
- if (isApproved) return null;
53
- return (
54
- <button onClick={() => walletProvider && approve({ params, walletProvider })} disabled={isPending}>
55
- {isPending ? 'Approving...' : 'Approve for Bridge'}
56
- </button>
57
- );
58
- }
59
- ```
60
-
61
- ## Execute Bridge
62
-
63
- ```tsx
64
- import { useBridge } from '@sodax/dapp-kit';
65
- import { useWalletProvider } from '@sodax/wallet-sdk-react';
66
- import { ChainKeys } from '@sodax/sdk';
67
-
68
- function BridgeButton({ srcAddress }: { srcAddress: `0x${string}` }) {
69
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
70
- const { mutateAsync: bridge, isPending } = useBridge();
71
-
72
- const handleBridge = async () => {
73
- if (!walletProvider) return;
74
- try {
75
- const { srcChainTxHash, dstChainTxHash } = await bridge({
76
- params: {
77
- srcChainKey: ChainKeys.BASE_MAINNET,
78
- srcAddress,
79
- srcToken: '0x0000000000000000000000000000000000000000',
80
- amount: 1000000000000000000n,
81
- dstChainKey: ChainKeys.POLYGON_MAINNET,
82
- dstToken: '0x0000000000000000000000000000000000000000',
83
- recipient: '0x0000000000000000000000000000000000000000',
84
- },
85
- walletProvider,
86
- });
87
- console.log('Bridge successful:', { srcChainTxHash, dstChainTxHash });
88
- } catch (e) {
89
- console.error(e);
90
- }
91
- };
92
-
93
- return (
94
- <button onClick={handleBridge} disabled={isPending}>
95
- {isPending ? 'Bridging...' : 'Bridge'}
96
- </button>
97
- );
98
- }
99
- ```
100
-
101
- ## Full Example
102
-
103
- ```tsx
104
- import { useState } from 'react';
105
- import { useBridge, useBridgeAllowance, useBridgeApprove, useGetBridgeableAmount } from '@sodax/dapp-kit';
106
- import { useWalletProvider } from '@sodax/wallet-sdk-react';
107
- import { ChainKeys, type XToken } from '@sodax/sdk';
108
- import type { CreateBridgeIntentParams } from '@sodax/sdk';
109
- import { parseUnits, formatUnits } from 'viem';
110
-
111
- export function BridgePage({ srcXToken, dstXToken, srcAddress }: { srcXToken: XToken; dstXToken: XToken; srcAddress: `0x${string}` }) {
112
- const [amount, setAmount] = useState('');
113
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
114
- const parsedAmount = amount ? parseUnits(amount, 6) : 0n;
115
-
116
- const bridgeParams: CreateBridgeIntentParams<typeof ChainKeys.BASE_MAINNET> | undefined = parsedAmount > 0n
117
- ? {
118
- srcChainKey: ChainKeys.BASE_MAINNET,
119
- srcAddress,
120
- srcToken: srcXToken.address,
121
- amount: parsedAmount,
122
- dstChainKey: ChainKeys.POLYGON_MAINNET,
123
- dstToken: dstXToken.address,
124
- recipient: '0x0000000000000000000000000000000000000000',
125
- }
126
- : undefined;
127
-
128
- // useGetBridgeableAmount in v2 takes a pair of XToken objects (each carries chainKey).
129
- // `data` is `BridgeLimit | undefined` (already unwrapped; hook throws on SDK !ok).
130
- const { data: bridgeableAmount } = useGetBridgeableAmount({
131
- params: { from: srcXToken, to: dstXToken },
132
- });
133
- const { data: isApproved } = useBridgeAllowance({
134
- params: bridgeParams ? { payload: bridgeParams, walletProvider } : undefined,
135
- });
136
- const { mutateAsyncSafe: approve, isPending: isApproving } = useBridgeApprove();
137
- const { mutateAsyncSafe: bridge, isPending: isBridging } = useBridge();
138
-
139
- const handleBridge = async () => {
140
- if (!bridgeParams || !walletProvider) return;
141
- if (!isApproved) {
142
- const r = await approve({ params: bridgeParams, walletProvider });
143
- if (!r.ok) { alert(r.error instanceof Error ? r.error.message : 'Approve failed'); return; }
144
- }
145
- const r = await bridge({ params: bridgeParams, walletProvider });
146
- if (r.ok) alert(`Bridge complete! src=${r.value.srcChainTxHash}`);
147
- else alert(r.error instanceof Error ? r.error.message : 'Bridge failed');
148
- };
149
-
150
- return (
151
- <div>
152
- <input placeholder="Amount" value={amount} onChange={(e) => setAmount(e.target.value)} />
153
- {bridgeableAmount && <p>Max: {formatUnits(bridgeableAmount.amount, bridgeableAmount.decimals)}</p>}
154
- <button onClick={handleBridge} disabled={isBridging || isApproving || !bridgeParams || !walletProvider}>
155
- {isApproving ? 'Approving...' : isBridging ? 'Bridging...' : 'Bridge'}
156
- </button>
157
- </div>
158
- );
159
- }
160
- ```
161
-
162
- ## Types
163
-
164
- ```typescript
165
- type CreateBridgeIntentParams<K extends SpokeChainKey = SpokeChainKey> = {
166
- srcChainKey: K;
167
- srcAddress: string;
168
- srcToken: string;
169
- amount: bigint;
170
- dstChainKey: SpokeChainKey;
171
- dstToken: string;
172
- recipient: string; // non-encoded recipient address on the destination chain
173
- };
174
- ```
@@ -1,204 +0,0 @@
1
- # Recipe: DEX
2
-
3
- Concentrated liquidity positions and asset management.
4
-
5
- **Depends on:** [setup.md](setup.md), [wallet-connectivity.md](wallet-connectivity.md)
6
-
7
- ## Hooks
8
-
9
- ### Assets
10
-
11
- | Hook | Type | Purpose |
12
- |------|------|---------|
13
- | `useDexDeposit` | Mutation | Deposit assets into pool tokens |
14
- | `useDexWithdraw` | Mutation | Withdraw assets from pool tokens |
15
- | `useDexAllowance` | Query | Check approval for deposit |
16
- | `useDexApprove` | Mutation | Approve tokens |
17
- | `usePoolBalances` | Query | User's pool token balances |
18
-
19
- ### Liquidity
20
-
21
- | Hook | Type | Purpose |
22
- |------|------|---------|
23
- | `useSupplyLiquidity` | Mutation | Supply liquidity to a position |
24
- | `useDecreaseLiquidity` | Mutation | Remove liquidity |
25
- | `useClaimRewards` | Mutation | Claim trading fees |
26
- | `usePools` | Query | List available pools |
27
- | `usePoolData` | Query | Pool details (price, tick, liquidity) |
28
- | `usePositionInfo` | Query | Position details |
29
- | `useLiquidityAmounts` | Query | Token amounts for a tick range |
30
-
31
- ### Param Builders
32
-
33
- | Hook | Purpose |
34
- |------|---------|
35
- | `useCreateDepositParams` | Build deposit params with ERC-4626 conversion |
36
- | `useCreateWithdrawParams` | Build withdraw params |
37
- | `useCreateSupplyLiquidityParams` | Build tick range + liquidity params |
38
- | `useCreateDecreaseLiquidityParams` | Build decrease params from position state |
39
-
40
- ## List Pools
41
-
42
- ```tsx
43
- import { usePools } from '@sodax/dapp-kit';
44
-
45
- function PoolsList() {
46
- // `usePools` returns `PoolKey[]` — pool keys carry `currency0`, `currency1`, `fee`,
47
- // `hooks`, `poolManager`, and `parameters`. Resolve token symbols via your own
48
- // token-list lookup (e.g. config-derived).
49
- const { data: pools } = usePools({});
50
- return (
51
- <div>
52
- {pools?.map((pool, i) => (
53
- <div key={`${pool.currency0}-${pool.currency1}-${pool.fee}-${i}`}>
54
- <h3>{pool.currency0} / {pool.currency1}</h3>
55
- <p>Fee: {pool.fee / 10000}%</p>
56
- </div>
57
- ))}
58
- </div>
59
- );
60
- }
61
- ```
62
-
63
- ## Deposit Assets
64
-
65
- ```tsx
66
- import { useDexDeposit, useDexAllowance, useDexApprove } from '@sodax/dapp-kit';
67
- import { useWalletProvider } from '@sodax/wallet-sdk-react';
68
- import { ChainKeys, type CreateAssetDepositParams } from '@sodax/sdk';
69
-
70
- function DepositToPool({ srcAddress }: { srcAddress: `0x${string}` }) {
71
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
72
- const depositParams: CreateAssetDepositParams<typeof ChainKeys.BASE_MAINNET> = {
73
- srcChainKey: ChainKeys.BASE_MAINNET,
74
- srcAddress,
75
- asset: '0x0000000000000000000000000000000000000000',
76
- amount: 1_000_000_000_000_000_000n,
77
- poolToken: '0x0000000000000000000000000000000000000000',
78
- };
79
-
80
- // useDexAllowance wraps CreateAssetDepositParams under params.payload. Read-only;
81
- // no walletProvider needed (the SDK call uses `raw: true`).
82
- const { data: isApproved } = useDexAllowance({
83
- params: { payload: depositParams },
84
- });
85
- const { mutateAsync: approve, isPending: isApproving } = useDexApprove();
86
- const { mutateAsync: deposit, isPending: isDepositing } = useDexDeposit();
87
-
88
- const handleDeposit = async () => {
89
- if (!walletProvider) return;
90
- try {
91
- if (!isApproved) await approve({ params: depositParams, walletProvider });
92
- const txHashPair = await deposit({ params: depositParams, walletProvider });
93
- console.log('Deposited:', txHashPair);
94
- } catch (e) {
95
- console.error(e);
96
- }
97
- };
98
-
99
- return (
100
- <button onClick={handleDeposit} disabled={isDepositing || isApproving || !walletProvider}>
101
- {isApproving ? 'Approving...' : isDepositing ? 'Depositing...' : 'Deposit'}
102
- </button>
103
- );
104
- }
105
- ```
106
-
107
- ## Supply Liquidity
108
-
109
- ```tsx
110
- // @ai-snippets-skip — illustrative flow only; `useCreateSupplyLiquidityParams` takes
111
- // a flat shape `{ poolData, poolKey, minPrice, maxPrice, liquidityToken0Amount,
112
- // liquidityToken1Amount, slippageTolerance }` and the consumer must add
113
- // `srcChainKey` + `srcAddress` at the mutation call site. Real consumers should
114
- // reference `useCreateSupplyLiquidityParams` source for the full param set.
115
- import { useSupplyLiquidity, useCreateSupplyLiquidityParams } from '@sodax/dapp-kit';
116
- import { useWalletProvider } from '@sodax/wallet-sdk-react';
117
- import { ChainKeys } from '@sodax/sdk';
118
-
119
- function SupplyLiquidity() {
120
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
121
- const supplyParams = useCreateSupplyLiquidityParams({
122
- params: {
123
- poolKey: { /* ... */ },
124
- tickLower: -60000n,
125
- tickUpper: 60000n,
126
- amount0: 1_000_000_000_000_000_000n,
127
- amount1: 1_000_000_000_000_000_000n,
128
- },
129
- });
130
- const { mutateAsync: supplyLiquidity, isPending } = useSupplyLiquidity();
131
-
132
- return (
133
- <button
134
- disabled={isPending || !supplyParams || !walletProvider}
135
- onClick={async () => {
136
- if (!supplyParams || !walletProvider) return;
137
- try {
138
- const txHashPair = await supplyLiquidity({ params: supplyParams, walletProvider });
139
- console.log('Supplied:', txHashPair);
140
- } catch (e) {
141
- console.error(e);
142
- }
143
- }}
144
- >
145
- {isPending ? 'Supplying...' : 'Supply Liquidity'}
146
- </button>
147
- );
148
- }
149
- ```
150
-
151
- ## Position + Claim Rewards
152
-
153
- ```tsx
154
- // @ai-snippets-skip — illustrative flow only. Real call-shape notes:
155
- // - `usePositionInfo` params.tokenId is `string | null`, not bigint
156
- // - `usePositionInfo` data is `{ positionInfo: ClPositionInfo, isValid: boolean }` —
157
- // access `position.positionInfo.liquidity` etc.
158
- // - `useClaimRewards` params shape: `{ srcChainKey, srcAddress, poolKey, tokenId,
159
- // tickLower, tickUpper }` — far richer than shown.
160
- // See `features/dex.md` for the canonical param types.
161
- import { usePositionInfo, useClaimRewards } from '@sodax/dapp-kit';
162
- import { useWalletProvider } from '@sodax/wallet-sdk-react';
163
- import { ChainKeys } from '@sodax/sdk';
164
- import type { PoolKey } from '@sodax/sdk';
165
-
166
- function Position({ positionId, poolKey }: { positionId: bigint; poolKey: PoolKey }) {
167
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
168
- const { data: position } = usePositionInfo({ params: { tokenId: positionId, poolKey } });
169
- const { mutateAsync: claimRewards, isPending } = useClaimRewards();
170
-
171
- if (!position) return null;
172
- return (
173
- <div>
174
- <p>Liquidity: {position.liquidity.toString()}</p>
175
- <p>Range: [{position.tickLower}, {position.tickUpper}]</p>
176
- <button
177
- onClick={() => walletProvider && claimRewards({ params: { srcChainKey: ChainKeys.BASE_MAINNET, positionId }, walletProvider })}
178
- disabled={isPending || !walletProvider}
179
- >
180
- Claim Fees
181
- </button>
182
- </div>
183
- );
184
- }
185
- ```
186
-
187
- ## Remove Liquidity
188
-
189
- ```tsx
190
- // @ai-snippets-skip
191
- const walletProvider = useWalletProvider({ xChainId: ChainKeys.BASE_MAINNET });
192
- const { mutateAsync: decreaseLiquidity } = useDecreaseLiquidity();
193
-
194
- await decreaseLiquidity({
195
- params: { srcChainKey: ChainKeys.BASE_MAINNET, positionId, liquidity: 500_000n, amount0Min: 0n, amount1Min: 0n },
196
- walletProvider,
197
- });
198
- ```
199
-
200
- ## Notes
201
-
202
- - **Two-step flow**: deposit assets (spoke → hub pool tokens) then supply liquidity (pool tokens → position).
203
- - **Ticks**: logarithmic price units (like Uniswap V3). Wider range = more trades, less capital efficiency.
204
- - **ERC-4626**: pool tokens are vault shares. Use `useCreateDepositParams` to handle the conversion.
@@ -1,115 +0,0 @@
1
- # Recipe: Invalidations — hook-owned, composable
2
-
3
- Every dapp-kit mutation hook owns its own query invalidations. After a successful mutation, the hook's `onSuccess` fires invalidation calls against the relevant query keys; **then** your consumer-provided `onSuccess` runs.
4
-
5
- ## Default — invalidations just work
6
-
7
- ```tsx
8
- import { useSwap } from '@sodax/dapp-kit';
9
- import type { CreateIntentParams, IEvmWalletProvider } from '@sodax/sdk';
10
-
11
- function SwapButton({ params, walletProvider }: { params: CreateIntentParams; walletProvider: IEvmWalletProvider }) {
12
- const { mutateAsync: swap } = useSwap();
13
-
14
- const handleClick = async () => {
15
- // After this resolves successfully, dapp-kit invalidates `xBalances`
16
- // for the source and destination chains automatically.
17
- await swap({ params, walletProvider });
18
- };
19
-
20
- return <button onClick={handleClick}>Swap</button>;
21
- }
22
- ```
23
-
24
- You don't need to call `queryClient.invalidateQueries` yourself. Each mutation hook knows what queries it can invalidate (e.g. `useSwap` invalidates `xBalances` for `srcChainKey` and `dstChainKey` from the variables).
25
-
26
- ## Composing your own `onSuccess`
27
-
28
- Pass `mutationOptions.onSuccess` to run logic AFTER dapp-kit's invalidations:
29
-
30
- ```tsx
31
- import { useSwap } from '@sodax/dapp-kit';
32
-
33
- const { mutateAsync: swap } = useSwap({
34
- mutationOptions: {
35
- onSuccess: (data, vars) => {
36
- // Runs AFTER dapp-kit's xBalances invalidations.
37
- // `data` is the unwrapped success value (SwapResponse).
38
- trackSwap(data);
39
- console.log('swap_complete', { from: vars.params.srcChainKey });
40
- },
41
- },
42
- });
43
- console.log(swap);
44
- ```
45
-
46
- The order is fixed:
47
-
48
- 1. `mutationFn` resolves successfully (SDK returned `{ ok: true }`).
49
- 2. dapp-kit's hook-internal `onSuccess` runs the invalidations.
50
- 3. Your `mutationOptions.onSuccess` runs.
51
- 4. Per-call `mutate(vars, { onSuccess })` runs (if provided).
52
-
53
- Failed mutations never trigger any of steps 2–4 — invalidations are correctness logic, not "always run."
54
-
55
- ## What gets invalidated, by feature
56
-
57
- Each feature mutation hook invalidates the related read keys. Common patterns:
58
-
59
- | Mutation | Invalidates |
60
- |---|---|
61
- | `useSwap` | `['shared', 'xBalances', srcChainKey]`, `['shared', 'xBalances', dstChainKey]` |
62
- | `useBridge` | Same as `useSwap` (xBalances on both chains). |
63
- | `useSupply`, `useWithdraw`, `useBorrow`, `useRepay` | `['mm', 'userReservesData']`, `['shared', 'xBalances', srcChainKey]`, plus reserves data on the affected token. |
64
- | `useStake`, `useUnstake`, `useClaim`, `useCancelUnstake`, `useInstantUnstake` | `['staking', 'info']`, `['staking', 'unstakingInfo']`, `['shared', 'xBalances', srcChainKey]`. |
65
- | `useDexDeposit`, `useDexWithdraw` | `['dex', 'poolBalances']`, `['shared', 'xBalances', srcChainKey]`. |
66
- | `useSupplyLiquidity`, `useDecreaseLiquidity`, `useClaimRewards` | `['dex', 'positionInfo', tokenId]`, `['dex', 'poolBalances']`. |
67
- | `useMigrateIcxToSoda`, etc. | `['shared', 'xBalances']` for source + destination chains. |
68
- | Approve hooks (`useSwapApprove`, etc.) | The corresponding allowance read (`['swap', 'allowance']`, etc.). |
69
-
70
- The exact keys are derived from `vars` at success time — so a successful supply on Base only invalidates Base-side reserves, not Arbitrum's.
71
-
72
- ## Adding cross-feature invalidations
73
-
74
- If you operate across multiple features (e.g. you have a custom hook that does `swap → migrate`), invalidate the cross-feature keys yourself in the consumer `onSuccess`:
75
-
76
- ```tsx
77
- import { useQueryClient } from '@tanstack/react-query';
78
- import { useSwap } from '@sodax/dapp-kit';
79
-
80
- const qc = useQueryClient();
81
- const { mutateAsync: swap } = useSwap({
82
- mutationOptions: {
83
- onSuccess: async (data, vars) => {
84
- // dapp-kit invalidates xBalances. We additionally want to refresh a
85
- // custom analytics view that tracks completed swap volume.
86
- await qc.invalidateQueries({ queryKey: ['my-app', 'swap-volume'] });
87
- },
88
- },
89
- });
90
- ```
91
-
92
- ## Per-call invalidation
93
-
94
- For one-off invalidations (only on this specific click), pass `onSuccess` to `mutate`:
95
-
96
- ```tsx
97
- // @ai-snippets-skip
98
- await swap.mutateAsync(
99
- { params, walletProvider },
100
- { onSuccess: () => navigate(`/swap/${data.intent.intentHash}`) }
101
- );
102
- ```
103
-
104
- The order is unchanged: hook invalidations → consumer `onSuccess` → per-call `onSuccess`.
105
-
106
- ## v1 → v2
107
-
108
- In v1 dapp-kit, consumers managed invalidations themselves — most apps had a `lib/invalidate*Queries.ts` utility that fired `queryClient.invalidateQueries(...)` after each mutation. Those utilities are no longer needed in v2; delete them.
109
-
110
- If you're migrating v1 code, see [`../../migration/breaking-changes/hook-signatures.md`](../../migration/breaking-changes/hook-signatures.md) for the full delta.
111
-
112
- ## Cross-references
113
-
114
- - [`mutation-error-handling.md`](mutation-error-handling.md) — picking call shapes.
115
- - [`../architecture.md`](../architecture.md) — `_mutationContract.test.ts` enforces the canonical `onSuccess` composition pattern.