xrpld
Loading...
Searching...
No Matches
LoanDelete.cpp
1#include <xrpl/tx/transactors/lending/LoanDelete.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h> // IWYU pragma: keep
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/ledger/helpers/AccountRootHelpers.h>
8#include <xrpl/ledger/helpers/LendingHelpers.h>
9#include <xrpl/protocol/Indexes.h>
10#include <xrpl/protocol/SField.h>
11#include <xrpl/protocol/STAmount.h> // IWYU pragma: keep
12#include <xrpl/protocol/STLedgerEntry.h>
13#include <xrpl/protocol/STTakesAsset.h>
14#include <xrpl/protocol/STTx.h>
15#include <xrpl/protocol/TER.h>
16#include <xrpl/protocol/XRPAmount.h>
17#include <xrpl/tx/Transactor.h>
18
19namespace xrpl {
20
21bool
26
29{
30 if (ctx.tx[sfLoanID] == beast::kZero)
31 return temINVALID;
32
33 return tesSUCCESS;
34}
35
36TER
38{
39 auto const& tx = ctx.tx;
40
41 auto const account = tx[sfAccount];
42 auto const loanID = tx[sfLoanID];
43
44 auto const loanSle = ctx.view.read(keylet::loan(loanID));
45 if (!loanSle)
46 {
47 JLOG(ctx.j.warn()) << "Loan does not exist.";
48 return tecNO_ENTRY;
49 }
50 if (loanSle->at(sfPaymentRemaining) > 0)
51 {
52 JLOG(ctx.j.warn()) << "Active loan can not be deleted.";
53 return tecHAS_OBLIGATIONS;
54 }
55
56 auto const loanBrokerID = loanSle->at(sfLoanBrokerID);
57 auto const loanBrokerSle = ctx.view.read(keylet::loanBroker(loanBrokerID));
58 if (!loanBrokerSle)
59 {
60 // should be impossible
61 return tecINTERNAL; // LCOV_EXCL_LINE
62 }
63 if (loanBrokerSle->at(sfOwner) != account && loanSle->at(sfBorrower) != account)
64 {
65 JLOG(ctx.j.warn()) << "Account is not Loan Broker Owner or Loan Borrower.";
66 return tecNO_PERMISSION;
67 }
68
69 return tesSUCCESS;
70}
71
72TER
74{
75 auto const& tx = ctx_.tx;
76 auto& view = ctx_.view();
77
78 auto const loanID = tx[sfLoanID];
79 auto const loanSle = view.peek(keylet::loan(loanID));
80 if (!loanSle)
81 return tefBAD_LEDGER; // LCOV_EXCL_LINE
82 auto const borrower = loanSle->at(sfBorrower);
83 auto const borrowerSle = view.peek(keylet::account(borrower));
84 if (!borrowerSle)
85 return tefBAD_LEDGER; // LCOV_EXCL_LINE
86
87 auto const brokerID = loanSle->at(sfLoanBrokerID);
88 auto const brokerSle = view.peek(keylet::loanBroker(brokerID));
89 if (!brokerSle)
90 return tefBAD_LEDGER; // LCOV_EXCL_LINE
91 auto const brokerPseudoAccount = brokerSle->at(sfAccount);
92
93 auto const vaultSle = view.peek(keylet::vault(brokerSle->at(sfVaultID)));
94 if (!vaultSle)
95 return tefBAD_LEDGER; // LCOV_EXCL_LINE
96 auto const vaultAsset = vaultSle->at(sfAsset);
97
98 // Remove LoanID from Directory of the LoanBroker pseudo-account.
99 if (!view.dirRemove(
100 keylet::ownerDir(brokerPseudoAccount), loanSle->at(sfLoanBrokerNode), loanID, false))
101 return tefBAD_LEDGER; // LCOV_EXCL_LINE
102 // Remove LoanID from Directory of the Borrower.
103 if (!view.dirRemove(keylet::ownerDir(borrower), loanSle->at(sfOwnerNode), loanID, false))
104 return tefBAD_LEDGER; // LCOV_EXCL_LINE
105
106 // Delete the Loan object
107 view.erase(loanSle);
108
109 // Decrement the LoanBroker's owner count.
110 // The broker's owner count is solely for the number of outstanding loans,
111 // and is distinct from the broker's pseudo-account's owner count
112 adjustOwnerCount(view, brokerSle, -1, j_);
113 // If there are no loans left, then any remaining debt must be forgiven,
114 // because there is no other way to pay it back.
115 if (brokerSle->at(sfOwnerCount) == 0)
116 {
117 auto debtTotalProxy = brokerSle->at(sfDebtTotal);
118 if (*debtTotalProxy != beast::kZero)
119 {
120 XRPL_ASSERT_PARTS(
122 vaultSle->at(sfAsset),
123 debtTotalProxy,
124 getAssetsTotalScale(vaultSle),
125 Number::RoundingMode::TowardsZero) == beast::kZero,
126 "xrpl::LoanDelete::doApply",
127 "last loan, remaining debt rounds to zero");
128 debtTotalProxy = 0;
129 }
130 }
131 // Decrement the borrower's owner count
132 adjustOwnerCount(view, borrowerSle, -1, j_);
133
134 // These associations shouldn't do anything, but do them just to be safe
135 associateAsset(*loanSle, vaultAsset);
136 associateAsset(*brokerSle, vaultAsset);
137 associateAsset(*vaultSle, vaultAsset);
138
139 return tesSUCCESS;
140}
141
142void
144{
145 // No transaction-specific invariants yet (future work).
146}
147
148bool
150{
151 // No transaction-specific invariants yet (future work).
152 return true;
153}
154
155//------------------------------------------------------------------------------
156
157} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream warn() const
Definition Journal.h:309
static TER preclaim(PreclaimContext const &ctx)
static bool checkExtraFeatures(PreflightContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
static NotTEC preflight(PreflightContext const &ctx)
TER doApply() override
A view into a ledger.
Definition ReadView.h:31
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
std::shared_ptr< STLedgerEntry const > const & const_ref
beast::Journal const j_
Definition Transactor.h:118
ApplyView & view()
Definition Transactor.h:136
ApplyContext & ctx_
Definition Transactor.h:116
Keylet loanBroker(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:557
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:357
Keylet loan(uint256 const &loanBrokerID, std::uint32_t loanSeq) noexcept
Definition Indexes.cpp:563
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:551
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:186
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
int getAssetsTotalScale(SLE::const_ref vaultSle)
@ tefBAD_LEDGER
Definition TER.h:160
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:594
void adjustOwnerCount(ApplyView &view, SLE::ref sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
Definition STAmount.h:722
@ temINVALID
Definition TER.h:96
TERSubset< CanCvtToTER > TER
Definition TER.h:634
@ tecNO_ENTRY
Definition TER.h:304
@ tecINTERNAL
Definition TER.h:308
@ tecNO_PERMISSION
Definition TER.h:303
@ tecHAS_OBLIGATIONS
Definition TER.h:315
void associateAsset(STLedgerEntry &sle, Asset const &asset)
Associate an Asset with all sMD_NeedsAsset fields in a ledger entry.
@ tesSUCCESS
Definition TER.h:240
bool checkLendingProtocolDependencies(Rules const &rules, STTx const &tx)
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
beast::Journal const j
Definition Transactor.h:69
State information when preflighting a tx.
Definition Transactor.h:18