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/STAccount.h>
34#include <xrpl/protocol/STAmount.h>
45 static Number const reducedOfferPct(9999, -4);
49 return amount * reducedOfferPct;
61 STAmount
const& asset1,
62 STAmount
const& asset2,
63 Issue
const& lptIssue);
74 STAmount
const& asset1Balance,
75 STAmount
const& asset1Deposit,
76 STAmount
const& lptAMMBalance,
88 STAmount
const& asset1Balance,
89 STAmount
const& lptAMMBalance,
90 STAmount
const& lpTokens,
103 STAmount
const& asset1Balance,
104 STAmount
const& asset1Withdraw,
105 STAmount
const& lptAMMBalance,
117 STAmount
const& assetBalance,
118 STAmount
const& lptAMMBalance,
119 STAmount
const& lpTokens,
131 Quality
const& calcQuality,
132 Quality
const& reqQuality,
135 if (calcQuality == reqQuality)
137 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
141 return ((min.rate() - max.rate()) / min.rate()) < dist;
152template <
typename Amt>
154 std::is_same_v<Amt, STAmount> || std::is_same_v<Amt, IOUAmount> ||
155 std::is_same_v<Amt, XRPAmount> || std::is_same_v<Amt, Number>)
162 return ((max - min) / max) < dist;
195template <
typename TIn,
typename TOut>
198 TAmounts<TIn, TOut>
const& pool,
199 Quality
const& targetQuality,
202 if (targetQuality.rate() == beast::zero)
208 auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out;
210 pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate();
213 if (!nTakerGets || *nTakerGets <= 0)
216 auto const nTakerGetsConstraint =
217 pool.out - pool.in / (targetQuality.rate() * f);
218 if (nTakerGetsConstraint <= 0)
222 if (nTakerGetsConstraint < *nTakerGets)
223 nTakerGets = nTakerGetsConstraint;
225 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
228 auto const takerGets = toAmount<TOut>(
230 return TAmounts<TIn, TOut>{
236 if (
auto const amounts = getAmounts(*nTakerGets);
237 Quality{amounts} < targetQuality)
266template <
typename TIn,
typename TOut>
269 TAmounts<TIn, TOut>
const& pool,
270 Quality
const& targetQuality,
273 if (targetQuality.rate() == beast::zero)
279 auto const b = pool.in * (1 + f);
281 pool.in * pool.in - pool.in * pool.out * targetQuality.rate();
284 if (!nTakerPays || nTakerPays <= 0)
287 auto const nTakerPaysConstraint =
288 pool.out * targetQuality.rate() - pool.in / f;
289 if (nTakerPaysConstraint <= 0)
293 if (nTakerPaysConstraint < *nTakerPays)
294 nTakerPays = nTakerPaysConstraint;
296 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
299 auto const takerPays = toAmount<TIn>(
301 return TAmounts<TIn, TOut>{
307 if (
auto const amounts = getAmounts(*nTakerPays);
308 Quality{amounts} < targetQuality)
330template <
typename TIn,
typename TOut>
333 TAmounts<TIn, TOut>
const& pool,
334 Quality
const& quality,
339 if (!rules.
enabled(fixAMMv1_1))
349 auto const b = pool.in * (1 + f);
351 pool.in * pool.in - pool.in * pool.out * quality.rate();
352 if (
auto const res = b * b - 4 * a * c; res < 0)
354 else if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a);
355 nTakerPaysPropose > 0)
357 auto const nTakerPays = [&]() {
362 auto const nTakerPaysConstraint =
363 pool.out * quality.rate() - pool.in / f;
364 if (nTakerPaysPropose > nTakerPaysConstraint)
365 return nTakerPaysConstraint;
366 return nTakerPaysPropose;
371 <<
"changeSpotPriceQuality calc failed: "
373 << quality <<
" " << tfee;
376 auto const takerPays =
379 if (
auto const amounts =
382 Quality{amounts} < quality &&
384 Quality{amounts}, quality,
Number(1, -7)))
387 <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in)
388 <<
" " <<
to_string(pool.out) <<
" " <<
" " << quality
389 <<
" " << tfee <<
" " <<
to_string(amounts.in) <<
" "
391 Throw<std::runtime_error>(
"changeSpotPriceQuality failed");
396 <<
"changeSpotPriceQuality succeeded: "
398 <<
" " << quality <<
" " << tfee <<
" "
403 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: "
405 <<
" " << quality <<
" " << tfee;
411 auto const amounts = [&]() {
418 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.in)
419 <<
" " <<
to_string(pool.out) <<
" " << quality <<
" "
424 if (Quality{*amounts} < quality)
426 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: "
428 <<
" " << quality <<
" " << tfee <<
" "
434 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: "
436 <<
" " << quality <<
" " << tfee <<
" "
463template <
typename TIn,
typename TOut>
466 TAmounts<TIn, TOut>
const& pool,
471 rules && rules->enabled(fixAMMv1_1))
497 auto const numerator = pool.in * pool.out;
498 auto const fee =
getFee(tfee);
501 auto const denom = pool.in + assetIn * (1 - fee);
503 if (denom.signum() <= 0)
504 return toAmount<TOut>(
getIssue(pool.out), 0);
507 auto const ratio = numerator / denom;
510 auto const swapOut = pool.out - ratio;
512 if (swapOut.signum() < 0)
513 return toAmount<TOut>(
getIssue(pool.out), 0);
519 return toAmount<TOut>(
522 (pool.in * pool.out) / (pool.in + assetIn *
feeMult(tfee)),
536template <
typename TIn,
typename TOut>
539 TAmounts<TIn, TOut>
const& pool,
540 TOut
const& assetOut,
544 rules && rules->enabled(fixAMMv1_1))
566 auto const numerator = pool.in * pool.out;
569 auto const denom = pool.out - assetOut;
570 if (denom.signum() <= 0)
572 return toMaxAmount<TIn>(
getIssue(pool.in));
576 auto const ratio = numerator / denom;
577 auto const numerator2 = ratio - pool.in;
578 auto const fee =
getFee(tfee);
584 auto const swapIn = numerator2 /
feeMult;
585 if (swapIn.signum() < 0)
586 return toAmount<TIn>(
getIssue(pool.in), 0);
592 return toAmount<TIn>(
594 ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
618 STAmount
const& lptAMMBalance,
619 STAmount
const& lpTokens,
635 STAmount
const& amountBalance,
636 STAmount
const& amount,
638 STAmount
const& lptAMMBalance,
639 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.