Skip to content

Commit f8cf293

Browse files
committed
optimize _calcSurplusAndCap() in LiquidationLibrary
1 parent 4a1648d commit f8cf293

File tree

1 file changed

+66
-39
lines changed

1 file changed

+66
-39
lines changed

packages/contracts/contracts/LiquidationLibrary.sol

Lines changed: 66 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -237,12 +237,15 @@ contract LiquidationLibrary is CdpManagerStorage {
237237
);
238238

239239
{
240-
(_cappedColPortion, _collSurplus, _debtToRedistribute) = _calculateSurplusAndCap(
240+
(
241+
_cappedColPortion,
242+
_collSurplus,
243+
_debtToRedistribute
244+
) = _calculateFullLiquidationSurplusAndCap(
241245
_liqState.ICR,
242246
_liqState.price,
243247
_totalDebtToBurn,
244-
_totalColToSend,
245-
true
248+
_totalColToSend
246249
);
247250
if (_collSurplus > 0) {
248251
// due to division precision loss, should be zero surplus in normal mode
@@ -308,12 +311,15 @@ contract LiquidationLibrary is CdpManagerStorage {
308311

309312
// avoid stack too deep
310313
{
311-
(_cappedColPortion, _collSurplus, _debtToRedistribute) = _calculateSurplusAndCap(
314+
(
315+
_cappedColPortion,
316+
_collSurplus,
317+
_debtToRedistribute
318+
) = _calculateFullLiquidationSurplusAndCap(
312319
_recoveryState.ICR,
313320
_recoveryState.price,
314321
_totalDebtToBurn,
315-
_totalColToSend,
316-
true
322+
_totalColToSend
317323
);
318324
if (_collSurplus > 0) {
319325
collSurplusPool.increaseSurplusCollShares(_borrower, _collSurplus);
@@ -389,12 +395,11 @@ contract LiquidationLibrary is CdpManagerStorage {
389395
uint256 newDebt = _debtAndColl.entireDebt - _partialDebt;
390396

391397
// credit to https://arxiv.org/pdf/2212.07306.pdf for details
392-
(uint256 _partialColl, uint256 newColl, ) = _calculateSurplusAndCap(
398+
(uint256 _partialColl, uint256 newColl, ) = _calculatePartialLiquidationSurplusAndCap(
393399
_partialState.ICR,
394400
_partialState.price,
395401
_partialDebt,
396-
_debtAndColl.entireColl,
397-
false
402+
_debtAndColl.entireColl
398403
);
399404

400405
// early return: if new collateral is zero, we have a full liqudiation
@@ -525,45 +530,67 @@ contract LiquidationLibrary is CdpManagerStorage {
525530
);
526531
}
527532

528-
// Function that calculates the amount of collateral to send to liquidator (plus incentive) and the amount of collateral surplus
529-
function _calculateSurplusAndCap(
533+
// Partial Liquidation Cap Logic
534+
function _calculatePartialLiquidationSurplusAndCap(
530535
uint256 _ICR,
531536
uint256 _price,
532537
uint256 _totalDebtToBurn,
533-
uint256 _totalColToSend,
534-
bool _fullLiquidation
535-
)
536-
private
537-
view
538-
returns (uint256 cappedColPortion, uint256 collSurplus, uint256 debtToRedistribute)
539-
{
540-
// Calculate liquidation incentive for liquidator:
541-
// If ICR is less than 103%: give away 103% worth of collateral to liquidator, i.e., repaidDebt * 103% / price
542-
// If ICR is more than 103%: give away min(ICR, 110%) worth of collateral to liquidator, i.e., repaidDebt * min(ICR, 110%) / price
538+
uint256 _totalColToSend
539+
) private view returns (uint256 toLiquidator, uint256 collSurplus, uint256 debtToRedistribute) {
543540
uint256 _incentiveColl;
541+
542+
// CLAMP
544543
if (_ICR > LICR) {
544+
// Cap at 10%
545545
_incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;
546546
} else {
547-
if (_fullLiquidation) {
548-
// for full liquidation, there would be some bad debt to redistribute
549-
_incentiveColl = collateral.getPooledEthByShares(_totalColToSend);
550-
uint256 _debtToRepay = (_incentiveColl * _price) / LICR;
551-
debtToRedistribute = _debtToRepay < _totalDebtToBurn
552-
? _totalDebtToBurn - _debtToRepay
553-
: 0;
554-
// now CDP owner should have zero surplus to claim
555-
cappedColPortion = _totalColToSend;
556-
} else {
557-
// for partial liquidation, new ICR would deteriorate
558-
// since we give more incentive (103%) than current _ICR allowed
559-
_incentiveColl = (_totalDebtToBurn * LICR) / _price;
560-
}
547+
// Min 103%
548+
_incentiveColl = (_totalDebtToBurn * LICR) / _price;
561549
}
562-
if (cappedColPortion == 0) {
563-
cappedColPortion = collateral.getSharesByPooledEth(_incentiveColl);
550+
551+
// NOTE: IT MAY BE TOO MUCH
552+
// NOTE: IT SHOULD NEVER BE TOO MUCH CAUSE IT's PARTIAL!!!
553+
toLiquidator = collateral.getSharesByPooledEth(_incentiveColl);
554+
toLiquidator = toLiquidator < _totalColToSend ? toLiquidator : _totalColToSend; // Cap the Coll (should never happen on partial)
555+
collSurplus = (toLiquidator == _totalColToSend) ? 0 : _totalColToSend - toLiquidator; // Can use unchecked but w/e
556+
557+
// debtToRedistribute is 0 always // TO AUDIT
558+
}
559+
560+
function _calculateFullLiquidationSurplusAndCap(
561+
uint256 _ICR,
562+
uint256 _price,
563+
uint256 _totalDebtToBurn,
564+
uint256 _totalColToSend
565+
) private view returns (uint256 toLiquidator, uint256 collSurplus, uint256 debtToRedistribute) {
566+
uint256 _incentiveColl;
567+
568+
if (_ICR > LICR) {
569+
_incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;
570+
} else {
571+
// for full liquidation, there would be some bad debt to redistribute
572+
_incentiveColl = collateral.getPooledEthByShares(_totalColToSend);
573+
574+
// Since it's full and there's bad debt we use spot conversion to
575+
// Determine the amount of debt that willl be repaid after adding the LICR discount
576+
// Basically this is buying underwater Coll
577+
// By repaying debt at 3% discount
578+
// Can there be a rounding error where the _debtToRepay > debtToBurn?
579+
uint256 _debtToRepay = (_incentiveColl * _price) / LICR;
580+
581+
debtToRedistribute = _debtToRepay < _totalDebtToBurn
582+
? _totalDebtToBurn - _debtToRepay // Bad Debt (to be redistributed) is (CdpDebt - Repaid)
583+
: 0; // Else 0 (note we may underpay per the comment above, althought that may be imaginary)
584+
585+
// now CDP owner should have zero surplus to claim
586+
toLiquidator = _totalColToSend;
587+
}
588+
589+
if (toLiquidator == 0) {
590+
toLiquidator = collateral.getSharesByPooledEth(_incentiveColl);
564591
}
565-
cappedColPortion = cappedColPortion < _totalColToSend ? cappedColPortion : _totalColToSend;
566-
collSurplus = (cappedColPortion == _totalColToSend) ? 0 : _totalColToSend - cappedColPortion;
592+
toLiquidator = toLiquidator < _totalColToSend ? toLiquidator : _totalColToSend;
593+
collSurplus = (toLiquidator == _totalColToSend) ? 0 : _totalColToSend - toLiquidator;
567594
}
568595

569596
// --- Batch liquidation functions ---

0 commit comments

Comments
 (0)