UNPKG

@solarity/hardhat-migrate

Version:
498 lines 24.8 kB
var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || typeof result !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_); else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; import { join } from "path"; import { format } from "prettier"; import { existsSync, mkdirSync, writeFile, writeFileSync } from "fs"; import { Reporter } from "./Reporter.js"; import { Stats } from "../Stats.js"; import { castAmount, CatchClassError } from "../../utils/index.js"; /** * Class that manages the storage of the reported operation. * * Produces reports, metrics and logs in a file format. */ let ReporterStorage = (() => { let _classDecorators = [CatchClassError]; let _classDescriptor; let _classExtraInitializers = []; let _classThis; var ReporterStorage = class { static { _classThis = this; } static { const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0; __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers); ReporterStorage = _classThis = _classDescriptor.value; if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); __runInitializers(_classThis, _classExtraInitializers); } _hre; _currentReportID = null; _state; _currentlyDeployingInstance = ""; _defaultVerificationState = "Nothing to verify"; constructor(_hre) { this._hre = _hre; this._state = { title: "Migration Report", generalInfo: { title: "General Information", migrationFiles: new Set(), networks: {}, }, reportedContracts: new Set(), detailedMigrationFiles: [], stats: { totalContracts: 0, totalTransactions: 0, gasUsed: 0n, totalGasPrice: 0n, feePayed: 0n, nativeCurrencySent: 0n, }, missingLibraries: new Set(), recoveredContracts: new Set(), recoveredTransactions: new Set(), verificationStats: { status: this._defaultVerificationState, verifiedContracts: new Set(), failedContracts: new Set(), failedToSaveContracts: new Set(), alreadyVerifiedContracts: new Set(), proxyLinkingSuccess: new Set(), proxyLinkingFailure: new Set(), }, collisions: { contracts: new Set(), transactions: new Set(), unknown: new Set(), }, allContracts: new Set(), allTransactions: new Set(), }; } storeMigrationBegin() { this._commitReport(); } storeMigrationFileBegin(migrationName) { this._state.detailedMigrationFiles[Stats.currentMigration] = { migrationName, links: new Set(), responses: new Set(), receipts: new Set(), }; } storeTransactionResponseHeader(transactionResponse, instanceName, txLink) { if (!this._state.detailedMigrationFiles[Stats.currentMigration]) { Reporter.addWarning(`Direct deploy without migration file. Cannot process detailed migration file data for ${instanceName} and ${txLink}`); return; } this._state.detailedMigrationFiles[Stats.currentMigration].links.add(txLink); this._state.detailedMigrationFiles[Stats.currentMigration].responses.add(transactionResponse); this._currentlyDeployingInstance = instanceName; this._commitReport(); } storeTransactionReceipt(transactionReceipt, value) { if (!this._state.detailedMigrationFiles[Stats.currentMigration]) { Reporter.addWarning(`Direct deploy without migration file. Cannot process detailed migration file data for ${transactionReceipt.hash}`); return; } this._state.detailedMigrationFiles[Stats.currentMigration].receipts.add(transactionReceipt); if (transactionReceipt.contractAddress) { this._state.stats.totalContracts += 1; this._state.allContracts.add([this._currentlyDeployingInstance, transactionReceipt.contractAddress]); } else { this._state.stats.totalTransactions += 1; this._state.allTransactions.add([this._currentlyDeployingInstance, transactionReceipt.hash]); } this._state.stats.gasUsed += BigInt(transactionReceipt.gasUsed); const gasPrice = transactionReceipt.gasPrice ?? 0n; this._state.stats.totalGasPrice += BigInt(gasPrice); this._state.stats.feePayed += BigInt(transactionReceipt.fee); this._state.stats.nativeCurrencySent += BigInt(value); this._commitReport(); } storeReportedContracts(contracts) { for (const contract of contracts) { this._state.reportedContracts.add(contract); } this._commitReport(); } storeDeploymentOfMissingLibrary(libraryName) { this._state.missingLibraries.add(libraryName); this._commitReport(); } storeContractRecovery(contractName, contractAddress) { this._state.recoveredContracts.add([contractName, contractAddress]); this._commitReport(); } storeTransactionRecovery(methodString, savedTx) { const receipt = savedTx.receipt; this._state.recoveredTransactions.add([methodString, receipt.hash ? receipt.hash : "N/A"]); this._commitReport(); } storeNothingToVerify() { this._commitReport(); } storeVerificationSuccess(contractName, contractAddress) { if (this._state.verificationStats.status === this._defaultVerificationState) { this._state.verificationStats.status = "Verification successful"; } this._state.verificationStats.verifiedContracts.add([contractName, contractAddress]); this._commitReport(); } storeAlreadyVerified(contractName, contractAddress) { if (this._state.verificationStats.status === this._defaultVerificationState) { this._state.verificationStats.status = "Verification successful with already verified contracts"; } this._state.verificationStats.alreadyVerifiedContracts.add([contractName, contractAddress]); this._commitReport(); } storeVerificationFailure(contractName, contractAddress) { this._state.verificationStats.status = "Verification failed"; this._state.verificationStats.failedContracts.add([contractName, contractAddress]); this._commitReport(); } storeVerificationSaveFailure(contractName) { this._state.verificationStats.status = "Verification failed"; this._state.verificationStats.failedToSaveContracts.add(contractName); this._commitReport(); } storeTransactionCollision(oldData, dataToSave) { this._state.collisions.transactions.add({ prevMigrationNumber: oldData.metadata.migrationNumber, prevMethodName: oldData.metadata.methodName || "N/A", newMigrationNumber: dataToSave.metadata.migrationNumber, newMethodName: dataToSave.metadata.methodName || "N/A", }); this._commitReport(); } storeUnknownCollision(metadata, dataToSave) { this._state.collisions.unknown.add({ prevMigrationNumber: metadata.migrationNumber, prevContractAddress: metadata.contractName || "N/A", prevMethodName: metadata.methodName || "N/A", newMigrationNumber: dataToSave.metadata.migrationNumber, newContractAddress: dataToSave.metadata.contractName || "N/A", newMethodName: dataToSave.metadata.methodName || "N/A", }); this._commitReport(); } storeContractCollision(oldData, dataToSave) { this._state.collisions.contracts.add({ prevMigrationNumber: oldData.metadata.migrationNumber, prevContractAddress: oldData.metadata.contractName || "N/A", newMigrationNumber: dataToSave.metadata.migrationNumber, newContractAddress: dataToSave.metadata.contractName || "N/A", }); this._commitReport(); } storeMigrationFiles(migrationFiles) { for (const migrationFile of migrationFiles) { this._state.generalInfo.migrationFiles.add(migrationFile); } this._commitReport(); } storeChainInfo(network) { this._state.generalInfo.networks[network.network.name] = network; this._commitReport(); } storeSuccessfulProxyLinking(contractName, contractAddress) { this._state.verificationStats.proxyLinkingSuccess.add([contractName, contractAddress]); this._commitReport(); } storeFailedProxyLinking(contractName, contractAddress) { this._state.verificationStats.proxyLinkingFailure.add([contractName, contractAddress]); this._commitReport(); } completeReport() { this._commitReport(); } _commitReport() { const reportID = this._getReportID(); const pathToReportDir = join(this._hre.config.paths.root, this._hre.config.migrate.paths.reportPath); if (!existsSync(pathToReportDir)) { mkdirSync(pathToReportDir, { recursive: true }); } this._getReportContent().then((content) => { writeFile(join(pathToReportDir, reportID), content, { flag: "w" }, (err) => { if (err) { console.error(`Error writing report to ${pathToReportDir}`); console.error(err); } }); }); } async finishReport() { const reportID = this._getReportID(); const pathToReportDir = join(this._hre.config.paths.root, this._hre.config.migrate.paths.reportPath); if (!existsSync(pathToReportDir)) { mkdirSync(pathToReportDir, { recursive: true }); } const content = await this._getReportContent(); writeFileSync(join(pathToReportDir, reportID), content, { flag: "w" }); } _getReportID() { if (this._currentReportID !== null) { return this._currentReportID; } this._state.title = this._getReportName(); this._currentReportID = this._getReportName(); return this._currentReportID; } _getReportName() { const date = new Date(Date.now()).toISOString(); const extension = this._hre.config.migrate.paths.reportFormat === "json" ? "json" : "md"; return `Migration Report ${date}.${extension}`; } _getReportContent() { const reportFormat = this._hre.config.migrate.paths.reportFormat; if (reportFormat === "json") { const serializableState = this._getSerializableState(); return Promise.resolve(JSON.stringify(serializableState, (_, value) => { if (typeof value === "bigint") { return value.toString(); } if (value instanceof Set) { return Array.from(value); } if (value instanceof Map) { return Object.fromEntries(value); } return value; }, 2)); } else { return this._getMarkdownReportContent(); } } _getAverageGasPrice() { const totalExecutions = this._state.stats.totalContracts + this._state.stats.totalTransactions; if (totalExecutions === 0) { return 0n; } return this._state.stats.totalGasPrice / BigInt(totalExecutions); } _getSerializableState() { return { ...this._state, stats: { ...this._state.stats, averageGasPrice: this._getAverageGasPrice(), }, }; } async _getMarkdownReportContent() { const { title, generalInfo, reportedContracts } = this._state; const actualState = []; actualState.push({ h1: title }); actualState.push({ h2: generalInfo.title }); actualState.push({ h3: "Migration Files" }); actualState.push({ ul: Array.from(generalInfo.migrationFiles) }); actualState.push({ h3: "Networks" }); actualState.push({ ul: Object.values(generalInfo.networks).map((network) => { const name = network.network.name; const chainId = network.network.chainId; const explorer = network.explorer; return `${name} - Chain ID: ${chainId}. Explorer: ${explorer}`; }), }); if (reportedContracts.size > 0) { actualState.push({ h2: "Reported Contracts" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(reportedContracts) } }); } actualState.push({ h2: "Detailed Migration Files" }); for (const migrationFile of this._state.detailedMigrationFiles) { if (!migrationFile) { continue; } actualState.push({ h3: migrationFile.migrationName }); actualState.push({ ul: Array.from(migrationFile.links) }); } actualState.push({ h2: "Stats" }); const averageGasPrice = this._getAverageGasPrice(); actualState.push({ table: { headers: [ "Total Contracts", "Total Transactions", "Gas Used", "Average Gas Price", "Fee Payed", "Native Currency Sent", ], rows: [ [ this._state.stats.totalContracts, this._state.stats.totalTransactions, String(this._state.stats.gasUsed), castAmount(averageGasPrice), castAmount(this._state.stats.feePayed), castAmount(this._state.stats.nativeCurrencySent), ], ], }, }); actualState.push({ p: ["Total Cost: ", castAmount(this._state.stats.feePayed + this._state.stats.nativeCurrencySent)], }); if (this._state.missingLibraries.size > 0) { actualState.push({ h2: "Missing Libraries" }); actualState.push({ ul: Array.from(this._state.missingLibraries) }); } if (this._state.recoveredContracts.size > 0) { actualState.push({ h2: "Recovered Contracts" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.recoveredContracts) } }); } if (this._state.recoveredTransactions.size > 0) { actualState.push({ h2: "Recovered Transactions" }); actualState.push({ table: { headers: ["Name", "Hash"], rows: Array.from(this._state.recoveredTransactions) } }); } if (this._state.verificationStats.status !== this._defaultVerificationState) { actualState.push({ h2: `Verification Stats. ${this._state.verificationStats.status}` }); if (this._state.verificationStats.verifiedContracts.size > 0) { actualState.push({ h3: "Verified Contracts" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.verificationStats.verifiedContracts) }, }); } if (this._state.verificationStats.alreadyVerifiedContracts.size > 0) { actualState.push({ h3: "Already Verified Contracts" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.verificationStats.alreadyVerifiedContracts), }, }); } if (this._state.verificationStats.failedContracts.size > 0) { actualState.push({ h3: "Failed Contracts" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.verificationStats.failedContracts) }, }); } if (this._state.verificationStats.failedToSaveContracts.size > 0) { actualState.push({ h3: "Failed to Save Contracts" }); actualState.push({ ul: Array.from(this._state.verificationStats.failedToSaveContracts) }); } if (this._state.verificationStats.proxyLinkingSuccess.size > 0) { actualState.push({ h3: "Proxy Linking Success" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.verificationStats.proxyLinkingSuccess) }, }); } if (this._state.verificationStats.proxyLinkingFailure.size > 0) { actualState.push({ h3: "Proxy Linking Failure" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.verificationStats.proxyLinkingFailure) }, }); } } if (this._state.collisions.contracts.size > 0 || this._state.collisions.transactions.size > 0 || this._state.collisions.unknown.size > 0) { actualState.push({ h2: "Collisions" }); if (this._state.collisions.contracts.size > 0) { actualState.push({ h3: "Contracts" }); actualState.push({ table: { headers: ["Prev Migration Number", "Prev Contract Address", "New Migration Number", "New Contract Address"], rows: Array.from(this._state.collisions.contracts).map((contract) => [ contract.prevMigrationNumber, contract.prevContractAddress, contract.newMigrationNumber, contract.newContractAddress, ]), }, }); } if (this._state.collisions.transactions.size > 0) { actualState.push({ h3: "Transactions" }); actualState.push({ table: { headers: ["Prev Migration Number", "Prev Method Name", "New Migration Number", "New Method Name"], rows: Array.from(this._state.collisions.transactions).map((transaction) => [ transaction.prevMigrationNumber, transaction.prevMethodName, transaction.newMigrationNumber, transaction.newMethodName, ]), }, }); } if (this._state.collisions.unknown.size > 0) { actualState.push({ h3: "Unknown" }); actualState.push({ table: { headers: [ "Prev Migration Number", "Prev Contract Address", "Prev Method Name", "New Migration Number", "New Contract Address", "New Method Name", ], rows: Array.from(this._state.collisions.unknown).map((unknown) => [ unknown.prevMigrationNumber, unknown.prevContractAddress, unknown.prevMethodName, unknown.newMigrationNumber, unknown.newContractAddress, unknown.newMethodName, ]), }, }); } } if (this._state.allContracts.size > 0) { actualState.push({ h2: "All Contracts" }); actualState.push({ table: { headers: ["Name", "Address"], rows: Array.from(this._state.allContracts) } }); } if (this._state.allTransactions.size > 0) { actualState.push({ h2: "All Transactions" }); actualState.push({ table: { headers: ["Name", "Hash"], rows: Array.from(this._state.allTransactions) } }); } return format((await import("json2md")).default(actualState), { parser: "markdown", printWidth: 80, proseWrap: "always", }); } }; return ReporterStorage = _classThis; })(); export { ReporterStorage }; //# sourceMappingURL=ReporterStorage.js.map