Medium
The LevelOne
contract contains several functions with O(n) array operations that scale linearly with the number of teachers and students. Most critically, the graduateAndUpgrade()
function includes an unbounded loop that iterates through all teachers to distribute payments. As the number of teachers grows, gas costs will increase proportionally, eventually making the function prohibitively expensive or impossible to execute. This results in:
Complete system paralysis - The school cannot progress to LevelTwo
Permanent fund lockup - All school fees become permanently trapped in the contract
Payment failure - Teachers cannot receive their wages (35% of bursary)
Administrative payment failure - Principal cannot receive payment (5% of bursary)
Contract stuck in expired state - School system cannot progress as designed
Escalating transaction costs - Even before reaching gas limits, costs will grow significantly with each new teacher
Additionally, other administrative functions with O(n) scaling will also become increasingly expensive and eventually unusable as the contract grows:
Students can no longer be expelled
Teachers can no longer be removed
The graduateAndUpgrade()
function contains a critical unbounded loop that processes payments for all teachers:
This implementation has several critical issues:
The loop scales linearly with the number of teachers (O(n) complexity)
ERC20 transfers are gas-intensive operations
There is no mechanism to partially process teachers or resume a failed upgrade
When the number of teachers exceeds a certain threshold, the function will revert due to exceeding block gas limits
Additionally, two other functions have similar O(n) scaling issues:
removeTeacher()
uses a loop to find and remove a teacher:
expel()
uses a similar loop for students:
Foundry, Manual code review
Multiple strategies are needed to fully address these issues:
Replace the push-based payment system with a pull-based approach:
Use index tracking to achieve O(1) removal operations:
For larger schools, implement batch processing to handle operations in manageable chunks:
Our PoC demonstrates how the gas costs for operations scale linearly with the size of arrays, with particular focus on the graduation function that causes system failure.
The most significant test is testGraduateDoS()
, which shows that the payment loop in the graduation process becomes increasingly expensive as teacher count grows. While our test simulates up to 500 teachers, real-world deployment could potentially involve thousands, easily exceeding block gas limits.
Sample output from testGraduateDoS()
:
This demonstrates that:
This demonstrates that:
Gas costs scale proportionally with teacher count
With 10× more teachers, we see roughly 10× more gas usage
With 50× more teachers, we see roughly 50× more gas usage
At around 3,000-5,000 teachers, the function would exceed block gas limits
Note that this scaling issue is particularly critical for graduateAndUpgrade()
since its failure prevents the entire system from progressing and locks all funds permanently.
Unbounded loops in teacher lists could result in high gas usage when trying to remove a teacher when teachers are plenty. This could result in a possible DoS
Due to the use of a push system as regards payment of teacher wages, there is a risk of possible DoS as gas costs increase in direct proportion to size of teachers list.
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.