20#include <xrpld/app/misc/AMMHelpers.h> 
   21#include <xrpld/app/misc/AMMUtils.h> 
   22#include <xrpld/app/tx/detail/AMMDeposit.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/TxFlags.h> 
   50    auto const amount = ctx.
tx[~sfAmount];
 
   51    auto const amount2 = ctx.
tx[~sfAmount2];
 
   52    auto const ePrice = ctx.
tx[~sfEPrice];
 
   53    auto const lpTokens = ctx.
tx[~sfLPTokenOut];
 
   54    auto const tradingFee = ctx.
tx[~sfTradingFee];
 
   64        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid flags.";
 
   70        if (!lpTokens || ePrice || (amount && !amount2) ||
 
   71            (!amount && amount2) || tradingFee)
 
   77        if (!amount || amount2 || ePrice || tradingFee)
 
   83        if (!amount || !amount2 || ePrice || tradingFee)
 
   88        if (!amount || !lpTokens || amount2 || ePrice || tradingFee)
 
   93        if (!amount || !ePrice || lpTokens || amount2 || tradingFee)
 
   98        if (!amount || !amount2 || ePrice || lpTokens)
 
  102    auto const asset = ctx.
tx[sfAsset].get<
Issue>();
 
  103    auto const asset2 = ctx.
tx[sfAsset2].get<
Issue>();
 
  106        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid asset pair.";
 
  110    if (amount && amount2 && amount->issue() == amount2->issue())
 
  112        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid tokens, same issue." 
  113                            << amount->issue() << 
" " << amount2->issue();
 
  117    if (lpTokens && *lpTokens <= beast::zero)
 
  119        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid LPTokens";
 
  130            JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid amount";
 
  140            JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid amount2";
 
  146    if (amount && ePrice)
 
  153            JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid EPrice";
 
  160        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid trading fee.";
 
 
  170    auto const accountID = ctx.
tx[sfAccount];
 
  176        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: Invalid asset pair.";
 
  188        return expected.error();  
 
  189    auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
 
  192        if (lptAMMBalance != beast::zero)
 
  194        if (amountBalance != beast::zero || amount2Balance != beast::zero)
 
  197            JLOG(ctx.
j.
debug()) << 
"AMM Deposit: tokens balance is not zero.";
 
  204        if (lptAMMBalance == beast::zero)
 
  206        if (amountBalance <= beast::zero || amount2Balance <= beast::zero ||
 
  207            lptAMMBalance < beast::zero)
 
  211                << 
"AMM Deposit: reserves or tokens balance is zero.";
 
  222    auto balance = [&](
auto const& 
deposit) -> 
TER {
 
  225            auto const lpIssue = (*ammSle)[sfLPTokenBalance].issue();
 
  228                keylet::line(accountID, lpIssue.account, lpIssue.currency));
 
  235        return (accountID == 
deposit.issue().account ||
 
  250        auto checkAsset = [&](
Issue const& asset) -> 
TER {
 
  254                    << 
"AMM Deposit: account is not authorized, " << asset;
 
  261                    << 
"AMM Deposit: account or currency is frozen, " 
  270        if (
auto const ter = checkAsset(ctx.
tx[sfAsset].get<
Issue>()))
 
  273        if (
auto const ter = checkAsset(ctx.
tx[sfAsset2].get<
Issue>()))
 
  277    auto const amount = ctx.
tx[~sfAmount];
 
  278    auto const amount2 = ctx.
tx[~sfAmount2];
 
  279    auto const ammAccountID = ammSle->
getAccountID(sfAccount);
 
  282                           bool checkBalance) -> 
TER {
 
  293                    << 
"AMM Deposit: account is not authorized, " 
  302                    << 
"AMM Deposit: AMM account or currency is frozen, " 
  309                JLOG(ctx.
j.
debug()) << 
"AMM Deposit: account is frozen, " 
  316                if (
auto const ter = balance(*amount))
 
  319                        << 
"AMM Deposit: account has insufficient funds, " 
  331        if (
auto const ter = checkAmount(amount, 
true))
 
  334        if (
auto const ter = checkAmount(amount2, 
true))
 
  339        if (
auto const ter = checkAmount(amountBalance, 
false))
 
  341        if (
auto const ter = checkAmount(amount2Balance, 
false))
 
  346    if (
auto const lpTokens = ctx.
tx[~sfLPTokenOut];
 
  347        lpTokens && lpTokens->issue() != lptAMMBalance.issue())
 
  349        JLOG(ctx.
j.
debug()) << 
"AMM Deposit: invalid LPTokens.";
 
  359        if (xrpBalance <= beast::zero)
 
  361            JLOG(ctx.
j.
debug()) << 
"AMM Instance: insufficient reserves";
 
 
  372    auto const amount = 
ctx_.
tx[~sfAmount];
 
  373    auto const amount2 = 
ctx_.
tx[~sfAmount2];
 
  374    auto const ePrice = 
ctx_.
tx[~sfEPrice];
 
  375    auto const lpTokensDeposit = 
ctx_.
tx[~sfLPTokenOut];
 
  379    auto const ammAccountID = (*ammSle)[sfAccount];
 
  389        return {expected.error(), 
false};  
 
  390    auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
 
  391    auto const tfee = (lptAMMBalance == beast::zero)
 
  392        ? 
ctx_.
tx[~sfTradingFee].value_or(0)
 
  397    auto const [result, newLPTokenBalance] =
 
  399         &amountBalance = amountBalance,
 
  400         &amount2Balance = amount2Balance,
 
  457                lptAMMBalance.issue(),
 
  461        JLOG(
j_.
error()) << 
"AMM Deposit: invalid options.";
 
  469            newLPTokenBalance > beast::zero,
 
  470            "ripple::AMMDeposit::applyGuts : valid new LP token balance");
 
  471        ammSle->setFieldAmount(sfLPTokenBalance, newLPTokenBalance);
 
  474        if (lptAMMBalance == beast::zero)
 
  476                sb, ammSle, 
account_, lptAMMBalance.issue(), tfee);
 
 
  514    auto checkBalance = [&](
auto const& depositAmount) -> 
TER {
 
  515        if (depositAmount <= beast::zero)
 
  517        if (
isXRP(depositAmount))
 
  519            auto const& lpIssue = lpTokensDeposit.
issue();
 
  527            account_ == depositAmount.issue().account ||
 
  531                depositAmount.issue(),
 
  539        [amountDepositActual, amount2DepositActual, lpTokensDepositActual] =
 
  549    if (lpTokensDepositActual <= beast::zero)
 
  555    if (amountDepositActual < depositMin ||
 
  556        amount2DepositActual < deposit2Min ||
 
  557        lpTokensDepositActual < lpTokensDepositMin)
 
  560            << 
"AMM Deposit: min deposit fails " << amountDepositActual << 
" " 
  562            << amount2DepositActual.value_or(
STAmount{}) << 
" " 
  569    if (
auto const ter = checkBalance(amountDepositActual))
 
  572                                      "checkBalance to deposit or is 0" 
  573                                   << amountDepositActual;
 
  587            << 
"AMM Deposit: failed to deposit " << amountDepositActual;
 
  592    if (amount2DepositActual)
 
  594        if (
auto const ter = checkBalance(*amount2DepositActual))
 
  597                << 
"AMM Deposit: account has insufficient checkBalance to " 
  599                << *amount2DepositActual;
 
  607            *amount2DepositActual,
 
  613                << 
"AMM Deposit: failed to deposit " << *amount2DepositActual;
 
  627    return {
tesSUCCESS, lptAMMBalance + lpTokensDepositActual};
 
 
  636    if (!rules.
enabled(fixAMMv1_3))
 
  637        return lpTokensDeposit;
 
 
  658        auto const tokensAdj =
 
  663            divide(tokensAdj, lptAMMBalance, lptAMMBalance.
issue());
 
  665        auto const amountDeposit =
 
  667        auto const amount2Deposit =
 
  685        JLOG(
j_.
error()) << 
"AMMDeposit::equalDepositTokens exception " 
 
  732    auto frac = 
Number{amount} / amountBalance;
 
  735    if (tokensAdj == beast::zero)
 
  744    auto const amount2Deposit =
 
  746    if (amount2Deposit <= amount2)
 
  759    frac = 
Number{amount2} / amount2Balance;
 
  762    if (tokensAdj == beast::zero)
 
  771    auto const amountDeposit =
 
  773    if (amountDeposit <= amount)
 
 
  810        lpTokensOut(amountBalance, amount, lptAMMBalance, tfee));
 
  811    if (tokens == beast::zero)
 
  820        view.
rules(), amountBalance, amount, lptAMMBalance, tokens, tfee);
 
 
  854    auto const tokensAdj =
 
  859    auto const amountDeposit =
 
  860        ammAssetIn(amountBalance, lptAMMBalance, tokensAdj, tfee);
 
  861    if (amountDeposit > amount)
 
 
  912    if (amount != beast::zero)
 
  917            lpTokensOut(amountBalance, amount, lptAMMBalance, tfee));
 
  918        if (tokens <= beast::zero)
 
  927            view.
rules(), amountBalance, amount, lptAMMBalance, tokens, tfee);
 
  930        auto const ep = 
Number{amountDepositAdj} / tokensAdj;
 
  965    auto const c = f1 * amountBalance / (ePrice * lptAMMBalance);
 
  966    auto const d = f1 + c * f2 - c;
 
  967    auto const a1 = c * c;
 
  968    auto const b1 = c * c * f2 * f2 + 2 * c - d * d;
 
  969    auto const c1 = 2 * c * f2 * f2 + 1 - 2 * d * f2;
 
  970    auto amtNoRoundCb = [&] {
 
  976    if (amountDeposit <= beast::zero)
 
  978    auto tokNoRoundCb = [&] { 
return amountDeposit / ePrice; };
 
  979    auto tokProdCb = [&] { 
return amountDeposit / ePrice; };
 
 
 1013    Issue const& lptIssue,
 
 
std::pair< TER, bool > applyGuts(Sandbox &view)
 
std::pair< TER, STAmount > equalDepositLimit(Sandbox &view, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount2Balance, STAmount const &lptAMMBalance, STAmount const &amount, STAmount const &amount2, std::optional< STAmount > const &lpTokensDepositMin, std::uint16_t tfee)
Equal asset deposit (Asset1In, Asset2In) with the constraint on the maximum amount of both assets tha...
 
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
 
std::pair< TER, STAmount > singleDepositEPrice(Sandbox &view, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &ePrice, std::uint16_t tfee)
Single asset deposit (Asset1In, EPrice) with two constraints.
 
static TER preclaim(PreclaimContext const &ctx)
 
std::pair< TER, STAmount > singleDeposit(Sandbox &view, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &lptAMMBalance, STAmount const &amount, std::optional< STAmount > const &lpTokensDepositMin, std::uint16_t tfee)
Single asset deposit (Asset1In) by the amount.
 
static NotTEC preflight(PreflightContext const &ctx)
 
std::pair< TER, STAmount > equalDepositTokens(Sandbox &view, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount2Balance, STAmount const &lptAMMBalance, STAmount const &lpTokensDeposit, std::optional< STAmount > const &depositMin, std::optional< STAmount > const &deposit2Min, std::uint16_t tfee)
Equal asset deposit (LPTokens) for the specified share of the AMM instance pools.
 
static bool checkExtraFeatures(PreflightContext const &ctx)
 
std::pair< TER, STAmount > equalDepositInEmptyState(Sandbox &view, AccountID const &ammAccount, STAmount const &amount, STAmount const &amount2, Issue const &lptIssue, std::uint16_t tfee)
Equal deposit in empty AMM state (LP tokens balance is 0)
 
std::pair< TER, STAmount > singleDepositTokens(Sandbox &view, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &lpTokensDeposit, std::uint16_t tfee)
Single asset deposit (Asset1In, LPTokens) by the tokens.
 
std::pair< TER, STAmount > deposit(Sandbox &view, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amountDeposit, std::optional< STAmount > const &amount2Deposit, STAmount const &lptAMMBalance, STAmount const &lpTokensDeposit, std::optional< STAmount > const &depositMin, std::optional< STAmount > const &deposit2Min, std::optional< STAmount > const &lpTokensDepositMin, std::uint16_t tfee)
Deposit requested assets and token amount into LP account.
 
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 Rules const & rules() const =0
Returns the tx processing rules.
 
Rules controlling protocol behavior.
 
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
 
Issue const & issue() const
 
AccountID getAccountID(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 > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
 
T make_optional(T... args)
 
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.
 
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
 
constexpr std::uint32_t tfSingleAsset
 
NotTEC invalidAMMAmount(STAmount const &amount, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt, bool validZero=false)
Validate the amount.
 
STAmount divide(STAmount const &amount, Rate const &rate)
 
std::pair< STAmount, STAmount > adjustAssetInByTokens(Rules const &rules, STAmount const &balance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &tokens, std::uint16_t tfee)
 
bool isXRP(AccountID const &c)
 
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
 
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
 
Number solveQuadraticEq(Number const &a, Number const &b, Number const &c)
Positive solution for quadratic equation: x = (-b + sqrt(b**2 + 4*a*c))/(2*a)
 
constexpr std::uint32_t tfLimitLPToken
 
STAmount ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset deposit given LP Tokens.
 
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
 
constexpr std::uint32_t tfOneAssetLPToken
 
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.
 
STAmount getRoundedLPTokens(Rules const &rules, STAmount const &balance, Number const &frac, IsDeposit isDeposit)
Round AMM deposit/withdrawal LPToken amount.
 
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
 
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account, AuthType authType=AuthType::Legacy)
Check if the account lacks required authorization.
 
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, IsDeposit isDeposit)
Adjust LP tokens to deposit/withdraw.
 
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
 
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.
 
constexpr std::uint32_t tfTwoAsset
 
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.
 
std::tuple< STAmount, std::optional< STAmount >, STAmount > adjustAmountsByLPTokens(STAmount const &amountBalance, STAmount const &amount, std::optional< STAmount > const &amount2, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee, IsDeposit isDeposit)
Calls adjustLPTokens() and adjusts deposit or withdraw amounts if the adjusted LP tokens are less tha...
 
constexpr std::uint32_t tfDepositSubTx
 
static STAmount adjustLPTokensOut(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &lpTokensDeposit)
 
constexpr std::uint32_t tfLPToken
 
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
 
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
 
constexpr std::uint32_t tfDepositMask
 
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 ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
 
std::string to_string(base_uint< Bits, Tag > const &a)
 
constexpr std::uint32_t tfTwoAssetIfEmpty
 
Number feeMultHalf(std::uint16_t tfee)
Get fee multiplier (1 - tfee / 2) @tfee trading fee in basis points.
 
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
 
TERSubset< CanCvtToTER > TER
 
std::uint16_t constexpr TRADING_FEE_THRESHOLD
 
STAmount getRoundedAsset(Rules const &rules, STAmount const &balance, A const &frac, IsDeposit isDeposit)
Round AMM equal deposit/withdrawal amount.
 
Number adjustFracByTokens(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &tokens, Number const &frac)
Find a fraction of tokens after the tokens are adjusted.
 
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.