rippled
Loading...
Searching...
No Matches
AMMWithdraw.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#include <xrpld/app/misc/AMMUtils.h>
22#include <xrpld/app/tx/detail/AMMWithdraw.h>
23#include <xrpld/ledger/Sandbox.h>
24
25#include <xrpl/basics/Number.h>
26#include <xrpl/protocol/AMMCore.h>
27#include <xrpl/protocol/TxFlags.h>
28
29namespace ripple {
30
33{
34 if (!ammEnabled(ctx.rules))
35 return temDISABLED;
36
37 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
38 return ret;
39
40 auto const flags = ctx.tx.getFlags();
41 if (flags & tfWithdrawMask)
42 {
43 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid flags.";
44 return temINVALID_FLAG;
45 }
46
47 auto const amount = ctx.tx[~sfAmount];
48 auto const amount2 = ctx.tx[~sfAmount2];
49 auto const ePrice = ctx.tx[~sfEPrice];
50 auto const lpTokens = ctx.tx[~sfLPTokenIn];
51 // Valid combinations are:
52 // LPTokens
53 // tfWithdrawAll
54 // Amount
55 // tfOneAssetWithdrawAll & Amount
56 // Amount and Amount2
57 // Amount and LPTokens
58 // Amount and EPrice
59 if (std::popcount(flags & tfWithdrawSubTx) != 1)
60 {
61 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid flags.";
62 return temMALFORMED;
63 }
64 if (flags & tfLPToken)
65 {
66 if (!lpTokens || amount || amount2 || ePrice)
67 return temMALFORMED;
68 }
69 else if (flags & tfWithdrawAll)
70 {
71 if (lpTokens || amount || amount2 || ePrice)
72 return temMALFORMED;
73 }
74 else if (flags & tfOneAssetWithdrawAll)
75 {
76 if (!amount || lpTokens || amount2 || ePrice)
77 return temMALFORMED;
78 }
79 else if (flags & tfSingleAsset)
80 {
81 if (!amount || lpTokens || amount2 || ePrice)
82 return temMALFORMED;
83 }
84 else if (flags & tfTwoAsset)
85 {
86 if (!amount || !amount2 || lpTokens || ePrice)
87 return temMALFORMED;
88 }
89 else if (flags & tfOneAssetLPToken)
90 {
91 if (!amount || !lpTokens || amount2 || ePrice)
92 return temMALFORMED;
93 }
94 else if (flags & tfLimitLPToken)
95 {
96 if (!amount || !ePrice || lpTokens || amount2)
97 return temMALFORMED;
98 }
99
100 auto const asset = ctx.tx[sfAsset].get<Issue>();
101 auto const asset2 = ctx.tx[sfAsset2].get<Issue>();
102 if (auto const res = invalidAMMAssetPair(asset, asset2))
103 {
104 JLOG(ctx.j.debug()) << "AMM Withdraw: Invalid asset pair.";
105 return res;
106 }
107
108 if (amount && amount2 && amount->issue() == amount2->issue())
109 {
110 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid tokens, same issue."
111 << amount->issue() << " " << amount2->issue();
112 return temBAD_AMM_TOKENS;
113 }
114
115 if (lpTokens && *lpTokens <= beast::zero)
116 {
117 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid tokens.";
118 return temBAD_AMM_TOKENS;
119 }
120
121 if (amount)
122 {
123 if (auto const res = invalidAMMAmount(
124 *amount,
125 std::make_optional(std::make_pair(asset, asset2)),
127 ePrice))
128 {
129 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid Asset1Out";
130 return res;
131 }
132 }
133
134 if (amount2)
135 {
136 if (auto const res = invalidAMMAmount(
137 *amount2, std::make_optional(std::make_pair(asset, asset2))))
138 {
139 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid Asset2OutAmount";
140 return res;
141 }
142 }
143
144 if (ePrice)
145 {
146 if (auto const res = invalidAMMAmount(*ePrice))
147 {
148 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid EPrice";
149 return res;
150 }
151 }
152
153 return preflight2(ctx);
154}
155
158 STAmount const& lpTokens,
159 std::optional<STAmount> const& tokensIn,
160 std::uint32_t flags)
161{
162 if (flags & (tfWithdrawAll | tfOneAssetWithdrawAll))
163 return lpTokens;
164 return tokensIn;
165}
166
167TER
169{
170 auto const accountID = ctx.tx[sfAccount];
171
172 auto const ammSle =
173 ctx.view.read(keylet::amm(ctx.tx[sfAsset], ctx.tx[sfAsset2]));
174 if (!ammSle)
175 {
176 JLOG(ctx.j.debug()) << "AMM Withdraw: Invalid asset pair.";
177 return terNO_AMM;
178 }
179
180 auto const amount = ctx.tx[~sfAmount];
181 auto const amount2 = ctx.tx[~sfAmount2];
182
183 auto const expected = ammHolds(
184 ctx.view,
185 *ammSle,
186 amount ? amount->issue() : std::optional<Issue>{},
187 amount2 ? amount2->issue() : std::optional<Issue>{},
189 ctx.j);
190 if (!expected)
191 return expected.error();
192 auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
193 if (lptAMMBalance == beast::zero)
194 return tecAMM_EMPTY;
195 if (amountBalance <= beast::zero || amount2Balance <= beast::zero ||
196 lptAMMBalance < beast::zero)
197 {
198 JLOG(ctx.j.debug())
199 << "AMM Withdraw: reserves or tokens balance is zero.";
200 return tecINTERNAL; // LCOV_EXCL_LINE
201 }
202
203 auto const ammAccountID = ammSle->getAccountID(sfAccount);
204
205 auto checkAmount = [&](std::optional<STAmount> const& amount,
206 auto const& balance) -> TER {
207 if (amount)
208 {
209 if (amount > balance)
210 {
211 JLOG(ctx.j.debug())
212 << "AMM Withdraw: withdrawing more than the balance, "
213 << *amount;
214 return tecAMM_BALANCE;
215 }
216 if (auto const ter =
217 requireAuth(ctx.view, amount->issue(), accountID))
218 {
219 JLOG(ctx.j.debug())
220 << "AMM Withdraw: account is not authorized, "
221 << amount->issue();
222 return ter;
223 }
224 // AMM account or currency frozen
225 if (isFrozen(ctx.view, ammAccountID, amount->issue()))
226 {
227 JLOG(ctx.j.debug())
228 << "AMM Withdraw: AMM account or currency is frozen, "
229 << to_string(accountID);
230 return tecFROZEN;
231 }
232 // Account frozen
233 if (isIndividualFrozen(ctx.view, accountID, amount->issue()))
234 {
235 JLOG(ctx.j.debug()) << "AMM Withdraw: account is frozen, "
236 << to_string(accountID) << " "
237 << to_string(amount->issue().currency);
238 return tecFROZEN;
239 }
240 }
241 return tesSUCCESS;
242 };
243
244 if (auto const ter = checkAmount(amount, amountBalance))
245 return ter;
246
247 if (auto const ter = checkAmount(amount2, amount2Balance))
248 return ter;
249
250 auto const lpTokens =
251 ammLPHolds(ctx.view, *ammSle, ctx.tx[sfAccount], ctx.j);
252 auto const lpTokensWithdraw =
253 tokensWithdraw(lpTokens, ctx.tx[~sfLPTokenIn], ctx.tx.getFlags());
254
255 if (lpTokens <= beast::zero)
256 {
257 JLOG(ctx.j.debug()) << "AMM Withdraw: tokens balance is zero.";
258 return tecAMM_BALANCE;
259 }
260
261 if (lpTokensWithdraw && lpTokensWithdraw->issue() != lpTokens.issue())
262 {
263 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid LPTokens.";
264 return temBAD_AMM_TOKENS;
265 }
266
267 if (lpTokensWithdraw && *lpTokensWithdraw > lpTokens)
268 {
269 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid tokens.";
271 }
272
273 if (auto const ePrice = ctx.tx[~sfEPrice];
274 ePrice && ePrice->issue() != lpTokens.issue())
275 {
276 JLOG(ctx.j.debug()) << "AMM Withdraw: invalid EPrice.";
277 return temBAD_AMM_TOKENS;
278 }
279
280 if (ctx.tx.getFlags() & (tfLPToken | tfWithdrawAll))
281 {
282 if (auto const ter = checkAmount(amountBalance, amountBalance))
283 return ter;
284 if (auto const ter = checkAmount(amount2Balance, amount2Balance))
285 return ter;
286 }
287
288 return tesSUCCESS;
289}
290
293{
294 auto const amount = ctx_.tx[~sfAmount];
295 auto const amount2 = ctx_.tx[~sfAmount2];
296 auto const ePrice = ctx_.tx[~sfEPrice];
297 auto ammSle = sb.peek(keylet::amm(ctx_.tx[sfAsset], ctx_.tx[sfAsset2]));
298 if (!ammSle)
299 return {tecINTERNAL, false}; // LCOV_EXCL_LINE
300 auto const ammAccountID = (*ammSle)[sfAccount];
301 auto const accountSle = sb.read(keylet::account(ammAccountID));
302 if (!accountSle)
303 return {tecINTERNAL, false}; // LCOV_EXCL_LINE
304 auto const lpTokens =
305 ammLPHolds(ctx_.view(), *ammSle, ctx_.tx[sfAccount], ctx_.journal);
306 auto const lpTokensWithdraw =
307 tokensWithdraw(lpTokens, ctx_.tx[~sfLPTokenIn], ctx_.tx.getFlags());
308
309 // Due to rounding, the LPTokenBalance of the last LP
310 // might not match the LP's trustline balance
311 if (sb.rules().enabled(fixAMMv1_1))
312 {
313 if (auto const res =
314 isOnlyLiquidityProvider(sb, lpTokens.issue(), account_);
315 !res)
316 return {res.error(), false};
317 else if (res.value())
318 {
320 lpTokens,
321 ammSle->getFieldAmount(sfLPTokenBalance),
322 Number{1, -3}))
323 {
324 ammSle->setFieldAmount(sfLPTokenBalance, lpTokens);
325 sb.update(ammSle);
326 }
327 else
328 {
329 return {tecAMM_INVALID_TOKENS, false};
330 }
331 }
332 }
333
334 auto const tfee = getTradingFee(ctx_.view(), *ammSle, account_);
335
336 auto const expected = ammHolds(
337 sb,
338 *ammSle,
339 amount ? amount->issue() : std::optional<Issue>{},
340 amount2 ? amount2->issue() : std::optional<Issue>{},
342 ctx_.journal);
343 if (!expected)
344 return {expected.error(), false};
345 auto const [amountBalance, amount2Balance, lptAMMBalance] = *expected;
346
347 auto const subTxType = ctx_.tx.getFlags() & tfWithdrawSubTx;
348
349 auto const [result, newLPTokenBalance] =
350 [&,
351 &amountBalance = amountBalance,
352 &amount2Balance = amount2Balance,
353 &lptAMMBalance = lptAMMBalance]() -> std::pair<TER, STAmount> {
354 if (subTxType & tfTwoAsset)
355 return equalWithdrawLimit(
356 sb,
357 *ammSle,
358 ammAccountID,
359 amountBalance,
360 amount2Balance,
361 lptAMMBalance,
362 *amount,
363 *amount2,
364 tfee);
365 if (subTxType & tfOneAssetLPToken || subTxType & tfOneAssetWithdrawAll)
367 sb,
368 *ammSle,
369 ammAccountID,
370 amountBalance,
371 lptAMMBalance,
372 *amount,
373 *lpTokensWithdraw,
374 tfee);
375 if (subTxType & tfLimitLPToken)
377 sb,
378 *ammSle,
379 ammAccountID,
380 amountBalance,
381 lptAMMBalance,
382 *amount,
383 *ePrice,
384 tfee);
385 if (subTxType & tfSingleAsset)
386 return singleWithdraw(
387 sb,
388 *ammSle,
389 ammAccountID,
390 amountBalance,
391 lptAMMBalance,
392 *amount,
393 tfee);
394 if (subTxType & tfLPToken || subTxType & tfWithdrawAll)
395 {
396 return equalWithdrawTokens(
397 sb,
398 *ammSle,
399 ammAccountID,
400 amountBalance,
401 amount2Balance,
402 lptAMMBalance,
403 lpTokens,
404 *lpTokensWithdraw,
405 tfee);
406 }
407 // should not happen.
408 // LCOV_EXCL_START
409 JLOG(j_.error()) << "AMM Withdraw: invalid options.";
411 // LCOV_EXCL_STOP
412 }();
413
414 if (result != tesSUCCESS)
415 return {result, false};
416
417 auto const res = deleteAMMAccountIfEmpty(
418 sb,
419 ammSle,
420 newLPTokenBalance,
421 ctx_.tx[sfAsset].get<Issue>(),
422 ctx_.tx[sfAsset2].get<Issue>(),
423 j_);
424 // LCOV_EXCL_START
425 if (!res.second)
426 return {res.first, false};
427 // LCOV_EXCL_STOP
428
429 JLOG(ctx_.journal.trace())
430 << "AMM Withdraw: tokens " << to_string(newLPTokenBalance.iou()) << " "
431 << to_string(lpTokens.iou()) << " " << to_string(lptAMMBalance.iou());
432
433 return {tesSUCCESS, true};
434}
435
436TER
438{
439 // This is the ledger view that we work against. Transactions are applied
440 // as we go on processing transactions.
441 Sandbox sb(&ctx_.view());
442
443 auto const result = applyGuts(sb);
444 if (result.second)
445 sb.apply(ctx_.rawView());
446
447 return result.first;
448}
449
452 Sandbox& view,
453 SLE const& ammSle,
454 AccountID const& ammAccount,
455 STAmount const& amountBalance,
456 STAmount const& amountWithdraw,
457 std::optional<STAmount> const& amount2Withdraw,
458 STAmount const& lpTokensAMMBalance,
459 STAmount const& lpTokensWithdraw,
460 std::uint16_t tfee)
461{
462 TER ter;
463 STAmount newLPTokenBalance;
464 std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) = withdraw(
465 view,
466 ammSle,
467 ammAccount,
468 account_,
469 amountBalance,
470 amountWithdraw,
471 amount2Withdraw,
472 lpTokensAMMBalance,
473 lpTokensWithdraw,
474 tfee,
478 j_);
479 return {ter, newLPTokenBalance};
480}
481
484 Sandbox& view,
485 SLE const& ammSle,
486 AccountID const& ammAccount,
487 AccountID const& account,
488 STAmount const& amountBalance,
489 STAmount const& amountWithdraw,
490 std::optional<STAmount> const& amount2Withdraw,
491 STAmount const& lpTokensAMMBalance,
492 STAmount const& lpTokensWithdraw,
493 std::uint16_t tfee,
494 FreezeHandling freezeHandling,
495 WithdrawAll withdrawAll,
496 XRPAmount const& priorBalance,
497 beast::Journal const& journal)
498{
499 auto const lpTokens = ammLPHolds(view, ammSle, account, journal);
500 auto const expected = ammHolds(
501 view,
502 ammSle,
503 amountWithdraw.issue(),
504 std::nullopt,
505 freezeHandling,
506 journal);
507 // LCOV_EXCL_START
508 if (!expected)
509 return {expected.error(), STAmount{}, STAmount{}, STAmount{}};
510 // LCOV_EXCL_STOP
511 auto const [curBalance, curBalance2, _] = *expected;
512 (void)_;
513
514 auto const
515 [amountWithdrawActual, amount2WithdrawActual, lpTokensWithdrawActual] =
517 if (withdrawAll == WithdrawAll::No)
519 amountBalance,
520 amountWithdraw,
521 amount2Withdraw,
522 lpTokensAMMBalance,
523 lpTokensWithdraw,
524 tfee,
526 return std::make_tuple(
527 amountWithdraw, amount2Withdraw, lpTokensWithdraw);
528 }();
529
530 if (lpTokensWithdrawActual <= beast::zero ||
531 lpTokensWithdrawActual > lpTokens)
532 {
533 JLOG(journal.debug())
534 << "AMM Withdraw: failed to withdraw, invalid LP tokens: "
535 << lpTokensWithdrawActual << " " << lpTokens << " "
536 << lpTokensAMMBalance;
538 }
539
540 // Should not happen since the only LP on last withdraw
541 // has the balance set to the lp token trustline balance.
542 if (view.rules().enabled(fixAMMv1_1) &&
543 lpTokensWithdrawActual > lpTokensAMMBalance)
544 {
545 // LCOV_EXCL_START
546 JLOG(journal.debug())
547 << "AMM Withdraw: failed to withdraw, unexpected LP tokens: "
548 << lpTokensWithdrawActual << " " << lpTokens << " "
549 << lpTokensAMMBalance;
550 return {tecINTERNAL, STAmount{}, STAmount{}, STAmount{}};
551 // LCOV_EXCL_STOP
552 }
553
554 // Withdrawing one side of the pool
555 if ((amountWithdrawActual == curBalance &&
556 amount2WithdrawActual != curBalance2) ||
557 (amount2WithdrawActual == curBalance2 &&
558 amountWithdrawActual != curBalance))
559 {
560 JLOG(journal.debug())
561 << "AMM Withdraw: failed to withdraw one side of the pool "
562 << " curBalance: " << curBalance << " " << amountWithdrawActual
563 << " lpTokensBalance: " << lpTokensWithdraw << " lptBalance "
564 << lpTokensAMMBalance;
565 return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}};
566 }
567
568 // May happen if withdrawing an amount close to one side of the pool
569 if (lpTokensWithdrawActual == lpTokensAMMBalance &&
570 (amountWithdrawActual != curBalance ||
571 amount2WithdrawActual != curBalance2))
572 {
573 JLOG(journal.debug())
574 << "AMM Withdraw: failed to withdraw all tokens "
575 << " curBalance: " << curBalance << " " << amountWithdrawActual
576 << " curBalance2: " << amount2WithdrawActual.value_or(STAmount{0})
577 << " lpTokensBalance: " << lpTokensWithdraw << " lptBalance "
578 << lpTokensAMMBalance;
579 return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}};
580 }
581
582 // Withdrawing more than the pool's balance
583 if (amountWithdrawActual > curBalance ||
584 amount2WithdrawActual > curBalance2)
585 {
586 JLOG(journal.debug())
587 << "AMM Withdraw: withdrawing more than the pool's balance "
588 << " curBalance: " << curBalance << " " << amountWithdrawActual
589 << " curBalance2: " << curBalance2 << " "
590 << (amount2WithdrawActual ? *amount2WithdrawActual : STAmount{})
591 << " lpTokensBalance: " << lpTokensWithdraw << " lptBalance "
592 << lpTokensAMMBalance;
593 return {tecAMM_BALANCE, STAmount{}, STAmount{}, STAmount{}};
594 }
595
596 // Check the reserve in case a trustline has to be created
597 bool const enabledFixAMMv1_2 = view.rules().enabled(fixAMMv1_2);
598 auto sufficientReserve = [&](Issue const& issue) -> TER {
599 if (!enabledFixAMMv1_2 || isXRP(issue))
600 return tesSUCCESS;
601 if (!view.exists(keylet::line(account, issue)))
602 {
603 auto const sleAccount = view.read(keylet::account(account));
604 if (!sleAccount)
605 return tecINTERNAL; // LCOV_EXCL_LINE
606 auto const balance = (*sleAccount)[sfBalance].xrp();
607 std::uint32_t const ownerCount = sleAccount->at(sfOwnerCount);
608
609 // See also SetTrust::doApply()
610 XRPAmount const reserve(
611 (ownerCount < 2) ? XRPAmount(beast::zero)
612 : view.fees().accountReserve(ownerCount + 1));
613
614 if (std::max(priorBalance, balance) < reserve)
616 }
617 return tesSUCCESS;
618 };
619
620 if (auto const err = sufficientReserve(amountWithdrawActual.issue()))
621 return {err, STAmount{}, STAmount{}, STAmount{}};
622
623 // Withdraw amountWithdraw
624 auto res = accountSend(
625 view,
626 ammAccount,
627 account,
628 amountWithdrawActual,
629 journal,
631 if (res != tesSUCCESS)
632 {
633 // LCOV_EXCL_START
634 JLOG(journal.debug())
635 << "AMM Withdraw: failed to withdraw " << amountWithdrawActual;
636 return {res, STAmount{}, STAmount{}, STAmount{}};
637 // LCOV_EXCL_STOP
638 }
639
640 // Withdraw amount2Withdraw
641 if (amount2WithdrawActual)
642 {
643 if (auto const err = sufficientReserve(amount2WithdrawActual->issue());
644 err != tesSUCCESS)
645 return {err, STAmount{}, STAmount{}, STAmount{}};
646
647 res = accountSend(
648 view,
649 ammAccount,
650 account,
651 *amount2WithdrawActual,
652 journal,
654 if (res != tesSUCCESS)
655 {
656 // LCOV_EXCL_START
657 JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw "
658 << *amount2WithdrawActual;
659 return {res, STAmount{}, STAmount{}, STAmount{}};
660 // LCOV_EXCL_STOP
661 }
662 }
663
664 // Withdraw LP tokens
665 res = redeemIOU(
666 view,
667 account,
668 lpTokensWithdrawActual,
669 lpTokensWithdrawActual.issue(),
670 journal);
671 if (res != tesSUCCESS)
672 {
673 // LCOV_EXCL_START
674 JLOG(journal.debug()) << "AMM Withdraw: failed to withdraw LPTokens";
675 return {res, STAmount{}, STAmount{}, STAmount{}};
676 // LCOV_EXCL_STOP
677 }
678
679 return std::make_tuple(
681 lpTokensAMMBalance - lpTokensWithdrawActual,
682 amountWithdrawActual,
683 amount2WithdrawActual);
684}
685
686static STAmount
688 Rules const& rules,
689 STAmount const& lptAMMBalance,
690 STAmount const& lpTokensWithdraw,
691 WithdrawAll withdrawAll)
692{
693 if (!rules.enabled(fixAMMv1_3) || withdrawAll == WithdrawAll::Yes)
694 return lpTokensWithdraw;
695 return adjustLPTokens(lptAMMBalance, lpTokensWithdraw, IsDeposit::No);
696}
697
702 Sandbox& view,
703 SLE const& ammSle,
704 AccountID const& ammAccount,
705 STAmount const& amountBalance,
706 STAmount const& amount2Balance,
707 STAmount const& lptAMMBalance,
708 STAmount const& lpTokens,
709 STAmount const& lpTokensWithdraw,
710 std::uint16_t tfee)
711{
712 TER ter;
713 STAmount newLPTokenBalance;
714 std::tie(ter, newLPTokenBalance, std::ignore, std::ignore) =
716 view,
717 ammSle,
718 account_,
719 ammAccount,
720 amountBalance,
721 amount2Balance,
722 lptAMMBalance,
723 lpTokens,
724 lpTokensWithdraw,
725 tfee,
729 ctx_.journal);
730 return {ter, newLPTokenBalance};
731}
732
735 Sandbox& sb,
736 std::shared_ptr<SLE> const ammSle,
737 STAmount const& lpTokenBalance,
738 Issue const& issue1,
739 Issue const& issue2,
740 beast::Journal const& journal)
741{
742 TER ter;
743 bool updateBalance = true;
744 if (lpTokenBalance == beast::zero)
745 {
746 ter = deleteAMMAccount(sb, issue1, issue2, journal);
747 if (ter != tesSUCCESS && ter != tecINCOMPLETE)
748 return {ter, false}; // LCOV_EXCL_LINE
749 else
750 updateBalance = (ter == tecINCOMPLETE);
751 }
752
753 if (updateBalance)
754 {
755 ammSle->setFieldAmount(sfLPTokenBalance, lpTokenBalance);
756 sb.update(ammSle);
757 }
758
759 return {ter, true};
760}
761
766 Sandbox& view,
767 SLE const& ammSle,
768 AccountID const account,
769 AccountID const& ammAccount,
770 STAmount const& amountBalance,
771 STAmount const& amount2Balance,
772 STAmount const& lptAMMBalance,
773 STAmount const& lpTokens,
774 STAmount const& lpTokensWithdraw,
775 std::uint16_t tfee,
776 FreezeHandling freezeHanding,
777 WithdrawAll withdrawAll,
778 XRPAmount const& priorBalance,
779 beast::Journal const& journal)
780{
781 try
782 {
783 // Withdrawing all tokens in the pool
784 if (lpTokensWithdraw == lptAMMBalance)
785 {
786 return withdraw(
787 view,
788 ammSle,
789 ammAccount,
790 account,
791 amountBalance,
792 amountBalance,
793 amount2Balance,
794 lptAMMBalance,
795 lpTokensWithdraw,
796 tfee,
797 freezeHanding,
799 priorBalance,
800 journal);
801 }
802
803 auto const tokensAdj = adjustLPTokensIn(
804 view.rules(), lptAMMBalance, lpTokensWithdraw, withdrawAll);
805 if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
806 return {
807 tecAMM_INVALID_TOKENS, STAmount{}, STAmount{}, std::nullopt};
808 // the adjusted tokens are factored in
809 auto const frac = divide(tokensAdj, lptAMMBalance, noIssue());
810 auto const amountWithdraw =
811 getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No);
812 auto const amount2Withdraw =
813 getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No);
814 // LP is making equal withdrawal by tokens but the requested amount
815 // of LP tokens is likely too small and results in one-sided pool
816 // withdrawal due to round off. Fail so the user withdraws
817 // more tokens.
818 if (amountWithdraw == beast::zero || amount2Withdraw == beast::zero)
819 return {tecAMM_FAILED, STAmount{}, STAmount{}, STAmount{}};
820
821 return withdraw(
822 view,
823 ammSle,
824 ammAccount,
825 account,
826 amountBalance,
827 amountWithdraw,
828 amount2Withdraw,
829 lptAMMBalance,
830 tokensAdj,
831 tfee,
832 freezeHanding,
833 withdrawAll,
834 priorBalance,
835 journal);
836 }
837 // LCOV_EXCL_START
838 catch (std::exception const& e)
839 {
840 JLOG(journal.error())
841 << "AMMWithdraw::equalWithdrawTokens exception " << e.what();
842 }
843 return {tecINTERNAL, STAmount{}, STAmount{}, STAmount{}};
844 // LCOV_EXCL_STOP
845}
846
874 Sandbox& view,
875 SLE const& ammSle,
876 AccountID const& ammAccount,
877 STAmount const& amountBalance,
878 STAmount const& amount2Balance,
879 STAmount const& lptAMMBalance,
880 STAmount const& amount,
881 STAmount const& amount2,
882 std::uint16_t tfee)
883{
884 auto frac = Number{amount} / amountBalance;
885 auto amount2Withdraw =
886 getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No);
887 auto tokensAdj =
888 getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::No);
889 if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
891 // factor in the adjusted tokens
892 frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac);
893 amount2Withdraw =
894 getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No);
895 if (amount2Withdraw <= amount2)
896 {
897 return withdraw(
898 view,
899 ammSle,
900 ammAccount,
901 amountBalance,
902 amount,
903 amount2Withdraw,
904 lptAMMBalance,
905 tokensAdj,
906 tfee);
907 }
908
909 frac = Number{amount2} / amount2Balance;
910 auto amountWithdraw =
911 getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No);
912 tokensAdj =
913 getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::No);
914 if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
915 return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
916 // factor in the adjusted tokens
917 frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac);
918 amountWithdraw =
919 getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No);
920 if (!view.rules().enabled(fixAMMv1_3))
921 {
922 // LCOV_EXCL_START
923 XRPL_ASSERT(
924 amountWithdraw <= amount,
925 "ripple::AMMWithdraw::equalWithdrawLimit : maximum amountWithdraw");
926 // LCOV_EXCL_STOP
927 }
928 else if (amountWithdraw > amount)
929 return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
930 return withdraw(
931 view,
932 ammSle,
933 ammAccount,
934 amountBalance,
935 amountWithdraw,
936 amount2,
937 lptAMMBalance,
938 tokensAdj,
939 tfee);
940}
941
949 Sandbox& view,
950 SLE const& ammSle,
951 AccountID const& ammAccount,
952 STAmount const& amountBalance,
953 STAmount const& lptAMMBalance,
954 STAmount const& amount,
955 std::uint16_t tfee)
956{
957 auto const tokens = adjustLPTokensIn(
958 view.rules(),
959 lptAMMBalance,
960 lpTokensIn(amountBalance, amount, lptAMMBalance, tfee),
962 if (tokens == beast::zero)
963 {
964 if (!view.rules().enabled(fixAMMv1_3))
965 return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
966 else
968 }
969 // factor in the adjusted tokens
970 auto const [tokensAdj, amountWithdrawAdj] = adjustAssetOutByTokens(
971 view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee);
972 if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
973 return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
974 return withdraw(
975 view,
976 ammSle,
977 ammAccount,
978 amountBalance,
979 amountWithdrawAdj,
980 std::nullopt,
981 lptAMMBalance,
982 tokensAdj,
983 tfee);
984}
985
998 Sandbox& view,
999 SLE const& ammSle,
1000 AccountID const& ammAccount,
1001 STAmount const& amountBalance,
1002 STAmount const& lptAMMBalance,
1003 STAmount const& amount,
1004 STAmount const& lpTokensWithdraw,
1005 std::uint16_t tfee)
1006{
1007 auto const tokensAdj = adjustLPTokensIn(
1008 view.rules(), lptAMMBalance, lpTokensWithdraw, isWithdrawAll(ctx_.tx));
1009 if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
1010 return {tecAMM_INVALID_TOKENS, STAmount{}};
1011 // the adjusted tokens are factored in
1012 auto const amountWithdraw =
1013 ammAssetOut(amountBalance, lptAMMBalance, tokensAdj, tfee);
1014 if (amount == beast::zero || amountWithdraw >= amount)
1015 {
1016 return withdraw(
1017 view,
1018 ammSle,
1019 ammAccount,
1020 amountBalance,
1021 amountWithdraw,
1022 std::nullopt,
1023 lptAMMBalance,
1024 tokensAdj,
1025 tfee);
1026 }
1027
1028 return {tecAMM_FAILED, STAmount{}};
1029}
1030
1052 Sandbox& view,
1053 SLE const& ammSle,
1054 AccountID const& ammAccount,
1055 STAmount const& amountBalance,
1056 STAmount const& lptAMMBalance,
1057 STAmount const& amount,
1058 STAmount const& ePrice,
1059 std::uint16_t tfee)
1060{
1061 // LPTokens is asset in => E = t / a and formula (8) is:
1062 // a = A*(t1**2 + t1*(f - 2))/(t1*f - 1)
1063 // substitute a as t/E =>
1064 // t/E = A*(t1**2 + t1*(f - 2))/(t1*f - 1), t1=t/T => t = t1*T
1065 // t1*T/E = A*((t/T)**2 + t*(f - 2)/T)/(t*f/T - 1) =>
1066 // T/E = A*(t1 + f-2)/(t1*f - 1) =>
1067 // T*(t1*f - 1) = A*E*(t1 + f - 2) =>
1068 // t1*T*f - T = t1*A*E + A*E*(f - 2) =>
1069 // t1*(T*f - A*E) = T + A*E*(f - 2) =>
1070 // t = T*(T + A*E*(f - 2))/(T*f - A*E)
1071 Number const ae = amountBalance * ePrice;
1072 auto const f = getFee(tfee);
1073 auto tokNoRoundCb = [&] {
1074 return lptAMMBalance * (lptAMMBalance + ae * (f - 2)) /
1075 (lptAMMBalance * f - ae);
1076 };
1077 auto tokProdCb = [&] {
1078 return (lptAMMBalance + ae * (f - 2)) / (lptAMMBalance * f - ae);
1079 };
1080 auto const tokensAdj = getRoundedLPTokens(
1081 view.rules(), tokNoRoundCb, lptAMMBalance, tokProdCb, IsDeposit::No);
1082 if (tokensAdj <= beast::zero)
1083 {
1084 if (!view.rules().enabled(fixAMMv1_3))
1085 return {tecAMM_FAILED, STAmount{}};
1086 else
1087 return {tecAMM_INVALID_TOKENS, STAmount{}};
1088 }
1089 auto amtNoRoundCb = [&] { return tokensAdj / ePrice; };
1090 auto amtProdCb = [&] { return tokensAdj / ePrice; };
1091 // the adjusted tokens are factored in
1092 auto const amountWithdraw = getRoundedAsset(
1093 view.rules(), amtNoRoundCb, amount, amtProdCb, IsDeposit::No);
1094 if (amount == beast::zero || amountWithdraw >= amount)
1095 {
1096 return withdraw(
1097 view,
1098 ammSle,
1099 ammAccount,
1100 amountBalance,
1101 amountWithdraw,
1102 std::nullopt,
1103 lptAMMBalance,
1104 tokensAdj,
1105 tfee);
1106 }
1107
1108 return {tecAMM_FAILED, STAmount{}};
1109}
1110
1113{
1114 if (tx[sfFlags] & (tfWithdrawAll | tfOneAssetWithdrawAll))
1115 return WithdrawAll::Yes;
1116 return WithdrawAll::No;
1117}
1118} // namespace ripple
A generic endpoint for log messages.
Definition: Journal.h:60
Stream error() const
Definition: Journal.h:346
Stream debug() const
Definition: Journal.h:328
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
static WithdrawAll isWithdrawAll(STTx const &tx)
Check from the flags if it's withdraw all.
std::pair< TER, STAmount > singleWithdrawEPrice(Sandbox &view, SLE const &ammSle, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &lptAMMBalance, STAmount const &amount, STAmount const &ePrice, std::uint16_t tfee)
Withdraw single asset (Asset1Out, EPrice) with two constraints.
std::pair< TER, STAmount > equalWithdrawLimit(Sandbox &view, SLE const &ammSle, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount2Balance, STAmount const &lptAMMBalance, STAmount const &amount, STAmount const &amount2, std::uint16_t tfee)
Withdraw both assets (Asset1Out, Asset2Out) with the constraints on the maximum amount of each asset ...
static std::tuple< TER, STAmount, STAmount, std::optional< STAmount > > equalWithdrawTokens(Sandbox &view, SLE const &ammSle, AccountID const account, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &amount2Balance, STAmount const &lptAMMBalance, STAmount const &lpTokens, STAmount const &lpTokensWithdraw, std::uint16_t tfee, FreezeHandling freezeHanding, WithdrawAll withdrawAll, XRPAmount const &priorBalance, beast::Journal const &journal)
Equal-asset withdrawal (LPTokens) of some AMM instance pools shares represented by the number of LPTo...
std::pair< TER, bool > applyGuts(Sandbox &view)
std::pair< TER, STAmount > singleWithdraw(Sandbox &view, SLE const &ammSle, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &lptAMMBalance, STAmount const &amount, std::uint16_t tfee)
Single asset withdrawal (Asset1Out) equivalent to the amount specified in Asset1Out.
static std::pair< TER, bool > deleteAMMAccountIfEmpty(Sandbox &sb, std::shared_ptr< SLE > const ammSle, STAmount const &lpTokenBalance, Issue const &issue1, Issue const &issue2, beast::Journal const &journal)
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
Definition: AMMWithdraw.cpp:32
static std::tuple< TER, STAmount, STAmount, std::optional< STAmount > > withdraw(Sandbox &view, SLE const &ammSle, AccountID const &ammAccount, AccountID const &account, STAmount const &amountBalance, STAmount const &amountWithdraw, std::optional< STAmount > const &amount2Withdraw, STAmount const &lpTokensAMMBalance, STAmount const &lpTokensWithdraw, std::uint16_t tfee, FreezeHandling freezeHandling, WithdrawAll withdrawAll, XRPAmount const &priorBalance, beast::Journal const &journal)
Withdraw requested assets and token from AMM into LP account.
TER doApply() override
std::pair< TER, STAmount > singleWithdrawTokens(Sandbox &view, SLE const &ammSle, AccountID const &ammAccount, STAmount const &amountBalance, STAmount const &lptAMMBalance, STAmount const &amount, STAmount const &lpTokensWithdraw, std::uint16_t tfee)
Single asset withdrawal (Asset1Out, LPTokens) proportional to the share specified by tokens.
RawView & rawView()
Definition: ApplyContext.h:91
ApplyView & view()
Definition: ApplyContext.h:78
beast::Journal const journal
Definition: ApplyContext.h:75
A currency issued by an account.
Definition: Issue.h:36
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual Rules const & rules() const =0
Returns the tx processing rules.
Rules controlling protocol behavior.
Definition: Rules.h:38
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition: Rules.cpp:130
Issue const & issue() const
Definition: STAmount.h:496
std::uint32_t getFlags() const
Definition: STObject.cpp:537
Discardable, editable view to a ledger.
Definition: Sandbox.h:35
void apply(RawView &to)
Definition: Sandbox.h:55
AccountID const account_
Definition: Transactor.h:143
ApplyView & view()
Definition: Transactor.h:159
beast::Journal const j_
Definition: Transactor.h:141
XRPAmount mPriorBalance
Definition: Transactor.h:144
ApplyContext & ctx_
Definition: Transactor.h:140
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
Rules const & rules() const override
Returns the tx processing rules.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
T make_optional(T... args)
T make_pair(T... args)
T make_tuple(T... args)
T max(T... args)
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Definition: Indexes.cpp:446
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition: Indexes.cpp:244
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:184
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
constexpr std::uint32_t tfSingleAsset
Definition: TxFlags.h:217
NotTEC invalidAMMAmount(STAmount const &amount, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt, bool validZero=false)
Validate the amount.
Definition: AMMCore.cpp:95
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:93
constexpr std::uint32_t tfOneAssetWithdrawAll
Definition: TxFlags.h:216
WithdrawAll
AMMWithdraw implements AMM withdraw Transactor.
Definition: AMMWithdraw.h:67
FreezeHandling
Controls the treatment of frozen account balances.
Definition: View.h:78
@ fhZERO_IF_FROZEN
Definition: View.h:78
@ fhIGNORE_FREEZE
Definition: View.h:78
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
bool isIndividualFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:215
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Definition: AMMUtils.cpp:178
constexpr std::uint32_t tfWithdrawMask
Definition: TxFlags.h:228
TER deleteAMMAccount(Sandbox &view, Issue const &asset, Issue const &asset2, beast::Journal j)
Delete trustlines to AMM.
Definition: AMMUtils.cpp:282
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:2288
std::pair< STAmount, STAmount > adjustAssetOutByTokens(Rules const &rules, STAmount const &balance, STAmount const &amount, STAmount const &lptAMMBalance, STAmount const &tokens, std::uint16_t tfee)
Definition: AMMHelpers.cpp:375
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:2172
constexpr std::uint32_t tfLimitLPToken
Definition: TxFlags.h:220
bool ammEnabled(Rules const &)
Return true if required AMM amendments are enabled.
Definition: AMMCore.cpp:129
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
Definition: Transactor.cpp:91
constexpr std::uint32_t tfOneAssetLPToken
Definition: TxFlags.h:219
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.
Definition: AMMUtils.cpp:386
STAmount getRoundedLPTokens(Rules const &rules, STAmount const &balance, Number const &frac, IsDeposit isDeposit)
Round AMM deposit/withdrawal LPToken amount.
Definition: AMMHelpers.cpp:311
static std::optional< STAmount > tokensWithdraw(STAmount const &lpTokens, std::optional< STAmount > const &tokensIn, std::uint32_t flags)
bool isFrozen(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer)
Definition: View.cpp:249
STAmount adjustLPTokens(STAmount const &lptAMMBalance, STAmount const &lpTokens, IsDeposit isDeposit)
Adjust LP tokens to deposit/withdraw.
Definition: AMMHelpers.cpp:173
constexpr std::uint32_t tfTwoAsset
Definition: TxFlags.h:218
STAmount ammLPHolds(ReadView const &view, Currency const &cur1, Currency const &cur2, AccountID const &ammAccount, AccountID const &lpAccount, beast::Journal const j)
Get the balance of LP tokens.
Definition: AMMUtils.cpp:112
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...
Definition: AMMHelpers.cpp:187
constexpr std::uint32_t tfWithdrawAll
Definition: TxFlags.h:215
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
Definition: Transactor.cpp:160
static STAmount adjustLPTokensIn(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &lpTokensWithdraw, WithdrawAll withdrawAll)
STAmount ammAssetOut(STAmount const &assetBalance, STAmount const &lptAMMBalance, STAmount const &lpTokens, std::uint16_t tfee)
Calculate asset withdrawal by tokens.
Definition: AMMHelpers.cpp:145
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:126
@ tecINCOMPLETE
Definition: TER.h:335
@ tecFROZEN
Definition: TER.h:303
@ tecAMM_EMPTY
Definition: TER.h:332
@ tecINTERNAL
Definition: TER.h:310
@ tecAMM_FAILED
Definition: TER.h:330
@ tecAMM_INVALID_TOKENS
Definition: TER.h:331
@ tecAMM_BALANCE
Definition: TER.h:329
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:307
constexpr std::uint32_t tfLPToken
Definition: TxFlags.h:214
Number getFee(std::uint16_t tfee)
Convert to the fee from the basis points.
Definition: AMMCore.h:101
@ tesSUCCESS
Definition: TER.h:244
NotTEC invalidAMMAssetPair(Issue const &issue1, Issue const &issue2, std::optional< std::pair< Issue, Issue > > const &pair=std::nullopt)
Definition: AMMCore.cpp:80
bool isTesSuccess(TER x) noexcept
Definition: TER.h:672
Expected< std::tuple< STAmount, STAmount, STAmount >, TER > ammHolds(ReadView const &view, SLE const &ammSle, std::optional< Issue > const &optIssue1, std::optional< Issue > const &optIssue2, FreezeHandling freezeHandling, beast::Journal const j)
Get AMM pool and LP token balances.
Definition: AMMUtils.cpp:46
constexpr std::uint32_t tfWithdrawSubTx
Definition: TxFlags.h:222
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
STAmount lpTokensIn(STAmount const &asset1Balance, STAmount const &asset1Withdraw, STAmount const &lptAMMBalance, std::uint16_t tfee)
Calculate LP Tokens given asset's withdraw amount.
Definition: AMMHelpers.cpp:112
@ terNO_AMM
Definition: TER.h:227
TERSubset< CanCvtToTER > TER
Definition: TER.h:643
STAmount getRoundedAsset(Rules const &rules, STAmount const &balance, A const &frac, IsDeposit isDeposit)
Round AMM equal deposit/withdrawal amount.
Definition: AMMHelpers.h:678
bool withinRelativeDistance(Quality const &calcQuality, Quality const &reqQuality, Number const &dist)
Check if the relative distance between the qualities is within the requested distance.
Definition: AMMHelpers.h:129
Number adjustFracByTokens(Rules const &rules, STAmount const &lptAMMBalance, STAmount const &tokens, Number const &frac)
Find a fraction of tokens after the tokens are adjusted.
Definition: AMMHelpers.cpp:401
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
Definition: View.cpp:1998
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:603
@ temMALFORMED
Definition: TER.h:87
@ temBAD_AMM_TOKENS
Definition: TER.h:129
@ temINVALID_FLAG
Definition: TER.h:111
@ temDISABLED
Definition: TER.h:114
T popcount(T... args)
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
Definition: protocol/Fees.h:49
State information when determining if a tx is likely to claim a fee.
Definition: Transactor.h:79
ReadView const & view
Definition: Transactor.h:82
beast::Journal const j
Definition: Transactor.h:87
State information when preflighting a tx.
Definition: Transactor.h:34
beast::Journal const j
Definition: Transactor.h:41
T tie(T... args)
T what(T... args)