create-mn-app 0.3.13 → 0.3.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-mn-app",
3
- "version": "0.3.13",
3
+ "version": "0.3.15",
4
4
  "description": "Create Midnight Network applications with zero configuration",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -167,16 +167,63 @@ async function main() {
167
167
  const rl = createInterface({ input: stdin, output: stdout });
168
168
 
169
169
  try {
170
+ // Check for existing deployment.json (previous attempt or completed deployment)
171
+ let existingSeed: string | undefined;
172
+ let existingContract: string | undefined;
173
+
174
+ if (fs.existsSync('deployment.json')) {
175
+ try {
176
+ const existing = JSON.parse(fs.readFileSync('deployment.json', 'utf-8'));
177
+ if (existing.seed) existingSeed = existing.seed;
178
+ if (existing.contractAddress) existingContract = existing.contractAddress;
179
+ } catch {
180
+ // Ignore parse errors
181
+ }
182
+ }
183
+
184
+ // If already deployed, ask if they want to redeploy
185
+ if (existingContract) {
186
+ console.log('─── Existing Deployment Found ──────────────────────────────────\n');
187
+ console.log(` Contract: ${existingContract}`);
188
+ const redeploy = await rl.question('\n Deploy a new contract? [y/N] ');
189
+ if (redeploy.toLowerCase() !== 'y') {
190
+ console.log('\n Run `npm run cli` to interact with your existing contract.\n');
191
+ return;
192
+ }
193
+ existingSeed = undefined; // Fresh deployment = fresh wallet
194
+ }
195
+
170
196
  // 1. Wallet setup
171
197
  console.log('─── Step 1: Wallet Setup ───────────────────────────────────────\n');
172
- const choice = await rl.question(' [1] Create new wallet\n [2] Restore from seed\n > ');
173
-
174
- const seed = choice.trim() === '2'
175
- ? await rl.question('\n Enter your 64-character seed: ')
176
- : toHex(Buffer.from(generateRandomSeed()));
177
198
 
178
- if (choice.trim() !== '2') {
179
- console.log(`\n ⚠️ SAVE THIS SEED (you'll need it later):\n ${seed}\n`);
199
+ let seed: string;
200
+
201
+ if (existingSeed) {
202
+ // Resume from previous failed deployment
203
+ console.log(' Found saved seed from previous attempt.');
204
+ const useSaved = await rl.question(' Use saved wallet? [Y/n] ');
205
+ if (useSaved.toLowerCase() !== 'n') {
206
+ seed = existingSeed;
207
+ console.log(' Using saved wallet...\n');
208
+ } else {
209
+ const choice = await rl.question(' [1] Create new wallet\n [2] Restore from seed\n > ');
210
+ seed = choice.trim() === '2'
211
+ ? await rl.question('\n Enter your 64-character seed: ')
212
+ : toHex(Buffer.from(generateRandomSeed()));
213
+
214
+ if (choice.trim() !== '2') {
215
+ console.log(`\n ⚠️ SAVE THIS SEED (you'll need it later):\n ${seed}\n`);
216
+ }
217
+ }
218
+ } else {
219
+ const choice = await rl.question(' [1] Create new wallet\n [2] Restore from seed\n > ');
220
+ seed = choice.trim() === '2'
221
+ ? await rl.question('\n Enter your 64-character seed: ')
222
+ : toHex(Buffer.from(generateRandomSeed()));
223
+
224
+ if (choice.trim() !== '2') {
225
+ console.log(`\n ⚠️ SAVE THIS SEED (you'll need it later):\n ${seed}\n`);
226
+ }
180
227
  }
181
228
 
182
229
  console.log(' Creating wallet...');
@@ -236,12 +283,82 @@ async function main() {
236
283
  console.log(' Setting up providers...');
237
284
  const providers = await createProviders(walletCtx);
238
285
 
239
- console.log(' Deploying contract (this may take 30-60 seconds)...\n');
240
- const deployed = await deployContract(providers, {
241
- compiledContract,
242
- privateStateId: 'helloWorldState',
243
- initialPrivateState: {},
244
- });
286
+ console.log(' Deploying contract...\n');
287
+
288
+ const MAX_RETRIES = 8;
289
+ const RETRY_DELAY_MS = 15000; // 15 seconds between retries
290
+
291
+ let deployed: Awaited<ReturnType<typeof deployContract>> | undefined;
292
+
293
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
294
+ try {
295
+ deployed = await deployContract(providers, {
296
+ compiledContract,
297
+ privateStateId: 'helloWorldState',
298
+ initialPrivateState: {},
299
+ });
300
+ break; // Success - exit retry loop
301
+ } catch (err: any) {
302
+ const errMsg = err?.message || err?.toString() || '';
303
+
304
+ // Check if it's a DUST-related error
305
+ if (errMsg.includes('Not enough Dust') || errMsg.includes('Wallet.Transacting')) {
306
+ // Get current DUST balance
307
+ const currentState = await Rx.firstValueFrom(walletCtx.wallet.state().pipe(Rx.filter((s) => s.isSynced)));
308
+ const dustBalance = currentState.dust.walletBalance(new Date());
309
+
310
+ if (attempt < MAX_RETRIES) {
311
+ console.log(` ⏳ DUST balance: ${dustBalance.toLocaleString()} (need more for tx fees)`);
312
+ console.log(` Attempt ${attempt}/${MAX_RETRIES} - waiting for DUST to accumulate...`);
313
+
314
+ // Countdown display
315
+ for (let i = RETRY_DELAY_MS / 1000; i > 0; i -= 5) {
316
+ process.stdout.write(`\r Retrying in ${i}s... `);
317
+ await new Promise((r) => setTimeout(r, 5000));
318
+ }
319
+ process.stdout.write('\r \r\n');
320
+ } else {
321
+ // All retries exhausted
322
+ console.log(' ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
323
+ console.log(' ❌ Not enough DUST for transaction fees\n');
324
+ console.log(` Current DUST: ${dustBalance.toLocaleString()}`);
325
+ console.log(' This is a new wallet - DUST generates over time.\n');
326
+ console.log(' ┌─ Options ─────────────────────────────────────────────────┐');
327
+ console.log(' │ │');
328
+ console.log(' │ [1] Wait & retry $ npm run deploy │');
329
+ console.log(' │ (DUST accumulates as blocks are produced) │');
330
+ console.log(' │ │');
331
+ console.log(' │ [2] Send DUST from existing wallet to this address: │');
332
+ console.log(` │ ${address.slice(0, 50)}... │`);
333
+ console.log(' │ │');
334
+ console.log(' │ [3] Import wallet with DUST (choose option 2 on retry) │');
335
+ console.log(' │ │');
336
+ console.log(' └───────────────────────────────────────────────────────────┘\n');
337
+
338
+ // Save partial deployment info so user can resume
339
+ const partialInfo = {
340
+ seed,
341
+ address,
342
+ network: 'preprod',
343
+ status: 'pending_dust',
344
+ lastAttempt: new Date().toISOString(),
345
+ };
346
+ fs.writeFileSync('deployment.json', JSON.stringify(partialInfo, null, 2));
347
+ console.log(' Wallet saved to deployment.json\n');
348
+
349
+ await walletCtx.wallet.stop();
350
+ process.exit(1);
351
+ }
352
+ } else {
353
+ // Not a DUST error - rethrow
354
+ throw err;
355
+ }
356
+ }
357
+ }
358
+
359
+ if (!deployed) {
360
+ throw new Error('Deployment failed after all retries');
361
+ }
245
362
 
246
363
  const contractAddress = deployed.deployTxData.public.contractAddress;
247
364
  console.log(' ✅ Contract deployed successfully!\n');