1#include <xrpld/app/misc/LendingHelpers.h>
3#include <xrpld/app/tx/detail/VaultCreate.h>
20 "xrpl::LoanPaymentParts::operator+= : other principal "
24 "xrpl::LoanPaymentParts::operator+= : other interest paid "
28 "xrpl::LoanPaymentParts::operator+= : other fee paid "
90 return power(1 + periodicRate, paymentsRemaining);
100 Number const& periodicRate,
103 if (paymentsRemaining == 0)
107 if (periodicRate == beast::zero)
108 return Number{1} / paymentsRemaining;
113 return (periodicRate * raisedRate) / (raisedRate - 1);
123 Number const& principalOutstanding,
124 Number const& periodicRate,
127 if (principalOutstanding == 0 || paymentsRemaining == 0)
131 if (periodicRate == beast::zero)
132 return principalOutstanding / paymentsRemaining;
134 return principalOutstanding *
145 Number const& periodicPayment,
146 Number const& periodicRate,
149 if (paymentsRemaining == 0)
152 if (periodicRate == 0)
153 return periodicPayment * paymentsRemaining;
155 return periodicPayment /
184 Number const& principalOutstanding,
189 if (principalOutstanding == beast::zero)
199 if (now <= nextPaymentDueDate)
203 auto const secondsOverdue = now - nextPaymentDueDate;
207 return principalOutstanding * rate;
217 Number const& principalOutstanding,
218 Number const& periodicRate,
224 if (periodicRate == beast::zero)
227 if (paymentInterval == 0)
230 auto const lastPaymentDate =
std::max(prevPaymentDate, startDate);
235 if (now <= lastPaymentDate)
239 auto const secondsSinceLastPayment = now - lastPaymentDate;
244 return principalOutstanding * periodicRate * secondsSinceLastPayment /
257template <
class NumberProxy,
class UInt32Proxy,
class UInt32OptionalProxy>
261 NumberProxy& totalValueOutstandingProxy,
262 NumberProxy& principalOutstandingProxy,
263 NumberProxy& managementFeeOutstandingProxy,
264 UInt32Proxy& paymentRemainingProxy,
265 UInt32Proxy& prevPaymentDateProxy,
266 UInt32OptionalProxy& nextDueDateProxy,
270 nextDueDateProxy,
"xrpl::detail::doPayment",
"Next due date proxy set");
276 "xrpl::detail::doPayment",
277 "Full principal payment");
280 "xrpl::detail::doPayment",
281 "Full value payment");
284 "xrpl::detail::doPayment",
285 "Full management fee payment");
288 paymentRemainingProxy = 0;
291 prevPaymentDateProxy = *nextDueDateProxy;
295 nextDueDateProxy = 0;
300 principalOutstandingProxy = 0;
301 totalValueOutstandingProxy = 0;
302 managementFeeOutstandingProxy = 0;
309 paymentRemainingProxy -= 1;
311 prevPaymentDateProxy = nextDueDateProxy;
312 nextDueDateProxy += paymentInterval;
316 "xrpl::detail::doPayment",
317 "Partial principal payment");
320 "xrpl::detail::doPayment",
321 "Partial value payment");
326 "xrpl::detail::doPayment",
327 "Valid management fee");
339 static_cast<Number>(principalOutstandingProxy) <=
340 static_cast<Number>(totalValueOutstandingProxy),
341 "xrpl::detail::doPayment",
342 "principal does not exceed total");
347 static_cast<Number>(managementFeeOutstandingProxy) >= beast::zero,
348 "xrpl::detail::doPayment",
349 "fee outstanding stays valid");
389 Number const& periodicPayment,
390 Number const& periodicRate,
397 periodicPayment, periodicRate, paymentRemaining, managementFeeRate);
403 auto const errors = roundedOldState - theoreticalState;
407 auto const newTheoreticalPrincipal =
std::max(
408 theoreticalState.principalOutstanding -
417 newTheoreticalPrincipal,
423 JLOG(j.
debug()) <<
"new periodic payment: "
424 << newLoanProperties.periodicPayment
425 <<
", new total value: "
426 << newLoanProperties.loanState.valueOutstanding
427 <<
", first payment principal: "
428 << newLoanProperties.firstPaymentPrincipal;
433 newLoanProperties.periodicPayment,
439 JLOG(j.
debug()) <<
"new theoretical value: "
440 << newTheoreticalState.valueOutstanding <<
", principal: "
441 << newTheoreticalState.principalOutstanding
442 <<
", interest gross: "
443 << newTheoreticalState.interestOutstanding();
451 newTheoreticalState.principalOutstanding,
456 auto const totalValueOutstanding =
std::clamp(
459 principalOutstanding + newTheoreticalState.interestOutstanding(),
464 auto const managementFeeOutstanding =
std::clamp(
465 roundToAsset(asset, newTheoreticalState.managementFeeDue, loanScale),
470 totalValueOutstanding, principalOutstanding, managementFeeOutstanding);
474 newLoanProperties.loanState = roundedNewState;
476 JLOG(j.
debug()) <<
"new rounded value: " << roundedNewState.valueOutstanding
477 <<
", principal: " << roundedNewState.principalOutstanding
478 <<
", interest gross: "
479 << roundedNewState.interestOutstanding();
484 principalOutstanding,
489 roundedNewState.interestOutstanding() != beast::zero,
494 JLOG(j.
warn()) <<
"Principal overpayment would cause the loan to be in "
495 "an invalid state. Ignore the overpayment";
502 if (newLoanProperties.periodicPayment <= 0 ||
503 newLoanProperties.loanState.valueOutstanding <= 0 ||
504 newLoanProperties.loanState.managementFeeDue < 0)
507 JLOG(j.
warn()) <<
"Overpayment not allowed: Computed loan "
508 "properties are invalid. Does "
509 "not compute. TotalValueOutstanding: "
510 << newLoanProperties.loanState.valueOutstanding
511 <<
", PeriodicPayment : "
512 << newLoanProperties.periodicPayment
513 <<
", ManagementFeeOwedToBroker: "
514 << newLoanProperties.loanState.managementFeeDue;
519 auto const deltas = roundedOldState - roundedNewState;
524 deltas.managementFee ==
526 "xrpl::detail::tryOverpayment",
536 auto const valueChange = -deltas.interest;
539 JLOG(j.
warn()) <<
"Principal overpayment would increase the value of "
540 "the loan. Ignore the overpayment";
574template <
class NumberProxy>
580 NumberProxy& totalValueOutstandingProxy,
581 NumberProxy& principalOutstandingProxy,
582 NumberProxy& managementFeeOutstandingProxy,
583 NumberProxy& periodicPaymentProxy,
584 Number const& periodicRate,
590 totalValueOutstandingProxy,
591 principalOutstandingProxy,
592 managementFeeOutstandingProxy);
593 auto const periodicPayment = periodicPaymentProxy;
595 <<
"overpayment components:"
596 <<
", totalValue before: " << *totalValueOutstandingProxy
599 <<
", managementFeeDelta: "
603 <<
", totalDue: " << overpaymentComponents.
totalDue
604 <<
", payments remaining :" << paymentRemaining;
611 overpaymentComponents,
621 auto const& [loanPaymentParts, newLoanProperties] = *ret;
622 auto const newRoundedLoanState = newLoanProperties.loanState;
627 if (principalOutstandingProxy <= newRoundedLoanState.principalOutstanding)
630 JLOG(j.
warn()) <<
"Overpayment not allowed: principal "
631 <<
"outstanding did not decrease. Before: "
632 << *principalOutstandingProxy <<
". After: "
633 << newRoundedLoanState.principalOutstanding;
644 principalOutstandingProxy -
645 newRoundedLoanState.principalOutstanding,
646 "xrpl::detail::doOverpayment",
647 "principal change agrees");
653 <<
"valueChange: " << loanPaymentParts.valueChange
654 <<
", totalValue before: " << *totalValueOutstandingProxy
655 <<
", totalValue after: " << newRoundedLoanState.valueOutstanding
656 <<
", totalValue delta: "
657 << (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding)
659 <<
", principalPaid: " << loanPaymentParts.principalPaid
660 <<
", Computed difference: "
662 (totalValueOutstandingProxy - newRoundedLoanState.valueOutstanding);
665 loanPaymentParts.valueChange ==
666 newRoundedLoanState.valueOutstanding -
667 (totalValueOutstandingProxy -
670 "xrpl::detail::doOverpayment",
671 "interest paid agrees");
675 loanPaymentParts.principalPaid,
676 "xrpl::detail::doOverpayment",
677 "principal payment matches");
681 totalValueOutstandingProxy = newRoundedLoanState.valueOutstanding;
682 principalOutstandingProxy = newRoundedLoanState.principalOutstanding;
683 managementFeeOutstandingProxy = newRoundedLoanState.managementFeeDue;
684 periodicPaymentProxy = newLoanProperties.periodicPayment;
686 return loanPaymentParts;
706 Number const& principalOutstanding,
711 Number const& latePaymentFee,
723 principalOutstanding,
731 auto const [roundedLateInterest, roundedLateManagementFee] = [&]() {
732 auto const interest =
735 asset, interest, managementFeeRate, loanScale);
739 roundedLateInterest >= 0,
740 "xrpl::detail::computeLatePayment : valid late interest");
743 "xrpl::detail::computeLatePayment",
744 "no extra parts to this payment");
758 roundedLateManagementFee,
769 "xrpl::detail::computeLatePayment",
770 "total due is rounded");
775 if (amount <
late.totalDue)
777 JLOG(j.
warn()) <<
"Late loan payment amount is insufficient. Due: "
778 <<
late.totalDue <<
", paid: " << amount;
808 Number const& principalOutstanding,
809 Number const& managementFeeOutstanding,
810 Number const& periodicPayment,
817 Number const& totalInterestOutstanding,
818 Number const& periodicRate,
819 Number const& closePaymentFee,
825 if (paymentRemaining <= 1)
828 JLOG(j.
warn()) <<
"Last payment cannot be a full payment.";
835 Number const theoreticalPrincipalOutstanding =
837 periodicPayment, periodicRate, paymentRemaining);
842 theoreticalPrincipalOutstanding,
852 auto const [roundedFullInterest, roundedFullManagementFee] = [&]() {
856 asset, interest, managementFeeRate, loanScale);
865 totalInterestOutstanding + managementFeeOutstanding,
866 .trackedPrincipalDelta = principalOutstanding,
870 .trackedManagementFeeDelta = managementFeeOutstanding,
881 closePaymentFee + roundedFullManagementFee - managementFeeOutstanding,
890 roundedFullInterest - totalInterestOutstanding,
895 "xrpl::detail::computeFullPayment",
896 "total due is rounded");
898 JLOG(j.
trace()) <<
"computeFullPayment result: periodicPayment: "
899 << periodicPayment <<
", periodicRate: " << periodicRate
900 <<
", paymentRemaining: " << paymentRemaining
901 <<
", theoreticalPrincipalOutstanding: "
902 << theoreticalPrincipalOutstanding
903 <<
", fullPaymentInterest: " << fullPaymentInterest
904 <<
", roundedFullInterest: " << roundedFullInterest
905 <<
", roundedFullManagementFee: "
906 << roundedFullManagementFee
907 <<
", untrackedInterest: " <<
full.untrackedInterest;
909 if (amount <
full.totalDue)
946 Number const& totalValueOutstanding,
947 Number const& principalOutstanding,
948 Number const& managementFeeOutstanding,
949 Number const& periodicPayment,
950 Number const& periodicRate,
955 isRounded(asset, totalValueOutstanding, scale) &&
956 isRounded(asset, principalOutstanding, scale) &&
957 isRounded(asset, managementFeeOutstanding, scale),
958 "xrpl::detail::computePaymentComponents",
959 "Outstanding values are rounded");
961 paymentRemaining > 0,
962 "xrpl::detail::computePaymentComponents",
963 "some payments remaining");
965 auto const roundedPeriodicPayment =
970 if (paymentRemaining == 1 ||
971 totalValueOutstanding <= roundedPeriodicPayment)
977 .trackedPrincipalDelta = principalOutstanding,
978 .trackedManagementFeeDelta = managementFeeOutstanding,
985 periodicPayment, periodicRate, paymentRemaining - 1, managementFeeRate);
992 .principalOutstanding =
1000 totalValueOutstanding, principalOutstanding, managementFeeOutstanding);
1013 "xrpl::detail::computePaymentComponents",
1014 "principal delta not greater than outstanding");
1022 "xrpl::detail::computePaymentComponents",
1023 "interest due delta not greater than outstanding");
1034 "xrpl::detail::computePaymentComponents",
1035 "management fee due delta not greater than outstanding");
1048 auto takeFrom = [](
Number& component,
Number& excess) {
1049 if (excess > beast::zero)
1051 auto part =
std::min(component, excess);
1056 excess >= beast::zero,
1057 "xrpl::detail::computePaymentComponents",
1058 "excess non-negative");
1072 Number totalOverpayment =
1075 if (totalOverpayment > beast::zero)
1079 "xrpl::detail::computePaymentComponents : payment exceeded loan "
1081 addressExcess(deltas, totalOverpayment);
1086 Number shortage = roundedPeriodicPayment - deltas.
total();
1090 "xrpl::detail::computePaymentComponents",
1091 "shortage is rounded");
1093 if (shortage < beast::zero)
1096 Number excess = -shortage;
1097 addressExcess(deltas, excess);
1105 shortage >= beast::zero,
1106 "xrpl::detail::computePaymentComponents",
1107 "no shortage or excess");
1113 "xrpl::detail::computePaymentComponents",
1114 "total value adds up");
1119 "xrpl::detail::computePaymentComponents",
1120 "valid principal result");
1124 "xrpl::detail::computePaymentComponents",
1125 "valid interest result");
1129 "xrpl::detail::computePaymentComponents",
1130 "valid fee result");
1134 "xrpl::detail::computePaymentComponents",
1135 "payment parts add to payment");
1166ExtendedPaymentComponents
1169 int32_t
const loanScale,
1177 "xrpl::detail::computeOverpaymentComponents : valid overpayment "
1190 auto const [roundedOverpaymentInterest, roundedOverpaymentManagementFee] =
1197 asset, interest, managementFeeRate, loanScale);
1206 .trackedPrincipalDelta =
overpayment - roundedOverpaymentInterest -
1207 roundedOverpaymentManagementFee - overpaymentFee,
1208 .trackedManagementFeeDelta = roundedOverpaymentManagementFee,
1217 roundedOverpaymentInterest};
1219 result.trackedInterestPart() == roundedOverpaymentInterest,
1220 "xrpl::detail::computeOverpaymentComponents",
1221 "valid interest computation");
1227detail::LoanStateDeltas
1267 Asset const& vaultAsset,
1268 Number const& principalRequested,
1269 bool expectInterest,
1274 auto const totalInterestOutstanding =
1279 if (expectInterest && totalInterestOutstanding <= 0)
1283 JLOG(j.
warn()) <<
"Loan for " << principalRequested
1284 <<
" with interest has no interest due";
1289 if (!expectInterest && totalInterestOutstanding > 0)
1292 JLOG(j.
warn()) <<
"Loan for " << principalRequested
1293 <<
" with no interest has interest due";
1307 JLOG(j.
warn()) <<
"Loan is unable to pay principal.";
1316 if (roundedPayment == beast::zero)
1318 JLOG(j.
warn()) <<
"Loan Periodic payment ("
1331 computedPayments != paymentTotal)
1333 JLOG(j.
warn()) <<
"Loan Periodic payment ("
1335 << roundedPayment <<
") on a total value of "
1337 <<
" can not complete the loan in the specified "
1338 "number of payments ("
1339 << computedPayments <<
" != " << paymentTotal <<
")";
1354 Number const& theoreticalPrincipalOutstanding,
1355 Number const& periodicRate,
1363 theoreticalPrincipalOutstanding,
1370 accruedInterest >= 0,
1371 "xrpl::detail::computeFullPaymentInterest : valid accrued "
1375 auto const prepaymentPenalty = closeInterestRate == beast::zero
1380 prepaymentPenalty >= 0,
1381 "xrpl::detail::computeFullPaymentInterest : valid prepayment "
1385 return accruedInterest + prepaymentPenalty;
1412 Number const& periodicPayment,
1413 Number const& periodicRate,
1417 if (paymentRemaining == 0)
1421 .principalOutstanding = 0,
1423 .managementFeeDue = 0};
1427 Number const totalValueOutstanding = periodicPayment * paymentRemaining;
1429 Number const principalOutstanding =
1431 periodicPayment, periodicRate, paymentRemaining);
1434 Number const interestOutstandingGross =
1435 totalValueOutstanding - principalOutstanding;
1438 Number const managementFeeOutstanding =
1442 Number const interestOutstandingNet =
1443 interestOutstandingGross - managementFeeOutstanding;
1447 .principalOutstanding = principalOutstanding,
1448 .interestDue = interestOutstandingNet,
1449 .managementFeeDue = managementFeeOutstanding,
1475 Number const& totalValueOutstanding,
1476 Number const& principalOutstanding,
1477 Number const& managementFeeOutstanding)
1483 .principalOutstanding = principalOutstanding,
1484 .interestDue = totalValueOutstanding - principalOutstanding -
1485 managementFeeOutstanding,
1486 .managementFeeDue = managementFeeOutstanding};
1493 loan->at(sfTotalValueOutstanding),
1494 loan->at(sfPrincipalOutstanding),
1495 loan->at(sfManagementFeeOutstanding));
1529 Number const& principalOutstanding,
1538 interestRate == 0 || periodicRate > 0,
1539 "xrpl::computeLoanProperties : valid rate");
1542 principalOutstanding,
1560 Number const& principalOutstanding,
1561 Number const& periodicRate,
1567 principalOutstanding, periodicRate, paymentsRemaining);
1569 auto const [totalValueOutstanding, loanScale] = [&]() {
1578 STAmount amount{asset, periodicPayment * paymentsRemaining};
1583 auto const loanScale =
std::max(minimumScale, amount.exponent());
1585 (amount.integral() && loanScale == 0) ||
1586 (!amount.integral() &&
1588 "xrpl::computeLoanProperties",
1589 "loanScale value fits expectations");
1605 auto const totalInterestOutstanding =
1606 totalValueOutstanding - roundedPrincipalOutstanding;
1608 asset, totalInterestOutstanding, managementFeeRate, loanScale);
1613 auto const firstPaymentPrincipal = [&]() {
1625 paymentsRemaining - 1,
1630 return startingState.principalOutstanding -
1631 firstPaymentState.principalOutstanding;
1637 totalValueOutstanding,
1638 roundedPrincipalOutstanding,
1640 .loanScale = loanScale,
1641 .firstPaymentPrincipal = firstPaymentPrincipal,
1651Expected<LoanPaymentParts, TER>
1661 using namespace Lending;
1663 auto principalOutstandingProxy = loan->at(sfPrincipalOutstanding);
1664 auto paymentRemainingProxy = loan->at(sfPaymentRemaining);
1666 if (paymentRemainingProxy == 0 || principalOutstandingProxy == 0)
1670 JLOG(j.
warn()) <<
"Loan is already paid off.";
1675 auto totalValueOutstandingProxy = loan->at(sfTotalValueOutstanding);
1676 auto managementFeeOutstandingProxy = loan->at(sfManagementFeeOutstanding);
1679 auto nextDueDateProxy = loan->at(sfNextPaymentDueDate);
1680 if (*nextDueDateProxy == 0)
1682 JLOG(j.
warn()) <<
"Loan next payment due date is not set.";
1688 TenthBips32 const interestRate{loan->at(sfInterestRate)};
1690 Number const serviceFee = loan->at(sfLoanServiceFee);
1691 TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)};
1693 Number const periodicPayment = loan->at(sfPeriodicPayment);
1695 auto prevPaymentDateProxy = loan->at(sfPreviousPaymentDueDate);
1698 std::uint32_t const paymentInterval = loan->at(sfPaymentInterval);
1704 interestRate == 0 || periodicRate > 0,
1705 "xrpl::loanMakePayment : valid rate");
1708 *totalValueOutstandingProxy > 0,
1709 "xrpl::loanMakePayment : valid total value");
1720 JLOG(j.
warn()) <<
"Loan payment is overdue. Use the tfLoanLatePayment "
1722 "flag to make a late payment. Loan was created on "
1723 << startDate <<
", prev payment due date is "
1724 << prevPaymentDateProxy <<
", next payment due date is "
1725 << nextDueDateProxy <<
", ledger time is "
1734 TenthBips32 const closeInterestRate{loan->at(sfCloseInterestRate)};
1735 Number const closePaymentFee =
1736 roundToAsset(asset, loan->at(sfClosePaymentFee), loanScale);
1739 totalValueOutstandingProxy,
1740 principalOutstandingProxy,
1741 managementFeeOutstandingProxy);
1746 principalOutstandingProxy,
1747 managementFeeOutstandingProxy,
1749 paymentRemainingProxy,
1750 prevPaymentDateProxy,
1763 *fullPaymentComponents,
1764 totalValueOutstandingProxy,
1765 principalOutstandingProxy,
1766 managementFeeOutstandingProxy,
1767 paymentRemainingProxy,
1768 prevPaymentDateProxy,
1772 else if (fullPaymentComponents.error())
1776 return Unexpected(fullPaymentComponents.error());
1779 UNREACHABLE(
"xrpl::loanMakePayment : invalid full payment result");
1780 JLOG(j.
error()) <<
"Full payment computation failed unexpectedly.";
1792 totalValueOutstandingProxy,
1793 principalOutstandingProxy,
1794 managementFeeOutstandingProxy,
1797 paymentRemainingProxy,
1801 periodic.trackedPrincipalDelta >= 0,
1802 "xrpl::loanMakePayment",
1803 "regular payment valid principal");
1809 TenthBips32 const lateInterestRate{loan->at(sfLateInterestRate)};
1810 Number const latePaymentFee = loan->at(sfLatePaymentFee);
1815 principalOutstandingProxy,
1826 *latePaymentComponents,
1827 totalValueOutstandingProxy,
1828 principalOutstandingProxy,
1829 managementFeeOutstandingProxy,
1830 paymentRemainingProxy,
1831 prevPaymentDateProxy,
1835 else if (latePaymentComponents.error())
1839 return Unexpected(latePaymentComponents.error());
1843 UNREACHABLE(
"xrpl::loanMakePayment : invalid late payment result");
1844 JLOG(j.
error()) <<
"Late payment computation failed unexpectedly.";
1855 "xrpl::loanMakePayment",
1856 "regular payment type");
1863 while ((amount >= (totalPaid + periodic.totalDue)) &&
1864 paymentRemainingProxy > 0 &&
1865 numPayments < loanMaximumPaymentsPerTransaction)
1869 periodic.trackedPrincipalDelta >= 0,
1870 "xrpl::loanMakePayment",
1871 "payment pays non-negative principal");
1873 totalPaid += periodic.totalDue;
1876 totalValueOutstandingProxy,
1877 principalOutstandingProxy,
1878 managementFeeOutstandingProxy,
1879 paymentRemainingProxy,
1880 prevPaymentDateProxy,
1887 (paymentRemainingProxy == 0),
1888 "xrpl::loanMakePayment",
1889 "final payment is the final payment");
1899 totalValueOutstandingProxy,
1900 principalOutstandingProxy,
1901 managementFeeOutstandingProxy,
1904 paymentRemainingProxy,
1909 if (numPayments == 0)
1911 JLOG(j.
warn()) <<
"Regular loan payment amount is insufficient. Due: "
1912 << periodic.totalDue <<
", paid: " << amount;
1920 "xrpl::loanMakePayment",
1921 "payment parts add up");
1924 "xrpl::loanMakePayment",
1931 totalPaid < amount && numPayments < loanMaximumPaymentsPerTransaction)
1934 loan->at(sfOverpaymentInterestRate)};
1935 TenthBips32 const overpaymentFeeRate{loan->at(sfOverpaymentFee)};
1941 std::min(amount - totalPaid, *totalValueOutstandingProxy);
1948 overpaymentInterestRate,
1958 "xrpl::loanMakePayment",
1959 "overpayment penalty did not reduce value of loan");
1962 auto periodicPaymentProxy = loan->at(sfPeriodicPayment);
1966 overpaymentComponents,
1967 totalValueOutstandingProxy,
1968 principalOutstandingProxy,
1969 managementFeeOutstandingProxy,
1970 periodicPaymentProxy,
1972 paymentRemainingProxy,
1975 totalParts += *overResult;
1976 else if (overResult.error())
1990 "xrpl::loanMakePayment : total principal paid is valid");
1994 "xrpl::loanMakePayment : total interest paid is valid");
1997 "xrpl::loanMakePayment : loan value change is valid");
2000 totalParts.
feePaid >= beast::zero,
2001 "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.
constexpr int exponent() const noexcept
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
Number roundToAsset(A const &asset, Number const &value, std::int32_t scale, Number::rounding_mode rounding=Number::getround())
Round an arbitrary precision Number to the precision of a given Asset.
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)
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)