the SDLPool contract allows a malicious actor to perform a sandwich attack to gain immediate rewards by exploiting the timing of reward distribution transactions.
The SDLPool contract's reward distribution mechanism it's susceptible to exploitation due to the way of reward calculations. There is a global rewardPerToken
variable used to calculate the rewards for stakers and is updated (only increases) whenever new rewards are added to the pool via the distributeToken
function. However, this mechanism allow A malicious actor to simply buy sdl
tokens and stake right before the distributeToken function is called to immediately accrue a portion of rewards that were meant to be attributed to other stakers. The malicious actor can then immediately claim these rewards, unstake and sell thier sdl
therefore stealing rewards from other stakers.
assume we have 10 sdl
tokens staked before for alice .. and the rewardPerToken is 1 r
bob observes a pending transaction that will trigger a reward distribution with 100 r
.
bob sends 100 sdl
token triggering onTokenTransfer
to deposit and front-running the pending reward distribution transaction.
in this case bob userRewardPerTokenPaid will be 1
, and he got 0 r
in rewards.
Once the distributeToken
transaction is confirmed, rewardPerToken
is updated to be : rewardPerToken += 100 / 110 ≈ 1.9 r
.
bob immediately calls withdrawRewards
to claim the rewards based on the updated rewardPerToken
which will be :
staked * (rewardPerToken - userRewardPerTokenPaid[bob])
100 * (1.9 - 1) =
90 r
bob then calls withdraw
to remove their SDL tokens from the SdlPool
.
This sequence of actions allowed bob to receive 90% of the rewards immediately, disadvantaging other stakers.
a foundry test with a min setup shows how bob sandwich the distribute reward tx to gain more then 90%
of rewards.
console after running test :
This attack allows an actor to unfairly claim a portion of the rewards,that were meant to be attributed to other stakers. whitout actually staking sdl
tokens
vs code
foundry
manual review
There are many approaches that can be taken in this case, and it depends on the team how to mitigate that. One example is adding a warmup period
before the distributeToken
function is called, where those who stake during this period will not accrue rewards.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.