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.
This commit is contained in:
Vito
2026-07-27 11:49:22 +02:00
parent 20358587ce
commit 9a2b4b7dc4
6 changed files with 45 additions and 46 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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

View File

@@ -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)

View File

@@ -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);