@sodax/dapp-kit 1.5.7-beta → 2.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +300 -422
- package/ai-exported/AGENTS.md +134 -0
- package/ai-exported/integration/README.md +49 -0
- package/ai-exported/integration/ai-rules.md +79 -0
- package/ai-exported/integration/architecture.md +274 -0
- package/ai-exported/integration/features/README.md +29 -0
- package/ai-exported/integration/features/auxiliary-services.md +169 -0
- package/ai-exported/integration/features/bitcoin.md +87 -0
- package/ai-exported/integration/features/bridge.md +91 -0
- package/ai-exported/integration/features/dex.md +152 -0
- package/ai-exported/integration/features/migration.md +118 -0
- package/ai-exported/integration/features/money-market.md +116 -0
- package/ai-exported/integration/features/staking.md +123 -0
- package/ai-exported/integration/features/swap.md +101 -0
- package/ai-exported/integration/quickstart.md +187 -0
- package/ai-exported/integration/recipes/README.md +136 -0
- package/ai-exported/integration/recipes/backend-queries.md +157 -0
- package/ai-exported/integration/recipes/bitcoin.md +193 -0
- package/ai-exported/integration/recipes/bridge.md +174 -0
- package/ai-exported/integration/recipes/dex.md +204 -0
- package/ai-exported/integration/recipes/invalidations.md +115 -0
- package/ai-exported/integration/recipes/migration.md +212 -0
- package/ai-exported/integration/recipes/money-market.md +206 -0
- package/ai-exported/integration/recipes/mutation-error-handling.md +118 -0
- package/ai-exported/integration/recipes/observability.md +93 -0
- package/ai-exported/integration/recipes/setup.md +144 -0
- package/ai-exported/integration/recipes/staking.md +202 -0
- package/ai-exported/integration/recipes/swap.md +272 -0
- package/ai-exported/integration/recipes/wallet-connectivity.md +101 -0
- package/ai-exported/integration/reference/README.md +12 -0
- package/ai-exported/integration/reference/glossary.md +188 -0
- package/ai-exported/integration/reference/hooks-index.md +194 -0
- package/ai-exported/integration/reference/public-api.md +110 -0
- package/ai-exported/integration/reference/querykey-conventions.md +179 -0
- package/ai-exported/migration/README.md +60 -0
- package/ai-exported/migration/ai-rules.md +81 -0
- package/ai-exported/migration/breaking-changes/hook-signatures.md +233 -0
- package/ai-exported/migration/breaking-changes/querykey-conventions.md +108 -0
- package/ai-exported/migration/breaking-changes/result-handling.md +211 -0
- package/ai-exported/migration/breaking-changes/sdk-leakage.md +165 -0
- package/ai-exported/migration/checklist.md +89 -0
- package/ai-exported/migration/features/README.md +34 -0
- package/ai-exported/migration/features/auxiliary-services.md +114 -0
- package/ai-exported/migration/features/bitcoin.md +88 -0
- package/ai-exported/migration/features/bridge.md +123 -0
- package/ai-exported/migration/features/dex.md +101 -0
- package/ai-exported/migration/features/migration.md +120 -0
- package/ai-exported/migration/features/money-market.md +97 -0
- package/ai-exported/migration/features/staking.md +109 -0
- package/ai-exported/migration/features/swap.md +118 -0
- package/ai-exported/migration/recipes.md +188 -0
- package/ai-exported/migration/reference/README.md +15 -0
- package/ai-exported/migration/reference/deleted-hooks.md +110 -0
- package/ai-exported/migration/reference/error-shape-crosswalk.md +144 -0
- package/ai-exported/migration/reference/renamed-hooks.md +66 -0
- package/dist/index.cjs +2642 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1550 -0
- package/dist/index.d.ts +1020 -2051
- package/dist/index.mjs +1581 -1531
- package/dist/index.mjs.map +1 -1
- package/package.json +20 -10
- package/src/contexts/index.ts +0 -3
- package/src/hooks/_mutationContract.test.ts +99 -0
- package/src/hooks/backend/README.md +2 -2
- package/src/hooks/backend/index.ts +13 -13
- package/src/hooks/backend/unwrapResult.ts +1 -0
- package/src/hooks/backend/useBackendAllMoneyMarketAssets.ts +13 -45
- package/src/hooks/backend/useBackendAllMoneyMarketBorrowers.ts +29 -59
- package/src/hooks/backend/useBackendIntentByHash.ts +21 -47
- package/src/hooks/backend/useBackendIntentByTxHash.ts +23 -50
- package/src/hooks/backend/useBackendMoneyMarketAsset.ts +21 -54
- package/src/hooks/backend/useBackendMoneyMarketAssetBorrowers.ts +30 -57
- package/src/hooks/backend/useBackendMoneyMarketAssetSuppliers.ts +31 -58
- package/src/hooks/backend/useBackendMoneyMarketPosition.ts +22 -38
- package/src/hooks/backend/useBackendOrderbook.ts +27 -49
- package/src/hooks/backend/useBackendSubmitSwapTx.ts +30 -36
- package/src/hooks/backend/useBackendSubmitSwapTxStatus.ts +38 -58
- package/src/hooks/backend/useBackendUserIntents.ts +25 -63
- package/src/hooks/bitcoin/index.ts +9 -8
- package/src/hooks/bitcoin/useBitcoinBalance.ts +20 -5
- package/src/hooks/bitcoin/useExpiredUtxos.ts +26 -16
- package/src/hooks/bitcoin/useFundTradingWallet.ts +33 -30
- package/src/hooks/bitcoin/useRadfiAuth.ts +43 -40
- package/src/hooks/bitcoin/useRadfiSession.ts +53 -59
- package/src/hooks/bitcoin/useRadfiWithdraw.ts +35 -53
- package/src/hooks/bitcoin/useRenewUtxos.ts +30 -50
- package/src/hooks/bitcoin/useTradingWallet.ts +1 -1
- package/src/hooks/bitcoin/useTradingWalletBalance.ts +25 -14
- package/src/hooks/bridge/index.ts +5 -5
- package/src/hooks/bridge/useBridge.ts +29 -55
- package/src/hooks/bridge/useBridgeAllowance.ts +38 -38
- package/src/hooks/bridge/useBridgeApprove.ts +32 -57
- package/src/hooks/bridge/useGetBridgeableAmount.ts +23 -37
- package/src/hooks/bridge/useGetBridgeableTokens.ts +27 -50
- package/src/hooks/dex/index.ts +16 -16
- package/src/hooks/dex/useClaimRewards.ts +35 -54
- package/src/hooks/dex/useCreateDecreaseLiquidityParams.ts +7 -20
- package/src/hooks/dex/useCreateDepositParams.ts +7 -21
- package/src/hooks/dex/useCreateSupplyLiquidityParams.ts +13 -28
- package/src/hooks/dex/useCreateWithdrawParams.ts +7 -20
- package/src/hooks/dex/useDecreaseLiquidity.ts +40 -66
- package/src/hooks/dex/useDexAllowance.ts +29 -75
- package/src/hooks/dex/useDexApprove.ts +32 -43
- package/src/hooks/dex/useDexDeposit.ts +42 -49
- package/src/hooks/dex/useDexWithdraw.ts +32 -43
- package/src/hooks/dex/useLiquidityAmounts.ts +13 -82
- package/src/hooks/dex/usePoolBalances.ts +50 -72
- package/src/hooks/dex/usePoolData.ts +17 -43
- package/src/hooks/dex/usePools.ts +11 -38
- package/src/hooks/dex/usePositionInfo.ts +27 -62
- package/src/hooks/dex/useSupplyLiquidity.ts +80 -75
- package/src/hooks/index.ts +12 -10
- package/src/hooks/migrate/index.ts +13 -4
- package/src/hooks/migrate/useMigrateBaln.ts +42 -0
- package/src/hooks/migrate/useMigrateIcxToSoda.ts +44 -0
- package/src/hooks/migrate/useMigratebnUSD.ts +47 -0
- package/src/hooks/migrate/useMigrationAllowance.ts +76 -0
- package/src/hooks/migrate/useMigrationApprove.ts +66 -0
- package/src/hooks/migrate/useRevertMigrateSodaToIcx.ts +39 -0
- package/src/hooks/mm/index.ts +14 -12
- package/src/hooks/mm/useAToken.ts +25 -41
- package/src/hooks/mm/useATokensBalances.ts +29 -60
- package/src/hooks/mm/useBorrow.ts +38 -56
- package/src/hooks/mm/useMMAllowance.ts +37 -73
- package/src/hooks/mm/useMMApprove.ts +36 -43
- package/src/hooks/mm/useRepay.ts +33 -53
- package/src/hooks/mm/useReservesData.ts +12 -38
- package/src/hooks/mm/useReservesHumanized.ts +12 -31
- package/src/hooks/mm/useReservesList.ts +11 -31
- package/src/hooks/mm/useReservesUsdFormat.ts +15 -35
- package/src/hooks/mm/useSupply.ts +45 -51
- package/src/hooks/mm/useUserFormattedSummary.ts +32 -84
- package/src/hooks/mm/useUserReservesData.ts +27 -77
- package/src/hooks/mm/useWithdraw.ts +38 -54
- package/src/hooks/partner/index.ts +6 -0
- package/src/hooks/partner/useApproveToken.ts +42 -0
- package/src/hooks/partner/useFeeClaimSwap.ts +38 -0
- package/src/hooks/partner/useFetchAssetsBalances.ts +37 -0
- package/src/hooks/partner/useGetAutoSwapPreferences.ts +37 -0
- package/src/hooks/partner/useIsTokenApproved.ts +39 -0
- package/src/hooks/partner/useSetSwapPreference.ts +50 -0
- package/src/hooks/provider/index.ts +1 -2
- package/src/hooks/provider/useHubProvider.ts +1 -1
- package/src/hooks/recovery/index.ts +2 -0
- package/src/hooks/recovery/useHubAssetBalances.ts +43 -0
- package/src/hooks/recovery/useWithdrawHubAsset.ts +48 -0
- package/src/hooks/shared/index.ts +10 -6
- package/src/hooks/shared/types.ts +77 -0
- package/src/hooks/shared/unwrapResult.ts +19 -0
- package/src/hooks/shared/useDeriveUserWalletAddress.ts +22 -40
- package/src/hooks/shared/useEstimateGas.ts +18 -15
- package/src/hooks/shared/useGetUserHubWalletAddress.ts +25 -26
- package/src/hooks/shared/useRequestTrustline.ts +28 -61
- package/src/hooks/shared/useSafeMutation.test.ts +43 -0
- package/src/hooks/shared/useSafeMutation.ts +68 -0
- package/src/hooks/shared/useSodaxContext.ts +1 -1
- package/src/hooks/shared/useStellarTrustlineCheck.ts +30 -64
- package/src/hooks/shared/useXBalances.test.ts +113 -0
- package/src/hooks/shared/useXBalances.ts +61 -0
- package/src/hooks/staking/index.ts +18 -18
- package/src/hooks/staking/useCancelUnstake.ts +30 -41
- package/src/hooks/staking/useClaim.ts +27 -36
- package/src/hooks/staking/useConvertedAssets.ts +24 -34
- package/src/hooks/staking/useInstantUnstake.ts +33 -40
- package/src/hooks/staking/useInstantUnstakeAllowance.ts +37 -45
- package/src/hooks/staking/useInstantUnstakeApprove.ts +42 -42
- package/src/hooks/staking/useInstantUnstakeRatio.ts +24 -41
- package/src/hooks/staking/useStake.ts +32 -37
- package/src/hooks/staking/useStakeAllowance.ts +30 -43
- package/src/hooks/staking/useStakeApprove.ts +40 -40
- package/src/hooks/staking/useStakeRatio.ts +24 -40
- package/src/hooks/staking/useStakingConfig.ts +14 -27
- package/src/hooks/staking/useStakingInfo.ts +30 -38
- package/src/hooks/staking/useUnstake.ts +29 -43
- package/src/hooks/staking/useUnstakeAllowance.ts +37 -44
- package/src/hooks/staking/useUnstakeApprove.ts +40 -43
- package/src/hooks/staking/useUnstakingInfo.ts +29 -41
- package/src/hooks/staking/useUnstakingInfoWithPenalty.ts +31 -47
- package/src/hooks/swap/index.ts +8 -8
- package/src/hooks/swap/useCancelLimitOrder.ts +24 -41
- package/src/hooks/swap/useCancelSwap.ts +24 -33
- package/src/hooks/swap/useCreateLimitOrder.ts +29 -62
- package/src/hooks/swap/useQuote.ts +17 -43
- package/src/hooks/swap/useStatus.ts +22 -29
- package/src/hooks/swap/useSwap.ts +31 -49
- package/src/hooks/swap/useSwapAllowance.ts +38 -35
- package/src/hooks/swap/useSwapApprove.ts +48 -57
- package/src/index.ts +5 -3
- package/src/providers/SodaxProvider.tsx +17 -11
- package/src/providers/createSodaxQueryClient.ts +96 -0
- package/src/providers/index.ts +2 -1
- package/src/utils/dex-utils.ts +27 -5
- package/src/utils/index.ts +1 -1
- package/dist/index.d.mts +0 -2581
- package/dist/index.js +0 -2574
- package/dist/index.js.map +0 -1
- package/src/hooks/migrate/types.ts +0 -15
- package/src/hooks/migrate/useMigrate.tsx +0 -110
- package/src/hooks/migrate/useMigrationAllowance.tsx +0 -79
- package/src/hooks/migrate/useMigrationApprove.tsx +0 -129
- package/src/hooks/provider/useSpokeProvider.ts +0 -172
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Money Market — `@sodax/dapp-kit`
|
|
2
|
+
|
|
3
|
+
Cross-chain lending and borrowing.
|
|
4
|
+
|
|
5
|
+
Pair: [`../../migration/features/money-market.md`](../../migration/features/money-market.md).
|
|
6
|
+
|
|
7
|
+
## Hook surface
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// @ai-snippets-skip
|
|
11
|
+
// User mutations (4 actions)
|
|
12
|
+
useSupply({ mutationOptions });
|
|
13
|
+
useWithdraw({ mutationOptions });
|
|
14
|
+
useBorrow({ mutationOptions });
|
|
15
|
+
useRepay({ mutationOptions });
|
|
16
|
+
|
|
17
|
+
// Allowance + approve — useMMAllowance wraps the MM params under `params.payload`
|
|
18
|
+
useMMAllowance({ params: { payload: MoneyMarketParams<K> }, queryOptions }); // disabled for borrow/withdraw (data is undefined)
|
|
19
|
+
useMMApprove({ mutationOptions });
|
|
20
|
+
|
|
21
|
+
// Reserves data (read-only)
|
|
22
|
+
useReservesData({ queryOptions }); // All reserve data
|
|
23
|
+
useReservesHumanized({ queryOptions }); // Decimal-normalized
|
|
24
|
+
useReservesList({ queryOptions }); // List of reserve asset addresses
|
|
25
|
+
useReservesUsdFormat({ queryOptions }); // With USD values
|
|
26
|
+
|
|
27
|
+
// User position
|
|
28
|
+
useUserFormattedSummary({ params, queryOptions }); // Health factor, collateral, debt
|
|
29
|
+
useUserReservesData({ params, queryOptions }); // Per-reserve user position
|
|
30
|
+
|
|
31
|
+
// aTokens
|
|
32
|
+
useAToken({ params, queryOptions }); // aToken metadata
|
|
33
|
+
useATokensBalances({ params, queryOptions }); // aToken balances
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Mutation params
|
|
37
|
+
|
|
38
|
+
All four user mutations share the same TVars shape (only the `action` literal differs):
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// @ai-snippets-skip
|
|
42
|
+
type UseSupplyVars<K extends SpokeChainKey = SpokeChainKey> = {
|
|
43
|
+
params: MoneyMarketSupplyParams<K>;
|
|
44
|
+
walletProvider: GetWalletProviderType<K>;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// MoneyMarketSupplyParams<K>:
|
|
48
|
+
// {
|
|
49
|
+
// srcChainKey: K;
|
|
50
|
+
// srcAddress: GetAddressType<K>;
|
|
51
|
+
// token: string;
|
|
52
|
+
// amount: bigint;
|
|
53
|
+
// action: 'supply';
|
|
54
|
+
// dstChainKey?: SpokeChainKey; // optional cross-chain delivery
|
|
55
|
+
// dstAddress?: string;
|
|
56
|
+
// }
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
`borrow`, `withdraw`, `repay` follow the same shape with their respective `action` literals (`'borrow'` / `'withdraw'` / `'repay'`). **All four actions** accept optional `dstChainKey`/`dstAddress` for cross-chain delivery — supply on chain A and credit collateral on chain B, withdraw from chain A into a wallet on chain B, etc.
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
// @ai-snippets-skip
|
|
63
|
+
const { mutateAsyncSafe: supply } = useSupply();
|
|
64
|
+
const result = await supply({
|
|
65
|
+
params: { srcChainKey: ChainKeys.BASE_MAINNET, srcAddress: '0x...', token: '0x...', amount: 1_000_000n, action: 'supply' },
|
|
66
|
+
walletProvider,
|
|
67
|
+
});
|
|
68
|
+
if (!result.ok) return;
|
|
69
|
+
const { srcChainTxHash, dstChainTxHash } = result.value; // TxHashPair
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Approve / allowance
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// @ai-snippets-skip
|
|
76
|
+
// useMMAllowance reads `params.payload` (the MM params); no walletProvider — the read calls
|
|
77
|
+
// `isAllowanceValid` with `raw: true` internally. For borrow/withdraw, returns true automatically.
|
|
78
|
+
const { data: isApproved } = useMMAllowance({ params: { payload: supplyParams } });
|
|
79
|
+
const { mutateAsync: approve } = useMMApprove();
|
|
80
|
+
if (!isApproved) await approve({ params: supplyParams, walletProvider });
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`useMMAllowance` skips the on-chain check entirely for `'borrow'` / `'withdraw'` actions — the query is `enabled: false` for those, so `data` stays `undefined`. Treat "absent allowance for borrow/withdraw" as "approval not required" at the call site (these actions never need ERC-20 approval).
|
|
84
|
+
|
|
85
|
+
## Reserves data hooks
|
|
86
|
+
|
|
87
|
+
| Hook | Returns | When to use |
|
|
88
|
+
|---|---|---|
|
|
89
|
+
| `useReservesData` | `[ReserveData[], ...]` | Raw data for custom rendering |
|
|
90
|
+
| `useReservesHumanized` | `ReserveDataHumanized[]` | Decimal-normalized (most common for UI) |
|
|
91
|
+
| `useReservesList` | `Address[]` | Just the reserve addresses |
|
|
92
|
+
| `useReservesUsdFormat` | `ReserveDataWithUsd[]` | With USD price overlays |
|
|
93
|
+
| `useUserFormattedSummary` | `{ totalCollateralUSD, totalBorrowsUSD, healthFactor, ... }` | Dashboard-ready summary |
|
|
94
|
+
| `useUserReservesData` | `UserReserveData[]` | Per-reserve user position |
|
|
95
|
+
|
|
96
|
+
## Return shapes
|
|
97
|
+
|
|
98
|
+
| Hook | Returns |
|
|
99
|
+
|---|---|
|
|
100
|
+
| `useSupply` / `useBorrow` / `useWithdraw` / `useRepay` | `SafeUseMutationResult<TxHashPair, Error, ...>` (`{ srcChainTxHash, dstChainTxHash }`) |
|
|
101
|
+
| `useMMApprove` | `SafeUseMutationResult<TxReturnType<K, false>, Error, ...>` — chain-keyed receipt union |
|
|
102
|
+
| `useMMAllowance` | `UseQueryResult<boolean, Error>` — already unwrapped; for `borrow`/`withdraw` actions the query is `enabled: false` and `data` is `undefined` |
|
|
103
|
+
| Reserve / position hooks | `UseQueryResult<TData, Error>` — already unwrapped; queries throw on SDK `!ok` |
|
|
104
|
+
|
|
105
|
+
## Gotchas
|
|
106
|
+
|
|
107
|
+
1. **Health factor < 1.0 is liquidation territory.** Always render a warning when `useUserFormattedSummary().healthFactor < 1.05` or whatever margin your UX uses.
|
|
108
|
+
2. **Cross-chain delivery via `dstChainKey`/`dstAddress`** — supported on all four actions (supply / withdraw / borrow / repay). Omit for same-chain operations; don't pass `dstChainKey === srcChainKey` (let the default kick in).
|
|
109
|
+
3. **`useMMAllowance` is `enabled: false` for borrow/withdraw** — `data` stays `undefined` (not `true`). Treat "no allowance result for borrow/withdraw" as "approval not required" — those actions never need ERC-20 approval.
|
|
110
|
+
4. **Position queries take `{ spokeChainKey, userAddress }`** (NOT `srcChainKey`/`srcAddress` — those are mutation-side names). The hub wallet derivation is automatic.
|
|
111
|
+
|
|
112
|
+
## Cross-references
|
|
113
|
+
|
|
114
|
+
- [`../recipes/money-market.md`](../recipes/money-market.md) — full worked examples.
|
|
115
|
+
- [`../../migration/features/money-market.md`](../../migration/features/money-market.md) — v1 → v2 porting.
|
|
116
|
+
- [`../../../../sdk/ai-exported/integration/features/money-market.md`](../../../../sdk/ai-exported/integration/features/money-market.md) — underlying SDK MM surface.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Staking — `@sodax/dapp-kit`
|
|
2
|
+
|
|
3
|
+
SODA → xSODA staking via ERC-4626 vault. Five user actions plus reads.
|
|
4
|
+
|
|
5
|
+
Pair: [`../../migration/features/staking.md`](../../migration/features/staking.md).
|
|
6
|
+
|
|
7
|
+
## Hook surface
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// @ai-snippets-skip
|
|
11
|
+
// Mutations
|
|
12
|
+
useStake({ mutationOptions });
|
|
13
|
+
useUnstake({ mutationOptions }); // Request unstake (waiting period)
|
|
14
|
+
useInstantUnstake({ mutationOptions }); // Instant unstake with slippage
|
|
15
|
+
useClaim({ mutationOptions }); // Claim SODA after waiting period
|
|
16
|
+
useCancelUnstake({ mutationOptions }); // Cancel pending unstake
|
|
17
|
+
|
|
18
|
+
// Allowance + approve (one per mutation that needs approval)
|
|
19
|
+
useStakeApprove({ mutationOptions });
|
|
20
|
+
useUnstakeApprove({ mutationOptions });
|
|
21
|
+
useInstantUnstakeApprove({ mutationOptions });
|
|
22
|
+
// Allowance hooks wrap the action params (without `action`) under params.payload.
|
|
23
|
+
// Read-only — no walletProvider needed (the SDK call uses `raw: true`).
|
|
24
|
+
useStakeAllowance({ params: { payload: Omit<StakeParams<K>, 'action'> }, queryOptions });
|
|
25
|
+
useUnstakeAllowance({ params: { payload: Omit<UnstakeParams<K>, 'action'> }, queryOptions });
|
|
26
|
+
useInstantUnstakeAllowance({ params: { payload: Omit<InstantUnstakeParams<K>, 'action'> }, queryOptions });
|
|
27
|
+
|
|
28
|
+
// Reads
|
|
29
|
+
useStakingInfo({ params, queryOptions });
|
|
30
|
+
useUnstakingInfo({ params, queryOptions });
|
|
31
|
+
useUnstakingInfoWithPenalty({ params, queryOptions });
|
|
32
|
+
useStakingConfig({ queryOptions });
|
|
33
|
+
useStakeRatio({ params, queryOptions });
|
|
34
|
+
useInstantUnstakeRatio({ params, queryOptions });
|
|
35
|
+
useConvertedAssets({ params, queryOptions });
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Mutation TVars
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
// @ai-snippets-skip
|
|
42
|
+
type StakeParams<K> = { srcChainKey: K; srcAddress: Address; amount: bigint; minReceive: bigint; action: 'stake' };
|
|
43
|
+
type UnstakeParams<K> = { srcChainKey: K; srcAddress: Address; amount: bigint; action: 'unstake' };
|
|
44
|
+
type InstantUnstakeParams<K> = { srcChainKey: K; srcAddress: Address; amount: bigint; minAmount: bigint; action: 'instantUnstake' };
|
|
45
|
+
type ClaimParams<K> = { srcChainKey: K; srcAddress: Address; requestId: bigint; amount: bigint; action: 'claim' };
|
|
46
|
+
type CancelUnstakeParams<K> = { srcChainKey: K; srcAddress: Address; requestId: bigint; action: 'cancelUnstake' };
|
|
47
|
+
|
|
48
|
+
// All wrapped as TVars: { params: <ParamsType>, walletProvider }
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Read shapes (key picks)
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
// @ai-snippets-skip
|
|
55
|
+
// useStakingInfo — user position (data is already unwrapped from Result by the hook)
|
|
56
|
+
useStakingInfo({ params: { srcAddress, srcChainKey } })
|
|
57
|
+
// → UseQueryResult<StakingInfo>
|
|
58
|
+
// StakingInfo = { totalStaked: bigint, userXSodaBalance: bigint, userXSodaValue: bigint, ... }
|
|
59
|
+
|
|
60
|
+
// useUnstakingInfo — pending unstake requests
|
|
61
|
+
useUnstakingInfo({ params: { srcAddress, srcChainKey } })
|
|
62
|
+
// → UseQueryResult<UnstakingInfo>
|
|
63
|
+
// UnstakingInfo = { userUnstakeSodaRequests: UserUnstakeInfo[], totalUnstaking: bigint }
|
|
64
|
+
|
|
65
|
+
// useUnstakingInfoWithPenalty — same with penalty annotations
|
|
66
|
+
useUnstakingInfoWithPenalty({ params: { srcAddress, srcChainKey } })
|
|
67
|
+
// → UseQueryResult<UnstakingInfo & { requestsWithPenalty: UnstakeRequestWithPenalty[] }>
|
|
68
|
+
// each request adds { penalty, penaltyPercentage, claimableAmount }
|
|
69
|
+
|
|
70
|
+
// useStakingConfig — protocol params (no `params` input — only `queryOptions`)
|
|
71
|
+
useStakingConfig()
|
|
72
|
+
// → UseQueryResult<StakingConfig>
|
|
73
|
+
// StakingConfig = { unstakingPeriod: bigint, minUnstakingPeriod: bigint, maxPenalty: bigint }
|
|
74
|
+
|
|
75
|
+
// useStakeRatio — ratio with preview (data is a tuple, not a single bigint)
|
|
76
|
+
useStakeRatio({ params: { amount: 1_000_000_000_000_000_000n } })
|
|
77
|
+
// → UseQueryResult<[xSodaAmount: bigint, previewDepositAmount: bigint]>
|
|
78
|
+
// data is the tuple directly (unwrapped) — read data?.[0] / data?.[1]
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Approval pattern
|
|
82
|
+
|
|
83
|
+
Each of stake / unstake / instantUnstake has its OWN approve hook (different tokens):
|
|
84
|
+
|
|
85
|
+
| Action | Token approved | Hook |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| `stake` | SODA | `useStakeApprove`, `useStakeAllowance` |
|
|
88
|
+
| `unstake` | xSODA | `useUnstakeApprove`, `useUnstakeAllowance` |
|
|
89
|
+
| `instantUnstake` | xSODA | `useInstantUnstakeApprove`, `useInstantUnstakeAllowance` |
|
|
90
|
+
|
|
91
|
+
`claim` and `cancelUnstake` don't need approval (operating on hub-side state).
|
|
92
|
+
|
|
93
|
+
## Return shapes
|
|
94
|
+
|
|
95
|
+
| Hook | Returns |
|
|
96
|
+
|---|---|
|
|
97
|
+
All read hooks here are **already unwrapped** — they call `unwrapResult` internally so SDK `!ok` becomes a thrown error (engages `isError` / `error` / `retry`). Read `data` directly; do NOT branch on `data.ok`.
|
|
98
|
+
|
|
99
|
+
| Hook | Returns |
|
|
100
|
+
|---|---|
|
|
101
|
+
| `useStake` / `useUnstake` / `useInstantUnstake` / `useClaim` / `useCancelUnstake` | `SafeUseMutationResult<TxHashPair, Error, ...>` |
|
|
102
|
+
| `useStakeApprove` etc. | `SafeUseMutationResult<TxReturnType<K, false>, Error, ...>` — chain-keyed receipt union |
|
|
103
|
+
| `useStakingInfo` | `UseQueryResult<StakingInfo, Error>` |
|
|
104
|
+
| `useUnstakingInfo` | `UseQueryResult<UnstakingInfo, Error>` |
|
|
105
|
+
| `useUnstakingInfoWithPenalty` | `UseQueryResult<UnstakingInfoWithPenalty, Error>` (= `UnstakingInfo & { requestsWithPenalty: UnstakeRequestWithPenalty[] }`) |
|
|
106
|
+
| `useStakingConfig` | `UseQueryResult<StakingConfig, Error>` |
|
|
107
|
+
| `useStakeRatio` | `UseQueryResult<[bigint, bigint], Error>` (2-tuple: `[xSodaAmount, previewDepositAmount]`) |
|
|
108
|
+
| `useInstantUnstakeRatio` / `useConvertedAssets` | `UseQueryResult<bigint, Error>` |
|
|
109
|
+
| `useStakeAllowance` / `useUnstakeAllowance` / `useInstantUnstakeAllowance` | `UseQueryResult<boolean, Error>` |
|
|
110
|
+
|
|
111
|
+
## Gotchas
|
|
112
|
+
|
|
113
|
+
1. **`useStakeRatio` returns a tuple, not a bigint.** `data` is `[xSodaAmount, previewDepositAmount]` (already unwrapped) — index it: `data?.[0]` for the xSODA amount. Don't treat it as a single number.
|
|
114
|
+
2. **Unstake penalty is piecewise, not purely linear.** Penalty is flat `maxPenalty` during the `minUnstakingPeriod`, then decays linearly to 0 by the full `unstakingPeriod`. `useStakingConfig` returns `{ unstakingPeriod, minUnstakingPeriod, maxPenalty }`. Use `useUnstakingInfoWithPenalty` to display per-request `penaltyPercentage` and `claimableAmount`.
|
|
115
|
+
3. **Instant unstake bypasses the waiting period but pays slippage.** Use `useInstantUnstakeRatio` to preview the effective rate, then set `minAmount` for slippage protection.
|
|
116
|
+
4. **`useUnstakingInfoWithPenalty` returns an object with an embedded array.** Access `data?.requestsWithPenalty` directly (already unwrapped) — do NOT chain `.value.` first. Each request is `UserUnstakeInfo & { penalty, penaltyPercentage, claimableAmount }`; the request id lives at `req.id`, NOT `req.request.requestId`.
|
|
117
|
+
5. **All staking reads are unwrapped** (the hook throws on SDK `!ok`). Read `data` fields directly — no `.ok` / `.value` branching. This applies to `useStakingInfo`, `useUnstakingInfo`, `useUnstakingInfoWithPenalty`, `useStakingConfig`, `useStakeRatio`, `useInstantUnstakeRatio`, `useConvertedAssets`, and all three allowance hooks.
|
|
118
|
+
|
|
119
|
+
## Cross-references
|
|
120
|
+
|
|
121
|
+
- [`../recipes/staking.md`](../recipes/staking.md) — full worked examples.
|
|
122
|
+
- [`../../migration/features/staking.md`](../../migration/features/staking.md) — v1 → v2 porting.
|
|
123
|
+
- [`../../../../sdk/ai-exported/integration/features/staking.md`](../../../../sdk/ai-exported/integration/features/staking.md) — underlying SDK staking surface.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Swap — `@sodax/dapp-kit`
|
|
2
|
+
|
|
3
|
+
Cross-chain token swaps via the intent-based solver.
|
|
4
|
+
|
|
5
|
+
Pair: [`../../migration/features/swap.md`](../../migration/features/swap.md).
|
|
6
|
+
|
|
7
|
+
## Hook surface
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
// @ai-snippets-skip
|
|
11
|
+
// Queries — note the nested `params.payload` shape on useQuote and useSwapAllowance.
|
|
12
|
+
// `payload` is the SDK request value (SolverIntentQuoteRequest, CreateIntentParams, etc.).
|
|
13
|
+
useQuote({ params: { payload }, queryOptions }); // Real-time quote (3s)
|
|
14
|
+
useSwapAllowance({ params: { payload, srcChainKey, walletProvider }, queryOptions }); // allowance (2s)
|
|
15
|
+
useStatus({ params: { intentTxHash }, queryOptions }); // Intent execution status (3s)
|
|
16
|
+
|
|
17
|
+
// Mutations — domain inputs flow through mutate(vars), see Mutation params below
|
|
18
|
+
useSwap({ mutationOptions });
|
|
19
|
+
useSwapApprove({ mutationOptions });
|
|
20
|
+
useCancelSwap({ mutationOptions }); // TVars are FLAT: { srcChainKey, intent, walletProvider }
|
|
21
|
+
useCreateLimitOrder({ mutationOptions }); // No deadline; cancel manually
|
|
22
|
+
useCancelLimitOrder({ mutationOptions }); // TVars are FLAT: { srcChainKey, intent, walletProvider }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
(In actual code, you import each hook directly: `import { useSwap, useSwapAllowance, ... } from '@sodax/dapp-kit'`.)
|
|
26
|
+
|
|
27
|
+
## Mutation params
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
// @ai-snippets-skip
|
|
31
|
+
const { mutateAsyncSafe: swap } = useSwap();
|
|
32
|
+
|
|
33
|
+
// vars shape (TVars):
|
|
34
|
+
type UseSwapVars<K extends SpokeChainKey = SpokeChainKey> = Omit<SwapActionParams<K, false>, 'raw'>;
|
|
35
|
+
// = { params: CreateIntentParams; walletProvider: GetWalletProviderType<K> }
|
|
36
|
+
|
|
37
|
+
const result = await swap({ params: intentParams, walletProvider });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
`useSwapApprove` follows the same `{ params, walletProvider }` shape via `mutate(vars)`, where `params` is `CreateIntentParams<K> | CreateLimitOrderParams<K>` (the union — limit-order params also flow through `useSwapApprove`).
|
|
41
|
+
|
|
42
|
+
`useCreateLimitOrder` takes `{ params: CreateLimitOrderParams; walletProvider }` (no deadline; the order persists until cancelled).
|
|
43
|
+
|
|
44
|
+
**Cancel hooks are flat** (no `params` wrapper):
|
|
45
|
+
- `useCancelSwap` takes `{ srcChainKey, intent, walletProvider }`.
|
|
46
|
+
- `useCancelLimitOrder` takes `{ srcChainKey, intent, walletProvider }`.
|
|
47
|
+
|
|
48
|
+
## Query params
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// @ai-snippets-skip
|
|
52
|
+
// useQuote — SDK request wrapped under params.payload
|
|
53
|
+
type UseQuoteParams = ReadHookParams<
|
|
54
|
+
Result<SolverIntentQuoteResponse, SolverErrorResponse> | undefined,
|
|
55
|
+
{ payload: SolverIntentQuoteRequest | undefined }
|
|
56
|
+
>;
|
|
57
|
+
|
|
58
|
+
// useSwapAllowance — payload + srcChainKey + walletProvider all nested under params
|
|
59
|
+
type UseSwapAllowanceParams<K extends SpokeChainKey> = ReadHookParams<
|
|
60
|
+
boolean,
|
|
61
|
+
{
|
|
62
|
+
payload: CreateIntentParams | CreateLimitOrderParams | undefined;
|
|
63
|
+
srcChainKey: K | undefined;
|
|
64
|
+
walletProvider: GetWalletProviderType<K> | undefined;
|
|
65
|
+
}
|
|
66
|
+
>;
|
|
67
|
+
|
|
68
|
+
// useStatus — flat (no payload wrapper). Key is `intentTxHash` (NOT `intentHash`).
|
|
69
|
+
// Return is Result-wrapped, like useQuote — branch on data?.ok before reading status fields.
|
|
70
|
+
type UseStatusParams = ReadHookParams<
|
|
71
|
+
Result<SolverIntentStatusResponse, SolverErrorResponse> | undefined,
|
|
72
|
+
{ intentTxHash: Hex | undefined }
|
|
73
|
+
>;
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Return shapes
|
|
77
|
+
|
|
78
|
+
| Hook | Returns |
|
|
79
|
+
|---|---|
|
|
80
|
+
| `useSwap` | `SafeUseMutationResult<SwapResponse, Error, UseSwapVars>` where `SwapResponse = { intent, intentDeliveryInfo, solverExecutionResponse }` |
|
|
81
|
+
| `useSwapApprove` | `SafeUseMutationResult<TxReturnType<K, false>, Error, UseSwapApproveVars<K>>` — chain-keyed receipt union (EVM/Stellar/Sui differ) |
|
|
82
|
+
| `useCancelSwap` | `SafeUseMutationResult<TxHashPair, Error, { srcChainKey, intent, walletProvider }>` — note FLAT TVars |
|
|
83
|
+
| `useCancelLimitOrder` | `SafeUseMutationResult<TxHashPair, Error, { srcChainKey, intent, walletProvider }>` — note FLAT TVars |
|
|
84
|
+
| `useCreateLimitOrder` | `SafeUseMutationResult<{ intent, intentDeliveryInfo, ... }, Error, ...>` |
|
|
85
|
+
| `useQuote` | `UseQueryResult<Result<SolverIntentQuoteResponse, SolverErrorResponse> \| undefined, Error>` — `data?.ok` branching required; polls 3 s |
|
|
86
|
+
| `useSwapAllowance` | `UseQueryResult<boolean, Error>` — `data` is already-unwrapped `boolean \| undefined`; truthy when approved; polls 2 s |
|
|
87
|
+
| `useStatus` | `UseQueryResult<Result<SolverIntentStatusResponse, SolverErrorResponse> \| undefined, Error>` — Result-wrapped like `useQuote`; `data?.ok` branching required; polls 3 s |
|
|
88
|
+
|
|
89
|
+
## Gotchas
|
|
90
|
+
|
|
91
|
+
1. **`Intent.srcChain` and `Intent.dstChain` keep their v1 names.** Even though request-side params use `srcChainKey`/`dstChainKey`, the read-side `Intent` type didn't rename. Don't blanket-replace these names.
|
|
92
|
+
2. **Default `mutationKey` is `['swap']`.** Use `useIsMutating({ mutationKey: ['swap'] })` to get a global "any swap in flight" state. Override via `mutationOptions.mutationKey` if you want narrower scoping per-call.
|
|
93
|
+
3. **Quotes auto-refresh every 3s** — pause polling by setting `queryOptions.refetchInterval: false` if the quote is in a non-visible UI.
|
|
94
|
+
4. **Token list has duplicate addresses across chains.** `sodax.swaps.getSupportedSwapTokens()` returns `Record<SpokeChainKey, readonly XToken[]>`. Flattening it (e.g. `Object.values(...).flat()`) yields multiple tokens that share a contract address (same token deployed on different chains). When rendering a flat token list, use a composite key like `${token.address}-${token.blockchain_id}` — not `token.address` alone.
|
|
95
|
+
|
|
96
|
+
## Cross-references
|
|
97
|
+
|
|
98
|
+
- [`../recipes/swap.md`](../recipes/swap.md) — full worked example.
|
|
99
|
+
- [`../recipes/mutation-error-handling.md`](../recipes/mutation-error-handling.md) — call-shape patterns.
|
|
100
|
+
- [`../../migration/features/swap.md`](../../migration/features/swap.md) — v1 → v2 porting.
|
|
101
|
+
- [`../../../../sdk/ai-exported/integration/features/swap.md`](../../../../sdk/ai-exported/integration/features/swap.md) — underlying SDK swap surface.
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Quickstart — `@sodax/dapp-kit` v2
|
|
2
|
+
|
|
3
|
+
Get a React app running with dapp-kit in five minutes. For copy-paste recipes per feature, see [`recipes/`](recipes/). For design rationale, see [`architecture.md`](architecture.md).
|
|
4
|
+
|
|
5
|
+
## 1. Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Required
|
|
9
|
+
pnpm add @sodax/dapp-kit @tanstack/react-query
|
|
10
|
+
|
|
11
|
+
# Wallet connectivity (the canonical companion)
|
|
12
|
+
pnpm add @sodax/wallet-sdk-react
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`@sodax/dapp-kit` peers on `react`, `react-dom` (>=18), and `@tanstack/react-query`. It re-exports `@sodax/sdk` — don't add `@sodax/types` separately.
|
|
16
|
+
|
|
17
|
+
## 2. Wire providers
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
// providers.tsx
|
|
21
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
22
|
+
import { SodaxProvider, createSodaxQueryClient } from '@sodax/dapp-kit';
|
|
23
|
+
import { SodaxWalletProvider, type SodaxWalletConfig } from '@sodax/wallet-sdk-react';
|
|
24
|
+
import { ChainKeys, type DeepPartial, type SodaxConfig } from '@sodax/sdk';
|
|
25
|
+
|
|
26
|
+
const queryClient = createSodaxQueryClient();
|
|
27
|
+
|
|
28
|
+
const sodaxConfig: DeepPartial<SodaxConfig> = {
|
|
29
|
+
chains: {
|
|
30
|
+
[ChainKeys.SONIC_MAINNET]: { rpcUrl: 'https://sonic-rpc.publicnode.com' },
|
|
31
|
+
[ChainKeys.BSC_MAINNET]: { rpcUrl: 'https://bsc-dataseed.binance.org' },
|
|
32
|
+
[ChainKeys.BASE_MAINNET]: { rpcUrl: 'https://mainnet.base.org' },
|
|
33
|
+
[ChainKeys.ARBITRUM_MAINNET]: { rpcUrl: 'https://arb1.arbitrum.io/rpc' },
|
|
34
|
+
// Add chains your dApp needs
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const walletConfig: SodaxWalletConfig = {
|
|
39
|
+
EVM: {
|
|
40
|
+
chains: {
|
|
41
|
+
[ChainKeys.BSC_MAINNET]: { rpcUrl: 'https://bsc-dataseed.binance.org' },
|
|
42
|
+
[ChainKeys.BASE_MAINNET]: { rpcUrl: 'https://mainnet.base.org' },
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export function Providers({ children }: { children: React.ReactNode }) {
|
|
48
|
+
return (
|
|
49
|
+
<SodaxProvider config={sodaxConfig}>
|
|
50
|
+
<QueryClientProvider client={queryClient}>
|
|
51
|
+
<SodaxWalletProvider config={walletConfig}>
|
|
52
|
+
{children}
|
|
53
|
+
</SodaxWalletProvider>
|
|
54
|
+
</QueryClientProvider>
|
|
55
|
+
</SodaxProvider>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`createSodaxQueryClient` gives you a `QueryClient` pre-wired with global mutation observability. Optional — if you construct your own `QueryClient`, nothing changes. See [`recipes/observability.md`](recipes/observability.md).
|
|
61
|
+
|
|
62
|
+
## 3. Initialize the SDK (optional)
|
|
63
|
+
|
|
64
|
+
For the latest tokens / chains / fee parameters from the backend:
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useEffect } from 'react';
|
|
68
|
+
import { useSodaxContext } from '@sodax/dapp-kit';
|
|
69
|
+
|
|
70
|
+
export function useInitializeSodax() {
|
|
71
|
+
const { sodax } = useSodaxContext();
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
sodax.config.initialize().then((result) => {
|
|
74
|
+
if (!result.ok) console.error('Failed to initialize Sodax:', result.error);
|
|
75
|
+
});
|
|
76
|
+
}, [sodax]);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Skipping this works — feature services fall back to packaged defaults — but you'll miss tokens / chains added after the SDK release.
|
|
81
|
+
|
|
82
|
+
## 4. Get a wallet provider
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
86
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
87
|
+
|
|
88
|
+
function MyFeature() {
|
|
89
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
|
|
90
|
+
// undefined until the user connects a BSC wallet
|
|
91
|
+
return <button disabled={!walletProvider}>...</button>;
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
`useWalletProvider` returns a chain-specific wallet provider object that satisfies `IEvmWalletProvider` (or `IIconWalletProvider`, `ISolanaWalletProvider`, etc., depending on the chain).
|
|
96
|
+
|
|
97
|
+
## 5. Run a mutation
|
|
98
|
+
|
|
99
|
+
The canonical pattern: hook takes `{ mutationOptions }` (optional); domain inputs flow through `mutate(vars)`. Use `mutateAsyncSafe` for explicit `Result<T>` branching:
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
import { useSwap } from '@sodax/dapp-kit';
|
|
103
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
104
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
105
|
+
import type { CreateIntentParams } from '@sodax/sdk';
|
|
106
|
+
|
|
107
|
+
function SwapButton({ intentParams }: { intentParams: CreateIntentParams }) {
|
|
108
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BSC_MAINNET });
|
|
109
|
+
const { mutateAsyncSafe: swap, isPending } = useSwap();
|
|
110
|
+
|
|
111
|
+
const handleSwap = async () => {
|
|
112
|
+
if (!walletProvider) return;
|
|
113
|
+
const result = await swap({ params: intentParams, walletProvider });
|
|
114
|
+
if (!result.ok) {
|
|
115
|
+
alert(result.error instanceof Error ? result.error.message : 'Swap failed');
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
console.log('Swap submitted!', result.value);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<button onClick={handleSwap} disabled={isPending || !walletProvider}>
|
|
123
|
+
{isPending ? 'Swapping...' : 'Swap'}
|
|
124
|
+
</button>
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The exact same pattern works for every mutation: `useBridge`, `useSupply`, `useStake`, `useDexDeposit`, etc. The only difference is the `params` shape (each feature's reference doc has the type signature).
|
|
130
|
+
|
|
131
|
+
## 6. Run a query
|
|
132
|
+
|
|
133
|
+
Queries take `{ params, queryOptions }`. The hook owns `queryKey`, `queryFn`, and `enabled`:
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
import { useQuote } from '@sodax/dapp-kit';
|
|
137
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
138
|
+
|
|
139
|
+
function SwapQuote({ amount }: { amount: bigint }) {
|
|
140
|
+
const { data: quoteResult, isLoading } = useQuote({
|
|
141
|
+
params: {
|
|
142
|
+
payload: amount > 0n
|
|
143
|
+
? {
|
|
144
|
+
token_src: '0x0000000000000000000000000000000000000000',
|
|
145
|
+
token_dst: '0x0000000000000000000000000000000000000000',
|
|
146
|
+
token_src_blockchain_id: ChainKeys.BSC_MAINNET,
|
|
147
|
+
token_dst_blockchain_id: ChainKeys.ARBITRUM_MAINNET,
|
|
148
|
+
amount,
|
|
149
|
+
quote_type: 'exact_input',
|
|
150
|
+
}
|
|
151
|
+
: undefined,
|
|
152
|
+
},
|
|
153
|
+
queryOptions: { staleTime: 3000 },
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
if (isLoading) return <p>Loading...</p>;
|
|
157
|
+
if (quoteResult?.ok) return <p>Output: {quoteResult.value.quoted_amount}</p>;
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Some query hooks return `Result<T>` as their `data` (the underlying SDK method returns Result and we surface it directly for query hooks; only mutations unwrap). Always check `.ok` before reading `.value`.
|
|
163
|
+
|
|
164
|
+
## First-time troubleshooting
|
|
165
|
+
|
|
166
|
+
| Error | Why | Fix |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `Module '"@sodax/dapp-kit"' has no exported member 'useSpokeProvider'` | v1 hook deleted in v2. | Drop the import. Pass `walletProvider` (from `useWalletProvider`) into `mutate(vars)` instead. |
|
|
169
|
+
| `Property 'approve' does not exist on type 'SafeUseMutationResult'` | v1 approve hooks returned `{ approve, isLoading, error }`; v2 returns `SafeUseMutationResult`. | Use `mutateAsync` / `mutateAsyncSafe`. `isLoading` → `isPending`. |
|
|
170
|
+
| `Type 'CreateIntentParams' is missing the following properties from ...: walletProvider` | v1 hooks took params at hook-init; v2 takes them via `mutate(vars)`. | Move `params` and `walletProvider` from hook init to `mutate({ params, walletProvider })`. |
|
|
171
|
+
| `Property 'xChainId' does not exist on type 'XToken'` | SDK-leakage rename: `xChainId` → `chainKey` on `XToken` in v2. | Use `xToken.chainKey`. (Note: `useXBalances` params still use `xChainId` for the request shape — that's distinct from the read shape.) |
|
|
172
|
+
| `Type ... is missing the following properties from type 'MoneyMarketSupplyParams': srcChainKey, srcAddress` | SDK-leakage: v2 added required `srcChainKey` + `srcAddress` to action params. | Add both to your `params` payload. See [`features/money-market.md`](features/money-market.md). |
|
|
173
|
+
| `Cannot read properties of undefined (reading 'sodax')` | `useSodaxContext` (or any dapp-kit hook) called outside `<SodaxProvider>`. | Wrap your component tree in `<SodaxProvider>` from this package. |
|
|
174
|
+
|
|
175
|
+
For broader v1 → v2 migration, see [`../migration/README.md`](../migration/README.md).
|
|
176
|
+
|
|
177
|
+
## What to read next
|
|
178
|
+
|
|
179
|
+
- [`recipes/`](recipes/) — copy-paste patterns for each feature and cross-cutting concerns.
|
|
180
|
+
- [`architecture.md`](architecture.md) — full design rationale for `useSafeMutation`, `unwrapResult`, queryKey conventions, etc.
|
|
181
|
+
- [`features/<x>.md`](features/) — per-feature reference (hook tables, types, gotchas).
|
|
182
|
+
- [`reference/hooks-index.md`](reference/hooks-index.md) — full hook table.
|
|
183
|
+
- [`ai-rules.md`](ai-rules.md) — DO / DO NOT for AI agents writing dapp-kit code.
|
|
184
|
+
|
|
185
|
+
## Cross-references
|
|
186
|
+
|
|
187
|
+
- [`../../../sdk/ai-exported/AGENTS.md`](../../../sdk/ai-exported/AGENTS.md) — the underlying Core SDK's tree (resolves correctly in `node_modules/@sodax/`-layout). Useful when you hit SDK-level types or behaviors leaking through hook signatures.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Recipes — `@sodax/dapp-kit`
|
|
2
|
+
|
|
3
|
+
Copy-paste patterns for adding SODAX features to a React app. Each recipe is self-contained and shows the canonical v2 hook shape (single-object params, `mutateAsyncSafe` for imperative flows, `Result<T>` handling).
|
|
4
|
+
|
|
5
|
+
## Reading order
|
|
6
|
+
|
|
7
|
+
1. **[`setup.md`](setup.md)** — Install packages, wire `SodaxProvider` + `QueryClientProvider`, optional `createSodaxQueryClient` for global mutation observability.
|
|
8
|
+
2. **[`wallet-connectivity.md`](wallet-connectivity.md)** — Connect wallets via `@sodax/wallet-sdk-react`, get a typed `walletProvider` per chain, fetch token balances.
|
|
9
|
+
3. Pick a feature recipe — each one is independent of the others.
|
|
10
|
+
|
|
11
|
+
## Index
|
|
12
|
+
|
|
13
|
+
### Foundation
|
|
14
|
+
|
|
15
|
+
| Recipe | Purpose |
|
|
16
|
+
|---|---|
|
|
17
|
+
| [`setup.md`](setup.md) | Install packages, wire providers, optional `createSodaxQueryClient` |
|
|
18
|
+
| [`wallet-connectivity.md`](wallet-connectivity.md) | Wallet connection, `useWalletProvider`, balance hooks |
|
|
19
|
+
|
|
20
|
+
### Cross-cutting patterns
|
|
21
|
+
|
|
22
|
+
| Recipe | Purpose |
|
|
23
|
+
|---|---|
|
|
24
|
+
| [`mutation-error-handling.md`](mutation-error-handling.md) | Pick between `mutate` / `mutateAsync` / `mutateAsyncSafe` |
|
|
25
|
+
| [`observability.md`](observability.md) | Global mutation logging via `createSodaxQueryClient`, per-mutation `meta.silent` |
|
|
26
|
+
| [`invalidations.md`](invalidations.md) | Hook-owned invalidations and how to compose your own `onSuccess` |
|
|
27
|
+
|
|
28
|
+
### Per-feature
|
|
29
|
+
|
|
30
|
+
| Recipe | Hooks covered |
|
|
31
|
+
|---|---|
|
|
32
|
+
| [`swap.md`](swap.md) | `useQuote`, `useSwap`, `useSwapAllowance`, `useSwapApprove`, limit orders |
|
|
33
|
+
| [`bridge.md`](bridge.md) | `useBridge`, allowance/approval, bridgeable amounts/tokens |
|
|
34
|
+
| [`money-market.md`](money-market.md) | `useSupply`, `useBorrow`, `useWithdraw`, `useRepay`, reserves data |
|
|
35
|
+
| [`staking.md`](staking.md) | `useStake`, `useUnstake`, `useClaim`, staking info, ratios |
|
|
36
|
+
| [`migration.md`](migration.md) | `useMigrateIcxToSoda`, `useRevertMigrateSodaToIcx`, `useMigratebnUSD`, `useMigrateBaln` |
|
|
37
|
+
| [`dex.md`](dex.md) | `useDexDeposit`, `useSupplyLiquidity`, positions, pools |
|
|
38
|
+
| [`bitcoin.md`](bitcoin.md) | `useRadfiSession`, `useFundTradingWallet`, `useRadfiWithdraw`, UTXO management |
|
|
39
|
+
| [`backend-queries.md`](backend-queries.md) | Intent tracking, orderbook, money market position queries (read-only, no wallet) |
|
|
40
|
+
|
|
41
|
+
## Hook conventions (mandatory)
|
|
42
|
+
|
|
43
|
+
These rules are enforced across every dapp-kit hook by [`packages/dapp-kit/src/hooks/_mutationContract.test.ts`](../../../src/hooks/_mutationContract.test.ts) and apply to everything you write against this package.
|
|
44
|
+
|
|
45
|
+
### Single-object params
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { useSwap, useSwapAllowance } from '@sodax/dapp-kit';
|
|
49
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
50
|
+
|
|
51
|
+
// Query hooks — { params, queryOptions }
|
|
52
|
+
// Note: many query hooks wrap the SDK request under `params.payload`; some nest sibling
|
|
53
|
+
// fields like `walletProvider` or `srcChainKey` under `params` alongside `payload`.
|
|
54
|
+
// `useSwapAllowance` is one such hook — see features/swap.md for the canonical shape.
|
|
55
|
+
const { data: isApproved } = useSwapAllowance({
|
|
56
|
+
params: { payload: intentParams, srcChainKey: ChainKeys.BSC_MAINNET, walletProvider },
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Mutation hooks — hook takes only mutationOptions; domain inputs flow through mutate(vars)
|
|
60
|
+
const { mutateAsync: swap } = useSwap();
|
|
61
|
+
async function runSwap() {
|
|
62
|
+
if (!walletProvider) return;
|
|
63
|
+
await swap({ params: intentParams, walletProvider });
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
No positional args. No `spokeProvider` at the hook level (that was v1; deleted in v2). All domain inputs (`params`, `walletProvider`, per-call config) flow through `mutate(vars)` for mutations and through `params` for queries.
|
|
68
|
+
|
|
69
|
+
### `mutateAsyncSafe`
|
|
70
|
+
|
|
71
|
+
Every mutation hook returns three call shapes. `mutateAsyncSafe` is the recommended default for sequenced flows — it returns `Promise<Result<TData>>` and never rejects:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { useSwap } from '@sodax/dapp-kit';
|
|
75
|
+
|
|
76
|
+
const { mutateAsyncSafe: swap } = useSwap();
|
|
77
|
+
async function runSwap() {
|
|
78
|
+
if (!walletProvider) return;
|
|
79
|
+
const result = await swap({ params: intentParams, walletProvider });
|
|
80
|
+
if (!result.ok) { toast.error(result.error instanceof Error ? result.error.message : 'failed'); return; }
|
|
81
|
+
const { intent } = result.value;
|
|
82
|
+
console.log(intent);
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Full comparison in [`mutation-error-handling.md`](mutation-error-handling.md).
|
|
87
|
+
|
|
88
|
+
### `queryOptions`
|
|
89
|
+
|
|
90
|
+
All query hooks accept optional `queryOptions` to override React Query defaults. The hook owns `queryKey`, `queryFn`, and `enabled` — those are not consumer-overridable.
|
|
91
|
+
|
|
92
|
+
```tsx
|
|
93
|
+
import { useQuote } from '@sodax/dapp-kit';
|
|
94
|
+
|
|
95
|
+
// `useQuote` wraps the SDK request under `params.payload` — don't pass the SDK request
|
|
96
|
+
// directly under `params`. `payload` here is a `SolverIntentQuoteRequest`.
|
|
97
|
+
const { data } = useQuote({
|
|
98
|
+
params: { payload },
|
|
99
|
+
queryOptions: { staleTime: 5000, refetchInterval: 10000 },
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `Result<T>` in query hooks
|
|
104
|
+
|
|
105
|
+
Some query hooks return `Result<T>` as their `data` (the underlying SDK method can fail). Always check `.ok` before accessing `.value`:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import { useQuote } from '@sodax/dapp-kit';
|
|
109
|
+
|
|
110
|
+
// useQuote nests the SDK request under params.payload. `payload` here is a `SolverIntentQuoteRequest`.
|
|
111
|
+
const { data: quoteResult } = useQuote({ params: { payload } });
|
|
112
|
+
if (quoteResult?.ok) {
|
|
113
|
+
const quote = quoteResult.value;
|
|
114
|
+
console.log(quote);
|
|
115
|
+
} else {
|
|
116
|
+
console.error(quoteResult?.error);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### `bigint` for amounts
|
|
121
|
+
|
|
122
|
+
Token amounts are `bigint` scaled by decimals. Use `viem`'s `parseUnits` / `formatUnits`:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
import { parseUnits, formatUnits } from 'viem';
|
|
126
|
+
const amount = parseUnits('1.5', 18); // 1500000000000000000n
|
|
127
|
+
const display = formatUnits(amount, 18); // '1.5'
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Backend / non-React consumers
|
|
131
|
+
|
|
132
|
+
If you're building a backend (API server, bot, script), you don't need `@sodax/dapp-kit` at all — use `@sodax/sdk` directly. The SDK has its own AI-agent docs at `node_modules/@sodax/sdk/ai-exported/AGENTS.md`.
|
|
133
|
+
|
|
134
|
+
## Migration pointer
|
|
135
|
+
|
|
136
|
+
If you're porting v1 dapp-kit code to v2, start at [`../../migration/README.md`](../../migration/README.md). It covers: hook signatures (single-arg policy), `Result<T>` handling shift, deleted `useSpokeProvider`, queryKey conventions, and SDK leakage.
|