Lines of code
<https://github.com/code-423n4/2023-06-lybra/blob/main/contracts/lybra/miner/EUSDMiningIncentives.sol#L184-L186>
The reward distribution logic of the ProtocolRewardsPool and EUSDMiningIncentives contracts effectively allow a user to mint much more rewards than they should be allowed to. This is possible because, unlike a true implementation of the synthetix staking contract, there is no staking function which records an amount deposited for a user, along with updating the userRewardPerTokenPaid for the user. Instead, stakedOf will just return the current balance of the user (rather than e.g. some amount locked in the contract). Additionally, this also means that in the first call to earned, the userRewardPerTokenPaid for the user will always be 0.
The attack path for exploiting this in both the ProtocolRewardsPool and EUSDMiningIncentives contracts are different, but both have the same root cause. In the ProtocolRewardsPool contract, a user who receives (considered staking in this contract) the same amount of esLBR at a future date will receive the same amount of rewards as a user who gets that esLBR earlier. This fundamentally breaks the intended rewards dynamics.
Itβs even worse in the EUSDMiningIncentives contract, where this can be exploited to mint an ~inf number of reward tokens. This is done by looping through many different accounts and having each call getReward after borrowing EUSD or PeUSD atomically (and repaying in the same tx).
Since there is no true stake function for either of the ProtocolRewardsPool and EUSDMiningIncentives contracts, userRewardPerTokenPaid for a user will always be 0 on the first call. A malicious user can take advantage of this and perform the following attack (here I am referring to the EUSDMiningIncentives contract):
Manual review
If the ProtocolRewardsPool and EUSDMiningIncentives contracts are intended to use Synthetix-like reward distribution logic, then there should be a function where the user actually stakes their tokens (which also updates the userRewardPerTokenPaid), rather than using the current balance of the user.
Other
The text was updated successfully, but these errors were encountered:
All reactions