40 for (
auto const& feature : {features, features - featureSingleAssetVault})
42 Env env(*
this, feature);
46 env.
fund(
XRP(100000), gw, alice, bob);
49 env(
fset(gw, asfAllowTrustLineClawback));
59 auto const usd = gw[
"USD"];
60 env.
trust(usd(10000), alice);
61 env(
pay(gw, alice, usd(100)));
64 AMM amm(env, gw, btc(100), usd(100));
76 gw, alice,
Issue{gw[
"USD"].currency, alice.
id()}, btc, std::nullopt),
85 gw, alice, usd, btc,
STAmount{
Issue{gw[
"USD"].currency, alice.
id()}, 1}),
103 Issue const ammUsd(usd.currency,
amm.ammAccount());
107 env(
claw(gw, amount),
Ter(err));
114 BEAST_EXPECT(!
amm.ammExists());
122 Env env(*
this, features);
125 env.
fund(
XRP(100000), gw, alice);
128 env(
fset(gw, asfAllowTrustLineClawback));
132 MPTTester({.env = env, .issuer = gw, .holders = {alice}, .pay = 40'000});
134 auto const usd = gw[
"USD"];
135 env.
trust(usd(10000), alice);
136 env(
pay(gw, alice, usd(10000)));
139 AMM amm(env, gw, btc(100), usd(100));
141 amm.deposit(alice, 1'000);
150 Env env(*
this, features);
154 env.
fund(
XRP(100000), gw, gw2, alice);
157 env(
fset(gw, asfAllowTrustLineClawback));
160 auto const usd = gw[
"USD"];
161 env.
trust(usd(10000), alice);
162 env(
pay(gw, alice, usd(10000)));
173 AMM const amm(env, alice, btc(100), usd(100));
190 Env env(*
this, features);
193 env.
fund(
XRP(10000), gw, alice);
203 AMM const amm(env, alice, btc(100),
XRP(100));
250 testcase(
"test AMMClawback specific amount");
255 Env env(*
this, features);
259 env.
fund(
XRP(100000), gw, gw2, alice);
262 env(
fset(gw, asfAllowTrustLineClawback));
263 env(
fset(gw2, asfAllowTrustLineClawback));
266 auto const usd = gw[
"USD"];
267 env.
trust(usd(100000), alice);
268 env(
pay(gw, alice, usd(50000)));
275 .pay = 40'000'000000,
278 AMM const amm(env, alice, btc(1000000000), usd(2000));
280 BEAST_EXPECT(
amm.expectBalances(
281 btc(1'000'000000), usd(2000),
IOUAmount{1414'213'562373095, -9}));
289 auto aliceUSD = env.
balance(alice, usd);
290 auto aliceBTC = env.
balance(alice, btc);
296 amm.expectBalances(btc(500'000000), usd(1000),
IOUAmount{707'106'7811865475, -10}));
301 aliceBTC = env.
balance(alice, btc);
307 amm.expectBalances(btc(250'000000), usd(500),
IOUAmount{353'553'3905932737, -10}));
310 aliceUSD = env.
balance(alice, usd);
316 BEAST_EXPECT(!
amm.ammExists());
323 Env env(*
this, features);
327 env.
fund(
XRP(100000), gw, alice, bob);
330 env(
fset(gw, asfAllowTrustLineClawback));
336 .holders = {alice, bob},
337 .pay = 40'000'000000,
340 AMM amm(env, alice, btc(1000000000),
XRP(2000));
342 BEAST_EXPECT(
amm.expectBalances(
343 btc(1'000'000000),
XRP(2000),
IOUAmount{1'414'213'562'373095, -6}));
345 amm.deposit(bob, btc(2'000'000000),
XRP(4000));
346 BEAST_EXPECT(
amm.expectBalances(
347 btc(3'000'000000),
XRP(6000),
IOUAmount{4'242'640'687'119285, -6}));
350 auto aliceBTC = env.
balance(alice, btc);
352 auto bobBTC = env.
balance(bob, btc);
364 BEAST_EXPECT(
amm.expectBalances(
372 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'414'212'855'266314, -6}));
373 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'828'427'124'74619, -5}));
379 BEAST_EXPECT(
amm.expectBalances(
387 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'414'212'855'266314, -6}));
388 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{1'414'213'562'844499, -6}));
395 BEAST_EXPECT(
amm.expectBalances(
402 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{1'414'213'562'844499, -6}));
409 BEAST_EXPECT(!
amm.ammExists());
418 Env env(*
this, features);
423 env.
fund(
XRP(100000), gw, gw2, alice, bob);
426 env(
fset(gw, asfAllowTrustLineClawback));
427 env(
fset(gw2, asfAllowTrustLineClawback));
433 .holders = {alice, bob},
434 .pay = 40'000'000000,
440 .holders = {alice, bob},
441 .pay = 30'000'000000,
444 AMM amm(env, alice, btc(2'000'000000), eth(3'000'000000));
446 BEAST_EXPECT(
amm.expectBalances(
447 btc(2'000'000000), eth(3'000'000000),
IOUAmount{2'449'489'742'783178, -6}));
449 amm.deposit(bob, btc(4'000'000000), eth(6'000'000000));
450 BEAST_EXPECT(
amm.expectBalances(
451 btc(6'000'000000), eth(9'000'000000),
IOUAmount{7'348'469'228'349534, -6}));
453 auto aliceBTC = env.
balance(alice, btc);
454 auto aliceETH = env.
balance(alice, eth);
455 auto bobBTC = env.
balance(bob, btc);
456 auto bobETH = env.
balance(bob, eth);
461 BEAST_EXPECT(
amm.expectBalances(
462 btc(5'000'000000), eth(7'500'000000),
IOUAmount{6'123'724'356'957944, -6}));
467 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
468 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{4'898'979'485'566356, -6}));
469 aliceETH = env.
balance(alice, eth);
474 BEAST_EXPECT(
amm.expectBalances(
475 btc(3'000'000000), eth(4'500'000000),
IOUAmount{3'674'234'614'174766, -6}));
480 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
481 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'449'489'742'783178, -6}));
482 bobBTC = env.
balance(bob, btc);
487 BEAST_EXPECT(
amm.expectBalances(
488 btc(2'000'000001), eth(3'000'000001),
IOUAmount{2'449'489'742'783178, -6}));
493 aliceBTC = env.
balance(alice, btc);
499 BEAST_EXPECT(!
amm.ammExists());
512 testcase(
"test AMMClawback amount that rounds down to zero");
515 Env env(*
this, features);
519 env.
fund(
XRP(10'000'000), gw, alice, bob);
522 env(
fset(gw, asfAllowTrustLineClawback));
531 .holders = {alice, bob},
534 MPT const btc = mptBtc;
536 AMM amm(env, alice, btc(3),
XRP(333'000));
537 amm.deposit(bob, btc(3),
XRP(333'000));
539 [[maybe_unused]]
auto const [poolBtcBefore, poolXrpBefore, lptBefore] =
amm.balances();
540 BEAST_EXPECT(poolBtcBefore == btc(6));
542 auto const issuerOABefore = mptBtc.getBalance(gw);
543 auto const aliceLpBefore =
amm.getLPTokensBalance(alice.
id());
544 auto const bobLpBefore =
amm.getLPTokensBalance(bob.
id());
553 [[maybe_unused]]
auto const [poolBtcAfter, poolXrpAfter, lptAfter] =
amm.balances();
554 auto const issuerOAAfter = mptBtc.getBalance(gw);
555 auto const aliceLpAfter =
amm.getLPTokensBalance(alice.
id());
556 auto const bobLpAfter =
amm.getLPTokensBalance(bob.
id());
558 if (features[fixCleanup3_4_0])
562 BEAST_EXPECT(poolBtcAfter == poolBtcBefore);
563 BEAST_EXPECT(poolXrpAfter == poolXrpBefore);
564 BEAST_EXPECT(issuerOAAfter == issuerOABefore);
565 BEAST_EXPECT(aliceLpAfter == aliceLpBefore);
566 BEAST_EXPECT(bobLpAfter == bobLpBefore);
572 BEAST_EXPECT(poolBtcAfter == poolBtcBefore);
573 BEAST_EXPECT(poolXrpAfter < poolXrpBefore);
574 BEAST_EXPECT(issuerOAAfter == issuerOABefore);
575 BEAST_EXPECT(aliceLpAfter < aliceLpBefore);
576 BEAST_EXPECT(bobLpAfter == bobLpBefore);
588 env.
fund(
XRP(10'000'000), carol, dan);
594 .holders = {carol, dan},
597 MPT const btc = mptBtc;
602 .holders = {carol, dan},
605 MPT const eth = mptEth;
609 AMM amm(env, carol, btc(3'000), eth(3));
610 amm.deposit(dan, btc(3'000), eth(3));
612 [[maybe_unused]]
auto const [poolBtcBefore, poolEthBefore, lptBefore] =
amm.balances();
613 BEAST_EXPECT(poolBtcBefore == btc(6'000));
614 BEAST_EXPECT(poolEthBefore == eth(6));
616 auto const carolLpBefore =
amm.getLPTokensBalance(carol.
id());
617 auto const danLpBefore =
amm.getLPTokensBalance(dan.
id());
623 [[maybe_unused]]
auto const [poolBtcAfter, poolEthAfter, lptAfter] =
amm.balances();
624 auto const carolLpAfter =
amm.getLPTokensBalance(carol.
id());
625 auto const danLpAfter =
amm.getLPTokensBalance(dan.
id());
627 if (features[fixCleanup3_4_0])
632 BEAST_EXPECT(poolBtcAfter == poolBtcBefore);
633 BEAST_EXPECT(poolEthAfter == poolEthBefore);
634 BEAST_EXPECT(carolLpAfter == carolLpBefore);
635 BEAST_EXPECT(danLpAfter == danLpBefore);
643 BEAST_EXPECT(poolBtcAfter < poolBtcBefore);
644 BEAST_EXPECT(poolEthAfter == poolEthBefore);
645 BEAST_EXPECT(carolLpAfter < carolLpBefore);
646 BEAST_EXPECT(danLpAfter == danLpBefore);
659 Env env(*
this, features);
664 env.
fund(
XRP(100000), gw, gw2, alice, bob);
667 env(
fset(gw, asfAllowTrustLineClawback));
668 env(
fset(gw2, asfAllowTrustLineClawback));
671 auto const usd = gw[
"USD"];
672 env.
trust(usd(100000), alice);
673 env(
pay(gw, alice, usd(50000)));
674 env.
trust(usd(200000), bob);
675 env(
pay(gw, bob, usd(60000)));
681 .holders = {alice, bob},
682 .pay = 40'000'000000,
685 AMM amm(env, alice, btc(2000000000), usd(2000));
687 BEAST_EXPECT(
amm.expectBalances(btc(2'000'000000), usd(2000),
IOUAmount(2000000)));
690 amm.deposit(bob, btc(1'000'000000), usd(2000));
691 BEAST_EXPECT(
amm.expectBalances(btc(3'000'000000), usd(3000),
IOUAmount(3000000)));
693 auto aliceBTC = env.
balance(alice, btc);
694 auto aliceUSD = env.
balance(alice, usd);
695 auto bobBTC = env.
balance(bob, btc);
696 auto bobUSD = env.
balance(bob, usd);
701 BEAST_EXPECT(
amm.expectBalances(btc(1'000'000000), usd(1000),
IOUAmount(1000000)));
706 aliceUSD = env.
balance(alice, usd);
712 BEAST_EXPECT(!
amm.ammExists());
721 Env env(*
this, features);
725 env.
fund(
XRP(100000), gw, alice, bob);
728 env(
fset(gw, asfAllowTrustLineClawback));
734 .holders = {alice, bob},
735 .pay = 40'000'000000,
738 AMM amm(env, alice, btc(5000),
XRP(10'000));
741 amm.expectBalances(btc(5'000),
XRP(10'000),
IOUAmount{7'071'067'811865475, -9}));
743 amm.deposit(bob, btc(10'000),
XRP(20'000));
745 amm.expectBalances(btc(15'000),
XRP(30'000),
IOUAmount{21'213'203'43559642, -8}));
748 auto aliceBTC = env.
balance(alice, btc);
750 auto bobBTC = env.
balance(bob, btc);
756 amm.expectBalances(btc(10'000),
XRP(20'000),
IOUAmount{14'142'135'62373094, -8}));
767 BEAST_EXPECT(!
amm.ammExists());
776 Env env(*
this, features);
781 env.
fund(
XRP(100000), gw, gw2, alice, bob);
784 env(
fset(gw, asfAllowTrustLineClawback));
785 env(
fset(gw2, asfAllowTrustLineClawback));
791 .holders = {alice, bob},
792 .pay = 40'000'000000,
798 .holders = {alice, bob},
799 .pay = 30'000'000000,
802 AMM amm(env, alice, btc(20'000), eth(50'000));
805 amm.expectBalances(btc(20'000), eth(50'000),
IOUAmount{31'622'77660168379, -11}));
807 amm.deposit(bob, btc(40'000), eth(100'000));
809 amm.expectBalances(btc(60'000), eth(150'000),
IOUAmount{94'868'32980505137, -11}));
811 auto aliceBTC = env.
balance(alice, btc);
812 auto aliceETH = env.
balance(alice, eth);
813 auto bobBTC = env.
balance(bob, btc);
814 auto bobETH = env.
balance(bob, eth);
820 amm.expectBalances(btc(20'000), eth(50'000),
IOUAmount{31'622'77660168379, -11}));
825 bobETH = env.
balance(bob, eth);
831 BEAST_EXPECT(!
amm.ammExists());
842 testcase(
"test AMMClawback specific amount, assets have the same issuer");
847 Env env(*
this, features);
851 env.
fund(
XRP(100000), gw, alice, bob);
854 env(
fset(gw, asfAllowTrustLineClawback));
857 auto const usd = gw[
"USD"];
858 env.
trust(usd(100000), alice);
859 env(
pay(gw, alice, usd(50000)));
860 env.
trust(usd(100000), bob);
861 env(
pay(gw, bob, usd(40000)));
867 .holders = {alice, bob},
868 .pay = 40'000'000000,
871 AMM amm(env, alice, btc(1'000'000000), usd(2000));
873 BEAST_EXPECT(
amm.expectBalances(
874 btc(1'000'000000), usd(2000),
IOUAmount{1414'213'562373095, -9}));
876 amm.deposit(bob, btc(500'000000), usd(1000));
877 BEAST_EXPECT(
amm.expectBalances(
879 STAmount{usd, UINT64_C(2'999'999999999999), -12},
882 auto aliceUSD = env.
balance(alice, usd);
883 auto aliceBTC = env.
balance(alice, btc);
884 auto bobUSD = env.
balance(bob, usd);
885 auto bobBTC = env.
balance(bob, btc);
890 BEAST_EXPECT(
amm.expectBalances(
891 btc(1250'000001), usd(2500),
IOUAmount{1'767'766'952966369, -9}));
896 aliceBTC = env.
balance(alice, btc);
901 BEAST_EXPECT(
amm.expectBalances(
903 STAmount{usd, UINT64_C(2000'0000004), -7},
909 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'060'660'171779822, -9}));
910 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{353'553'390876116, -9}));
915 BEAST_EXPECT(
amm.expectBalances(
917 STAmount{usd, UINT64_C(500'0000004), -7},
924 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{353'553'390876116, -9}));
925 aliceBTC = env.
balance(alice, btc);
932 BEAST_EXPECT(!
amm.ammExists());
943 Env env(*
this, features);
947 env.
fund(
XRP(100000), gw, alice, bob);
950 env(
fset(gw, asfAllowTrustLineClawback));
956 .holders = {alice, bob},
957 .pay = 40'000'000000,
963 .holders = {alice, bob},
964 .pay = 30'000'000000,
967 AMM amm(env, alice, btc(2'000'000000), eth(3'000'000000));
969 BEAST_EXPECT(
amm.expectBalances(
970 btc(2'000'000000), eth(3'000'000000),
IOUAmount{2'449'489'742'783178, -6}));
972 amm.deposit(bob, btc(4'000'000000), eth(6'000'000000));
973 BEAST_EXPECT(
amm.expectBalances(
974 btc(6'000'000000), eth(9'000'000000),
IOUAmount{7'348'469'228'349534, -6}));
976 auto aliceBTC = env.
balance(alice, btc);
977 auto aliceETH = env.
balance(alice, eth);
978 auto bobBTC = env.
balance(bob, btc);
979 auto bobETH = env.
balance(bob, eth);
984 BEAST_EXPECT(
amm.expectBalances(
985 btc(5'000'000000), eth(7'500'000000),
IOUAmount{6'123'724'356'957944, -6}));
990 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
991 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{4'898'979'485'566356, -6}));
992 aliceETH = env.
balance(alice, eth);
997 BEAST_EXPECT(
amm.expectBalances(
998 btc(3'000'000000), eth(4'500'000000),
IOUAmount{3'674'234'614'174766, -6}));
1003 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
1004 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'449'489'742'783178, -6}));
1010 BEAST_EXPECT(
amm.expectBalances(
1011 btc(2'000'000001), eth(3'000'000001),
IOUAmount{2'449'489'742'783178, -6}));
1017 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'449'489'742'783178, -6}));
1023 BEAST_EXPECT(!
amm.ammExists());
1034 testcase(
"test AMMClawback all, assets have the same issuer");
1035 using namespace jtx;
1039 Env env(*
this, features);
1043 env.
fund(
XRP(100000), gw, alice, bob);
1046 env(
fset(gw, asfAllowTrustLineClawback));
1049 auto const usd = gw[
"USD"];
1050 env.
trust(usd(100000), alice);
1051 env(
pay(gw, alice, usd(50000)));
1052 env.
trust(usd(200000), bob);
1053 env(
pay(gw, bob, usd(60000)));
1059 .holders = {alice, bob},
1060 .pay = 40'000'000000,
1063 AMM amm(env, alice, btc(2'000'000000), usd(8'000));
1065 BEAST_EXPECT(
amm.expectBalances(btc(2'000'000000), usd(8'000),
IOUAmount(4'000'000)));
1067 amm.deposit(bob, btc(1'000'000000), usd(4'000));
1068 BEAST_EXPECT(
amm.expectBalances(btc(3'000'000000), usd(12'000),
IOUAmount(6'000'000)));
1070 auto aliceBTC = env.
balance(alice, btc);
1071 auto aliceUSD = env.
balance(alice, usd);
1072 auto bobBTC = env.
balance(bob, btc);
1073 auto bobUSD = env.
balance(bob, usd);
1079 BEAST_EXPECT(
amm.expectBalances(btc(1'000'000000), usd(4'000),
IOUAmount(2'000'000)));
1080 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount(2'000'000)));
1091 BEAST_EXPECT(!
amm.ammExists());
1100 Env env(*
this, features);
1104 env.
fund(
XRP(100000), gw, alice, bob);
1107 env(
fset(gw, asfAllowTrustLineClawback));
1113 .holders = {alice, bob},
1114 .pay = 40'000'000000,
1120 .holders = {alice, bob},
1121 .pay = 30'000'000000,
1124 AMM amm(env, alice, btc(20'000), eth(10'000));
1127 amm.expectBalances(btc(20'000), eth(10'000),
IOUAmount{14'142'13562373095, -11}));
1129 amm.deposit(bob, btc(40'000), eth(20'000));
1131 amm.expectBalances(btc(60'000), eth(30'000),
IOUAmount{42'426'40687119285, -11}));
1133 auto aliceBTC = env.
balance(alice, btc);
1134 auto aliceETH = env.
balance(alice, eth);
1135 auto bobBTC = env.
balance(bob, btc);
1136 auto bobETH = env.
balance(bob, eth);
1142 amm.expectBalances(btc(20'000), eth(10'000),
IOUAmount{14'142'13562373095, -11}));
1147 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{14'142'13562373095, -11}));
1149 bobBTC = env.
balance(bob, btc);
1156 BEAST_EXPECT(!
amm.ammExists());
1167 testcase(
"test AMMClawback when issuing token for each other");
1168 using namespace jtx;
1172 Env env(*
this, features);
1174 Account const gw2{
"gateway2"};
1176 env.
fund(
XRP(1000000), gw, gw2, alice);
1179 env(
fset(gw, asfAllowTrustLineClawback));
1180 env(
fset(gw2, asfAllowTrustLineClawback));
1183 auto const usd = gw[
"USD"];
1184 env.
trust(usd(100000), gw2);
1185 env(
pay(gw, gw2, usd(5000)));
1186 env.
trust(usd(100000), alice);
1187 env(
pay(gw, alice, usd(5000)));
1192 .holders = {alice, gw},
1193 .pay = 40'000'000000,
1196 AMM amm(env, gw, usd(1000), btc(2000));
1199 amm.expectBalances(usd(1000), btc(2000),
IOUAmount{1414'213562373095, -12}));
1201 amm.deposit(gw2, usd(2000), btc(4000));
1203 amm.expectBalances(usd(3000), btc(6000),
IOUAmount{4242'640687119285, -12}));
1205 amm.deposit(alice, usd(3000), btc(6000));
1207 amm.expectBalances(usd(6000), btc(12000),
IOUAmount{8485'281374238570, -12}));
1209 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{1414'213562373095, -12}));
1210 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{2828'427124746190, -12}));
1211 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{4242'640687119285, -12}));
1213 auto aliceBTC = env.
balance(alice, btc);
1214 auto aliceUSD = env.
balance(alice, usd);
1215 auto gwBTC = env.
balance(gw, btc);
1216 auto gw2USD = env.
balance(gw2, usd);
1222 amm.expectBalances(usd(5000), btc(10000),
IOUAmount{7071'067811865474, -12}));
1223 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{1414'213562373095, -12}));
1224 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{1414'213562373094, -12}));
1225 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{4242'640687119285, -12}));
1235 amm.expectBalances(usd(4500), btc(9001),
IOUAmount{6363'961030678927, -12}));
1237 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{707'1067811865480, -13}));
1238 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{1414'213562373094, -12}));
1239 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{4242'640687119285, -12}));
1248 BEAST_EXPECT(
amm.expectBalances(
1249 STAmount{usd, UINT64_C(2500'222197533607), -12},
1253 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{707'1067811865480, -13}));
1254 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{1414'213562373094, -12}));
1255 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1414'527797138648, -12}));
1264 Env env(*
this, features);
1266 Account const gw2{
"gateway2"};
1268 env.
fund(
XRP(100000), gw, gw2, alice);
1271 env(
fset(gw, asfAllowTrustLineClawback));
1272 env(
fset(gw2, asfAllowTrustLineClawback));
1278 .holders = {gw2, alice},
1279 .pay = 40'000'000000,
1285 .holders = {gw, alice},
1286 .pay = 30'000'000000,
1289 AMM amm(env, gw, btc(10'000), eth(50'000));
1292 amm.expectBalances(btc(10'000), eth(50'000),
IOUAmount{22'360'67977499789, -11}));
1294 amm.deposit(gw2, btc(20'000), eth(100'000));
1296 amm.expectBalances(btc(30'000), eth(150'000),
IOUAmount{67'082'03932499367, -11}));
1298 amm.deposit(alice, btc(40'000), eth(200'000));
1300 amm.expectBalances(btc(70'000), eth(350'000),
IOUAmount{156'524'7584249852, -10}));
1302 auto aliceBTC = env.
balance(alice, btc);
1303 auto aliceETH = env.
balance(alice, eth);
1304 auto gw2BTC = env.
balance(gw2, btc);
1305 auto gwETH = env.
balance(gw, eth);
1311 amm.expectBalances(btc(69'001), eth(345'001),
IOUAmount{154'288'6904474855, -10}));
1321 amm.expectBalances(btc(59'001), eth(295'001),
IOUAmount{131'928'0106724876, -10}));
1331 amm.expectBalances(btc(19'001), eth(95'001),
IOUAmount{42'485'29157249607, -11}));
1342 testcase(
"test AMMClawback when asset is frozen or locked");
1343 using namespace jtx;
1347 Env env{*
this, features};
1350 env.
fund(
XRP(1'000'000), gw, alice);
1352 env(
fset(gw, asfAllowTrustLineClawback));
1354 auto const usd = gw[
"USD"];
1355 env.
trust(usd(1'000'000), alice);
1356 env(
pay(gw, alice, usd(500'000)));
1363 .flags = tfMPTCanClawback | tfMPTCanLock |
kMptDexFlags});
1364 AMM const ammAlice(env, alice, usd(10'000), btc(10'000));
1365 BEAST_EXPECT(ammAlice.expectBalances(usd(10'000), btc(10'000),
IOUAmount(10'000)));
1368 auto aliceBTC = env.
balance(alice,
MPT(btc));
1369 auto aliceUSD = env.
balance(alice, usd);
1373 btc.set({.flags = tfMPTLock});
1375 BEAST_EXPECT(ammAlice.expectBalances(usd(9'000), btc(9'000),
IOUAmount(9'000)));
1378 aliceUSD = env.
balance(alice, usd);
1381 btc.set({.flags = tfMPTUnlock});
1383 BEAST_EXPECT(ammAlice.expectBalances(
1384 STAmount(usd, UINT64_C(7'000'000000000001), -12), btc(7'001),
IOUAmount(7'000)));
1387 aliceUSD = env.
balance(alice, usd);
1391 env(
trust(gw, alice[
"USD"](0), tfSetFreeze));
1394 BEAST_EXPECT(ammAlice.expectBalances(
1395 STAmount(usd, UINT64_C(6000'000000000002), -12),
1404 env(
fset(gw, asfGlobalFreeze));
1407 BEAST_EXPECT(ammAlice.expectBalances(
1408 STAmount(usd, UINT64_C(4'000'000000000002), -12),
1418 Env env{*
this, features};
1421 env.
fund(
XRP(1'000'000), gw, alice);
1423 env(
fset(gw, asfAllowTrustLineClawback));
1425 auto const usd = gw[
"USD"];
1426 env.
trust(usd(1'000'000), alice);
1427 env(
pay(gw, alice, usd(500'000)));
1434 .flags = tfMPTCanClawback | tfMPTCanLock |
kMptDexFlags});
1435 AMM const ammAlice(env, alice, usd(10'000), btc(10'000));
1436 BEAST_EXPECT(ammAlice.expectBalances(usd(10'000), btc(10'000),
IOUAmount(10'000)));
1439 auto aliceBTC = env.
balance(alice,
MPT(btc));
1440 auto aliceUSD = env.
balance(alice, usd);
1443 btc.set({.holder = alice, .flags = tfMPTLock});
1445 BEAST_EXPECT(ammAlice.expectBalances(usd(8'000), btc(8'000),
IOUAmount(8'000)));
1448 aliceUSD = env.
balance(alice, usd);
1451 env(
trust(gw, alice[
"USD"](0), tfSetFreeze));
1454 BEAST_EXPECT(ammAlice.expectBalances(usd(7'000), btc(7'000),
IOUAmount(7'000)));
1460 btc.set({.holder = alice, .flags = tfMPTUnlock});
1462 BEAST_EXPECT(ammAlice.expectBalances(
1463 STAmount{usd, UINT64_C(4000'000000000001), -12}, btc(4'001),
IOUAmount(4'000)));
1466 aliceUSD = env.
balance(alice, usd);
1469 env(
trust(gw, alice[
"USD"](0), tfClearFreeze));
1472 BEAST_EXPECT(ammAlice.expectBalances(
1473 STAmount(usd, UINT64_C(3'000'000000000002), -12),
1538 testcase(
"test single depoit and clawback");
1539 using namespace jtx;
1543 Env env(*
this, features);
1546 env.
fund(
XRP(1000000000), gw, alice);
1553 .pay = 40'000'000000,
1559 BEAST_EXPECT(
amm.expectBalances(
XRP(100), btc(400),
IOUAmount(200000)));
1560 amm.deposit(alice, btc(400));
1561 BEAST_EXPECT(
amm.expectBalances(
XRP(100), btc(800),
IOUAmount{282842'712474619, -9}));
1563 auto aliceBTC = env.
balance(alice,
MPT(btc));
1568 BEAST_EXPECT(
amm.expectBalances(
1577 Env env(*
this, features);
1580 env.
fund(
XRP(1000000000), gw, alice);
1584 env(
fset(gw, asfAllowTrustLineClawback));
1589 auto const usd = gw[
"USD"];
1590 env.
trust(usd(100000), alice);
1591 env(
pay(gw, alice, usd(1000)));
1598 .pay = 40'000'000000,
1604 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(400),
IOUAmount(200)));
1605 amm.deposit(alice, btc(400));
1606 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(800),
IOUAmount{282'842712474619, -12}));
1608 auto aliceBTC = env.
balance(alice,
MPT(btc));
1609 auto aliceUSD = env.
balance(alice, usd);
1613 BEAST_EXPECT(
amm.expectBalances(
1614 STAmount{usd, UINT64_C(87'50000000000003), -14},
1620 aliceUSD = env.
balance(alice, usd);
1625 BEAST_EXPECT(
amm.expectBalances(
1635 Env env(*
this, features);
1638 env.
fund(
XRP(1000000000), gw, alice);
1645 .pay = 40'000'000000,
1652 .pay = 40'000'000000,
1658 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(400),
IOUAmount(200)));
1659 amm.deposit(alice, btc(400));
1660 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(800),
IOUAmount{282'842712474619, -12}));
1662 auto aliceBTC = env.
balance(alice,
MPT(btc));
1663 auto aliceUSD = env.
balance(alice, usd);
1667 BEAST_EXPECT(
amm.expectBalances(usd(88), btc(701),
IOUAmount{247'4873734152917, -13}));
1671 aliceUSD = env.
balance(alice, usd);
1676 BEAST_EXPECT(
amm.expectBalances(usd(72), btc(567),
IOUAmount(200)));
1688 "test last holder's lptoken balance not equal to AMM's lptoken "
1689 "balance before clawback");
1690 using namespace jtx;
1696 Account const gw{
"gateway"}, alice{
"alice"}, bob{
"bob"};
1697 env.
fund(
XRP(100000), gw, alice, bob);
1699 env(
fset(gw, asfAllowTrustLineClawback));
1702 auto const usd = gw[
"USD"];
1703 env.
trust(usd(100000), alice);
1704 env(
pay(gw, alice, usd(50000)));
1705 env.
trust(usd(100000), bob);
1706 env(
pay(gw, bob, usd(40000)));
1712 .holders = {alice, bob},
1713 .pay = 40'000'000000,
1716 AMM amm(env, alice, usd(2), eur(1));
1719 amm.withdraw(alice,
IOUAmount{1'576123487565916, -15});
1720 amm.withdrawAll(bob);
1722 auto const lpToken =
1725 auto const lpTokenBalance =
1726 amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value].asString();
1727 if (features[featureSingleAssetVault] || features[featureLendingProtocol])
1729 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.4142135623741");
1733 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.414213562374");
1737 BEAST_EXPECT(res && res.value());
1739 if (features[fixAMMv1_3] && features[fixAMMClawbackRounding])
1742 BEAST_EXPECT(!
amm.ammExists());
1745 features[fixAMMv1_3] &&
1746 (features[featureSingleAssetVault] || features[featureLendingProtocol]))
1751 BEAST_EXPECT(
amm.ammExists());
1753 else if (!features[featureSingleAssetVault] && !features[featureLendingProtocol])
1756 BEAST_EXPECT(
amm.ammExists());
1761 BEAST_EXPECT(
amm.ammExists());
1768 Account const gw{
"gateway"}, alice{
"alice"}, bob{
"bob"};
1769 env.
fund(
XRP(100000), gw, alice, bob);
1775 .holders = {alice, bob},
1776 .pay = 40'000'000000,
1782 .holders = {alice, bob},
1783 .pay = 40'000'000000,
1786 AMM amm(env, alice, usd(2), eur(1));
1789 amm.withdraw(alice,
IOUAmount{1'576123487565916, -15});
1790 amm.withdrawAll(bob);
1792 auto const lpToken =
1795 auto const lpTokenBalance =
1796 amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value].asString();
1797 if (!features[featureSingleAssetVault] && !features[featureLendingProtocol])
1799 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.414213562374");
1803 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.4142135623741");
1807 BEAST_EXPECT(res && res.value());
1809 if (features[fixAMMv1_3] && features[fixAMMClawbackRounding])
1812 BEAST_EXPECT(!
amm.ammExists());
1815 features[fixAMMv1_3] &&
1816 (features[featureSingleAssetVault] || features[featureLendingProtocol]))
1821 BEAST_EXPECT(
amm.ammExists());
1823 else if (!features[featureSingleAssetVault] && !features[featureLendingProtocol])
1826 BEAST_EXPECT(
amm.ammExists());
1828 else if (features[featureMPTokensV2])
1831 BEAST_EXPECT(
amm.ammExists());
1839 testcase(
"claw asset check for MPT and IOU");
1840 using namespace jtx;
1844 Env env(*
this, features);
1847 env.
fund(
XRP(100000), gw, alice);
1850 env(
fset(gw, asfAllowTrustLineClawback));
1853 auto const usd = gw[
"USD"];
1854 env.
trust(usd(100000), alice);
1855 env(
pay(gw, alice, usd(1000)));
1859 MPTTester({.env = env, .issuer = gw, .holders = {alice}, .pay = 40'000});
1861 AMM const amm(env, alice, usd(200), btc(100));
1878 Env env(*
this, features);
1881 env.
fund(
XRP(100000), gw, alice);
1884 auto const usd = gw[
"USD"];
1885 env.
trust(usd(100000), alice);
1886 env(
pay(gw, alice, usd(1000)));
1897 AMM const amm(env, alice, usd(200), btc(100));
1914 Env env(*
this, features);
1916 Account const gw2{
"gateway2"};
1918 env.
fund(
XRP(100000), gw, gw2, alice);
1921 env(
fset(gw, asfAllowTrustLineClawback));
1924 auto const usd = gw[
"USD"];
1925 env.
trust(usd(100000), alice);
1926 env(
pay(gw, alice, usd(1000)));
1936 AMM const amm(env, alice, usd(200), btc(100));
1945 auto test = [&](
auto&& issue1,
auto&& issue2) {
1947 Account const gw(
"gateway"), alice(
"alice"), bob(
"bob");
1948 env.
fund(
XRP(30'000), alice, bob, gw);
1950 auto const usd = issue1(
1955 .
limit = 1'000'000});
1956 auto const btc = issue2(
1961 .limit = 1'000'000});
1962 env(
pay(gw, alice, usd(50000)));
1963 env(
pay(bob, alice, btc(50000)));
1966 auto ammAlice =
AMM(env, alice, usd(10000), btc(10100));
1975 auto test = [&](
auto&& issue1,
auto&& issue2) {
1977 Account const gw(
"gateway"), alice(
"alice"), bob(
"bob");
1978 env.
fund(
XRP(30'000), alice, bob, gw);
1980 auto const usd = issue1(
1985 .
limit = 1'000'000});
1986 auto const btc = issue2(
1991 .limit = 1'000'000});
1992 env(
pay(gw, alice, usd(50000)));
1993 env(
pay(bob, alice, btc(50000)));
1996 auto ammAlice =
AMM(env, alice, usd(10000), btc(10100));
2015 testcase(
"test AMMClawback after holder deletes zero-balance MPTokens");
2016 using namespace jtx;
2021 Env env(*
this, features);
2024 env.
fund(
XRP(100'000), gw, alice);
2043 AMM const amm(env, alice, btc(10'000), eth(10'000));
2045 BEAST_EXPECT(
amm.expectBalances(btc(10'000), eth(10'000),
IOUAmount{10'000}));
2047 auto aliceBTC = env.
balance(alice, btc);
2048 auto aliceETH = env.
balance(alice, eth);
2049 BEAST_EXPECT(aliceBTC == btc(0));
2050 BEAST_EXPECT(aliceETH == eth(0));
2053 btc.authorize({.account = alice, .flags = tfMPTUnauthorize});
2054 eth.authorize({.account = alice, .flags = tfMPTUnauthorize});
2069 BEAST_EXPECT(env.
balance(alice, eth) > aliceETH);
2072 BEAST_EXPECT(
amm.ammExists());
2078 Env env(*
this, features);
2081 env.
fund(
XRP(100'000), gw, alice);
2098 AMM const amm(env, alice, btc(10'000), eth(10'000));
2101 auto aliceBTC = env.
balance(alice, btc);
2102 auto aliceETH = env.
balance(alice, eth);
2104 btc.authorize({.account = alice, .flags = tfMPTUnauthorize});
2105 eth.authorize({.account = alice, .flags = tfMPTUnauthorize});
2114 BEAST_EXPECT(!
amm.ammExists());
2124 testcase(
"test AMMClawback recreates paired-issuer MPToken unauthorized");
2125 using namespace jtx;
2136 Env env(*
this, features);
2138 Account const gw2{
"gateway2"};
2140 env.
fund(
XRP(100'000), gw, gw2, alice);
2148 .flags = tfMPTCanClawback | tfMPTRequireAuth |
kMptDexFlags,
2149 .authHolder =
true});
2156 .flags = tfMPTCanClawback | tfMPTRequireAuth |
kMptDexFlags,
2157 .authHolder =
true});
2160 AMM const amm(env, alice, btc(10'000), eth(10'000));
2162 BEAST_EXPECT(
amm.expectBalances(btc(10'000), eth(10'000),
IOUAmount{10'000}));
2163 BEAST_EXPECT(env.
balance(alice, btc) == btc(0));
2164 BEAST_EXPECT(env.
balance(alice, eth) == eth(0));
2167 btc.authorize({.account = alice, .flags = tfMPTUnauthorize});
2168 eth.authorize({.account = alice, .flags = tfMPTUnauthorize});
2181 BEAST_EXPECT(sleBtc);
2182 BEAST_EXPECT(sleEth);
2186 BEAST_EXPECT(sleBtc && sleBtc->isFlag(lsfMPTAuthorized));
2191 BEAST_EXPECT(sleEth && !sleEth->isFlag(lsfMPTAuthorized));
2196 BEAST_EXPECT(sleBtc && sleBtc->getFieldU64(sfMPTAmount) == 0);
2197 BEAST_EXPECT(sleEth && sleEth->getFieldU64(sfMPTAmount) > 0);
2198 BEAST_EXPECT(
amm.ammExists());