UNPKG

hardhat-gas-reporter

Version:
229 lines (197 loc) 6.93 kB
import { cloneDeep } from "lodash" // used in extendConfig, cannot await import import { EIP1193Provider, HardhatConfig, HardhatUserConfig } from "hardhat/types"; import { TASK_TEST, TASK_COMPILE } from "hardhat/builtin-tasks/task-names"; import { extendConfig, extendEnvironment, extendProvider, task, subtask } from "hardhat/config"; import "./type-extensions"; import { GasReporterExecutionContext, GasReporterOutput } from "./types"; import { getDefaultOptions } from './lib/options'; import { GasReporterProvider } from "./lib/provider"; import { TASK_GAS_REPORTER_MERGE, TASK_GAS_REPORTER_MERGE_REPORTS, TASK_GAS_REPORTER_MERGE_LEGACY, TASK_GAS_REPORTER_MERGE_REPORTS_LEGACY, TASK_GAS_REPORTER_START, TASK_GAS_REPORTER_STOP } from "./task-names" let _globalGasReporterProviderReference: GasReporterProvider; // ======================== // EXTENSIONS // ======================== /* Config */ extendConfig( (config: HardhatConfig, userConfig: Readonly<HardhatUserConfig>) => { let options = getDefaultOptions(userConfig); // Deep clone userConfig otherwise HH will throw unauthorized modification error if (userConfig.gasReporter !== undefined) { options = Object.assign(options, cloneDeep(userConfig.gasReporter)); } (config as any).gasReporter = options; } ); /* Environment */ extendEnvironment((hre) => { hre.__hhgrec = { collector: undefined, task: undefined, } }); /* Provider */ extendProvider(async (provider) => { const newProvider = new GasReporterProvider(provider); _globalGasReporterProviderReference = newProvider; return newProvider; }); /* Initialize the provider with the execution context. This is called in `TASK_GAS_REPORTER_START` at the very end of setup. Provider extension above should not be used on unrelated tasks. */ export async function initializeGasReporterProvider( provider: EIP1193Provider, context: GasReporterExecutionContext ) { // Other plugins (ex: hardhat-tracer) may wrap the provider in a way // that doesn't expose `init()`, so we init the underlying provider // here by making a cheap call. await provider.request({ method: "eth_blockNumber", params: []}); _globalGasReporterProviderReference.initializeGasReporterProvider(context); } // ======================== // BUILT-IN OVERRIDES // ======================== /** * Overrides Hardhat built-in task TASK_TEST to report gas usage */ task(TASK_TEST).setAction( async (args: any, hre, runSuper) => { hre.__hhgrec.task = TASK_TEST; await hre.run(TASK_GAS_REPORTER_START, args); await runSuper(args); await hre.run(TASK_GAS_REPORTER_STOP, args); } ); // ======================== // GAS REPORTER TASKS // ======================== /** * Initializes gas tracking */ subtask(TASK_GAS_REPORTER_START).setAction( async (args: any, hre) => { const options = hre.config.gasReporter; if (options.enabled === true) { // Lazy load all imports to minimize HH startup time const { getContracts } = await import("./lib/artifacts"); const { Collector } = await import("./lib/collector"); const { warnParallel } = await import("./utils/ui"); // Temporarily skipping when in parallel mode because it crashes and // unsure how to resolve... if (args.parallel === true) { warnParallel(); return; } // solidity-coverage disables gas reporter via mocha but that // no longer works for this version. (No warning necessary) if ((hre as any).__SOLIDITY_COVERAGE_RUNNING === true) { return; } // Need to compile so we have access to the artifact data. // This will rerun in TASK_TEST & TASK_RUN but should be a noop there. if (!args.noCompile) { await hre.run(TASK_COMPILE, { quiet: true }); } const contracts = await getContracts(hre, options); hre.__hhgrec.usingCall = options.reportPureAndViewMethods; hre.__hhgrec.usingViem = (hre as any).viem; hre.__hhgrec.usingOZ = (hre as any).upgrades || (hre as any).defender hre.__hhgrec.collector = new Collector(hre, options); hre.__hhgrec.collector.data.initialize(hre.network.provider, contracts); // Custom proxy resolvers are instantiated in the config, // OZ proxy resolver instantiated in Resolver constructor called by new Collector() hre.__hhgrec.methodIgnoreList = (options.proxyResolver) ? options.proxyResolver.ignore() : []; await initializeGasReporterProvider(hre.network.provider, hre.__hhgrec); } } ); /** * Completes gas reporting: gets live market data, runs analysis and renders */ subtask(TASK_GAS_REPORTER_STOP).setAction( async (args: any, hre) => { const options = hre.config.gasReporter; if ( options.enabled === true && args.parallel !== true && (hre as any).__SOLIDITY_COVERAGE_RUNNING !== true ) { const { setGasAndPriceRates } = await import("./utils/prices"); const { render } = await import("./lib/render"); const warnings = await setGasAndPriceRates(options); await hre.__hhgrec.collector?.data.runAnalysis(hre, options); render(hre, options, warnings); } } ); /** * ======================== * CLI COMMAND TASKS * ======================== */ subtask(TASK_GAS_REPORTER_MERGE_REPORTS) .addOptionalVariadicPositionalParam( "inputFiles", "Path of several gasReporterOutput.json files to merge", [] ) .setAction( async ({ inputFiles }: { inputFiles: string[] } ): Promise<GasReporterOutput> => { const { subtaskMergeReportsImplementation } = await import("./tasks/mergeReports") return subtaskMergeReportsImplementation({ inputFiles }) }); task(TASK_GAS_REPORTER_MERGE) .addOptionalParam( "output", "Target file to save the merged report", "gasReporterOutput.json" ) .addVariadicPositionalParam( "input", "A list of JSON data files generated by the gas reporter plugin. " + "Files can be defined using glob patterns" ) .setAction(async (taskArguments, hre) => { const { taskMergeImplementation } = await import("./tasks/mergeReports") return taskMergeImplementation(taskArguments, hre); }); /** * ======================== * DEPRECATED TASKS * ======================== */ task(TASK_GAS_REPORTER_MERGE_LEGACY) .addOptionalParam( "output", "Target file to save the merged report", "gasReporterOutput.json" ) .addVariadicPositionalParam("input") .setAction(async () => { const { warnDeprecatedTask } = await import("./utils/ui"); warnDeprecatedTask(TASK_GAS_REPORTER_MERGE) }); subtask(TASK_GAS_REPORTER_MERGE_REPORTS_LEGACY) .addOptionalVariadicPositionalParam("inputFiles", "", []) .setAction(async ({}: { inputFiles: string[] }) => { const { warnDeprecatedTask } = await import("./utils/ui"); warnDeprecatedTask(TASK_GAS_REPORTER_MERGE_REPORTS); });