diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index a8c4533d2..f66e08efd 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -60,3 +60,4 @@ export { ValidateUpgradeSafetyOptions, validateUpgradeSafety, ProjectReport, Ref export { getUpgradeInterfaceVersion } from './upgrade-interface-version'; export { makeNamespacedInput } from './utils/make-namespaced'; +export { isNamespaceSupported } from './storage/namespace'; diff --git a/packages/core/src/storage/namespace.ts b/packages/core/src/storage/namespace.ts index 6d24326bc..a6f9946eb 100644 --- a/packages/core/src/storage/namespace.ts +++ b/packages/core/src/storage/namespace.ts @@ -7,6 +7,7 @@ import { getAnnotationArgs, getDocumentation, hasAnnotationTag } from '../utils/ import { Node } from 'solidity-ast/node'; import { CompilationContext, getTypeMembers, loadLayoutType } from './extract'; import { UpgradesError } from '../error'; +import * as versions from 'compare-versions'; /** * Loads a contract's namespaces and namespaced type information into the storage layout. @@ -260,3 +261,7 @@ function findLayoutStructMember( function findTypeWithLabel(types: Record, label: string) { return Object.values(types).find(type => type.label === label); } + +export function isNamespaceSupported(solcVersion: string) { + return versions.compare(solcVersion, '0.8.20', '>='); +} diff --git a/packages/core/src/validate/run.ts b/packages/core/src/validate/run.ts index 5afe6db1b..ea97b1816 100644 --- a/packages/core/src/validate/run.ts +++ b/packages/core/src/validate/run.ts @@ -2,7 +2,6 @@ import { Node } from 'solidity-ast/node'; import { isNodeType, findAll, ASTDereferencer, astDereferencer } from 'solidity-ast/utils'; import type { ContractDefinition, FunctionDefinition } from 'solidity-ast'; import debug from '../utils/debug'; -import * as versions from 'compare-versions'; import { SolcOutput, SolcBytecode, SolcInput } from '../solc-api'; import { SrcDecoder } from '../src-decoder'; @@ -14,7 +13,7 @@ import { extractStorageLayout } from '../storage/extract'; import { StorageLayout } from '../storage/layout'; import { getFullyQualifiedName } from '../utils/contract-name'; import { getAnnotationArgs as getSupportedAnnotationArgs, getDocumentation } from '../utils/annotations'; -import { getStorageLocationAnnotation } from '../storage/namespace'; +import { getStorageLocationAnnotation, isNamespaceSupported } from '../storage/namespace'; import { UpgradesError } from '../error'; export type ValidationRunData = Record; @@ -243,7 +242,7 @@ function checkNamespaceSolidityVersion(source: string, solcVersion?: string, sol () => `Structs with the @custom:storage-location annotation can only be used with Solidity version 0.8.20 or higher. Pass the solcVersion parameter to the validate function, or remove the annotation if the struct is not used for namespaced storage.`, ); - } else if (versions.compare(solcVersion, '0.8.20', '<')) { + } else if (!isNamespaceSupported(solcVersion)) { throw new UpgradesError( `${source}: Namespace annotations require Solidity version >= 0.8.20, but ${solcVersion} was used`, () => diff --git a/packages/plugin-hardhat/contracts/MakeNamespaced0516.sol b/packages/plugin-hardhat/contracts/MakeNamespaced0516.sol new file mode 100644 index 000000000..166a916ee --- /dev/null +++ b/packages/plugin-hardhat/contracts/MakeNamespaced0516.sol @@ -0,0 +1,12 @@ +pragma solidity ^0.5.16; + +/** + * @dev foo + */ +contract MakeNamespaced0516 { + /** + * @dev bar + */ + function bar() public view { + } +} diff --git a/packages/plugin-hardhat/src/index.ts b/packages/plugin-hardhat/src/index.ts index c34b8ec91..b2da94c17 100644 --- a/packages/plugin-hardhat/src/index.ts +++ b/packages/plugin-hardhat/src/index.ts @@ -97,7 +97,7 @@ subtask(TASK_COMPILE_SOLIDITY, async (args: { force: boolean }, hre, runSuper) = }); subtask(TASK_COMPILE_SOLIDITY_COMPILE, async (args: RunCompilerArgs, hre, runSuper) => { - const { validate, solcInputOutputDecoder, makeNamespacedInput } = await import('@openzeppelin/upgrades-core'); + const { isNamespaceSupported, validate, solcInputOutputDecoder, makeNamespacedInput } = await import('@openzeppelin/upgrades-core'); const { writeValidations } = await import('./utils/validations'); // TODO: patch input @@ -107,9 +107,12 @@ subtask(TASK_COMPILE_SOLIDITY_COMPILE, async (args: RunCompilerArgs, hre, runSup if (isFullSolcOutput(output)) { const decodeSrc = solcInputOutputDecoder(args.input, output); - const namespacedInput = makeNamespacedInput(args.input, output); - const { output: namespacedOutput } = await runSuper({ ...args, quiet: true, input: namespacedInput }); - await checkNamespacedCompileErrors(namespacedOutput); + let namespacedOutput = undefined; + if (isNamespaceSupported(args.solcVersion)) { + const namespacedInput = makeNamespacedInput(args.input, output); + namespacedOutput = (await runSuper({ ...args, quiet: true, input: namespacedInput })).output; + await checkNamespacedCompileErrors(namespacedOutput); + } const validations = validate(output, decodeSrc, args.solcVersion, args.input, namespacedOutput); await writeValidations(hre, validations); diff --git a/packages/plugin-hardhat/test/namespaced.js b/packages/plugin-hardhat/test/namespaced.js index 85812290d..9164efcb2 100644 --- a/packages/plugin-hardhat/test/namespaced.js +++ b/packages/plugin-hardhat/test/namespaced.js @@ -28,6 +28,7 @@ test.before(async t => { t.context.InheritsNamespaceV2_BadAndHasLayout = await ethers.getContractFactory( 'InheritsNamespaceV2_BadAndHasLayout', ); + t.context.MakeNamespaced0516 = await ethers.getContractFactory('MakeNamespaced0516'); }); test('validate namespace - ok', async t => { @@ -231,3 +232,9 @@ test('moving namespace to inherited contract - delete variable and has layout - const error = await t.throwsAsync(() => upgrades.validateUpgrade(Example, InheritsNamespaceV2_BadAndHasLayout)); t.snapshot(error.message); }); + +test('validate 0.5.16 contract without namespaces - ok', async t => { + const { MakeNamespaced0516 } = t.context; + + await upgrades.validateImplementation(MakeNamespaced0516); +});