3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/ledger/ReadView.h>
7#include <xrpl/ledger/Sandbox.h>
8#include <xrpl/ledger/helpers/RippleStateHelpers.h>
9#include <xrpl/ledger/helpers/TokenHelpers.h>
10#include <xrpl/protocol/AMMCore.h>
11#include <xrpl/protocol/AmountConversions.h>
12#include <xrpl/protocol/Feature.h>
13#include <xrpl/protocol/IOUAmount.h>
14#include <xrpl/protocol/Issue.h>
15#include <xrpl/protocol/Quality.h>
16#include <xrpl/protocol/Rules.h>
17#include <xrpl/protocol/STAmount.h>
18#include <xrpl/protocol/STLedgerEntry.h>
29 static Number const kReducedOfferPct(9999, -4);
33 return amount * kReducedOfferPct;
48ammLPTokens(STAmount
const& asset1, STAmount
const& asset2, Asset
const& lptIssue);
59 STAmount
const& asset1Balance,
60 STAmount
const& asset1Deposit,
61 STAmount
const& lptAMMBalance,
73 STAmount
const& asset1Balance,
74 STAmount
const& lptAMMBalance,
75 STAmount
const& lpTokens,
88 STAmount
const& asset1Balance,
89 STAmount
const& asset1Withdraw,
90 STAmount
const& lptAMMBalance,
102 STAmount
const& assetBalance,
103 STAmount
const& lptAMMBalance,
104 STAmount
const& lpTokens,
117 if (calcQuality == reqQuality)
119 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
123 return ((min.rate() - max.rate()) / min.rate()) < dist;
133template <
typename Amt>
144 return ((max - min) / max) < dist;
176template <
typename TIn,
typename TOut>
183 if (targetQuality.
rate() == beast::kZero)
189 auto const b = pool.
in * (1 - 1 / f) / targetQuality.
rate() - 2 * pool.
out;
190 auto const c = pool.
out * pool.
out - (pool.
in * pool.
out) / targetQuality.
rate();
193 if (!nTakerGets || *nTakerGets <= 0)
196 auto const nTakerGetsConstraint = pool.
out - pool.
in / (targetQuality.
rate() * f);
197 if (nTakerGetsConstraint <= 0)
201 if (nTakerGetsConstraint < *nTakerGets)
202 nTakerGets = nTakerGetsConstraint;
204 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
207 auto const takerGets =
214 auto amounts = getAmounts(*nTakerGets);
215 if (
Quality{amounts} < targetQuality)
243template <
typename TIn,
typename TOut>
250 if (targetQuality.
rate() == beast::kZero)
256 auto const b = pool.
in * (1 + f);
257 auto const c = pool.
in * pool.
in - pool.
in * pool.
out * targetQuality.
rate();
260 if (!nTakerPays || nTakerPays <= 0)
263 auto const nTakerPaysConstraint = pool.
out * targetQuality.
rate() - pool.
in / f;
264 if (nTakerPaysConstraint <= 0)
268 if (nTakerPaysConstraint < *nTakerPays)
269 nTakerPays = nTakerPaysConstraint;
271 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
274 auto const takerPays =
281 auto amounts = getAmounts(*nTakerPays);
282 if (
Quality{amounts} < targetQuality)
303template <
typename TIn,
typename TOut>
312 if (!rules.
enabled(fixAMMv1_1))
322 auto const b = pool.
in * (1 + f);
323 Number const c = pool.
in * pool.
in - pool.
in * pool.
out * quality.rate();
324 auto const res = b * b - 4 * a * c;
329 if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a); nTakerPaysPropose > 0)
331 auto const nTakerPays = [&]() {
336 auto const nTakerPaysConstraint = pool.
out * quality.rate() - pool.
in / f;
337 if (nTakerPaysPropose > nTakerPaysConstraint)
338 return nTakerPaysConstraint;
339 return nTakerPaysPropose;
343 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.
in)
344 <<
" " <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee;
347 auto const takerPays =
354 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.
in) <<
" "
356 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in)
362 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.
in) <<
" "
364 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in)
369 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.
in) <<
" "
370 <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee;
376 auto amounts = [&]() {
383 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.
in) <<
" "
384 <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee;
388 if (
Quality{*amounts} < quality)
390 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.
in) <<
" "
391 <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee <<
" "
396 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.
in) <<
" "
398 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts->in) <<
" "
425template <
typename TIn,
typename TOut>
455 auto const numerator = pool.
in * pool.
out;
456 auto const fee =
getFee(tfee);
459 auto const denom = pool.
in + assetIn * (1 - fee);
461 if (denom.signum() <= 0)
465 auto const ratio = numerator / denom;
468 auto const swapOut = pool.
out - ratio;
470 if (swapOut.signum() < 0)
491template <
typename TIn,
typename TOut>
517 auto const numerator = pool.
in * pool.
out;
520 auto const denom = pool.
out - assetOut;
521 if (denom.signum() <= 0)
527 auto const ratio = numerator / denom;
528 auto const numerator2 = ratio - pool.
in;
529 auto const fee =
getFee(tfee);
535 auto const swapIn = numerator2 /
feeMult;
536 if (swapIn.signum() < 0)
580 STAmount
const& amountBalance,
581 STAmount
const& amount,
583 STAmount
const& lptAMMBalance,
584 STAmount
const& lpTokens,
628 if (!rules.
enabled(fixAMMv1_3))
656 STAmount
const& balance,
670 STAmount
const& balance,
689 STAmount
const& lptAMMBalance,
707 STAmount
const& balance,
708 STAmount
const& amount,
709 STAmount
const& lptAMMBalance,
710 STAmount
const& tokens,
715 STAmount
const& balance,
716 STAmount
const& amount,
717 STAmount
const& lptAMMBalance,
718 STAmount
const& tokens,
727 STAmount
const& lptAMMBalance,
728 STAmount
const& tokens,
735 ReadView
const& view,
760 ReadView
const& view,
764 STAmount
const& newLPTokenBalance,
771std::expected<std::tuple<STAmount, STAmount, STAmount>,
TER>
773 ReadView
const& view,
785 ReadView
const& view,
794 ReadView
const& view,
824 Asset
const& lptAsset,
831std::expected<bool, TER>
838std::expected<bool, TER>
841 STAmount
const& lpTokens,
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 RoundingMode setround(RoundingMode inMode)
static RoundingMode getround()
Represents the logical ratio of output currency to input currency.
STAmount rate() const
Returns the quality as STAmount.
Rules controlling protocol behavior.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Asset const & asset() const
std::shared_ptr< STLedgerEntry > pointer
Number reduceOffer(auto const &amount)
Number::RoundingMode getLPTokenRounding(IsDeposit isDeposit)
Number::RoundingMode getAssetRounding(IsDeposit isDeposit)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount ammLPHolds(ReadView const &view, Asset const &asset1, Asset const &asset2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
FreezeHandling
Controls the treatment of frozen account balances.
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.
T toMaxAmount(Asset const &asset)
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Asset const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
std::expected< bool, TER > isOnlyLiquidityProvider(ReadView const &view, Issue const &ammIssue, AccountID const &lpAccount)
Return true if the Liquidity Provider is the only AMM provider, false otherwise.
std::expected< bool, TER > verifyAndAdjustLPTokenBalance(Sandbox &sb, STAmount const &lpTokens, SLE::pointer &ammSle, AccountID const &account)
Due to rounding, the LPTokenBalance of the last LP might not match the LP's trustline balance.
void initializeFeeAuctionVote(ApplyView &view, SLE::pointer &ammSle, AccountID const &account, Asset const &lptAsset, std::uint16_t tfee)
Initialize Auction and Voting slots and set the trading/discounted fee.
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 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::string to_string(BaseUInt< Bits, Tag > const &a)
std::pair< STAmount, STAmount > ammPoolHolds(ReadView const &view, AccountID const &ammAccountID, Asset const &asset1, Asset const &asset2, FreezeHandling freezeHandling, AuthHandling authHandling, beast::Journal const j)
Get AMM pool balances.
T toAmount(STAmount const &amt)=delete
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(...
STAmount ammAccountHolds(ReadView const &view, AccountID const &ammAccountID, Asset const &asset)
Returns total amount held by AMM for the given token.
Asset getAsset(T const &amt)
std::pair< STAmount, STAmount > adjustAssetOutByTokens(Rules const &rules, STAmount const &balance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &tokens, std::uint16_t tfee)
TER deleteAMMAccount(Sandbox &view, Asset const &asset, Asset const &asset2, beast::Journal j)
Delete trustlines to AMM.
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.
AuthHandling
Controls the treatment of unauthorized MPT balances.
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
TER checkAMMPrecisionLoss(Number const &poolProductMean, STAmount const &newLPTokenBalance)
Check AMM pool product invariant after an AMM operation that changes LP tokens (deposit/withdraw/claw...
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.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
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.
TERSubset< CanCvtToTER > TER
Number const kAMMInvariantRelativeTolerance
bool withinRelativeDistance(Quality const &calcQuality, Quality const &reqQuality, Number const &dist)
Check if the relative distance between the qualities is within the requested distance.
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
std::expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Asset > const &optAsset1, std::optional< Asset > const &optAsset2, FreezeHandling freezeHandling, AuthHandling authHandling, beast::Journal const j)
Get AMM pool and LP token balances.
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Number square(Number const &n)
Return square of n.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
STAmount toSTAmount(IOUAmount const &iou, Asset const &asset)
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
Represents a pair of input and output currencies.