20#include <xrpld/app/ledger/OrderBookDB.h> 
   21#include <xrpld/app/misc/AMMHelpers.h> 
   22#include <xrpld/app/misc/AMMUtils.h> 
   23#include <xrpld/app/tx/detail/AMMCreate.h> 
   25#include <xrpl/ledger/Sandbox.h> 
   26#include <xrpl/ledger/View.h> 
   27#include <xrpl/protocol/AMMCore.h> 
   28#include <xrpl/protocol/Feature.h> 
   29#include <xrpl/protocol/STIssue.h> 
   30#include <xrpl/protocol/TxFlags.h> 
   43    auto const amount = ctx.
tx[sfAmount];
 
   44    auto const amount2 = ctx.
tx[sfAmount2];
 
   46    if (amount.issue() == amount2.issue())
 
   49            << 
"AMM Instance: tokens can not have the same currency/issuer.";
 
   55        JLOG(ctx.
j.
debug()) << 
"AMM Instance: invalid asset1 amount.";
 
   61        JLOG(ctx.
j.
debug()) << 
"AMM Instance: invalid asset2 amount.";
 
   67        JLOG(ctx.
j.
debug()) << 
"AMM Instance: invalid trading fee.";
 
 
   84    auto const accountID = ctx.
tx[sfAccount];
 
   85    auto const amount = ctx.
tx[sfAmount];
 
   86    auto const amount2 = ctx.
tx[sfAmount2];
 
   89    if (
auto const ammKeylet = 
keylet::amm(amount.issue(), amount2.issue());
 
   92        JLOG(ctx.
j.
debug()) << 
"AMM Instance: ltAMM already exists.";
 
  100            << 
"AMM Instance: account is not authorized, " << amount.issue();
 
  104    if (
auto const ter = 
requireAuth(ctx.
view, amount2.issue(), accountID);
 
  108            << 
"AMM Instance: account is not authorized, " << amount2.issue();
 
  116        JLOG(ctx.
j.
debug()) << 
"AMM Instance: involves frozen asset.";
 
  124        if (
auto const issuerAccount =
 
  131    if (noDefaultRipple(ctx.
view, amount.issue()) ||
 
  132        noDefaultRipple(ctx.
view, amount2.issue()))
 
  134        JLOG(ctx.
j.
debug()) << 
"AMM Instance: DefaultRipple not set";
 
  141    if (xrpBalance <= beast::zero)
 
  143        JLOG(ctx.
j.
debug()) << 
"AMM Instance: insufficient reserves";
 
  147    auto insufficientBalance = [&](
STAmount const& asset) {
 
  149            return xrpBalance < asset;
 
  159    if (insufficientBalance(amount) || insufficientBalance(amount2))
 
  162            << 
"AMM Instance: insufficient funds, " << amount << 
" " << amount2;
 
  166    auto isLPToken = [&](
STAmount const& amount) -> 
bool {
 
  169            return sle->isFieldPresent(sfAMMID);
 
  173    if (isLPToken(amount) || isLPToken(amount2))
 
  175        JLOG(ctx.
j.
debug()) << 
"AMM Instance: can't create with LPTokens " 
  176                            << amount << 
" " << amount2;
 
  184            accountId == beast::zero)
 
  195    auto clawbackDisabled = [&](
Issue const& issue) -> 
TER {
 
  206    if (
auto const ter = clawbackDisabled(amount.issue()); ter != 
tesSUCCESS)
 
  208    return clawbackDisabled(amount2.issue());
 
 
  218    auto const amount = ctx_.
tx[sfAmount];
 
  219    auto const amount2 = ctx_.
tx[sfAmount2];
 
  221    auto const ammKeylet = 
keylet::amm(amount.issue(), amount2.issue());
 
  228        JLOG(j_.
error()) << 
"AMM Instance: failed to create pseudo account.";
 
  229        return {maybeAccount.error(), 
false};
 
  231    auto& account = *maybeAccount;
 
  232    auto const accountId = (*account)[sfAccount];
 
  236        amount.issue().currency, amount2.issue().currency, accountId);
 
  239        JLOG(j_.
error()) << 
"AMM Instance: LP Token already exists.";
 
  250    auto const lpTokens = 
ammLPTokens(amount, amount2, lptIss);
 
  254    ammSle->setAccountID(sfAccount, accountId);
 
  255    ammSle->setFieldAmount(sfLPTokenBalance, lpTokens);
 
  256    auto const& [issue1, issue2] = 
std::minmax(amount.issue(), amount2.issue());
 
  257    ammSle->setFieldIssue(sfAsset, 
STIssue{sfAsset, issue1});
 
  258    ammSle->setFieldIssue(sfAsset2, 
STIssue{sfAsset2, issue2});
 
  261        ctx_.
view(), ammSle, account_, lptIss, ctx_.
tx[sfTradingFee]);
 
  264    if (
auto ter = 
dirLink(sb, accountId, ammSle); ter)
 
  266        JLOG(j_.
debug()) << 
"AMM Instance: failed to insert owner dir";
 
  275        JLOG(j_.
debug()) << 
"AMM Instance: failed to send LPT " << lpTokens;
 
  279    auto sendAndTrustSet = [&](
STAmount const& amount) -> 
TER {
 
  297                auto const flags = sleRippleState->getFlags();
 
  298                sleRippleState->setFieldU32(sfFlags, flags | 
lsfAMMNode);
 
  299                sb.
update(sleRippleState);
 
  306    res = sendAndTrustSet(amount);
 
  309        JLOG(j_.
debug()) << 
"AMM Instance: failed to send " << amount;
 
  314    res = sendAndTrustSet(amount2);
 
  317        JLOG(j_.
debug()) << 
"AMM Instance: failed to send " << amount2;
 
  321    JLOG(j_.
debug()) << 
"AMM Instance: success " << accountId << 
" " 
  322                     << ammKeylet.key << 
" " << lpTokens << 
" " << amount << 
" " 
  328            if (
auto const bookExisted = 
static_cast<bool>(sb.
read(dir));
 
  332    addOrderBook(amount.issue(), amount2.issue(), 
getRate(amount2, amount));
 
  333    addOrderBook(amount2.issue(), amount.issue(), 
getRate(amount, amount2));
 
 
A generic endpoint for log messages.
 
static TER preclaim(PreclaimContext const &ctx)
 
static bool checkExtraFeatures(PreflightContext const &ctx)
 
TER doApply() override
Attempt to create the AMM instance.
 
static NotTEC preflight(PreflightContext const &ctx)
 
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
 
virtual OrderBookDB & getOrderBookDB()=0
 
State information when applying a tx.
 
beast::Journal const journal
 
A currency issued by an account.
 
void addOrderBook(Book const &)
 
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
 
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
 
Discardable, editable view to a ledger.
 
static XRPAmount calculateOwnerReserveFee(ReadView const &view, STTx const &tx)
 
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
 
void insert(std::shared_ptr< SLE > const &sle) override
Insert a new state 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 quality(Keylet const &k, std::uint64_t q) noexcept
The initial directory page for a specific quality.
 
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
 
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
 
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.
 
bool isXRP(AccountID const &c)
 
@ lsfAllowTrustLineClawback
 
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
 
Issue ammLPTIssue(Currency const &cur1, Currency const &cur2, AccountID const &ammAccountID)
Calculate LPT Issue from AMM asset pair.
 
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.
 
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
 
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
 
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account, AuthType authType=AuthType::Legacy)
Check if the account lacks required authorization.
 
void initializeFeeAuctionVote(ApplyView &view, std::shared_ptr< SLE > &ammSle, AccountID const &account, Issue const &lptIssue, std::uint16_t tfee)
Initialize Auction and Voting slots and set the trading/discounted fee.
 
static std::pair< TER, bool > applyCreate(ApplyContext &ctx_, Sandbox &sb, AccountID const &account_, beast::Journal j_)
 
Expected< std::shared_ptr< SLE >, TER > createPseudoAccount(ApplyView &view, uint256 const &pseudoOwnerKey, SField const &ownerField)
Create pseudo-account, storing pseudoOwnerKey into ownerField.
 
AccountID pseudoAccountAddress(ReadView const &view, uint256 const &pseudoOwnerKey)
 
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
 
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
 
TERSubset< CanCvtToTER > TER
 
std::uint16_t constexpr TRADING_FEE_THRESHOLD
 
TER dirLink(ApplyView &view, AccountID const &owner, std::shared_ptr< SLE > &object)
 
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
 
State information when determining if a tx is likely to claim a fee.
 
State information when preflighting a tx.