3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/beast/utility/Journal.h>
7#include <xrpl/beast/utility/Zero.h>
8#include <xrpl/ledger/ApplyView.h>
9#include <xrpl/ledger/ReadView.h>
10#include <xrpl/ledger/Sandbox.h>
11#include <xrpl/ledger/helpers/TokenHelpers.h>
12#include <xrpl/protocol/AMMCore.h>
13#include <xrpl/protocol/AccountID.h>
14#include <xrpl/protocol/AmountConversions.h>
15#include <xrpl/protocol/Asset.h>
16#include <xrpl/protocol/Feature.h>
17#include <xrpl/protocol/IOUAmount.h>
18#include <xrpl/protocol/Issue.h>
19#include <xrpl/protocol/MPTAmount.h>
20#include <xrpl/protocol/Quality.h>
21#include <xrpl/protocol/Rules.h>
22#include <xrpl/protocol/STAmount.h>
23#include <xrpl/protocol/STLedgerEntry.h>
24#include <xrpl/protocol/TER.h>
25#include <xrpl/protocol/XRPAmount.h>
43 static Number const kReducedOfferPct(9999, -4);
47 return amount * kReducedOfferPct;
63ammLPTokens(STAmount
const& asset1, STAmount
const& asset2, Asset
const& lptIssue);
75 STAmount
const& asset1Balance,
76 STAmount
const& asset1Deposit,
77 STAmount
const& lptAMMBalance,
90 STAmount
const& asset1Balance,
91 STAmount
const& lptAMMBalance,
92 STAmount
const& lpTokens,
106 STAmount
const& asset1Balance,
107 STAmount
const& asset1Withdraw,
108 STAmount
const& lptAMMBalance,
121 STAmount
const& assetBalance,
122 STAmount
const& lptAMMBalance,
123 STAmount
const& lpTokens,
137 if (calcQuality == reqQuality)
139 auto const [min, max] =
std::minmax(calcQuality, reqQuality);
143 return ((min.rate() - max.rate()) / min.rate()) < dist;
154template <
typename Amt>
165 return ((max - min) / max) < dist;
199template <
typename TIn,
typename TOut>
212 auto const b = pool.
in * (1 - 1 / f) / targetQuality.
rate() - 2 * pool.
out;
213 auto const c = pool.
out * pool.
out - (pool.
in * pool.
out) / targetQuality.
rate();
216 if (!nTakerGets || *nTakerGets <= 0)
219 auto const nTakerGetsConstraint = pool.
out - pool.
in / (targetQuality.
rate() * f);
220 if (nTakerGetsConstraint <= 0)
224 if (nTakerGetsConstraint < *nTakerGets)
225 nTakerGets = nTakerGetsConstraint;
227 auto getAmounts = [&pool, &tfee](
Number const& nTakerGetsProposed) {
230 auto const takerGets =
237 auto amounts = getAmounts(*nTakerGets);
238 if (
Quality{amounts} < targetQuality)
267template <
typename TIn,
typename TOut>
280 auto const b = pool.
in * (1 + f);
281 auto const c = pool.
in * pool.
in - pool.
in * pool.
out * targetQuality.
rate();
284 if (!nTakerPays || nTakerPays <= 0)
287 auto const nTakerPaysConstraint = pool.
out * targetQuality.
rate() - pool.
in / f;
288 if (nTakerPaysConstraint <= 0)
292 if (nTakerPaysConstraint < *nTakerPays)
293 nTakerPays = nTakerPaysConstraint;
295 auto getAmounts = [&pool, &tfee](
Number const& nTakerPaysProposed) {
298 auto const takerPays =
305 auto amounts = getAmounts(*nTakerPays);
306 if (
Quality{amounts} < targetQuality)
328template <
typename TIn,
typename TOut>
337 if (!rules.
enabled(fixAMMv1_1))
347 auto const b = pool.
in * (1 + f);
348 Number const c = pool.
in * pool.
in - pool.
in * pool.
out * quality.rate();
349 auto const res = b * b - 4 * a * c;
354 if (
auto const nTakerPaysPropose = (-b +
root2(res)) / (2 * a); nTakerPaysPropose > 0)
356 auto const nTakerPays = [&]() {
361 auto const nTakerPaysConstraint = pool.
out * quality.rate() - pool.
in / f;
362 if (nTakerPaysPropose > nTakerPaysConstraint)
363 return nTakerPaysConstraint;
364 return nTakerPaysPropose;
368 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.
in)
369 <<
" " <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee;
372 auto const takerPays =
379 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.
in) <<
" "
381 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in)
387 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.
in) <<
" "
389 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts.in)
394 JLOG(j.
trace()) <<
"changeSpotPriceQuality calc failed: " <<
to_string(pool.
in) <<
" "
395 <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee;
399 auto amounts = [&]() {
410 if (outIntegral && (!inIntegral ||
Number(quality.rate()) >= 1))
416 JLOG(j.
trace()) <<
"changeSpotPrice calc failed: " <<
to_string(pool.
in) <<
" "
417 <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee;
421 if (
Quality{*amounts} < quality)
423 JLOG(j.
error()) <<
"changeSpotPriceQuality failed: " <<
to_string(pool.
in) <<
" "
424 <<
to_string(pool.
out) <<
" " << quality <<
" " << tfee <<
" "
429 JLOG(j.
trace()) <<
"changeSpotPriceQuality succeeded: " <<
to_string(pool.
in) <<
" "
431 <<
" " << quality <<
" " << tfee <<
" " <<
to_string(amounts->in) <<
" "
460template <
typename TIn,
typename TOut>
490 auto const numerator = pool.
in * pool.
out;
491 auto const fee =
getFee(tfee);
494 auto const denom = pool.
in + assetIn * (1 - fee);
496 if (denom.signum() <= 0)
500 auto const ratio = numerator / denom;
503 auto const swapOut = pool.
out - ratio;
505 if (swapOut.signum() < 0)
527template <
typename TIn,
typename TOut>
553 auto const numerator = pool.
in * pool.
out;
556 auto const denom = pool.
out - assetOut;
557 if (denom.signum() <= 0)
563 auto const ratio = numerator / denom;
564 auto const numerator2 = ratio - pool.
in;
565 auto const fee =
getFee(tfee);
571 auto const swapIn = numerator2 /
feeMult;
572 if (swapIn.signum() < 0)
619 STAmount
const& amountBalance,
620 STAmount
const& amount,
622 STAmount
const& lptAMMBalance,
623 STAmount
const& lpTokens,
669 if (!rules.
enabled(fixAMMv1_3))
698 STAmount
const& balance,
713 STAmount
const& balance,
733 STAmount
const& lptAMMBalance,
751 STAmount
const& balance,
752 STAmount
const& amount,
753 STAmount
const& lptAMMBalance,
754 STAmount
const& tokens,
759 STAmount
const& balance,
760 STAmount
const& amount,
761 STAmount
const& lptAMMBalance,
762 STAmount
const& tokens,
772 STAmount
const& lptAMMBalance,
773 STAmount
const& tokens,
781 ReadView
const& view,
808 ReadView
const& view,
812 STAmount
const& newLPTokenBalance,
820std::expected<std::tuple<STAmount, STAmount, STAmount>,
TER>
822 ReadView
const& view,
835 ReadView
const& view,
844 ReadView
const& view,
878 Asset
const& lptAsset,
886std::expected<bool, TER>
894std::expected<bool, TER>
897 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.
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
@ Yes
We have consensus along with the network.
@ No
We do not have consensus.
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.