Hawk High

First Flight #39
Beginner FriendlySolidity
100 EXP
View results
Submission Details
Impact: medium
Likelihood: medium
Invalid

For the sake of this project, assume USDC has 18 decimals

Summary

The initialize function accepts schoolFees without validating it is provided in 18-decimal wei, as required by the USDC invariant. This mismatch propagates to enroll, causing bursary to misrepresent the actual USDC balance, risking failed transfers and upgrade issues.

Vulnerability Details

  • Root Cause: The initialize function sets schoolFees = _schoolFees without ensuring _schoolFees is in 18-decimal wei (e.g., 100 USDC = 100 * 10^18). If a caller provides 100e6 (6-decimal USDC), schoolFees is misinterpreted.

  • Attack Path: In enroll, usdc.safeTransferFrom transfers the correct 18-decimal amount, but bursary += schoolFees adds the misaligned value. In graduateAndUpgrade, payPerTeacher and principalPay use the incorrect bursary, leading to insufficient funds for transfers.

  • Affected Component: Initialization and financial tracking (schoolFees, bursary).

Proof of Concept

The following steps demonstrate the vulnerability:

  • Step 1: Initialize the contract with schoolFees = 100e6 (intended as 100 USDC but provided as 6-decimal units).

  • Step 2: Enroll 2 students, each transferring 100e18 USDC (correct 18-decimal amount). bursary becomes 200e6 (misaligned), while the actual balance is 200e18.

  • Step 3: Add 2 teachers and start a session with startSession(70).

  • Step 4: After 5 weeks, call graduateAndUpgrade(address(new LevelTwo()), "").

  • Expected Result: Transfers succeed, with bursary reflecting 200e18.

  • Actual Result: payPerTeacher = (200e6 * 35) / 100 = 70e6 per teacher, totaling 140e6 + 10e6 (principal) = 150e6, but the balance is 200e18. The transfer of 70e6 (interpreted as 70e6 wei, not 70 USDC) fails due to a mismatch.

Impact

  • Financial Discrepancy: bursary underrepresents the actual USDC, leading to failed wage transfers.

  • Upgrade Failure: Prevents the upgrade to LevelTwo, stalling the system.

Recommendations

Validate and convert schoolFees to 18-decimal wei in initialize. Here’s the diff:

function initialize(address _principal, uint256 _schoolFees, address _usdcAddress) public initializer {
if (_principal == address(0)) {
revert HH__ZeroAddress();
}
if (_schoolFees == 0) {
revert HH__ZeroValue();
}
if (_usdcAddress == address(0)) {
revert HH__ZeroAddress();
}
principal = _principal;
- schoolFees = _schoolFees;
+ schoolFees = _schoolFees * 10**12; // Convert from 6-decimal to 18-decimal (assuming 6-decimal input)
usdc = IERC20(_usdcAddress);
__UUPSUpgradeable_init();
}

Note: Adjust the multiplier (1012) based on the expected input decimal (e.g., 1018 if raw wei is expected). Add documentation to clarify expected units.

Updates

Lead Judging Commences

yeahchibyke Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
yeahchibyke Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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