1#include <xrpld/app/misc/LendingHelpers.h>
3#include <xrpld/app/tx/detail/VaultCreate.h>
19 "xrpl::LoanPaymentParts::operator+= : other principal "
23 "xrpl::LoanPaymentParts::operator+= : other interest paid "
27 "xrpl::LoanPaymentParts::operator+= : other fee paid "
86 return power(1 + periodicRate, paymentsRemaining);
97 if (paymentsRemaining == 0)
101 if (periodicRate == beast::zero)
102 return Number{1} / paymentsRemaining;
106 return (periodicRate * raisedRate) / (raisedRate - 1);
117 if (principalOutstanding == 0 || paymentsRemaining == 0)
121 if (periodicRate == beast::zero)
122 return principalOutstanding / paymentsRemaining;
134 Number const& periodicPayment,
135 Number const& periodicRate,
138 if (paymentsRemaining == 0)
141 if (periodicRate == 0)
142 return periodicPayment * paymentsRemaining;
171 Number const& principalOutstanding,
176 if (principalOutstanding == beast::zero)
186 if (now <= nextPaymentDueDate)
190 auto const secondsOverdue = now - nextPaymentDueDate;
194 return principalOutstanding * rate;
204 Number const& principalOutstanding,
205 Number const& periodicRate,
211 if (periodicRate == beast::zero)
214 if (paymentInterval == 0)
217 auto const lastPaymentDate =
std::max(prevPaymentDate, startDate);
222 if (now <= lastPaymentDate)
226 auto const secondsSinceLastPayment = now - lastPaymentDate;
231 return principalOutstanding * periodicRate * secondsSinceLastPayment / paymentInterval;
243template <
class NumberProxy,
class UInt32Proxy,
class UInt32OptionalProxy>
247 NumberProxy& totalValueOutstandingProxy,
248 NumberProxy& principalOutstandingProxy,
249 NumberProxy& managementFeeOutstandingProxy,
250 UInt32Proxy& paymentRemainingProxy,
251 UInt32Proxy& prevPaymentDateProxy,
252 UInt32OptionalProxy& nextDueDateProxy,
255 XRPL_ASSERT_PARTS(nextDueDateProxy,
"xrpl::detail::doPayment",
"Next due date proxy set");
261 "xrpl::detail::doPayment",
262 "Full principal payment");
264 totalValueOutstandingProxy == payment.
trackedValueDelta,
"xrpl::detail::doPayment",
"Full value payment");
267 "xrpl::detail::doPayment",
268 "Full management fee payment");
271 paymentRemainingProxy = 0;
274 prevPaymentDateProxy = *nextDueDateProxy;
278 nextDueDateProxy = 0;
283 principalOutstandingProxy = 0;
284 totalValueOutstandingProxy = 0;
285 managementFeeOutstandingProxy = 0;
292 paymentRemainingProxy -= 1;
294 prevPaymentDateProxy = nextDueDateProxy;
295 nextDueDateProxy += paymentInterval;
299 "xrpl::detail::doPayment",
300 "Partial principal payment");
302 totalValueOutstandingProxy > payment.
trackedValueDelta,
"xrpl::detail::doPayment",
"Partial value payment");
307 "xrpl::detail::doPayment",
308 "Valid management fee");
320 static_cast<Number>(principalOutstandingProxy) <=
static_cast<Number>(totalValueOutstandingProxy),
321 "xrpl::detail::doPayment",
322 "principal does not exceed total");
327 static_cast<Number>(managementFeeOutstandingProxy) >= beast::zero,
328 "xrpl::detail::doPayment",
329 "fee outstanding stays valid");
366 Number const& periodicPayment,
367 Number const& periodicRate,
373 auto const theoreticalState =
380 auto const errors = roundedOldState - theoreticalState;
384 auto const newTheoreticalPrincipal =
391 asset, newTheoreticalPrincipal, periodicRate, paymentRemaining, managementFeeRate, loanScale);
393 JLOG(j.
debug()) <<
"new periodic payment: " << newLoanProperties.periodicPayment
394 <<
", new total value: " << newLoanProperties.loanState.valueOutstanding
395 <<
", first payment principal: " << newLoanProperties.firstPaymentPrincipal;
399 auto const newTheoreticalState =
401 newLoanProperties.periodicPayment, periodicRate, paymentRemaining, managementFeeRate) +
404 JLOG(j.
debug()) <<
"new theoretical value: " << newTheoreticalState.valueOutstanding
405 <<
", principal: " << newTheoreticalState.principalOutstanding
406 <<
", interest gross: " << newTheoreticalState.interestOutstanding();
415 auto const totalValueOutstanding =
std::clamp(
417 asset, principalOutstanding + newTheoreticalState.interestOutstanding(), loanScale,
Number::upward),
420 auto const managementFeeOutstanding =
std::clamp(
421 roundToAsset(asset, newTheoreticalState.managementFeeDue, loanScale),
425 auto const roundedNewState =
426 constructLoanState(totalValueOutstanding, principalOutstanding, managementFeeOutstanding);
430 newLoanProperties.loanState = roundedNewState;
432 JLOG(j.
debug()) <<
"new rounded value: " << roundedNewState.valueOutstanding
433 <<
", principal: " << roundedNewState.principalOutstanding
434 <<
", interest gross: " << roundedNewState.interestOutstanding();
439 principalOutstanding,
444 roundedNewState.interestOutstanding() != beast::zero,
449 JLOG(j.
warn()) <<
"Principal overpayment would cause the loan to be in "
450 "an invalid state. Ignore the overpayment";
457 if (newLoanProperties.periodicPayment <= 0 || newLoanProperties.loanState.valueOutstanding <= 0 ||
458 newLoanProperties.loanState.managementFeeDue < 0)
461 JLOG(j.
warn()) <<
"Overpayment not allowed: Computed loan "
462 "properties are invalid. Does "
463 "not compute. TotalValueOutstanding: "
464 << newLoanProperties.loanState.valueOutstanding
465 <<
", PeriodicPayment : " << newLoanProperties.periodicPayment
466 <<
", ManagementFeeOwedToBroker: " << newLoanProperties.loanState.managementFeeDue;
471 auto const deltas = roundedOldState - roundedNewState;
476 deltas.managementFee == roundedOldState.
managementFeeDue - managementFeeOutstanding,
477 "xrpl::detail::tryOverpayment",
487 auto const valueChange = -deltas.interest;
490 JLOG(j.
warn()) <<
"Principal overpayment would increase the value of "
491 "the loan. Ignore the overpayment";
523template <
class NumberProxy>
529 NumberProxy& totalValueOutstandingProxy,
530 NumberProxy& principalOutstandingProxy,
531 NumberProxy& managementFeeOutstandingProxy,
532 NumberProxy& periodicPaymentProxy,
533 Number const& periodicRate,
538 auto const loanState =
539 constructLoanState(totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy);
540 auto const periodicPayment = periodicPaymentProxy;
541 JLOG(j.
debug()) <<
"overpayment components:"
542 <<
", totalValue before: " << *totalValueOutstandingProxy
548 <<
", totalDue: " << overpaymentComponents.
totalDue <<
", payments remaining :" << paymentRemaining;
555 overpaymentComponents,
565 auto const& [loanPaymentParts, newLoanProperties] = *ret;
566 auto const newRoundedLoanState = newLoanProperties.loanState;
571 if (principalOutstandingProxy <= newRoundedLoanState.principalOutstanding)
574 JLOG(j.
warn()) <<
"Overpayment not allowed: principal "
575 <<
"outstanding did not decrease. Before: " << *principalOutstandingProxy
576 <<
". After: " << newRoundedLoanState.principalOutstanding;
587 principalOutstandingProxy - newRoundedLoanState.principalOutstanding,
588 "xrpl::detail::doOverpayment",
589 "principal change agrees");
594 JLOG(j.
debug()) <<
"valueChange: " << loanPaymentParts.valueChange
595 <<
", totalValue before: " << *totalValueOutstandingProxy
596 <<
", totalValue after: " << newRoundedLoanState.valueOutstanding
597 <<
", totalValue delta: " << (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding)
599 <<
", principalPaid: " << loanPaymentParts.principalPaid <<
", Computed difference: "
601 (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding);
604 loanPaymentParts.valueChange ==
605 newRoundedLoanState.valueOutstanding -
608 "xrpl::detail::doOverpayment",
609 "interest paid agrees");
613 "xrpl::detail::doOverpayment",
614 "principal payment matches");
618 totalValueOutstandingProxy = newRoundedLoanState.valueOutstanding;
619 principalOutstandingProxy = newRoundedLoanState.principalOutstanding;
620 managementFeeOutstandingProxy = newRoundedLoanState.managementFeeDue;
621 periodicPaymentProxy = newLoanProperties.periodicPayment;
623 return loanPaymentParts;
643 Number const& principalOutstanding,
648 Number const& latePaymentFee,
659 auto const latePaymentInterest =
665 auto const [roundedLateInterest, roundedLateManagementFee] = [&]() {
666 auto const interest =
roundToAsset(asset, latePaymentInterest, loanScale);
670 XRPL_ASSERT(roundedLateInterest >= 0,
"xrpl::detail::computeLatePayment : valid late interest");
673 "xrpl::detail::computeLatePayment",
674 "no extra parts to this payment");
697 isRounded(asset,
late.totalDue, loanScale),
"xrpl::detail::computeLatePayment",
"total due is rounded");
702 if (amount <
late.totalDue)
704 JLOG(j.
warn()) <<
"Late loan payment amount is insufficient. Due: " <<
late.totalDue <<
", paid: " << amount;
734 Number const& principalOutstanding,
735 Number const& managementFeeOutstanding,
736 Number const& periodicPayment,
743 Number const& totalInterestOutstanding,
744 Number const& periodicRate,
745 Number const& closePaymentFee,
751 if (paymentRemaining <= 1)
754 JLOG(j.
warn()) <<
"Last payment cannot be a full payment.";
761 Number const theoreticalPrincipalOutstanding =
767 theoreticalPrincipalOutstanding,
777 auto const [roundedFullInterest, roundedFullManagementFee] = [&]() {
787 .
trackedValueDelta = principalOutstanding + totalInterestOutstanding + managementFeeOutstanding,
788 .trackedPrincipalDelta = principalOutstanding,
792 .trackedManagementFeeDelta = managementFeeOutstanding,
803 closePaymentFee + roundedFullManagementFee - managementFeeOutstanding,
812 roundedFullInterest - totalInterestOutstanding,
816 isRounded(asset,
full.totalDue, loanScale),
"xrpl::detail::computeFullPayment",
"total due is rounded");
818 JLOG(j.
trace()) <<
"computeFullPayment result: periodicPayment: " << periodicPayment
819 <<
", periodicRate: " << periodicRate <<
", paymentRemaining: " << paymentRemaining
820 <<
", theoreticalPrincipalOutstanding: " << theoreticalPrincipalOutstanding
821 <<
", fullPaymentInterest: " << fullPaymentInterest
822 <<
", roundedFullInterest: " << roundedFullInterest
823 <<
", roundedFullManagementFee: " << roundedFullManagementFee
824 <<
", untrackedInterest: " <<
full.untrackedInterest;
826 if (amount <
full.totalDue)
862 Number const& totalValueOutstanding,
863 Number const& principalOutstanding,
864 Number const& managementFeeOutstanding,
865 Number const& periodicPayment,
866 Number const& periodicRate,
871 isRounded(asset, totalValueOutstanding, scale) &&
isRounded(asset, principalOutstanding, scale) &&
872 isRounded(asset, managementFeeOutstanding, scale),
873 "xrpl::detail::computePaymentComponents",
874 "Outstanding values are rounded");
875 XRPL_ASSERT_PARTS(paymentRemaining > 0,
"xrpl::detail::computePaymentComponents",
"some payments remaining");
881 if (paymentRemaining == 1 || totalValueOutstanding <= roundedPeriodicPayment)
887 .trackedPrincipalDelta = principalOutstanding,
888 .trackedManagementFeeDelta = managementFeeOutstanding,
907 constructLoanState(totalValueOutstanding, principalOutstanding, managementFeeOutstanding);
920 "xrpl::detail::computePaymentComponents",
921 "principal delta not greater than outstanding");
928 "xrpl::detail::computePaymentComponents",
929 "interest due delta not greater than outstanding");
940 "xrpl::detail::computePaymentComponents",
941 "management fee due delta not greater than outstanding");
955 if (excess > beast::zero)
957 auto part =
std::min(component, excess);
961 XRPL_ASSERT_PARTS(excess >= beast::zero,
"xrpl::detail::computePaymentComponents",
"excess non-negative");
977 if (totalOverpayment > beast::zero)
981 "xrpl::detail::computePaymentComponents : payment exceeded loan "
983 addressExcess(deltas, totalOverpayment);
988 Number shortage = roundedPeriodicPayment - deltas.
total();
991 isRounded(asset, shortage, scale),
"xrpl::detail::computePaymentComponents",
"shortage is rounded");
993 if (shortage < beast::zero)
996 Number excess = -shortage;
997 addressExcess(deltas, excess);
1004 XRPL_ASSERT_PARTS(shortage >= beast::zero,
"xrpl::detail::computePaymentComponents",
"no shortage or excess");
1009 "xrpl::detail::computePaymentComponents",
1010 "total value adds up");
1014 "xrpl::detail::computePaymentComponents",
1015 "valid principal result");
1018 "xrpl::detail::computePaymentComponents",
1019 "valid interest result");
1022 "xrpl::detail::computePaymentComponents",
1023 "valid fee result");
1027 "xrpl::detail::computePaymentComponents",
1028 "payment parts add to payment");
1056ExtendedPaymentComponents
1059 int32_t
const loanScale,
1067 "xrpl::detail::computeOverpaymentComponents : valid overpayment "
1079 auto const [roundedOverpaymentInterest, roundedOverpaymentManagementFee] = [&]() {
1090 .trackedPrincipalDelta =
1091 overpayment - roundedOverpaymentInterest - roundedOverpaymentManagementFee - overpaymentFee,
1092 .trackedManagementFeeDelta = roundedOverpaymentManagementFee,
1101 roundedOverpaymentInterest};
1103 result.trackedInterestPart() == roundedOverpaymentInterest,
1104 "xrpl::detail::computeOverpaymentComponents",
1105 "valid interest computation");
1111detail::LoanStateDeltas
1151 Asset const& vaultAsset,
1152 Number const& principalRequested,
1153 bool expectInterest,
1162 if (expectInterest && totalInterestOutstanding <= 0)
1166 JLOG(j.
warn()) <<
"Loan for " << principalRequested <<
" with interest has no interest due";
1171 if (!expectInterest && totalInterestOutstanding > 0)
1174 JLOG(j.
warn()) <<
"Loan for " << principalRequested <<
" with no interest has interest due";
1188 JLOG(j.
warn()) <<
"Loan is unable to pay principal.";
1196 if (roundedPayment == beast::zero)
1198 JLOG(j.
warn()) <<
"Loan Periodic payment (" << properties.
periodicPayment <<
") rounds to 0. ";
1209 computedPayments != paymentTotal)
1211 JLOG(j.
warn()) <<
"Loan Periodic payment (" << properties.
periodicPayment <<
") rounding ("
1213 <<
" can not complete the loan in the specified "
1214 "number of payments ("
1215 << computedPayments <<
" != " << paymentTotal <<
")";
1230 Number const& theoreticalPrincipalOutstanding,
1231 Number const& periodicRate,
1239 theoreticalPrincipalOutstanding, periodicRate, parentCloseTime, startDate, prevPaymentDate, paymentInterval);
1241 accruedInterest >= 0,
1242 "xrpl::detail::computeFullPaymentInterest : valid accrued "
1246 auto const prepaymentPenalty = closeInterestRate == beast::zero
1251 prepaymentPenalty >= 0,
1252 "xrpl::detail::computeFullPaymentInterest : valid prepayment "
1256 return accruedInterest + prepaymentPenalty;
1283 Number const& periodicPayment,
1284 Number const& periodicRate,
1288 if (paymentRemaining == 0)
1294 Number const totalValueOutstanding = periodicPayment * paymentRemaining;
1296 Number const principalOutstanding =
1300 Number const interestOutstandingGross = totalValueOutstanding - principalOutstanding;
1306 Number const interestOutstandingNet = interestOutstandingGross - managementFeeOutstanding;
1310 .principalOutstanding = principalOutstanding,
1311 .interestDue = interestOutstandingNet,
1312 .managementFeeDue = managementFeeOutstanding,
1338 Number const& totalValueOutstanding,
1339 Number const& principalOutstanding,
1340 Number const& managementFeeOutstanding)
1346 .principalOutstanding = principalOutstanding,
1347 .interestDue = totalValueOutstanding - principalOutstanding - managementFeeOutstanding,
1348 .managementFeeDue = managementFeeOutstanding};
1355 loan->at(sfTotalValueOutstanding), loan->at(sfPrincipalOutstanding), loan->at(sfManagementFeeOutstanding));
1381 Number const& principalOutstanding,
1389 XRPL_ASSERT(interestRate == 0 || periodicRate > 0,
"xrpl::computeLoanProperties : valid rate");
1391 asset, principalOutstanding, periodicRate, paymentsRemaining, managementFeeRate, minimumScale);
1405 Number const& principalOutstanding,
1406 Number const& periodicRate,
1413 auto const [totalValueOutstanding, loanScale] = [&]() {
1421 STAmount amount{asset, periodicPayment * paymentsRemaining};
1426 auto const loanScale =
std::max(minimumScale, amount.exponent());
1428 (amount.integral() && loanScale == 0) ||
1429 (!amount.integral() && loanScale >=
static_cast<Number>(amount).
exponent()),
1430 "xrpl::computeLoanProperties",
1431 "loanScale value fits expectations");
1446 auto const totalInterestOutstanding = totalValueOutstanding - roundedPrincipalOutstanding;
1447 auto const feeOwedToBroker =
computeManagementFee(asset, totalInterestOutstanding, managementFeeRate, loanScale);
1452 auto const firstPaymentPrincipal = [&]() {
1455 auto const startingState =
1458 auto const firstPaymentState =
1463 return startingState.principalOutstanding - firstPaymentState.principalOutstanding;
1468 .loanState =
constructLoanState(totalValueOutstanding, roundedPrincipalOutstanding, feeOwedToBroker),
1469 .loanScale = loanScale,
1470 .firstPaymentPrincipal = firstPaymentPrincipal,
1480Expected<LoanPaymentParts, TER>
1490 using namespace Lending;
1492 auto principalOutstandingProxy = loan->at(sfPrincipalOutstanding);
1493 auto paymentRemainingProxy = loan->at(sfPaymentRemaining);
1495 if (paymentRemainingProxy == 0 || principalOutstandingProxy == 0)
1499 JLOG(j.
warn()) <<
"Loan is already paid off.";
1504 auto totalValueOutstandingProxy = loan->at(sfTotalValueOutstanding);
1505 auto managementFeeOutstandingProxy = loan->at(sfManagementFeeOutstanding);
1508 auto nextDueDateProxy = loan->at(sfNextPaymentDueDate);
1509 if (*nextDueDateProxy == 0)
1511 JLOG(j.
warn()) <<
"Loan next payment due date is not set.";
1517 TenthBips32 const interestRate{loan->at(sfInterestRate)};
1519 Number const serviceFee = loan->at(sfLoanServiceFee);
1520 TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)};
1522 Number const periodicPayment = loan->at(sfPeriodicPayment);
1524 auto prevPaymentDateProxy = loan->at(sfPreviousPaymentDueDate);
1527 std::uint32_t const paymentInterval = loan->at(sfPaymentInterval);
1532 XRPL_ASSERT(interestRate == 0 || periodicRate > 0,
"xrpl::loanMakePayment : valid rate");
1534 XRPL_ASSERT(*totalValueOutstandingProxy > 0,
"xrpl::loanMakePayment : valid total value");
1544 JLOG(j.
warn()) <<
"Loan payment is overdue. Use the tfLoanLatePayment "
1546 "flag to make a late payment. Loan was created on "
1547 << startDate <<
", prev payment due date is " << prevPaymentDateProxy
1548 <<
", next payment due date is " << nextDueDateProxy <<
", ledger time is "
1557 TenthBips32 const closeInterestRate{loan->at(sfCloseInterestRate)};
1558 Number const closePaymentFee =
roundToAsset(asset, loan->at(sfClosePaymentFee), loanScale);
1561 constructLoanState(totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy);
1566 principalOutstandingProxy,
1567 managementFeeOutstandingProxy,
1569 paymentRemainingProxy,
1570 prevPaymentDateProxy,
1583 *fullPaymentComponents,
1584 totalValueOutstandingProxy,
1585 principalOutstandingProxy,
1586 managementFeeOutstandingProxy,
1587 paymentRemainingProxy,
1588 prevPaymentDateProxy,
1592 else if (fullPaymentComponents.error())
1596 return Unexpected(fullPaymentComponents.error());
1599 UNREACHABLE(
"xrpl::loanMakePayment : invalid full payment result");
1600 JLOG(j.
error()) <<
"Full payment computation failed unexpectedly.";
1612 totalValueOutstandingProxy,
1613 principalOutstandingProxy,
1614 managementFeeOutstandingProxy,
1617 paymentRemainingProxy,
1620 XRPL_ASSERT_PARTS(periodic.trackedPrincipalDelta >= 0,
"xrpl::loanMakePayment",
"regular payment valid principal");
1626 TenthBips32 const lateInterestRate{loan->at(sfLateInterestRate)};
1627 Number const latePaymentFee = loan->at(sfLatePaymentFee);
1632 principalOutstandingProxy,
1643 *latePaymentComponents,
1644 totalValueOutstandingProxy,
1645 principalOutstandingProxy,
1646 managementFeeOutstandingProxy,
1647 paymentRemainingProxy,
1648 prevPaymentDateProxy,
1652 else if (latePaymentComponents.error())
1656 return Unexpected(latePaymentComponents.error());
1660 UNREACHABLE(
"xrpl::loanMakePayment : invalid late payment result");
1661 JLOG(j.
error()) <<
"Late payment computation failed unexpectedly.";
1671 "xrpl::loanMakePayment",
1672 "regular payment type");
1679 while ((amount >= (totalPaid + periodic.totalDue)) && paymentRemainingProxy > 0 &&
1680 numPayments < loanMaximumPaymentsPerTransaction)
1684 periodic.trackedPrincipalDelta >= 0,
"xrpl::loanMakePayment",
"payment pays non-negative principal");
1686 totalPaid += periodic.totalDue;
1689 totalValueOutstandingProxy,
1690 principalOutstandingProxy,
1691 managementFeeOutstandingProxy,
1692 paymentRemainingProxy,
1693 prevPaymentDateProxy,
1700 "xrpl::loanMakePayment",
1701 "final payment is the final payment");
1711 totalValueOutstandingProxy,
1712 principalOutstandingProxy,
1713 managementFeeOutstandingProxy,
1716 paymentRemainingProxy,
1721 if (numPayments == 0)
1723 JLOG(j.
warn()) <<
"Regular loan payment amount is insufficient. Due: " << periodic.totalDue
1724 <<
", paid: " << amount;
1730 "xrpl::loanMakePayment",
1731 "payment parts add up");
1732 XRPL_ASSERT_PARTS(totalParts.
valueChange == 0,
"xrpl::loanMakePayment",
"no value change");
1737 totalPaid < amount && numPayments < loanMaximumPaymentsPerTransaction)
1739 TenthBips32 const overpaymentInterestRate{loan->at(sfOverpaymentInterestRate)};
1740 TenthBips32 const overpaymentFeeRate{loan->at(sfOverpaymentFee)};
1748 asset, loanScale,
overpayment, overpaymentInterestRate, overpaymentFeeRate, managementFeeRate);
1756 "xrpl::loanMakePayment",
1757 "overpayment penalty did not reduce value of loan");
1760 auto periodicPaymentProxy = loan->at(sfPeriodicPayment);
1764 overpaymentComponents,
1765 totalValueOutstandingProxy,
1766 principalOutstandingProxy,
1767 managementFeeOutstandingProxy,
1768 periodicPaymentProxy,
1770 paymentRemainingProxy,
1773 totalParts += *overResult;
1774 else if (overResult.error())
1787 "xrpl::loanMakePayment : total principal paid is valid");
1790 "xrpl::loanMakePayment : total interest paid is valid");
1792 isRounded(asset, totalParts.
valueChange, loanScale),
"xrpl::loanMakePayment : loan value change is valid");
1795 "xrpl::loanMakePayment : fee paid is valid");
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
Writeable view to a ledger, for applying a transaction.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
Number is a floating point type that can represent a wide range of values.
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
static bool checkExtraFeatures(PreflightContext const &ctx)
PaymentComponents computePaymentComponents(Asset const &asset, std::int32_t scale, Number const &totalValueOutstanding, Number const &principalOutstanding, Number const &managementFeeOutstanding, Number const &periodicPayment, Number const &periodicRate, std::uint32_t paymentRemaining, TenthBips16 managementFeeRate)
Expected< ExtendedPaymentComponents, TER > computeFullPayment(Asset const &asset, ApplyView &view, Number const &principalOutstanding, Number const &managementFeeOutstanding, Number const &periodicPayment, std::uint32_t paymentRemaining, std::uint32_t prevPaymentDate, std::uint32_t const startDate, std::uint32_t const paymentInterval, TenthBips32 const closeInterestRate, std::int32_t loanScale, Number const &totalInterestOutstanding, Number const &periodicRate, Number const &closePaymentFee, STAmount const &amount, TenthBips16 managementFeeRate, beast::Journal j)
Number computeRaisedRate(Number const &periodicRate, std::uint32_t paymentsRemaining)
Number loanPeriodicPayment(Number const &principalOutstanding, Number const &periodicRate, std::uint32_t paymentsRemaining)
ExtendedPaymentComponents computeOverpaymentComponents(Asset const &asset, int32_t const loanScale, Number const &overpayment, TenthBips32 const overpaymentInterestRate, TenthBips32 const overpaymentFeeRate, TenthBips16 const managementFeeRate)
Expected< LoanPaymentParts, TER > doOverpayment(Asset const &asset, std::int32_t loanScale, ExtendedPaymentComponents const &overpaymentComponents, NumberProxy &totalValueOutstandingProxy, NumberProxy &principalOutstandingProxy, NumberProxy &managementFeeOutstandingProxy, NumberProxy &periodicPaymentProxy, Number const &periodicRate, std::uint32_t const paymentRemaining, TenthBips16 const managementFeeRate, beast::Journal j)
Expected< ExtendedPaymentComponents, TER > computeLatePayment(Asset const &asset, ApplyView const &view, Number const &principalOutstanding, std::int32_t nextDueDate, ExtendedPaymentComponents const &periodic, TenthBips32 lateInterestRate, std::int32_t loanScale, Number const &latePaymentFee, STAmount const &amount, TenthBips16 managementFeeRate, beast::Journal j)
Number loanAccruedInterest(Number const &principalOutstanding, Number const &periodicRate, NetClock::time_point parentCloseTime, std::uint32_t startDate, std::uint32_t prevPaymentDate, std::uint32_t paymentInterval)
std::pair< Number, Number > computeInterestAndFeeParts(Asset const &asset, Number const &interest, TenthBips16 managementFeeRate, std::int32_t loanScale)
Number loanLatePaymentInterest(Number const &principalOutstanding, TenthBips32 lateInterestRate, NetClock::time_point parentCloseTime, std::uint32_t nextPaymentDueDate)
Number computePaymentFactor(Number const &periodicRate, std::uint32_t paymentsRemaining)
Number loanPrincipalFromPeriodicPayment(Number const &periodicPayment, Number const &periodicRate, std::uint32_t paymentsRemaining)
Expected< std::pair< LoanPaymentParts, LoanProperties >, TER > tryOverpayment(Asset const &asset, std::int32_t loanScale, ExtendedPaymentComponents const &overpaymentComponents, LoanState const &roundedOldState, Number const &periodicPayment, Number const &periodicRate, std::uint32_t paymentRemaining, TenthBips16 const managementFeeRate, beast::Journal j)
LoanPaymentParts doPayment(ExtendedPaymentComponents const &payment, NumberProxy &totalValueOutstandingProxy, NumberProxy &principalOutstandingProxy, NumberProxy &managementFeeOutstandingProxy, UInt32Proxy &paymentRemainingProxy, UInt32Proxy &prevPaymentDateProxy, UInt32OptionalProxy &nextDueDateProxy, std::uint32_t paymentInterval)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Number loanPeriodicRate(TenthBips32 interestRate, std::uint32_t paymentInterval)
Number computeManagementFee(Asset const &asset, Number const &value, TenthBips32 managementFeeRate, std::int32_t scale)
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Number operator-(Number const &x, Number const &y)
static constexpr Number numZero
constexpr T tenthBipsOfValue(T value, TenthBips< TBips > bips)
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
bool checkLendingProtocolDependencies(PreflightContext const &ctx)
static constexpr std::uint32_t secondsInYear
LoanState computeTheoreticalLoanState(Number const &periodicPayment, Number const &periodicRate, std::uint32_t const paymentRemaining, TenthBips32 const managementFeeRate)
Number power(Number const &f, unsigned n)
TER checkLoanGuards(Asset const &vaultAsset, Number const &principalRequested, bool expectInterest, std::uint32_t paymentTotal, LoanProperties const &properties, beast::Journal j)
TERSubset< CanCvtToTER > TER
Expected< LoanPaymentParts, TER > loanMakePayment(Asset const &asset, ApplyView &view, SLE::ref loan, SLE::const_ref brokerSle, STAmount const &amount, LoanPaymentType const paymentType, beast::Journal j)
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
Number roundPeriodicPayment(Asset const &asset, Number const &periodicPayment, std::int32_t scale)
Ensure the periodic payment is always rounded consistently.
LoanState constructRoundedLoanState(SLE::const_ref loan)
@ tecINSUFFICIENT_PAYMENT
LoanProperties computeLoanProperties(Asset const &asset, Number const &principalOutstanding, TenthBips32 interestRate, std::uint32_t paymentInterval, std::uint32_t paymentsRemaining, TenthBips32 managementFeeRate, std::int32_t minimumScale)
LoanState constructLoanState(Number const &totalValueOutstanding, Number const &principalOutstanding, Number const &managementFeeOutstanding)
Number computeFullPaymentInterest(Number const &theoreticalPrincipalOutstanding, Number const &periodicRate, NetClock::time_point parentCloseTime, std::uint32_t paymentInterval, std::uint32_t prevPaymentDate, std::uint32_t startDate, TenthBips32 closeInterestRate)
bool isRounded(Asset const &asset, Number const &value, std::int32_t scale)
bool operator==(LoanPaymentParts const &other) const
LoanPaymentParts & operator+=(LoanPaymentParts const &other)
Number firstPaymentPrincipal
This structure captures the parts of a loan state.
Number principalOutstanding
State information when preflighting a tx.
Number untrackedManagementFee
Number trackedPrincipalDelta
PaymentSpecialCase specialCase
Number trackedManagementFeeDelta
Number trackedInterestPart() const
T time_since_epoch(T... args)