Description: LevelOne:graduateAndUpgrade
function is meant to disburse money 5% for pricipal and 35% to teacher w/c need to be divided to teachers. but this function does not divide the 35% of the bursary but rather give each teacher 35% and 35%.
Vulnerability Details: LevelOne:graduateAndUpgrade
function does not divide 35% of fee but rather give each teacher 35%
function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
uint256 totalTeachers = listOfTeachers.length;
uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
@> usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
}
usdc.safeTransfer(principal, principalPay);
}
Impact: the protocol will loose money
Tools Used: Manual Review
Proof of Concept: Add this test code
function test_WrongTranferOfTokenToTeachers() public {
vm.startPrank(principal);
levelOneProxy.addTeacher(alice);
levelOneProxy.addTeacher(bob);
vm.stopPrank();
vm.startPrank(clara);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(dan);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(eli);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(fin);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(grey);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
vm.startPrank(harriet);
usdc.approve(address(levelOneProxy), schoolFees);
levelOneProxy.enroll();
vm.stopPrank();
uint256 cuttOffScroe = 70;
vm.prank(principal);
levelOneProxy.startSession(cuttOffScroe);
bytes memory data = abi.encodeCall(LevelTwo.graduate, ());
vm.startPrank(principal);
levelOneProxy.graduateAndUpgrade(levelTwoImplementationAddress, data);
levelOneProxy.upgradeToAndCall(levelTwoImplementationAddress, data);
vm.stopPrank();
assert(usdc.balanceOf(alice) == 10500 ether);
assert(usdc.balanceOf(bob) == 10500 ether);
assert(usdc.balanceOf(proxyAddress) < 18000 ether);
}
Recommendations: Make another variable and divide 35% of bursary by number of teachers and store it in new variable created, then use that new variable to transfer the money to each teacher
function graduateAndUpgrade(address _levelTwo, bytes memory) public onlyPrincipal {
if (_levelTwo == address(0)) {
revert HH__ZeroAddress();
}
uint256 totalTeachers = listOfTeachers.length;
uint256 payPerTeacher = (bursary * TEACHER_WAGE) / PRECISION;
uint256 principalPay = (bursary * PRINCIPAL_WAGE) / PRECISION;
+ uint256 payForEachTeacher = payPerTeacher / totalTeachers;
_authorizeUpgrade(_levelTwo);
for (uint256 n = 0; n < totalTeachers; n++) {
- usdc.safeTransfer(listOfTeachers[n], payPerTeacher);
+ usdc.safeTransfer(listOfTeachers[n], payForEachTeacher);
}
usdc.safeTransfer(principal, principalPay);
}