@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.
- package/README.md +9 -63
- package/dist/index.mjs +0 -2
- package/package.json +31 -20
- package/ai-exported/AGENTS.md +0 -134
- package/ai-exported/integration/README.md +0 -49
- package/ai-exported/integration/ai-rules.md +0 -80
- package/ai-exported/integration/architecture.md +0 -276
- 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 -144
- 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 -207
- 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 -168
- 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 -128
- package/ai-exported/integration/reference/README.md +0 -12
- package/ai-exported/integration/reference/glossary.md +0 -190
- 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 -167
- 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 -160
- 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 -139
- package/ai-exported/migration/features/staking.md +0 -109
- package/ai-exported/migration/features/swap.md +0 -133
- package/ai-exported/migration/recipes.md +0 -185
- 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 -68
- package/dist/index.cjs +0 -2641
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -1557
- 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.
|