Convert from Ownable-Upgradeable to AccessControl

The most common go-to access has been Ownable for smart contracts. With the push to decentralize always high priority to me, my question is for UUPS Upgradeable Proxy contracts that are already deployed & live. Can you substitute AccessControl in and start using it in an upgrade, even if the contracts on chain are using Ownable-Upgradeable (>0.4.3)?

I know that these often preserve space for future upgrades, but I wasn't sure if it'd be as simple as changing the import to AccessControl, and whether or not the storage slots would continue to function as expected, or if there'd likely be collisions?

You won't be able to simply swap Ownable for AccessControl. To do something like that, you can add AccessControl as a new module at the end, and replace Ownable with a kind of "stub" in the place of the old Ownable storage variables and without any of the ownership logic.

It should go without saying that this would be a very sensitive operation that should test extensively.

Yeah, it seems like a pretty massive change. The part I'm not sure about is since it would be an inherited import, that would be put in place before all of the contract state variables, right?

You'd need to do something like:

contract MyContract is ReentrancyGuard, OwnableUpgradeable, UUPSUpgradeable, AccessControl {
// vars
uint256....
//stuff
}

Wouldn't that stuff in 50+ new storage slots before getting to the MyContract state variables & basically reek havoc?

I'm feeling like it'd basically need to be written into the contract as state variables & utilized that way rather than through inheritance yeah? Could just leave Ownable there & update function level access/modifiers to look at those new perms... Yeah? Or is there a better way?

Thanks for your time!

You're on the right track with that concern.

But you need to think about it in the opposite way of what you're describing here. You will need to take the existing state variables and put them in a contract that you use via inheritance, then you will be able to include AccessControl:

contract MyContractV2 is ..., MyContractV1Storage, AccessControlUpgradeable {
    ...
}

Ahhh, interesting. That makes total sense. Just order it within the inheritance pattern such that it cannot possibly be mixed up. Then when you start adding variables in the v2, it'd still have all the v1 (from inheritance of v1 storage, in the correct position) plus whatever is needed for v2.

Thank you ser! Will play around with it and make sure it tests out correctly :slight_smile:

1 Like