Hawk High

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

Unused 60% of bursary Remains Permanently Locked in Contract

Summary

The LevelOne::graduateAndUpgrade function distributes only 40% of the contract’s bursary balance—35% to teachers and 5% to the principal—while the remaining 60% is never used or withdrawn. This leftover amount stays permanently locked in the contract, with no way for any party to access or repurpose the funds, resulting in a silent fund sink.


Vulnerability Details

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
uint256 totalTeachers = listOfTeachers.length;
uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
// @audit-issue Remaining 60% of bursary is never used, causing permanent fund lock
// @> No logic exists to distribute or withdraw leftover bursary
}

Issue Explanation

The function calculates fixed percentages for principal and teacher payments:

  1. Fixed Distribution
    Only 40% of bursary is allocated via TEACHER_WAGE and PRINCIPAL_WAGE.

  2. No Remainder Handling
    The remaining 60% is not distributed, refunded, or tracked for future use.

  3. Permanent Fund Lock
    Since bursary is never reduced after payouts, it accumulates locked USDC that cannot be retrieved.


Impact

  • Funds Inaccessible: 60% of each enrollment payment becomes permanently locked.

  • Protocol Inefficiency: Long-term operation will accumulate unusable capital.


Tools Used

  • Manual Code Review


Recommendations

Option A – Calculate total distributed and refund the remainder

uint256 totalDistributed = payPerTeacher * totalTeachers + principalPay;
uint256 leftover = bursary - totalDistributed;
usdc.safeTransfer(principal, leftover); // or handle per business logic
bursary = 0; // Reset afterwards

Option B – Redefine wage constants to sum to 100%

// e.g., TEACHER_WAGE = 80, PRINCIPAL_WAGE = 20
// Ensures all bursary is consumed in graduate payout

Updates

Lead Judging Commences

yeahchibyke Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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