-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rewards accrued will be permanently locked when there are no stakers #369
Comments
MarioPoneder marked the issue as duplicate of #9 |
MarioPoneder marked the issue as not a duplicate |
MarioPoneder marked the issue as primary issue |
apbendi (sponsor) disputed |
We do not consider this a valid report for several reasons:
|
Thought about this for a while since I can agree with both sides, the wardens and the sponsor.
No user loss + protocol can handle this situation with current design / codebase, therefore invalidating this group of issues. |
MarioPoneder marked the issue as unsatisfactory: |
I believe this should be a valid Medium for three reasons:
|
Agree with EperezOk, its should be valid medium, because DAO could not always track the presence of users in the stake contract. Rewards, distributed in period, when there are no stakers, weth will be permanently locked inside UniStaker. This is a loss of funds. Could be different situations, when no stakers in contract, but there is fact, that funds will be locked permanently in such situations. |
This issue should be at least a valid QA IMO. Agree its hard to go higher given:
However stuck funds are stuck funds and the sponsors mitigation of the DAO giving an address power to call |
The argument that the situation when there are no stakers or no one calls the notify function is unlikely, I consider incorrect. Because we cannot know whether the project will be successful or not. Therefore, it is necessary to consider all situations in this case. |
Thanks for raising your concerns! My take: At no point in time, funds are irrecoverably stuck. They simply cannot be claimed by a staker when no one is staking, which is a very unlikely edge-case. Users are never at a loss because of this. This behaviour is simply a design decision. Thank you for your understanding! |
@MarioPoneder , look at this case, please. There is a situation where funds will be irretrievably lost. January 1 - notifyreward As a result, funds from the first notification call, which were intended for stakers in the period from January 1 to January 10 and were not distributed, will not be added on February 5, so they will be permanently lost |
Lines of code
https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/UniStaker.sol#L570
Vulnerability details
Impact
When an MEV searcher claims the fees and there are no stakers for the entire
REWARD_PERIOD
, rewards will be locked forever.Stakers only have 30 days to stake their tokens before all rewards are permanently locked.
A partial amount of these rewards will be lost anyway if someone stakes before the full 30 days (e.g. first stake after 3 days will result in a 10% total loss).
Proof of Concept
Suppose the following: no one has staked their token in UniStaker yet, so
totalStaked = 0
.An MEV searcher calls
V3FactoryOwner.claimFees
immediately after deployment with a valid pool. ThenUniStaker.notifyRewardAmount
is also called:Due to
totalStaked = 0
, thenrewardPerTokenAccumulatedCheckpoint
is also zero:Let's analyze the previous values step by step, let's say we are at
block.timestamp = 1_000_000
for simplicity,REWARD_DURATION = 30 days = 2_592_000
, andrewardAmount = 10e18
Worst-case scenario: suppose that in these 30 days, no one calls
stake
. We are now attimestamp = 3_592_001
, and someone finally callsstake
:_checkpointGlobalReward
is called:_checkpointReward
is called:Finally stake data is updated:
Claim has no effect, as
rewardPerTokenAccumulated() = 0
andbeneficiaryRewardPerTokenCheckpoint[_beneficiary] = 0
:https://github.com/code-423n4/2024-02-uniswap-foundation/blob/main/src/UniStaker.sol#L241
So, the initial reward will be permanently locked inside
UniStaker
. Note that this loss of funds can occur even when the entire 30 days are not fully passed. For example, if no one stakes during the first 3 days, 10% of the rewards will be permanently locked anyway.This can result in a large amount of funds being locked based on how big the rewards are. Suppose that
payoutAmount
is 10 WETH (this is currently worth $35k), so the total loss for 3 days would be 3.5k.Coded PoC
Copy-paste the following test in
test/UniStaker.t.sol
, then runforge test --match-test test_RewardsAreLostWithNoStakers
:Tools Used
Manual review
Recommended Mitigation Steps
I recommend one of these two solutions or a combination of them:
Consider adding a timelock to
V3FactoryOwner.claimFees
so that no one can claim fees for a reasonable amount of time, long enough to let users stake their tokens.Consider reverting the TX when no one has staked their tokens in
UniStaker.notifyRewardAmount
yet (i.e. whentotalStaked = 0
).Assessed type
Timing
The text was updated successfully, but these errors were encountered: