mirror of
https://github.com/XRPLF/rippled.git
synced 2026-10-21 19:18:22 +00:00
Compare commits
5 Commits
nb-seriali
...
mvadari/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72dda48103 | ||
|
|
7e25d8cd5a | ||
|
|
4f314a2e67 | ||
|
|
2d427ec676 | ||
|
|
1ff6147795 |
@@ -11,6 +11,10 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// Defined in <xrpl/ledger/helpers/LendingHelpers.h>, which includes this
|
||||
// header; include that header to call state().
|
||||
struct LoanState;
|
||||
|
||||
template <typename ViewT>
|
||||
class LoanEntry : public SLEBase<ViewT, ltLOAN>
|
||||
{
|
||||
@@ -37,6 +41,11 @@ public:
|
||||
: Base(keylet::loan(loanID), view, j)
|
||||
{
|
||||
}
|
||||
|
||||
// Build a LoanState from the three tracked fields. The Loan ledger object
|
||||
// always holds rounded values.
|
||||
[[nodiscard]] LoanState
|
||||
state() const;
|
||||
};
|
||||
|
||||
using LoanEntryR = LoanEntry<ReadView>;
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
|
||||
@@ -301,12 +302,6 @@ constructLoanState(
|
||||
Number const& principalOutstanding,
|
||||
Number const& managementFeeOutstanding);
|
||||
|
||||
// Overload of constructLoanState() that reads the three tracked fields
|
||||
// directly from a Loan ledger object, which always holds rounded values,
|
||||
// rather than taking them as separate Number arguments.
|
||||
LoanState
|
||||
constructLoanState(SLE::ConstRef loan);
|
||||
|
||||
Number
|
||||
computeManagementFee(
|
||||
Asset const& asset,
|
||||
@@ -328,7 +323,7 @@ computeFullPaymentInterest(
|
||||
// boundary is amendment-gated: with fixCleanup3_4_0 the due date must be
|
||||
// strictly in the past, otherwise the exact due-date instant counts as late.
|
||||
[[nodiscard]] bool
|
||||
isPaymentLate(ReadView const& view, SLE::ConstRef loanSle);
|
||||
isPaymentLate(ReadView const& view, LoanEntryR const& loanSle);
|
||||
|
||||
// Deltas applied to Vault.AssetsTotal and LoanBroker.DebtTotal at a single
|
||||
// accounting touch point (origination, payment, impair/unimpair/default).
|
||||
@@ -356,7 +351,7 @@ loanOriginationExceedsVaultMaximum(
|
||||
|
||||
// LoanManage impair/unimpair/default: the vault's exposure to this loan
|
||||
Number
|
||||
loanVaultExposure(SLE::ConstRef loanSle);
|
||||
loanVaultExposure(LoanEntryR const& loanSle);
|
||||
|
||||
// LoanPay: what's added to Vault.AssetsTotal and subtracted from LoanBroker.DebtTotal for a payment
|
||||
AccountingDeltas
|
||||
@@ -372,7 +367,7 @@ AccountingDeltas
|
||||
loanOriginationDeltas(Number const& principalRequested);
|
||||
|
||||
Number
|
||||
loanVaultExposure(SLE::ConstRef loanSle);
|
||||
loanVaultExposure(LoanEntryR const& loanSle);
|
||||
|
||||
AccountingDeltas
|
||||
loanPaymentDeltas(LoanPaymentParts const& parts);
|
||||
@@ -396,7 +391,7 @@ loanOriginationExceedsVaultMaximum(
|
||||
Number const& interestDue);
|
||||
|
||||
Number
|
||||
loanVaultExposure(SLE::ConstRef vaultSle, SLE::ConstRef loanSle);
|
||||
loanVaultExposure(SLE::ConstRef vaultSle, LoanEntryR const& loanSle);
|
||||
|
||||
AccountingDeltas
|
||||
loanPaymentDeltas(SLE::ConstRef vaultSle, LoanPaymentParts const& parts);
|
||||
@@ -667,7 +662,7 @@ std::expected<LoanPaymentParts, TER>
|
||||
loanMakePayment(
|
||||
Asset const& asset,
|
||||
ApplyView& view,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
SLE::ConstRef brokerSle,
|
||||
STAmount const& amount,
|
||||
LoanPaymentType const paymentType,
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/STTx.h>
|
||||
#include <xrpl/protocol/TER.h>
|
||||
@@ -42,7 +43,7 @@ public:
|
||||
static TER
|
||||
defaultLoan(
|
||||
ApplyView& view,
|
||||
SLE::Ref loanSle,
|
||||
LoanEntryW& loanSle,
|
||||
SLE::Ref brokerSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
@@ -54,7 +55,7 @@ public:
|
||||
static TER
|
||||
impairLoan(
|
||||
ApplyView& view,
|
||||
SLE::Ref loanSle,
|
||||
LoanEntryW& loanSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
beast::Journal j);
|
||||
@@ -65,7 +66,7 @@ public:
|
||||
[[nodiscard]] static TER
|
||||
unimpairLoan(
|
||||
ApplyView& view,
|
||||
SLE::Ref loanSle,
|
||||
LoanEntryW& loanSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
beast::Journal j);
|
||||
|
||||
29
src/libxrpl/ledger/entries/LoanEntry.cpp
Normal file
29
src/libxrpl/ledger/entries/LoanEntry.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
template <typename ViewT>
|
||||
LoanState
|
||||
LoanEntry<ViewT>::state() const
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
this->exists() && (*this)->getType() == ltLOAN,
|
||||
"xrpl::constructLoanState : valid loan SLE");
|
||||
|
||||
return constructLoanState(
|
||||
(*this)->at(sfTotalValueOutstanding),
|
||||
(*this)->at(sfPrincipalOutstanding),
|
||||
(*this)->at(sfManagementFeeOutstanding));
|
||||
}
|
||||
|
||||
template class LoanEntry<ReadView>;
|
||||
template class LoanEntry<ApplyView>;
|
||||
|
||||
} // namespace xrpl
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/VaultHelpers.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -91,7 +92,7 @@ getLoanDefaultFreezeExemptAccounts(ReadView const& view, STTx const& tx)
|
||||
// Unlike the broker/vault lookups below, the submitter picks the LoanID,
|
||||
// so a nonexistent Loan is an ordinary (if unusual) input, not a
|
||||
// structural impossibility -- exercised directly in LendingHelpers_test.
|
||||
auto const loanSle = view.read(keylet::loan(tx[sfLoanID]));
|
||||
LoanEntryR const loanSle(tx[sfLoanID], view);
|
||||
if (!loanSle)
|
||||
return std::nullopt;
|
||||
|
||||
@@ -170,7 +171,7 @@ isRounded(Asset const& asset, Number const& value, std::int32_t scale)
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
isPaymentLate(ReadView const& view, SLE::ConstRef loanSle)
|
||||
isPaymentLate(ReadView const& view, LoanEntryR const& loanSle)
|
||||
{
|
||||
return hasExpired(
|
||||
view,
|
||||
@@ -204,7 +205,7 @@ DefaultAmount = (Loan.PrincipalOutstanding + Loan.InterestOutstanding)
|
||||
Which is equivalent to (Loan.TotalValueOutstanding - Loan.ManagementFeeOutstanding)
|
||||
*/
|
||||
Number
|
||||
loanVaultExposure(SLE::ConstRef loanSle)
|
||||
loanVaultExposure(LoanEntryR const& loanSle)
|
||||
{
|
||||
return loanSle->at(sfTotalValueOutstanding) - loanSle->at(sfManagementFeeOutstanding);
|
||||
}
|
||||
@@ -233,7 +234,7 @@ loanOriginationDeltas(Number const& principalRequested)
|
||||
* DefaultAmount = Loan.PrincipalOutstanding
|
||||
*/
|
||||
Number
|
||||
loanVaultExposure(SLE::ConstRef loanSle)
|
||||
loanVaultExposure(LoanEntryR const& loanSle)
|
||||
{
|
||||
return loanSle->at(sfPrincipalOutstanding);
|
||||
}
|
||||
@@ -288,7 +289,7 @@ loanOriginationExceedsVaultMaximum(
|
||||
}
|
||||
|
||||
Number
|
||||
loanVaultExposure(SLE::ConstRef vaultSle, SLE::ConstRef loanSle)
|
||||
loanVaultExposure(SLE::ConstRef vaultSle, LoanEntryR const& loanSle)
|
||||
{
|
||||
return cashBasisEnabled(vaultSle) ? cash_basis::loanVaultExposure(loanSle)
|
||||
: instant_recognition::loanVaultExposure(loanSle);
|
||||
@@ -579,7 +580,7 @@ loanAccruedInterest(
|
||||
* a computed payment.
|
||||
*/
|
||||
LoanPaymentParts
|
||||
doPayment(ExtendedPaymentComponents const& payment, SLE::Ref loan)
|
||||
doPayment(ExtendedPaymentComponents const& payment, LoanEntryW& loan)
|
||||
{
|
||||
auto totalValueOutstandingProxy = loan->at(sfTotalValueOutstanding);
|
||||
auto principalOutstandingProxy = loan->at(sfPrincipalOutstanding);
|
||||
@@ -905,7 +906,7 @@ doOverpayment(
|
||||
Asset const& asset,
|
||||
std::int32_t loanScale,
|
||||
ExtendedPaymentComponents const& overpaymentComponents,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
Number const& periodicRate,
|
||||
TenthBips16 const managementFeeRate,
|
||||
beast::Journal j)
|
||||
@@ -1047,7 +1048,7 @@ std::expected<ExtendedPaymentComponents, TER>
|
||||
computeLatePayment(
|
||||
Asset const& asset,
|
||||
ReadView const& view,
|
||||
SLE::ConstRef loan,
|
||||
LoanEntryR const& loan,
|
||||
ExtendedPaymentComponents const& periodic,
|
||||
STAmount const& amount,
|
||||
TenthBips16 managementFeeRate,
|
||||
@@ -1143,7 +1144,7 @@ std::expected<ExtendedPaymentComponents, TER>
|
||||
computeFullPayment(
|
||||
Asset const& asset,
|
||||
ReadView const& view,
|
||||
SLE::ConstRef loan,
|
||||
LoanEntryR const& loan,
|
||||
Number const& periodicRate,
|
||||
STAmount const& amount,
|
||||
TenthBips16 managementFeeRate,
|
||||
@@ -1182,7 +1183,7 @@ computeFullPayment(
|
||||
auto const [roundedFullInterest, roundedFullManagementFee] = roundAndSplitInterest(
|
||||
asset, fullPaymentInterest, managementFeeRate, loanScale, Number::RoundingMode::Downward);
|
||||
|
||||
LoanState const loanState = constructLoanState(loan);
|
||||
LoanState const loanState = loan.state();
|
||||
Number const principalOutstanding = loanState.principalOutstanding;
|
||||
Number const managementFeeOutstanding = loanState.managementFeeDue;
|
||||
Number const totalInterestOutstanding = loanState.interestDue;
|
||||
@@ -1489,7 +1490,7 @@ PaymentComponents
|
||||
computePaymentComponents(
|
||||
Rules const& rules,
|
||||
Asset const& asset,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
Number const& periodicRate,
|
||||
TenthBips16 managementFeeRate)
|
||||
{
|
||||
@@ -1587,7 +1588,7 @@ computeOverpaymentComponents(
|
||||
* interest rate.
|
||||
*/
|
||||
std::pair<TenthBips16, Number>
|
||||
loanRatesFor(SLE::ConstRef loan, SLE::ConstRef brokerSle)
|
||||
loanRatesFor(LoanEntryR const& loan, SLE::ConstRef brokerSle)
|
||||
{
|
||||
TenthBips16 const managementFeeRate{brokerSle->at(sfManagementFeeRate)};
|
||||
TenthBips32 const interestRate{loan->at(sfInterestRate)};
|
||||
@@ -1604,7 +1605,7 @@ std::expected<LoanPaymentParts, TER>
|
||||
makeFullPayment(
|
||||
Asset const& asset,
|
||||
ApplyView& view,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
SLE::ConstRef brokerSle,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
@@ -1629,7 +1630,7 @@ std::expected<LoanPaymentParts, TER>
|
||||
makeLatePayment(
|
||||
Asset const& asset,
|
||||
ApplyView const& view,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
SLE::ConstRef brokerSle,
|
||||
STAmount const& amount,
|
||||
beast::Journal j)
|
||||
@@ -1663,7 +1664,7 @@ std::expected<LoanPaymentParts, TER>
|
||||
makeRegularPayment(
|
||||
Asset const& asset,
|
||||
ApplyView const& view,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
SLE::ConstRef brokerSle,
|
||||
STAmount const& amount,
|
||||
LoanPaymentType const paymentType,
|
||||
@@ -2099,17 +2100,6 @@ constructLoanState(
|
||||
.managementFeeDue = managementFeeOutstanding};
|
||||
}
|
||||
|
||||
LoanState
|
||||
constructLoanState(SLE::ConstRef loan)
|
||||
{
|
||||
XRPL_ASSERT(loan && loan->getType() == ltLOAN, "xrpl::constructLoanState : valid loan SLE");
|
||||
|
||||
return constructLoanState(
|
||||
loan->at(sfTotalValueOutstanding),
|
||||
loan->at(sfPrincipalOutstanding),
|
||||
loan->at(sfManagementFeeOutstanding));
|
||||
}
|
||||
|
||||
/*
|
||||
* This function calculates the fee owed to the broker based on the asset,
|
||||
* value, and management fee rate.
|
||||
@@ -2254,7 +2244,7 @@ std::expected<LoanPaymentParts, TER>
|
||||
loanMakePayment(
|
||||
Asset const& asset,
|
||||
ApplyView& view,
|
||||
SLE::Ref loan,
|
||||
LoanEntryW& loan,
|
||||
SLE::ConstRef brokerSle,
|
||||
STAmount const& amount,
|
||||
LoanPaymentType const paymentType,
|
||||
@@ -2280,7 +2270,7 @@ loanMakePayment(
|
||||
XRPL_ASSERT(
|
||||
*loan->at(sfTotalValueOutstanding) > 0, "xrpl::loanMakePayment : valid total value");
|
||||
|
||||
view.update(loan);
|
||||
loan.update();
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// A late payment not flagged as late overrides all other options.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <xrpl/basics/Number.h> // IWYU pragma: keep
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -41,7 +42,7 @@ LoanDelete::preclaim(PreclaimContext const& ctx)
|
||||
auto const account = tx[sfAccount];
|
||||
auto const loanID = tx[sfLoanID];
|
||||
|
||||
auto const loanSle = ctx.view.read(keylet::loan(loanID));
|
||||
LoanEntryR const loanSle(loanID, ctx.view);
|
||||
if (!loanSle)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Loan does not exist.";
|
||||
@@ -76,7 +77,7 @@ LoanDelete::doApply()
|
||||
auto& view = ctx_.view();
|
||||
|
||||
auto const loanID = tx[sfLoanID];
|
||||
auto const loanSle = view.peek(keylet::loan(loanID));
|
||||
LoanEntryW loanSle(loanID, view);
|
||||
if (!loanSle)
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
auto const borrower = loanSle->at(sfBorrower);
|
||||
@@ -104,7 +105,9 @@ LoanDelete::doApply()
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
|
||||
// Delete the Loan object
|
||||
view.erase(loanSle);
|
||||
// Erase through the view, not loanSle.erase(): decreaseOwnerCountForObject
|
||||
// below still reads the erased SLE.
|
||||
view.erase(loanSle.mutableRawSle());
|
||||
|
||||
// Decrement the LoanBroker's owner count.
|
||||
adjustLoanBrokerOwnerCount(view, brokerSle, -1, j_);
|
||||
@@ -128,7 +131,7 @@ LoanDelete::doApply()
|
||||
}
|
||||
}
|
||||
// Decrement the borrower's owner count
|
||||
decreaseOwnerCountForObject(view, borrowerSle, loanSle, 1, j_);
|
||||
decreaseOwnerCountForObject(view, borrowerSle, loanSle.mutableRawSle(), 1, j_);
|
||||
|
||||
associateAsset(*vaultSle, vaultAsset);
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
@@ -69,7 +70,7 @@ LoanManage::preclaim(PreclaimContext const& ctx)
|
||||
auto const account = tx[sfAccount];
|
||||
auto const loanID = tx[sfLoanID];
|
||||
|
||||
auto const loanSle = ctx.view.read(keylet::loan(loanID));
|
||||
LoanEntryR const loanSle(loanID, ctx.view);
|
||||
if (!loanSle)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Loan does not exist.";
|
||||
@@ -134,7 +135,7 @@ LoanManage::preclaim(PreclaimContext const& ctx)
|
||||
TER
|
||||
LoanManage::defaultLoan(
|
||||
ApplyView& view,
|
||||
SLE::Ref loanSle,
|
||||
LoanEntryW& loanSle,
|
||||
SLE::Ref brokerSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
@@ -269,7 +270,7 @@ LoanManage::defaultLoan(
|
||||
// Zero out the next due date. Since it's default, it'll be removed from
|
||||
// the object.
|
||||
loanSle->at(sfNextPaymentDueDate) = 0;
|
||||
view.update(loanSle);
|
||||
loanSle.update();
|
||||
|
||||
// Return funds from the LoanBroker pseudo-account to the
|
||||
// Vault pseudo-account:
|
||||
@@ -286,7 +287,7 @@ LoanManage::defaultLoan(
|
||||
TER
|
||||
LoanManage::impairLoan(
|
||||
ApplyView& view,
|
||||
SLE::Ref loanSle,
|
||||
LoanEntryW& loanSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
beast::Journal j)
|
||||
@@ -330,7 +331,7 @@ LoanManage::impairLoan(
|
||||
loanNextDueProxy = view.parentCloseTime().time_since_epoch().count();
|
||||
}
|
||||
}
|
||||
view.update(loanSle);
|
||||
loanSle.update();
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -338,7 +339,7 @@ LoanManage::impairLoan(
|
||||
[[nodiscard]] TER
|
||||
LoanManage::unimpairLoan(
|
||||
ApplyView& view,
|
||||
SLE::Ref loanSle,
|
||||
LoanEntryW& loanSle,
|
||||
SLE::Ref vaultSle,
|
||||
Asset const& vaultAsset,
|
||||
beast::Journal j)
|
||||
@@ -384,7 +385,7 @@ LoanManage::unimpairLoan(
|
||||
view.parentCloseTime().time_since_epoch().count() + paymentInterval;
|
||||
}
|
||||
}
|
||||
view.update(loanSle);
|
||||
loanSle.update();
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
@@ -396,7 +397,7 @@ LoanManage::doApply()
|
||||
auto& view = ctx_.view();
|
||||
|
||||
auto const loanID = tx[sfLoanID];
|
||||
auto const loanSle = view.peek(keylet::loan(loanID));
|
||||
LoanEntryW loanSle(loanID, view);
|
||||
if (!loanSle)
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/beast/utility/instrumentation.h>
|
||||
#include <xrpl/json/to_string.h>
|
||||
#include <xrpl/ledger/ReadView.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/ledger/helpers/TokenHelpers.h>
|
||||
#include <xrpl/protocol/AccountID.h>
|
||||
@@ -137,7 +138,7 @@ LoanPay::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
auto const amount = tx[sfAmount];
|
||||
auto const loanID = tx[sfLoanID];
|
||||
|
||||
auto const loanSle = view.read(keylet::loan(loanID));
|
||||
LoanEntryR const loanSle(loanID, view);
|
||||
if (!loanSle)
|
||||
{
|
||||
// Let preclaim worry about the error for this
|
||||
@@ -234,7 +235,7 @@ LoanPay::preclaim(PreclaimContext const& ctx)
|
||||
auto const loanID = tx[sfLoanID];
|
||||
auto const amount = tx[sfAmount];
|
||||
|
||||
auto const loanSle = ctx.view.read(keylet::loan(loanID));
|
||||
LoanEntryR const loanSle(loanID, ctx.view);
|
||||
if (!loanSle)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "Loan does not exist.";
|
||||
@@ -337,7 +338,7 @@ LoanPay::doApply()
|
||||
auto const amount = tx[sfAmount];
|
||||
|
||||
auto const loanID = tx[sfLoanID];
|
||||
auto const loanSle = view.peek(keylet::loan(loanID));
|
||||
LoanEntryW loanSle(loanID, view);
|
||||
if (!loanSle)
|
||||
return tefBAD_LEDGER; // LCOV_EXCL_LINE
|
||||
std::int32_t const loanScale = loanSle->at(sfLoanScale);
|
||||
@@ -442,7 +443,7 @@ LoanPay::doApply()
|
||||
|
||||
// If the payment computation completed without error, the loanSle object
|
||||
// has been modified.
|
||||
view.update(loanSle);
|
||||
loanSle.update();
|
||||
|
||||
XRPL_ASSERT_PARTS(
|
||||
// It is possible to pay 0 principal
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <xrpl/core/ServiceRegistry.h>
|
||||
#include <xrpl/ledger/ApplyView.h>
|
||||
#include <xrpl/ledger/View.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/ledger/helpers/SponsorHelpers.h>
|
||||
@@ -655,8 +656,8 @@ LoanSet::doApply()
|
||||
auto loanSequenceProxy = brokerSle->at(sfLoanSequence);
|
||||
|
||||
// Create the loan
|
||||
auto loan =
|
||||
std::make_shared<SLE>(keylet::loan(brokerID, SeqProxy::rawSequence(*loanSequenceProxy)));
|
||||
LoanEntryW loan(brokerID, SeqProxy::rawSequence(*loanSequenceProxy), view);
|
||||
loan.newSLE();
|
||||
|
||||
// Prevent copy/paste errors
|
||||
auto setLoanField = [&loan, &tx](auto const& field, std::uint32_t const defValue = 0) {
|
||||
@@ -693,7 +694,7 @@ LoanSet::doApply()
|
||||
loan->at(sfPreviousPaymentDueDate) = 0;
|
||||
loan->at(sfNextPaymentDueDate) = startDate + paymentInterval;
|
||||
loan->at(sfPaymentRemaining) = paymentTotal;
|
||||
view.insert(loan);
|
||||
loan.insert();
|
||||
|
||||
// Update the balances in the vault
|
||||
vaultAvailableProxy -= principalRequested;
|
||||
@@ -714,11 +715,13 @@ LoanSet::doApply()
|
||||
return tecMAX_SEQUENCE_REACHED;
|
||||
view.update(brokerSle);
|
||||
|
||||
// dirLink takes a non-const SLE::pointer&, so pass it a copy of the handle.
|
||||
SLE::pointer loanSle = loan.mutableRawSle();
|
||||
// Put the loan into the pseudo-account's directory
|
||||
if (auto const ter = dirLink(view, brokerPseudo, loan, sfLoanBrokerNode))
|
||||
if (auto const ter = dirLink(view, brokerPseudo, loanSle, sfLoanBrokerNode))
|
||||
return ter;
|
||||
// Borrower is the owner of the loan
|
||||
if (auto const ter = dirLink(view, borrower, loan, sfOwnerNode))
|
||||
if (auto const ter = dirLink(view, borrower, loanSle, sfOwnerNode))
|
||||
return ter;
|
||||
|
||||
associateAsset(*vaultSle, vaultAsset);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <xrpl/basics/Number.h>
|
||||
#include <xrpl/basics/chrono.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
@@ -1624,8 +1625,11 @@ class LendingHelpers_test : public beast::unit_test::Suite
|
||||
{
|
||||
testcase("instant_recognition::loanVaultExposure");
|
||||
|
||||
jtx::Env const env{*this};
|
||||
auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50});
|
||||
BEAST_EXPECT(xrpl::instant_recognition::loanVaultExposure(sle) == Number{950});
|
||||
BEAST_EXPECT(
|
||||
xrpl::instant_recognition::loanVaultExposure(LoanEntryR(sle, *env.current())) ==
|
||||
Number{950});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1633,8 +1637,10 @@ class LendingHelpers_test : public beast::unit_test::Suite
|
||||
{
|
||||
testcase("cash_basis::loanVaultExposure");
|
||||
|
||||
jtx::Env const env{*this};
|
||||
auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50});
|
||||
BEAST_EXPECT(xrpl::cash_basis::loanVaultExposure(sle) == Number{800});
|
||||
BEAST_EXPECT(
|
||||
xrpl::cash_basis::loanVaultExposure(LoanEntryR(sle, *env.current())) == Number{800});
|
||||
}
|
||||
|
||||
void
|
||||
@@ -1752,8 +1758,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
|
||||
Env const env{*this};
|
||||
auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50});
|
||||
BEAST_EXPECT(
|
||||
loanVaultExposure(legacyVault, sle) ==
|
||||
xrpl::instant_recognition::loanVaultExposure(sle));
|
||||
loanVaultExposure(legacyVault, LoanEntryR(sle, *env.current())) ==
|
||||
xrpl::instant_recognition::loanVaultExposure(LoanEntryR(sle, *env.current())));
|
||||
}
|
||||
|
||||
{
|
||||
@@ -1764,7 +1770,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
|
||||
Env const env{*this};
|
||||
auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50});
|
||||
BEAST_EXPECT(
|
||||
loanVaultExposure(cashBasisVault, sle) == xrpl::cash_basis::loanVaultExposure(sle));
|
||||
loanVaultExposure(cashBasisVault, LoanEntryR(sle, *env.current())) ==
|
||||
xrpl::cash_basis::loanVaultExposure(LoanEntryR(sle, *env.current())));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <xrpl/beast/unit_test/suite.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/protocol/Asset.h>
|
||||
#include <xrpl/protocol/Feature.h>
|
||||
@@ -144,7 +145,7 @@ private:
|
||||
auto const loanSle = env.le(loanKeylet);
|
||||
if (!BEAST_EXPECT(loanSle))
|
||||
return;
|
||||
auto const state = constructLoanState(loanSle);
|
||||
auto const state = LoanEntryR(loanSle, *env.current()).state();
|
||||
|
||||
log << "Loan state:" << std::endl;
|
||||
log << " ValueOutstanding: " << state.valueOutstanding << std::endl;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <xrpl/beast/utility/Journal.h>
|
||||
#include <xrpl/beast/utility/Zero.h>
|
||||
#include <xrpl/json/json_value.h>
|
||||
#include <xrpl/ledger/entries/LoanEntry.h>
|
||||
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
|
||||
#include <xrpl/ledger/helpers/LendingHelpers.h>
|
||||
#include <xrpl/ledger/helpers/VaultHelpers.h>
|
||||
@@ -428,7 +429,7 @@ protected:
|
||||
env.test.BEAST_EXPECT(loan->at(sfPeriodicPayment) == periodicPayment);
|
||||
env.test.BEAST_EXPECT(loan->at(sfFlags) == flags);
|
||||
|
||||
auto const ls = constructLoanState(loan);
|
||||
auto const ls = LoanEntryR(loan, *env.current()).state();
|
||||
|
||||
auto const interestRate = TenthBips32{loan->at(sfInterestRate)};
|
||||
auto const paymentInterval = loan->at(sfPaymentInterval);
|
||||
@@ -1254,7 +1255,7 @@ protected:
|
||||
// No reason for this not to exist
|
||||
return;
|
||||
}
|
||||
auto const current = constructLoanState(loanSle);
|
||||
auto const current = LoanEntryR(loanSle, *env.current()).state();
|
||||
auto const errors = nextTrueState - current;
|
||||
log << currencyLabel << " Loan balances: "
|
||||
<< "\n\tAmount taken: " << paymentComponents.trackedValueDelta
|
||||
@@ -2873,7 +2874,7 @@ protected:
|
||||
bool const impairAllowed = BEAST_EXPECT(loanSle) &&
|
||||
canImpairLoan(env, broker, state) &&
|
||||
(!env.current()->rules().enabled(fixCleanup3_4_0) ||
|
||||
isPaymentLate(*env.current(), loanSle));
|
||||
isPaymentLate(*env.current(), LoanEntryR(loanSle, *env.current())));
|
||||
if (impairAllowed)
|
||||
{
|
||||
// Making a payment will unimpair the loan
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <xrpl/ledger/entries/XChainOwnedClaimIDEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/ledger/entries/XChainOwnedCreateAccountClaimIDEntry.h> // IWYU pragma: keep
|
||||
#include <xrpl/protocol/Indexes.h>
|
||||
#include <xrpl/protocol/Keylet.h>
|
||||
#include <xrpl/protocol/LedgerFormats.h>
|
||||
#include <xrpl/protocol/SField.h>
|
||||
#include <xrpl/protocol/STLedgerEntry.h>
|
||||
@@ -76,12 +77,22 @@ template class SLEBase<ApplyView>;
|
||||
#pragma push_macro("LEDGER_ENTRY")
|
||||
#undef LEDGER_ENTRY
|
||||
|
||||
// No explicit instantiation here, neither a definition nor a declaration.
|
||||
// A definition would instantiate an entry a second time once its member
|
||||
// bodies live in its own .cpp (MSVC rejects that with C4661 under /WX), and a
|
||||
// declaration (`extern template`) stops clang from emitting the inline
|
||||
// constructors of the header-only entries at -O0, which leaves them undefined
|
||||
// at link time in the debug builds. Naming the class in a static_assert is
|
||||
// enough to instantiate its definition, which is all this exhaustiveness
|
||||
// check needs; the per-type suites exercise the members.
|
||||
#define LEDGER_ENTRY(tag, value, name, ...) \
|
||||
template class name##Entry<ReadView>; \
|
||||
template class name##Entry<ApplyView>; \
|
||||
static_assert( \
|
||||
name##Entry<ReadView>::kEntryType == tag && name##Entry<ApplyView>::kEntryType == tag, \
|
||||
#name "Entry must be bound to " #tag);
|
||||
#name "Entry must be bound to " #tag); \
|
||||
static_assert( \
|
||||
std::is_constructible_v<name##Entry<ReadView>, Keylet const&, ReadView const&> && \
|
||||
std::is_constructible_v<name##Entry<ApplyView>, Keylet const&, ApplyView&>, \
|
||||
#name "Entry must be constructible from a Keylet and a view");
|
||||
|
||||
#include <xrpl/protocol/detail/ledger_entries.macro>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user