fix: LoanBrokerSet is malformed if Cover fields don't align

- sfCoverRateMinimum and sfCoverRateLiquidation must be both zero or
  both non-zero, because both are used in the default amount
  calculations, which is the only place they're really meaningful.
This commit is contained in:
Ed Hennis
2025-11-03 12:31:20 -05:00
parent b472cc3493
commit 4920e65b14
3 changed files with 36 additions and 10 deletions

View File

@@ -658,6 +658,8 @@ class LoanBroker_test : public beast::unit_test::suite
using namespace loanBroker;
TenthBips32 const tenthBipsZero{0};
auto badKeylet = keylet::vault(alice.id(), env.seq(alice));
// Try some failure cases
// not the vault owner
@@ -683,22 +685,35 @@ class LoanBroker_test : public beast::unit_test::suite
env(set(evan, vault.vaultID),
managementFeeRate(maxManagementFeeRate + TenthBips16(10)),
ter(temINVALID));
// sfCoverRateMinimum: good value, bad account
// sfCoverRateMinimum and sfCoverRateLiquidation are linked
// Cover: good value, bad account
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate),
ter(tecNO_PERMISSION));
// sfCoverRateMinimum: too big
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate + 1),
ter(temINVALID));
// sfCoverRateLiquidation: good value, bad account
env(set(evan, vault.vaultID),
coverRateLiquidation(maxCoverRate),
ter(tecNO_PERMISSION));
// sfCoverRateLiquidation: too big
// Cover: too big
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate + 1),
coverRateLiquidation(maxCoverRate + 1),
ter(temINVALID));
// Cover: zero min, non-zero liquidation - implicit and
// explicit zero values.
env(set(evan, vault.vaultID),
coverRateLiquidation(maxCoverRate),
ter(temINVALID));
env(set(evan, vault.vaultID),
coverRateMinimum(tenthBipsZero),
coverRateLiquidation(maxCoverRate),
ter(temINVALID));
// Cover: non-zero min, zero liquidation - implicit and
// explicit zero values.
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate),
ter(temINVALID));
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate),
coverRateLiquidation(tenthBipsZero),
ter(temINVALID));
// sfDebtMaximum: good value, bad account
env(set(evan, vault.vaultID),
debtMaximum(Number(0)),

View File

@@ -4499,7 +4499,7 @@ class Loan_test : public beast::unit_test::suite
env.close();
BrokerInfo broker{
createVaultAndBroker(env, iouAsset, lender, Number(0), 0)};
createVaultAndBroker(env, iouAsset, lender, Number(0), 1)};
using namespace loan;

View File

@@ -56,6 +56,17 @@ LoanBrokerSet::preflight(PreflightContext const& ctx)
return temINVALID;
}
{
auto const minimumZero = tx[~sfCoverRateMinimum].value_or(0) == 0;
auto const liquidationZero =
tx[~sfCoverRateLiquidation].value_or(0) == 0;
// Both must be zero or non-zero.
if (minimumZero != liquidationZero)
{
return temINVALID;
}
}
return tesSUCCESS;
}