@@ -603,40 +603,29 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
603
603
// several cycles.
604
604
cr = _updateDueInfo (borrower, false , true );
605
605
}
606
- console.log ("After updateDueInfo, cr.unbilledPrincipal= " , cr.unbilledPrincipal);
607
-
608
- // Computes payoff amount, including correction
609
- // Since only payback generates generative correction, and all other actions (e.g. drawdown)
610
- // will only increase totalDue, unbilledPrincipal, and move correction to the positive
611
- // side, if abs(cr.correction) is larger than the sum of due and principal, the credit line
612
- // would have been paid off at the last payment when the big negative cr.correction was
613
- // generated. This statement is recursively true. Thus the assertion below.
606
+
607
+ // Computes the final payoff amount. Needs to consider the correction associated with
608
+ // all outstanding principals.
614
609
uint256 payoffCorrection = _feeManager.calcCorrection (
615
610
cr.dueDate,
616
611
_creditRecordStaticMapping[borrower].aprInBps,
617
612
cr.unbilledPrincipal + cr.totalDue - cr.feesAndInterestDue
618
613
);
619
614
620
- bool paidOff = false ;
621
615
uint256 payoffAmount = uint256 (
622
616
int256 (int96 (cr.totalDue + cr.unbilledPrincipal)) + int256 (cr.correction)
623
617
) - payoffCorrection;
624
618
625
- console.log ("In payoffAmount calculation, cr.unbilledPrincipal= " , cr.unbilledPrincipal);
626
- console.log ("cr.totalDue= " , cr.totalDue);
627
- console.logInt (cr.correction);
628
- console.log ("payoffCorrection= " , payoffCorrection);
629
- console.log ("payoffAmount= " , payoffAmount);
630
-
631
- // The amount to be applied towards principal
632
- uint256 principalPayment = 0 ;
619
+ bool paidOff = false ;
633
620
634
621
// The amount to be collected from the borrower. When _amount is more than what is needed
635
622
// for payoff, only the payoff amount will be transferred
636
623
uint256 amountToCollect;
637
624
625
+ // The amount to be applied towards principal
626
+ uint256 principalPayment = 0 ;
627
+
638
628
if (amount < cr.totalDue) {
639
- console.log ("Below totalDue path " );
640
629
amountToCollect = amount;
641
630
cr.totalDue = uint96 (cr.totalDue - amount);
642
631
@@ -646,19 +635,17 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
646
635
principalPayment = amount - cr.feesAndInterestDue;
647
636
cr.feesAndInterestDue = 0 ;
648
637
}
638
+ if (cr.state == BS.CreditState.Defaulted)
639
+ _recoverDefaultedAmount (borrower, amountToCollect);
649
640
} else if (amount < payoffAmount) {
650
- console.log ("below payoff path " );
651
641
amountToCollect = amount;
652
642
653
643
// Apply extra payments towards principal, reduce unbilledPrincipal amount
654
644
cr.unbilledPrincipal -= uint96 (amount - cr.totalDue);
655
645
656
646
principalPayment = amount - cr.feesAndInterestDue;
657
- console.log ("principalPayment= " , principalPayment);
658
647
if (principalPayment > 0 ) {
659
648
// If there is principal payment, calcuate new correction
660
- console.log ("Before updating, cr.correction= " );
661
- console.logInt (cr.correction);
662
649
cr.correction -= int96 (
663
650
uint96 (
664
651
_feeManager.calcCorrection (
@@ -668,57 +655,36 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
668
655
)
669
656
)
670
657
);
671
- console.log ("After updating. " );
672
- console.logInt (cr.correction);
673
658
}
674
659
cr.feesAndInterestDue = 0 ;
675
660
cr.totalDue = 0 ;
676
661
cr.missedPeriods = 0 ;
662
+
663
+ // Moves account to GoodStanding if it was delayed.
677
664
if (cr.state == BS.CreditState.Delayed) cr.state = BS.CreditState.GoodStanding;
665
+
666
+ // Recovers funds to the pool if the account is Defaulted.
667
+ // Only moves it to GoodStanding only after payoff, handled in the payoff branch
668
+ if (cr.state == BS.CreditState.Defaulted)
669
+ _recoverDefaultedAmount (borrower, amountToCollect);
678
670
} else {
671
+ // Payoff logic
679
672
paidOff = true ;
680
673
principalPayment = cr.unbilledPrincipal + cr.totalDue - cr.feesAndInterestDue;
681
674
amountToCollect = payoffAmount;
682
- // Distribut or reverse income to consume outstanding correction.
683
- // Book income with positive correction, i.e., user had drawdown in the past cycle.
684
- // Reverse income with negative correction, i.e., interest for the entire final pay
685
- // period has been booked and distributed, but the user paid off early, thus negative
686
- // correction and income reverse.
687
- cr.correction = cr.correction - int96 (int256 (payoffCorrection));
688
- }
689
675
690
- // For account in default, record the recovered principal for the pool.
691
- // Note: correction only impacts interest amount, thus no impact on recovered principal
692
- if (cr.state == BS.CreditState.Defaulted) {
693
- console.log ("\nIn default recovery flow, principalPayment= " , principalPayment);
694
- console.log ("_totalPoolValue= " , _totalPoolValue);
695
- console.log ("defaultAmount= " , _creditRecordStaticMapping[borrower].defaultAmount);
696
-
697
- uint96 _defaultAmount = _creditRecordStaticMapping[borrower].defaultAmount;
698
-
699
- if (_defaultAmount > 0 ) {
700
- uint256 recoveredPrincipal;
701
- if (_defaultAmount >= amountToCollect) {
702
- recoveredPrincipal = amountToCollect;
703
- } else {
704
- recoveredPrincipal = _defaultAmount;
705
- distributeIncome (amountToCollect - recoveredPrincipal);
706
- }
707
- _totalPoolValue += recoveredPrincipal;
708
- _defaultAmount -= uint96 (recoveredPrincipal);
709
- _creditRecordStaticMapping[borrower].defaultAmount = _defaultAmount;
710
- console.log ("\nAfter adjusting, recoveredPrincipal= " , recoveredPrincipal);
676
+ if (cr.state == BS.CreditState.Defaulted) {
677
+ _recoverDefaultedAmount (borrower, amountToCollect);
711
678
} else {
712
- distributeIncome (amountToCollect);
713
- }
714
-
715
- console.log ("After default logic, _totalPoolValue= " , _totalPoolValue);
716
- }
717
-
718
- if (paidOff) {
719
- console.log ("In payoff flow, before distributeIncome, cr.correction= " );
720
- console.logInt (cr.correction);
721
- if (cr.state != BS.CreditState.Defaulted) {
679
+ // Distribut or reverse income to consume outstanding correction.
680
+ // Positive correction is generated becasue of a drawdown within this period,
681
+ // it is not booked or distributed yet, needs to be distributed.
682
+ // Negative correction is generated because of a payment including principal
683
+ // within this period, the extra interest paid is not accounted for yet, thus
684
+ // a reversal.
685
+ // Note: For defaulted account, we do not distributed fees and interests
686
+ // until they are paid. It is handled in _recoverDefaultedAmount().
687
+ cr.correction = cr.correction - int96 (int256 (payoffCorrection));
722
688
if (cr.correction > 0 ) distributeIncome (uint256 (uint96 (cr.correction)));
723
689
else if (cr.correction < 0 ) reverseIncome (uint256 (uint96 (0 - cr.correction)));
724
690
}
@@ -727,6 +693,7 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
727
693
cr.unbilledPrincipal = 0 ;
728
694
cr.feesAndInterestDue = 0 ;
729
695
cr.totalDue = 0 ;
696
+
730
697
// Closes the credit line if it is in the final period
731
698
if (cr.remainingPeriods == 0 ) {
732
699
cr.state = BS.CreditState.Deleted;
@@ -735,8 +702,6 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
735
702
}
736
703
737
704
_creditRecordMapping[borrower] = cr;
738
- console.log ("\nAfter processing. cr.correction= " );
739
- console.logInt (cr.correction);
740
705
741
706
if (amountToCollect > 0 && isPaymentReceived == false ) {
742
707
// Transfer assets from the _borrower to pool locker
@@ -749,10 +714,36 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
749
714
msg .sender
750
715
);
751
716
}
752
- console.log ("amountToCollect= " , amountToCollect);
753
717
return (amountToCollect, paidOff);
754
718
}
755
719
720
+ /**
721
+ * @notice Recovers amount when a payment is paid towards a defaulted account.
722
+ * @dev For any payment after a default, it is applied towards principal losses first.
723
+ * Only after the principal is fully recovered, it is applied towards fees & interest.
724
+ */
725
+ function _recoverDefaultedAmount (address borrower , uint256 amountToCollect ) internal {
726
+ uint96 _defaultAmount = _creditRecordStaticMapping[borrower].defaultAmount;
727
+
728
+ if (_defaultAmount > 0 ) {
729
+ uint256 recoveredPrincipal;
730
+ if (_defaultAmount >= amountToCollect) {
731
+ recoveredPrincipal = amountToCollect;
732
+ } else {
733
+ recoveredPrincipal = _defaultAmount;
734
+ distributeIncome (amountToCollect - recoveredPrincipal);
735
+ }
736
+ _totalPoolValue += recoveredPrincipal;
737
+ _defaultAmount -= uint96 (recoveredPrincipal);
738
+ _creditRecordStaticMapping[borrower].defaultAmount = _defaultAmount;
739
+ } else {
740
+ // note The account is moved out of Defaulted state only if the entire due
741
+ // including principals, fees&Interest are paid off. It is possible for
742
+ // the account to owe fees&Interest after _defaultAmount becomes zero.
743
+ distributeIncome (amountToCollect);
744
+ }
745
+ }
746
+
756
747
/// Checks if the given amount is higher than what is allowed by the pool
757
748
function _maxCreditLineCheck (uint256 amount ) internal view {
758
749
if (amount > _poolConfig.maxCreditLine ()) {
@@ -796,8 +787,6 @@ contract BaseCreditPool is BasePool, BaseCreditPoolStorage, ICredit {
796
787
797
788
if (periodsPassed > 0 ) {
798
789
// Distribute income
799
- console.log ("before distributeIncome, newCharges= " , newCharges);
800
- console.log ("distributeChargesForLastCycle= " , distributeChargesForLastCycle);
801
790
if (cr.state != BS.CreditState.Defaulted) {
802
791
if (distributeChargesForLastCycle) distributeIncome (newCharges);
803
792
else distributeIncome (newCharges - cr.feesAndInterestDue);
0 commit comments