Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: low
Likelihood: medium
Invalid

[L-2] Direct ERC-20 Transfers Bypass Bursary Accounting

Summary

The LevelOne contract only credits student tuition fees when the enroll() function is called, which transfers USDC and increments bursary. If someone transfers USDC directly to the proxy—bypassing enroll()—the contract’s token balance rises, but bursary remains unchanged. This breaks the invariant that “all collected fees are reflected in bursary,” leading to stranded funds.

Vulnerability Details

ERC-20 tokens sent by calling IERC20(usdc).transfer(address(levelOne), amount) do increase usdc.balanceOf(levelOne), but because there is no hook or fallback to adjust bursary, those tokens are never recorded or usable by any withdrawal or distribution logic.

Impact

While no attacker can withdraw those locked tokens, legitimate users or integrators may lose assets by accidentally sending fees outside the intended path. Locked funds degrade contract usability and trust. This can be considered a low issue because it does not lead to unauthorized access or direct financial loss via theft, only by misplacement.

Tools Used

  • Foundry

  • Manual Review

  • Aderyn

Recommendations

Because the primary fee token is USDC (ERC-20), the safest and simplest approach is to revert on any direct ERC-20 transfers. This ensures that, the user will not strand/lock their funds accidentally in the contract, and will have to call LevelOne::enroll().

+ // add where all the other errors are declared:
+ error HH__DirectTransfersNotAllowedUseEnrollInstead();
...
+ receive() external payable {
+ revert HH__DirectTransfersNotAllowedUseEnrollInstead();
+ }
+ fallback() external payable {
+ revert HH__DirectTransfersNotAllowedUseEnrollInstead();
+ }
Updates

Lead Judging Commences

yeahchibyke Lead Judge
2 months ago
yeahchibyke Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement
yeahchibyke Lead Judge 2 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.