Hawk High

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

The teachers are each paid more than they are supposed to be paid thereby draining the bursary.

Description: At the end of a session, the Principal calls LevelOne::graduateAndUpgrade to upgrade the existing system and pay all wages. According to the intended logic:

  • Teacher wage: 35% of the bursary (to be shared among all teachers).

  • Principal wage: 5% of the bursary
    However, the current implementation in the protocol incorrectly remits 35% of the bursary to each individual teacher, rather than splitting the 35% among all teachers as intended.

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

Impact: Teachers receive significantly higher wages than intended. In cases where there are multiple teachers, the entire bursary may be exhausted before all teachers are paid potentially leaving the Principal unpaid.

Proof of Concept: 60% of the bursary should be left after upgrading, but clearly less is left. Paste this code block in the test suite:

function testTeacherSalaryIsMoreThanExpected() public schoolInSession {
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
uint256 bursaryAmountBeforeGraduation = levelOneProxy.bursary();
vm.prank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
uint256 sixtyPercentOfBursary = (bursaryAmountBeforeGraduation * 60) / 100;
uint256 aliceBalance = usdc.balanceOf(alice);
uint256 bobBalance = usdc.balanceOf(bob);
uint256 principalBalance = usdc.balanceOf(principal);
uint256 actualBursaryBalanceAfterGraduation = bursaryAmountBeforeGraduation - (principalBalance + bobBalance + aliceBalance);
console2.log(actualBursaryBalanceAfterGraduation);
console2.log(bursaryAmountBeforeGraduation);
console2.log(sixtyPercentOfBursary);
assert(sixtyPercentOfBursary != actualBursaryBalanceAfterGraduation);
assert(sixtyPercentOfBursary > actualBursaryBalanceAfterGraduation);
}

Recommended Mitigation: Calculate the wage each teacher is supposed to earn from the 35% before disbursing the funds.

+ uint256 totalTeacherPay = (bursary * TEACHER_WAGE) / PRECISION;
+ uint256 payPerTeacher = totalTeacherPay / totalTeachers;
- 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);
}
Updates

Lead Judging Commences

yeahchibyke Lead Judge about 1 month 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.