DittoETH

Ditto
DeFiFoundryOracle
55,000 USDC
View results
Submission Details
Severity: medium
Invalid

Incorrect formula is used to socialize debt

Summary

According to documentation, socializedDebt is distributed according to following formula:

ercDebtRate is calculated as ercDebt[socialized] / (ercDebt[Asset] - ercDebt[socialized]) and is written to every shortRecord record to modify each position's ercDebt amount.

However code uses different formula: ercDebt[socialized] / (ercDebt[Asset] - ercDebtOfShortRecord)

Vulnerability Details

Assets ercDebtRate increases when debt is socialized. It means that TAPP doesn't have enough funds to perform Primary Liquidation, and distributes debt that can't repay between all shortRecords.
Here you can see that instead of ercDebt[socialized] argument ercDebtPrev is used:

function _performForcedBid(
MTypes.MarginCallPrimary memory m,
uint16[] memory shortHintArray
) private {
uint256 startGas = gasleft();
uint88 ercAmountLeft;
//@dev Provide higher price to better ensure it can fully fill the margin call
uint80 _bidPrice = m.oraclePrice.mulU80(m.forcedBidPriceBuffer);
// Shorter loses leftover collateral to TAPP when unable to maintain CR above the minimum
m.loseCollateral = m.cRatio <= m.minimumCR;
//@dev Increase ethEscrowed by shorter's full collateral for forced bid
s.vaultUser[m.vault][address(this)].ethEscrowed += m.short.collateral;
// Check ability of TAPP plus short collateral to pay back ethDebt
if (s.vaultUser[m.vault][address(this)].ethEscrowed < m.ethDebt) {
uint96 ercDebtPrev = m.short.ercDebt;
if (s.asset[m.asset].ercDebt <= ercDebtPrev) {
// Occurs when only one shortRecord in the asset (market)
revert Errors.CannotSocializeDebt();
}
m.loseCollateral = true;
// @dev Max ethDebt can only be the ethEscrowed in the TAPP
m.ethDebt = s.vaultUser[m.vault][address(this)].ethEscrowed;
// Reduce ercDebt proportional to ethDebt
m.short.ercDebt = uint88(
m.ethDebt.div(_bidPrice.mul(1 ether + m.callerFeePct + m.tappFeePct))
); // @dev(safe-cast)
uint96 ercDebtSocialized = ercDebtPrev - m.short.ercDebt;
// Update ercDebtRate to socialize loss (increase debt) to other shorts
s.asset[m.asset].ercDebtRate +=
@> ercDebtSocialized.divU64(s.asset[m.asset].ercDebt - ercDebtPrev);
}
...
}

Impact

Debt is socialized according to incorrect formula. More likely it breaks debt distribution logic

Tools Used

Manual Review

Recommendations

Refactor to

s.asset[m.asset].ercDebtRate +=
- ercDebtSocialized.divU64(s.asset[m.asset].ercDebt - ercDebtPrev);
+ ercDebtSocialized.divU64(s.asset[m.asset].ercDebt - ercDebtSocialized);
Updates

Lead Judging Commences

0xnevi Lead Judge
about 2 years ago
0xnevi Lead Judge
about 2 years ago
0xnevi Lead Judge about 2 years ago
Submission Judgement Published
Invalidated
Reason: Other

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.