20#include <xrpld/app/tx/detail/VaultClawback.h>
22#include <xrpl/beast/utility/instrumentation.h>
23#include <xrpl/ledger/View.h>
24#include <xrpl/protocol/AccountID.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/MPTIssue.h>
27#include <xrpl/protocol/SField.h>
28#include <xrpl/protocol/STAmount.h>
29#include <xrpl/protocol/STNumber.h>
30#include <xrpl/protocol/TER.h>
31#include <xrpl/protocol/TxFlags.h>
47 if (ctx.
tx[sfVaultID] == beast::zero)
49 JLOG(ctx.
j.
debug()) <<
"VaultClawback: zero/empty vault ID.";
58 JLOG(ctx.
j.
debug()) <<
"VaultClawback: issuer cannot be holder.";
62 auto const amount = ctx.
tx[~sfAmount];
66 if (*amount < beast::zero)
68 else if (
isXRP(amount->asset()))
70 JLOG(ctx.
j.
debug()) <<
"VaultClawback: cannot clawback XRP.";
73 else if (amount->asset().getIssuer() != issuer)
76 <<
"VaultClawback: only asset issuer can clawback.";
91 auto account = ctx.
tx[sfAccount];
96 JLOG(ctx.
j.
error()) <<
"VaultClawback: missing issuer account.";
101 Asset const vaultAsset = vault->at(sfAsset);
102 if (
auto const amount = ctx.
tx[~sfAmount];
103 amount && vaultAsset != amount->asset())
108 JLOG(ctx.
j.
debug()) <<
"VaultClawback: cannot clawback XRP.";
111 else if (vaultAsset.
getIssuer() != account)
113 JLOG(ctx.
j.
debug()) <<
"VaultClawback: only asset issuer can clawback.";
120 auto const mptIssue =
122 if (mptIssue ==
nullptr)
125 std::uint32_t const issueFlags = mptIssue->getFieldU32(sfFlags);
129 <<
"VaultClawback: cannot clawback MPT vault asset.";
135 std::uint32_t const issuerFlags = issuer->getFieldU32(sfFlags);
140 <<
"VaultClawback: cannot clawback IOU vault asset.";
156 auto const mptIssuanceID = *((*vault)[sfShareMPTID]);
161 JLOG(
j_.
error()) <<
"VaultClawback: missing issuance of vault shares.";
166 Asset const vaultAsset = vault->at(sfAsset);
168 auto const maybeAmount = tx[~sfAmount];
171 return {sfAmount, vaultAsset, 0};
174 amount.
asset() == vaultAsset,
175 "ripple::VaultClawback::doApply : matching asset");
177 auto assetsAvailable = vault->at(sfAssetsAvailable);
178 auto assetsTotal = vault->at(sfAssetsTotal);
179 [[maybe_unused]]
auto const lossUnrealized = vault->at(sfLossUnrealized);
181 lossUnrealized <= (assetsTotal - assetsAvailable),
182 "ripple::VaultClawback::doApply : loss and assets do balance");
185 MPTIssue const share{mptIssuanceID};
190 if (amount == beast::zero)
200 auto const maybeAssets =
204 assetsRecovered = *maybeAssets;
208 assetsRecovered = amount;
210 auto const maybeShares =
214 sharesDestroyed = *maybeShares;
217 auto const maybeAssets =
221 assetsRecovered = *maybeAssets;
225 if (assetsRecovered > *assetsAvailable)
227 assetsRecovered = *assetsAvailable;
235 sharesDestroyed = *maybeShares;
238 auto const maybeAssets =
242 assetsRecovered = *maybeAssets;
243 if (assetsRecovered > *assetsAvailable)
247 <<
"VaultClawback: invalid rounding of shares.";
258 <<
"VaultClawback: overflow error with"
259 <<
" scale=" << (int)vault->at(sfScale).value()
260 <<
", assetsTotal=" << vault->at(sfAssetsTotal).value()
261 <<
", sharesTotal=" << sleIssuance->at(sfOutstandingAmount)
262 <<
", amount=" << amount.
value();
266 if (sharesDestroyed == beast::zero)
269 assetsTotal -= assetsRecovered;
270 assetsAvailable -= assetsRecovered;
273 auto const& vaultAccount = vault->at(sfAccount);
288 if (holder != vault->at(sfOwner))
295 <<
"VaultClawback: removed empty MPToken for vault shares"
303 <<
"VaultClawback: failed to remove MPToken for vault shares"
328 assetsRecovered.
asset(),
334 JLOG(
j_.
error()) <<
"VaultClawback: negative balance of vault assets.";
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.
constexpr TIss const & get() const
AccountID const & getIssuer() const
constexpr bool holds() const
A currency issued by an account.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Asset const & asset() const
STAmount const & value() const noexcept
std::uint32_t getFlags() const
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
Keylet mptIssuance(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.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
bool isXRP(AccountID const &c)
@ lsfAllowTrustLineClawback
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
std::optional< STAmount > assetsToSharesWithdraw(std::shared_ptr< SLE const > const &vault, std::shared_ptr< SLE const > const &issuance, STAmount const &assets, TruncateShares truncate=TruncateShares::no)
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.
std::optional< STAmount > sharesToAssetsWithdraw(std::shared_ptr< SLE const > const &vault, std::shared_ptr< SLE const > const &issuance, STAmount const &shares)
std::string transToken(TER code)
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
bool isTesSuccess(TER x) noexcept
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfUniversalMask
TER removeEmptyHolding(ApplyView &view, AccountID const &accountID, Issue const &issue, beast::Journal journal)
TERSubset< CanCvtToNotTEC > NotTEC
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.