UNPKG

@solarity/hardhat-migrate

Version:
210 lines (169 loc) 7.44 kB
import { isAbsolute } from "path"; import { HardhatPluginError } from "hardhat/plugins"; import { ConfigExtender } from "hardhat/types"; import { pluginName } from "./constants"; import { DeepPartial, MigrateConfig, MigrateConfigArgs, MigrateVerifyConfig } from "./types/migrations"; const defaultConfig: MigrateConfig = { filter: { from: -1, to: -1, only: -1, skip: -1, }, verification: { verify: false, verificationDelay: 5000, verifyParallel: 1, verifyAttempts: 3, }, paths: { pathToMigrations: "./deploy", namespace: "", reportPath: "cache", reportFormat: "md", }, execution: { force: false, continue: false, wait: 1, transactionStatusCheckInterval: 2000, withoutCLIReporting: false, }, castWallet: {}, trezorWallet: { enabled: false, mnemonicIndex: 0, }, }; const defaultVerifyConfig: MigrateVerifyConfig = { inputFile: undefined, parallel: 1, attempts: 3, }; export const migrateConfigExtender: ConfigExtender = (resolvedConfig, config) => { resolvedConfig.migrate = mergeConfigs(config.migrate, defaultConfig); }; export const mergeConfigs = ( externalConfig: DeepPartial<MigrateConfig> | undefined, migrateConfig: MigrateConfig, ): MigrateConfig => { if (externalConfig) { return deepMerge(migrateConfig, externalConfig); } return migrateConfig; }; export function convertFlatToNested(flatConfig: MigrateConfigArgs): Partial<MigrateConfig> { const result: Partial<MigrateConfig> = {}; if (flatConfig.from || flatConfig.to || flatConfig.only || flatConfig.skip) { result.filter = {} as any; } if (flatConfig.from) result.filter!.from = flatConfig.from; if (flatConfig.to) result.filter!.to = flatConfig.to; if (flatConfig.only) result.filter!.only = flatConfig.only; if (flatConfig.skip) result.filter!.skip = flatConfig.skip; if (flatConfig.verify || flatConfig.verificationDelay || flatConfig.verifyParallel || flatConfig.verifyAttempts) { result.verification = {} as any; } if (flatConfig.verify) result.verification!.verify = flatConfig.verify; if (flatConfig.verificationDelay) result.verification!.verificationDelay = flatConfig.verificationDelay; if (flatConfig.verifyParallel) result.verification!.verifyParallel = flatConfig.verifyParallel; if (flatConfig.verifyAttempts) result.verification!.verifyAttempts = flatConfig.verifyAttempts; if (flatConfig.pathToMigrations || flatConfig.namespace || flatConfig.reportPath || flatConfig.reportFormat) { result.paths = {} as any; } if (flatConfig.pathToMigrations) result.paths!.pathToMigrations = flatConfig.pathToMigrations; if (flatConfig.namespace) result.paths!.namespace = flatConfig.namespace; if (flatConfig.reportPath) result.paths!.reportPath = flatConfig.reportPath; if (flatConfig.reportFormat) result.paths!.reportFormat = flatConfig.reportFormat; if (flatConfig.force || flatConfig.continue || flatConfig.wait || flatConfig.transactionStatusCheckInterval) { result.execution = {} as any; } if (flatConfig.force) result.execution!.force = flatConfig.force; if (flatConfig.continue) result.execution!.continue = flatConfig.continue; if (flatConfig.wait) result.execution!.wait = flatConfig.wait; if (flatConfig.transactionStatusCheckInterval) result.execution!.transactionStatusCheckInterval = flatConfig.transactionStatusCheckInterval; if (flatConfig.passwordFile || flatConfig.keystore || flatConfig.account) { result.castWallet = {} as any; } if (flatConfig.passwordFile) result.castWallet!.passwordFile = flatConfig.passwordFile; if (flatConfig.keystore) result.castWallet!.keystore = flatConfig.keystore; if (flatConfig.account) result.castWallet!.account = flatConfig.account; if (flatConfig.trezorEnabled || flatConfig.trezorMnemonicIndex) { result.trezorWallet = {} as any; } if (flatConfig.trezorEnabled) result.trezorWallet!.enabled = flatConfig.trezorEnabled; if (flatConfig.trezorMnemonicIndex) result.trezorWallet!.mnemonicIndex = flatConfig.trezorMnemonicIndex; return result; } // Deep merge utility for nested objects function deepMerge(target: any, source: any): any { const output = { ...target }; if (isObject(target) && isObject(source)) { Object.keys(source).forEach((key) => { if (isObject(source[key])) { if (!(key in target)) { Object.assign(output, { [key]: source[key] }); } else { output[key] = deepMerge(target[key], source[key]); } } else { Object.assign(output, { [key]: source[key] }); } }); } return output; } function isObject(item: any): boolean { return item && typeof item === "object" && !Array.isArray(item); } export const validateConfig = (config: MigrateConfig): void => { if (config.execution.wait !== undefined && config.execution.wait < 1) { throw new HardhatPluginError(pluginName, "config.migrate.execution.wait must be greater than 0"); } if (config.verification.verifyParallel !== undefined && config.verification.verifyParallel < 1) { throw new HardhatPluginError(pluginName, "config.migrate.verification.verifyParallel must be greater than 0"); } if (config.verification.verifyAttempts !== undefined && config.verification.verifyAttempts < 1) { throw new HardhatPluginError(pluginName, "config.migrate.verification.verifyAttempts must be greater than 0"); } if (config.paths.pathToMigrations !== undefined && !isRelativePath(config.paths.pathToMigrations)) { throw new HardhatPluginError(pluginName, "config.migrate.paths.pathToMigrations must be a relative path"); } if (config.paths.reportFormat !== undefined && !["json", "md"].includes(config.paths.reportFormat)) { throw new HardhatPluginError(pluginName, "config.migrate.paths.reportFormat must be either 'json' or 'md'"); } if (config.trezorWallet.enabled && config.castWallet.account) { throw new HardhatPluginError( pluginName, "config.migrate.trezorWallet.enabled and config.migrate.castWallet.account cannot be enabled at the same time", ); } if (config.castWallet.account && config.castWallet.keystore) { throw new HardhatPluginError( pluginName, "config.migrate.castWallet.account and config.migrate.castWallet.keystore cannot be enabled at the same time", ); } if ( config.execution.transactionStatusCheckInterval !== undefined && config.execution.transactionStatusCheckInterval < 1000 ) { throw new HardhatPluginError( pluginName, "config.migrate.execution.transactionStatusCheckInterval must be greater or equal to 1000", ); } }; export const extendVerifyConfigs = (cliArgs: Partial<MigrateVerifyConfig> | undefined): MigrateVerifyConfig => { const config = cliArgs === undefined ? defaultVerifyConfig : { ...defaultVerifyConfig, ...definedProps(cliArgs) }; if (config.parallel !== undefined && config.parallel < 1) { throw new HardhatPluginError(pluginName, "parallel must be greater than 0"); } if (config.attempts !== undefined && config.attempts < 1) { throw new HardhatPluginError(pluginName, "attempts must be greater than 0"); } return config; }; const definedProps = (obj: any): any => Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined)); const isRelativePath = (path?: string): boolean => path === undefined || !isAbsolute(path);