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;
58 STAmount
const& asset1,
59 STAmount
const& asset2,
60 Issue
const& lptIssue);
71 STAmount
const& asset1Balance,
72 STAmount
const& asset1Deposit,
73 STAmount
const& lptAMMBalance,
85 STAmount
const& asset1Balance,
86 STAmount
const& lptAMMBalance,
87 STAmount
const& lpTokens,
100 STAmount
const& asset1Balance,
101 STAmount
const& asset1Withdraw,
102 STAmount
const& lptAMMBalance,
114 STAmount
const& assetBalance,
115 STAmount
const& lptAMMBalance,
116 STAmount
const& lpTokens,
128 Quality
const& calcQuality,
129 Quality
const& reqQuality,
132 if (calcQuality == reqQuality)
134 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
138 return ((min.rate() - max.rate()) / min.rate()) < dist;
149template <
typename Amt>
151 std::is_same_v<Amt, STAmount> || std::is_same_v<Amt, IOUAmount> ||
152 std::is_same_v<Amt, XRPAmount> || std::is_same_v<Amt, Number>)
159 return ((max - min) / max) < dist;
192template <
typename TIn,
typename TOut>
195 TAmounts<TIn, TOut>
const& pool,
196 Quality
const& targetQuality,
199 if (targetQuality.rate() == beast::zero)
205 auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out;
207 pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate();
210 if (!nTakerGets || *nTakerGets <= 0)
213 auto const nTakerGetsConstraint =
214 pool.out - pool.in / (targetQuality.rate() * f);
215 if (nTakerGetsConstraint <= 0)
219 if (nTakerGetsConstraint < *nTakerGets)
220 nTakerGets = nTakerGetsConstraint;
222 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
225 auto const takerGets = toAmount<TOut>(
227 return TAmounts<TIn, TOut>{
233 if (
auto const amounts = getAmounts(*nTakerGets);
234 Quality{amounts} < targetQuality)
263template <
typename TIn,
typename TOut>
266 TAmounts<TIn, TOut>
const& pool,
267 Quality
const& targetQuality,
270 if (targetQuality.rate() == beast::zero)
276 auto const b = pool.in * (1 + f);
278 pool.in * pool.in - pool.in * pool.out * targetQuality.rate();
281 if (!nTakerPays || nTakerPays <= 0)
284 auto const nTakerPaysConstraint =
285 pool.out * targetQuality.rate() - pool.in / f;
286 if (nTakerPaysConstraint <= 0)
290 if (nTakerPaysConstraint < *nTakerPays)
291 nTakerPays = nTakerPaysConstraint;
293 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
296 auto const takerPays = toAmount<TIn>(
298 return TAmounts<TIn, TOut>{
304 if (
auto const amounts = getAmounts(*nTakerPays);
305 Quality{amounts} < targetQuality)
327template <
typename TIn,
typename TOut>
330 TAmounts<TIn, TOut>
const& pool,
331 Quality
const& quality,
336 if (!rules.
enabled(fixAMMv1_1))
346 auto const b = pool.in * (1 + f);
348 pool.in * pool.in - pool.in * pool.out * quality.rate();
349 if (
auto const res = b * b - 4 * a * c; res < 0)
351 else if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a);
352 nTakerPaysPropose > 0)
354 auto const nTakerPays = [&]() {
359 auto const nTakerPaysConstraint =
360 pool.out * quality.rate() - pool.in / f;
361 if (nTakerPaysPropose > nTakerPaysConstraint)
362 return nTakerPaysConstraint;
363 return nTakerPaysPropose;
368 <<
"changeSpotPriceQuality calc failed: "
370 << quality <<
" " << tfee;
373 auto const takerPays =
376 if (
auto const amounts =
379 Quality{amounts} < quality &&
381 Quality{amounts}, quality,
Number(1, -7)))
384 <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in)
386 <<
" " << quality <<
" " << tfee <<
" "
388 Throw<std::runtime_error>(
"changeSpotPriceQuality failed");
393 <<
"changeSpotPriceQuality succeeded: "
395 <<
" " << quality <<
" " << tfee <<
" "
400 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: "
402 <<
" " << quality <<
" " << tfee;
408 auto const amounts = [&]() {
415 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.in)
416 <<
" " <<
to_string(pool.out) <<
" " << quality <<
" "
421 if (Quality{*amounts} < quality)
423 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: "
425 <<
" " << quality <<
" " << tfee <<
" "
431 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: "
433 <<
" " << quality <<
" " << tfee <<
" "
460template <
typename TIn,
typename TOut>
463 TAmounts<TIn, TOut>
const& pool,
468 rules && rules->enabled(fixAMMv1_1))
494 auto const numerator = pool.in * pool.out;
498 auto const denom = pool.in + assetIn * (1 -
fee);
500 if (denom.signum() <= 0)
501 return toAmount<TOut>(
getIssue(pool.out), 0);
504 auto const ratio = numerator / denom;
507 auto const swapOut = pool.out - ratio;
509 if (swapOut.signum() < 0)
510 return toAmount<TOut>(
getIssue(pool.out), 0);
516 return toAmount<TOut>(
519 (pool.in * pool.out) / (pool.in + assetIn *
feeMult(tfee)),
533template <
typename TIn,
typename TOut>
536 TAmounts<TIn, TOut>
const& pool,
537 TOut
const& assetOut,
541 rules && rules->enabled(fixAMMv1_1))
563 auto const numerator = pool.in * pool.out;
566 auto const denom = pool.out - assetOut;
567 if (denom.signum() <= 0)
569 return toMaxAmount<TIn>(
getIssue(pool.in));
573 auto const ratio = numerator / denom;
574 auto const numerator2 = ratio - pool.in;
581 auto const swapIn = numerator2 /
feeMult;
582 if (swapIn.signum() < 0)
583 return toAmount<TIn>(
getIssue(pool.in), 0);
589 return toAmount<TIn>(
591 ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
615 STAmount
const& lptAMMBalance,
616 STAmount
const& lpTokens,
632 STAmount
const& amountBalance,
633 STAmount
const& amount,
635 STAmount
const& lptAMMBalance,
636 STAmount
const& lpTokens,
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.
Number reduceOffer(auto const &amount)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, bool isDeposit)
Adjust LP tokens to deposit/withdraw.
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)
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 lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's withdraw amount.
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.
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)
Calls adjustLPTokens() and adjusts deposit or withdraw amounts if the adjusted LP tokens are less tha...
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(...
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
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...
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()
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(...
STAmount withdrawByTokens(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset withdrawal by tokens.
bool withinRelativeDistance(Quality const &calcQuality, Quality const &reqQuality, Number const &dist)
Check if the relative distance between the qualities is within the requested distance.
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.