The graduateAndUpgrade() function incorrectly uses the _authorizeUpgrade internal hook instead of the standard upgradeToAndCall function, and the Level Two contract is not properly configured for UUPS. This prevents the proxy contract from upgrading correctly to the Level Two implementation, failing the intended transition.
The contract attempts to use the UUPS (Universal Upgradeable Proxy Standard) pattern for upgrades. However, the graduateAndUpgrade() function in the LevelOne contract misuses the _authorizeUpgrade function. In the UUPS pattern, _authorizeUpgrade is designed as an internal hook that is called by the standard upgrade functions like upgradeTo or upgradeToAndCall (provided by OpenZeppelin's UUPSUpgradeable base contract) to perform access control or other pre-upgrade checks. It is not the function intended to trigger the upgrade process itself.
The problematic line is:
Furthermore, for the UUPS pattern to work correctly, the new implementation contract (LevelTwo) must also inherit from UUPSUpgradeable and provide its own implementation of the _authorizeUpgrade hook (even if empty, as shown in the recommended fix). The original LevelTwo contract did not appear to do this.
This misuse means the OpenZeppelin UUPS proxy logic, which handles updating the proxy's implementation address, is never invoked correctly. The test case provided demonstrates that without the fix, the intended state of Level Two is not reached:
The assertion assertEq(LevelTwo(proxyAddress).TEACHER_WAGE_L2(), levelTwoTeacherWage); would fail because proxyAddress is still directing calls to the LevelOne implementation, which does not have the TEACHER_WAGE_L2() function or the expected state of the Level Two contract.
The proxy contract's implementation address is not updated to point to the new Level Two contract. Any calls made through the proxy after the failed upgrade attempt will continue to execute the code of the Level One implementation, not the Level Two implementation.
To correctly implement the UUPS upgrade using OpenZeppelin's libraries, modify the graduateAndUpgrade() function to call upgradeToAndCall() instead of _authorizeUpgrade(). Additionally, ensure the LevelTwo contract correctly inherits from UUPSUpgradeable and implements the _authorizeUpgrade hook.
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.