Hawk High

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

Invalid payPerTeacher logic when disbursing funds to teachers.

Summary

The graduateAndUpgrade function contains a critical bug in its fund distribution logic where it incorrectly calculates teacher payments. Instead of splitting the 35% TEACHER_WAGE pool among all teachers, it gives each teacher 35% of the total bursary, leading to severe overpayment if there are multiple teachers.

Vulnerability Details

The bug is located in the payment calculation logic of graduateAndUpgrade:

uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;

View code on github

This calculation takes the full bursary amount, multiplies by the wage of the teacher (35%), and assigns the full 35% amount to EACH teacher.

According to the protocol invariants:

  • Teachers should collectively shre 35% of the total bursary bursary

  • Principal gets 5% of the total bursary

  • 60 should remain in the bursary (100 - (35 + 4))

Impact

The impact is severe financial miscalculation:

  • With N teachers, the contract will distribute N*35% of the bursary to teachers. This quickly depletes (and can exceed) the total bursary when N > 1

  • Violates the intended 35/5/60 distribution ratio

  • Can make the contract insolvent when paying principal and multiple teachers

Example Scenario

  • Principal starts a new academic session, sets the school fees to $1000 and registers 2 new teachers.

  • 10 students enroll in the progam.

  • Principal starts the section with the LevelOne::startSession().

  • At the end of the session, the principal calls LevelOne::graduateAndUpgrade() function to conclude the session and disburse funds to the teachers and himself (the principal).

State of the system

Bursary: 10,000USD (10 Students @1000 each)

Teachers: 2 teachers

  • Each teacher gets 3500 USD (7000 USD total), and the principal gets (500)

  • Total Funds disbursed 7500 USD (75% of the total bursary)

Tools Used

Manual review
Remix

Recommendations

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; // remove
++ uint256 totalTeacherPay = (bursary * TEACHER_WAGE) / PRECISION; // add
++ uint256 payPerTeacher = totalTeachers > 0 ? totalTeacherPay / totalTeachers : 0; // add
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}
Updates

Lead Judging Commences

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

incorrect teacher pay calculation

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

yeahchibyke Lead Judge 3 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.