From 66331aaaf16c406a2b9fb873d2f48a846a841bc8 Mon Sep 17 00:00:00 2001 From: Eric Lau Date: Mon, 16 Sep 2024 13:28:27 -0400 Subject: [PATCH] Defender: Add `metadata` option (#1079) --- .../ROOT/pages/api-hardhat-upgrades.adoc | 5 +- packages/plugin-hardhat/CHANGELOG.md | 4 ++ packages/plugin-hardhat/package.json | 8 +-- .../plugin-hardhat/src/defender/deploy.ts | 1 + packages/plugin-hardhat/src/utils/options.ts | 3 +- .../plugin-hardhat/test/defender-deploy.js | 62 +++++++++++++++++++ yarn.lock | 59 +++++++++++++----- 7 files changed, 117 insertions(+), 25 deletions(-) diff --git a/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc b/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc index 6f0c0a620..278489fbb 100644 --- a/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc +++ b/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc @@ -32,9 +32,8 @@ The following options are common to some functions. * `useDefenderDeploy`: (`boolean`) Deploy contracts using OpenZeppelin Defender instead of ethers.js. See xref:defender-deploy.adoc[Using with OpenZeppelin Defender]. * `verifySourceCode`: (`boolean`) When using OpenZeppelin Defender deployments, whether to verify source code on block explorers. Defaults to `true`. * `relayerId`: (`string`) When using OpenZeppelin Defender deployments, the ID of the relayer to use for the deployment. Defaults to the relayer configured for your deployment environment on Defender. -* `salt`: (`string`) When using OpenZeppelin Defender deployments, if this is not set, deployments will be performed using the CREATE opcode. If this is set, deployments will be performed using the CREATE2 opcode with the provided salt. Note that deployments using a Safe are done using CREATE2 and require a salt. **Warning:** CREATE2 affects `msg.sender` behavior. See https://docs.openzeppelin.com/defender/v2/tutorial/deploy#deploy-caveat[Caveats] for more information. - - +* `salt`: (`string`) When using OpenZeppelin Defender deployments, if this is not set, deployments will be performed using the CREATE opcode. If this is set, deployments will be performed using the CREATE2 opcode with the provided salt. Note that deployments using a Safe are done using CREATE2 and require a salt. **Warning:** CREATE2 affects `msg.sender` behavior. See https://docs.openzeppelin.com/defender/tutorial/deploy#deploy-caveat[Caveats] for more information. +* `metadata`: (`{ commitHash?: string; tag?: string; [k: string]: any; }`) When using OpenZeppelin Defender deployments, you can use this to identify, tag, or classify deployments. See https://docs.openzeppelin.com/defender/module/deploy#metadata[Metadata]. Note that the options `unsafeAllow` can also be specified in a more granular way directly in the source code if using Solidity >=0.8.2. See xref:faq.adoc#how-can-i-disable-checks[How can I disable some of the checks?] diff --git a/packages/plugin-hardhat/CHANGELOG.md b/packages/plugin-hardhat/CHANGELOG.md index 001a174ae..13fb6b1a6 100644 --- a/packages/plugin-hardhat/CHANGELOG.md +++ b/packages/plugin-hardhat/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 3.3.0 (2024-09-16) + +- Defender: Add `metadata` option. ([#1079](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1079)) + ## 3.2.1 (2024-07-31) - Fix Hardhat compile error when public variables are used to implement interface functions. ([#1055](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1055)) diff --git a/packages/plugin-hardhat/package.json b/packages/plugin-hardhat/package.json index 1055be568..bd4ee4020 100644 --- a/packages/plugin-hardhat/package.json +++ b/packages/plugin-hardhat/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/hardhat-upgrades", - "version": "3.2.1", + "version": "3.3.0", "description": "", "repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/plugin-hardhat", "license": "MIT", @@ -35,9 +35,9 @@ "sinon": "^18.0.0" }, "dependencies": { - "@openzeppelin/defender-sdk-base-client": "^1.10.0", - "@openzeppelin/defender-sdk-deploy-client": "^1.10.0", - "@openzeppelin/defender-sdk-network-client": "^1.10.0", + "@openzeppelin/defender-sdk-base-client": "^1.14.4", + "@openzeppelin/defender-sdk-deploy-client": "^1.14.4", + "@openzeppelin/defender-sdk-network-client": "^1.14.4", "@openzeppelin/upgrades-core": "^1.35.0", "chalk": "^4.1.0", "debug": "^4.1.1", diff --git a/packages/plugin-hardhat/src/defender/deploy.ts b/packages/plugin-hardhat/src/defender/deploy.ts index c7994e5b9..aad4699f9 100644 --- a/packages/plugin-hardhat/src/defender/deploy.ts +++ b/packages/plugin-hardhat/src/defender/deploy.ts @@ -113,6 +113,7 @@ export async function defenderDeploy( createFactoryAddress: opts.createFactoryAddress, txOverrides: parseTxOverrides(opts.txOverrides), libraries: contractInfo.libraries, + metadata: opts.metadata, }; let deploymentResponse: DeploymentResponse; diff --git a/packages/plugin-hardhat/src/utils/options.ts b/packages/plugin-hardhat/src/utils/options.ts index 318416fdf..9d8fc12ef 100644 --- a/packages/plugin-hardhat/src/utils/options.ts +++ b/packages/plugin-hardhat/src/utils/options.ts @@ -1,4 +1,4 @@ -import { SourceCodeLicense } from '@openzeppelin/defender-sdk-deploy-client'; +import { DeployMetadata, SourceCodeLicense } from '@openzeppelin/defender-sdk-deploy-client'; import { DeployOpts, ProxyKindOption, @@ -67,6 +67,7 @@ export type DefenderDeployOptions = DefenderDeploy & { createFactoryAddress?: string; licenseType?: SourceCodeLicense; skipLicenseType?: boolean; + metadata?: DeployMetadata; }; /** diff --git a/packages/plugin-hardhat/test/defender-deploy.js b/packages/plugin-hardhat/test/defender-deploy.js index a72f1534c..4ec7eb5a4 100644 --- a/packages/plugin-hardhat/test/defender-deploy.js +++ b/packages/plugin-hardhat/test/defender-deploy.js @@ -109,6 +109,7 @@ test('calls defender deploy', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -137,6 +138,7 @@ test('calls defender deploy with relayerId', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -165,6 +167,7 @@ test('calls defender deploy with salt', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -193,6 +196,7 @@ test('calls defender deploy with createFactoryAddress', async t => { createFactoryAddress: CREATE_FACTORY, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -221,6 +225,7 @@ test('calls defender deploy with license', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -251,6 +256,7 @@ test('calls defender deploy - licenseType', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -281,6 +287,7 @@ test('calls defender deploy - verifySourceCode false', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -311,6 +318,7 @@ test('calls defender deploy - skipLicenseType', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -392,6 +400,7 @@ test('calls defender deploy - no contract license', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -420,6 +429,7 @@ test('calls defender deploy - unlicensed', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -448,6 +458,7 @@ test('calls defender deploy with constructor args', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -476,6 +487,7 @@ test('calls defender deploy with constructor args with array', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -504,6 +516,7 @@ test('calls defender deploy with verify false', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -532,6 +545,7 @@ test('calls defender deploy with ERC1967Proxy', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); }); @@ -558,6 +572,7 @@ test('calls defender deploy with ERC1967Proxy - ignores constructorArgs', async createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); }); @@ -584,6 +599,7 @@ test('calls defender deploy with ERC1967Proxy - ignores empty constructorArgs', createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); }); @@ -610,6 +626,7 @@ test('calls defender deploy with BeaconProxy', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); }); @@ -639,6 +656,7 @@ test('calls defender deploy with TransparentUpgradeableProxy', async t => { createFactoryAddress: undefined, txOverrides: undefined, libraries: undefined, + metadata: undefined, }); }); @@ -670,6 +688,7 @@ test('calls defender deploy with txOverrides.gasLimit', async t => { maxPriorityFeePerGas: undefined, }, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -703,6 +722,7 @@ test('calls defender deploy with txOverrides.gasPrice', async t => { maxPriorityFeePerGas: undefined, }, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -738,6 +758,7 @@ test('calls defender deploy with txOverrides.maxFeePerGas and txOverrides.maxPri maxPriorityFeePerGas: '0xa', }, libraries: undefined, + metadata: undefined, }); assertResult(t, result); @@ -772,6 +793,7 @@ test('calls defender deploy with external library', async t => { libraries: { 'contracts/ExternalLibraries.sol:SafeMath': EXTERNAL_LIBRARY_ADDRESS, }, + metadata: undefined, }); assertResult(t, result); @@ -808,6 +830,46 @@ test('calls defender deploy with multiple external libraries', async t => { 'contracts/ExternalLibraries.sol:SafeMath': EXTERNAL_LIBRARY_ADDRESS, 'contracts/ExternalLibraries.sol:SafeMathV2': EXTERNAL_LIBRARY_2_ADDRESS, }, + metadata: undefined, + }); + + assertResult(t, result); +}); + +test('calls defender deploy with metadata', async t => { + const { spy, deploy, fakeHre, fakeChainId } = t.context; + + const contractPath = 'contracts/Greeter.sol'; + const contractName = 'Greeter'; + + const factory = await ethers.getContractFactory(contractName); + const result = await deploy.defenderDeploy(fakeHre, factory, { + metadata: { + commitHash: '4ae3e0d', + tag: 'v1.0.0', + anyOtherField: 'anyValue', + }, + }); + + const buildInfo = await hre.artifacts.getBuildInfo(`${contractPath}:${contractName}`); + sinon.assert.calledWithExactly(spy, { + contractName: contractName, + contractPath: contractPath, + network: fakeChainId, + artifactPayload: JSON.stringify(buildInfo), + licenseType: undefined, + constructorBytecode: '0x', + verifySourceCode: true, + relayerId: undefined, + salt: undefined, + createFactoryAddress: undefined, + txOverrides: undefined, + libraries: undefined, + metadata: { + commitHash: '4ae3e0d', + tag: 'v1.0.0', + anyOtherField: 'anyValue', + }, }); assertResult(t, result); diff --git a/yarn.lock b/yarn.lock index 97843a12c..6b797956f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -803,29 +803,29 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== -"@openzeppelin/defender-sdk-base-client@1.14.3", "@openzeppelin/defender-sdk-base-client@^1.10.0": - version "1.14.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.14.3.tgz#f44d6cdf709c1cfd44f5f5120679eb7c81678e71" - integrity sha512-4yG9E8N1c/ZP2jNR+Ah19wi7SBKpauAV/VcYcm7rg1dltDbzbH/oZnnXJlymT7IfjTPXkKHW8TPsaqz3EjS7tA== +"@openzeppelin/defender-sdk-base-client@^1.14.4": + version "1.14.4" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.14.4.tgz#3ccd3beb94cba61883f769afe7e6fdbdc5daa12d" + integrity sha512-tOePVQLKpqfGQ1GMzHvSBNd2psPYd86LDNpvdl5gjD0Y2kW/zNh5qBXy29RraGtk/qc8zs9hzS5pAOh0vhGkGQ== dependencies: amazon-cognito-identity-js "^6.3.6" async-retry "^1.3.3" -"@openzeppelin/defender-sdk-deploy-client@^1.10.0": - version "1.14.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.14.3.tgz#4676f454ba333664174edcf8c419a1fc0d04e780" - integrity sha512-51WIZJz251lndK7uQU4gBE0gBX+2ZNTgf+hemtJUEPCpHtkooBRFFMID3EPGMKXVqf872pU8K3Huu9PyYQu6bw== +"@openzeppelin/defender-sdk-deploy-client@^1.14.4": + version "1.14.4" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.14.4.tgz#1feb94575a32ed4ddee81d03cdb060064936a528" + integrity sha512-+diSoz1zid37LMsY2RDxI+uAsYx9Eryg8Vz+yfvuyd56fXrzjQEln7BBtYQw+2zp9yvyAByOL5XSQdrQga9OBQ== dependencies: - "@openzeppelin/defender-sdk-base-client" "1.14.3" + "@openzeppelin/defender-sdk-base-client" "^1.14.4" axios "^1.7.2" lodash "^4.17.21" -"@openzeppelin/defender-sdk-network-client@^1.10.0": - version "1.14.3" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.14.3.tgz#7b8ab18b5f7a62d2fd41d4b9f13581be91861f4d" - integrity sha512-qrJLs2ubKSwrhP0x4V2QOPhlc1q8TYnkAcvjvk34VXMS8lhY1cpXSGoxnTw3Mi+eCSE1xOzKWISLi1UAOQOJIw== +"@openzeppelin/defender-sdk-network-client@^1.14.4": + version "1.14.4" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.14.4.tgz#0f89c45f601e28c2f87c487b62b48d9cd4b5b956" + integrity sha512-OS0H5b0vgYacJcwkvUFJUaRuyUaXhIRl916W5xLvGia5H6i/qn3dP8MZ7oLcPwKc8jB+ucRytO4H/AHsea0aVA== dependencies: - "@openzeppelin/defender-sdk-base-client" "1.14.3" + "@openzeppelin/defender-sdk-base-client" "^1.14.4" axios "^1.7.2" lodash "^4.17.21" @@ -5143,7 +5143,16 @@ statuses@2.0.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5214,7 +5223,7 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5228,6 +5237,13 @@ strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: dependencies: ansi-regex "^4.1.0" +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -5700,7 +5716,7 @@ workerpool@^6.5.1: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -5727,6 +5743,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"