Closed code423n4 closed 1 year ago
Users can make sandwich attacks on lottery purchases ( themselves or others). Consider Med.
thereksfour marked the issue as primary issue
thereksfour changed the severity to 2 (Med Risk)
I think the staking system is misunderstood here. It is based on tickets sold, not time staked. The attack vector involves a time/block trick (e.g. flashloan) whereas the attacked system is time/block-independent.
Staking is meant to reward stakers for any ticket purchases that occur during their staking. It depends only on the number of tickets sold, NOT the time staked. It therefore seems absolutely in line with the stated intention to be able to concentrate staking to a specific period (such as one block) of ticket purchases, as long as that is when the ticket purchases happen. LOT has little use besides staking, so deciding to stake only when tickets are purchased and otherwise unstake has no impact on the reward system and is rather pointless.
The possibility to do this with a flashloan might be a consideration for the sponsor. But if LOT ever becomes available for flashloans, then this opportunity will increase the flashloan fees in equal measure through competition, rendering this simply an alternative method of staking.
thereksfour marked the issue as duplicate of #126
thereksfour changed the severity to QA (Quality Assurance)
thereksfour marked the issue as grade-c
Lines of code
https://github.com/code-423n4/2023-03-wenwin/blob/91b89482aaedf8b8feb73c771d11c257eed997e8/src/staking/Staking.sol#L67-L89 https://github.com/code-423n4/2023-03-wenwin/blob/91b89482aaedf8b8feb73c771d11c257eed997e8/src/staking/Staking.sol#L118-L124
Vulnerability details
Impact
Stake and withdraw in the same block completly defeats the purpose of staking as anyone can either bundle transaction to sandwich large ticket buy orders or use flashloans to stake, buy tickets and withdraw in a single transaction to essentially receive a ~19% discount on tickets as long as there is more liquidity on DEXes than staked. As staking becomes almost obsolete with this issue, it should always hold that DEX liquidity >> staked liquidity. Rated high, because it impacts both stakers and ticket buyers, is easy to execute and makes a part of the protocol obsolete.
Proof of Concept
Neither the stake and withdraw functions nor the _updateReward function do any kind of check on timestamps or block numbers. This means one can
Technicals
The technicals are the same for both attacks:
You can add a test case to Staking.t.sol to verify the possibility of staking, buying tickets, claiming rewards and withdrawing in the same block or tx:
Tools Used
VSCode, Manual review
Recommended Mitigation Steps
I recommend either updating rewards only once per block (this would save gas, too) or tracking the last staked blocks for every user and preventing withdraw in the same block. For the first solution add this to Staking.sol
For the second solution add the following:
You can replace block.timestamp with block.number