create-mn-app 0.3.28 → 0.4.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 +75 -89
- package/dist/utils/templates.js +4 -4
- package/package.json +1 -1
- package/templates/hello-world/README.md.template +145 -60
- package/templates/hello-world/_gitignore +3 -1
- package/templates/hello-world/contracts/hello-world.compact.template +1 -1
- package/templates/hello-world/docker-compose.yml.template +66 -5
- package/templates/hello-world/package.json.template +17 -15
- package/templates/hello-world/scripts/e2e-check.ts.template +158 -0
- package/templates/hello-world/src/check-balance.ts.template +23 -36
- package/templates/hello-world/src/cli.ts.template +34 -32
- package/templates/hello-world/src/deploy.ts.template +241 -310
- package/templates/hello-world/src/network.ts +320 -0
- package/templates/hello-world/src/setup.ts.template +37 -0
- package/templates/hello-world/tsconfig.json.template +1 -1
- package/dist/installers/wallet-generator.d.ts +0 -4
- package/dist/installers/wallet-generator.d.ts.map +0 -1
- package/dist/installers/wallet-generator.js +0 -78
- package/dist/installers/wallet-generator.js.map +0 -1
- package/dist/test.d.ts +0 -2
- package/dist/test.d.ts.map +0 -1
- package/dist/test.js +0 -65
- package/dist/test.js.map +0 -1
|
@@ -8,40 +8,42 @@
|
|
|
8
8
|
"scripts": {
|
|
9
9
|
"compile": "compact compile contracts/hello-world.compact contracts/managed/hello-world",
|
|
10
10
|
"build": "npx tsc --noEmit || true",
|
|
11
|
-
"setup": "
|
|
11
|
+
"setup": "npx tsx src/setup.ts",
|
|
12
12
|
"deploy": "npx tsx src/deploy.ts",
|
|
13
13
|
"cli": "npx tsx src/cli.ts",
|
|
14
14
|
"check-balance": "npx tsx src/check-balance.ts",
|
|
15
|
+
"network": "npx tsx src/network.ts",
|
|
15
16
|
"proof-server:start": "docker compose up -d",
|
|
16
17
|
"proof-server:stop": "docker compose down",
|
|
17
|
-
"clean": "rm -rf contracts/managed
|
|
18
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
18
|
+
"clean": "rm -rf contracts/managed .midnight-state.json",
|
|
19
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
20
|
+
"test:e2e": "tsx scripts/e2e-check.ts"
|
|
19
21
|
},
|
|
20
22
|
"dependencies": {
|
|
21
23
|
"@midnight-ntwrk/compact-js": "2.5.0",
|
|
22
|
-
"rxjs": "^7.8.
|
|
23
|
-
"@midnight-ntwrk/compact-runtime": "0.
|
|
24
|
+
"rxjs": "^7.8.2",
|
|
25
|
+
"@midnight-ntwrk/compact-runtime": "0.16.0",
|
|
24
26
|
"@midnight-ntwrk/ledger-v8": "8.0.3",
|
|
25
|
-
"@midnight-ntwrk/midnight-js-contracts": "4.0.
|
|
26
|
-
"@midnight-ntwrk/midnight-js-http-client-proof-provider": "4.0.
|
|
27
|
-
"@midnight-ntwrk/midnight-js-indexer-public-data-provider": "4.0.
|
|
28
|
-
"@midnight-ntwrk/midnight-js-level-private-state-provider": "4.0.
|
|
29
|
-
"@midnight-ntwrk/midnight-js-network-id": "4.0.
|
|
30
|
-
"@midnight-ntwrk/midnight-js-node-zk-config-provider": "4.0.
|
|
31
|
-
"@midnight-ntwrk/midnight-js-types": "4.0.
|
|
32
|
-
"@midnight-ntwrk/midnight-js-utils": "4.0.
|
|
27
|
+
"@midnight-ntwrk/midnight-js-contracts": "4.0.4",
|
|
28
|
+
"@midnight-ntwrk/midnight-js-http-client-proof-provider": "4.0.4",
|
|
29
|
+
"@midnight-ntwrk/midnight-js-indexer-public-data-provider": "4.0.4",
|
|
30
|
+
"@midnight-ntwrk/midnight-js-level-private-state-provider": "4.0.4",
|
|
31
|
+
"@midnight-ntwrk/midnight-js-network-id": "4.0.4",
|
|
32
|
+
"@midnight-ntwrk/midnight-js-node-zk-config-provider": "4.0.4",
|
|
33
|
+
"@midnight-ntwrk/midnight-js-types": "4.0.4",
|
|
34
|
+
"@midnight-ntwrk/midnight-js-utils": "4.0.4",
|
|
33
35
|
"@midnight-ntwrk/wallet-sdk-dust-wallet": "3.0.0",
|
|
34
36
|
"@midnight-ntwrk/wallet-sdk-facade": "3.0.0",
|
|
35
37
|
"@midnight-ntwrk/wallet-sdk-hd": "3.0.1",
|
|
36
38
|
"@midnight-ntwrk/wallet-sdk-shielded": "2.1.0",
|
|
37
39
|
"@midnight-ntwrk/wallet-sdk-unshielded-wallet": "2.1.0",
|
|
38
|
-
"ws": "^8.
|
|
40
|
+
"ws": "^8.20.0"
|
|
39
41
|
},
|
|
40
42
|
"devDependencies": {
|
|
41
43
|
"@types/node": "^22.0.0",
|
|
42
44
|
"@types/ws": "^8.18.1",
|
|
43
45
|
"tsx": "^4.21.0",
|
|
44
|
-
"typescript": "^
|
|
46
|
+
"typescript": "^6.0.3"
|
|
45
47
|
},
|
|
46
48
|
"engines": {
|
|
47
49
|
"node": ">=22.0.0"
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* End-to-end smoke check for {{projectName}}.
|
|
3
|
+
*
|
|
4
|
+
* Reconnects to the deployed contract, reads its ledger state, and exits 0
|
|
5
|
+
* on success. Used by `npm run test:e2e` and by the project's CI workflows.
|
|
6
|
+
*/
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
10
|
+
import { WebSocket } from 'ws';
|
|
11
|
+
import { Buffer } from 'buffer';
|
|
12
|
+
|
|
13
|
+
import { findDeployedContract } from '@midnight-ntwrk/midnight-js-contracts';
|
|
14
|
+
import { httpClientProofProvider } from '@midnight-ntwrk/midnight-js-http-client-proof-provider';
|
|
15
|
+
import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-public-data-provider';
|
|
16
|
+
import { levelPrivateStateProvider } from '@midnight-ntwrk/midnight-js-level-private-state-provider';
|
|
17
|
+
import { NodeZkConfigProvider } from '@midnight-ntwrk/midnight-js-node-zk-config-provider';
|
|
18
|
+
import { setNetworkId, getNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
19
|
+
import { resolveNetwork, getOrCreateSeed, getDeployment } from '../src/network';
|
|
20
|
+
import * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
21
|
+
import { WalletFacade } from '@midnight-ntwrk/wallet-sdk-facade';
|
|
22
|
+
import { DustWallet } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
|
|
23
|
+
import { HDWallet, Roles } from '@midnight-ntwrk/wallet-sdk-hd';
|
|
24
|
+
import { ShieldedWallet } from '@midnight-ntwrk/wallet-sdk-shielded';
|
|
25
|
+
import { createKeystore, NoOpTransactionHistoryStorage, PublicKey, UnshieldedWallet } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
|
|
26
|
+
import { CompiledContract } from '@midnight-ntwrk/compact-js';
|
|
27
|
+
|
|
28
|
+
// @ts-expect-error wallet sync requires WebSocket
|
|
29
|
+
globalThis.WebSocket = WebSocket;
|
|
30
|
+
|
|
31
|
+
// ─── Network configuration ─────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
const { network, config: networkConfig } = resolveNetwork();
|
|
34
|
+
setNetworkId(networkConfig.networkId);
|
|
35
|
+
const SEED = getOrCreateSeed(network);
|
|
36
|
+
|
|
37
|
+
function fail(msg: string): never {
|
|
38
|
+
console.error(`❌ e2e-check failed: ${msg}`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isHexAddress(s: unknown): s is string {
|
|
43
|
+
return typeof s === 'string' && /^[0-9a-fA-F]+$/.test(s) && s.length >= 32;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function main() {
|
|
47
|
+
// 1. Deployment sanity
|
|
48
|
+
const deployment = getDeployment(network);
|
|
49
|
+
if (!deployment) {
|
|
50
|
+
console.error(`No deploy on file for network ${network}.`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
if (!isHexAddress(deployment.address)) {
|
|
54
|
+
fail(`Deployment address missing or invalid: ${JSON.stringify(deployment, null, 2)}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// 2. Build wallet (genesis seed) and providers
|
|
58
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
59
|
+
const zkConfigPath = path.resolve(__dirname, '..', 'contracts', 'managed', 'hello-world');
|
|
60
|
+
const contractPath = path.join(zkConfigPath, 'contract', 'index.js');
|
|
61
|
+
if (!fs.existsSync(contractPath)) fail('Compiled contract missing — run `npm run compile`.');
|
|
62
|
+
const HelloWorld = await import(pathToFileURL(contractPath).href);
|
|
63
|
+
const compiledContract = CompiledContract.make('hello-world', HelloWorld.Contract).pipe(
|
|
64
|
+
CompiledContract.withVacantWitnesses,
|
|
65
|
+
CompiledContract.withCompiledFileAssets(zkConfigPath),
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
const hd = HDWallet.fromSeed(Buffer.from(SEED, 'hex'));
|
|
69
|
+
if (hd.type !== 'seedOk') fail('Bad seed.');
|
|
70
|
+
const derived = hd.hdWallet
|
|
71
|
+
.selectAccount(0)
|
|
72
|
+
.selectRoles([Roles.Zswap, Roles.NightExternal, Roles.Dust])
|
|
73
|
+
.deriveKeysAt(0);
|
|
74
|
+
if (derived.type !== 'keysDerived') fail('Key derivation failed.');
|
|
75
|
+
hd.hdWallet.clear();
|
|
76
|
+
|
|
77
|
+
const networkId = getNetworkId();
|
|
78
|
+
const shieldedSecretKeys = ledger.ZswapSecretKeys.fromSeed(derived.keys[Roles.Zswap]);
|
|
79
|
+
const dustSecretKey = ledger.DustSecretKey.fromSeed(derived.keys[Roles.Dust]);
|
|
80
|
+
const unshieldedKeystore = createKeystore(derived.keys[Roles.NightExternal], networkId);
|
|
81
|
+
|
|
82
|
+
const wallet = await WalletFacade.init({
|
|
83
|
+
configuration: {
|
|
84
|
+
networkId,
|
|
85
|
+
indexerClientConnection: { indexerHttpUrl: networkConfig.indexer, indexerWsUrl: networkConfig.indexerWS },
|
|
86
|
+
provingServerUrl: new URL(networkConfig.proofServer),
|
|
87
|
+
relayURL: new URL(networkConfig.node.replace(/^http/, 'ws')),
|
|
88
|
+
txHistoryStorage: new NoOpTransactionHistoryStorage(),
|
|
89
|
+
costParameters: { additionalFeeOverhead: 300_000_000_000_000n, feeBlocksMargin: 5 },
|
|
90
|
+
},
|
|
91
|
+
shielded: async (c) => ShieldedWallet(c).startWithSecretKeys(shieldedSecretKeys),
|
|
92
|
+
unshielded: async (c) =>
|
|
93
|
+
UnshieldedWallet(c).startWithPublicKey(PublicKey.fromKeyStore(unshieldedKeystore)),
|
|
94
|
+
dust: async (c) =>
|
|
95
|
+
DustWallet(c).startWithSecretKey(dustSecretKey, ledger.LedgerParameters.initialParameters().dust),
|
|
96
|
+
});
|
|
97
|
+
await wallet.start(shieldedSecretKeys, dustSecretKey);
|
|
98
|
+
const state = await wallet.waitForSyncedState();
|
|
99
|
+
|
|
100
|
+
const zkConfigProvider = new NodeZkConfigProvider(zkConfigPath);
|
|
101
|
+
const walletProvider = {
|
|
102
|
+
getCoinPublicKey: () => state.shielded.coinPublicKey.toHexString(),
|
|
103
|
+
getEncryptionPublicKey: () => state.shielded.encryptionPublicKey.toHexString(),
|
|
104
|
+
async balanceTx() {
|
|
105
|
+
throw new Error('e2e-check is read-only and should not balance transactions');
|
|
106
|
+
},
|
|
107
|
+
submitTx() {
|
|
108
|
+
throw new Error('e2e-check is read-only and should not submit transactions');
|
|
109
|
+
},
|
|
110
|
+
} as any;
|
|
111
|
+
|
|
112
|
+
const providers = {
|
|
113
|
+
privateStateProvider: levelPrivateStateProvider({
|
|
114
|
+
privateStateStoreName: 'hello-world-state',
|
|
115
|
+
accountId: unshieldedKeystore.getBech32Address().toString(),
|
|
116
|
+
// SDK requires ≥16 chars. e2e-check is read-only so we don't expose
|
|
117
|
+
// the env-var override here — match the deploy script's local-devnet default.
|
|
118
|
+
privateStoragePasswordProvider: () => 'Local-Devnet-Development-Placeholder-1',
|
|
119
|
+
}),
|
|
120
|
+
publicDataProvider: indexerPublicDataProvider(networkConfig.indexer, networkConfig.indexerWS),
|
|
121
|
+
zkConfigProvider,
|
|
122
|
+
proofProvider: httpClientProofProvider(networkConfig.proofServer, zkConfigProvider),
|
|
123
|
+
walletProvider,
|
|
124
|
+
midnightProvider: walletProvider,
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
// 3. Reconnect to the deployed contract — proves callTx interface is wired
|
|
128
|
+
try {
|
|
129
|
+
await findDeployedContract(providers, {
|
|
130
|
+
contractAddress: deployment.address,
|
|
131
|
+
compiledContract: compiledContract as any,
|
|
132
|
+
});
|
|
133
|
+
} catch (err: any) {
|
|
134
|
+
await wallet.stop();
|
|
135
|
+
fail(`findDeployedContract threw: ${err?.message ?? err}`);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// 4. Read the on-chain contract state via the public data provider — proves
|
|
139
|
+
// the contract is indexed and queryable on the chain itself, not just that
|
|
140
|
+
// we know how to construct the local handle.
|
|
141
|
+
const onChainState = await providers.publicDataProvider.queryContractState(deployment.address);
|
|
142
|
+
if (!onChainState) {
|
|
143
|
+
await wallet.stop();
|
|
144
|
+
fail(`queryContractState returned null for ${deployment.address}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
console.log(`✅ e2e-check passed`);
|
|
148
|
+
console.log(` contractAddress: ${deployment.address}`);
|
|
149
|
+
console.log(` network: ${network}`);
|
|
150
|
+
|
|
151
|
+
await wallet.stop();
|
|
152
|
+
process.exit(0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
main().catch(async (err) => {
|
|
156
|
+
console.error(err);
|
|
157
|
+
process.exit(1);
|
|
158
|
+
});
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Check wallet balance on Midnight
|
|
2
|
+
* Check wallet balance on the local Midnight devnet
|
|
3
3
|
*/
|
|
4
|
-
import * as fs from 'node:fs';
|
|
5
4
|
import { WebSocket } from 'ws';
|
|
6
5
|
import * as Rx from 'rxjs';
|
|
7
6
|
import { Buffer } from 'buffer';
|
|
@@ -14,23 +13,18 @@ import { WalletFacade } from '@midnight-ntwrk/wallet-sdk-facade';
|
|
|
14
13
|
import { DustWallet } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
|
|
15
14
|
import { HDWallet, Roles } from '@midnight-ntwrk/wallet-sdk-hd';
|
|
16
15
|
import { ShieldedWallet } from '@midnight-ntwrk/wallet-sdk-shielded';
|
|
17
|
-
import { createKeystore,
|
|
16
|
+
import { createKeystore, NoOpTransactionHistoryStorage, PublicKey, UnshieldedWallet } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
|
|
17
|
+
import { resolveNetwork, getOrCreateSeed } from './network';
|
|
18
18
|
|
|
19
19
|
// Enable WebSocket for GraphQL subscriptions
|
|
20
20
|
// @ts-expect-error Required for wallet sync
|
|
21
21
|
globalThis.WebSocket = WebSocket;
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
setNetworkId('preprod');
|
|
23
|
+
// ─── Network configuration ─────────────────────────────────────────────────────
|
|
25
24
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
indexerWS: 'wss://indexer.preprod.midnight.network/api/v3/graphql/ws',
|
|
30
|
-
node: 'https://rpc.preprod.midnight.network',
|
|
31
|
-
proofServer: 'http://127.0.0.1:6300',
|
|
32
|
-
faucetUrl: 'https://faucet.preprod.midnight.network/',
|
|
33
|
-
};
|
|
25
|
+
const { network, config: networkConfig } = resolveNetwork();
|
|
26
|
+
setNetworkId(networkConfig.networkId);
|
|
27
|
+
const SEED = getOrCreateSeed(network);
|
|
34
28
|
|
|
35
29
|
// ─── Wallet Functions ──────────────────────────────────────────────────────────
|
|
36
30
|
|
|
@@ -52,10 +46,10 @@ async function createWallet(seed: string) {
|
|
|
52
46
|
|
|
53
47
|
const walletConfig = {
|
|
54
48
|
networkId,
|
|
55
|
-
indexerClientConnection: { indexerHttpUrl:
|
|
56
|
-
provingServerUrl: new URL(
|
|
57
|
-
relayURL: new URL(
|
|
58
|
-
txHistoryStorage: new
|
|
49
|
+
indexerClientConnection: { indexerHttpUrl: networkConfig.indexer, indexerWsUrl: networkConfig.indexerWS },
|
|
50
|
+
provingServerUrl: new URL(networkConfig.proofServer),
|
|
51
|
+
relayURL: new URL(networkConfig.node.replace(/^http/, 'ws')),
|
|
52
|
+
txHistoryStorage: new NoOpTransactionHistoryStorage(),
|
|
59
53
|
costParameters: { additionalFeeOverhead: 300_000_000_000_000n, feeBlocksMargin: 5 },
|
|
60
54
|
};
|
|
61
55
|
|
|
@@ -78,19 +72,7 @@ async function main() {
|
|
|
78
72
|
console.log('║ Wallet Balance Checker ║');
|
|
79
73
|
console.log('╚══════════════════════════════════════════════════════════════╝\n');
|
|
80
74
|
|
|
81
|
-
|
|
82
|
-
if (!fs.existsSync('deployment.json')) {
|
|
83
|
-
console.error('❌ No deployment.json found! Run: npm run deploy\n');
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const deployment = JSON.parse(fs.readFileSync('deployment.json', 'utf-8'));
|
|
88
|
-
|
|
89
|
-
if (!fs.existsSync('.midnight-seed')) {
|
|
90
|
-
console.error('❌ No .midnight-seed file found! Run: npm run deploy\n');
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
const seed = fs.readFileSync('.midnight-seed', 'utf-8').trim();
|
|
75
|
+
const seed = SEED;
|
|
94
76
|
|
|
95
77
|
try {
|
|
96
78
|
console.log(' Building wallet...');
|
|
@@ -114,18 +96,23 @@ async function main() {
|
|
|
114
96
|
|
|
115
97
|
console.log('\n─── Wallet Details ─────────────────────────────────────────────\n');
|
|
116
98
|
console.log(` Address: ${address}`);
|
|
117
|
-
console.log(` Network:
|
|
99
|
+
console.log(` Network: ${networkConfig.networkId}\n`);
|
|
118
100
|
|
|
119
101
|
console.log('─── Balances ───────────────────────────────────────────────────\n');
|
|
120
102
|
console.log(` tNight: ${tNightBalance.toLocaleString()}`);
|
|
121
103
|
console.log(` DUST: ${dustBalance.toLocaleString()}\n`);
|
|
122
104
|
|
|
123
105
|
if (tNightBalance === 0n) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
106
|
+
if (network === 'undeployed') {
|
|
107
|
+
console.log(' ⚠ Wallet has no tNight. Make sure the local devnet is running');
|
|
108
|
+
console.log(' (npm run setup) — the genesis seed is pre-funded by the dev preset.\n');
|
|
109
|
+
} else if (networkConfig.faucet) {
|
|
110
|
+
console.log(` ⚠ Wallet has no tNight. Fund it from the faucet:`);
|
|
111
|
+
console.log(` ${networkConfig.faucet}`);
|
|
112
|
+
console.log(` Wallet address: ${address}\n`);
|
|
113
|
+
} else {
|
|
114
|
+
console.log(' ⚠ Wallet has no tNight.\n');
|
|
115
|
+
}
|
|
129
116
|
} else {
|
|
130
117
|
console.log(' ✅ Wallet is funded and ready!\n');
|
|
131
118
|
}
|
|
@@ -17,29 +17,23 @@ import { indexerPublicDataProvider } from '@midnight-ntwrk/midnight-js-indexer-p
|
|
|
17
17
|
import { levelPrivateStateProvider } from '@midnight-ntwrk/midnight-js-level-private-state-provider';
|
|
18
18
|
import { NodeZkConfigProvider } from '@midnight-ntwrk/midnight-js-node-zk-config-provider';
|
|
19
19
|
import { setNetworkId, getNetworkId } from '@midnight-ntwrk/midnight-js-network-id';
|
|
20
|
+
import { resolveNetwork, getOrCreateSeed, getDeployment } from './network';
|
|
20
21
|
import * as ledger from '@midnight-ntwrk/ledger-v8';
|
|
21
22
|
import { unshieldedToken } from '@midnight-ntwrk/ledger-v8';
|
|
22
23
|
import { WalletFacade } from '@midnight-ntwrk/wallet-sdk-facade';
|
|
23
24
|
import { DustWallet } from '@midnight-ntwrk/wallet-sdk-dust-wallet';
|
|
24
25
|
import { HDWallet, Roles } from '@midnight-ntwrk/wallet-sdk-hd';
|
|
25
26
|
import { ShieldedWallet } from '@midnight-ntwrk/wallet-sdk-shielded';
|
|
26
|
-
import { createKeystore,
|
|
27
|
+
import { createKeystore, NoOpTransactionHistoryStorage, PublicKey, UnshieldedWallet } from '@midnight-ntwrk/wallet-sdk-unshielded-wallet';
|
|
27
28
|
import { CompiledContract } from '@midnight-ntwrk/compact-js';
|
|
28
29
|
|
|
29
30
|
// Enable WebSocket for GraphQL subscriptions
|
|
30
31
|
// @ts-expect-error Required for wallet sync
|
|
31
32
|
globalThis.WebSocket = WebSocket;
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
setNetworkId(
|
|
35
|
-
|
|
36
|
-
// Preprod network configuration
|
|
37
|
-
const CONFIG = {
|
|
38
|
-
indexer: 'https://indexer.preprod.midnight.network/api/v3/graphql',
|
|
39
|
-
indexerWS: 'wss://indexer.preprod.midnight.network/api/v3/graphql/ws',
|
|
40
|
-
node: 'https://rpc.preprod.midnight.network',
|
|
41
|
-
proofServer: 'http://127.0.0.1:6300',
|
|
42
|
-
};
|
|
34
|
+
const { network, config: networkConfig } = resolveNetwork();
|
|
35
|
+
setNetworkId(networkConfig.networkId);
|
|
36
|
+
const SEED = getOrCreateSeed(network);
|
|
43
37
|
|
|
44
38
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
45
39
|
const zkConfigPath = path.resolve(__dirname, '..', 'contracts', 'managed', 'hello-world');
|
|
@@ -80,10 +74,10 @@ async function createWallet(seed: string) {
|
|
|
80
74
|
|
|
81
75
|
const walletConfig = {
|
|
82
76
|
networkId,
|
|
83
|
-
indexerClientConnection: { indexerHttpUrl:
|
|
84
|
-
provingServerUrl: new URL(
|
|
85
|
-
relayURL: new URL(
|
|
86
|
-
txHistoryStorage: new
|
|
77
|
+
indexerClientConnection: { indexerHttpUrl: networkConfig.indexer, indexerWsUrl: networkConfig.indexerWS },
|
|
78
|
+
provingServerUrl: new URL(networkConfig.proofServer),
|
|
79
|
+
relayURL: new URL(networkConfig.node.replace(/^http/, 'ws')),
|
|
80
|
+
txHistoryStorage: new NoOpTransactionHistoryStorage(),
|
|
87
81
|
costParameters: { additionalFeeOverhead: 300_000_000_000_000n, feeBlocksMargin: 5 },
|
|
88
82
|
};
|
|
89
83
|
|
|
@@ -100,7 +94,10 @@ async function createWallet(seed: string) {
|
|
|
100
94
|
}
|
|
101
95
|
|
|
102
96
|
async function createProviders(walletCtx: ReturnType<typeof createWallet> extends Promise<infer T> ? T : never) {
|
|
103
|
-
|
|
97
|
+
// The SDK requires the private-state password to be at least 16 characters.
|
|
98
|
+
// The default below is a placeholder for local devnet only — set a strong
|
|
99
|
+
// password via PRIVATE_STATE_PASSWORD when you move to a non-local target.
|
|
100
|
+
const privateStatePassword = process.env.PRIVATE_STATE_PASSWORD?.trim() || 'Local-Devnet-Development-Placeholder-1';
|
|
104
101
|
|
|
105
102
|
const state = await walletCtx.wallet.waitForSyncedState();
|
|
106
103
|
|
|
@@ -130,9 +127,9 @@ async function createProviders(walletCtx: ReturnType<typeof createWallet> extend
|
|
|
130
127
|
accountId,
|
|
131
128
|
privateStoragePasswordProvider: () => privateStatePassword,
|
|
132
129
|
}),
|
|
133
|
-
publicDataProvider: indexerPublicDataProvider(
|
|
130
|
+
publicDataProvider: indexerPublicDataProvider(networkConfig.indexer, networkConfig.indexerWS),
|
|
134
131
|
zkConfigProvider,
|
|
135
|
-
proofProvider: httpClientProofProvider(
|
|
132
|
+
proofProvider: httpClientProofProvider(networkConfig.proofServer, zkConfigProvider),
|
|
136
133
|
walletProvider,
|
|
137
134
|
midnightProvider: walletProvider,
|
|
138
135
|
};
|
|
@@ -148,22 +145,16 @@ async function main() {
|
|
|
148
145
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
149
146
|
|
|
150
147
|
// Check for deployment
|
|
151
|
-
|
|
152
|
-
|
|
148
|
+
const deployment = getDeployment(network);
|
|
149
|
+
if (!deployment) {
|
|
150
|
+
console.error(`No deploy on file for network ${network}. Run \`npm run setup -- --network ${network}\` first.`);
|
|
153
151
|
process.exit(1);
|
|
154
152
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
console.log(` Contract: ${deployment.contractAddress}`);
|
|
158
|
-
console.log(` Network: ${deployment.network || 'preprod'}\n`);
|
|
153
|
+
console.log(` Contract: ${deployment.address}`);
|
|
154
|
+
console.log(` Network: ${network}\n`);
|
|
159
155
|
|
|
160
156
|
try {
|
|
161
|
-
|
|
162
|
-
if (!fs.existsSync('.midnight-seed')) {
|
|
163
|
-
console.error('❌ No .midnight-seed file found! Run: npm run deploy\n');
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
const seed = fs.readFileSync('.midnight-seed', 'utf-8').trim();
|
|
157
|
+
const seed = SEED;
|
|
167
158
|
|
|
168
159
|
console.log(' Connecting to wallet...');
|
|
169
160
|
const walletCtx = await createWallet(seed);
|
|
@@ -182,13 +173,24 @@ async function main() {
|
|
|
182
173
|
const balance = state.unshielded.balances[unshieldedToken().raw] ?? 0n;
|
|
183
174
|
console.log(` Balance: ${balance.toLocaleString()} tNight\n`);
|
|
184
175
|
|
|
176
|
+
// Surface a faucet hint when a public-network wallet has 0 tNIGHT.
|
|
177
|
+
// Reads (option 2) work without funds, but writes (option 1) need DUST
|
|
178
|
+
// generated from registered NIGHT — without this hint the next failure
|
|
179
|
+
// mode is a confusing "Insufficient Funds" deep inside the tx builder.
|
|
180
|
+
if (balance === 0n && network !== 'undeployed' && networkConfig.faucet) {
|
|
181
|
+
const address = walletCtx.unshieldedKeystore.getBech32Address();
|
|
182
|
+
console.log(' ⚠ Wallet has no tNight. Fund it from the faucet to send transactions:');
|
|
183
|
+
console.log(` ${networkConfig.faucet}`);
|
|
184
|
+
console.log(` Wallet address: ${address}\n`);
|
|
185
|
+
}
|
|
186
|
+
|
|
185
187
|
// Setup providers and connect to contract
|
|
186
188
|
console.log(' Connecting to contract...');
|
|
187
189
|
const providers = await createProviders(walletCtx);
|
|
188
190
|
|
|
189
191
|
const deployed: any = await findDeployedContract(providers, {
|
|
190
192
|
compiledContract: compiledContract as any,
|
|
191
|
-
contractAddress: deployment.
|
|
193
|
+
contractAddress: deployment.address,
|
|
192
194
|
});
|
|
193
195
|
|
|
194
196
|
console.log(' ✅ Connected!\n');
|
|
@@ -222,7 +224,7 @@ async function main() {
|
|
|
222
224
|
case '2': {
|
|
223
225
|
console.log('\n Reading message from blockchain...');
|
|
224
226
|
try {
|
|
225
|
-
const contractState = await providers.publicDataProvider.queryContractState(deployment.
|
|
227
|
+
const contractState = await providers.publicDataProvider.queryContractState(deployment.address);
|
|
226
228
|
if (contractState) {
|
|
227
229
|
const ledgerState = HelloWorld.ledger(contractState.data);
|
|
228
230
|
const message = Buffer.from(ledgerState.message).toString();
|