58337 sc high incorrect handling of cumulativeearmarked in forcerepay leads to inflated survival accumulator
#58337 [SC-High] Incorrect Handling of cumulativeEarmarked in _forceRepay leads to inflated survival accumulator.
Description
Brief/Intro
Vulnerability Details
function _forceRepay(uint256 accountId, uint256 amount) internal returns (uint256) {
if (amount == 0) {
return 0;
}
_checkForValidAccountId(accountId);
Account storage account = _accounts[accountId];
// Query transmuter and earmark global debt
_earmark();
// Sync current user debt before deciding how much is available to be repaid
_sync(accountId);
uint256 debt;
// Burning yieldTokens will pay off all types of debt
_checkState((debt = account.debt) > 0);
uint256 credit = amount > debt ? debt : amount;
uint256 creditToYield = convertDebtTokensToYield(credit);
_subDebt(accountId, credit);
// Repay debt from earmarked amount of debt first
uint256 earmarkToRemove = credit > account.earmarked ? account.earmarked : credit;
@1> account.earmarked -= earmarkToRemove;
creditToYield = creditToYield > account.collateralBalance ? account.collateralBalance : creditToYield;
account.collateralBalance -= creditToYield;
uint256 protocolFeeTotal = creditToYield * protocolFee / BPS;
emit ForceRepay(accountId, amount, creditToYield, protocolFeeTotal);
if (account.collateralBalance > protocolFeeTotal) {
account.collateralBalance -= protocolFeeTotal;
// Transfer the protocol fee to the protocol fee receiver
TokenUtils.safeTransfer(myt, protocolFeeReceiver, protocolFeeTotal);
}
if (creditToYield > 0) {
// Transfer the repaid tokens from the account to the transmuter.
TokenUtils.safeTransfer(myt, address(transmuter), creditToYield);
}
return creditToYield;
}
function redeem(uint256 amount) external onlyTransmuter {
_earmark();
@2> uint256 liveEarmarked = cumulativeEarmarked;
if (amount > liveEarmarked) amount = liveEarmarked;
---
uint256 redeemedDebtTotal = amount + coverToApplyDebt;
// Apply redemption weights/decay to the full amount that left the earmarked bucket
if (liveEarmarked != 0 && redeemedDebtTotal != 0) {
@3> uint256 survival = ((liveEarmarked - redeemedDebtTotal) << 128) / liveEarmarked;
@4> _survivalAccumulator = _mulQ128(_survivalAccumulator, survival);
_redemptionWeight += PositionDecay.WeightIncrement(redeemedDebtTotal, cumulativeEarmarked);
}
// earmarks are reduced by the full redeemed amount (net + cover)
cumulativeEarmarked -= redeemedDebtTotal;
// global borrower debt falls by the full redeemed amount
totalDebt -= redeemedDebtTotal;
---
emit Redemption(redeemedDebtTotal);
}
Impact Details
Attack Path
References
Proof of Concept
Previous58113 sc high stargateethpoolstrategy realassets return false real assets Next58793 sc critical repayment fee overpayment from global collateral pool
Was this helpful?