endBlock can be set equal to 0 once the farm is ongoing
Summary
endBlock can be changed to be 0 when the Farm is ongoing. This should never be allowed as by definition and condition should be:
if (_startBlock == 0) {
revert InvalidStartBlock();
}
function setStartBlock(uint256 _startBlock) public onlyOwner {
if (_startBlock == 0 || (endBlock != 0 && _startBlock >= endBlock)) {
revert InvalidStartBlock();
}
Vulnerability Detail
The setEndBlock function allows in its if condition to change the endBlock to 0 for all ongoing pools and so for all the users of the contract. Changing the endBlock to 0 should not be allowed because pools have been already started.
Impact
Changing the endBlock to 0 once the Farm is ongoing could impact the pending points of all the users on all pools because it changes the pool.lastRewardBlock to the current block.number on all the pools impacting on the BlockMultiplier every time the pendingPoints function is called.
Therefore, a wrong pending points calculation is provided to the users for every pool.
Pending points in this contract can be considered as rewards for all users because based on these points there could be in the future airdrops, and reward distributions.
Therefore, it could have an impact on all ongoing pools and not just on one of them.
POC
function test_PendingPoints () public {
uint256 start = block.number;
uint256 amountToDeposit1 = 100e25;
uint256 poolId1 = sophonFarming.typeToId(SophonFarmingState.PredefinedPool.wstETH);
vm.startPrank(account1);
deal(address(wstETH), account1, amountToDeposit1);
wstETH.approve(address(sophonFarming), 50e25);
sophonFarming.deposit(poolId1, 50e25, 0);
vm.stopPrank();
vm.startPrank(account2);
deal(address(wstETH), account2, amountToDeposit1);
wstETH.approve(address(sophonFarming), amountToDeposit1);
sophonFarming.deposit(poolId1, amountToDeposit1, 0);
vm.stopPrank();
uint256 amountToDeposit2 = 10000e25;
uint256 poolId2 = sophonFarming.typeToId(SophonFarmingState.PredefinedPool.sDAI);
vm.startPrank(account2);
deal(address(sDAI), account2, amountToDeposit2);
sDAI.approve(address(sophonFarming), amountToDeposit2);
sophonFarming.deposit(poolId2, amountToDeposit2, 0);
vm.stopPrank();
// some time passes
vm.roll(start + 30);
vm.startPrank(account1);
uint256 ppvalue_1 = sophonFarming.pendingPoints(poolId1, account1);
vm.stopPrank();
vm.prank(account2);
uint256 ppvalue_2 = sophonFarming.pendingPoints(poolId1, account2);
SophonFarmingState.PoolInfo[] memory PoolInfo;
PoolInfo = sophonFarming.getPoolInfo();
emit log(PoolInfo[1].lastRewardBlock);
// make deposit to update lastRewardBlock.
vm.startPrank(account1);
wstETH.approve(address(sophonFarming), 30e25);
sophonFarming.deposit(poolId1, 30e18, 0);
vm.stopPrank();
PoolInfo = sophonFarming.getPoolInfo();
emit log(PoolInfo[1].lastRewardBlock);
sophonFarming._getBlockMultiplier(PoolInfo[1].lastRewardBlock,block.number);
// some time passes
vm.roll(start + 3500);
uint256 PP_oldendblock = sophonFarming.pendingPoints(poolId1, account1);
vm.prank(deployer);
sophonFarming.setEndBlock(0,0);
uint256 PP_newendblock = sophonFarming.pendingPoints(poolId1, account1);
// difference in pending points calculated before and after change of endBlock
uint256 PP_difference = PP_oldendblock-PP_newendblock;
assertGt(PP_difference, 0, "No difference in pending points");
emit log (PP_difference);
4th05
high
endBlock
can be set equal to0
once thefarm
is ongoingSummary
endBlock
can be changed to be0
when theFarm
is ongoing. This should never be allowed as by definition and condition should be:Vulnerability Detail
The
setEndBlock
function allows in its if condition to change theendBlock
to0
for all ongoingpools
and so for all the users of the contract. Changing theendBlock
to0
should not be allowed because pools have been already started.Impact
Changing the
endBlock
to0
once theFarm
is ongoing could impact the pending points of all the users on all pools because it changes thepool.lastRewardBlock
to the currentblock.number
on all the pools impacting on theBlockMultiplier
every time thependingPoints
function is called. Therefore, a wrong pending points calculation is provided to the users for every pool.Pending points in this contract can be considered as rewards for all users because based on these points there could be in the future airdrops, and reward distributions. Therefore, it could have an impact on all ongoing
pools
and not just on one of them.POC
Code Snippet
Tool used
Foundry
Recommendation
To change the code as below: