From 1ea0727d5f079476c999a9302084ceaab96de88c Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Thu, 14 Nov 2024 08:26:50 -0500 Subject: [PATCH] Add IsDeposit enum. Update tests. Cnange swap error allowance back to 10e-7. --- src/test/app/AMM_test.cpp | 99 +++++++++++----------- src/xrpld/app/misc/AMMHelpers.h | 78 +++++++++++++---- src/xrpld/app/misc/detail/AMMHelpers.cpp | 44 ++++------ src/xrpld/app/tx/detail/AMMBid.cpp | 4 +- src/xrpld/app/tx/detail/AMMDeposit.cpp | 48 +++++------ src/xrpld/app/tx/detail/AMMWithdraw.cpp | 42 ++++----- src/xrpld/app/tx/detail/InvariantCheck.cpp | 2 +- 7 files changed, 175 insertions(+), 142 deletions(-) diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index 337c6611784..e439ddd7f7f 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -2138,14 +2138,22 @@ struct AMM_test : public jtx::AMMTest // Withdraw close to one side of the pool. Account's LP tokens // are rounded to all LP tokens. - testAMM([&](AMM& ammAlice, Env&) { - ammAlice.withdraw( - alice, - STAmount{USD, UINT64_C(9'999'999999999999), -12}, - std::nullopt, - std::nullopt, - ter(tecAMM_BALANCE)); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { + auto const err = env.enabled(fixAMMv1_3) + ? ter(tecINVARIANT_FAILED) + : ter(tecAMM_BALANCE); + ammAlice.withdraw( + alice, + STAmount{USD, UINT64_C(9'999'999999999999), -12}, + std::nullopt, + std::nullopt, + err); + }, + std::nullopt, + 0, + std::nullopt, + {all, all - fixAMMv1_3}); // Tiny withdraw testAMM([&](AMM& ammAlice, Env&) { @@ -3155,30 +3163,15 @@ struct AMM_test : public jtx::AMMTest } else { - if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'499'00572620544), -11)); - else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'499'00572620543), -11)); - if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(bob, USD) == - STAmount(USD, UINT64_C(18'999'00572616194), -11)); - else - BEAST_EXPECT( - env.balance(bob, USD) == - STAmount(USD, UINT64_C(18'999'00572616191), -11)); - if (!features[fixAMMv1_3]) - BEAST_EXPECT( - env.balance(ed, USD) == - STAmount(USD, UINT64_C(18'999'0057261184), -10)); - else - BEAST_EXPECT( - env.balance(ed, USD) == - STAmount(USD, UINT64_C(18'999'00572611839), -11)); + BEAST_EXPECT( + env.balance(carol, USD) == + STAmount(USD, UINT64_C(29'499'00572620544), -11)); + BEAST_EXPECT( + env.balance(bob, USD) == + STAmount(USD, UINT64_C(18'999'00572616194), -11)); + BEAST_EXPECT( + env.balance(ed, USD) == + STAmount(USD, UINT64_C(18'999'0057261184), -10)); // USD pool is slightly higher because of the fees. if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( @@ -3188,7 +3181,7 @@ struct AMM_test : public jtx::AMMTest else BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'003}, - STAmount(USD, UINT64_C(13'002'98282151427), -11), + STAmount(USD, UINT64_C(13'002'98282151422), -11), ammTokens)); } ammTokens = ammAlice.getLPTokensBalance(); @@ -3238,7 +3231,7 @@ struct AMM_test : public jtx::AMMTest else BEAST_EXPECT( env.balance(dan, USD) == - STAmount(USD, UINT64_C(19'490'05672274393), -11)); + STAmount(USD, UINT64_C(19'490'05672274398), -11)); // USD pool gains more in dan's fees. if (!features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( @@ -3248,7 +3241,7 @@ struct AMM_test : public jtx::AMMTest else BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'003}, - STAmount{USD, UINT64_C(13'012'92609877034), -11}, + STAmount{USD, UINT64_C(13'012'92609877024), -11}, ammTokens)); // Discounted fee payment ammAlice.deposit(carol, USD(100)); @@ -3261,7 +3254,7 @@ struct AMM_test : public jtx::AMMTest else BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'003}, - STAmount{USD, UINT64_C(13'112'92609877034), -11}, + STAmount{USD, UINT64_C(13'112'92609877024), -11}, ammTokens)); env(pay(carol, bob, USD(100)), path(~USD), @@ -3277,7 +3270,7 @@ struct AMM_test : public jtx::AMMTest else BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'100'000'671}, - STAmount{USD, UINT64_C(13'012'92609877034), -11}, + STAmount{USD, UINT64_C(13'012'92609877024), -11}, ammTokens)); } // Payment with the trading fee @@ -3304,7 +3297,7 @@ struct AMM_test : public jtx::AMMTest { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'671}, - STAmount{USD, UINT64_C(13'114'03663044947), -11}, + STAmount{USD, UINT64_C(13'114'03663044937), -11}, ammTokens)); } // Auction slot expired, no discounted fee @@ -3319,10 +3312,6 @@ struct AMM_test : public jtx::AMMTest BEAST_EXPECT( env.balance(carol, USD) == STAmount(USD, UINT64_C(29'399'00572620544), -11)); - else - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'399'00572620543), -11)); ammTokens = ammAlice.getLPTokensBalance(); for (int i = 0; i < 10; ++i) { @@ -3355,10 +3344,10 @@ struct AMM_test : public jtx::AMMTest { BEAST_EXPECT( env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'389'06197177119), -11)); + STAmount(USD, UINT64_C(29'389'06197177129), -11)); BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'671}, - STAmount{USD, UINT64_C(13'123'98038488371), -11}, + STAmount{USD, UINT64_C(13'123'98038488352), -11}, ammTokens)); } env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); @@ -3384,7 +3373,7 @@ struct AMM_test : public jtx::AMMTest { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(13'100'824'793), - STAmount{USD, UINT64_C(13'023'98038488371), -11}, + STAmount{USD, UINT64_C(13'023'98038488352), -11}, ammTokens)); } }, @@ -5394,12 +5383,17 @@ struct AMM_test : public jtx::AMMTest // Due to round off some accounts have a tiny gain, while // other have a tiny loss. The last account to withdraw // gets everything in the pool. - if (!features[fixAMMv1_1] || features[fixAMMv1_3]) + if (!features[fixAMMv1_1] && !features[fixAMMv1_3]) BEAST_EXPECT(ammAlice.expectBalances( XRP(10'000), STAmount{USD, UINT64_C(10'000'0000000013), -10}, IOUAmount{10'000'000})); - else if (features[fixAMMv1_1] && !features[fixAMMv1_3]) + else if (features[fixAMMv1_3]) + BEAST_EXPECT(ammAlice.expectBalances( + XRP(10'000), + STAmount{USD, UINT64_C(10'000'0000000003), -10}, + IOUAmount{10'000'000})); + else BEAST_EXPECT(ammAlice.expectBalances( XRP(10'000), USD(10'000), IOUAmount{10'000'000})); BEAST_EXPECT(expectLine(env, ben, USD(1'500'000))); @@ -5431,11 +5425,16 @@ struct AMM_test : public jtx::AMMTest BEAST_EXPECT(expectLine(env, nataly, USD(1'500'000))); ammAlice.withdrawAll(alice); BEAST_EXPECT(!ammAlice.ammExists()); - if (!features[fixAMMv1_1] || features[fixAMMv1_3]) + if (!features[fixAMMv1_1]) BEAST_EXPECT(expectLine( env, alice, STAmount{USD, UINT64_C(30'000'0000000013), -10})); + else if (features[fixAMMv1_3]) + BEAST_EXPECT(expectLine( + env, + alice, + STAmount{USD, UINT64_C(30'000'0000000003), -10})); else BEAST_EXPECT(expectLine(env, alice, USD(30'000))); // alice XRP balance is 30,000initial - 50 ammcreate fee - @@ -5523,8 +5522,8 @@ struct AMM_test : public jtx::AMMTest BEAST_EXPECT(accountBalance(env, chris) == "1999999999790"); BEAST_EXPECT(accountBalance(env, dan) == "1999999999790"); BEAST_EXPECT(accountBalance(env, carol) == "29999999790"); - BEAST_EXPECT(accountBalance(env, ed) == "1999999999791"); - BEAST_EXPECT(accountBalance(env, paul) == "1999999999794"); + BEAST_EXPECT(accountBalance(env, ed) == "1999999999792"); + BEAST_EXPECT(accountBalance(env, paul) == "1999999999793"); BEAST_EXPECT( accountBalance(env, nataly) == "1999999999795"); BEAST_EXPECT(accountBalance(env, alice) == "29950000070"); diff --git a/src/xrpld/app/misc/AMMHelpers.h b/src/xrpld/app/misc/AMMHelpers.h index f291a48d999..31585cdcbbe 100644 --- a/src/xrpld/app/misc/AMMHelpers.h +++ b/src/xrpld/app/misc/AMMHelpers.h @@ -51,6 +51,8 @@ reduceOffer(auto const& amount) } // namespace detail +enum class IsDeposit : bool { Yes, No }; + /** Calculate LP Tokens given AMM pool reserves. * @param asset1 AMM one side of the pool reserve * @param asset2 AMM another side of the pool reserve @@ -611,13 +613,13 @@ square(Number const& n); * withdraw to cancel out the precision loss. * @param lptAMMBalance LPT AMM Balance * @param lpTokens LP tokens to deposit or withdraw - * @param isDeposit true if deposit, false if withdraw + * @param isDeposit Yes if deposit, No if withdraw */ STAmount adjustLPTokens( STAmount const& lptAMMBalance, STAmount const& lpTokens, - bool isDeposit); + IsDeposit isDeposit); /** Calls adjustLPTokens() and adjusts deposit or withdraw amounts if * the adjusted LP tokens are less than the provided LP tokens. @@ -627,7 +629,7 @@ adjustLPTokens( * @param lptAMMBalance LPT AMM Balance * @param lpTokens LP tokens to deposit or withdraw * @param tfee trading fee in basis points - * @param isDeposit true if deposit, false if withdraw + * @param isDeposit Yes if deposit, No if withdraw * @return */ std::tuple, STAmount> @@ -638,7 +640,7 @@ adjustAmountsByLPTokens( STAmount const& lptAMMBalance, STAmount const& lpTokens, std::uint16_t tfee, - bool isDeposit); + IsDeposit isDeposit); /** Positive solution for quadratic equation: * x = (-b + sqrt(b**2 + 4*a*c))/(2*a) @@ -652,30 +654,35 @@ multiply(STAmount const& amount, Number const& frac, Number::rounding_mode rm); namespace detail { inline Number::rounding_mode -getLPTokenRounding(bool isDeposit) +getLPTokenRounding(IsDeposit isDeposit) { // Minimize on deposit, maximize on withdraw to ensure // AMM invariant sqrt(poolAsset1 * poolAsset2) >= LPTokensBalance - return isDeposit ? Number::downward : Number::upward; + return isDeposit == IsDeposit::Yes ? Number::downward : Number::upward; } inline Number::rounding_mode -getAssetRounding(bool isDeposit) +getAssetRounding(IsDeposit isDeposit) { // Maximize on deposit, minimize on withdraw to ensure // AMM invariant sqrt(poolAsset1 * poolAsset2) >= LPTokensBalance - return isDeposit ? Number::upward : Number::downward; + return isDeposit == IsDeposit::Yes ? Number::upward : Number::downward; } } // namespace detail +/** Round AMM equal deposit/withdrawal amount. Deposit/withdrawal formulas + * calculate the amount as a fractional value of the pool balance. The rounding + * takes place on the last step of multiplying the balance by the fraction if + * AMMv1_3 is enabled. + */ template STAmount getRoundedAsset( Rules const& rules, STAmount const& balance, A const& frac, - bool isDeposit) + IsDeposit isDeposit) { if (!rules.enabled(fixAMMv1_3)) { @@ -688,6 +695,14 @@ getRoundedAsset( return multiply(balance, frac, rm); } +/** Round AMM single deposit/withdrawal amount. In this case + * there is no a shared frac value, which is calculated the same way pre/post + * AMMv1_3. The lambda is used to delay evaluation until the function + * is executed so that the calculation is not done twice. noRoundCb() is + * called if AMMv1_3 is disabled. If productOnly is true then the requested + * rounding is set and the result of productCb() is returned. Otherwise + * the balance is multiplied by productCb() with the requested rounding. + */ STAmount getRoundedAsset( Rules const& rules, @@ -695,15 +710,31 @@ getRoundedAsset( STAmount const& balance, std::function&& productCb, bool productOnly, - bool isDeposit); - + IsDeposit isDeposit); + +/** Round AMM deposit/withdrawal LPToken amount. Deposit/withdrawal formulas + * calculate the lptokens as a fractional value of the AMM total lptokens. + * The rounding takes place on the last step of multiplying the balance by + * the fraction if AMMv1_3 is enabled. The tokens are then + * adjusted to factor in the loss in precision (we only keep 16 significant + * digits) when adding the lptokens to the balance. + */ STAmount getRoundedLPTokens( Rules const& rules, STAmount const& balance, Number const& frac, - bool isDeposit); - + IsDeposit isDeposit); + +/** Round AMM single deposit/withdrawal LPToken amount. + * The lambda are used to delay evaluation until the function is executed + * so that the calculations are not done twice. + * noRoundCb() is called if AMMv1_3 is disabled. If productOnly is true then + * the requested rounding is set and the result of productCb() is returned. + * Otherwise the balance is multiplied by productCb() with the requested + * rounding. The tokens are then adjusted to factor in the loss in precision + * (we only keep 16 significant digits) when adding the tokens to the balance. + */ STAmount getRoundedLPTokens( Rules const& rules, @@ -711,8 +742,19 @@ getRoundedLPTokens( STAmount const& lptAMMBalance, std::function&& productCb, bool productOnly, - bool isDeposit); - + IsDeposit isDeposit); + +/* Next two functions adjust asset in/out amount to factor in the adjusted + * lptokens. The lptokens are calculated from the asset in/out. The lptokens are + * then adjusted to factor in the loss in precision. The adjusted lptokens might + * be less than the initially calculated tokens. Therefore, the asset in/out + * must be adjusted. The rounding might result in the adjusted amount being + * greater than the original asset in/out amount. If this happens, + * then the original amount is reduced by the difference in the adjusted amount + * and the original amount. The actual tokens and the actual adjusted amount + * are then recalculated. The minimum of the original and the actual + * adjusted amount is returned. + */ std::pair adjustAssetInByTokens( Rules const& rules, @@ -721,8 +763,7 @@ adjustAssetInByTokens( STAmount const& lptAMMBalance, STAmount const& tokens, std::uint16_t tfee); - -STAmount +std::pair adjustAssetOutByTokens( Rules const& rules, STAmount const& balance, @@ -731,6 +772,9 @@ adjustAssetOutByTokens( STAmount const& tokens, std::uint16_t tfee); +/** Find a fraction of tokens after the tokens are adjusted. The fraction + * is used to adjust equal deposit/withdraw amount. + */ Number adjustFracByTokens( Rules const& rules, diff --git a/src/xrpld/app/misc/detail/AMMHelpers.cpp b/src/xrpld/app/misc/detail/AMMHelpers.cpp index 4a1eeb3bd42..a72d15b7a25 100644 --- a/src/xrpld/app/misc/detail/AMMHelpers.cpp +++ b/src/xrpld/app/misc/detail/AMMHelpers.cpp @@ -173,12 +173,12 @@ STAmount adjustLPTokens( STAmount const& lptAMMBalance, STAmount const& lpTokens, - bool isDeposit) + IsDeposit isDeposit) { // Force rounding downward to ensure adjusted tokens are less or equal // to requested tokens. saveNumberRoundMode rm(Number::setround(Number::rounding_mode::downward)); - if (isDeposit) + if (isDeposit == IsDeposit::Yes) return (lptAMMBalance + lpTokens) - lptAMMBalance; return (lpTokens - lptAMMBalance) + lptAMMBalance; } @@ -191,7 +191,7 @@ adjustAmountsByLPTokens( STAmount const& lptAMMBalance, STAmount const& lpTokens, std::uint16_t tfee, - bool isDeposit) + IsDeposit isDeposit) { // AMMv1_3 amendment adjusts tokens and amounts in deposit/withdraw if (isFeatureEnabled(fixAMMv1_3)) @@ -235,7 +235,7 @@ adjustAmountsByLPTokens( // Single trade auto const amountActual = [&]() { - if (isDeposit) + if (isDeposit == IsDeposit::Yes) return ammAssetIn( amountBalance, lptAMMBalance, lpTokensActual, tfee); else if (!ammRoundingEnabled) @@ -294,7 +294,7 @@ getRoundedAsset( STAmount const& balance, std::function&& productCb, bool productOnly, - bool isDeposit) + IsDeposit isDeposit) { if (!rules.enabled(fixAMMv1_3)) return toSTAmount(balance.issue(), noRoundCb()); @@ -313,7 +313,7 @@ getRoundedLPTokens( Rules const& rules, STAmount const& balance, Number const& frac, - bool isDeposit) + IsDeposit isDeposit) { if (!rules.enabled(fixAMMv1_3)) return toSTAmount(balance.issue(), balance * frac); @@ -330,7 +330,7 @@ getRoundedLPTokens( STAmount const& lptAMMBalance, std::function&& productCb, bool productOnly, - bool isDeposit) + IsDeposit isDeposit) { if (!rules.enabled(fixAMMv1_3)) return toSTAmount(lptAMMBalance.issue(), noRoundCb()); @@ -365,21 +365,15 @@ adjustAssetInByTokens( // in adjust and original amount. Then adjust tokens and deposit amount. if (adjAsset > amount) { - auto const adjAmount = [&] { - NumberRoundModeGuard g(Number::getround()); - Number::setround(Number::downward); - auto const diff = adjAsset - amount; - Number::setround(Number::upward); - return amount - diff; - }(); + auto const adjAmount = amount - (adjAsset - amount); auto const t = lpTokensOut(balance, adjAmount, lptAMMBalance, tfee); - adjTokens = adjustLPTokens(lptAMMBalance, t, /*isDeposit*/ true); - adjAsset = ammAssetIn(balance, lptAMMBalance, tokens, tfee); + adjTokens = adjustLPTokens(lptAMMBalance, t, IsDeposit::Yes); + adjAsset = ammAssetIn(balance, lptAMMBalance, adjTokens, tfee); } return {adjTokens, std::min(amount, adjAsset)}; } -STAmount +std::pair adjustAssetOutByTokens( Rules const& rules, STAmount const& balance, @@ -389,7 +383,7 @@ adjustAssetOutByTokens( std::uint16_t tfee) { if (!rules.enabled(fixAMMv1_3)) - return amount; + return {tokens, amount}; auto adjAsset = ammAssetOut(balance, lptAMMBalance, tokens, tfee); auto adjTokens = tokens; // Rounding didn't work the right way. @@ -397,18 +391,12 @@ adjustAssetOutByTokens( // in adjust and original amount. Then adjust tokens and deposit amount. if (adjAsset > amount) { - auto const adjAmount = [&] { - NumberRoundModeGuard g(Number::getround()); - Number::setround(Number::upward); - auto const diff = adjAsset - amount; - Number::setround(Number::downward); - return amount - diff; - }(); + auto const adjAmount = amount - (adjAsset - amount); auto const t = lpTokensIn(balance, adjAmount, lptAMMBalance, tfee); - adjTokens = adjustLPTokens(lptAMMBalance, t, /*isDeposit*/ false); - adjAsset = ammAssetOut(balance, lptAMMBalance, tokens, tfee); + adjTokens = adjustLPTokens(lptAMMBalance, t, IsDeposit::No); + adjAsset = ammAssetOut(balance, lptAMMBalance, adjTokens, tfee); } - return std::min(amount, ammAssetOut(balance, lptAMMBalance, tokens, tfee)); + return {adjTokens, std::min(amount, adjAsset)}; } Number diff --git a/src/xrpld/app/tx/detail/AMMBid.cpp b/src/xrpld/app/tx/detail/AMMBid.cpp index 64ac9cab9bb..0d8cde7c9bf 100644 --- a/src/xrpld/app/tx/detail/AMMBid.cpp +++ b/src/xrpld/app/tx/detail/AMMBid.cpp @@ -242,7 +242,9 @@ applyBid( auctionSlot.makeFieldAbsent(sfAuthAccounts); // Burn the remaining bid amount auto const saBurn = adjustLPTokens( - lptAMMBalance, toSTAmount(lptAMMBalance.issue(), burn), false); + lptAMMBalance, + toSTAmount(lptAMMBalance.issue(), burn), + IsDeposit::No); if (saBurn >= lptAMMBalance) { // This error case should never occur. diff --git a/src/xrpld/app/tx/detail/AMMDeposit.cpp b/src/xrpld/app/tx/detail/AMMDeposit.cpp index 564bfe94117..c021ab309cc 100644 --- a/src/xrpld/app/tx/detail/AMMDeposit.cpp +++ b/src/xrpld/app/tx/detail/AMMDeposit.cpp @@ -543,7 +543,7 @@ AMMDeposit::deposit( lptAMMBalance, lpTokensDeposit, tfee, - true); + IsDeposit::Yes); if (lpTokensDepositActual <= beast::zero) { @@ -634,7 +634,7 @@ adjustLPTokensOut( { if (!rules.enabled(fixAMMv1_3)) return lpTokensDeposit; - return adjustLPTokens(lptAMMBalance, lpTokensDeposit, /*isDeposit*/ true); + return adjustLPTokens(lptAMMBalance, lpTokensDeposit, IsDeposit::Yes); } /** Proportional deposit of pools assets in exchange for the specified @@ -658,10 +658,10 @@ AMMDeposit::equalDepositTokens( adjustLPTokensOut(view.rules(), lptAMMBalance, lpTokensDeposit); auto const frac = divide(tokens, lptAMMBalance, lptAMMBalance.issue()); // amounts factor in the adjusted tokens - auto const amountDeposit = getRoundedAsset( - view.rules(), amountBalance, frac, /*isDeposit*/ true); - auto const amount2Deposit = getRoundedAsset( - view.rules(), amount2Balance, frac, /*isDeposit*/ true); + auto const amountDeposit = + getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::Yes); + auto const amount2Deposit = + getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::Yes); return deposit( view, ammAccount, @@ -726,8 +726,8 @@ AMMDeposit::equalDepositLimit( std::uint16_t tfee) { auto frac = Number{amount} / amountBalance; - auto tokens = getRoundedLPTokens( - view.rules(), lptAMMBalance, frac, /*isDeposit*/ true); + auto tokens = + getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::Yes); if (tokens == beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) @@ -738,7 +738,7 @@ AMMDeposit::equalDepositLimit( // factor in the adjusted tokens frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokens, frac); auto const amount2Deposit = - getRoundedAsset(view.rules(), amount2Balance, frac, /*isDeposit*/ true); + getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::Yes); if (amount2Deposit <= amount2) return deposit( view, @@ -753,8 +753,8 @@ AMMDeposit::equalDepositLimit( lpTokensDepositMin, tfee); frac = Number{amount2} / amount2Balance; - tokens = getRoundedLPTokens( - view.rules(), lptAMMBalance, frac, /*isDeposit*/ true); + tokens = + getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::Yes); if (tokens == beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) @@ -765,7 +765,7 @@ AMMDeposit::equalDepositLimit( // factor in the adjusted tokens frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokens, frac); auto const amountDeposit = - getRoundedAsset(view.rules(), amountBalance, frac, /*isDeposit*/ true); + getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::Yes); if (amountDeposit <= amount) return deposit( view, @@ -812,16 +812,16 @@ AMMDeposit::singleDeposit( return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens - auto const [tokensActual, amountDeposit] = adjustAssetInByTokens( + auto const [tokensAdj, amountDepositAdj] = adjustAssetInByTokens( view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee); return deposit( view, ammAccount, amountBalance, - amountDeposit, + amountDepositAdj, std::nullopt, lptAMMBalance, - tokensActual, + tokensAdj, std::nullopt, std::nullopt, lpTokensDepositMin, @@ -915,18 +915,18 @@ AMMDeposit::singleDepositEPrice( return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens - auto const [tokensActual, amountDeposit] = adjustAssetInByTokens( + auto const [tokensAdj, amountDepositAdj] = adjustAssetInByTokens( view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee); - auto const ep = Number{amountDeposit} / tokensActual; + auto const ep = Number{amountDepositAdj} / tokensAdj; if (ep <= ePrice) return deposit( view, ammAccount, amountBalance, - amountDeposit, + amountDepositAdj, std::nullopt, lptAMMBalance, - tokensActual, + tokensAdj, std::nullopt, std::nullopt, std::nullopt, @@ -967,7 +967,7 @@ AMMDeposit::singleDepositEPrice( amountBalance, amtProdCb, /*productOnly*/ false, - /*isDeposit*/ true); + IsDeposit::Yes); if (amountDeposit <= beast::zero) return {tecAMM_FAILED, STAmount{}}; auto tokNoRoundCb = [&] { return amountDeposit / ePrice; }; @@ -978,9 +978,9 @@ AMMDeposit::singleDepositEPrice( lptAMMBalance, tokProdCb, /*productOnly*/ true, - /*isDeposit*/ true); + IsDeposit::Yes); // factor in the adjusted tokens - auto const [tokensActual, amountDepositActual] = adjustAssetInByTokens( + auto const [tokensAdj, amountDepositAdj] = adjustAssetInByTokens( view.rules(), amountBalance, amountDeposit, @@ -992,10 +992,10 @@ AMMDeposit::singleDepositEPrice( view, ammAccount, amountBalance, - amountDepositActual, + amountDepositAdj, std::nullopt, lptAMMBalance, - tokensActual, + tokensAdj, std::nullopt, std::nullopt, std::nullopt, diff --git a/src/xrpld/app/tx/detail/AMMWithdraw.cpp b/src/xrpld/app/tx/detail/AMMWithdraw.cpp index 0e11a1b5989..d649f41b1f9 100644 --- a/src/xrpld/app/tx/detail/AMMWithdraw.cpp +++ b/src/xrpld/app/tx/detail/AMMWithdraw.cpp @@ -518,7 +518,7 @@ AMMWithdraw::withdraw( lpTokensAMMBalance, lpTokensWithdraw, tfee, - false); + IsDeposit::No); return std::make_tuple( amountWithdraw, amount2Withdraw, lpTokensWithdraw); }(); @@ -657,7 +657,7 @@ adjustLPTokensIn( { if (!rules.enabled(fixAMMv1_3) || withdrawAll == WithdrawAll::Yes) return lpTokensWithdraw; - return adjustLPTokens(lptAMMBalance, lpTokensWithdraw, /*isDeposit*/ false); + return adjustLPTokens(lptAMMBalance, lpTokensWithdraw, IsDeposit::No); } /** Proportional withdrawal of pool assets for the amount of LPTokens. @@ -766,10 +766,10 @@ AMMWithdraw::equalWithdrawTokens( view.rules(), lptAMMBalance, lpTokensWithdraw, withdrawAll); // the adjusted tokens are factored in auto const frac = divide(tokens, lptAMMBalance, noIssue()); - auto const withdrawAmount = getRoundedAsset( - view.rules(), amountBalance, frac, /*isDeposit*/ false); - auto const withdraw2Amount = getRoundedAsset( - view.rules(), amount2Balance, frac, /*isDeposit*/ false); + auto const withdrawAmount = + getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No); + auto const withdraw2Amount = + getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No); // LP is making equal withdrawal by tokens but the requested amount // of LP tokens is likely too small and results in one-sided pool // withdrawal due to round off. Fail so the user withdraws @@ -840,14 +840,14 @@ AMMWithdraw::equalWithdrawLimit( std::uint16_t tfee) { auto frac = Number{amount} / amountBalance; - auto amount2Withdraw = getRoundedAsset( - view.rules(), amount2Balance, frac, /*isDeposit*/ false); - auto tokens = getRoundedLPTokens( - view.rules(), lptAMMBalance, frac, /*isDeposit*/ false); + auto amount2Withdraw = + getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No); + auto tokens = + getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::No); // factor in the adjusted tokens frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokens, frac); - amount2Withdraw = getRoundedAsset( - view.rules(), amount2Balance, frac, /*isDeposit*/ false); + amount2Withdraw = + getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No); if (amount2Withdraw <= amount2) { return withdraw( @@ -864,13 +864,13 @@ AMMWithdraw::equalWithdrawLimit( frac = Number{amount2} / amount2Balance; auto amountWithdraw = - getRoundedAsset(view.rules(), amountBalance, frac, /*isDeposit*/ false); - tokens = getRoundedLPTokens( - view.rules(), lptAMMBalance, frac, /*isDeposit*/ false); + getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No); + tokens = + getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::No); // factor in the adjusted tokens frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokens, frac); amountWithdraw = - getRoundedAsset(view.rules(), amountBalance, frac, /*isDeposit*/ false); + getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No); if (!view.rules().enabled(fixAMMv1_3)) assert(amountWithdraw <= amount); else if (amountWithdraw > amount) @@ -915,17 +915,17 @@ AMMWithdraw::singleWithdraw( return {tecAMM_INVALID_TOKENS, STAmount{}}; } // factor in the adjusted tokens - auto const amountWithdraw = adjustAssetOutByTokens( + auto const [tokensAdj, amountWithdrawAdj] = adjustAssetOutByTokens( view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee); return withdraw( view, ammSle, ammAccount, amountBalance, - amountWithdraw, + amountWithdrawAdj, std::nullopt, lptAMMBalance, - tokens, + tokensAdj, tfee); } @@ -1027,7 +1027,7 @@ AMMWithdraw::singleWithdrawEPrice( lptAMMBalance, tokProdCb, /*productOnly*/ false, - /*isDeposit*/ false); + IsDeposit::No); if (tokens <= beast::zero) { if (!view.rules().enabled(fixAMMv1_3)) @@ -1044,7 +1044,7 @@ AMMWithdraw::singleWithdrawEPrice( amount, amtProdCb, /*productOnly*/ true, - /*isDeposit*/ false); + IsDeposit::No); if (amount == beast::zero || amountWithdraw >= amount) { return withdraw( diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index 292424d0664..d3d65870af0 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -1299,7 +1299,7 @@ ValidAMM::finalize( balanceAfter_[k][asset] * balanceAfter_[k][asset2]; if (productAfter >= productBefore || withinRelativeDistance( - productBefore, productAfter, Number{1, -11})) + productBefore, productAfter, Number{1, -7})) return true; JLOG(j.error())