Trey asked on Telegram:
So I guess I’m just struggling with what the “intended” workflow is here for making contract updates. Say I’ve got a project with:
CustomERC20 is IERC20
PausableCustomERC20 is CustomERC20
MyToken is PausableCustomERC20
Given what has been recommended, if I want to deploy a new version of MyToken
, I should make a MyTokenV2
contract that either inherits from MyToken
or is just copy of it with a compatible storage structure.
But what if I make a change to CustomERC20
or PausableCustomERC20
? If I truly want the migrations to be reproducible, then it seems like going the route of renaming to “v2” is going to result in me having the rename every class in the inheritance chain to V2. That would logically extend to the OpenZeppelin contracts themselves if I upgrade from one version to another, but you guys don’t update the contract names like this when you make updates, so I don’t really have that option short of forking the Openzeppelin code.
So for example “V1” could include contracts/v1/MyToken
, contracts/v1/pausableCustomERC20
, contracts/v2/CustomERC20
.
Then for V2, that made a change to PausableCustomERC20
, I would need to create contracts/v2/MyToken.sol
and contracts/v2/PausableCustomERC20.sol
, and then contracts/v2/PausableCustomERC20.sol
could inherit from either from a new contracts/v2/customERC20.sol
or still just from contracts/v1/CustomERC20.sol
(since the file didn’t change).
If, as suggested, I need to also publicly change my contract name to be clear/transparent that the contract has changed, then I’ll need to also update the code at each level of the hierarchy to refer to the classes as MyTokenV2
, PausableCustomERC20V2
, etc. instead of just referencing them with the same class names and relative folder structure as before (i.e. if I just create a parallel path under contracts/v1
, contracts/v2
, etc. so all the code importing other contracts with relative paths doesn’t have to be modified)
As a parallel, when OpenZeppelin releases a new version of it’s contracts, it versions the release, but leaves the contract names the same between versioned releases, which is pretty standard practice in the software world.
I’m willing to go a different route, but the dependency hierarchy of “just make a MyTokenV2” doesn’t seem to me like it works all that great either, as you essentially end up having to fork every contract in the hierarchy every time you make any change to that contract or any parent class, and constantly updating all the code to add “v2”, “v3”, etc. to referenced classes seems strange.
I feel like I must be overthinking this, but I’m just trying to wrap my head around how people make this work in practice. The “create a release commit with any changes and deploy that commit with consistent contract names” approach feels clean, but requires that every release be run sequentially through the release commits to recreate current state.
The “create a full copy of the hierarchy in the main branch the for every release” also seems like it would work pretty well, so long as we can keep the contract names the same and don’t have to then slap a “v2” at the end of every class name.
If I’m going to increment the contract names to append “v2”, “v3”, etc., It feels like it is going to get messy forking every class name and modifying inheritance hierarchies for every change.
Any pointers on how other people managing this process?