diff --git a/pallets/loans/src/entities/loans.rs b/pallets/loans/src/entities/loans.rs index 20344370f6..a6659da785 100644 --- a/pallets/loans/src/entities/loans.rs +++ b/pallets/loans/src/entities/loans.rs @@ -14,7 +14,7 @@ use sp_runtime::{ }, DispatchError, }; -use sp_std::collections::btree_map::BTreeMap; +use sp_std::{cmp::min, collections::btree_map::BTreeMap}; use crate::{ entities::{ @@ -359,7 +359,8 @@ impl ActiveLoan { inner.adjust(Adjustment::Increase(amount.balance()?))? } ActivePricing::External(inner) => { - inner.adjust(Adjustment::Increase(amount.external()?), Zero::zero())? + let when = T::Time::now(); + inner.adjust(Adjustment::Increase(amount.external()?), Zero::zero(), when)? } } @@ -433,7 +434,8 @@ impl ActiveLoan { } ActivePricing::External(inner) => { let principal = amount.principal.external()?; - inner.adjust(Adjustment::Decrease(principal), amount.interest)?; + let when = min(T::Time::now(), self.schedule.maturity.date()); + inner.adjust(Adjustment::Decrease(principal), amount.interest, when)?; } } diff --git a/pallets/loans/src/entities/pricing/external.rs b/pallets/loans/src/entities/pricing/external.rs index c9070c1fae..c3d10d7b0d 100644 --- a/pallets/loans/src/entities/pricing/external.rs +++ b/pallets/loans/src/entities/pricing/external.rs @@ -143,6 +143,10 @@ impl ExternalActivePricing { self.info.price_id } + pub fn settlement_price_updated(&self) -> Seconds { + self.settlement_price_updated + } + pub fn has_registered_price(&self, pool_id: T::PoolId) -> bool { T::PriceRegistry::get(&self.info.price_id, &pool_id).is_ok() } @@ -298,6 +302,7 @@ impl ExternalActivePricing { &mut self, amount_adj: Adjustment>, interest: T::Balance, + when: Seconds, ) -> DispatchResult { self.outstanding_quantity = amount_adj .clone() @@ -313,7 +318,7 @@ impl ExternalActivePricing { self.interest.adjust_debt(interest_adj)?; self.latest_settlement_price = amount_adj.abs().settlement_price; - self.settlement_price_updated = T::Time::now(); + self.settlement_price_updated = when; Ok(()) } diff --git a/pallets/loans/src/tests/repay_loan.rs b/pallets/loans/src/tests/repay_loan.rs index 1f76f922b2..d72d4f1d58 100644 --- a/pallets/loans/src/tests/repay_loan.rs +++ b/pallets/loans/src/tests/repay_loan.rs @@ -812,3 +812,41 @@ fn with_unregister_price_id_and_oracle_not_required() { ); }); } + +#[test] +fn with_external_pricing_and_overdue() { + new_test_ext().execute_with(|| { + let loan_id = util::create_loan(LoanInfo { + ..util::base_external_loan() + }); + + let amount = ExternalAmount::new(QUANTITY, PRICE_VALUE); + util::borrow_loan(loan_id, PrincipalInput::External(amount)); + + // The loan is overdue + advance_time(YEAR * 2); + + let amount = ExternalAmount::new(QUANTITY, PRICE_VALUE); + config_mocks(amount.balance().unwrap()); + assert_ok!(Loans::repay( + RuntimeOrigin::signed(BORROWER), + POOL_A, + loan_id, + RepaidInput { + principal: PrincipalInput::External(amount), + interest: 0, + unscheduled: 0, + }, + )); + + let active_loan = util::get_loan(loan_id); + + let settlement_price_updated = match active_loan.pricing() { + ActivePricing::External(inner) => inner.settlement_price_updated(), + _ => unreachable!(), + }; + + // We must never overpass madurity date + assert_eq!(active_loan.maturity_date(), settlement_price_updated); + }); +}