rippled
Loading...
Searching...
No Matches
AMMHelpers.cpp
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#include <xrpld/app/misc/AMMHelpers.h>
21
22namespace ripple {
23
24STAmount
26 STAmount const& asset1,
27 STAmount const& asset2,
28 Issue const& lptIssue)
29{
30 auto const tokens = root2(asset1 * asset2);
31 return toSTAmount(lptIssue, tokens);
32}
33
34/*
35 * Equation 3:
36 * t = T * [(b/B - (sqrt(f2**2 - b/(B*f1)) - f2)) /
37 * (1 + sqrt(f2**2 - b/(B*f1)) - f2)]
38 * where f1 = 1 - tfee, f2 = (1 - tfee/2)/f1
39 */
40STAmount
42 STAmount const& asset1Balance,
43 STAmount const& asset1Deposit,
44 STAmount const& lptAMMBalance,
45 std::uint16_t tfee)
46{
47 auto const f1 = feeMult(tfee);
48 auto const f2 = feeMultHalf(tfee) / f1;
49 Number const r = asset1Deposit / asset1Balance;
50 auto const c = root2(f2 * f2 + r / f1) - f2;
51 auto const t = lptAMMBalance * (r - c) / (1 + c);
52 return toSTAmount(lptAMMBalance.issue(), t);
53}
54
55/* Equation 4 solves equation 3 for b:
56 * Let f1 = 1 - tfee, f2 = (1 - tfee/2)/f1, t1 = t/T, t2 = 1 + t1, R = b/B
57 * then
58 * t1 = [R - sqrt(f2**2 + R/f1) + f2] / [1 + sqrt(f2**2 + R/f1] - f2] =>
59 * sqrt(f2**2 + R/f1)*(t1 + 1) = R + f2 + t1*f2 - t1 =>
60 * sqrt(f2**2 + R/f1)*t2 = R + t2*f2 - t1 =>
61 * sqrt(f2**2 + R/f1) = R/t2 + f2 - t1/t2, let d = f2 - t1/t2 =>
62 * sqrt(f2**2 + R/f1) = R/t2 + d =>
63 * f2**2 + R/f1 = (R/t2)**2 +2*d*R/t2 + d**2 =>
64 * (R/t2)**2 + R*(2*d/t2 - 1/f1) + d**2 - f2**2 = 0
65 */
66STAmount
68 STAmount const& asset1Balance,
69 STAmount const& lptAMMBalance,
70 STAmount const& lpTokens,
71 std::uint16_t tfee)
72{
73 auto const f1 = feeMult(tfee);
74 auto const f2 = feeMultHalf(tfee) / f1;
75 auto const t1 = lpTokens / lptAMMBalance;
76 auto const t2 = 1 + t1;
77 auto const d = f2 - t1 / t2;
78 auto const a = 1 / (t2 * t2);
79 auto const b = 2 * d / t2 - 1 / f1;
80 auto const c = d * d - f2 * f2;
81 return toSTAmount(
82 asset1Balance.issue(), asset1Balance * solveQuadraticEq(a, b, c));
83}
84
85/* Equation 7:
86 * t = T * (c - sqrt(c**2 - 4*R))/2
87 * where R = b/B, c = R*fee + 2 - fee
88 */
89STAmount
91 STAmount const& asset1Balance,
92 STAmount const& asset1Withdraw,
93 STAmount const& lptAMMBalance,
94 std::uint16_t tfee)
95{
96 Number const fr = asset1Withdraw / asset1Balance;
97 auto const f1 = getFee(tfee);
98 auto const c = fr * f1 + 2 - f1;
99 auto const t = lptAMMBalance * (c - root2(c * c - 4 * fr)) / 2;
100 return toSTAmount(lptAMMBalance.issue(), t);
101}
102
103/* Equation 8 solves equation 7 for b:
104 * c - 2*t/T = sqrt(c**2 - 4*R) =>
105 * c**2 - 4*c*t/T + 4*t**2/T**2 = c**2 - 4*R =>
106 * -4*c*t/T + 4*t**2/T**2 = -4*R =>
107 * -c*t/T + t**2/T**2 = -R -=>
108 * substitute c = R*f + 2 - f =>
109 * -(t/T)*(R*f + 2 - f) + (t/T)**2 = -R, let t1 = t/T =>
110 * -t1*R*f -2*t1 +t1*f +t1**2 = -R =>
111 * R = (t1**2 + t1*(f - 2)) / (t1*f - 1)
112 */
113STAmount
115 STAmount const& assetBalance,
116 STAmount const& lptAMMBalance,
117 STAmount const& lpTokens,
118 std::uint16_t tfee)
119{
120 auto const f = getFee(tfee);
121 Number const t1 = lpTokens / lptAMMBalance;
122 auto const b = assetBalance * (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1);
123 return toSTAmount(assetBalance.issue(), b);
124}
125
126Number
127square(Number const& n)
128{
129 return n * n;
130}
131
132STAmount
134 STAmount const& lptAMMBalance,
135 STAmount const& lpTokens,
136 bool isDeposit)
137{
138 // Force rounding downward to ensure adjusted tokens are less or equal
139 // to requested tokens.
141 if (isDeposit)
142 return (lptAMMBalance + lpTokens) - lptAMMBalance;
143 return (lpTokens - lptAMMBalance) + lptAMMBalance;
144}
145
148 STAmount const& amountBalance,
149 STAmount const& amount,
150 std::optional<STAmount> const& amount2,
151 STAmount const& lptAMMBalance,
152 STAmount const& lpTokens,
153 std::uint16_t tfee,
154 bool isDeposit)
155{
156 auto const lpTokensActual =
157 adjustLPTokens(lptAMMBalance, lpTokens, isDeposit);
158
159 if (lpTokensActual == beast::zero)
160 {
161 auto const amount2Opt =
162 amount2 ? std::make_optional(STAmount{}) : std::nullopt;
163 return std::make_tuple(STAmount{}, amount2Opt, lpTokensActual);
164 }
165
166 if (lpTokensActual < lpTokens)
167 {
168 bool const ammRoundingEnabled = [&]() {
169 if (auto const& rules = getCurrentTransactionRules();
170 rules && rules->enabled(fixAMMv1_1))
171 return true;
172 return false;
173 }();
174
175 // Equal trade
176 if (amount2)
177 {
178 Number const fr = lpTokensActual / lpTokens;
179 auto const amountActual = toSTAmount(amount.issue(), fr * amount);
180 auto const amount2Actual =
181 toSTAmount(amount2->issue(), fr * *amount2);
182 if (!ammRoundingEnabled)
183 return std::make_tuple(
184 amountActual < amount ? amountActual : amount,
185 amount2Actual < amount2 ? amount2Actual : amount2,
186 lpTokensActual);
187 else
188 return std::make_tuple(
189 amountActual, amount2Actual, lpTokensActual);
190 }
191
192 // Single trade
193 auto const amountActual = [&]() {
194 if (isDeposit)
195 return ammAssetIn(
196 amountBalance, lptAMMBalance, lpTokensActual, tfee);
197 else if (!ammRoundingEnabled)
198 return withdrawByTokens(
199 amountBalance, lptAMMBalance, lpTokens, tfee);
200 else
201 return withdrawByTokens(
202 amountBalance, lptAMMBalance, lpTokensActual, tfee);
203 }();
204 if (!ammRoundingEnabled)
205 return amountActual < amount
206 ? std::make_tuple(amountActual, std::nullopt, lpTokensActual)
207 : std::make_tuple(amount, std::nullopt, lpTokensActual);
208 else
209 return std::make_tuple(amountActual, std::nullopt, lpTokensActual);
210 }
211
212 XRPL_ASSERT(
213 lpTokensActual == lpTokens,
214 "ripple::adjustAmountsByLPTokens : LP tokens match actual");
215
216 return {amount, amount2, lpTokensActual};
217}
218
219Number
220solveQuadraticEq(Number const& a, Number const& b, Number const& c)
221{
222 return (-b + root2(b * b - 4 * a * c)) / (2 * a);
223}
224
225// Minimize takerGets or takerPays
227solveQuadraticEqSmallest(Number const& a, Number const& b, Number const& c)
228{
229 auto const d = b * b - 4 * a * c;
230 if (d < 0)
231 return std::nullopt;
232 // use numerically stable citardauq formula for quadratic equation solution
233 // https://people.csail.mit.edu/bkph/articles/Quadratics.pdf
234 if (b > 0)
235 return (2 * c) / (-b - root2(d));
236 else
237 return (2 * c) / (-b + root2(d));
238}
239
240} // namespace ripple
A currency issued by an account.
Definition: Issue.h:36
static rounding_mode setround(rounding_mode mode)
Definition: Number.cpp:53
Issue const & issue() const
Definition: STAmount.h:496
T make_optional(T... args)
T make_tuple(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Deposit, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's deposit amount.
Definition: AMMHelpers.cpp:41
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, bool isDeposit)
Adjust LP tokens to deposit/withdraw.
Definition: AMMHelpers.cpp:133
std::optional< Number > solveQuadraticEqSmallest(Number const &a, Number const &b, Number const &c)
Solve quadratic equation to find takerGets or takerPays.
Definition: AMMHelpers.cpp:227
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)
Definition: AMMHelpers.cpp:220
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
STAmount lpTokensOut(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's withdraw amount.
Definition: AMMHelpers.cpp:90
STAmount ammAssetIn(STAmount const &asset1Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset deposit given LP Tokens.
Definition: AMMHelpers.cpp:67
Number square(Number const &n)
Return square of n.
Definition: AMMHelpers.cpp:127
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)
Calls adjustLPTokens() and adjusts deposit or withdraw amounts if the adjusted LP tokens are less tha...
Definition: AMMHelpers.cpp:147
Number feeMult(std::uint16_t tfee)
Get fee multiplier (1 - tfee) @tfee trading fee in basis points.
Definition: AMMCore.h:110
Number getFee(std::uint16_t tfee)
Convert to the fee from the basis points.
Definition: AMMCore.h:101
STAmount ammLPTokens(STAmount const &asset1, STAmount const &asset2, Issue const &lptIssue)
Calculate LP Tokens given AMM pool reserves.
Definition: AMMHelpers.cpp:25
std::optional< Rules > const & getCurrentTransactionRules()
Definition: Rules.cpp:47
Number feeMultHalf(std::uint16_t tfee)
Get fee multiplier (1 - tfee / 2) @tfee trading fee in basis points.
Definition: AMMCore.h:119
STAmount withdrawByTokens(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset withdrawal by tokens.
Definition: AMMHelpers.cpp:114
Number root2(Number f)
Definition: Number.cpp:701