Socket
Socket
Sign inDemoInstall

@nomiclabs/hardhat-etherscan

Package Overview
Dependencies
286
Maintainers
3
Versions
34
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.1.4 to 2.1.5

29

dist/src/index.js

@@ -59,2 +59,3 @@ "use strict";

const verifySubtask = async ({ address, constructorArguments, contract: contractFQN, libraries }, { config, network, run }) => {
var _a;
const { etherscan } = config;

@@ -88,3 +89,5 @@ if (etherscan.apiKey === undefined || etherscan.apiKey.trim() === "") {

});
if (matchingCompilerVersions.length === 0) {
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;

@@ -114,4 +117,23 @@ if (compilerVersions.length > 1) {

});
// 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, {

@@ -332,3 +354,4 @@ sourceName: contractInformation.sourceName,

}
if (!matchingCompilerVersions.includes(buildInfo.solcVersion)) {
if (!matchingCompilerVersions.includes(buildInfo.solcVersion) &&
!deployedBytecode.isOvmInferred()) {
const inferredSolcVersion = deployedBytecode.getInferredSolcVersion();

@@ -335,0 +358,0 @@ let versionDetails;

4

dist/src/network/prober.js

@@ -71,7 +71,7 @@ "use strict";

[NetworkID.OPTIMISTIC_ETHEREUM]: {
apiURL: "https://api-optimistic.etherscan.io",
apiURL: "https://api-optimistic.etherscan.io/api",
browserURL: "https://optimistic.etherscan.io/",
},
[NetworkID.OPTIMISTIC_KOVAN]: {
apiURL: "https://api-kovan-optimistic.etherscan.io",
apiURL: "https://api-kovan-optimistic.etherscan.io/api",
browserURL: "https://kovan-optimistic.etherscan.io/",

@@ -78,0 +78,0 @@ },

@@ -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,3 +106,6 @@ 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;

@@ -77,0 +112,0 @@ }

{
"name": "@nomiclabs/hardhat-etherscan",
"version": "2.1.4",
"version": "2.1.5",
"description": "Hardhat plugin for verifying contracts on etherscan",

@@ -5,0 +5,0 @@ "repository": "github:nomiclabs/hardhat",

@@ -210,3 +210,7 @@ import {

});
if (matchingCompilerVersions.length === 0) {
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;

@@ -243,2 +247,21 @@ if (compilerVersions.length > 1) {

// 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(

@@ -251,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);

@@ -619,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();

@@ -622,0 +651,0 @@ let versionDetails;

@@ -83,7 +83,7 @@ import {

[NetworkID.OPTIMISTIC_ETHEREUM]: {
apiURL: "https://api-optimistic.etherscan.io",
apiURL: "https://api-optimistic.etherscan.io/api",
browserURL: "https://optimistic.etherscan.io/",
},
[NetworkID.OPTIMISTIC_KOVAN]: {
apiURL: "https://api-kovan-optimistic.etherscan.io",
apiURL: "https://api-kovan-optimistic.etherscan.io/api",
browserURL: "https://kovan-optimistic.etherscan.io/",

@@ -90,0 +90,0 @@ },

@@ -50,5 +50,18 @@ import {

// 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;

@@ -72,2 +85,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);
}

@@ -79,2 +105,6 @@

public isOvmInferred(): boolean {
return this._isOvm;
}
public getExecutableSection(): string {

@@ -105,3 +135,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;

@@ -136,2 +170,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(

@@ -168,3 +209,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()
) {

@@ -171,0 +215,0 @@ return null;

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc