i read this article UUPSUpgradeable Vulnerability Post-mortem describing how an attacker can initialize the implementation contract and become the owner, which naively seems harmless, but nevertheless creates a security vulnerability.
however, i don't understand what the conclusion is for the best-practice fix. what if, for all my OwnableUpgradeable implementation contracts, i just add
on a related (or unrelated?) note i made an edit from constructor() to constructor() initializer because I see there was recently a change from
function __Ownable_init() internal initializer
to
function __Ownable_init() internal onlyInitializing
In the previous case, simply calling __Ownable_init() would be enough to toggle _initialized but now it appears to be necessary to also label the constructor with initializer
Ok, sorry for the repeated notes here. But I now think the best solution is to just write
constructor() initializer {}
at the beginning of the contract, with no logic inside {}. This way, _initialized == true in the storage of the implementation contract, and no one is the owner. This appears to be what is done in the wizard, although the reason wasn't clear to me at first.