20#include <xrpld/app/misc/AMMHelpers.h>
21#include <xrpld/app/misc/AMMUtils.h>
22#include <xrpld/app/tx/detail/AMMBid.h>
24#include <xrpl/ledger/Sandbox.h>
25#include <xrpl/ledger/View.h>
26#include <xrpl/protocol/AMMCore.h>
27#include <xrpl/protocol/Feature.h>
28#include <xrpl/protocol/TER.h>
29#include <xrpl/protocol/TxFlags.h>
44 JLOG(ctx.
j.
debug()) <<
"AMM Bid: invalid flags.";
51 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid asset pair.";
55 if (
auto const bidMin = ctx.
tx[~sfBidMin])
59 JLOG(ctx.
j.
debug()) <<
"AMM Bid: invalid min slot price.";
64 if (
auto const bidMax = ctx.
tx[~sfBidMax])
68 JLOG(ctx.
j.
debug()) <<
"AMM Bid: invalid max slot price.";
78 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid number of AuthAccounts.";
85 for (
auto const& obj : authAccounts)
87 auto authAccount = obj[sfAccount];
88 if (authAccount == account || unique.contains(authAccount))
90 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid auth.account.";
93 unique.insert(authAccount);
108 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid asset pair.";
112 auto const lpTokensBalance = (*ammSle)[sfLPTokenBalance];
113 if (lpTokensBalance == beast::zero)
122 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid Account.";
128 auto const lpTokens =
131 if (lpTokens == beast::zero)
133 JLOG(ctx.
j.
debug()) <<
"AMM Bid: account is not LP.";
137 auto const bidMin = ctx.
tx[~sfBidMin];
141 if (bidMin->issue() != lpTokens.issue())
143 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid LPToken.";
146 if (*bidMin > lpTokens || *bidMin >= lpTokensBalance)
148 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid Tokens.";
153 auto const bidMax = ctx.
tx[~sfBidMax];
156 if (bidMax->issue() != lpTokens.issue())
158 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid LPToken.";
161 if (*bidMax > lpTokens || *bidMax >= lpTokensBalance)
163 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid Tokens.";
168 if (bidMin && bidMax && bidMin > bidMax)
170 JLOG(ctx.
j.
debug()) <<
"AMM Bid: Invalid Max/MinSlotPrice.";
189 STAmount const lptAMMBalance = (*ammSle)[sfLPTokenBalance];
192 if (!rules.enabled(fixInnerObjTemplate))
194 if (!ammSle->isFieldPresent(sfAuctionSlot))
195 ammSle->makeFieldPresent(sfAuctionSlot);
200 ammSle->isFieldPresent(sfAuctionSlot),
201 "ripple::applyBid : has auction slot");
202 if (!ammSle->isFieldPresent(sfAuctionSlot))
205 auto& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot);
207 duration_cast<seconds>(
211 auto const discountedFee =
213 auto const tradingFee =
getFee((*ammSle)[sfTradingFee]);
215 auto const minSlotPrice =
225 auto validOwner = [&](
AccountID const& account) {
228 return timeSlot && *timeSlot < tailingSlot &&
235 auctionSlot.setAccountID(sfAccount, account_);
238 auctionSlot.setFieldU16(sfDiscountedFee, fee);
239 else if (auctionSlot.isFieldPresent(sfDiscountedFee))
240 auctionSlot.makeFieldAbsent(sfDiscountedFee);
241 auctionSlot.setFieldAmount(
242 sfPrice,
toSTAmount(lpTokens.issue(), minPrice));
244 auctionSlot.setFieldArray(
247 auctionSlot.makeFieldAbsent(sfAuthAccounts);
253 if (saBurn >= lptAMMBalance)
257 <<
"AMM Bid: LP Token burn exceeds AMM balance " << burn <<
" "
265 JLOG(ctx_.
journal.
debug()) <<
"AMM Bid: failed to redeem.";
268 ammSle->setFieldAmount(sfLPTokenBalance, lptAMMBalance - saBurn);
275 auto const bidMin = ctx_.
tx[~sfBidMin];
276 auto const bidMax = ctx_.
tx[~sfBidMax];
282 if (bidMin && bidMax)
284 if (computedPrice <= *bidMax)
287 <<
"AMM Bid: not in range " << computedPrice <<
" "
288 << *bidMin <<
" " << *bidMax;
298 if (computedPrice <= *bidMax)
299 return computedPrice;
301 << computedPrice <<
" " << *bidMax;
305 return computedPrice;
309 else if (payPrice > lpTokens)
315 if (
auto const acct = auctionSlot[~sfAccount]; !acct || !validOwner(*acct))
317 if (
auto const payPrice = getPayPrice(minSlotPrice); !payPrice)
318 return {payPrice.error(),
false};
320 res = updateSlot(discountedFee, *payPrice, *payPrice);
325 STAmount const pricePurchased = auctionSlot[sfPrice];
326 XRPL_ASSERT(timeSlot,
"ripple::applyBid : timeSlot is set");
327 auto const fractionUsed =
329 auto const fractionRemaining =
Number(1) - fractionUsed;
330 auto const computedPrice = [&]() ->
Number {
331 auto const p1_05 =
Number(105, -2);
334 return pricePurchased * p1_05 + minSlotPrice;
336 return pricePurchased * p1_05 * (1 -
power(fractionUsed, 60)) +
340 auto const payPrice = getPayPrice(computedPrice);
343 return {payPrice.error(),
false};
347 auto const refund = fractionRemaining * pricePurchased;
348 if (refund > *payPrice)
351 JLOG(ctx_.
journal.
fatal()) <<
"AMM Bid: refund exceeds payPrice "
352 << refund <<
" " << *payPrice;
358 auctionSlot[sfAccount],
363 JLOG(ctx_.
journal.
debug()) <<
"AMM Bid: failed to refund.";
367 auto const burn = *payPrice - refund;
368 res = updateSlot(discountedFee, *payPrice, burn);
A generic endpoint for log messages.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
State information when applying a tx.
beast::Journal const journal
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.
virtual LedgerInfo const & info() const =0
Returns information about the ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Issue const & issue() const
STArray const & getFieldArray(SField const &field) const
bool isFieldPresent(SField const &field) const
std::uint32_t getFlags() const
Discardable, editable view to a ledger.
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with 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.
NotTEC invalidAMMAmount(STAmount const &amount, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt, bool validZero=false)
Validate the amount.
std::uint32_t constexpr TOTAL_TIME_SLOT_SECS
std::uint16_t constexpr AUCTION_SLOT_TIME_INTERVALS
std::optional< std::uint8_t > ammAuctionTimeSlot(std::uint64_t current, STObject const &auctionSlot)
Get time slot of the auction slot.
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
@ current
This was a new validation and was added.
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::uint32_t constexpr AUCTION_SLOT_MIN_FEE_FRACTION
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, IsDeposit isDeposit)
Adjust LP tokens to deposit/withdraw.
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.
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Number getFee(std::uint16_t tfee)
Convert to the fee from the basis points.
Number power(Number const &f, unsigned n)
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
bool isTesSuccess(TER x) noexcept
constexpr std::uint32_t tfUniversalMask
static std::pair< TER, bool > applyBid(ApplyContext &ctx_, Sandbox &sb, AccountID const &account_, beast::Journal j_)
TERSubset< CanCvtToTER > TER
std::uint16_t constexpr AUCTION_SLOT_MAX_AUTH_ACCOUNTS
TERSubset< CanCvtToNotTEC > NotTEC
std::uint32_t constexpr AUCTION_SLOT_DISCOUNTED_FEE_FRACTION
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.
T time_since_epoch(T... args)