Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Incorrect Fund Distribution in Graduation Function

Issue Description

The graduateAndUpgrade function incorrectly distributes funds from the bursary, violating the invariant that "60% should reflect in the bursary after upgrade." The current implementation distributes 35% to teachers and 5% to the principal but fails to preserve the remaining 60% for the upgraded contract.

Impact - Critical

The implementation will deplete the entire bursary balance during the upgrade, leaving 0% (instead of the required 60%) for the next level. This completely breaks the financial model of the school system and renders the upgraded contract financially non-functional.

Likelihood - Certain (High)

This issue will occur 100% of the time the graduateAndUpgrade function is executed, as it's a flaw in the core logic of fund distribution.

Detailed Analysis

The contract's graduateAndUpgrade function contains the following distribution logic:

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);

Let's break down the calculations:

  1. TEACHER_WAGE is defined as 35, which with PRECISION at 100 means 35% of the bursary is allocated for teachers

  2. PRINCIPAL_WAGE is defined as 5, which with PRECISION at 100 means 5% of the bursary is allocated for the principal

  3. However, the teacher allocation doesn't account for the number of teachers:

    • Each teacher receives (bursary * 35%) / 100

    • With N teachers, this totals N * (bursary * 35%) / 100

    • This equals N * 35% of the bursary, not just 35%

For example, with 10 teachers:

  • Each teacher gets 35% of the bursary

  • Total teacher payment = 10 * 35% = 350% of the bursary

  • Principal payment = 5% of the bursary

  • Total payment = 355% of the bursary

This not only fails to leave 60% in the bursary but attempts to pay out 3.55x the available funds.

Recommendation

Correct the payment calculation to properly distribute funds according to the 35/5/60 split:

function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
// ... existing checks ...
uint256 totalTeachers = listOfTeachers.length;
uint256 teacherPoolAmount = (bursary * TEACHER_WAGE) / PRECISION; // 35% of bursary
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION; // 5% of bursary
// Calculate per-teacher amount (evenly splitting the 35% pool)
uint256 payPerTeacher = totalTeachers > 0 ? teacherPoolAmount / totalTeachers : 0;
_authorizeUpgrade(_levelTwo);
// Transfer funds to teachers
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
// Handle any remainder from integer division
uint256 actualTeacherPayout = payPerTeacher * totalTeachers;
if (actualTeacherPayout < teacherPoolAmount) {
// Send remainder to last teacher or back to bursary
usdc.safeTransfer(listOfTeachers[totalTeachers - 1], teacherPoolAmount - actualTeacherPayout);
}
// Transfer funds to principal
usdc.safeTransfer(principal, principalPay);
// Note: 60% remains in contract for the next level
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

incorrect teacher pay calculation

`payPerTeacher` in `graduateAndUpgrade()` is incorrectly calculated.

Support

FAQs

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

Give us feedback!