Several contracts in the protocol are designed to be upgradeable. But these contracts don't follow the required upgradeable pattern.
The UpgradeableProxy
contract is designed to be a proxy of SystemConfig
, PreMarkets
, DeliveryPlace
, CapitalPool
and TokenManager
contracts. These contracts are designed to be upgradeable using the Transparent Proxy pattern from OpenZeppelin. The problem is that the most of the contracts don't follow the upgradeable pattern.
The UpgradeableProxyContract
uses a constructor. But the constructors are not called during proxy deployment, which leads to uninitialized contract states:
The SystemConfig
and TokenManager
contracts have initialize
function but this function has modifier onlyOwner
. The initialize
function should have initializer
modifier even when the owner is trusted. That ensures the function can only be called once, preventing accidental reinitialization.
Also, all contracts that are upgradeable (UpgradeableProxy
, SystemConfig
, PreMarkets
, DeliveryPlace
, CapitalPool
and TokenManager
) should call in the constructor
the _disableInitializers
function to prevent the base contract from being initialized again. This is a best practice for upgradeable contracts to ensure that the contract cannot be reinitialized after deployment.
The use of constructors
instead of initialize
function in the upgradeable contracts leads to uninitialized contract states, because the constructors
are not called during proxy deployment.
Also the lack of call to the _disableInitializers
function can lead to re-initialization of the contracts and respectively to loss of funds.
Manual Review
Use initialize
function instead of constructor
and add a call to the _disableInitializers
function in the upgradeable contracts. Also, add initializer
modifier to ensure the function is only called once and to set the contract’s initialization state.
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.