Skip to content

Commit

Permalink
redo multi-cashflows work
Browse files Browse the repository at this point in the history
  • Loading branch information
lemunozm committed Jul 18, 2023
1 parent a3bd197 commit bb9ae51
Show file tree
Hide file tree
Showing 6 changed files with 345 additions and 11 deletions.
25 changes: 21 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions pallets/loans/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ cfg-types = { path = "../../libs/types", default-features = false }
orml-traits = { git = "https://github.com/open-web3-stack/open-runtime-module-library", default-features = false, branch = "polkadot-v0.9.38" }

strum = { version = "0.24", default-features = false, features = ["derive"] }
chrono = { version = "0.4", default-features = false }
chronoutil = "0.2"

# Optionals for benchmarking
frame-benchmarking = { git = "https://github.com/paritytech/substrate", default-features = false, optional = true, branch = "polkadot-v0.9.38" }
Expand Down Expand Up @@ -63,6 +65,7 @@ std = [
"sp-io/std",
"strum/std",
"orml-traits/std",
"chrono/std",
]
runtime-benchmarks = [
"frame-benchmarking",
Expand Down
53 changes: 49 additions & 4 deletions pallets/loans/src/entities/loans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,12 @@ impl<T: Config> ActiveLoan<T> {
&self.pricing
}

pub fn principal(&self) -> Result<T::Balance, DispatchError> {
Ok(self
.total_borrowed
.ensure_sub(self.total_repaid.principal)?)
}

pub fn write_off_status(&self) -> WriteOffStatus<T::Rate> {
WriteOffStatus {
percentage: self.write_off_percentage,
Expand Down Expand Up @@ -241,6 +247,35 @@ impl<T: Config> ActiveLoan<T> {
}
ActivePricing::Internal(_) => Ok(false),
},
WriteOffTrigger::InterestOverdue(_overdue_seconds) => match &self.pricing {
// TODO: should be implemented once interest_rate is moved to ActiveLoan
ActivePricing::External(_) => Ok(false),
ActivePricing::Internal(pricing) => {
let cashflows = self.schedule.generate_expected_cashflows(
self.origination_date,
self.principal()?,
&pricing.interest.rate(),
)?;

// TODO(Luis): If from this point, any field of ActiveLoan is needed, I would
// move this code into cashflow.rs

/*
let now_date = NaiveDateTime::from_timestamp_opt(now as i64, 0)
.ok_or(DispatchError::Other("Invalid now date"))?;
let cashflows_in_past = cashflows
.iter()
.filter(|(d, _)| d.and_hms_opt(0, 0, 0).unwrap() > now_date);
*/

// TODO: should find the first cashflow that was not paid,
// based on total_repaid_interest and by reducing the cashflows_in_past
// from this, and should the ncompare the first cash flow that was not paid date
// with now - overdue_secs.

Ok(false)
}
},
}
}

Expand Down Expand Up @@ -313,6 +348,19 @@ impl<T: Config> ActiveLoan<T> {
Error::<T>::from(BorrowLoanError::MaturityDatePassed)
);

// If the loan has an interest or pay down schedule other than None,
// then we should only allow borrowing more if no interest or principal
// payments are overdue.
//
// This is required because after borrowing more, it is not possible
// to validate anymore whether previous cashflows matched the repayment
// schedule, as we don't store historic data of the principal.
//
// Therefore, in `borrow()` we set repayments_on_schedule_until to now.
//
// TODO: check total_repaid_interest >= total_expected_interest
// and total_repaid_principal >= total_expected_principal

Ok(())
}

Expand Down Expand Up @@ -347,10 +395,7 @@ impl<T: Config> ActiveLoan<T> {
let (interest_accrued, max_repay_principal) = match &self.pricing {
ActivePricing::Internal(inner) => {
amount.principal.internal()?;

let principal = self
.total_borrowed
.ensure_sub(self.total_repaid.principal)?;
let principal = self.principal()?;

(inner.current_interest(principal)?, principal)
}
Expand Down
Loading

0 comments on commit bb9ae51

Please sign in to comment.