1#ifndef XRPL_APP_MISC_AMMHELPERS_H_INCLUDED
2#define XRPL_APP_MISC_AMMHELPERS_H_INCLUDED
4#include <xrpl/basics/Log.h>
5#include <xrpl/basics/Number.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/protocol/AMMCore.h>
8#include <xrpl/protocol/AmountConversions.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/IOUAmount.h>
11#include <xrpl/protocol/Issue.h>
12#include <xrpl/protocol/Quality.h>
13#include <xrpl/protocol/Rules.h>
14#include <xrpl/protocol/STAmount.h>
23 static Number const reducedOfferPct(9999, -4);
27 return amount * reducedOfferPct;
41 STAmount
const& asset1,
42 STAmount
const& asset2,
43 Issue
const& lptIssue);
54 STAmount
const& asset1Balance,
55 STAmount
const& asset1Deposit,
56 STAmount
const& lptAMMBalance,
68 STAmount
const& asset1Balance,
69 STAmount
const& lptAMMBalance,
70 STAmount
const& lpTokens,
83 STAmount
const& asset1Balance,
84 STAmount
const& asset1Withdraw,
85 STAmount
const& lptAMMBalance,
97 STAmount
const& assetBalance,
98 STAmount
const& lptAMMBalance,
99 STAmount
const& lpTokens,
111 Quality
const& calcQuality,
112 Quality
const& reqQuality,
115 if (calcQuality == reqQuality)
117 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
121 return ((min.rate() - max.rate()) / min.rate()) < dist;
132template <
typename Amt>
142 return ((max - min) / max) < dist;
175template <
typename TIn,
typename TOut>
178 TAmounts<TIn, TOut>
const& pool,
179 Quality
const& targetQuality,
182 if (targetQuality.rate() == beast::zero)
188 auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out;
190 pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate();
193 if (!nTakerGets || *nTakerGets <= 0)
196 auto const nTakerGetsConstraint =
197 pool.out - pool.in / (targetQuality.rate() * f);
198 if (nTakerGetsConstraint <= 0)
202 if (nTakerGetsConstraint < *nTakerGets)
203 nTakerGets = nTakerGetsConstraint;
205 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
208 auto const takerGets = toAmount<TOut>(
210 return TAmounts<TIn, TOut>{
216 if (
auto const amounts = getAmounts(*nTakerGets);
217 Quality{amounts} < targetQuality)
246template <
typename TIn,
typename TOut>
249 TAmounts<TIn, TOut>
const& pool,
250 Quality
const& targetQuality,
253 if (targetQuality.rate() == beast::zero)
259 auto const b = pool.in * (1 + f);
261 pool.in * pool.in - pool.in * pool.out * targetQuality.rate();
264 if (!nTakerPays || nTakerPays <= 0)
267 auto const nTakerPaysConstraint =
268 pool.out * targetQuality.rate() - pool.in / f;
269 if (nTakerPaysConstraint <= 0)
273 if (nTakerPaysConstraint < *nTakerPays)
274 nTakerPays = nTakerPaysConstraint;
276 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
279 auto const takerPays = toAmount<TIn>(
281 return TAmounts<TIn, TOut>{
287 if (
auto const amounts = getAmounts(*nTakerPays);
288 Quality{amounts} < targetQuality)
310template <
typename TIn,
typename TOut>
313 TAmounts<TIn, TOut>
const& pool,
314 Quality
const& quality,
319 if (!rules.
enabled(fixAMMv1_1))
329 auto const b = pool.in * (1 + f);
331 pool.in * pool.in - pool.in * pool.out * quality.rate();
332 if (
auto const res = b * b - 4 * a * c; res < 0)
334 else if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a);
335 nTakerPaysPropose > 0)
337 auto const nTakerPays = [&]() {
342 auto const nTakerPaysConstraint =
343 pool.out * quality.rate() - pool.in / f;
344 if (nTakerPaysPropose > nTakerPaysConstraint)
345 return nTakerPaysConstraint;
346 return nTakerPaysPropose;
351 <<
"changeSpotPriceQuality calc failed: "
353 << quality <<
" " << tfee;
356 auto const takerPays =
359 if (
auto const amounts =
362 Quality{amounts} < quality &&
364 Quality{amounts}, quality,
Number(1, -7)))
367 <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in)
369 <<
" " << quality <<
" " << tfee <<
" "
371 Throw<std::runtime_error>(
"changeSpotPriceQuality failed");
376 <<
"changeSpotPriceQuality succeeded: "
378 <<
" " << quality <<
" " << tfee <<
" "
383 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: "
385 <<
" " << quality <<
" " << tfee;
391 auto const amounts = [&]() {
398 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.in)
399 <<
" " <<
to_string(pool.out) <<
" " << quality <<
" "
404 if (Quality{*amounts} < quality)
406 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: "
408 <<
" " << quality <<
" " << tfee <<
" "
414 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: "
416 <<
" " << quality <<
" " << tfee <<
" "
443template <
typename TIn,
typename TOut>
446 TAmounts<TIn, TOut>
const& pool,
451 rules && rules->enabled(fixAMMv1_1))
477 auto const numerator = pool.in * pool.out;
478 auto const fee =
getFee(tfee);
481 auto const denom = pool.in + assetIn * (1 - fee);
483 if (denom.signum() <= 0)
484 return toAmount<TOut>(
getIssue(pool.out), 0);
487 auto const ratio = numerator / denom;
490 auto const swapOut = pool.out - ratio;
492 if (swapOut.signum() < 0)
493 return toAmount<TOut>(
getIssue(pool.out), 0);
499 return toAmount<TOut>(
502 (pool.in * pool.out) / (pool.in + assetIn *
feeMult(tfee)),
516template <
typename TIn,
typename TOut>
519 TAmounts<TIn, TOut>
const& pool,
520 TOut
const& assetOut,
524 rules && rules->enabled(fixAMMv1_1))
546 auto const numerator = pool.in * pool.out;
549 auto const denom = pool.out - assetOut;
550 if (denom.signum() <= 0)
552 return toMaxAmount<TIn>(
getIssue(pool.in));
556 auto const ratio = numerator / denom;
557 auto const numerator2 = ratio - pool.in;
558 auto const fee =
getFee(tfee);
564 auto const swapIn = numerator2 /
feeMult;
565 if (swapIn.signum() < 0)
566 return toAmount<TIn>(
getIssue(pool.in), 0);
572 return toAmount<TIn>(
574 ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
598 STAmount
const& lptAMMBalance,
599 STAmount
const& lpTokens,
615 STAmount
const& amountBalance,
616 STAmount
const& amount,
618 STAmount
const& lptAMMBalance,
619 STAmount
const& lpTokens,
665 if (!rules.
enabled(fixAMMv1_3))
689 STAmount
const& balance,
703 STAmount
const& balance,
722 STAmount
const& lptAMMBalance,
740 STAmount
const& balance,
741 STAmount
const& amount,
742 STAmount
const& lptAMMBalance,
743 STAmount
const& tokens,
748 STAmount
const& balance,
749 STAmount
const& amount,
750 STAmount
const& lptAMMBalance,
751 STAmount
const& tokens,
760 STAmount
const& lptAMMBalance,
761 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.