Skip to content

Commit

Permalink
feat: hardhat task to run hardhat-upgrade verification
Browse files Browse the repository at this point in the history
  • Loading branch information
adjisb committed Dec 6, 2023
1 parent af5a206 commit ade7e7c
Show file tree
Hide file tree
Showing 5 changed files with 205 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/deploy/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
addNodeAndMnemonic,
skipDeploymentsOnLiveNetworks,
} from './utils/hardhatConfig';
import './tasks/deployHook';
import './tasks/importedPackages';

// Package name : solidity source code path
Expand Down
3 changes: 3 additions & 0 deletions packages/deploy/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@
"@ethersproject/abi": "^5.7.0",
"@ethersproject/providers": "^5.7.2",
"@nomicfoundation/hardhat-chai-matchers": "1",
"@nomicfoundation/hardhat-ethers": "^3.0.0",
"@nomicfoundation/hardhat-network-helpers": "^1.0.8",
"@nomicfoundation/hardhat-verify": "^1.1.0",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@openzeppelin/hardhat-upgrades": "^2.5.0",
"@typechain/ethers-v5": "^11.0.0",
"@typechain/hardhat": "^8.0.0",
"@types/chai": "^4.3.5",
Expand Down
113 changes: 113 additions & 0 deletions packages/deploy/tasks/deployHook.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import {extendEnvironment, task} from 'hardhat/config';
import 'dotenv/config';
import 'hardhat-deploy';
import '@openzeppelin/hardhat-upgrades';
import {HardhatPluginError, lazyFunction} from 'hardhat/plugins';
import {
DeploymentsExtension,
DeployOptions,
DeployResult,
} from 'hardhat-deploy/types';
import {HardhatRuntimeEnvironment} from 'hardhat/types';
import {ContractFactory} from 'ethers';
import {TASK_DEPLOY} from 'hardhat-deploy';
import {ValidateUpgradeOptions} from '@openzeppelin/hardhat-upgrades/src/utils/options';

declare module 'hardhat/types/runtime' {
interface HardhatRuntimeEnvironment {
_ozVerifyOpts: ValidateUpgradeOptions;
}
}
type ValidationErrorKind = NonNullable<
ValidateUpgradeOptions['unsafeAllow']
> extends (infer U)[]
? U
: never;
const unsafeOpts: {[k: string]: ValidationErrorKind} = {
StateVariableAssignment: 'state-variable-assignment',
StateVariableImmutable: 'state-variable-immutable',
ExternalLibraryLinking: 'external-library-linking',
StructDefinition: 'struct-definition',
EnumDefinition: 'enum-definition',
Constructor: 'constructor',
DelegateCall: 'delegatecall',
SelfDestruct: 'selfdestruct',
MissingPublicUpgradeTo: 'missing-public-upgradeto',
};

function deployHook(
hre: HardhatRuntimeEnvironment,
orig: DeploymentsExtension
) {
return async (
name: string,
options: DeployOptions
): Promise<DeployResult> => {
// We assume same name different contract => upgrade.
const deployment = await hre.deployments.getOrNull(
name + '_Implementation'
);
if (deployment) {
console.log('CHECKING UPGRADE', name, options.contract);
if (!deployment.bytecode) {
throw new HardhatPluginError(`missing bytecode for deployment ${name}`);
}
const oldFactory = new ContractFactory(
deployment.abi,
deployment.bytecode
);
await hre.upgrades.validateImplementation(oldFactory, hre._ozVerifyOpts);
if (!options.contract || typeof options.contract !== 'string') {
throw new HardhatPluginError(`missing new contract for ${name}`);
}
const newName = options.contract as string;
const artifact = await hre.artifacts.readArtifact(newName);
if (!artifact || !artifact.abi || !artifact.bytecode) {
throw new HardhatPluginError(
`missing bytecode for artifact ${newName}`
);
}
const newFactory = new ContractFactory(artifact.abi, artifact.bytecode);
await hre.upgrades.validateImplementation(newFactory, hre._ozVerifyOpts);
await hre.upgrades.validateUpgrade(
oldFactory,
newFactory,
hre._ozVerifyOpts
);
}
return await orig.deploy(name, options);
};
}

extendEnvironment((hre) => {
const origClone: DeploymentsExtension = Object.assign({}, hre.deployments);
hre.deployments.deploy = lazyFunction(() => deployHook(hre, origClone));
});

Object.keys(unsafeOpts)
.reduce(
(task, o) =>
task.addFlag(
'unsafeAllow' + o,
'Selectively disable one or more validation errors'
),
task(TASK_DEPLOY, 'use defender admin to propose transactions')
)
.addFlag(
'unsafeAllowRenames',
'Configure storage layout check to allow variable renaming'
)
.addFlag(
'unsafeSkipStorageCheck',
'Upgrades the proxy or beacon without first checking for storage layout compatibility errors. This is a dangerous option meant to be used as a last resort'
)
.setAction(async (args: {[flag: string]: boolean}, hre, runSuper) => {
hre._ozVerifyOpts = {...args};
hre._ozVerifyOpts.unsafeAllow = [];
for (const o in unsafeOpts) {
if (args['unsafeAllow' + o]) {
hre._ozVerifyOpts.unsafeAllow.push(unsafeOpts[o]);
}
}
return await runSuper(args);
});
2 changes: 1 addition & 1 deletion packages/deploy/tasks/importedPackages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ declare module 'hardhat/types/runtime' {
}
declare module 'hardhat/types/config' {
interface HardhatUserConfig {
importedPackages: {[name: string]: string};
importedPackages: {[name: string]: string | string[]};
}
}

Expand Down
90 changes: 87 additions & 3 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1306,6 +1306,19 @@ __metadata:
languageName: node
linkType: hard

"@nomicfoundation/hardhat-ethers@npm:^3.0.0":
version: 3.0.5
resolution: "@nomicfoundation/hardhat-ethers@npm:3.0.5"
dependencies:
debug: ^4.1.1
lodash.isequal: ^4.5.0
peerDependencies:
ethers: ^6.1.0
hardhat: ^2.0.0
checksum: 34b092dfec68f8d8673c96af717660327edc814bc5c9cdb5bc1f82d5bde2b18bc9b9d3499a632784a3d4f2505ac174217e55d31b546b7eaa77a5bb30b3c80bb4
languageName: node
linkType: hard

"@nomicfoundation/hardhat-ethers@npm:^3.0.3, @nomicfoundation/hardhat-ethers@npm:^3.0.4":
version: 3.0.4
resolution: "@nomicfoundation/hardhat-ethers@npm:3.0.4"
Expand Down Expand Up @@ -1382,7 +1395,7 @@ __metadata:
languageName: node
linkType: hard

"@nomicfoundation/hardhat-verify@npm:^1.0.0":
"@nomicfoundation/hardhat-verify@npm:^1.0.0, @nomicfoundation/hardhat-verify@npm:^1.1.0":
version: 1.1.1
resolution: "@nomicfoundation/hardhat-verify@npm:1.1.1"
dependencies:
Expand Down Expand Up @@ -1867,7 +1880,7 @@ __metadata:
languageName: node
linkType: hard

"@openzeppelin/defender-admin-client@npm:^1.48.0":
"@openzeppelin/defender-admin-client@npm:^1.48.0, @openzeppelin/defender-admin-client@npm:^1.52.0":
version: 1.52.0
resolution: "@openzeppelin/defender-admin-client@npm:1.52.0"
dependencies:
Expand All @@ -1880,7 +1893,7 @@ __metadata:
languageName: node
linkType: hard

"@openzeppelin/defender-base-client@npm:1.52.0, @openzeppelin/defender-base-client@npm:^1.48.0":
"@openzeppelin/defender-base-client@npm:1.52.0, @openzeppelin/defender-base-client@npm:^1.48.0, @openzeppelin/defender-base-client@npm:^1.52.0":
version: 1.52.0
resolution: "@openzeppelin/defender-base-client@npm:1.52.0"
dependencies:
Expand Down Expand Up @@ -1916,6 +1929,16 @@ __metadata:
languageName: node
linkType: hard

"@openzeppelin/defender-sdk-base-client@npm:^1.6.0":
version: 1.6.0
resolution: "@openzeppelin/defender-sdk-base-client@npm:1.6.0"
dependencies:
amazon-cognito-identity-js: ^6.3.6
async-retry: ^1.3.3
checksum: 4516d16d18d42f6a43a856c9a8b5569ed17482e2714d80aaca9581ba7345deec4e654844933877e2ff0addad2594e127c2ffeac0d092bbbebb0b2cc7e984fce1
languageName: node
linkType: hard

"@openzeppelin/defender-sdk-deploy-client@npm:^1.2.0":
version: 1.5.0
resolution: "@openzeppelin/defender-sdk-deploy-client@npm:1.5.0"
Expand All @@ -1928,6 +1951,18 @@ __metadata:
languageName: node
linkType: hard

"@openzeppelin/defender-sdk-deploy-client@npm:^1.5.0":
version: 1.6.0
resolution: "@openzeppelin/defender-sdk-deploy-client@npm:1.6.0"
dependencies:
"@ethersproject/abi": ^5.7.0
"@openzeppelin/defender-sdk-base-client": ^1.6.0
axios: ^1.4.0
lodash: ^4.17.21
checksum: 32ed9c36affb976460945b1ecdb6f9c1d7e505e2f46e04943de1fae6aeb4cb0410205cff51c6552ab757d167ffae3a7eab0631580c9dbccb3fa7649220a930ed
languageName: node
linkType: hard

"@openzeppelin/hardhat-upgrades@npm:^1.28.0":
version: 1.28.0
resolution: "@openzeppelin/hardhat-upgrades@npm:1.28.0"
Expand Down Expand Up @@ -1980,6 +2015,34 @@ __metadata:
languageName: node
linkType: hard

"@openzeppelin/hardhat-upgrades@npm:^2.5.0":
version: 2.5.0
resolution: "@openzeppelin/hardhat-upgrades@npm:2.5.0"
dependencies:
"@openzeppelin/defender-admin-client": ^1.52.0
"@openzeppelin/defender-base-client": ^1.52.0
"@openzeppelin/defender-sdk-base-client": ^1.5.0
"@openzeppelin/defender-sdk-deploy-client": ^1.5.0
"@openzeppelin/upgrades-core": ^1.31.2
chalk: ^4.1.0
debug: ^4.1.1
ethereumjs-util: ^7.1.5
proper-lockfile: ^4.1.1
undici: ^5.14.0
peerDependencies:
"@nomicfoundation/hardhat-ethers": ^3.0.0
"@nomicfoundation/hardhat-verify": ^1.1.0
ethers: ^6.6.0
hardhat: ^2.0.2
peerDependenciesMeta:
"@nomicfoundation/hardhat-verify":
optional: true
bin:
migrate-oz-cli-project: dist/scripts/migrate-oz-cli-project.js
checksum: 2d431ad84635ddbefeb83e1d651e5ec49c1574c7cc70cf67ad98c1c8c75d359dc73d6a1e1b99c2543784a25f57b38b4cf6fae3ca621318f320a64c496df5696f
languageName: node
linkType: hard

"@openzeppelin/platform-deploy-client@npm:^0.8.0":
version: 0.8.0
resolution: "@openzeppelin/platform-deploy-client@npm:0.8.0"
Expand Down Expand Up @@ -2029,6 +2092,24 @@ __metadata:
languageName: node
linkType: hard

"@openzeppelin/upgrades-core@npm:^1.31.2":
version: 1.31.3
resolution: "@openzeppelin/upgrades-core@npm:1.31.3"
dependencies:
cbor: ^9.0.0
chalk: ^4.1.0
compare-versions: ^6.0.0
debug: ^4.1.1
ethereumjs-util: ^7.0.3
minimist: ^1.2.7
proper-lockfile: ^4.1.1
solidity-ast: ^0.4.51
bin:
openzeppelin-upgrades-core: dist/cli/cli.js
checksum: e7ab98bb822b7b69b0a5f333fd9113e13d05b995ccf880ea8e15406c2a5a0a8c0c61205e8b548859fac779c646d621c9315112c4bc16d7f5001b7fbf29972644
languageName: node
linkType: hard

"@parcel/watcher@npm:2.0.4":
version: 2.0.4
resolution: "@parcel/watcher@npm:2.0.4"
Expand Down Expand Up @@ -2337,8 +2418,11 @@ __metadata:
"@ethersproject/abi": ^5.7.0
"@ethersproject/providers": ^5.7.2
"@nomicfoundation/hardhat-chai-matchers": 1
"@nomicfoundation/hardhat-ethers": ^3.0.0
"@nomicfoundation/hardhat-network-helpers": ^1.0.8
"@nomicfoundation/hardhat-verify": ^1.1.0
"@nomiclabs/hardhat-ethers": ^2.2.3
"@openzeppelin/hardhat-upgrades": ^2.5.0
"@sandbox-smart-contracts/asset": "*"
"@sandbox-smart-contracts/core": "*"
"@sandbox-smart-contracts/dependency-operator-filter": "*"
Expand Down

0 comments on commit ade7e7c

Please sign in to comment.