Update the test case for RIPD-3459 with more detailed output data

This commit is contained in:
Ed Hennis
2025-11-08 22:47:50 -05:00
parent 4fbf687166
commit 43174d31d1

View File

@@ -651,14 +651,13 @@ protected:
void
describeLoan(
jtx::Env& env,
BrokerParameters const& brokerParams,
LoanParameters const& loanParams,
AssetType assetType)
{
using namespace jtx;
Env env(*this);
auto const asset = createAsset(
env,
assetType,
@@ -672,18 +671,20 @@ protected:
loanParams.payInterval.value_or(LoanSet::defaultPaymentInterval);
auto const total =
loanParams.payTotal.value_or(LoanSet::defaultPaymentTotal);
auto const feeRate = brokerParams.managementFeeRate;
auto const props = computeLoanProperties(
asset,
principal,
interest,
interval,
total,
brokerParams.managementFeeRate,
feeRate,
asset(brokerParams.vaultDeposit).number().exponent());
log << "Loan properties:\n"
<< "\tPrincipal: " << principal << std::endl
<< "\tInterest rate: " << interest << std::endl
<< "\tPayment interval: " << interval << std::endl
<< "\tManagement Fee Rate: " << feeRate << std::endl
<< "\tTotal Payments: " << total << std::endl
<< "\tPeriodic Payment: " << props.periodicPayment << std::endl
<< "\tTotal Value: " << props.totalValueOutstanding << std::endl
@@ -721,6 +722,8 @@ protected:
issuer,
noripple(lender, borrower));
describeLoan(env, brokerParams, loanParams, assetType);
// Make the asset
auto const asset =
createAsset(env, assetType, brokerParams, issuer, lender, borrower);
@@ -815,7 +818,8 @@ protected:
BrokerInfo const& broker,
LoanParameters const& loanParams,
Keylet const& loanKeylet,
VerifyLoanStatus const& verifyLoanStatus)
VerifyLoanStatus const& verifyLoanStatus,
bool showStepBalances = false)
{
// Make all the individual payments
using namespace jtx;
@@ -859,11 +863,14 @@ protected:
roundPeriodicPayment(
broker.asset, state.periodicPayment, state.loanScale)};
log << currencyLabel << " Payment components: "
<< "Payments remaining, rawInterest, rawPrincipal, "
"rawMFee, trackedValueDelta, trackedPrincipalDelta, "
"trackedInterestDelta, trackedMgmtFeeDelta, special"
<< std::endl;
if (!showStepBalances)
log << currencyLabel << " Payment components: "
<< "Payments remaining, "
<< "rawInterest, rawPrincipal, "
"rawMFee, "
<< "trackedValueDelta, trackedPrincipalDelta, "
"trackedInterestDelta, trackedMgmtFeeDelta, special"
<< std::endl;
// Include the service fee
STAmount const totalDue = roundToScale(
@@ -881,13 +888,28 @@ protected:
state.totalValue,
state.principalOutstanding,
state.managementFeeOutstanding);
log << currencyLabel
<< " Loan starting state: " << state.paymentRemaining << ", "
<< raw.interestDue << ", " << raw.principalOutstanding << ", "
<< raw.managementFeeDue << ", " << rounded.valueOutstanding
<< ", " << rounded.principalOutstanding << ", "
<< rounded.interestDue << ", " << rounded.managementFeeDue
<< std::endl;
if (showStepBalances)
{
log << currencyLabel << " Starting loan balances: "
<< "\n\tTotal value: " << rounded.valueOutstanding
<< "\n\tPrincipal: " << rounded.principalOutstanding
<< "\n\tInterest: " << rounded.interestDue
<< "\n\tMgmt fee: " << rounded.managementFeeDue
<< "\n\tPayments remaining " << state.paymentRemaining
<< std::endl;
}
else
{
log << currencyLabel
<< " Loan starting state: " << state.paymentRemaining
<< ", " << raw.interestDue << ", "
<< raw.principalOutstanding << ", " << raw.managementFeeDue
<< ", " << rounded.valueOutstanding << ", "
<< rounded.principalOutstanding << ", "
<< rounded.interestDue << ", " << rounded.managementFeeDue
<< std::endl;
}
}
// Try to pay a little extra to show that it's _not_
@@ -922,6 +944,11 @@ protected:
env.balance(borrower, broker.asset).number() ==
borrowerInitialBalance - totalSpent);
};
auto truncate = [](Number const& n, int places = 3) {
auto const factor = Number{1, places};
return (n * factor).truncate() / factor;
};
while (state.paymentRemaining > 0)
{
validateBorrowerBalance();
@@ -967,22 +994,24 @@ protected:
(deltas.valueDelta() - state.periodicPayment).exponent()) >
14);
log << currencyLabel
<< " Payment components: " << state.paymentRemaining << ", "
<< deltas.interestDueDelta << ", " << deltas.principalDelta
<< ", " << deltas.managementFeeDueDelta << ", "
<< paymentComponents.trackedValueDelta << ", "
<< paymentComponents.trackedPrincipalDelta << ", "
<< paymentComponents.trackedInterestPart() << ", "
<< paymentComponents.trackedManagementFeeDelta << ", "
<< (paymentComponents.specialCase ==
detail::PaymentSpecialCase::final
? "final"
: paymentComponents.specialCase ==
detail::PaymentSpecialCase::extra
? "extra"
: "none")
<< std::endl;
if (!showStepBalances)
log << currencyLabel
<< " Payment components: " << state.paymentRemaining << ", "
<< deltas.interestDueDelta << ", " << deltas.principalDelta
<< ", " << deltas.managementFeeDueDelta << ", "
<< paymentComponents.trackedValueDelta << ", "
<< paymentComponents.trackedPrincipalDelta << ", "
<< paymentComponents.trackedInterestPart() << ", "
<< paymentComponents.trackedManagementFeeDelta << ", "
<< (paymentComponents.specialCase ==
detail::PaymentSpecialCase::final
? "final"
: paymentComponents.specialCase ==
detail::PaymentSpecialCase::extra
? "extra"
: "none")
<< std::endl;
auto const totalDueAmount = STAmount{
broker.asset, paymentComponents.trackedValueDelta + serviceFee};
@@ -1037,6 +1066,34 @@ protected:
totalDueAmount,
adjustment);
if (showStepBalances)
{
auto const loanSle = env.le(loanKeylet);
if (!BEAST_EXPECT(loanSle))
// No reason for this not to exist
return;
auto const current = calculateRoundedLoanState(loanSle);
auto const errors = nextTrueState - current;
log << currencyLabel << " Loan balances: "
<< "\n\tAmount taken: "
<< paymentComponents.trackedValueDelta
<< "\n\tTotal value: " << current.valueOutstanding
<< " (true: " << truncate(nextTrueState.valueOutstanding)
<< ", error: " << truncate(errors.valueDelta())
<< ")\n\tPrincipal: " << current.principalOutstanding
<< " (true: "
<< truncate(nextTrueState.principalOutstanding)
<< ", error: " << truncate(errors.principalDelta)
<< ")\n\tInterest: " << current.interestDue
<< " (true: " << truncate(nextTrueState.interestDue)
<< ", error: " << truncate(errors.interestDueDelta)
<< ")\n\tMgmt fee: " << current.managementFeeDue
<< " (true: " << truncate(nextTrueState.managementFeeDue)
<< ", error: " << truncate(errors.managementFeeDueDelta)
<< ")\n\tPayments remaining "
<< loanSle->at(sfPaymentRemaining) << std::endl;
}
--state.paymentRemaining;
state.previousPaymentDate = state.nextPaymentDate;
if (paymentComponents.specialCase ==
@@ -1083,12 +1140,43 @@ protected:
initialState.managementFeeOutstanding);
// This is almost a tautology given the previous checks, but
// check it anyway for completeness.
BEAST_EXPECT(
totalInterestPaid ==
initialState.totalValue -
(initialState.principalOutstanding +
initialState.managementFeeOutstanding));
auto const initialInterestDue = initialState.totalValue -
(initialState.principalOutstanding +
initialState.managementFeeOutstanding);
BEAST_EXPECT(totalInterestPaid == initialInterestDue);
BEAST_EXPECT(totalPaymentsMade == initialState.paymentRemaining);
if (showStepBalances)
{
auto const loanSle = env.le(loanKeylet);
if (!BEAST_EXPECT(loanSle))
// No reason for this not to exist
return;
log << currencyLabel << " Total amounts paid: "
<< "\n\tTotal value: " << totalPaid.trackedValueDelta
<< " (initial: " << truncate(initialState.totalValue)
<< ", error: "
<< truncate(
initialState.totalValue - totalPaid.trackedValueDelta)
<< ")\n\tPrincipal: " << totalPaid.trackedPrincipalDelta
<< " (initial: " << truncate(initialState.principalOutstanding)
<< ", error: "
<< truncate(
initialState.principalOutstanding -
totalPaid.trackedPrincipalDelta)
<< ")\n\tInterest: " << totalInterestPaid
<< " (initial: " << truncate(initialInterestDue) << ", error: "
<< truncate(initialInterestDue - totalInterestPaid)
<< ")\n\tMgmt fee: " << totalPaid.trackedManagementFeeDelta
<< " (initial: "
<< truncate(initialState.managementFeeOutstanding)
<< ", error: "
<< truncate(
initialState.managementFeeOutstanding -
totalPaid.trackedManagementFeeDelta)
<< ")\n\tTotal payments made: " << totalPaymentsMade
<< std::endl;
}
}
void
@@ -6222,8 +6310,6 @@ protected:
auto const assetType = AssetType::XRP;
describeLoan(brokerParams, loanParams, assetType);
Env env(*this, all);
auto loanResult = createLoan(
@@ -6241,8 +6327,8 @@ protected:
auto state = getCurrentState(env, broker, loanKeylet);
if (auto loan = env.le(loanKeylet); BEAST_EXPECT(loan))
{
log << "loan after create: " << to_string(loan->getJson())
<< std::endl;
// log << "loan after create: " << to_string(loan->getJson())
// << std::endl;
env.close(tp{d{
loan->at(sfNextPaymentDueDate) + loan->at(sfGracePeriod) + 1}});
@@ -6258,10 +6344,10 @@ protected:
{
auto const submitParam = to_string(jv);
log << "about to submit: " << submitParam << std::endl;
// log << "about to submit: " << submitParam << std::endl;
auto const jr = env.rpc("submit", borrower.name(), submitParam);
log << jr << std::endl;
// log << jr << std::endl;
BEAST_EXPECT(jr.isMember(jss::result));
auto const jResult = jr[jss::result];
// BEAST_EXPECT(jResult[jss::error] == "invalidTransaction");
@@ -6296,7 +6382,7 @@ protected:
.vaultDeposit = 200'000,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
// .managementFeeRate = TenthBips16{5919},
.managementFeeRate = TenthBips16{500},
.coverRateLiquidation = TenthBips32{0}};
LoanParameters const loanParams{
.account = lender,
@@ -6310,8 +6396,6 @@ protected:
auto const assetType = AssetType::MPT;
describeLoan(brokerParams, loanParams, assetType);
Env env(*this, all);
auto loanResult = createLoan(
@@ -6337,18 +6421,18 @@ protected:
}
}
makeLoanPayments(env, broker, loanParams, loanKeylet, verifyLoanStatus);
makeLoanPayments(
env, broker, loanParams, loanKeylet, verifyLoanStatus, true);
if (auto const brokerSle = env.le(broker.brokerKeylet());
BEAST_EXPECT(brokerSle))
{
if (auto const loanSle = env.le(loanKeylet); BEAST_EXPECT(loanSle))
{
log << pretty(brokerSle->getJson()) << std::endl
<< pretty(loanSle->getJson()) << std::endl;
BEAST_EXPECT(
brokerSle->at(sfDebtTotal) ==
loanSle->at(sfTotalValueOutstanding));
BEAST_EXPECT(brokerSle->at(sfDebtTotal) == beast::zero);
}
}
}
@@ -6531,8 +6615,6 @@ class LoanArbitrary_test : public LoanBatch_test
// .payTotal = 5816,
.payInterval = 150};
describeLoan(brokerParams, loanParams, AssetType::XRP);
runLoan(AssetType::XRP, brokerParams, loanParams);
}
};