@nomiclabs/hardhat-etherscan
Advanced tools
Comparing version 2.1.1 to 2.1.8
@@ -59,2 +59,3 @@ "use strict"; | ||
const verifySubtask = async ({ address, constructorArguments, contract: contractFQN, libraries }, { config, network, run }) => { | ||
var _a; | ||
const { etherscan } = config; | ||
@@ -88,21 +89,16 @@ if (etherscan.apiKey === undefined || etherscan.apiKey.trim() === "") { | ||
}); | ||
if (matchingCompilerVersions.length === 0) { | ||
const detailedContext = []; | ||
if (isVersionRange(inferredSolcVersion)) { | ||
detailedContext.push(`The expected version range is ${inferredSolcVersion}.`); | ||
} | ||
else { | ||
detailedContext.push(`The expected version is ${inferredSolcVersion}.`); | ||
} | ||
// There is always at least one configured version. | ||
if (matchingCompilerVersions.length === 0 && | ||
// don't error if the bytecode appears to be OVM bytecode, because we can't infer a specific OVM solc version from the bytecode | ||
!deployedBytecode.isOvmInferred()) { | ||
let configuredCompilersFragment; | ||
if (compilerVersions.length > 1) { | ||
detailedContext.push(`The selected compiler versions are: ${compilerVersions.join(", ")}`); | ||
configuredCompilersFragment = `your configured compiler versions are: ${compilerVersions.join(", ")}`; | ||
} | ||
else { | ||
detailedContext.push(`The selected compiler version is: ${compilerVersions[0]}`); | ||
configuredCompilersFragment = `your configured compiler version is: ${compilerVersions[0]}`; | ||
} | ||
const message = `The bytecode retrieved could not have been generated by any of the selected compilers. | ||
${detailedContext.join("\n")} | ||
const message = `The contract you want to verify was compiled with solidity ${inferredSolcVersion}, but ${configuredCompilersFragment}. | ||
Possible causes are: | ||
- You are not in the same commit that was used to deploy the contract. | ||
- Wrong compiler version selected in hardhat config. | ||
@@ -121,4 +117,23 @@ - The given address is wrong. | ||
}); | ||
// Override solc version based on hardhat config if verifying for the OVM. This is used instead of fetching the | ||
// full version name from a solc bin JSON file (as is done for EVM solc in src/solc/version.ts) because it's | ||
// simpler and avoids a network request we don't need. This is ok because the solc version specified in the OVM | ||
// config always equals the full solc version | ||
if (deployedBytecode.isOvmInferred()) { | ||
// We cast to this custom type here instead of using `extendConfig` to avoid always mutating the HardhatConfig | ||
// type. We don't want that type to always contain the `ovm` field, because users only using hardhat-etherscan | ||
// without the Optimism plugin should not have that field in their type definitions | ||
const configCopy = Object.assign({}, config); | ||
const ovmSolcVersion = (_a = configCopy.ovm) === null || _a === void 0 ? void 0 : _a.solcVersion; | ||
if (ovmSolcVersion === undefined) { | ||
const message = `It looks like you are verifying an OVM contract, but do not have an OVM solcVersion specified in the hardhat config.`; | ||
throw new plugins_1.NomicLabsHardhatPluginError(constants_1.pluginName, message); | ||
} | ||
contractInformation.solcVersion = `v${ovmSolcVersion}`; // Etherscan requires the leading `v` before the version string | ||
} | ||
const deployArgumentsEncoded = await ABIEncoder_1.encodeArguments(contractInformation.contract.abi, contractInformation.sourceName, contractInformation.contractName, constructorArguments); | ||
const solcFullVersion = await version_1.getLongVersion(contractInformation.solcVersion); | ||
// If OVM, the full version string was already read from the hardhat config. If solc, get the full version string | ||
const solcFullVersion = deployedBytecode.isOvmInferred() | ||
? contractInformation.solcVersion | ||
: await version_1.getLongVersion(contractInformation.solcVersion); | ||
const minimumBuild = await run(constants_1.TASK_VERIFY_GET_MINIMUM_BUILD, { | ||
@@ -339,3 +354,4 @@ sourceName: contractInformation.sourceName, | ||
} | ||
if (!matchingCompilerVersions.includes(buildInfo.solcVersion)) { | ||
if (!matchingCompilerVersions.includes(buildInfo.solcVersion) && | ||
!deployedBytecode.isOvmInferred()) { | ||
const inferredSolcVersion = deployedBytecode.getInferredSolcVersion(); | ||
@@ -342,0 +358,0 @@ let versionDetails; |
@@ -17,2 +17,23 @@ "use strict"; | ||
NetworkID[NetworkID["BSC_TESTNET"] = 97] = "BSC_TESTNET"; | ||
// Huobi ECO Chain | ||
NetworkID[NetworkID["HECO"] = 128] = "HECO"; | ||
NetworkID[NetworkID["HECO_TESTNET"] = 256] = "HECO_TESTNET"; | ||
// Fantom mainnet | ||
NetworkID[NetworkID["OPERA"] = 250] = "OPERA"; | ||
NetworkID[NetworkID["FTM_TESTNET"] = 4002] = "FTM_TESTNET"; | ||
// Optimistim | ||
NetworkID[NetworkID["OPTIMISTIC_ETHEREUM"] = 10] = "OPTIMISTIC_ETHEREUM"; | ||
NetworkID[NetworkID["OPTIMISTIC_KOVAN"] = 69] = "OPTIMISTIC_KOVAN"; | ||
// Polygon | ||
NetworkID[NetworkID["POLYGON"] = 137] = "POLYGON"; | ||
NetworkID[NetworkID["POLYGON_MUMBAI"] = 80001] = "POLYGON_MUMBAI"; | ||
// Arbitrum | ||
NetworkID[NetworkID["ARBITRUM_ONE"] = 42161] = "ARBITRUM_ONE"; | ||
NetworkID[NetworkID["ARBITRUM_TESTNET"] = 421611] = "ARBITRUM_TESTNET"; | ||
// Avalanche | ||
NetworkID[NetworkID["AVALANCHE"] = 43114] = "AVALANCHE"; | ||
NetworkID[NetworkID["AVALANCHE_FUJI_TESTNET"] = 43113] = "AVALANCHE_FUJI_TESTNET"; | ||
// Moonriver | ||
NetworkID[NetworkID["MOONRIVER"] = 1285] = "MOONRIVER"; | ||
NetworkID[NetworkID["MOONBASE_ALPHA"] = 1287] = "MOONBASE_ALPHA"; | ||
})(NetworkID || (NetworkID = {})); | ||
@@ -22,3 +43,3 @@ const networkIDtoEndpoints = { | ||
apiURL: "https://api.etherscan.io/api", | ||
browserURL: "https://etherscan.io/", | ||
browserURL: "https://etherscan.io", | ||
}, | ||
@@ -49,2 +70,58 @@ [NetworkID.ROPSTEN]: { | ||
}, | ||
[NetworkID.HECO]: { | ||
apiURL: "https://api.hecoinfo.com/api", | ||
browserURL: "https://hecoinfo.com", | ||
}, | ||
[NetworkID.HECO_TESTNET]: { | ||
apiURL: "https://api-testnet.hecoinfo.com/api", | ||
browserURL: "https://testnet.hecoinfo.com", | ||
}, | ||
[NetworkID.OPERA]: { | ||
apiURL: "https://api.ftmscan.com/api", | ||
browserURL: "https://ftmscan.com", | ||
}, | ||
[NetworkID.FTM_TESTNET]: { | ||
apiURL: "https://api-testnet.ftmscan.com/api", | ||
browserURL: "https://testnet.ftmscan.com", | ||
}, | ||
[NetworkID.OPTIMISTIC_ETHEREUM]: { | ||
apiURL: "https://api-optimistic.etherscan.io/api", | ||
browserURL: "https://optimistic.etherscan.io/", | ||
}, | ||
[NetworkID.OPTIMISTIC_KOVAN]: { | ||
apiURL: "https://api-kovan-optimistic.etherscan.io/api", | ||
browserURL: "https://kovan-optimistic.etherscan.io/", | ||
}, | ||
[NetworkID.POLYGON]: { | ||
apiURL: "https://api.polygonscan.com/api", | ||
browserURL: "https://polygonscan.com", | ||
}, | ||
[NetworkID.POLYGON_MUMBAI]: { | ||
apiURL: "https://api-testnet.polygonscan.com/api", | ||
browserURL: "https://mumbai.polygonscan.com/", | ||
}, | ||
[NetworkID.ARBITRUM_ONE]: { | ||
apiURL: "https://api.arbiscan.io/api", | ||
browserURL: "https://arbiscan.io/", | ||
}, | ||
[NetworkID.ARBITRUM_TESTNET]: { | ||
apiURL: "https://api-testnet.arbiscan.io/api", | ||
browserURL: "https://testnet.arbiscan.io/", | ||
}, | ||
[NetworkID.AVALANCHE]: { | ||
apiURL: "https://api.snowtrace.io/api", | ||
browserURL: "https://snowtrace.io/", | ||
}, | ||
[NetworkID.AVALANCHE_FUJI_TESTNET]: { | ||
apiURL: "https://api-testnet.snowtrace.io/api", | ||
browserURL: "https://testnet.snowtrace.io/", | ||
}, | ||
[NetworkID.MOONRIVER]: { | ||
apiURL: "https://api-moonriver.moonscan.io/api", | ||
browserURL: "https://moonscan.io", | ||
}, | ||
[NetworkID.MOONBASE_ALPHA]: { | ||
apiURL: "https://api-moonbase.moonscan.io/api", | ||
browserURL: "https://moonbase.moonscan.io/", | ||
}, | ||
}; | ||
@@ -51,0 +128,0 @@ async function getEtherscanEndpoints(provider, networkName) { |
@@ -28,2 +28,3 @@ import { Artifacts, BuildInfo, CompilerInput, CompilerOutput, CompilerOutputBytecode } from "hardhat/types"; | ||
private _version; | ||
private _isOvm; | ||
private _executableSection; | ||
@@ -33,2 +34,3 @@ private _metadataSection; | ||
getInferredSolcVersion(): string; | ||
isOvmInferred(): boolean; | ||
getExecutableSection(): string; | ||
@@ -35,0 +37,0 @@ hasMetadata(): boolean; |
@@ -6,2 +6,11 @@ "use strict"; | ||
const metadata_1 = require("./metadata"); | ||
// If the compiler output bytecode is OVM bytecode, we need to make a fix to account for a bug in some versions of | ||
// the OVM compiler. The artifact’s deployedBytecode is incorrect, but because its bytecode (initcode) is correct, when we | ||
// actually deploy contracts, the code that ends up getting stored on chain is also correct. During verification, | ||
// Etherscan will compile the source code, pull out the artifact’s deployedBytecode, and then perform the | ||
// below find and replace, then check that resulting output against the code retrieved on chain from eth_getCode. | ||
// We define the strings for that find and replace here, and use them later so we can know if the bytecode matches | ||
// before it gets to Etherscan. Source: https://github.com/ethereum-optimism/optimism/blob/8d67991aba584c1703692ea46273ea8a1ef45f56/packages/contracts/src/contract-dumps.ts#L195-L204 | ||
const ovmFindOpcodes = "336000905af158601d01573d60011458600c01573d6000803e3d621234565260ea61109c52"; | ||
const ovmReplaceOpcodes = "336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b"; | ||
class Bytecode { | ||
@@ -20,2 +29,14 @@ constructor(bytecode) { | ||
}; | ||
// Check if this is OVM bytecode by looking for the concatenation of the two opcodes defined here: | ||
// https://github.com/ethereum-optimism/optimism/blob/33cb9025f5e463525d6abe67c8457f81a87c5a24/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_SafetyChecker.sol#L143 | ||
// - This check would only fail if the EVM solidity compiler didn't use any of the following opcodes: https://github.com/ethereum-optimism/optimism/blob/c42fc0df2790a5319027393cb8fa34e4f7bb520f/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol#L94-L175 | ||
// This is the list of opcodes that calls the OVM execution manager. But the current solidity | ||
// compiler seems to add REVERT in all cases, meaning it currently won't happen and this check | ||
// will always be correct. | ||
// - It is possible, though very unlikely, that this string appears in the bytecode of an EVM | ||
// contract. As a result result, this _isOvm flag should only be used after trying to infer | ||
// the solc version | ||
// - We need this check because OVM bytecode has no metadata, so when verifying | ||
// OVM bytecode the check in `inferSolcVersion` will always return `METADATA_ABSENT_VERSION_RANGE`. | ||
this._isOvm = bytecode.includes(ovmReplaceOpcodes); | ||
} | ||
@@ -25,2 +46,5 @@ getInferredSolcVersion() { | ||
} | ||
isOvmInferred() { | ||
return this._isOvm; | ||
} | ||
getExecutableSection() { | ||
@@ -43,3 +67,5 @@ const { start, length } = this._executableSection; | ||
} | ||
if (!matchingCompilerVersions.includes(buildInfo.solcVersion)) { | ||
if (!matchingCompilerVersions.includes(buildInfo.solcVersion) && | ||
// if OVM, we will not have matching compiler versions because we can't infer a specific OVM solc version from the bytecode | ||
!deployedBytecode.isOvmInferred()) { | ||
continue; | ||
@@ -60,2 +86,8 @@ } | ||
const { deployedBytecode: runtimeBytecodeSymbols } = contract.evm; | ||
// If this is OVM bytecode, do the required find and replace (see above comments for more info) | ||
if (deployedBytecode.isOvmInferred()) { | ||
runtimeBytecodeSymbols.object = runtimeBytecodeSymbols.object | ||
.split(ovmFindOpcodes) | ||
.join(ovmReplaceOpcodes); | ||
} | ||
const analyzedBytecode = await compareBytecode(deployedBytecode, runtimeBytecodeSymbols); | ||
@@ -74,7 +106,10 @@ if (analyzedBytecode !== null) { | ||
const runtimeBytecodeExecutableSectionLength = metadata_1.measureExecutableSectionLength(runtimeBytecodeSymbols.object); | ||
if (deployedExecutableSection.length !== runtimeBytecodeExecutableSectionLength) { | ||
if (deployedExecutableSection.length !== | ||
runtimeBytecodeExecutableSectionLength && | ||
// OVM bytecode has no metadata so we ignore this comparison if operating on OVM bytecode | ||
!deployedBytecode.isOvmInferred()) { | ||
return null; | ||
} | ||
// Normalize deployed bytecode according to this contract. | ||
const { immutableValues, libraryLinks, normalizedBytecode, } = await normalizeBytecode(deployedExecutableSection, runtimeBytecodeSymbols); | ||
const { immutableValues, libraryLinks, normalizedBytecode } = await normalizeBytecode(deployedExecutableSection, runtimeBytecodeSymbols); | ||
// Library hash placeholders are embedded into the bytes where the library addresses are linked. | ||
@@ -81,0 +116,0 @@ // We need to zero them out to compare them. |
@@ -131,3 +131,4 @@ "use strict"; | ||
} | ||
normalizedLibraries[neededLibrary.sourceName][neededLibrary.libName] = linkedLibraryAddress; | ||
normalizedLibraries[neededLibrary.sourceName][neededLibrary.libName] = | ||
linkedLibraryAddress; | ||
} | ||
@@ -134,0 +135,0 @@ return normalizedLibraries; |
@@ -45,3 +45,3 @@ "use strict"; | ||
} | ||
return response.json(); | ||
return await response.json(); | ||
} | ||
@@ -48,0 +48,0 @@ catch (error) { |
{ | ||
"name": "@nomiclabs/hardhat-etherscan", | ||
"version": "2.1.1", | ||
"version": "2.1.8", | ||
"description": "Hardhat plugin for verifying contracts on etherscan", | ||
@@ -23,7 +23,9 @@ "repository": "github:nomiclabs/hardhat", | ||
"scripts": { | ||
"lint:fix": "node ../../node_modules/prettier/bin-prettier.js --write \"src/**/*.{js,ts}\" \"test/**/*.{js,ts}\" && yarn lint --fix", | ||
"lint": "node ../../node_modules/tslint/bin/tslint --config tslint.json --project ./tsconfig.json", | ||
"test": "node ../../node_modules/mocha/bin/mocha --recursive \"test/**/*.ts\" --exit", | ||
"build": "node ../../node_modules/typescript/bin/tsc --build .", | ||
"clean": "node ../../node_modules/rimraf/bin.js dist" | ||
"lint": "yarn prettier --check && yarn eslint", | ||
"lint:fix": "yarn prettier --write && yarn eslint --fix", | ||
"eslint": "eslint 'src/**/*.ts' 'test/**/*.ts'", | ||
"prettier": "prettier \"**/*.{js,md,json}\"", | ||
"test": "mocha --recursive \"test/**/*.ts\" --exit", | ||
"build": "tsc --build .", | ||
"clean": "rimraf dist" | ||
}, | ||
@@ -37,3 +39,3 @@ "files": [ | ||
"dependencies": { | ||
"@ethersproject/abi": "^5.0.2", | ||
"@ethersproject/abi": "^5.1.2", | ||
"@ethersproject/address": "^5.0.2", | ||
@@ -51,8 +53,21 @@ "cbor": "^5.0.2", | ||
"@types/fs-extra": "^5.1.0", | ||
"@types/mocha": "^5.2.6", | ||
"@types/node-fetch": "^2.3.7", | ||
"@types/node": "^10.17.24", | ||
"@types/semver": "^6.0.2", | ||
"@typescript-eslint/eslint-plugin": "4.29.2", | ||
"@typescript-eslint/parser": "4.29.2", | ||
"chai": "^4.2.0", | ||
"eslint": "^7.29.0", | ||
"eslint-config-prettier": "8.3.0", | ||
"eslint-plugin-import": "2.24.1", | ||
"eslint-plugin-prettier": "3.4.0", | ||
"ethers": "^5.0.8", | ||
"hardhat": "^2.0.4", | ||
"nock": "^13.0.5" | ||
"mocha": "^7.1.2", | ||
"nock": "^13.0.5", | ||
"prettier": "2.3.2", | ||
"rimraf": "^3.0.2", | ||
"ts-node": "^8.1.0", | ||
"typescript": "~4.0.3" | ||
}, | ||
@@ -59,0 +74,0 @@ "peerDependencies": { |
@@ -1,3 +0,2 @@ | ||
[![npm](https://img.shields.io/npm/v/@nomiclabs/hardhat-etherscan.svg)](https://www.npmjs.com/package/@nomiclabs/hardhat-etherscan) | ||
[![hardhat](https://hardhat.org/buidler-plugin-badge.svg?1)](https://hardhat.org) | ||
[![npm](https://img.shields.io/npm/v/@nomiclabs/hardhat-etherscan.svg)](https://www.npmjs.com/package/@nomiclabs/hardhat-etherscan) [![hardhat](https://hardhat.org/buidler-plugin-badge.svg?1)](https://hardhat.org) | ||
@@ -13,2 +12,3 @@ # hardhat-etherscan | ||
It's smart and it tries to do as much as possible to facilitate the process: | ||
- Just provide the deployment address and constructor arguments, and the plugin will detect locally which contract to verify. | ||
@@ -70,3 +70,3 @@ - If your contract uses Solidity libraries, the plugin will detect them and deal with them automatically. You don't need to do anything about them. | ||
When the constructor has a complex argument list, it might be easier to write a javascript module that exports the argument list. The expected format is the same as a constructor list for an [ethers contract](https://docs.ethers.io/v5/api/contract/). For example, if you have a contract like this: | ||
When the constructor has a complex argument list, you'll need to write a javascript module that exports the argument list. The expected format is the same as a constructor list for an [ethers contract](https://docs.ethers.io/v5/api/contract/). For example, if you have a contract like this: | ||
@@ -122,3 +122,3 @@ ```solidity | ||
SomeLibrary: "0x...", | ||
} | ||
}; | ||
``` | ||
@@ -130,3 +130,2 @@ | ||
```js | ||
@@ -144,3 +143,3 @@ await hre.run("verify:verify", { | ||
], | ||
}) | ||
}); | ||
``` | ||
@@ -147,0 +146,0 @@ |
@@ -137,3 +137,3 @@ import { NomicLabsHardhatPluginError } from "hardhat/plugins"; | ||
public constructor(response: any) { | ||
constructor(response: any) { | ||
this.status = parseInt(response.status, 10); | ||
@@ -140,0 +140,0 @@ this.message = response.result; |
@@ -210,25 +210,19 @@ import { | ||
}); | ||
if (matchingCompilerVersions.length === 0) { | ||
const detailedContext = []; | ||
if (isVersionRange(inferredSolcVersion)) { | ||
detailedContext.push( | ||
`The expected version range is ${inferredSolcVersion}.` | ||
); | ||
} else { | ||
detailedContext.push(`The expected version is ${inferredSolcVersion}.`); | ||
} | ||
// There is always at least one configured version. | ||
if ( | ||
matchingCompilerVersions.length === 0 && | ||
// don't error if the bytecode appears to be OVM bytecode, because we can't infer a specific OVM solc version from the bytecode | ||
!deployedBytecode.isOvmInferred() | ||
) { | ||
let configuredCompilersFragment; | ||
if (compilerVersions.length > 1) { | ||
detailedContext.push( | ||
`The selected compiler versions are: ${compilerVersions.join(", ")}` | ||
); | ||
configuredCompilersFragment = `your configured compiler versions are: ${compilerVersions.join( | ||
", " | ||
)}`; | ||
} else { | ||
detailedContext.push( | ||
`The selected compiler version is: ${compilerVersions[0]}` | ||
); | ||
configuredCompilersFragment = `your configured compiler version is: ${compilerVersions[0]}`; | ||
} | ||
const message = `The bytecode retrieved could not have been generated by any of the selected compilers. | ||
${detailedContext.join("\n")} | ||
const message = `The contract you want to verify was compiled with solidity ${inferredSolcVersion}, but ${configuredCompilersFragment}. | ||
Possible causes are: | ||
- You are not in the same commit that was used to deploy the contract. | ||
- Wrong compiler version selected in hardhat config. | ||
@@ -253,2 +247,21 @@ - The given address is wrong. | ||
// Override solc version based on hardhat config if verifying for the OVM. This is used instead of fetching the | ||
// full version name from a solc bin JSON file (as is done for EVM solc in src/solc/version.ts) because it's | ||
// simpler and avoids a network request we don't need. This is ok because the solc version specified in the OVM | ||
// config always equals the full solc version | ||
if (deployedBytecode.isOvmInferred()) { | ||
// We cast to this custom type here instead of using `extendConfig` to avoid always mutating the HardhatConfig | ||
// type. We don't want that type to always contain the `ovm` field, because users only using hardhat-etherscan | ||
// without the Optimism plugin should not have that field in their type definitions | ||
const configCopy = { ...config } as unknown as { | ||
ovm?: { solcVersion?: string }; | ||
}; | ||
const ovmSolcVersion = configCopy.ovm?.solcVersion; | ||
if (ovmSolcVersion === undefined) { | ||
const message = `It looks like you are verifying an OVM contract, but do not have an OVM solcVersion specified in the hardhat config.`; | ||
throw new NomicLabsHardhatPluginError(pluginName, message); | ||
} | ||
contractInformation.solcVersion = `v${ovmSolcVersion}`; // Etherscan requires the leading `v` before the version string | ||
} | ||
const deployArgumentsEncoded = await encodeArguments( | ||
@@ -261,3 +274,6 @@ contractInformation.contract.abi, | ||
const solcFullVersion = await getLongVersion(contractInformation.solcVersion); | ||
// If OVM, the full version string was already read from the hardhat config. If solc, get the full version string | ||
const solcFullVersion = deployedBytecode.isOvmInferred() | ||
? contractInformation.solcVersion | ||
: await getLongVersion(contractInformation.solcVersion); | ||
@@ -629,3 +645,6 @@ const minimumBuild: Build = await run(TASK_VERIFY_GET_MINIMUM_BUILD, { | ||
if (!matchingCompilerVersions.includes(buildInfo.solcVersion)) { | ||
if ( | ||
!matchingCompilerVersions.includes(buildInfo.solcVersion) && | ||
!deployedBytecode.isOvmInferred() | ||
) { | ||
const inferredSolcVersion = deployedBytecode.getInferredSolcVersion(); | ||
@@ -651,5 +670,4 @@ let versionDetails; | ||
const { sourceName, contractName } = parseFullyQualifiedName( | ||
contractFQN | ||
); | ||
const { sourceName, contractName } = | ||
parseFullyQualifiedName(contractFQN); | ||
contractInformation = await extractMatchingContractInformation( | ||
@@ -656,0 +674,0 @@ sourceName, |
@@ -28,2 +28,23 @@ import { | ||
BSC_TESTNET = 97, | ||
// Huobi ECO Chain | ||
HECO = 128, | ||
HECO_TESTNET = 256, | ||
// Fantom mainnet | ||
OPERA = 250, | ||
FTM_TESTNET = 4002, | ||
// Optimistim | ||
OPTIMISTIC_ETHEREUM = 10, | ||
OPTIMISTIC_KOVAN = 69, | ||
// Polygon | ||
POLYGON = 137, | ||
POLYGON_MUMBAI = 80001, | ||
// Arbitrum | ||
ARBITRUM_ONE = 42161, | ||
ARBITRUM_TESTNET = 421611, | ||
// Avalanche | ||
AVALANCHE = 43114, | ||
AVALANCHE_FUJI_TESTNET = 43113, | ||
// Moonriver | ||
MOONRIVER = 1285, | ||
MOONBASE_ALPHA = 1287, | ||
} | ||
@@ -34,3 +55,3 @@ | ||
apiURL: "https://api.etherscan.io/api", | ||
browserURL: "https://etherscan.io/", | ||
browserURL: "https://etherscan.io", | ||
}, | ||
@@ -61,2 +82,58 @@ [NetworkID.ROPSTEN]: { | ||
}, | ||
[NetworkID.HECO]: { | ||
apiURL: "https://api.hecoinfo.com/api", | ||
browserURL: "https://hecoinfo.com", | ||
}, | ||
[NetworkID.HECO_TESTNET]: { | ||
apiURL: "https://api-testnet.hecoinfo.com/api", | ||
browserURL: "https://testnet.hecoinfo.com", | ||
}, | ||
[NetworkID.OPERA]: { | ||
apiURL: "https://api.ftmscan.com/api", | ||
browserURL: "https://ftmscan.com", | ||
}, | ||
[NetworkID.FTM_TESTNET]: { | ||
apiURL: "https://api-testnet.ftmscan.com/api", | ||
browserURL: "https://testnet.ftmscan.com", | ||
}, | ||
[NetworkID.OPTIMISTIC_ETHEREUM]: { | ||
apiURL: "https://api-optimistic.etherscan.io/api", | ||
browserURL: "https://optimistic.etherscan.io/", | ||
}, | ||
[NetworkID.OPTIMISTIC_KOVAN]: { | ||
apiURL: "https://api-kovan-optimistic.etherscan.io/api", | ||
browserURL: "https://kovan-optimistic.etherscan.io/", | ||
}, | ||
[NetworkID.POLYGON]: { | ||
apiURL: "https://api.polygonscan.com/api", | ||
browserURL: "https://polygonscan.com", | ||
}, | ||
[NetworkID.POLYGON_MUMBAI]: { | ||
apiURL: "https://api-testnet.polygonscan.com/api", | ||
browserURL: "https://mumbai.polygonscan.com/", | ||
}, | ||
[NetworkID.ARBITRUM_ONE]: { | ||
apiURL: "https://api.arbiscan.io/api", | ||
browserURL: "https://arbiscan.io/", | ||
}, | ||
[NetworkID.ARBITRUM_TESTNET]: { | ||
apiURL: "https://api-testnet.arbiscan.io/api", | ||
browserURL: "https://testnet.arbiscan.io/", | ||
}, | ||
[NetworkID.AVALANCHE]: { | ||
apiURL: "https://api.snowtrace.io/api", | ||
browserURL: "https://snowtrace.io/", | ||
}, | ||
[NetworkID.AVALANCHE_FUJI_TESTNET]: { | ||
apiURL: "https://api-testnet.snowtrace.io/api", | ||
browserURL: "https://testnet.snowtrace.io/", | ||
}, | ||
[NetworkID.MOONRIVER]: { | ||
apiURL: "https://api-moonriver.moonscan.io/api", | ||
browserURL: "https://moonscan.io", | ||
}, | ||
[NetworkID.MOONBASE_ALPHA]: { | ||
apiURL: "https://api-moonbase.moonscan.io/api", | ||
browserURL: "https://moonbase.moonscan.io/", | ||
}, | ||
}; | ||
@@ -63,0 +140,0 @@ |
@@ -10,8 +10,3 @@ import { | ||
import { LibraryNames } from "./libraries"; | ||
import { | ||
inferSolcVersion, | ||
measureExecutableSectionLength, | ||
METADATA_ABSENT_VERSION_RANGE, | ||
} from "./metadata"; | ||
import { inferSolcVersion, measureExecutableSectionLength } from "./metadata"; | ||
@@ -56,5 +51,18 @@ interface BytecodeExtractedData { | ||
// If the compiler output bytecode is OVM bytecode, we need to make a fix to account for a bug in some versions of | ||
// the OVM compiler. The artifact’s deployedBytecode is incorrect, but because its bytecode (initcode) is correct, when we | ||
// actually deploy contracts, the code that ends up getting stored on chain is also correct. During verification, | ||
// Etherscan will compile the source code, pull out the artifact’s deployedBytecode, and then perform the | ||
// below find and replace, then check that resulting output against the code retrieved on chain from eth_getCode. | ||
// We define the strings for that find and replace here, and use them later so we can know if the bytecode matches | ||
// before it gets to Etherscan. Source: https://github.com/ethereum-optimism/optimism/blob/8d67991aba584c1703692ea46273ea8a1ef45f56/packages/contracts/src/contract-dumps.ts#L195-L204 | ||
const ovmFindOpcodes = | ||
"336000905af158601d01573d60011458600c01573d6000803e3d621234565260ea61109c52"; | ||
const ovmReplaceOpcodes = | ||
"336000905af158600e01573d6000803e3d6000fd5b3d6001141558600a015760016000f35b"; | ||
export class Bytecode { | ||
private _bytecode: string; | ||
private _version: string; | ||
private _isOvm: boolean; | ||
@@ -78,2 +86,15 @@ private _executableSection: BytecodeSlice; | ||
}; | ||
// Check if this is OVM bytecode by looking for the concatenation of the two opcodes defined here: | ||
// https://github.com/ethereum-optimism/optimism/blob/33cb9025f5e463525d6abe67c8457f81a87c5a24/packages/contracts/contracts/optimistic-ethereum/OVM/execution/OVM_SafetyChecker.sol#L143 | ||
// - This check would only fail if the EVM solidity compiler didn't use any of the following opcodes: https://github.com/ethereum-optimism/optimism/blob/c42fc0df2790a5319027393cb8fa34e4f7bb520f/packages/contracts/contracts/optimistic-ethereum/iOVM/execution/iOVM_ExecutionManager.sol#L94-L175 | ||
// This is the list of opcodes that calls the OVM execution manager. But the current solidity | ||
// compiler seems to add REVERT in all cases, meaning it currently won't happen and this check | ||
// will always be correct. | ||
// - It is possible, though very unlikely, that this string appears in the bytecode of an EVM | ||
// contract. As a result result, this _isOvm flag should only be used after trying to infer | ||
// the solc version | ||
// - We need this check because OVM bytecode has no metadata, so when verifying | ||
// OVM bytecode the check in `inferSolcVersion` will always return `METADATA_ABSENT_VERSION_RANGE`. | ||
this._isOvm = bytecode.includes(ovmReplaceOpcodes); | ||
} | ||
@@ -85,2 +106,6 @@ | ||
public isOvmInferred(): boolean { | ||
return this._isOvm; | ||
} | ||
public getExecutableSection(): string { | ||
@@ -111,3 +136,7 @@ const { start, length } = this._executableSection; | ||
if (!matchingCompilerVersions.includes(buildInfo.solcVersion)) { | ||
if ( | ||
!matchingCompilerVersions.includes(buildInfo.solcVersion) && | ||
// if OVM, we will not have matching compiler versions because we can't infer a specific OVM solc version from the bytecode | ||
!deployedBytecode.isOvmInferred() | ||
) { | ||
continue; | ||
@@ -142,2 +171,9 @@ } | ||
// If this is OVM bytecode, do the required find and replace (see above comments for more info) | ||
if (deployedBytecode.isOvmInferred()) { | ||
runtimeBytecodeSymbols.object = runtimeBytecodeSymbols.object | ||
.split(ovmFindOpcodes) | ||
.join(ovmReplaceOpcodes); | ||
} | ||
const analyzedBytecode = await compareBytecode( | ||
@@ -174,3 +210,6 @@ deployedBytecode, | ||
if ( | ||
deployedExecutableSection.length !== runtimeBytecodeExecutableSectionLength | ||
deployedExecutableSection.length !== | ||
runtimeBytecodeExecutableSectionLength && | ||
// OVM bytecode has no metadata so we ignore this comparison if operating on OVM bytecode | ||
!deployedBytecode.isOvmInferred() | ||
) { | ||
@@ -181,10 +220,4 @@ return null; | ||
// Normalize deployed bytecode according to this contract. | ||
const { | ||
immutableValues, | ||
libraryLinks, | ||
normalizedBytecode, | ||
} = await normalizeBytecode( | ||
deployedExecutableSection, | ||
runtimeBytecodeSymbols | ||
); | ||
const { immutableValues, libraryLinks, normalizedBytecode } = | ||
await normalizeBytecode(deployedExecutableSection, runtimeBytecodeSymbols); | ||
@@ -191,0 +224,0 @@ // Library hash placeholders are embedded into the bytes where the library addresses are linked. |
@@ -199,5 +199,4 @@ import { NomicLabsHardhatPluginError } from "hardhat/plugins"; | ||
} | ||
normalizedLibraries[neededLibrary.sourceName][ | ||
neededLibrary.libName | ||
] = linkedLibraryAddress; | ||
normalizedLibraries[neededLibrary.sourceName][neededLibrary.libName] = | ||
linkedLibraryAddress; | ||
} | ||
@@ -204,0 +203,0 @@ return normalizedLibraries; |
@@ -5,4 +5,2 @@ import type cbor from "cbor"; | ||
import { pluginName } from "../constants"; | ||
interface MetadataDescription { | ||
@@ -128,7 +126,6 @@ solcVersion: string; | ||
const runtimeMetadataSectionLength = getSolcMetadataSectionLength( | ||
metadataLengthSlice | ||
); | ||
const runtimeMetadataSectionLength = | ||
getSolcMetadataSectionLength(metadataLengthSlice); | ||
return bytecode.length - runtimeMetadataSectionLength * 2; | ||
} |
@@ -44,3 +44,3 @@ import { NomicLabsHardhatPluginError } from "hardhat/plugins"; | ||
return response.json(); | ||
return await response.json(); | ||
} catch (error) { | ||
@@ -47,0 +47,0 @@ throw new NomicLabsHardhatPluginError( |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
206081
74
3508
23
164
Updated@ethersproject/abi@^5.1.2