UNPKG

dop-stick

Version:

Source control tooling for versionable-upgradeable smart contracts

335 lines 13.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ParallelDeploymentTimelineAdapter = void 0; const timelineLogAdapter_1 = require("./timelineLogAdapter"); const terminal_1 = require("../core/terminal"); const ethers_1 = require("ethers"); const logFormatters_1 = require("../logFormatters"); const COLORS = { HEADER: '\x1b[95m', SUCCESS: '\x1b[32m', PENDING: '\x1b[90m', ERROR: '\x1b[31m', RESET: '\x1b[0m' // Reset color }; const ICONS = { NETWORK: '🌐', CHECKS: '🔍', WALLET: '🔐', BYTECODE: '⌘', DEPLOYMENT: '📡', COMPILING: '💻', PREPARING: '📝', SENT: '⚡', PENDING: '⠋', SUCCESS: '✓', ERROR: '✖', PROGRESS: '📈', CHECK: '✓', WARNING: '⚠️' }; class ParallelDeploymentTimelineAdapter { constructor() { this.spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏']; this.currentFrame = 0; this.timeline = new timelineLogAdapter_1.TimelineLogAdapter(); this.state = { modules: new Map() }; this.startTime = Date.now(); this.totalModules = 0; } setTotalModules(total) { this.totalModules = total; } startDeployment(networkInfo) { this.timeline.startSection('PARALLEL DEPLOYMENT PROCESS'); this.timeline.logStep(`${ICONS.NETWORK} ${COLORS.HEADER}Network Info${COLORS.RESET}`); this.timeline.logInnerStep(`• Network: ${networkInfo.name}`, 1); this.timeline.logInnerStep(`• ChainId: ${networkInfo.chainId}`, 1); this.timeline.logInnerStep(`• Gas Price: ${networkInfo.gasPrice} gwei`, 1); this.timeline.logEmptyStep(); } logPreDeploymentChecks(checks) { this.timeline.logStep(`${ICONS.CHECKS} ${COLORS.HEADER}Pre-deployment Checks${COLORS.RESET}`); checks.forEach(check => { var _a, _b, _c; const status = this.getStatusIcon(check.status); let message = ''; switch (check.type) { case 'cuts': message = `Cuts validation`.padEnd(20) + `${status} ${(_a = check.details) === null || _a === void 0 ? void 0 : _a.moduleCount} modules (${(_b = check.details) === null || _b === void 0 ? void 0 : _b.functionCount} functions)`; break; case 'emergency': message = `Emergency status`.padEnd(20) + `${status} Diamond active`; break; case 'gas': message = `Gas price check`.padEnd(20) + `${status} Normal mode`; break; case 'balance': message = `Balance check`.padEnd(20) + `${status} ${(_c = check.details) === null || _c === void 0 ? void 0 : _c.balance} ETH available`; break; } this.timeline.logInnerStep(`• ${message}`, 1); }); this.timeline.logEmptyStep(); } logWalletGeneration(wallets) { this.timeline.logStep(`${ICONS.WALLET} ${COLORS.HEADER}Wallet Generation${COLORS.RESET}`); wallets.forEach(({ moduleName, address }) => { this.timeline.logInnerStep(`• ${moduleName.padEnd(15)}${logFormatters_1.LogFormatters.makeAddressCopyable(address)}`, 1); }); this.timeline.logEmptyStep(); } handleDeploymentEvent(event) { let moduleState = this.state.modules.get(event.moduleName); if (!moduleState) { moduleState = { status: 'pending' }; this.state.modules.set(event.moduleName, moduleState); } switch (event.type) { case 'bytecode': moduleState.bytecodeSize = event.data.bytecodeSize; break; case 'compile': moduleState.status = 'compiling'; break; case 'prepare': moduleState.status = 'preparing'; break; case 'deploy': moduleState.status = 'deploying'; break; case 'send': moduleState.status = 'sent'; break; case 'transaction': moduleState.txHash = event.data.txHash; break; case 'confirmation': moduleState.status = 'confirmed'; moduleState.address = event.data.address; moduleState.gasUsed = event.data.gasUsed; moduleState.blockNumber = event.data.blockNumber; moduleState.details = event.data.details; break; case 'error': moduleState.status = 'failed'; moduleState.error = event.data.error; break; } this.displayCurrentProgress(); } getDeploymentState() { return this.state; } displayCurrentProgress() { const completed = Array.from(this.state.modules.values()).filter(s => s.status === 'confirmed').length; const pending = Array.from(this.state.modules.values()).filter(s => s.status !== 'confirmed' && s.status !== 'failed').length; const failed = Array.from(this.state.modules.values()).filter(s => s.status === 'failed').length; const totalGasUsed = Array.from(this.state.modules.values()) .reduce((sum, s) => sum.add(s.gasUsed || ethers_1.ethers.BigNumber.from(0)), ethers_1.ethers.BigNumber.from(0)); this.timeline.logEmptyStep(); this.timeline.logStep(`${ICONS.PROGRESS} ${COLORS.HEADER}Current Progress${COLORS.RESET}`); // Fix the completed/total display this.timeline.logInnerStep(`• Completed: ${COLORS.SUCCESS}${completed}/${this.totalModules}${COLORS.RESET}`, 1); if (pending > 0) { this.timeline.logInnerStep(`• In Progress: ${COLORS.PENDING}${pending}${COLORS.RESET}`, 1); } if (failed > 0) { this.timeline.logInnerStep(`• Failed: ${COLORS.ERROR}${failed}${COLORS.RESET}`, 1); } // Add percentage complete const percentComplete = Math.round((completed / this.totalModules) * 100); this.timeline.logInnerStep(`• Progress: ${COLORS.SUCCESS}${percentComplete}%${COLORS.RESET}`, 1); this.timeline.logInnerStep(`• Gas used so far: ${this.formatGas(totalGasUsed)}`, 1); this.timeline.logInnerStep(`• Time elapsed: ${this.formatDuration(Date.now() - this.startTime)}`, 1); this.timeline.logEmptyStep(); } displaySummary(results, duration) { this.timeline.logStep(`${ICONS.PROGRESS} ${COLORS.HEADER}Deployment Summary${COLORS.RESET}`); const totalModules = results.length; const totalBytecode = Array.from(this.state.modules.values()) .reduce((sum, s) => sum + (s.bytecodeSize || 0), 0); const totalGasUsed = results .reduce((sum, result) => { if (result.gasUsed) { return sum.add(result.gasUsed); } return sum; }, ethers_1.ethers.BigNumber.from(0)); this.timeline.logInnerStep(`• Total modules: ${totalModules}`, 1); this.timeline.logInnerStep(`• Total bytecode: ${this.formatBytes(totalBytecode)}`, 1); this.timeline.logInnerStep(`• Total gas used: ${this.formatGas(totalGasUsed)}`, 1); this.timeline.logInnerStep(`• Total deployment time: ${this.formatDuration(duration)}`, 1); // Log any failed deployments const failedDeployments = results.filter(r => r.status === 'failed'); if (failedDeployments.length > 0) { this.timeline.logEmptyStep(); this.timeline.logInnerStep(`${terminal_1.Terminal.colors.error}Failed Deployments:${terminal_1.Terminal.colors.reset}`, 1); failedDeployments.forEach(result => { this.timeline.logInnerStep(`• ${result.moduleName}: ${result.error}`, 2); }); } // Fix the duplicate timing in the completion message this.timeline.logEmptyStep(); this.timeline.logSuccessWithTime(`Parallel deployment completed`); } startModuleDeployment(moduleName, index) { this.handleDeploymentEvent({ moduleName, type: 'compile', data: {} }); } logTransactionSent(moduleName, txHash) { this.handleDeploymentEvent({ moduleName, type: 'transaction', data: { txHash } }); } logDeploymentSuccess(moduleName, address, gasUsed, blockNumber, details) { this.handleDeploymentEvent({ moduleName, type: 'confirmation', data: { address, gasUsed, blockNumber, details } }); // Enhanced success message with details let message = `${ICONS.SUCCESS} ${moduleName} deployed to: ${logFormatters_1.LogFormatters.makeAddressCopyable(address)}`; if (details) { message += `\n Gas Used: ${this.formatGas(gasUsed)}`; if (details.gasPrice) message += ` @ ${details.gasPrice} gwei`; if (details.totalCost) message += ` (${details.totalCost} ETH)`; if (details.deployTime) message += `\n Deploy Time: ${details.deployTime}`; } this.timeline.logColoredStep(message, 1, terminal_1.Terminal.colors.success); this.timeline.logEmptyStep(); } logDeploymentError(moduleName, error) { this.handleDeploymentEvent({ moduleName, type: 'error', data: { error } }); } updateModuleProgress(progress) { const { moduleName, stage, bytecodeSize, txHash, address, gasUsed, error } = progress; let eventType; switch (stage) { case 'bytecode': eventType = 'bytecode'; break; case 'transaction': eventType = 'transaction'; break; case 'deployed': eventType = 'confirmation'; break; case 'error': eventType = 'error'; break; default: eventType = 'compile'; } this.handleDeploymentEvent({ moduleName, type: eventType, data: { bytecodeSize, txHash, address, gasUsed, error } }); } logWarning(message) { this.timeline.logColoredStep(`${ICONS.WARNING} ${message}`, 1, terminal_1.Terminal.colors.warning); this.timeline.logEmptyStep(); } /** * Log an error message * @param message Error message to display */ logError(message) { this.timeline.logColoredStep(`${ICONS.ERROR} ${message}`, 1, terminal_1.Terminal.colors.error); this.timeline.logEmptyStep(); } /** * Log a library deployment error */ logLibraryDeploymentError(libraryName, error) { this.timeline.logColoredStep(`${ICONS.ERROR} Library ${libraryName} deployment failed: ${error}`, 1, terminal_1.Terminal.colors.error); this.timeline.logEmptyStep(); } /** * Log a library deployment success */ logLibraryDeploymentSuccess(libraryName, address) { this.timeline.logColoredStep(`${ICONS.SUCCESS} Library ${libraryName} deployed to: ${logFormatters_1.LogFormatters.makeAddressCopyable(address)}`, 1, terminal_1.Terminal.colors.success); } /** * Log a library detection error */ logLibraryDetectionError(moduleName, error) { const errorMessage = error instanceof Error ? error.message : String(error); this.timeline.logColoredStep(`${ICONS.ERROR} Failed to detect libraries for ${moduleName}: ${errorMessage}`, 1, terminal_1.Terminal.colors.error); this.timeline.logEmptyStep(); } /** * Log an informational message */ logInfo(message) { this.timeline.logColoredStep(message, 0, terminal_1.Terminal.colors.info); } /** * Log a success message */ logSuccess(message) { this.timeline.logColoredStep(`${ICONS.SUCCESS} ${message}`, 1, terminal_1.Terminal.colors.success); this.timeline.logEmptyStep(); } // Helper methods getStatusIcon(status) { switch (status) { case 'success': return `${COLORS.SUCCESS}${ICONS.CHECK}${COLORS.RESET}`; case 'warning': return `${COLORS.PENDING}${ICONS.ERROR}${COLORS.RESET}`; case 'failed': return `${COLORS.ERROR}${ICONS.ERROR}${COLORS.RESET}`; } } formatBytes(bytes) { return `${(bytes / 1024).toFixed(1)} KB`; } formatGas(gas) { return `${(gas.toNumber() / 1000000).toFixed(1)}M`; } formatDuration(ms) { return `${(ms / 1000).toFixed(1)}s`; } capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } startSpinner(message) { if (this.spinner) { clearInterval(this.spinner); } process.stdout.write('\r'); this.spinner = setInterval(() => { const frame = this.spinnerFrames[this.currentFrame]; process.stdout.write(`\r${frame} ${message}`); this.currentFrame = (this.currentFrame + 1) % this.spinnerFrames.length; }, 80); } stopSpinner() { if (this.spinner) { clearInterval(this.spinner); this.spinner = null; process.stdout.write('\r\n'); } } } exports.ParallelDeploymentTimelineAdapter = ParallelDeploymentTimelineAdapter; //# sourceMappingURL=parallelDeploymentTimelineAdapter.js.map