Skip to content

Commit 46c318f

Browse files
Amxxfrangio
andauthored
Support constructorArgs for implementation (#433)
Co-authored-by: Francisco Giordano <[email protected]>
1 parent 6a1969f commit 46c318f

File tree

21 files changed

+257
-43
lines changed

21 files changed

+257
-43
lines changed

docs/modules/ROOT/pages/api-hardhat-upgrades.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ The following options are common to all functions.
1717
** `"delegatecall"`, `"selfdestruct"`: Allow the use of these operations. Incorrect use of this option can put funds at risk of permanent loss. See xref:faq.adoc#delegatecall-selfdestruct[Can I safely use `delegatecall` and `selfdestruct`?]
1818
** `"missing-public-upgradeto"`: Allow UUPS implementations that do not contain a public `upgradeTo` function. Enabling this option is likely to cause a revert due to the built-in UUPS safety mechanism.
1919
* `unsafeAllowRenames`: (`boolean`) Configure storage layout check to allow variable renaming.
20+
* `constructorArgs`: (`unknown[]`) Provide arguments for the constructor of the implementation contract. Note that these are different from initializer arguments, and will be used in the deployment of the implementation contract itself. Can be used to initialize immutable variables.
2021

2122
Note that the options un `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?]
2223

docs/modules/ROOT/pages/api-truffle-upgrades.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ The following options are common to all functions.
1818
** `"delegatecall"`, `"selfdestruct"`: Allow the use of these operations. Incorrect use of this option can put funds at risk of permanent loss. See xref:faq.adoc#delegatecall-selfdestruct[Can I safely use `delegatecall` and `selfdestruct`?]
1919
** `"missing-public-upgradeto"`: Allow UUPS implementations that do not contain a public `upgradeTo` function. Enabling this option is likely to cause a revert due to the built-in UUPS safety mechanism.
2020
* `unsafeAllowRenames`: (`boolean`) Configure storage layout check to allow variable renaming.
21+
* `constructorArgs`: (`unknown[]`) Provide arguments for the constructor of the implementation contract. Note that these are different from initializer arguments, and will be used in the deployment of the implementation contract itself. Can be used to initialize immutable variables.
2122

2223
Note that the options un `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?]
2324

packages/core/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
- Infer whether a proxy should be UUPS or Transparent. ([#441](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/441))
66
- Add a standalone interface to the core. ([#442](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/442))
7+
- Add implementation constructor arguments to initialize immutable variables. ([#433](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/433))
78

89
## 1.9.2 (2021-09-17)
910

packages/core/src/version.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ export interface Version {
77
linkedWithoutMetadata: string;
88
}
99

10-
export function getVersion(bytecode: string, linkedBytecode?: string): Version {
10+
export function getVersion(bytecode: string, linkedBytecode?: string, constructorArgs = ''): Version {
1111
if (bytecode !== '') {
1212
return {
1313
withMetadata: hashBytecode(bytecode),
1414
withoutMetadata: hashBytecodeWithoutMetadata(bytecode),
15-
linkedWithoutMetadata: hashBytecodeWithoutMetadata(linkedBytecode ?? bytecode),
15+
linkedWithoutMetadata: hashBytecodeWithoutMetadata(linkedBytecode ?? bytecode, constructorArgs),
1616
};
1717
} else {
1818
throw new Error('Abstract contract not allowed here');
1919
}
2020
}
2121

22-
export function hashBytecode(bytecode: string): string {
22+
export function hashBytecode(bytecode: string, constructorArgs = ''): string {
2323
bytecode = bytecode
2424
.replace(/__\$([0-9a-fA-F]{34})\$__/g, (_, placeholder) => `000${placeholder}000`)
2525
.replace(/__\w{36}__/g, placeholder => keccak256(Buffer.from(placeholder)).toString('hex', 0, 20));
@@ -31,12 +31,20 @@ export function hashBytecode(bytecode: string): string {
3131
throw new Error('Bytecode is not a valid hex string');
3232
}
3333

34-
const buf = Buffer.from(bytecode.replace(/^0x/, ''), 'hex');
34+
if (!/^(0x)?[0-9a-fA-F]*$/.test(constructorArgs)) {
35+
throw new Error('Constructor arguments are not a valid hex string');
36+
}
37+
38+
const buf = Buffer.concat([
39+
Buffer.from(bytecode.replace(/^0x/, ''), 'hex'),
40+
Buffer.from(constructorArgs.replace(/^0x/, ''), 'hex'),
41+
]);
42+
3543
return keccak256(buf).toString('hex');
3644
}
3745

38-
export function hashBytecodeWithoutMetadata(bytecode: string): string {
39-
return hashBytecode(trimBytecodeMetadata(bytecode));
46+
export function hashBytecodeWithoutMetadata(bytecode: string, constructorArgs = ''): string {
47+
return hashBytecode(trimBytecodeMetadata(bytecode), constructorArgs);
4048
}
4149

4250
function trimBytecodeMetadata(bytecode: string): string {

packages/plugin-hardhat/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## 1.11.0
44

55
- Infer whether a proxy should be UUPS or Transparent. ([#441](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/441))
6+
- Add implementation constructor arguments to initialize immutable variables. ([#433](https://github.com/OpenZeppelin/openzeppelin-upgrades/pull/433))
67

78
## 1.10.0 (2021-08-25)
89

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.0;
3+
4+
contract WithConstructor {
5+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
6+
uint256 public immutable value;
7+
8+
/// @custom:oz-upgrades-unsafe-allow constructor
9+
constructor(uint256 args) {
10+
value = args;
11+
}
12+
}

packages/plugin-hardhat/hardhat.config.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ module.exports = {
44
solidity: {
55
compilers: [
66
{
7-
version: '0.5.15',
7+
version: '0.8.9',
88
},
99
{
10-
version: '0.6.7',
10+
version: '0.7.6',
11+
},
12+
{
13+
version: '0.6.12',
14+
},
15+
{
16+
version: '0.5.17',
1117
},
1218
],
1319
},

packages/plugin-hardhat/src/deploy-proxy.ts

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import type { HardhatRuntimeEnvironment } from 'hardhat/types';
22
import type { ContractFactory, Contract } from 'ethers';
33

4-
import {
5-
Manifest,
6-
ValidationOptions,
7-
fetchOrDeployAdmin,
8-
logWarning,
9-
ProxyDeployment,
10-
} from '@openzeppelin/upgrades-core';
4+
import { Manifest, fetchOrDeployAdmin, logWarning, ProxyDeployment } from '@openzeppelin/upgrades-core';
115

126
import {
7+
DeployOptions,
138
deploy,
149
deployImpl,
1510
getProxyFactory,
@@ -23,10 +18,6 @@ export interface DeployFunction {
2318
(ImplFactory: ContractFactory, opts?: DeployOptions): Promise<Contract>;
2419
}
2520

26-
export interface DeployOptions extends ValidationOptions {
27-
initializer?: string | false;
28-
}
29-
3021
export function makeDeployProxy(hre: HardhatRuntimeEnvironment): DeployFunction {
3122
return async function deployProxy(
3223
ImplFactory: ContractFactory,

packages/plugin-hardhat/src/prepare-upgrade.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,16 @@
11
import { HardhatRuntimeEnvironment } from 'hardhat/types';
22
import type { ContractFactory } from 'ethers';
33

4-
import { ValidationOptions } from '@openzeppelin/upgrades-core';
5-
6-
import { ContractAddressOrInstance, deployImpl, getContractAddress } from './utils';
4+
import { Options, ContractAddressOrInstance, deployImpl, getContractAddress } from './utils';
75

86
export type PrepareUpgradeFunction = (
97
proxyAddress: ContractAddressOrInstance,
108
ImplFactory: ContractFactory,
11-
opts?: ValidationOptions,
9+
opts?: Options,
1210
) => Promise<string>;
1311

1412
export function makePrepareUpgrade(hre: HardhatRuntimeEnvironment): PrepareUpgradeFunction {
15-
return async function prepareUpgrade(proxy, ImplFactory, opts: ValidationOptions = {}) {
13+
return async function prepareUpgrade(proxy, ImplFactory, opts: Options = {}) {
1614
const proxyAddress = getContractAddress(proxy);
1715
const { impl } = await deployImpl(hre, ImplFactory, opts, proxyAddress);
1816
return impl;

packages/plugin-hardhat/src/upgrade-proxy.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { HardhatRuntimeEnvironment } from 'hardhat/types';
22
import type { ethers, ContractFactory, Contract, Signer } from 'ethers';
33

4-
import { Manifest, ValidationOptions, getAdminAddress, getCode } from '@openzeppelin/upgrades-core';
4+
import { Manifest, getAdminAddress, getCode } from '@openzeppelin/upgrades-core';
55

66
import {
7+
Options,
78
deployImpl,
89
getTransparentUpgradeableProxyFactory,
910
getProxyAdminFactory,
@@ -14,11 +15,11 @@ import {
1415
export type UpgradeFunction = (
1516
proxy: ContractAddressOrInstance,
1617
ImplFactory: ContractFactory,
17-
opts?: ValidationOptions,
18+
opts?: Options,
1819
) => Promise<Contract>;
1920

2021
export function makeUpgradeProxy(hre: HardhatRuntimeEnvironment): UpgradeFunction {
21-
return async function upgradeProxy(proxy, ImplFactory, opts: ValidationOptions = {}) {
22+
return async function upgradeProxy(proxy, ImplFactory, opts: Options = {}) {
2223
const proxyAddress = getContractAddress(proxy);
2324

2425
const upgradeTo = await getUpgrader(proxyAddress, ImplFactory.signer);

0 commit comments

Comments
 (0)