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> 
   45        JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid asset pair.";
 
   49    if (
auto const bidMin = ctx.
tx[~sfBidMin])
 
   53            JLOG(ctx.
j.
debug()) << 
"AMM Bid: invalid min slot price.";
 
   58    if (
auto const bidMax = ctx.
tx[~sfBidMax])
 
   62            JLOG(ctx.
j.
debug()) << 
"AMM Bid: invalid max slot price.";
 
   72            JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid number of AuthAccounts.";
 
   79            for (
auto const& obj : authAccounts)
 
   81                auto authAccount = obj[sfAccount];
 
   82                if (authAccount == account || unique.contains(authAccount))
 
   84                    JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid auth.account.";
 
   87                unique.insert(authAccount);
 
 
  102        JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid asset pair.";
 
  106    auto const lpTokensBalance = (*ammSle)[sfLPTokenBalance];
 
  107    if (lpTokensBalance == beast::zero)
 
  116                JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid Account.";
 
  122    auto const lpTokens =
 
  125    if (lpTokens == beast::zero)
 
  127        JLOG(ctx.
j.
debug()) << 
"AMM Bid: account is not LP.";
 
  131    auto const bidMin = ctx.
tx[~sfBidMin];
 
  135        if (bidMin->issue() != lpTokens.issue())
 
  137            JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid LPToken.";
 
  140        if (*bidMin > lpTokens || *bidMin >= lpTokensBalance)
 
  142            JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid Tokens.";
 
  147    auto const bidMax = ctx.
tx[~sfBidMax];
 
  150        if (bidMax->issue() != lpTokens.issue())
 
  152            JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid LPToken.";
 
  155        if (*bidMax > lpTokens || *bidMax >= lpTokensBalance)
 
  157            JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid Tokens.";
 
  162    if (bidMin && bidMax && bidMin > bidMax)
 
  164        JLOG(ctx.
j.
debug()) << 
"AMM Bid: Invalid Max/MinSlotPrice.";
 
 
  183    STAmount const lptAMMBalance = (*ammSle)[sfLPTokenBalance];
 
  186    if (!rules.enabled(fixInnerObjTemplate))
 
  188        if (!ammSle->isFieldPresent(sfAuctionSlot))
 
  189            ammSle->makeFieldPresent(sfAuctionSlot);
 
  194            ammSle->isFieldPresent(sfAuctionSlot),
 
  195            "ripple::applyBid : has auction slot");
 
  196        if (!ammSle->isFieldPresent(sfAuctionSlot))
 
  199    auto& auctionSlot = ammSle->peekFieldObject(sfAuctionSlot);
 
  201        duration_cast<seconds>(
 
  205    auto const discountedFee =
 
  207    auto const tradingFee = 
getFee((*ammSle)[sfTradingFee]);
 
  209    auto const minSlotPrice =
 
  219    auto validOwner = [&](
AccountID const& account) {
 
  222        return timeSlot && *timeSlot < tailingSlot &&
 
  229        auctionSlot.setAccountID(sfAccount, account_);
 
  232            auctionSlot.setFieldU16(sfDiscountedFee, fee);
 
  233        else if (auctionSlot.isFieldPresent(sfDiscountedFee))
 
  234            auctionSlot.makeFieldAbsent(sfDiscountedFee);
 
  235        auctionSlot.setFieldAmount(
 
  236            sfPrice, 
toSTAmount(lpTokens.issue(), minPrice));
 
  238            auctionSlot.setFieldArray(
 
  241            auctionSlot.makeFieldAbsent(sfAuthAccounts);
 
  247        if (saBurn >= lptAMMBalance)
 
  252                << 
"AMM Bid: LP Token burn exceeds AMM balance " << burn << 
" " 
  261            JLOG(ctx_.
journal.
debug()) << 
"AMM Bid: failed to redeem.";
 
  264        ammSle->setFieldAmount(sfLPTokenBalance, lptAMMBalance - saBurn);
 
  271    auto const bidMin = ctx_.
tx[~sfBidMin];
 
  272    auto const bidMax = ctx_.
tx[~sfBidMax];
 
  278            if (bidMin && bidMax)
 
  280                if (computedPrice <= *bidMax)
 
  283                    << 
"AMM Bid: not in range " << computedPrice << 
" " 
  284                    << *bidMin << 
" " << *bidMax;
 
  294                if (computedPrice <= *bidMax)
 
  295                    return computedPrice;
 
  297                                           << computedPrice << 
" " << *bidMax;
 
  301                return computedPrice;
 
  305        else if (payPrice > lpTokens)
 
  311    if (
auto const acct = auctionSlot[~sfAccount]; !acct || !validOwner(*acct))
 
  313        if (
auto const payPrice = getPayPrice(minSlotPrice); !payPrice)
 
  314            return {payPrice.error(), 
false};
 
  316            res = updateSlot(discountedFee, *payPrice, *payPrice);
 
  321        STAmount const pricePurchased = auctionSlot[sfPrice];
 
  322        XRPL_ASSERT(timeSlot, 
"ripple::applyBid : timeSlot is set");
 
  323        auto const fractionUsed =
 
  325        auto const fractionRemaining = 
Number(1) - fractionUsed;
 
  326        auto const computedPrice = [&]() -> 
Number {
 
  327            auto const p1_05 = 
Number(105, -2);
 
  330                return pricePurchased * p1_05 + minSlotPrice;
 
  332            return pricePurchased * p1_05 * (1 - 
power(fractionUsed, 60)) +
 
  336        auto const payPrice = getPayPrice(computedPrice);
 
  339            return {payPrice.error(), 
false};
 
  343        auto const refund = fractionRemaining * pricePurchased;
 
  344        if (refund > *payPrice)
 
  347            JLOG(ctx_.
journal.
fatal()) << 
"AMM Bid: refund exceeds payPrice " 
  348                                       << refund << 
" " << *payPrice;
 
  354            auctionSlot[sfAccount],
 
  359            JLOG(ctx_.
journal.
debug()) << 
"AMM Bid: failed to refund.";
 
  363        auto const burn = *payPrice - refund;
 
  364        res = updateSlot(discountedFee, *payPrice, burn);
 
 
A generic endpoint for log messages.
 
static TER preclaim(PreclaimContext const &ctx)
 
static bool checkExtraFeatures(PreflightContext 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
 
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.
 
@ 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.
 
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)
 
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
 
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)