Hawk High

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

Inconsistent Bursary Tracking During Upgrade

Summary

The LevelOne contract's graduateAndUpgrade function fails to update the bursary variable after distributing 40% of its value to the principal and teachers. This creates a state inconsistency between the storage variable and the actual token balance, violating the invariant that "remaining 60% should reflect in the bursary after upgrade."

Vulnerability Details

When the graduateAndUpgrade function is called, it distributes funds to teachers and the principal:

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

However, the function never updates the bursary state variable after these transfers. This creates a discrepancy where:

  1. The contract's USDC balance is reduced by the payments

  2. The bursary variable still reflects the pre-payment amount (100%)

The README explicitly states that "remaining 60% should reflect in the bursary after upgrade," indicating that the bursary variable should be updated to 60% of its value after payments.

Impact

This inconsistency between the contract's state and actual token balance has several consequences:

  1. State Corruption: The bursary variable doesn't accurately reflect available funds

  2. Future Calculation Errors: Any future calculations based on the bursary value will be incorrect

  3. Invariant Violation: The system requirement that "60% should reflect in the bursary after upgrade" is not fulfilled

  4. Accounting Issues: If multiple upgrades occur, the discrepancy will compound over time

Recommendations

The bursary variable should be updated after payments to accurately reflect the remaining funds:

function graduateAndUpgrade(address _levelTwo, bytes memory data) public onlyPrincipal {
// Existing code for payments
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);
// Update bursary to reflect remaining 60%
bursary = (bursary * 60) / PRECISION;
}

Updates

Lead Judging Commences

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

bursary not updated

The bursary is not updated after wages have been paid in `graduateAndUpgrade()` function

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

bursary not updated

The bursary is not updated after wages have been paid in `graduateAndUpgrade()` function

Support

FAQs

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