xrpld
Loading...
Searching...
No Matches
LoanBrokerDelete.cpp
1#include <xrpl/tx/transactors/lending/LoanBrokerDelete.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/ledger/helpers/AccountRootHelpers.h>
7#include <xrpl/ledger/helpers/LendingHelpers.h>
8#include <xrpl/ledger/helpers/TokenHelpers.h>
9#include <xrpl/protocol/Asset.h>
10#include <xrpl/protocol/Feature.h>
11#include <xrpl/protocol/Indexes.h>
12#include <xrpl/protocol/SField.h>
13#include <xrpl/protocol/STAmount.h>
14#include <xrpl/protocol/STLedgerEntry.h>
15#include <xrpl/protocol/STTakesAsset.h>
16#include <xrpl/protocol/STTx.h>
17#include <xrpl/protocol/TER.h>
18#include <xrpl/protocol/XRPAmount.h>
19#include <xrpl/tx/Transactor.h>
20
21namespace xrpl {
22
23bool
28
31{
32 if (ctx.tx[sfLoanBrokerID] == beast::kZero)
33 return temINVALID;
34
35 return tesSUCCESS;
36}
37
38TER
40{
41 auto const& tx = ctx.tx;
42
43 auto const account = tx[sfAccount];
44 auto const brokerID = tx[sfLoanBrokerID];
45
46 auto const sleBroker = ctx.view.read(keylet::loanBroker(brokerID));
47 if (!sleBroker)
48 {
49 JLOG(ctx.j.warn()) << "LoanBroker does not exist.";
50 return tecNO_ENTRY;
51 }
52
53 auto const brokerOwner = sleBroker->at(sfOwner);
54
55 if (account != brokerOwner)
56 {
57 JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker.";
58 return tecNO_PERMISSION;
59 }
60 if (auto const ownerCount = sleBroker->at(sfOwnerCount); ownerCount != 0)
61 {
62 JLOG(ctx.j.warn()) << "LoanBrokerDelete: Owner count is " << ownerCount;
63 return tecHAS_OBLIGATIONS;
64 }
65
66 auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
67 if (!vault)
68 {
69 // LCOV_EXCL_START
70 JLOG(ctx.j.fatal()) << "Vault is missing for Broker " << brokerID;
71 return tefBAD_LEDGER;
72 // LCOV_EXCL_STOP
73 }
74
75 Asset const asset = vault->at(sfAsset);
76
77 if (auto const debtTotal = sleBroker->at(sfDebtTotal); debtTotal != beast::kZero)
78 {
79 // Any remaining debt should have been wiped out by the last Loan
80 // Delete. This check is purely defensive.
81 auto const scale = getAssetsTotalScale(vault);
82
83 auto const rounded =
85
86 if (rounded != beast::kZero)
87 {
88 // LCOV_EXCL_START
89 JLOG(ctx.j.warn()) << "LoanBrokerDelete: Debt total is " << debtTotal
90 << ", which rounds to " << rounded;
91 return tecHAS_OBLIGATIONS;
92 // LCOV_EXCL_STOP
93 }
94 }
95
96 auto const coverAvailable = STAmount{asset, sleBroker->at(sfCoverAvailable)};
97 // If there are assets in the cover, broker will receive them on deletion.
98 // So we need to check if the broker owner is deep frozen for that asset.
99 if (coverAvailable > beast::kZero)
100 {
101 if (auto const ret = checkDeepFrozen(ctx.view, brokerOwner, asset))
102 {
103 JLOG(ctx.j.warn()) << "Broker owner account is frozen.";
104 return ret;
105 }
106 }
107
108 if (ctx.view.rules().enabled(fixCleanup3_2_0))
109 {
110 if (coverAvailable > beast::kZero)
111 {
112 auto const brokerPseudo = sleBroker->at(sfAccount);
113 if (auto const ret = checkFrozen(ctx.view, brokerPseudo, asset))
114 {
115 JLOG(ctx.j.warn()) << "Broker pseudo-account is frozen/locked.";
116 return ret;
117 }
118 }
119 }
120
121 return tesSUCCESS;
122}
123
124TER
126{
127 auto const& tx = ctx_.tx;
128
129 auto const brokerID = tx[sfLoanBrokerID];
130
131 // Delete the loan broker
132 auto broker = view().peek(keylet::loanBroker(brokerID));
133 if (!broker)
134 return tefBAD_LEDGER; // LCOV_EXCL_LINE
135 auto const vaultID = broker->at(sfVaultID);
136 auto const sleVault = view().read(keylet::vault(vaultID));
137 if (!sleVault)
138 return tefBAD_LEDGER; // LCOV_EXCL_LINE
139 auto const vaultPseudoID = sleVault->at(sfAccount);
140 auto const vaultAsset = sleVault->at(sfAsset);
141
142 auto const brokerPseudoID = broker->at(sfAccount);
143
144 if (!view().dirRemove(
145 keylet::ownerDir(accountID_), broker->at(sfOwnerNode), broker->key(), false))
146 {
147 return tefBAD_LEDGER; // LCOV_EXCL_LINE
148 }
149 if (!view().dirRemove(
150 keylet::ownerDir(vaultPseudoID), broker->at(sfVaultNode), broker->key(), false))
151 {
152 return tefBAD_LEDGER; // LCOV_EXCL_LINE
153 }
154
155 {
156 auto const coverAvailable = STAmount{vaultAsset, broker->at(sfCoverAvailable)};
157 if (auto const ter = accountSend(
158 view(), brokerPseudoID, accountID_, coverAvailable, j_, WaiveTransferFee::Yes))
159 return ter;
160 }
161
162 if (auto ter = removeEmptyHolding(view(), brokerPseudoID, vaultAsset, j_))
163 return ter;
164
165 auto brokerPseudoSLE = view().peek(keylet::account(brokerPseudoID));
166 if (!brokerPseudoSLE)
167 return tefBAD_LEDGER; // LCOV_EXCL_LINE
168
169 // Making the payment and removing the empty holding should have deleted any
170 // obligations associated with the broker or broker pseudo-account.
171 if (*brokerPseudoSLE->at(sfBalance))
172 {
173 JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account has a balance";
174 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
175 }
176 if (brokerPseudoSLE->at(sfOwnerCount) != 0)
177 {
178 JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account still owns objects";
179 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
180 }
181 if (auto const directory = keylet::ownerDir(brokerPseudoID); view().read(directory))
182 {
183 JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account has a directory";
184 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
185 }
186
187 view().erase(brokerPseudoSLE);
188
189 view().erase(broker);
190
191 {
192 auto owner = view().peek(keylet::account(accountID_));
193 if (!owner)
194 return tefBAD_LEDGER; // LCOV_EXCL_LINE
195
196 // Decreases the owner count by two: one for the LoanBroker object, and
197 // one for the pseudo-account.
198 adjustOwnerCount(view(), owner, -2, j_);
199 }
200
201 associateAsset(*broker, vaultAsset);
202
203 return tesSUCCESS;
204}
205
206void
208{
209 // No transaction-specific invariants yet (future work).
210}
211
212bool
214 STTx const&,
215 TER,
216 XRPAmount,
217 ReadView const&,
218 beast::Journal const&)
219{
220 // No transaction-specific invariants yet (future work).
221 return true;
222}
223
224//------------------------------------------------------------------------------
225
226} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:38
Stream fatal() const
Definition Journal.h:321
Stream warn() const
Definition Journal.h:309
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(SLE::ref sle)=0
Remove a peeked SLE.
static TER preclaim(PreclaimContext const &ctx)
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.
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
static NotTEC preflight(PreflightContext const &ctx)
static bool checkExtraFeatures(PreflightContext const &ctx)
A view into a ledger.
Definition ReadView.h:31
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:171
std::shared_ptr< STLedgerEntry const > const & const_ref
beast::Journal const j_
Definition Transactor.h:118
ApplyView & view()
Definition Transactor.h:136
AccountID const accountID_
Definition Transactor.h:120
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 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
TER checkDeepFrozen(ReadView const &view, AccountID const &account, Issue const &issue)
int getAssetsTotalScale(SLE::const_ref vaultSle)
TER checkFrozen(ReadView const &view, AccountID const &account, Issue const &issue)
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
Definition STAmount.h:779
@ 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.
TER accountSend(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee=WaiveTransferFee::No, AllowMPTOverflow allowOverflow=AllowMPTOverflow::No)
Calls static accountSendIOU if saAmount represents Issue.
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
@ 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.
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, MPTIssue const &mptIssue, beast::Journal journal)
@ 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