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