diff --git a/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc b/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc index b483d520d..52343528c 100644 --- a/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc +++ b/docs/modules/ROOT/pages/api-hardhat-upgrades.adoc @@ -40,6 +40,10 @@ The following options are common to some functions. * `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/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]. +* `proxyFactory`: (`ethers.ContractFactory`) Customizes the ethers contract factory to use for deploying the proxy, allowing a custom proxy contract to be deployed. See https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/plugin-hardhat/src/utils/factories.ts[factories.ts] for the default contract factory for each kind of proxy. +** *Since:* `@openzeppelin/hardhat-upgrades@3.7.0` +* `deployFunction`: (`(hre, opts, factory, ...args) => Promise`) Customizes the function used to deploy the proxy. Can be used along with the `proxyFactory` option to override constructor parameters for custom proxy deployments. See https://github.com/OpenZeppelin/openzeppelin-upgrades/blob/master/packages/plugin-hardhat/src/utils/deploy.ts[deploy.ts] for the default deploy function. +** *Since:* `@openzeppelin/hardhat-upgrades@3.7.0` 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?] @@ -69,6 +73,8 @@ async function deployProxy( txOverrides?: ethers.Overrides, kind?: 'uups' | 'transparent', useDefenderDeploy?: boolean, + proxyFactory?: ethers.ContractFactory, + deployFunction?: () => Promise, }, ): Promise ---- @@ -212,6 +218,8 @@ async function deployBeaconProxy( initializer?: string | false, txOverrides?: ethers.Overrides, useDefenderDeploy?: boolean, + proxyFactory?: ethers.ContractFactory, + deployFunction?: () => Promise, }, ): Promise ---- diff --git a/docs/modules/ROOT/pages/foundry/pages/foundry-upgrades.adoc b/docs/modules/ROOT/pages/foundry/pages/foundry-upgrades.adoc index 57290467e..70c68f5d2 100644 --- a/docs/modules/ROOT/pages/foundry/pages/foundry-upgrades.adoc +++ b/docs/modules/ROOT/pages/foundry/pages/foundry-upgrades.adoc @@ -49,6 +49,34 @@ Set the following in `remappings.txt`: NOTE: Use `LegacyUpgrades.sol` instead of `Upgrades.sol` to upgrade existing deployments that were created with OpenZeppelin Contracts v4. +=== Optional: Alternative installation methods + +==== NPM + +Follow the steps above, but instead of running `forge install OpenZeppelin/openzeppelin-foundry-upgrades`, use this command instead: +[source,console] +---- +npm install @openzeppelin/foundry-upgrades +---- + +Then add the following additional lines to `remappings.txt`, in addition to the ones described above: +[source,console] +---- +openzeppelin-foundry-upgrades/=node_modules/@openzeppelin/foundry-upgrades/src/ +solidity-stringutils/=node_modules/@openzeppelin/foundry-upgrades/lib/solidity-stringutils/ +---- + +==== Soldeer + +Follow the steps above, but instead of running `forge install OpenZeppelin/openzeppelin-foundry-upgrades`, use one of the install commands described in https://soldeer.xyz/project/openzeppelin-foundry-upgrades + +Then add the following additional lines to `remappings.txt`, in addition to the ones described above (replace `0.3.6` with the version of the plugin that you installed): +[source,console] +---- +openzeppelin-foundry-upgrades/=dependencies/openzeppelin-foundry-upgrades-0.3.6/src/ +solidity-stringutils/=dependencies/openzeppelin-foundry-upgrades-0.3.6/lib/solidity-stringutils/ +---- + == Foundry Requirements This library requires https://github.com/foundry-rs/forge-std[forge-std] version 1.8.0 or higher. diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md index 5d9d60461..860c04f07 100644 --- a/packages/core/CHANGELOG.md +++ b/packages/core/CHANGELOG.md @@ -4,6 +4,11 @@ - Detect issues in parent initializer calls. ([#1095](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1095)) +## 1.41.0 (2024-11-25) + +- Update Slang dependency to 0.18.3. ([#1102](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1102)) + - Improves reliability of Hardhat compilation step for namespaced storage layout validations when using Solidity versions 0.8.27 and 0.8.28. + ## 1.40.0 (2024-10-10) - Fix Hardhat compile error when overriding interface functions with public constant variables. ([#1091](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1091)) diff --git a/packages/core/package.json b/packages/core/package.json index 31d27cb30..905b44a63 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/upgrades-core", - "version": "1.40.0", + "version": "1.41.0", "description": "", "repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/core", "license": "MIT", @@ -61,7 +61,7 @@ "typescript": "^5.0.0" }, "dependencies": { - "@nomicfoundation/slang": "^0.17.0", + "@nomicfoundation/slang": "^0.18.3", "cbor": "^9.0.0", "chalk": "^4.1.0", "compare-versions": "^6.0.0", diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index d173104d6..cfeafaa55 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -60,7 +60,7 @@ export { export { ValidateUpgradeSafetyOptions, validateUpgradeSafety, ProjectReport, ReferenceContractNotFound } from './cli'; export { getUpgradeInterfaceVersion } from './upgrade-interface-version'; -export { makeNamespacedInput } from './utils/make-namespaced'; +export { makeNamespacedInput, trySanitizeNatSpec } from './utils/make-namespaced'; export { isNamespaceSupported } from './storage/namespace'; export { inferProxyAdmin } from './infer-proxy-admin'; export { assertUnreachable } from './utils/assert'; diff --git a/packages/core/src/utils/make-namespaced.test.ts b/packages/core/src/utils/make-namespaced.test.ts index 918b4ec67..b267fbbd8 100644 --- a/packages/core/src/utils/make-namespaced.test.ts +++ b/packages/core/src/utils/make-namespaced.test.ts @@ -6,7 +6,7 @@ import { TASK_COMPILE_SOLIDITY_RUN_SOLCJS, } from 'hardhat/builtin-tasks/task-names'; -import { makeNamespacedInput } from './make-namespaced'; +import { makeNamespacedInput, trySanitizeNatSpec } from './make-namespaced'; import { SolcBuild } from 'hardhat/types/builtin-tasks'; import { SolcInput, SolcOutput } from '../solc-api'; import { BuildInfo } from 'hardhat/types'; @@ -40,11 +40,10 @@ async function testMakeNamespaced( // Inefficient, but we want to test that we don't actually modify the original input object const origInput = JSON.parse(JSON.stringify(origBuildInfo.input)); - const modifiedInput = makeNamespacedInput( - origBuildInfo.input, - origBuildInfo.output, - keepAllNatSpec ? undefined : origBuildInfo.solcVersion, - ); + let modifiedInput = makeNamespacedInput(origBuildInfo.input, origBuildInfo.output, origBuildInfo.solcVersion); + if (!keepAllNatSpec) { + modifiedInput = await trySanitizeNatSpec(modifiedInput, origBuildInfo.solcVersion); + } // Run hardhat compile on the modified input and make sure it has no errors const modifiedOutput = await hardhatCompile(modifiedInput, solcVersion); diff --git a/packages/core/src/utils/make-namespaced.ts b/packages/core/src/utils/make-namespaced.ts index 850f33f58..c30c74ed1 100644 --- a/packages/core/src/utils/make-namespaced.ts +++ b/packages/core/src/utils/make-namespaced.ts @@ -34,10 +34,10 @@ const OUTPUT_SELECTION = { * * @param input The original solc input. * @param output The original solc output. - * @param solcVersion The version of the solc compiler that was originally used to compile the input. + * @param _solcVersion The version of the solc compiler that was originally used to compile the input. This argument is no longer used and is kept for backwards compatibility. * @returns The modified solc input with storage layout that includes namespaced type information. */ -export function makeNamespacedInput(input: SolcInput, output: SolcOutput, solcVersion?: string): SolcInput { +export function makeNamespacedInput(input: SolcInput, output: SolcOutput, _solcVersion?: string): SolcInput { const modifiedSources: Record = {}; for (const [sourcePath] of Object.entries(input.sources)) { @@ -163,74 +163,77 @@ export function makeNamespacedInput(input: SolcInput, output: SolcOutput, solcVe } } - const modifiedSource = tryRemoveNonStructNatSpec(getModifiedSource(orig, modifications), solcVersion); - - modifiedSources[sourcePath] = { ...source, content: modifiedSource }; + modifiedSources[sourcePath] = { ...source, content: getModifiedSource(orig, modifications) }; } return { ...input, sources: modifiedSources, settings: { ...input.settings, outputSelection: OUTPUT_SELECTION } }; } /** - * If we have the compiler version available and Slang is supported for the current platform and compiler version, - * use Slang to parse and remove all NatSpec comments that do not precede a struct definition and return the modified content. + * Attempts to remove all NatSpec comments that do not precede a struct definition from the input source contents. + * Directly modifies the input source contents, and also returns the modified input. + * + * If the solc version is not supported by the parser, the original content is kept. + * + * @param solcInput Solc input. + * @param solcVersion The version of the solc compiler that was originally used to compile the input. + * @returns The modified solc input with NatSpec comments removed where they do not precede a struct definition. + */ +export async function trySanitizeNatSpec(solcInput: SolcInput, solcVersion: string): Promise { + for (const [sourcePath, source] of Object.entries(solcInput.sources)) { + if (source.content !== undefined) { + solcInput.sources[sourcePath].content = await tryRemoveNonStructNatSpec(source.content, solcVersion); + } + } + return solcInput; +} + +/** + * If Slang is supported for the current compiler version, use Slang to parse and remove all NatSpec comments + * that do not precede a struct definition and return the modified content. * * Otherwise, return the original content. */ -function tryRemoveNonStructNatSpec(origContent: string, solcVersion: string | undefined): string { - const natSpecRemovals: Modification[] = []; +async function tryRemoveNonStructNatSpec(origContent: string, solcVersion: string): Promise { + if (solcVersion === undefined) { + return origContent; + } - if (solcVersion !== undefined && tryRequire('@nomicfoundation/slang') && slangSupportsVersion(solcVersion)) { - /* eslint-disable @typescript-eslint/no-var-requires */ - const { Language } = require('@nomicfoundation/slang/language'); - const { NonterminalKind, TerminalKind } = require('@nomicfoundation/slang/kinds'); - const { TerminalNode } = require('@nomicfoundation/slang/cst'); - const { isTrivia } = require('./slang/trivia'); - /* eslint-enable @typescript-eslint/no-var-requires */ + const { Parser } = await import('@nomicfoundation/slang/parser'); + if (!Parser.supportedVersions().includes(solcVersion)) { + return origContent; + } + + const { TerminalKind, TerminalKindExtensions } = await import('@nomicfoundation/slang/cst'); - const language = new Language(solcVersion); - const parseOutput = language.parse(NonterminalKind.SourceUnit, origContent); - const cursor = parseOutput.createTreeCursor(); + const parser = Parser.create(solcVersion); + const parseOutput = parser.parse(Parser.rootKind(), origContent); + const cursor = parseOutput.createTreeCursor(); + + const natSpecRemovals: Modification[] = []; + while ( + cursor.goToNextTerminalWithKinds([TerminalKind.MultiLineNatSpecComment, TerminalKind.SingleLineNatSpecComment]) + ) { + // Lookahead to determine if the next non-trivia node is the struct keyword. + // If so, this NatSpec is part of the struct definition and should not be removed. + const lookaheadCursor = cursor.clone(); while ( - cursor.goToNextTerminalWithKinds([TerminalKind.MultiLineNatSpecComment, TerminalKind.SingleLineNatSpecComment]) + lookaheadCursor.goToNextTerminal() && + lookaheadCursor.node.isTerminalNode() && + TerminalKindExtensions.isTrivia(lookaheadCursor.node.kind) ) { - // Lookahead to determine if the next non-trivia node is the struct keyword. - // If so, this NatSpec is part of the struct definition and should not be removed. - const lookaheadCursor = cursor.clone(); - while (lookaheadCursor.goToNextTerminal() && isTrivia(lookaheadCursor.node())) { - // skip over trivia nodes - } - if (lookaheadCursor.node().kind === TerminalKind.StructKeyword) { - continue; - } + // skip over trivia nodes + } - const triviaNode = cursor.node(); - assert(triviaNode instanceof TerminalNode); - natSpecRemovals.push(makeDeleteRange(cursor.textRange.start.utf8, cursor.textRange.end.utf8)); + if (lookaheadCursor.node.kind === TerminalKind.StructKeyword) { + continue; } - return getModifiedSource(Buffer.from(origContent, 'utf8'), natSpecRemovals); - } else { - return origContent; - } -} -function tryRequire(id: string) { - try { - require(id); - return true; - } catch (e: any) { - // do nothing + natSpecRemovals.push(makeDeleteRange(cursor.textRange.start.utf8, cursor.textRange.end.utf8)); } - return false; -} - -function slangSupportsVersion(solcVersion: string): boolean { - /* eslint-disable @typescript-eslint/no-var-requires */ - const { Language } = require('@nomicfoundation/slang/language'); - /* eslint-enable @typescript-eslint/no-var-requires */ - return Language.supportedVersions().includes(solcVersion); + return getModifiedSource(Buffer.from(origContent, 'utf8'), natSpecRemovals); } interface Modification { diff --git a/packages/core/src/utils/slang/trivia.ts b/packages/core/src/utils/slang/trivia.ts deleted file mode 100644 index b8b716b0a..000000000 --- a/packages/core/src/utils/slang/trivia.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { TerminalKind } from '@nomicfoundation/slang/kinds'; -import { Node, TerminalNode } from '@nomicfoundation/slang/cst'; - -/** - * Returns true if the node is a trivia terminal (whitespace or comment or NatSpec) - * - * CAUTION: This must be imported dynamically. - * Only import this file if Slang is supported on the current platform, otherwise an error will be thrown on import. - */ -export function isTrivia(node: Node) { - return node instanceof TerminalNode && isTriviaKind(node.kind); -} - -function isTriviaKind(kind: TerminalKind) { - return ( - kind === TerminalKind.EndOfLine || - kind === TerminalKind.MultiLineComment || - kind === TerminalKind.MultiLineNatSpecComment || - kind === TerminalKind.SingleLineComment || - kind === TerminalKind.SingleLineNatSpecComment || - kind === TerminalKind.Whitespace - ); -} diff --git a/packages/plugin-hardhat/CHANGELOG.md b/packages/plugin-hardhat/CHANGELOG.md index 02f25b39b..97f40e6c4 100644 --- a/packages/plugin-hardhat/CHANGELOG.md +++ b/packages/plugin-hardhat/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 3.7.0 (2024-12-04) + +- Add `proxyFactory` and `deployFunction` options which can be used to deploy a custom proxy contract. ([#1104](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1104)) + +## 3.6.0 (2024-11-25) + +- Update Slang dependency to 0.18.3. ([#1102](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1102)) + - Improves reliability of Hardhat compilation step for namespaced storage layout validations when using Solidity versions 0.8.27 and 0.8.28. + ## 3.5.0 (2024-10-10) - Support ignoring Hardhat compile errors when extracting detailed namespaced storage layouts for validations. ([#1090](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/1090)) diff --git a/packages/plugin-hardhat/contracts/AccessManagedProxy.sol b/packages/plugin-hardhat/contracts/AccessManagedProxy.sol new file mode 100644 index 000000000..9cc234ec1 --- /dev/null +++ b/packages/plugin-hardhat/contracts/AccessManagedProxy.sol @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +// Example of a custom proxy. +// This contract is for testing only. + +import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; +import {AccessManager} from "@openzeppelin/contracts/access/manager/AccessManager.sol"; +import {IAccessManager} from "@openzeppelin/contracts/access/manager/IAccessManager.sol"; +import {IAccessManaged} from "@openzeppelin/contracts/access/manager/IAccessManaged.sol"; + +contract AccessManagedProxy is ERC1967Proxy { + IAccessManager public immutable ACCESS_MANAGER; + + constructor(address implementation, bytes memory _data, IAccessManager manager) payable ERC1967Proxy(implementation, _data) { + ACCESS_MANAGER = manager; + } + + /** + * @dev Checks with the ACCESS_MANAGER if msg.sender is authorized to call the current call's function, + * and if so, delegates the current call to `implementation`. + * + * This function does not return to its internal call site, it will return directly to the external caller. + */ + function _delegate(address implementation) internal virtual override { + (bool immediate, ) = ACCESS_MANAGER.canCall(msg.sender, address(this), bytes4(msg.data[0:4])); + if (!immediate) revert IAccessManaged.AccessManagedUnauthorized(msg.sender); + super._delegate(implementation); + } +} diff --git a/packages/plugin-hardhat/contracts/CustomBeaconProxy.sol b/packages/plugin-hardhat/contracts/CustomBeaconProxy.sol new file mode 100644 index 000000000..656157ba6 --- /dev/null +++ b/packages/plugin-hardhat/contracts/CustomBeaconProxy.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +import {BeaconProxy} from "@openzeppelin/contracts/proxy/beacon/BeaconProxy.sol"; + +// Example of a custom beacon proxy. +// This contract is for testing only, it is not safe for use in production. + +contract CustomBeaconProxy is BeaconProxy { + address private immutable _deployer; + // The beacon that will be used on calls by the deployer address + address private immutable _deployerBeacon; + + constructor(address beacon, bytes memory data, address deployerBeacon) payable BeaconProxy(beacon, data) { + _deployer = msg.sender; + _deployerBeacon = deployerBeacon; + } + + function _getBeacon() internal view override returns (address) { + if (msg.sender == _deployer) return _deployerBeacon; + return super._getBeacon(); + } +} diff --git a/packages/plugin-hardhat/package.json b/packages/plugin-hardhat/package.json index 12223d56a..298f8dec9 100644 --- a/packages/plugin-hardhat/package.json +++ b/packages/plugin-hardhat/package.json @@ -1,6 +1,6 @@ { "name": "@openzeppelin/hardhat-upgrades", - "version": "3.5.0", + "version": "3.7.0", "description": "", "repository": "https://github.com/OpenZeppelin/openzeppelin-upgrades/tree/master/packages/plugin-hardhat", "license": "MIT", @@ -38,7 +38,7 @@ "@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.40.0", + "@openzeppelin/upgrades-core": "^1.41.0", "chalk": "^4.1.0", "debug": "^4.1.1", "ethereumjs-util": "^7.1.5", diff --git a/packages/plugin-hardhat/src/defender/deploy.ts b/packages/plugin-hardhat/src/defender/deploy.ts index aad4699f9..1bc1e933b 100644 --- a/packages/plugin-hardhat/src/defender/deploy.ts +++ b/packages/plugin-hardhat/src/defender/deploy.ts @@ -9,12 +9,7 @@ import { DeployContractRequest, DeployRequestLibraries, } from '@openzeppelin/defender-sdk-deploy-client'; -import { - Deployment, - RemoteDeploymentId, - getContractNameAndRunValidation, - UpgradesError, -} from '@openzeppelin/upgrades-core'; +import { getContractNameAndRunValidation, UpgradesError } from '@openzeppelin/upgrades-core'; import artifactsBuildInfo from '@openzeppelin/upgrades-core/artifacts/build-info-v5.json'; @@ -24,7 +19,7 @@ import UpgradeableBeacon from '@openzeppelin/upgrades-core/artifacts/@openzeppel import TransparentUpgradeableProxy from '@openzeppelin/upgrades-core/artifacts/@openzeppelin/contracts-v5/proxy/transparent/TransparentUpgradeableProxy.sol/TransparentUpgradeableProxy.json'; import { getNetwork, parseTxOverrides } from './utils'; -import { DeployTransaction, DefenderDeployOptions, UpgradeOptions, EthersDeployOptions } from '../utils'; +import { DefenderDeployOptions, UpgradeOptions, EthersDeployOptions, DefenderDeployment } from '../utils'; import debug from '../utils/debug'; import { getDeployData } from '../utils/deploy-impl'; import { ContractSourceNotFoundError } from '@openzeppelin/upgrades-core'; @@ -60,7 +55,7 @@ export async function defenderDeploy( factory: ContractFactory, opts: UpgradeOptions & EthersDeployOptions & DefenderDeployOptions, ...args: unknown[] -): Promise & DeployTransaction> { +): Promise { const client = getDeployClient(hre); // Override constructor arguments in options with the ones passed as arguments to this function. diff --git a/packages/plugin-hardhat/src/deploy-beacon-proxy.ts b/packages/plugin-hardhat/src/deploy-beacon-proxy.ts index 68514532f..63686dbed 100644 --- a/packages/plugin-hardhat/src/deploy-beacon-proxy.ts +++ b/packages/plugin-hardhat/src/deploy-beacon-proxy.ts @@ -80,10 +80,10 @@ export function makeDeployBeaconProxy( ]); } - const BeaconProxyFactory = await getBeaconProxyFactory(hre, getSigner(attachTo.runner)); + const BeaconProxyFactory = opts.proxyFactory || (await getBeaconProxyFactory(hre, getSigner(attachTo.runner))); const proxyDeployment: Required & DeployTransaction & RemoteDeploymentId = Object.assign( { kind: opts.kind }, - await deploy(hre, opts, BeaconProxyFactory, beaconAddress, data), + await (opts.deployFunction || deploy)(hre, opts, BeaconProxyFactory, beaconAddress, data), ); await manifest.addProxy(proxyDeployment); diff --git a/packages/plugin-hardhat/src/deploy-contract.ts b/packages/plugin-hardhat/src/deploy-contract.ts index e29fa4962..080d7e677 100644 --- a/packages/plugin-hardhat/src/deploy-contract.ts +++ b/packages/plugin-hardhat/src/deploy-contract.ts @@ -1,12 +1,10 @@ import { HardhatRuntimeEnvironment } from 'hardhat/types'; import type { ContractFactory, Contract } from 'ethers'; -import { deploy, DeployContractOptions, DeployTransaction } from './utils'; +import { deploy, DeployContractOptions, EthersOrDefenderDeployment } from './utils'; import { DeployData, getDeployData } from './utils/deploy-impl'; import { enableDefender } from './defender/utils'; import { - Deployment, - RemoteDeploymentId, getContractNameAndRunValidation, inferProxyKind, UpgradesError, @@ -30,7 +28,7 @@ async function deployNonUpgradeableContract( assertNonUpgradeable(deployData); } - const deployment: Required & DeployTransaction & RemoteDeploymentId = await deploy( + const deployment: EthersOrDefenderDeployment = await deploy( hre, opts, Contract, diff --git a/packages/plugin-hardhat/src/deploy-proxy.ts b/packages/plugin-hardhat/src/deploy-proxy.ts index 1fdf68b0b..370464f56 100644 --- a/packages/plugin-hardhat/src/deploy-proxy.ts +++ b/packages/plugin-hardhat/src/deploy-proxy.ts @@ -51,6 +51,7 @@ export function makeDeployProxy(hre: HardhatRuntimeEnvironment, defenderModule: const contractInterface = ImplFactory.interface; const data = getInitializerData(contractInterface, args, opts.initializer); + const deployFn = opts.deployFunction || deploy; if (await manifest.getAdmin()) { if (kind === 'uups') { @@ -79,8 +80,8 @@ export function makeDeployProxy(hre: HardhatRuntimeEnvironment, defenderModule: throw new InitialOwnerUnsupportedKindError(kind); } - const ProxyFactory = await getProxyFactory(hre, signer); - proxyDeployment = Object.assign({ kind }, await deploy(hre, opts, ProxyFactory, impl, data)); + const ProxyFactory = opts.proxyFactory || (await getProxyFactory(hre, signer)); + proxyDeployment = Object.assign({ kind }, await deployFn(hre, opts, ProxyFactory, impl, data)); break; } @@ -95,10 +96,11 @@ export function makeDeployProxy(hre: HardhatRuntimeEnvironment, defenderModule: ); } - const TransparentUpgradeableProxyFactory = await getTransparentUpgradeableProxyFactory(hre, signer); + const TransparentUpgradeableProxyFactory = + opts.proxyFactory || (await getTransparentUpgradeableProxyFactory(hre, signer)); proxyDeployment = Object.assign( { kind }, - await deploy(hre, opts, TransparentUpgradeableProxyFactory, impl, initialOwner, data), + await deployFn(hre, opts, TransparentUpgradeableProxyFactory, impl, initialOwner, data), ); break; } diff --git a/packages/plugin-hardhat/src/index.ts b/packages/plugin-hardhat/src/index.ts index f7458a300..21bb4241f 100644 --- a/packages/plugin-hardhat/src/index.ts +++ b/packages/plugin-hardhat/src/index.ts @@ -69,7 +69,9 @@ interface RunCompilerArgs { } subtask(TASK_COMPILE_SOLIDITY, async (args: { force: boolean }, hre, runSuper) => { - const { readValidations, ValidationsCacheOutdated, ValidationsCacheNotFound } = await import('./utils/validations'); + const { readValidations, ValidationsCacheOutdated, ValidationsCacheNotFound } = await import( + './utils/validations.js' + ); try { await readValidations(hre); @@ -85,21 +87,21 @@ subtask(TASK_COMPILE_SOLIDITY, async (args: { force: boolean }, hre, runSuper) = }); subtask(TASK_COMPILE_SOLIDITY_COMPILE, async (args: RunCompilerArgs, hre, runSuper) => { - const { isNamespaceSupported, validate, solcInputOutputDecoder, makeNamespacedInput } = await import( - '@openzeppelin/upgrades-core' - ); - const { writeValidations } = await import('./utils/validations'); + const { isNamespaceSupported, validate, solcInputOutputDecoder, makeNamespacedInput, trySanitizeNatSpec } = + await import('@openzeppelin/upgrades-core'); + const { writeValidations } = await import('./utils/validations.js'); // TODO: patch input const { output, solcBuild } = await runSuper(); - const { isFullSolcOutput } = await import('./utils/is-full-solc-output'); + const { isFullSolcOutput } = await import('./utils/is-full-solc-output.js'); if (isFullSolcOutput(output)) { const decodeSrc = solcInputOutputDecoder(args.input, output); let namespacedOutput = undefined; if (isNamespaceSupported(args.solcVersion)) { - const namespacedInput = makeNamespacedInput(args.input, output, args.solcVersion); + let namespacedInput = makeNamespacedInput(args.input, output, args.solcVersion); + namespacedInput = await trySanitizeNatSpec(namespacedInput, args.solcVersion); namespacedOutput = (await runSuper({ ...args, quiet: true, input: namespacedInput })).output; const namespacedCompileErrors = getNamespacedCompileErrors(namespacedOutput); @@ -210,7 +212,7 @@ extendConfig((config: HardhatConfig) => { if (tryRequire('@nomicfoundation/hardhat-verify')) { subtask('verify:etherscan').setAction(async (args, hre, runSuper) => { - const { verify } = await import('./verify-proxy'); + const { verify } = await import('./verify-proxy.js'); return await verify(args, hre, runSuper); }); } diff --git a/packages/plugin-hardhat/src/utils/deploy.ts b/packages/plugin-hardhat/src/utils/deploy.ts index fab957310..954331726 100644 --- a/packages/plugin-hardhat/src/utils/deploy.ts +++ b/packages/plugin-hardhat/src/utils/deploy.ts @@ -8,13 +8,17 @@ export interface DeployTransaction { deployTransaction?: ethers.TransactionResponse; } +// Defender always includes RemoteDeploymentId, while ethers always includes DeployTransaction +export type EthersOrDefenderDeployment = Required & DeployTransaction & RemoteDeploymentId; +export type DefenderDeployment = Required & DeployTransaction; +export type EthersDeployment = Required & RemoteDeploymentId; + export async function deploy( hre: HardhatRuntimeEnvironment, opts: UpgradeOptions & EthersDeployOptions & DefenderDeployOptions, factory: ContractFactory, ...args: unknown[] -): Promise & DeployTransaction & RemoteDeploymentId> { - // defender always includes RemoteDeploymentId, while ethers always includes DeployTransaction +): Promise { if (opts?.useDefenderDeploy) { return await defenderDeploy(hre, factory, opts, ...args); } else { @@ -28,7 +32,7 @@ export async function deploy( async function ethersDeploy( factory: ContractFactory, ...args: ContractMethodArgs -): Promise & RemoteDeploymentId> { +): Promise { const contractInstance = await factory.deploy(...args); const deployTransaction = contractInstance.deploymentTransaction(); diff --git a/packages/plugin-hardhat/src/utils/options.ts b/packages/plugin-hardhat/src/utils/options.ts index cd2ba413c..3ee7954a1 100644 --- a/packages/plugin-hardhat/src/utils/options.ts +++ b/packages/plugin-hardhat/src/utils/options.ts @@ -6,7 +6,23 @@ import { ValidationOptions, withValidationDefaults, } from '@openzeppelin/upgrades-core'; -import { Overrides } from 'ethers'; +import { ContractFactory, Overrides } from 'ethers'; +import { EthersOrDefenderDeployment } from './deploy'; + +/** + * Options for customizing the factory or deploy functions + */ +export type DeployFactoryOpts = { + /** + * Allows to customize the ethers ContractFactory of the proxy to deploy, instead of using the ones defined in utils/factories.ts + */ + proxyFactory?: ContractFactory; + + /** + * Allows to customize the deploy function used instead of utils/deploy.ts:deploy + */ + deployFunction?: () => Promise; +}; /** * Options for functions that can deploy an implementation contract. @@ -91,6 +107,7 @@ export type InitialOwner = { export type DeployBeaconProxyOptions = EthersDeployOptions & DeployOpts & + DeployFactoryOpts & ProxyKindOption & Initializer & DefenderDeployOptions; @@ -101,7 +118,11 @@ export type DeployContractOptions = Omit & // DefenderDeployOptions & { unsafeAllowDeployContract?: boolean; }; -export type DeployProxyOptions = StandaloneOptions & Initializer & InitialOwner & DefenderDeployOptions; +export type DeployProxyOptions = StandaloneOptions & + DeployFactoryOpts & + Initializer & + InitialOwner & + DefenderDeployOptions; export type ForceImportOptions = ProxyKindOption; export type PrepareUpgradeOptions = UpgradeOptions & GetTxResponse & DefenderDeployOptions; export type UpgradeBeaconOptions = UpgradeOptions & DefenderDeploy; diff --git a/packages/plugin-hardhat/test/beacon-custom-beacon-proxy.js b/packages/plugin-hardhat/test/beacon-custom-beacon-proxy.js new file mode 100644 index 000000000..9a77472e5 --- /dev/null +++ b/packages/plugin-hardhat/test/beacon-custom-beacon-proxy.js @@ -0,0 +1,56 @@ +const test = require('ava'); + +const { ethers, upgrades } = require('hardhat'); +const { deploy } = require('../dist/utils/deploy'); + +test.before(async t => { + t.context.Greeter = await ethers.getContractFactory('Greeter'); + t.context.GreeterV2 = await ethers.getContractFactory('GreeterV2'); + t.context.GreeterV3 = await ethers.getContractFactory('GreeterV3'); + t.context.CustomBeaconProxy = await ethers.getContractFactory('CustomBeaconProxy'); + const [deployer, anon] = await ethers.getSigners(); + t.context.deployer = deployer; + t.context.anon = anon; +}); + +async function deployWithExtraProxyArgs(hre, opts, factory, ...args) { + const allArgs = [...args, ...(opts.proxyExtraConstructorArgs || [])]; + return deploy(hre, opts, factory, ...allArgs); +} + +test('custom beacon proxy factory and deploy function', async t => { + const { Greeter, GreeterV2, GreeterV3, CustomBeaconProxy, deployer, anon } = t.context; + + const greeterBeacon = await upgrades.deployBeacon(Greeter); + const greeterBeaconDeployer = await upgrades.deployBeacon(GreeterV2); + const greeter = await upgrades.deployBeaconProxy(greeterBeacon, Greeter, ['Hello, Hardhat!'], { + proxyFactory: CustomBeaconProxy, + deployFunction: deployWithExtraProxyArgs, + proxyExtraConstructorArgs: [await greeterBeaconDeployer.getAddress()], + }); + await greeter.waitForDeployment(); + t.is(await greeter.greet(), 'Hello, Hardhat!'); + + const greeterAsV2 = GreeterV2.attach(await greeter.getAddress()); + + // When calling from anon, uses Greeter as implementation and doesn't have resetGreeting method + let e = await t.throwsAsync(() => greeterAsV2.connect(anon).resetGreeting()); + t.true(e.message.includes('Transaction reverted: function selector was not recognized'), e.message); + + // When calling from deployer address, uses Greeter as implementation and doesn't have resetGreeting method + await greeterAsV2.connect(deployer).resetGreeting(); + + // For both changes the greet, because even when using different implementations, they share the storage + t.is(await greeterAsV2.connect(anon).greet(), 'Hello World'); + t.is(await greeterAsV2.connect(deployer).greet(), 'Hello World'); + + // Upgrade only the deployer beacon + await upgrades.upgradeBeacon(greeterBeaconDeployer, GreeterV3); + + const greeterAsV3 = GreeterV3.attach(await greeter.getAddress()); + + // When calling from anon, still uses Greeter as implementation and doesn't have version() method + e = await t.throwsAsync(() => greeterAsV3.connect(anon).version()); + t.true(e.message.includes('Transaction reverted: function selector was not recognized'), e.message); + t.is(await greeterAsV3.connect(deployer).version(), 'V3'); +}); diff --git a/packages/plugin-hardhat/test/uups-custom-proxy.js b/packages/plugin-hardhat/test/uups-custom-proxy.js new file mode 100644 index 000000000..fd1dd1441 --- /dev/null +++ b/packages/plugin-hardhat/test/uups-custom-proxy.js @@ -0,0 +1,53 @@ +const test = require('ava'); + +const { ethers, upgrades } = require('hardhat'); +const { deploy } = require('../dist/utils/deploy'); + +test.before(async t => { + t.context.Greeter = await ethers.getContractFactory('GreeterProxiable'); + t.context.GreeterV2 = await ethers.getContractFactory('GreeterV2Proxiable'); + t.context.GreeterV3 = await ethers.getContractFactory('GreeterV3Proxiable'); + t.context.AccessManagedProxy = await ethers.getContractFactory('AccessManagedProxy'); + const AccessManager = await ethers.getContractFactory('AccessManager'); + const [admin, anon] = await ethers.getSigners(); + t.context.admin = admin; + t.context.anon = anon; + t.context.acMgr = await AccessManager.deploy(admin); +}); + +async function deployWithExtraProxyArgs(hre, opts, factory, ...args) { + const allArgs = [...args, ...(opts.proxyExtraConstructorArgs || [])]; + return deploy(hre, opts, factory, ...allArgs); +} + +test('custom uups proxy factory and deploy function', async t => { + const { Greeter, GreeterV2, GreeterV3, AccessManagedProxy, acMgr, admin, anon } = t.context; + + const greeter = await upgrades.deployProxy(Greeter, ['Hello, Hardhat!'], { + kind: 'uups', + proxyExtraConstructorArgs: [await acMgr.getAddress()], + deployFunction: deployWithExtraProxyArgs, + proxyFactory: AccessManagedProxy, + }); + + // By default it calls from admin address, so, it works fine + let greet = await greeter.connect(admin).greet(); + t.is(greet, 'Hello, Hardhat!'); + // But fails when called from other user + let e = await t.throwsAsync(() => greeter.connect(anon).greet()); + t.true(e.message.includes('AccessManagedUnauthorized'), e.message); + + // Upgrades work well, because the call executed from the default signer that is the admin + const greeter2 = await upgrades.upgradeProxy(greeter, GreeterV2); + await greeter2.waitForDeployment(); + await greeter2.resetGreeting(); + + // Upgrades don't break the access control + e = await t.throwsAsync(() => greeter2.connect(anon).resetGreeting()); + t.true(e.message.includes('AccessManagedUnauthorized'), e.message); + + const greeter3ImplAddr = await upgrades.prepareUpgrade(await greeter.getAddress(), GreeterV3); + const greeter3 = GreeterV3.attach(greeter3ImplAddr); + const version3 = await greeter3.version(); + t.is(version3, 'V3'); +}); diff --git a/submodules/openzeppelin-foundry-upgrades b/submodules/openzeppelin-foundry-upgrades index 16e0ae21e..6461ba385 160000 --- a/submodules/openzeppelin-foundry-upgrades +++ b/submodules/openzeppelin-foundry-upgrades @@ -1 +1 @@ -Subproject commit 16e0ae21e0e39049f619f2396fa28c57fad07368 +Subproject commit 6461ba3851dea1fa4381a0fb1477c669279cdd44 diff --git a/tsconfig.base.json b/tsconfig.base.json index 3d424f2c4..546061581 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -2,9 +2,9 @@ "compilerOptions": { "incremental": true, "target": "es2020", - "module": "commonjs", + "module": "nodenext", "strict": true, - "moduleResolution": "node", + "moduleResolution": "nodenext", "esModuleInterop": true, "sourceMap": true, "declaration": true, diff --git a/yarn.lock b/yarn.lock index 960f6012a..8a44640ba 100644 --- a/yarn.lock +++ b/yarn.lock @@ -208,6 +208,11 @@ "@babel/helper-validator-identifier" "^7.24.7" to-fast-properties "^2.0.0" +"@bytecodealliance/preview2-shim@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz#9bc1cadbb9f86c446c6f579d3431c08a06a6672e" + integrity sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ== + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -685,65 +690,12 @@ table "^6.8.0" undici "^5.14.0" -"@nomicfoundation/slang-darwin-arm64@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-darwin-arm64/-/slang-darwin-arm64-0.17.0.tgz#8cded3c24322624e3b6618760caba8e840bd1c1d" - integrity sha512-O0q94EUtoWy9A5kOTOa9/khtxXDYnLqmuda9pQELurSiwbQEVCPQL8kb34VbOW+ifdre66JM/05Xw9JWhIZ9sA== - -"@nomicfoundation/slang-darwin-x64@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-darwin-x64/-/slang-darwin-x64-0.17.0.tgz#6ebeb33a2ced89fc6023f6cda4af96403486038a" - integrity sha512-IaDbHzvT08sBK2HyGzonWhq1uu8IxdjmTqAWHr25Oh/PYnamdi8u4qchZXXYKz/DHLoYN3vIpBXoqLQIomhD/g== - -"@nomicfoundation/slang-linux-arm64-gnu@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-arm64-gnu/-/slang-linux-arm64-gnu-0.17.0.tgz#41c7e57a9b1a3aee6911f0cab22e683c149fb470" - integrity sha512-Lj4anvOsQZxs1SycG8VyT2Rl2oqIhyLSUCgGepTt3CiJ/bM+8r8bLJIgh8vKkki4BWz49YsYIgaJB2IPv8FFTw== - -"@nomicfoundation/slang-linux-arm64-musl@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-arm64-musl/-/slang-linux-arm64-musl-0.17.0.tgz#9c4b51689274ae75c2c8a4cddd2e1cc0a79c191d" - integrity sha512-/xkTCa9d5SIWUBQE3BmLqDFfJRr4yUBwbl4ynPiGUpRXrD69cs6pWKkwjwz/FdBpXqVo36I+zY95qzoTj/YhOA== - -"@nomicfoundation/slang-linux-x64-gnu@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-x64-gnu/-/slang-linux-x64-gnu-0.17.0.tgz#c3a3b6a7b775fc617832958d10e6664bf86d39d0" - integrity sha512-oe5IO5vntOqYvTd67deCHPIWuSuWm6aYtT2/0Kqz2/VLtGz4ClEulBSRwfnNzBVtw2nksWipE1w8BzhImI7Syg== - -"@nomicfoundation/slang-linux-x64-musl@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-linux-x64-musl/-/slang-linux-x64-musl-0.17.0.tgz#725118ff99a7217b9f1d1bd84411d9442084077d" - integrity sha512-PpYCI5K/kgLAMXaPY0V4VST5gCDprEOh7z/47tbI8kJQumI5odjsj/Cs8MpTo7/uRH6flKYbVNgUzcocWVYrAQ== - -"@nomicfoundation/slang-win32-arm64-msvc@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-win32-arm64-msvc/-/slang-win32-arm64-msvc-0.17.0.tgz#9c8bc4ccf21eaaac0cfcb6d3954ede4e2dea4c02" - integrity sha512-u/Mkf7OjokdBilP7QOJj6QYJU4/mjkbKnTX21wLyCIzeVWS7yafRPYpBycKIBj2pRRZ6ceAY5EqRpb0aiCq+0Q== - -"@nomicfoundation/slang-win32-ia32-msvc@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-win32-ia32-msvc/-/slang-win32-ia32-msvc-0.17.0.tgz#3fc5d00a3f8c1d85a5e94146af78a5526a4f3d27" - integrity sha512-XJBVQfNnZQUv0tP2JSJ573S+pmgrLWgqSZOGaMllnB/TL1gRci4Z7dYRJUF2s82GlRJE+FHSI2Ro6JISKmlXCg== - -"@nomicfoundation/slang-win32-x64-msvc@0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang-win32-x64-msvc/-/slang-win32-x64-msvc-0.17.0.tgz#f6a5e3250fa07cbda49151edeb80f09090e5b71a" - integrity sha512-zPGsAeiTfqfPNYHD8BfrahQmYzA78ZraoHKTGraq/1xwJwzBK4bu/NtvVA4pJjBV+B4L6DCxVhSbpn40q26JQA== - -"@nomicfoundation/slang@^0.17.0": - version "0.17.0" - resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.17.0.tgz#d9c25cd711ebf3490c9d0c99e9b4ca2481341a6b" - integrity sha512-1GlkGRcGpVnjFw9Z1vvDKOKo2mzparFt7qrl2pDxWp+jrVtlvej98yCMX52pVyrYE7ZeOSZFnx/DtsSgoukStQ== - dependencies: - "@nomicfoundation/slang-darwin-arm64" "0.17.0" - "@nomicfoundation/slang-darwin-x64" "0.17.0" - "@nomicfoundation/slang-linux-arm64-gnu" "0.17.0" - "@nomicfoundation/slang-linux-arm64-musl" "0.17.0" - "@nomicfoundation/slang-linux-x64-gnu" "0.17.0" - "@nomicfoundation/slang-linux-x64-musl" "0.17.0" - "@nomicfoundation/slang-win32-arm64-msvc" "0.17.0" - "@nomicfoundation/slang-win32-ia32-msvc" "0.17.0" - "@nomicfoundation/slang-win32-x64-msvc" "0.17.0" +"@nomicfoundation/slang@^0.18.3": + version "0.18.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.18.3.tgz#976b6c3820081cebf050afbea434038aac9313cc" + integrity sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ== + dependencies: + "@bytecodealliance/preview2-shim" "0.17.0" "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": version "0.1.2" @@ -2250,7 +2202,7 @@ elliptic@6.5.4: minimalistic-assert "^1.0.1" minimalistic-crypto-utils "^1.0.1" -elliptic@^6.5.2, elliptic@^6.5.4: +elliptic@^6.5.2, elliptic@^6.5.7: version "6.5.7" resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.7.tgz#8ec4da2cb2939926a1b9a73619d768207e647c8b" integrity sha512-ESVCtTwiA+XhY3wyh24QqRGBoP3rEdDUl3EDUUo9tft074fi19IrdpH7hLCMMP3CIj7jb3W96rn8lt/BqIlt5Q== @@ -4177,6 +4129,11 @@ node-addon-api@^2.0.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -4874,12 +4831,12 @@ scrypt-js@^3.0.0: integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + version "4.0.4" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.4.tgz#58f0bfe1830fe777d9ca1ffc7574962a8189f8ab" + integrity sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw== dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" + elliptic "^6.5.7" + node-addon-api "^5.0.0" node-gyp-build "^4.2.0" "semver@2 || 3 || 4 || 5", semver@^5.5.0: @@ -5141,16 +5098,7 @@ 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": - 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: +"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: 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== @@ -5221,7 +5169,7 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", 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== @@ -5235,13 +5183,6 @@ 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" @@ -5714,7 +5655,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-cjs@npm:wrap-ansi@^7.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== @@ -5741,15 +5682,6 @@ 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"