rippled
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/instrumentation.h>
5#include <xrpl/protocol/LedgerFormats.h>
6#include <xrpl/protocol/STNumber.h>
7
8namespace xrpl {
9
10void
12 bool isDelete,
13 std::shared_ptr<SLE const> const& before,
15{
16 if (after && after->getType() == ltLOAN)
17 {
18 loans_.emplace_back(before, after);
19 }
20}
21
22bool
24 STTx const& tx,
25 TER const,
26 XRPAmount const,
27 ReadView const& view,
28 beast::Journal const& j)
29{
30 // Loans will not exist on ledger if the Lending Protocol amendment
31 // is not enabled, so there's no need to check it.
32
33 for (auto const& [before, after] : loans_)
34 {
35 // https://github.com/Tapanito/XRPL-Standards/blob/xls-66-lending-protocol/XLS-0066d-lending-protocol/README.md#3223-invariants
36 // If `Loan.PaymentRemaining = 0` then the loan MUST be fully paid off
37 if (after->at(sfPaymentRemaining) == 0 &&
38 (after->at(sfTotalValueOutstanding) != beast::zero ||
39 after->at(sfPrincipalOutstanding) != beast::zero ||
40 after->at(sfManagementFeeOutstanding) != beast::zero))
41 {
42 JLOG(j.fatal()) << "Invariant failed: Loan with zero payments "
43 "remaining has not been paid off";
44 return false;
45 }
46 // If `Loan.PaymentRemaining != 0` then the loan MUST NOT be fully paid
47 // off
48 if (after->at(sfPaymentRemaining) != 0 &&
49 after->at(sfTotalValueOutstanding) == beast::zero &&
50 after->at(sfPrincipalOutstanding) == beast::zero &&
51 after->at(sfManagementFeeOutstanding) == beast::zero)
52 {
53 JLOG(j.fatal()) << "Invariant failed: Fully paid off Loan still has payments remaining";
54 return false;
55 }
56 if (before && (before->isFlag(lsfLoanOverpayment) != after->isFlag(lsfLoanOverpayment)))
57 {
58 JLOG(j.fatal()) << "Invariant failed: Loan Overpayment flag changed";
59 return false;
60 }
61 // Must not be negative - STNumber
62 for (auto const field :
63 {&sfLoanServiceFee,
64 &sfLatePaymentFee,
65 &sfClosePaymentFee,
66 &sfPrincipalOutstanding,
67 &sfTotalValueOutstanding,
68 &sfManagementFeeOutstanding})
69 {
70 if (after->at(*field) < 0)
71 {
72 JLOG(j.fatal()) << "Invariant failed: " << field->getName() << " is negative ";
73 return false;
74 }
75 }
76 // Must be positive - STNumber
77 for (auto const field : {
78 &sfPeriodicPayment,
79 })
80 {
81 if (after->at(*field) <= 0)
82 {
83 JLOG(j.fatal()) << "Invariant failed: " << field->getName()
84 << " is zero or negative ";
85 return false;
86 }
87 }
88 }
89 return true;
90}
91
92} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:40
Stream fatal() const
Definition Journal.h:325
A view into a ledger.
Definition ReadView.h:31
void visitEntry(bool, std::shared_ptr< SLE const > const &, std::shared_ptr< SLE const > const &)
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:523