rippled
Loading...
Searching...
No Matches
LoanBrokerDelete.cpp
1#include <xrpld/app/tx/detail/LoanBrokerDelete.h>
2//
3#include <xrpld/app/misc/LendingHelpers.h>
4
5#include <xrpl/protocol/STTakesAsset.h>
6
7namespace xrpl {
8
9bool
14
17{
18 if (ctx.tx[sfLoanBrokerID] == beast::zero)
19 return temINVALID;
20
21 return tesSUCCESS;
22}
23
24TER
26{
27 auto const& tx = ctx.tx;
28
29 auto const account = tx[sfAccount];
30 auto const brokerID = tx[sfLoanBrokerID];
31
32 auto const sleBroker = ctx.view.read(keylet::loanbroker(brokerID));
33 if (!sleBroker)
34 {
35 JLOG(ctx.j.warn()) << "LoanBroker does not exist.";
36 return tecNO_ENTRY;
37 }
38
39 auto const brokerOwner = sleBroker->at(sfOwner);
40
41 if (account != brokerOwner)
42 {
43 JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker.";
44 return tecNO_PERMISSION;
45 }
46 if (auto const ownerCount = sleBroker->at(sfOwnerCount); ownerCount != 0)
47 {
48 JLOG(ctx.j.warn()) << "LoanBrokerDelete: Owner count is " << ownerCount;
49 return tecHAS_OBLIGATIONS;
50 }
51
52 auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
53 if (!vault)
54 {
55 // LCOV_EXCL_START
56 JLOG(ctx.j.fatal()) << "Vault is missing for Broker " << brokerID;
57 return tefBAD_LEDGER;
58 // LCOV_EXCL_STOP
59 }
60
61 Asset const asset = vault->at(sfAsset);
62
63 if (auto const debtTotal = sleBroker->at(sfDebtTotal); debtTotal != beast::zero)
64 {
65 // Any remaining debt should have been wiped out by the last Loan
66 // Delete. This check is purely defensive.
67 auto const scale = getAssetsTotalScale(vault);
68
69 auto const rounded = roundToAsset(asset, debtTotal, scale, Number::towards_zero);
70
71 if (rounded != beast::zero)
72 {
73 // LCOV_EXCL_START
74 JLOG(ctx.j.warn()) << "LoanBrokerDelete: Debt total is " << debtTotal << ", which rounds to " << rounded;
75 return tecHAS_OBLIGATIONS;
76 // LCOV_EXCL_STOP
77 }
78 }
79
80 auto const coverAvailable = STAmount{asset, sleBroker->at(sfCoverAvailable)};
81 // If there are assets in the cover, broker will receive them on deletion.
82 // So we need to check if the broker owner is deep frozen for that asset.
83 if (coverAvailable > beast::zero)
84 {
85 if (auto const ret = checkDeepFrozen(ctx.view, brokerOwner, asset))
86 {
87 JLOG(ctx.j.warn()) << "Broker owner account is frozen.";
88 return ret;
89 }
90 }
91
92 return tesSUCCESS;
93}
94
95TER
97{
98 auto const& tx = ctx_.tx;
99
100 auto const brokerID = tx[sfLoanBrokerID];
101
102 // Delete the loan broker
103 auto broker = view().peek(keylet::loanbroker(brokerID));
104 if (!broker)
105 return tefBAD_LEDGER; // LCOV_EXCL_LINE
106 auto const vaultID = broker->at(sfVaultID);
107 auto const sleVault = view().read(keylet::vault(vaultID));
108 if (!sleVault)
109 return tefBAD_LEDGER; // LCOV_EXCL_LINE
110 auto const vaultPseudoID = sleVault->at(sfAccount);
111 auto const vaultAsset = sleVault->at(sfAsset);
112
113 auto const brokerPseudoID = broker->at(sfAccount);
114
115 if (!view().dirRemove(keylet::ownerDir(account_), broker->at(sfOwnerNode), broker->key(), false))
116 {
117 return tefBAD_LEDGER; // LCOV_EXCL_LINE
118 }
119 if (!view().dirRemove(keylet::ownerDir(vaultPseudoID), broker->at(sfVaultNode), broker->key(), false))
120 {
121 return tefBAD_LEDGER; // LCOV_EXCL_LINE
122 }
123
124 {
125 auto const coverAvailable = STAmount{vaultAsset, broker->at(sfCoverAvailable)};
126 if (auto const ter = accountSend(view(), brokerPseudoID, account_, coverAvailable, j_, WaiveTransferFee::Yes))
127 return ter;
128 }
129
130 if (auto ter = removeEmptyHolding(view(), brokerPseudoID, vaultAsset, j_))
131 return ter;
132
133 auto brokerPseudoSLE = view().peek(keylet::account(brokerPseudoID));
134 if (!brokerPseudoSLE)
135 return tefBAD_LEDGER; // LCOV_EXCL_LINE
136
137 // Making the payment and removing the empty holding should have deleted any
138 // obligations associated with the broker or broker pseudo-account.
139 if (*brokerPseudoSLE->at(sfBalance))
140 {
141 JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account has a balance";
142 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
143 }
144 if (brokerPseudoSLE->at(sfOwnerCount) != 0)
145 {
146 JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account still owns objects";
147 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
148 }
149 if (auto const directory = keylet::ownerDir(brokerPseudoID); view().read(directory))
150 {
151 JLOG(j_.warn()) << "LoanBrokerDelete: Pseudo-account has a directory";
152 return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE
153 }
154
155 view().erase(brokerPseudoSLE);
156
157 view().erase(broker);
158
159 {
160 auto owner = view().peek(keylet::account(account_));
161 if (!owner)
162 return tefBAD_LEDGER; // LCOV_EXCL_LINE
163
164 // Decreases the owner count by two: one for the LoanBroker object, and
165 // one for the pseudo-account.
166 adjustOwnerCount(view(), owner, -2, j_);
167 }
168
169 associateAsset(*broker, vaultAsset);
170
171 return tesSUCCESS;
172}
173
174//------------------------------------------------------------------------------
175
176} // namespace xrpl
Stream fatal() const
Definition Journal.h:324
Stream warn() const
Definition Journal.h:312
STTx const & tx
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static bool checkExtraFeatures(PreflightContext const &ctx)
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
AccountID const account_
Definition Transactor.h:112
beast::Journal const j_
Definition Transactor.h:110
ApplyView & view()
Definition Transactor.h:128
ApplyContext & ctx_
Definition Transactor.h:108
Keylet loanbroker(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:498
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:325
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:492
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:160
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)
Definition View.h:198
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, Issue const &issue, beast::Journal journal)
Definition View.cpp:1554
int getAssetsTotalScale(SLE::const_ref vaultSle)
@ tefBAD_LEDGER
Definition TER.h:150
bool checkLendingProtocolDependencies(PreflightContext const &ctx)
TER accountSend(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee=WaiveTransferFee::No)
Calls static accountSendIOU if saAmount represents Issue.
Definition View.cpp:2446
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
Definition View.cpp:941
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
Definition STAmount.h:674
@ temINVALID
Definition TER.h:90
@ tecNO_ENTRY
Definition TER.h:287
@ tecNO_PERMISSION
Definition TER.h:286
@ tecHAS_OBLIGATIONS
Definition TER.h:298
void associateAsset(STLedgerEntry &sle, Asset const &asset)
Associate an Asset with all sMD_NeedsAsset fields in a ledger entry.
@ tesSUCCESS
Definition TER.h:225
uint256 key
Definition Keylet.h:20
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:53
ReadView const & view
Definition Transactor.h:56
beast::Journal const j
Definition Transactor.h:61
State information when preflighting a tx.
Definition Transactor.h:15