The UpgradeableProxy
contract, which is based on OpenZeppelin's TransparentUpgradeableProxy
, improperly uses a constructor for initialization, which is not ideal for upgradeable contracts. This practice could lead to potential inflexibility and the inability to properly upgrade the contract.
The UpgradeableProxy
contract inherits from OpenZeppelin’s TransparentUpgradeableProxy
, and the constructor is used to set up important state variables such as tadleFactory
. While this works initially, it becomes problematic in the context of upgradeable contracts where re-initialization or upgrading might be required. Constructors are only called once, during the deployment, and cannot be called again during an upgrade, which limits the flexibility of the contract.
Inflexibility in Upgrades: The use of a constructor means that if a contract is upgraded, there is no way to re-initialize it without redeploying the entire proxy, which defeats the purpose of using a proxy pattern.
Potential Misconfiguration: Future versions of the contract that need to modify or re-initialize variables set by the constructor would be unable to do so, leading to potential misconfigurations.
The root cause is the reliance on a constructor for initialization in a context where the contract is expected to be upgradeable. Since constructors are not re-executed on upgrades, any state changes required during an upgrade cannot be accomplished if they rely on constructor logic.
Deploy the Proxy Contract: Deploy the UpgradeableProxy
contract using the provided constructor.
Attempt to Upgrade: Upgrade the logic contract to a new version that requires re-initialization of variables. Notice that the constructor logic is not executed during the upgrade, potentially leaving the contract in an inconsistent or uninitialized state.
Observe Inflexibility: Any attempt to modify or re-initialize variables initially set by the constructor during an upgrade will fail, highlighting the inflexibility of this approach.
To address this issue, it's recommended to avoid using constructors in upgradeable contracts and instead use an initializer function. The initializer
function should be protected with OpenZeppelin’s initializer
modifier to ensure it can only be called once.Tools Used
Valid high severity, since `initializeOwner` is not called for proxy contracts and the constructor for each `Rescuable.sol` contract will not be invoked during proxy deployment, this leaves the `owner` for each proxy unitialized allowing potential to withdraw fund from other proxy contracts inheriting `Rescuable.sol` respectively.
Valid high severity, since `initializeOwner` is not called for proxy contracts and the constructor for each `Rescuable.sol` contract will not be invoked during proxy deployment, this leaves the `owner` for each proxy unitialized allowing potential to withdraw fund from other proxy contracts inheriting `Rescuable.sol` respectively.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.