xrpld
Loading...
Searching...
No Matches
LoanInvariant.cpp
1#include <xrpl/tx/invariants/LoanInvariant.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/beast/utility/Journal.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/ledger/ReadView.h>
7#include <xrpl/protocol/LedgerFormats.h>
8#include <xrpl/protocol/SField.h>
9#include <xrpl/protocol/STLedgerEntry.h>
10#include <xrpl/protocol/STNumber.h> // IWYU pragma: keep
11#include <xrpl/protocol/STTx.h>
12#include <xrpl/protocol/TER.h>
13#include <xrpl/protocol/XRPAmount.h>
14
15namespace xrpl {
16
17void
19{
20 if (after && after->getType() == ltLOAN)
21 {
22 loans_.emplace_back(before, after);
23 }
24}
25
26bool
28 STTx const& tx,
29 TER const,
30 XRPAmount const,
31 ReadView const& view,
32 beast::Journal const& j)
33{
34 // Loans will not exist on ledger if the Lending Protocol amendment
35 // is not enabled, so there's no need to check it.
36
37 for (auto const& [before, after] : loans_)
38 {
39 // https://github.com/Tapanito/XRPL-Standards/blob/xls-66-lending-protocol/XLS-0066d-lending-protocol/README.md#3223-invariants
40 // If `Loan.PaymentRemaining = 0` then the loan MUST be fully paid off
41 if (after->at(sfPaymentRemaining) == 0 &&
42 (after->at(sfTotalValueOutstanding) != beast::kZero ||
43 after->at(sfPrincipalOutstanding) != beast::kZero ||
44 after->at(sfManagementFeeOutstanding) != beast::kZero))
45 {
46 JLOG(j.fatal()) << "Invariant failed: Loan with zero payments "
47 "remaining has not been paid off";
48 return false;
49 }
50 // If `Loan.PaymentRemaining != 0` then the loan MUST NOT be fully paid
51 // off
52 if (after->at(sfPaymentRemaining) != 0 &&
53 after->at(sfTotalValueOutstanding) == beast::kZero &&
54 after->at(sfPrincipalOutstanding) == beast::kZero &&
55 after->at(sfManagementFeeOutstanding) == beast::kZero)
56 {
57 JLOG(j.fatal()) << "Invariant failed: Fully paid off Loan still has payments remaining";
58 return false;
59 }
60 if (before && (before->isFlag(lsfLoanOverpayment) != after->isFlag(lsfLoanOverpayment)))
61 {
62 JLOG(j.fatal()) << "Invariant failed: Loan Overpayment flag changed";
63 return false;
64 }
65 // Must not be negative - STNumber
66 for (auto const field :
67 {&sfLoanServiceFee,
68 &sfLatePaymentFee,
69 &sfClosePaymentFee,
70 &sfPrincipalOutstanding,
71 &sfTotalValueOutstanding,
72 &sfManagementFeeOutstanding})
73 {
74 if (after->at(*field) < 0)
75 {
76 JLOG(j.fatal()) << "Invariant failed: " << field->getName() << " is negative ";
77 return false;
78 }
79 }
80 // Must be positive - STNumber
81 for (auto const field : {
82 &sfPeriodicPayment,
83 })
84 {
85 if (after->at(*field) <= 0)
86 {
87 JLOG(j.fatal()) << "Invariant failed: " << field->getName()
88 << " is zero or negative ";
89 return false;
90 }
91 }
92 }
93 return true;
94}
95
96} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream fatal() const
Definition Journal.h:321
A view into a ledger.
Definition ReadView.h:31
std::shared_ptr< STLedgerEntry const > const & const_ref
void visitEntry(bool, SLE::const_ref, SLE::const_ref)
std::vector< std::pair< SLE::const_pointer, SLE::const_pointer > > loans_
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:554
TERSubset< CanCvtToTER > TER
Definition TER.h:634