dop-stick
Version:
Source control tooling for versionable-upgradeable smart contracts
335 lines • 13.8 kB
JavaScript
;
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