create-miden-app 1.0.4 → 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 -1
- 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 +1580 -781
- package/template/src/miden/lib/demo.ts +0 -106
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useMemo, useState, useCallback, useEffect } from "react";
|
|
2
|
+
import {
|
|
3
|
+
useSyncState,
|
|
4
|
+
useAccount,
|
|
5
|
+
useImportAccount,
|
|
6
|
+
} from "@miden-sdk/react";
|
|
7
|
+
import {
|
|
8
|
+
useWallet,
|
|
9
|
+
Transaction,
|
|
10
|
+
} from "@miden-sdk/miden-wallet-adapter";
|
|
11
|
+
import {
|
|
12
|
+
TransactionRequestBuilder,
|
|
13
|
+
Package,
|
|
14
|
+
NoteScript,
|
|
15
|
+
Note,
|
|
16
|
+
NoteAssets,
|
|
17
|
+
NoteMetadata,
|
|
18
|
+
NoteRecipient,
|
|
19
|
+
NoteInputs,
|
|
20
|
+
NoteTag,
|
|
21
|
+
NoteType,
|
|
22
|
+
NoteAttachment,
|
|
23
|
+
NoteExecutionHint,
|
|
24
|
+
OutputNote,
|
|
25
|
+
OutputNoteArray,
|
|
26
|
+
AccountId,
|
|
27
|
+
Felt,
|
|
28
|
+
FeltArray,
|
|
29
|
+
Word,
|
|
30
|
+
} from "@miden-sdk/miden-sdk";
|
|
31
|
+
import { randomWord } from "@/lib/miden";
|
|
32
|
+
import {
|
|
33
|
+
COUNTER_SLOT_NAME,
|
|
34
|
+
EXPLORER_BASE_URL,
|
|
35
|
+
NETWORK_SYNC_DELAY_MS,
|
|
36
|
+
} from "@/config";
|
|
37
|
+
|
|
38
|
+
export function useIncrementCounter(counterAddress: string) {
|
|
39
|
+
const [error, setError] = useState<string | null>(null);
|
|
40
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
41
|
+
const [isWaiting, setIsWaiting] = useState(false);
|
|
42
|
+
|
|
43
|
+
const { address: walletAddress, connected, requestTransaction } = useWallet();
|
|
44
|
+
const { importAccount } = useImportAccount();
|
|
45
|
+
const { account, refetch } = useAccount(counterAddress);
|
|
46
|
+
const { sync } = useSyncState();
|
|
47
|
+
|
|
48
|
+
// Import the counter account so the local client tracks it.
|
|
49
|
+
// The catch is intentional — the account may already be imported.
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
importAccount({ type: "id", accountId: counterAddress }).catch(() => {});
|
|
52
|
+
}, [importAccount, counterAddress]);
|
|
53
|
+
|
|
54
|
+
// Read count from StorageMap
|
|
55
|
+
const count = useMemo(() => {
|
|
56
|
+
if (!account) return null;
|
|
57
|
+
const countKey = Word.newFromFelts([
|
|
58
|
+
new Felt(0n),
|
|
59
|
+
new Felt(0n),
|
|
60
|
+
new Felt(0n),
|
|
61
|
+
new Felt(1n),
|
|
62
|
+
]);
|
|
63
|
+
const value = account.storage().getMapItem(COUNTER_SLOT_NAME, countKey);
|
|
64
|
+
return value ? Number(value.toU64s()[3]) : 0;
|
|
65
|
+
}, [account]);
|
|
66
|
+
|
|
67
|
+
const increment = useCallback(async () => {
|
|
68
|
+
if (!walletAddress || !requestTransaction) return;
|
|
69
|
+
setError(null);
|
|
70
|
+
setIsSubmitting(true);
|
|
71
|
+
try {
|
|
72
|
+
// Load pre-compiled increment-note package
|
|
73
|
+
const buf = await fetch("/packages/increment_note.masp").then((r) =>
|
|
74
|
+
r.arrayBuffer(),
|
|
75
|
+
);
|
|
76
|
+
const pkg = Package.deserialize(new Uint8Array(buf));
|
|
77
|
+
const noteScript = NoteScript.fromPackage(pkg);
|
|
78
|
+
|
|
79
|
+
const counterAccountId = AccountId.fromBech32(counterAddress);
|
|
80
|
+
const walletAccountId = AccountId.fromBech32(walletAddress);
|
|
81
|
+
|
|
82
|
+
// Build note recipient
|
|
83
|
+
const serialNum = randomWord();
|
|
84
|
+
const inputs = new NoteInputs(new FeltArray());
|
|
85
|
+
const recipient = new NoteRecipient(serialNum, noteScript, inputs);
|
|
86
|
+
|
|
87
|
+
// Build note metadata targeting the network counter account
|
|
88
|
+
const tag = NoteTag.withAccountTarget(counterAccountId);
|
|
89
|
+
const attachment = NoteAttachment.newNetworkAccountTarget(
|
|
90
|
+
counterAccountId,
|
|
91
|
+
NoteExecutionHint.always(),
|
|
92
|
+
);
|
|
93
|
+
const metadata = new NoteMetadata(
|
|
94
|
+
walletAccountId,
|
|
95
|
+
NoteType.Public,
|
|
96
|
+
tag,
|
|
97
|
+
).withAttachment(attachment);
|
|
98
|
+
|
|
99
|
+
// Assemble the note and submit via wallet adapter
|
|
100
|
+
const note = new Note(new NoteAssets(), metadata, recipient);
|
|
101
|
+
const outputNote = OutputNote.full(note);
|
|
102
|
+
const txRequest = new TransactionRequestBuilder()
|
|
103
|
+
.withOwnOutputNotes(new OutputNoteArray([outputNote]))
|
|
104
|
+
.build();
|
|
105
|
+
|
|
106
|
+
const tx = Transaction.createCustomTransaction(
|
|
107
|
+
walletAddress,
|
|
108
|
+
counterAddress,
|
|
109
|
+
txRequest,
|
|
110
|
+
);
|
|
111
|
+
await requestTransaction(tx);
|
|
112
|
+
setIsSubmitting(false);
|
|
113
|
+
|
|
114
|
+
// Wait for network to process the note, then re-sync
|
|
115
|
+
setIsWaiting(true);
|
|
116
|
+
await new Promise((r) => setTimeout(r, NETWORK_SYNC_DELAY_MS));
|
|
117
|
+
await sync();
|
|
118
|
+
await refetch();
|
|
119
|
+
setIsWaiting(false);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
setIsSubmitting(false);
|
|
122
|
+
setIsWaiting(false);
|
|
123
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
124
|
+
}
|
|
125
|
+
}, [walletAddress, requestTransaction, counterAddress, sync, refetch]);
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
increment,
|
|
129
|
+
count,
|
|
130
|
+
isSubmitting,
|
|
131
|
+
isWaiting,
|
|
132
|
+
error,
|
|
133
|
+
walletConnected: connected,
|
|
134
|
+
explorerUrl: `${EXPLORER_BASE_URL}/account/${counterAddress}`,
|
|
135
|
+
};
|
|
136
|
+
}
|
package/template/src/index.css
CHANGED
|
@@ -54,6 +54,13 @@ button:focus-visible {
|
|
|
54
54
|
outline: 4px auto -webkit-focus-ring-color;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
+
#root {
|
|
58
|
+
max-width: 1280px;
|
|
59
|
+
margin: 0 auto;
|
|
60
|
+
padding: 2rem;
|
|
61
|
+
text-align: center;
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
@media (prefers-color-scheme: light) {
|
|
58
65
|
:root {
|
|
59
66
|
color: #213547;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Felt, Word } from "@miden-sdk/miden-sdk";
|
|
2
|
+
|
|
3
|
+
/** Generate a random 4-felt Word (used as note serial number). */
|
|
4
|
+
export function randomWord(): Word {
|
|
5
|
+
const felts = Array.from({ length: 4 }, () =>
|
|
6
|
+
new Felt(BigInt(Math.floor(Math.random() * 2 ** 32))),
|
|
7
|
+
);
|
|
8
|
+
return Word.newFromFelts(felts);
|
|
9
|
+
}
|
package/template/src/main.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { StrictMode } from
|
|
2
|
-
import { createRoot } from
|
|
3
|
-
import
|
|
4
|
-
import App from
|
|
1
|
+
import { StrictMode } from "react";
|
|
2
|
+
import { createRoot } from "react-dom/client";
|
|
3
|
+
import "./index.css";
|
|
4
|
+
import App from "./App.tsx";
|
|
5
5
|
|
|
6
|
-
createRoot(document.getElementById(
|
|
6
|
+
createRoot(document.getElementById("root")!).render(
|
|
7
7
|
<StrictMode>
|
|
8
8
|
<App />
|
|
9
9
|
</StrictMode>,
|
|
10
|
-
)
|
|
10
|
+
);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useMemo, type ReactNode } from "react";
|
|
2
|
+
import { MidenProvider } from "@miden-sdk/react";
|
|
3
|
+
import {
|
|
4
|
+
MidenWalletAdapter,
|
|
5
|
+
WalletProvider,
|
|
6
|
+
WalletModalProvider,
|
|
7
|
+
} from "@miden-sdk/miden-wallet-adapter";
|
|
8
|
+
import "@miden-sdk/miden-wallet-adapter/styles.css";
|
|
9
|
+
import { APP_NAME, MIDEN_RPC_URL, MIDEN_PROVER } from "@/config";
|
|
10
|
+
|
|
11
|
+
export function AppProviders({ children }: { children: ReactNode }) {
|
|
12
|
+
const wallets = useMemo(
|
|
13
|
+
() => [new MidenWalletAdapter({ appName: APP_NAME })],
|
|
14
|
+
[],
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<WalletProvider wallets={wallets} autoConnect>
|
|
19
|
+
<WalletModalProvider>
|
|
20
|
+
<MidenProvider
|
|
21
|
+
config={{ rpcUrl: MIDEN_RPC_URL, prover: MIDEN_PROVER }}
|
|
22
|
+
loadingComponent={
|
|
23
|
+
<div className="loading">Loading Miden WASM...</div>
|
|
24
|
+
}
|
|
25
|
+
>
|
|
26
|
+
{children}
|
|
27
|
+
</MidenProvider>
|
|
28
|
+
</WalletModalProvider>
|
|
29
|
+
</WalletProvider>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"useDefineForClassFields": true,
|
|
6
6
|
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
7
7
|
"module": "ESNext",
|
|
8
|
-
"types": ["vite/client"],
|
|
8
|
+
"types": ["vite/client", "vitest/globals", "@testing-library/jest-dom/vitest"],
|
|
9
9
|
"skipLibCheck": true,
|
|
10
10
|
|
|
11
11
|
/* Bundler mode */
|
|
@@ -16,13 +16,17 @@
|
|
|
16
16
|
"noEmit": true,
|
|
17
17
|
"jsx": "react-jsx",
|
|
18
18
|
|
|
19
|
+
/* Path aliases */
|
|
20
|
+
"baseUrl": ".",
|
|
21
|
+
"paths": {
|
|
22
|
+
"@/*": ["./src/*"]
|
|
23
|
+
},
|
|
24
|
+
|
|
19
25
|
/* Linting */
|
|
20
26
|
"strict": true,
|
|
21
27
|
"noUnusedLocals": true,
|
|
22
28
|
"noUnusedParameters": true,
|
|
23
|
-
"
|
|
24
|
-
"noFallthroughCasesInSwitch": true,
|
|
25
|
-
"noUncheckedSideEffectImports": true
|
|
29
|
+
"noFallthroughCasesInSwitch": true
|
|
26
30
|
},
|
|
27
31
|
"include": ["src"]
|
|
28
32
|
}
|
|
@@ -18,9 +18,7 @@
|
|
|
18
18
|
"strict": true,
|
|
19
19
|
"noUnusedLocals": true,
|
|
20
20
|
"noUnusedParameters": true,
|
|
21
|
-
"
|
|
22
|
-
"noFallthroughCasesInSwitch": true,
|
|
23
|
-
"noUncheckedSideEffectImports": true
|
|
21
|
+
"noFallthroughCasesInSwitch": true
|
|
24
22
|
},
|
|
25
23
|
"include": ["vite.config.ts"]
|
|
26
24
|
}
|
package/template/vite.config.ts
CHANGED
|
@@ -1,26 +1,14 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { defineConfig } from "vite";
|
|
2
3
|
import react from "@vitejs/plugin-react";
|
|
3
|
-
import
|
|
4
|
-
import topLevelAwait from "vite-plugin-top-level-await";
|
|
5
|
-
import path from "path";
|
|
4
|
+
import { midenVitePlugin } from "@miden-sdk/vite-plugin";
|
|
6
5
|
|
|
7
|
-
// https://vite.dev/config/
|
|
8
6
|
export default defineConfig({
|
|
9
|
-
plugins: [react(),
|
|
7
|
+
plugins: [react(), midenVitePlugin()],
|
|
10
8
|
resolve: {
|
|
9
|
+
dedupe: ["react", "react-dom", "react/jsx-runtime"],
|
|
11
10
|
alias: {
|
|
12
|
-
|
|
13
|
-
dexie: path.resolve(__dirname, "node_modules/dexie"),
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
optimizeDeps: {
|
|
17
|
-
exclude: ["@miden-sdk/miden-sdk"],
|
|
18
|
-
include: ["dexie"],
|
|
19
|
-
},
|
|
20
|
-
server: {
|
|
21
|
-
headers: {
|
|
22
|
-
"Cross-Origin-Opener-Policy": "same-origin",
|
|
23
|
-
"Cross-Origin-Embedder-Policy": "require-corp",
|
|
11
|
+
"@": path.resolve(__dirname, "./src"),
|
|
24
12
|
},
|
|
25
13
|
},
|
|
26
14
|
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { defineConfig } from "vitest/config";
|
|
3
|
+
import react from "@vitejs/plugin-react";
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [react()],
|
|
7
|
+
resolve: {
|
|
8
|
+
alias: {
|
|
9
|
+
"@": path.resolve(__dirname, "./src"),
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
test: {
|
|
13
|
+
environment: "jsdom",
|
|
14
|
+
globals: true,
|
|
15
|
+
setupFiles: ["./vitest.setup.ts"],
|
|
16
|
+
include: ["src/**/*.{test,spec}.{ts,tsx}"],
|
|
17
|
+
passWithNoTests: true,
|
|
18
|
+
server: {
|
|
19
|
+
deps: {
|
|
20
|
+
// The wallet-adapter-reactui sub-package has incorrect exports in package.json.
|
|
21
|
+
// Tests mock the wallet adapter at the module level, so externalizing is safe.
|
|
22
|
+
external: [/@miden-sdk\/miden-wallet-adapter/],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/vitest";
|