Skip to content

Commit cf33c9d

Browse files
committed
fixes overpayment valuechange calculation
1 parent e27fecd commit cf33c9d

File tree

4 files changed

+194
-99
lines changed

4 files changed

+194
-99
lines changed

src/test/app/LendingHelpers_test.cpp

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,10 +620,117 @@ class LendingHelpers_test : public beast::unit_test::suite
620620
}
621621
}
622622

623+
void
624+
testTryOverpaymentValueChange()
625+
{
626+
// This test ensures that overpayment value change is computed
627+
// correctly. I am sorry, this unit test will be a pain in the ass.
628+
testcase("tryOverpay - Value Change is the decrease in interest");
629+
630+
using namespace jtx;
631+
using namespace ripple::detail;
632+
633+
Env env{*this};
634+
Account const issuer{"issuer"};
635+
PrettyAsset const asset = issuer["USD"];
636+
637+
// Interest delta is 40 (100 - 50 - 10)
638+
ExtendedPaymentComponents const overpaymentComponents = {
639+
PaymentComponents{
640+
.trackedValueDelta = Number{50, 0},
641+
.trackedPrincipalDelta = Number{50, 0},
642+
.trackedManagementFeeDelta = Number{0, 0},
643+
.specialCase = PaymentSpecialCase::extra,
644+
},
645+
numZero,
646+
numZero,
647+
};
648+
649+
TenthBips16 managementFeeRate{20'000}; // 10%
650+
TenthBips32 loanInterestRate{10'000}; // 20%
651+
Number loanPrincipal{1'000};
652+
std::uint32_t paymentInterval = 30 * 24 * 60 * 60;
653+
std::uint32_t paymentsRemaining = 10;
654+
std::int32_t loanScale = -5;
655+
auto const periodicRate =
656+
loanPeriodicRate(loanInterestRate, paymentInterval);
657+
658+
auto loanProperites = computeLoanProperties(
659+
asset,
660+
loanPrincipal,
661+
loanInterestRate,
662+
paymentInterval,
663+
paymentsRemaining,
664+
managementFeeRate,
665+
loanScale);
666+
std::cout << loanProperites.periodicPayment << std::endl;
667+
std::cout << loanProperites.loanState.valueOutstanding << std::endl;
668+
std::cout << loanProperites.loanState.interestOutstanding()
669+
<< std::endl;
670+
671+
Number periodicPayment = loanProperites.periodicPayment;
672+
673+
auto const ret = tryOverpayment(
674+
asset,
675+
loanScale,
676+
overpaymentComponents,
677+
loanProperites.loanState,
678+
periodicPayment,
679+
periodicRate,
680+
paymentsRemaining,
681+
managementFeeRate,
682+
env.journal);
683+
684+
BEAST_EXPECT(ret);
685+
686+
auto const& [actualPaymentParts, newLoanProperties] = *ret;
687+
auto const newState = newLoanProperties.loanState;
688+
689+
// value change should be equal to interest decrease
690+
BEAST_EXPECTS(
691+
actualPaymentParts.valueChange ==
692+
newState.interestDue - loanProperites.loanState.interestDue,
693+
" valueChange mismatch: expected " +
694+
to_string(
695+
newState.interestDue -
696+
loanProperites.loanState.interestDue) +
697+
", got " + to_string(actualPaymentParts.valueChange));
698+
699+
BEAST_EXPECTS(
700+
actualPaymentParts.feePaid ==
701+
loanProperites.loanState.managementFeeDue -
702+
newState.managementFeeDue,
703+
" feePaid mismatch: expected " +
704+
to_string(
705+
loanProperites.loanState.managementFeeDue -
706+
newState.managementFeeDue) +
707+
", got " + to_string(actualPaymentParts.feePaid));
708+
709+
BEAST_EXPECTS(
710+
actualPaymentParts.principalPaid ==
711+
loanProperites.loanState.principalOutstanding -
712+
newState.principalOutstanding,
713+
" principalPaid mismatch: expected " +
714+
to_string(
715+
loanProperites.loanState.principalOutstanding -
716+
newState.principalOutstanding) +
717+
", got " + to_string(actualPaymentParts.principalPaid));
718+
719+
BEAST_EXPECTS(
720+
actualPaymentParts.interestPaid ==
721+
loanProperites.loanState.interestDue - newState.interestDue,
722+
" interestPaid mismatch: expected " +
723+
to_string(
724+
loanProperites.loanState.interestDue -
725+
newState.interestDue) +
726+
", got " + to_string(actualPaymentParts.interestPaid));
727+
}
728+
623729
public:
624730
void
625731
run() override
626732
{
733+
testTryOverpaymentValueChange();
627734
testComputeFullPaymentInterest();
628735
testLoanAccruedInterest();
629736
testLoanLatePaymentInterest();

src/test/app/Loan_test.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -700,8 +700,7 @@ class Loan_test : public beast::unit_test::suite
700700
interval,
701701
total,
702702
feeRate,
703-
asset(brokerParams.vaultDeposit).number().exponent(),
704-
env.journal);
703+
asset(brokerParams.vaultDeposit).number().exponent());
705704
log << "Loan properties:\n"
706705
<< "\tPrincipal: " << principal << std::endl
707706
<< "\tInterest rate: " << interest << std::endl
@@ -1483,8 +1482,7 @@ class Loan_test : public beast::unit_test::suite
14831482
state.paymentInterval,
14841483
state.paymentRemaining,
14851484
broker.params.managementFeeRate,
1486-
state.loanScale,
1487-
env.journal);
1485+
state.loanScale);
14881486

14891487
verifyLoanStatus(
14901488
0,

src/xrpld/app/misc/LendingHelpers.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,18 @@ struct LoanStateDeltas
362362
nonNegative();
363363
};
364364

365+
Expected<std::pair<LoanPaymentParts, LoanProperties>, TER>
366+
tryOverpayment(
367+
Asset const& asset,
368+
std::int32_t loanScale,
369+
ExtendedPaymentComponents const& overpaymentComponents,
370+
LoanState const& roundedLoanState,
371+
Number const& periodicPayment,
372+
Number const& periodicRate,
373+
std::uint32_t paymentRemaining,
374+
TenthBips16 const managementFeeRate,
375+
beast::Journal j);
376+
365377
Number
366378
computeRaisedRate(Number const& periodicRate, std::uint32_t paymentsRemaining);
367379

0 commit comments

Comments
 (0)