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
|
@@ -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
|
-
|
|
179
|
-
|
|
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
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
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');
|