20 #include <ripple/app/tx/impl/AMMDeposit.h>
22 #include <ripple/app/misc/AMMHelpers.h>
23 #include <ripple/app/misc/AMMUtils.h>
24 #include <ripple/ledger/Sandbox.h>
25 #include <ripple/ledger/View.h>
26 #include <ripple/protocol/AMMCore.h>
27 #include <ripple/protocol/Feature.h>
28 #include <ripple/protocol/STAccount.h>
29 #include <ripple/protocol/TxFlags.h>
47 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid flags.";
65 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid flags.";
71 if (!lpTokens || ePrice || (amount && !amount2) ||
72 (!amount && amount2) || tradingFee)
78 if (!amount || amount2 || ePrice || tradingFee)
84 if (!amount || !amount2 || ePrice || tradingFee)
89 if (!amount || !lpTokens || amount2 || ePrice || tradingFee)
94 if (!amount || !ePrice || lpTokens || amount2 || tradingFee)
99 if (!amount || !amount2 || ePrice || lpTokens)
107 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid asset pair.";
111 if (amount && amount2 && amount->issue() == amount2->issue())
113 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid tokens, same issue."
114 << amount->issue() <<
" " << amount2->issue();
118 if (lpTokens && *lpTokens <= beast::zero)
120 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid LPTokens";
131 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid amount";
141 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid amount2";
147 if (amount && ePrice)
154 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid EPrice";
161 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid trading fee.";
177 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: Invalid asset pair.";
186 FreezeHandling::fhIGNORE_FREEZE,
189 return expected.error();
190 auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
193 if (lptAMMBalance != beast::zero)
195 if (amountBalance != beast::zero || amount2Balance != beast::zero)
197 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: tokens balance is not zero.";
203 if (lptAMMBalance == beast::zero)
205 if (amountBalance <= beast::zero || amount2Balance <= beast::zero ||
206 lptAMMBalance < beast::zero)
209 <<
"AMM Deposit: reserves or tokens balance is zero.";
219 auto balance = [&](
auto const&
deposit) ->
TER {
225 keylet::line(accountID, lpIssue.account, lpIssue.currency));
232 return (accountID ==
deposit.issue().account ||
237 FreezeHandling::fhIGNORE_FREEZE,
248 bool checkBalance) ->
TER {
258 <<
"AMM Deposit: account is not authorized, "
266 <<
"AMM Deposit: AMM account or currency is frozen, "
273 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: account is frozen, "
280 if (
auto const ter = balance(*amount))
283 <<
"AMM Deposit: account has insufficient funds, "
295 if (
auto const ter = checkAmount(amount,
true))
298 if (
auto const ter = checkAmount(amount2,
true))
303 if (
auto const ter = checkAmount(amountBalance,
false))
305 if (
auto const ter = checkAmount(amount2Balance,
false))
311 lpTokens && lpTokens->issue() != lptAMMBalance.issue())
313 JLOG(ctx.
j.
debug()) <<
"AMM Deposit: invalid LPTokens.";
323 if (xrpBalance <= beast::zero)
325 JLOG(ctx.
j.
debug()) <<
"AMM Instance: insufficient reserves";
350 FreezeHandling::fhZERO_IF_FROZEN,
353 return {expected.error(),
false};
354 auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
355 auto const tfee = (lptAMMBalance == beast::zero)
361 auto const [result, newLPTokenBalance] =
363 &amountBalance = amountBalance,
364 &amount2Balance = amount2Balance,
421 lptAMMBalance.issue(),
424 JLOG(
j_.
error()) <<
"AMM Deposit: invalid options.";
430 assert(newLPTokenBalance > beast::zero);
434 if (lptAMMBalance == beast::zero)
436 sb, ammSle,
account_, lptAMMBalance.issue(), tfee);
474 auto checkBalance = [&](
auto const& depositAmount) ->
TER {
475 if (depositAmount <= beast::zero)
477 if (
isXRP(depositAmount))
479 auto const& lpIssue = lpTokensDeposit.
issue();
487 account_ == depositAmount.issue().account ||
491 depositAmount.issue(),
492 FreezeHandling::fhIGNORE_FREEZE,
499 [amountDepositActual, amount2DepositActual, lpTokensDepositActual] =
509 if (lpTokensDepositActual <= beast::zero)
515 if (amountDepositActual < depositMin ||
516 amount2DepositActual < deposit2Min ||
517 lpTokensDepositActual < lpTokensDepositMin)
520 <<
"AMM Deposit: min deposit fails " << amountDepositActual <<
" "
522 << amount2DepositActual.value_or(
STAmount{}) <<
" "
529 if (
auto const ter = checkBalance(amountDepositActual))
532 "checkBalance to deposit or is 0"
533 << amountDepositActual;
547 <<
"AMM Deposit: failed to deposit " << amountDepositActual;
552 if (amount2DepositActual)
554 if (
auto const ter = checkBalance(*amount2DepositActual))
557 <<
"AMM Deposit: account has insufficient checkBalance to "
559 << *amount2DepositActual;
567 *amount2DepositActual,
573 <<
"AMM Deposit: failed to deposit " << *amount2DepositActual;
587 return {
tesSUCCESS, lptAMMBalance + lpTokensDepositActual};
608 divide(lpTokensDeposit, lptAMMBalance, lptAMMBalance.
issue());
624 JLOG(
j_.
error()) <<
"AMMDeposit::equalDepositTokens exception "
670 auto frac =
Number{amount} / amountBalance;
672 if (tokens == beast::zero)
674 auto const amount2Deposit = amount2Balance * frac;
675 if (amount2Deposit <= amount2)
688 frac =
Number{amount2} / amount2Balance;
690 if (tokens == beast::zero)
692 auto const amountDeposit = amountBalance * frac;
693 if (amountDeposit <= amount)
727 auto const tokens =
lpTokensIn(amountBalance, amount, lptAMMBalance, tfee);
728 if (tokens == beast::zero)
761 auto const amountDeposit =
762 ammAssetIn(amountBalance, lptAMMBalance, lpTokensDeposit, tfee);
763 if (amountDeposit > amount)
814 if (amount != beast::zero)
817 lpTokensIn(amountBalance, amount, lptAMMBalance, tfee);
818 if (tokens <= beast::zero)
820 auto const ep =
Number{amount} / tokens;
855 auto const c = f1 * amountBalance / (ePrice * lptAMMBalance);
856 auto const d = f1 + c * f2 - c;
857 auto const a1 = c * c;
858 auto const b1 = c * c * f2 * f2 + 2 * c - d * d;
859 auto const c1 = 2 * c * f2 * f2 + 1 - 2 * d * f2;
861 amountBalance.
issue(),
863 if (amountDeposit <= beast::zero)
887 Issue const& lptIssue,
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.
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.
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
A currency issued by an account.
Number solveQuadraticEq(Number const &a, Number const &b, Number const &c)
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Issue const & issue() const
const SF_AMOUNT sfAmount2
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.
const SF_AMOUNT sfLPTokenBalance
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Keylet amm(Issue const &issue1, Issue const &issue2) noexcept
AMM entry.
T make_optional(T... args)
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
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, bool isDeposit)
const beast::Journal journal
static TER preclaim(PreclaimContext const &ctx)
const SF_AMOUNT sfLPTokenOut
AccountID ammAccountID(std::uint16_t prefix, uint256 const &parentHash, uint256 const &ammID)
Calculate AMM account ID.
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
const SF_UINT16 sfTradingFee
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account requires authorization.
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)
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Discardable, editable view to a ledger.
STAmount ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
TERSubset< CanCvtToTER > TER
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
std::uint32_t getFlags() const
bool isXRP(AccountID const &c)
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue >> const &pair=std::nullopt)
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
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.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
constexpr std::uint32_t tfSingleAsset
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...
STAmount multiply(STAmount const &amount, Rate const &rate)
State information when determining if a tx is likely to claim a fee.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint16_t TRADING_FEE_THRESHOLD
constexpr std::uint32_t tfDepositMask
std::pair< TER, bool > applyGuts(Sandbox &view)
constexpr std::uint32_t tfLPToken
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
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.
constexpr std::uint32_t tfDepositSubTx
constexpr std::uint32_t tfTwoAsset
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
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.
static NotTEC preflight(PreflightContext 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.
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
const SF_ACCOUNT sfAccount
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
State information when preflighting a tx.
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.
constexpr std::uint32_t tfOneAssetLPToken
constexpr std::uint32_t tfTwoAssetIfEmpty
Number feeMultHalf(std::uint16_t tfee)
Get fee multiplier (1 - tfee / 2) @tfee trading fee in basis points.
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)
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
TERSubset< CanCvtToNotTEC > NotTEC
constexpr std::uint32_t tfLimitLPToken