-
Notifications
You must be signed in to change notification settings - Fork 272
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for constructor in logic holding contracts. #312
Comments
There are two components to this:
|
Bypassing the check is now implemented, and basic immutable variables should work with the appropriate overrides: /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
address immutable self = address(this); Empty constructors should also be possible: /// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
// set immutable vars here?
} But it's still not possible to provide arguments to the constructor. |
We also encountered this issue when we need to provide constructor arguments to initialize I also tried to hook |
@lbeder Yes this is possible, but I don't know when we'll be able to work on it. |
I totally understand. If I'd create such a PR (converging both truffle and hardhat, UUPS and TransparentProxy, and full tests) - will this be something you'd consider merging? |
@lbeder provided that it follows the style and logic of the rest of the code, we would definitely consider it ! |
Thanks :) |
@Amxx I've made good progress, but I'm currently stuck on some the last stage and contemplating how to proceed. Everything is hunky-dory, other than the fact that the calculation of the "version" of the logic in For example, given the following test contract: contract ImmutableStateVariable {
uint public immutable x;
constructor(uint _x) public {
x = _x;
}
} And the following test (please ignore the new arguments spec for a moment): const test = require('ava');
const { ethers, upgrades } = require('hardhat');
test.before(async t => {
t.context.ImmutableStateVariable = await ethers.getContractFactory('ImmutableStateVariable');
});
test('initialize immutable state variables', async t => {
const { ImmutableStateVariable } = t.context;
const instance = await upgrades.deployProxy(ImmutableStateVariable, [], {
kind: 'transparent',
ctorArgs: [42],
unsafeAllow: ['constructor', 'state-variable-immutable'],
});
t.is((await instance.x()).toString(), '42');
const instance2 = await upgrades.deployProxy(ImmutableStateVariable, [], {
kind: 'transparent',
ctorArgs: [100],
unsafeAllow: ['constructor', 'state-variable-immutable'],
});
t.is((await instance2.x()).toString(), '100');
}); The last Can you think of a quick way to take immutable state variables into account without rewriting |
You can find it here: https://github.com/OpenZeppelin/openzeppelin-upgrades/compare/master...lbeder:ctor-args?expand=1 and other than the issue with the caching of the logic contract (which causes the tests to fail) - it's good for review. |
Thanks for tackling this! Making this work with immutable variables is going to be a lot more effort. Can you add a test using This is just a rough idea but I think we should store the ABI-encoded constructor arguments for an impl deployment in the network manifest. When we look up an existing deployment to see if we can reuse it, we should also consider the constructor arguments and if they don't match, we should deploy a new one. |
Oh, I missed that. I'll definitely add a test using I'll try the ABI-encoded constructor arguments key approach. Good idea! |
When deploying the logic contract for a proxy, you are expected to replace the constructor with an initialize function, for the part that is instance-specific (let's say the name and symbol of an ERC20). This is verified by the plugin, which will refuse to work with implementations that have non-trivial constructors
However, it can still make sense to have a constructor that sets an immutable variable (such as the address of a forwarder for the
ERC2771Context
). That way the logic contract can "hardcode" the forwarder in an immutable variable, and then all instances use the same forwarder out of the box, without having to initialize it.Therefore, I think it would be useful to have a way to bypass this check and provide constructor arguments for the logic contract.
The text was updated successfully, but these errors were encountered: