1#include <xrpl/tx/transactors/lending/LendingHelpers.h>
3#include <xrpl/tx/transactors/vault/VaultCreate.h>
19 "xrpl::LoanPaymentParts::operator+= : other principal "
23 "xrpl::LoanPaymentParts::operator+= : other interest paid "
27 "xrpl::LoanPaymentParts::operator+= : other fee paid "
87 return power(1 + periodicRate, paymentsRemaining);
98 if (paymentsRemaining == 0)
102 if (periodicRate == beast::zero)
103 return Number{1} / paymentsRemaining;
107 return (periodicRate * raisedRate) / (raisedRate - 1);
117 Number const& principalOutstanding,
118 Number const& periodicRate,
121 if (principalOutstanding == 0 || paymentsRemaining == 0)
125 if (periodicRate == beast::zero)
126 return principalOutstanding / paymentsRemaining;
138 Number const& periodicPayment,
139 Number const& periodicRate,
142 if (paymentsRemaining == 0)
145 if (periodicRate == 0)
146 return periodicPayment * paymentsRemaining;
175 Number const& principalOutstanding,
180 if (principalOutstanding == beast::zero)
190 if (now <= nextPaymentDueDate)
194 auto const secondsOverdue = now - nextPaymentDueDate;
198 return principalOutstanding * rate;
208 Number const& principalOutstanding,
209 Number const& periodicRate,
215 if (periodicRate == beast::zero)
218 if (paymentInterval == 0)
221 auto const lastPaymentDate =
std::max(prevPaymentDate, startDate);
226 if (now <= lastPaymentDate)
230 auto const secondsSinceLastPayment = now - lastPaymentDate;
235 return principalOutstanding * periodicRate * secondsSinceLastPayment / paymentInterval;
247template <
class NumberProxy,
class UInt32Proxy,
class UInt32OptionalProxy>
251 NumberProxy& totalValueOutstandingProxy,
252 NumberProxy& principalOutstandingProxy,
253 NumberProxy& managementFeeOutstandingProxy,
254 UInt32Proxy& paymentRemainingProxy,
255 UInt32Proxy& prevPaymentDateProxy,
256 UInt32OptionalProxy& nextDueDateProxy,
259 XRPL_ASSERT_PARTS(nextDueDateProxy,
"xrpl::detail::doPayment",
"Next due date proxy set");
265 "xrpl::detail::doPayment",
266 "Full principal payment");
269 "xrpl::detail::doPayment",
270 "Full value payment");
273 "xrpl::detail::doPayment",
274 "Full management fee payment");
277 paymentRemainingProxy = 0;
280 prevPaymentDateProxy = *nextDueDateProxy;
284 nextDueDateProxy = 0;
289 principalOutstandingProxy = 0;
290 totalValueOutstandingProxy = 0;
291 managementFeeOutstandingProxy = 0;
298 paymentRemainingProxy -= 1;
300 prevPaymentDateProxy = nextDueDateProxy;
301 nextDueDateProxy += paymentInterval;
305 "xrpl::detail::doPayment",
306 "Partial principal payment");
309 "xrpl::detail::doPayment",
310 "Partial value payment");
315 "xrpl::detail::doPayment",
316 "Valid management fee");
328 static_cast<Number>(principalOutstandingProxy) <=
329 static_cast<Number>(totalValueOutstandingProxy),
330 "xrpl::detail::doPayment",
331 "principal does not exceed total");
336 static_cast<Number>(managementFeeOutstandingProxy) >= beast::zero,
337 "xrpl::detail::doPayment",
338 "fee outstanding stays valid");
376 Number const& periodicPayment,
377 Number const& periodicRate,
384 periodicPayment, periodicRate, paymentRemaining, managementFeeRate);
390 auto const errors = roundedOldState - theoreticalState;
394 auto const newTheoreticalPrincipal =
std::max(
403 newTheoreticalPrincipal,
409 JLOG(j.
debug()) <<
"new periodic payment: " << newLoanProperties.periodicPayment
410 <<
", new total value: " << newLoanProperties.loanState.valueOutstanding
411 <<
", first payment principal: " << newLoanProperties.firstPaymentPrincipal;
415 auto const newTheoreticalState =
417 newLoanProperties.periodicPayment, periodicRate, paymentRemaining, managementFeeRate) +
420 JLOG(j.
debug()) <<
"new theoretical value: " << newTheoreticalState.valueOutstanding
421 <<
", principal: " << newTheoreticalState.principalOutstanding
422 <<
", interest gross: " << newTheoreticalState.interestOutstanding();
431 auto const totalValueOutstanding =
std::clamp(
434 principalOutstanding + newTheoreticalState.interestOutstanding(),
439 auto const managementFeeOutstanding =
std::clamp(
440 roundToAsset(asset, newTheoreticalState.managementFeeDue, loanScale),
444 auto const roundedNewState =
445 constructLoanState(totalValueOutstanding, principalOutstanding, managementFeeOutstanding);
449 newLoanProperties.loanState = roundedNewState;
451 JLOG(j.
debug()) <<
"new rounded value: " << roundedNewState.valueOutstanding
452 <<
", principal: " << roundedNewState.principalOutstanding
453 <<
", interest gross: " << roundedNewState.interestOutstanding();
458 principalOutstanding,
463 roundedNewState.interestOutstanding() != beast::zero,
468 JLOG(j.
warn()) <<
"Principal overpayment would cause the loan to be in "
469 "an invalid state. Ignore the overpayment";
476 if (newLoanProperties.periodicPayment <= 0 ||
477 newLoanProperties.loanState.valueOutstanding <= 0 ||
478 newLoanProperties.loanState.managementFeeDue < 0)
481 JLOG(j.
warn()) <<
"Overpayment not allowed: Computed loan "
482 "properties are invalid. Does "
483 "not compute. TotalValueOutstanding: "
484 << newLoanProperties.loanState.valueOutstanding
485 <<
", PeriodicPayment : " << newLoanProperties.periodicPayment
486 <<
", ManagementFeeOwedToBroker: "
487 << newLoanProperties.loanState.managementFeeDue;
492 auto const deltas = roundedOldState - roundedNewState;
497 deltas.managementFee == roundedOldState.
managementFeeDue - managementFeeOutstanding,
498 "xrpl::detail::tryOverpayment",
508 auto const valueChange = -deltas.interest;
511 JLOG(j.
warn()) <<
"Principal overpayment would increase the value of "
512 "the loan. Ignore the overpayment";
545template <
class NumberProxy>
551 NumberProxy& totalValueOutstandingProxy,
552 NumberProxy& principalOutstandingProxy,
553 NumberProxy& managementFeeOutstandingProxy,
554 NumberProxy& periodicPaymentProxy,
555 Number const& periodicRate,
561 totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy);
562 auto const periodicPayment = periodicPaymentProxy;
563 JLOG(j.
debug()) <<
"overpayment components:"
564 <<
", totalValue before: " << *totalValueOutstandingProxy
570 <<
", totalDue: " << overpaymentComponents.
totalDue
571 <<
", payments remaining :" << paymentRemaining;
578 overpaymentComponents,
588 auto const& [loanPaymentParts, newLoanProperties] = *ret;
589 auto const newRoundedLoanState = newLoanProperties.loanState;
594 if (principalOutstandingProxy <= newRoundedLoanState.principalOutstanding)
597 JLOG(j.
warn()) <<
"Overpayment not allowed: principal "
598 <<
"outstanding did not decrease. Before: " << *principalOutstandingProxy
599 <<
". After: " << newRoundedLoanState.principalOutstanding;
610 principalOutstandingProxy - newRoundedLoanState.principalOutstanding,
611 "xrpl::detail::doOverpayment",
612 "principal change agrees");
617 JLOG(j.
debug()) <<
"valueChange: " << loanPaymentParts.valueChange
618 <<
", totalValue before: " << *totalValueOutstandingProxy
619 <<
", totalValue after: " << newRoundedLoanState.valueOutstanding
620 <<
", totalValue delta: "
621 << (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding)
623 <<
", principalPaid: " << loanPaymentParts.principalPaid
624 <<
", Computed difference: "
626 (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding);
629 loanPaymentParts.valueChange ==
630 newRoundedLoanState.valueOutstanding -
633 "xrpl::detail::doOverpayment",
634 "interest paid agrees");
638 "xrpl::detail::doOverpayment",
639 "principal payment matches");
643 totalValueOutstandingProxy = newRoundedLoanState.valueOutstanding;
644 principalOutstandingProxy = newRoundedLoanState.principalOutstanding;
645 managementFeeOutstandingProxy = newRoundedLoanState.managementFeeDue;
646 periodicPaymentProxy = newLoanProperties.periodicPayment;
648 return loanPaymentParts;
668 Number const& principalOutstanding,
673 Number const& latePaymentFee,
685 principalOutstanding, lateInterestRate, view.
parentCloseTime(), nextDueDate);
690 auto const [roundedLateInterest, roundedLateManagementFee] = [&]() {
691 auto const interest =
roundToAsset(asset, latePaymentInterest, loanScale);
695 XRPL_ASSERT(roundedLateInterest >= 0,
"xrpl::detail::computeLatePayment : valid late interest");
698 "xrpl::detail::computeLatePayment",
699 "no extra parts to this payment");
723 "xrpl::detail::computeLatePayment",
724 "total due is rounded");
729 if (amount <
late.totalDue)
731 JLOG(j.
warn()) <<
"Late loan payment amount is insufficient. Due: " <<
late.totalDue
732 <<
", paid: " << amount;
762 Number const& principalOutstanding,
763 Number const& managementFeeOutstanding,
764 Number const& periodicPayment,
771 Number const& totalInterestOutstanding,
772 Number const& periodicRate,
773 Number const& closePaymentFee,
779 if (paymentRemaining <= 1)
782 JLOG(j.
warn()) <<
"Last payment cannot be a full payment.";
789 Number const theoreticalPrincipalOutstanding =
795 theoreticalPrincipalOutstanding,
805 auto const [roundedFullInterest, roundedFullManagementFee] = [&]() {
816 principalOutstanding + totalInterestOutstanding + managementFeeOutstanding,
817 .trackedPrincipalDelta = principalOutstanding,
821 .trackedManagementFeeDelta = managementFeeOutstanding,
832 closePaymentFee + roundedFullManagementFee - managementFeeOutstanding,
841 roundedFullInterest - totalInterestOutstanding,
846 "xrpl::detail::computeFullPayment",
847 "total due is rounded");
849 JLOG(j.
trace()) <<
"computeFullPayment result: periodicPayment: " << periodicPayment
850 <<
", periodicRate: " << periodicRate
851 <<
", paymentRemaining: " << paymentRemaining
852 <<
", theoreticalPrincipalOutstanding: " << theoreticalPrincipalOutstanding
853 <<
", fullPaymentInterest: " << fullPaymentInterest
854 <<
", roundedFullInterest: " << roundedFullInterest
855 <<
", roundedFullManagementFee: " << roundedFullManagementFee
856 <<
", untrackedInterest: " <<
full.untrackedInterest;
858 if (amount <
full.totalDue)
896 Number const& totalValueOutstanding,
897 Number const& principalOutstanding,
898 Number const& managementFeeOutstanding,
899 Number const& periodicPayment,
900 Number const& periodicRate,
905 isRounded(asset, totalValueOutstanding, scale) &&
906 isRounded(asset, principalOutstanding, scale) &&
907 isRounded(asset, managementFeeOutstanding, scale),
908 "xrpl::detail::computePaymentComponents",
909 "Outstanding values are rounded");
911 paymentRemaining > 0,
"xrpl::detail::computePaymentComponents",
"some payments remaining");
917 if (paymentRemaining == 1 || totalValueOutstanding <= roundedPeriodicPayment)
923 .trackedPrincipalDelta = principalOutstanding,
924 .trackedManagementFeeDelta = managementFeeOutstanding,
931 periodicPayment, periodicRate, paymentRemaining - 1, managementFeeRate);
943 constructLoanState(totalValueOutstanding, principalOutstanding, managementFeeOutstanding);
956 "xrpl::detail::computePaymentComponents",
957 "principal delta not greater than outstanding");
964 "xrpl::detail::computePaymentComponents",
965 "interest due delta not greater than outstanding");
976 "xrpl::detail::computePaymentComponents",
977 "management fee due delta not greater than outstanding");
991 if (excess > beast::zero)
993 auto part =
std::min(component, excess);
998 excess >= beast::zero,
"xrpl::detail::computePaymentComponents",
"excess non-negative");
1014 if (totalOverpayment > beast::zero)
1018 "xrpl::detail::computePaymentComponents : payment exceeded loan "
1020 addressExcess(deltas, totalOverpayment);
1025 Number shortage = roundedPeriodicPayment - deltas.
total();
1029 "xrpl::detail::computePaymentComponents",
1030 "shortage is rounded");
1032 if (shortage < beast::zero)
1035 Number excess = -shortage;
1036 addressExcess(deltas, excess);
1044 shortage >= beast::zero,
"xrpl::detail::computePaymentComponents",
"no shortage or excess");
1049 "xrpl::detail::computePaymentComponents",
1050 "total value adds up");
1055 "xrpl::detail::computePaymentComponents",
1056 "valid principal result");
1059 "xrpl::detail::computePaymentComponents",
1060 "valid interest result");
1064 "xrpl::detail::computePaymentComponents",
1065 "valid fee result");
1069 "xrpl::detail::computePaymentComponents",
1070 "payment parts add to payment");
1076 .trackedPrincipalDelta =
1078 .trackedManagementFeeDelta =
1101ExtendedPaymentComponents
1104 int32_t
const loanScale,
1112 "xrpl::detail::computeOverpaymentComponents : valid overpayment "
1118 Number const overpaymentFee =
1125 auto const [roundedOverpaymentInterest, roundedOverpaymentManagementFee] = [&]() {
1126 auto const interest =
1137 .trackedPrincipalDelta =
overpayment - roundedOverpaymentInterest -
1138 roundedOverpaymentManagementFee - overpaymentFee,
1139 .trackedManagementFeeDelta = roundedOverpaymentManagementFee,
1148 roundedOverpaymentInterest};
1150 result.trackedInterestPart() == roundedOverpaymentInterest,
1151 "xrpl::detail::computeOverpaymentComponents",
1152 "valid interest computation");
1158detail::LoanStateDeltas
1198 Asset const& vaultAsset,
1199 Number const& principalRequested,
1200 bool expectInterest,
1205 auto const totalInterestOutstanding =
1210 if (expectInterest && totalInterestOutstanding <= 0)
1214 JLOG(j.
warn()) <<
"Loan for " << principalRequested <<
" with interest has no interest due";
1219 if (!expectInterest && totalInterestOutstanding > 0)
1222 JLOG(j.
warn()) <<
"Loan for " << principalRequested <<
" with no interest has interest due";
1236 JLOG(j.
warn()) <<
"Loan is unable to pay principal.";
1243 auto const roundedPayment =
1245 if (roundedPayment == beast::zero)
1248 <<
") rounds to 0. ";
1260 computedPayments != paymentTotal)
1263 <<
") rounding (" << roundedPayment <<
") on a total value of "
1265 <<
" can not complete the loan in the specified "
1266 "number of payments ("
1267 << computedPayments <<
" != " << paymentTotal <<
")";
1282 Number const& theoreticalPrincipalOutstanding,
1283 Number const& periodicRate,
1291 theoreticalPrincipalOutstanding,
1298 accruedInterest >= 0,
1299 "xrpl::detail::computeFullPaymentInterest : valid accrued "
1303 auto const prepaymentPenalty = closeInterestRate == beast::zero
1308 prepaymentPenalty >= 0,
1309 "xrpl::detail::computeFullPaymentInterest : valid prepayment "
1313 return accruedInterest + prepaymentPenalty;
1340 Number const& periodicPayment,
1341 Number const& periodicRate,
1345 if (paymentRemaining == 0)
1349 .principalOutstanding = 0,
1351 .managementFeeDue = 0};
1355 Number const totalValueOutstanding = periodicPayment * paymentRemaining;
1357 Number const principalOutstanding =
1361 Number const interestOutstandingGross = totalValueOutstanding - principalOutstanding;
1364 Number const managementFeeOutstanding =
1368 Number const interestOutstandingNet = interestOutstandingGross - managementFeeOutstanding;
1372 .principalOutstanding = principalOutstanding,
1373 .interestDue = interestOutstandingNet,
1374 .managementFeeDue = managementFeeOutstanding,
1400 Number const& totalValueOutstanding,
1401 Number const& principalOutstanding,
1402 Number const& managementFeeOutstanding)
1408 .principalOutstanding = principalOutstanding,
1409 .interestDue = totalValueOutstanding - principalOutstanding - managementFeeOutstanding,
1410 .managementFeeDue = managementFeeOutstanding};
1417 loan->at(sfTotalValueOutstanding),
1418 loan->at(sfPrincipalOutstanding),
1419 loan->at(sfManagementFeeOutstanding));
1449 Number const& principalOutstanding,
1457 XRPL_ASSERT(interestRate == 0 || periodicRate > 0,
"xrpl::computeLoanProperties : valid rate");
1460 principalOutstanding,
1478 Number const& principalOutstanding,
1479 Number const& periodicRate,
1484 auto const periodicPayment =
1487 auto const [totalValueOutstanding, loanScale] = [&]() {
1495 STAmount amount{asset, periodicPayment * paymentsRemaining};
1500 auto const loanScale =
std::max(minimumScale, amount.exponent());
1502 (amount.integral() && loanScale == 0) ||
1503 (!amount.integral() && loanScale >=
static_cast<Number>(amount).
exponent()),
1504 "xrpl::computeLoanProperties",
1505 "loanScale value fits expectations");
1517 auto const roundedPrincipalOutstanding =
1521 auto const totalInterestOutstanding = totalValueOutstanding - roundedPrincipalOutstanding;
1522 auto const feeOwedToBroker =
1528 auto const firstPaymentPrincipal = [&]() {
1532 periodicPayment, periodicRate, paymentsRemaining, managementFeeRate);
1535 periodicPayment, periodicRate, paymentsRemaining - 1, managementFeeRate);
1539 return startingState.principalOutstanding - firstPaymentState.principalOutstanding;
1545 constructLoanState(totalValueOutstanding, roundedPrincipalOutstanding, feeOwedToBroker),
1546 .loanScale = loanScale,
1547 .firstPaymentPrincipal = firstPaymentPrincipal,
1557Expected<LoanPaymentParts, TER>
1567 using namespace Lending;
1569 auto principalOutstandingProxy = loan->at(sfPrincipalOutstanding);
1570 auto paymentRemainingProxy = loan->at(sfPaymentRemaining);
1572 if (paymentRemainingProxy == 0 || principalOutstandingProxy == 0)
1576 JLOG(j.
warn()) <<
"Loan is already paid off.";
1581 auto totalValueOutstandingProxy = loan->at(sfTotalValueOutstanding);
1582 auto managementFeeOutstandingProxy = loan->at(sfManagementFeeOutstanding);
1585 auto nextDueDateProxy = loan->at(sfNextPaymentDueDate);
1586 if (*nextDueDateProxy == 0)
1588 JLOG(j.
warn()) <<
"Loan next payment due date is not set.";
1594 TenthBips32 const interestRate{loan->at(sfInterestRate)};
1596 Number const serviceFee = loan->at(sfLoanServiceFee);
1597 TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)};
1599 Number const periodicPayment = loan->at(sfPeriodicPayment);
1601 auto prevPaymentDateProxy = loan->at(sfPreviousPaymentDueDate);
1604 std::uint32_t const paymentInterval = loan->at(sfPaymentInterval);
1609 XRPL_ASSERT(interestRate == 0 || periodicRate > 0,
"xrpl::loanMakePayment : valid rate");
1611 XRPL_ASSERT(*totalValueOutstandingProxy > 0,
"xrpl::loanMakePayment : valid total value");
1621 JLOG(j.
warn()) <<
"Loan payment is overdue. Use the tfLoanLatePayment "
1623 "flag to make a late payment. Loan was created on "
1624 << startDate <<
", prev payment due date is " << prevPaymentDateProxy
1625 <<
", next payment due date is " << nextDueDateProxy <<
", ledger time is "
1634 TenthBips32 const closeInterestRate{loan->at(sfCloseInterestRate)};
1635 Number const closePaymentFee =
roundToAsset(asset, loan->at(sfClosePaymentFee), loanScale);
1638 totalValueOutstandingProxy, principalOutstandingProxy, managementFeeOutstandingProxy);
1643 principalOutstandingProxy,
1644 managementFeeOutstandingProxy,
1646 paymentRemainingProxy,
1647 prevPaymentDateProxy,
1659 if (fullPaymentComponents.has_value())
1662 *fullPaymentComponents,
1663 totalValueOutstandingProxy,
1664 principalOutstandingProxy,
1665 managementFeeOutstandingProxy,
1666 paymentRemainingProxy,
1667 prevPaymentDateProxy,
1672 if (fullPaymentComponents.error())
1677 return Unexpected(fullPaymentComponents.error());
1681 UNREACHABLE(
"xrpl::loanMakePayment : invalid full payment result");
1682 JLOG(j.
error()) <<
"Full payment computation failed unexpectedly.";
1694 totalValueOutstandingProxy,
1695 principalOutstandingProxy,
1696 managementFeeOutstandingProxy,
1699 paymentRemainingProxy,
1703 periodic.trackedPrincipalDelta >= 0,
1704 "xrpl::loanMakePayment",
1705 "regular payment valid principal");
1711 TenthBips32 const lateInterestRate{loan->at(sfLateInterestRate)};
1712 Number const latePaymentFee = loan->at(sfLatePaymentFee);
1717 principalOutstandingProxy,
1727 if (latePaymentComponents.has_value())
1730 *latePaymentComponents,
1731 totalValueOutstandingProxy,
1732 principalOutstandingProxy,
1733 managementFeeOutstandingProxy,
1734 paymentRemainingProxy,
1735 prevPaymentDateProxy,
1740 if (latePaymentComponents.error())
1744 return Unexpected(latePaymentComponents.error());
1748 UNREACHABLE(
"xrpl::loanMakePayment : invalid late payment result");
1749 JLOG(j.
error()) <<
"Late payment computation failed unexpectedly.";
1759 "xrpl::loanMakePayment",
1760 "regular payment type");
1767 while ((amount >= (totalPaid + periodic.totalDue)) && paymentRemainingProxy > 0 &&
1768 numPayments < loanMaximumPaymentsPerTransaction)
1772 periodic.trackedPrincipalDelta >= 0,
1773 "xrpl::loanMakePayment",
1774 "payment pays non-negative principal");
1776 totalPaid += periodic.totalDue;
1779 totalValueOutstandingProxy,
1780 principalOutstandingProxy,
1781 managementFeeOutstandingProxy,
1782 paymentRemainingProxy,
1783 prevPaymentDateProxy,
1790 (paymentRemainingProxy == 0),
1791 "xrpl::loanMakePayment",
1792 "final payment is the final payment");
1802 totalValueOutstandingProxy,
1803 principalOutstandingProxy,
1804 managementFeeOutstandingProxy,
1807 paymentRemainingProxy,
1812 if (numPayments == 0)
1814 JLOG(j.
warn()) <<
"Regular loan payment amount is insufficient. Due: " << periodic.totalDue
1815 <<
", paid: " << amount;
1821 "xrpl::loanMakePayment",
1822 "payment parts add up");
1823 XRPL_ASSERT_PARTS(totalParts.
valueChange == 0,
"xrpl::loanMakePayment",
"no value change");
1828 paymentRemainingProxy > 0 && totalPaid < amount &&
1829 numPayments < loanMaximumPaymentsPerTransaction)
1831 TenthBips32 const overpaymentInterestRate{loan->at(sfOverpaymentInterestRate)};
1832 TenthBips32 const overpaymentFeeRate{loan->at(sfOverpaymentFee)};
1844 overpaymentInterestRate,
1854 "xrpl::loanMakePayment",
1855 "overpayment penalty did not reduce value of loan");
1858 auto periodicPaymentProxy = loan->at(sfPeriodicPayment);
1862 overpaymentComponents,
1863 totalValueOutstandingProxy,
1864 principalOutstandingProxy,
1865 managementFeeOutstandingProxy,
1866 periodicPaymentProxy,
1868 paymentRemainingProxy,
1872 totalParts += *overResult;
1874 else if (overResult.error())
1890 "xrpl::loanMakePayment : total principal paid is valid");
1894 "xrpl::loanMakePayment : total interest paid is valid");
1897 "xrpl::loanMakePayment : loan value change is valid");
1900 "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 &roundedLoanState, 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)
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)
Number computeManagementFee(Asset const &asset, Number const &interest, TenthBips32 managementFeeRate, std::int32_t scale)
@ 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)