1#include <xrpl/ledger/Sandbox.h>
2#include <xrpl/ledger/View.h>
3#include <xrpl/protocol/Feature.h>
4#include <xrpl/protocol/Indexes.h>
5#include <xrpl/protocol/TxFlags.h>
6#include <xrpl/protocol/st.h>
7#include <xrpl/tx/transactors/dex/AMMClawback.h>
8#include <xrpl/tx/transactors/dex/AMMHelpers.h>
9#include <xrpl/tx/transactors/dex/AMMUtils.h>
10#include <xrpl/tx/transactors/dex/AMMWithdraw.h>
19 return tfAMMClawbackMask;
30 JLOG(ctx.
j.
trace()) <<
"AMMClawback: holder cannot be the same as issuer.";
35 auto const asset = ctx.
tx[sfAsset].get<
Issue>();
36 auto const asset2 = ctx.
tx[sfAsset2].get<
Issue>();
43 if (((flags & tfClawTwoAssets) != 0u) && asset.account != asset2.
account)
45 JLOG(ctx.
j.
trace()) <<
"AMMClawback: tfClawTwoAssets can only be enabled when two "
46 "assets in the AMM pool are both issued by the issuer";
50 if (asset.account != issuer)
52 JLOG(ctx.
j.
trace()) <<
"AMMClawback: Asset's account does not "
53 "match Account field.";
57 if (clawAmount && clawAmount->get<
Issue>() != asset)
59 JLOG(ctx.
j.
trace()) <<
"AMMClawback: Amount's issuer/currency subfield "
60 "does not match Asset field";
64 if (clawAmount && *clawAmount <= beast::zero)
73 auto const asset = ctx.
tx[sfAsset].get<
Issue>();
74 auto const asset2 = ctx.
tx[sfAsset2].get<
Issue>();
85 JLOG(ctx.
j.
debug()) <<
"AMM Clawback: Invalid asset pair.";
89 std::uint32_t const issuerFlagsIn = sleIssuer->getFieldU32(sfFlags);
93 if (((issuerFlagsIn & lsfAllowTrustLineClawback) == 0u) ||
94 ((issuerFlagsIn & lsfNoFreeze) != 0u))
125 auto const ammAccount = (*ammSle)[sfAccount];
133 auto const lpTokenBalance =
ammLPHolds(sb, *ammSle, holder,
j_);
134 if (lpTokenBalance == beast::zero)
141 auto const expected =
145 return expected.error();
146 auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
155 auto const holdLPtokens =
ammLPHolds(sb, *ammSle, holder,
j_);
156 if (holdLPtokens == beast::zero)
163 std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) =
182 std::tie(result, newLPTokenBalance, amountWithdraw, amount2Withdraw) =
203 JLOG(
ctx_.
journal.
trace()) <<
"AMM Withdraw during AMMClawback: lptoken new balance: "
205 <<
" old balance: " <<
to_string(lptAMMBalance.iou());
207 auto const ter =
rippleCredit(sb, holder, issuer, amountWithdraw,
true,
j_);
215 if (!amount2Withdraw)
219 if ((flags & tfClawTwoAssets) != 0u)
220 return rippleCredit(sb, holder, issuer, *amount2Withdraw,
true,
j_);
237 auto frac =
Number{amount} / amountBalance;
238 auto amount2Withdraw = amount2Balance * frac;
240 auto const lpTokensWithdraw =
toSTAmount(lptAMMBalance.
issue(), lptAMMBalance * frac);
242 if (lpTokensWithdraw > holdLPtokens)
264 auto const& rules = sb.
rules();
265 if (rules.enabled(fixAMMClawbackRounding))
270 if (tokensAdj == beast::zero)
Stream trace() const
Severity stream access functions.
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
TER applyGuts(Sandbox &view)
std::tuple< TER, STAmount, STAmount, std::optional< STAmount > > equalWithdrawMatchingOneAmount(Sandbox &view, SLE const &ammSle, AccountID const &holder, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount2Balance, STAmount const &lptAMMBalance, STAmount const &holdLPtokens, STAmount const &amount)
Withdraw both assets by providing maximum amount of asset1, asset2's amount will be calculated accord...
static std::tuple< TER, STAmount, STAmount, std::optional< STAmount > > equalWithdrawTokens(Sandbox &view, SLE const &ammSle, AccountID const account, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount2Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, STAmount const &lpTokensWithdraw, std::uint16_t tfee, FreezeHandling freezeHanding, WithdrawAll withdrawAll, XRPAmount const &priorBalance, beast::Journal const &journal)
Equal-asset withdrawal (LPTokens) of some AMM instance pools shares represented by the number of LPTo...
static std::tuple< TER, STAmount, STAmount, std::optional< STAmount > > withdraw(Sandbox &view, SLE const &ammSle, AccountID const &ammAccount, AccountID const &account, STAmount const &amountBalance, STAmount const &amountWithdraw, std::optional< STAmount > const &amount2Withdraw, STAmount const &lpTokensAMMBalance, STAmount const &lpTokensWithdraw, std::uint16_t tfee, FreezeHandling freezeHandling, WithdrawAll withdrawAll, XRPAmount const &priorBalance, beast::Journal const &journal)
Withdraw requested assets and token from AMM into LP account.
static std::pair< TER, bool > deleteAMMAccountIfEmpty(Sandbox &sb, std::shared_ptr< SLE > const ammSle, STAmount const &lpTokenBalance, Issue const &issue1, Issue const &issue2, beast::Journal const &journal)
beast::Journal const journal
A currency issued by an account.
Number is a floating point type that can represent a wide range of values.
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.
Issue const & issue() const
std::uint32_t getFlags() const
Discardable, editable view to a ledger.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
Rules const & rules() const override
Returns the tx processing rules.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet account(AccountID const &id) noexcept
AccountID root.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool isXRP(AccountID const &c)
Number adjustFracByTokens(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &tokens, Number const &frac)
Find a fraction of tokens after the tokens are adjusted.
std::string to_string(base_uint< Bits, Tag > const &a)
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
STAmount getRoundedLPTokens(Rules const &rules, STAmount const &balance, Number const &frac, IsDeposit isDeposit)
Round AMM deposit/withdrawal LPToken amount.
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
STAmount getRoundedAsset(Rules const &rules, STAmount const &balance, A const &frac, IsDeposit isDeposit)
Round AMM equal deposit/withdrawal amount.
bool isTesSuccess(TER x) noexcept
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Expected< bool, TER > verifyAndAdjustLPTokenBalance(Sandbox &sb, STAmount const &lpTokens, std::shared_ptr< SLE > &ammSle, AccountID const &account)
Due to rounding, the LPTokenBalance of the last LP might not match the LP's trustline balance.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.