20#ifndef RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED
21#define RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED
23#include <xrpl/basics/Log.h>
24#include <xrpl/basics/Number.h>
25#include <xrpl/beast/utility/Journal.h>
26#include <xrpl/protocol/AMMCore.h>
27#include <xrpl/protocol/AmountConversions.h>
28#include <xrpl/protocol/Feature.h>
29#include <xrpl/protocol/IOUAmount.h>
30#include <xrpl/protocol/Issue.h>
31#include <xrpl/protocol/Quality.h>
32#include <xrpl/protocol/Rules.h>
33#include <xrpl/protocol/STAmount.h>
42 static Number const reducedOfferPct(9999, -4);
46 return amount * reducedOfferPct;
60 STAmount
const& asset1,
61 STAmount
const& asset2,
62 Issue
const& lptIssue);
73 STAmount
const& asset1Balance,
74 STAmount
const& asset1Deposit,
75 STAmount
const& lptAMMBalance,
87 STAmount
const& asset1Balance,
88 STAmount
const& lptAMMBalance,
89 STAmount
const& lpTokens,
102 STAmount
const& asset1Balance,
103 STAmount
const& asset1Withdraw,
104 STAmount
const& lptAMMBalance,
116 STAmount
const& assetBalance,
117 STAmount
const& lptAMMBalance,
118 STAmount
const& lpTokens,
130 Quality
const& calcQuality,
131 Quality
const& reqQuality,
134 if (calcQuality == reqQuality)
136 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
140 return ((min.rate() - max.rate()) / min.rate()) < dist;
151template <
typename Amt>
161 return ((max - min) / max) < dist;
194template <
typename TIn,
typename TOut>
197 TAmounts<TIn, TOut>
const& pool,
198 Quality
const& targetQuality,
201 if (targetQuality.rate() == beast::zero)
207 auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out;
209 pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate();
212 if (!nTakerGets || *nTakerGets <= 0)
215 auto const nTakerGetsConstraint =
216 pool.out - pool.in / (targetQuality.rate() * f);
217 if (nTakerGetsConstraint <= 0)
221 if (nTakerGetsConstraint < *nTakerGets)
222 nTakerGets = nTakerGetsConstraint;
224 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
227 auto const takerGets = toAmount<TOut>(
229 return TAmounts<TIn, TOut>{
235 if (
auto const amounts = getAmounts(*nTakerGets);
236 Quality{amounts} < targetQuality)
265template <
typename TIn,
typename TOut>
268 TAmounts<TIn, TOut>
const& pool,
269 Quality
const& targetQuality,
272 if (targetQuality.rate() == beast::zero)
278 auto const b = pool.in * (1 + f);
280 pool.in * pool.in - pool.in * pool.out * targetQuality.rate();
283 if (!nTakerPays || nTakerPays <= 0)
286 auto const nTakerPaysConstraint =
287 pool.out * targetQuality.rate() - pool.in / f;
288 if (nTakerPaysConstraint <= 0)
292 if (nTakerPaysConstraint < *nTakerPays)
293 nTakerPays = nTakerPaysConstraint;
295 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
298 auto const takerPays = toAmount<TIn>(
300 return TAmounts<TIn, TOut>{
306 if (
auto const amounts = getAmounts(*nTakerPays);
307 Quality{amounts} < targetQuality)
329template <
typename TIn,
typename TOut>
332 TAmounts<TIn, TOut>
const& pool,
333 Quality
const& quality,
338 if (!rules.
enabled(fixAMMv1_1))
348 auto const b = pool.in * (1 + f);
350 pool.in * pool.in - pool.in * pool.out * quality.rate();
351 if (
auto const res = b * b - 4 * a * c; res < 0)
353 else if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a);
354 nTakerPaysPropose > 0)
356 auto const nTakerPays = [&]() {
361 auto const nTakerPaysConstraint =
362 pool.out * quality.rate() - pool.in / f;
363 if (nTakerPaysPropose > nTakerPaysConstraint)
364 return nTakerPaysConstraint;
365 return nTakerPaysPropose;
370 <<
"changeSpotPriceQuality calc failed: "
372 << quality <<
" " << tfee;
375 auto const takerPays =
378 if (
auto const amounts =
381 Quality{amounts} < quality &&
383 Quality{amounts}, quality,
Number(1, -7)))
386 <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in)
388 <<
" " << quality <<
" " << tfee <<
" "
390 Throw<std::runtime_error>(
"changeSpotPriceQuality failed");
395 <<
"changeSpotPriceQuality succeeded: "
397 <<
" " << quality <<
" " << tfee <<
" "
402 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: "
404 <<
" " << quality <<
" " << tfee;
410 auto const amounts = [&]() {
417 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.in)
418 <<
" " <<
to_string(pool.out) <<
" " << quality <<
" "
423 if (Quality{*amounts} < quality)
425 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: "
427 <<
" " << quality <<
" " << tfee <<
" "
433 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: "
435 <<
" " << quality <<
" " << tfee <<
" "
462template <
typename TIn,
typename TOut>
465 TAmounts<TIn, TOut>
const& pool,
470 rules && rules->enabled(fixAMMv1_1))
496 auto const numerator = pool.in * pool.out;
497 auto const fee =
getFee(tfee);
500 auto const denom = pool.in + assetIn * (1 - fee);
502 if (denom.signum() <= 0)
503 return toAmount<TOut>(
getIssue(pool.out), 0);
506 auto const ratio = numerator / denom;
509 auto const swapOut = pool.out - ratio;
511 if (swapOut.signum() < 0)
512 return toAmount<TOut>(
getIssue(pool.out), 0);
518 return toAmount<TOut>(
521 (pool.in * pool.out) / (pool.in + assetIn *
feeMult(tfee)),
535template <
typename TIn,
typename TOut>
538 TAmounts<TIn, TOut>
const& pool,
539 TOut
const& assetOut,
543 rules && rules->enabled(fixAMMv1_1))
565 auto const numerator = pool.in * pool.out;
568 auto const denom = pool.out - assetOut;
569 if (denom.signum() <= 0)
571 return toMaxAmount<TIn>(
getIssue(pool.in));
575 auto const ratio = numerator / denom;
576 auto const numerator2 = ratio - pool.in;
577 auto const fee =
getFee(tfee);
583 auto const swapIn = numerator2 /
feeMult;
584 if (swapIn.signum() < 0)
585 return toAmount<TIn>(
getIssue(pool.in), 0);
591 return toAmount<TIn>(
593 ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
617 STAmount
const& lptAMMBalance,
618 STAmount
const& lpTokens,
634 STAmount
const& amountBalance,
635 STAmount
const& amount,
637 STAmount
const& lptAMMBalance,
638 STAmount
const& lpTokens,
684 if (!rules.
enabled(fixAMMv1_3))
708 STAmount
const& balance,
722 STAmount
const& balance,
741 STAmount
const& lptAMMBalance,
759 STAmount
const& balance,
760 STAmount
const& amount,
761 STAmount
const& lptAMMBalance,
762 STAmount
const& tokens,
767 STAmount
const& balance,
768 STAmount
const& amount,
769 STAmount
const& lptAMMBalance,
770 STAmount
const& tokens,
779 STAmount
const& lptAMMBalance,
780 STAmount
const& tokens,
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
static rounding_mode getround()
static rounding_mode setround(rounding_mode mode)
Rules controlling protocol behavior.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Issue const & issue() const
Number::rounding_mode getAssetRounding(IsDeposit isDeposit)
Number::rounding_mode getLPTokenRounding(IsDeposit isDeposit)
Number reduceOffer(auto const &amount)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
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)
std::optional< Number > solveQuadraticEqSmallest(Number const &a, Number const &b, Number const &c)
Solve quadratic equation to find takerGets or takerPays.
Issue getIssue(T const &amt)
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)
std::pair< STAmount, STAmount > adjustAssetOutByTokens(Rules const &rules, STAmount const &balance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &tokens, std::uint16_t tfee)
TOut swapAssetIn(TAmounts< TIn, TOut > const &pool, TIn const &assetIn, std::uint16_t tfee)
AMM pool invariant - the product (A * B) after swap in/out has to remain at least the same: (A + in) ...
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
STAmount ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset deposit given LP Tokens.
Number square(Number const &n)
Return square of n.
STAmount multiply(STAmount const &amount, Rate const &rate)
std::optional< TAmounts< TIn, TOut > > getAMMOfferStartWithTakerGets(TAmounts< TIn, TOut > const &pool, Quality const &targetQuality, std::uint16_t const &tfee)
Generate AMM offer starting with takerGets when AMM pool from the payment perspective is IOU(in)/XRP(...
STAmount getRoundedLPTokens(Rules const &rules, STAmount const &balance, Number const &frac, IsDeposit isDeposit)
Round AMM deposit/withdrawal LPToken amount.
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.
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...
std::optional< TAmounts< TIn, TOut > > changeSpotPriceQuality(TAmounts< TIn, TOut > const &pool, Quality const &quality, std::uint16_t tfee, Rules const &rules, beast::Journal j)
Generate AMM offer so that either updated Spot Price Quality (SPQ) is equal to LOB quality (in this c...
STAmount ammAssetOut(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset withdrawal by tokens.
Number getFee(std::uint16_t tfee)
Convert to the fee from the basis points.
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)
std::optional< Rules > const & getCurrentTransactionRules()
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's withdraw amount.
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
STAmount getRoundedAsset(Rules const &rules, STAmount const &balance, A const &frac, IsDeposit isDeposit)
Round AMM equal deposit/withdrawal amount.
std::optional< TAmounts< TIn, TOut > > getAMMOfferStartWithTakerPays(TAmounts< TIn, TOut > const &pool, Quality const &targetQuality, std::uint16_t tfee)
Generate AMM offer starting with takerPays when AMM pool from the payment perspective is XRP(in)/IOU(...
bool withinRelativeDistance(Quality const &calcQuality, Quality const &reqQuality, Number const &dist)
Check if the relative distance between the qualities is within the requested distance.
Number adjustFracByTokens(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &tokens, Number const &frac)
Find a fraction of tokens after the tokens are adjusted.
TIn swapAssetOut(TAmounts< TIn, TOut > const &pool, TOut const &assetOut, std::uint16_t tfee)
Swap assetOut out of the pool and swap in a proportional amount of the other asset.