(src/LevelOne.sol#261-278)
The function calls _authorizeUpgrade(_levelTwo)
to verify permissions but never actually invokes the UUPS upgrade mechanism (_upgradeToAndCall
or the public upgradeToAndCall
) to point the proxy at the new implementation. As a result, the proxy’s implementation slot remains set to LevelOne, so LevelTwo’s logic (including its graduate()
entrypoint) is never executed.
Enrolled students can never transition to Level Two, and any graduation‑specific state or payouts in LevelTwo never occur.
Calls to graduateAndUpgrade
succeed (no revert), giving the false impression that the upgrade—and thus graduation—has happened, while in reality nothing changes.
Foundry
Manual Review
A unit test (test_storage_collision
_ _demonstrated that after calling graduateAndUpgrade
, reading sessionEnd()
still shows the old value (zero), proving no upgrade occurred.
OpenZeppelin UUPS Docs
Reference for the correct usage of upgradeToAndCall
in UUPS‐style upgradeable contracts.
1. Invoke the Upgrade
Replace the line _authorizeUpgrade(_levelTwo)
call with a full UUPS upgrade, for example:
This ensures the proxy’s implementation pointer is updated before executing any new logic.
2. Add a Test Guard
Write a unit test that asserts the proxy’s implementation address has changed after graduateAndUpgrade
, preventing regressions in future versions.
For more information reffer to https://github.com/crytic/slither/wiki/Detector-Documentation#unprotected-upgradeable-contract
The system doesn't implement UUPS properly.
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.