Merge fixAMMv1_3 amendment into featureAMM amendment

This commit is contained in:
tequ
2026-02-19 12:14:41 +09:00
parent 821671a60d
commit 8dfb437f63
13 changed files with 322 additions and 946 deletions

View File

@@ -31,7 +31,6 @@
// If you add an amendment here, then do not forget to increment `numFeatures`
// in include/xrpl/protocol/Feature.h.
XRPL_FIX (AMMv1_3, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(HookAPISerializedType240, Supported::yes, VoteBehavior::DefaultNo)
XRPL_FEATURE(PermissionedDomains, Supported::no, VoteBehavior::DefaultNo)
XRPL_FEATURE(DynamicNFT, Supported::no, VoteBehavior::DefaultNo)

View File

@@ -581,12 +581,8 @@ class AMMClawback_test : public jtx::AMMTest
AMM amm(env, alice, EUR(5000), USD(4000), ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(4000), EUR(5000), IOUAmount{4472135954999580, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(4000), EUR(5000), IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(4000), EUR(5000), IOUAmount{4472135954999579, -12}));
// gw clawback 1000 USD from the AMM pool
env(amm::ammClawback(gw, alice, USD, EUR, USD(1000)),
@@ -605,20 +601,12 @@ class AMMClawback_test : public jtx::AMMTest
// 1000 USD and 1250 EUR was withdrawn from the AMM pool, so the
// current balance is 3000 USD and 3750 EUR.
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(3000), EUR(3750), IOUAmount{3354101966249685, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(3000), EUR(3750), IOUAmount{3354101966249684, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(3000), EUR(3750), IOUAmount{3354101966249684, -12}));
// Alice has 3/4 of its initial lptokens Left.
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{3354101966249685, -12}));
else
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{3354101966249684, -12}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{3354101966249684, -12}));
// gw clawback another 500 USD from the AMM pool.
env(amm::ammClawback(gw, alice, USD, EUR, USD(500)),
@@ -629,21 +617,10 @@ class AMMClawback_test : public jtx::AMMTest
// AMM pool.
env.require(balance(alice, gw["USD"](2000)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(2500000000000001), -12},
STAmount{EUR, UINT64_C(3125000000000001), -12},
IOUAmount{2795084971874738, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(2500), EUR(3125), IOUAmount{2795084971874737, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(2500), EUR(3125), IOUAmount{2795084971874737, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
env.balance(alice, EUR) ==
STAmount(EUR, UINT64_C(2874999999999999), -12));
else
BEAST_EXPECT(env.balance(alice, EUR) == EUR(2875));
BEAST_EXPECT(env.balance(alice, EUR) == EUR(2875));
// gw clawback small amount, 1 USD.
env(amm::ammClawback(gw, alice, USD, EUR, USD(1)), ter(tesSUCCESS));
@@ -652,21 +629,10 @@ class AMMClawback_test : public jtx::AMMTest
// Another 1 USD / 1.25 EUR was withdrawn.
env.require(balance(alice, gw["USD"](2000)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(2499000000000002), -12},
STAmount{EUR, UINT64_C(3123750000000002), -12},
IOUAmount{2793966937885989, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(2499), EUR(3123.75), IOUAmount{2793966937885987, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(2499), EUR(3123.75), IOUAmount{2793966937885987, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
env.balance(alice, EUR) ==
STAmount(EUR, UINT64_C(2'876'249999999998), -12));
else
BEAST_EXPECT(env.balance(alice, EUR) == EUR(2876.25));
BEAST_EXPECT(env.balance(alice, EUR) == EUR(2876.25));
// gw clawback 4000 USD, exceeding the current balance. We
// will clawback all.
@@ -739,26 +705,14 @@ class AMMClawback_test : public jtx::AMMTest
// gw2 creates AMM pool of XRP/EUR, alice and bob deposit XRP/EUR.
AMM amm2(env, gw2, XRP(3000), EUR(1000), ter(tesSUCCESS));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectBalances(
EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9}));
else
BEAST_EXPECT(amm2.expectBalances(
EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9}));
BEAST_EXPECT(amm2.expectBalances(
EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9}));
amm2.deposit(alice, EUR(1000), XRP(3000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectBalances(
EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9}));
else
BEAST_EXPECT(amm2.expectBalances(
EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9}));
BEAST_EXPECT(amm2.expectBalances(
EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9}));
amm2.deposit(bob, EUR(1000), XRP(3000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectBalances(
EUR(3000), XRP(9000), IOUAmount{5196152422706634, -9}));
else
BEAST_EXPECT(amm2.expectBalances(
EUR(3000), XRP(9000), IOUAmount{5196152422706631, -9}));
BEAST_EXPECT(amm2.expectBalances(
EUR(3000), XRP(9000), IOUAmount{5196152422706631, -9}));
env.close();
auto aliceXrpBalance = env.balance(alice, XRP);
@@ -781,18 +735,10 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(
expectLedgerEntryRoot(env, alice, aliceXrpBalance + XRP(1000)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(2500), XRP(5000), IOUAmount{3535533905932738, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(2500), XRP(5000), IOUAmount{3535533905932737, -9}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{7071067811865480, -10}));
else
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{7071067811865474, -10}));
BEAST_EXPECT(amm.expectBalances(
USD(2500), XRP(5000), IOUAmount{3535533905932737, -9}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{7071067811865474, -10}));
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1414213562373095, -9}));
@@ -806,26 +752,12 @@ class AMMClawback_test : public jtx::AMMTest
// Bob gets 20 XRP back.
BEAST_EXPECT(
expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(20)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(2490000000000001), -12},
XRP(4980),
IOUAmount{3521391770309008, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(2'490), XRP(4980), IOUAmount{3521391770309006, -9}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{7071067811865480, -10}));
else
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{7071067811865474, -10}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9}));
else
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9}));
BEAST_EXPECT(amm.expectBalances(
USD(2'490), XRP(4980), IOUAmount{3521391770309006, -9}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{7071067811865474, -10}));
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9}));
// gw2 clawback 200 EUR from amm2.
env(amm::ammClawback(gw2, alice, EUR, XRP, EUR(200)),
@@ -838,24 +770,12 @@ class AMMClawback_test : public jtx::AMMTest
// Alice gets 600 XRP back.
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(1000) + XRP(600)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectBalances(
EUR(2800), XRP(8400), IOUAmount{4849742261192859, -9}));
else
BEAST_EXPECT(amm2.expectBalances(
EUR(2800), XRP(8400), IOUAmount{4849742261192856, -9}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectLPTokens(
alice, IOUAmount{1385640646055103, -9}));
else
BEAST_EXPECT(amm2.expectLPTokens(
alice, IOUAmount{1385640646055102, -9}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
amm2.expectLPTokens(bob, IOUAmount{1732050807568878, -9}));
else
BEAST_EXPECT(
amm2.expectLPTokens(bob, IOUAmount{1732050807568877, -9}));
BEAST_EXPECT(amm2.expectBalances(
EUR(2800), XRP(8400), IOUAmount{4849742261192856, -9}));
BEAST_EXPECT(
amm2.expectLPTokens(alice, IOUAmount{1385640646055102, -9}));
BEAST_EXPECT(
amm2.expectLPTokens(bob, IOUAmount{1732050807568877, -9}));
// gw claw back 1000 USD from alice in amm, which exceeds alice's
// balance. This will clawback all the remaining LP tokens of alice
@@ -868,34 +788,18 @@ class AMMClawback_test : public jtx::AMMTest
env.require(balance(bob, gw["USD"](4000)));
// Alice gets 1000 XRP back.
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000)));
else
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) -
XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) -
XRPAmount{1}));
BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1400071426749365, -9}));
else
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(1990000000000001), -12},
XRP(3980),
IOUAmount{2814284989122460, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(1'990),
XRPAmount{3'980'000'001},
IOUAmount{2814284989122459, -9}));
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{1400071426749364, -9}));
BEAST_EXPECT(amm.expectBalances(
USD(1'990),
XRPAmount{3'980'000'001},
IOUAmount{2814284989122459, -9}));
// gw clawback 1000 USD from bob in amm, which also exceeds bob's
// balance in amm. All bob's lptoken in amm will be consumed, which
@@ -907,17 +811,11 @@ class AMMClawback_test : public jtx::AMMTest
env.require(balance(alice, gw["USD"](5000)));
env.require(balance(bob, gw["USD"](4000)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000)));
else
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) -
XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) -
XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env, bob, bobXrpBalance + XRP(20) + XRP(1980)));
@@ -937,30 +835,19 @@ class AMMClawback_test : public jtx::AMMTest
// Alice gets another 2400 XRP back, bob's XRP balance remains the
// same.
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) +
XRP(2400)));
else
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) +
XRP(2400) - XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + XRP(2400) -
XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env, bob, bobXrpBalance + XRP(20) + XRP(1980)));
// Alice now does not have any lptoken in amm2
BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectBalances(
EUR(2000), XRP(6000), IOUAmount{3464101615137756, -9}));
else
BEAST_EXPECT(amm2.expectBalances(
EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9}));
BEAST_EXPECT(amm2.expectBalances(
EUR(2000), XRP(6000), IOUAmount{3464101615137754, -9}));
// gw2 claw back 2000 EUR from bob in amm2, which exceeds bob's
// balance. All bob's lptokens will be consumed, which corresponds
@@ -974,18 +861,11 @@ class AMMClawback_test : public jtx::AMMTest
// Bob gets another 3000 XRP back. Alice's XRP balance remains the
// same.
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) +
XRP(2400)));
else
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) +
XRP(2400) - XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env,
alice,
aliceXrpBalance + XRP(1000) + XRP(600) + XRP(1000) + XRP(2400) -
XRPAmount{1}));
BEAST_EXPECT(expectLedgerEntryRoot(
env, bob, bobXrpBalance + XRP(20) + XRP(1980) + XRP(3000)));
@@ -993,12 +873,8 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(amm2.expectLPTokens(alice, IOUAmount(0)));
BEAST_EXPECT(amm2.expectLPTokens(bob, IOUAmount(0)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm2.expectBalances(
EUR(1000), XRP(3000), IOUAmount{1732050807568878, -9}));
else
BEAST_EXPECT(amm2.expectBalances(
EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9}));
BEAST_EXPECT(amm2.expectBalances(
EUR(1000), XRP(3000), IOUAmount{1732050807568877, -9}));
}
}
@@ -1056,45 +932,21 @@ class AMMClawback_test : public jtx::AMMTest
AMM amm(env, alice, EUR(5000), USD(4000), ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(4000), EUR(5000), IOUAmount{4472135954999580, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(4000), EUR(5000), IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(4000), EUR(5000), IOUAmount{4472135954999579, -12}));
amm.deposit(bob, USD(2000), EUR(2500));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(6000), EUR(7500), IOUAmount{6708203932499370, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(6000), EUR(7500), IOUAmount{6708203932499368, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(6000), EUR(7500), IOUAmount{6708203932499368, -12}));
amm.deposit(carol, USD(1000), EUR(1250));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(7000), EUR(8750), IOUAmount{7826237921249265, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(7000), EUR(8750), IOUAmount{7826237921249262, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(7000), EUR(8750), IOUAmount{7826237921249262, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{4472135954999580, -12}));
else
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{4472135954999579, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{2236067977499790, -12}));
else
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{2236067977499789, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
carol, IOUAmount{1118033988749895, -12}));
else
BEAST_EXPECT(amm.expectLPTokens(
carol, IOUAmount{1118033988749894, -12}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(
amm.expectLPTokens(bob, IOUAmount{2236067977499789, -12}));
BEAST_EXPECT(
amm.expectLPTokens(carol, IOUAmount{1118033988749894, -12}));
env.require(balance(alice, gw["USD"](2000)));
env.require(balance(alice, gw2["EUR"](1000)));
@@ -1108,30 +960,16 @@ class AMMClawback_test : public jtx::AMMTest
ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(4999999999999999), -12},
STAmount{EUR, UINT64_C(6249999999999999), -12},
IOUAmount{5590169943749475, -12}));
else
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(5000000000000001), -12},
STAmount{EUR, UINT64_C(6250000000000001), -12},
IOUAmount{5590169943749473, -12}));
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(5000000000000001), -12},
STAmount{EUR, UINT64_C(6250000000000001), -12},
IOUAmount{5590169943749473, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{4472135954999580, -12}));
else
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
carol, IOUAmount{1118033988749895, -12}));
else
BEAST_EXPECT(amm.expectLPTokens(
carol, IOUAmount{1118033988749894, -12}));
BEAST_EXPECT(
amm.expectLPTokens(carol, IOUAmount{1118033988749894, -12}));
// Bob will get 2500 EUR back.
env.require(balance(alice, gw["USD"](2000)));
@@ -1140,14 +978,9 @@ class AMMClawback_test : public jtx::AMMTest
env.balance(bob, USD) ==
STAmount(USD, UINT64_C(3000000000000000), -12));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
env.balance(bob, EUR) ==
STAmount(EUR, UINT64_C(5000000000000001), -12));
else
BEAST_EXPECT(
env.balance(bob, EUR) ==
STAmount(EUR, UINT64_C(4999999999999999), -12));
BEAST_EXPECT(
env.balance(bob, EUR) ==
STAmount(EUR, UINT64_C(4999999999999999), -12));
env.require(balance(carol, gw["USD"](3000)));
env.require(balance(carol, gw2["EUR"](2750)));
@@ -1155,23 +988,13 @@ class AMMClawback_test : public jtx::AMMTest
env(amm::ammClawback(gw2, carol, EUR, USD, std::nullopt),
ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(3999999999999999), -12},
STAmount{EUR, UINT64_C(4999999999999999), -12},
IOUAmount{4472135954999580, -12}));
else
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(4000000000000001), -12},
STAmount{EUR, UINT64_C(5000000000000002), -12},
IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(amm.expectBalances(
STAmount{USD, UINT64_C(4000000000000001), -12},
STAmount{EUR, UINT64_C(5000000000000002), -12},
IOUAmount{4472135954999579, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{4472135954999580, -12}));
else
BEAST_EXPECT(amm.expectLPTokens(
alice, IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{4472135954999579, -12}));
BEAST_EXPECT(amm.expectLPTokens(bob, IOUAmount(0)));
BEAST_EXPECT(amm.expectLPTokens(carol, IOUAmount(0)));
@@ -1210,26 +1033,14 @@ class AMMClawback_test : public jtx::AMMTest
// gw creates AMM pool of XRP/USD, alice and bob deposit XRP/USD.
AMM amm(env, gw, XRP(2000), USD(10000), ter(tesSUCCESS));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(10000), XRP(2000), IOUAmount{4472135954999580, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(10000), XRP(2000), IOUAmount{4472135954999579, -9}));
BEAST_EXPECT(amm.expectBalances(
USD(10000), XRP(2000), IOUAmount{4472135954999579, -9}));
amm.deposit(alice, USD(1000), XRP(200));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(11000), XRP(2200), IOUAmount{4919349550499538, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(11000), XRP(2200), IOUAmount{4919349550499536, -9}));
BEAST_EXPECT(amm.expectBalances(
USD(11000), XRP(2200), IOUAmount{4919349550499536, -9}));
amm.deposit(bob, USD(2000), XRP(400));
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(13000), XRP(2600), IOUAmount{5813776741499453, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(13000), XRP(2600), IOUAmount{5813776741499451, -9}));
BEAST_EXPECT(amm.expectBalances(
USD(13000), XRP(2600), IOUAmount{5813776741499451, -9}));
env.close();
auto aliceXrpBalance = env.balance(alice, XRP);
@@ -1239,34 +1050,22 @@ class AMMClawback_test : public jtx::AMMTest
env(amm::ammClawback(gw, alice, USD, XRP, std::nullopt),
ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(12000), XRP(2400), IOUAmount{5366563145999495, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(12000),
XRPAmount(2400000001),
IOUAmount{5366563145999494, -9}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(200)));
else
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(200) - XRPAmount{1}));
BEAST_EXPECT(amm.expectBalances(
USD(12000),
XRPAmount(2400000001),
IOUAmount{5366563145999494, -9}));
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(200) - XRPAmount{1}));
BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0)));
// gw clawback all bob's USD in amm. (2000 USD / 400 XRP)
env(amm::ammClawback(gw, bob, USD, XRP, std::nullopt),
ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(10000), XRP(2000), IOUAmount{4472135954999580, -9}));
else
BEAST_EXPECT(amm.expectBalances(
USD(10000),
XRPAmount(2000000001),
IOUAmount{4472135954999579, -9}));
BEAST_EXPECT(amm.expectBalances(
USD(10000),
XRPAmount(2000000001),
IOUAmount{4472135954999579, -9}));
BEAST_EXPECT(
expectLedgerEntryRoot(env, bob, bobXrpBalance + XRP(400)));
BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0)));
@@ -1322,10 +1121,7 @@ class AMMClawback_test : public jtx::AMMTest
amm.deposit(bob, USD(4000), EUR(1000));
BEAST_EXPECT(
amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000)));
if (!features[fixAMMv1_3])
amm.deposit(carol, USD(2000), EUR(500));
else
amm.deposit(carol, USD(2000.25), EUR(500));
amm.deposit(carol, USD(2000.25), EUR(500));
BEAST_EXPECT(
amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000)));
// gw clawback 1000 USD from carol.
@@ -1341,12 +1137,9 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
// 250 EUR goes back to carol.
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
@@ -1368,12 +1161,9 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
// 250 EUR did not go back to bob because tfClawTwoAssets is set.
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
// gw clawback all USD from alice and set tfClawTwoAssets.
@@ -1390,12 +1180,9 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
}
@@ -1580,21 +1367,10 @@ class AMMClawback_test : public jtx::AMMTest
// gw2 claws back 1000 EUR from gw.
env(amm::ammClawback(gw2, gw, EUR, USD, EUR(1000)), ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(4500),
STAmount(EUR, UINT64_C(9000000000000001), -12),
IOUAmount{6363961030678928, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(4500), EUR(9000), IOUAmount{6363961030678928, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(4500), EUR(9000), IOUAmount{6363961030678928, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13}));
else
BEAST_EXPECT(
amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13}));
BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13}));
BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{4242640687119285, -12}));
@@ -1607,21 +1383,10 @@ class AMMClawback_test : public jtx::AMMTest
// gw2 claws back 4000 EUR from alice.
env(amm::ammClawback(gw2, alice, EUR, USD, EUR(4000)), ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
USD(2500),
STAmount(EUR, UINT64_C(5000000000000001), -12),
IOUAmount{3535533905932738, -12}));
else
BEAST_EXPECT(amm.expectBalances(
USD(2500), EUR(5000), IOUAmount{3535533905932738, -12}));
BEAST_EXPECT(amm.expectBalances(
USD(2500), EUR(5000), IOUAmount{3535533905932738, -12}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(
amm.expectLPTokens(gw, IOUAmount{7071067811865480, -13}));
else
BEAST_EXPECT(
amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13}));
BEAST_EXPECT(amm.expectLPTokens(gw, IOUAmount{7071067811865475, -13}));
BEAST_EXPECT(amm.expectLPTokens(gw2, IOUAmount{1414213562373095, -12}));
BEAST_EXPECT(
amm.expectLPTokens(alice, IOUAmount{1414213562373095, -12}));
@@ -1885,10 +1650,7 @@ class AMMClawback_test : public jtx::AMMTest
amm.deposit(bob, USD(4000), EUR(1000));
BEAST_EXPECT(
amm.expectBalances(USD(12000), EUR(3000), IOUAmount(6000)));
if (!features[fixAMMv1_3])
amm.deposit(carol, USD(2000), EUR(500));
else
amm.deposit(carol, USD(2000.25), EUR(500));
amm.deposit(carol, USD(2000.25), EUR(500));
BEAST_EXPECT(
amm.expectBalances(USD(14000), EUR(3500), IOUAmount(7000)));
@@ -1910,12 +1672,9 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
// 250 EUR goes back to carol.
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
@@ -1937,12 +1696,9 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
// 250 EUR did not go back to bob because tfClawTwoAssets is set.
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
// gw clawback all USD from alice and set tfClawTwoAssets.
@@ -1960,12 +1716,9 @@ class AMMClawback_test : public jtx::AMMTest
BEAST_EXPECT(env.balance(alice, EUR) == EUR(8000));
BEAST_EXPECT(env.balance(bob, USD) == USD(5000));
BEAST_EXPECT(env.balance(bob, EUR) == EUR(8000));
if (!features[fixAMMv1_3])
BEAST_EXPECT(env.balance(carol, USD) == USD(6000));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(5999'999999999999), -12));
BEAST_EXPECT(env.balance(carol, EUR) == EUR(7750));
}
}
@@ -2013,23 +1766,13 @@ class AMMClawback_test : public jtx::AMMTest
env(amm::ammClawback(gw, alice, USD, XRP, USD(400)), ter(tesSUCCESS));
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(amm.expectBalances(
STAmount(USD, UINT64_C(5656854249492380), -13),
XRP(70.710678),
IOUAmount(200000)));
else
BEAST_EXPECT(amm.expectBalances(
STAmount(USD, UINT64_C(565'685424949238), -12),
XRP(70.710679),
IOUAmount(200000)));
BEAST_EXPECT(amm.expectBalances(
STAmount(USD, UINT64_C(565'685424949238), -12),
XRP(70.710679),
IOUAmount(200000)));
BEAST_EXPECT(amm.expectLPTokens(alice, IOUAmount(0)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(29.289322)));
else
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(29.289321)));
BEAST_EXPECT(expectLedgerEntryRoot(
env, alice, aliceXrpBalance + XRP(29.289321)));
}
void
@@ -2040,18 +1783,13 @@ class AMMClawback_test : public jtx::AMMTest
testFeatureDisabled(all - featureAMMClawback);
testAMMClawbackSpecificAmount(all);
testAMMClawbackExceedBalance(all);
testAMMClawbackExceedBalance(all - fixAMMv1_3);
testAMMClawbackAll(all);
testAMMClawbackAll(all - fixAMMv1_3);
testAMMClawbackSameIssuerAssets(all);
testAMMClawbackSameIssuerAssets(all - fixAMMv1_3);
testAMMClawbackSameCurrency(all);
testAMMClawbackIssuesEachOther(all);
testNotHoldingLptoken(all);
testAssetFrozen(all);
testAssetFrozen(all - fixAMMv1_3);
testSingleDepositAndClawback(all);
testSingleDepositAndClawback(all - fixAMMv1_3);
}
};
BEAST_DEFINE_TESTSUITE(AMMClawback, app, ripple);

View File

@@ -1405,7 +1405,6 @@ private:
using namespace jtx;
FeatureBitset const all{supported_amendments()};
testRmFundedOffer(all);
testRmFundedOffer(all - fixAMMv1_3);
testEnforceNoRipple(all);
testFillModes(all);
testOfferCrossWithXRP(all);
@@ -1419,7 +1418,6 @@ private:
testOfferCreateThenCross(all);
testSellFlagExceedLimit(all);
testGatewayCrossCurrency(all);
testGatewayCrossCurrency(all - fixAMMv1_3);
testBridgedCross(all);
testSellWithFillOrKill(all);
testTransferRateOffer(all);
@@ -1427,7 +1425,6 @@ private:
testBadPathAssert(all);
testSellFlagBasic(all);
testDirectToDirectPath(all);
testDirectToDirectPath(all - fixAMMv1_3);
testRequireAuth(all);
testMissingAuth(all);
}
@@ -3838,9 +3835,7 @@ private:
testBookStep(all);
testBookStep(all | ownerPaysFee);
testTransferRate(all | ownerPaysFee);
testTransferRate((all - fixAMMv1_3) | ownerPaysFee);
testTransferRateNoOwnerFee(all);
testTransferRateNoOwnerFee(all - fixAMMv1_3);
testLimitQuality();
testXRPPathLoop();
}
@@ -3851,7 +3846,6 @@ private:
using namespace jtx;
FeatureBitset const all{supported_amendments()};
testStepLimit(all);
testStepLimit(all - fixAMMv1_3);
}
void
@@ -3860,7 +3854,6 @@ private:
using namespace jtx;
FeatureBitset const all{supported_amendments()};
test_convert_all_of_an_asset(all);
test_convert_all_of_an_asset(all - fixAMMv1_3);
}
void

View File

@@ -833,10 +833,7 @@ private:
// Tiny deposit
testAMM(
[&](AMM& ammAlice, Env& env) {
auto const enabledv1_3 =
env.current()->rules().enabled(fixAMMv1_3);
auto const err =
!enabledv1_3 ? ter(temBAD_AMOUNT) : ter(tesSUCCESS);
auto const err = ter(tesSUCCESS);
// Pre-amendment XRP deposit side is rounded to 0
// and deposit fails.
// Post-amendment XRP deposit side is rounded to 1
@@ -856,7 +853,7 @@ private:
std::nullopt,
0,
std::nullopt,
{features, features - fixAMMv1_3});
{features});
// Invalid AMM
testAMM([&](AMM& ammAlice, Env& env) {
@@ -1322,15 +1319,6 @@ private:
});
// Equal deposit limit, tokens rounded to 0
testAMM(
[&](AMM& amm, Env& env) {
amm.deposit(DepositArg{
.asset1In = STAmount{USD, 1, -15},
.asset2In = XRPAmount{1},
.err = ter(tecAMM_INVALID_TOKENS)});
},
{.pool = {{USD(1'000'000), XRP(1'000'000)}},
.features = {features - fixAMMv1_3}});
testAMM([&](AMM& amm, Env& env) {
amm.deposit(DepositArg{
.asset1In = STAmount{USD, 1, -15},
@@ -1573,7 +1561,7 @@ private:
});
// Issuer create/deposit
for (auto const& feat : {all, all - fixAMMv1_3})
for (auto const& feat : {all})
{
Env env(*this, feat);
env.fund(XRP(30000), gw);
@@ -2003,22 +1991,20 @@ private:
// while leaving a tiny amount in USD pool.
// Post-amendment:
// Most of the pool is withdrawn with remaining tiny amounts
auto err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS)
: ter(tecAMM_BALANCE);
auto err = ter(tesSUCCESS);
ammAlice.withdraw(
alice,
IOUAmount{9'999'999'9999, -4},
std::nullopt,
std::nullopt,
err);
if (env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(1), STAmount{USD, 1, -7}, IOUAmount{1, -4}));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(1), STAmount{USD, 1, -7}, IOUAmount{1, -4}));
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
testAMM(
[&](AMM& ammAlice, Env& env) {
@@ -2028,22 +2014,20 @@ private:
// Equal withdraw but due to XRP precision limit,
// this results in full withdraw of XRP pool only,
// while leaving a tiny amount in USD pool.
auto err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS)
: ter(tecAMM_BALANCE);
auto err = ter(tesSUCCESS);
ammAlice.withdraw(
alice,
IOUAmount{9'999'999'999999999, -9},
std::nullopt,
std::nullopt,
err);
if (env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(1), STAmount{USD, 1, -11}, IOUAmount{1, -8}));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(1), STAmount{USD, 1, -11}, IOUAmount{1, -8}));
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
// Invalid AMM
testAMM([&](AMM& ammAlice, Env& env) {
@@ -2111,16 +2095,14 @@ private:
testAMM(
[&](AMM& ammAlice, Env& env) {
ammAlice.deposit(carol, 1'000'000);
auto const err = env.enabled(fixAMMv1_3)
? ter(tecAMM_INVALID_TOKENS)
: ter(tecAMM_FAILED);
auto const err = ter(tecAMM_INVALID_TOKENS);
ammAlice.withdraw(
carol, USD(100), std::nullopt, IOUAmount{500, 0}, err);
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
// Withdraw with EPrice limit. Fails to withdraw, calculated tokens
// to withdraw are greater than the LP shares.
@@ -2187,9 +2169,7 @@ private:
// are rounded to all LP tokens.
testAMM(
[&](AMM& ammAlice, Env& env) {
auto const err = env.enabled(fixAMMv1_3)
? ter(tecINVARIANT_FAILED)
: ter(tecAMM_BALANCE);
auto const err = ter(tecINVARIANT_FAILED);
ammAlice.withdraw(
alice,
STAmount{USD, UINT64_C(9'999'999999999999), -12},
@@ -2197,7 +2177,7 @@ private:
std::nullopt,
err);
},
{.features = {all, all - fixAMMv1_3}, .noLog = true});
{.features = {all}, .noLog = true});
// Tiny withdraw
testAMM([&](AMM& ammAlice, Env&) {
@@ -2305,21 +2285,15 @@ private:
testAMM(
[&](AMM& ammAlice, Env& env) {
ammAlice.withdraw(alice, XRP(1'000));
if (!env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRP(9'000),
USD(10'000),
IOUAmount{9'486'832'98050514, -8}));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{9'000'000'001},
USD(10'000),
IOUAmount{9'486'832'98050514, -8}));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{9'000'000'001},
USD(10'000),
IOUAmount{9'486'832'98050514, -8}));
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
// Single withdrawal by tokens 10000.
testAMM([&](AMM& ammAlice, Env&) {
@@ -2381,20 +2355,14 @@ private:
ammAlice.withdraw(carol, lpTokens, USD(0));
lpTokens = ammAlice.deposit(carol, XRPAmount(1));
ammAlice.withdraw(carol, lpTokens, XRPAmount(0));
if (!env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRP(10'000), USD(10'000), ammAlice.tokens()));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(10'000'000'001),
USD(10'000),
ammAlice.tokens()));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(10'000'000'001), USD(10'000), ammAlice.tokens()));
BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0}));
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
// Single deposit by different accounts and then withdraw
// in reverse.
@@ -2445,20 +2413,14 @@ private:
carol, USD(100), std::nullopt, IOUAmount{520, 0});
BEAST_EXPECT(ammAlice.expectLPTokens(
carol, IOUAmount{153'846'15384616, -8}));
if (!env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(11'000'000'000),
STAmount{USD, UINT64_C(9'372'781065088769), -12},
IOUAmount{10'153'846'15384616, -8}));
else if (env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(11'000'000'000),
STAmount{USD, UINT64_C(9'372'78106508877), -11},
IOUAmount{10'153'846'15384616, -8}));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(11'000'000'000),
STAmount{USD, UINT64_C(9'372'78106508877), -11},
IOUAmount{10'153'846'15384616, -8}));
ammAlice.withdrawAll(carol);
BEAST_EXPECT(ammAlice.expectLPTokens(carol, IOUAmount{0}));
},
{.features = {all, all - fixAMMv1_3}, .noLog = true});
{.features = {all}, .noLog = true});
// Withdraw with EPrice limit. AssetOut is 0.
testAMM(
@@ -2468,21 +2430,15 @@ private:
carol, USD(0), std::nullopt, IOUAmount{520, 0});
BEAST_EXPECT(ammAlice.expectLPTokens(
carol, IOUAmount{153'846'15384616, -8}));
if (!env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRP(11'000),
STAmount{USD, UINT64_C(9'372'781065088769), -12},
IOUAmount{10'153'846'15384616, -8}));
else if (env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRP(11'000),
STAmount{USD, UINT64_C(9'372'78106508877), -11},
IOUAmount{10'153'846'15384616, -8}));
BEAST_EXPECT(ammAlice.expectBalances(
XRP(11'000),
STAmount{USD, UINT64_C(9'372'78106508877), -11},
IOUAmount{10'153'846'15384616, -8}));
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
// IOU to IOU + transfer fee
{
@@ -2525,21 +2481,13 @@ private:
[&](AMM& ammAlice, Env& env) {
// Single XRP pool
ammAlice.withdraw(alice, std::nullopt, XRPAmount{1});
if (!env.enabled(fixAMMv1_3))
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{9'999'999'999},
USD(10'000),
IOUAmount{9'999'999'9995, -4}));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRP(10'000),
USD(10'000),
IOUAmount{9'999'999'9995, -4}));
BEAST_EXPECT(ammAlice.expectBalances(
XRP(10'000), USD(10'000), IOUAmount{9'999'999'9995, -4}));
},
std::nullopt,
0,
std::nullopt,
{all, all - fixAMMv1_3});
{all});
testAMM([&](AMM& ammAlice, Env&) {
// Single USD pool
ammAlice.withdraw(alice, std::nullopt, STAmount{USD, 1, -10});
@@ -2679,8 +2627,7 @@ private:
// in order to ensure AMM invariant sqrt(asset1 * asset2) >= tokens
// fund just one USD higher in this case, which is enough for
// deposit to succeed
if (env.enabled(fixAMMv1_3))
++fundUSD;
++fundUSD;
fund(env, gw, {a}, {USD(fundUSD)}, Fund::Acct);
ammAlice.deposit(a, tokens);
ammAlice.vote(a, 50 * (i + 1));
@@ -3092,14 +3039,10 @@ private:
fund(env, gw, {bob}, {USD(10'000)}, Fund::Acct);
ammAlice.deposit(bob, 1'000'000);
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectBalances(
XRP(12'000), USD(12'000), IOUAmount{12'000'000, 0}));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{12'000'000'001},
USD(12'000),
IOUAmount{12'000'000, 0}));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{12'000'000'001},
USD(12'000),
IOUAmount{12'000'000, 0}));
// Initial state. Pay bidMin.
env(ammAlice.bid({.account = carol, .bidMin = 110})).close();
@@ -3131,16 +3074,10 @@ private:
BEAST_EXPECT(ammAlice.expectAuctionSlot(
0, std::nullopt, IOUAmount{110}));
// ~321.09 tokens burnt on bidding fees.
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectBalances(
XRP(12'000),
USD(12'000),
IOUAmount{11'999'678'91, -2}));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{12'000'000'001},
USD(12'000),
IOUAmount{11'999'678'91, -2}));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{12'000'000'001},
USD(12'000),
IOUAmount{11'999'678'91, -2}));
},
std::nullopt,
0,
@@ -3169,12 +3106,8 @@ private:
auto const slotPrice = IOUAmount{5'200};
ammTokens -= slotPrice;
BEAST_EXPECT(ammAlice.expectAuctionSlot(100, 0, slotPrice));
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectBalances(
XRP(13'000), USD(13'000), ammTokens));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003}, USD(13'000), ammTokens));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003}, USD(13'000), ammTokens));
// Discounted trade
for (int i = 0; i < 10; ++i)
{
@@ -3196,16 +3129,10 @@ private:
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(
XRP(13'000),
STAmount(USD, UINT64_C(13'002'98282151422), -11),
ammTokens));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003},
STAmount(USD, UINT64_C(13'002'98282151422), -11),
ammTokens));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003},
STAmount(USD, UINT64_C(13'002'98282151422), -11),
ammTokens));
ammTokens = ammAlice.getLPTokensBalance();
// Trade with the fee
for (int i = 0; i < 10; ++i)
@@ -3217,80 +3144,44 @@ private:
// carol, bob, ed. the discounted fee is 10 times less
// than the trading fee.
if (!features[fixAMMv1_3])
BEAST_EXPECT(
env.balance(dan, USD) ==
STAmount(USD, UINT64_C(19'490'05672274399), -11));
else
BEAST_EXPECT(
env.balance(dan, USD) ==
STAmount(USD, UINT64_C(19'490'05672274398), -11));
BEAST_EXPECT(
env.balance(dan, USD) ==
STAmount(USD, UINT64_C(19'490'05672274398), -11));
// USD pool gains more in dan's fees.
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectBalances(
XRP(13'000),
STAmount{USD, UINT64_C(13'012'92609877023), -11},
ammTokens));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003},
STAmount{USD, UINT64_C(13'012'92609877024), -11},
ammTokens));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003},
STAmount{USD, UINT64_C(13'012'92609877024), -11},
ammTokens));
// Discounted fee payment
ammAlice.deposit(carol, USD(100));
ammTokens = ammAlice.getLPTokensBalance();
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectBalances(
XRP(13'000),
STAmount{USD, UINT64_C(13'112'92609877023), -11},
ammTokens));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003},
STAmount{USD, UINT64_C(13'112'92609877024), -11},
ammTokens));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'003},
STAmount{USD, UINT64_C(13'112'92609877024), -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
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'100'000'668},
STAmount{USD, UINT64_C(13'012'92609877023), -11},
ammTokens));
else
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'100'000'671},
STAmount{USD, UINT64_C(13'012'92609877024), -11},
ammTokens));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'100'000'671},
STAmount{USD, UINT64_C(13'012'92609877024), -11},
ammTokens));
// Payment with the trading fee
env(pay(alice, carol, XRP(100)), path(~XRP), sendmax(USD(110)));
env.close();
// alice pays ~1.011USD in fees, which is ~10 times more
// than carol's fee
// 100.099431529USD swapped in for 100XRP
if (!features[fixAMMv1_3])
{
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'668},
STAmount{USD, UINT64_C(13'114'03663047269), -11},
ammTokens));
}
else
{
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'671},
STAmount{USD, UINT64_C(13'114'03663044937), -11},
ammTokens));
}
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'671},
STAmount{USD, UINT64_C(13'114'03663044937), -11},
ammTokens));
// Auction slot expired, no discounted fee
env.close(seconds(TOTAL_TIME_SLOT_SECS + 1));
// clock is parent's based
env.close();
if (!features[fixAMMv1_3])
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(29'399'00572620544), -11));
ammTokens = ammAlice.getLPTokensBalance();
for (int i = 0; i < 10; ++i)
{
@@ -3299,45 +3190,23 @@ private:
}
// carol pays ~9.94USD in fees, which is ~10 times more in
// trading fees vs discounted fee.
if (!features[fixAMMv1_3])
{
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(29'389'06197177124), -11));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'668},
STAmount{USD, UINT64_C(13'123'98038490689), -11},
ammTokens));
}
else
{
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(29'389'06197177129), -11));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'671},
STAmount{USD, UINT64_C(13'123'98038488352), -11},
ammTokens));
}
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(29'389'06197177129), -11));
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount{13'000'000'671},
STAmount{USD, UINT64_C(13'123'98038488352), -11},
ammTokens));
env(pay(carol, bob, USD(100)), path(~USD), sendmax(XRP(110)));
env.close();
// carol pays ~1.008XRP in trading fee, which is
// ~10 times more than the discounted fee.
// 99.815876XRP is swapped in for 100USD
if (!features[fixAMMv1_3])
{
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(13'100'824'790),
STAmount{USD, UINT64_C(13'023'98038490689), -11},
ammTokens));
}
else
{
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(13'100'824'793),
STAmount{USD, UINT64_C(13'023'98038488352), -11},
ammTokens));
}
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(13'100'824'793),
STAmount{USD, UINT64_C(13'023'98038488352), -11},
ammTokens));
},
std::nullopt,
1'000,
@@ -4819,10 +4688,7 @@ private:
carol, USD(100), std::nullopt, IOUAmount{520, 0});
// carol withdraws ~1,443.44USD
auto const balanceAfterWithdraw = [&]() {
if (!features[fixAMMv1_3])
return STAmount(USD, UINT64_C(30'443'43891402714), -11);
else
return STAmount(USD, UINT64_C(30'443'43891402713), -11);
return STAmount(USD, UINT64_C(30'443'43891402713), -11);
}();
BEAST_EXPECT(env.balance(carol, USD) == balanceAfterWithdraw);
// Set to original pool size
@@ -4832,22 +4698,12 @@ private:
ammAlice.vote(alice, 0);
BEAST_EXPECT(ammAlice.expectTradingFee(0));
auto const tokensNoFee = ammAlice.withdraw(carol, deposit);
if (!features[fixAMMv1_3])
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(30'443'43891402716), -11));
else
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(30'443'43891402713), -11));
BEAST_EXPECT(
env.balance(carol, USD) ==
STAmount(USD, UINT64_C(30'443'43891402713), -11));
// carol pays ~4008 LPTokens in fees or ~0.5% of the no-fee
// LPTokens
if (!features[fixAMMv1_3])
BEAST_EXPECT(
tokensNoFee == IOUAmount(746'579'80779912, -8));
else
BEAST_EXPECT(
tokensNoFee == IOUAmount(746'579'80779911, -8));
BEAST_EXPECT(tokensNoFee == IOUAmount(746'579'80779911, -8));
BEAST_EXPECT(tokensFee == IOUAmount(750'588'23529411, -8));
},
std::nullopt,
@@ -5109,40 +4965,24 @@ private:
// 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_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(ammAlice.expectBalances(
XRP(10'000),
STAmount{USD, UINT64_C(10'000'0000000003), -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)));
if (!features[fixAMMv1_3])
BEAST_EXPECT(expectLine(env, carol, USD(30'000)));
else
BEAST_EXPECT(expectLine(env, carol, USD(30'000)));
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_3])
BEAST_EXPECT(expectLine(
env,
nataly,
STAmount{USD, UINT64_C(1'500'000'000000005), -9}));
else
BEAST_EXPECT(expectLine(env, nataly, USD(1'500'000)));
BEAST_EXPECT(expectLine(env, nataly, USD(1'500'000)));
ammAlice.withdrawAll(alice);
BEAST_EXPECT(!ammAlice.ammExists());
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)));
BEAST_EXPECT(expectLine(
env,
alice,
STAmount{USD, UINT64_C(30'000'0000000003), -10}));
// alice XRP balance is 30,000initial - 50 ammcreate fee -
// 10drops fee
BEAST_EXPECT(accountBalance(env, alice) == "29949999990");
@@ -5192,66 +5032,36 @@ private:
ammAlice.withdrawAll(nataly, XRP(0));
}
auto const baseFee = env.current()->fees().base.drops();
if (!features[fixAMMv1_3])
{
// No round off with XRP in this test
BEAST_EXPECT(ammAlice.expectBalances(
XRP(10'000), USD(10'000), IOUAmount{10'000'000}));
ammAlice.withdrawAll(alice);
BEAST_EXPECT(!ammAlice.ammExists());
// 20,000 initial - (deposit+withdraw) * 10
auto const xrpBalance =
(XRP(2'000'000) - txfee(env, 20)).getText();
BEAST_EXPECT(accountBalance(env, ben) == xrpBalance);
BEAST_EXPECT(accountBalance(env, simon) == xrpBalance);
BEAST_EXPECT(accountBalance(env, chris) == xrpBalance);
BEAST_EXPECT(accountBalance(env, dan) == xrpBalance);
// 30,000 initial - (deposit+withdraw) * 10
BEAST_EXPECT(
accountBalance(env, carol) ==
std::to_string(30'000'000'000 - 20 * baseFee));
BEAST_EXPECT(accountBalance(env, ed) == xrpBalance);
BEAST_EXPECT(accountBalance(env, paul) == xrpBalance);
BEAST_EXPECT(accountBalance(env, nataly) == xrpBalance);
// 30,000 initial - 50 ammcreate fee - 10drops withdraw fee
BEAST_EXPECT(
accountBalance(env, alice) ==
std::to_string(29'950'000'000 - baseFee));
}
else
{
// post-amendment the rounding takes place to ensure
// AMM invariant
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(10'000'000'080),
USD(10'000),
IOUAmount{10'000'000}));
ammAlice.withdrawAll(alice);
BEAST_EXPECT(!ammAlice.ammExists());
auto const xrpBalance =
XRP(2'000'000) - txfee(env, 20) - drops(10);
auto const xrpBalanceText = xrpBalance.getText();
BEAST_EXPECT(accountBalance(env, ben) == xrpBalanceText);
BEAST_EXPECT(accountBalance(env, simon) == xrpBalanceText);
BEAST_EXPECT(accountBalance(env, chris) == xrpBalanceText);
BEAST_EXPECT(accountBalance(env, dan) == xrpBalanceText);
BEAST_EXPECT(
accountBalance(env, carol) ==
std::to_string(30'000'000'000 - 20 * baseFee - 10));
BEAST_EXPECT(
accountBalance(env, ed) ==
(xrpBalance + drops(2)).getText());
BEAST_EXPECT(
accountBalance(env, paul) ==
(xrpBalance + drops(3)).getText());
BEAST_EXPECT(
accountBalance(env, nataly) ==
(xrpBalance + drops(5)).getText());
BEAST_EXPECT(
accountBalance(env, alice) ==
std::to_string(29'950'000'000 - baseFee + 80));
}
// post-amendment the rounding takes place to ensure
// AMM invariant
BEAST_EXPECT(ammAlice.expectBalances(
XRPAmount(10'000'000'080),
USD(10'000),
IOUAmount{10'000'000}));
ammAlice.withdrawAll(alice);
BEAST_EXPECT(!ammAlice.ammExists());
auto const xrpBalance =
XRP(2'000'000) - txfee(env, 20) - drops(10);
auto const xrpBalanceText = xrpBalance.getText();
BEAST_EXPECT(accountBalance(env, ben) == xrpBalanceText);
BEAST_EXPECT(accountBalance(env, simon) == xrpBalanceText);
BEAST_EXPECT(accountBalance(env, chris) == xrpBalanceText);
BEAST_EXPECT(accountBalance(env, dan) == xrpBalanceText);
BEAST_EXPECT(
accountBalance(env, carol) ==
std::to_string(30'000'000'000 - 20 * baseFee - 10));
BEAST_EXPECT(
accountBalance(env, ed) ==
(xrpBalance + drops(2)).getText());
BEAST_EXPECT(
accountBalance(env, paul) ==
(xrpBalance + drops(3)).getText());
BEAST_EXPECT(
accountBalance(env, nataly) ==
(xrpBalance + drops(5)).getText());
BEAST_EXPECT(
accountBalance(env, alice) ==
std::to_string(29'950'000'000 - baseFee + 80));
},
std::nullopt,
0,
@@ -6374,7 +6184,7 @@ private:
})
{
testcase(input.testCase);
for (auto const& features : {all - fixAMMv1_3, all})
for (auto const& features : {all})
{
// Env env(*this, features,
// std::make_unique<CaptureLogs>(&logs));
@@ -6432,8 +6242,7 @@ private:
auto const goodUsdGH = input.goodUsdGHr;
auto const goodUsdBIT = input.goodUsdBITr;
auto const lpTokenBalance =
env.enabled(fixAMMv1_3) && input.lpTokenBalanceAlt
auto const lpTokenBalance = input.lpTokenBalanceAlt
? *input.lpTokenBalanceAlt
: input.lpTokenBalance;
@@ -6973,8 +6782,7 @@ private:
};
test(
[&](AMM& amm, Env& env) {
auto const err = env.enabled(fixAMMv1_3) ? ter(tesSUCCESS)
: ter(tecUNFUNDED_AMM);
auto const err = ter(tesSUCCESS);
amm.deposit(DepositArg{
.account = alice, .asset1In = amount, .err = err});
},
@@ -6986,10 +6794,7 @@ private:
amm.withdraw(WithdrawArg{.asset1Out = STAmount{XPM, 1, -5}});
auto const [amount_, amount2_, lptAMM_] =
amm.balances(XRP, XPM);
if (!env.enabled(fixAMMv1_3))
BEAST_EXPECT((amount2 - amount2_) > withdraw);
else
BEAST_EXPECT((amount2 - amount2_) <= withdraw);
BEAST_EXPECT((amount2 - amount2_) <= withdraw);
},
0);
}
@@ -7003,8 +6808,7 @@ private:
{
auto const [amount, amount2, lptBalance] = amm.balances(GBP, EUR);
NumberRoundModeGuard g(
env.enabled(fixAMMv1_3) ? Number::upward : Number::getround());
NumberRoundModeGuard g(Number::upward);
auto const res = root2(amount * amount2);
if (shouldFail)
@@ -7046,7 +6850,7 @@ private:
env,
"dep1",
deposit == STAmount{EUR, 1, -3} &&
!env.enabled(fixAMMv1_3));
!true /*env.enabled(fixAMMv1_3)*/);
},
{{GBP(30'000), EUR(30'000)}},
0,
@@ -7107,7 +6911,7 @@ private:
ammAlice,
env,
"dep3",
exponent != -3 && !env.enabled(fixAMMv1_3));
exponent != -3 && !true /*env.enabled(fixAMMv1_3)*/);
},
{{GBP(10'000), EUR(30'000)}},
0,
@@ -7329,51 +7133,35 @@ private:
testFeeVote();
testInvalidBid();
testBid(all);
testBid(all - fixAMMv1_3);
testInvalidAMMPayment();
testBasicPaymentEngine(all);
testBasicPaymentEngine(all - fixAMMv1_3);
testBasicPaymentEngine(all - fixReducedOffersV2);
testBasicPaymentEngine(all - fixAMMv1_3 - fixReducedOffersV2);
testAMMTokens();
testAmendment();
testFlags();
testRippling();
testAMMAndCLOB(all);
testAMMAndCLOB(all - fixAMMv1_3);
testTradingFee(all);
testTradingFee(all - fixAMMv1_3);
testAdjustedTokens(all);
testAdjustedTokens(all - fixAMMv1_3);
testAutoDelete();
testClawback();
testAMMID();
testSelection(all);
testSelection(all - fixAMMv1_3);
testFixDefaultInnerObj();
testMalformed();
testFixOverflowOffer(all);
testFixOverflowOffer(all - fixAMMv1_3);
testSwapRounding();
testFixChangeSpotPriceQuality(all);
testFixChangeSpotPriceQuality(all - fixAMMv1_3);
testFixAMMOfferBlockedByLOB(all);
testFixAMMOfferBlockedByLOB(all - fixAMMv1_3);
testLPTokenBalance(all);
testLPTokenBalance(all - fixAMMv1_3);
testAMMClawback(all);
testAMMClawback(all - featureAMMClawback);
testAMMClawback(all - fixAMMv1_3 - featureAMMClawback);
testAMMDepositWithFrozenAssets(all);
testAMMDepositWithFrozenAssets(all - featureAMMClawback);
testAMMDepositWithFrozenAssets(all - fixAMMv1_3 - featureAMMClawback);
testFixReserveCheckOnWithdrawal(all);
testDepositAndWithdrawRounding(all);
testDepositAndWithdrawRounding(all - fixAMMv1_3);
testDepositRounding(all);
testDepositRounding(all - fixAMMv1_3);
testWithdrawRounding(all);
testWithdrawRounding(all - fixAMMv1_3);
// testFailedPseudoAccount();
}
};

View File

@@ -42,12 +42,6 @@ number(STAmount const& a)
IOUAmount
AMM::initialTokens()
{
if (!env_.enabled(fixAMMv1_3))
{
auto const product = number(asset1_) * number(asset2_);
return (IOUAmount)(product.mantissa() >= 0 ? root2(product)
: root2(-product));
}
return getLPTokensBalance();
}

View File

@@ -218,10 +218,7 @@ public:
{
Account a(std::to_string(i));
votes.insert({a.human(), 50 * (i + 1)});
if (!features[fixAMMv1_3])
fund(env, gw, {a}, {USD(10000)}, Fund::Acct);
else
fund(env, gw, {a}, {USD(10001)}, Fund::Acct);
fund(env, gw, {a}, {USD(10001)}, Fund::Acct);
ammAlice.deposit(a, 10000000);
ammAlice.vote(a, 50 * (i + 1));
}
@@ -231,22 +228,13 @@ public:
env.fund(XRP(1000), bob, ed, bill);
env(ammAlice.bid(
{.bidMin = 100, .authAccounts = {carol, bob, ed, bill}}));
if (!features[fixAMMv1_3])
BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
XRP(80000),
USD(80000),
IOUAmount{79994400},
std::nullopt,
std::nullopt,
ammAlice.ammAccount()));
else
BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
XRPAmount(80000000005),
STAmount{USD, UINT64_C(80'000'00000000005), -11},
IOUAmount{79994400},
std::nullopt,
std::nullopt,
ammAlice.ammAccount()));
BEAST_EXPECT(ammAlice.expectAmmRpcInfo(
XRPAmount(80000000005),
STAmount{USD, UINT64_C(80'000'00000000005), -11},
IOUAmount{79994400},
std::nullopt,
std::nullopt,
ammAlice.ammAccount()));
for (auto i = 0; i < 2; ++i)
{
std::unordered_set<std::string> authAccounts = {
@@ -363,7 +351,6 @@ public:
testErrors();
testSimpleRpc();
testVoteAndBid(all);
testVoteAndBid(all - fixAMMv1_3);
testFreeze();
testInvalidAmmField();
}

View File

@@ -590,13 +590,6 @@ getRoundedAsset(
A const& frac,
IsDeposit isDeposit)
{
if (!rules.enabled(fixAMMv1_3))
{
if constexpr (std::is_same_v<A, STAmount>)
return multiply(balance, frac, balance.issue());
else
return toSTAmount(balance.issue(), balance * frac);
}
auto const rm = detail::getAssetRounding(isDeposit);
return multiply(balance, frac, rm);
}

View File

@@ -28,8 +28,7 @@ ammLPTokens(
Issue const& lptIssue)
{
// AMM invariant: sqrt(asset1 * asset2) >= LPTokensBalance
auto const rounding =
isFeatureEnabled(fixAMMv1_3) ? Number::downward : Number::getround();
auto const rounding = Number::downward;
NumberRoundModeGuard g(rounding);
auto const tokens = root2(asset1 * asset2);
return toSTAmount(lptIssue, tokens);
@@ -52,17 +51,10 @@ lpTokensOut(
auto const f2 = feeMultHalf(tfee) / f1;
Number const r = asset1Deposit / asset1Balance;
auto const c = root2(f2 * f2 + r / f1) - f2;
if (!isFeatureEnabled(fixAMMv1_3))
{
auto const t = lptAMMBalance * (r - c) / (1 + c);
return toSTAmount(lptAMMBalance.issue(), t);
}
else
{
// minimize tokens out
auto const frac = (r - c) / (1 + c);
return multiply(lptAMMBalance, frac, Number::downward);
}
// minimize tokens out
auto const frac = (r - c) / (1 + c);
return multiply(lptAMMBalance, frac, Number::downward);
}
/* Equation 4 solves equation 3 for b:
@@ -91,17 +83,10 @@ ammAssetIn(
auto const a = 1 / (t2 * t2);
auto const b = 2 * d / t2 - 1 / f1;
auto const c = d * d - f2 * f2;
if (!isFeatureEnabled(fixAMMv1_3))
{
return toSTAmount(
asset1Balance.issue(), asset1Balance * solveQuadraticEq(a, b, c));
}
else
{
// maximize deposit
auto const frac = solveQuadraticEq(a, b, c);
return multiply(asset1Balance, frac, Number::upward);
}
// maximize deposit
auto const frac = solveQuadraticEq(a, b, c);
return multiply(asset1Balance, frac, Number::upward);
}
/* Equation 7:
@@ -118,17 +103,10 @@ lpTokensIn(
Number const fr = asset1Withdraw / asset1Balance;
auto const f1 = getFee(tfee);
auto const c = fr * f1 + 2 - f1;
if (!isFeatureEnabled(fixAMMv1_3))
{
auto const t = lptAMMBalance * (c - root2(c * c - 4 * fr)) / 2;
return toSTAmount(lptAMMBalance.issue(), t);
}
else
{
// maximize tokens in
auto const frac = (c - root2(c * c - 4 * fr)) / 2;
return multiply(lptAMMBalance, frac, Number::upward);
}
// maximize tokens in
auto const frac = (c - root2(c * c - 4 * fr)) / 2;
return multiply(lptAMMBalance, frac, Number::upward);
}
/* Equation 8 solves equation 7 for b:
@@ -150,17 +128,10 @@ ammAssetOut(
{
auto const f = getFee(tfee);
Number const t1 = lpTokens / lptAMMBalance;
if (!isFeatureEnabled(fixAMMv1_3))
{
auto const b = assetBalance * (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1);
return toSTAmount(assetBalance.issue(), b);
}
else
{
// minimize withdraw
auto const frac = (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1);
return multiply(assetBalance, frac, Number::downward);
}
// minimize withdraw
auto const frac = (t1 * t1 - t1 * (2 - f)) / (t1 * f - 1);
return multiply(assetBalance, frac, Number::downward);
}
Number
@@ -194,48 +165,7 @@ adjustAmountsByLPTokens(
IsDeposit isDeposit)
{
// AMMv1_3 amendment adjusts tokens and amounts in deposit/withdraw
if (isFeatureEnabled(fixAMMv1_3))
return std::make_tuple(amount, amount2, lpTokens);
auto const lpTokensActual =
adjustLPTokens(lptAMMBalance, lpTokens, isDeposit);
if (lpTokensActual == beast::zero)
{
auto const amount2Opt =
amount2 ? std::make_optional(STAmount{}) : std::nullopt;
return std::make_tuple(STAmount{}, amount2Opt, lpTokensActual);
}
if (lpTokensActual < lpTokens)
{
// Equal trade
if (amount2)
{
Number const fr = lpTokensActual / lpTokens;
auto const amountActual = toSTAmount(amount.issue(), fr * amount);
auto const amount2Actual =
toSTAmount(amount2->issue(), fr * *amount2);
return std::make_tuple(amountActual, amount2Actual, lpTokensActual);
}
// Single trade
auto const amountActual = [&]() {
if (isDeposit == IsDeposit::Yes)
return ammAssetIn(
amountBalance, lptAMMBalance, lpTokensActual, tfee);
return ammAssetOut(
amountBalance, lptAMMBalance, lpTokensActual, tfee);
}();
return std::make_tuple(amountActual, std::nullopt, lpTokensActual);
}
XRPL_ASSERT(
lpTokensActual == lpTokens,
"ripple::adjustAmountsByLPTokens : LP tokens match actual");
return {amount, amount2, lpTokensActual};
return std::make_tuple(amount, amount2, lpTokens);
}
Number
@@ -275,9 +205,6 @@ getRoundedAsset(
std::function<Number()>&& productCb,
IsDeposit isDeposit)
{
if (!rules.enabled(fixAMMv1_3))
return toSTAmount(balance.issue(), noRoundCb());
auto const rm = detail::getAssetRounding(isDeposit);
if (isDeposit == IsDeposit::Yes)
return multiply(balance, productCb(), rm);
@@ -292,9 +219,6 @@ getRoundedLPTokens(
Number const& frac,
IsDeposit isDeposit)
{
if (!rules.enabled(fixAMMv1_3))
return toSTAmount(balance.issue(), balance * frac);
auto const rm = detail::getLPTokenRounding(isDeposit);
auto const tokens = multiply(balance, frac, rm);
return adjustLPTokens(balance, tokens, isDeposit);
@@ -308,9 +232,6 @@ getRoundedLPTokens(
std::function<Number()>&& productCb,
IsDeposit isDeposit)
{
if (!rules.enabled(fixAMMv1_3))
return toSTAmount(lptAMMBalance.issue(), noRoundCb());
auto const tokens = [&] {
auto const rm = detail::getLPTokenRounding(isDeposit);
if (isDeposit == IsDeposit::Yes)
@@ -332,8 +253,6 @@ adjustAssetInByTokens(
STAmount const& tokens,
std::uint16_t tfee)
{
if (!rules.enabled(fixAMMv1_3))
return {tokens, amount};
auto assetAdj = ammAssetIn(balance, lptAMMBalance, tokens, tfee);
auto tokensAdj = tokens;
// Rounding didn't work the right way.
@@ -358,8 +277,6 @@ adjustAssetOutByTokens(
STAmount const& tokens,
std::uint16_t tfee)
{
if (!rules.enabled(fixAMMv1_3))
return {tokens, amount};
auto assetAdj = ammAssetOut(balance, lptAMMBalance, tokens, tfee);
auto tokensAdj = tokens;
// Rounding didn't work the right way.
@@ -382,8 +299,6 @@ adjustFracByTokens(
STAmount const& tokens,
Number const& frac)
{
if (!rules.enabled(fixAMMv1_3))
return frac;
return tokens / lptAMMBalance;
}

View File

@@ -79,7 +79,7 @@ AMMBid::preflight(PreflightContext const& ctx)
JLOG(ctx.j.debug()) << "AMM Bid: Invalid number of AuthAccounts.";
return temMALFORMED;
}
else if (ctx.rules.enabled(fixAMMv1_3))
else
{
AccountID account = ctx.tx[sfAccount];
std::set<AccountID> unique;

View File

@@ -634,8 +634,6 @@ adjustLPTokensOut(
STAmount const& lptAMMBalance,
STAmount const& lpTokensDeposit)
{
if (!rules.enabled(fixAMMv1_3))
return lpTokensDeposit;
return adjustLPTokens(lptAMMBalance, lpTokensDeposit, IsDeposit::Yes);
}
@@ -658,7 +656,7 @@ AMMDeposit::equalDepositTokens(
{
auto const tokensAdj =
adjustLPTokensOut(view.rules(), lptAMMBalance, lpTokensDeposit);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}};
auto const frac =
divide(tokensAdj, lptAMMBalance, lptAMMBalance.issue());
@@ -735,10 +733,7 @@ AMMDeposit::equalDepositLimit(
getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::Yes);
if (tokensAdj == beast::zero)
{
if (!view.rules().enabled(fixAMMv1_3))
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
else
return {tecAMM_INVALID_TOKENS, STAmount{}};
return {tecAMM_INVALID_TOKENS, STAmount{}};
}
// factor in the adjusted tokens
frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac);
@@ -762,10 +757,7 @@ AMMDeposit::equalDepositLimit(
getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::Yes);
if (tokensAdj == beast::zero)
{
if (!view.rules().enabled(fixAMMv1_3))
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
else
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
}
// factor in the adjusted tokens
frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac);
@@ -811,15 +803,12 @@ AMMDeposit::singleDeposit(
lpTokensOut(amountBalance, amount, lptAMMBalance, tfee));
if (tokens == beast::zero)
{
if (!view.rules().enabled(fixAMMv1_3))
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
else
return {tecAMM_INVALID_TOKENS, STAmount{}};
return {tecAMM_INVALID_TOKENS, STAmount{}};
}
// factor in the adjusted tokens
auto const [tokensAdj, amountDepositAdj] = adjustAssetInByTokens(
view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
return deposit(
view,
@@ -854,7 +843,7 @@ AMMDeposit::singleDepositTokens(
{
auto const tokensAdj =
adjustLPTokensOut(view.rules(), lptAMMBalance, lpTokensDeposit);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}};
// the adjusted tokens are factored in
auto const amountDeposit =
@@ -918,15 +907,12 @@ AMMDeposit::singleDepositEPrice(
lpTokensOut(amountBalance, amount, lptAMMBalance, tfee));
if (tokens <= beast::zero)
{
if (!view.rules().enabled(fixAMMv1_3))
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
else
return {tecAMM_INVALID_TOKENS, STAmount{}};
return {tecAMM_INVALID_TOKENS, STAmount{}};
}
// factor in the adjusted tokens
auto const [tokensAdj, amountDepositAdj] = adjustAssetInByTokens(
view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
auto const ep = Number{amountDepositAdj} / tokensAdj;
if (ep <= ePrice)
@@ -988,7 +974,7 @@ AMMDeposit::singleDepositEPrice(
lptAMMBalance,
tokens,
tfee);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
return deposit(

View File

@@ -689,7 +689,7 @@ adjustLPTokensIn(
STAmount const& lpTokensWithdraw,
WithdrawAll withdrawAll)
{
if (!rules.enabled(fixAMMv1_3) || withdrawAll == WithdrawAll::Yes)
if (withdrawAll == WithdrawAll::Yes)
return lpTokensWithdraw;
return adjustLPTokens(lptAMMBalance, lpTokensWithdraw, IsDeposit::No);
}
@@ -801,7 +801,7 @@ AMMWithdraw::equalWithdrawTokens(
auto const tokensAdj = adjustLPTokensIn(
view.rules(), lptAMMBalance, lpTokensWithdraw, withdrawAll);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {
tecAMM_INVALID_TOKENS, STAmount{}, STAmount{}, std::nullopt};
// the adjusted tokens are factored in
@@ -885,7 +885,7 @@ AMMWithdraw::equalWithdrawLimit(
getRoundedAsset(view.rules(), amount2Balance, frac, IsDeposit::No);
auto tokensAdj =
getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::No);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}};
// factor in the adjusted tokens
frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac);
@@ -910,21 +910,13 @@ AMMWithdraw::equalWithdrawLimit(
getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No);
tokensAdj =
getRoundedLPTokens(view.rules(), lptAMMBalance, frac, IsDeposit::No);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
// factor in the adjusted tokens
frac = adjustFracByTokens(view.rules(), lptAMMBalance, tokensAdj, frac);
amountWithdraw =
getRoundedAsset(view.rules(), amountBalance, frac, IsDeposit::No);
if (!view.rules().enabled(fixAMMv1_3))
{
// LCOV_EXCL_START
XRPL_ASSERT(
amountWithdraw <= amount,
"ripple::AMMWithdraw::equalWithdrawLimit : maximum amountWithdraw");
// LCOV_EXCL_STOP
}
else if (amountWithdraw > amount)
if (amountWithdraw > amount)
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
return withdraw(
view,
@@ -960,15 +952,12 @@ AMMWithdraw::singleWithdraw(
isWithdrawAll(ctx_.tx));
if (tokens == beast::zero)
{
if (!view.rules().enabled(fixAMMv1_3))
return {tecAMM_FAILED, STAmount{}}; // LCOV_EXCL_LINE
else
return {tecAMM_INVALID_TOKENS, STAmount{}};
return {tecAMM_INVALID_TOKENS, STAmount{}};
}
// factor in the adjusted tokens
auto const [tokensAdj, amountWithdrawAdj] = adjustAssetOutByTokens(
view.rules(), amountBalance, amount, lptAMMBalance, tokens, tfee);
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}}; // LCOV_EXCL_LINE
return withdraw(
view,
@@ -1005,7 +994,7 @@ AMMWithdraw::singleWithdrawTokens(
{
auto const tokensAdj = adjustLPTokensIn(
view.rules(), lptAMMBalance, lpTokensWithdraw, isWithdrawAll(ctx_.tx));
if (view.rules().enabled(fixAMMv1_3) && tokensAdj == beast::zero)
if (tokensAdj == beast::zero)
return {tecAMM_INVALID_TOKENS, STAmount{}};
// the adjusted tokens are factored in
auto const amountWithdraw =
@@ -1080,10 +1069,7 @@ AMMWithdraw::singleWithdrawEPrice(
view.rules(), tokNoRoundCb, lptAMMBalance, tokProdCb, IsDeposit::No);
if (tokensAdj <= beast::zero)
{
if (!view.rules().enabled(fixAMMv1_3))
return {tecAMM_FAILED, STAmount{}};
else
return {tecAMM_INVALID_TOKENS, STAmount{}};
return {tecAMM_INVALID_TOKENS, STAmount{}};
}
auto amtNoRoundCb = [&] { return tokensAdj / ePrice; };
auto amtProdCb = [&] { return tokensAdj / ePrice; };

View File

@@ -1954,7 +1954,7 @@ ValidAMM::finalize(
if (result != tesSUCCESS && result != tecINCOMPLETE)
return true;
bool const enforce = view.rules().enabled(fixAMMv1_3);
bool const enforce = true; // view.rules().enabled(fixAMMv1_3);
switch (tx.getTxnType())
{

View File

@@ -173,9 +173,6 @@ public:
bool
checkInvariant(TAmounts<TIn, TOut> const& consumed, beast::Journal j) const
{
if (!isFeatureEnabled(fixAMMv1_3))
return true;
if (consumed.in > m_amounts.in || consumed.out > m_amounts.out)
{
// LCOV_EXCL_START