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.
- package/README.md +45 -0
- package/bin/create-midnight-app.js +47 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +35 -0
- package/dist/cli.js.map +1 -0
- package/dist/create-app.d.ts +10 -0
- package/dist/create-app.d.ts.map +1 -0
- package/dist/create-app.js +169 -0
- package/dist/create-app.js.map +1 -0
- package/dist/installers/package-installer.d.ts +8 -0
- package/dist/installers/package-installer.d.ts.map +1 -0
- package/dist/installers/package-installer.js +62 -0
- package/dist/installers/package-installer.js.map +1 -0
- package/dist/installers/proof-server-setup.d.ts +6 -0
- package/dist/installers/proof-server-setup.d.ts.map +1 -0
- package/dist/installers/proof-server-setup.js +54 -0
- package/dist/installers/proof-server-setup.js.map +1 -0
- package/dist/installers/wallet-generator.d.ts +4 -0
- package/dist/installers/wallet-generator.d.ts.map +1 -0
- package/dist/installers/wallet-generator.js +64 -0
- package/dist/installers/wallet-generator.js.map +1 -0
- package/dist/test.d.ts +2 -0
- package/dist/test.d.ts.map +1 -0
- package/dist/test.js +53 -0
- package/dist/test.js.map +1 -0
- package/dist/utils/git-utils.d.ts +6 -0
- package/dist/utils/git-utils.d.ts.map +1 -0
- package/dist/utils/git-utils.js +51 -0
- package/dist/utils/git-utils.js.map +1 -0
- package/dist/utils/template-manager.d.ts +7 -0
- package/dist/utils/template-manager.d.ts.map +1 -0
- package/dist/utils/template-manager.js +61 -0
- package/dist/utils/template-manager.js.map +1 -0
- package/dist/utils/validation.d.ts +6 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +32 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +60 -0
- package/templates/hello-world/README.md.template +100 -0
- package/templates/hello-world/_env.template +0 -0
- package/templates/hello-world/_gitignore +52 -0
- package/templates/hello-world/contracts/hello-world.compact.template +12 -0
- package/templates/hello-world/nodemon.json.template +7 -0
- package/templates/hello-world/package.json.template +49 -0
- package/templates/hello-world/src/cli.ts.template +194 -0
- package/templates/hello-world/src/deploy.ts.template +181 -0
- package/templates/hello-world/src/providers/midnight-providers.ts.template +46 -0
- package/templates/hello-world/src/utils/environment.ts.template +51 -0
- 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 @@
|
|
|
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 @@
|
|
|
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,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);
|