1#include <xrpl/tx/transactors/lending/LoanBrokerCoverClawback.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/beast/utility/Zero.h>
7#include <xrpl/core/ServiceRegistry.h>
8#include <xrpl/ledger/ReadView.h>
9#include <xrpl/ledger/helpers/LendingHelpers.h>
10#include <xrpl/ledger/helpers/TokenHelpers.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/Asset.h>
13#include <xrpl/protocol/Concepts.h>
14#include <xrpl/protocol/Feature.h>
15#include <xrpl/protocol/Indexes.h>
16#include <xrpl/protocol/Issue.h>
17#include <xrpl/protocol/LedgerFormats.h>
18#include <xrpl/protocol/MPTIssue.h>
19#include <xrpl/protocol/Protocol.h>
20#include <xrpl/protocol/SField.h>
21#include <xrpl/protocol/STAmount.h>
22#include <xrpl/protocol/STLedgerEntry.h>
23#include <xrpl/protocol/STTakesAsset.h>
24#include <xrpl/protocol/STTx.h>
25#include <xrpl/protocol/TER.h>
26#include <xrpl/protocol/Units.h>
27#include <xrpl/protocol/XRPAmount.h>
28#include <xrpl/tx/Transactor.h>
45 auto const brokerID = ctx.
tx[~sfLoanBrokerID];
46 auto const amount = ctx.
tx[~sfAmount];
48 if (!brokerID && !amount)
51 if (brokerID && *brokerID == beast::kZero)
61 if (*amount < beast::kZero)
73 auto const account = ctx.
tx[sfAccount];
77 auto const holder = amount->getIssuer();
78 if (holder == account || holder == beast::kZero)
86std::expected<uint256, TER>
91 if (
auto const brokerID = tx[~sfLoanBrokerID])
97 auto const dstAmount = tx[~sfAmount];
98 if (!dstAmount || !dstAmount->holds<
Issue>())
110 auto const maybePseudo = dstAmount->getIssuer();
120 if (
auto const brokerID = sle->at(~sfLoanBrokerID))
129std::expected<Asset, TER>
137 return amount.
asset();
145 if (holder == account)
147 return amount.
asset();
149 if (holder == brokerPseudoAccountID)
159std::expected<STAmount, TER>
161 SLE const& sleBroker,
162 Asset const& vaultAsset,
167 auto const maxClawAmount = [&]() {
168 auto const minRequiredCover = [&]() {
169 if (rules.
enabled(fixCleanup3_2_0))
172 sleBroker[sfDebtTotal],
TenthBips32(sleBroker[sfCoverRateMinimum]), vaultSle);
178 sleBroker[sfDebtTotal],
TenthBips32(sleBroker[sfCoverRateMinimum]));
182 return sleBroker[sfCoverAvailable] - minRequiredCover;
184 if (maxClawAmount <= beast::kZero)
190 if (!amount || *amount == beast::kZero)
191 return STAmount{vaultAsset, maxClawAmount};
192 Number const magnitude{*amount};
193 if (magnitude > maxClawAmount)
194 return STAmount{vaultAsset, maxClawAmount};
195 return STAmount{vaultAsset, magnitude};
198template <Val
idIssueType T>
208 if (!(sleIssuer.
isFlag(lsfAllowTrustLineClawback)) || (sleIssuer.
isFlag(lsfNoFreeze)))
218 SLE const& sleIssuer,
222 auto const sleIssuance = ctx.
view.
read(issuanceKey);
226 if (!sleIssuance->isFlag(lsfMPTCanClawback))
230 if (sleIssuance->at(sfIssuer) != sleIssuer[sfAccount])
239 auto const& tx = ctx.
tx;
241 auto const account = tx[sfAccount];
244 return findBrokerID.error();
245 auto const brokerID = *findBrokerID;
246 auto const amount = tx[~sfAmount];
251 JLOG(ctx.
j.
warn()) <<
"LoanBroker does not exist.";
255 auto const brokerPseudoAccountID = sleBroker->at(sfAccount);
261 JLOG(ctx.
j.
fatal()) <<
"Vault is missing for Broker " << brokerID;
266 auto const vaultAsset = vault->at(sfAsset);
268 if (vaultAsset.native())
270 JLOG(ctx.
j.
warn()) <<
"Cannot clawback native asset.";
276 if (vaultAsset.getIssuer() != account)
278 JLOG(ctx.
j.
warn()) <<
"Account is not the issuer of the vault asset.";
284 auto const findAsset =
determineAsset(ctx.
view, account, brokerPseudoAccountID, *amount);
286 return findAsset.error();
287 auto const txAsset = *findAsset;
288 if (txAsset != vaultAsset)
290 JLOG(ctx.
j.
warn()) <<
"Account is the correct issuer, but trying "
291 "to clawback the wrong asset from LoanBroker";
296 auto const findClawAmount =
300 JLOG(ctx.
j.
warn()) <<
"LoanBroker cover is already at minimum.";
301 return findClawAmount.error();
303 STAmount const& clawAmount = *findClawAmount;
306 ctx.
view, sleBroker, vaultAsset, clawAmount, ctx.
j,
"LoanBrokerCoverClawback"))
314 brokerPseudoAccountID,
326 JLOG(ctx.
j.
fatal()) <<
"Issuer account does not exist.";
332 [&]<
typename T>(T
const&) {
return preclaimHelper<T>(ctx, *sleIssuer, clawAmount); },
339 auto const& tx =
ctx_.tx;
340 auto const account = tx[sfAccount];
344 auto const brokerID = *findBrokerID;
345 auto const amount = tx[~sfAmount];
351 auto const brokerPseudoID = *sleBroker->at(sfAccount);
357 auto const vaultAsset = vault->at(sfAsset);
359 auto const findClawAmount =
363 STAmount const& clawAmount = *findClawAmount;
369 sleBroker->at(sfCoverAvailable) -= clawAmount;
A generic endpoint for log messages.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::ref sle)=0
Indicate changes to a peeked SLE.
A currency issued by an account.
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.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
static bool checkExtraFeatures(PreflightContext const &ctx)
constexpr MPTID const & getMptID() const
Number is a floating point type that can represent a wide range of values.
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.
Rules controlling protocol behavior.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
constexpr bool holds() const noexcept
constexpr TIss const & get() const
bool native() const noexcept
Asset const & asset() const
AccountID const & getIssuer() const
std::shared_ptr< STLedgerEntry const > const & const_ref
bool isFlag(std::uint32_t) const
Keylet loanBroker(AccountID const &owner, std::uint32_t seq) noexcept
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet vault(AccountID const &owner, std::uint32_t seq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
TER canApplyToBrokerCover(ReadView const &view, SLE::const_ref sleBroker, Asset const &vaultAsset, STAmount const &amount, beast::Journal j, std::string_view logPrefix)
Broker cover preclaim precision guard (fixCleanup3_2_0).
constexpr T tenthBipsOfValue(T value, TenthBips< TBips > bips)
Number minimumBrokerCover(Number const &debtTotal, TenthBips32 coverRateMinimum, SLE::const_ref vaultSle)
bool isLegalNet(STAmount const &value)
TenthBips< std::uint32_t > TenthBips32
TERSubset< CanCvtToNotTEC > NotTEC
TER preclaimHelper< Issue >(PreclaimContext const &ctx, SLE const &sleIssuer, STAmount const &clawAmount)
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.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TERSubset< CanCvtToTER > TER
TER preclaimHelper< MPTIssue >(PreclaimContext const &ctx, SLE const &sleIssuer, STAmount const &clawAmount)
void associateAsset(STLedgerEntry &sle, Asset const &asset)
Associate an Asset with all sMD_NeedsAsset fields in a ledger entry.
std::expected< uint256, TER > determineBrokerID(ReadView const &view, STTx const &tx)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=SpendableHandling::SimpleBalance)
static TER preclaimHelper(PreclaimContext const &ctx, SLE const &sleIssuer, STAmount const &clawAmount)
std::expected< STAmount, TER > determineClawAmount(SLE const &sleBroker, Asset const &vaultAsset, std::optional< STAmount > const &amount, SLE::const_ref vaultSle, Rules const &rules)
bool checkLendingProtocolDependencies(Rules const &rules, STTx const &tx)
std::expected< Asset, TER > determineAsset(ReadView const &view, AccountID const &account, AccountID const &brokerPseudoAccountID, STAmount const &amount)
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.