create-miden-app 1.0.4 → 1.0.7

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 (56) hide show
  1. package/cli.js +6 -6
  2. package/package.json +1 -1
  3. package/template/.claude/commands/review-security.md +67 -0
  4. package/template/.claude/hooks/check-artifacts.sh +45 -0
  5. package/template/.claude/hooks/run-affected-tests.sh +31 -0
  6. package/template/.claude/hooks/typecheck.sh +27 -0
  7. package/template/.claude/settings.json +29 -0
  8. package/template/.claude/settings.local.json +24 -0
  9. package/template/.claude/skills/frontend-pitfalls/SKILL.md +186 -0
  10. package/template/.claude/skills/frontend-source-guide/SKILL.md +163 -0
  11. package/template/.claude/skills/miden-concepts/SKILL.md +110 -0
  12. package/template/.claude/skills/react-sdk-patterns/SKILL.md +562 -0
  13. package/template/.claude/skills/signer-integration/SKILL.md +177 -0
  14. package/template/.claude/skills/testing-patterns/SKILL.md +338 -0
  15. package/template/.claude/skills/vite-wasm-setup/SKILL.md +134 -0
  16. package/template/.claude/skills/web-client-usage/SKILL.md +454 -0
  17. package/template/.env.example +18 -0
  18. package/template/.mcp.json +9 -0
  19. package/template/CLAUDE.md +243 -0
  20. package/template/README.md +119 -14
  21. package/template/index.html +1 -1
  22. package/template/package.json +18 -8
  23. package/template/public/packages/counter_account.masp +0 -0
  24. package/template/public/packages/increment_note.masp +0 -0
  25. package/template/src/App.tsx +6 -59
  26. package/template/src/__tests__/fixtures/accounts.ts +68 -0
  27. package/template/src/__tests__/fixtures/index.ts +22 -0
  28. package/template/src/__tests__/fixtures/notes.ts +33 -0
  29. package/template/src/__tests__/mocks/miden-sdk-react.ts +261 -0
  30. package/template/src/__tests__/patterns/README.md +44 -0
  31. package/template/src/__tests__/patterns/mutation-hook.test.tsx +146 -0
  32. package/template/src/__tests__/patterns/provider-setup.test.tsx +77 -0
  33. package/template/src/__tests__/patterns/query-hook.test.tsx +143 -0
  34. package/template/src/{App.css → components/AppContent.css} +9 -9
  35. package/template/src/components/AppContent.tsx +80 -0
  36. package/template/src/components/ConfiguredCounter.tsx +48 -0
  37. package/template/src/components/Counter.css +27 -0
  38. package/template/src/components/Counter.tsx +16 -0
  39. package/template/src/components/__tests__/AppContent.test.tsx +274 -0
  40. package/template/src/components/__tests__/ConfiguredCounter.test.tsx +116 -0
  41. package/template/src/components/__tests__/Counter.test.tsx +44 -0
  42. package/template/src/config.ts +41 -0
  43. package/template/src/hooks/__tests__/useIncrementCounter.test.tsx +257 -0
  44. package/template/src/hooks/useIncrementCounter.ts +195 -0
  45. package/template/src/index.css +7 -0
  46. package/template/src/lib/miden.ts +9 -0
  47. package/template/src/main.tsx +6 -6
  48. package/template/src/providers.tsx +27 -0
  49. package/template/src/vite-env.d.ts +1 -0
  50. package/template/tsconfig.app.json +8 -4
  51. package/template/tsconfig.node.json +1 -3
  52. package/template/vite.config.ts +5 -17
  53. package/template/vitest.config.ts +25 -0
  54. package/template/vitest.setup.ts +1 -0
  55. package/template/yarn.lock +1687 -815
  56. package/template/src/miden/lib/demo.ts +0 -106
@@ -0,0 +1,243 @@
1
+ # Miden Frontend App
2
+
3
+ React 19 + TypeScript + Vite frontend for the Miden blockchain.
4
+
5
+ ## Project Structure
6
+
7
+ - `src/` — React application source
8
+ - `src/components/` — UI components (Counter, AppContent)
9
+ - `src/hooks/` — Custom hooks (useIncrementCounter)
10
+ - `src/lib/` — Shared utilities
11
+ - `src/__tests__/` — Test infrastructure (mocks, fixtures, patterns)
12
+ - `src/components/__tests__/` — Component tests
13
+ - `vite.config.ts` — Vite config with midenVitePlugin() from @miden-sdk/vite-plugin
14
+ - `vitest.config.ts` — Vitest test runner config
15
+ - `package.json` — Dependencies: @miden-sdk/react, @miden-sdk/miden-sdk
16
+
17
+ ## Build, Dev & Test
18
+
19
+ ```
20
+ yarn dev # Start dev server (Vite)
21
+ yarn build # Type check + production build (tsc -b && vite build)
22
+ yarn lint # ESLint
23
+ yarn test # Run all tests once (vitest --run)
24
+ yarn test:watch # Run tests in watch mode (vitest)
25
+ yarn test:coverage # Run tests with coverage report
26
+ ```
27
+
28
+ Type checking alone:
29
+ ```
30
+ npx tsc -b --noEmit
31
+ ```
32
+
33
+ ## SDK Choice: React SDK Hooks First
34
+
35
+ ALWAYS prefer `@miden-sdk/react` hooks over low-level `WasmWebClient` methods.
36
+ Only use the WASM client directly via `useMidenClient()` for operations not covered by hooks.
37
+
38
+ ### Setup — this template's actual providers (`src/providers.tsx`)
39
+ ```tsx
40
+ import { MidenProvider } from "@miden-sdk/react";
41
+ import { MidenFiSignerProvider } from "@miden-sdk/miden-wallet-adapter-react";
42
+
43
+ <MidenFiSignerProvider
44
+ appName={APP_NAME}
45
+ network={WalletAdapterNetwork.Testnet}
46
+ autoConnect
47
+ >
48
+ <MidenProvider
49
+ config={{ rpcUrl: MIDEN_RPC_URL, prover: MIDEN_PROVER }}
50
+ loadingComponent={<div className="loading">Loading Miden WASM...</div>}
51
+ >
52
+ <App />
53
+ </MidenProvider>
54
+ </MidenFiSignerProvider>
55
+ ```
56
+
57
+ > `MidenFiSignerProvider` must wrap `MidenProvider`. `MidenProvider` reads from `SignerContext` during initialization (to wire its external-keystore client), so the signer context has to exist before `MidenProvider` mounts.
58
+
59
+ ### Query Hooks
60
+ Each returns its own result shape plus `isLoading`, `error`, `refetch`:
61
+ ```tsx
62
+ const { wallets, faucets } = useAccounts();
63
+ const { account, assets, getBalance } = useAccount(accountId);
64
+ const { notes, consumableNotes } = useNotes();
65
+ const { syncHeight, sync } = useSyncState();
66
+ const { assetMetadata } = useAssetMetadata(faucetId);
67
+ ```
68
+
69
+ ### Mutation Hooks
70
+ Each returns its own action function plus `isLoading`, `stage`, `error`, `reset`.
71
+ Transaction stages: `idle → executing → proving → submitting → complete`
72
+ ```tsx
73
+ const { createWallet } = useCreateWallet();
74
+ const { send, stage } = useSend();
75
+ const { consume } = useConsume();
76
+ const { mint } = useMint();
77
+ const { swap } = useSwap();
78
+ const { execute } = useTransaction(); // arbitrary tx requests
79
+ ```
80
+
81
+ ### Token Amounts Are BigInt
82
+ ```tsx
83
+ import { formatAssetAmount, parseAssetAmount } from "@miden-sdk/react";
84
+ const display = formatAssetAmount(balance, 8); // bigint → string
85
+ const amount = parseAssetAmount("1.5", 8); // string → bigint
86
+ ```
87
+
88
+ For exhaustive hook API reference, read `node_modules/@miden-sdk/react/CLAUDE.md` and `node_modules/@miden-sdk/react/README.md`.
89
+
90
+ ## TDD Workflow
91
+
92
+ When building features, follow this test-driven cycle:
93
+
94
+ 1. **Write a failing test** for the feature/component
95
+ 2. **Run tests** — confirm the test fails (red)
96
+ 3. **Implement** the minimum code to make the test pass
97
+ 4. **Run tests** — confirm all tests pass (green)
98
+ 5. **Refactor** if needed, re-run tests
99
+ 6. Type checking runs automatically after each edit (PostToolUse hook)
100
+ 7. Affected tests run automatically after each edit (PostToolUse hook)
101
+
102
+ ### Test file conventions
103
+ - Component tests: `src/components/__tests__/ComponentName.test.tsx`
104
+ - Hook tests: `src/hooks/__tests__/hookName.test.ts`
105
+ - Pattern references: `src/__tests__/patterns/` — copy and adapt these
106
+
107
+ ### Writing tests for Miden components
108
+ ```tsx
109
+ // 1. Mock the SDK at module level (always required)
110
+ vi.mock("@miden-sdk/react", () => import("@/__tests__/mocks/miden-sdk-react"));
111
+
112
+ // 2. Import hooks to override per-test
113
+ import { useAccounts } from "@miden-sdk/react";
114
+
115
+ // 3. Override in individual tests
116
+ vi.mocked(useAccounts).mockReturnValue({ wallets: [], ... });
117
+ ```
118
+
119
+ See `testing-patterns` skill for full mock factory reference and fixture data.
120
+
121
+ ## Verification Sequence
122
+
123
+ Automated verification runs in layers (each catches different failure classes):
124
+
125
+ 1. **TypeScript type check** (auto, per-edit) — catches type errors immediately
126
+ 2. **Affected tests** (auto, per-edit) — catches logic regressions from changes
127
+ 3. **Full test suite + type check + build** (auto, on each edit via PostToolUse) — catches integration issues
128
+ 4. **Browser verification** (Playwright MCP / Claude in Chrome) — catches "compiles but doesn't work" failures
129
+
130
+ ### Browser verification (when needed)
131
+
132
+ Two tools are available for browser verification. Use whichever is appropriate:
133
+
134
+ #### Playwright MCP (visual verification, no wallet)
135
+ Configured in `.mcp.json`. Use for checking that the UI renders correctly, no console errors, layout looks right. Cannot interact with the MidenFi wallet extension.
136
+
137
+ 1. Start dev server: `yarn dev`
138
+ 2. Use Playwright MCP tools to navigate to `http://localhost:5173`
139
+ 3. Take a screenshot, check for render errors
140
+ 4. Check the browser console for errors
141
+
142
+ #### Claude in Chrome (full verification, with wallet)
143
+ Use for wallet-dependent features. Connects to the user's real browser where MidenFi is installed.
144
+
145
+ 1. Start Claude Code with `claude --chrome` (or run `/chrome` in session)
146
+ 2. Start dev server: `yarn dev`
147
+ 3. Navigate to `http://localhost:5173`
148
+ 4. Interact with wallet connect, transaction flows, etc.
149
+
150
+ ## Contract Artifact Handoff
151
+
152
+ Frontend loads pre-compiled `.masp` packages from `public/packages/` at runtime.
153
+
154
+ ### Artifact location
155
+ ```
156
+ public/packages/
157
+ ├── counter_account.masp # Counter account component
158
+ └── increment_note.masp # Increment note script
159
+ ```
160
+
161
+ ### Building artifacts
162
+ In the contract project (e.g., `project-template/`):
163
+ ```bash
164
+ cargo miden build --release
165
+ # Copy .masp files from contracts/*/target/miden/release/ to public/packages/
166
+ ```
167
+
168
+ ### Validate artifacts
169
+ ```bash
170
+ .claude/hooks/check-artifacts.sh
171
+ ```
172
+
173
+ ### Failure recovery
174
+ - **Missing artifacts**: Build contracts with `cargo miden build` or ask the PM to supply the `.masp` files
175
+ - **Stale artifacts**: Rebuild and re-copy after contract changes
176
+ - **Deserialization failure at runtime**: Version mismatch — rebuild contracts with the SDK version matching `@miden-sdk/miden-sdk` in `package.json`
177
+
178
+ ## Known Temporary Workarounds
179
+
180
+ One remaining upstream feature gap. The README has full rationale + removal steps; summary below.
181
+
182
+ **Fixed-interval network poll** ([0xMiden/miden-client#2111](https://github.com/0xMiden/miden-client/issues/2111)): `useIncrementCounter.ts::increment` polls the counter's storage map every `NETWORK_POLL_INTERVAL_MS` (2.5 s) until the value changes or `NETWORK_POLL_TIMEOUT_MS` (30 s) elapses. `useWaitForCommit` doesn't apply because the increment is wallet-submitted and consumed externally by the network operator — the local client never sees the tx. #2111 tracks a React-SDK subscription primitive for this case (narrowed from the broader event-system discussion in #467).
183
+
184
+ ## Critical Pitfalls
185
+
186
+ **WASM init must complete first**: Always use MidenProvider's `loadingComponent` or check `useMiden().isReady`. Components rendering before WASM init will crash.
187
+
188
+ **Recursive WASM access crashes**: Never call client methods concurrently. Use `runExclusive()` from `useMiden()` for sequential execution. Built-in hooks handle this automatically.
189
+
190
+ **COOP/COEP headers required**: WASM SharedArrayBuffer needs `Cross-Origin-Opener-Policy: same-origin` and `Cross-Origin-Embedder-Policy: require-corp` in vite.config.ts AND production server.
191
+
192
+ **Token amounts are bigint, not number**: `send({ amount: 1000 })` will fail. Use `amount: 1000n` or `parseAssetAmount("10", 8)`.
193
+
194
+ ## PM Workflow
195
+
196
+ For non-developer users building with this template:
197
+
198
+ 1. Clone the repository and run `yarn install`
199
+ 2. Start Claude Code in the project directory
200
+ 3. Describe the app you want to build in natural language
201
+ 4. Claude will implement features using TDD — tests are written first, then code
202
+ 5. Automated hooks verify correctness at every step
203
+ 6. Automated hooks run full tests + build after each code edit
204
+ 7. Review the app in the browser: `yarn dev` → open `http://localhost:5173`
205
+ 8. If using wallet features, install the MidenFi browser extension to test
206
+
207
+ ### Known limitations
208
+ - **Visual correctness**: Automated tests verify structure and behavior, not visual appearance. Review the app in the browser for styling issues.
209
+ - **Wallet extension**: Real wallet interactions require the MidenFi browser extension. Tests mock the wallet adapter.
210
+ - **Network-dependent features**: Some features (syncing, transaction submission) require testnet connectivity.
211
+
212
+ ## Miden Skills
213
+
214
+ For Miden-specific guidance, Claude will auto-load these skills when relevant:
215
+ - `react-sdk-patterns` — Complete React SDK hook API reference
216
+ - `testing-patterns` — Test mock factory, fixtures, and TDD conventions
217
+ - `frontend-pitfalls` — All frontend/WASM/browser pitfalls with safe/unsafe examples
218
+ - `miden-concepts` — Miden architecture from a developer perspective
219
+ - `vite-wasm-setup` — Vite + WASM configuration, deployment headers, troubleshooting
220
+ - `signer-integration` — External signer setup (Para, Turnkey, MidenFi)
221
+
222
+ ## General Frontend Skills (Recommended)
223
+
224
+ For general React, TypeScript, and design capabilities, install these official skills alongside our Miden-specific ones:
225
+
226
+ ```bash
227
+ # Vercel's React/design skills
228
+ git clone https://github.com/vercel-labs/agent-skills.git
229
+ # Install: react-best-practices, web-design-guidelines, composition-patterns
230
+
231
+ # Anthropic's frontend design skill (Claude Code plugin)
232
+ # See: https://github.com/anthropics/claude-code/tree/main/plugins/frontend-design
233
+ ```
234
+
235
+ ## Advanced Development
236
+
237
+ For complex applications beyond basic hook usage (custom signers, direct WasmWebClient access, advanced note flows):
238
+
239
+ 1. Clone `miden-client` repo alongside this project (see `frontend-source-guide` skill)
240
+ 2. Use Plan Mode first — Claude explores React SDK source + examples before coding
241
+ 3. Claude uses sub-agents to explore repos efficiently without filling main context
242
+
243
+ The basic skills cover ~80% of patterns. Source repos provide the remaining 20% for advanced builders.
@@ -1,22 +1,127 @@
1
- # React + TypeScript + Vite + Miden
1
+ # Miden Frontend Template
2
2
 
3
- This template provides a minimal example on how to work with Miden using Vite.
3
+ Minimal Vite + React + TypeScript template for building Miden frontends. Includes a live Miden testnet network counter demo that publishes an increment note via the MidenFi wallet adapter and lets the network operator auto-execute it against the counter.
4
4
 
5
- This repository is based on the actual [create-vite NPM template](https://www.npmjs.com/package/create-vite).
5
+ ## Getting Started
6
6
 
7
- ## Demo Client Interaction
7
+ ```bash
8
+ yarn install
9
+ yarn dev
10
+ ```
8
11
 
9
- The project includes a simple example of Miden client interactions in `src/miden/lib/demo.ts`. This demo file showcases a workflow for interacting with the Miden network, including:
12
+ Open [http://localhost:5173](http://localhost:5173). The app connects to Miden testnet out of the box and renders the current counter value. Install the [MidenFi wallet extension](https://chromewebstore.google.com/detail/midenfi), connect, and click the counter to submit an increment.
10
13
 
11
- - **Client Initialization**: Connecting to the Miden Testnet
12
- - **Account Creation**: Creating new wallet accounts (Alice)
13
- - **Faucet Setup**: Creating a fungible token faucet with custom tokens
14
- - **Token Minting**: Minting tokens to an account via P2ID notes
15
- - **Note Consumption**: Consuming notes to receive fungible assets
16
- - **Token Transfers**: Sending tokens between accounts
14
+ ## Project Structure
17
15
 
18
- The demo is a practical reference for building client-side applications that interact with the Miden rollup network, demonstrating the key primitives and transaction flows available through the Miden SDK.
16
+ ```
17
+ src/
18
+ ├── App.tsx # Root component
19
+ ├── providers.tsx # MidenProvider + wallet adapter setup
20
+ ├── config.ts # Constants (counter address, explorer URL, SDK config)
21
+ ├── components/
22
+ │ ├── AppContent.tsx # Page layout, logos, wallet button
23
+ │ ├── Counter.tsx # Counter UI (configured / unconfigured)
24
+ │ └── ConfiguredCounter.tsx # Counter UI when address is set
25
+ ├── hooks/
26
+ │ └── useIncrementCounter.ts # Note construction, wallet submission, bounded poll
27
+ └── lib/
28
+ └── miden.ts # Shared Miden utilities
19
29
 
20
- ### Running the Demo
30
+ public/packages/
31
+ ├── counter_account.masp # Compiled counter contract (MASP format v4)
32
+ └── increment_note.masp # Compiled increment note script
33
+ ```
21
34
 
22
- To explore the demo implementation, check out `src/miden/lib/demo.ts`. This file can serve as a starting point for building your own Miden-enabled applications.
35
+ ## Network Counter Demo
36
+
37
+ The template demonstrates the Miden network-note pattern on testnet:
38
+
39
+ 1. A **counter account** is deployed as a network account (`AccountStorageMode::Network`) on testnet. This template ships with a live deployment at [`mtst1aqmx7qv6h3y92sqsmunh8uht4ujmfy4j`](https://testnet.midenscan.com/account/mtst1aqmx7qv6h3y92sqsmunh8uht4ujmfy4j).
40
+ 2. On button click, the frontend constructs a **public note** targeting the counter and submits it through the MidenFi wallet (the wallet signs and posts the transaction, not the in-browser client).
41
+ 3. The **network operator** picks up the note (tag + `NoteAttachment::newNetworkAccountTarget`) and executes it against the counter account, incrementing the on-chain count.
42
+ 4. The frontend polls `client.getAccount(counterAddress)` and re-reads the `StorageMap`; once the value changes it updates the UI. If the network is slow, polling falls back to a 30 s timeout.
43
+
44
+ Pre-compiled `.masp` packages built with `cargo-miden 0.8.1` (matching `@miden-sdk/miden-sdk@0.14.x`) live in `public/packages/`.
45
+
46
+ ### Pointing at your own counter
47
+
48
+ The counter address is resolved at runtime via the `VITE_MIDEN_COUNTER_ADDRESS` environment variable (`src/config.ts`):
49
+
50
+ | `VITE_MIDEN_COUNTER_ADDRESS` value | Effect |
51
+ |---|---|
52
+ | unset / commented out (default) | Use the live testnet counter shipped with the template (`mtst1aqmx7qv6h3y92sqsmunh8uht4ujmfy4j`). |
53
+ | empty string (`VITE_MIDEN_COUNTER_ADDRESS=`) | Unconfigured — `<Counter>` renders the "address not configured" card and makes no network calls. |
54
+ | any bech32 string (`mtst1...`) | Uses your own deployment. |
55
+
56
+ The slot-name constant is fixed in `src/config.ts` and must match the counter contract's storage map name.
57
+
58
+ To redeploy (e.g. after modifying contract sources):
59
+
60
+ 1. In the [project-template](https://github.com/0xMiden/project-template) repo on the `migrate-clien-v014` branch, run the deployment binary:
61
+ ```bash
62
+ cargo install cargo-miden --version 0.8.1
63
+ cargo run -p integration --release --bin increment_count
64
+ ```
65
+ The binary builds `contracts/counter-account` + `contracts/increment-note`, creates the counter with `AccountStorageMode::Network`, and prints the bech32 address.
66
+ 2. Copy the freshly built artifacts into this template:
67
+ ```bash
68
+ cp contracts/counter-account/target/miden/release/counter_account.masp \
69
+ <frontend-template>/public/packages/
70
+ cp contracts/increment-note/target/miden/release/increment_note.masp \
71
+ <frontend-template>/public/packages/
72
+ ```
73
+ 3. Set `VITE_MIDEN_COUNTER_ADDRESS=<your bech32 address>` in `.env` (or your shell environment) — no source edit required.
74
+ 4. Verify with `.claude/hooks/check-artifacts.sh` (checks MASP format version).
75
+
76
+ ## Key Dependencies
77
+
78
+ | Package | Version pin | Purpose |
79
+ |---------|-------------|---------|
80
+ | `@miden-sdk/react` | `0.14.x` | React hooks for Miden (useAccount, useSyncState, useMiden, useMidenClient, useTransaction, …) |
81
+ | `@miden-sdk/miden-sdk` | `0.14.x` | Core SDK types (Note, NoteScript, AccountId, Word, Felt, …) |
82
+ | `@miden-sdk/vite-plugin` | `0.14.x` | Vite plugin that handles WASM loading, top-level await, and COOP/COEP |
83
+ | `@miden-sdk/miden-wallet-adapter-react` | `0.14.x` | MidenFi wallet adapter React context + hooks |
84
+ | `@miden-sdk/miden-wallet-adapter-base` | `0.14.x` | `Transaction.createCustomTransaction` helper used by the increment flow |
85
+
86
+ ## Configuration
87
+
88
+ SDK settings can be overridden via environment variables (see `.env.example`):
89
+
90
+ ```bash
91
+ VITE_MIDEN_RPC_URL=testnet # "devnet" | "testnet" | "localhost" | custom URL
92
+ VITE_MIDEN_PROVER=testnet # "devnet" | "testnet" | "local" | custom URL
93
+ ```
94
+
95
+ ## Verification
96
+
97
+ Automated gates that must all stay green:
98
+
99
+ ```bash
100
+ npx tsc -b --noEmit # type check
101
+ npx vitest --run # 36 unit tests (components, hook, patterns)
102
+ npx vite build # production build (emits dist/)
103
+ npx eslint . # lint
104
+ ```
105
+
106
+ The PostToolUse hook runs typecheck + affected tests after every edit. The Stop hook runs the full suite when a task completes.
107
+
108
+ Browser-level verification (render correctness, no console errors, wallet popup, E2E increment) can be done with either:
109
+ - **Playwright MCP** for headless render / console checks
110
+ - **Claude in Chrome** (via the `/chrome` command) to exercise the real MidenFi extension
111
+
112
+ ## Known Temporary Workarounds
113
+
114
+ One active workaround remains after the 0.14.4 upgrade, covering an upstream feature gap. The inline comment in `src/hooks/useIncrementCounter.ts` describes the removal steps.
115
+
116
+ ### Fixed-interval network poll — waiting for Network-mode account updates ([miden-client#2111](https://github.com/0xMiden/miden-client/issues/2111))
117
+
118
+ After `wallet.requestTransaction` returns, `src/hooks/useIncrementCounter.ts` bounded-polls the counter's storage map until the value changes or a 30 s timeout elapses. The React SDK's `useWaitForCommit` only watches *locally-submitted* transactions — our increment is wallet-submitted and consumed externally by the network operator, so it never reaches the local client's transaction log. [`#2111`](https://github.com/0xMiden/miden-client/issues/2111) tracks a React-SDK subscription primitive for account-state updates driven by external consumers (scoped narrowly from the broader event-system discussion in [`#467`](https://github.com/0xMiden/miden-client/issues/467)).
119
+
120
+ **After #2111 lands a subscription primitive:**
121
+ 1. Replace the `while` poll loop in `useIncrementCounter.ts::increment` with the new subscription / waitFor API.
122
+ 2. Remove `NETWORK_POLL_INTERVAL_MS` + `NETWORK_POLL_TIMEOUT_MS` from `src/config.ts` if no other consumer depends on them.
123
+ 3. Remove the `#2111` TODO block.
124
+
125
+ ## AI Developer Experience
126
+
127
+ This template ships with `.claude/` skills for AI coding tools. Skills cover React SDK patterns, frontend pitfalls, Vite + WASM setup, signer integration, testing patterns, and Miden architecture. See `CLAUDE.md` for the full developer guide.
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>miden-frontend</title>
7
+ <title>Miden Template</title>
8
8
  </head>
9
9
  <body>
10
10
  <div id="root"></div>
@@ -7,28 +7,38 @@
7
7
  "dev": "vite",
8
8
  "build": "tsc -b && vite build",
9
9
  "lint": "eslint .",
10
- "preview": "vite preview"
10
+ "preview": "vite preview",
11
+ "test": "vitest --run",
12
+ "test:watch": "vitest",
13
+ "test:coverage": "vitest --run --coverage"
11
14
  },
12
15
  "dependencies": {
13
- "@miden-sdk/miden-sdk": "^0.13.0",
14
- "dexie": "^4.2.1",
16
+ "@miden-sdk/miden-wallet-adapter-base": "0.14.3",
17
+ "@miden-sdk/miden-wallet-adapter-react": "0.14.3",
18
+ "@miden-sdk/miden-sdk": "0.14.4",
19
+ "@miden-sdk/react": "0.14.4",
15
20
  "react": "^19.1.1",
16
21
  "react-dom": "^19.1.1"
17
22
  },
18
23
  "devDependencies": {
19
24
  "@eslint/js": "^9.36.0",
25
+ "@miden-sdk/vite-plugin": "0.14.4",
26
+ "@testing-library/dom": "^10.4.1",
27
+ "@testing-library/jest-dom": "^6.9.1",
28
+ "@testing-library/react": "^16.3.2",
29
+ "@testing-library/user-event": "^14.6.1",
20
30
  "@types/node": "^24.6.0",
21
31
  "@types/react": "^19.1.16",
22
32
  "@types/react-dom": "^19.1.9",
23
- "@vitejs/plugin-react": "^5.0.4",
33
+ "@vitejs/plugin-react": "^4.7.0",
24
34
  "eslint": "^9.36.0",
25
35
  "eslint-plugin-react-hooks": "^5.2.0",
26
36
  "eslint-plugin-react-refresh": "^0.4.22",
27
37
  "globals": "^16.4.0",
28
- "typescript": "~5.9.3",
38
+ "jsdom": "^28.1.0",
39
+ "typescript": "~5.7.0",
29
40
  "typescript-eslint": "^8.45.0",
30
- "vite": "^7.1.7",
31
- "vite-plugin-top-level-await": "^1.6.0",
32
- "vite-plugin-wasm": "^3.5.0"
41
+ "vite": "^6.0.0",
42
+ "vitest": "^4.0.18"
33
43
  }
34
44
  }
@@ -1,63 +1,10 @@
1
- import { useState } from "react";
2
- import reactLogo from "./assets/react.svg";
3
- import midenLogo from "./assets/miden.svg";
4
- import viteLogo from "/vite.svg";
5
- import "./App.css";
6
- import { demo } from "./miden/lib/demo";
7
-
8
- function App() {
9
- const [count, setCount] = useState(0);
10
- const [isRunning, setIsRunning] = useState(false);
11
- const [result, setResult] = useState<string>("");
12
-
13
- const handleDemoClick = async () => {
14
- setIsRunning(true);
15
- setResult("");
16
- try {
17
- await demo();
18
- setResult("Demo executed successfully! Check console for output.");
19
- } catch (error) {
20
- setResult(
21
- `Error: ${error instanceof Error ? error.message : String(error)}`
22
- );
23
- } finally {
24
- setIsRunning(false);
25
- }
26
- };
1
+ import { AppProviders } from "@/providers";
2
+ import { AppContent } from "@/components/AppContent";
27
3
 
4
+ export default function App() {
28
5
  return (
29
- <>
30
- <div>
31
- <a href="https://vite.dev" target="_blank">
32
- <img src={viteLogo} className="logo" alt="Vite logo" />
33
- </a>
34
- <a href="https://react.dev" target="_blank">
35
- <img src={reactLogo} className="logo react" alt="React logo" />
36
- </a>
37
- <a href="https://docs.miden.xyz" target="_blank">
38
- <img src={midenLogo} className="logo miden" alt="Miden logo" />
39
- </a>
40
- </div>
41
- <h1>Vite + React + Miden</h1>
42
- <div className="card">
43
- <button onClick={() => setCount((count) => count + 1)}>
44
- count is {count}
45
- </button>
46
- <p>
47
- Edit <code>src/App.tsx</code> and save to test HMR
48
- </p>
49
- </div>
50
- <div className="card">
51
- <button onClick={handleDemoClick} disabled={isRunning}>
52
- {isRunning ? "Running Demo..." : "Run Miden Demo"}
53
- </button>
54
- {result && <p style={{ marginTop: "1rem" }}>{result}</p>}
55
- </div>
56
- <p className="read-the-docs">
57
- Click on the Vite, React, and Miden logos to learn more
58
- </p>
59
- </>
6
+ <AppProviders>
7
+ <AppContent />
8
+ </AppProviders>
60
9
  );
61
10
  }
62
-
63
- export default App;
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Test fixtures for Miden frontend tests.
3
+ * Uses hex IDs (network-agnostic) and BigInt amounts matching real SDK shapes.
4
+ * These are mock values — never parsed by the real SDK at runtime.
5
+ */
6
+
7
+ export const WALLET_ID_1 = "0x0a00000000000001";
8
+ export const WALLET_ID_2 = "0x0a00000000000002";
9
+ export const FAUCET_ID = "0x0a00000000000003";
10
+ export const COUNTER_ID = "0x0a00000000000004";
11
+
12
+ export const MOCK_WALLET_HEADER = {
13
+ id: WALLET_ID_1,
14
+ nonce: 1n,
15
+ storageCommitment: "0x0000000000000000000000000000000000000000000000000000000000000001",
16
+ };
17
+
18
+ export const MOCK_WALLET_HEADER_2 = {
19
+ id: WALLET_ID_2,
20
+ nonce: 0n,
21
+ storageCommitment: "0x0000000000000000000000000000000000000000000000000000000000000000",
22
+ };
23
+
24
+ export const MOCK_FAUCET_HEADER = {
25
+ id: FAUCET_ID,
26
+ nonce: 5n,
27
+ storageCommitment: "0x0000000000000000000000000000000000000000000000000000000000000005",
28
+ };
29
+
30
+ export const MOCK_ASSET_BALANCE = {
31
+ assetId: FAUCET_ID,
32
+ amount: 1000000000n, // 10.0 tokens with 8 decimals
33
+ symbol: "TEST",
34
+ decimals: 8,
35
+ };
36
+
37
+ export const MOCK_ASSET_BALANCE_EMPTY = {
38
+ assetId: FAUCET_ID,
39
+ amount: 0n,
40
+ symbol: "TEST",
41
+ decimals: 8,
42
+ };
43
+
44
+ export const MOCK_ACCOUNT = {
45
+ id: WALLET_ID_1,
46
+ nonce: 1n,
47
+ bech32id: () => WALLET_ID_1,
48
+ };
49
+
50
+ export const MOCK_ASSET_METADATA = {
51
+ assetId: FAUCET_ID,
52
+ symbol: "TEST",
53
+ decimals: 8,
54
+ };
55
+
56
+ // TransactionResult shape — matches @miden-sdk/react types for useMint / useConsume /
57
+ // useSwap / useMultiSend / useTransaction result payloads.
58
+ export const MOCK_TRANSACTION_RESULT = {
59
+ transactionId: "0xabc123def456789012345678901234567890123456789012345678901234abcd",
60
+ };
61
+
62
+ // SendResult shape — distinct from TransactionResult. @miden-sdk/react's useSend
63
+ // returns { txId, note }, not { transactionId }. Keep these fixtures separate so
64
+ // mocks for useSend don't bleed into mocks for TransactionResult-typed hooks.
65
+ export const MOCK_SEND_RESULT = {
66
+ txId: "0xabc123def456789012345678901234567890123456789012345678901234abcd",
67
+ note: null,
68
+ };
@@ -0,0 +1,22 @@
1
+ export {
2
+ WALLET_ID_1,
3
+ WALLET_ID_2,
4
+ FAUCET_ID,
5
+ COUNTER_ID,
6
+ MOCK_WALLET_HEADER,
7
+ MOCK_WALLET_HEADER_2,
8
+ MOCK_FAUCET_HEADER,
9
+ MOCK_ASSET_BALANCE,
10
+ MOCK_ASSET_BALANCE_EMPTY,
11
+ MOCK_ACCOUNT,
12
+ MOCK_ASSET_METADATA,
13
+ MOCK_TRANSACTION_RESULT,
14
+ MOCK_SEND_RESULT,
15
+ } from "./accounts";
16
+
17
+ export {
18
+ MOCK_NOTE_ASSET,
19
+ MOCK_NOTE_SUMMARY,
20
+ MOCK_INPUT_NOTE_RECORD,
21
+ MOCK_CONSUMABLE_NOTE_RECORD,
22
+ } from "./notes";
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Realistic note fixtures for Miden frontend tests.
3
+ */
4
+
5
+ import { FAUCET_ID, WALLET_ID_1, WALLET_ID_2 } from "./accounts";
6
+
7
+ export const MOCK_NOTE_ASSET = {
8
+ assetId: FAUCET_ID,
9
+ amount: 500000000n, // 5.0 tokens with 8 decimals
10
+ symbol: "TEST",
11
+ decimals: 8,
12
+ };
13
+
14
+ export const MOCK_NOTE_SUMMARY = {
15
+ id: "0xnote1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab",
16
+ assets: [MOCK_NOTE_ASSET],
17
+ sender: WALLET_ID_2,
18
+ };
19
+
20
+ export const MOCK_INPUT_NOTE_RECORD = {
21
+ id: () => "0xnote1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab",
22
+ assets: () => [{ faucetId: () => FAUCET_ID, amount: () => 500000000n }],
23
+ metadata: () => ({
24
+ sender: () => ({ toBech32: () => WALLET_ID_2 }),
25
+ noteType: () => 1,
26
+ }),
27
+ status: () => "committed",
28
+ };
29
+
30
+ export const MOCK_CONSUMABLE_NOTE_RECORD = {
31
+ ...MOCK_INPUT_NOTE_RECORD,
32
+ accountId: WALLET_ID_1,
33
+ };