refactor: Gate loan impairment fix behind fixCleanup3_4_0

Switches the impair/unimpair behaviour change (reject non-late impair
with tecTOO_SOON; stop rewriting sfNextPaymentDueDate on impair/unimpair)
from featureLendingProtocolV1_1 to fixCleanup3_4_0, along with the
associated tests.
This commit is contained in:
Vito
2026-08-17 12:23:10 +02:00
parent daf2c7934c
commit 5bd363b3d0
3 changed files with 18 additions and 18 deletions

View File

@@ -287,7 +287,7 @@ LoanManage::impairLoan(
Asset const& vaultAsset,
beast::Journal j)
{
if (view.rules().enabled(featureLendingProtocolV1_1) && !isPaymentLate(view, loanSle))
if (view.rules().enabled(fixCleanup3_4_0) && !isPaymentLate(view, loanSle))
{
JLOG(j.warn()) << "Cannot impair a loan that is not late";
return tecTOO_SOON;
@@ -315,7 +315,7 @@ LoanManage::impairLoan(
// Update the Loan object
loanSle->setFlag(lsfLoanImpaired);
if (!view.rules().enabled(featureLendingProtocolV1_1))
if (!view.rules().enabled(fixCleanup3_4_0))
{
auto loanNextDueProxy = loanSle->at(sfNextPaymentDueDate);
if (!isPaymentLate(view, loanSle))
@@ -359,7 +359,7 @@ LoanManage::unimpairLoan(
// Update the Loan object
loanSle->clearFlag(lsfLoanImpaired);
if (!view.rules().enabled(featureLendingProtocolV1_1))
if (!view.rules().enabled(fixCleanup3_4_0))
{
auto const paymentInterval = loanSle->at(sfPaymentInterval);
auto const normalPaymentDueDate =

View File

@@ -542,10 +542,10 @@ private:
return std::make_tuple(broker, loanKeylet, lender, borrower);
};
// Under featureLendingProtocolV1_1 impairment is only allowed once the
// Under fixCleanup3_4_0 impairment is only allowed once the
// payment is late. Advance past the first due date before impairing.
auto advancePastDueDate = [&](Env& env, Keylet const& loanKeylet) {
if (!env.current()->rules().enabled(featureLendingProtocolV1_1))
if (!env.current()->rules().enabled(fixCleanup3_4_0))
return;
auto const loan = env.le(loanKeylet);
BEAST_EXPECT(loan);
@@ -835,7 +835,7 @@ private:
Number const managementFeeBeforeImpair = loanBeforeImpair->at(sfManagementFeeOutstanding);
Number const expectedExposure = totalValueBeforeImpair - managementFeeBeforeImpair;
// With featureLendingProtocolV1_1, impairment is only allowed once the
// With fixCleanup3_4_0, impairment is only allowed once the
// payment is late. After the earlier LoanPay the due date advanced by
// one interval, so use the current due date rather than startDate.
std::uint32_t const dueDateBeforeImpair = loanBeforeImpair->at(sfNextPaymentDueDate);

View File

@@ -512,7 +512,7 @@ private:
PaymentParameters{.showStepBalances = true});
}
// Verify that with featureLendingProtocolV1_1:
// Verify that with fixCleanup3_4_0:
// 1. A loan cannot be impaired before its payment is late.
// 2. Impairing a late loan does not change sfNextPaymentDueDate.
// 3. The unimpair operation does not change sfNextPaymentDueDate.
@@ -525,8 +525,8 @@ private:
testcase("Impairment does not change payment due date");
Env env(*this, all_ | featureLendingProtocolV1_1);
BEAST_EXPECT(env.enabled(featureLendingProtocolV1_1));
Env env(*this, all_ | fixCleanup3_4_0);
BEAST_EXPECT(env.enabled(fixCleanup3_4_0));
Account const lender{"lender"};
Account const borrower{"borrower"};
@@ -590,7 +590,7 @@ private:
}
}
// Verify that without featureLendingProtocolV1_1, the pre-amendment
// Verify that without fixCleanup3_4_0, the pre-amendment
// impair/unimpair behaviour is preserved:
// 1. Impairing a loan before its payment is late moves
// sfNextPaymentDueDate to "now".
@@ -607,8 +607,8 @@ private:
testcase("Pre-amendment impair/unimpair date restoration");
Env env(*this, all_ - featureLendingProtocolV1_1);
BEAST_EXPECT(!env.enabled(featureLendingProtocolV1_1));
Env env(*this, all_ - fixCleanup3_4_0);
BEAST_EXPECT(!env.enabled(fixCleanup3_4_0));
Account const lender{"lender"};
Account const borrower{"borrower"};
@@ -729,7 +729,7 @@ private:
// FN-68: a borrower must not be able to bypass late-payment charges by
// paying an impaired, overdue loan with a plain LoanPay. Under
// featureLendingProtocolV1_1 impairment no longer moves the due date, so
// fixCleanup3_4_0 impairment no longer moves the due date, so
// the payment logic sees the real (overdue) date: a regular payment is
// rejected with tecEXPIRED, and only a tfLoanLatePayment (which charges
// the late fee + late interest) is accepted.
@@ -742,8 +742,8 @@ private:
testcase("Impaired overdue LoanPay requires late-payment flag");
Env env(*this, all_ | featureLendingProtocolV1_1);
BEAST_EXPECT(env.enabled(featureLendingProtocolV1_1));
Env env(*this, all_ | fixCleanup3_4_0);
BEAST_EXPECT(env.enabled(fixCleanup3_4_0));
Account const lender{"lender"};
Account const borrower{"borrower"};
@@ -830,7 +830,7 @@ private:
}
// FN-68 (pre-amendment): documents the original vulnerability. Without
// featureLendingProtocolV1_1, impairing moves the due date and LoanPay
// fixCleanup3_4_0, impairing moves the due date and LoanPay
// auto-unimpair pushes it into the future before the late check, so a
// plain (Flags = 0) LoanPay on an impaired, overdue loan is accepted as
// on-time (tesSUCCESS) and the borrower dodges the late-payment charges.
@@ -845,8 +845,8 @@ private:
testcase("Impaired overdue LoanPay bypass (pre-amendment)");
Env env(*this, all_ - featureLendingProtocolV1_1);
BEAST_EXPECT(!env.enabled(featureLendingProtocolV1_1));
Env env(*this, all_ - fixCleanup3_4_0);
BEAST_EXPECT(!env.enabled(fixCleanup3_4_0));
Account const lender{"lender"};
Account const borrower{"borrower"};