rippled
AMMHelpers.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2023 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED
21 #define RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED
22 
23 #include <ripple/basics/IOUAmount.h>
24 #include <ripple/basics/Number.h>
25 #include <ripple/protocol/AMMCore.h>
26 #include <ripple/protocol/AmountConversions.h>
27 #include <ripple/protocol/Issue.h>
28 #include <ripple/protocol/Quality.h>
29 #include <ripple/protocol/STAccount.h>
30 #include <ripple/protocol/STAmount.h>
31 
32 #include <type_traits>
33 
34 namespace ripple {
35 
41 STAmount
43  STAmount const& asset1,
44  STAmount const& asset2,
45  Issue const& lptIssue);
46 
54 STAmount
56  STAmount const& asset1Balance,
57  STAmount const& asset1Deposit,
58  STAmount const& lptAMMBalance,
59  std::uint16_t tfee);
60 
68 STAmount
70  STAmount const& asset1Balance,
71  STAmount const& lptAMMBalance,
72  STAmount const& lpTokens,
73  std::uint16_t tfee);
74 
83 STAmount
85  STAmount const& asset1Balance,
86  STAmount const& asset1Withdraw,
87  STAmount const& lptAMMBalance,
88  std::uint16_t tfee);
89 
97 STAmount
99  STAmount const& assetBalance,
100  STAmount const& lptAMMBalance,
101  STAmount const& lpTokens,
102  std::uint16_t tfee);
103 
111 inline bool
112 withinRelativeDistance(
113  Quality const& calcQuality,
114  Quality const& reqQuality,
115  Number const& dist)
116 {
117  if (calcQuality == reqQuality)
118  return true;
119  auto const [min, max] = std::minmax(calcQuality, reqQuality);
120  // Relative distance is (max - min)/max. Can't use basic operations
121  // on Quality. Have to use Quality::rate() instead, which
122  // is inverse of quality: (1/max.rate - 1/min.rate)/(1/max.rate)
123  return ((min.rate() - max.rate()) / min.rate()) < dist;
124 }
125 
133 // clang-format off
134 template <typename Amt>
135  requires(
136  std::is_same_v<Amt, STAmount> || std::is_same_v<Amt, IOUAmount> ||
137  std::is_same_v<Amt, XRPAmount>)
138 bool
139 withinRelativeDistance(Amt const& calc, Amt const& req, Number const& dist)
140 {
141  if (calc == req)
142  return true;
143  auto const [min, max] = std::minmax(calc, req);
144  return ((max - min) / max) < dist;
145 }
146 // clang-format on
147 
159 template <typename TIn, typename TOut>
161 changeSpotPriceQuality(
162  TAmounts<TIn, TOut> const& pool,
163  Quality const& quality,
164  std::uint16_t tfee)
165 {
166  auto const f = feeMult(tfee); // 1 - fee
167  auto const& a = f;
168  auto const b = pool.in * (1 + f);
169  Number const c = pool.in * pool.in - pool.in * pool.out * quality.rate();
170  if (auto const res = b * b - 4 * a * c; res < 0)
171  return std::nullopt;
172  else if (auto const nTakerPaysPropose = (-b + root2(res)) / (2 * a);
173  nTakerPaysPropose > 0)
174  {
175  auto const nTakerPays = [&]() {
176  // The fee might make the AMM offer quality less than CLOB quality.
177  // Therefore, AMM offer has to satisfy this constraint: o / i >= q.
178  // Substituting o with swapAssetIn() gives:
179  // i <= O / q - I / (1 - fee).
180  auto const nTakerPaysConstraint =
181  pool.out * quality.rate() - pool.in / f;
182  if (nTakerPaysPropose > nTakerPaysConstraint)
183  return nTakerPaysConstraint;
184  return nTakerPaysPropose;
185  }();
186  if (nTakerPays <= 0)
187  return std::nullopt;
188  auto const takerPays = toAmount<TIn>(
189  getIssue(pool.in), nTakerPays, Number::rounding_mode::upward);
190  // should not fail
191  if (auto const amounts =
192  TAmounts<TIn, TOut>{
193  takerPays, swapAssetIn(pool, takerPays, tfee)};
194  Quality{amounts} < quality &&
195  !withinRelativeDistance(Quality{amounts}, quality, Number(1, -7)))
196  Throw<std::runtime_error>("changeSpotPriceQuality failed");
197  else
198  return amounts;
199  }
200  return std::nullopt;
201 }
202 
224 template <typename TIn, typename TOut>
225 TOut
226 swapAssetIn(
227  TAmounts<TIn, TOut> const& pool,
228  TIn const& assetIn,
229  std::uint16_t tfee)
230 {
231  return toAmount<TOut>(
232  getIssue(pool.out),
233  pool.out - (pool.in * pool.out) / (pool.in + assetIn * feeMult(tfee)),
234  Number::rounding_mode::downward);
235 }
236 
246 template <typename TIn, typename TOut>
247 TIn
248 swapAssetOut(
249  TAmounts<TIn, TOut> const& pool,
250  TOut const& assetOut,
251  std::uint16_t tfee)
252 {
253  return toAmount<TIn>(
254  getIssue(pool.in),
255  ((pool.in * pool.out) / (pool.out - assetOut) - pool.in) /
256  feeMult(tfee),
257  Number::rounding_mode::upward);
258 }
259 
262 Number
263 square(Number const& n);
264 
276 STAmount
278  STAmount const& lptAMMBalance,
279  STAmount const& lpTokens,
280  bool isDeposit);
281 
295  STAmount const& amountBalance,
296  STAmount const& amount,
297  std::optional<STAmount> const& amount2,
298  STAmount const& lptAMMBalance,
299  STAmount const& lpTokens,
300  std::uint16_t tfee,
301  bool isDeposit);
302 
306 Number
307 solveQuadraticEq(Number const& a, Number const& b, Number const& c);
308 
309 } // namespace ripple
310 
311 #endif // RIPPLE_APP_MISC_AMMHELPERS_H_INCLUDED
ripple::lpTokensOut
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Definition: AMMHelpers.cpp:90
ripple::root2
Number root2(Number f)
Definition: Number.cpp:689
ripple::solveQuadraticEq
Number solveQuadraticEq(Number const &a, Number const &b, Number const &c)
Definition: AMMHelpers.cpp:201
ripple::lpTokensIn
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Definition: AMMHelpers.cpp:41
ripple::feeMult
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
Definition: AMMCore.h:118
ripple::adjustAmountsByLPTokens
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)
Definition: AMMHelpers.cpp:147
std::tuple
ripple::square
Number square(Number const &n)
Definition: AMMHelpers.cpp:127
ripple::requires
requires(T::ConsequencesFactory==Transactor::Normal) TxConsequences consequences_helper(PreflightContext const &ctx)
Definition: applySteps.cpp:187
ripple::withdrawByTokens
STAmount withdrawByTokens(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Definition: AMMHelpers.cpp:114
ripple::getIssue
Issue getIssue(T const &amt)
Definition: AmountConversions.h:156
std::minmax
T minmax(T... args)
ripple::ammAssetIn
STAmount ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Definition: AMMHelpers.cpp:67
std::uint16_t
std::min
T min(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::ammLPTokens
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Definition: AMMHelpers.cpp:25
std::optional
ripple::keylet::quality
Keylet quality(Keylet const &k, std::uint64_t q) noexcept
The initial directory page for a specific quality.
Definition: Indexes.cpp:238
std::max
T max(T... args)
ripple::adjustLPTokens
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, bool isDeposit)
Definition: AMMHelpers.cpp:133
type_traits