@sodax/skills 2.0.0-rc.11 → 2.0.0-rc.12
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/package.json +1 -1
- package/skills/sodax-dapp-kit/SKILL.md +2 -2
- package/skills/sodax-dapp-kit/integration/knowledge/README.md +1 -1
- package/skills/sodax-dapp-kit/integration/knowledge/features/README.md +1 -1
- package/skills/sodax-dapp-kit/integration/knowledge/features/auxiliary-services.md +44 -0
- package/skills/sodax-dapp-kit/integration/knowledge/features/bitcoin.md +6 -6
- package/skills/sodax-dapp-kit/integration/knowledge/features/money-market.md +5 -0
- package/skills/sodax-dapp-kit/integration/knowledge/recipes/bitcoin.md +8 -8
- package/skills/sodax-dapp-kit/integration/knowledge/recipes/wallet-connectivity.md +3 -0
- package/skills/sodax-dapp-kit/integration/knowledge/reference/glossary.md +1 -1
- package/skills/sodax-dapp-kit/integration/knowledge/reference/hooks-index.md +6 -2
- package/skills/sodax-dapp-kit/integration/knowledge/reference/querykey-conventions.md +2 -0
- package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/breaking-changes/hook-signatures.md +1 -1
- package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/breaking-changes/sdk-leakage.md +1 -1
- package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/checklist.md +1 -1
- package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/features/README.md +1 -1
- package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/features/bitcoin.md +2 -2
- package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/reference/renamed-hooks.md +1 -1
- package/skills/sodax-sdk/SKILL.md +1 -1
- package/skills/sodax-sdk/integration/knowledge/README.md +1 -1
- package/skills/sodax-sdk/integration/knowledge/architecture.md +5 -3
- package/skills/sodax-sdk/integration/knowledge/chain-specifics.md +33 -8
- package/skills/sodax-sdk/integration/knowledge/features/bridge.md +1 -0
- package/skills/sodax-sdk/integration/knowledge/features/money-market.md +1 -0
- package/skills/sodax-sdk/integration/knowledge/features/swap.md +1 -0
- package/skills/sodax-sdk/integration/knowledge/recipes/README.md +1 -0
- package/skills/sodax-sdk/integration/knowledge/recipes/initialize-sodax.md +6 -2
- package/skills/sodax-sdk/integration/knowledge/recipes/logging.md +102 -0
- package/skills/sodax-sdk/integration/knowledge/reference/public-api.md +8 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sodax-dapp-kit
|
|
3
|
-
description: 'INTEGRATION (write NEW code) — @sodax/dapp-kit is React hooks wrapping @sodax/sdk with React Query across 11 feature domains (swap, money market, staking, bridge, dex, migration, partner, recovery, bitcoin/
|
|
3
|
+
description: 'INTEGRATION (write NEW code) — @sodax/dapp-kit is React hooks wrapping @sodax/sdk with React Query across 11 feature domains (swap, money market, staking, bridge, dex, migration, partner, recovery, bitcoin/Bound Exchange, backend queries, shared). React-only — Node and backend code uses `@sodax/sdk` directly. Use whenever a React dapp needs SODAX feature hooks. Triggers on "use @sodax/dapp-kit", "useSwap", "useMoneyMarket", "useStake", "useBridge", "useDex", "useMigrate", any `use<Feature>` hook name from dapp-kit, "Sodax React hooks", "dapp-kit query / mutation". v2 hook shape: mutation hooks return `SafeUseMutationResult` with `mutateAsyncSafe(vars): Promise<Result<TData>>`. mutationFn unwraps SDK Result<T> and throws on `!ok` so React Query''s native error model engages. Hook-owned invalidations — consumer onSuccess runs after. MIGRATION (port v1 → v2) — a deep canonicalization pass: single-object hook params, mandatory `mutateAsyncSafe`, hook-owned invalidations, throw-on-`Result.!ok` inside `mutationFn`, canonical queryKey/mutationKey conventions. Plus the SDK underneath was reshaped (chain-key-driven routing, `Result<T>` everywhere, `WalletProviderSlot<K, Raw>`). v1 dapp-kit code will not compile against v2. Triggers on "migrate @sodax/dapp-kit", "useSpokeProvider gone", "dapp-kit v1 → v2", "invalidateMmQueries broken", "dapp-kit hook signatures changed", v1 fingerprints (positional args, hook-init `spokeProvider`, `useSpokeProvider`, `invalidateMmQueries`, legacy `useMigrate`, `*_MAINNET_CHAIN_ID`). Load this skill if EITHER applies; the body gates by mode.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# When to use this skill
|
|
@@ -32,7 +32,7 @@ Pick this mode when the consumer is a React dapp using `@sodax/dapp-kit` hooks.
|
|
|
32
32
|
1. Read [`integration/knowledge/ai-rules.md`](./integration/knowledge/ai-rules.md) — DO / DO NOT / workflow / stop conditions.
|
|
33
33
|
2. Read [`integration/knowledge/quickstart.md`](./integration/knowledge/quickstart.md) — install + wire providers + first feature.
|
|
34
34
|
3. Read [`integration/knowledge/architecture.md`](./integration/knowledge/architecture.md) — hook shapes, queryKey conventions, `useSafeMutation`, `unwrapResult`, `Result<T>`.
|
|
35
|
-
4. For each feature you use, read [`integration/knowledge/features/`](./integration/knowledge/features/) — `swap.md`, `money-market.md`, `staking.md`, `bridge.md`, `dex.md`, `migration.md`, `bitcoin.md` (
|
|
35
|
+
4. For each feature you use, read [`integration/knowledge/features/`](./integration/knowledge/features/) — `swap.md`, `money-market.md`, `staking.md`, `bridge.md`, `dex.md`, `migration.md`, `bitcoin.md` (Bound Exchange, dapp-kit-unique), `auxiliary-services.md` (partner + recovery + backend + shared).
|
|
36
36
|
5. Recipes → [`integration/knowledge/recipes/`](./integration/knowledge/recipes/) — `setup.md`, `wallet-connectivity.md`, per-feature, `mutation-error-handling.md`, `observability.md`, `invalidations.md`.
|
|
37
37
|
6. Lookups → [`integration/knowledge/reference/`](./integration/knowledge/reference/) — `hooks-index.md`, `querykey-conventions.md`, `public-api.md`, `glossary.md`.
|
|
38
38
|
|
|
@@ -15,7 +15,7 @@ This tree documents v2 of the dapp-kit React hooks for **new consumers** buildin
|
|
|
15
15
|
| [`features/bridge.md`](features/bridge.md) | Bridge hooks: `useBridge`, allowance/approve, bridgeable amount/tokens. |
|
|
16
16
|
| [`features/dex.md`](features/dex.md) | DEX hooks: deposit/withdraw, supply/decrease liquidity, claim rewards, position info, pools. |
|
|
17
17
|
| [`features/migration.md`](features/migration.md) | Migration hooks: ICX/bnUSD/BALN forward + reverse, allowance/approve. |
|
|
18
|
-
| [`features/bitcoin.md`](features/bitcoin.md) |
|
|
18
|
+
| [`features/bitcoin.md`](features/bitcoin.md) | Bound Exchange hooks (dapp-kit-unique): session, trading wallet, fund/withdraw, UTXOs. |
|
|
19
19
|
| [`features/auxiliary-services.md`](features/auxiliary-services.md) | Partner, recovery, backend queries, shared (xBalances, gas estimation, trustlines). |
|
|
20
20
|
| [`recipes/`](recipes/) | Copy-paste patterns: setup, wallet connectivity, per-feature flows, mutation error handling, observability, invalidations. |
|
|
21
21
|
| [`reference/`](reference/) | Lookup tables: full hook index, queryKey conventions, public API surface, glossary. |
|
|
@@ -10,7 +10,7 @@ Per-feature reference docs. Each file documents the hooks, params types, return
|
|
|
10
10
|
| [`bridge.md`](bridge.md) | Cross-chain token bridging: `useBridge`, allowance/approve, bridgeable amount/tokens. |
|
|
11
11
|
| [`dex.md`](dex.md) | Concentrated liquidity DEX: assets in/out, liquidity supply/decrease, claim rewards, position info, pool reads, param builders. |
|
|
12
12
|
| [`migration.md`](migration.md) | Token migration: `useMigrateIcxToSoda`, `useRevertMigrateSodaToIcx`, `useMigratebnUSD`, `useMigrateBaln`, allowance/approve. |
|
|
13
|
-
| [`bitcoin.md`](bitcoin.md) |
|
|
13
|
+
| [`bitcoin.md`](bitcoin.md) | Bound Exchange (dapp-kit-unique): session, trading wallet, fund/withdraw, UTXOs. |
|
|
14
14
|
| [`auxiliary-services.md`](auxiliary-services.md) | Partner fee claiming, recovery, backend queries (intent tracking, orderbook, MM data), shared utilities (xBalances, gas, trustlines). |
|
|
15
15
|
|
|
16
16
|
## Reference vs recipes
|
|
@@ -94,6 +94,10 @@ useGetUserHubWalletAddress({ params, queryOptions }); // Hub wallet via wallet r
|
|
|
94
94
|
useEstimateGas({ mutationOptions }); // Gas estimation for raw tx
|
|
95
95
|
useStellarTrustlineCheck({ params, queryOptions });
|
|
96
96
|
useRequestTrustline({ mutationOptions });
|
|
97
|
+
useNearStorageCheck({ params, queryOptions }); // NEP-141 storage registration check (NEAR)
|
|
98
|
+
useRegisterNearStorage({ mutationOptions }); // NEP-141 storage_deposit (NEAR)
|
|
99
|
+
useNearStorageGate({ dstChainKey, token, accountId, walletProvider }); // composite NEAR receive-side gate
|
|
100
|
+
resolveNearStorageGate(chainKey, check); // unwrapped util: gate-state from a useNearStorageCheck result
|
|
97
101
|
```
|
|
98
102
|
|
|
99
103
|
### `useXBalances` shape
|
|
@@ -144,6 +148,46 @@ if (hasTrustline === false) {
|
|
|
144
148
|
}
|
|
145
149
|
```
|
|
146
150
|
|
|
151
|
+
### NEAR storage registration
|
|
152
|
+
|
|
153
|
+
NEP-141 accounts must pay a one-time storage bond before they can receive a token — delivering to an unregistered account fails. The receive-side analogue of Stellar trustlines: gate any flow that delivers a token to the user on NEAR (swap output on NEAR, bridge into NEAR, money-market borrow/withdraw to NEAR). Use `useNearStorageGate` for app UI; use the lower-level `useNearStorageCheck` + `useRegisterNearStorage` pair when you need custom wiring.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// @ai-snippets-skip — illustrative only; real types pulled into agents below.
|
|
157
|
+
// useNearStorageCheck is a canonical read hook: { params: { token, accountId, chainId }, queryOptions }.
|
|
158
|
+
// `chainId` is a SpokeChainKey typed loosely — the hook returns `true` for non-NEAR chains (safe to
|
|
159
|
+
// gate conditionally) and `true` for native NEAR (not a NEP-141 token). data is a boolean;
|
|
160
|
+
// queryKey: ['shared', 'nearStorageCheck', chainId, token, accountId].
|
|
161
|
+
const { data: isRegistered, isLoading } = useNearStorageCheck({
|
|
162
|
+
params: { token, accountId, chainId: ChainKeys.NEAR_MAINNET },
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// useRegisterNearStorage IS a canonical mutation hook: { mutationOptions }, returns
|
|
166
|
+
// SafeUseMutationResult. Domain inputs flow through mutate / mutateAsync / mutateAsyncSafe.
|
|
167
|
+
// Vars: { token, accountId, walletProvider, deposit? } — deposit defaults to the NEP-141
|
|
168
|
+
// storage bond (0.00125 NEAR). mutationKey: ['shared', 'registerNearStorage'].
|
|
169
|
+
const { mutateAsyncSafe: registerStorage } = useRegisterNearStorage();
|
|
170
|
+
if (isRegistered === false) {
|
|
171
|
+
await registerStorage({ token, accountId, walletProvider });
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
For the common UI path, `useNearStorageGate` returns `{ isNear, needsRegistration, blocksAction, isChecking, isRegistering, registerStorage }`.
|
|
176
|
+
|
|
177
|
+
Derive UI gate flags with the unwrapped `resolveNearStorageGate` util (no hook) when you need custom check/register composition:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
// @ai-snippets-skip — illustrative only.
|
|
181
|
+
// resolveNearStorageGate(chainKey, check) reads `isLoading` + `data` off the useNearStorageCheck
|
|
182
|
+
// result and returns { isNear, needsRegistration, blocksAction }:
|
|
183
|
+
// needsRegistration — show the register action (check resolved AND not registered)
|
|
184
|
+
// blocksAction — keep the downstream action disabled (still checking OR needs registration)
|
|
185
|
+
const check = useNearStorageCheck({ params: { token, accountId, chainId: dstChainKey } });
|
|
186
|
+
const { needsRegistration, blocksAction } = resolveNearStorageGate(dstChainKey, check);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
The underlying SDK methods (`isStorageRegistered` / `registerStorage` on the NEAR spoke service, and the `NEAR_STORAGE_DEPOSIT` constant) are documented in the `sodax-sdk` skill (integration mode).
|
|
190
|
+
|
|
147
191
|
## Default polling intervals
|
|
148
192
|
|
|
149
193
|
| Hook | Polling | Notes |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Bitcoin (
|
|
1
|
+
# Bitcoin (Bound Exchange) — `@sodax/dapp-kit`
|
|
2
2
|
|
|
3
|
-
Bitcoin trading via the
|
|
3
|
+
Bitcoin trading via the Bound Exchange protocol — authenticate, fund a trading wallet, withdraw, manage UTXOs. **Dapp-kit-unique surface** (no SDK equivalent — these flows are React-shaped).
|
|
4
4
|
|
|
5
5
|
Pair: [`features/bitcoin.md`](../../../migration-v1-to-v2/knowledge/features/bitcoin.md).
|
|
6
6
|
|
|
@@ -15,7 +15,7 @@ useTradingWallet(walletAddress); // Synchronous: read persisted
|
|
|
15
15
|
|
|
16
16
|
// Balances
|
|
17
17
|
useBitcoinBalance({ params: { address, rpcUrl? }, queryOptions }); // Personal wallet (default mempool.space)
|
|
18
|
-
useTradingWalletBalance({ params: { walletProvider, tradingAddress }, queryOptions }); //
|
|
18
|
+
useTradingWalletBalance({ params: { walletProvider, tradingAddress }, queryOptions }); // Bound Exchange API
|
|
19
19
|
|
|
20
20
|
// Operations
|
|
21
21
|
useFundTradingWallet({ mutationOptions });
|
|
@@ -26,7 +26,7 @@ useRenewUtxos({ mutationOptions });
|
|
|
26
26
|
|
|
27
27
|
## Session flow
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Bound Exchange requires authentication before trading operations. `useRadfiSession` handles the full lifecycle:
|
|
30
30
|
|
|
31
31
|
```ts
|
|
32
32
|
// @ai-snippets-skip
|
|
@@ -76,8 +76,8 @@ type RenewUtxosVars = { txIdVouts: string[]; walletProvider: IBitcoinWalletProvi
|
|
|
76
76
|
|
|
77
77
|
1. **Authentication required before any trading operation.** `useRadfiSession` manages this automatically — gate buttons on `isAuthed`.
|
|
78
78
|
2. **Trading wallet is created during first authentication** — not a separate step.
|
|
79
|
-
3. **`useTradingWallet(walletAddress)` is synchronous** (no network call). It reads persisted
|
|
80
|
-
4. **PSBT signing flow for withdrawals.**
|
|
79
|
+
3. **`useTradingWallet(walletAddress)` is synchronous** (no network call). It reads persisted Bound Exchange session from localStorage. Use it when you don't have a `walletProvider` available yet but need the trading address.
|
|
80
|
+
4. **PSBT signing flow for withdrawals.** Bound Exchange server builds an unsigned PSBT, the user signs locally via the wallet provider, then submits back for co-signing and broadcast. The dapp-kit hook orchestrates this — consumers don't see PSBTs directly.
|
|
81
81
|
5. **Session tokens are for API rate-limiting, not asset access.** Stored in localStorage keyed by wallet address. Compromise of localStorage data doesn't affect funds.
|
|
82
82
|
6. **`useExpiredUtxos` polls every 60s** — set `queryOptions.refetchInterval: false` to disable while UI is hidden.
|
|
83
83
|
|
|
@@ -43,6 +43,8 @@ type UseUserFormattedSummaryParams = ReadHookParams<FormatUserSummaryResponse, {
|
|
|
43
43
|
userAddress: string | undefined;
|
|
44
44
|
}>;
|
|
45
45
|
// Same shape on useUserReservesData. The hook derives the hub wallet from (spokeChainKey, userAddress) internally.
|
|
46
|
+
// Bitcoin: always pass the personal address as userAddress — the hook transparently resolves to the
|
|
47
|
+
// Bound Exchange trading-wallet-derived hub wallet when a session is active (local lookup, no network).
|
|
46
48
|
|
|
47
49
|
// useAToken — single aToken metadata; FLAT (no chain/user fields)
|
|
48
50
|
type UseATokenParams = ReadHookParams<ATokenData, {
|
|
@@ -57,10 +59,13 @@ type UseATokensBalancesParams = ReadHookParams<Map<Address, bigint>, {
|
|
|
57
59
|
userAddress: string | undefined;
|
|
58
60
|
}>;
|
|
59
61
|
// Returns a Map keyed by aToken address. The hook resolves the hub wallet from (spokeChainKey, userAddress).
|
|
62
|
+
// Bitcoin: always pass the personal address — trading-wallet resolution is automatic when a session exists.
|
|
60
63
|
```
|
|
61
64
|
|
|
62
65
|
> **Read-side chain key is `spokeChainKey`, not `srcChainKey`.** Mutation hooks (`useSupply`/`useBorrow`/etc.) use `srcChainKey` because the request crosses chains and needs a source. Read hooks describe a user's position on a single spoke chain — the field is `spokeChainKey`. Applies to `useATokensBalances`, `useUserFormattedSummary`, and `useUserReservesData` (`useAToken` is metadata-only and takes neither). Don't grep-replace one for the other.
|
|
63
66
|
|
|
67
|
+
> **Bitcoin `userAddress`**: always pass the **personal** address (the user's wallet address), not the Bound Exchange trading address. The read hooks (`useATokensBalances`, `useUserReservesData`, `useUserFormattedSummary`, `useGetUserHubWalletAddress`) automatically resolve to the trading-wallet-derived hub wallet when a Bound Exchange session is active — this is a local lookup with no network call and no throw on an unauthenticated session. See [`features/bitcoin.md`](bitcoin.md) for Bound Exchange session setup.
|
|
68
|
+
|
|
64
69
|
## Mutation params
|
|
65
70
|
|
|
66
71
|
All four user mutations share the same TVars shape (only the `action` literal differs):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Recipe: Bitcoin (
|
|
1
|
+
# Recipe: Bitcoin (Bound Exchange)
|
|
2
2
|
|
|
3
|
-
Bitcoin trading via the
|
|
3
|
+
Bitcoin trading via the Bound Exchange protocol. Authenticate, fund a trading wallet, trade, withdraw, and manage UTXOs.
|
|
4
4
|
|
|
5
5
|
**Depends on:** [setup.md](setup.md), [wallet-connectivity.md](wallet-connectivity.md)
|
|
6
6
|
|
|
@@ -10,7 +10,7 @@ Bitcoin trading via the Radfi protocol. Authenticate, fund a trading wallet, tra
|
|
|
10
10
|
|
|
11
11
|
| Hook | Type | Purpose |
|
|
12
12
|
|------|------|---------|
|
|
13
|
-
| `useRadfiAuth` | Mutation | Authenticate with
|
|
13
|
+
| `useRadfiAuth` | Mutation | Authenticate with Bound Exchange via BIP322 signing |
|
|
14
14
|
| `useRadfiSession` | Utility | Manage full session lifecycle (login, refresh, auto-refresh) |
|
|
15
15
|
| `useTradingWallet` | Utility | Get trading wallet address from persisted session (synchronous) |
|
|
16
16
|
|
|
@@ -19,7 +19,7 @@ Bitcoin trading via the Radfi protocol. Authenticate, fund a trading wallet, tra
|
|
|
19
19
|
| Hook | Type | Purpose |
|
|
20
20
|
|------|------|---------|
|
|
21
21
|
| `useBitcoinBalance` | Query | BTC balance for any address (sums UTXOs from mempool.space) |
|
|
22
|
-
| `useTradingWalletBalance` | Query | Trading wallet balance from
|
|
22
|
+
| `useTradingWalletBalance` | Query | Trading wallet balance from Bound Exchange API (confirmed + pending) |
|
|
23
23
|
|
|
24
24
|
### Operations
|
|
25
25
|
|
|
@@ -32,7 +32,7 @@ Bitcoin trading via the Radfi protocol. Authenticate, fund a trading wallet, tra
|
|
|
32
32
|
|
|
33
33
|
## Session Flow
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Bound Exchange requires authentication before any trading operation. The typical flow:
|
|
36
36
|
|
|
37
37
|
```tsx
|
|
38
38
|
import { useRadfiSession } from '@sodax/dapp-kit';
|
|
@@ -49,7 +49,7 @@ function BitcoinAuth() {
|
|
|
49
49
|
|
|
50
50
|
return (
|
|
51
51
|
<button onClick={login} disabled={isLoginPending}>
|
|
52
|
-
{isLoginPending ? 'Signing...' : 'Login to
|
|
52
|
+
{isLoginPending ? 'Signing...' : 'Login to Bound Exchange'}
|
|
53
53
|
</button>
|
|
54
54
|
);
|
|
55
55
|
}
|
|
@@ -77,7 +77,7 @@ function BitcoinBalances({ walletAddress }: { walletAddress: string }) {
|
|
|
77
77
|
params: { address: walletAddress },
|
|
78
78
|
});
|
|
79
79
|
|
|
80
|
-
// Trading wallet balance (from
|
|
80
|
+
// Trading wallet balance (from Bound Exchange API). `RadfiWalletBalance` fields:
|
|
81
81
|
// `btcSatoshi`, `pendingSatoshi`, `externalPendingSatoshi`, `totalUtxos`.
|
|
82
82
|
const { data: tradingBalance } = useTradingWalletBalance({
|
|
83
83
|
params: { walletProvider, tradingAddress },
|
|
@@ -188,6 +188,6 @@ function UtxoManager({ tradingAddress }: { tradingAddress: string }) {
|
|
|
188
188
|
|
|
189
189
|
- **Authentication required** before any trading operation. `useRadfiSession` manages this automatically.
|
|
190
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
|
|
191
|
+
- **`useTradingWallet(walletAddress)`** is a synchronous utility (no network call) — it reads the persisted Bound Exchange session from localStorage.
|
|
192
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
193
|
- **Session tokens** are stored in localStorage keyed by wallet address. They're for API rate-limiting, not for accessing user assets.
|
|
@@ -16,6 +16,9 @@ Connect wallets and pass wallet providers to feature hooks.
|
|
|
16
16
|
| `useEstimateGas` | `@sodax/dapp-kit` | Mutation | Estimate gas for raw transactions |
|
|
17
17
|
| `useStellarTrustlineCheck` | `@sodax/dapp-kit` | Query | Check if Stellar account has sufficient trustline |
|
|
18
18
|
| `useRequestTrustline` | `@sodax/dapp-kit` | Mutation | Request a Stellar trustline for a token |
|
|
19
|
+
| `useNearStorageCheck` | `@sodax/dapp-kit` | Query | Check if a NEAR account is NEP-141 storage-registered for a token |
|
|
20
|
+
| `useRegisterNearStorage` | `@sodax/dapp-kit` | Mutation | Submit a NEP-141 `storage_deposit` so a NEAR account can receive a token |
|
|
21
|
+
| `useNearStorageGate` | `@sodax/dapp-kit` | Hook | Combine the NEAR storage check, registration mutation, and UI gate flags |
|
|
19
22
|
|
|
20
23
|
## Connect a Wallet
|
|
21
24
|
|
|
@@ -130,7 +130,7 @@ App-level React component. Provides:
|
|
|
130
130
|
- RPC config for all chains
|
|
131
131
|
- Hub provider access (via `useHubProvider()`)
|
|
132
132
|
|
|
133
|
-
Optional config: `<SodaxProvider config={DeepPartial<SodaxConfig>}
|
|
133
|
+
Optional config: `<SodaxProvider config={SodaxOptions}>` (`SodaxOptions = DeepPartial<SodaxConfig> & { logger? }`). Without config, SDK uses packaged defaults.
|
|
134
134
|
|
|
135
135
|
Config is tracked by **reference** - see [`recipes/setup.md § Config reactivity`](../recipes/setup.md#config-reactivity) for module-const vs `useMemo` patterns.
|
|
136
136
|
|
|
@@ -108,7 +108,7 @@ Comprehensive hook table across 11 feature domains. Use this when you know the f
|
|
|
108
108
|
| `useMigrationApprove` | Mutation | Approve before migration (action-discriminated) |
|
|
109
109
|
| `useMigrationAllowance` | Query | Approval check (action-discriminated) |
|
|
110
110
|
|
|
111
|
-
## Bitcoin /
|
|
111
|
+
## Bitcoin / Bound Exchange
|
|
112
112
|
|
|
113
113
|
| Hook | Type | Purpose |
|
|
114
114
|
|---|---|---|
|
|
@@ -116,7 +116,7 @@ Comprehensive hook table across 11 feature domains. Use this when you know the f
|
|
|
116
116
|
| `useRadfiSession` | Utility | Manage full session lifecycle |
|
|
117
117
|
| `useTradingWallet` | Utility | Synchronously read trading wallet from localStorage |
|
|
118
118
|
| `useBitcoinBalance` | Query | BTC balance for any address |
|
|
119
|
-
| `useTradingWalletBalance` | Query | Trading wallet balance from
|
|
119
|
+
| `useTradingWalletBalance` | Query | Trading wallet balance from Bound Exchange API |
|
|
120
120
|
| `useFundTradingWallet` | Mutation | Fund trading wallet from personal wallet |
|
|
121
121
|
| `useRadfiWithdraw` | Mutation | Withdraw from trading wallet |
|
|
122
122
|
| `useExpiredUtxos` | Query | Expired UTXOs (polls 60s) |
|
|
@@ -179,6 +179,10 @@ Comprehensive hook table across 11 feature domains. Use this when you know the f
|
|
|
179
179
|
| `useEstimateGas` | Mutation | Estimate gas for raw tx |
|
|
180
180
|
| `useStellarTrustlineCheck` | Query | Check Stellar trustline |
|
|
181
181
|
| `useRequestTrustline` | Mutation | Request a Stellar trustline |
|
|
182
|
+
| `useNearStorageCheck` | Query | Check NEP-141 storage registration (NEAR) |
|
|
183
|
+
| `useRegisterNearStorage` | Mutation | Submit NEP-141 `storage_deposit` (NEAR) |
|
|
184
|
+
| `useNearStorageGate` | Hook | Composite NEAR receive-side storage gate |
|
|
185
|
+
| `resolveNearStorageGate` | Utility | Derive gate flags from a `useNearStorageCheck` result (unwrapped) |
|
|
182
186
|
| `useSafeMutation` | Internal | The wrapper every mutation hook calls |
|
|
183
187
|
| `unwrapResult` | Internal | `Result<T>` → throw / return |
|
|
184
188
|
| `toResult` | Internal | `Promise<T>` → `Result<T>` |
|
|
@@ -77,6 +77,7 @@ queryKey: ['staking', 'allowance', srcChainKey, action, srcAddress, amount.toStr
|
|
|
77
77
|
queryKey: ['mm', 'userReservesData', spokeChainKey, userAddress]
|
|
78
78
|
queryKey: ['staking', 'info', srcChainKey, srcAddress] // useStakingInfo — second segment is 'info', not 'stakingInfo'
|
|
79
79
|
queryKey: ['shared', 'xBalances', xChainId, tokens, address]
|
|
80
|
+
queryKey: ['shared', 'nearStorageCheck', chainId, token, accountId] // useNearStorageCheck
|
|
80
81
|
|
|
81
82
|
// Mutation default keys
|
|
82
83
|
mutationKey: ['swap'] // useSwap
|
|
@@ -90,6 +91,7 @@ mutationKey: ['staking', 'approve', 'stake'] // useStake
|
|
|
90
91
|
mutationKey: ['bridge'] // useBridge — single segment (no 'execute' suffix)
|
|
91
92
|
mutationKey: ['migrate', 'icxToSoda']
|
|
92
93
|
mutationKey: ['dex', 'supplyLiquidity']
|
|
94
|
+
mutationKey: ['shared', 'registerNearStorage'] // useRegisterNearStorage
|
|
93
95
|
```
|
|
94
96
|
|
|
95
97
|
## Per-feature key tables
|
package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/breaking-changes/hook-signatures.md
CHANGED
|
@@ -27,7 +27,7 @@ The structural shape of every dapp-kit hook changed in v2. Five categories of br
|
|
|
27
27
|
+ }}>
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
The `config` prop is `
|
|
30
|
+
The `config` prop is `SodaxOptions` from `@sodax/sdk` (`= DeepPartial<SodaxConfig> & { logger? }`). Data override fields: `api`, `solver`, `swaps`, `bridge`, `dex`, `moneyMarket`, `hub`, `relay`, `fee`, plus the client-side `logger` sink. See `sodax-sdk`: `migration-v1-to-v2/knowledge/breaking-changes/architecture.md` for the SDK-side reshape.
|
|
31
31
|
|
|
32
32
|
**Recommended pairing**: replace `new QueryClient()` with `createSodaxQueryClient()` for global mutation observability.
|
|
33
33
|
|
|
@@ -81,7 +81,7 @@ Full SDK-level detail: `sodax-sdk`: `migration-v1-to-v2/knowledge/breaking-chang
|
|
|
81
81
|
|
|
82
82
|
## `SodaxConfig` reshape — `rpcConfig` → `chains`
|
|
83
83
|
|
|
84
|
-
`SodaxProvider`'s config prop is `DeepPartial<SodaxConfig
|
|
84
|
+
`SodaxProvider`'s config prop is `SodaxOptions` (`= DeepPartial<SodaxConfig> & { logger? }`). The SDK renamed/restructured the config:
|
|
85
85
|
|
|
86
86
|
```diff
|
|
87
87
|
- <SodaxProvider rpcConfig={{
|
|
@@ -33,7 +33,7 @@ For each feature your app uses, walk the matching `migration/features/<feature>.
|
|
|
33
33
|
- [ ] [`features/bridge.md`](features/bridge.md) — bridge.
|
|
34
34
|
- [ ] [`features/dex.md`](features/dex.md) — deposit / supply liquidity / etc.
|
|
35
35
|
- [ ] [`features/migration.md`](features/migration.md) — ICX / bnUSD / BALN. **Note:** v1's `useMigrate(spokeProvider)` is gone; v2 has 6 per-action hooks.
|
|
36
|
-
- [ ] [`features/bitcoin.md`](features/bitcoin.md) —
|
|
36
|
+
- [ ] [`features/bitcoin.md`](features/bitcoin.md) — Bound Exchange.
|
|
37
37
|
- [ ] [`features/auxiliary-services.md`](features/auxiliary-services.md) — partner, recovery, backend queries, shared utilities.
|
|
38
38
|
|
|
39
39
|
The cross-cutting pattern at every call site:
|
|
@@ -10,7 +10,7 @@ Per-feature porting playbooks. Each file shows the v1 → v2 delta for one featu
|
|
|
10
10
|
| [`bridge.md`](bridge.md) | Field renames in `useBridge` params (`srcChainId` → `srcChainKey`, `recipient` → `dstAddress`). `useGetBridgeableAmount` shape change. |
|
|
11
11
|
| [`dex.md`](dex.md) | Two-step flow stayed the same; field renames + `srcChainKey` requirement. `useSupplyLiquidity` mint/increase routing. |
|
|
12
12
|
| [`migration.md`](migration.md) | **Biggest change**: v1's `useMigrate(spokeProvider)` → 6 per-action hooks. |
|
|
13
|
-
| [`bitcoin.md`](bitcoin.md) |
|
|
13
|
+
| [`bitcoin.md`](bitcoin.md) | Bound Exchange flow shapes are mostly unchanged; provider/session lifecycle hooks tightened. |
|
|
14
14
|
| [`auxiliary-services.md`](auxiliary-services.md) | Partner / recovery / backend queries / shared utilities — small per-hook changes. |
|
|
15
15
|
|
|
16
16
|
## Pair-completeness
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# Bitcoin (
|
|
1
|
+
# Bitcoin (Bound Exchange) migration — v1 → v2 (dapp-kit)
|
|
2
2
|
|
|
3
3
|
Pair: [`features/bitcoin.md`](../../../integration/knowledge/features/bitcoin.md).
|
|
4
4
|
|
|
5
|
-
Bitcoin /
|
|
5
|
+
Bitcoin / Bound Exchange hook surface was new in v1 with limited adoption; v2 standardizes its shapes against the canonical hook conventions. Treat the v2 forms below as the canonical reference — if your v1 code used a different shape, swap to v2's directly.
|
|
6
6
|
|
|
7
7
|
## TL;DR
|
|
8
8
|
|
|
@@ -59,7 +59,7 @@ These keep their name but their TypeScript signature is different. Usually requi
|
|
|
59
59
|
| `useTradingWalletBalance` | Return is `RadfiWalletBalance = { btcSatoshi, pendingSatoshi, externalPendingSatoshi, totalUtxos }` — NOT `{ confirmed, pending }`. |
|
|
60
60
|
| `useExpiredUtxos` | Return is `RadfiUtxo[]` (with `_id`, `txid`, `vout`, `txidVout`, `satoshi`, `amount`, `address`, `isSpent`, `status`, `source`, optional `runes`). Both this and `useTradingWalletBalance` take `{ params: { walletProvider, tradingAddress } }`. |
|
|
61
61
|
| `useRadfiAuth` | TData is `RadfiAuthResult = { accessToken, refreshToken, tradingAddress }` (3 fields — `publicKey` is persisted to localStorage but NOT returned). |
|
|
62
|
-
| All Bitcoin/
|
|
62
|
+
| All Bitcoin/Bound Exchange mutations | Standard pattern — drop hook-init args; pass through `mutate(vars)`. |
|
|
63
63
|
|
|
64
64
|
## Cross-references
|
|
65
65
|
|
|
@@ -72,7 +72,7 @@ Follow in order. Skipping `ai-rules.md` is the most common cause of agents rever
|
|
|
72
72
|
1. Read [`integration/knowledge/ai-rules.md`](./integration/knowledge/ai-rules.md) — DO / DO NOT / workflow / stop conditions.
|
|
73
73
|
2. Read [`integration/knowledge/quickstart.md`](./integration/knowledge/quickstart.md) — install, initialize, first-run troubleshooting.
|
|
74
74
|
3. For your feature, read [`integration/knowledge/features/`](./integration/knowledge/features/) — `swap.md`, `money-market.md`, `staking.md`, `bridge.md`, `dex.md`, `migration.md`, `partner.md`, `recovery.md`, `backend-api.md`.
|
|
75
|
-
4. For specific patterns (init, raw vs signed, chain narrowing, gas, testing, errors), read [`integration/knowledge/recipes/`](./integration/knowledge/recipes/).
|
|
75
|
+
4. For specific patterns (init, raw vs signed, chain narrowing, gas, testing, errors, logging), read [`integration/knowledge/recipes/`](./integration/knowledge/recipes/).
|
|
76
76
|
5. Lookups (chain keys, error codes, public API surface, wallet provider types, glossary) → [`integration/knowledge/reference/`](./integration/knowledge/reference/).
|
|
77
77
|
6. Non-EVM quirks (Stellar trustline, BTC PSBT, Solana PDA, ICON, NEAR) → [`integration/knowledge/chain-specifics.md`](./integration/knowledge/chain-specifics.md).
|
|
78
78
|
|
|
@@ -19,7 +19,7 @@ This tree documents v2 of the SDK for **new consumers** building against it. If
|
|
|
19
19
|
| [`features/backend-api.md`](features/backend-api.md) | `BackendApiService` — HTTP client for backend reads + swap-tx submission. |
|
|
20
20
|
| [`recipes/`](recipes/) | Copy-pasteable patterns: SDK initialization, `Result` + error discrimination, raw-tx flow, signed-tx flow, chain-key narrowing + cast-at-boundary, testing (mocks/stubs), gas estimation, backend-server init. |
|
|
21
21
|
| [`reference/`](reference/) | Lookup tables: 20-chain `ChainKeys` table with family + relay id, `I*WalletProvider` interfaces, 13 `SodaxErrorCode` meanings + per-feature narrow unions, public API surface (incl. `@sodax/types` re-export rule), glossary. |
|
|
22
|
-
| [`chain-specifics.md`](chain-specifics.md) | Non-EVM quirks — Stellar trustline check/request, Bitcoin PSBT +
|
|
22
|
+
| [`chain-specifics.md`](chain-specifics.md) | Non-EVM quirks — Stellar trustline check/request, Bitcoin PSBT + Bound Exchange auth/session, Solana PDA derivation, ICON Hana wallet + chain-key string, NEAR connector discovery. |
|
|
23
23
|
|
|
24
24
|
## Reading order for a new integrator
|
|
25
25
|
|
|
@@ -95,7 +95,7 @@ The chain key is the bridge between the type system and runtime routing.
|
|
|
95
95
|
The `Sodax` class is the public entry point. It constructs and wires every service once at construction time, then reuses them across calls:
|
|
96
96
|
|
|
97
97
|
```ts
|
|
98
|
-
const sodax = new Sodax(/* optional
|
|
98
|
+
const sodax = new Sodax(/* optional SodaxOptions */);
|
|
99
99
|
await sodax.config.initialize(); // fetch dynamic config; fall back to packaged defaults
|
|
100
100
|
|
|
101
101
|
// All feature services accessed off the instance:
|
|
@@ -127,11 +127,13 @@ All feature services receive `{ hubProvider, config, spoke }` via constructor in
|
|
|
127
127
|
### Constructor
|
|
128
128
|
|
|
129
129
|
```ts
|
|
130
|
-
import { Sodax, type
|
|
130
|
+
import { Sodax, type SodaxOptions } from '@sodax/sdk';
|
|
131
131
|
|
|
132
|
-
new Sodax(config?:
|
|
132
|
+
new Sodax(config?: SodaxOptions): Sodax;
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
+
`SodaxOptions` is `DeepPartial<SodaxConfig> & { logger?: SodaxLoggerOption }` — a deep-partial override of the `SodaxConfig` data contract, plus the client-side `logger` sink (kept off `SodaxConfig` itself; see [`recipes/logging.md`](recipes/logging.md)).
|
|
136
|
+
|
|
135
137
|
`SodaxConfig` has exactly **10 fields** (all required at the type level, but `DeepPartial` makes every leaf optional):
|
|
136
138
|
|
|
137
139
|
- `fee: PartnerFee | undefined` — global partner fee, applied unless a feature-level config overrides.
|
|
@@ -5,7 +5,7 @@ EVM chains (12 of them) work uniformly through `IEvmWalletProvider`. Non-EVM cha
|
|
|
5
5
|
## Section index
|
|
6
6
|
|
|
7
7
|
1. [Stellar trustline](#1-stellar-trustline) — `STELLAR_MAINNET`. Required before receiving any non-XLM asset.
|
|
8
|
-
2. [Bitcoin PSBT and
|
|
8
|
+
2. [Bitcoin PSBT and Bound Exchange](#2-bitcoin-psbt-and-radfi) — `BITCOIN_MAINNET`. PSBT signing; trading wallet; Bound Exchange auth/session.
|
|
9
9
|
3. [Solana PDA derivation](#3-solana-pda-derivation) — `SOLANA_MAINNET`. Deterministic addresses; one-time setup utilities.
|
|
10
10
|
4. [ICON Hana wallet](#4-icon-hana-wallet) — `ICON_MAINNET`. Low-level Hana-extension helpers; chain key string vs numeric ID.
|
|
11
11
|
5. [NEAR connector discovery](#5-near-connector-discovery) — `NEAR_MAINNET`. Account-id semantics; multiple wallet variants.
|
|
@@ -39,7 +39,7 @@ Stellar accounts that have never held the asset have **no** trustline — receiv
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
-
## 2. Bitcoin PSBT and
|
|
42
|
+
## 2. Bitcoin PSBT and Bound Exchange
|
|
43
43
|
|
|
44
44
|
Bitcoin support uses Partially Signed Bitcoin Transactions (PSBT) — a different model than EVM tx signing. The wallet provider (`BTCWalletProvider`) handles PSBT construction and signing internally.
|
|
45
45
|
|
|
@@ -51,11 +51,11 @@ type BtcAddressType = 'P2PKH' | 'P2SH' | 'P2WPKH' | 'P2TR';
|
|
|
51
51
|
|
|
52
52
|
`BTCWalletProvider` config takes an `addressType`. `'P2WPKH'` (native SegWit) is the modern default; `'P2TR'` (Taproot) is supported but may have lower compatibility with some on-chain logic.
|
|
53
53
|
|
|
54
|
-
###
|
|
54
|
+
### Bound Exchange (auth + trading wallet)
|
|
55
55
|
|
|
56
|
-
SODAX uses the
|
|
56
|
+
SODAX uses the Bound Exchange infrastructure for Bitcoin. Each user gets a derived "trading wallet" funded from their main BTC address. Operations consume UTXOs from the trading wallet rather than directly from the user's main address.
|
|
57
57
|
|
|
58
|
-
The
|
|
58
|
+
The Bound Exchange provider is owned by `BitcoinSpokeService`. Reach it via the spoke router:
|
|
59
59
|
|
|
60
60
|
```ts
|
|
61
61
|
import { ChainKeys, type BitcoinSpokeService } from '@sodax/sdk';
|
|
@@ -64,10 +64,10 @@ const btcSpoke = sodax.spoke.getSpokeService(ChainKeys.BITCOIN_MAINNET) as Bitco
|
|
|
64
64
|
const radfi = btcSpoke.radfi; // RadfiProvider instance
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
Most consumer flows don't need to touch `radfi` directly — `sodax.bridge.bridge(...)`, `sodax.swaps.createIntent(...)`, etc. handle the
|
|
67
|
+
Most consumer flows don't need to touch `radfi` directly — `sodax.bridge.bridge(...)`, `sodax.swaps.createIntent(...)`, etc. handle the Bound Exchange auth + trading-wallet routing internally on the Bitcoin path. For explicit lifecycle management:
|
|
68
68
|
|
|
69
69
|
```ts
|
|
70
|
-
// Authenticate against
|
|
70
|
+
// Authenticate against Bound Exchange (the wallet signs an auth message):
|
|
71
71
|
await radfi.authenticateWithWallet(/* args per RadfiProvider source */);
|
|
72
72
|
|
|
73
73
|
// Fetch the trading wallet for an address (creating it if needed):
|
|
@@ -84,7 +84,7 @@ Other public methods on `RadfiProvider` you may need: `setRadfiAccessToken`, `re
|
|
|
84
84
|
|
|
85
85
|
### Pitfall
|
|
86
86
|
|
|
87
|
-
`BitcoinSpokeService.radfi` is what feature services use under the hood. Bypassing the feature services and driving
|
|
87
|
+
`BitcoinSpokeService.radfi` is what feature services use under the hood. Bypassing the feature services and driving Bound Exchange yourself works but is rarely needed — and you have to wire token balances + UTXO state manually. Prefer the standard feature flows unless you specifically need lifecycle control.
|
|
88
88
|
|
|
89
89
|
---
|
|
90
90
|
|
|
@@ -168,6 +168,31 @@ Both are valid. `GetAddressType<typeof ChainKeys.NEAR_MAINNET>` accepts both via
|
|
|
168
168
|
|
|
169
169
|
`NearWalletProvider` requires the `accountId` field at construction (alongside `privateKey`). Unlike EVM, NEAR can't derive an account from a key alone — keys are scoped to accounts.
|
|
170
170
|
|
|
171
|
+
### Receiving tokens: NEP-141 storage registration
|
|
172
|
+
|
|
173
|
+
Before a NEAR account can **receive** (hold a balance of) a NEP-141 token, it must pay a one-time storage bond on that token contract — delivering to an unregistered account fails. This gates any flow that delivers a token to a user on NEAR: swap output on NEAR, bridge into NEAR, money-market borrow/withdraw to NEAR. (Native NEAR is not a NEP-141 token and needs no registration.)
|
|
174
|
+
|
|
175
|
+
The NEAR spoke service exposes two methods — reach it via `sodax.spoke.near` or `sodax.spoke.getSpokeService(ChainKeys.NEAR_MAINNET)`:
|
|
176
|
+
|
|
177
|
+
- `isStorageRegistered(token, accountId): Promise<boolean>` — whether `accountId` can already receive `token`. Returns `true` for the native token (no NEP-141). Read-only; uses the configured NEAR RPC.
|
|
178
|
+
- `registerStorage({ token, accountId, walletProvider, deposit?, raw? })` — submits a `storage_deposit` for `accountId`; returns the tx hash (or the unsigned tx when `raw: true`). `deposit` defaults to `NEAR_STORAGE_DEPOSIT` (0.00125 NEAR, exported from `@sodax/sdk`) — override per token if its `storage_balance_bounds.min` differs. Throws for the native token. The recipient's NEAR wallet signs it.
|
|
179
|
+
|
|
180
|
+
Gate pattern, run before delivering to NEAR:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
// @ai-snippets-skip — illustrative.
|
|
184
|
+
const near = sodax.spoke.near;
|
|
185
|
+
if (!(await near.isStorageRegistered(token, accountId))) {
|
|
186
|
+
await near.registerStorage({ token, accountId, walletProvider });
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The `sodax-dapp-kit` skill wraps these as the `useNearStorageCheck` / `useRegisterNearStorage` hooks plus a `resolveNearStorageGate` helper (integration mode).
|
|
191
|
+
|
|
192
|
+
### `ft_transfer_call` attaches 1 yoctoNEAR
|
|
193
|
+
|
|
194
|
+
Deposits **from** NEAR (`deposit()` / `fillIntent()` on the NEAR spoke service) call the token's `ft_transfer_call`, which per NEP-141 must carry **exactly 1 yoctoNEAR** — the spoke service attaches it automatically. The signer only needs a small NEAR balance to cover gas (the 1 yoctoNEAR is dust). Native-token deposits use a plain `transfer` and aren't subject to this.
|
|
195
|
+
|
|
171
196
|
---
|
|
172
197
|
|
|
173
198
|
## Other non-EVM chains
|
|
@@ -169,4 +169,5 @@ if (result.ok) {
|
|
|
169
169
|
|
|
170
170
|
- v1 → v2 bridge migration: [`features/bridge.md`](../../../migration-v1-to-v2/knowledge/features/bridge.md).
|
|
171
171
|
- Stellar destinations need a trustline first: [`../chain-specifics.md`](../chain-specifics.md).
|
|
172
|
+
- NEAR destinations need NEP-141 storage registration first: [`../chain-specifics.md`](../chain-specifics.md).
|
|
172
173
|
- Hub-and-spoke vault architecture: [`../architecture.md`](../architecture.md) § 1.
|
|
@@ -196,3 +196,4 @@ Aave's RAY precision (27 decimals) is used for interest calculations under the h
|
|
|
196
196
|
- v1 → v2 money market migration: [`features/money-market.md`](../../../migration-v1-to-v2/knowledge/features/money-market.md).
|
|
197
197
|
- Architecture (hub-side wallet abstraction, ConfigService): [`../architecture.md`](../architecture.md) §§ 3, 4.
|
|
198
198
|
- Stellar destinations need a trustline: [`../chain-specifics.md`](../chain-specifics.md).
|
|
199
|
+
- NEAR destinations (borrow/withdraw to NEAR) need NEP-141 storage registration: [`../chain-specifics.md`](../chain-specifics.md).
|
|
@@ -271,3 +271,4 @@ Solver-specific context on `EXTERNAL_API_ERROR`:
|
|
|
271
271
|
- v1 → v2 swap migration: [`features/swap.md`](../../../migration-v1-to-v2/knowledge/features/swap.md).
|
|
272
272
|
- Error model: [`../architecture.md`](../architecture.md) § 8 and [`../reference/`](../reference/) § 3.
|
|
273
273
|
- Stellar destinations require a trustline first: [`../chain-specifics.md`](../chain-specifics.md) § "Stellar trustline".
|
|
274
|
+
- NEAR destinations require NEP-141 storage registration first: [`../chain-specifics.md`](../chain-specifics.md) § "Receiving tokens: NEP-141 storage registration".
|
|
@@ -6,6 +6,7 @@ Copy-pasteable patterns for the most common Core SDK consumer tasks. Each file i
|
|
|
6
6
|
|---|---|
|
|
7
7
|
| [`initialize-sodax.md`](initialize-sodax.md) | App startup. `new Sodax()` + `await sodax.config.initialize()`, with and without config override. |
|
|
8
8
|
| [`result-and-errors.md`](result-and-errors.md) | Branching on `result.ok`, switching on `(error.feature, error.code)`, `isSodaxError` over `instanceof`, sub-Result propagation, logger integration. |
|
|
9
|
+
| [`logging.md`](logging.md) | Select a `SodaxLogger` (`'console'` / `'silent'` / custom sink) at construction; forward SDK diagnostics to Sentry / Pino / Datadog. |
|
|
9
10
|
| [`signed-tx-flow.md`](signed-tx-flow.md) | `raw: false` + chain-narrowed `walletProvider`. Returns tx hash (or `TxHashPair` for cross-chain mutations). |
|
|
10
11
|
| [`raw-tx-flow.md`](raw-tx-flow.md) | `raw: true`. Builds an unsigned chain-specific payload; you sign elsewhere. |
|
|
11
12
|
| [`chain-key-narrowing.md`](chain-key-narrowing.md) | Cast-at-boundary pattern; runtime `chainType` discriminant. |
|
|
@@ -15,9 +15,10 @@ const result = sodax.config.isValidSpokeChainKey(ChainKeys.ARBITRUM_MAINNET);
|
|
|
15
15
|
### With config override
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
|
-
import { Sodax, ChainKeys, type
|
|
18
|
+
import { Sodax, ChainKeys, type SodaxOptions } from '@sodax/sdk';
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
// `SodaxOptions` = `DeepPartial<SodaxConfig>` (the data override) plus the client-side `logger` option.
|
|
21
|
+
const config: SodaxOptions = {
|
|
21
22
|
// Per-chain overrides — merged with packaged defaults at the field level.
|
|
22
23
|
chains: {
|
|
23
24
|
[ChainKeys.SONIC_MAINNET]: { rpcUrl: process.env.SONIC_RPC_URL },
|
|
@@ -31,6 +32,8 @@ const config: DeepPartial<SodaxConfig> = {
|
|
|
31
32
|
solver: {
|
|
32
33
|
solverApiEndpoint: 'https://my-solver.example.com',
|
|
33
34
|
},
|
|
35
|
+
// SDK log sink: 'console' (default) | 'silent' | a custom SodaxLogger. See logging.md.
|
|
36
|
+
logger: 'silent',
|
|
34
37
|
};
|
|
35
38
|
|
|
36
39
|
const sodax = new Sodax(config);
|
|
@@ -74,5 +77,6 @@ export const SUPPORTED_TOKENS_PER_CHAIN = sodaxConfig.swaps.supportedTokens;
|
|
|
74
77
|
## Cross-references
|
|
75
78
|
|
|
76
79
|
- [`README.md`](README.md) — recipe index.
|
|
80
|
+
- [`logging.md`](logging.md) — the `logger` constructor option in depth (presets + custom sinks).
|
|
77
81
|
- [`../architecture.md`](../architecture.md) — concepts behind these patterns.
|
|
78
82
|
- [`../reference/`](../reference/) — chain keys, error codes, public API surface.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Logging
|
|
2
|
+
|
|
3
|
+
The SDK routes all of its internal diagnostics through a single `SodaxLogger` instead of calling
|
|
4
|
+
`console.*` directly. Pick a preset or forward to a structured sink (Sentry, Pino, Datadog, …) without
|
|
5
|
+
patching globals.
|
|
6
|
+
|
|
7
|
+
## Select a logger at construction
|
|
8
|
+
|
|
9
|
+
`logger` is a `Sodax` constructor option — a field on `SodaxOptions` (the constructor's parameter
|
|
10
|
+
type), kept off the `SodaxConfig` data contract because it is a client-side sink, not backend-fetched
|
|
11
|
+
config. It accepts a preset name or a custom implementation:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { Sodax } from '@sodax/sdk';
|
|
15
|
+
|
|
16
|
+
new Sodax(); // default — same as { logger: 'console' }
|
|
17
|
+
new Sodax({ logger: 'console' }); // mirror console.* output
|
|
18
|
+
new Sodax({ logger: 'silent' }); // drop all SDK logs
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The logger is resolved **once** at construction and held on `ConfigService` outside the swappable
|
|
22
|
+
dynamic config (read it back as `sodax.config.logger`). `await sodax.config.initialize()` fetches fresh
|
|
23
|
+
chain config from the backend but **never** replaces the logger — the backend cannot set or overwrite
|
|
24
|
+
it.
|
|
25
|
+
|
|
26
|
+
> Combine with the other constructor options freely — pass `logger` alongside `chains` / `api` /
|
|
27
|
+
> `solver` overrides in the same object. The constructor splits `logger` off the data override before
|
|
28
|
+
> merging, so it never lands in `sodax.instanceConfig`. See [`initialize-sodax.md`](initialize-sodax.md).
|
|
29
|
+
|
|
30
|
+
## Custom sink
|
|
31
|
+
|
|
32
|
+
Implement the `SodaxLogger` interface and pass the instance:
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { Sodax, type SodaxLogger } from '@sodax/sdk';
|
|
36
|
+
|
|
37
|
+
const sentryLogger: SodaxLogger = {
|
|
38
|
+
debug: (message, data) => Sentry.addBreadcrumb({ level: 'debug', message, data }),
|
|
39
|
+
info: (message, data) => Sentry.addBreadcrumb({ level: 'info', message, data }),
|
|
40
|
+
warn: (message, data) => Sentry.captureMessage(message, { level: 'warning', extra: data }),
|
|
41
|
+
error: (message, error, data) =>
|
|
42
|
+
error !== undefined
|
|
43
|
+
? Sentry.captureException(error, { extra: { message, ...data } })
|
|
44
|
+
: Sentry.captureMessage(message, { level: 'error', extra: data }),
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const sodax = new Sodax({ logger: sentryLogger });
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Interface
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import type { SodaxLogger, SodaxLoggerOption } from '@sodax/sdk';
|
|
54
|
+
|
|
55
|
+
// SodaxLogger:
|
|
56
|
+
// debug(message: string, data?: Record<string, unknown>): void;
|
|
57
|
+
// info(message: string, data?: Record<string, unknown>): void;
|
|
58
|
+
// warn(message: string, data?: Record<string, unknown>): void;
|
|
59
|
+
// error(message: string, error?: unknown, data?: Record<string, unknown>): void;
|
|
60
|
+
//
|
|
61
|
+
// SodaxLoggerOption = SodaxLogger | 'console' | 'silent';
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`error()` takes the thrown value as a separate second argument (before structured `data`) so adapters
|
|
65
|
+
can attach it as the exception — `warn` / `info` / `debug` take only `(message, data?)`. SDK errors are
|
|
66
|
+
`SodaxError` instances; their `toJSON()` is the canonical serialization surface (`JSON.stringify(error)`
|
|
67
|
+
invokes it automatically). For routing a failed `Result<T>`'s `error` into a sink, see the **Logging**
|
|
68
|
+
section of [`result-and-errors.md`](result-and-errors.md).
|
|
69
|
+
|
|
70
|
+
## Built-in loggers and resolver
|
|
71
|
+
|
|
72
|
+
`consoleLogger`, `silentLogger`, and `resolveLogger(option)` are exported from `@sodax/sdk` for
|
|
73
|
+
composition — e.g. wrapping the console logger to add a prefix, or resolving a preset name yourself:
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { consoleLogger, resolveLogger, type SodaxLogger } from '@sodax/sdk';
|
|
77
|
+
|
|
78
|
+
// Wrap the default to add a prefix
|
|
79
|
+
const prefixed: SodaxLogger = {
|
|
80
|
+
debug: (m, d) => consoleLogger.debug(`[sodax] ${m}`, d),
|
|
81
|
+
info: (m, d) => consoleLogger.info(`[sodax] ${m}`, d),
|
|
82
|
+
warn: (m, d) => consoleLogger.warn(`[sodax] ${m}`, d),
|
|
83
|
+
error: (m, e, d) => consoleLogger.error(`[sodax] ${m}`, e, d),
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// Resolve a preset name to a concrete logger
|
|
87
|
+
const resolved = resolveLogger('silent'); // → silentLogger
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Coverage
|
|
91
|
+
|
|
92
|
+
All instance feature services (swap, bridge, money market, DEX, staking, partner, recovery, the spoke
|
|
93
|
+
services), `BackendApiService`, and the solver API client route through the configured logger. A small
|
|
94
|
+
number of pure utility / static-helper functions still call `console.*` directly because they have no
|
|
95
|
+
access to the instance logger.
|
|
96
|
+
|
|
97
|
+
## Cross-references
|
|
98
|
+
|
|
99
|
+
- [`README.md`](README.md) — recipe index.
|
|
100
|
+
- [`initialize-sodax.md`](initialize-sodax.md) — the constructor options object `logger` lives in.
|
|
101
|
+
- [`result-and-errors.md`](result-and-errors.md) — routing a failed `Result<T>` into a logging sink.
|
|
102
|
+
- [`../reference/public-api.md`](../reference/public-api.md) — exported logger symbols.
|
|
@@ -8,9 +8,17 @@ Import everything from `@sodax/sdk`. The barrel re-exports the entire `@sodax/ty
|
|
|
8
8
|
import {
|
|
9
9
|
// Main entry
|
|
10
10
|
Sodax,
|
|
11
|
+
type SodaxOptions, // constructor param: DeepPartial<SodaxConfig> & { logger? }
|
|
11
12
|
type SodaxConfig,
|
|
12
13
|
type DeepPartial,
|
|
13
14
|
|
|
15
|
+
// Logging (see recipes/logging.md)
|
|
16
|
+
type SodaxLogger,
|
|
17
|
+
type SodaxLoggerOption,
|
|
18
|
+
consoleLogger,
|
|
19
|
+
silentLogger,
|
|
20
|
+
resolveLogger,
|
|
21
|
+
|
|
14
22
|
// Chain keys + narrowing
|
|
15
23
|
ChainKeys,
|
|
16
24
|
type ChainKey,
|