Hawk High

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

[H-07] Incorrect Teacher Payment Distribution Violates 35% Bursary Sharing Requirement

Summary

The payment distribution system incorrectly allocates the full 35% teacher share to EACH teacher rather than splitting it among all teachers, resulting in massive overpayments that drain the contract balance and violate protocol specifications.

Vulnerability Details

Location

  • File: levelOne.sol

  • Function: graduateAndUpgrade(address _levelTwo, bytes memory)

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

Critical Issues

  1. Multiplicative Overpayment:

    • Currently pays (bursary * 35%) to EACH teacher

    • With 2 teachers, pays 70% of bursary instead of 35% total

    • Scales dangerously with more teachers (3 teachers → 105% payout)

  2. Documentation Violation:

    • Explicitly contradicts protocol specs requiring "teachers share of 35% of bursary" (total, not per-teacher)

  3. Bursary Drain Risk:

    • Could completely deplete contract funds

    • Makes remaining 60% bursary guarantee impossible

Proof of Concept

Test Case:

function test_teacher_overpayment_distribution_error() public {
levelTwoImplementation = new LevelTwo();
levelTwoImplementationAddress = address(levelTwoImplementation);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
// Setup student and teachers
vm.prank(clara);
usdc.approve(address(levelOneProxy), schoolFees); // 5,000e18
levelOneProxy.enroll();
vm.startPrank(principal);
levelOneProxy.addTeacher(alice);
levelOneProxy.addTeacher(bob); // 2 teachers
// Process payments
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
vm.stopPrank();
// Verify incorrect payments
assertEq(
usdc.balanceOf(alice),
1_750e18, // Should be 875e18 (35%/2)
"Alice overpaid by 100%"
);
assertEq(
usdc.balanceOf(bob),
1_750e18, // Should be 875e18
"Bob overpaid by 100%"
);
assertEq(
usdc.balanceOf(address(levelOneProxy)),
1_250e18, // Should be 3,000e18 (60% remaining)
"Bursary drained from overpayments"
);
}

Test Result:

Ran 1 test for test/LevelOneAndGraduateTest.t.sol:LevelOneAndGraduateTest
[PASS] test_teacher_overpayment_distribution_error() (gas: 938284)
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 13.74ms (2.43ms CPU time)

Impact

Critical Severity because:

  • Can drain entire bursary with enough teachers

  • Makes financial promises mathematically impossible

  • Violates core protocol economic model

  • Could bankrupt the system

Tools Used

  • Foundry (forge test)

Recommendations

  • Calculate Correct Per-Teacher Share:

function graduateAndUpgrade(address _levelTwo, bytes memory) public {
// ...
uint256 totalTeacherShare = (bursary * 35) / 100;
uint256 payPerTeacher = totalTeacherShare / listOfTeachers.length;
// ...
}
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.