@sodax/skills 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/.claude-plugin/plugin.json +13 -0
- package/AGENTS.md +81 -0
- package/LICENSE +21 -0
- package/README.md +49 -0
- package/knowledge/dapp-kit/AGENTS.md +50 -0
- package/knowledge/dapp-kit/integration/README.md +49 -0
- package/knowledge/dapp-kit/integration/ai-rules.md +80 -0
- package/knowledge/dapp-kit/integration/architecture.md +276 -0
- package/knowledge/dapp-kit/integration/features/README.md +29 -0
- package/knowledge/dapp-kit/integration/features/auxiliary-services.md +169 -0
- package/knowledge/dapp-kit/integration/features/bitcoin.md +87 -0
- package/knowledge/dapp-kit/integration/features/bridge.md +91 -0
- package/knowledge/dapp-kit/integration/features/dex.md +152 -0
- package/knowledge/dapp-kit/integration/features/migration.md +118 -0
- package/knowledge/dapp-kit/integration/features/money-market.md +144 -0
- package/knowledge/dapp-kit/integration/features/staking.md +123 -0
- package/knowledge/dapp-kit/integration/features/swap.md +101 -0
- package/knowledge/dapp-kit/integration/quickstart.md +188 -0
- package/knowledge/dapp-kit/integration/recipes/README.md +136 -0
- package/knowledge/dapp-kit/integration/recipes/backend-queries.md +157 -0
- package/knowledge/dapp-kit/integration/recipes/bitcoin.md +193 -0
- package/knowledge/dapp-kit/integration/recipes/bridge.md +174 -0
- package/knowledge/dapp-kit/integration/recipes/dex.md +204 -0
- package/knowledge/dapp-kit/integration/recipes/invalidations.md +115 -0
- package/knowledge/dapp-kit/integration/recipes/migration.md +212 -0
- package/knowledge/dapp-kit/integration/recipes/money-market.md +207 -0
- package/knowledge/dapp-kit/integration/recipes/mutation-error-handling.md +118 -0
- package/knowledge/dapp-kit/integration/recipes/observability.md +93 -0
- package/knowledge/dapp-kit/integration/recipes/setup.md +168 -0
- package/knowledge/dapp-kit/integration/recipes/staking.md +202 -0
- package/knowledge/dapp-kit/integration/recipes/swap.md +272 -0
- package/knowledge/dapp-kit/integration/recipes/wallet-connectivity.md +128 -0
- package/knowledge/dapp-kit/integration/reference/README.md +12 -0
- package/knowledge/dapp-kit/integration/reference/glossary.md +190 -0
- package/knowledge/dapp-kit/integration/reference/hooks-index.md +190 -0
- package/knowledge/dapp-kit/integration/reference/public-api.md +110 -0
- package/knowledge/dapp-kit/integration/reference/querykey-conventions.md +179 -0
- package/knowledge/dapp-kit/migration/README.md +60 -0
- package/knowledge/dapp-kit/migration/ai-rules.md +81 -0
- package/knowledge/dapp-kit/migration/breaking-changes/hook-signatures.md +233 -0
- package/knowledge/dapp-kit/migration/breaking-changes/querykey-conventions.md +108 -0
- package/knowledge/dapp-kit/migration/breaking-changes/result-handling.md +211 -0
- package/knowledge/dapp-kit/migration/breaking-changes/sdk-leakage.md +167 -0
- package/knowledge/dapp-kit/migration/checklist.md +89 -0
- package/knowledge/dapp-kit/migration/features/README.md +34 -0
- package/knowledge/dapp-kit/migration/features/auxiliary-services.md +114 -0
- package/knowledge/dapp-kit/migration/features/bitcoin.md +88 -0
- package/knowledge/dapp-kit/migration/features/bridge.md +160 -0
- package/knowledge/dapp-kit/migration/features/dex.md +101 -0
- package/knowledge/dapp-kit/migration/features/migration.md +120 -0
- package/knowledge/dapp-kit/migration/features/money-market.md +139 -0
- package/knowledge/dapp-kit/migration/features/staking.md +109 -0
- package/knowledge/dapp-kit/migration/features/swap.md +133 -0
- package/knowledge/dapp-kit/migration/recipes.md +185 -0
- package/knowledge/dapp-kit/migration/reference/README.md +15 -0
- package/knowledge/dapp-kit/migration/reference/deleted-hooks.md +110 -0
- package/knowledge/dapp-kit/migration/reference/error-shape-crosswalk.md +144 -0
- package/knowledge/dapp-kit/migration/reference/renamed-hooks.md +68 -0
- package/knowledge/sdk/AGENTS.md +41 -0
- package/knowledge/sdk/integration/README.md +41 -0
- package/knowledge/sdk/integration/ai-rules.md +75 -0
- package/knowledge/sdk/integration/architecture.md +533 -0
- package/knowledge/sdk/integration/chain-specifics.md +189 -0
- package/knowledge/sdk/integration/features/README.md +19 -0
- package/knowledge/sdk/integration/features/auxiliary-services.md +189 -0
- package/knowledge/sdk/integration/features/bridge.md +136 -0
- package/knowledge/sdk/integration/features/dex.md +182 -0
- package/knowledge/sdk/integration/features/icx-bnusd-baln.md +181 -0
- package/knowledge/sdk/integration/features/money-market.md +198 -0
- package/knowledge/sdk/integration/features/staking.md +166 -0
- package/knowledge/sdk/integration/features/swap.md +207 -0
- package/knowledge/sdk/integration/quickstart.md +213 -0
- package/knowledge/sdk/integration/recipes/README.md +21 -0
- package/knowledge/sdk/integration/recipes/backend-server-init.md +69 -0
- package/knowledge/sdk/integration/recipes/chain-key-narrowing.md +65 -0
- package/knowledge/sdk/integration/recipes/gas-estimation.md +33 -0
- package/knowledge/sdk/integration/recipes/initialize-sodax.md +78 -0
- package/knowledge/sdk/integration/recipes/raw-tx-flow.md +71 -0
- package/knowledge/sdk/integration/recipes/result-and-errors.md +104 -0
- package/knowledge/sdk/integration/recipes/signed-tx-flow.md +46 -0
- package/knowledge/sdk/integration/recipes/testing.md +101 -0
- package/knowledge/sdk/integration/reference/README.md +18 -0
- package/knowledge/sdk/integration/reference/chain-keys.md +67 -0
- package/knowledge/sdk/integration/reference/error-codes.md +165 -0
- package/knowledge/sdk/integration/reference/glossary.md +32 -0
- package/knowledge/sdk/integration/reference/public-api.md +138 -0
- package/knowledge/sdk/integration/reference/wallet-providers.md +62 -0
- package/knowledge/sdk/migration/README.md +58 -0
- package/knowledge/sdk/migration/ai-rules.md +80 -0
- package/knowledge/sdk/migration/breaking-changes/architecture.md +344 -0
- package/knowledge/sdk/migration/breaking-changes/result-and-errors.md +363 -0
- package/knowledge/sdk/migration/breaking-changes/type-system.md +341 -0
- package/knowledge/sdk/migration/checklist.md +67 -0
- package/knowledge/sdk/migration/features/README.md +35 -0
- package/knowledge/sdk/migration/features/auxiliary-services.md +156 -0
- package/knowledge/sdk/migration/features/bridge.md +128 -0
- package/knowledge/sdk/migration/features/dex.md +143 -0
- package/knowledge/sdk/migration/features/icx-bnusd-baln.md +151 -0
- package/knowledge/sdk/migration/features/money-market.md +214 -0
- package/knowledge/sdk/migration/features/staking.md +138 -0
- package/knowledge/sdk/migration/features/swap.md +198 -0
- package/knowledge/sdk/migration/recipes.md +350 -0
- package/knowledge/sdk/migration/reference/README.md +18 -0
- package/knowledge/sdk/migration/reference/deleted-exports.md +127 -0
- package/knowledge/sdk/migration/reference/error-code-crosswalk.md +104 -0
- package/knowledge/sdk/migration/reference/return-shapes.md +49 -0
- package/knowledge/sdk/migration/reference/sodax-config.md +145 -0
- package/knowledge/wallet-sdk-core/AGENTS.md +43 -0
- package/knowledge/wallet-sdk-core/integration/README.md +108 -0
- package/knowledge/wallet-sdk-core/integration/ai-rules.md +141 -0
- package/knowledge/wallet-sdk-core/integration/architecture.md +212 -0
- package/knowledge/wallet-sdk-core/integration/features/README.md +22 -0
- package/knowledge/wallet-sdk-core/integration/features/bitcoin.md +103 -0
- package/knowledge/wallet-sdk-core/integration/features/evm.md +102 -0
- package/knowledge/wallet-sdk-core/integration/features/icon.md +88 -0
- package/knowledge/wallet-sdk-core/integration/features/injective.md +92 -0
- package/knowledge/wallet-sdk-core/integration/features/near.md +92 -0
- package/knowledge/wallet-sdk-core/integration/features/solana.md +104 -0
- package/knowledge/wallet-sdk-core/integration/features/stacks.md +91 -0
- package/knowledge/wallet-sdk-core/integration/features/stellar.md +95 -0
- package/knowledge/wallet-sdk-core/integration/features/sui.md +96 -0
- package/knowledge/wallet-sdk-core/integration/quickstart.md +259 -0
- package/knowledge/wallet-sdk-core/integration/recipes/README.md +15 -0
- package/knowledge/wallet-sdk-core/integration/recipes/bridge-to-sdk.md +145 -0
- package/knowledge/wallet-sdk-core/integration/recipes/defaults-and-overrides.md +159 -0
- package/knowledge/wallet-sdk-core/integration/recipes/library-exports.md +129 -0
- package/knowledge/wallet-sdk-core/integration/recipes/setup-browser-extension.md +137 -0
- package/knowledge/wallet-sdk-core/integration/recipes/setup-private-key.md +115 -0
- package/knowledge/wallet-sdk-core/integration/recipes/sign-and-broadcast.md +201 -0
- package/knowledge/wallet-sdk-core/integration/recipes/testing.md +163 -0
- package/knowledge/wallet-sdk-core/integration/reference/README.md +13 -0
- package/knowledge/wallet-sdk-core/integration/reference/chain-support.md +65 -0
- package/knowledge/wallet-sdk-core/integration/reference/glossary.md +28 -0
- package/knowledge/wallet-sdk-core/integration/reference/interfaces.md +131 -0
- package/knowledge/wallet-sdk-core/integration/reference/provider-classes.md +54 -0
- package/knowledge/wallet-sdk-core/integration/reference/public-api.md +128 -0
- package/knowledge/wallet-sdk-core/migration/README.md +84 -0
- package/knowledge/wallet-sdk-core/migration/ai-rules.md +139 -0
- package/knowledge/wallet-sdk-core/migration/breaking-changes/README.md +14 -0
- package/knowledge/wallet-sdk-core/migration/breaking-changes/base-wallet-provider.md +52 -0
- package/knowledge/wallet-sdk-core/migration/breaking-changes/defaults-config.md +57 -0
- package/knowledge/wallet-sdk-core/migration/breaking-changes/folder-layout.md +99 -0
- package/knowledge/wallet-sdk-core/migration/breaking-changes/library-exports.md +58 -0
- package/knowledge/wallet-sdk-core/migration/checklist.md +62 -0
- package/knowledge/wallet-sdk-core/migration/recipes/README.md +12 -0
- package/knowledge/wallet-sdk-core/migration/recipes/adopt-defaults.md +84 -0
- package/knowledge/wallet-sdk-core/migration/recipes/adopt-library-exports.md +99 -0
- package/knowledge/wallet-sdk-core/migration/reference/README.md +12 -0
- package/knowledge/wallet-sdk-core/migration/reference/added-fields.md +71 -0
- package/knowledge/wallet-sdk-core/migration/reference/deleted-exports.md +35 -0
- package/knowledge/wallet-sdk-core/migration/reference/renamed-symbols.md +31 -0
- package/knowledge/wallet-sdk-core/migration/reference/return-shapes.md +23 -0
- package/knowledge/wallet-sdk-react/AGENTS.md +46 -0
- package/knowledge/wallet-sdk-react/integration/README.md +103 -0
- package/knowledge/wallet-sdk-react/integration/ai-rules.md +136 -0
- package/knowledge/wallet-sdk-react/integration/architecture.md +185 -0
- package/knowledge/wallet-sdk-react/integration/examples/01-minimal-evm.tsx +75 -0
- package/knowledge/wallet-sdk-react/integration/examples/02-multi-chain-modal.tsx +169 -0
- package/knowledge/wallet-sdk-react/integration/examples/03-nextjs-app-router.tsx +99 -0
- package/knowledge/wallet-sdk-react/integration/examples/04-walletconnect-setup.tsx +89 -0
- package/knowledge/wallet-sdk-react/integration/examples/README.md +29 -0
- package/knowledge/wallet-sdk-react/integration/recipes/batch-operations.md +224 -0
- package/knowledge/wallet-sdk-react/integration/recipes/bridge-to-sdk.md +165 -0
- package/knowledge/wallet-sdk-react/integration/recipes/chain-detection.md +259 -0
- package/knowledge/wallet-sdk-react/integration/recipes/connect-button.md +159 -0
- package/knowledge/wallet-sdk-react/integration/recipes/multi-chain-modal.md +203 -0
- package/knowledge/wallet-sdk-react/integration/recipes/setup.md +163 -0
- package/knowledge/wallet-sdk-react/integration/recipes/sign-message.md +138 -0
- package/knowledge/wallet-sdk-react/integration/recipes/sub-path-imports.md +97 -0
- package/knowledge/wallet-sdk-react/integration/recipes/switch-chain.md +144 -0
- package/knowledge/wallet-sdk-react/integration/recipes/walletconnect-setup.md +139 -0
- package/knowledge/wallet-sdk-react/integration/reference/api-surface.md +176 -0
- package/knowledge/wallet-sdk-react/integration/reference/chain-support.md +79 -0
- package/knowledge/wallet-sdk-react/integration/reference/connectors.md +75 -0
- package/knowledge/wallet-sdk-react/integration/reference/hooks.md +212 -0
- package/knowledge/wallet-sdk-react/integration/reference/wallet-brands.md +107 -0
- package/knowledge/wallet-sdk-react/migration/README.md +49 -0
- package/knowledge/wallet-sdk-react/migration/ai-rules.md +144 -0
- package/knowledge/wallet-sdk-react/migration/breaking-changes.md +310 -0
- package/knowledge/wallet-sdk-react/migration/checklist.md +159 -0
- package/knowledge/wallet-sdk-react/migration/recipes/connect-button.md +170 -0
- package/knowledge/wallet-sdk-react/migration/recipes/multi-chain-modal.md +245 -0
- package/knowledge/wallet-sdk-react/migration/recipes/ssr-setup.md +165 -0
- package/knowledge/wallet-sdk-react/migration/recipes/walletconnect-migration.md +170 -0
- package/knowledge/wallet-sdk-react/migration/reference/components.md +75 -0
- package/knowledge/wallet-sdk-react/migration/reference/config.md +339 -0
- package/knowledge/wallet-sdk-react/migration/reference/hooks.md +336 -0
- package/knowledge/wallet-sdk-react/migration/reference/imports.md +158 -0
- package/package.json +59 -0
- package/skills/sodax-dapp-kit-integration/SKILL.md +71 -0
- package/skills/sodax-dapp-kit-migration/SKILL.md +58 -0
- package/skills/sodax-sdk-integration/SKILL.md +66 -0
- package/skills/sodax-sdk-migration/SKILL.md +75 -0
- package/skills/sodax-wallet-sdk-core-integration/SKILL.md +55 -0
- package/skills/sodax-wallet-sdk-core-migration/SKILL.md +56 -0
- package/skills/sodax-wallet-sdk-react-integration/SKILL.md +80 -0
- package/skills/sodax-wallet-sdk-react-migration/SKILL.md +71 -0
|
@@ -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 knowledge tree shipped via `@sodax/skills` — load the `sodax-sdk-integration` skill or read `node_modules/@sodax/skills/knowledge/sdk/AGENTS.md` directly.
|
|
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.
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Recipe: Backend Queries
|
|
2
|
+
|
|
3
|
+
Read-only data hooks. No wallet connection required.
|
|
4
|
+
|
|
5
|
+
**Depends on:** [setup.md](setup.md)
|
|
6
|
+
|
|
7
|
+
## Hooks
|
|
8
|
+
|
|
9
|
+
### Intents
|
|
10
|
+
|
|
11
|
+
| Hook | Purpose |
|
|
12
|
+
|------|---------|
|
|
13
|
+
| `useBackendIntentByTxHash` | Intent by hub chain tx hash (polls 1s) |
|
|
14
|
+
| `useBackendIntentByHash` | Intent by intent hash |
|
|
15
|
+
| `useBackendUserIntents` | All intents for a user with date filtering |
|
|
16
|
+
|
|
17
|
+
### Orderbook
|
|
18
|
+
|
|
19
|
+
| Hook | Purpose |
|
|
20
|
+
|------|---------|
|
|
21
|
+
| `useBackendOrderbook` | Solver orderbook with pagination (cached 30s, no auto-refetch) |
|
|
22
|
+
|
|
23
|
+
### Money Market
|
|
24
|
+
|
|
25
|
+
| Hook | Purpose |
|
|
26
|
+
|------|---------|
|
|
27
|
+
| `useBackendMoneyMarketPosition` | User's money market position |
|
|
28
|
+
| `useBackendMoneyMarketAsset` | Specific asset details |
|
|
29
|
+
| `useBackendAllMoneyMarketAssets` | All money market assets |
|
|
30
|
+
| `useBackendMoneyMarketAssetSuppliers` | Suppliers for an asset |
|
|
31
|
+
| `useBackendMoneyMarketAssetBorrowers` | Borrowers for an asset |
|
|
32
|
+
| `useBackendAllMoneyMarketBorrowers` | All borrowers |
|
|
33
|
+
|
|
34
|
+
### Swap Submission
|
|
35
|
+
|
|
36
|
+
| Hook | Purpose |
|
|
37
|
+
|------|---------|
|
|
38
|
+
| `useBackendSubmitSwapTx` | Submit swap tx to backend |
|
|
39
|
+
| `useBackendSubmitSwapTxStatus` | Check submitted swap status |
|
|
40
|
+
|
|
41
|
+
## Track Intent
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { useBackendIntentByTxHash } from '@sodax/dapp-kit';
|
|
45
|
+
|
|
46
|
+
function IntentTracker({ txHash }: { txHash: string }) {
|
|
47
|
+
const { data: intent, isLoading } = useBackendIntentByTxHash({
|
|
48
|
+
params: { txHash },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
if (isLoading) return <div>Loading...</div>;
|
|
52
|
+
return <pre>{JSON.stringify(intent, null, 2)}</pre>;
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## User Intent History
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { useBackendUserIntents } from '@sodax/dapp-kit';
|
|
60
|
+
|
|
61
|
+
function IntentHistory({ userAddress }: { userAddress: `0x${string}` }) {
|
|
62
|
+
const { data: intents } = useBackendUserIntents({
|
|
63
|
+
params: {
|
|
64
|
+
userAddress,
|
|
65
|
+
startDate: Date.now() - 7 * 24 * 60 * 60 * 1000,
|
|
66
|
+
endDate: Date.now(),
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<div>
|
|
72
|
+
{intents?.items.map((intent, i) => (
|
|
73
|
+
<div key={i}>
|
|
74
|
+
<p>{intent.intentHash} -- {intent.open ? 'open' : 'closed'}</p>
|
|
75
|
+
</div>
|
|
76
|
+
))}
|
|
77
|
+
</div>
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Orderbook
|
|
83
|
+
|
|
84
|
+
```tsx
|
|
85
|
+
import { useBackendOrderbook } from '@sodax/dapp-kit';
|
|
86
|
+
|
|
87
|
+
function Orderbook() {
|
|
88
|
+
// `pagination` is nested under `params` per the canonical query-hook shape.
|
|
89
|
+
const { data: orderbook } = useBackendOrderbook({
|
|
90
|
+
params: { pagination: { offset: '0', limit: '20' } },
|
|
91
|
+
});
|
|
92
|
+
return <pre>{JSON.stringify(orderbook, null, 2)}</pre>;
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Money Market Dashboard
|
|
97
|
+
|
|
98
|
+
```tsx
|
|
99
|
+
// @ai-snippets-skip — uses example field name supplyAPY not in MoneyMarketAsset type
|
|
100
|
+
import { useBackendMoneyMarketPosition, useBackendAllMoneyMarketAssets } from '@sodax/dapp-kit';
|
|
101
|
+
|
|
102
|
+
function MMDashboard({ userAddress }: { userAddress: string }) {
|
|
103
|
+
const { data: position } = useBackendMoneyMarketPosition({ params: { userAddress } });
|
|
104
|
+
const { data: assets } = useBackendAllMoneyMarketAssets({});
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div>
|
|
108
|
+
{position && <pre>{JSON.stringify(position, null, 2)}</pre>}
|
|
109
|
+
{assets?.map((a, i) => <p key={i}>{a.symbol}: Supply {a.supplyAPY}%</p>)}
|
|
110
|
+
</div>
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Custom Query Options
|
|
116
|
+
|
|
117
|
+
All read hooks accept `queryOptions` to override defaults:
|
|
118
|
+
|
|
119
|
+
```tsx
|
|
120
|
+
// @ai-snippets-skip
|
|
121
|
+
const { data } = useBackendIntentByTxHash({
|
|
122
|
+
params: { txHash },
|
|
123
|
+
queryOptions: { staleTime: 5000, refetchInterval: 2000, retry: 3 },
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Submit a Swap Tx
|
|
128
|
+
|
|
129
|
+
`useBackendSubmitSwapTx` is a mutation hook. Per-call config (e.g. backend base URL) flows through `mutate(vars)`; TanStack Query knobs flow through the optional `mutationOptions` slot:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
import { useBackendSubmitSwapTx } from '@sodax/dapp-kit';
|
|
133
|
+
|
|
134
|
+
function SubmitButton({ swapPayload, baseURL }) {
|
|
135
|
+
const { mutateAsync: submitSwapTx, isPending } = useBackendSubmitSwapTx({
|
|
136
|
+
mutationOptions: { retry: 5 }, // overrides default retry: 3
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const handleSubmit = async () => {
|
|
140
|
+
const response = await submitSwapTx({
|
|
141
|
+
request: swapPayload,
|
|
142
|
+
apiConfig: { baseURL }, // per-call backend override
|
|
143
|
+
});
|
|
144
|
+
console.log('Submitted:', response);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return <button onClick={handleSubmit} disabled={isPending}>Submit</button>;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Default Polling
|
|
152
|
+
|
|
153
|
+
| Hook | Interval |
|
|
154
|
+
|------|---------|
|
|
155
|
+
| `useBackendIntentByTxHash` | 1s |
|
|
156
|
+
| `useBackendOrderbook` | none (`staleTime: 30s`, no auto-refetch) |
|
|
157
|
+
| Others | No auto-refresh |
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Recipe: Bitcoin (Radfi)
|
|
2
|
+
|
|
3
|
+
Bitcoin trading via the Radfi protocol. Authenticate, fund a trading wallet, trade, withdraw, and manage UTXOs.
|
|
4
|
+
|
|
5
|
+
**Depends on:** [setup.md](setup.md), [wallet-connectivity.md](wallet-connectivity.md)
|
|
6
|
+
|
|
7
|
+
## Hooks
|
|
8
|
+
|
|
9
|
+
### Session
|
|
10
|
+
|
|
11
|
+
| Hook | Type | Purpose |
|
|
12
|
+
|------|------|---------|
|
|
13
|
+
| `useRadfiAuth` | Mutation | Authenticate with Radfi via BIP322 signing |
|
|
14
|
+
| `useRadfiSession` | Utility | Manage full session lifecycle (login, refresh, auto-refresh) |
|
|
15
|
+
| `useTradingWallet` | Utility | Get trading wallet address from persisted session (synchronous) |
|
|
16
|
+
|
|
17
|
+
### Balance
|
|
18
|
+
|
|
19
|
+
| Hook | Type | Purpose |
|
|
20
|
+
|------|------|---------|
|
|
21
|
+
| `useBitcoinBalance` | Query | BTC balance for any address (sums UTXOs from mempool.space) |
|
|
22
|
+
| `useTradingWalletBalance` | Query | Trading wallet balance from Radfi API (confirmed + pending) |
|
|
23
|
+
|
|
24
|
+
### Operations
|
|
25
|
+
|
|
26
|
+
| Hook | Type | Purpose |
|
|
27
|
+
|------|------|---------|
|
|
28
|
+
| `useFundTradingWallet` | Mutation | Send BTC from personal wallet to trading wallet |
|
|
29
|
+
| `useRadfiWithdraw` | Mutation | Withdraw BTC from trading wallet to personal wallet |
|
|
30
|
+
| `useExpiredUtxos` | Query | Fetch UTXOs that need renewal (polls every 60s) |
|
|
31
|
+
| `useRenewUtxos` | Mutation | Renew expired UTXOs in trading wallet |
|
|
32
|
+
|
|
33
|
+
## Session Flow
|
|
34
|
+
|
|
35
|
+
Radfi requires authentication before any trading operation. The typical flow:
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
import { useRadfiSession } from '@sodax/dapp-kit';
|
|
39
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
40
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
41
|
+
|
|
42
|
+
function BitcoinAuth() {
|
|
43
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BITCOIN_MAINNET });
|
|
44
|
+
const { isAuthed, tradingAddress, login, isLoginPending } = useRadfiSession(walletProvider);
|
|
45
|
+
|
|
46
|
+
if (isAuthed) {
|
|
47
|
+
return <p>Authenticated. Trading wallet: {tradingAddress}</p>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<button onClick={login} disabled={isLoginPending}>
|
|
52
|
+
{isLoginPending ? 'Signing...' : 'Login to Radfi'}
|
|
53
|
+
</button>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
`useRadfiSession` handles the full lifecycle:
|
|
59
|
+
- On mount: refreshes token to validate existing session
|
|
60
|
+
- Every 5 min: auto-refreshes access token
|
|
61
|
+
- If refresh fails: clears session, sets `isAuthed = false`
|
|
62
|
+
- Session persisted in localStorage (keyed by wallet address)
|
|
63
|
+
|
|
64
|
+
## Check Balances
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
import { useBitcoinBalance, useTradingWalletBalance, useTradingWallet } from '@sodax/dapp-kit';
|
|
68
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
69
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
70
|
+
|
|
71
|
+
function BitcoinBalances({ walletAddress }: { walletAddress: string }) {
|
|
72
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BITCOIN_MAINNET });
|
|
73
|
+
const { tradingAddress } = useTradingWallet(walletAddress);
|
|
74
|
+
|
|
75
|
+
// Personal wallet balance (from mempool.space)
|
|
76
|
+
const { data: personalBalance } = useBitcoinBalance({
|
|
77
|
+
params: { address: walletAddress },
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Trading wallet balance (from Radfi API). `RadfiWalletBalance` fields:
|
|
81
|
+
// `btcSatoshi`, `pendingSatoshi`, `externalPendingSatoshi`, `totalUtxos`.
|
|
82
|
+
const { data: tradingBalance } = useTradingWalletBalance({
|
|
83
|
+
params: { walletProvider, tradingAddress },
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<div>
|
|
88
|
+
<p>Personal: {personalBalance?.toString() ?? '...'} sats</p>
|
|
89
|
+
<p>Trading: {tradingBalance?.btcSatoshi?.toString() ?? '...'} sats</p>
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Fund Trading Wallet
|
|
96
|
+
|
|
97
|
+
```tsx
|
|
98
|
+
import { useFundTradingWallet } from '@sodax/dapp-kit';
|
|
99
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
100
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
101
|
+
|
|
102
|
+
function FundButton() {
|
|
103
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BITCOIN_MAINNET });
|
|
104
|
+
const { mutateAsyncSafe: fundWallet, isPending } = useFundTradingWallet();
|
|
105
|
+
|
|
106
|
+
const handleFund = async () => {
|
|
107
|
+
if (!walletProvider) return;
|
|
108
|
+
const result = await fundWallet({ amount: 100_000n, walletProvider }); // 100,000 satoshis
|
|
109
|
+
if (result.ok) console.log('Funded:', result.value);
|
|
110
|
+
else console.error('Fund failed:', result.error);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<button onClick={handleFund} disabled={isPending || !walletProvider}>
|
|
115
|
+
{isPending ? 'Funding...' : 'Fund Trading Wallet'}
|
|
116
|
+
</button>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Withdraw from Trading Wallet
|
|
122
|
+
|
|
123
|
+
```tsx
|
|
124
|
+
import { useRadfiWithdraw } from '@sodax/dapp-kit';
|
|
125
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
126
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
127
|
+
|
|
128
|
+
function WithdrawButton({ withdrawTo }: { withdrawTo: string }) {
|
|
129
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BITCOIN_MAINNET });
|
|
130
|
+
const { mutateAsync: withdraw, isPending } = useRadfiWithdraw();
|
|
131
|
+
|
|
132
|
+
const handleWithdraw = async () => {
|
|
133
|
+
if (!walletProvider) return;
|
|
134
|
+
const result = await withdraw({
|
|
135
|
+
amount: '10000',
|
|
136
|
+
tokenId: '0:0',
|
|
137
|
+
withdrawTo, // user's personal BTC address
|
|
138
|
+
walletProvider,
|
|
139
|
+
});
|
|
140
|
+
console.log('Withdrawn:', result.txId, 'Fee:', result.fee);
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<button onClick={handleWithdraw} disabled={isPending || !walletProvider}>
|
|
145
|
+
{isPending ? 'Withdrawing...' : 'Withdraw'}
|
|
146
|
+
</button>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Manage Expired UTXOs
|
|
152
|
+
|
|
153
|
+
UTXOs in the trading wallet can expire. Check and renew them:
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { useExpiredUtxos, useRenewUtxos } from '@sodax/dapp-kit';
|
|
157
|
+
import { useWalletProvider } from '@sodax/wallet-sdk-react';
|
|
158
|
+
import { ChainKeys } from '@sodax/sdk';
|
|
159
|
+
|
|
160
|
+
function UtxoManager({ tradingAddress }: { tradingAddress: string }) {
|
|
161
|
+
const walletProvider = useWalletProvider({ xChainId: ChainKeys.BITCOIN_MAINNET });
|
|
162
|
+
const { data: expiredUtxos } = useExpiredUtxos({
|
|
163
|
+
params: { walletProvider, tradingAddress },
|
|
164
|
+
});
|
|
165
|
+
const { mutateAsync: renewUtxos, isPending } = useRenewUtxos();
|
|
166
|
+
|
|
167
|
+
if (!expiredUtxos?.length) return <p>No expired UTXOs</p>;
|
|
168
|
+
|
|
169
|
+
const handleRenew = async () => {
|
|
170
|
+
if (!walletProvider) return;
|
|
171
|
+
const txIdVouts = expiredUtxos.map((u) => u.txidVout);
|
|
172
|
+
const txId = await renewUtxos({ txIdVouts, walletProvider });
|
|
173
|
+
console.log('Renewed:', txId);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
return (
|
|
177
|
+
<div>
|
|
178
|
+
<p>{expiredUtxos.length} expired UTXOs</p>
|
|
179
|
+
<button onClick={handleRenew} disabled={isPending || !walletProvider}>
|
|
180
|
+
{isPending ? 'Renewing...' : 'Renew UTXOs'}
|
|
181
|
+
</button>
|
|
182
|
+
</div>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Notes
|
|
188
|
+
|
|
189
|
+
- **Authentication required** before any trading operation. `useRadfiSession` manages this automatically.
|
|
190
|
+
- **Trading wallet** is created during first authentication — not a separate step.
|
|
191
|
+
- **`useTradingWallet(walletAddress)`** is a synchronous utility (no network call) — it reads the persisted Radfi session from localStorage.
|
|
192
|
+
- **PSBT signing flow**: withdraw and renew operations build an unsigned PSBT server-side, user signs it locally, then submits back for co-signing and broadcast.
|
|
193
|
+
- **Session tokens** are stored in localStorage keyed by wallet address. They're for API rate-limiting, not for accessing user assets.
|
|
@@ -0,0 +1,174 @@
|
|
|
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
|
+
```
|