From 3ff7f34d7cb5bc6ef14b6aaa499f15813f1d6ed2 Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Sat, 4 May 2024 18:50:59 -0400 Subject: [PATCH] Fix adjustAmountsByLPTokens(): The fix is to return the actual adjusted lp tokens and amounts by the function. --- src/ripple/app/misc/impl/AMMHelpers.cpp | 33 +- src/test/app/AMMExtended_test.cpp | 20 +- src/test/app/AMM_test.cpp | 406 ++++++++++++++++-------- src/test/jtx/AMMTest.h | 2 +- src/test/jtx/impl/AMMTest.cpp | 67 ++-- 5 files changed, 338 insertions(+), 190 deletions(-) diff --git a/src/ripple/app/misc/impl/AMMHelpers.cpp b/src/ripple/app/misc/impl/AMMHelpers.cpp index 57b3d3a07..33669dcdc 100644 --- a/src/ripple/app/misc/impl/AMMHelpers.cpp +++ b/src/ripple/app/misc/impl/AMMHelpers.cpp @@ -165,6 +165,13 @@ adjustAmountsByLPTokens( if (lpTokensActual < lpTokens) { + bool const ammRoundingEnabled = [&]() { + if (auto const& rules = getCurrentTransactionRules(); + rules && rules->enabled(fixAMMRounding)) + return true; + return false; + }(); + // Equal trade if (amount2) { @@ -172,10 +179,14 @@ adjustAmountsByLPTokens( auto const amountActual = toSTAmount(amount.issue(), fr * amount); auto const amount2Actual = toSTAmount(amount2->issue(), fr * *amount2); - return std::make_tuple( - amountActual < amount ? amountActual : amount, - amount2Actual < amount2 ? amount2Actual : amount2, - lpTokensActual); + if (!ammRoundingEnabled) + return std::make_tuple( + amountActual < amount ? amountActual : amount, + amount2Actual < amount2 ? amount2Actual : amount2, + lpTokensActual); + else + return std::make_tuple( + amountActual, amount2Actual, lpTokensActual); } // Single trade @@ -183,13 +194,19 @@ adjustAmountsByLPTokens( if (isDeposit) return ammAssetIn( amountBalance, lptAMMBalance, lpTokensActual, tfee); - else + else if (!ammRoundingEnabled) return withdrawByTokens( amountBalance, lptAMMBalance, lpTokens, tfee); + else + return withdrawByTokens( + amountBalance, lptAMMBalance, lpTokensActual, tfee); }(); - return amountActual < amount - ? std::make_tuple(amountActual, std::nullopt, lpTokensActual) - : std::make_tuple(amount, std::nullopt, lpTokensActual); + if (!ammRoundingEnabled) + return amountActual < amount + ? std::make_tuple(amountActual, std::nullopt, lpTokensActual) + : std::make_tuple(amount, std::nullopt, lpTokensActual); + else + return std::make_tuple(amountActual, std::nullopt, lpTokensActual); } assert(lpTokensActual == lpTokens); diff --git a/src/test/app/AMMExtended_test.cpp b/src/test/app/AMMExtended_test.cpp index d5803271e..c2060d572 100644 --- a/src/test/app/AMMExtended_test.cpp +++ b/src/test/app/AMMExtended_test.cpp @@ -233,7 +233,7 @@ private: {{XRP(10'100), USD(10'000)}}, 0, std::nullopt, - tweakedFeatures); + {tweakedFeatures}); // Immediate or Cancel - cross as much as possible // and add nothing on the books. @@ -257,7 +257,7 @@ private: {{XRP(10'100), USD(10'000)}}, 0, std::nullopt, - tweakedFeatures); + {tweakedFeatures}); // tfPassive -- place the offer without crossing it. testAMM( @@ -274,7 +274,7 @@ private: {{XRP(10'100), USD(10'000)}}, 0, std::nullopt, - tweakedFeatures); + {tweakedFeatures}); // tfPassive -- cross only offers of better quality. testAMM( @@ -296,7 +296,7 @@ private: {{XRP(11'000), USD(9'000)}}, 0, std::nullopt, - tweakedFeatures); + {tweakedFeatures}); } } @@ -430,7 +430,7 @@ private: {{XRP(10'000), USD(10'000)}}, 0, std::nullopt, - features); + {features}); } void @@ -453,7 +453,7 @@ private: {{XRP(10'000), USD(10'100)}}, 0, std::nullopt, - features); + {features}); } void @@ -477,7 +477,7 @@ private: {{XRP(10'100), USD(10'000)}}, 0, std::nullopt, - features); + {features}); } void @@ -643,7 +643,7 @@ private: {{XRP(9'900), USD(10'100)}}, 0, std::nullopt, - features); + {features}); } void @@ -952,7 +952,7 @@ private: {{XRP(10'000), USD(10'100)}}, 0, std::nullopt, - features); + {features}); // Reverse the order, so the offer in the books is to sell XRP // in return for USD. @@ -973,7 +973,7 @@ private: {{XRP(10'100), USD(10'000)}}, 0, std::nullopt, - features); + {features}); { // Bridged crossing. diff --git a/src/test/app/AMM_test.cpp b/src/test/app/AMM_test.cpp index baa39ae43..4bba05683 100644 --- a/src/test/app/AMM_test.cpp +++ b/src/test/app/AMM_test.cpp @@ -2215,33 +2215,64 @@ private: IOUAmount{10'000'000, 0})); }); + auto const all = supported_amendments(); // Withdraw with EPrice limit. - testAMM([&](AMM& ammAlice, Env&) { - ammAlice.deposit(carol, 1'000'000); - ammAlice.withdraw(carol, USD(100), std::nullopt, IOUAmount{520, 0}); - BEAST_EXPECT( - ammAlice.expectBalances( - XRPAmount(11'000'000'000), - STAmount{USD, UINT64_C(9'372'781065088757), -12}, - IOUAmount{10'153'846'15384616, -8}) && - ammAlice.expectLPTokens( - carol, IOUAmount{153'846'15384616, -8})); - ammAlice.withdrawAll(carol); - BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { + ammAlice.deposit(carol, 1'000'000); + ammAlice.withdraw( + carol, USD(100), std::nullopt, IOUAmount{520, 0}); + if (!env.current()->rules().enabled(fixAMMv1_1)) + BEAST_EXPECT( + ammAlice.expectBalances( + XRPAmount(11'000'000'000), + STAmount{USD, UINT64_C(9'372'781065088757), -12}, + IOUAmount{10'153'846'15384616, -8}) && + ammAlice.expectLPTokens( + carol, IOUAmount{153'846'15384616, -8})); + else + BEAST_EXPECT( + ammAlice.expectBalances( + XRPAmount(11'000'000'000), + STAmount{USD, UINT64_C(9'372'781065088769), -12}, + IOUAmount{10'153'846'15384616, -8}) && + ammAlice.expectLPTokens( + carol, IOUAmount{153'846'15384616, -8})); + ammAlice.withdrawAll(carol); + BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0})); + }, + std::nullopt, + 0, + std::nullopt, + {all, all - fixAMMv1_1}); // Withdraw with EPrice limit. AssetOut is 0. - testAMM([&](AMM& ammAlice, Env&) { - ammAlice.deposit(carol, 1'000'000); - ammAlice.withdraw(carol, USD(0), std::nullopt, IOUAmount{520, 0}); - BEAST_EXPECT( - ammAlice.expectBalances( - XRPAmount(11'000'000'000), - STAmount{USD, UINT64_C(9'372'781065088757), -12}, - IOUAmount{10'153'846'15384616, -8}) && - ammAlice.expectLPTokens( - carol, IOUAmount{153'846'15384616, -8})); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { + ammAlice.deposit(carol, 1'000'000); + ammAlice.withdraw( + carol, USD(0), std::nullopt, IOUAmount{520, 0}); + if (!env.current()->rules().enabled(fixAMMv1_1)) + BEAST_EXPECT( + ammAlice.expectBalances( + XRPAmount(11'000'000'000), + STAmount{USD, UINT64_C(9'372'781065088757), -12}, + IOUAmount{10'153'846'15384616, -8}) && + ammAlice.expectLPTokens( + carol, IOUAmount{153'846'15384616, -8})); + else + BEAST_EXPECT( + ammAlice.expectBalances( + XRPAmount(11'000'000'000), + STAmount{USD, UINT64_C(9'372'781065088769), -12}, + IOUAmount{10'153'846'15384616, -8}) && + ammAlice.expectLPTokens( + carol, IOUAmount{153'846'15384616, -8})); + }, + std::nullopt, + 0, + std::nullopt, + {all, all - fixAMMv1_1}); // IOU to IOU + transfer fee { @@ -2904,20 +2935,40 @@ private: ammAlice.withdraw(ed, tokens, USD(0)); } // carol, bob, and ed pay ~0.99USD in fees. - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'499'00572620545), -11)); - BEAST_EXPECT( - env.balance(bob, USD) == - STAmount(USD, UINT64_C(18'999'00572616195), -11)); - BEAST_EXPECT( - env.balance(ed, USD) == - STAmount(USD, UINT64_C(18'999'00572611841), -11)); - // USD pool is slightly higher because of the fees. - BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount(USD, UINT64_C(13'002'98282151419), -11), - ammTokens)); + if (!features[fixAMMv1_1]) + { + BEAST_EXPECT( + env.balance(carol, USD) == + STAmount(USD, UINT64_C(29'499'00572620545), -11)); + BEAST_EXPECT( + env.balance(bob, USD) == + STAmount(USD, UINT64_C(18'999'00572616195), -11)); + BEAST_EXPECT( + env.balance(ed, USD) == + STAmount(USD, UINT64_C(18'999'00572611841), -11)); + // USD pool is slightly higher because of the fees. + BEAST_EXPECT(ammAlice.expectBalances( + XRP(13'000), + STAmount(USD, UINT64_C(13'002'98282151419), -11), + ammTokens)); + } + else + { + 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. + BEAST_EXPECT(ammAlice.expectBalances( + XRP(13'000), + STAmount(USD, UINT64_C(13'002'98282151422), -11), + ammTokens)); + } ammTokens = ammAlice.getLPTokensBalance(); // Trade with the fee for (int i = 0; i < 10; ++i) @@ -2928,29 +2979,62 @@ private: // dan pays ~9.94USD, which is ~10 times more in fees than // carol, bob, ed. the discounted fee is 10 times less // than the trading fee. - BEAST_EXPECT( - env.balance(dan, USD) == - STAmount(USD, UINT64_C(19'490'056722744), -9)); - // USD pool gains more in dan's fees. - BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount{USD, UINT64_C(13'012'92609877019), -11}, - ammTokens)); - // Discounted fee payment - ammAlice.deposit(carol, USD(100)); - ammTokens = ammAlice.getLPTokensBalance(); - BEAST_EXPECT(ammAlice.expectBalances( - XRP(13'000), - STAmount{USD, UINT64_C(13'112'92609877019), -11}, - ammTokens)); - env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); - env.close(); - // carol pays 100000 drops in fees - // 99900668XRP swapped in for 100USD - BEAST_EXPECT(ammAlice.expectBalances( - XRPAmount{13'100'000'668}, - STAmount{USD, UINT64_C(13'012'92609877019), -11}, - ammTokens)); + if (!features[fixAMMv1_1]) + { + BEAST_EXPECT( + env.balance(dan, USD) == + STAmount(USD, UINT64_C(19'490'056722744), -9)); + // USD pool gains more in dan's fees. + BEAST_EXPECT(ammAlice.expectBalances( + XRP(13'000), + STAmount{USD, UINT64_C(13'012'92609877019), -11}, + ammTokens)); + // Discounted fee payment + ammAlice.deposit(carol, USD(100)); + ammTokens = ammAlice.getLPTokensBalance(); + BEAST_EXPECT(ammAlice.expectBalances( + XRP(13'000), + STAmount{USD, UINT64_C(13'112'92609877019), -11}, + ammTokens)); + env(pay(carol, bob, USD(100)), + path(~USD), + sendmax(XRP(110))); + env.close(); + // carol pays 100000 drops in fees + // 99900668XRP swapped in for 100USD + BEAST_EXPECT(ammAlice.expectBalances( + XRPAmount{13'100'000'668}, + STAmount{USD, UINT64_C(13'012'92609877019), -11}, + ammTokens)); + } + else + { + BEAST_EXPECT( + env.balance(dan, USD) == + STAmount(USD, UINT64_C(19'490'05672274399), -11)); + // USD pool gains more in dan's fees. + BEAST_EXPECT(ammAlice.expectBalances( + XRP(13'000), + STAmount{USD, UINT64_C(13'012'92609877023), -11}, + ammTokens)); + // Discounted fee payment + ammAlice.deposit(carol, USD(100)); + ammTokens = ammAlice.getLPTokensBalance(); + BEAST_EXPECT(ammAlice.expectBalances( + XRP(13'000), + STAmount{USD, UINT64_C(13'112'92609877023), -11}, + ammTokens)); + env(pay(carol, bob, USD(100)), + path(~USD), + sendmax(XRP(110))); + env.close(); + // carol pays 100000 drops in fees + // 99900668XRP swapped in for 100USD + BEAST_EXPECT(ammAlice.expectBalances( + XRPAmount{13'100'000'668}, + STAmount{USD, UINT64_C(13'012'92609877023), -11}, + ammTokens)); + } // Payment with the trading fee env(pay(alice, carol, XRP(100)), path(~XRP), sendmax(USD(110))); env.close(); @@ -2968,16 +3052,21 @@ private: { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'668}, - STAmount{USD, UINT64_C(13'114'03663047265), -11}, + STAmount{USD, UINT64_C(13'114'03663047269), -11}, ammTokens)); } // Auction slot expired, no discounted fee env.close(seconds(TOTAL_TIME_SLOT_SECS + 1)); // clock is parent's based env.close(); - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'399'00572620545), -11)); + if (!features[fixAMMv1_1]) + BEAST_EXPECT( + env.balance(carol, USD) == + STAmount(USD, UINT64_C(29'399'00572620545), -11)); + else + BEAST_EXPECT( + env.balance(carol, USD) == + STAmount(USD, UINT64_C(29'399'00572620544), -11)); ammTokens = ammAlice.getLPTokensBalance(); for (int i = 0; i < 10; ++i) { @@ -3000,10 +3089,10 @@ private: { BEAST_EXPECT( env.balance(carol, USD) == - STAmount(USD, UINT64_C(29'389'06197177127), -11)); + STAmount(USD, UINT64_C(29'389'06197177124), -11)); BEAST_EXPECT(ammAlice.expectBalances( XRPAmount{13'000'000'668}, - STAmount{USD, UINT64_C(13'123'98038490683), -11}, + STAmount{USD, UINT64_C(13'123'98038490689), -11}, ammTokens)); } env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110))); @@ -3022,14 +3111,14 @@ private: { BEAST_EXPECT(ammAlice.expectBalances( XRPAmount(13'100'824'790), - STAmount{USD, UINT64_C(13'023'98038490683), -11}, + STAmount{USD, UINT64_C(13'023'98038490689), -11}, ammTokens)); } }, std::nullopt, 1'000, std::nullopt, - features); + {features}); // Bid tiny amount testAMM( @@ -4497,8 +4586,11 @@ private: auto const tokensFee = ammAlice.withdraw( carol, USD(100), std::nullopt, IOUAmount{520, 0}); // carol withdraws ~1,443.44USD - auto const balanceAfterWithdraw = - STAmount(USD, UINT64_C(30'443'43891402715), -11); + auto const balanceAfterWithdraw = [&]() { + if (!features[fixAMMv1_1]) + return STAmount(USD, UINT64_C(30'443'43891402715), -11); + return STAmount(USD, UINT64_C(30'443'43891402714), -11); + }(); BEAST_EXPECT(env.balance(carol, USD) == balanceAfterWithdraw); // Set to original pool size auto const deposit = balanceAfterWithdraw - USD(29'000); @@ -4507,12 +4599,22 @@ private: ammAlice.vote(alice, 0); BEAST_EXPECT(ammAlice.expectTradingFee(0)); auto const tokensNoFee = ammAlice.withdraw(carol, deposit); - BEAST_EXPECT( - env.balance(carol, USD) == - STAmount(USD, UINT64_C(30'443'43891402717), -11)); + if (!features[fixAMMv1_1]) + BEAST_EXPECT( + env.balance(carol, USD) == + STAmount(USD, UINT64_C(30'443'43891402717), -11)); + else + BEAST_EXPECT( + env.balance(carol, USD) == + STAmount(USD, UINT64_C(30'443'43891402716), -11)); // carol pays ~4008 LPTokens in fees or ~0.5% of the no-fee // LPTokens - BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779913, -8)); + if (!features[fixAMMv1_1]) + BEAST_EXPECT( + tokensNoFee == IOUAmount(746'579'80779913, -8)); + else + BEAST_EXPECT( + tokensNoFee == IOUAmount(746'579'80779912, -8)); BEAST_EXPECT(tokensFee == IOUAmount(750'588'23529411, -8)); }, std::nullopt, @@ -4762,74 +4864,101 @@ private: } void - testAdjustedTokens() + testAdjustedTokens(FeatureBitset features) { testcase("Adjusted Deposit/Withdraw Tokens"); using namespace jtx; // Deposit/Withdraw in USD - testAMM([&](AMM& ammAlice, Env& env) { - Account const bob("bob"); - Account const ed("ed"); - Account const paul("paul"); - Account const dan("dan"); - Account const chris("chris"); - Account const simon("simon"); - Account const ben("ben"); - Account const nataly("nataly"); - fund( - env, - gw, - {bob, ed, paul, dan, chris, simon, ben, nataly}, - {USD(1'500'000)}, - Fund::Acct); - for (int i = 0; i < 10; ++i) - { - ammAlice.deposit(ben, STAmount{USD, 1, -10}); - ammAlice.withdrawAll(ben, USD(0)); - ammAlice.deposit(simon, USD(0.1)); - ammAlice.withdrawAll(simon, USD(0)); - ammAlice.deposit(chris, USD(1)); - ammAlice.withdrawAll(chris, USD(0)); - ammAlice.deposit(dan, USD(10)); - ammAlice.withdrawAll(dan, USD(0)); - ammAlice.deposit(bob, USD(100)); - ammAlice.withdrawAll(bob, USD(0)); - ammAlice.deposit(carol, USD(1'000)); - ammAlice.withdrawAll(carol, USD(0)); - ammAlice.deposit(ed, USD(10'000)); - ammAlice.withdrawAll(ed, USD(0)); - ammAlice.deposit(paul, USD(100'000)); - ammAlice.withdrawAll(paul, USD(0)); - ammAlice.deposit(nataly, USD(1'000'000)); - ammAlice.withdrawAll(nataly, USD(0)); - } - // 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. - BEAST_EXPECT(ammAlice.expectBalances( - XRP(10'000), - STAmount{USD, UINT64_C(10'000'0000000013), -10}, - IOUAmount{10'000'000})); - BEAST_EXPECT(expectLine(env, ben, USD(1'500'000))); - BEAST_EXPECT(expectLine(env, simon, USD(1'500'000))); - BEAST_EXPECT(expectLine(env, chris, USD(1'500'000))); - BEAST_EXPECT(expectLine(env, dan, USD(1'500'000))); - BEAST_EXPECT(expectLine( - env, carol, STAmount{USD, UINT64_C(30'000'00000000001), -11})); - BEAST_EXPECT(expectLine(env, ed, USD(1'500'000))); - BEAST_EXPECT(expectLine(env, paul, USD(1'500'000))); - BEAST_EXPECT(expectLine( - env, nataly, STAmount{USD, UINT64_C(1'500'000'000000002), -9})); - ammAlice.withdrawAll(alice); - BEAST_EXPECT(!ammAlice.ammExists()); - BEAST_EXPECT(expectLine( - env, alice, STAmount{USD, UINT64_C(30'000'0000000013), -10})); - // alice XRP balance is 30,000initial - 50 ammcreate fee - - // 10drops fee - BEAST_EXPECT(accountBalance(env, alice) == "29949999990"); - }); + testAMM( + [&](AMM& ammAlice, Env& env) { + Account const bob("bob"); + Account const ed("ed"); + Account const paul("paul"); + Account const dan("dan"); + Account const chris("chris"); + Account const simon("simon"); + Account const ben("ben"); + Account const nataly("nataly"); + fund( + env, + gw, + {bob, ed, paul, dan, chris, simon, ben, nataly}, + {USD(1'500'000)}, + Fund::Acct); + for (int i = 0; i < 10; ++i) + { + ammAlice.deposit(ben, STAmount{USD, 1, -10}); + ammAlice.withdrawAll(ben, USD(0)); + ammAlice.deposit(simon, USD(0.1)); + ammAlice.withdrawAll(simon, USD(0)); + ammAlice.deposit(chris, USD(1)); + ammAlice.withdrawAll(chris, USD(0)); + ammAlice.deposit(dan, USD(10)); + ammAlice.withdrawAll(dan, USD(0)); + ammAlice.deposit(bob, USD(100)); + ammAlice.withdrawAll(bob, USD(0)); + ammAlice.deposit(carol, USD(1'000)); + ammAlice.withdrawAll(carol, USD(0)); + ammAlice.deposit(ed, USD(10'000)); + ammAlice.withdrawAll(ed, USD(0)); + ammAlice.deposit(paul, USD(100'000)); + ammAlice.withdrawAll(paul, USD(0)); + ammAlice.deposit(nataly, USD(1'000'000)); + ammAlice.withdrawAll(nataly, USD(0)); + } + // 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]) + BEAST_EXPECT(ammAlice.expectBalances( + XRP(10'000), + STAmount{USD, UINT64_C(10'000'0000000013), -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))); + BEAST_EXPECT(expectLine(env, simon, USD(1'500'000))); + BEAST_EXPECT(expectLine(env, chris, USD(1'500'000))); + BEAST_EXPECT(expectLine(env, dan, USD(1'500'000))); + if (!features[fixAMMv1_1]) + BEAST_EXPECT(expectLine( + env, + carol, + STAmount{USD, UINT64_C(30'000'00000000001), -11})); + else + BEAST_EXPECT(expectLine(env, carol, USD(30'000))); + BEAST_EXPECT(expectLine(env, ed, USD(1'500'000))); + BEAST_EXPECT(expectLine(env, paul, USD(1'500'000))); + if (!features[fixAMMv1_1]) + BEAST_EXPECT(expectLine( + env, + nataly, + STAmount{USD, UINT64_C(1'500'000'000000002), -9})); + else + BEAST_EXPECT(expectLine( + env, + nataly, + STAmount{USD, UINT64_C(1'500'000'000000005), -9})); + ammAlice.withdrawAll(alice); + BEAST_EXPECT(!ammAlice.ammExists()); + if (!features[fixAMMv1_1]) + BEAST_EXPECT(expectLine( + env, + alice, + STAmount{USD, UINT64_C(30'000'0000000013), -10})); + else + BEAST_EXPECT(expectLine(env, alice, USD(30'000))); + // alice XRP balance is 30,000initial - 50 ammcreate fee - + // 10drops fee + BEAST_EXPECT(accountBalance(env, alice) == "29949999990"); + }, + std::nullopt, + 0, + std::nullopt, + {features}); // Same as above but deposit/withdraw in XRP testAMM([&](AMM& ammAlice, Env& env) { @@ -6440,7 +6569,8 @@ private: testAMMAndCLOB(all - fixAMMv1_1); testTradingFee(all); testTradingFee(all - fixAMMv1_1); - testAdjustedTokens(); + testAdjustedTokens(all); + testAdjustedTokens(all - fixAMMv1_1); testAutoDelete(); testClawback(); testAMMID(); diff --git a/src/test/jtx/AMMTest.h b/src/test/jtx/AMMTest.h index 783171338..5de805a10 100644 --- a/src/test/jtx/AMMTest.h +++ b/src/test/jtx/AMMTest.h @@ -84,7 +84,7 @@ protected: std::optional> const& pool = std::nullopt, std::uint16_t tfee = 0, std::optional const& ter = std::nullopt, - std::optional const& features = std::nullopt); + std::vector const& features = {supported_amendments()}); }; class AMMTest : public jtx::AMMTestBase diff --git a/src/test/jtx/impl/AMMTest.cpp b/src/test/jtx/impl/AMMTest.cpp index 2c384a7d6..b9dea7d1f 100644 --- a/src/test/jtx/impl/AMMTest.cpp +++ b/src/test/jtx/impl/AMMTest.cpp @@ -103,44 +103,45 @@ AMMTestBase::testAMM( std::optional> const& pool, std::uint16_t tfee, std::optional const& ter, - std::optional const& features) + std::vector const& vfeatures) { using namespace jtx; - auto env = [&]() { - if (features) - return Env{*this, *features}; - return Env{*this}; - }(); - auto const [asset1, asset2] = - pool ? *pool : std::make_pair(XRP(10000), USD(10000)); - auto tofund = [&](STAmount const& a) -> STAmount { - if (a.native()) - { - auto const defXRP = XRP(30000); - if (a <= defXRP) - return defXRP; - return a + XRP(1000); - } - auto const defIOU = STAmount{a.issue(), 30000}; - if (a <= defIOU) - return defIOU; - return a + STAmount{a.issue(), 1000}; - }; - auto const toFund1 = tofund(asset1); - auto const toFund2 = tofund(asset2); - BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); + for (auto const& features : vfeatures) + { + Env env{*this, features}; - if (!asset1.native() && !asset2.native()) - fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All); - else if (asset1.native()) - fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All); - else if (asset2.native()) - fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All); + auto const [asset1, asset2] = + pool ? *pool : std::make_pair(XRP(10000), USD(10000)); + auto tofund = [&](STAmount const& a) -> STAmount { + if (a.native()) + { + auto const defXRP = XRP(30000); + if (a <= defXRP) + return defXRP; + return a + XRP(1000); + } + auto const defIOU = STAmount{a.issue(), 30000}; + if (a <= defIOU) + return defIOU; + return a + STAmount{a.issue(), 1000}; + }; + auto const toFund1 = tofund(asset1); + auto const toFund2 = tofund(asset2); + BEAST_EXPECT(asset1 <= toFund1 && asset2 <= toFund2); - AMM ammAlice(env, alice, asset1, asset2, false, tfee); - BEAST_EXPECT(ammAlice.expectBalances(asset1, asset2, ammAlice.tokens())); - cb(ammAlice, env); + if (!asset1.native() && !asset2.native()) + fund(env, gw, {alice, carol}, {toFund1, toFund2}, Fund::All); + else if (asset1.native()) + fund(env, gw, {alice, carol}, toFund1, {toFund2}, Fund::All); + else if (asset2.native()) + fund(env, gw, {alice, carol}, toFund2, {toFund1}, Fund::All); + + AMM ammAlice(env, alice, asset1, asset2, false, tfee); + BEAST_EXPECT( + ammAlice.expectBalances(asset1, asset2, ammAlice.tokens())); + cb(ammAlice, env); + } } XRPAmount