The LevelOne contract inherits from Initializable and UUPSUpgradeable but fails to implement a storage gap (__gap) variable. In upgradeable contracts, storage gaps are essential safeguards that reserve storage slots for future versions, preventing storage collision during upgrades.
The UUPS (Universal Upgradeable Proxy Standard) pattern allows contracts to be upgraded while preserving their state. However, this requires careful management of the storage layout. When a contract is upgraded:
The storage layout of the new implementation must be compatible with the existing storage.
Adding new variables to a parent contract will push down all child contract variables in storage.
In the current implementation:
OpenZeppelin's upgradeable contracts include a __gap variable to reserve storage slots:
But LevelOne does not implement its own storage gap. If future versions of Initializable or UUPSUpgradeable add new storage variables, they will collide with LevelOne's storage.
Deploy LevelOne as a proxy.
Users interact with the contract, storing critical data.
OpenZeppelin releases a new version of UUPSUpgradeable with additional state variables.
The contract is upgraded to use the new OpenZeppelin contracts.
The new state variables from UUPSUpgradeable now occupy the same slots as the beginning of LevelOne's state.
This causes principal, inSession, and possibly other critical variables to be corrupted.
Add a storage gap at the end of the contract:
This reserves 50 storage slots for potential parent contract additions, significantly reducing the risk of storage collisions during upgrades.
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.