create-miden-app 1.0.6 → 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.
- package/package.json +1 -1
- package/template/.claude/commands/review-security.md +67 -0
- package/template/.claude/settings.json +1 -7
- package/template/.claude/settings.local.json +24 -0
- package/template/.claude/skills/frontend-pitfalls/SKILL.md +28 -31
- package/template/.claude/skills/frontend-source-guide/SKILL.md +14 -14
- package/template/.claude/skills/miden-concepts/SKILL.md +4 -2
- package/template/.claude/skills/react-sdk-patterns/SKILL.md +294 -28
- package/template/.claude/skills/signer-integration/SKILL.md +22 -3
- package/template/.claude/skills/testing-patterns/SKILL.md +201 -40
- package/template/.claude/skills/vite-wasm-setup/SKILL.md +20 -14
- package/template/.claude/skills/web-client-usage/SKILL.md +454 -0
- package/template/.env.example +15 -2
- package/template/.mcp.json +9 -0
- package/template/CLAUDE.md +49 -16
- package/template/README.md +85 -19
- package/template/package.json +5 -4
- package/template/public/packages/counter_account.masp +0 -0
- package/template/public/packages/increment_note.masp +0 -0
- package/template/src/__tests__/fixtures/accounts.ts +17 -6
- package/template/src/__tests__/fixtures/index.ts +1 -0
- package/template/src/__tests__/mocks/miden-sdk-react.ts +18 -1
- package/template/src/__tests__/patterns/mutation-hook.test.tsx +2 -2
- package/template/src/__tests__/patterns/provider-setup.test.tsx +2 -0
- package/template/src/components/AppContent.tsx +33 -3
- package/template/{create-miden-app/template/src/components/Counter.tsx → src/components/ConfiguredCounter.tsx} +7 -4
- package/template/src/components/Counter.tsx +12 -41
- package/template/src/components/__tests__/AppContent.test.tsx +192 -4
- package/template/src/components/__tests__/ConfiguredCounter.test.tsx +116 -0
- package/template/src/components/__tests__/Counter.test.tsx +24 -94
- package/template/src/config.ts +26 -6
- package/template/src/hooks/__tests__/useIncrementCounter.test.tsx +257 -0
- package/template/src/hooks/useIncrementCounter.ts +109 -50
- package/template/src/providers.tsx +20 -24
- package/template/vite.config.ts +1 -1
- package/template/vitest.config.ts +1 -2
- package/template/yarn.lock +761 -688
- package/template/create-miden-app/template/.claude/hooks/typecheck.sh +0 -27
- package/template/create-miden-app/template/.claude/settings.json +0 -17
- package/template/create-miden-app/template/.claude/skills/frontend-pitfalls/SKILL.md +0 -189
- package/template/create-miden-app/template/.claude/skills/frontend-source-guide/SKILL.md +0 -163
- package/template/create-miden-app/template/.claude/skills/miden-concepts/SKILL.md +0 -108
- package/template/create-miden-app/template/.claude/skills/react-sdk-patterns/SKILL.md +0 -294
- package/template/create-miden-app/template/.claude/skills/signer-integration/SKILL.md +0 -158
- package/template/create-miden-app/template/.claude/skills/vite-wasm-setup/SKILL.md +0 -128
- package/template/create-miden-app/template/.env.example +0 -5
- package/template/create-miden-app/template/CLAUDE.md +0 -116
- package/template/create-miden-app/template/README.md +0 -61
- package/template/create-miden-app/template/eslint.config.js +0 -23
- package/template/create-miden-app/template/index.html +0 -13
- package/template/create-miden-app/template/package.json +0 -34
- package/template/create-miden-app/template/public/vite.svg +0 -1
- package/template/create-miden-app/template/src/App.tsx +0 -10
- package/template/create-miden-app/template/src/assets/miden.svg +0 -3
- package/template/create-miden-app/template/src/assets/react.svg +0 -1
- package/template/create-miden-app/template/src/components/AppContent.css +0 -45
- package/template/create-miden-app/template/src/components/AppContent.tsx +0 -50
- package/template/create-miden-app/template/src/components/Counter.css +0 -27
- package/template/create-miden-app/template/src/config.ts +0 -21
- package/template/create-miden-app/template/src/hooks/useIncrementCounter.ts +0 -136
- package/template/create-miden-app/template/src/index.css +0 -75
- package/template/create-miden-app/template/src/lib/miden.ts +0 -9
- package/template/create-miden-app/template/src/main.tsx +0 -10
- package/template/create-miden-app/template/src/providers.tsx +0 -31
- package/template/create-miden-app/template/src/vite-env.d.ts +0 -1
- package/template/create-miden-app/template/tsconfig.app.json +0 -32
- package/template/create-miden-app/template/tsconfig.json +0 -7
- package/template/create-miden-app/template/tsconfig.node.json +0 -24
- package/template/create-miden-app/template/vite.config.ts +0 -17
- package/template/create-miden-app/template/yarn.lock +0 -1697
package/template/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Miden Frontend Template
|
|
2
2
|
|
|
3
|
-
Minimal Vite + React + TypeScript template for building Miden frontends. Includes a network counter demo that publishes an increment note via the MidenFi wallet adapter.
|
|
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
5
|
## Getting Started
|
|
6
6
|
|
|
@@ -9,7 +9,7 @@ yarn install
|
|
|
9
9
|
yarn dev
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
Open [http://localhost:5173](http://localhost:5173).
|
|
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.
|
|
13
13
|
|
|
14
14
|
## Project Structure
|
|
15
15
|
|
|
@@ -20,42 +20,108 @@ src/
|
|
|
20
20
|
├── config.ts # Constants (counter address, explorer URL, SDK config)
|
|
21
21
|
├── components/
|
|
22
22
|
│ ├── AppContent.tsx # Page layout, logos, wallet button
|
|
23
|
-
│
|
|
23
|
+
│ ├── Counter.tsx # Counter UI (configured / unconfigured)
|
|
24
|
+
│ └── ConfiguredCounter.tsx # Counter UI when address is set
|
|
24
25
|
├── hooks/
|
|
25
|
-
│ └── useIncrementCounter.ts # Note construction, wallet submission,
|
|
26
|
+
│ └── useIncrementCounter.ts # Note construction, wallet submission, bounded poll
|
|
26
27
|
└── lib/
|
|
27
28
|
└── miden.ts # Shared Miden utilities
|
|
29
|
+
|
|
30
|
+
public/packages/
|
|
31
|
+
├── counter_account.masp # Compiled counter contract (MASP format v4)
|
|
32
|
+
└── increment_note.masp # Compiled increment note script
|
|
28
33
|
```
|
|
29
34
|
|
|
30
35
|
## Network Counter Demo
|
|
31
36
|
|
|
32
|
-
The template demonstrates the network
|
|
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`):
|
|
33
49
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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. |
|
|
38
55
|
|
|
39
|
-
|
|
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).
|
|
40
75
|
|
|
41
76
|
## Key Dependencies
|
|
42
77
|
|
|
43
|
-
| Package | Purpose |
|
|
44
|
-
|
|
45
|
-
| `@miden-sdk/react` | React hooks for Miden (useAccount, useSyncState,
|
|
46
|
-
| `@miden-sdk/miden-sdk` | Core SDK types (Note, NoteScript, AccountId, Word,
|
|
47
|
-
| `@miden-sdk/vite-plugin` | Vite plugin
|
|
48
|
-
| `@miden-sdk/miden-wallet-adapter` | MidenFi wallet adapter
|
|
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 |
|
|
49
85
|
|
|
50
86
|
## Configuration
|
|
51
87
|
|
|
52
88
|
SDK settings can be overridden via environment variables (see `.env.example`):
|
|
53
89
|
|
|
54
90
|
```bash
|
|
55
|
-
VITE_MIDEN_RPC_URL=testnet
|
|
56
|
-
VITE_MIDEN_PROVER=testnet
|
|
91
|
+
VITE_MIDEN_RPC_URL=testnet # "devnet" | "testnet" | "localhost" | custom URL
|
|
92
|
+
VITE_MIDEN_PROVER=testnet # "devnet" | "testnet" | "local" | custom URL
|
|
57
93
|
```
|
|
58
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
|
+
|
|
59
125
|
## AI Developer Experience
|
|
60
126
|
|
|
61
|
-
This template ships with `.claude/` skills for AI coding tools. Skills cover React SDK patterns, frontend pitfalls, Vite + WASM setup, signer integration, and Miden architecture. See `CLAUDE.md` for the full developer guide.
|
|
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.
|
package/template/package.json
CHANGED
|
@@ -13,15 +13,16 @@
|
|
|
13
13
|
"test:coverage": "vitest --run --coverage"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@miden-sdk/miden-wallet-adapter": "0.
|
|
17
|
-
"@miden-sdk/miden-
|
|
18
|
-
"@miden-sdk/
|
|
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",
|
|
19
20
|
"react": "^19.1.1",
|
|
20
21
|
"react-dom": "^19.1.1"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
24
|
"@eslint/js": "^9.36.0",
|
|
24
|
-
"@miden-sdk/vite-plugin": "0.
|
|
25
|
+
"@miden-sdk/vite-plugin": "0.14.4",
|
|
25
26
|
"@testing-library/dom": "^10.4.1",
|
|
26
27
|
"@testing-library/jest-dom": "^6.9.1",
|
|
27
28
|
"@testing-library/react": "^16.3.2",
|
|
Binary file
|
|
Binary file
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* Uses
|
|
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.
|
|
4
5
|
*/
|
|
5
6
|
|
|
6
|
-
export const WALLET_ID_1 = "
|
|
7
|
-
export const WALLET_ID_2 = "
|
|
8
|
-
export const FAUCET_ID = "
|
|
9
|
-
export const COUNTER_ID = "
|
|
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";
|
|
10
11
|
|
|
11
12
|
export const MOCK_WALLET_HEADER = {
|
|
12
13
|
id: WALLET_ID_1,
|
|
@@ -52,6 +53,16 @@ export const MOCK_ASSET_METADATA = {
|
|
|
52
53
|
decimals: 8,
|
|
53
54
|
};
|
|
54
55
|
|
|
56
|
+
// TransactionResult shape — matches @miden-sdk/react types for useMint / useConsume /
|
|
57
|
+
// useSwap / useMultiSend / useTransaction result payloads.
|
|
55
58
|
export const MOCK_TRANSACTION_RESULT = {
|
|
56
59
|
transactionId: "0xabc123def456789012345678901234567890123456789012345678901234abcd",
|
|
57
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
|
+
};
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
MOCK_CONSUMABLE_NOTE_RECORD,
|
|
24
24
|
MOCK_NOTE_SUMMARY,
|
|
25
25
|
MOCK_TRANSACTION_RESULT,
|
|
26
|
+
MOCK_SEND_RESULT,
|
|
26
27
|
FAUCET_ID,
|
|
27
28
|
} from "../fixtures";
|
|
28
29
|
|
|
@@ -95,6 +96,8 @@ export const useNoteStream = vi.fn(() => ({
|
|
|
95
96
|
// Mutation hooks
|
|
96
97
|
// ---------------------------------------------------------------------------
|
|
97
98
|
|
|
99
|
+
// Mutation hooks that resolve to TransactionResult { transactionId } —
|
|
100
|
+
// useMint / useConsume / useSwap / useMultiSend / useTransaction.
|
|
98
101
|
function createMutationMock(mutateKey: string) {
|
|
99
102
|
return vi.fn(() => ({
|
|
100
103
|
[mutateKey]: vi.fn(async () => MOCK_TRANSACTION_RESULT),
|
|
@@ -106,6 +109,19 @@ function createMutationMock(mutateKey: string) {
|
|
|
106
109
|
}));
|
|
107
110
|
}
|
|
108
111
|
|
|
112
|
+
// useSend resolves to SendResult { txId, note } — not TransactionResult.
|
|
113
|
+
// Keep this separate so tests that call `send()` get the correct shape.
|
|
114
|
+
function createSendMock() {
|
|
115
|
+
return vi.fn(() => ({
|
|
116
|
+
send: vi.fn(async () => MOCK_SEND_RESULT),
|
|
117
|
+
result: null,
|
|
118
|
+
isLoading: false,
|
|
119
|
+
stage: "idle" as const,
|
|
120
|
+
error: null,
|
|
121
|
+
reset: vi.fn(),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
124
|
+
|
|
109
125
|
export const useCreateWallet = vi.fn(() => ({
|
|
110
126
|
createWallet: vi.fn(async () => MOCK_ACCOUNT),
|
|
111
127
|
wallet: null,
|
|
@@ -122,7 +138,7 @@ export const useCreateFaucet = vi.fn(() => ({
|
|
|
122
138
|
reset: vi.fn(),
|
|
123
139
|
}));
|
|
124
140
|
|
|
125
|
-
export const useSend =
|
|
141
|
+
export const useSend = createSendMock();
|
|
126
142
|
export const useMultiSend = createMutationMock("sendMany");
|
|
127
143
|
export const useMint = createMutationMock("mint");
|
|
128
144
|
export const useConsume = createMutationMock("consume");
|
|
@@ -181,6 +197,7 @@ export const useMiden = vi.fn(() => ({
|
|
|
181
197
|
runExclusive: vi.fn(async <T>(fn: () => Promise<T>) => fn()),
|
|
182
198
|
prover: null,
|
|
183
199
|
signerAccountId: null,
|
|
200
|
+
signerConnected: null,
|
|
184
201
|
}));
|
|
185
202
|
|
|
186
203
|
export const useMidenClient = vi.fn(() => ({}));
|
|
@@ -85,7 +85,7 @@ describe("Mutation Hook Pattern", () => {
|
|
|
85
85
|
it("shows success message after transaction completes", () => {
|
|
86
86
|
vi.mocked(useSend).mockReturnValue({
|
|
87
87
|
send: vi.fn(),
|
|
88
|
-
result: {
|
|
88
|
+
result: { txId: "0xabc123", note: null },
|
|
89
89
|
isLoading: false,
|
|
90
90
|
stage: "complete" as const,
|
|
91
91
|
error: null,
|
|
@@ -121,7 +121,7 @@ describe("Mutation Hook Pattern", () => {
|
|
|
121
121
|
|
|
122
122
|
// Test the actual send call — verify correct arguments
|
|
123
123
|
it("calls send with correct arguments on click", async () => {
|
|
124
|
-
const mockSend = vi.fn(async () => ({
|
|
124
|
+
const mockSend = vi.fn(async () => ({ txId: "0xtx", note: null }));
|
|
125
125
|
vi.mocked(useSend).mockReturnValue({
|
|
126
126
|
send: mockSend,
|
|
127
127
|
result: null,
|
|
@@ -50,6 +50,7 @@ describe("Provider Setup Pattern", () => {
|
|
|
50
50
|
runExclusive: vi.fn(),
|
|
51
51
|
prover: null,
|
|
52
52
|
signerAccountId: null,
|
|
53
|
+
signerConnected: null,
|
|
53
54
|
});
|
|
54
55
|
|
|
55
56
|
render(<StatusIndicator />);
|
|
@@ -67,6 +68,7 @@ describe("Provider Setup Pattern", () => {
|
|
|
67
68
|
runExclusive: vi.fn(),
|
|
68
69
|
prover: null,
|
|
69
70
|
signerAccountId: null,
|
|
71
|
+
signerConnected: null,
|
|
70
72
|
});
|
|
71
73
|
|
|
72
74
|
render(<StatusIndicator />);
|
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
import { useMiden, useSyncState } from "@miden-sdk/react";
|
|
2
|
-
import {
|
|
2
|
+
import { useMidenFiWallet } from "@miden-sdk/miden-wallet-adapter-react";
|
|
3
|
+
import { WalletReadyState } from "@miden-sdk/miden-wallet-adapter-base";
|
|
3
4
|
import reactLogo from "@/assets/react.svg";
|
|
4
5
|
import midenLogo from "@/assets/miden.svg";
|
|
5
6
|
import viteLogo from "/vite.svg";
|
|
6
7
|
import { Counter } from "@/components/Counter";
|
|
7
8
|
import "./AppContent.css";
|
|
8
9
|
|
|
10
|
+
function WalletButton() {
|
|
11
|
+
// Use the MidenFi-specific hook (not the generic `useSigner()`) so we can
|
|
12
|
+
// gate on `wallet.readyState`. `useSigner().connect()` calls through to the
|
|
13
|
+
// same provider, but at the moment the user clicks the button the adapter
|
|
14
|
+
// may not yet have detected `window.midenWallet` — detection is polled, see
|
|
15
|
+
// `scopePollingDetectionStrategy` in @miden-sdk/miden-wallet-adapter-base.
|
|
16
|
+
// When readyState is NotDetected, MidenFiSignerProvider falls back to
|
|
17
|
+
// `window.open(adapter.url, "_blank")` — the Chrome Web Store URL — which
|
|
18
|
+
// on some platforms redirects to the Play Store. Disabling the button
|
|
19
|
+
// until the extension is detected prevents the fallback from firing.
|
|
20
|
+
const { wallet, connected, connecting, connect, disconnect } =
|
|
21
|
+
useMidenFiWallet();
|
|
22
|
+
const readyState = wallet?.readyState;
|
|
23
|
+
const walletReady =
|
|
24
|
+
readyState === WalletReadyState.Installed ||
|
|
25
|
+
readyState === WalletReadyState.Loadable;
|
|
26
|
+
|
|
27
|
+
if (!walletReady) {
|
|
28
|
+
return <button disabled>Install MidenFi Wallet</button>;
|
|
29
|
+
}
|
|
30
|
+
if (connected) {
|
|
31
|
+
return <button onClick={disconnect}>Disconnect Wallet</button>;
|
|
32
|
+
}
|
|
33
|
+
if (connecting) {
|
|
34
|
+
return <button disabled>Connecting...</button>;
|
|
35
|
+
}
|
|
36
|
+
return <button onClick={connect}>Connect Wallet</button>;
|
|
37
|
+
}
|
|
38
|
+
|
|
9
39
|
export function AppContent() {
|
|
10
40
|
const { isReady, isInitializing, error } = useMiden();
|
|
11
41
|
const { syncHeight } = useSyncState();
|
|
@@ -32,13 +62,13 @@ export function AppContent() {
|
|
|
32
62
|
<a href="https://react.dev" target="_blank" rel="noreferrer">
|
|
33
63
|
<img src={reactLogo} className="logo react" alt="React logo" />
|
|
34
64
|
</a>
|
|
35
|
-
<a href="https://docs.miden.
|
|
65
|
+
<a href="https://docs.miden.xyz" target="_blank" rel="noreferrer">
|
|
36
66
|
<img src={midenLogo} className="logo miden" alt="Miden logo" />
|
|
37
67
|
</a>
|
|
38
68
|
</div>
|
|
39
69
|
<h1>Vite + React + Miden</h1>
|
|
40
70
|
<div className="wallet-section">
|
|
41
|
-
<
|
|
71
|
+
<WalletButton />
|
|
42
72
|
</div>
|
|
43
73
|
<Counter />
|
|
44
74
|
<p className="read-the-docs">
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { useIncrementCounter } from "@/hooks/useIncrementCounter";
|
|
2
|
-
import { COUNTER_ADDRESS } from "@/config";
|
|
3
2
|
import "./Counter.css";
|
|
4
3
|
|
|
5
|
-
export function
|
|
4
|
+
export function ConfiguredCounter({
|
|
5
|
+
counterAddress,
|
|
6
|
+
}: {
|
|
7
|
+
counterAddress: string;
|
|
8
|
+
}) {
|
|
6
9
|
const {
|
|
7
10
|
increment,
|
|
8
11
|
count,
|
|
@@ -11,7 +14,7 @@ export function Counter() {
|
|
|
11
14
|
error,
|
|
12
15
|
walletConnected,
|
|
13
16
|
explorerUrl,
|
|
14
|
-
} = useIncrementCounter(
|
|
17
|
+
} = useIncrementCounter(counterAddress);
|
|
15
18
|
|
|
16
19
|
const busy = isSubmitting || isWaiting;
|
|
17
20
|
const buttonLabel = isSubmitting
|
|
@@ -36,7 +39,7 @@ export function Counter() {
|
|
|
36
39
|
rel="noreferrer"
|
|
37
40
|
className="account-id"
|
|
38
41
|
>
|
|
39
|
-
Counter: {
|
|
42
|
+
Counter: {counterAddress}
|
|
40
43
|
</a>
|
|
41
44
|
</p>
|
|
42
45
|
{error && <p className="error">{error}</p>}
|
|
@@ -1,45 +1,16 @@
|
|
|
1
|
-
import { useIncrementCounter } from "@/hooks/useIncrementCounter";
|
|
2
1
|
import { COUNTER_ADDRESS } from "@/config";
|
|
3
|
-
import "./
|
|
2
|
+
import { ConfiguredCounter } from "./ConfiguredCounter";
|
|
4
3
|
|
|
5
4
|
export function Counter() {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const buttonLabel = isSubmitting
|
|
18
|
-
? "Submitting..."
|
|
19
|
-
: isWaiting
|
|
20
|
-
? "Waiting for network..."
|
|
21
|
-
: `count is ${count ?? "..."}`;
|
|
22
|
-
|
|
23
|
-
return (
|
|
24
|
-
<div className="card">
|
|
25
|
-
<button
|
|
26
|
-
className="counter-button"
|
|
27
|
-
onClick={increment}
|
|
28
|
-
disabled={busy || count === null || !walletConnected}
|
|
29
|
-
>
|
|
30
|
-
{buttonLabel}
|
|
31
|
-
</button>
|
|
32
|
-
<p>
|
|
33
|
-
<a
|
|
34
|
-
href={explorerUrl}
|
|
35
|
-
target="_blank"
|
|
36
|
-
rel="noreferrer"
|
|
37
|
-
className="account-id"
|
|
38
|
-
>
|
|
39
|
-
Counter: {COUNTER_ADDRESS}
|
|
40
|
-
</a>
|
|
41
|
-
</p>
|
|
42
|
-
{error && <p className="error">{error}</p>}
|
|
43
|
-
</div>
|
|
44
|
-
);
|
|
5
|
+
if (!COUNTER_ADDRESS) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="card">
|
|
8
|
+
<p>
|
|
9
|
+
Counter address not configured — see README for deployment
|
|
10
|
+
instructions.
|
|
11
|
+
</p>
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
return <ConfiguredCounter counterAddress={COUNTER_ADDRESS} />;
|
|
45
16
|
}
|