The LevelOne::graduateAndUpgrade
function intends to perform contract upgrade logic alongside graduation and reward distribution. However, it incorrectly calls _authorizeUpgrade(_levelTwo)
directly, which only performs an access control check but does not execute the actual upgrade. As a result, the proxy contract's implementation is never changed, and the upgrade silently fails.
Misunderstanding of _authorizeUpgrade
Role
_authorizeUpgrade()
is a hook meant to be called by the upgrade mechanism to verify permissions. Calling it manually does not trigger any upgrade.
No Use of upgradeTo
or upgradeToAndCall
The correct upgrade mechanism provided by OpenZeppelin’s UUPSUpgradeable
is never invoked, meaning the proxy continues pointing to the old implementation.
Silent Failure
Since _authorizeUpgrade()
will pass if msg.sender
is authorized, the function appears to succeed, misleading developers and users into thinking the upgrade was applied.
Functionality Breakage: Proxy contract remains on the old implementation despite expecting a transition.
Upgrade Failure: New logic in LevelTwo
(e.g., updated graduate()
or state variables) never becomes active.
Misleading Execution: Graduation proceeds with the belief of successful upgrade, leading to inconsistencies.
Manual Code Review
Replace the manual _authorizeUpgrade
call with an actual upgrade operation:
upgradeTo
upgradeToAndCall
(if initialization logic is required)Ensure that the contract extends UUPSUpgradeable
and that _authorizeUpgrade()
is properly implemented for access control:
The system doesn't implement UUPS properly.
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.