1#include <xrpl/tx/transactors/dex/AMMVote.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/beast/utility/instrumentation.h>
7#include <xrpl/ledger/Sandbox.h>
8#include <xrpl/ledger/helpers/AMMHelpers.h>
9#include <xrpl/protocol/AMMCore.h>
10#include <xrpl/protocol/AccountID.h>
11#include <xrpl/protocol/Feature.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/MPTIssue.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STArray.h>
16#include <xrpl/protocol/STLedgerEntry.h>
17#include <xrpl/protocol/STTx.h>
18#include <xrpl/protocol/TER.h>
19#include <xrpl/protocol/XRPAmount.h>
20#include <xrpl/tx/ApplyContext.h>
21#include <xrpl/tx/Transactor.h>
45 JLOG(ctx.
j.
debug()) <<
"AMM Vote: invalid asset pair.";
51 JLOG(ctx.
j.
debug()) <<
"AMM Vote: invalid trading fee.";
64 JLOG(ctx.
j.
debug()) <<
"AMM Vote: Invalid asset pair.";
67 if (ammSle->getFieldAmount(sfLPTokenBalance) == beast::kZero)
71 if (
auto const lpTokensNew =
ammLPHolds(ctx.
view, *ammSle, ctx.
tx[sfAccount], ctx.
j);
72 lpTokensNew == beast::kZero)
74 JLOG(ctx.
j.
debug()) <<
"AMM Vote: account is not LP.";
84 auto const feeNew = ctx.
tx[sfTradingFee];
88 STAmount const lptAMMBalance = (*ammSle)[sfLPTokenBalance];
98 bool foundAccount =
false;
104 for (
auto const& entry : ammSle->getFieldArray(sfVoteSlots))
106 auto const entryAccount = entry[sfAccount];
108 if (lpTokens == beast::kZero)
110 JLOG(j.
debug()) <<
"AMMVote::applyVote, accountID " << entryAccount <<
" is not LP";
113 auto feeVal = entry[sfTradingFee];
116 if (entryAccount == accountID)
118 lpTokens = lpTokensNew;
123 num += feeVal * lpTokens;
135 (lpTokens < *minTokens ||
136 (lpTokens == *minTokens &&
137 (feeVal < minFee || (feeVal == minFee && entryAccount < minAccount)))))
139 minTokens = lpTokens;
140 minPos = updatedVoteSlots.
size();
141 minAccount = entryAccount;
144 updatedVoteSlots.
pushBack(std::move(newEntry));
159 num += feeNew * lpTokensNew;
163 *(updatedVoteSlots.
begin() + *minPos) = std::move(newEntry);
167 updatedVoteSlots.
pushBack(std::move(newEntry));
180 else if (lpTokensNew > *minTokens || (lpTokensNew == *minTokens && feeNew > minFee))
182 auto const entry = updatedVoteSlots.
begin() + minPos;
184 num -=
Number((*entry)[~sfTradingFee].valueOr(0)) * *minTokens;
193 JLOG(j.
debug()) <<
"AMMVote::applyVote, insufficient tokens to "
194 "override other votes";
199 !ctx.
view().
rules().
enabled(fixInnerObjTemplate) || ammSle->isFieldPresent(sfAuctionSlot),
200 "xrpl::applyVote : has auction slot");
203 ammSle->setFieldArray(sfVoteSlots, updatedVoteSlots);
204 if (
auto const fee =
static_cast<std::int64_t>(num / den))
206 ammSle->setFieldU16(sfTradingFee, fee);
207 if (ammSle->isFieldPresent(sfAuctionSlot))
209 auto& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot);
212 auctionSlot.setFieldU16(sfDiscountedFee, discountedFee);
214 else if (auctionSlot.isFieldPresent(sfDiscountedFee))
216 auctionSlot.makeFieldAbsent(sfDiscountedFee);
222 if (ammSle->isFieldPresent(sfTradingFee))
223 ammSle->makeFieldAbsent(sfTradingFee);
224 if (ammSle->isFieldPresent(sfAuctionSlot))
226 auto& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot);
227 if (auctionSlot.isFieldPresent(sfDiscountedFee))
228 auctionSlot.makeFieldAbsent(sfDiscountedFee);
A generic endpoint for log messages.
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.
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 bool checkExtraFeatures(PreflightContext const &ctx)
State information when applying a tx.
beast::Journal const journal
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.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
void pushBack(STObject const &object)
std::shared_ptr< STLedgerEntry const > const & const_ref
void setFieldU32(SField const &field, std::uint32_t)
void setFieldU16(SField const &field, std::uint16_t)
static STObject makeInnerObject(SField const &name)
void setAccountID(SField const &field, AccountID const &)
Discardable, editable view to a ledger.
AccountID const accountID_
SLE::pointer peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
void update(SLE::ref sle) override
Indicate changes to a peeked SLE.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint16_t kVoteMaxSlots
constexpr std::uint16_t kTradingFeeThreshold
STAmount ammLPHolds(ReadView const &view, Asset const &asset1, Asset const &asset2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
constexpr std::uint32_t kAuctionSlotDiscountedFeeFraction
bool ammEnabled(Rules const &)
Return true if required AMM amendment is enabled.
NotTEC invalidAMMAssetPair(Asset const &asset1, Asset const &asset2, std::optional< std::pair< Asset, Asset > > const &pair=std::nullopt)
TERSubset< CanCvtToNotTEC > NotTEC
static std::pair< TER, bool > applyVote(ApplyContext &ctx, Sandbox &sb, AccountID const &accountID, beast::Journal j)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t kVoteWeightScaleFactor
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.