Compare commits

...

1 Commits

Author SHA1 Message Date
Vito
9448d82fd1 removes liquidation rate field 2026-01-27 17:32:00 +01:00
11 changed files with 23 additions and 101 deletions

View File

@@ -514,7 +514,6 @@ LEDGER_ENTRY(ltLOAN_BROKER, 0x0088, LoanBroker, loan_broker, ({
{sfDebtMaximum, soeDEFAULT},
{sfCoverAvailable, soeDEFAULT},
{sfCoverRateMinimum, soeDEFAULT},
{sfCoverRateLiquidation, soeDEFAULT},
}))
/** A ledger object representing a loan between a Borrower and a Loan Broker

View File

@@ -108,7 +108,6 @@ TYPED_SFIELD(sfPaymentRemaining, UINT32, 59)
TYPED_SFIELD(sfPaymentTotal, UINT32, 60)
TYPED_SFIELD(sfLoanSequence, UINT32, 61)
TYPED_SFIELD(sfCoverRateMinimum, UINT32, 62) // 1/10 basis points (bips)
TYPED_SFIELD(sfCoverRateLiquidation, UINT32, 63) // 1/10 basis points (bips)
TYPED_SFIELD(sfOverpaymentFee, UINT32, 64) // 1/10 basis points (bips)
TYPED_SFIELD(sfInterestRate, UINT32, 65) // 1/10 basis points (bips)
TYPED_SFIELD(sfLateInterestRate, UINT32, 66) // 1/10 basis points (bips)

View File

@@ -941,7 +941,6 @@ TRANSACTION(ttLOAN_BROKER_SET, 74, LoanBrokerSet,
{sfManagementFeeRate, soeOPTIONAL},
{sfDebtMaximum, soeOPTIONAL},
{sfCoverRateMinimum, soeOPTIONAL},
{sfCoverRateLiquidation, soeOPTIONAL},
}))
/** This transaction deletes a Loan Broker */

View File

@@ -2738,8 +2738,7 @@ class Batch_test : public beast::unit_test::suite
env(set(lender, vaultKeylet.key),
managementFeeRate(TenthBips16(100)),
debtMaximum(debtMaximumValue),
coverRateMinimum(TenthBips32(percentageToTenthBips(10))),
coverRateLiquidation(TenthBips32(percentageToTenthBips(25))));
coverRateMinimum(TenthBips32(percentageToTenthBips(10))));
env(coverDeposit(lender, brokerKeylet.key, coverDepositValue));

View File

@@ -1850,9 +1850,6 @@ class Invariants_test : public beast::unit_test::suite
sle->at(sfManagementFeeRate) += 1;
},
[](SLE::pointer& sle) { sle->at(sfCoverRateMinimum) += 1; },
[](SLE::pointer& sle) {
sle->at(sfCoverRateLiquidation) += 1;
},
[](SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; },
[](SLE::pointer& sle) {
sle->at(sfLedgerIndex) = sle->at(sfVaultID).value();

View File

@@ -667,39 +667,13 @@ class LoanBroker_test : public beast::unit_test::suite
env(set(evan, vault.vaultID),
managementFeeRate(maxManagementFeeRate + TenthBips16(10)),
ter(temINVALID));
// sfCoverRateMinimum and sfCoverRateLiquidation are linked
// Cover: good value, bad account
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate),
coverRateLiquidation(maxCoverRate),
ter(tecNO_PERMISSION));
// CoverMinimum: too big
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate + 1),
coverRateLiquidation(maxCoverRate + 1),
ter(temINVALID));
// CoverLiquidation: too big
env(set(evan, vault.vaultID),
coverRateMinimum(maxCoverRate / 2),
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),
@@ -730,13 +704,10 @@ class LoanBroker_test : public beast::unit_test::suite
// Extra checks
BEAST_EXPECT(!broker->isFieldPresent(sfManagementFeeRate));
BEAST_EXPECT(!broker->isFieldPresent(sfCoverRateMinimum));
BEAST_EXPECT(
!broker->isFieldPresent(sfCoverRateLiquidation));
BEAST_EXPECT(!broker->isFieldPresent(sfData));
BEAST_EXPECT(!broker->isFieldPresent(sfDebtMaximum));
BEAST_EXPECT(broker->at(sfDebtMaximum) == 0);
BEAST_EXPECT(broker->at(sfCoverRateMinimum) == 0);
BEAST_EXPECT(broker->at(sfCoverRateLiquidation) == 0);
BEAST_EXPECT(
env.ownerCount(alice) == aliceOriginalCount + 4);
@@ -776,12 +747,6 @@ class LoanBroker_test : public beast::unit_test::suite
coverRateMinimum(maxManagementFeeRate),
ter(temINVALID),
THISLINE);
// CoverRateLiquidation
env(set(alice, vault.vaultID),
loanBrokerID(broker->key()),
coverRateLiquidation(maxManagementFeeRate),
ter(temINVALID),
THISLINE);
// fields that can be changed
testData = "Test Data 1234";
@@ -846,14 +811,12 @@ class LoanBroker_test : public beast::unit_test::suite
data(testData),
managementFeeRate(TenthBips16(123)),
debtMaximum(Number(9)),
coverRateMinimum(TenthBips32(100)),
coverRateLiquidation(TenthBips32(200)));
coverRateMinimum(TenthBips32(100)));
},
[&](SLE::const_ref broker) {
// Extra checks
BEAST_EXPECT(broker->at(sfManagementFeeRate) == 123);
BEAST_EXPECT(broker->at(sfCoverRateMinimum) == 100);
BEAST_EXPECT(broker->at(sfCoverRateLiquidation) == 200);
BEAST_EXPECT(broker->at(sfDebtMaximum) == Number(9));
BEAST_EXPECT(checkVL(broker->at(sfData), testData));
},

View File

@@ -83,7 +83,6 @@ protected:
TenthBips32 coverRateMin = percentageToTenthBips(10);
int coverDeposit = 1000;
TenthBips16 managementFeeRate{100};
TenthBips32 coverRateLiquidation = percentageToTenthBips(25);
std::string data{};
std::uint32_t flags = 0;
@@ -490,8 +489,7 @@ protected:
data(params.data),
managementFeeRate(params.managementFeeRate),
debtMaximum(debtMaximumValue),
coverRateMinimum(coverRateMinValue),
coverRateLiquidation(TenthBips32(params.coverRateLiquidation)));
coverRateMinimum(coverRateMinValue));
if (coverDepositValue != beast::zero)
env(coverDeposit(lender, keylet.key, coverDepositValue));
@@ -2119,10 +2117,8 @@ protected:
broker.asset,
std::min(
tenthBipsOfValue(
tenthBipsOfValue(
brokerSle->at(sfDebtTotal),
broker.params.coverRateMin),
broker.params.coverRateLiquidation),
brokerSle->at(sfDebtTotal),
broker.params.coverRateMin),
state.totalValue - state.managementFeeOutstanding),
state.loanScale);
return std::make_pair(defaultAmount, brokerSle->at(sfOwner));
@@ -6396,8 +6392,7 @@ protected:
BrokerParameters brokerParams{
.vaultDeposit = 10000,
.debtMax = Number{0},
.coverRateMin = TenthBips32{1000},
.coverRateLiquidation = TenthBips32{2500}};
.coverRateMin = TenthBips32{1000}};
auto broker = createVaultAndBroker(env, asset, lender, brokerParams);
@@ -6529,9 +6524,7 @@ protected:
BrokerParameters const brokerParams{
.vaultDeposit = 100000,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
// .managementFeeRate = TenthBips16{5919},
.coverRateLiquidation = TenthBips32{0}};
.coverRateMin = TenthBips32{0}};
LoanParameters const loanParams{
.account = lender,
.counter = borrower,
@@ -6560,8 +6553,10 @@ protected:
auto state = getCurrentState(env, broker, loanKeylet);
if (auto loan = env.le(loanKeylet); BEAST_EXPECT(loan))
{
env.close(tp{d{
loan->at(sfNextPaymentDueDate) + loan->at(sfGracePeriod) + 1}});
env.close(
tp{
d{loan->at(sfNextPaymentDueDate) + loan->at(sfGracePeriod) +
1}});
}
topUpBorrower(
@@ -6606,8 +6601,7 @@ protected:
.vaultDeposit = 200'000,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
.managementFeeRate = TenthBips16{500},
.coverRateLiquidation = TenthBips32{0}};
.managementFeeRate = TenthBips16{500}};
LoanParameters const loanParams{
.account = lender,
.counter = borrower,
@@ -6827,8 +6821,7 @@ protected:
.vaultDeposit = 10,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
.managementFeeRate = TenthBips16{0},
.coverRateLiquidation = TenthBips32{0}};
.managementFeeRate = TenthBips16{0}};
LoanParameters const loanParams{
.account = lender,
.counter = borrower,
@@ -7005,8 +6998,7 @@ protected:
.vaultDeposit = 100'000,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
.managementFeeRate = TenthBips16{0},
.coverRateLiquidation = TenthBips32{0}};
.managementFeeRate = TenthBips16{0}};
LoanParameters const loanParams{
.account = lender,
.counter = issuer,
@@ -7055,8 +7047,7 @@ protected:
.vaultDeposit = 100'000,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
.managementFeeRate = TenthBips16{0},
.coverRateLiquidation = TenthBips32{0}};
.managementFeeRate = TenthBips16{0}};
LoanParameters const loanParams{
.account = lender,
.counter = borrower,
@@ -7554,8 +7545,7 @@ protected:
.debtMax = 0,
.coverRateMin = TenthBips32(20000), // 20%
.coverDeposit = 21'000,
.managementFeeRate = TenthBips16(100), // 0.1%
.coverRateLiquidation = TenthBips32(100000),
.managementFeeRate = TenthBips16(100),
});
auto const brokerKeylet = brokerInfo.brokerKeylet();
@@ -7813,8 +7803,7 @@ class LoanArbitrary_test : public LoanBatch_test
.vaultDeposit = 10000,
.debtMax = 0,
.coverRateMin = TenthBips32{0},
.managementFeeRate = TenthBips16{0},
.coverRateLiquidation = TenthBips32{0}};
.managementFeeRate = TenthBips16{0}};
LoanParameters const loanParams{
.account = Account("lender"),
.counter = Account("borrower"),

View File

@@ -755,9 +755,6 @@ auto const debtMaximum = simpleField<SF_NUMBER>(sfDebtMaximum);
auto const coverRateMinimum =
valueUnitWrapper<SF_UINT32, unit::TenthBipsTag>(sfCoverRateMinimum);
auto const coverRateLiquidation =
valueUnitWrapper<SF_UINT32, unit::TenthBipsTag>(sfCoverRateLiquidation);
auto const destination = JTxFieldWrapper<accountIDField>(sfDestination);
} // namespace loanBroker

View File

@@ -2270,8 +2270,7 @@ NoModifiedUnmodifiableFields::finalize(
fieldChanged(before, after, sfAccount) ||
fieldChanged(before, after, sfOwner) ||
fieldChanged(before, after, sfManagementFeeRate) ||
fieldChanged(before, after, sfCoverRateMinimum) ||
fieldChanged(before, after, sfCoverRateLiquidation);
fieldChanged(before, after, sfCoverRateMinimum);
break;
case ltLOAN:
/*
@@ -2707,8 +2706,9 @@ ValidVault::visitEntry(
// At this moment we have no way of telling if this object holds
// vault shares or something else. Save it for finalize.
afterMPTs_.push_back(Shares::make(*after));
balanceDelta -= Number(static_cast<std::int64_t>(
after->getFieldU64(sfOutstandingAmount)));
balanceDelta -= Number(
static_cast<std::int64_t>(
after->getFieldU64(sfOutstandingAmount)));
sign = 1;
break;
case ltMPTOKEN:

View File

@@ -25,8 +25,6 @@ LoanBrokerSet::preflight(PreflightContext const& ctx)
return temINVALID;
if (!validNumericRange(tx[~sfCoverRateMinimum], maxCoverRate))
return temINVALID;
if (!validNumericRange(tx[~sfCoverRateLiquidation], maxCoverRate))
return temINVALID;
if (!validNumericRange(
tx[~sfDebtMaximum], Number(maxMPTokenAmount), Number(0)))
return temINVALID;
@@ -36,8 +34,7 @@ LoanBrokerSet::preflight(PreflightContext const& ctx)
// Fixed fields can not be specified if we're modifying an existing
// LoanBroker Object
if (tx.isFieldPresent(sfManagementFeeRate) ||
tx.isFieldPresent(sfCoverRateMinimum) ||
tx.isFieldPresent(sfCoverRateLiquidation))
tx.isFieldPresent(sfCoverRateMinimum))
return temINVALID;
if (tx[sfLoanBrokerID] == beast::zero)
@@ -50,17 +47,6 @@ 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;
}
@@ -260,8 +246,6 @@ LoanBrokerSet::doApply()
broker->at(sfDebtMaximum) = *debtMax;
if (auto const coverMin = tx[~sfCoverRateMinimum])
broker->at(sfCoverRateMinimum) = *coverMin;
if (auto const coverLiq = tx[~sfCoverRateLiquidation])
broker->at(sfCoverRateLiquidation) = *coverLiq;
view.insert(broker);

View File

@@ -151,8 +151,6 @@ LoanManage::defaultLoan(
// Apply the First-Loss Capital to the Default Amount
TenthBips32 const coverRateMinimum{brokerSle->at(sfCoverRateMinimum)};
TenthBips32 const coverRateLiquidation{
brokerSle->at(sfCoverRateLiquidation)};
auto const defaultCovered = [&]() {
// Always round the minimum required up.
NumberRoundModeGuard mg(Number::upward);
@@ -166,9 +164,7 @@ LoanManage::defaultLoan(
* Changes), specifically "if the `tfLoanDefault` flag is set" /
* "Apply the First-Loss Capital to the Default Amount"
*/
std::min(
tenthBipsOfValue(minimumCover, coverRateLiquidation),
totalDefaultAmount),
std::min(minimumCover, totalDefaultAmount),
loanScale);
auto const coverAvailable = *brokerSle->at(sfCoverAvailable);