create-mn-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.
Files changed (50) hide show
  1. package/README.md +45 -0
  2. package/bin/create-midnight-app.js +47 -0
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +35 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/create-app.d.ts +10 -0
  8. package/dist/create-app.d.ts.map +1 -0
  9. package/dist/create-app.js +169 -0
  10. package/dist/create-app.js.map +1 -0
  11. package/dist/installers/package-installer.d.ts +8 -0
  12. package/dist/installers/package-installer.d.ts.map +1 -0
  13. package/dist/installers/package-installer.js +62 -0
  14. package/dist/installers/package-installer.js.map +1 -0
  15. package/dist/installers/proof-server-setup.d.ts +6 -0
  16. package/dist/installers/proof-server-setup.d.ts.map +1 -0
  17. package/dist/installers/proof-server-setup.js +54 -0
  18. package/dist/installers/proof-server-setup.js.map +1 -0
  19. package/dist/installers/wallet-generator.d.ts +4 -0
  20. package/dist/installers/wallet-generator.d.ts.map +1 -0
  21. package/dist/installers/wallet-generator.js +64 -0
  22. package/dist/installers/wallet-generator.js.map +1 -0
  23. package/dist/test.d.ts +2 -0
  24. package/dist/test.d.ts.map +1 -0
  25. package/dist/test.js +53 -0
  26. package/dist/test.js.map +1 -0
  27. package/dist/utils/git-utils.d.ts +6 -0
  28. package/dist/utils/git-utils.d.ts.map +1 -0
  29. package/dist/utils/git-utils.js +51 -0
  30. package/dist/utils/git-utils.js.map +1 -0
  31. package/dist/utils/template-manager.d.ts +7 -0
  32. package/dist/utils/template-manager.d.ts.map +1 -0
  33. package/dist/utils/template-manager.js +61 -0
  34. package/dist/utils/template-manager.js.map +1 -0
  35. package/dist/utils/validation.d.ts +6 -0
  36. package/dist/utils/validation.d.ts.map +1 -0
  37. package/dist/utils/validation.js +32 -0
  38. package/dist/utils/validation.js.map +1 -0
  39. package/package.json +60 -0
  40. package/templates/hello-world/README.md.template +100 -0
  41. package/templates/hello-world/_env.template +0 -0
  42. package/templates/hello-world/_gitignore +52 -0
  43. package/templates/hello-world/contracts/hello-world.compact.template +12 -0
  44. package/templates/hello-world/nodemon.json.template +7 -0
  45. package/templates/hello-world/package.json.template +49 -0
  46. package/templates/hello-world/src/cli.ts.template +194 -0
  47. package/templates/hello-world/src/deploy.ts.template +181 -0
  48. package/templates/hello-world/src/providers/midnight-providers.ts.template +46 -0
  49. package/templates/hello-world/src/utils/environment.ts.template +51 -0
  50. package/templates/hello-world/tsconfig.json.template +20 -0
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitUtils = void 0;
4
+ const cross_spawn_1 = require("cross-spawn");
5
+ class GitUtils {
6
+ static async init(projectPath) {
7
+ // Check if git is available
8
+ const gitAvailable = await this.isGitAvailable();
9
+ if (!gitAvailable) {
10
+ throw new Error("Git is not available");
11
+ }
12
+ // Initialize git repository
13
+ await this.runGitCommand(projectPath, ["init"]);
14
+ // Add all files
15
+ await this.runGitCommand(projectPath, ["add", "."]);
16
+ // Create initial commit
17
+ await this.runGitCommand(projectPath, [
18
+ "commit",
19
+ "-m",
20
+ "Initial commit from create-midnight-app",
21
+ ]);
22
+ }
23
+ static async isGitAvailable() {
24
+ try {
25
+ await this.runGitCommand(process.cwd(), ["--version"]);
26
+ return true;
27
+ }
28
+ catch {
29
+ return false;
30
+ }
31
+ }
32
+ static async runGitCommand(cwd, args) {
33
+ return new Promise((resolve, reject) => {
34
+ const child = (0, cross_spawn_1.spawn)("git", args, {
35
+ cwd,
36
+ stdio: "pipe",
37
+ });
38
+ child.on("close", (code) => {
39
+ if (code === 0) {
40
+ resolve();
41
+ }
42
+ else {
43
+ reject(new Error(`Git command failed with code ${code}`));
44
+ }
45
+ });
46
+ child.on("error", reject);
47
+ });
48
+ }
49
+ }
50
+ exports.GitUtils = GitUtils;
51
+ //# sourceMappingURL=git-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-utils.js","sourceRoot":"","sources":["../../src/utils/git-utils.ts"],"names":[],"mappings":";;;AAAA,6CAAoC;AAIpC,MAAa,QAAQ;IACnB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,WAAmB;QACnC,4BAA4B;QAC5B,MAAM,YAAY,GAAG,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QACjD,IAAI,CAAC,YAAY,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;QAC1C,CAAC;QAED,4BAA4B;QAC5B,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QAEhD,gBAAgB;QAChB,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QAEpD,wBAAwB;QACxB,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE;YACpC,QAAQ;YACR,IAAI;YACJ,yCAAyC;SAC1C,CAAC,CAAC;IACL,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,cAAc;QACjC,IAAI,CAAC;YACH,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;YACvD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAEO,MAAM,CAAC,KAAK,CAAC,aAAa,CAChC,GAAW,EACX,IAAc;QAEd,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,KAAK,GAAG,IAAA,mBAAK,EAAC,KAAK,EAAE,IAAI,EAAE;gBAC/B,GAAG;gBACH,KAAK,EAAE,MAAM;aACd,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBACf,OAAO,EAAE,CAAC;gBACZ,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,IAAI,EAAE,CAAC,CAAC,CAAC;gBAC5D,CAAC;YACH,CAAC,CAAC,CAAC;YAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5B,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AApDD,4BAoDC"}
@@ -0,0 +1,7 @@
1
+ export declare class TemplateManager {
2
+ private templateName;
3
+ constructor(templateName: string);
4
+ scaffold(projectPath: string, projectName: string): Promise<void>;
5
+ private copyTemplate;
6
+ }
7
+ //# sourceMappingURL=template-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-manager.d.ts","sourceRoot":"","sources":["../../src/utils/template-manager.ts"],"names":[],"mappings":"AAIA,qBAAa,eAAe;IACd,OAAO,CAAC,YAAY;gBAAZ,YAAY,EAAE,MAAM;IAElC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAuBzD,YAAY;CAmC3B"}
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TemplateManager = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const mustache_1 = __importDefault(require("mustache"));
10
+ class TemplateManager {
11
+ constructor(templateName) {
12
+ this.templateName = templateName;
13
+ }
14
+ async scaffold(projectPath, projectName) {
15
+ const templatePath = path_1.default.join(__dirname, "../../templates", this.templateName);
16
+ if (!fs_extra_1.default.existsSync(templatePath)) {
17
+ throw new Error(`Template "${this.templateName}" not found`);
18
+ }
19
+ const templateVars = {
20
+ projectName,
21
+ timestamp: new Date().toISOString(),
22
+ year: new Date().getFullYear(),
23
+ capitalizedName: projectName.charAt(0).toUpperCase() + projectName.slice(1),
24
+ kebabName: projectName.toLowerCase().replace(/\s+/g, "-"),
25
+ };
26
+ await this.copyTemplate(templatePath, projectPath, templateVars);
27
+ }
28
+ async copyTemplate(templatePath, projectPath, templateVars) {
29
+ const files = await fs_extra_1.default.readdir(templatePath, { withFileTypes: true });
30
+ for (const file of files) {
31
+ const sourcePath = path_1.default.join(templatePath, file.name);
32
+ let destPath = path_1.default.join(projectPath, file.name);
33
+ // Handle special file names
34
+ if (file.name === "_gitignore") {
35
+ destPath = path_1.default.join(projectPath, ".gitignore");
36
+ }
37
+ else if (file.name === "_env.template") {
38
+ destPath = path_1.default.join(projectPath, ".env.example");
39
+ }
40
+ if (file.isDirectory()) {
41
+ await fs_extra_1.default.ensureDir(destPath);
42
+ await this.copyTemplate(sourcePath, destPath, templateVars);
43
+ }
44
+ else {
45
+ if (file.name.endsWith(".template")) {
46
+ // Render template file
47
+ const content = await fs_extra_1.default.readFile(sourcePath, "utf8");
48
+ const rendered = mustache_1.default.render(content, templateVars);
49
+ const finalPath = destPath.replace(".template", "");
50
+ await fs_extra_1.default.writeFile(finalPath, rendered);
51
+ }
52
+ else {
53
+ // Copy binary file as-is
54
+ await fs_extra_1.default.copy(sourcePath, destPath);
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ exports.TemplateManager = TemplateManager;
61
+ //# sourceMappingURL=template-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"template-manager.js","sourceRoot":"","sources":["../../src/utils/template-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface ValidationResult {
2
+ valid: boolean;
3
+ problems?: string[];
4
+ }
5
+ export declare function validateProjectName(name: string): ValidationResult;
6
+ //# sourceMappingURL=validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CA8BlE"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.validateProjectName = validateProjectName;
7
+ const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
8
+ function validateProjectName(name) {
9
+ const validation = (0, validate_npm_package_name_1.default)(name);
10
+ if (validation.validForNewPackages) {
11
+ return { valid: true };
12
+ }
13
+ const problems = [];
14
+ if (validation.errors) {
15
+ problems.push(...validation.errors);
16
+ }
17
+ if (validation.warnings) {
18
+ problems.push(...validation.warnings);
19
+ }
20
+ // Additional checks
21
+ if (name.length === 0) {
22
+ problems.push("Project name cannot be empty");
23
+ }
24
+ if (name.match(/[A-Z]/)) {
25
+ problems.push("Project name cannot contain uppercase letters");
26
+ }
27
+ return {
28
+ valid: false,
29
+ problems: problems.length > 0 ? problems : ["Invalid project name"],
30
+ };
31
+ }
32
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/utils/validation.ts"],"names":[],"mappings":";;;;;AAOA,kDA8BC;AArCD,0FAA4D;AAO5D,SAAgB,mBAAmB,CAAC,IAAY;IAC9C,MAAM,UAAU,GAAG,IAAA,mCAAmB,EAAC,IAAI,CAAC,CAAC;IAE7C,IAAI,UAAU,CAAC,mBAAmB,EAAE,CAAC;QACnC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IAED,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,oBAAoB;IACpB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,QAAQ,CAAC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAChD,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACxB,QAAQ,CAAC,IAAI,CAAC,+CAA+C,CAAC,CAAC;IACjE,CAAC;IAED,OAAO;QACL,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,sBAAsB,CAAC;KACpE,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "create-mn-app",
3
+ "version": "1.0.0",
4
+ "description": "Create Midnight Network applications with zero configuration",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "create-mn-app": "./bin/create-midnight-app.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "dist",
12
+ "templates"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "prepublishOnly": "npm run build",
18
+ "test": "npm run build && node dist/test.js",
19
+ "test-local": "npm run build && npm link && npx create-midnight-app test-app",
20
+ "clean": "rm -rf dist test-app"
21
+ },
22
+ "keywords": [
23
+ "midnight",
24
+ "blockchain",
25
+ "zero-knowledge",
26
+ "privacy",
27
+ "scaffold",
28
+ "cli",
29
+ "create-app"
30
+ ],
31
+ "author": "Midnight Network",
32
+ "license": "MIT",
33
+ "dependencies": {
34
+ "chalk": "^4.1.2",
35
+ "commander": "^11.0.0",
36
+ "cross-spawn": "^7.0.3",
37
+ "fs-extra": "^11.1.1",
38
+ "mustache": "^4.2.0",
39
+ "ora": "^5.4.1",
40
+ "prompts": "^2.4.2",
41
+ "semver": "^7.5.4",
42
+ "validate-npm-package-name": "^5.0.0"
43
+ },
44
+ "devDependencies": {
45
+ "@types/cross-spawn": "^6.0.2",
46
+ "@types/fs-extra": "^11.0.1",
47
+ "@types/mustache": "^4.2.2",
48
+ "@types/node": "^20.0.0",
49
+ "@types/prompts": "^2.4.4",
50
+ "@types/validate-npm-package-name": "^4.0.2",
51
+ "typescript": "^5.0.0"
52
+ },
53
+ "engines": {
54
+ "node": ">=18.0.0"
55
+ },
56
+ "repository": {
57
+ "type": "git",
58
+ "url": "https://github.com/midnightntwrk/create-midnight-app.git"
59
+ }
60
+ }
@@ -0,0 +1,100 @@
1
+ # {{projectName}}
2
+
3
+ A Midnight Network application created with `create-midnight-app`.
4
+
5
+ ## Getting Started
6
+
7
+ ### Prerequisites
8
+
9
+ - Node.js 18+ installed
10
+ - Docker installed (for proof server)
11
+
12
+ ### Quick Start
13
+
14
+ 1. **Install dependencies**:
15
+ ```bash
16
+ npm install
17
+ ```
18
+
19
+ 2. **Start development**:
20
+
21
+ ```bash
22
+ npm run dev
23
+ ```
24
+
25
+ This will:
26
+
27
+ - Start the proof server
28
+ - Watch for contract changes
29
+ - Auto-compile and build
30
+ - Deploy when ready
31
+
32
+ 3. **Interact with your contract**:
33
+ ```bash
34
+ npm run cli
35
+ ```
36
+
37
+ ### Available Scripts
38
+
39
+ - `npm run dev` - Start development server with hot reloading
40
+ - `npm run setup` - Compile, build, and deploy contract
41
+ - `npm run compile` - Compile Compact contract
42
+ - `npm run build` - Build TypeScript
43
+ - `npm run deploy` - Deploy contract to testnet
44
+ - `npm run cli` - Interactive CLI for contract
45
+ - `npm run reset` - Reset all compiled/built files
46
+ - `npm run clean` - Clean build artifacts
47
+
48
+ ### Environment Variables
49
+
50
+ Copy `.env.example` to `.env` and configure:
51
+
52
+ - `WALLET_SEED` - Your 64-character wallet seed (auto-generated)
53
+ - `MIDNIGHT_NETWORK` - Network to use (testnet)
54
+ - `PROOF_SERVER_URL` - Proof server URL
55
+ - `CONTRACT_NAME` - Contract name
56
+
57
+ ### Project Structure
58
+
59
+ ```
60
+ {{projectName}}/
61
+ ā”œā”€ā”€ contracts/
62
+ │ ā”œā”€ā”€ hello-world.compact # Smart contract source
63
+ │ └── managed/ # Compiled artifacts
64
+ ā”œā”€ā”€ src/
65
+ │ ā”œā”€ā”€ deploy.ts # Deployment script
66
+ │ ā”œā”€ā”€ cli.ts # Interactive CLI
67
+ │ ā”œā”€ā”€ providers/ # Shared providers
68
+ │ └── utils/ # Utility functions
69
+ ā”œā”€ā”€ .env # Environment config (keep private!)
70
+ ā”œā”€ā”€ deployment.json # Deployment info
71
+ └── package.json
72
+ ```
73
+
74
+ ### Getting Testnet Tokens
75
+
76
+ 1. Run `npm run deploy` to see your wallet address
77
+ 2. Visit [https://midnight.network/test-faucet](https://midnight.network/test-faucet)
78
+ 3. Enter your address to receive test tokens
79
+
80
+ ### Learn More
81
+
82
+ - [Midnight Documentation](https://docs.midnight.network)
83
+ - [Compact Language Guide](https://docs.midnight.network/compact)
84
+ - [Tutorial Series](https://docs.midnight.network/tutorials)
85
+
86
+ ## Contract Overview
87
+
88
+ This project includes a simple "Hello World" contract that:
89
+
90
+ - Stores a message on the blockchain
91
+ - Allows reading the current message
92
+ - Demonstrates basic Midnight functionality
93
+
94
+ The contract uses:
95
+
96
+ - **Public ledger state** for the message
97
+ - **Zero-knowledge proofs** for transactions
98
+ - **Privacy-preserving** architecture
99
+
100
+ Happy coding! šŸŒ™
File without changes
@@ -0,0 +1,52 @@
1
+ # Dependencies
2
+ node_modules/
3
+ npm-debug.log*
4
+ yarn-debug.log*
5
+ yarn-error.log*
6
+
7
+ # Build output
8
+ dist/
9
+ build/
10
+
11
+ # Environment variables
12
+ .env
13
+ .env.local
14
+ .env.development.local
15
+ .env.test.local
16
+ .env.production.local
17
+
18
+ # Contract artifacts
19
+ contracts/managed/
20
+
21
+ # Deployment info
22
+ deployment.json
23
+
24
+ # OS generated files
25
+ .DS_Store
26
+ Thumbs.db
27
+
28
+ # IDE files
29
+ .vscode/settings.json
30
+ .idea/
31
+ *.swp
32
+ *.swo
33
+
34
+ # Logs
35
+ logs/
36
+ *.log
37
+
38
+ # Runtime data
39
+ pids/
40
+ *.pid
41
+ *.seed
42
+ *.pid.lock
43
+
44
+ # Coverage directory
45
+ coverage/
46
+
47
+ # Private state
48
+ *-state/
49
+
50
+ # Temporary files
51
+ tmp/
52
+ temp/
@@ -0,0 +1,12 @@
1
+ pragma language_version >= 0.16 && <= 0.17;
2
+
3
+ import CompactStandardLibrary;
4
+
5
+ // Public ledger state - visible on blockchain
6
+ export ledger message: Opaque<"string">;
7
+
8
+ // Circuit to store a message on the blockchain
9
+ // The message will be publicly visible
10
+ export circuit storeMessage(customMessage: Opaque<"string">): [] {
11
+ message = disclose(customMessage);
12
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "watch": ["contracts/**/*.compact", "src/**/*.ts"],
3
+ "ext": "compact,ts",
4
+ "ignore": ["contracts/managed/**", "dist/**", "node_modules/**"],
5
+ "exec": "npm run compile && npm run build",
6
+ "delay": "1000"
7
+ }
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "{{projectName}}",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "A Midnight Network application created with create-midnight-app",
6
+ "author": "{{author}}",
7
+ "license": "MIT",
8
+ "scripts": {
9
+ "dev": "concurrently \"npm run proof-server\" \"npm run watch\"",
10
+ "watch": "nodemon --config nodemon.json",
11
+ "setup": "npm run compile && npm run build && npm run deploy",
12
+ "compile": "compact compile contracts/hello-world.compact contracts/managed/hello-world",
13
+ "build": "tsc",
14
+ "deploy": "node dist/deploy.js",
15
+ "cli": "node dist/cli.js",
16
+ "reset": "rm -rf contracts/managed deployment.json dist && npm run compile",
17
+ "validate": "tsc --noEmit && npm run compile",
18
+ "clean": "rm -rf dist contracts/managed deployment.json",
19
+ "proof-server": "docker run -p 6300:6300 midnightnetwork/proof-server -- 'midnight-proof-server --network testnet'",
20
+ "test": "echo \"Error: no test specified\" && exit 1"
21
+ },
22
+ "dependencies": {
23
+ "@midnight-ntwrk/compact-runtime": "^0.8.1",
24
+ "@midnight-ntwrk/ledger": "^4.0.0",
25
+ "@midnight-ntwrk/midnight-js-contracts": "2.0.2",
26
+ "@midnight-ntwrk/midnight-js-http-client-proof-provider": "2.0.2",
27
+ "@midnight-ntwrk/midnight-js-indexer-public-data-provider": "2.0.2",
28
+ "@midnight-ntwrk/midnight-js-level-private-state-provider": "2.0.2",
29
+ "@midnight-ntwrk/midnight-js-node-zk-config-provider": "2.0.2",
30
+ "@midnight-ntwrk/midnight-js-network-id": "2.0.2",
31
+ "@midnight-ntwrk/midnight-js-types": "2.0.2",
32
+ "@midnight-ntwrk/wallet": "5.0.0",
33
+ "@midnight-ntwrk/wallet-api": "5.0.0",
34
+ "@midnight-ntwrk/zswap": "^4.0.0",
35
+ "ws": "^8.18.3",
36
+ "dotenv": "^16.3.1"
37
+ },
38
+ "devDependencies": {
39
+ "@types/node": "^24.4.0",
40
+ "@types/ws": "^8.5.10",
41
+ "typescript": "^5.9.2",
42
+ "nodemon": "^3.0.1",
43
+ "concurrently": "^8.2.0"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ },
48
+ "keywords": ["midnight", "blockchain", "zero-knowledge", "privacy"]
49
+ }
@@ -0,0 +1,194 @@
1
+ import "dotenv/config";
2
+ import * as readline from "readline/promises";
3
+ import { WalletBuilder } from "@midnight-ntwrk/wallet";
4
+ import { findDeployedContract } from "@midnight-ntwrk/midnight-js-contracts";
5
+ import {
6
+ NetworkId,
7
+ setNetworkId,
8
+ getZswapNetworkId,
9
+ getLedgerNetworkId,
10
+ } from "@midnight-ntwrk/midnight-js-network-id";
11
+ import { createBalancedTx } from "@midnight-ntwrk/midnight-js-types";
12
+ import { Transaction } from "@midnight-ntwrk/ledger";
13
+ import { Transaction as ZswapTransaction } from "@midnight-ntwrk/zswap";
14
+ import { WebSocket } from "ws";
15
+ import * as path from "path";
16
+ import * as fs from "fs";
17
+ import * as Rx from "rxjs";
18
+ import { MidnightProviders } from "./providers/midnight-providers";
19
+ import { EnvironmentManager } from "./utils/environment";
20
+
21
+ // Fix WebSocket for Node.js environment
22
+ // @ts-ignore
23
+ globalThis.WebSocket = WebSocket;
24
+
25
+ // Configure for Midnight Testnet
26
+ setNetworkId(NetworkId.TestNet);
27
+
28
+ async function main() {
29
+ const rl = readline.createInterface({
30
+ input: process.stdin,
31
+ output: process.stdout,
32
+ });
33
+
34
+ console.log("šŸŒ™ {{projectName}} CLI\n");
35
+
36
+ try {
37
+ // Validate environment
38
+ EnvironmentManager.validateEnvironment();
39
+
40
+ // Check for deployment file
41
+ if (!fs.existsSync("deployment.json")) {
42
+ console.error("āŒ No deployment.json found! Run npm run deploy first.");
43
+ process.exit(1);
44
+ }
45
+
46
+ const deployment = JSON.parse(fs.readFileSync("deployment.json", "utf-8"));
47
+ console.log(`Contract: ${deployment.contractAddress}\n`);
48
+
49
+ const networkConfig = EnvironmentManager.getNetworkConfig();
50
+ const contractName =
51
+ deployment.contractName || process.env.CONTRACT_NAME || "hello-world";
52
+ const walletSeed = process.env.WALLET_SEED!;
53
+
54
+ console.log("Connecting to Midnight network...");
55
+
56
+ // Build wallet
57
+ const wallet = await WalletBuilder.buildFromSeed(
58
+ networkConfig.indexer,
59
+ networkConfig.indexerWS,
60
+ networkConfig.proofServer,
61
+ networkConfig.node,
62
+ walletSeed,
63
+ getZswapNetworkId(),
64
+ "info"
65
+ );
66
+
67
+ wallet.start();
68
+
69
+ // Wait for sync
70
+ await Rx.firstValueFrom(
71
+ wallet.state().pipe(Rx.filter((s) => s.syncProgress?.synced === true))
72
+ );
73
+
74
+ // Load contract
75
+ const contractPath = path.join(process.cwd(), "contracts");
76
+ const contractModulePath = path.join(
77
+ contractPath,
78
+ "managed",
79
+ contractName,
80
+ "contract",
81
+ "index.cjs"
82
+ );
83
+ const HelloWorldModule = await import(contractModulePath);
84
+ const contractInstance = new HelloWorldModule.Contract({});
85
+
86
+ // Create wallet provider
87
+ const walletState = await Rx.firstValueFrom(wallet.state());
88
+
89
+ const walletProvider = {
90
+ coinPublicKey: walletState.coinPublicKey,
91
+ encryptionPublicKey: walletState.encryptionPublicKey,
92
+ balanceTx(tx: any, newCoins: any) {
93
+ return wallet
94
+ .balanceTransaction(
95
+ ZswapTransaction.deserialize(
96
+ tx.serialize(getLedgerNetworkId()),
97
+ getZswapNetworkId()
98
+ ),
99
+ newCoins
100
+ )
101
+ .then((tx) => wallet.proveTransaction(tx))
102
+ .then((zswapTx) =>
103
+ Transaction.deserialize(
104
+ zswapTx.serialize(getZswapNetworkId()),
105
+ getLedgerNetworkId()
106
+ )
107
+ )
108
+ .then(createBalancedTx);
109
+ },
110
+ submitTx(tx: any) {
111
+ return wallet.submitTransaction(tx);
112
+ },
113
+ };
114
+
115
+ // Configure providers
116
+ const providers = MidnightProviders.create({
117
+ contractName,
118
+ walletProvider,
119
+ networkConfig,
120
+ });
121
+
122
+ // Connect to contract
123
+ const deployed: any = await findDeployedContract(providers, {
124
+ contractAddress: deployment.contractAddress,
125
+ contract: contractInstance,
126
+ privateStateId: "helloWorldState",
127
+ initialPrivateState: {},
128
+ });
129
+
130
+ console.log("āœ… Connected to contract\n");
131
+
132
+ // Main menu loop
133
+ let running = true;
134
+ while (running) {
135
+ console.log("--- Menu ---");
136
+ console.log("1. Store message");
137
+ console.log("2. Read current message");
138
+ console.log("3. Exit");
139
+
140
+ const choice = await rl.question("\nYour choice: ");
141
+
142
+ switch (choice) {
143
+ case "1":
144
+ console.log("\nStoring custom message...");
145
+ const customMessage = await rl.question("Enter your message: ");
146
+ try {
147
+ const tx = await deployed.callTx.storeMessage(customMessage);
148
+ console.log("āœ… Success!");
149
+ console.log(`Message: "${customMessage}"`);
150
+ console.log(`Transaction ID: ${tx.public.txId}`);
151
+ console.log(`Block height: ${tx.public.blockHeight}\n`);
152
+ } catch (error) {
153
+ console.error("āŒ Failed to store message:", error);
154
+ }
155
+ break;
156
+
157
+ case "2":
158
+ console.log("\nReading message from blockchain...");
159
+ try {
160
+ const state = await providers.publicDataProvider.queryContractState(
161
+ deployment.contractAddress
162
+ );
163
+ if (state) {
164
+ const ledger = HelloWorldModule.ledger(state.data);
165
+ const message = Buffer.from(ledger.message).toString();
166
+ console.log(`šŸ“‹ Current message: "${message}"\n`);
167
+ } else {
168
+ console.log("šŸ“‹ No message found\n");
169
+ }
170
+ } catch (error) {
171
+ console.error("āŒ Failed to read message:", error);
172
+ }
173
+ break;
174
+
175
+ case "3":
176
+ running = false;
177
+ console.log("\nšŸ‘‹ Goodbye!");
178
+ break;
179
+
180
+ default:
181
+ console.log("āŒ Invalid choice. Please enter 1, 2, or 3.\n");
182
+ }
183
+ }
184
+
185
+ // Clean up
186
+ await wallet.close();
187
+ } catch (error) {
188
+ console.error("\nāŒ Error:", error);
189
+ } finally {
190
+ rl.close();
191
+ }
192
+ }
193
+
194
+ main().catch(console.error);