@sodax/skills 2.0.0-rc.11 → 2.0.0-rc.13

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.
Files changed (39) hide show
  1. package/.claude-plugin/plugin.json +2 -0
  2. package/AGENTS.md +8 -8
  3. package/package.json +1 -1
  4. package/skills/sodax-dapp-kit/SKILL.md +2 -2
  5. package/skills/sodax-dapp-kit/integration/knowledge/README.md +1 -1
  6. package/skills/sodax-dapp-kit/integration/knowledge/features/README.md +3 -2
  7. package/skills/sodax-dapp-kit/integration/knowledge/features/auxiliary-services.md +44 -0
  8. package/skills/sodax-dapp-kit/integration/knowledge/features/bitcoin.md +6 -6
  9. package/skills/sodax-dapp-kit/integration/knowledge/features/leverage-yield.md +112 -0
  10. package/skills/sodax-dapp-kit/integration/knowledge/features/money-market.md +5 -0
  11. package/skills/sodax-dapp-kit/integration/knowledge/recipes/README.md +1 -0
  12. package/skills/sodax-dapp-kit/integration/knowledge/recipes/bitcoin.md +8 -8
  13. package/skills/sodax-dapp-kit/integration/knowledge/recipes/leverage-yield.md +168 -0
  14. package/skills/sodax-dapp-kit/integration/knowledge/recipes/wallet-connectivity.md +3 -0
  15. package/skills/sodax-dapp-kit/integration/knowledge/reference/glossary.md +1 -1
  16. package/skills/sodax-dapp-kit/integration/knowledge/reference/hooks-index.md +21 -3
  17. package/skills/sodax-dapp-kit/integration/knowledge/reference/querykey-conventions.md +17 -0
  18. package/skills/sodax-dapp-kit/leverage-yield/SKILL.md +50 -0
  19. package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/breaking-changes/hook-signatures.md +1 -1
  20. package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/breaking-changes/sdk-leakage.md +1 -1
  21. package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/checklist.md +1 -1
  22. package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/features/README.md +1 -1
  23. package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/features/bitcoin.md +2 -2
  24. package/skills/sodax-dapp-kit/migration-v1-to-v2/knowledge/reference/renamed-hooks.md +1 -1
  25. package/skills/sodax-sdk/SKILL.md +1 -1
  26. package/skills/sodax-sdk/integration/knowledge/README.md +1 -1
  27. package/skills/sodax-sdk/integration/knowledge/architecture.md +5 -3
  28. package/skills/sodax-sdk/integration/knowledge/chain-specifics.md +33 -8
  29. package/skills/sodax-sdk/integration/knowledge/features/README.md +2 -1
  30. package/skills/sodax-sdk/integration/knowledge/features/bridge.md +1 -0
  31. package/skills/sodax-sdk/integration/knowledge/features/leverage-yield.md +175 -0
  32. package/skills/sodax-sdk/integration/knowledge/features/money-market.md +1 -0
  33. package/skills/sodax-sdk/integration/knowledge/features/swap.md +1 -0
  34. package/skills/sodax-sdk/integration/knowledge/recipes/README.md +1 -0
  35. package/skills/sodax-sdk/integration/knowledge/recipes/initialize-sodax.md +6 -2
  36. package/skills/sodax-sdk/integration/knowledge/recipes/logging.md +102 -0
  37. package/skills/sodax-sdk/integration/knowledge/reference/error-codes.md +17 -1
  38. package/skills/sodax-sdk/integration/knowledge/reference/public-api.md +20 -0
  39. package/skills/sodax-sdk/leverage-yield/SKILL.md +46 -0
@@ -7,6 +7,7 @@
7
7
  "./skills/sodax-sdk/bridge",
8
8
  "./skills/sodax-sdk/staking",
9
9
  "./skills/sodax-sdk/dex",
10
+ "./skills/sodax-sdk/leverage-yield",
10
11
  "./skills/sodax-sdk/migration",
11
12
  "./skills/sodax-sdk/partner",
12
13
  "./skills/sodax-sdk/recovery",
@@ -34,6 +35,7 @@
34
35
  "./skills/sodax-dapp-kit/staking",
35
36
  "./skills/sodax-dapp-kit/bridge",
36
37
  "./skills/sodax-dapp-kit/dex",
38
+ "./skills/sodax-dapp-kit/leverage-yield",
37
39
  "./skills/sodax-dapp-kit/migration",
38
40
  "./skills/sodax-dapp-kit/bitcoin",
39
41
  "./skills/sodax-dapp-kit/auxiliary-services"
package/AGENTS.md CHANGED
@@ -8,10 +8,10 @@ This package ships **four mode-gated broad skills** (`skills/<name>/SKILL.md`)
8
8
 
9
9
  | SDK package | Broad skill | Granular per-feature skills |
10
10
  |---|---|---|
11
- | `@sodax/sdk` | `sodax-sdk` | `sodax-sdk/swap`, `sodax-sdk/money-market`, `sodax-sdk/bridge`, `sodax-sdk/staking`, `sodax-sdk/dex`, `sodax-sdk/migration`, `sodax-sdk/partner`, `sodax-sdk/recovery`, `sodax-sdk/backend-api` |
11
+ | `@sodax/sdk` | `sodax-sdk` | `sodax-sdk/swap`, `sodax-sdk/money-market`, `sodax-sdk/bridge`, `sodax-sdk/staking`, `sodax-sdk/dex`, `sodax-sdk/leverage-yield`, `sodax-sdk/migration`, `sodax-sdk/partner`, `sodax-sdk/recovery`, `sodax-sdk/backend-api` |
12
12
  | `@sodax/wallet-sdk-core` | `sodax-wallet-sdk-core` | `sodax-wallet-sdk-core/evm`, `sodax-wallet-sdk-core/solana`, `sodax-wallet-sdk-core/sui`, `sodax-wallet-sdk-core/bitcoin`, `sodax-wallet-sdk-core/stellar`, `sodax-wallet-sdk-core/icon`, `sodax-wallet-sdk-core/injective`, `sodax-wallet-sdk-core/near`, `sodax-wallet-sdk-core/stacks` |
13
13
  | `@sodax/wallet-sdk-react` | `sodax-wallet-sdk-react` | `sodax-wallet-sdk-react/connect`, `sodax-wallet-sdk-react/wallet-modal`, `sodax-wallet-sdk-react/bridge-to-sdk`, `sodax-wallet-sdk-react/switch-chain`, `sodax-wallet-sdk-react/sign-message`, `sodax-wallet-sdk-react/walletconnect` |
14
- | `@sodax/dapp-kit` | `sodax-dapp-kit` | `sodax-dapp-kit/swap`, `sodax-dapp-kit/money-market`, `sodax-dapp-kit/staking`, `sodax-dapp-kit/bridge`, `sodax-dapp-kit/dex`, `sodax-dapp-kit/migration`, `sodax-dapp-kit/bitcoin`, `sodax-dapp-kit/auxiliary-services` |
14
+ | `@sodax/dapp-kit` | `sodax-dapp-kit` | `sodax-dapp-kit/swap`, `sodax-dapp-kit/money-market`, `sodax-dapp-kit/staking`, `sodax-dapp-kit/bridge`, `sodax-dapp-kit/dex`, `sodax-dapp-kit/leverage-yield`, `sodax-dapp-kit/migration`, `sodax-dapp-kit/bitcoin`, `sodax-dapp-kit/auxiliary-services` |
15
15
 
16
16
  **When to prefer a granular skill:** if the consumer has already picked a sub-domain (e.g. *"swap with Sodax"*, *"supply on money market"*, *"useSwap hook"*, *"instantiate EvmWalletProvider"*, *"add a connect button"*), load the matching granular skill — it's ~3 KB vs the broad skill's ~13 KB and points at exactly the knowledge files needed. For a React dapp that has settled on one feature, load `sodax-dapp-kit/<feature>`; for raw SDK / backend work, load `sodax-sdk/<feature>`; for a known chain in a backend/Node wallet flow, load `sodax-wallet-sdk-core/<chain>`; for a known React wallet concern (connect, wallet-modal, bridge-to-sdk, switch-chain, sign-message, walletconnect), load `sodax-wallet-sdk-react/<concern>`. Load the broad skill when the sub-domain is undecided, the task spans several, or the consumer is porting a full v1 codebase.
17
17
 
@@ -23,8 +23,8 @@ Pick the consumer's situation, load the listed skills in order. Each entry names
23
23
 
24
24
  | Consumer is… | Load skills (mode) |
25
25
  |---|---|
26
- | **Scaffolding ONE specific Core SDK feature** (swap, money-market, bridge, staking, dex, migration, partner, recovery, backend-api) | `sodax-sdk/<feature>` (granular, covers both modes via internal links). Add `sodax-wallet-sdk-core` (integration) if it signs and lives outside React. Skip the broad `sodax-sdk` skill |
27
- | **Scaffolding ONE specific dapp-kit feature in React** (swap, money-market, staking, bridge, dex, migration, bitcoin, auxiliary-services) | `sodax-wallet-sdk-react` (integration) → `sodax-dapp-kit/<feature>` (granular, covers both modes via internal links). Skip the broad `sodax-dapp-kit` skill. If the wallet concern is also settled (just a connect button, modal, bridge, etc.), narrow to `sodax-wallet-sdk-react/<concern>` too |
26
+ | **Scaffolding ONE specific Core SDK feature** (swap, money-market, bridge, staking, dex, leverage-yield, migration, partner, recovery, backend-api) | `sodax-sdk/<feature>` (granular, covers both modes via internal links). Add `sodax-wallet-sdk-core` (integration) if it signs and lives outside React. Skip the broad `sodax-sdk` skill |
27
+ | **Scaffolding ONE specific dapp-kit feature in React** (swap, money-market, staking, bridge, dex, leverage-yield, migration, bitcoin, auxiliary-services) | `sodax-wallet-sdk-react` (integration) → `sodax-dapp-kit/<feature>` (granular, covers both modes via internal links). Skip the broad `sodax-dapp-kit` skill. If the wallet concern is also settled (just a connect button, modal, bridge, etc.), narrow to `sodax-wallet-sdk-react/<concern>` too |
28
28
  | **Scaffolding ONE chain's wallet provider** (backend/Node/non-React: evm, solana, sui, bitcoin, stellar, icon, injective, near, stacks) | `sodax-wallet-sdk-core/<chain>` (granular, covers both modes) → `sodax-sdk/<feature>` for the operation it signs. Skip the broad `sodax-wallet-sdk-core` skill |
29
29
  | **Scaffolding ONE React wallet concern** (connect, wallet-modal, bridge-to-sdk, switch-chain, sign-message, walletconnect) | `sodax-wallet-sdk-react/<concern>` (granular, covers both modes). Skip the broad `sodax-wallet-sdk-react` skill |
30
30
  | **Building a NEW React dapp** | `sodax-wallet-sdk-react` (integration) → `sodax-dapp-kit` (integration) → (`sodax-sdk` (integration) only if dropping below dapp-kit) |
@@ -58,8 +58,8 @@ packages/skills/
58
58
  ├── .claude-plugin/plugin.json # Skill registry (broad + nested granular paths)
59
59
  └── skills/ # Each broad skill is mode-gated; some have nested granular children
60
60
  ├── sodax-sdk/ {SKILL.md, integration/knowledge/, migration-v1-to-v2/knowledge/,
61
- │ <feature>/SKILL.md ×9 — swap, money-market, bridge, staking, dex,
62
- │ migration, partner, recovery, backend-api}
61
+ │ <feature>/SKILL.md ×10 — swap, money-market, bridge, staking, dex,
62
+ leverage-yield, migration, partner, recovery, backend-api}
63
63
  ├── sodax-wallet-sdk-core/ {SKILL.md, integration/knowledge/, migration-v1-to-v2/knowledge/,
64
64
  │ <chain>/SKILL.md ×9 — evm, solana, sui, bitcoin, stellar, icon,
65
65
  │ injective, near, stacks}
@@ -68,8 +68,8 @@ packages/skills/
68
68
  │ <concern>/SKILL.md ×6 — connect, wallet-modal, bridge-to-sdk,
69
69
  │ switch-chain, sign-message, walletconnect}
70
70
  └── sodax-dapp-kit/ {SKILL.md, integration/knowledge/, migration-v1-to-v2/knowledge/,
71
- <feature>/SKILL.md ×8 — swap, money-market, staking, bridge, dex,
72
- migration, bitcoin, auxiliary-services}
71
+ <feature>/SKILL.md ×9 — swap, money-market, staking, bridge, dex,
72
+ leverage-yield, migration, bitcoin, auxiliary-services}
73
73
  ```
74
74
 
75
75
  Each `<mode>/knowledge/` subtree contains `ai-rules.md`, `quickstart.md`, `architecture.md`, `features/`, `recipes/`, `reference/`, and `chain-specifics.md` / `breaking-changes/` where applicable.
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "2.0.0-rc.11",
7
+ "version": "2.0.0-rc.13",
8
8
  "license": "MIT",
9
9
  "description": "AI-agent skills and knowledge for consumers of @sodax/* SDKs (Claude Code, Codex, Cursor, …)",
10
10
  "keywords": [
@@ -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/Radfi, 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.'
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` (Radfi, dapp-kit-unique), `auxiliary-services.md` (partner + recovery + backend + shared).
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) | Radfi hooks (dapp-kit-unique): session, trading wallet, fund/withdraw, UTXOs. |
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. |
@@ -9,8 +9,9 @@ Per-feature reference docs. Each file documents the hooks, params types, return
9
9
  | [`staking.md`](staking.md) | SODA → xSODA staking: `useStake`, `useUnstake`, `useInstantUnstake`, `useClaim`, `useCancelUnstake`, allowance/approve, info/ratio reads. |
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
+ | [`leverage-yield.md`](leverage-yield.md) | Leveraged-yield ERC-4626 vaults: `useLeverageYieldDeposit`/`Withdraw` (build) + `useLeverageYieldVaultSwap` (execute), effective APR / position / TVL / share-balance reads. |
12
13
  | [`migration.md`](migration.md) | Token migration: `useMigrateIcxToSoda`, `useRevertMigrateSodaToIcx`, `useMigratebnUSD`, `useMigrateBaln`, allowance/approve. |
13
- | [`bitcoin.md`](bitcoin.md) | Radfi (dapp-kit-unique): session, trading wallet, fund/withdraw, UTXOs. |
14
+ | [`bitcoin.md`](bitcoin.md) | Bound Exchange (dapp-kit-unique): session, trading wallet, fund/withdraw, UTXOs. |
14
15
  | [`auxiliary-services.md`](auxiliary-services.md) | Partner fee claiming, recovery, backend queries (intent tracking, orderbook, MM data), shared utilities (xBalances, gas, trustlines). |
15
16
 
16
17
  ## Reference vs recipes
@@ -20,7 +21,7 @@ Per-feature reference docs. Each file documents the hooks, params types, return
20
21
 
21
22
  ## Pair-completeness
22
23
 
23
- Every file in this directory has a sibling in [`features/`](../../../migration-v1-to-v2/knowledge/features/) with the same filename — the v1→v2 porting playbook for that feature. When you're deep in one, the other is one path-swap away.
24
+ Every file in this directory has a sibling in [`features/`](../../../migration-v1-to-v2/knowledge/features/) with the same filename — the v1→v2 porting playbook for that feature. When you're deep in one, the other is one path-swap away. **Exception:** features introduced in v2 with no v1 equivalent (`leverage-yield.md`) have no migration sibling — there is nothing to port.
24
25
 
25
26
  ## Cross-references
26
27
 
@@ -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 (Radfi) — `@sodax/dapp-kit`
1
+ # Bitcoin (Bound Exchange) — `@sodax/dapp-kit`
2
2
 
3
- Bitcoin trading via the Radfi protocol — authenticate, fund a trading wallet, withdraw, manage UTXOs. **Dapp-kit-unique surface** (no SDK equivalent — these flows are React-shaped).
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 }); // Radfi API
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
- Radfi requires authentication before trading operations. `useRadfiSession` handles the full lifecycle:
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 Radfi 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.** Radfi 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.
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
 
@@ -0,0 +1,112 @@
1
+ # Leverage Yield — `@sodax/dapp-kit`
2
+
3
+ Leveraged-yield ERC-4626 vaults on the Sonic hub. Deposit any token → `lsoda*` vault shares, withdraw shares → any token; plus position / APR / TVL / share-balance reads. New in v2 (no v1 equivalent).
4
+
5
+ ## Hook surface
6
+
7
+ ```ts
8
+ // @ai-snippets-skip
9
+ // Mutations
10
+ useLeverageYieldDeposit({ mutationOptions }); // build a deposit payload (any token → lsoda*)
11
+ useLeverageYieldWithdraw({ mutationOptions }); // build a withdraw payload (lsoda* → any token; hubWalletSwap)
12
+ useLeverageYieldVaultSwap({ mutationOptions }); // EXECUTE the built payload end-to-end
13
+ useLeverageYieldNotifySolver({ mutationOptions }); // manual-flow: notify the solver after a self-driven relay
14
+
15
+ // Reads
16
+ useLeverageYieldEffectiveApr({ params, queryOptions }); // AAVE + LSD effective net APR (60s)
17
+ useLeverageYieldPosition({ params, queryOptions }); // collateral/debt/ltv/healthFactor/idle (30s)
18
+ useLeverageYieldTotalAssets({ params, queryOptions }); // vault TVL, 18-dp bigint (60s)
19
+ useLeverageYieldPreviewRedeem({ params, queryOptions }); // assets for N shares; price-per-share (60s)
20
+ useLeverageYieldShareBalances({ params, queryOptions }); // per-chain share balances via useQueries (15s)
21
+ ```
22
+
23
+ `deposit` / `withdraw` are **builders** — they assemble a `LeverageYieldSwapPayload`, they do NOT broadcast. Spread the built payload into `useLeverageYieldVaultSwap`'s `mutate`, adding the `walletProvider`. There is no dedicated leverage-yield approve hook: the swap-style deposit approves the spoke-side asset manager, so reuse `useSwapApprove` / `useSwapAllowance` (see Approval pattern).
24
+
25
+ ## Mutation TVars
26
+
27
+ ```ts
28
+ // @ai-snippets-skip
29
+ // deposit — vars are the SDK's deposit params (any token → lsoda* on the hub wallet)
30
+ type UseLeverageYieldDepositVars = LeverageYieldSwapDepositParams;
31
+ // { vault: Address; srcChainKey; srcAddress; inputToken; inputAmount: bigint;
32
+ // minOutputAmount: bigint; deadline?: bigint; solver?: Address; partnerFee? }
33
+
34
+ // withdraw — lsoda* shares → any token on any chain (hub-wallet sourced)
35
+ type UseLeverageYieldWithdrawVars = LeverageYieldSwapWithdrawParams;
36
+ // { vault: Address; srcChainKey; srcAddress; dstChainKey; outputToken;
37
+ // inputAmount: bigint; minOutputAmount: bigint; recipient?; deadline?; solver? }
38
+
39
+ // vaultSwap — the executor. Spread the built payload + walletProvider.
40
+ type UseLeverageYieldVaultSwapVars<K> = Omit<VaultSwapActionParams<K, false>, 'raw'>;
41
+ // = SpokeExecActionParams<K, false, CreateIntentParams<K>> & { hubWalletSwap?; partnerFee? }
42
+ // i.e. { params: CreateIntentParams<K>; walletProvider; hubWalletSwap?; partnerFee?; timeout? }
43
+
44
+ // notifySolver — manual-flow notify step (vaultSwap already notifies internally)
45
+ type UseLeverageYieldNotifySolverVars = SolverExecutionRequest;
46
+ // { intent_tx_hash: Hex } — the hub-side tx hash where the intent landed
47
+ ```
48
+
49
+ ## Read shapes (key picks)
50
+
51
+ ```ts
52
+ // @ai-snippets-skip
53
+ // useLeverageYieldEffectiveApr — AAVE rates + LSD staking yield, leverage re-applied (data unwrapped)
54
+ useLeverageYieldEffectiveApr({ params: { vault } })
55
+ // → UseQueryResult<LeverageYieldEffectiveApr>
56
+ // LeverageYieldEffectiveApr = LeverageYieldApr & { lsdApr, effectiveSupplyAprRay, effectiveNetAprRay }
57
+ // LeverageYieldApr = { supplyAprRay, borrowAprRay, targetLtvBps, leverageMultiplierWad, netAprRay } (RAY = 1e27)
58
+
59
+ // useLeverageYieldPosition — live position snapshot
60
+ useLeverageYieldPosition({ params: { vault } })
61
+ // → UseQueryResult<LeverageYieldPosition>
62
+ // LeverageYieldPosition = { collateral, debt, ltv, healthFactor, idleAsset } (all bigint)
63
+
64
+ // useLeverageYieldPreviewRedeem — assets per shares; pass 1e18 for price-per-share
65
+ useLeverageYieldPreviewRedeem({ params: { vault, shares: 10n ** 18n } })
66
+ // → UseQueryResult<bigint>
67
+
68
+ // useLeverageYieldShareBalances — returns an ARRAY (one query per holder), NOT a single result
69
+ useLeverageYieldShareBalances({ params: { vault, holders } })
70
+ // → UseQueryResult<LeverageYieldShareHolding>[]
71
+ // LeverageYieldShareHolding = { chainKey: SpokeChainKey; holder: Address; shares: bigint }
72
+ // holders: { chainKey: SpokeChainKey; address: string }[] — one row per chain the user may hold under
73
+ ```
74
+
75
+ ## Approval pattern
76
+
77
+ Leverage-yield has **no dedicated approve hook**. A deposit is a swap-style intent that bridges `inputToken` from the spoke chain, so it approves the spoke-side asset manager exactly like a swap — reuse the swap hooks. A withdraw needs no spoke-side approval: the payload carries `hubWalletSwap: true` and `vaultSwap` authorises the hub wallet to spend the `lsoda*` shares via a `Connection.sendMessage` the user signs on `srcChainKey`.
78
+
79
+ | Flow | Token approved | Hook |
80
+ |---|---|---|
81
+ | `deposit` | spoke `inputToken` → asset manager | `useSwapApprove`, `useSwapAllowance` (swap domain) |
82
+ | `withdraw` | none (hub-wallet `sendMessage` authorises the spend) | — |
83
+
84
+ ## Return shapes
85
+
86
+ All read hooks here are **already unwrapped** — they throw on SDK `!ok` so `isError` / `error` / `retry` engage. Read `data` directly; do NOT branch on `data.ok`.
87
+
88
+ | Hook | Returns |
89
+ |---|---|
90
+ | `useLeverageYieldDeposit` / `useLeverageYieldWithdraw` | `SafeUseMutationResult<LeverageYieldSwapPayload, Error, …>` (builder — `data` is the payload to spread into `useLeverageYieldVaultSwap`) |
91
+ | `useLeverageYieldVaultSwap` | `SafeUseMutationResult<VaultSwapResponse, Error, …>` (`{ solverExecutionResponse, intent, intentDeliveryInfo }`) |
92
+ | `useLeverageYieldNotifySolver` | `SafeUseMutationResult<SolverExecutionResponse, Error, …>` (`{ answer: 'OK', intent_hash }`) |
93
+ | `useLeverageYieldEffectiveApr` | `UseQueryResult<LeverageYieldEffectiveApr, Error>` |
94
+ | `useLeverageYieldPosition` | `UseQueryResult<LeverageYieldPosition, Error>` |
95
+ | `useLeverageYieldTotalAssets` | `UseQueryResult<bigint, Error>` |
96
+ | `useLeverageYieldPreviewRedeem` | `UseQueryResult<bigint, Error>` |
97
+ | `useLeverageYieldShareBalances` | `UseQueryResult<LeverageYieldShareHolding, Error>[]` (array — one entry per holder) |
98
+
99
+ ## Gotchas
100
+
101
+ 1. **`deposit` / `withdraw` are builders, not executors.** Their `data` is a `LeverageYieldSwapPayload` — spread it into `useLeverageYieldVaultSwap`'s `mutate` with a `walletProvider` to actually run the swap. Calling them does not broadcast anything.
102
+ 2. **`useLeverageYieldShareBalances` returns an ARRAY, not a single query.** It fans out one `useQueries` row per holder. Aggregate yourself: `balances.reduce((acc, q) => acc + (q.data?.shares ?? 0n), 0n)`. `queryOptions` is spread into every per-holder query (no top-level options slot on `useQueries`).
103
+ 3. **The share-balance key segment is singular: `shareBalance`** (`['leverageYield', 'shareBalance', vault, chainKey, address]`) — one per holder, even though the hook name is plural.
104
+ 4. **Withdraw needs no spoke approval.** Don't gate it on `useSwapAllowance` — the hub-wallet `sendMessage` path approves the share spend internally. Only `deposit` needs the swap-domain allowance/approve pair.
105
+ 5. **Deposit's per-intent `partnerFee` must be reflected in the quote.** If you charge a deposit-only fee (e.g. 1%), `vaultSwap`'s underlying `createVaultIntent` deducts it from `inputAmount` before the swap — quote on the post-fee amount, or `minOutputAmount` becomes unfillable and the intent never settles.
106
+ 6. **`useLeverageYieldVaultSwap` invalidates xBalances on both chains** (`['shared', 'xBalances', srcChainKey]` and `dstChainKey`) on success. Compose your own `onSuccess` after the hook's — it runs first.
107
+ 7. **`useLeverageYieldNotifySolver` is for the manual flow only.** `useLeverageYieldVaultSwap` already notifies the solver internally — only reach for the standalone notify hook when you built the intent with `sodax.leverageYield.createVaultIntent` and relayed it yourself. It does NOT invalidate any queries: its only var is `{ intent_tx_hash }` (no chain context), and the fill lands asynchronously afterward.
108
+
109
+ ## Cross-references
110
+
111
+ - [`../recipes/leverage-yield.md`](../recipes/leverage-yield.md) — full worked deposit / withdraw / reads examples.
112
+ - For the underlying SDK leverage-yield surface (`LeverageYieldService`, `createVaultIntent`, `notifySolver`, APR math), load the `sodax-sdk` skill (integration mode) — its `features/leverage-yield.md`.
@@ -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):
@@ -35,6 +35,7 @@ Copy-paste patterns for adding SODAX features to a React app. Each recipe is sel
35
35
  | [`staking.md`](staking.md) | `useStake`, `useUnstake`, `useClaim`, staking info, ratios |
36
36
  | [`migration.md`](migration.md) | `useMigrateIcxToSoda`, `useRevertMigrateSodaToIcx`, `useMigratebnUSD`, `useMigrateBaln` |
37
37
  | [`dex.md`](dex.md) | `useDexDeposit`, `useSupplyLiquidity`, positions, pools |
38
+ | [`leverage-yield.md`](leverage-yield.md) | `useLeverageYieldDeposit`, `useLeverageYieldWithdraw`, `useLeverageYieldVaultSwap`, APR/position/TVL/share-balance reads |
38
39
  | [`bitcoin.md`](bitcoin.md) | `useRadfiSession`, `useFundTradingWallet`, `useRadfiWithdraw`, UTXO management |
39
40
  | [`backend-queries.md`](backend-queries.md) | Intent tracking, orderbook, money market position queries (read-only, no wallet) |
40
41
 
@@ -1,6 +1,6 @@
1
- # Recipe: Bitcoin (Radfi)
1
+ # Recipe: Bitcoin (Bound Exchange)
2
2
 
3
- Bitcoin trading via the Radfi protocol. Authenticate, fund a trading wallet, trade, withdraw, and manage UTXOs.
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 Radfi via BIP322 signing |
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 Radfi API (confirmed + pending) |
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
- Radfi requires authentication before any trading operation. The typical flow:
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 Radfi'}
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 Radfi API). `RadfiWalletBalance` fields:
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 Radfi session from localStorage.
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.
@@ -0,0 +1,168 @@
1
+ # Recipe: Leverage Yield
2
+
3
+ Leveraged-yield ERC-4626 vaults on Sonic. Deposit any token → `lsoda*` shares, withdraw shares → any token, and read position / APR / TVL / balances.
4
+
5
+ **Depends on:** [setup.md](setup.md), [wallet-connectivity.md](wallet-connectivity.md)
6
+
7
+ ## Hooks
8
+
9
+ ### Mutations
10
+
11
+ | Hook | Purpose |
12
+ |------|---------|
13
+ | `useLeverageYieldDeposit` | Build a deposit payload (any token → `lsoda*`) |
14
+ | `useLeverageYieldWithdraw` | Build a withdraw payload (`lsoda*` → any token) |
15
+ | `useLeverageYieldVaultSwap` | Execute a built payload end-to-end (create → relay → notify solver) |
16
+ | `useSwapApprove` | Approve the spoke `inputToken` (deposit only — swap-domain hook) |
17
+
18
+ ### Queries
19
+
20
+ | Hook | Purpose |
21
+ |------|---------|
22
+ | `useSwapAllowance` | Check spoke `inputToken` approval (deposit only — swap-domain hook) |
23
+ | `useLeverageYieldEffectiveApr` | AAVE + LSD effective net APR |
24
+ | `useLeverageYieldPosition` | Live position (collateral, debt, LTV, health factor, idle) |
25
+ | `useLeverageYieldTotalAssets` | Vault TVL (18-dp bigint) |
26
+ | `useLeverageYieldPreviewRedeem` | Assets for N shares (pass `1e18` for price-per-share) |
27
+ | `useLeverageYieldShareBalances` | Per-chain share balances (array via `useQueries`) |
28
+
29
+ > A deposit is a swap-style intent, so it approves the **spoke asset manager** via the swap-domain hooks — there is no leverage-yield-specific approve hook. A withdraw carries `hubWalletSwap: true` and needs no spoke approval.
30
+
31
+ ## Vault stats + position
32
+
33
+ ```tsx
34
+ import { useLeverageYieldEffectiveApr, useLeverageYieldTotalAssets, useLeverageYieldPreviewRedeem, useLeverageYieldPosition } from '@sodax/dapp-kit';
35
+ import type { Address } from '@sodax/sdk';
36
+ import { formatUnits } from 'viem';
37
+
38
+ const RAY = 10n ** 27n;
39
+
40
+ function VaultStats({ vault }: { vault: Address }) {
41
+ const { data: apr } = useLeverageYieldEffectiveApr({ params: { vault } }); // 60s refresh
42
+ const { data: tvl } = useLeverageYieldTotalAssets({ params: { vault } }); // 60s refresh
43
+ const { data: position } = useLeverageYieldPosition({ params: { vault } }); // 30s refresh
44
+ const { data: sharePrice } = useLeverageYieldPreviewRedeem({ // 60s refresh
45
+ params: { vault, shares: 10n ** 18n },
46
+ });
47
+
48
+ // RAY (1e27) rates → percent. effectiveNetAprRay folds the LSD staking yield in.
49
+ const netAprPct = apr ? Number((apr.effectiveNetAprRay * 10000n) / RAY) / 100 : undefined;
50
+
51
+ return (
52
+ <div>
53
+ {netAprPct !== undefined && <p>Net APR: {netAprPct.toFixed(2)}%</p>}
54
+ {tvl !== undefined && <p>TVL: {formatUnits(tvl, 18)}</p>}
55
+ {sharePrice !== undefined && <p>1 share = {formatUnits(sharePrice, 18)} assets</p>}
56
+ {position && <p>Health factor: {formatUnits(position.healthFactor, 18)}</p>}
57
+ </div>
58
+ );
59
+ }
60
+ ```
61
+
62
+ ## Share balances across chains
63
+
64
+ `useLeverageYieldShareBalances` returns an **array** — one query per holder. Build `holders` from the chains the user has connected, then aggregate.
65
+
66
+ ```tsx
67
+ import { useLeverageYieldShareBalances } from '@sodax/dapp-kit';
68
+ import type { Address, SpokeChainKey } from '@sodax/sdk';
69
+ import { formatUnits } from 'viem';
70
+
71
+ function ShareTotal({ vault, holders }: { vault: Address; holders: { chainKey: SpokeChainKey; address: string }[] }) {
72
+ const balances = useLeverageYieldShareBalances({ params: { vault, holders } }); // 15s refresh per query
73
+ const total = balances.reduce((acc, q) => acc + (q.data?.shares ?? 0n), 0n);
74
+ return <p>Total shares: {formatUnits(total, 18)}</p>;
75
+ }
76
+ ```
77
+
78
+ ## Deposit (any token → `lsoda*`)
79
+
80
+ Build → approve-if-needed → execute. The built payload is spread straight into `vaultSwap`.
81
+
82
+ ```tsx
83
+ // @ai-snippets-skip — illustrative end-to-end flow wiring the builder, the swap-domain
84
+ // allowance/approve hooks, and the executor across a broad walletProvider union. Real
85
+ // call shapes per hook are in features/leverage-yield.md.
86
+ import { useState } from 'react';
87
+ import {
88
+ useLeverageYieldDeposit, useLeverageYieldVaultSwap, useSwapAllowance, useSwapApprove,
89
+ } from '@sodax/dapp-kit';
90
+ import { useWalletProvider } from '@sodax/wallet-sdk-react';
91
+ import { ChainKeys, type Address, type PartnerFee } from '@sodax/sdk';
92
+ import { parseUnits } from 'viem';
93
+
94
+ const DEPOSIT_PARTNER_FEE: PartnerFee = { address: '0xYourFeeReceiver…', percentage: 100 }; // 1%
95
+
96
+ function DepositForm({ vault, srcAddress, inputToken }: { vault: Address; srcAddress: string; inputToken: string }) {
97
+ const [amount, setAmount] = useState('');
98
+ const chainKey = ChainKeys.ARBITRUM_MAINNET;
99
+ const walletProvider = useWalletProvider({ xChainId: chainKey });
100
+
101
+ const { mutateAsyncSafe: buildDeposit } = useLeverageYieldDeposit();
102
+ const { mutateAsyncSafe: approve } = useSwapApprove();
103
+ const { mutateAsync: vaultSwap, isPending } = useLeverageYieldVaultSwap();
104
+
105
+ const handleDeposit = async () => {
106
+ if (!walletProvider) return;
107
+ const built = await buildDeposit({
108
+ vault, srcChainKey: chainKey, srcAddress, inputToken,
109
+ inputAmount: parseUnits(amount, 18),
110
+ minOutputAmount: 0n, // quote via sodax.swaps.getQuote (token_dst = vault), then subtract slippage
111
+ partnerFee: DEPOSIT_PARTNER_FEE, // per-intent fee — must match the quote's post-fee amount
112
+ });
113
+ if (!built.ok) return;
114
+
115
+ // Deposit approves the spoke asset manager (swap-style). Gate on useSwapAllowance in render.
116
+ await approve({ params: built.value.params, walletProvider });
117
+ await vaultSwap({ ...built.value, walletProvider }); // spread the payload; lsoda* lands in the hub wallet
118
+ };
119
+
120
+ return (
121
+ <div>
122
+ <input value={amount} onChange={(e) => setAmount(e.target.value)} placeholder="amount" />
123
+ <button onClick={handleDeposit} disabled={isPending || !walletProvider}>Deposit</button>
124
+ </div>
125
+ );
126
+ }
127
+ ```
128
+
129
+ ## Withdraw (`lsoda*` → any token)
130
+
131
+ No approval step — `hubWalletSwap: true` authorises the share spend via a `sendMessage`.
132
+
133
+ ```tsx
134
+ // @ai-snippets-skip — illustrative end-to-end flow (builder + executor) across a broad
135
+ // walletProvider union; see features/leverage-yield.md for exact per-hook shapes.
136
+ import { useLeverageYieldWithdraw, useLeverageYieldVaultSwap } from '@sodax/dapp-kit';
137
+ import { useWalletProvider } from '@sodax/wallet-sdk-react';
138
+ import { ChainKeys, type Address } from '@sodax/sdk';
139
+
140
+ function WithdrawButton({ vault, srcAddress, outputToken, shares }: { vault: Address; srcAddress: string; outputToken: string; shares: bigint }) {
141
+ const chainKey = ChainKeys.ARBITRUM_MAINNET;
142
+ const walletProvider = useWalletProvider({ xChainId: chainKey });
143
+ const { mutateAsyncSafe: buildWithdraw } = useLeverageYieldWithdraw();
144
+ const { mutateAsync: vaultSwap, isPending } = useLeverageYieldVaultSwap();
145
+
146
+ const handleWithdraw = async () => {
147
+ if (!walletProvider) return;
148
+ const built = await buildWithdraw({
149
+ vault, srcChainKey: chainKey, srcAddress,
150
+ dstChainKey: chainKey, outputToken,
151
+ inputAmount: shares, // lsoda* shares to burn
152
+ minOutputAmount: 0n, // quote via sodax.swaps.getQuote (token_src = vault), then subtract slippage
153
+ });
154
+ if (!built.ok) return;
155
+ await vaultSwap({ ...built.value, walletProvider }); // built.value.hubWalletSwap === true
156
+ };
157
+
158
+ return <button onClick={handleWithdraw} disabled={isPending || !walletProvider}>Withdraw</button>;
159
+ }
160
+ ```
161
+
162
+ ## Notes
163
+
164
+ - **Two roles:** `deposit` / `withdraw` *build* a `LeverageYieldSwapPayload`; `useLeverageYieldVaultSwap` *executes* it. Always spread the built payload into the executor with a `walletProvider`.
165
+ - **Quotes:** size `minOutputAmount` with `sodax.swaps.getQuote` — vault address as `token_dst` (deposit) or `token_src` (withdraw), since `lsoda*` shares are solver-tradeable. Subtract your slippage tolerance.
166
+ - **Deposit fee:** a per-intent `partnerFee` is deducted from `inputAmount` before the swap; quote on the post-fee amount or the intent won't fill.
167
+ - **Withdraw:** no spoke approval — the hub wallet authorises the share spend via `Connection.sendMessage`. Output lands at `recipient` (defaults to `srcAddress`) on `dstChainKey`.
168
+ - **Reads** (`useLeverageYieldEffectiveApr`, `Position`, `TotalAssets`, `PreviewRedeem`) are already unwrapped — read `data` directly. `useLeverageYieldShareBalances` returns an array; aggregate the `shares` yourself.
@@ -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