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,
63ammAssetIn(STAmount
const& asset1Balance, STAmount
const& lptAMMBalance, STAmount
const& lpTokens,
std::uint16_t tfee);
75 STAmount
const& asset1Balance,
76 STAmount
const& asset1Withdraw,
77 STAmount
const& lptAMMBalance,
88ammAssetOut(STAmount
const& assetBalance, STAmount
const& lptAMMBalance, STAmount
const& lpTokens,
std::uint16_t tfee);
100 if (calcQuality == reqQuality)
102 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
106 return ((min.rate() - max.rate()) / min.rate()) < dist;
117template <
typename Amt>
127 return ((max - min) / max) < dist;
160template <
typename TIn,
typename TOut>
164 if (targetQuality.rate() == beast::zero)
170 auto const b = pool.in * (1 - 1 / f) / targetQuality.rate() - 2 * pool.out;
171 auto const c = pool.out * pool.out - (pool.in * pool.out) / targetQuality.rate();
174 if (!nTakerGets || *nTakerGets <= 0)
177 auto const nTakerGetsConstraint = pool.out - pool.in / (targetQuality.rate() * f);
178 if (nTakerGetsConstraint <= 0)
182 if (nTakerGetsConstraint < *nTakerGets)
183 nTakerGets = nTakerGetsConstraint;
185 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
189 return TAmounts<TIn, TOut>{
swapAssetOut(pool, takerGets, tfee), takerGets};
194 if (
auto const amounts = getAmounts(*nTakerGets); Quality{amounts} < targetQuality)
223template <
typename TIn,
typename TOut>
227 if (targetQuality.rate() == beast::zero)
233 auto const b = pool.in * (1 + f);
234 auto const c = pool.in * pool.in - pool.in * pool.out * targetQuality.rate();
237 if (!nTakerPays || nTakerPays <= 0)
240 auto const nTakerPaysConstraint = pool.out * targetQuality.rate() - pool.in / f;
241 if (nTakerPaysConstraint <= 0)
245 if (nTakerPaysConstraint < *nTakerPays)
246 nTakerPays = nTakerPaysConstraint;
248 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
252 return TAmounts<TIn, TOut>{takerPays,
swapAssetIn(pool, takerPays, tfee)};
257 if (
auto const amounts = getAmounts(*nTakerPays); Quality{amounts} < targetQuality)
279template <
typename TIn,
typename TOut>
282 TAmounts<TIn, TOut>
const& pool,
283 Quality
const& quality,
288 if (!rules.
enabled(fixAMMv1_1))
298 auto const b = pool.in * (1 + f);
299 Number const c = pool.in * pool.in - pool.in * pool.out * quality.rate();
300 if (
auto const res = b * b - 4 * a * c; res < 0)
302 else if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a); nTakerPaysPropose > 0)
304 auto const nTakerPays = [&]() {
309 auto const nTakerPaysConstraint = pool.out * quality.rate() - pool.in / f;
310 if (nTakerPaysPropose > nTakerPaysConstraint)
311 return nTakerPaysConstraint;
312 return nTakerPaysPropose;
316 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.in) <<
" "
317 <<
to_string(pool.out) <<
" " << quality <<
" " << tfee;
322 if (
auto const amounts = TAmounts<TIn, TOut>{takerPays,
swapAssetIn(pool, takerPays, tfee)};
327 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in) <<
" "
329 Throw<std::runtime_error>(
"changeSpotPriceQuality failed");
333 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.in) <<
" "
335 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in) <<
" "
341 <<
" " << quality <<
" " << tfee;
347 auto const amounts = [&]() {
359 if (Quality{*amounts} < quality)
361 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.in) <<
" " <<
to_string(pool.out) <<
" "
362 << quality <<
" " << tfee <<
" " <<
to_string(amounts->in) <<
" " <<
to_string(amounts->out);
366 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.in) <<
" " <<
to_string(pool.out) <<
" "
367 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts->in) <<
" " <<
to_string(amounts->out);
393template <
typename TIn,
typename TOut>
423 auto const numerator = pool.in * pool.out;
424 auto const fee =
getFee(tfee);
427 auto const denom = pool.in + assetIn * (1 - fee);
429 if (denom.signum() <= 0)
430 return toAmount<TOut>(
getIssue(pool.out), 0);
433 auto const ratio = numerator / denom;
436 auto const swapOut = pool.out - ratio;
438 if (swapOut.signum() < 0)
439 return toAmount<TOut>(
getIssue(pool.out), 0);
445 return toAmount<TOut>(
447 pool.out - (pool.in * pool.out) / (pool.in + assetIn *
feeMult(tfee)),
461template <
typename TIn,
typename TOut>
487 auto const numerator = pool.in * pool.out;
490 auto const denom = pool.out - assetOut;
491 if (denom.signum() <= 0)
493 return toMaxAmount<TIn>(
getIssue(pool.in));
497 auto const ratio = numerator / denom;
498 auto const numerator2 = ratio - pool.in;
499 auto const fee =
getFee(tfee);
505 auto const swapIn = numerator2 /
feeMult;
506 if (swapIn.signum() < 0)
507 return toAmount<TIn>(
getIssue(pool.in), 0);
513 return toAmount<TIn>(
515 ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
feeMult(tfee),
552 STAmount
const& amountBalance,
553 STAmount
const& amount,
555 STAmount
const& lptAMMBalance,
556 STAmount
const& lpTokens,
598 if (!rules.
enabled(fixAMMv1_3))
622 STAmount
const& balance,
651 STAmount
const& lptAMMBalance,
669 STAmount
const& balance,
670 STAmount
const& amount,
671 STAmount
const& lptAMMBalance,
672 STAmount
const& tokens,
677 STAmount
const& balance,
678 STAmount
const& amount,
679 STAmount
const& lptAMMBalance,
680 STAmount
const& tokens,
687adjustFracByTokens(Rules
const& rules, STAmount
const& lptAMMBalance, STAmount
const& tokens, Number
const& frac);
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)