With no cap on listOfTeachers.length, gas usage grows linearly with the number of teachers. Once there are hundreds of entries, the call can exceed the block gas limit, revert every time, and trap the funds.
No files changed, compilation skipped
Ran 1 test for test/LeveOnelAndGraduateTest.t.sol:LevelOneAndGraduateTest
[PASS] test_manyTeachersMayExceedGas() (gas: 56977432)
Traces:
[57125632] LevelOneAndGraduateTest::test_manyTeachersMayExceedGas()
├─ [0] VM::startPrank(principal: [0x6b9470599cb23a06988C6332ABE964d6608A50ca])
│ └─ ← [Return]
├─ [0] VM::toString(0) [staticcall]
│ └─ ← [Return] "0"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0]
├─ [0] VM::label(t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0], "t0")
│ └─ ← [Return]
├─ [78232] ERC1967Proxy::fallback(t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0])
│ ├─ [73258] LevelOne::addTeacher(t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(1) [staticcall]
│ └─ ← [Return] "1"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718]
├─ [0] VM::label(t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718], "t1")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718])
│ ├─ [49358] LevelOne::addTeacher(t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(2) [staticcall]
│ └─ ← [Return] "2"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t2: [0x6A8548f54C723e46F27892911e8C1bADF15a21A5]
├─ [0] VM::label(t2: [0x6A8548f54C723e46F27892911e8C1bADF15a21A5], "t2")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t2: [0x6A8548f54C723e46F27892911e8C1bADF15a21A5])
│ ├─ [49358] LevelOne::addTeacher(t2: [0x6A8548f54C723e46F27892911e8C1bADF15a21A5]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t2: [0x6A8548f54C723e46F27892911e8C1bADF15a21A5])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(3) [staticcall]
│ └─ ← [Return] "3"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t3: [0x130e227F4ee7064a3C9AA0c06698e7F42e5D4BCd]
├─ [0] VM::label(t3: [0x130e227F4ee7064a3C9AA0c06698e7F42e5D4BCd], "t3")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t3: [0x130e227F4ee7064a3C9AA0c06698e7F42e5D4BCd])
│ ├─ [49358] LevelOne::addTeacher(t3: [0x130e227F4ee7064a3C9AA0c06698e7F42e5D4BCd]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t3: [0x130e227F4ee7064a3C9AA0c06698e7F42e5D4BCd])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(4) [staticcall]
│ └─ ← [Return] "4"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t4: [0x74d8470CD29D840ddA0a4F9D15869090Ad3565fe]
├─ [0] VM::label(t4: [0x74d8470CD29D840ddA0a4F9D15869090Ad3565fe], "t4")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t4: [0x74d8470CD29D840ddA0a4F9D15869090Ad3565fe])
│ ├─ [49358] LevelOne::addTeacher(t4: [0x74d8470CD29D840ddA0a4F9D15869090Ad3565fe]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t4: [0x74d8470CD29D840ddA0a4F9D15869090Ad3565fe])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(5) [staticcall]
│ └─ ← [Return] "5"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t5: [0x4A42da15BbD6c2336781f4e49795C19083Dc1BFf]
├─ [0] VM::label(t5: [0x4A42da15BbD6c2336781f4e49795C19083Dc1BFf], "t5")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t5: [0x4A42da15BbD6c2336781f4e49795C19083Dc1BFf])
│ ├─ [49358] LevelOne::addTeacher(t5: [0x4A42da15BbD6c2336781f4e49795C19083Dc1BFf]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t5: [0x4A42da15BbD6c2336781f4e49795C19083Dc1BFf])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(6) [staticcall]
│ └─ ← [Return] "6"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t6: [0xaDc9892085c8C124aBDbFeFf72edB33C9e7a3410]
├─ [0] VM::label(t6: [0xaDc9892085c8C124aBDbFeFf72edB33C9e7a3410], "t6")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t6: [0xaDc9892085c8C124aBDbFeFf72edB33C9e7a3410])
│ ├─ [49358] LevelOne::addTeacher(t6: [0xaDc9892085c8C124aBDbFeFf72edB33C9e7a3410]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t6: [0xaDc9892085c8C124aBDbFeFf72edB33C9e7a3410])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(7) [staticcall]
│ └─ ← [Return] "7"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t7: [0x5F0609dd31B4F9542406a2B3d3f01Ea013fC9070]
├─ [0] VM::label(t7: [0x5F0609dd31B4F9542406a2B3d3f01Ea013fC9070], "t7")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t7: [0x5F0609dd31B4F9542406a2B3d3f01Ea013fC9070])
│ ├─ [49358] LevelOne::addTeacher(t7: [0x5F0609dd31B4F9542406a2B3d3f01Ea013fC9070]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t7: [0x5F0609dd31B4F9542406a2B3d3f01Ea013fC9070])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(8) [staticcall]
│ └─ ← [Return] "8"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t8: [0xeD36A411A8263e69AF1A7fc5E045c08f53131bC3]
├─ [0] VM::label(t8: [0xeD36A411A8263e69AF1A7fc5E045c08f53131bC3], "t8")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t8: [0xeD36A411A8263e69AF1A7fc5E045c08f53131bC3])
│ ├─ [49358] LevelOne::addTeacher(t8: [0xeD36A411A8263e69AF1A7fc5E045c08f53131bC3]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t8: [0xeD36A411A8263e69AF1A7fc5E045c08f53131bC3])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(9) [staticcall]
│ └─ ← [Return] "9"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t9: [0x9B630750ae1F64B4757978063758a8684dcE647b]
├─ [0] VM::label(t9: [0x9B630750ae1F64B4757978063758a8684dcE647b], "t9")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t9: [0x9B630750ae1F64B4757978063758a8684dcE647b])
│ ├─ [49358] LevelOne::addTeacher(t9: [0x9B630750ae1F64B4757978063758a8684dcE647b]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t9: [0x9B630750ae1F64B4757978063758a8684dcE647b])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(10) [staticcall]
│ └─ ← [Return] "10"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t10: [0x55503E9Fe52FB2E180562d13E5450363A38e5352]
├─ [0] VM::label(t10: [0x55503E9Fe52FB2E180562d13E5450363A38e5352], "t10")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t10: [0x55503E9Fe52FB2E180562d13E5450363A38e5352])
│ ├─ [49358] LevelOne::addTeacher(t10: [0x55503E9Fe52FB2E180562d13E5450363A38e5352]) [delegatecall]
│ │ ├─ emit TeacherAdded(: t10: [0x55503E9Fe52FB2E180562d13E5450363A38e5352])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::toString(11) [staticcall]
│ └─ ← [Return] "11"
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] t11: [0xcd88ACC2FCc62152E9E4d0028c79e50A0D5A2Cfc]
├─ [0] VM::label(t11: [0xcd88ACC2FCc62152E9E4d0028c79e50A0D5A2Cfc], "t11")
│ └─ ← [Return]
├─ [49832] ERC1967Proxy::fallback(t11: [0xcd88ACC2FCc62152E9E4d0028c79e50A0D5A2Cfc])
│ ├─ [49358] LevelOne::addTeacher(t11: [0xcd88ACC2FCc62152E9E4d0028c79
├─ [0] VM::startPrank(six_student: [0x983Cec4DF373E6f3809b4483fEBf6C9469B0769b])
│ └─ ← [Return]
├─ [25298] MockUSDC::approve(ERC1967Proxy: [0x90193C961A926261B756D1E5bb255e67ff9498A1], 5000000000000000000000 [5e21])
│ ├─ emit Approval(owner: six_student: [0x983Cec4DF373E6f3809b4483fEBf6C9469B0769b], spender: ERC1967Proxy: [0x90193C961A926261B756D1E5bb255e67ff9498A1], value: 5000000000000000000000 [5e21])
│ └─ ← [Return] true
├─ [83022] ERC1967Proxy::fallback()
│ ├─ [82551] LevelOne::enroll() [delegatecall]
│ │ ├─ [9719] MockUSDC::transferFrom(six_student: [0x983Cec4DF373E6f3809b4483fEBf6C9469B0769b], ERC1967Proxy: [0x90193C961A926261B756D1E5bb255e67ff9498A1], 5000000000000000000000 [5e21])
│ │ │ ├─ emit Transfer(from: six_student: [0x983Cec4DF373E6f3809b4483fEBf6C9469B0769b], to: ERC1967Proxy: [0x90193C961A926261B756D1E5bb255e67ff9498A1], value: 5000000000000000000000 [5e21])
│ │ │ └─ ← [Return] true
│ │ ├─ emit Enrolled(: six_student: [0x983Cec4DF373E6f3809b4483fEBf6C9469B0769b])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::prank(principal: [0x6b9470599cb23a06988C6332ABE964d6608A50ca])
│ └─ ← [Return]
├─ [50532] ERC1967Proxy::fallback(70)
│ ├─ [50058] LevelOne::startSession(70) [delegatecall]
│ │ ├─ emit SchoolInSession(startTime: 1, endTime: 2419201 [2.419e6])
│ │ └─ ← [Stop]
│ └─ ← [Return]
├─ [0] VM::warp(2419201 [2.419e6])
│ └─ ← [Return]
├─ [445078] → new LevelTwo@0x2e234DAe75C793f67A35089C9d99245E1C58470b
│ └─ ← [Return] 2223 bytes of code
├─ [0] VM::prank(principal: [0x6b9470599cb23a06988C6332ABE964d6608A50ca])
│ └─ ← [Return]
├─ [0] VM::expectRevert(custom error 0xf4844814)
│ └─ ← [Return]
├─ [60008] ERC1967Proxy::fallback(LevelTwo: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 0x)
│ ├─ [59512] LevelOne::graduateAndUpgrade(LevelTwo: [0x2e234DAe75C793f67A35089C9d99245E1C58470b], 0x) [delegatecall]
│ │ ├─ [25750] MockUSDC::transfer(t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0], 10500000000000000000000 [1.05e22])
│ │ │ ├─ emit Transfer(from: ERC1967Proxy: [0x90193C961A926261B756D1E5bb255e67ff9498A1], to: t0: [0xe3B1eAb0030360C7fcA9b3Fab5B710C2Ed132ab0], value: 10500000000000000000000 [1.05e22])
│ │ │ └─ ← [Return] true
│ │ ├─ [25750] MockUSDC::transfer(t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718], 10500000000000000000000 [1.05e22])
│ │ │ ├─ emit Transfer(from: ERC1967Proxy: [0x90193C961A926261B756D1E5bb255e67ff9498A1], to: t1: [0x5B12BE6D349275cca1c24672D7cF0FAE19e23718], value: 10500000000000000000000 [1.05e22])
│ │ │ └─ ← [Return] true
│ │ ├─ [1541] MockUSDC::transfer(t2: [0x6A8548f54C723e46F27892911e8C1bADF15a21A5], 10500000000000000000000 [1.05e22])
│ │ │ └─ ← [Revert] ERC20InsufficientBalance(0x90193C961A926261B756D1E5bb255e67ff9498A1, 9000000000000000000000 [9e21], 10500000000000000000000 [1.05e22])
│ │ └─ ← [Revert] ERC20InsufficientBalance(0x90193C961A926261B756D1E5bb255e67ff9498A1, 9000000000000000000000 [9e21], 10500000000000000000000 [1.05e22])
│ └─ ← [Revert] ERC20InsufficientBalance(0x90193C961A926261B756D1E5bb255e67ff9498A1, 9000000000000000000000 [9e21], 10500000000000000000000 [1.05e22])
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 146.66ms (143.50ms CPU time)
Ran 1 test suite in 857.17ms (146.66ms CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
-Switch to a pull model: record each teacher’s salary and allow them to withdraw it individually (withdrawSalary).
-Implement batch payments (e.g. 50 teachers per transaction) with index tracking.
-Cap the size of listOfTeachers or enforce an internal gas check (require(gasleft() > X)).
-Perform the upgrade first, then execute the payments—this lets you introduce the optimized logic without risking the initial DoS.