TokenggAVAX: actual reward streaming period can be as small as 1 second due to rounding #154
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
duplicate-478
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L88-L109
Vulnerability details
Impact
The
TokenggAVAX
contract is supposed to stream rewards inAVAX
toggAVAX
holders over a period of 14 days.The 14 days period however is only an upper limit for the reward streaming period.
The way the reward streaming period is calculated can make is as small as 1 second (due to rounding).
This is clearly not intended and you should calculate
nextRewardsCycleEnd
differently such that the 14 day period is ensured.Proof of Concept
Rewards are streamed during a period of length
rewardsCycleEnd - lastSync
in thetotalAssets
function (https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L113-L130).rewardsCycleEnd
andlastSync
are calculated in thesyncRewards
function (https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L88-L109).I will show with a simple example that
rewardsCycleEnd - lastSync
can be as small as 1 second meaning that all rewards that are supposed to be streamed over a 14 days period are streamed within 1 second:syncRewards()
is called with:block.timestamp = 10099
,rewardsCycleLength = 100
nextRewardsCycleEnd
is calculated:timestamp + rewardsCycleLength
is equal to10199
. Dividing this byrewardsCycleLength
results in101
due to rounding.101
*100
is equal to10100
.So
nextRewardsCycleEnd = 10100
andlastSync = 10099
.This means that after 1 second all rewards are streamed.
Tools Used
VSCode
Recommended Mitigation Steps
In the code it is stated that you calculate
uint32 nextRewardsCycleEnd = ((timestamp + rewardsCycleLength) / rewardsCycleLength) * rewardsCycleLength;
becausenextRewardsCycleEnd
should be divisible byrewardsCycleLength
.I see no reason for this requirement and instead propose to calculate
nextRewardsCycleEnd
like this:The text was updated successfully, but these errors were encountered: