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.
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
).
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.
Financial Discrepancy: bursary
underrepresents the actual USDC, leading to failed wage transfers.
Upgrade Failure: Prevents the upgrade to LevelTwo
, stalling the system.
Validate and convert schoolFees
to 18-decimal wei in initialize
. Here’s the diff:
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.
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.