Function withdraw() in StRSR completes an accountβs unstaking. but when calculated amount of RSR token is 0 code still burn user draftRSR and returns. This would cause users small amount of deposits to get burned and user wonβt receive any funds. as withdraw() is callable by anyone a malicious attacker can call withdraw() for each item separately which result in 0 RSR amount and user would lose his funds. As users separate withdrawals can sum up and calculated rsrAmount would be bigger than 0 for user so contract shouldnβt burn the small amounts of user balance for nothing.
This is withdraw() code:
function withdraw(address account, uint256 endId) external notPausedOrFrozen {
// == Refresh ==
assetRegistry.refresh();
// == Checks + Effects ==
require(basketHandler.fullyCollateralized(), "RToken uncollateralized");
require(basketHandler.status() == CollateralStatus.SOUND, "basket defaulted");
uint256 firstId = firstRemainingDraft[draftEra][account];
CumulativeDraft[] storage queue = draftQueues[draftEra][account];
if (endId == 0 || firstId >= endId) return;
require(endId <= queue.length, "index out-of-bounds");
require(queue[endId - 1].availableAt <= block.timestamp, "withdrawal unavailable");
uint192 oldDrafts = firstId > 0 ? queue[firstId - 1].drafts : 0;
uint192 draftAmount = queue[endId - 1].drafts - oldDrafts;
// advance queue past withdrawal
firstRemainingDraft[draftEra][account] = endId;
// ==== Compute RSR amount
uint256 newTotalDrafts = totalDrafts - draftAmount;
// newDraftRSR: {qRSR} = {qDrafts} * D18 / D18{qDrafts/qRSR}
uint256 newDraftRSR = (newTotalDrafts * FIX_ONE_256 + (draftRate - 1)) / draftRate;
uint256 rsrAmount = draftRSR - newDraftRSR;
if (rsrAmount == 0) return;
// ==== Transfer RSR from the draft pool
totalDrafts = newTotalDrafts;
draftRSR = newDraftRSR;
emit UnstakingCompleted(firstId, endId, draftEra, account, rsrAmount);
// == Interaction ==
IERC20Upgradeable(address(rsr)).safeTransfer(account, rsrAmount);
}
As you can see function is callable by anyone and code would return when calculated rsrAmount is 0 and it would burn user draft items. This would cause users to lose funds if they withdraw small amounts even if those small amounts sums would create a bigger RSR Amount. code would burn those drafts separately and user would receive nothing. imagine this scenario:
the issue of wrong reward distribution happens passively and users lose their dusts and attacker can cause the issue intentionally.
VIM
revert instead of the return when rsr amount is 0
The text was updated successfully, but these errors were encountered:
All reactions