Open code423n4 opened 1 year ago
thereksfour marked the issue as primary issue
thereksfour changed the severity to 2 (Med Risk)
We will mark this issue as Sponsor Acknowledged. It is true the situation described by the warden and that's the behavior we observe. However we will not be implementing any change in the code (besides adding some comments) for the following reasons:
transfer
operation. It is important to remark that any deposit
or withdraw
done to the contract plus any call to collectRewards..
, and any claim of rewards from the Reserve protocol, would setup the correct balances. So while it is true that transfers may in some cases not transfer rewards we expect this to only be slightly off.To clarify this issue for users we will add a comment to the wrapper contract StaticATokenLM
to clarify the situation with how rewards are handled on transfer.
tbrent marked the issue as sponsor acknowledged
thereksfour marked the issue as satisfactory
thereksfour marked the issue as selected for report
Lines of code
https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/aave/StaticATokenLM.sol#L367-L386
Vulnerability details
Impact
This issue could lead to a permanent loss of rewards for the transferer of the token. During the token transfer process, the
_beforeTokenTransfer
function updates rewards for both the sender and the receiver. However, due to the specific call order and the behavior of the_updateUser
function and the_getPendingRewards
function, some rewards may not be accurately accounted for.The crux of the problem lies in the fact that the
_getPendingRewards
function, when called with thefresh
parameter set tofalse
, may not account for all the latest rewards from theINCENTIVES_CONTROLLER
. As a result, the_updateUserSnapshotRewardsPerToken
function, which relies on the output of the_getPendingRewards
function, could end up missing out on some rewards. This could be detrimental to the token sender, especially theBacking Manager
wheneverRToken
is redeemed. Apparently, most users having wrapped theirAToken
, would automatically use it to issueRToken
as part of the basket range of backing collaterals and be minimally impacted. But it would have the Reserve Protocol collectively affected depending on the frequency and volume of RToken redemption and the time elapsed since_updateRewards()
or_collectAndUpdateRewards()
was last called. The same impact shall also apply when making token transfers to successful auction bidders.Proof of Concept
As denoted in the function NatSpec below, function
_beforeTokenTransfer
updates rewards for senders and receivers in atransfer
.https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/aave/StaticATokenLM.sol#L367-L386
When function
_updateUser
is respectively invoked,_getPendingRewards(user, balance, false)
is called.https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/aave/StaticATokenLM.sol#L543-L550
However, because the third parameter has been entered
false
, the third if block of function_getPendingRewards
is skipped.https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/aave/StaticATokenLM.sol#L552-L591
Hence,
accRewardsPerToken
may not be updated with the latest rewards fromINCENTIVES_CONTROLLER
. Consequently,_updateUserSnapshotRewardsPerToken(user)
will miss out on claiming some rewards and is a loss to the StaticAtoken transferrer.https://github.com/reserve-protocol/protocol/blob/9ee60f142f9f5c1fe8bc50eef915cf33124a534f/contracts/plugins/assets/aave/StaticATokenLM.sol#L531-L537
Ironically, this works out as a zero-sum game where the loss of the transferrer is a gain to the transferee. But most assuredly, the Backing Manager is going to end up incurring more losses than gains in this regard.
Tools Used
Manual
Recommended Mitigation Steps
Consider introducing an additional call to update the state of rewards before any token transfer occurs. Specifically, within the
_beforeTokenTransfer
function, invoking_updateRewards
like it has been implemented inStaticATokenLM._deposit
andStaticATokenLM._withdraw
before updating the user balances would have the issues resolved.This method would not force an immediate claim of rewards, but rather ensure the internal accounting of rewards is up-to-date before the transfer. By doing so, the state of rewards for each user would be accurate and ensure no loss or premature gain of rewards during token transfers.
Assessed type
Token-Transfer