Compare commits

..

16 Commits

Author SHA1 Message Date
Ed Hennis
238735d18b Merge branch 'develop' into ximinez/directory 2025-12-05 21:13:17 -05:00
Ed Hennis
e5cdeab184 Merge remote-tracking branch 'XRPLF/develop' into ximinez/directory
* XRPLF/develop:
  Implement Lending Protocol (unsupported) (5270)
2025-12-02 18:04:40 -05:00
Ed Hennis
2acb3fc306 Merge branch 'develop' into ximinez/directory 2025-12-01 14:40:53 -05:00
Ed Hennis
f3a9a9362d Merge branch 'develop' into ximinez/directory 2025-11-28 15:46:52 -05:00
Ed Hennis
91c5ad2388 Merge branch 'develop' into ximinez/directory 2025-11-27 01:49:04 -05:00
Ed Hennis
ced186ae6a Merge branch 'develop' into ximinez/directory 2025-11-26 00:25:25 -05:00
Ed Hennis
e1b5945077 Merge branch 'develop' into ximinez/directory 2025-11-25 14:55:15 -05:00
Ed Hennis
a2b4b06918 Merge branch 'develop' into ximinez/directory 2025-11-24 21:49:19 -05:00
Ed Hennis
54d528868f Merge branch 'develop' into ximinez/directory 2025-11-24 21:30:30 -05:00
Ed Hennis
6dd31bdef6 Merge branch 'develop' into ximinez/directory 2025-11-21 12:48:09 -05:00
Ed Hennis
d411e38615 Merge branch 'develop' into ximinez/directory 2025-11-18 22:51:13 -05:00
Ed Hennis
730ac9b763 Merge branch 'develop' into ximinez/directory 2025-11-15 03:08:49 -05:00
Ed Hennis
39715d6915 Merge branch 'develop' into ximinez/directory 2025-11-13 12:19:43 -05:00
Ed Hennis
fbeae82d61 Merge branch 'develop' into ximinez/directory 2025-11-12 14:13:03 -05:00
Ed Hennis
429c15ac0d Move the lambdas to be helper functions 2025-11-10 19:53:31 -05:00
Ed Hennis
9382fe1c82 rabbit hole: refactor dirAdd to find gaps in "full" directories.
- This would potentially be very expensive to implement, so don't.
- However, it might be a good start for a ledger fix option.
2025-11-10 19:53:31 -05:00
11 changed files with 95 additions and 105 deletions

View File

@@ -16,6 +16,7 @@
// Add new amendments to the top of this list. // Add new amendments to the top of this list.
// Keep it sorted in reverse chronological order. // Keep it sorted in reverse chronological order.
XRPL_FEATURE(DefragDirectories, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(LendingProtocol, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(LendingProtocol, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo) XRPL_FEATURE(PermissionDelegationV1_1, Supported::no, VoteBehavior::DefaultNo)
XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo) XRPL_FIX (DirectoryLimit, Supported::yes, VoteBehavior::DefaultNo)

View File

@@ -10,6 +10,14 @@ namespace ripple {
namespace directory { namespace directory {
struct Gap
{
uint64_t const page;
SLE::pointer node;
uint64_t const nextPage;
SLE::pointer next;
};
std::uint64_t std::uint64_t
createRoot( createRoot(
ApplyView& view, ApplyView& view,
@@ -112,7 +120,9 @@ insertPage(
return std::nullopt; return std::nullopt;
if (!view.rules().enabled(fixDirectoryLimit) && if (!view.rules().enabled(fixDirectoryLimit) &&
page >= dirNodeMaxPages) // Old pages limit page >= dirNodeMaxPages) // Old pages limit
{
return std::nullopt; return std::nullopt;
}
// We are about to create a new node; we'll link it to // We are about to create a new node; we'll link it to
// the chain first: // the chain first:
@@ -134,15 +144,8 @@ insertPage(
// it's the default. // it's the default.
if (page != 1) if (page != 1)
node->setFieldU64(sfIndexPrevious, page - 1); node->setFieldU64(sfIndexPrevious, page - 1);
XRPL_ASSERT_PARTS(
!nextPage,
"ripple::directory::insertPage",
"nextPage has default value");
/* Reserved for future use when directory pages may be inserted in
* between two other pages instead of only at the end of the chain.
if (nextPage) if (nextPage)
node->setFieldU64(sfIndexNext, nextPage); node->setFieldU64(sfIndexNext, nextPage);
*/
describe(node); describe(node);
view.insert(node); view.insert(node);
@@ -158,7 +161,7 @@ ApplyView::dirAdd(
uint256 const& key, uint256 const& key,
std::function<void(std::shared_ptr<SLE> const&)> const& describe) std::function<void(std::shared_ptr<SLE> const&)> const& describe)
{ {
auto root = peek(directory); auto const root = peek(directory);
if (!root) if (!root)
{ {
@@ -169,6 +172,44 @@ ApplyView::dirAdd(
auto [page, node, indexes] = auto [page, node, indexes] =
directory::findPreviousPage(*this, directory, root); directory::findPreviousPage(*this, directory, root);
if (rules().enabled(featureDefragDirectories))
{
// If there are more nodes than just the root, and there's no space in
// the last one, walk backwards to find one with space, or to find one
// missing.
std::optional<directory::Gap> gapPages;
while (page && indexes.size() >= dirNodeMaxEntries)
{
// Find a page with space, or a gap in pages.
auto [prevPage, prevNode, prevIndexes] =
directory::findPreviousPage(*this, directory, node);
if (!gapPages && prevPage != page - 1)
gapPages.emplace(prevPage, prevNode, page, node);
page = prevPage;
node = prevNode;
indexes = prevIndexes;
}
// We looped through all the pages back to the root.
if (!page)
{
// If we found a gap, use it.
if (gapPages)
{
return directory::insertPage(
*this,
gapPages->page,
gapPages->node,
gapPages->nextPage,
gapPages->next,
key,
directory,
describe);
}
std::tie(page, node, indexes) =
directory::findPreviousPage(*this, directory, root);
}
}
// If there's space, we use it: // If there's space, we use it:
if (indexes.size() < dirNodeMaxEntries) if (indexes.size() < dirNodeMaxEntries)
{ {

View File

@@ -141,7 +141,7 @@ protected:
using namespace jtx; using namespace jtx;
auto const vaultSle = env.le(keylet::vault(vaultID)); auto const vaultSle = env.le(keylet::vault(vaultID));
return getAssetsTotalScale(vaultSle); return getVaultScale(vaultSle);
} }
}; };
@@ -551,15 +551,12 @@ protected:
broker.vaultScale(env), broker.vaultScale(env),
state.principalOutstanding.exponent()))); state.principalOutstanding.exponent())));
BEAST_EXPECT(state.paymentInterval == 600); BEAST_EXPECT(state.paymentInterval == 600);
{ BEAST_EXPECT(
NumberRoundModeGuard mg(Number::upward); state.totalValue ==
BEAST_EXPECT( roundToAsset(
state.totalValue == broker.asset,
roundToAsset( state.periodicPayment * state.paymentRemaining,
broker.asset, state.loanScale));
state.periodicPayment * state.paymentRemaining,
state.loanScale));
}
BEAST_EXPECT( BEAST_EXPECT(
state.managementFeeOutstanding == state.managementFeeOutstanding ==
computeManagementFee( computeManagementFee(
@@ -700,8 +697,7 @@ protected:
interval, interval,
total, total,
feeRate, feeRate,
asset(brokerParams.vaultDeposit).number().exponent(), asset(brokerParams.vaultDeposit).number().exponent());
env.journal);
log << "Loan properties:\n" log << "Loan properties:\n"
<< "\tPrincipal: " << principal << std::endl << "\tPrincipal: " << principal << std::endl
<< "\tInterest rate: " << interest << std::endl << "\tInterest rate: " << interest << std::endl
@@ -1481,8 +1477,7 @@ protected:
state.paymentInterval, state.paymentInterval,
state.paymentRemaining, state.paymentRemaining,
broker.params.managementFeeRate, broker.params.managementFeeRate,
state.loanScale, state.loanScale);
env.journal);
verifyLoanStatus( verifyLoanStatus(
0, 0,
@@ -2453,18 +2448,13 @@ protected:
// Make all the payments in one transaction // Make all the payments in one transaction
// service fee is 2 // service fee is 2
auto const startingPayments = state.paymentRemaining; auto const startingPayments = state.paymentRemaining;
STAmount const payoffAmount = [&]() { auto const rawPayoff = startingPayments *
NumberRoundModeGuard mg(Number::upward); (state.periodicPayment + broker.asset(2).value());
auto const rawPayoff = startingPayments * STAmount const payoffAmount{broker.asset, rawPayoff};
(state.periodicPayment + broker.asset(2).value()); BEAST_EXPECT(
STAmount const payoffAmount{broker.asset, rawPayoff}; payoffAmount ==
BEAST_EXPECTS( broker.asset(Number(1024014840139457, -12)));
payoffAmount == BEAST_EXPECT(payoffAmount > state.principalOutstanding);
broker.asset(Number(1024014840139457, -12)),
to_string(payoffAmount));
BEAST_EXPECT(payoffAmount > state.principalOutstanding);
return payoffAmount;
}();
singlePayment( singlePayment(
loanKeylet, loanKeylet,
@@ -4019,7 +4009,7 @@ protected:
createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); createJson = env.json(createJson, sig(sfCounterpartySignature, lender));
// Fails in preclaim because principal requested can't be // Fails in preclaim because principal requested can't be
// represented as XRP // represented as XRP
env(createJson, ter(tecPRECISION_LOSS), THISLINE); env(createJson, ter(tecPRECISION_LOSS));
env.close(); env.close();
BEAST_EXPECT(!env.le(keylet)); BEAST_EXPECT(!env.le(keylet));
@@ -4031,7 +4021,7 @@ protected:
createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); createJson = env.json(createJson, sig(sfCounterpartySignature, lender));
// Fails in doApply because the payment is too small to be // Fails in doApply because the payment is too small to be
// represented as XRP. // represented as XRP.
env(createJson, ter(tecPRECISION_LOSS), THISLINE); env(createJson, ter(tecPRECISION_LOSS));
env.close(); env.close();
} }
@@ -5006,7 +4996,7 @@ protected:
auto const keylet = keylet::loan(broker.brokerID, loanSequence); auto const keylet = keylet::loan(broker.brokerID, loanSequence);
createJson = env.json(createJson, sig(sfCounterpartySignature, lender)); createJson = env.json(createJson, sig(sfCounterpartySignature, lender));
env(createJson, ter(tecPRECISION_LOSS), THISLINE); env(createJson, ter(tecPRECISION_LOSS));
env.close(startDate); env.close(startDate);
auto loanPayTx = env.json( auto loanPayTx = env.json(

View File

@@ -179,12 +179,11 @@ adjustImpreciseNumber(
} }
inline int inline int
getAssetsTotalScale(SLE::const_ref vaultSle) getVaultScale(SLE::const_ref vaultSle)
{ {
if (!vaultSle) if (!vaultSle)
return Number::minExponent - 1; // LCOV_EXCL_LINE return Number::minExponent - 1; // LCOV_EXCL_LINE
return STAmount{vaultSle->at(sfAsset), vaultSle->at(sfAssetsTotal)} return vaultSle->at(sfAssetsTotal).exponent();
.exponent();
} }
TER TER
@@ -419,8 +418,7 @@ computeLoanProperties(
std::uint32_t paymentInterval, std::uint32_t paymentInterval,
std::uint32_t paymentsRemaining, std::uint32_t paymentsRemaining,
TenthBips32 managementFeeRate, TenthBips32 managementFeeRate,
std::int32_t minimumScale, std::int32_t minimumScale);
beast::Journal j);
bool bool
isRounded(Asset const& asset, Number const& value, std::int32_t scale); isRounded(Asset const& asset, Number const& value, std::int32_t scale);

View File

@@ -451,8 +451,7 @@ tryOverpayment(
paymentInterval, paymentInterval,
paymentRemaining, paymentRemaining,
managementFeeRate, managementFeeRate,
loanScale, loanScale);
j);
JLOG(j.debug()) << "new periodic payment: " JLOG(j.debug()) << "new periodic payment: "
<< newLoanProperties.periodicPayment << newLoanProperties.periodicPayment
@@ -554,8 +553,8 @@ tryOverpayment(
// Calculate how the loan's value changed due to the overpayment. // Calculate how the loan's value changed due to the overpayment.
// This should be negative (value decreased) or zero. A principal // This should be negative (value decreased) or zero. A principal
// overpayment should never increase the loan's value. // overpayment should never increase the loan's value.
auto const valueChange = newRounded.valueOutstanding - auto const valueChange =
hypotheticalValueOutstanding - deltas.managementFee; newRounded.valueOutstanding - hypotheticalValueOutstanding;
if (valueChange > 0) if (valueChange > 0)
{ {
JLOG(j.warn()) << "Principal overpayment would increase the value of " JLOG(j.warn()) << "Principal overpayment would increase the value of "
@@ -1612,8 +1611,7 @@ computeLoanProperties(
std::uint32_t paymentInterval, std::uint32_t paymentInterval,
std::uint32_t paymentsRemaining, std::uint32_t paymentsRemaining,
TenthBips32 managementFeeRate, TenthBips32 managementFeeRate,
std::int32_t minimumScale, std::int32_t minimumScale)
beast::Journal j)
{ {
auto const periodicRate = loanPeriodicRate(interestRate, paymentInterval); auto const periodicRate = loanPeriodicRate(interestRate, paymentInterval);
XRPL_ASSERT( XRPL_ASSERT(
@@ -1624,22 +1622,13 @@ computeLoanProperties(
principalOutstanding, periodicRate, paymentsRemaining); principalOutstanding, periodicRate, paymentsRemaining);
auto const [totalValueOutstanding, loanScale] = [&]() { auto const [totalValueOutstanding, loanScale] = [&]() {
// only round up if there should be interest NumberRoundModeGuard mg(Number::to_nearest);
NumberRoundModeGuard mg(
periodicRate == 0 ? Number::to_nearest : Number::upward);
// Use STAmount's internal rounding instead of roundToAsset, because // Use STAmount's internal rounding instead of roundToAsset, because
// we're going to use this result to determine the scale for all the // we're going to use this result to determine the scale for all the
// other rounding. // other rounding.
// Equation (30) from XLS-66 spec, Section A-2 Equation Glossary // Equation (30) from XLS-66 spec, Section A-2 Equation Glossary
STAmount amount{asset, periodicPayment * paymentsRemaining}; STAmount amount{asset, periodicPayment * paymentsRemaining};
JLOG(j.debug()) << "computeLoanProperties:" << " Principal requested: "
<< principalOutstanding
<< ". Periodic payment: " << periodicPayment
<< ". Payments remaining: " << paymentsRemaining
<< ". Raw total value: "
<< periodicPayment * paymentsRemaining
<< ". Candidate total value: " << amount << std::endl;
// Base the loan scale on the total value, since that's going to be // Base the loan scale on the total value, since that's going to be
// the biggest number involved (barring unusual parameters for late, // the biggest number involved (barring unusual parameters for late,
@@ -1654,10 +1643,7 @@ computeLoanProperties(
// We may need to truncate the total value because of the minimum // We may need to truncate the total value because of the minimum
// scale // scale
amount = roundToAsset(asset, amount, loanScale); amount = roundToAsset(asset, amount, loanScale, Number::to_nearest);
JLOG(j.debug()) << "computeLoanProperties: Loan scale:" << loanScale
<< ". Actual total value: " << amount << std::endl;
return std::make_pair(amount, loanScale); return std::make_pair(amount, loanScale);
}(); }();

View File

@@ -56,7 +56,7 @@ LoanBrokerDelete::preclaim(PreclaimContext const& ctx)
if (!vault) if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE return tefINTERNAL; // LCOV_EXCL_LINE
auto const asset = vault->at(sfAsset); auto const asset = vault->at(sfAsset);
auto const scale = getAssetsTotalScale(vault); auto const scale = getVaultScale(vault);
auto const rounded = auto const rounded =
roundToAsset(asset, debtTotal, scale, Number::towards_zero); roundToAsset(asset, debtTotal, scale, Number::towards_zero);

View File

@@ -115,7 +115,7 @@ LoanDelete::doApply()
roundToAsset( roundToAsset(
vaultSle->at(sfAsset), vaultSle->at(sfAsset),
debtTotalProxy, debtTotalProxy,
getAssetsTotalScale(vaultSle), getVaultScale(vaultSle),
Number::towards_zero) == beast::zero, Number::towards_zero) == beast::zero,
"ripple::LoanDelete::doApply", "ripple::LoanDelete::doApply",
"last loan, remaining debt rounds to zero"); "last loan, remaining debt rounds to zero");

View File

@@ -106,7 +106,7 @@ LoanManage::preclaim(PreclaimContext const& ctx)
if (loanBrokerSle->at(sfOwner) != account) if (loanBrokerSle->at(sfOwner) != account)
{ {
JLOG(ctx.j.warn()) JLOG(ctx.j.warn())
<< "LoanBroker for Loan does not belong to the account. LoanManage " << "LoanBroker for Loan does not belong to the account. LoanModify "
"can only be submitted by the Loan Broker."; "can only be submitted by the Loan Broker.";
return tecNO_PERMISSION; return tecNO_PERMISSION;
} }
@@ -178,7 +178,7 @@ LoanManage::defaultLoan(
// The vault may be at a different scale than the loan. Reduce rounding // 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 // errors during the accounting by rounding some of the values to that
// scale. // scale.
auto const vaultScale = getAssetsTotalScale(vaultSle); auto const vaultScale = getVaultScale(vaultSle);
{ {
// Decrease the Total Value of the Vault: // Decrease the Total Value of the Vault:
@@ -242,11 +242,7 @@ LoanManage::defaultLoan(
return tefBAD_LEDGER; return tefBAD_LEDGER;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
adjustImpreciseNumber( vaultLossUnrealizedProxy -= totalDefaultAmount;
vaultLossUnrealizedProxy,
-totalDefaultAmount,
vaultAsset,
vaultScale);
} }
view.update(vaultSle); view.update(vaultSle);
} }
@@ -254,9 +250,11 @@ LoanManage::defaultLoan(
// Update the LoanBroker object: // Update the LoanBroker object:
{ {
auto const asset = *vaultSle->at(sfAsset);
// Decrease the Debt of the LoanBroker: // Decrease the Debt of the LoanBroker:
adjustImpreciseNumber( adjustImpreciseNumber(
brokerDebtTotalProxy, -totalDefaultAmount, vaultAsset, vaultScale); brokerDebtTotalProxy, -totalDefaultAmount, asset, vaultScale);
// Decrease the First-Loss Capital Cover Available: // Decrease the First-Loss Capital Cover Available:
auto coverAvailableProxy = brokerSle->at(sfCoverAvailable); auto coverAvailableProxy = brokerSle->at(sfCoverAvailable);
if (coverAvailableProxy < defaultCovered) if (coverAvailableProxy < defaultCovered)
@@ -299,20 +297,13 @@ LoanManage::impairLoan(
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j) beast::Journal j)
{ {
Number const lossUnrealized = owedToVault(loanSle); Number const lossUnrealized = owedToVault(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
// scale.
auto const vaultScale = getAssetsTotalScale(vaultSle);
// Update the Vault object(set "paper loss") // Update the Vault object(set "paper loss")
auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized); auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized);
adjustImpreciseNumber( vaultLossUnrealizedProxy += lossUnrealized;
vaultLossUnrealizedProxy, lossUnrealized, vaultAsset, vaultScale);
if (vaultLossUnrealizedProxy > if (vaultLossUnrealizedProxy >
vaultSle->at(sfAssetsTotal) - vaultSle->at(sfAssetsAvailable)) vaultSle->at(sfAssetsTotal) - vaultSle->at(sfAssetsAvailable))
{ {
@@ -343,14 +334,8 @@ LoanManage::unimpairLoan(
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j) beast::Journal j)
{ {
// 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
// scale.
auto const vaultScale = getAssetsTotalScale(vaultSle);
// Update the Vault object(clear "paper loss") // Update the Vault object(clear "paper loss")
auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized); auto vaultLossUnrealizedProxy = vaultSle->at(sfLossUnrealized);
Number const lossReversed = owedToVault(loanSle); Number const lossReversed = owedToVault(loanSle);
@@ -362,10 +347,7 @@ LoanManage::unimpairLoan(
return tefBAD_LEDGER; return tefBAD_LEDGER;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
// Reverse the "paper loss" vaultLossUnrealizedProxy -= lossReversed;
adjustImpreciseNumber(
vaultLossUnrealizedProxy, -lossReversed, vaultAsset, vaultScale);
view.update(vaultSle); view.update(vaultSle);
// Update the Loan object // Update the Loan object
@@ -421,14 +403,12 @@ LoanManage::doApply()
} }
else if (tx.isFlag(tfLoanImpair)) else if (tx.isFlag(tfLoanImpair))
{ {
if (auto const ter = if (auto const ter = impairLoan(view, loanSle, vaultSle, j_))
impairLoan(view, loanSle, vaultSle, vaultAsset, j_))
return ter; return ter;
} }
else if (tx.isFlag(tfLoanUnimpair)) else if (tx.isFlag(tfLoanUnimpair))
{ {
if (auto const ter = if (auto const ter = unimpairLoan(view, loanSle, vaultSle, j_))
unimpairLoan(view, loanSle, vaultSle, vaultAsset, j_))
return ter; return ter;
} }

View File

@@ -44,7 +44,6 @@ public:
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j); beast::Journal j);
/** Helper function that might be needed by other transactors /** Helper function that might be needed by other transactors
@@ -54,7 +53,6 @@ public:
ApplyView& view, ApplyView& view,
SLE::ref loanSle, SLE::ref loanSle,
SLE::ref vaultSle, SLE::ref vaultSle,
Asset const& vaultAsset,
beast::Journal j); beast::Journal j);
TER TER

View File

@@ -305,7 +305,7 @@ LoanPay::doApply()
// change will be discarded. // change will be discarded.
if (loanSle->isFlag(lsfLoanImpaired)) if (loanSle->isFlag(lsfLoanImpaired))
{ {
LoanManage::unimpairLoan(view, loanSle, vaultSle, asset, j_); LoanManage::unimpairLoan(view, loanSle, vaultSle, j_);
} }
LoanPaymentType const paymentType = [&tx]() { LoanPaymentType const paymentType = [&tx]() {
@@ -379,7 +379,7 @@ LoanPay::doApply()
// The vault may be at a different scale than the loan. Reduce rounding // The vault may be at a different scale than the loan. Reduce rounding
// errors during the payment by rounding some of the values to that scale. // errors during the payment by rounding some of the values to that scale.
auto const vaultScale = getAssetsTotalScale(vaultSle); auto const vaultScale = assetsTotalProxy.value().exponent();
auto const totalPaidToVaultRaw = auto const totalPaidToVaultRaw =
paymentParts->principalPaid + paymentParts->interestPaid; paymentParts->principalPaid + paymentParts->interestPaid;

View File

@@ -383,7 +383,7 @@ LoanSet::doApply()
auto vaultAvailableProxy = vaultSle->at(sfAssetsAvailable); auto vaultAvailableProxy = vaultSle->at(sfAssetsAvailable);
auto vaultTotalProxy = vaultSle->at(sfAssetsTotal); auto vaultTotalProxy = vaultSle->at(sfAssetsTotal);
auto const vaultScale = getAssetsTotalScale(vaultSle); auto const vaultScale = getVaultScale(vaultSle);
if (vaultAvailableProxy < principalRequested) if (vaultAvailableProxy < principalRequested)
{ {
JLOG(j_.warn()) JLOG(j_.warn())
@@ -404,8 +404,7 @@ LoanSet::doApply()
paymentInterval, paymentInterval,
paymentTotal, paymentTotal,
TenthBips16{brokerSle->at(sfManagementFeeRate)}, TenthBips16{brokerSle->at(sfManagementFeeRate)},
vaultScale, vaultScale);
j_);
// Check that relevant values won't lose precision. This is mostly only // Check that relevant values won't lose precision. This is mostly only
// relevant for IOU assets. // relevant for IOU assets.
@@ -441,10 +440,7 @@ LoanSet::doApply()
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
JLOG(j_.warn()) JLOG(j_.warn())
<< "Computed loan properties are invalid. Does not compute." << "Computed loan properties are invalid. Does not compute.";
<< " Management fee: " << properties.managementFeeOwedToBroker
<< ". Total Value: " << properties.totalValueOutstanding
<< ". PeriodicPayment: " << properties.periodicPayment;
return tecINTERNAL; return tecINTERNAL;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }