rippled
Loading...
Searching...
No Matches
LoanBrokerCoverWithdraw.cpp
1#include <xrpld/app/tx/detail/LoanBrokerCoverWithdraw.h>
2//
3#include <xrpld/app/misc/LendingHelpers.h>
4#include <xrpld/app/tx/detail/Payment.h>
5
6#include <xrpl/ledger/CredentialHelpers.h>
7
8namespace xrpl {
9
10bool
15
18{
19 if (ctx.tx[sfLoanBrokerID] == beast::zero)
20 return temINVALID;
21
22 auto const dstAmount = ctx.tx[sfAmount];
23 if (dstAmount <= beast::zero)
24 return temBAD_AMOUNT;
25
26 if (!isLegalNet(dstAmount))
27 return temBAD_AMOUNT;
28
29 if (auto const destination = ctx.tx[~sfDestination])
30 {
31 if (*destination == beast::zero)
32 {
33 return temMALFORMED;
34 }
35 }
36
37 return tesSUCCESS;
38}
39
40TER
42{
43 auto const& tx = ctx.tx;
44
45 auto const account = tx[sfAccount];
46 auto const brokerID = tx[sfLoanBrokerID];
47 auto const amount = tx[sfAmount];
48
49 auto const dstAcct = tx[~sfDestination].value_or(account);
50
51 auto const sleBroker = ctx.view.read(keylet::loanbroker(brokerID));
52 if (!sleBroker)
53 {
54 JLOG(ctx.j.warn()) << "LoanBroker does not exist.";
55 return tecNO_ENTRY;
56 }
57 if (account != sleBroker->at(sfOwner))
58 {
59 JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker.";
60 return tecNO_PERMISSION;
61 }
62 auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
63 if (!vault)
64 {
65 // LCOV_EXCL_START
66 JLOG(ctx.j.fatal()) << "Vault is missing for Broker " << brokerID;
67 return tefBAD_LEDGER;
68 // LCOV_EXCL_STOP
69 }
70
71 auto const vaultAsset = vault->at(sfAsset);
72 if (amount.asset() != vaultAsset)
73 return tecWRONG_ASSET;
74
75 // The broker's pseudo-account is the source of funds.
76 auto const pseudoAccountID = sleBroker->at(sfAccount);
77 // Cannot transfer a non-transferable Asset
78 if (auto const ret =
79 canTransfer(ctx.view, vaultAsset, pseudoAccountID, dstAcct))
80 return ret;
81
82 // Withdrawal to a 3rd party destination account is essentially a transfer.
83 // Enforce all the usual asset transfer checks.
85 if (account != dstAcct)
86 {
87 if (auto const ret = canWithdraw(ctx.view, tx))
88 return ret;
89
90 // The destination account must have consented to receive the asset by
91 // creating a RippleState or MPToken
92 authType = AuthType::StrongAuth;
93 }
94
95 // Destination MPToken must exist (if asset is an MPT)
96 if (auto const ter = requireAuth(ctx.view, vaultAsset, dstAcct, authType))
97 return ter;
98
99 // Check for freezes, unless sending directly to the issuer
100 if (dstAcct != vaultAsset.getIssuer())
101 {
102 // Cannot send a frozen Asset
103 if (auto const ret = checkFrozen(ctx.view, pseudoAccountID, vaultAsset))
104 return ret;
105 // Destination account cannot receive if asset is deep frozen
106 if (auto const ret = checkDeepFrozen(ctx.view, dstAcct, vaultAsset))
107 return ret;
108 }
109
110 auto const coverAvail = sleBroker->at(sfCoverAvailable);
111 // Cover Rate is in 1/10 bips units
112 auto const currentDebtTotal = sleBroker->at(sfDebtTotal);
113 auto const minimumCover = [&]() {
114 // Always round the minimum required up.
115 // Applies to `tenthBipsOfValue` as well as `roundToAsset`.
117 return roundToAsset(
118 vaultAsset,
120 currentDebtTotal,
121 TenthBips32(sleBroker->at(sfCoverRateMinimum))),
122 currentDebtTotal.exponent());
123 }();
124 if (coverAvail < amount)
126 if ((coverAvail - amount) < minimumCover)
128
129 if (accountHolds(
130 ctx.view,
131 pseudoAccountID,
132 vaultAsset,
135 ctx.j) < amount)
137
138 return tesSUCCESS;
139}
140
141TER
143{
144 auto const& tx = ctx_.tx;
145
146 auto const brokerID = tx[sfLoanBrokerID];
147 auto const amount = tx[sfAmount];
148 auto const dstAcct = tx[~sfDestination].value_or(account_);
149
150 auto broker = view().peek(keylet::loanbroker(brokerID));
151 if (!broker)
152 return tecINTERNAL; // LCOV_EXCL_LINE
153
154 auto const brokerPseudoID = *broker->at(sfAccount);
155
156 // Decrease the LoanBroker's CoverAvailable by Amount
157 broker->at(sfCoverAvailable) -= amount;
158 view().update(broker);
159
160 return doWithdraw(
161 view(),
162 tx,
163 account_,
164 dstAcct,
165 brokerPseudoID,
167 amount,
168 j_);
169}
170
171//------------------------------------------------------------------------------
172
173} // namespace xrpl
Stream fatal() const
Definition Journal.h:333
Stream warn() const
Definition Journal.h:321
STTx const & tx
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static bool checkExtraFeatures(PreflightContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext 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:128
beast::Journal const j_
Definition Transactor.h:126
ApplyView & view()
Definition Transactor.h:144
XRPAmount mPriorBalance
Definition Transactor.h:129
ApplyContext & ctx_
Definition Transactor.h:124
Keylet loanbroker(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:552
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Definition Indexes.cpp:546
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
TER checkDeepFrozen(ReadView const &view, AccountID const &account, Issue const &issue)
Definition View.h:269
@ fhZERO_IF_FROZEN
Definition View.h:59
Number roundToAsset(A const &asset, Number const &value, std::int32_t scale, Number::rounding_mode rounding=Number::getround())
Round an arbitrary precision Number to the precision of a given Asset.
Definition STAmount.h:722
TER doWithdraw(ApplyView &view, STTx const &tx, AccountID const &senderAcct, AccountID const &dstAcct, AccountID const &sourceAcct, XRPAmount priorBalance, STAmount const &amount, beast::Journal j)
Definition View.cpp:1390
constexpr T tenthBipsOfValue(T value, TenthBips< TBips > bips)
Definition Protocol.h:108
TER checkFrozen(ReadView const &view, AccountID const &account, Issue const &issue)
Definition View.h:160
@ tefBAD_LEDGER
Definition TER.h:151
bool isLegalNet(STAmount const &value)
Definition STAmount.h:592
bool checkLendingProtocolDependencies(PreflightContext const &ctx)
TenthBips< std::uint32_t > TenthBips32
Definition Units.h:443
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition View.cpp:461
@ ahZERO_IF_UNAUTHORIZED
Definition View.h:62
AuthType
Definition View.h:985
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account, AuthType authType=AuthType::Legacy)
Check if the account lacks required authorization.
Definition View.cpp:3096
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
Definition View.cpp:3325
TER canWithdraw(AccountID const &from, ReadView const &view, AccountID const &to, SLE::const_ref toSle, bool hasDestinationTag)
Checks that can withdraw funds from an object to itself or a destination.
Definition View.cpp:1346
@ temINVALID
Definition TER.h:91
@ temMALFORMED
Definition TER.h:68
@ temBAD_AMOUNT
Definition TER.h:70
@ tecWRONG_ASSET
Definition TER.h:342
@ tecNO_ENTRY
Definition TER.h:288
@ tecINTERNAL
Definition TER.h:292
@ tecINSUFFICIENT_FUNDS
Definition TER.h:307
@ tecNO_PERMISSION
Definition TER.h:287
@ tesSUCCESS
Definition TER.h:226
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:16