create-miden-app 1.0.3 → 1.0.6
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/cli.js +6 -6
- package/package.json +1 -6
- package/template/.claude/hooks/check-artifacts.sh +45 -0
- package/template/.claude/hooks/run-affected-tests.sh +31 -0
- package/template/.claude/hooks/typecheck.sh +27 -0
- package/template/.claude/settings.json +35 -0
- package/template/.claude/skills/frontend-pitfalls/SKILL.md +189 -0
- package/template/.claude/skills/frontend-source-guide/SKILL.md +163 -0
- package/template/.claude/skills/miden-concepts/SKILL.md +108 -0
- package/template/.claude/skills/react-sdk-patterns/SKILL.md +296 -0
- package/template/.claude/skills/signer-integration/SKILL.md +158 -0
- package/template/.claude/skills/testing-patterns/SKILL.md +177 -0
- package/template/.claude/skills/vite-wasm-setup/SKILL.md +128 -0
- package/template/.env.example +5 -0
- package/template/CLAUDE.md +210 -0
- package/template/README.md +53 -14
- package/template/create-miden-app/template/.claude/hooks/typecheck.sh +27 -0
- package/template/create-miden-app/template/.claude/settings.json +17 -0
- package/template/create-miden-app/template/.claude/skills/frontend-pitfalls/SKILL.md +189 -0
- package/template/create-miden-app/template/.claude/skills/frontend-source-guide/SKILL.md +163 -0
- package/template/create-miden-app/template/.claude/skills/miden-concepts/SKILL.md +108 -0
- package/template/create-miden-app/template/.claude/skills/react-sdk-patterns/SKILL.md +294 -0
- package/template/create-miden-app/template/.claude/skills/signer-integration/SKILL.md +158 -0
- package/template/create-miden-app/template/.claude/skills/vite-wasm-setup/SKILL.md +128 -0
- package/template/create-miden-app/template/.env.example +5 -0
- package/template/create-miden-app/template/CLAUDE.md +116 -0
- package/template/create-miden-app/template/README.md +61 -0
- package/template/create-miden-app/template/eslint.config.js +23 -0
- package/template/create-miden-app/template/index.html +13 -0
- package/template/create-miden-app/template/package.json +34 -0
- package/template/create-miden-app/template/public/vite.svg +1 -0
- package/template/create-miden-app/template/src/App.tsx +10 -0
- package/template/create-miden-app/template/src/assets/miden.svg +3 -0
- package/template/create-miden-app/template/src/assets/react.svg +1 -0
- package/template/{src/App.css → create-miden-app/template/src/components/AppContent.css} +9 -9
- package/template/create-miden-app/template/src/components/AppContent.tsx +50 -0
- package/template/create-miden-app/template/src/components/Counter.css +27 -0
- package/template/create-miden-app/template/src/components/Counter.tsx +45 -0
- package/template/create-miden-app/template/src/config.ts +21 -0
- package/template/create-miden-app/template/src/hooks/useIncrementCounter.ts +136 -0
- package/template/create-miden-app/template/src/index.css +75 -0
- package/template/create-miden-app/template/src/lib/miden.ts +9 -0
- package/template/create-miden-app/template/src/main.tsx +10 -0
- package/template/create-miden-app/template/src/providers.tsx +31 -0
- package/template/create-miden-app/template/src/vite-env.d.ts +1 -0
- package/template/create-miden-app/template/tsconfig.app.json +32 -0
- package/template/create-miden-app/template/tsconfig.json +7 -0
- package/template/create-miden-app/template/tsconfig.node.json +24 -0
- package/template/create-miden-app/template/vite.config.ts +17 -0
- package/template/create-miden-app/template/yarn.lock +1697 -0
- package/template/index.html +1 -1
- package/template/package.json +17 -8
- package/template/public/packages/counter_account.masp +0 -0
- package/template/public/packages/increment_note.masp +0 -0
- package/template/src/App.tsx +6 -59
- package/template/src/__tests__/fixtures/accounts.ts +57 -0
- package/template/src/__tests__/fixtures/index.ts +21 -0
- package/template/src/__tests__/fixtures/notes.ts +33 -0
- package/template/src/__tests__/mocks/miden-sdk-react.ts +244 -0
- package/template/src/__tests__/patterns/README.md +44 -0
- package/template/src/__tests__/patterns/mutation-hook.test.tsx +146 -0
- package/template/src/__tests__/patterns/provider-setup.test.tsx +75 -0
- package/template/src/__tests__/patterns/query-hook.test.tsx +143 -0
- package/template/src/components/AppContent.css +45 -0
- package/template/src/components/AppContent.tsx +50 -0
- package/template/src/components/Counter.css +27 -0
- package/template/src/components/Counter.tsx +45 -0
- package/template/src/components/__tests__/AppContent.test.tsx +86 -0
- package/template/src/components/__tests__/Counter.test.tsx +114 -0
- package/template/src/config.ts +21 -0
- package/template/src/hooks/useIncrementCounter.ts +136 -0
- package/template/src/index.css +7 -0
- package/template/src/lib/miden.ts +9 -0
- package/template/src/main.tsx +6 -6
- package/template/src/providers.tsx +31 -0
- package/template/src/vite-env.d.ts +1 -0
- package/template/tsconfig.app.json +8 -4
- package/template/tsconfig.node.json +1 -3
- package/template/vite.config.ts +5 -17
- package/template/vitest.config.ts +26 -0
- package/template/vitest.setup.ts +1 -0
- package/template/yarn.lock +1318 -799
- package/template/src/miden/lib/demo.ts +0 -105
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-source-guide
|
|
3
|
+
description: Guide for advanced Miden frontend development using source repo exploration. Covers AI development practices (Plan Mode, verification-driven development, context engineering, sub-agents) and maps the miden-client source repository for discovering advanced patterns. Use when building complex applications beyond basic hook usage, implementing custom signers, working with raw WebClient, or troubleshooting SDK internals.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Advanced Miden Frontend Development: Source-Guided Context Engineering
|
|
7
|
+
|
|
8
|
+
## Development Approach
|
|
9
|
+
|
|
10
|
+
### 1. Plan Mode First
|
|
11
|
+
|
|
12
|
+
For any non-trivial frontend application, start in Plan Mode before writing code.
|
|
13
|
+
|
|
14
|
+
- Explore React SDK source and examples to understand available patterns
|
|
15
|
+
- Design the component hierarchy, data flow, and which hooks to use
|
|
16
|
+
- Identify which built-in hooks cover your needs vs what requires raw WebClient
|
|
17
|
+
- Map out the user flow: account creation, token operations, note handling
|
|
18
|
+
|
|
19
|
+
Rule of thumb: if the task involves custom transactions, external signers, or patterns not covered by the basic skills, plan first.
|
|
20
|
+
|
|
21
|
+
### 2. Verification-Driven Development
|
|
22
|
+
|
|
23
|
+
This is the single highest-leverage practice for AI-assisted frontend development.
|
|
24
|
+
|
|
25
|
+
**Type check loop**: After every file edit, run `npx tsc -b --noEmit`. The project's type check hook does this automatically. If types fail:
|
|
26
|
+
1. Read the error message
|
|
27
|
+
2. Search the React SDK source for the correct type signature or hook usage
|
|
28
|
+
3. Adapt the working pattern to your use case
|
|
29
|
+
4. Recheck
|
|
30
|
+
|
|
31
|
+
**Dev server loop**: Run `npm run dev` and check the browser. When something fails:
|
|
32
|
+
1. Check the browser console for WASM errors, network errors, or React errors
|
|
33
|
+
2. For WASM errors: check COOP/COEP headers and Vite config (see frontend-pitfalls skill)
|
|
34
|
+
3. For unexpected behavior: compare your code against the example wallet in the React SDK
|
|
35
|
+
|
|
36
|
+
Never submit code that doesn't type-check. The verification loop is your quality guarantee.
|
|
37
|
+
|
|
38
|
+
### 3. Context Engineering with Source Repos
|
|
39
|
+
|
|
40
|
+
The basic skills (react-sdk-patterns, frontend-pitfalls, vite-wasm-setup) cover standard patterns. For anything beyond those patterns, the miden-client source repository is the knowledge base.
|
|
41
|
+
|
|
42
|
+
**How to use source repos effectively**:
|
|
43
|
+
- Don't load entire repos into context. Use sub-agents to explore — they search, read relevant files, and summarize findings without filling the main conversation context.
|
|
44
|
+
- Read source files only when you need a specific answer (progressive disclosure)
|
|
45
|
+
- Look for working examples first, then adapt. The example wallet app is the most reliable reference.
|
|
46
|
+
- When you find a useful pattern in source, extract just what you need — the exact hook call, the exact type, the exact provider setup.
|
|
47
|
+
|
|
48
|
+
**Using sub-agents for exploration**:
|
|
49
|
+
- Launch an explore sub-agent with a specific question: "Find how useSwap handles the payback note type in the React SDK"
|
|
50
|
+
- The sub-agent searches, reads the relevant files, and returns a focused summary
|
|
51
|
+
- Your main context stays clean for implementation
|
|
52
|
+
|
|
53
|
+
### 4. Iterative Frontend Development
|
|
54
|
+
|
|
55
|
+
Break complex applications into stages. Complete each before starting the next:
|
|
56
|
+
|
|
57
|
+
1. **Design** (Plan Mode) — Component hierarchy, data flow, hook selection
|
|
58
|
+
2. **Provider setup** — MidenProvider config, signer integration if needed
|
|
59
|
+
3. **Query components** — Account display, balance rendering, note lists
|
|
60
|
+
4. **Mutation components** — Send forms, mint buttons, consume flows
|
|
61
|
+
5. **Transaction UX** — Stage progress, error handling, loading states
|
|
62
|
+
6. **Polish** — Auto-sync tuning, memoization, edge cases
|
|
63
|
+
|
|
64
|
+
When stuck at any stage: search the React SDK source for a similar working pattern. Adapt it, don't guess.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Miden Source Repository Map
|
|
69
|
+
|
|
70
|
+
Clone this repo alongside your project for reference. Claude will explore it when needed for advanced patterns.
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
# Contains React SDK source, WebClient WASM bindings, and working examples
|
|
74
|
+
git clone --depth 1 https://github.com/0xMiden/miden-client.git ../miden-client
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### `packages/react-sdk/` — React SDK Source
|
|
78
|
+
|
|
79
|
+
The primary reference for all frontend development.
|
|
80
|
+
|
|
81
|
+
- **`src/hooks/`** — All 18+ hook implementations. Each file is self-contained. Read these to understand exact parameters, error handling, and stage progression.
|
|
82
|
+
- **`src/context/MidenProvider.tsx`** — Client initialization, sync loop, signer detection, runExclusive lock. Read this to understand initialization order.
|
|
83
|
+
- **`src/context/SignerContext.ts`** — External signer interface. Read this when implementing custom signers.
|
|
84
|
+
- **`src/store/MidenStore.ts`** — Zustand store structure. Read this to understand cached state and what triggers re-renders.
|
|
85
|
+
- **`src/utils/`** — Utility implementations (amounts, notes, bech32, runExclusive, accountParsing).
|
|
86
|
+
- **`src/types/index.ts`** — All TypeScript interfaces. The single source of truth for option types, result types, and configuration.
|
|
87
|
+
- **`examples/wallet/`** — Complete working wallet app. The most reliable reference for how to set up MidenProvider, create accounts, display balances, claim notes, and send tokens.
|
|
88
|
+
|
|
89
|
+
**Explore when**: Writing any new component, understanding exact hook behavior, finding how a specific feature works, debugging unexpected behavior.
|
|
90
|
+
|
|
91
|
+
### `crates/web-client/` — WASM Client Bindings
|
|
92
|
+
|
|
93
|
+
The Rust-to-WASM bridge that the React SDK wraps.
|
|
94
|
+
|
|
95
|
+
- Contains the `WebClient` struct and all methods available via `useMidenClient()`
|
|
96
|
+
- JavaScript bindings in `js/` directory
|
|
97
|
+
|
|
98
|
+
**Explore when**: A hook doesn't exist for your operation, understanding what WebClient methods are available, debugging WASM-level errors.
|
|
99
|
+
|
|
100
|
+
### `crates/idxdb-store/` — IndexedDB Persistence
|
|
101
|
+
|
|
102
|
+
The browser storage layer for accounts, keys, notes, and transaction history.
|
|
103
|
+
|
|
104
|
+
**Explore when**: Debugging data persistence issues, understanding what's stored in IndexedDB, investigating storage isolation for external signers.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## What to Explore for Each Pattern
|
|
109
|
+
|
|
110
|
+
| Building This | Explore These Paths | What to Look For |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| Basic wallet UI | `examples/wallet/` | MidenProvider setup, useAccounts, useSend |
|
|
113
|
+
| Custom transaction | `src/hooks/useTransaction.ts` | Request factory pattern, client methods |
|
|
114
|
+
| External signer | `src/context/SignerContext.ts` | SignerContextValue interface, signCb |
|
|
115
|
+
| Note consumption flow | `src/hooks/useConsume.ts` | NoteId parsing, filter construction |
|
|
116
|
+
| Swap UI | `src/hooks/useSwap.ts` | Swap options, dual note types |
|
|
117
|
+
| Token display | `src/utils/amounts.ts` | formatAssetAmount, parseAssetAmount |
|
|
118
|
+
| Account ID formatting | `src/utils/accountBech32.ts` | toBech32AccountId |
|
|
119
|
+
| State management | `src/store/MidenStore.ts` | Zustand selectors, cached state |
|
|
120
|
+
| Direct WebClient usage | `src/context/MidenProvider.tsx` | useMidenClient(), runExclusive |
|
|
121
|
+
| Multi-step workflow | `src/hooks/useWaitForCommit.ts`, `useWaitForNotes.ts` | Polling, timeout patterns |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Common Advanced Patterns
|
|
126
|
+
|
|
127
|
+
### Custom Hooks Wrapping WebClient
|
|
128
|
+
For operations not covered by built-in hooks, create custom hooks that use useMidenClient() and runExclusive:
|
|
129
|
+
```tsx
|
|
130
|
+
function useBlockHeader(blockNumber: number) {
|
|
131
|
+
const client = useMidenClient();
|
|
132
|
+
const { runExclusive } = useMiden();
|
|
133
|
+
const [data, setData] = useState(null);
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
// Note: runExclusive() may be simplified in a future SDK version.
|
|
136
|
+
// Check SDK changelog when upgrading.
|
|
137
|
+
runExclusive(async () => {
|
|
138
|
+
const header = await client.getBlockHeaderByNumber(blockNumber);
|
|
139
|
+
setData(header);
|
|
140
|
+
});
|
|
141
|
+
}, [blockNumber]);
|
|
142
|
+
return data;
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Multi-Step Workflows
|
|
147
|
+
Compose hooks for complex flows (mint → wait for commit → sync → consume):
|
|
148
|
+
```tsx
|
|
149
|
+
const { mutate: mint } = useMint();
|
|
150
|
+
const { mutate: waitForCommit } = useWaitForCommit();
|
|
151
|
+
const { mutate: waitForNotes } = useWaitForNotes();
|
|
152
|
+
const { mutate: consume } = useConsume();
|
|
153
|
+
|
|
154
|
+
const mintAndConsume = async () => {
|
|
155
|
+
const { transactionId } = await mint({ targetAccountId, faucetId, amount });
|
|
156
|
+
await waitForCommit({ transactionId });
|
|
157
|
+
await waitForNotes({ accountId: targetAccountId });
|
|
158
|
+
await consume({ accountId: targetAccountId, noteIds: [...] });
|
|
159
|
+
};
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Custom Signer Implementation
|
|
163
|
+
Implement the SignerContextValue interface, wrap MidenProvider in your provider. Reference `src/context/SignerContext.ts` for the exact interface contract. The `storeName` field must be unique per user to ensure IndexedDB isolation.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: miden-concepts
|
|
3
|
+
description: Miden architecture and core concepts from a developer perspective. Covers the actor model, accounts, notes, transactions, assets, privacy model, and standard patterns. Use when designing Miden applications or understanding how Miden differs from traditional blockchains.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Miden Architecture for Developers
|
|
7
|
+
|
|
8
|
+
## What is Miden?
|
|
9
|
+
|
|
10
|
+
Miden is a zero-knowledge rollup that uses an **actor model** where each account is an independent smart contract. It settles on Ethereum via validity proofs through Agglayer.
|
|
11
|
+
|
|
12
|
+
Key properties:
|
|
13
|
+
- **Privacy by default** — accounts, notes, and transactions are private; the network stores only cryptographic commitments
|
|
14
|
+
- **Client-side execution** — transactions are executed and proven locally by the user's device
|
|
15
|
+
- **Programmable everything** — accounts hold code and storage; notes carry scripts and assets
|
|
16
|
+
|
|
17
|
+
## Mental Model Shifts from Traditional Blockchains
|
|
18
|
+
|
|
19
|
+
| Traditional (Ethereum) | Miden |
|
|
20
|
+
|------------------------|-------|
|
|
21
|
+
| Transactions involve sender + receiver | Transactions involve **one account only** |
|
|
22
|
+
| Public state by default | **Private by default** |
|
|
23
|
+
| Validators execute transactions | **Client executes and proves** locally |
|
|
24
|
+
| Gas metering | No gas (computational bounds exist) |
|
|
25
|
+
| Synchronous contract calls | **Asynchronous** communication via notes |
|
|
26
|
+
| Accounts are balances + storage | Accounts are **full smart contracts** with code, storage, and vault |
|
|
27
|
+
|
|
28
|
+
## Core Concepts
|
|
29
|
+
|
|
30
|
+
### Accounts
|
|
31
|
+
Each account is an independent smart contract containing:
|
|
32
|
+
- **Code** — Immutable logic compiled from Rust components
|
|
33
|
+
- **Storage** — Up to 255 slots (Value or StorageMap)
|
|
34
|
+
- **Vault** — Holds fungible and non-fungible assets
|
|
35
|
+
- **Nonce** — Incremented with each state change
|
|
36
|
+
- **ID** — Unique identifier (prefix + suffix, 2 Felts)
|
|
37
|
+
|
|
38
|
+
Accounts are composed from **components** — reusable Rust modules annotated with `#[component]`.
|
|
39
|
+
|
|
40
|
+
### Notes
|
|
41
|
+
Notes are **UTXO-like messages** for asynchronous inter-account communication. A note contains:
|
|
42
|
+
- **Script** — Logic that executes when the note is consumed
|
|
43
|
+
- **Inputs** — Data passed to the script (Vec<Felt>)
|
|
44
|
+
- **Assets** — Fungible/non-fungible tokens attached to the note
|
|
45
|
+
- **Metadata** — Sender, tag, note type (public/private)
|
|
46
|
+
|
|
47
|
+
Notes are created as **output notes** by one transaction and consumed as **input notes** by another.
|
|
48
|
+
|
|
49
|
+
### Transactions
|
|
50
|
+
A transaction is a **single-account state transition** with 4 phases:
|
|
51
|
+
1. Consume input notes (execute their scripts against the account)
|
|
52
|
+
2. Execute transaction script (optional, for one-off logic)
|
|
53
|
+
3. Update account state (storage, vault, nonce)
|
|
54
|
+
4. Produce output notes (for other accounts to consume later)
|
|
55
|
+
|
|
56
|
+
**Important**: A two-party transfer (Alice sends Bob tokens) requires TWO transactions:
|
|
57
|
+
1. Alice's transaction creates a P2ID note with tokens attached
|
|
58
|
+
2. Bob's transaction consumes that note, receiving the tokens
|
|
59
|
+
|
|
60
|
+
### Assets
|
|
61
|
+
- **Fungible**: `[amount, 0, faucet_suffix, faucet_prefix]` (1 Word)
|
|
62
|
+
- **Non-fungible**: Unique token tied to a faucet account
|
|
63
|
+
- Assets live in account **vaults** and move between accounts via notes
|
|
64
|
+
- Created by **faucet accounts** using `faucet::create_fungible_asset()` or `faucet::mint()`
|
|
65
|
+
|
|
66
|
+
### Felt and Word
|
|
67
|
+
- **Felt**: Field element in the Goldilocks prime field (p = 2^64 - 2^32 + 1). The fundamental data unit.
|
|
68
|
+
- **Word**: Array of 4 Felts (32 bytes). Used for cryptographic hashes, storage keys, account IDs.
|
|
69
|
+
|
|
70
|
+
**WARNING**: Felt arithmetic is **modular**. Subtraction wraps around the prime. Always validate with `.as_u64()` before subtracting. See the miden-pitfalls skill for details.
|
|
71
|
+
|
|
72
|
+
## Standard Note Patterns
|
|
73
|
+
|
|
74
|
+
| Pattern | Purpose | How It Works |
|
|
75
|
+
|---------|---------|-------------|
|
|
76
|
+
| **P2ID** | Send assets to a specific account | Note script checks consumer's ID matches target |
|
|
77
|
+
| **P2IDE** | P2ID with expiration | Adds block-height timelock; sender can reclaim after expiry |
|
|
78
|
+
| **SWAP** | Atomic asset exchange | Note offers asset A, requests asset B; consumer provides B |
|
|
79
|
+
|
|
80
|
+
## Standard Components (miden-standards)
|
|
81
|
+
|
|
82
|
+
| Component | Purpose |
|
|
83
|
+
|-----------|---------|
|
|
84
|
+
| `BasicWallet` | Standard wallet: `receive_asset()`, `move_asset_to_note()` |
|
|
85
|
+
| `BasicFungibleFaucet` | Mint/burn fungible tokens |
|
|
86
|
+
| `NoAuth` | No authentication (for testing) |
|
|
87
|
+
| `AuthFalcon512Rpo` | Production signature authentication |
|
|
88
|
+
|
|
89
|
+
## Development Model
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Developer writes Rust → Compiler produces MASM → VM executes and proves
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Three contract types:
|
|
96
|
+
- `#[component]` — Account logic and storage (can have multiple per account)
|
|
97
|
+
- `#[note]` — Note script (executes when consumed)
|
|
98
|
+
- `#[tx_script]` — One-off transaction logic
|
|
99
|
+
|
|
100
|
+
Contracts are tested locally with **MockChain** (no network needed) and deployed via **miden-client**.
|
|
101
|
+
|
|
102
|
+
## Key Design Decisions for App Architects
|
|
103
|
+
|
|
104
|
+
1. **One account per service** — Each bank, vault, or DEX pool is a separate account
|
|
105
|
+
2. **Notes for communication** — Use deposit/withdraw/request notes instead of direct calls
|
|
106
|
+
3. **Storage for state** — Use `Value` for flags, `StorageMap` for mappings
|
|
107
|
+
4. **Privacy by default** — Choose `NoteType::Public` only when discoverability is needed
|
|
108
|
+
5. **Components for reuse** — Standard wallet, auth, and faucet components compose into accounts
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: react-sdk-patterns
|
|
3
|
+
description: Complete guide to building Miden frontends with @miden-sdk/react hooks. Covers MidenProvider setup, all query hooks (useAccounts, useAccount, useNotes, useSyncState, useAssetMetadata), all mutation hooks (useCreateWallet, useSend, useMultiSend, useMint, useConsume, useSwap, useTransaction, useCreateFaucet), transaction stages, signer integration, and utility functions. Use when writing, editing, or reviewing Miden React frontend code.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Miden React SDK Patterns
|
|
7
|
+
|
|
8
|
+
## SDK Choice
|
|
9
|
+
|
|
10
|
+
ALWAYS use `@miden-sdk/react` hooks. Only fall back to raw `@miden-sdk/miden-sdk` WebClient via `useMidenClient()` for operations not covered by hooks. The React SDK handles WASM safety (runExclusive), state management (Zustand), auto-sync, and transaction stage tracking automatically.
|
|
11
|
+
|
|
12
|
+
## MidenProvider Configuration
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { MidenProvider } from "@miden-sdk/react";
|
|
16
|
+
|
|
17
|
+
<MidenProvider
|
|
18
|
+
config={{
|
|
19
|
+
rpcUrl: "devnet", // "devnet" | "testnet" | "localhost" | custom URL
|
|
20
|
+
prover: "devnet", // "local" | "devnet" | "testnet" | custom URL
|
|
21
|
+
autoSyncInterval: 15000, // ms, set to 0 to disable. Default: 15000
|
|
22
|
+
noteTransportUrl: "...", // optional: for private note delivery
|
|
23
|
+
}}
|
|
24
|
+
loadingComponent={<Loading />} // shown during WASM init
|
|
25
|
+
errorComponent={<Error />} // shown on init failure (receives Error prop)
|
|
26
|
+
>
|
|
27
|
+
<App />
|
|
28
|
+
</MidenProvider>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Network | rpcUrl | Use When |
|
|
32
|
+
|---------|--------|----------|
|
|
33
|
+
| Devnet | `"devnet"` | Development, testing with fake tokens |
|
|
34
|
+
| Testnet | `"testnet"` | Pre-production testing |
|
|
35
|
+
| Localhost | `"localhost"` | Local node at `http://localhost:57291` |
|
|
36
|
+
|
|
37
|
+
## Query Hooks
|
|
38
|
+
|
|
39
|
+
All return `{ data, isLoading, error, refetch }`.
|
|
40
|
+
|
|
41
|
+
### useAccounts()
|
|
42
|
+
```tsx
|
|
43
|
+
const { data: accounts } = useAccounts();
|
|
44
|
+
// accounts.wallets — regular wallet accounts
|
|
45
|
+
// accounts.faucets — token faucet accounts
|
|
46
|
+
// accounts.all — everything (AccountHeader[])
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### useAccount(accountId: string)
|
|
50
|
+
```tsx
|
|
51
|
+
const { data: account } = useAccount(accountId);
|
|
52
|
+
// account.account — Account object (.id, .nonce, .bech32id())
|
|
53
|
+
// account.assets — AssetBalance[] (assetId, amount, symbol?, decimals?)
|
|
54
|
+
// account.getBalance(faucetId) — bigint balance for specific token
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### useNotes(filter?)
|
|
58
|
+
```tsx
|
|
59
|
+
const { data: notes } = useNotes();
|
|
60
|
+
// notes.notes — InputNoteRecord[]
|
|
61
|
+
// notes.consumableNotes — ConsumableNoteRecord[]
|
|
62
|
+
// notes.noteSummaries — NoteSummary[] (id, assets, sender)
|
|
63
|
+
// notes.consumableNoteSummaries — NoteSummary[]
|
|
64
|
+
|
|
65
|
+
// Filter by account:
|
|
66
|
+
const { data } = useNotes({ accountId: "0x..." });
|
|
67
|
+
// Filter by status:
|
|
68
|
+
const { data } = useNotes({ status: "committed" });
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### useSyncState()
|
|
72
|
+
```tsx
|
|
73
|
+
const { syncHeight, isSyncing, lastSyncTime, sync, error } = useSyncState();
|
|
74
|
+
await sync(); // Manual sync
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### useAssetMetadata(faucetId: string | string[])
|
|
78
|
+
```tsx
|
|
79
|
+
const { data: metadata } = useAssetMetadata(faucetId);
|
|
80
|
+
// metadata.symbol — "TEST"
|
|
81
|
+
// metadata.decimals — 8
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### useTransactionHistory(options?)
|
|
85
|
+
```tsx
|
|
86
|
+
const { records, record, status, isLoading } = useTransactionHistory({ id: txId });
|
|
87
|
+
// status: "pending" | "committed" | "discarded" | null
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Mutation Hooks
|
|
91
|
+
|
|
92
|
+
All return `{ mutate, data, isLoading, stage, error, reset }`.
|
|
93
|
+
|
|
94
|
+
**Transaction stages**: `"idle"` → `"executing"` → `"proving"` → `"submitting"` → `"complete"`
|
|
95
|
+
|
|
96
|
+
### useCreateWallet()
|
|
97
|
+
```tsx
|
|
98
|
+
const { mutate: createWallet, isLoading } = useCreateWallet();
|
|
99
|
+
const account = await createWallet({
|
|
100
|
+
storageMode: "private", // "private" | "public" | "network". Default: "private"
|
|
101
|
+
mutable: true, // Default: true
|
|
102
|
+
authScheme: 0, // 0 = RpoFalcon512, 1 = EcdsaK256Keccak. Default: 0
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### useCreateFaucet()
|
|
107
|
+
```tsx
|
|
108
|
+
const { mutate: createFaucet } = useCreateFaucet();
|
|
109
|
+
const faucet = await createFaucet({
|
|
110
|
+
tokenSymbol: "TEST",
|
|
111
|
+
decimals: 8, // Default: 8
|
|
112
|
+
maxSupply: 1000000n, // bigint!
|
|
113
|
+
storageMode: "public", // Default: "private"
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### useSend()
|
|
118
|
+
```tsx
|
|
119
|
+
const { mutate: send, stage } = useSend();
|
|
120
|
+
await send({
|
|
121
|
+
from: senderAccountId,
|
|
122
|
+
to: recipientAccountId,
|
|
123
|
+
assetId: faucetId, // token faucet ID
|
|
124
|
+
amount: 1000n, // bigint!
|
|
125
|
+
noteType: "private", // "private" | "public". Default: "private"
|
|
126
|
+
recallHeight: 100, // optional: sender can reclaim after this block
|
|
127
|
+
timelockHeight: 50, // optional: recipient can consume after this block
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### useMultiSend()
|
|
132
|
+
```tsx
|
|
133
|
+
const { mutate: multiSend } = useMultiSend();
|
|
134
|
+
await multiSend({
|
|
135
|
+
from: senderAccountId,
|
|
136
|
+
assetId: faucetId,
|
|
137
|
+
recipients: [
|
|
138
|
+
{ to: recipient1, amount: 500n },
|
|
139
|
+
{ to: recipient2, amount: 300n },
|
|
140
|
+
],
|
|
141
|
+
noteType: "private",
|
|
142
|
+
});
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### useMint()
|
|
146
|
+
```tsx
|
|
147
|
+
const { mutate: mint } = useMint();
|
|
148
|
+
await mint({
|
|
149
|
+
targetAccountId: recipientId,
|
|
150
|
+
faucetId: myFaucetId,
|
|
151
|
+
amount: 10000n, // bigint!
|
|
152
|
+
noteType: "public",
|
|
153
|
+
});
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
### useConsume()
|
|
157
|
+
```tsx
|
|
158
|
+
const { mutate: consume } = useConsume();
|
|
159
|
+
await consume({
|
|
160
|
+
accountId: myAccountId,
|
|
161
|
+
noteIds: [noteId1, noteId2],
|
|
162
|
+
});
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### useSwap()
|
|
166
|
+
```tsx
|
|
167
|
+
const { mutate: swap } = useSwap();
|
|
168
|
+
await swap({
|
|
169
|
+
accountId: myAccountId,
|
|
170
|
+
offeredFaucetId: tokenA,
|
|
171
|
+
offeredAmount: 100n,
|
|
172
|
+
requestedFaucetId: tokenB,
|
|
173
|
+
requestedAmount: 50n,
|
|
174
|
+
noteType: "private",
|
|
175
|
+
paybackNoteType: "private",
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### useTransaction() — Escape Hatch
|
|
180
|
+
```tsx
|
|
181
|
+
const { mutate: execute } = useTransaction();
|
|
182
|
+
|
|
183
|
+
// With pre-built TransactionRequest:
|
|
184
|
+
await execute({ accountId, request: txRequest });
|
|
185
|
+
|
|
186
|
+
// With factory function (gets access to client):
|
|
187
|
+
await execute({
|
|
188
|
+
accountId,
|
|
189
|
+
request: (client) => client.newSwapTransactionRequest(/* ... */),
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### useWaitForCommit()
|
|
194
|
+
```tsx
|
|
195
|
+
const { mutate: waitForCommit } = useWaitForCommit();
|
|
196
|
+
await waitForCommit({
|
|
197
|
+
transactionId: result.transactionId,
|
|
198
|
+
timeoutMs: 10000, // Default: 10000
|
|
199
|
+
intervalMs: 1000, // Default: 1000
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### useWaitForNotes()
|
|
204
|
+
```tsx
|
|
205
|
+
const { mutate: waitForNotes } = useWaitForNotes();
|
|
206
|
+
await waitForNotes({
|
|
207
|
+
accountId: myAccountId,
|
|
208
|
+
minCount: 1, // Default: 1
|
|
209
|
+
timeoutMs: 10000,
|
|
210
|
+
});
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Transaction Progress UI
|
|
214
|
+
|
|
215
|
+
```tsx
|
|
216
|
+
function SendButton({ from, to, assetId, amount }) {
|
|
217
|
+
const { mutate: send, stage, isLoading, error } = useSend();
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div>
|
|
221
|
+
<button onClick={() => send({ from, to, assetId, amount })} disabled={isLoading}>
|
|
222
|
+
{isLoading ? `${stage}...` : "Send"}
|
|
223
|
+
</button>
|
|
224
|
+
{error && <p>Error: {error.message}</p>}
|
|
225
|
+
</div>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
## Signer Integration
|
|
231
|
+
|
|
232
|
+
### Local Keystore (Default)
|
|
233
|
+
No signer provider needed. Keys are managed in the browser via IndexedDB.
|
|
234
|
+
|
|
235
|
+
### External Signers
|
|
236
|
+
Wrap MidenProvider with a signer provider. Three pre-built options:
|
|
237
|
+
- `ParaSignerProvider` from `@miden-sdk/para` — EVM wallets
|
|
238
|
+
- `TurnkeySignerProvider` from `@miden-sdk/miden-turnkey-react` — passkey auth
|
|
239
|
+
- `MidenFiSignerProvider` from `@miden-sdk/wallet-adapter-react` — MidenFi wallet
|
|
240
|
+
|
|
241
|
+
```tsx
|
|
242
|
+
// Example: Para signer wrapping MidenProvider
|
|
243
|
+
import { ParaSignerProvider } from "@miden-sdk/para";
|
|
244
|
+
<ParaSignerProvider apiKey="..." environment="PRODUCTION">
|
|
245
|
+
<MidenProvider config={...}><App /></MidenProvider>
|
|
246
|
+
</ParaSignerProvider>
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### useSigner() — Unified Interface
|
|
250
|
+
```tsx
|
|
251
|
+
const { isConnected, connect, disconnect, name } = useSigner();
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Custom Signer
|
|
255
|
+
Implement `SignerContextValue` interface via `SignerContext.Provider`. Requires: `name`, `storeName` (unique per user for DB isolation), `accountConfig`, `signCb`, `connect`, `disconnect`. See `frontend-source-guide` skill for source references.
|
|
256
|
+
|
|
257
|
+
## Utility Functions
|
|
258
|
+
|
|
259
|
+
```tsx
|
|
260
|
+
import { formatAssetAmount, parseAssetAmount, getNoteSummary, formatNoteSummary, toBech32AccountId } from "@miden-sdk/react";
|
|
261
|
+
|
|
262
|
+
formatAssetAmount(1000000n, 8) // "0.01"
|
|
263
|
+
parseAssetAmount("0.01", 8) // 1000000n
|
|
264
|
+
const summary = getNoteSummary(note); // { id, assets, sender }
|
|
265
|
+
formatNoteSummary(summary); // "1.5 TEST"
|
|
266
|
+
toBech32AccountId("0x1234..."); // "miden1qy35..."
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Direct Client Access
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
const client = useMidenClient(); // throws if not ready
|
|
273
|
+
const { runExclusive } = useMiden();
|
|
274
|
+
|
|
275
|
+
// For operations not covered by hooks:
|
|
276
|
+
await runExclusive(async (client) => {
|
|
277
|
+
const header = await client.getBlockHeaderByNumber(100);
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Type Imports
|
|
282
|
+
|
|
283
|
+
```tsx
|
|
284
|
+
import type {
|
|
285
|
+
MidenConfig, QueryResult, MutationResult, TransactionStage,
|
|
286
|
+
AccountsResult, AccountResult, AssetBalance, NotesResult, NoteSummary,
|
|
287
|
+
SendOptions, MultiSendOptions, MintOptions, ConsumeOptions, SwapOptions,
|
|
288
|
+
CreateWalletOptions, CreateFaucetOptions, ExecuteTransactionOptions,
|
|
289
|
+
TransactionResult, SyncState, WaitForCommitOptions, WaitForNotesOptions,
|
|
290
|
+
Account, AccountId, InputNoteRecord, ConsumableNoteRecord,
|
|
291
|
+
TransactionRecord, TransactionRequest, NoteType, AccountStorageMode,
|
|
292
|
+
SignerContextValue, SignCallback, SignerAccountConfig,
|
|
293
|
+
} from "@miden-sdk/react";
|
|
294
|
+
```
|