create-miden-app 1.0.0

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 ADDED
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs";
3
+ import fsp from "fs/promises";
4
+ import path from "path";
5
+ import { fileURLToPath } from "url";
6
+
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+
10
+ async function copyDir(src, dest) {
11
+ await fsp.mkdir(dest, { recursive: true });
12
+ const entries = await fsp.readdir(src, { withFileTypes: true });
13
+ for (const entry of entries) {
14
+ const s = path.join(src, entry.name);
15
+ const d = path.join(dest, entry.name);
16
+ if (entry.isDirectory()) await copyDir(s, d);
17
+ else await fsp.copyFile(s, d);
18
+ }
19
+ }
20
+
21
+ async function main() {
22
+ const projectName = process.argv[2] || "miden-app";
23
+ const targetDir = path.resolve(process.cwd(), projectName);
24
+ const templateDir = path.join(__dirname, "template");
25
+
26
+ if (fs.existsSync(targetDir)) {
27
+ console.error(`❌ Directory '${projectName}' already exists.`);
28
+ process.exit(1);
29
+ }
30
+
31
+ console.log(`✨ Creating project ${projectName}...`);
32
+ await copyDir(templateDir, targetDir);
33
+
34
+ const pkgFile = path.join(targetDir, "package.json");
35
+ if (fs.existsSync(pkgFile)) {
36
+ const pkg = JSON.parse(await fsp.readFile(pkgFile, "utf8"));
37
+ pkg.name = projectName;
38
+ await fsp.writeFile(pkgFile, JSON.stringify(pkg, null, 2));
39
+ }
40
+
41
+ console.log(`
42
+ ✅ Done!
43
+ Next steps:
44
+ cd ${projectName}
45
+ npm install
46
+ npm run dev
47
+ `);
48
+ }
49
+
50
+ main();
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "create-miden-app",
3
+ "version": "1.0.0",
4
+ "description": "A CLI to scaffold a new Miden project from a template",
5
+ "bin": {
6
+ "create-miden-app": "cli.js"
7
+ },
8
+ "type": "module",
9
+ "files": [
10
+ "cli.js",
11
+ "template/"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "0xMiden",
15
+ "keywords": [
16
+ "scaffold",
17
+ "template",
18
+ "cli",
19
+ "init",
20
+ "create"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18"
24
+ }
25
+ }
@@ -0,0 +1,22 @@
1
+ # React + TypeScript + Vite + Miden
2
+
3
+ This template provides a minimal example on how to work with Miden using Vite.
4
+
5
+ This repository is based on the actual [create-vite NPM template](https://www.npmjs.com/package/create-vite).
6
+
7
+ ## Demo Client Interaction
8
+
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:
10
+
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
17
+
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.
19
+
20
+ ### Running the Demo
21
+
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.
@@ -0,0 +1,23 @@
1
+ import js from '@eslint/js'
2
+ import globals from 'globals'
3
+ import reactHooks from 'eslint-plugin-react-hooks'
4
+ import reactRefresh from 'eslint-plugin-react-refresh'
5
+ import tseslint from 'typescript-eslint'
6
+ import { defineConfig, globalIgnores } from 'eslint/config'
7
+
8
+ export default defineConfig([
9
+ globalIgnores(['dist']),
10
+ {
11
+ files: ['**/*.{ts,tsx}'],
12
+ extends: [
13
+ js.configs.recommended,
14
+ tseslint.configs.recommended,
15
+ reactHooks.configs['recommended-latest'],
16
+ reactRefresh.configs.vite,
17
+ ],
18
+ languageOptions: {
19
+ ecmaVersion: 2020,
20
+ globals: globals.browser,
21
+ },
22
+ },
23
+ ])
@@ -0,0 +1,13 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <title>miden-frontend</title>
8
+ </head>
9
+ <body>
10
+ <div id="root"></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "miden-app",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview"
11
+ },
12
+ "dependencies": {
13
+ "@demox-labs/miden-sdk": "^0.11.11",
14
+ "react": "^19.1.1",
15
+ "react-dom": "^19.1.1"
16
+ },
17
+ "devDependencies": {
18
+ "@eslint/js": "^9.36.0",
19
+ "@types/node": "^24.6.0",
20
+ "@types/react": "^19.1.16",
21
+ "@types/react-dom": "^19.1.9",
22
+ "@vitejs/plugin-react": "^5.0.4",
23
+ "eslint": "^9.36.0",
24
+ "eslint-plugin-react-hooks": "^5.2.0",
25
+ "eslint-plugin-react-refresh": "^0.4.22",
26
+ "globals": "^16.4.0",
27
+ "typescript": "~5.9.3",
28
+ "typescript-eslint": "^8.45.0",
29
+ "vite": "^7.1.7",
30
+ "vite-plugin-top-level-await": "^1.6.0",
31
+ "vite-plugin-wasm": "^3.5.0"
32
+ }
33
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
@@ -0,0 +1,45 @@
1
+ #root {
2
+ max-width: 1280px;
3
+ margin: 0 auto;
4
+ padding: 2rem;
5
+ text-align: center;
6
+ }
7
+
8
+ .logo {
9
+ height: 6em;
10
+ padding: 1.5em;
11
+ will-change: filter;
12
+ transition: filter 300ms;
13
+ }
14
+ .logo:hover {
15
+ filter: drop-shadow(0 0 2em #646cffaa);
16
+ }
17
+ .logo.react:hover {
18
+ filter: drop-shadow(0 0 2em #61dafbaa);
19
+ }
20
+ .logo.miden:hover {
21
+ filter: drop-shadow(0 0 2em #ff5500);
22
+ }
23
+
24
+ @keyframes logo-spin {
25
+ from {
26
+ transform: rotate(0deg);
27
+ }
28
+ to {
29
+ transform: rotate(360deg);
30
+ }
31
+ }
32
+
33
+ @media (prefers-reduced-motion: no-preference) {
34
+ a:nth-of-type(2) .logo {
35
+ animation: logo-spin infinite 20s linear;
36
+ }
37
+ }
38
+
39
+ .card {
40
+ padding: 2em;
41
+ }
42
+
43
+ .read-the-docs {
44
+ color: #888;
45
+ }
@@ -0,0 +1,63 @@
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
+ };
27
+
28
+ 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
+ </>
60
+ );
61
+ }
62
+
63
+ export default App;
@@ -0,0 +1,3 @@
1
+ <svg width="605" height="838" viewBox="0 0 605 838" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path d="M300.929 247.947L351.073 303.14C355.354 307.84 363.172 304.815 363.172 298.486V166.322C363.172 164.479 363.901 162.71 365.2 161.402C366.499 160.095 368.263 159.354 370.106 159.341H462.249C502.689 159.341 540.151 180.469 560.883 214.953L579.079 245.202C580.288 247.207 581.994 248.867 584.032 250.021C586.07 251.174 588.371 251.782 590.713 251.787H591.411C595.017 251.78 598.474 250.344 601.021 247.791C603.569 245.239 605 241.781 605 238.175V100.705C605 97.0992 603.569 93.6405 601.021 91.0884C598.474 88.5363 595.017 87.0995 591.411 87.0933H377.063C373.379 87.0933 369.846 85.6298 367.241 83.0247C364.636 80.4196 363.172 76.8863 363.172 73.2022V10.4242C363.172 4.67693 358.519 0 352.748 0H304.14C298.393 0 293.716 4.65367 293.716 10.4242V73.2022C293.716 80.8807 287.504 87.1166 279.825 87.1166H13.6352C10.0332 87.1166 6.57795 88.5443 4.02654 91.087C1.47513 93.6297 0.0355831 97.08 0.0232683 100.682V133.118C0.0232683 136.608 1.37283 139.959 3.76947 142.495L302.465 409.476C304.853 411.996 306.184 415.335 306.184 418.807C306.184 422.278 304.853 425.617 302.465 428.137L3.7462 695.141C1.34344 697.672 0.00267442 701.028 0 704.518V736.954C0 744.47 6.0963 750.543 13.612 750.543H279.802C287.48 750.543 293.693 756.779 293.693 764.458V827.235C293.693 832.983 298.347 837.66 304.117 837.66H352.725C358.472 837.66 363.149 833.006 363.149 827.235V764.458C363.149 756.779 369.362 750.566 377.017 750.566H591.365C593.158 750.569 594.934 750.218 596.592 749.532C598.249 748.847 599.754 747.841 601.021 746.571C602.288 745.302 603.292 743.795 603.975 742.137C604.658 740.478 605.006 738.701 605 736.908V599.462C605 595.852 603.566 592.389 601.013 589.837C598.46 587.284 594.998 585.85 591.388 585.85H590.736C588.387 585.846 586.076 586.45 584.029 587.604C581.982 588.758 580.269 590.422 579.056 592.435L560.883 622.684C550.636 639.669 536.17 653.715 518.892 663.459C501.613 673.203 482.109 678.314 462.272 678.295H370.106C369.192 678.292 368.288 678.109 367.445 677.756C366.603 677.404 365.837 676.889 365.193 676.241C364.55 675.593 364.04 674.824 363.693 673.979C363.346 673.133 363.169 672.228 363.172 671.314V539.15C363.178 537.744 362.756 536.369 361.962 535.208C361.168 534.047 360.04 533.155 358.727 532.651C357.415 532.146 355.98 532.052 354.613 532.382C353.245 532.711 352.011 533.449 351.073 534.497L300.929 589.689C296.276 594.808 293.716 601.463 293.716 608.397V671.338C293.716 673.177 292.986 674.94 291.685 676.241C290.385 677.541 288.621 678.272 286.782 678.272H115.9C115.511 678.282 115.126 678.191 114.783 678.008C114.44 677.824 114.151 677.554 113.945 677.225C113.716 676.835 113.614 676.385 113.651 675.935C113.689 675.485 113.864 675.058 114.154 674.712L380.414 424.507L380.461 424.438C381.755 422.842 382.461 420.85 382.461 418.795C382.461 416.74 381.755 414.748 380.461 413.152L380.414 413.106L114.154 162.925C113.864 162.579 113.689 162.151 113.651 161.702C113.614 161.252 113.716 160.801 113.945 160.412C114.151 160.082 114.44 159.812 114.783 159.629C115.126 159.445 115.511 159.354 115.9 159.365H286.782C290.598 159.365 293.716 162.459 293.716 166.299V229.24C293.716 236.15 296.276 242.828 300.929 247.947Z" fill="#FF5500"/>
3
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
@@ -0,0 +1,68 @@
1
+ :root {
2
+ font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+
6
+ color-scheme: light dark;
7
+ color: rgba(255, 255, 255, 0.87);
8
+ background-color: #242424;
9
+
10
+ font-synthesis: none;
11
+ text-rendering: optimizeLegibility;
12
+ -webkit-font-smoothing: antialiased;
13
+ -moz-osx-font-smoothing: grayscale;
14
+ }
15
+
16
+ a {
17
+ font-weight: 500;
18
+ color: #646cff;
19
+ text-decoration: inherit;
20
+ }
21
+ a:hover {
22
+ color: #535bf2;
23
+ }
24
+
25
+ body {
26
+ margin: 0;
27
+ display: flex;
28
+ place-items: center;
29
+ min-width: 320px;
30
+ min-height: 100vh;
31
+ }
32
+
33
+ h1 {
34
+ font-size: 3.2em;
35
+ line-height: 1.1;
36
+ }
37
+
38
+ button {
39
+ border-radius: 8px;
40
+ border: 1px solid transparent;
41
+ padding: 0.6em 1.2em;
42
+ font-size: 1em;
43
+ font-weight: 500;
44
+ font-family: inherit;
45
+ background-color: #1a1a1a;
46
+ cursor: pointer;
47
+ transition: border-color 0.25s;
48
+ }
49
+ button:hover {
50
+ border-color: #646cff;
51
+ }
52
+ button:focus,
53
+ button:focus-visible {
54
+ outline: 4px auto -webkit-focus-ring-color;
55
+ }
56
+
57
+ @media (prefers-color-scheme: light) {
58
+ :root {
59
+ color: #213547;
60
+ background-color: #ffffff;
61
+ }
62
+ a:hover {
63
+ color: #747bff;
64
+ }
65
+ button {
66
+ background-color: #f9f9f9;
67
+ }
68
+ }
@@ -0,0 +1,10 @@
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import './index.css'
4
+ import App from './App.tsx'
5
+
6
+ createRoot(document.getElementById('root')!).render(
7
+ <StrictMode>
8
+ <App />
9
+ </StrictMode>,
10
+ )
@@ -0,0 +1,102 @@
1
+ import {
2
+ WebClient,
3
+ AccountStorageMode,
4
+ NoteType,
5
+ ConsumableNoteRecord,
6
+ AccountId,
7
+ } from "@demox-labs/miden-sdk";
8
+
9
+ export async function demo() {
10
+ // Initialize client to connect with the Miden Testnet.
11
+ // NOTE: The client is our entry point to the Miden network.
12
+ // All interactions with the network go through the client.
13
+ const nodeEndpoint = "https://rpc.testnet.miden.io:443";
14
+ const client = await WebClient.createClient(nodeEndpoint);
15
+ await client.syncState();
16
+
17
+ // Creating Alice's account
18
+ const alice = await client.newWallet(AccountStorageMode.public(), true);
19
+ console.log("Alice's account ID:", alice.id().toString());
20
+
21
+ // Creating a faucet account
22
+ const symbol = "TEST";
23
+ const decimals = 8;
24
+ const initialSupply = BigInt(10_000_000 * 10 ** decimals);
25
+ const faucet = await client.newFaucet(
26
+ AccountStorageMode.public(), // Public: account state is visible on-chain
27
+ false, // Mutable: account code cannot be upgraded later
28
+ symbol, // Symbol of the token
29
+ decimals, // Number of decimals
30
+ initialSupply // Initial supply of tokens
31
+ );
32
+ console.log("Faucet account ID:", faucet.id().toString());
33
+
34
+ // Create transaction request to mint fungible asset to Alice's account
35
+ // NOTE: This transaction will create a P2ID note (a Miden note containing the minted asset)
36
+ // for Alice's account. Alice will be able to consume these notes to get the fungible asset in her vault
37
+ console.log("Minting 1000 tokens to Alice...");
38
+ const mintTxRequest = client.newMintTransactionRequest(
39
+ alice.id(), // Target account (who receives the tokens)
40
+ faucet.id(), // Faucet account (who mints the tokens)
41
+ NoteType.Public, // Note visibility (public = on-chain)
42
+ BigInt(1000) // Amount to mint (in base units)
43
+ );
44
+ const mintTx = await client.newTransaction(faucet.id(), mintTxRequest);
45
+ await client.submitTransaction(mintTx);
46
+
47
+ console.log(
48
+ "Mint transaction submitted successfully, ID:",
49
+ mintTx.executedTransaction().id().toHex()
50
+ );
51
+
52
+ await client.syncState();
53
+
54
+ let consumableNotes: ConsumableNoteRecord[] = [];
55
+ while (consumableNotes.length === 0) {
56
+ // Find consumable notes
57
+ consumableNotes = await client.getConsumableNotes(alice.id());
58
+
59
+ console.log("Waiting for note to be consumable...");
60
+ await new Promise((resolve) => setTimeout(resolve, 3000));
61
+ }
62
+
63
+ const noteIds = consumableNotes.map((note) =>
64
+ note.inputNoteRecord().id().toString()
65
+ );
66
+
67
+ // Create transaction request to consume notes
68
+ // NOTE: This transaction will consume the notes and add the fungible asset to Alice's vault
69
+ const consumeTxRequest = client.newConsumeTransactionRequest(noteIds);
70
+ const consumeTx = await client.newTransaction(alice.id(), consumeTxRequest);
71
+ await client.submitTransaction(consumeTx);
72
+ console.log(
73
+ "Consume transaction submitted successfully, ID:",
74
+ consumeTx.executedTransaction().id().toHex()
75
+ );
76
+
77
+ console.log(
78
+ "Alice's TEST token balance:",
79
+ Number(alice.vault().getBalance(faucet.id()))
80
+ );
81
+
82
+ await client.syncState();
83
+
84
+ // Send tokens from Alice to Bob
85
+ const bobAccountId = "0x599a54603f0cf9000000ed7a11e379";
86
+ console.log("Sending 100 tokens to Bob...");
87
+
88
+ // Build transaction request to send tokens from Alice to Bob
89
+ const sendTxRequest = client.newSendTransactionRequest(
90
+ alice.id(), // Sender account
91
+ AccountId.fromHex(bobAccountId), // Recipient account
92
+ faucet.id(), // Asset ID (faucet that created the tokens)
93
+ NoteType.Public, // Note visibility
94
+ BigInt(100) // Amount to send
95
+ );
96
+
97
+ const sendTx = await client.newTransaction(alice.id(), sendTxRequest);
98
+ await client.submitTransaction(sendTx);
99
+ console.log("Send transaction submitted successfully!");
100
+
101
+ await client.syncState();
102
+ }
File without changes
@@ -0,0 +1,28 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
4
+ "target": "ES2022",
5
+ "useDefineForClassFields": true,
6
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
7
+ "module": "ESNext",
8
+ "types": ["vite/client"],
9
+ "skipLibCheck": true,
10
+
11
+ /* Bundler mode */
12
+ "moduleResolution": "bundler",
13
+ "allowImportingTsExtensions": true,
14
+ "verbatimModuleSyntax": true,
15
+ "moduleDetection": "force",
16
+ "noEmit": true,
17
+ "jsx": "react-jsx",
18
+
19
+ /* Linting */
20
+ "strict": true,
21
+ "noUnusedLocals": true,
22
+ "noUnusedParameters": true,
23
+ "erasableSyntaxOnly": true,
24
+ "noFallthroughCasesInSwitch": true,
25
+ "noUncheckedSideEffectImports": true
26
+ },
27
+ "include": ["src"]
28
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "files": [],
3
+ "references": [
4
+ { "path": "./tsconfig.app.json" },
5
+ { "path": "./tsconfig.node.json" }
6
+ ]
7
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "compilerOptions": {
3
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
4
+ "target": "ES2023",
5
+ "lib": ["ES2023"],
6
+ "module": "ESNext",
7
+ "types": ["node"],
8
+ "skipLibCheck": true,
9
+
10
+ /* Bundler mode */
11
+ "moduleResolution": "bundler",
12
+ "allowImportingTsExtensions": true,
13
+ "verbatimModuleSyntax": true,
14
+ "moduleDetection": "force",
15
+ "noEmit": true,
16
+
17
+ /* Linting */
18
+ "strict": true,
19
+ "noUnusedLocals": true,
20
+ "noUnusedParameters": true,
21
+ "erasableSyntaxOnly": true,
22
+ "noFallthroughCasesInSwitch": true,
23
+ "noUncheckedSideEffectImports": true
24
+ },
25
+ "include": ["vite.config.ts"]
26
+ }
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from "vite";
2
+ import react from "@vitejs/plugin-react";
3
+ import wasm from "vite-plugin-wasm";
4
+ import topLevelAwait from "vite-plugin-top-level-await";
5
+
6
+ // https://vite.dev/config/
7
+ export default defineConfig({
8
+ plugins: [react(), wasm(), topLevelAwait()],
9
+ optimizeDeps: {
10
+ exclude: ["@demox-labs/miden-sdk"],
11
+ },
12
+ server: {
13
+ headers: {
14
+ "Cross-Origin-Opener-Policy": "same-origin",
15
+ "Cross-Origin-Embedder-Policy": "require-corp",
16
+ },
17
+ },
18
+ });