@@ -237,12 +237,15 @@ contract LiquidationLibrary is CdpManagerStorage {
237
237
);
238
238
239
239
{
240
- (_cappedColPortion, _collSurplus, _debtToRedistribute) = _calculateSurplusAndCap (
240
+ (
241
+ _cappedColPortion,
242
+ _collSurplus,
243
+ _debtToRedistribute
244
+ ) = _calculateFullLiquidationSurplusAndCap (
241
245
_liqState.ICR,
242
246
_liqState.price,
243
247
_totalDebtToBurn,
244
- _totalColToSend,
245
- true
248
+ _totalColToSend
246
249
);
247
250
if (_collSurplus > 0 ) {
248
251
// due to division precision loss, should be zero surplus in normal mode
@@ -308,12 +311,15 @@ contract LiquidationLibrary is CdpManagerStorage {
308
311
309
312
// avoid stack too deep
310
313
{
311
- (_cappedColPortion, _collSurplus, _debtToRedistribute) = _calculateSurplusAndCap (
314
+ (
315
+ _cappedColPortion,
316
+ _collSurplus,
317
+ _debtToRedistribute
318
+ ) = _calculateFullLiquidationSurplusAndCap (
312
319
_recoveryState.ICR,
313
320
_recoveryState.price,
314
321
_totalDebtToBurn,
315
- _totalColToSend,
316
- true
322
+ _totalColToSend
317
323
);
318
324
if (_collSurplus > 0 ) {
319
325
collSurplusPool.increaseSurplusCollShares (_borrower, _collSurplus);
@@ -389,12 +395,11 @@ contract LiquidationLibrary is CdpManagerStorage {
389
395
uint256 newDebt = _debtAndColl.entireDebt - _partialDebt;
390
396
391
397
// credit to https://arxiv.org/pdf/2212.07306.pdf for details
392
- (uint256 _partialColl , uint256 newColl , ) = _calculateSurplusAndCap (
398
+ (uint256 _partialColl , uint256 newColl , ) = _calculatePartialLiquidationSurplusAndCap (
393
399
_partialState.ICR,
394
400
_partialState.price,
395
401
_partialDebt,
396
- _debtAndColl.entireColl,
397
- false
402
+ _debtAndColl.entireColl
398
403
);
399
404
400
405
// early return: if new collateral is zero, we have a full liqudiation
@@ -525,45 +530,67 @@ contract LiquidationLibrary is CdpManagerStorage {
525
530
);
526
531
}
527
532
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 (
530
535
uint256 _ICR ,
531
536
uint256 _price ,
532
537
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 ) {
543
540
uint256 _incentiveColl;
541
+
542
+ // CLAMP
544
543
if (_ICR > LICR) {
544
+ // Cap at 10%
545
545
_incentiveColl = (_totalDebtToBurn * (_ICR > MCR ? MCR : _ICR)) / _price;
546
546
} 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;
561
549
}
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);
564
591
}
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 ;
567
594
}
568
595
569
596
// --- Batch liquidation functions ---
0 commit comments