@sodax/skills 2.0.0-rc.14 → 2.0.0-rc.16
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/bitcoin/SKILL.md +2 -2
- package/skills/sodax-dapp-kit/integration/knowledge/features/bitcoin.md +4 -0
- package/skills/sodax-dapp-kit/integration/knowledge/reference/hooks-index.md +1 -0
- package/skills/sodax-sdk/integration/knowledge/chain-specifics.md +2 -0
- package/skills/sodax-sdk/integration/knowledge/features/backend-api.md +6 -0
- package/skills/sodax-sdk/integration/knowledge/features/swap.md +8 -3
- package/skills/sodax-sdk/integration/knowledge/recipes/raw-tx-flow.md +25 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sodax-dapp-kit-bitcoin
|
|
3
|
-
description: 'Granular skill for the @sodax/dapp-kit v2 Bitcoin/Radfi feature only — React Query hooks for Bitcoin trading via the Radfi protocol: useRadfiAuth, useRadfiSession, useTradingWallet, useFundTradingWallet, useRadfiWithdraw, useExpiredUtxos, useRenewUtxos, useBitcoinBalance, useTradingWalletBalance. This is a dapp-kit-UNIQUE surface (no @sodax/sdk equivalent — the flows are React-shaped). Use when a React dapp task is Bitcoin/Radfi (e.g. "Radfi session hook", "fund trading wallet hook", "Radfi withdraw in React", "manage Bitcoin UTXOs hook", "BIP322 auth with dapp-kit"). Covers BOTH integration (new v2 hooks) and migration (port v1 Radfi hooks — mostly signature tightening, flow unchanged). Links into the parent sodax-dapp-kit knowledge tree.'
|
|
3
|
+
description: 'Granular skill for the @sodax/dapp-kit v2 Bitcoin/Radfi feature only — React Query hooks for Bitcoin trading via the Radfi protocol: useRadfiAuth, useRadfiSession, useEnsureRadfiAccessToken, useTradingWallet, useFundTradingWallet, useRadfiWithdraw, useExpiredUtxos, useRenewUtxos, useBitcoinBalance, useTradingWalletBalance. This is a dapp-kit-UNIQUE surface (no @sodax/sdk equivalent — the flows are React-shaped). Use when a React dapp task is Bitcoin/Radfi (e.g. "Radfi session hook", "fund trading wallet hook", "Radfi withdraw in React", "manage Bitcoin UTXOs hook", "BIP322 auth with dapp-kit"). Covers BOTH integration (new v2 hooks) and migration (port v1 Radfi hooks — mostly signature tightening, flow unchanged). Links into the parent sodax-dapp-kit knowledge tree.'
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
6
|
version: '0.0.1'
|
|
@@ -14,7 +14,7 @@ Granular skill for the Bitcoin trading hooks of `@sodax/dapp-kit` v2 — authent
|
|
|
14
14
|
## Step 1 — Clarify with user before coding
|
|
15
15
|
|
|
16
16
|
1. **New code or v1 → v2 port?**
|
|
17
|
-
2. **Which stage?** Session/auth (`useRadfiAuth`, `useRadfiSession`, `useTradingWallet`), balances (`useBitcoinBalance`, `useTradingWalletBalance`), operations (`useFundTradingWallet`, `useRadfiWithdraw`), UTXO maintenance (`useExpiredUtxos`, `useRenewUtxos`).
|
|
17
|
+
2. **Which stage?** Session/auth (`useRadfiAuth`, `useRadfiSession`, `useEnsureRadfiAccessToken`, `useTradingWallet`), balances (`useBitcoinBalance`, `useTradingWalletBalance`), operations (`useFundTradingWallet`, `useRadfiWithdraw`), UTXO maintenance (`useExpiredUtxos`, `useRenewUtxos`).
|
|
18
18
|
3. **Session lifecycle handled?** `useRadfiSession(walletProvider)` manages login/refresh/auto-refresh + localStorage persistence; gate trading buttons on `isAuthed`.
|
|
19
19
|
|
|
20
20
|
## Integration workflow (new v2 code)
|
|
@@ -11,6 +11,7 @@ Pair: [`features/bitcoin.md`](../../../migration-v1-to-v2/knowledge/features/bit
|
|
|
11
11
|
// Session lifecycle
|
|
12
12
|
useRadfiAuth({ mutationOptions }); // Authenticate via BIP322 signing
|
|
13
13
|
useRadfiSession(walletProvider); // Manage full lifecycle (login, refresh, auto-refresh)
|
|
14
|
+
useEnsureRadfiAccessToken({ mutationOptions }); // Ensure a fresh Bound token; resolves to the token string
|
|
14
15
|
useTradingWallet(walletAddress); // Synchronous: read persisted session
|
|
15
16
|
|
|
16
17
|
// Balances
|
|
@@ -24,6 +25,8 @@ useExpiredUtxos({ params: { walletProvider, tradingAddress }, queryOptions }); /
|
|
|
24
25
|
useRenewUtxos({ mutationOptions });
|
|
25
26
|
```
|
|
26
27
|
|
|
28
|
+
`useEnsureRadfiAccessToken` is for raw / server-side `createIntent`: it resolves a valid Bound token to forward as `extras.bound.accessToken` (the Bitcoin-gated `bound` slot) on a `raw: true` swap intent, or as `bound.accessToken` on a backend createIntent DTO. See the `sodax-sdk` skill (swap feature) for the `extras.bound` slot.
|
|
29
|
+
|
|
27
30
|
## Session flow
|
|
28
31
|
|
|
29
32
|
Bound Exchange requires authentication before trading operations. `useRadfiSession` handles the full lifecycle:
|
|
@@ -63,6 +66,7 @@ type RenewUtxosVars = { txIdVouts: string[]; walletProvider: IBitcoinWalletProvi
|
|
|
63
66
|
| Hook | Returns |
|
|
64
67
|
|---|---|
|
|
65
68
|
| `useRadfiAuth` | `SafeUseMutationResult<RadfiAuthResult, Error, UseRadfiAuthVars>` where `RadfiAuthResult = { accessToken, refreshToken, tradingAddress }` (3 fields, NOT `RadfiSession` — the hook persists `publicKey` to localStorage internally but doesn't return it) |
|
|
69
|
+
| `useEnsureRadfiAccessToken` | `SafeUseMutationResult<string, Error, { walletProvider }>` — resolves to a valid Bound Exchange access token (silent refresh when possible, else BIP322 re-auth) |
|
|
66
70
|
| `useFundTradingWallet` | `SafeUseMutationResult<TxId, Error, ...>` |
|
|
67
71
|
| `useRadfiWithdraw` | `SafeUseMutationResult<{ txId, fee }, Error, ...>` |
|
|
68
72
|
| `useRenewUtxos` | `SafeUseMutationResult<TxId, Error, ...>` |
|
|
@@ -127,6 +127,7 @@ Comprehensive hook table across 12 feature domains. Use this when you know the f
|
|
|
127
127
|
| Hook | Type | Purpose |
|
|
128
128
|
|---|---|---|
|
|
129
129
|
| `useRadfiAuth` | Mutation | Authenticate via BIP322 signing |
|
|
130
|
+
| `useEnsureRadfiAccessToken` | Mutation | Ensure a fresh Bound access token (silent refresh or BIP322 re-auth) |
|
|
130
131
|
| `useRadfiSession` | Utility | Manage full session lifecycle |
|
|
131
132
|
| `useTradingWallet` | Utility | Synchronously read trading wallet from localStorage |
|
|
132
133
|
| `useBitcoinBalance` | Query | BTC balance for any address |
|
|
@@ -80,6 +80,8 @@ const balance = await radfi.getBalance(tradingWallet.address);
|
|
|
80
80
|
const exists = await radfi.checkIfTradingWalletExists(personalAddress);
|
|
81
81
|
```
|
|
82
82
|
|
|
83
|
+
**Server-side / raw flows (no interactive sign-in).** A backend that builds raw Bitcoin intents can't run the BIP322 login, so seed a pre-provisioned Bound token instead of authenticating. `RadfiProvider` honors three injection points: `new Sodax({ ... })` with `radfi.accessToken` (and optional `refreshToken`) in the Bitcoin chain config (the constructor seeds them), `radfi.setRadfiAccessToken(token)` at runtime, or a per-action `extras.bound.accessToken` on `createIntent` (the Bitcoin-gated `bound` slot groups Bound/Radfi inputs). If an authenticated Bound call has neither a token nor a configured `apiKey`, `RadfiProvider` throws a legible `RadfiApiError` (the message names the fix: inject via `setRadfiAccessToken` or `new Sodax({ ... })` with `radfi.accessToken`) instead of sending an empty bearer and getting an opaque 403.
|
|
84
|
+
|
|
83
85
|
Other public methods on `RadfiProvider` you may need: `setRadfiAccessToken`, `refreshAccessToken`, `createTradingWallet`, `createWithdrawTransaction`, `requestRadfiSignature`, `getExpiredUtxos`, `buildRenewUtxoTransaction`, `signAndBroadcastRenewUtxo`, `withdrawToUser`, `signAndBroadcastWithdraw`, `getMaxWithdrawable`. Read `RadfiProvider` source for argument shapes — the API surface is broader than typical chain providers.
|
|
84
86
|
|
|
85
87
|
### Pitfall
|
|
@@ -53,6 +53,12 @@ const submitResult = await sodax.backendApi.submitSwapTx({
|
|
|
53
53
|
if (!submitResult.ok) return;
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
+
## Swap-intent request DTO — `bound.accessToken` (Bitcoin TRADING)
|
|
57
|
+
|
|
58
|
+
`CreateIntentParamsV2` is the shared wire-level request body behind the typed `/swaps/allowance/check`, `/swaps/approve`, and `/swaps/intents` calls (the `IBackendApiV2` methods the SDK drives internally). It inherits the swap extras — `partnerFee`, `srcPublicKey`, and `bound` — from `SwapExtrasV2`, the JSON-safe mirror of the SDK `SwapExtras` (`QuoteRequestV2` inherits the same trio for its `includeTxData=true` path). For Bitcoin **TRADING**-mode `raw` intents the Bound Exchange (Radfi) token is carried as `bound.accessToken` — passed in the request body instead of an `x-bound-access-token` header so it stays inside the typed DTO. Required only when the source chain is Bitcoin in TRADING mode; ignored otherwise.
|
|
59
|
+
|
|
60
|
+
You rarely build this DTO yourself: `sodax.swaps.createIntent` takes the token via the chain-key-gated `extras.bound.accessToken` slot and maps it onto `CreateIntentParamsV2.bound.accessToken`. See [`swap.md`](swap.md) § `SwapExtras` and [`../chain-specifics.md`](../chain-specifics.md) § "Bitcoin PSBT and Bound Exchange" for the consumer-facing flow and token-injection points.
|
|
61
|
+
|
|
56
62
|
## Custom backend (sandbox / fixtures)
|
|
57
63
|
|
|
58
64
|
`SodaxConfig` does not expose a typed slot to inject a custom `IConfigApi` implementation at construction. Two supported patterns:
|
|
@@ -60,12 +60,17 @@ type SwapActionParams<K extends SpokeChainKey, Raw extends boolean> = {
|
|
|
60
60
|
} & WalletProviderSlot<K, Raw>;
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`extras` and every field on it are optional. `partnerFee` overrides the configured swap fee for this single action (the same override `getQuote` accepts, below); `srcPublicKey` is chain-key-gated — only typeable when `K` is a Stacks chain (`never` elsewhere) and only needed for raw (`raw: true`) Stacks `createIntent
|
|
63
|
+
`extras` and every field on it are optional. `partnerFee` overrides the configured swap fee for this single action (the same override `getQuote` accepts, below); `srcPublicKey` is chain-key-gated — only typeable when `K` is a Stacks chain (`never` elsewhere) and only needed for raw (`raw: true`) Stacks `createIntent`; `bound` is chain-key-gated to Bitcoin and groups the Bound Exchange (Radfi) inputs — its `accessToken` is only needed for raw Bitcoin TRADING-mode `createIntent`, overriding the RadfiProvider's configured token and falling back to that instance token when omitted. (Grouping keeps future Bound inputs — trading mode, refresh token — under one slot rather than spreading a new `extras` field per item.) `LimitOrderActionParams<K, Raw>` carries the same `SwapExtras<K>`.
|
|
64
64
|
|
|
65
65
|
```ts
|
|
66
66
|
type SwapExtras<K extends SpokeChainKey> = {
|
|
67
|
-
partnerFee?: PartnerFee;
|
|
68
|
-
srcPublicKey?: string;
|
|
67
|
+
partnerFee?: PartnerFee; // overrides the configured swap fee for this action; falls back to config
|
|
68
|
+
srcPublicKey?: string; // Stacks only (raw createIntent): signer public key. Chain-key-gated — `never` on non-Stacks K.
|
|
69
|
+
bound?: BitcoinBoundExtras; // Bitcoin only: grouped Bound Exchange (Radfi) inputs. Chain-key-gated — `never` on non-Bitcoin K.
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
type BitcoinBoundExtras = {
|
|
73
|
+
accessToken?: string; // raw TRADING createIntent: Bound Exchange token; falls back to the RadfiProvider instance token.
|
|
69
74
|
};
|
|
70
75
|
```
|
|
71
76
|
|
|
@@ -18,6 +18,31 @@ const { tx, intent, relayData } = result.value;
|
|
|
18
18
|
// - …
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
### Chain-specific raw inputs (`extras`)
|
|
22
|
+
|
|
23
|
+
Some chains need a per-action input on the **raw** path, supplied via the chain-key-gated `extras` slot:
|
|
24
|
+
|
|
25
|
+
- **Stacks** (`raw: true`): `extras.srcPublicKey` is **required** — the unsigned source tx is built from the signer public key (a `SP…` address can't yield it). Omitting it fails fast with a `VALIDATION_FAILED` `SodaxError` before any network call.
|
|
26
|
+
- **Bitcoin** TRADING mode (`raw: true`): `extras.bound.accessToken` carries a Bound Exchange token so the PSBT build authenticates (`bound` is the Bitcoin-gated slot that groups Bound/Radfi inputs). It falls back to the RadfiProvider instance token (`new Sodax({ ... })` with `radfi.accessToken`, or `radfi.setRadfiAccessToken(token)`) when omitted; with no token anywhere the call fails with a legible `RadfiApiError`.
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// Stacks raw intent — srcPublicKey is mandatory:
|
|
30
|
+
await sodax.swaps.createIntent({
|
|
31
|
+
params: { ...params, srcChainKey: ChainKeys.STACKS_MAINNET },
|
|
32
|
+
extras: { srcPublicKey },
|
|
33
|
+
raw: true,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Bitcoin raw intent (TRADING) — bound.accessToken (or a seeded radfi token):
|
|
37
|
+
await sodax.swaps.createIntent({
|
|
38
|
+
params: { ...params, srcChainKey: ChainKeys.BITCOIN_MAINNET },
|
|
39
|
+
extras: { bound: { accessToken } },
|
|
40
|
+
raw: true,
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> **Note (Bitcoin):** even on the `raw: true` path, a Bitcoin TRADING intent makes a live Bound Exchange call to resolve the trading-wallet address (`getEffectiveWalletAddress`) before the PSBT is built. The unsigned PSBT is returned for you to sign offline, but the address lookup is **not** offline — Bound must be reachable, and a valid `accessToken` (per-action or seeded) is required for it.
|
|
45
|
+
|
|
21
46
|
Submit the raw tx via your own signing infrastructure. Once you have the spoke tx hash, you'll typically need to manually call the relay to complete the cross-chain flow:
|
|
22
47
|
|
|
23
48
|
```ts
|