create-mn-app 0.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/README.md +239 -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 +186 -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 +99 -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 +51 -0
- package/templates/hello-world/src/check-balance.ts.template +107 -0
- package/templates/hello-world/src/cli.ts.template +194 -0
- package/templates/hello-world/src/deploy.ts.template +218 -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
|
+
{
|
|
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
|
+
"check-balance": "npm run build && node dist/check-balance.js",
|
|
17
|
+
"reset": "rm -rf contracts/managed deployment.json dist && npm run compile",
|
|
18
|
+
"validate": "tsc --noEmit && npm run compile",
|
|
19
|
+
"clean": "rm -rf dist contracts/managed deployment.json",
|
|
20
|
+
"proof-server": "docker run -p 6300:6300 midnightnetwork/proof-server -- 'midnight-proof-server --network testnet'",
|
|
21
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@midnight-ntwrk/compact-runtime": "^0.8.1",
|
|
25
|
+
"@midnight-ntwrk/ledger": "^4.0.0",
|
|
26
|
+
"@midnight-ntwrk/midnight-js-contracts": "2.0.2",
|
|
27
|
+
"@midnight-ntwrk/midnight-js-http-client-proof-provider": "2.0.2",
|
|
28
|
+
"@midnight-ntwrk/midnight-js-indexer-public-data-provider": "2.0.2",
|
|
29
|
+
"@midnight-ntwrk/midnight-js-level-private-state-provider": "2.0.2",
|
|
30
|
+
"@midnight-ntwrk/midnight-js-node-zk-config-provider": "2.0.2",
|
|
31
|
+
"@midnight-ntwrk/midnight-js-network-id": "2.0.2",
|
|
32
|
+
"@midnight-ntwrk/midnight-js-types": "2.0.2",
|
|
33
|
+
"@midnight-ntwrk/wallet": "5.0.0",
|
|
34
|
+
"@midnight-ntwrk/wallet-api": "5.0.0",
|
|
35
|
+
"@midnight-ntwrk/zswap": "^4.0.0",
|
|
36
|
+
"ws": "^8.18.3",
|
|
37
|
+
"dotenv": "^16.3.1",
|
|
38
|
+
"chalk": "^5.3.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^24.4.0",
|
|
42
|
+
"@types/ws": "^8.5.10",
|
|
43
|
+
"typescript": "^5.9.2",
|
|
44
|
+
"nodemon": "^3.0.1",
|
|
45
|
+
"concurrently": "^8.2.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=18.0.0"
|
|
49
|
+
},
|
|
50
|
+
"keywords": ["midnight", "blockchain", "zero-knowledge", "privacy"]
|
|
51
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { WalletBuilder } from "@midnight-ntwrk/wallet";
|
|
3
|
+
import {
|
|
4
|
+
NetworkId,
|
|
5
|
+
setNetworkId,
|
|
6
|
+
getZswapNetworkId,
|
|
7
|
+
getLedgerNetworkId,
|
|
8
|
+
} from "@midnight-ntwrk/midnight-js-network-id";
|
|
9
|
+
import { nativeToken } from "@midnight-ntwrk/ledger";
|
|
10
|
+
import { WebSocket } from "ws";
|
|
11
|
+
import * as Rx from "rxjs";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
import { EnvironmentManager } from "./utils/environment.js";
|
|
14
|
+
|
|
15
|
+
// Fix WebSocket for Node.js environment
|
|
16
|
+
// @ts-ignore
|
|
17
|
+
globalThis.WebSocket = WebSocket;
|
|
18
|
+
|
|
19
|
+
// Configure for Midnight Testnet
|
|
20
|
+
setNetworkId(NetworkId.TestNet);
|
|
21
|
+
|
|
22
|
+
async function checkBalance() {
|
|
23
|
+
try {
|
|
24
|
+
console.log();
|
|
25
|
+
console.log(chalk.blue.bold("━".repeat(60)));
|
|
26
|
+
console.log(chalk.blue.bold("🌙 Wallet Balance Checker"));
|
|
27
|
+
console.log(chalk.blue.bold("━".repeat(60)));
|
|
28
|
+
console.log();
|
|
29
|
+
|
|
30
|
+
const seed = process.env.WALLET_SEED;
|
|
31
|
+
if (!seed) {
|
|
32
|
+
throw new Error("WALLET_SEED not found in .env file");
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log(chalk.gray("Building wallet..."));
|
|
36
|
+
console.log();
|
|
37
|
+
|
|
38
|
+
// Get network configuration
|
|
39
|
+
const networkConfig = EnvironmentManager.getNetworkConfig();
|
|
40
|
+
|
|
41
|
+
// Build wallet from seed
|
|
42
|
+
const wallet = await WalletBuilder.buildFromSeed(
|
|
43
|
+
networkConfig.indexer,
|
|
44
|
+
networkConfig.indexerWS,
|
|
45
|
+
networkConfig.proofServer,
|
|
46
|
+
networkConfig.node,
|
|
47
|
+
seed,
|
|
48
|
+
getZswapNetworkId(),
|
|
49
|
+
"info"
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
wallet.start();
|
|
53
|
+
|
|
54
|
+
const state = await Rx.firstValueFrom(wallet.state());
|
|
55
|
+
|
|
56
|
+
console.log(chalk.cyan.bold("📍 Wallet Address:"));
|
|
57
|
+
console.log(chalk.white(` ${state.address}`));
|
|
58
|
+
console.log();
|
|
59
|
+
|
|
60
|
+
const balance = state.balances[nativeToken()] || 0n;
|
|
61
|
+
|
|
62
|
+
if (balance === 0n) {
|
|
63
|
+
console.log(chalk.yellow.bold("💰 Balance: ") + chalk.red.bold("0 DUST"));
|
|
64
|
+
console.log();
|
|
65
|
+
console.log(chalk.red("❌ No funds detected."));
|
|
66
|
+
console.log();
|
|
67
|
+
console.log(chalk.magenta.bold("━".repeat(60)));
|
|
68
|
+
console.log(chalk.magenta.bold("📝 How to Get Test Tokens:"));
|
|
69
|
+
console.log(chalk.magenta.bold("━".repeat(60)));
|
|
70
|
+
console.log();
|
|
71
|
+
console.log(chalk.white(" 1. ") + chalk.cyan("Visit: ") + chalk.underline("https://midnight.network/test-faucet"));
|
|
72
|
+
console.log(chalk.white(" 2. ") + chalk.cyan("Paste your wallet address (shown above)"));
|
|
73
|
+
console.log(chalk.white(" 3. ") + chalk.cyan("Request tokens from the faucet"));
|
|
74
|
+
console.log(chalk.white(" 4. ") + chalk.cyan("Wait 2-5 minutes for processing"));
|
|
75
|
+
console.log(chalk.white(" 5. ") + chalk.cyan("Run ") + chalk.yellow.bold("'npm run check-balance'") + chalk.cyan(" again"));
|
|
76
|
+
console.log();
|
|
77
|
+
console.log(chalk.gray("━".repeat(60)));
|
|
78
|
+
console.log(chalk.gray("💡 Tip: Faucet transactions typically take 2-5 minutes to process."));
|
|
79
|
+
console.log(chalk.gray("━".repeat(60)));
|
|
80
|
+
} else {
|
|
81
|
+
console.log(chalk.yellow.bold("💰 Balance: ") + chalk.green.bold(`${balance} DUST`));
|
|
82
|
+
console.log();
|
|
83
|
+
console.log(chalk.green.bold("✅ Wallet is funded and ready!"));
|
|
84
|
+
console.log();
|
|
85
|
+
console.log(chalk.magenta.bold("━".repeat(60)));
|
|
86
|
+
console.log(chalk.magenta.bold("🚀 Next Step:"));
|
|
87
|
+
console.log(chalk.magenta.bold("━".repeat(60)));
|
|
88
|
+
console.log();
|
|
89
|
+
console.log(chalk.cyan(" Deploy your contract with:"));
|
|
90
|
+
console.log(chalk.yellow.bold(" npm run deploy"));
|
|
91
|
+
console.log();
|
|
92
|
+
console.log(chalk.gray("━".repeat(60)));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log();
|
|
96
|
+
wallet.close();
|
|
97
|
+
process.exit(0);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
console.log();
|
|
100
|
+
console.log(chalk.red.bold("❌ Error checking balance:"));
|
|
101
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
102
|
+
console.log();
|
|
103
|
+
process.exit(1);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
checkBalance();
|
|
@@ -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.js";
|
|
19
|
+
import { EnvironmentManager } from "./utils/environment.js";
|
|
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);
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import "dotenv/config";
|
|
2
|
+
import { WalletBuilder } from "@midnight-ntwrk/wallet";
|
|
3
|
+
import { deployContract } from "@midnight-ntwrk/midnight-js-contracts";
|
|
4
|
+
import { httpClientProofProvider } from "@midnight-ntwrk/midnight-js-http-client-proof-provider";
|
|
5
|
+
import { indexerPublicDataProvider } from "@midnight-ntwrk/midnight-js-indexer-public-data-provider";
|
|
6
|
+
import { NodeZkConfigProvider } from "@midnight-ntwrk/midnight-js-node-zk-config-provider";
|
|
7
|
+
import { levelPrivateStateProvider } from "@midnight-ntwrk/midnight-js-level-private-state-provider";
|
|
8
|
+
import {
|
|
9
|
+
NetworkId,
|
|
10
|
+
setNetworkId,
|
|
11
|
+
getZswapNetworkId,
|
|
12
|
+
getLedgerNetworkId,
|
|
13
|
+
} from "@midnight-ntwrk/midnight-js-network-id";
|
|
14
|
+
import { createBalancedTx } from "@midnight-ntwrk/midnight-js-types";
|
|
15
|
+
import { nativeToken, Transaction } from "@midnight-ntwrk/ledger";
|
|
16
|
+
import { Transaction as ZswapTransaction } from "@midnight-ntwrk/zswap";
|
|
17
|
+
import { WebSocket } from "ws";
|
|
18
|
+
import * as fs from "fs";
|
|
19
|
+
import * as path from "path";
|
|
20
|
+
import * as Rx from "rxjs";
|
|
21
|
+
import { type Wallet } from "@midnight-ntwrk/wallet-api";
|
|
22
|
+
import chalk from "chalk";
|
|
23
|
+
import { MidnightProviders } from "./providers/midnight-providers.js";
|
|
24
|
+
import { EnvironmentManager } from "./utils/environment.js";
|
|
25
|
+
|
|
26
|
+
// Fix WebSocket for Node.js environment
|
|
27
|
+
// @ts-ignore
|
|
28
|
+
globalThis.WebSocket = WebSocket;
|
|
29
|
+
|
|
30
|
+
// Configure for Midnight Testnet
|
|
31
|
+
setNetworkId(NetworkId.TestNet);
|
|
32
|
+
|
|
33
|
+
const waitForFunds = (wallet: Wallet) =>
|
|
34
|
+
Rx.firstValueFrom(
|
|
35
|
+
wallet.state().pipe(
|
|
36
|
+
Rx.tap((state) => {
|
|
37
|
+
if (state.syncProgress) {
|
|
38
|
+
console.log(
|
|
39
|
+
`Sync progress: synced=${state.syncProgress.synced}, sourceGap=${state.syncProgress.lag.sourceGap}, applyGap=${state.syncProgress.lag.applyGap}`
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}),
|
|
43
|
+
Rx.filter((state) => state.syncProgress?.synced === true),
|
|
44
|
+
Rx.map((s) => s.balances[nativeToken()] ?? 0n),
|
|
45
|
+
Rx.filter((balance) => balance > 0n),
|
|
46
|
+
Rx.tap((balance) => console.log(`Wallet funded with balance: ${balance}`))
|
|
47
|
+
)
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
async function main() {
|
|
51
|
+
console.log();
|
|
52
|
+
console.log(chalk.blue.bold("━".repeat(60)));
|
|
53
|
+
console.log(chalk.blue.bold("🌙 {{projectName}} Deployment"));
|
|
54
|
+
console.log(chalk.blue.bold("━".repeat(60)));
|
|
55
|
+
console.log();
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
// Validate environment
|
|
59
|
+
EnvironmentManager.validateEnvironment();
|
|
60
|
+
|
|
61
|
+
const networkConfig = EnvironmentManager.getNetworkConfig();
|
|
62
|
+
const contractName = process.env.CONTRACT_NAME || "hello-world";
|
|
63
|
+
|
|
64
|
+
// Check if contract is compiled
|
|
65
|
+
if (!EnvironmentManager.checkContractCompiled(contractName)) {
|
|
66
|
+
console.error("❌ Contract not compiled! Run: npm run compile");
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const walletSeed = process.env.WALLET_SEED!;
|
|
71
|
+
|
|
72
|
+
// Build wallet from seed
|
|
73
|
+
console.log("Building wallet...");
|
|
74
|
+
const wallet = await WalletBuilder.buildFromSeed(
|
|
75
|
+
networkConfig.indexer,
|
|
76
|
+
networkConfig.indexerWS,
|
|
77
|
+
networkConfig.proofServer,
|
|
78
|
+
networkConfig.node,
|
|
79
|
+
walletSeed,
|
|
80
|
+
getZswapNetworkId(),
|
|
81
|
+
"info"
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
wallet.start();
|
|
85
|
+
const state = await Rx.firstValueFrom(wallet.state());
|
|
86
|
+
|
|
87
|
+
console.log(chalk.cyan.bold("📍 Wallet Address:"));
|
|
88
|
+
console.log(chalk.white(` ${state.address}`));
|
|
89
|
+
console.log();
|
|
90
|
+
|
|
91
|
+
let balance = state.balances[nativeToken()] || 0n;
|
|
92
|
+
|
|
93
|
+
if (balance === 0n) {
|
|
94
|
+
console.log(chalk.yellow.bold("💰 Balance: ") + chalk.red.bold("0 DUST"));
|
|
95
|
+
console.log();
|
|
96
|
+
console.log(chalk.red.bold("❌ Wallet needs funding to deploy contracts."));
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(chalk.magenta.bold("━".repeat(60)));
|
|
99
|
+
console.log(chalk.magenta.bold("📝 How to Get Test Tokens:"));
|
|
100
|
+
console.log(chalk.magenta.bold("━".repeat(60)));
|
|
101
|
+
console.log();
|
|
102
|
+
console.log(chalk.white(" 1. ") + chalk.cyan("Visit: ") + chalk.underline("https://midnight.network/test-faucet"));
|
|
103
|
+
console.log(chalk.white(" 2. ") + chalk.cyan("Paste your wallet address (shown above)"));
|
|
104
|
+
console.log(chalk.white(" 3. ") + chalk.cyan("Request tokens from the faucet"));
|
|
105
|
+
console.log();
|
|
106
|
+
console.log(chalk.gray("━".repeat(60)));
|
|
107
|
+
console.log(chalk.gray("⏱️ Faucet transactions can take 2-5 minutes to process."));
|
|
108
|
+
console.log(chalk.gray("━".repeat(60)));
|
|
109
|
+
console.log();
|
|
110
|
+
console.log(chalk.yellow.bold("💡 Options while waiting:"));
|
|
111
|
+
console.log(chalk.white(" • ") + chalk.cyan("Let this script wait (it will auto-detect when funds arrive)"));
|
|
112
|
+
console.log(chalk.white(" • ") + chalk.cyan("OR press ") + chalk.yellow("Ctrl+C") + chalk.cyan(" to stop, then check balance with:"));
|
|
113
|
+
console.log(chalk.yellow.bold(" npm run check-balance"));
|
|
114
|
+
console.log(chalk.white(" • ") + chalk.cyan("Once funded, run: ") + chalk.yellow.bold("npm run deploy"));
|
|
115
|
+
console.log();
|
|
116
|
+
console.log(chalk.blue("⏳ Waiting to receive tokens..."));
|
|
117
|
+
balance = await waitForFunds(wallet);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
console.log(chalk.yellow.bold("💰 Balance: ") + chalk.green.bold(`${balance} DUST`));
|
|
121
|
+
console.log();
|
|
122
|
+
|
|
123
|
+
// Load compiled contract files
|
|
124
|
+
console.log(chalk.gray("📦 Loading contract..."));
|
|
125
|
+
const contractPath = path.join(process.cwd(), "contracts");
|
|
126
|
+
const contractModulePath = path.join(
|
|
127
|
+
contractPath,
|
|
128
|
+
"managed",
|
|
129
|
+
contractName,
|
|
130
|
+
"contract",
|
|
131
|
+
"index.cjs"
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
const HelloWorldModule = await import(contractModulePath);
|
|
135
|
+
const contractInstance = new HelloWorldModule.Contract({});
|
|
136
|
+
|
|
137
|
+
// Create wallet provider for transactions
|
|
138
|
+
const walletState = await Rx.firstValueFrom(wallet.state());
|
|
139
|
+
|
|
140
|
+
const walletProvider = {
|
|
141
|
+
coinPublicKey: walletState.coinPublicKey,
|
|
142
|
+
encryptionPublicKey: walletState.encryptionPublicKey,
|
|
143
|
+
balanceTx(tx: any, newCoins: any) {
|
|
144
|
+
return wallet
|
|
145
|
+
.balanceTransaction(
|
|
146
|
+
ZswapTransaction.deserialize(
|
|
147
|
+
tx.serialize(getLedgerNetworkId()),
|
|
148
|
+
getZswapNetworkId()
|
|
149
|
+
),
|
|
150
|
+
newCoins
|
|
151
|
+
)
|
|
152
|
+
.then((tx) => wallet.proveTransaction(tx))
|
|
153
|
+
.then((zswapTx) =>
|
|
154
|
+
Transaction.deserialize(
|
|
155
|
+
zswapTx.serialize(getZswapNetworkId()),
|
|
156
|
+
getLedgerNetworkId()
|
|
157
|
+
)
|
|
158
|
+
)
|
|
159
|
+
.then(createBalancedTx);
|
|
160
|
+
},
|
|
161
|
+
submitTx(tx: any) {
|
|
162
|
+
return wallet.submitTransaction(tx);
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
// Configure all required providers
|
|
167
|
+
console.log("Setting up providers...");
|
|
168
|
+
const providers = MidnightProviders.create({
|
|
169
|
+
contractName,
|
|
170
|
+
walletProvider,
|
|
171
|
+
networkConfig,
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// Deploy contract to blockchain
|
|
175
|
+
console.log(chalk.blue("🚀 Deploying contract (30-60 seconds)..."));
|
|
176
|
+
console.log();
|
|
177
|
+
|
|
178
|
+
const deployed = await deployContract(providers, {
|
|
179
|
+
contract: contractInstance,
|
|
180
|
+
privateStateId: "helloWorldState",
|
|
181
|
+
initialPrivateState: {},
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
const contractAddress = deployed.deployTxData.public.contractAddress;
|
|
185
|
+
|
|
186
|
+
// Save deployment information
|
|
187
|
+
console.log();
|
|
188
|
+
console.log(chalk.green.bold("━".repeat(60)));
|
|
189
|
+
console.log(chalk.green.bold("🎉 CONTRACT DEPLOYED SUCCESSFULLY!"));
|
|
190
|
+
console.log(chalk.green.bold("━".repeat(60)));
|
|
191
|
+
console.log();
|
|
192
|
+
console.log(chalk.cyan.bold("📍 Contract Address:"));
|
|
193
|
+
console.log(chalk.white(` ${contractAddress}`));
|
|
194
|
+
console.log();
|
|
195
|
+
|
|
196
|
+
const info = {
|
|
197
|
+
contractAddress,
|
|
198
|
+
deployedAt: new Date().toISOString(),
|
|
199
|
+
network: networkConfig.name,
|
|
200
|
+
contractName,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
fs.writeFileSync("deployment.json", JSON.stringify(info, null, 2));
|
|
204
|
+
console.log(chalk.gray("✅ Saved to deployment.json"));
|
|
205
|
+
console.log();
|
|
206
|
+
|
|
207
|
+
// Close wallet connection
|
|
208
|
+
await wallet.close();
|
|
209
|
+
} catch (error) {
|
|
210
|
+
console.log();
|
|
211
|
+
console.log(chalk.red.bold("❌ Deployment Failed:"));
|
|
212
|
+
console.error(chalk.red(error instanceof Error ? error.message : String(error)));
|
|
213
|
+
console.log();
|
|
214
|
+
process.exit(1);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import path from "path";
|
|
2
|
+
import { levelPrivateStateProvider } from "@midnight-ntwrk/midnight-js-level-private-state-provider";
|
|
3
|
+
import { indexerPublicDataProvider } from "@midnight-ntwrk/midnight-js-indexer-public-data-provider";
|
|
4
|
+
import { NodeZkConfigProvider } from "@midnight-ntwrk/midnight-js-node-zk-config-provider";
|
|
5
|
+
import { httpClientProofProvider } from "@midnight-ntwrk/midnight-js-http-client-proof-provider";
|
|
6
|
+
|
|
7
|
+
export interface NetworkConfig {
|
|
8
|
+
indexer: string;
|
|
9
|
+
indexerWS: string;
|
|
10
|
+
node: string;
|
|
11
|
+
proofServer: string;
|
|
12
|
+
name: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface ProviderConfig {
|
|
16
|
+
contractName: string;
|
|
17
|
+
walletProvider: any;
|
|
18
|
+
networkConfig: NetworkConfig;
|
|
19
|
+
privateStateStoreName?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class MidnightProviders {
|
|
23
|
+
static create(config: ProviderConfig) {
|
|
24
|
+
const contractPath = path.join(process.cwd(), "contracts");
|
|
25
|
+
const zkConfigPath = path.join(
|
|
26
|
+
contractPath,
|
|
27
|
+
"managed",
|
|
28
|
+
config.contractName
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
privateStateProvider: levelPrivateStateProvider({
|
|
33
|
+
privateStateStoreName:
|
|
34
|
+
config.privateStateStoreName || `${config.contractName}-state`,
|
|
35
|
+
}),
|
|
36
|
+
publicDataProvider: indexerPublicDataProvider(
|
|
37
|
+
config.networkConfig.indexer,
|
|
38
|
+
config.networkConfig.indexerWS
|
|
39
|
+
),
|
|
40
|
+
zkConfigProvider: new NodeZkConfigProvider(zkConfigPath),
|
|
41
|
+
proofProvider: httpClientProofProvider(config.networkConfig.proofServer),
|
|
42
|
+
walletProvider: config.walletProvider,
|
|
43
|
+
midnightProvider: config.walletProvider,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { NetworkConfig } from "../providers/midnight-providers.js";
|
|
4
|
+
|
|
5
|
+
export class EnvironmentManager {
|
|
6
|
+
static getNetworkConfig(): NetworkConfig {
|
|
7
|
+
const network = process.env.MIDNIGHT_NETWORK || "testnet";
|
|
8
|
+
|
|
9
|
+
const networks = {
|
|
10
|
+
testnet: {
|
|
11
|
+
indexer: "https://indexer.testnet-02.midnight.network/api/v1/graphql",
|
|
12
|
+
indexerWS:
|
|
13
|
+
"wss://indexer.testnet-02.midnight.network/api/v1/graphql/ws",
|
|
14
|
+
node: "https://rpc.testnet-02.midnight.network",
|
|
15
|
+
proofServer: process.env.PROOF_SERVER_URL || "http://127.0.0.1:6300",
|
|
16
|
+
name: "Testnet",
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
return networks[network as keyof typeof networks] || networks.testnet;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static validateEnvironment(): void {
|
|
24
|
+
const required = ["WALLET_SEED"];
|
|
25
|
+
const missing = required.filter((key) => !process.env[key]);
|
|
26
|
+
|
|
27
|
+
if (missing.length > 0) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`Missing required environment variables: ${missing.join(", ")}`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const walletSeed = process.env.WALLET_SEED!;
|
|
34
|
+
if (!/^[a-fA-F0-9]{64}$/.test(walletSeed)) {
|
|
35
|
+
throw new Error("WALLET_SEED must be a 64-character hexadecimal string");
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static checkContractCompiled(contractName: string): boolean {
|
|
40
|
+
const contractPath = path.join(
|
|
41
|
+
process.cwd(),
|
|
42
|
+
"contracts",
|
|
43
|
+
"managed",
|
|
44
|
+
contractName
|
|
45
|
+
);
|
|
46
|
+
const keysPath = path.join(contractPath, "keys");
|
|
47
|
+
const contractModulePath = path.join(contractPath, "contract", "index.cjs");
|
|
48
|
+
|
|
49
|
+
return fs.existsSync(keysPath) && fs.existsSync(contractModulePath);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "node",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"resolveJsonModule": true,
|
|
13
|
+
"allowSyntheticDefaultImports": true,
|
|
14
|
+
"declaration": true,
|
|
15
|
+
"declarationMap": true,
|
|
16
|
+
"sourceMap": true
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*"],
|
|
19
|
+
"exclude": ["node_modules", "dist", "contracts/managed"]
|
|
20
|
+
}
|