Address AI comments

This commit is contained in:
JCW
2026-07-07 19:23:42 +01:00
parent 6d84c1c422
commit dd6c4e35c0
2 changed files with 34 additions and 1 deletions

View File

@@ -86,6 +86,15 @@ ValidLoan::finalize(
return false;
}
}
// Interest due (the total value owed less principal and management fee)
// must never be negative.
if (after->at(sfTotalValueOutstanding) - after->at(sfPrincipalOutstanding) -
after->at(sfManagementFeeOutstanding) <
beast::kZero)
{
JLOG(j.fatal()) << "Invariant failed: Loan interest due is negative";
return false;
}
// Must be positive - STNumber
for (auto const field : {
&sfPeriodicPayment,
@@ -112,7 +121,10 @@ ValidLoan::finalize(
return false;
}
if (loan->at(sfPaymentRemaining) != 0)
if (loan->at(sfPaymentRemaining) != 0 ||
loan->at(sfTotalValueOutstanding) != beast::kZero ||
loan->at(sfPrincipalOutstanding) != beast::kZero ||
loan->at(sfManagementFeeOutstanding) != beast::kZero)
{
JLOG(j.fatal()) << "Invariant failed: Loan deleted while not fully "
"paid off";

View File

@@ -3814,6 +3814,27 @@ class Invariants_test : public beast::unit_test::Suite
"the change in the loan claim"));
}
// Loan interest due (total value less principal and management fee)
// must never be negative. A neutral transaction type is used so the
// vault invariants short-circuit and only the loan check fires. The
// loan object is created directly with principal 100, total value 90
// and management fee 0, so interest due = 90 - 100 - 0 = -10 (< 0)
// while every individual field stays non-negative.
doInvariantCheck(
{"Loan interest due is negative"},
[&](Account const& a1, Account const&, ApplyContext& ac) {
auto const vaultKeylet = keylet::vault(a1.id(), ac.view().seq());
auto const loanKeylet = keylet::loan(vaultKeylet.key, 1);
auto sleLoan = std::make_shared<SLE>(loanKeylet);
sleLoan->at(sfPrincipalOutstanding) = Number(100);
sleLoan->at(sfTotalValueOutstanding) = Number(90);
sleLoan->at(sfManagementFeeOutstanding) = Number(0);
sleLoan->at(sfPeriodicPayment) = Number(1);
sleLoan->setFieldU32(sfPaymentRemaining, 1);
ac.view().insert(sleLoan);
return true;
});
// ttVAULT_SET: owner is immutable
doInvariantCheck(
{"violation of vault immutable data"},