rippled
Loading...
Searching...
No Matches
LoanBrokerSet.cpp
1#include <xrpld/app/tx/detail/LoanBrokerSet.h>
2//
3#include <xrpld/app/misc/LendingHelpers.h>
4
5namespace xrpl {
6
7bool
12
15{
16 using namespace Lending;
17
18 auto const& tx = ctx.tx;
19 if (auto const data = tx[~sfData]; data && !data->empty() &&
21 return temINVALID;
22 if (!validNumericRange(tx[~sfManagementFeeRate], maxManagementFeeRate))
23 return temINVALID;
24 if (!validNumericRange(tx[~sfCoverRateMinimum], maxCoverRate))
25 return temINVALID;
26 if (!validNumericRange(tx[~sfCoverRateLiquidation], maxCoverRate))
27 return temINVALID;
29 tx[~sfDebtMaximum], Number(maxMPTokenAmount), Number(0)))
30 return temINVALID;
31
32 if (tx.isFieldPresent(sfLoanBrokerID))
33 {
34 // Fixed fields can not be specified if we're modifying an existing
35 // LoanBroker Object
36 if (tx.isFieldPresent(sfManagementFeeRate) ||
37 tx.isFieldPresent(sfCoverRateMinimum) ||
38 tx.isFieldPresent(sfCoverRateLiquidation))
39 return temINVALID;
40
41 if (tx[sfLoanBrokerID] == beast::zero)
42 return temINVALID;
43 }
44
45 if (auto const vaultID = tx.at(~sfVaultID))
46 {
47 if (*vaultID == beast::zero)
48 return temINVALID;
49 }
50
51 {
52 auto const minimumZero = tx[~sfCoverRateMinimum].value_or(0) == 0;
53 auto const liquidationZero =
54 tx[~sfCoverRateLiquidation].value_or(0) == 0;
55 // Both must be zero or non-zero.
56 if (minimumZero != liquidationZero)
57 {
58 return temINVALID;
59 }
60 }
61
62 return tesSUCCESS;
63}
64
65TER
67{
68 auto const& tx = ctx.tx;
69
70 auto const account = tx[sfAccount];
71 auto const vaultID = tx[sfVaultID];
72
73 if (auto const brokerID = tx[~sfLoanBrokerID])
74 {
75 auto const sleBroker = ctx.view.read(keylet::loanbroker(*brokerID));
76 if (!sleBroker)
77 {
78 JLOG(ctx.j.warn()) << "LoanBroker does not exist.";
79 return tecNO_ENTRY;
80 }
81 if (vaultID != sleBroker->at(sfVaultID))
82 {
83 JLOG(ctx.j.warn())
84 << "Can not change VaultID on an existing LoanBroker.";
85 return tecNO_PERMISSION;
86 }
87 if (account != sleBroker->at(sfOwner))
88 {
89 JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker.";
90 return tecNO_PERMISSION;
91 }
92 }
93 else
94 {
95 auto const sleVault = ctx.view.read(keylet::vault(vaultID));
96 if (!sleVault)
97 {
98 JLOG(ctx.j.warn()) << "Vault does not exist.";
99 return tecNO_ENTRY;
100 }
101 if (account != sleVault->at(sfOwner))
102 {
103 JLOG(ctx.j.warn()) << "Account is not the owner of the Vault.";
104 return tecNO_PERMISSION;
105 }
106 if (auto const ter = canAddHolding(ctx.view, sleVault->at(sfAsset)))
107 return ter;
108 }
109 return tesSUCCESS;
110}
111
112TER
114{
115 auto const& tx = ctx_.tx;
116 auto& view = ctx_.view();
117
118 if (auto const brokerID = tx[~sfLoanBrokerID])
119 {
120 // Modify an existing LoanBroker
121 auto broker = view.peek(keylet::loanbroker(*brokerID));
122 if (!broker)
123 {
124 // This should be impossible
125 // LCOV_EXCL_START
126 JLOG(j_.fatal()) << "LoanBroker does not exist.";
127 return tefBAD_LEDGER;
128 // LCOV_EXCL_STOP
129 }
130
131 if (auto const data = tx[~sfData])
132 broker->at(sfData) = *data;
133 if (auto const debtMax = tx[~sfDebtMaximum])
134 broker->at(sfDebtMaximum) = *debtMax;
135
136 view.update(broker);
137 }
138 else
139 {
140 // Create a new LoanBroker pointing back to the given Vault
141 auto const vaultID = tx[sfVaultID];
142 auto const sleVault = view.read(keylet::vault(vaultID));
143 if (!sleVault)
144 {
145 // This should be impossible
146 // LCOV_EXCL_START
147 JLOG(j_.fatal()) << "Vault does not exist.";
148 return tefBAD_LEDGER;
149 // LCOV_EXCL_STOP
150 }
151 auto const vaultPseudoID = sleVault->at(sfAccount);
152 auto const sequence = tx.getSeqValue();
153
154 auto owner = view.peek(keylet::account(account_));
155 if (!owner)
156 {
157 // This should be impossible
158 // LCOV_EXCL_START
159 JLOG(j_.fatal()) << "Account does not exist.";
160 return tefBAD_LEDGER;
161 // LCOV_EXCL_STOP
162 }
163 auto broker =
165
166 if (auto const ter = dirLink(view, account_, broker))
167 return ter; // LCOV_EXCL_LINE
168 if (auto const ter = dirLink(view, vaultPseudoID, broker, sfVaultNode))
169 return ter; // LCOV_EXCL_LINE
170
171 // Increases the owner count by two: one for the LoanBroker object, and
172 // one for the pseudo-account.
173 adjustOwnerCount(view, owner, 2, j_);
174 auto const ownerCount = owner->at(sfOwnerCount);
175 if (mPriorBalance < view.fees().accountReserve(ownerCount))
177
178 auto maybePseudo =
179 createPseudoAccount(view, broker->key(), sfLoanBrokerID);
180 if (!maybePseudo)
181 return maybePseudo.error(); // LCOV_EXCL_LINE
182 auto& pseudo = *maybePseudo;
183 auto pseudoId = pseudo->at(sfAccount);
184
185 if (auto ter = addEmptyHolding(
186 view, pseudoId, mPriorBalance, sleVault->at(sfAsset), j_))
187 return ter;
188
189 // Initialize data fields:
190 broker->at(sfSequence) = sequence;
191 broker->at(sfVaultID) = vaultID;
192 broker->at(sfOwner) = account_;
193 broker->at(sfAccount) = pseudoId;
194 // The LoanSequence indexes loans created by this broker, starting at 1
195 broker->at(sfLoanSequence) = 1;
196 if (auto const data = tx[~sfData])
197 broker->at(sfData) = *data;
198 if (auto const rate = tx[~sfManagementFeeRate])
199 broker->at(sfManagementFeeRate) = *rate;
200 if (auto const debtMax = tx[~sfDebtMaximum])
201 broker->at(sfDebtMaximum) = *debtMax;
202 if (auto const coverMin = tx[~sfCoverRateMinimum])
203 broker->at(sfCoverRateMinimum) = *coverMin;
204 if (auto const coverLiq = tx[~sfCoverRateLiquidation])
205 broker->at(sfCoverRateLiquidation) = *coverLiq;
206
207 view.insert(broker);
208 }
209
210 return tesSUCCESS;
211}
212
213//------------------------------------------------------------------------------
214
215} // namespace xrpl
Stream fatal() const
Definition Journal.h:333
Stream warn() const
Definition Journal.h:321
STTx const & tx
ApplyView & view()
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
TER doApply() override
static bool checkExtraFeatures(PreflightContext const &ctx)
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
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
static bool validDataLength(std::optional< Slice > const &slice, std::size_t maxLength)
ApplyContext & ctx_
Definition Transactor.h:124
static bool validNumericRange(std::optional< T > value, T max, T min=T{})
Definition Transactor.h:420
T is_same_v
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
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:166
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
TER addEmptyHolding(ApplyView &view, AccountID const &accountID, XRPAmount priorBalance, Issue const &issue, beast::Journal journal)
Any transactors that call addEmptyHolding() in doApply must call canAddHolding() in preflight with th...
Definition View.cpp:1439
TER canAddHolding(ReadView const &view, Asset const &asset)
Definition View.cpp:1322
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
Definition Protocol.h:235
@ tefBAD_LEDGER
Definition TER.h:151
bool checkLendingProtocolDependencies(PreflightContext const &ctx)
std::size_t constexpr maxDataPayloadLength
The maximum length of Data payload.
Definition Protocol.h:238
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:1134
TER dirLink(ApplyView &view, AccountID const &owner, std::shared_ptr< SLE > &object, SF_UINT64 const &node=sfOwnerNode)
Definition View.cpp:1160
@ temINVALID
Definition TER.h:91
@ tecNO_ENTRY
Definition TER.h:288
@ tecINSUFFICIENT_RESERVE
Definition TER.h:289
@ tecNO_PERMISSION
Definition TER.h:287
Expected< std::shared_ptr< SLE >, TER > createPseudoAccount(ApplyView &view, uint256 const &pseudoOwnerKey, SField const &ownerField)
Create pseudo-account, storing pseudoOwnerKey into ownerField.
Definition View.cpp:1246
@ tesSUCCESS
Definition TER.h:226
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
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