3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/protocol/AMMCore.h>
7#include <xrpl/protocol/AmountConversions.h>
8#include <xrpl/protocol/Feature.h>
9#include <xrpl/protocol/IOUAmount.h>
10#include <xrpl/protocol/Issue.h>
11#include <xrpl/protocol/Quality.h>
12#include <xrpl/protocol/Rules.h>
13#include <xrpl/protocol/STAmount.h>
22 static Number const reducedOfferPct(9999, -4);
26 return amount * reducedOfferPct;
39ammLPTokens(STAmount
const& asset1, STAmount
const& asset2, Issue
const& lptIssue);
50 STAmount
const& asset1Balance,
51 STAmount
const& asset1Deposit,
52 STAmount
const& lptAMMBalance,
64 STAmount
const& asset1Balance,
65 STAmount
const& lptAMMBalance,
66 STAmount
const& lpTokens,
79 STAmount
const& asset1Balance,
80 STAmount
const& asset1Withdraw,
81 STAmount
const& lptAMMBalance,
93 STAmount
const& assetBalance,
94 STAmount
const& lptAMMBalance,
95 STAmount
const& lpTokens,
108 if (calcQuality == reqQuality)
110 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
114 return ((min.rate() - max.rate()) / min.rate()) < dist;
124template <
typename Amt>
134 return ((max - min) / max) < dist;
166template <
typename TIn,
typename TOut>
169 TAmounts<TIn, TOut>
const& pool,
170 Quality
const& targetQuality,
173 if (targetQuality.rate() == beast::zero)
179 auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out;
180 auto const c = pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate();
183 if (!nTakerGets || *nTakerGets <= 0)
186 auto const nTakerGetsConstraint = pool.out - pool.in / (targetQuality.rate() * f);
187 if (nTakerGetsConstraint <= 0)
191 if (nTakerGetsConstraint < *nTakerGets)
192 nTakerGets = nTakerGetsConstraint;
194 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
197 auto const takerGets =
199 return TAmounts<TIn, TOut>{
swapAssetOut(pool, takerGets, tfee), takerGets};
204 if (
auto amounts = getAmounts(*nTakerGets); Quality{amounts} < targetQuality)
233template <
typename TIn,
typename TOut>
236 TAmounts<TIn, TOut>
const& pool,
237 Quality
const& targetQuality,
240 if (targetQuality.rate() == beast::zero)
246 auto const b = pool.in * (1 + f);
247 auto const c = pool.in * pool.in - pool.in * pool.out * targetQuality.rate();
250 if (!nTakerPays || nTakerPays <= 0)
253 auto const nTakerPaysConstraint = pool.out * targetQuality.rate() - pool.in / f;
254 if (nTakerPaysConstraint <= 0)
258 if (nTakerPaysConstraint < *nTakerPays)
259 nTakerPays = nTakerPaysConstraint;
261 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
264 auto const takerPays =
266 return TAmounts<TIn, TOut>{takerPays,
swapAssetIn(pool, takerPays, tfee)};
271 if (
auto amounts = getAmounts(*nTakerPays); Quality{amounts} < targetQuality)
293template <
typename TIn,
typename TOut>
296 TAmounts<TIn, TOut>
const& pool,
297 Quality
const& quality,
302 if (!rules.
enabled(fixAMMv1_1))
312 auto const b = pool.in * (1 + f);
313 Number const c = pool.in * pool.in - pool.in * pool.out * quality.rate();
314 if (
auto const res = b * b - 4 * a * c; res < 0)
316 else if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a); nTakerPaysPropose > 0)
318 auto const nTakerPays = [&]() {
323 auto const nTakerPaysConstraint = pool.out * quality.rate() - pool.in / f;
324 if (nTakerPaysPropose > nTakerPaysConstraint)
325 return nTakerPaysConstraint;
326 return nTakerPaysPropose;
330 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.in)
331 <<
" " <<
to_string(pool.out) <<
" " << quality <<
" " << tfee;
336 if (
auto amounts = TAmounts<TIn, TOut>{takerPays,
swapAssetIn(pool, takerPays, tfee)};
337 Quality{amounts} < quality &&
340 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in) <<
" "
342 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in)
344 Throw<std::runtime_error>(
"changeSpotPriceQuality failed");
348 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.in) <<
" "
350 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in)
355 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.in) <<
" "
356 <<
to_string(pool.out) <<
" " << quality <<
" " << tfee;
362 auto amounts = [&]() {
369 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.in) <<
" "
370 <<
to_string(pool.out) <<
" " << quality <<
" " << tfee;
374 if (Quality{*amounts} < quality)
376 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in) <<
" "
377 <<
to_string(pool.out) <<
" " << quality <<
" " << tfee <<
" "
382 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.in) <<
" "
384 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts->in) <<
" "
411template <
typename TIn,
typename TOut>
441 auto const numerator = pool.in * pool.out;
442 auto const fee =
getFee(tfee);
445 auto const denom = pool.in + assetIn * (1 - fee);
447 if (denom.signum() <= 0)
448 return toAmount<TOut>(
getIssue(pool.out), 0);
451 auto const ratio = numerator / denom;
454 auto const swapOut = pool.out - ratio;
456 if (swapOut.signum() < 0)
457 return toAmount<TOut>(
getIssue(pool.out), 0);
463 return toAmount<TOut>(
465 pool.out - (pool.in * pool.out) / (pool.in + assetIn *
feeMult(tfee)),
479template <
typename TIn,
typename TOut>
505 auto const numerator = pool.in * pool.out;
508 auto const denom = pool.out - assetOut;
509 if (denom.signum() <= 0)
511 return toMaxAmount<TIn>(
getIssue(pool.in));
515 auto const ratio = numerator / denom;
516 auto const numerator2 = ratio - pool.in;
517 auto const fee =
getFee(tfee);
523 auto const swapIn = numerator2 /
feeMult;
524 if (swapIn.signum() < 0)
525 return toAmount<TIn>(
getIssue(pool.in), 0);
531 return toAmount<TIn>(
533 ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
feeMult(tfee),
570 STAmount
const& amountBalance,
571 STAmount
const& amount,
573 STAmount
const& lptAMMBalance,
574 STAmount
const& lpTokens,
616 if (!rules.
enabled(fixAMMv1_3))
640 STAmount
const& balance,
654 STAmount
const& balance,
673 STAmount
const& lptAMMBalance,
691 STAmount
const& balance,
692 STAmount
const& amount,
693 STAmount
const& lptAMMBalance,
694 STAmount
const& tokens,
699 STAmount
const& balance,
700 STAmount
const& amount,
701 STAmount
const& lptAMMBalance,
702 STAmount
const& tokens,
711 STAmount
const& lptAMMBalance,
712 STAmount
const& tokens,
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
Number is a floating point type that can represent a wide range of values.
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 reduceOffer(auto const &amount)
Number::rounding_mode getLPTokenRounding(IsDeposit isDeposit)
Number::rounding_mode getAssetRounding(IsDeposit isDeposit)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool isXRP(AccountID const &c)
Number adjustFracByTokens(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &tokens, Number const &frac)
Find a fraction of tokens after the tokens are adjusted.
std::string to_string(base_uint< Bits, Tag > const &a)
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, IsDeposit isDeposit)
Adjust LP tokens to deposit/withdraw.
std::optional< Rules > const & getCurrentTransactionRules()
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 ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
STAmount multiply(STAmount const &amount, Rate const &rate)
STAmount ammAssetOut(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset withdrawal by tokens.
STAmount getRoundedLPTokens(Rules const &rules, STAmount const &balance, Number const &frac, IsDeposit isDeposit)
Round AMM deposit/withdrawal LPToken amount.
std::pair< STAmount, STAmount > adjustAssetInByTokens(Rules const &rules, STAmount const &balance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &tokens, std::uint16_t tfee)
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(...
std::pair< STAmount, STAmount > adjustAssetOutByTokens(Rules const &rules, STAmount const &balance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &tokens, std::uint16_t tfee)
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 getRoundedAsset(Rules const &rules, STAmount const &balance, A const &frac, IsDeposit isDeposit)
Round AMM equal deposit/withdrawal amount.
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
std::optional< Number > solveQuadraticEqSmallest(Number const &a, Number const &b, Number const &c)
Solve quadratic equation to find takerGets or takerPays.
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 ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset deposit given LP Tokens.
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...
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's withdraw amount.
Number getFee(std::uint16_t tfee)
Convert to the fee from the basis points.
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.
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 square(Number const &n)
Return square of n.
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
Issue getIssue(T const &amt)