The LevelOne contract fails to manage the remaining 60% of the bursary (school fees collected) as per the project's defined invariants during the graduateAndUpgrade process. Specifically, these funds are not transferred or made accessible to the new contract implementation (LevelTwo) after the principal and teachers are paid. This results in the funds becoming effectively stranded within the LevelOne contract, directly violating the invariant that "remaining 60% should reflect in the bursary after upgrade."
The project's invariants explicitly state: "remaining 60% should reflect in the bursary after upgrade." This implies that after the principal (5%) and teachers (35%) receive their wages from the bursary, the substantial remainder (60%) should be available to or form part of the bursary of the newly upgraded system.
However, the LevelOne.graduateAndUpgrade(address _levelTwo, bytes memory) function operates as follows:
It calculates payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION.
It calculates principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION.
It calls _authorizeUpgrade(_levelTwo) to set up the UUPS upgrade.
It transfers payPerTeacher to each teacher.
It transfers principalPay to the principal.
At this point, the function concludes. There is no mechanism or code within graduateAndUpgrade to:
Transfer the remaining USDC tokens (representing 60% of the original bursary value) from the LevelOne contract's balance to the _levelTwo contract address.
Update any state in _levelTwo to reflect this amount.
The bursary state variable in LevelOne itself is not reset or decremented beyond the implicit value it held before payments. The actual USDC tokens corresponding to this 60% remain held by the LevelOne contract address. The LevelTwo contract, as provided, also has no function to pull or claim these funds from LevelOne post-upgrade.
This directly contravenes the specified operational requirement for the residual bursary.
The failure to manage and transfer the residual 60% of the bursary has several significant negative impacts:
Direct Financial Loss:
60% of all school fees collected and held in the bursary at the time of upgrade become inaccessible and effectively lost to the Hawk High school entity. These funds cannot be used for future operational costs, reinvestment, development of LevelTwo (or subsequent levels), or to benefit future student cohorts as might be intended.
Breach of Core Business Logic and Invariants:
The fundamental financial model and a key invariant of the school's operation are violated. This indicates a flaw in the contract's adherence to its specified design.
Operational Disruption for LevelTwo:
If the LevelTwo contract (or the school's operational model) anticipates having access to these residual funds to form its own initial bursary or to cover its operational expenses, it will start with a significant, un-catered-for deficit.
Erosion of Trust and Accountability:
Mishandling or "losing" a significant portion of collected fees can severely damage the trust of users (students, parents, stakeholders) in the platform's financial management and its ability to operate according to its own stated rules.
Potential for Unintended Accumulation:
If the LevelOne contract address somehow remains active or accessible after the upgrade (though UUPS typically redirects calls), these funds would just sit there, potentially accumulating across multiple "sessions" if the upgrade process was flawed in other ways, further complicating accounting.
manual review
To rectify the mishandling of the residual 60% of the bursary and ensure compliance with the project invariant, the following changes and considerations are recommended:
Modify LevelOne.graduateAndUpgrade to Transfer Residual Funds:
Calculate Residual Amount: After calculating principalPay and the total amount to be paid to all teachers, determine the remainingBursary.
content_copydownload
Use code with caution.Solidity
Transfer to _levelTwo: Before the function concludes, transfer these remainingBursaryToTransfer funds to the _levelTwo contract address.
content_copydownload
Use code with caution.Solidity
Update LevelOne.bursary State (Crucial for Session Logic): After all transfers (principal, teachers, and residual to _levelTwo), the bursary variable in LevelOne should be reset to 0 or appropriately reduced to reflect that the funds for that session have been fully processed. This is critical if LevelOne persists or to prevent miscalculation in unlikely re-entry scenarios.
content_copydownload
Use code with caution.Solidity
Ensure LevelTwo Can Receive and Manage Funds:
The LevelTwo contract (and its initialize or initializeV2 function) should be designed to be aware that it might start with an initial USDC balance if this transfer occurs.
Its internal bursary variable should be set or incremented based on the USDC balance it holds upon initialization/upgrade, or it should account for these funds as intended by the school's operational model.
content_copydownload
Use code with caution.Solidity
Emit an Event for Transparency:
Add an event in LevelOne to log the transfer of residual bursary funds to the new contract.
content_copydownload
Use code with caution.Solidity
Address Overall Bursary Management (Session-Specific):
Strongly Recommended: The underlying issue that bursary in LevelOne is a cumulative figure across all sessions needs to be addressed. Implement a sessionBursary that is reset at the start of each new session (or after graduation). All calculations (enrollment fees, principal wage, teacher wages, residual) should be based on this sessionBursary. This will make the 60% residual calculation accurate for the current graduating session.
If this is not done, the "60% residual" will be 60% of all funds ever collected and not yet spent, which may not be the intended logic.
Thorough Testing:
Test the upgrade process extensively, specifically verifying:
Correct calculation of principal, teacher, and residual shares.
Successful transfer of USDC to all parties, including LevelTwo.
The balance of LevelOne after upgrade (should be 0 or significantly reduced for USDC).
The balance and bursary state of LevelTwo immediately after upgrade.
Edge cases: no teachers, zero bursary, etc.
By implementing these recommendations, the contract will align with the specified invariant, ensuring that the residual 60% of the (session-specific) bursary is properly handled and made available to the subsequent contract version, preventing financial loss and maintaining the integrity of the school's financial operations.
The bursary is not updated after wages have been paid in `graduateAndUpgrade()` function
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.