Open code423n4 opened 1 year ago
GalloDaSballo marked the issue as duplicate of #380
GalloDaSballo marked the issue as not a duplicate
GalloDaSballo marked the issue as primary issue
Better Description
I think that medium severity is more appropriate. User funds aren't drained or lost, but liquid staking rewards may be unfairly calculated.
Good find. I think there is something we could do to either incentivize the syncRewards
call or call it on deposit and withdraw.
But I disagree with the concept that the user who staked for 8 days is entitled to rewards for staking. Rewards depend on properly running minipools. Reward amounts can fluctuate depend on the utilization of liquid staking funds by minipools.
Going to tie in this issue https://github.com/code-423n4/2022-12-gogopool-findings/issues/99
After some more discussion, this is working as designed. And Rialto will call syncRewards
at the start of each reward cycle, so the possible loss to the user who withdraws before syncRewards
was supposed to be called is mitigated.
The Warden has shown a potential risk for end-users that withdraw before syncRewards
is called
Because the finding pertains to a loss of yield, I believe the finding to be of Medium Severity.
While Rialto may call this as a perfect actor, we cannot guarantee that a end user could forfeit some amount of yield, due to external conditions.
I believe this finding to potentially be a nofix, as long as all participants are aware of the mechanic.
Per discussions had on #99 I don't believe that any specific MEV attack has been identified, however this finding does highlight a potential risk that a mistimed withdrawal could cause
GalloDaSballo changed the severity to 2 (Med Risk)
Acknowledged.
Not fixing but will add a note in our docs.
GalloDaSballo marked the issue as selected for report
Lines of code
https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L88-L109 https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L166-L178 https://github.com/code-423n4/2022-12-gogopool/blob/aec9928d8bdce8a5a4efe45f54c39d4fc7313731/contracts/contract/tokens/TokenggAVAX.sol#L180-L189
Vulnerability details
Impact
Function
syncRewards()
distributes rewards to TokenggAVAX holders, it linearly distribute cycle's rewards fromblock.timestamp
to the cycle end time which is next multiple of therewardsCycleLength
(the end time of the cycle is defined and the real duration of the cycle changes). when a cycle endssyncRewards()
should be called so the next cycle starts but ifsyncRewards()
doesn't get called fast, then users depositing or withdrawing funds before call tosyncRewards()
would lose their rewards and those rewards would go to users who deposited funds aftersyncRewards()
call. contract should try to start the next cycle whenever deposit or withdraw happens to make sure rewards are distributed fairly between users.Proof of Concept
This is
syncRewards()
code:As you can see whenever this function is called it starts the new cycle and sets the end of the cycle to the next multiple of the
rewardsCycleLength
and it release the rewards linearly between current timestamp and cycle end time. so ifsyncRewards()
get called near to multiple of therewardsCycleLength
then rewards would be distributed with higher speed in less time. the problem is that users depositing funds before callsyncRewards()
won't receive new cycles rewards and early depositing won't get considered in reward distribution if deposits happen beforesyncRewards()
call and if a user withdraws his funds before thesyncRewards()
call then he receive no rewards. imagine this scenario:rewardsCycleLength
is 10 days and the rewards for the next cycle is100
AVAX.10000
AVAX deposited and has 50% of the pool shares.syncRewards()
don't get called for 8 days.10000
AVAX even so he deposits for 8 days in the current cycle.1000
AVAX and get 10% of pool shares and the user2 would callsyncRewards()
and contract would start distributing100
avax as reward.100 * 10% = 10
AVAX as rewards for his1000
AVAX deposit for 2 days but user1 had10000
AVAX for 8 days and would receive 0 rewards.so rewards won't distribute fairly between depositors across the time and any user interacting with contract before the
syncRewards()
call can lose his rewards. contract won't consider deposit amounts and duration beforesyncRewards()
call and it won't make sure thatsyncRewards()
logic would be executed as early as possible with deposit or withdraw calls when a cycle ends.Tools Used
VIM
Recommended Mitigation Steps
one way to solve this is to call
syncRewards()
logic in each deposit or withdraw and make sure that cycles start as early as possible (the revert "SyncError()" in thesyncRewards()
should be removed for this).