From 9a2b4b7dc42f8d7f1b4f3ae666e2b9d65023d96e Mon Sep 17 00:00:00 2001 From: Vito <5780819+Tapanito@users.noreply.github.com> Date: Mon, 27 Jul 2026 11:49:22 +0200 Subject: [PATCH] refactor: Drop unused rules argument from cashBasisEnabled callers cashBasisEnabled now only checks the Vault's LEVersion, so the Rules parameter threaded through loanOriginationDeltas, loanOriginationExceedsVaultMaximum, loanVaultExposure, and loanPaymentDeltas is dead weight. Remove it from the declarations, definitions, and call sites. --- include/xrpl/ledger/helpers/LendingHelpers.h | 6 ++-- src/libxrpl/ledger/helpers/LendingHelpers.cpp | 35 +++++++++++------- .../tx/transactors/lending/LoanManage.cpp | 6 ++-- .../tx/transactors/lending/LoanPay.cpp | 3 +- .../tx/transactors/lending/LoanSet.cpp | 5 ++- src/test/app/LendingHelpers_test.cpp | 36 ++++++++----------- 6 files changed, 45 insertions(+), 46 deletions(-) diff --git a/include/xrpl/ledger/helpers/LendingHelpers.h b/include/xrpl/ledger/helpers/LendingHelpers.h index 5503fe5b97..fef18e3e09 100644 --- a/include/xrpl/ledger/helpers/LendingHelpers.h +++ b/include/xrpl/ledger/helpers/LendingHelpers.h @@ -341,23 +341,21 @@ loanPaymentDeltas(LoanPaymentParts const& parts); // transactors call. AccountingDeltas loanOriginationDeltas( - Rules const& rules, SLE::const_ref vaultSle, Number const& principalRequested, Number const& interestDue); bool loanOriginationExceedsVaultMaximum( - Rules const& rules, SLE::const_ref vaultSle, Number const& vaultTotal, Number const& interestDue); Number -loanVaultExposure(Rules const& rules, SLE::const_ref vaultSle, SLE::const_ref loanSle); +loanVaultExposure(SLE::const_ref vaultSle, SLE::const_ref loanSle); AccountingDeltas -loanPaymentDeltas(Rules const& rules, SLE::const_ref vaultSle, LoanPaymentParts const& parts); +loanPaymentDeltas(SLE::const_ref vaultSle, LoanPaymentParts const& parts); namespace detail { // These classes and functions should only be accessed by LendingHelper diff --git a/src/libxrpl/ledger/helpers/LendingHelpers.cpp b/src/libxrpl/ledger/helpers/LendingHelpers.cpp index 4259b8eee9..dac2c67181 100644 --- a/src/libxrpl/ledger/helpers/LendingHelpers.cpp +++ b/src/libxrpl/ledger/helpers/LendingHelpers.cpp @@ -148,6 +148,13 @@ loanOriginationExceedsVaultMaximum( return vaultMaximum != 0 && interestDue > vaultMaximum - vaultTotal; } +/* +XLS-66 section 3.2.3.2, defines the default amount as + +DefaultAmount = (Loan.PrincipalOutstanding + Loan.InterestOutstanding) + +Which is equivalent to (Loan.TotalValueOutstanding - Loan.ManagementFeeOutstanding) +*/ Number loanVaultExposure(SLE::const_ref loanSle) { @@ -172,6 +179,11 @@ loanOriginationDeltas(Number const& principalRequested) return {.assetsTotalDelta = kNumZero, .debtTotalDelta = principalRequested}; } +/* + * Under CashBasis accounting, Loan default amount is: + * + * DefaultAmount = Loan.PrincipalOutstanding + */ Number loanVaultExposure(SLE::const_ref loanSle) { @@ -193,36 +205,33 @@ namespace { // VaultVersion::CashBasis). Vaults created before activation keep accrual-basis // accounting forever, even after the amendment later turns on. bool -cashBasisEnabled(Rules const& rules, SLE::const_ref vaultSle) +cashBasisEnabled(SLE::const_ref vaultSle) { - return rules.enabled(featureLendingProtocolV1_1) && - getVaultVersion(vaultSle) == VaultVersion::CashBasis; + return getVaultVersion(vaultSle) == VaultVersion::CashBasis; } } // namespace AccountingDeltas loanOriginationDeltas( - Rules const& rules, SLE::const_ref vaultSle, Number const& principalRequested, Number const& interestDue) { - return cashBasisEnabled(rules, vaultSle) + return cashBasisEnabled(vaultSle) ? CashBasis::loanOriginationDeltas(principalRequested) : Accrual::loanOriginationDeltas(principalRequested, interestDue); } bool loanOriginationExceedsVaultMaximum( - Rules const& rules, SLE::const_ref vaultSle, Number const& vaultTotal, Number const& interestDue) { // Cash-basis origination doesn't recognize interest into AssetsTotal, so // interest due can never push the vault past AssetsMaximum at origination. - if (cashBasisEnabled(rules, vaultSle)) + if (cashBasisEnabled(vaultSle)) return false; auto const vaultMaximum = vaultSle->at(sfAssetsMaximum); @@ -230,17 +239,17 @@ loanOriginationExceedsVaultMaximum( } Number -loanVaultExposure(Rules const& rules, SLE::const_ref vaultSle, SLE::const_ref loanSle) +loanVaultExposure(SLE::const_ref vaultSle, SLE::const_ref loanSle) { - return cashBasisEnabled(rules, vaultSle) ? CashBasis::loanVaultExposure(loanSle) - : Accrual::loanVaultExposure(loanSle); + return cashBasisEnabled(vaultSle) ? CashBasis::loanVaultExposure(loanSle) + : Accrual::loanVaultExposure(loanSle); } AccountingDeltas -loanPaymentDeltas(Rules const& rules, SLE::const_ref vaultSle, LoanPaymentParts const& parts) +loanPaymentDeltas(SLE::const_ref vaultSle, LoanPaymentParts const& parts) { - return cashBasisEnabled(rules, vaultSle) ? CashBasis::loanPaymentDeltas(parts) - : Accrual::loanPaymentDeltas(parts); + return cashBasisEnabled(vaultSle) ? CashBasis::loanPaymentDeltas(parts) + : Accrual::loanPaymentDeltas(parts); } namespace detail { diff --git a/src/libxrpl/tx/transactors/lending/LoanManage.cpp b/src/libxrpl/tx/transactors/lending/LoanManage.cpp index 5c71843129..a312dba3b3 100644 --- a/src/libxrpl/tx/transactors/lending/LoanManage.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanManage.cpp @@ -141,7 +141,7 @@ LoanManage::defaultLoan( std::int32_t const loanScale = loanSle->at(sfLoanScale); auto brokerDebtTotalProxy = brokerSle->at(sfDebtTotal); - Number const totalDefaultAmount = loanVaultExposure(view.rules(), vaultSle, loanSle); + Number const totalDefaultAmount = loanVaultExposure(vaultSle, loanSle); // Apply the First-Loss Capital to the Default Amount TenthBips32 const coverRateMinimum{brokerSle->at(sfCoverRateMinimum)}; @@ -287,7 +287,7 @@ LoanManage::impairLoan( Asset const& vaultAsset, beast::Journal j) { - Number const lossUnrealized = loanVaultExposure(view.rules(), vaultSle, loanSle); + Number const lossUnrealized = loanVaultExposure(vaultSle, loanSle); // The vault may be at a different scale than the loan. Reduce rounding // errors during the accounting by rounding some of the values to that @@ -336,7 +336,7 @@ LoanManage::unimpairLoan( // Update the Vault object(clear "paper loss") auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized); - Number const lossReversed = loanVaultExposure(view.rules(), vaultSle, loanSle); + Number const lossReversed = loanVaultExposure(vaultSle, loanSle); if (vaultLossUnrealizedProxy < lossReversed) { // LCOV_EXCL_START diff --git a/src/libxrpl/tx/transactors/lending/LoanPay.cpp b/src/libxrpl/tx/transactors/lending/LoanPay.cpp index 5af6107eda..0053ed496e 100644 --- a/src/libxrpl/tx/transactors/lending/LoanPay.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanPay.cpp @@ -420,8 +420,7 @@ LoanPay::doApply() // LCOV_EXCL_STOP } - auto const [assetsTotalDelta, debtTotalDelta] = - loanPaymentDeltas(view.rules(), vaultSle, *paymentParts); + auto const [assetsTotalDelta, debtTotalDelta] = loanPaymentDeltas(vaultSle, *paymentParts); JLOG(j_.debug()) << "Loan Pay: principal paid: " << paymentParts->principalPaid << ", interest paid: " << paymentParts->interestPaid diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index a4575e40b0..bafadd7c1d 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -444,8 +444,7 @@ LoanSet::doApply() "xrpl::LoanSet::doApply", "Vault is below maximum limit"); - if (loanOriginationExceedsVaultMaximum( - ctx_.view().rules(), vaultSle, vaultTotalProxy, state.interestDue)) + if (loanOriginationExceedsVaultMaximum(vaultSle, vaultTotalProxy, state.interestDue)) { JLOG(j_.warn()) << "Loan would exceed the maximum assets of the vault"; return tecLIMIT_EXCEEDED; @@ -492,7 +491,7 @@ LoanSet::doApply() auto const loanAssetsToBorrower = principalRequested - originationFee; auto const [assetsTotalDelta, debtTotalDelta] = - loanOriginationDeltas(ctx_.view().rules(), vaultSle, principalRequested, state.interestDue); + loanOriginationDeltas(vaultSle, principalRequested, state.interestDue); auto const newDebtTotal = brokerSle->at(sfDebtTotal) + debtTotalDelta; if (auto const debtMaximum = brokerSle->at(sfDebtMaximum); debtMaximum != 0 && debtMaximum < newDebtTotal) diff --git a/src/test/app/LendingHelpers_test.cpp b/src/test/app/LendingHelpers_test.cpp index 82f455ce6b..94f5813bd8 100644 --- a/src/test/app/LendingHelpers_test.cpp +++ b/src/test/app/LendingHelpers_test.cpp @@ -1672,8 +1672,8 @@ class LendingHelpers_test : public beast::unit_test::Suite testcase("loanOriginationDeltas dispatcher: amendment disabled picks Accrual"); Env env{*this}; env.disableFeature(featureLendingProtocolV1_1); - auto const deltas = loanOriginationDeltas( - env.current()->rules(), cashBasisVault, principalRequested, interestDue); + auto const deltas = + loanOriginationDeltas(cashBasisVault, principalRequested, interestDue); auto const expected = xrpl::Accrual::loanOriginationDeltas(principalRequested, interestDue); BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta); @@ -1685,8 +1685,7 @@ class LendingHelpers_test : public beast::unit_test::Suite "loanOriginationDeltas dispatcher: amendment enabled, legacy vault picks " "Accrual"); Env const env{*this}; - auto const deltas = loanOriginationDeltas( - env.current()->rules(), legacyVault, principalRequested, interestDue); + auto const deltas = loanOriginationDeltas(legacyVault, principalRequested, interestDue); auto const expected = xrpl::Accrual::loanOriginationDeltas(principalRequested, interestDue); BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta); @@ -1698,8 +1697,8 @@ class LendingHelpers_test : public beast::unit_test::Suite "loanOriginationDeltas dispatcher: amendment enabled, LEVersion == " "VaultVersion::CashBasis picks CashBasis"); Env const env{*this}; - auto const deltas = loanOriginationDeltas( - env.current()->rules(), cashBasisVault, principalRequested, interestDue); + auto const deltas = + loanOriginationDeltas(cashBasisVault, principalRequested, interestDue); auto const expected = xrpl::CashBasis::loanOriginationDeltas(principalRequested); BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta); BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta); @@ -1726,8 +1725,7 @@ class LendingHelpers_test : public beast::unit_test::Suite Env env{*this}; env.disableFeature(featureLendingProtocolV1_1); BEAST_EXPECT( - loanOriginationExceedsVaultMaximum( - env.current()->rules(), cashBasisVault, vaultTotal, interestDue) == + loanOriginationExceedsVaultMaximum(cashBasisVault, vaultTotal, interestDue) == xrpl::Accrual::loanOriginationExceedsVaultMaximum( vaultMaximum, vaultTotal, interestDue)); } @@ -1738,8 +1736,7 @@ class LendingHelpers_test : public beast::unit_test::Suite "picks Accrual"); Env const env{*this}; BEAST_EXPECT( - loanOriginationExceedsVaultMaximum( - env.current()->rules(), legacyVault, vaultTotal, interestDue) == + loanOriginationExceedsVaultMaximum(legacyVault, vaultTotal, interestDue) == xrpl::Accrual::loanOriginationExceedsVaultMaximum( vaultMaximum, vaultTotal, interestDue)); } @@ -1750,8 +1747,8 @@ class LendingHelpers_test : public beast::unit_test::Suite "VaultVersion::CashBasis picks CashBasis"); Env const env{*this}; BEAST_EXPECT( - loanOriginationExceedsVaultMaximum( - env.current()->rules(), cashBasisVault, vaultTotal, interestDue) == false); + loanOriginationExceedsVaultMaximum(cashBasisVault, vaultTotal, interestDue) == + false); } } @@ -1769,8 +1766,7 @@ class LendingHelpers_test : public beast::unit_test::Suite env.disableFeature(featureLendingProtocolV1_1); auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50}); BEAST_EXPECT( - loanVaultExposure(env.current()->rules(), cashBasisVault, sle) == - xrpl::Accrual::loanVaultExposure(sle)); + loanVaultExposure(cashBasisVault, sle) == xrpl::Accrual::loanVaultExposure(sle)); } { @@ -1778,8 +1774,7 @@ class LendingHelpers_test : public beast::unit_test::Suite Env const env{*this}; auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50}); BEAST_EXPECT( - loanVaultExposure(env.current()->rules(), legacyVault, sle) == - xrpl::Accrual::loanVaultExposure(sle)); + loanVaultExposure(legacyVault, sle) == xrpl::Accrual::loanVaultExposure(sle)); } { @@ -1790,8 +1785,7 @@ class LendingHelpers_test : public beast::unit_test::Suite Env const env{*this}; auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50}); BEAST_EXPECT( - loanVaultExposure(env.current()->rules(), cashBasisVault, sle) == - xrpl::CashBasis::loanVaultExposure(sle)); + loanVaultExposure(cashBasisVault, sle) == xrpl::CashBasis::loanVaultExposure(sle)); } } @@ -1813,7 +1807,7 @@ class LendingHelpers_test : public beast::unit_test::Suite testcase("loanPaymentDeltas dispatcher: amendment disabled picks Accrual"); Env env{*this}; env.disableFeature(featureLendingProtocolV1_1); - auto const deltas = loanPaymentDeltas(env.current()->rules(), cashBasisVault, parts); + auto const deltas = loanPaymentDeltas(cashBasisVault, parts); auto const expected = xrpl::Accrual::loanPaymentDeltas(parts); BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta); BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta); @@ -1822,7 +1816,7 @@ class LendingHelpers_test : public beast::unit_test::Suite { testcase("loanPaymentDeltas dispatcher: amendment enabled, legacy vault picks Accrual"); Env const env{*this}; - auto const deltas = loanPaymentDeltas(env.current()->rules(), legacyVault, parts); + auto const deltas = loanPaymentDeltas(legacyVault, parts); auto const expected = xrpl::Accrual::loanPaymentDeltas(parts); BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta); BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta); @@ -1834,7 +1828,7 @@ class LendingHelpers_test : public beast::unit_test::Suite "VaultVersion::CashBasis " "picks CashBasis"); Env const env{*this}; - auto const deltas = loanPaymentDeltas(env.current()->rules(), cashBasisVault, parts); + auto const deltas = loanPaymentDeltas(cashBasisVault, parts); auto const expected = xrpl::CashBasis::loanPaymentDeltas(parts); BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta); BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta);