From 5d4d951fa9f5595ea55bbd98dba328b9a1a15327 Mon Sep 17 00:00:00 2001 From: dule-git <61541725+dule-git@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:15:14 +0200 Subject: [PATCH] extract ethers from hardhat-tenderly-core (#201) --- packages/tenderly-hardhat/package.json | 15 +- .../src/hre-extender/ethers.ts | 354 ------------------ .../src/hre-extender/extender.ts | 354 ------------------ .../src/hre-extender/hardhat-deploy.ts | 39 -- packages/tenderly-hardhat/src/index.ts | 16 +- .../src/tenderly/ethers/Contract.ts | 133 ------- .../src/tenderly/ethers/ContractFactory.ts | 75 ---- .../src/tenderly/ethers/ProxyContract.ts | 48 --- .../src/tenderly/types/utils.ts | 2 +- .../src/{hre-extender => }/type-extensions.ts | 11 +- packages/tenderly-hardhat/tsconfig.json | 4 +- 11 files changed, 19 insertions(+), 1032 deletions(-) delete mode 100644 packages/tenderly-hardhat/src/hre-extender/ethers.ts delete mode 100644 packages/tenderly-hardhat/src/hre-extender/extender.ts delete mode 100644 packages/tenderly-hardhat/src/hre-extender/hardhat-deploy.ts delete mode 100644 packages/tenderly-hardhat/src/tenderly/ethers/Contract.ts delete mode 100644 packages/tenderly-hardhat/src/tenderly/ethers/ContractFactory.ts delete mode 100644 packages/tenderly-hardhat/src/tenderly/ethers/ProxyContract.ts rename packages/tenderly-hardhat/src/{hre-extender => }/type-extensions.ts (98%) diff --git a/packages/tenderly-hardhat/package.json b/packages/tenderly-hardhat/package.json index c3cb0ff8..129e5d9d 100644 --- a/packages/tenderly-hardhat/package.json +++ b/packages/tenderly-hardhat/package.json @@ -1,10 +1,10 @@ { - "name": "@tenderly/hardhat-tenderly", + "name": "@tenderly/hardhat-tenderly-core", "author": "Tenderly", "license": "MIT", "homepage": "https://tenderly.co", "description": "Hardhat plugin for integration with Tenderly", - "version": "2.3.0", + "version": "0.0.0", "main": "dist/index.js", "types": "dist/index.d.ts", "repository": { @@ -24,8 +24,8 @@ "README.md" ], "scripts": { - "build": "rm -rf ./dist && tsc --build .", - "clean": "rm -rf node_modules && rm -rf dist", + "build": "rm -rf ./dist && rm -f tsconfig.tsbuildinfo && tsc --build .", + "clean": "rm -rf node_modules && rm -rf dist && rm -f tsconfig.tsbuildinfo", "lint": "yarn run prettier --check && yarn run eslint", "lint:fix": "yarn run prettier --write && yarn run eslint --fix", "eslint": "eslint 'src/**/*.ts'", @@ -48,13 +48,7 @@ "typescript": "^5.5.4" }, "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@nomicfoundation/hardhat-ignition": "^0.15.5", - "@nomicfoundation/hardhat-verify": "^2.0.8", - "@openzeppelin/hardhat-upgrades": "^3.0.1", - "@openzeppelin/upgrades-core": "^1.32.2", "axios": "^1.6.7", - "ethers": "^6.8.1", "fs-extra": "^10.1.0", "hardhat-deploy": "^0.11.43", "tenderly": "^0.9.1", @@ -63,7 +57,6 @@ "typescript": "^5.5.4" }, "peerDependencies": { - "ethers": "^6.8.1", "hardhat": "^2.22.6" } } diff --git a/packages/tenderly-hardhat/src/hre-extender/ethers.ts b/packages/tenderly-hardhat/src/hre-extender/ethers.ts deleted file mode 100644 index 9b2a96e3..00000000 --- a/packages/tenderly-hardhat/src/hre-extender/ethers.ts +++ /dev/null @@ -1,354 +0,0 @@ -import { Contract, ContractFactory, ethers } from "ethers"; -import { Artifact, HardhatRuntimeEnvironment } from "hardhat/types"; -import { - Libraries, - FactoryOptions, - HardhatEthersHelpers, - DeployContractOptions, -} from "@nomicfoundation/hardhat-ethers/types"; - -import { upgrades } from "hardhat"; -import { - ContractAddressOrInstance, - DeployBeaconProxyOptions, - DeployProxyOptions, -} from "@openzeppelin/hardhat-upgrades/dist/utils"; -import { TenderlyPlugin } from "./type-extensions"; -import { logger } from "../utils/logger"; -import { TdlyContractFactory } from "../tenderly/ethers/ContractFactory"; -import { TdlyContract } from "../tenderly/ethers/Contract"; -import { TdlyProxyContract } from "../tenderly/ethers/ProxyContract"; - -export function wrapEthers( - nativeEthers: typeof ethers & HardhatEthersHelpers, - tenderly: TenderlyPlugin, -): typeof ethers & HardhatEthersHelpers { - // Factory - nativeEthers.getContractFactoryFromArtifact = - wrapGetContractFactoryFromArtifact( - nativeEthers.getContractFactoryFromArtifact, - tenderly, - ) as typeof nativeEthers.getContractFactoryFromArtifact; - nativeEthers.getContractFactory = wrapGetContractFactory( - nativeEthers.getContractFactory, - tenderly, - ) as typeof nativeEthers.getContractFactory; - - // Ethers's deployContract - nativeEthers.deployContract = wrapDeployContract( - nativeEthers.deployContract, - tenderly, - ) as typeof nativeEthers.deployContract; - - // Contract - nativeEthers.getContractAtFromArtifact = wrapGetContractAtFromArtifact( - nativeEthers.getContractAtFromArtifact, - tenderly, - ) as typeof nativeEthers.getContractAtFromArtifact; - nativeEthers.getContractAt = wrapGetContractAt( - nativeEthers.getContractAt, - tenderly, - ) as typeof nativeEthers.getContractAt; - - return nativeEthers; -} - -export function wrapUpgrades( - hre: HardhatRuntimeEnvironment, - nativeUpgrades: typeof upgrades & HardhatEthersHelpers, - tenderly: TenderlyPlugin, -): typeof upgrades & HardhatEthersHelpers { - // Deploy Proxy - nativeUpgrades.deployProxy = wrapDeployProxy( - hre, - nativeUpgrades.deployProxy, - tenderly, - ) as typeof nativeUpgrades.deployProxy; - - // Deploy BeaconProxy - nativeUpgrades.deployBeaconProxy = wrapDeployBeaconProxy( - hre, - nativeUpgrades.deployBeaconProxy, - tenderly, - ) as typeof nativeUpgrades.deployBeaconProxy; - - return nativeUpgrades; -} - -export interface DeployFunction { - ( - ImplFactory: ContractFactory, - args?: unknown[], - opts?: DeployProxyOptions, - ): Promise; - (ImplFactory: ContractFactory, opts?: DeployProxyOptions): Promise; -} - -function wrapDeployProxy( - hre: HardhatRuntimeEnvironment, - func: DeployFunction, - tenderly: TenderlyPlugin, -): DeployFunction { - return async function ( - implFactory: ContractFactory, - argsOrOpts?: unknown[] | DeployProxyOptions, - opts?: DeployProxyOptions, - ) { - logger.debug("Calling ethers.Contract.deployProxy"); - let proxyContract; - if (opts !== undefined && opts !== null) { - proxyContract = await func(implFactory, argsOrOpts as unknown[], opts); - } else { - proxyContract = await func(implFactory, argsOrOpts as DeployProxyOptions); - } - - logger.debug("Returning TdlyProxyContract instance"); - return new TdlyProxyContract( - hre, - tenderly, - proxyContract, - ) as unknown as ethers.Contract; - }; -} - -export interface DeployBeaconProxyFunction { - ( - beacon: ContractAddressOrInstance, - attachTo: ContractFactory, - args?: unknown[], - opts?: DeployBeaconProxyOptions, - ): Promise; - ( - beacon: ContractAddressOrInstance, - attachTo: ContractFactory, - opts?: DeployBeaconProxyOptions, - ): Promise; -} - -function wrapDeployBeaconProxy( - hre: HardhatRuntimeEnvironment, - func: DeployBeaconProxyFunction, - tenderly: TenderlyPlugin, -): DeployBeaconProxyFunction { - return async function ( - beacon: ContractAddressOrInstance, - implFactory: ContractFactory, - argsOrOpts?: unknown[] | DeployBeaconProxyOptions, - opts?: DeployBeaconProxyOptions, - ): Promise { - if (isTdlyContractFactory(implFactory)) { - implFactory = implFactory.getNativeContractFactory(); - } - - let proxyContract; - if (opts !== undefined && opts !== null) { - proxyContract = await func( - beacon, - implFactory, - argsOrOpts as unknown[], - opts, - ); - } else { - proxyContract = await func( - beacon, - implFactory, - argsOrOpts as DeployBeaconProxyOptions, - ); - } - - return new TdlyProxyContract( - hre, - tenderly, - proxyContract, - ) as unknown as ethers.Contract; - }; -} - -function isTdlyContractFactory( - factory: ContractFactory | TdlyContractFactory, -): factory is TdlyContractFactory { - return ( - (factory as TdlyContractFactory).getNativeContractFactory !== undefined - ); -} - -export declare function getContractFactoryName( - name: string, - signerOrOptions?: ethers.Signer | FactoryOptions, -): Promise; - -export declare function getContractFactoryABI( - abi: any[], - bytecode: ethers.BytesLike, - signer?: ethers.Signer, -): Promise; - -function wrapGetContractFactory( - func: typeof getContractFactoryName | typeof getContractFactoryABI, - tenderly: TenderlyPlugin, -): typeof getContractFactoryName | typeof getContractFactoryABI { - return async function ( - nameOrAbi: string | any[], - bytecodeOrFactoryOptions?: - | (ethers.Signer | FactoryOptions) - | ethers.BytesLike, - signer?: ethers.Signer, - ): Promise { - if (typeof nameOrAbi === "string") { - const contractFactory = await (func as typeof getContractFactoryName)( - nameOrAbi, - bytecodeOrFactoryOptions as ethers.Signer | FactoryOptions, - ); - - let libs; - const factoryOpts = bytecodeOrFactoryOptions as - | ethers.Signer - | FactoryOptions; - if (factoryOpts !== undefined && "libraries" in factoryOpts) { - libs = factoryOpts.libraries; - } - - return wrapContractFactory(contractFactory, tenderly, nameOrAbi, libs); - } - - return (func as typeof getContractFactoryABI)( - nameOrAbi, - bytecodeOrFactoryOptions as ethers.BytesLike, - signer, - ); - }; -} - -export declare function deployContract( - name: string, - signerOrOptions?: ethers.Signer | DeployContractOptions, -): Promise; - -function wrapDeployContract( - func: typeof deployContract, - tenderly: TenderlyPlugin, -): typeof deployContract { - return async function ( - name: string, - signerOrOptions?: ethers.Signer | DeployContractOptions, - ): Promise { - const contract = await func(name, signerOrOptions); - - let libraries; - if (signerOrOptions !== undefined && "libraries" in signerOrOptions) { - libraries = signerOrOptions.libraries; - } - - return new TdlyContract( - contract, - tenderly, - name, - libraries, - ) as unknown as ethers.Contract; - }; -} - -export declare function getContractAt( - nameOrAbi: string | any[], - address: string, - signer?: ethers.Signer, -): Promise; - -function wrapGetContractAt( - func: typeof getContractAt, - tenderly: TenderlyPlugin, -): typeof getContractAt { - return async function ( - nameOrAbi: string | any[], - address: string, - signer?: ethers.Signer, - ): Promise { - if (typeof nameOrAbi === "string") { - const contract = await func(nameOrAbi, address, signer); - await tryToVerify(tenderly, nameOrAbi, contract); - - return contract; - } - - return func(nameOrAbi, address, signer); - }; -} - -export declare function getContractFactoryFromArtifact( - artifact: Artifact, - signerOrOptions?: ethers.Signer | FactoryOptions, -): Promise; - -function wrapGetContractFactoryFromArtifact( - func: typeof getContractFactoryFromArtifact, - tenderly: TenderlyPlugin, -): typeof getContractFactoryFromArtifact { - return async function ( - artifact: Artifact, - signerOrOptions?: ethers.Signer | FactoryOptions, - ): Promise { - const contractFactory = await func(artifact, signerOrOptions); - - let libs; - const factoryOpts = signerOrOptions as ethers.Signer | FactoryOptions; - if (factoryOpts !== undefined && "libraries" in factoryOpts) { - libs = factoryOpts.libraries; - } - - return wrapContractFactory( - contractFactory, - tenderly, - artifact.contractName, - libs, - ); - }; -} - -export declare function getContractAtFromArtifact( - artifact: Artifact, - address: string, - signer?: ethers.Signer, -): Promise; - -function wrapGetContractAtFromArtifact( - func: typeof getContractAtFromArtifact, - tenderly: TenderlyPlugin, -): typeof getContractAtFromArtifact { - return async function ( - artifact: Artifact, - address: string, - signer?: ethers.Signer, - ): Promise { - const contract = await func(artifact, address, signer); - await tryToVerify(tenderly, artifact.contractName, contract); - - return contract; - }; -} - -function wrapContractFactory( - contractFactory: ethers.ContractFactory, - tenderly: TenderlyPlugin, - name: string, - libraries?: Libraries, -): ethers.ContractFactory { - contractFactory = new TdlyContractFactory( - contractFactory, - tenderly, - name, - libraries, - ) as unknown as ethers.ContractFactory; - - return contractFactory; -} - -async function tryToVerify( - tenderly: TenderlyPlugin, - name: string, - contract: ethers.Contract, -) { - await tenderly.verify({ - name, - address: await contract.getAddress(), - }); -} diff --git a/packages/tenderly-hardhat/src/hre-extender/extender.ts b/packages/tenderly-hardhat/src/hre-extender/extender.ts deleted file mode 100644 index 2e36dd6c..00000000 --- a/packages/tenderly-hardhat/src/hre-extender/extender.ts +++ /dev/null @@ -1,354 +0,0 @@ -import "@openzeppelin/hardhat-upgrades"; -import { lazyObject } from "hardhat/plugins"; -import { extendConfig, extendEnvironment } from "hardhat/config"; -import { - HardhatRuntimeEnvironment, - HttpNetworkConfig, - HardhatConfig, - Network, -} from "hardhat/types"; -import { HardhatEthersHelpers } from "@nomicfoundation/hardhat-ethers/types"; -import { TenderlyService } from "tenderly"; -import { logger as serviceLogger } from "tenderly/utils/logger"; -import { TenderlyNetwork as TenderlyNetworkInterface } from "tenderly/types"; -import { - CHAIN_ID_NETWORK_NAME_MAP, - NETWORK_NAME_CHAIN_ID_MAP, - TENDERLY_JSON_RPC_BASE_URL, -} from "tenderly/common/constants"; - -import { ethers } from "ethers"; -import { upgrades } from "hardhat"; -import { getAccessToken } from "tenderly/utils/config"; -import { logger } from "../utils/logger"; -import { Tenderly } from "../Tenderly"; -import { TenderlyNetwork } from "../TenderlyNetwork"; -import { PLUGIN_NAME } from "../constants"; -import { - isHttpNetworkConfig, - isTenderlyGatewayNetworkConfig, - isTenderlyNetworkConfig, -} from "../utils/util"; -import * as URLComposer from "../utils/url-composer"; -import { wrapEthers, wrapUpgrades } from "./ethers"; -import { wrapHHDeployments } from "./hardhat-deploy"; -import { getVnetTypeByEndpointId, VnetType } from "../tenderly/vnet-type"; - -const tenderlyService = new TenderlyService(PLUGIN_NAME); - -export function setup() { - // set to loggers to error level by default - logger.settings.minLevel = 4; - serviceLogger.settings.minLevel = 4; - - extendEnvironment(async (hre: HardhatRuntimeEnvironment) => { - hre.tenderly = lazyObject(() => new Tenderly(hre)); - - if (hre.hardhatArguments.verbose) { - logger.settings.minLevel = 1; // trace level - serviceLogger.settings.minLevel = 1; // trace level - } - logger.info( - `Setting up hardhat-tenderly plugin. Log level of hardhat tenderly plugin set to: ${logger.settings.minLevel}`, - ); - // serviceLogger is used here just for initialization, nothing else, it will be used in TenderlyService.ts - serviceLogger.info( - `Log level of tenderly service set to: ${serviceLogger.settings.minLevel}`, - ); - - const pjson = require("../../package.json"); - logger.info("@tenderly/hardhat-tenderly version:", pjson.version); - - logger.info("Tenderly running configuration: ", { - username: hre.config.tenderly?.username, - project: hre.config.tenderly?.project, - automaticVerification: process.env.AUTOMATIC_VERIFICATION_ENABLED, - privateVerification: hre.config.tenderly?.privateVerification, - networkName: hre.network.name, - }); - - extendProvider(hre); - populateNetworks(); - if (process.env.AUTOMATIC_VERIFICATION_ENABLED === "true") { - logger.debug( - "Automatic verification is enabled, proceeding to extend ethers library.", - ); - extendEthers(hre); - extendUpgrades(hre); - extendHardhatDeploy(hre); - logger.debug("Wrapping ethers library finished."); - } - - if (shouldPopulateHardhatVerifyConfig(hre)) { - logger.info( - "Automatic population of hardhat-verify `etherscan` configuration is enabled.", - ); - // If the config already exists, we should not overwrite it, either remove it or turn off automatic population. - const etherscanConfig = await findEtherscanConfig(hre); - if (etherscanConfig !== undefined) { - throw new Error( - `Hardhat-verify's 'etherscan' configuration with network '${ - hre.network.name - }' is already populated. Please remove the following configuration:\n${JSON.stringify( - etherscanConfig, - null, - 2, - )}\nOr set 'TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG' environment variable to 'false'`, - ); - } - await populateHardhatVerifyConfig(hre); - } - - logger.debug("Setup finished."); - }); -} - -extendEnvironment((hre: HardhatRuntimeEnvironment) => { - hre.tenderly = lazyObject(() => new Tenderly(hre)); - extendProvider(hre); - populateNetworks(); -}); - -extendConfig((resolvedConfig: HardhatConfig) => { - resolvedConfig.networks.tenderly = { - ...resolvedConfig.networks.tenderly, - }; -}); - -const extendProvider = (hre: HardhatRuntimeEnvironment): void => { - if (!isTenderlyNetworkConfig(hre.network.config)) { - logger.info( - `Used network is not 'tenderly' so there is no extending of the provider.`, - ); - return; - } - - if ("url" in hre.network.config && hre.network.config.url !== undefined) { - if (hre.network.config.url.includes("devnet")) { - const devnetID = hre.network.config.url.split("/").pop(); - hre.tenderly.network().setDevnetID(devnetID); - logger.info( - `There is a devnet url in the '${hre.network.name}' network`, - { devnetID }, - ); - return; - } - const forkID = hre.network.config.url.split("/").pop(); - hre.tenderly.network().setFork(forkID); - logger.info(`There is a fork url in the 'tenderly' network`, { forkID }); - return; - } - - const tenderlyNetwork = new TenderlyNetwork(hre); - tenderlyNetwork - .initializeFork() - .then(async (_) => { - hre.tenderly.setNetwork(tenderlyNetwork); - const forkID = await hre.tenderly.network().getForkID(); - ( - hre.network.config as HttpNetworkConfig - ).url = `${TENDERLY_JSON_RPC_BASE_URL}/fork/${forkID ?? ""}`; - // hre.ethers.provider = new hre.ethers.BrowserProvider(hre.tenderly.network()); - }) - .catch((_) => { - logger.error( - `Error happened while trying to initialize fork ${PLUGIN_NAME}. Check your tenderly configuration`, - ); - }); -}; - -const populateNetworks = (): void => { - tenderlyService - .getNetworks() - .then((networks: TenderlyNetworkInterface[]) => { - let network: TenderlyNetworkInterface; - let slug: string; - for (network of networks) { - NETWORK_NAME_CHAIN_ID_MAP[network.slug] = network.ethereum_network_id; - - if (network?.metadata?.slug !== undefined) { - NETWORK_NAME_CHAIN_ID_MAP[network.metadata.slug] = - network.ethereum_network_id; - } - - CHAIN_ID_NETWORK_NAME_MAP[network.ethereum_network_id] = network.slug; - - for (slug of network.metadata.secondary_slugs) { - NETWORK_NAME_CHAIN_ID_MAP[slug] = network.ethereum_network_id; - } - } - logger.silly( - "Obtained supported public networks: ", - NETWORK_NAME_CHAIN_ID_MAP, - ); - }) - .catch((_) => { - logger.error("Error encountered while fetching public networks"); - }); -}; - -const extendEthers = (hre: HardhatRuntimeEnvironment): void => { - if ( - "ethers" in hre && - hre.ethers !== undefined && - hre.ethers !== null && - "tenderly" in hre && - hre.tenderly !== undefined - ) { - Object.assign( - hre.ethers, - wrapEthers( - hre.ethers as unknown as typeof ethers & HardhatEthersHelpers, - hre.tenderly, - ) as unknown as typeof hre.ethers, - ); - } -}; - -const extendUpgrades = (hre: HardhatRuntimeEnvironment): void => { - if ( - "upgrades" in hre && - hre.upgrades !== undefined && - hre.upgrades !== null && - "tenderly" in hre && - hre.tenderly !== undefined - ) { - logger.debug("Extending upgrades library"); - Object.assign( - hre.upgrades, - wrapUpgrades( - hre, - hre.upgrades as unknown as typeof upgrades & HardhatEthersHelpers, - hre.tenderly, - ) as unknown as typeof hre.upgrades, - ); - } -}; - -// Returns true if the user has selected automatic population of hardhat-verify `etherscan` configuration through the TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG env variable, -// and the network is some of the Tenderly networks. -function shouldPopulateHardhatVerifyConfig( - hre: HardhatRuntimeEnvironment, -): boolean { - return ( - // Must cover both since AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG is the legacy because we didn't use the TENDERLY_ prefix. - (process.env.TENDERLY_AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG === "true" || - process.env.AUTOMATIC_POPULATE_HARDHAT_VERIFY_CONFIG === "true") && - (isTenderlyNetworkConfig(hre.network.config) || - isTenderlyGatewayNetworkConfig(hre.network.config)) && - isHttpNetworkConfig(hre.network.config) - ); -} - -// populateHardhatVerifyConfig will populate `hre.config.etherscan` configuration of the `@nomicfoundation/hardhat-verify` plugin. -// This function should import `@nomicfoundation/hardhat-verify` type declaration expansion of the `HardhatConfig`, but can't since there will be double overloading task error if the client application also uses `@nomicfoundation/hardhat-verify` plugin. -async function populateHardhatVerifyConfig( - hre: HardhatRuntimeEnvironment, -): Promise { - if ( - (!isTenderlyNetworkConfig(hre.network.config) && - !isTenderlyGatewayNetworkConfig(hre.network.config)) || - !isHttpNetworkConfig(hre.network.config) - ) { - return; - } - - const accessKey = getAccessToken(); - if (accessKey === "") { - logger.error( - "Tenderly access key is not set. Please set TENDERLY_ACCESS_KEY environment variable.", - ); - return; - } - - if ( - (hre.config as any).etherscan === undefined || - (hre.config as any).etherscan === null - ) { - (hre.config as any).etherscan = { - apiKey: accessKey, - customChains: [], - }; - } - - if ( - isRecord((hre.config as any).etherscan.apiKey) && - (hre.config as any).etherscan.apiKey[hre.network.name] === undefined - ) { - (hre.config as any).etherscan.apiKey[hre.network.name] = accessKey; - } else if (typeof (hre.config as any).etherscan.apiKey === "string") { - (hre.config as any).etherscan.apiKey = accessKey; - } - - const chainId = await getChainId(hre.network); - - const endpointId = hre.network.config.url.split("/").pop(); - if (endpointId === undefined) { - throw new Error( - "Could not locate the UUID at the end of a Tenderly RPC URL.", - ); - } - - const vnetType = await getVnetTypeByEndpointId(hre, endpointId); - if (vnetType === VnetType.NULL_TYPE) { - throw new Error("Couldn't recognize VnetType from endpoint id."); - } - - (hre.config as any).etherscan.customChains.push({ - network: hre.network.name, - chainId, - urls: { - apiURL: URLComposer.composeApiURL(hre, endpointId, chainId, vnetType), - browserURL: URLComposer.composeBrowserURL( - hre, - endpointId, - chainId, - vnetType, - ), - }, - }); -} - -function isRecord(value: any): value is Record { - return typeof value === "object" && value !== null && !Array.isArray(value); -} - -async function getChainId(network: Network): Promise { - if (network.config.chainId !== undefined && network.config.chainId !== null) { - return network.config.chainId; - } - - return Number(await network.provider.send("eth_chainId", [])); -} - -async function findEtherscanConfig( - hre: HardhatRuntimeEnvironment, -): Promise { - if ((hre.config as any).etherscan === undefined) { - return undefined; - } - if ((hre.config as any).etherscan.customChains === undefined) { - return undefined; - } - - return ((hre.config as any).etherscan.customChains as any[]).find( - (chainConfig) => { - return chainConfig.network === hre.network.name; - }, - ); -} - -const extendHardhatDeploy = (hre: HardhatRuntimeEnvironment): void => { - // ts-ignore is needed here because we want to avoid importing hardhat-deploy in order not to cause duplicated initialization of the .deployments field - if ( - "deployments" in hre && - // @ts-ignore - hre.deployments !== undefined && - "tenderly" in hre && - // @ts-ignore - hre.tenderly !== undefined - ) { - // @ts-ignore - hre.deployments = wrapHHDeployments(hre.deployments, hre.tenderly); - } -}; diff --git a/packages/tenderly-hardhat/src/hre-extender/hardhat-deploy.ts b/packages/tenderly-hardhat/src/hre-extender/hardhat-deploy.ts deleted file mode 100644 index 32c52e54..00000000 --- a/packages/tenderly-hardhat/src/hre-extender/hardhat-deploy.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { - DeploymentsExtension, - DeployOptions, - DeployResult, -} from "hardhat-deploy/types"; - -import { TenderlyPlugin } from "./type-extensions"; - -export function wrapHHDeployments( - deployments: DeploymentsExtension, - tenderly: TenderlyPlugin, -) { - deployments.deploy = wrapDeploy(deployments.deploy, tenderly); - - return deployments; -} - -export declare function hhDeploy( - name: string, - options: DeployOptions, -): Promise; - -function wrapDeploy( - deployFunc: typeof hhDeploy, - tenderly: TenderlyPlugin, -): typeof hhDeploy { - return async function ( - name: string, - options: DeployOptions, - ): Promise { - const depResult = await deployFunc(name, options); - await tenderly.verify({ - name, - address: depResult.address, - }); - - return depResult; - }; -} diff --git a/packages/tenderly-hardhat/src/index.ts b/packages/tenderly-hardhat/src/index.ts index a4450fcf..a3707445 100644 --- a/packages/tenderly-hardhat/src/index.ts +++ b/packages/tenderly-hardhat/src/index.ts @@ -1,17 +1,11 @@ -import "./hre-extender/type-extensions"; import "./tasks"; +import { logger } from "./utils/logger"; -import * as tenderlyExtender from "./hre-extender/extender"; +logger.settings.minLevel = 4; // info level -export function setup( - cfg: { automaticVerifications: boolean } = { automaticVerifications: true }, -): void { - process.env.AUTOMATIC_VERIFICATION_ENABLED = cfg.automaticVerifications - ? "true" - : "false"; - - tenderlyExtender.setup(); -} +export { Tenderly } from "./Tenderly"; +export { TenderlyNetwork } from "./TenderlyNetwork"; +export * from "./type-extensions"; // ProxyPlaceholderName is used for the `name` parameter in the `tenderly.verify` method because the name is actually not important. // Beneath we use `@nomicfoundation/hardhat-verify` task in order to verify the proxy, and it doesn't need a name. diff --git a/packages/tenderly-hardhat/src/tenderly/ethers/Contract.ts b/packages/tenderly-hardhat/src/tenderly/ethers/Contract.ts deleted file mode 100644 index 672761ab..00000000 --- a/packages/tenderly-hardhat/src/tenderly/ethers/Contract.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { Contract, ethers } from "ethers"; -import { BigNumber } from "@ethersproject/bignumber"; -import { Libraries } from "@nomicfoundation/hardhat-ethers/types"; - -import { TenderlyPlugin } from "../../hre-extender/type-extensions"; -import { ContractByName } from "../types"; - -export class TdlyContract { - [key: string]: any; - - private readonly contractName: string; - private nativeContract: ethers.Contract; - private tenderly: TenderlyPlugin; - private readonly libraries: Libraries | undefined; - - constructor( - nativeContract: ethers.Contract, - tenderly: TenderlyPlugin, - contractName: string, - libs?: Libraries, - ) { - this.contractName = contractName; - this.nativeContract = nativeContract; - this.tenderly = tenderly; - this.libraries = libs; - - Object.keys(nativeContract).forEach((key) => { - if (this[key] !== undefined) { - return; - } - - if (key === "deploymentTransaction") { - const deploymentTransaction = nativeContract[key](); - if ( - deploymentTransaction === undefined || - deploymentTransaction === null - ) { - return; - } - - const wait = deploymentTransaction.wait; - - deploymentTransaction.wait = async ( - confirmations?: number | undefined, - ): Promise => { - const receipt = await wait(confirmations); - if (receipt === undefined || receipt === null) { - return null; - } - - if ( - receipt.contractAddress === undefined || - receipt.contractAddress === null - ) { - return receipt; - } - await this._tdlyVerify(receipt.contractAddress); - - return receipt; - }; - } - - this[key] = nativeContract[key]; - }); - } - - public async waitForDeployment(): Promise { - const contract = await this.nativeContract.waitForDeployment(); - const deploymentTransaction = this.nativeContract.deploymentTransaction(); - if (deploymentTransaction !== undefined && deploymentTransaction !== null) { - await this._tdlyVerify(await contract.getAddress()); - } - - return contract; - } - - public deploymentTransaction(): null | ethers.ContractTransactionResponse { - return this.nativeContract.deploymentTransaction(); - } - - public async getAddress(): Promise { - return this.nativeContract.getAddress(); - } - - private async _tdlyVerify(address: string) { - const contPair: ContractByName = { - name: this.contractName, - address, - }; - if (this.libraries !== undefined && this.libraries !== null) { - contPair.libraries = this.libraries; - } - - await this.tenderly.persistArtifacts(contPair); - await this.tenderly.verify(contPair); - } -} - -export interface TransactionReceipt { - to: string; - from: string; - contractAddress: string; - transactionIndex: number; - root?: string; - gasUsed: BigNumber; - logsBloom: string; - blockHash: string; - transactionHash: string; - logs: Log[]; - blockNumber: number; - confirmations: number; - cumulativeGasUsed: BigNumber; - effectiveGasPrice: BigNumber; - byzantium: boolean; - type: number; - status?: number; -} - -export interface Log { - blockNumber: number; - blockHash: string; - transactionIndex: number; - - removed: boolean; - - address: string; - data: string; - - topics: string[]; - - transactionHash: string; - logIndex: number; -} diff --git a/packages/tenderly-hardhat/src/tenderly/ethers/ContractFactory.ts b/packages/tenderly-hardhat/src/tenderly/ethers/ContractFactory.ts deleted file mode 100644 index d5fdaf4f..00000000 --- a/packages/tenderly-hardhat/src/tenderly/ethers/ContractFactory.ts +++ /dev/null @@ -1,75 +0,0 @@ -import { Contract, ContractFactory, Signer } from "ethers"; -import { Libraries } from "@nomicfoundation/hardhat-ethers/types"; - -import { classFunctions } from "../../utils/util"; -import { TenderlyPlugin } from "../../hre-extender/type-extensions"; -import { TdlyContract } from "./Contract"; - -export class TdlyContractFactory { - [key: string]: any; - - private readonly contractName: string; - private readonly libs: Libraries | undefined; - private readonly nativeContractFactory: ContractFactory; - private readonly tenderly: TenderlyPlugin; - - constructor( - nativeContractFactory: ContractFactory, - tenderly: TenderlyPlugin, - contractName: string, - libs?: Libraries, - ) { - this.nativeContractFactory = nativeContractFactory; - this.tenderly = tenderly; - this.contractName = contractName; - this.libs = libs; - - for (const attribute in Object.assign(nativeContractFactory)) { - if (this[attribute] !== undefined) { - continue; - } - this[attribute] = (nativeContractFactory as any)[attribute]; - } - - classFunctions(nativeContractFactory).forEach((funcName: string) => { - if (this[funcName] !== undefined) { - return; - } - this[funcName] = (nativeContractFactory as any)[funcName]; - }); - } - - public async deploy(...args: any[]): Promise { - const contract = await this.nativeContractFactory.deploy(...args); - - return new TdlyContract( - contract as Contract, - this.tenderly, - this.contractName, - this.libs, - ) as unknown as Contract; - } - - public connect(signer: Signer) { - const contractFactory = this.nativeContractFactory.connect(signer); - - return new TdlyContractFactory( - contractFactory, - this.tenderly, - this.contractName, - this.libs, - ); - } - - public getLibs(): Libraries | undefined { - return this.libs; - } - - public getContractName(): string { - return this.contractName; - } - - public getNativeContractFactory(): ContractFactory { - return this.nativeContractFactory; - } -} diff --git a/packages/tenderly-hardhat/src/tenderly/ethers/ProxyContract.ts b/packages/tenderly-hardhat/src/tenderly/ethers/ProxyContract.ts deleted file mode 100644 index bab51df2..00000000 --- a/packages/tenderly-hardhat/src/tenderly/ethers/ProxyContract.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ethers } from "ethers"; - -import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { TenderlyPlugin } from "../../hre-extender/type-extensions"; -import { logger } from "../../utils/logger"; - -export class TdlyProxyContract { - [key: string]: any; - - private readonly hre: HardhatRuntimeEnvironment; - private tenderly: TenderlyPlugin; - private proxyContract: ethers.Contract; - - constructor( - hre: HardhatRuntimeEnvironment, - tenderly: TenderlyPlugin, - proxyContract: ethers.Contract, - ) { - this.hre = hre; - this.tenderly = tenderly; - this.proxyContract = proxyContract; - } - - public async waitForDeployment(): Promise { - logger.debug("Waiting for deployment in TdlyProxyContract"); - - const proxyContract = await this.proxyContract.waitForDeployment(); - const deploymentTransaction = this.proxyContract.deploymentTransaction(); - if (deploymentTransaction !== undefined && deploymentTransaction !== null) { - // verify:verify task should verify the proxy (regardless of proxy type), implementation and all the related contracts. - logger.debug("Running hardhat-verify's verify task "); - await this.hre.run("verify:verify", { - address: await proxyContract.getAddress(), - constructorArguments: [], - }); - } - - return proxyContract; - } - - public deploymentTransaction(): null | ethers.ContractTransactionResponse { - return this.proxyContract.deploymentTransaction(); - } - - public async getAddress(): Promise { - return this.nativeContract.getAddress(); - } -} diff --git a/packages/tenderly-hardhat/src/tenderly/types/utils.ts b/packages/tenderly-hardhat/src/tenderly/types/utils.ts index 6eaccf4b..28f867d5 100644 --- a/packages/tenderly-hardhat/src/tenderly/types/utils.ts +++ b/packages/tenderly-hardhat/src/tenderly/types/utils.ts @@ -6,7 +6,7 @@ export interface BytecodeMismatchError { got: string; } -export interface TenderlyConfig { +export interface HardhatTenderlyConfig { project: string; username: string; forkNetwork?: string; diff --git a/packages/tenderly-hardhat/src/hre-extender/type-extensions.ts b/packages/tenderly-hardhat/src/type-extensions.ts similarity index 98% rename from packages/tenderly-hardhat/src/hre-extender/type-extensions.ts rename to packages/tenderly-hardhat/src/type-extensions.ts index a2c21493..347a26d8 100644 --- a/packages/tenderly-hardhat/src/hre-extender/type-extensions.ts +++ b/packages/tenderly-hardhat/src/type-extensions.ts @@ -5,10 +5,11 @@ import { TenderlyContractUploadRequest, TenderlyForkContractUploadRequest, TenderlyVerifyContractsRequest, -} from "src/tenderly/types"; +} from "tenderly/types"; -import { ContractByName, TenderlyConfig } from "../tenderly/types"; -import { TenderlyNetwork } from "../TenderlyNetwork"; +import { ContractByName } from "./tenderly/types"; +import { HardhatTenderlyConfig } from "./tenderly/types"; +import { TenderlyNetwork } from "./TenderlyNetwork"; export interface TenderlyPlugin { /** * @@ -424,10 +425,10 @@ declare module "hardhat/types/runtime" { declare module "hardhat/types/config" { export interface HardhatUserConfig { - tenderly?: TenderlyConfig; + tenderly?: HardhatTenderlyConfig; } export interface HardhatConfig { - tenderly: TenderlyConfig; + tenderly: HardhatTenderlyConfig; } } diff --git a/packages/tenderly-hardhat/tsconfig.json b/packages/tenderly-hardhat/tsconfig.json index 1e4f3511..9fcc211c 100644 --- a/packages/tenderly-hardhat/tsconfig.json +++ b/packages/tenderly-hardhat/tsconfig.json @@ -1,7 +1,9 @@ { "extends": "../../config/typescript/tsconfig.json", "compilerOptions": { - "outDir": "./dist" + "outDir": "./dist", + "rootDir": "./src", + "composite": true }, "exclude": ["./dist", "./node_modules"], "references": [