49 for (
auto const& feature : {features, features - featureSingleAssetVault})
51 Env env(*
this, feature);
55 env.
fund(
XRP(100000), gw, alice, bob);
58 env(
fset(gw, asfAllowTrustLineClawback));
68 auto const usd = gw[
"USD"];
69 env.
trust(usd(10000), alice);
70 env(
pay(gw, alice, usd(100)));
73 AMM amm(env, gw, btc(100), usd(100));
85 gw, alice,
Issue{gw[
"USD"].currency, alice.
id()}, btc, std::nullopt),
94 gw, alice, usd, btc,
STAmount{
Issue{gw[
"USD"].currency, alice.
id()}, 1}),
112 Issue const ammUsd(usd.currency,
amm.ammAccount());
116 env(
claw(gw, amount),
Ter(err));
123 BEAST_EXPECT(!
amm.ammExists());
131 Env env(*
this, features);
134 env.
fund(
XRP(100000), gw, alice);
137 env(
fset(gw, asfAllowTrustLineClawback));
141 MPTTester({.env = env, .issuer = gw, .holders = {alice}, .pay = 40'000});
143 auto const usd = gw[
"USD"];
144 env.
trust(usd(10000), alice);
145 env(
pay(gw, alice, usd(10000)));
148 AMM amm(env, gw, btc(100), usd(100));
150 amm.deposit(alice, 1'000);
159 Env env(*
this, features);
163 env.
fund(
XRP(100000), gw, gw2, alice);
166 env(
fset(gw, asfAllowTrustLineClawback));
169 auto const usd = gw[
"USD"];
170 env.
trust(usd(10000), alice);
171 env(
pay(gw, alice, usd(10000)));
182 AMM const amm(env, alice, btc(100), usd(100));
199 Env env(*
this, features);
202 env.
fund(
XRP(10000), gw, alice);
212 AMM const amm(env, alice, btc(100),
XRP(100));
259 testcase(
"test AMMClawback specific amount");
264 Env env(*
this, features);
268 env.
fund(
XRP(100000), gw, gw2, alice);
271 env(
fset(gw, asfAllowTrustLineClawback));
272 env(
fset(gw2, asfAllowTrustLineClawback));
275 auto const usd = gw[
"USD"];
276 env.
trust(usd(100000), alice);
277 env(
pay(gw, alice, usd(50000)));
284 .pay = 40'000'000000,
287 AMM const amm(env, alice, btc(1000000000), usd(2000));
289 BEAST_EXPECT(
amm.expectBalances(
290 btc(1'000'000000), usd(2000),
IOUAmount{1414'213'562373095, -9}));
298 auto aliceUSD = env.
balance(alice, usd);
299 auto aliceBTC = env.
balance(alice, btc);
305 amm.expectBalances(btc(500'000000), usd(1000),
IOUAmount{707'106'7811865475, -10}));
310 aliceBTC = env.
balance(alice, btc);
316 amm.expectBalances(btc(250'000000), usd(500),
IOUAmount{353'553'3905932737, -10}));
319 aliceUSD = env.
balance(alice, usd);
325 BEAST_EXPECT(!
amm.ammExists());
332 Env env(*
this, features);
336 env.
fund(
XRP(100000), gw, alice, bob);
339 env(
fset(gw, asfAllowTrustLineClawback));
345 .holders = {alice, bob},
346 .pay = 40'000'000000,
349 AMM amm(env, alice, btc(1000000000),
XRP(2000));
351 BEAST_EXPECT(
amm.expectBalances(
352 btc(1'000'000000),
XRP(2000),
IOUAmount{1'414'213'562'373095, -6}));
354 amm.deposit(bob, btc(2'000'000000),
XRP(4000));
355 BEAST_EXPECT(
amm.expectBalances(
356 btc(3'000'000000),
XRP(6000),
IOUAmount{4'242'640'687'119285, -6}));
359 auto aliceBTC = env.
balance(alice, btc);
361 auto bobBTC = env.
balance(bob, btc);
373 BEAST_EXPECT(
amm.expectBalances(
381 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'414'212'855'266314, -6}));
382 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'828'427'124'74619, -5}));
388 BEAST_EXPECT(
amm.expectBalances(
396 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'414'212'855'266314, -6}));
397 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{1'414'213'562'844499, -6}));
404 BEAST_EXPECT(
amm.expectBalances(
411 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{1'414'213'562'844499, -6}));
418 BEAST_EXPECT(!
amm.ammExists());
427 Env env(*
this, features);
432 env.
fund(
XRP(100000), gw, gw2, alice, bob);
435 env(
fset(gw, asfAllowTrustLineClawback));
436 env(
fset(gw2, asfAllowTrustLineClawback));
442 .holders = {alice, bob},
443 .pay = 40'000'000000,
449 .holders = {alice, bob},
450 .pay = 30'000'000000,
453 AMM amm(env, alice, btc(2'000'000000), eth(3'000'000000));
455 BEAST_EXPECT(
amm.expectBalances(
456 btc(2'000'000000), eth(3'000'000000),
IOUAmount{2'449'489'742'783178, -6}));
458 amm.deposit(bob, btc(4'000'000000), eth(6'000'000000));
459 BEAST_EXPECT(
amm.expectBalances(
460 btc(6'000'000000), eth(9'000'000000),
IOUAmount{7'348'469'228'349534, -6}));
462 auto aliceBTC = env.
balance(alice, btc);
463 auto aliceETH = env.
balance(alice, eth);
464 auto bobBTC = env.
balance(bob, btc);
465 auto bobETH = env.
balance(bob, eth);
470 BEAST_EXPECT(
amm.expectBalances(
471 btc(5'000'000000), eth(7'500'000000),
IOUAmount{6'123'724'356'957944, -6}));
476 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
477 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{4'898'979'485'566356, -6}));
478 aliceETH = env.
balance(alice, eth);
483 BEAST_EXPECT(
amm.expectBalances(
484 btc(3'000'000000), eth(4'500'000000),
IOUAmount{3'674'234'614'174766, -6}));
489 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
490 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'449'489'742'783178, -6}));
491 bobBTC = env.
balance(bob, btc);
496 BEAST_EXPECT(
amm.expectBalances(
497 btc(2'000'000001), eth(3'000'000001),
IOUAmount{2'449'489'742'783178, -6}));
502 aliceBTC = env.
balance(alice, btc);
508 BEAST_EXPECT(!
amm.ammExists());
521 testcase(
"test AMMClawback amount that rounds down to zero");
524 Env env(*
this, features);
528 env.
fund(
XRP(10'000'000), gw, alice, bob);
531 env(
fset(gw, asfAllowTrustLineClawback));
540 .holders = {alice, bob},
543 MPT const btc = mptBtc;
545 AMM amm(env, alice, btc(3),
XRP(333'000));
546 amm.deposit(bob, btc(3),
XRP(333'000));
548 [[maybe_unused]]
auto const [poolBtcBefore, poolXrpBefore, lptBefore] =
amm.balances();
549 BEAST_EXPECT(poolBtcBefore == btc(6));
551 auto const issuerOABefore = mptBtc.getBalance(gw);
552 auto const aliceLpBefore =
amm.getLPTokensBalance(alice.
id());
553 auto const bobLpBefore =
amm.getLPTokensBalance(bob.
id());
562 [[maybe_unused]]
auto const [poolBtcAfter, poolXrpAfter, lptAfter] =
amm.balances();
563 auto const issuerOAAfter = mptBtc.getBalance(gw);
564 auto const aliceLpAfter =
amm.getLPTokensBalance(alice.
id());
565 auto const bobLpAfter =
amm.getLPTokensBalance(bob.
id());
567 if (features[fixCleanup3_4_0])
571 BEAST_EXPECT(poolBtcAfter == poolBtcBefore);
572 BEAST_EXPECT(poolXrpAfter == poolXrpBefore);
573 BEAST_EXPECT(issuerOAAfter == issuerOABefore);
574 BEAST_EXPECT(aliceLpAfter == aliceLpBefore);
575 BEAST_EXPECT(bobLpAfter == bobLpBefore);
581 BEAST_EXPECT(poolBtcAfter == poolBtcBefore);
582 BEAST_EXPECT(poolXrpAfter < poolXrpBefore);
583 BEAST_EXPECT(issuerOAAfter == issuerOABefore);
584 BEAST_EXPECT(aliceLpAfter < aliceLpBefore);
585 BEAST_EXPECT(bobLpAfter == bobLpBefore);
597 env.
fund(
XRP(10'000'000), carol, dan);
603 .holders = {carol, dan},
606 MPT const btc = mptBtc;
611 .holders = {carol, dan},
614 MPT const eth = mptEth;
618 AMM amm(env, carol, btc(3'000), eth(3));
619 amm.deposit(dan, btc(3'000), eth(3));
621 [[maybe_unused]]
auto const [poolBtcBefore, poolEthBefore, lptBefore] =
amm.balances();
622 BEAST_EXPECT(poolBtcBefore == btc(6'000));
623 BEAST_EXPECT(poolEthBefore == eth(6));
625 auto const carolLpBefore =
amm.getLPTokensBalance(carol.
id());
626 auto const danLpBefore =
amm.getLPTokensBalance(dan.
id());
632 [[maybe_unused]]
auto const [poolBtcAfter, poolEthAfter, lptAfter] =
amm.balances();
633 auto const carolLpAfter =
amm.getLPTokensBalance(carol.
id());
634 auto const danLpAfter =
amm.getLPTokensBalance(dan.
id());
636 if (features[fixCleanup3_4_0])
641 BEAST_EXPECT(poolBtcAfter == poolBtcBefore);
642 BEAST_EXPECT(poolEthAfter == poolEthBefore);
643 BEAST_EXPECT(carolLpAfter == carolLpBefore);
644 BEAST_EXPECT(danLpAfter == danLpBefore);
652 BEAST_EXPECT(poolBtcAfter < poolBtcBefore);
653 BEAST_EXPECT(poolEthAfter == poolEthBefore);
654 BEAST_EXPECT(carolLpAfter < carolLpBefore);
655 BEAST_EXPECT(danLpAfter == danLpBefore);
668 Env env(*
this, features);
673 env.
fund(
XRP(100000), gw, gw2, alice, bob);
676 env(
fset(gw, asfAllowTrustLineClawback));
677 env(
fset(gw2, asfAllowTrustLineClawback));
680 auto const usd = gw[
"USD"];
681 env.
trust(usd(100000), alice);
682 env(
pay(gw, alice, usd(50000)));
683 env.
trust(usd(200000), bob);
684 env(
pay(gw, bob, usd(60000)));
690 .holders = {alice, bob},
691 .pay = 40'000'000000,
694 AMM amm(env, alice, btc(2000000000), usd(2000));
696 BEAST_EXPECT(
amm.expectBalances(btc(2'000'000000), usd(2000),
IOUAmount(2000000)));
699 amm.deposit(bob, btc(1'000'000000), usd(2000));
700 BEAST_EXPECT(
amm.expectBalances(btc(3'000'000000), usd(3000),
IOUAmount(3000000)));
702 auto aliceBTC = env.
balance(alice, btc);
703 auto aliceUSD = env.
balance(alice, usd);
704 auto bobBTC = env.
balance(bob, btc);
705 auto bobUSD = env.
balance(bob, usd);
710 BEAST_EXPECT(
amm.expectBalances(btc(1'000'000000), usd(1000),
IOUAmount(1000000)));
715 aliceUSD = env.
balance(alice, usd);
721 BEAST_EXPECT(!
amm.ammExists());
730 Env env(*
this, features);
734 env.
fund(
XRP(100000), gw, alice, bob);
737 env(
fset(gw, asfAllowTrustLineClawback));
743 .holders = {alice, bob},
744 .pay = 40'000'000000,
747 AMM amm(env, alice, btc(5000),
XRP(10'000));
750 amm.expectBalances(btc(5'000),
XRP(10'000),
IOUAmount{7'071'067'811865475, -9}));
752 amm.deposit(bob, btc(10'000),
XRP(20'000));
754 amm.expectBalances(btc(15'000),
XRP(30'000),
IOUAmount{21'213'203'43559642, -8}));
757 auto aliceBTC = env.
balance(alice, btc);
759 auto bobBTC = env.
balance(bob, btc);
765 amm.expectBalances(btc(10'000),
XRP(20'000),
IOUAmount{14'142'135'62373094, -8}));
776 BEAST_EXPECT(!
amm.ammExists());
785 Env env(*
this, features);
790 env.
fund(
XRP(100000), gw, gw2, alice, bob);
793 env(
fset(gw, asfAllowTrustLineClawback));
794 env(
fset(gw2, asfAllowTrustLineClawback));
800 .holders = {alice, bob},
801 .pay = 40'000'000000,
807 .holders = {alice, bob},
808 .pay = 30'000'000000,
811 AMM amm(env, alice, btc(20'000), eth(50'000));
814 amm.expectBalances(btc(20'000), eth(50'000),
IOUAmount{31'622'77660168379, -11}));
816 amm.deposit(bob, btc(40'000), eth(100'000));
818 amm.expectBalances(btc(60'000), eth(150'000),
IOUAmount{94'868'32980505137, -11}));
820 auto aliceBTC = env.
balance(alice, btc);
821 auto aliceETH = env.
balance(alice, eth);
822 auto bobBTC = env.
balance(bob, btc);
823 auto bobETH = env.
balance(bob, eth);
829 amm.expectBalances(btc(20'000), eth(50'000),
IOUAmount{31'622'77660168379, -11}));
834 bobETH = env.
balance(bob, eth);
840 BEAST_EXPECT(!
amm.ammExists());
851 testcase(
"test AMMClawback specific amount, assets have the same issuer");
856 Env env(*
this, features);
860 env.
fund(
XRP(100000), gw, alice, bob);
863 env(
fset(gw, asfAllowTrustLineClawback));
866 auto const usd = gw[
"USD"];
867 env.
trust(usd(100000), alice);
868 env(
pay(gw, alice, usd(50000)));
869 env.
trust(usd(100000), bob);
870 env(
pay(gw, bob, usd(40000)));
876 .holders = {alice, bob},
877 .pay = 40'000'000000,
880 AMM amm(env, alice, btc(1'000'000000), usd(2000));
882 BEAST_EXPECT(
amm.expectBalances(
883 btc(1'000'000000), usd(2000),
IOUAmount{1414'213'562373095, -9}));
885 amm.deposit(bob, btc(500'000000), usd(1000));
886 BEAST_EXPECT(
amm.expectBalances(
888 STAmount{usd, UINT64_C(2'999'999999999999), -12},
891 auto aliceUSD = env.
balance(alice, usd);
892 auto aliceBTC = env.
balance(alice, btc);
893 auto bobUSD = env.
balance(bob, usd);
894 auto bobBTC = env.
balance(bob, btc);
899 BEAST_EXPECT(
amm.expectBalances(
900 btc(1250'000001), usd(2500),
IOUAmount{1'767'766'952966369, -9}));
905 aliceBTC = env.
balance(alice, btc);
910 BEAST_EXPECT(
amm.expectBalances(
912 STAmount{usd, UINT64_C(2000'0000004), -7},
918 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'060'660'171779822, -9}));
919 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{353'553'390876116, -9}));
924 BEAST_EXPECT(
amm.expectBalances(
926 STAmount{usd, UINT64_C(500'0000004), -7},
933 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{353'553'390876116, -9}));
934 aliceBTC = env.
balance(alice, btc);
941 BEAST_EXPECT(!
amm.ammExists());
952 Env env(*
this, features);
956 env.
fund(
XRP(100000), gw, alice, bob);
959 env(
fset(gw, asfAllowTrustLineClawback));
965 .holders = {alice, bob},
966 .pay = 40'000'000000,
972 .holders = {alice, bob},
973 .pay = 30'000'000000,
976 AMM amm(env, alice, btc(2'000'000000), eth(3'000'000000));
978 BEAST_EXPECT(
amm.expectBalances(
979 btc(2'000'000000), eth(3'000'000000),
IOUAmount{2'449'489'742'783178, -6}));
981 amm.deposit(bob, btc(4'000'000000), eth(6'000'000000));
982 BEAST_EXPECT(
amm.expectBalances(
983 btc(6'000'000000), eth(9'000'000000),
IOUAmount{7'348'469'228'349534, -6}));
985 auto aliceBTC = env.
balance(alice, btc);
986 auto aliceETH = env.
balance(alice, eth);
987 auto bobBTC = env.
balance(bob, btc);
988 auto bobETH = env.
balance(bob, eth);
993 BEAST_EXPECT(
amm.expectBalances(
994 btc(5'000'000000), eth(7'500'000000),
IOUAmount{6'123'724'356'957944, -6}));
999 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
1000 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{4'898'979'485'566356, -6}));
1001 aliceETH = env.
balance(alice, eth);
1006 BEAST_EXPECT(
amm.expectBalances(
1007 btc(3'000'000000), eth(4'500'000000),
IOUAmount{3'674'234'614'174766, -6}));
1012 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1'224'744'871'391588, -6}));
1013 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'449'489'742'783178, -6}));
1019 BEAST_EXPECT(
amm.expectBalances(
1020 btc(2'000'000001), eth(3'000'000001),
IOUAmount{2'449'489'742'783178, -6}));
1026 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount{2'449'489'742'783178, -6}));
1032 BEAST_EXPECT(!
amm.ammExists());
1043 testcase(
"test AMMClawback all, assets have the same issuer");
1044 using namespace jtx;
1048 Env env(*
this, features);
1052 env.
fund(
XRP(100000), gw, alice, bob);
1055 env(
fset(gw, asfAllowTrustLineClawback));
1058 auto const usd = gw[
"USD"];
1059 env.
trust(usd(100000), alice);
1060 env(
pay(gw, alice, usd(50000)));
1061 env.
trust(usd(200000), bob);
1062 env(
pay(gw, bob, usd(60000)));
1068 .holders = {alice, bob},
1069 .pay = 40'000'000000,
1072 AMM amm(env, alice, btc(2'000'000000), usd(8'000));
1074 BEAST_EXPECT(
amm.expectBalances(btc(2'000'000000), usd(8'000),
IOUAmount(4'000'000)));
1076 amm.deposit(bob, btc(1'000'000000), usd(4'000));
1077 BEAST_EXPECT(
amm.expectBalances(btc(3'000'000000), usd(12'000),
IOUAmount(6'000'000)));
1079 auto aliceBTC = env.
balance(alice, btc);
1080 auto aliceUSD = env.
balance(alice, usd);
1081 auto bobBTC = env.
balance(bob, btc);
1082 auto bobUSD = env.
balance(bob, usd);
1088 BEAST_EXPECT(
amm.expectBalances(btc(1'000'000000), usd(4'000),
IOUAmount(2'000'000)));
1089 BEAST_EXPECT(
amm.expectLPTokens(bob,
IOUAmount(2'000'000)));
1100 BEAST_EXPECT(!
amm.ammExists());
1109 Env env(*
this, features);
1113 env.
fund(
XRP(100000), gw, alice, bob);
1116 env(
fset(gw, asfAllowTrustLineClawback));
1122 .holders = {alice, bob},
1123 .pay = 40'000'000000,
1129 .holders = {alice, bob},
1130 .pay = 30'000'000000,
1133 AMM amm(env, alice, btc(20'000), eth(10'000));
1136 amm.expectBalances(btc(20'000), eth(10'000),
IOUAmount{14'142'13562373095, -11}));
1138 amm.deposit(bob, btc(40'000), eth(20'000));
1140 amm.expectBalances(btc(60'000), eth(30'000),
IOUAmount{42'426'40687119285, -11}));
1142 auto aliceBTC = env.
balance(alice, btc);
1143 auto aliceETH = env.
balance(alice, eth);
1144 auto bobBTC = env.
balance(bob, btc);
1145 auto bobETH = env.
balance(bob, eth);
1151 amm.expectBalances(btc(20'000), eth(10'000),
IOUAmount{14'142'13562373095, -11}));
1156 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{14'142'13562373095, -11}));
1158 bobBTC = env.
balance(bob, btc);
1165 BEAST_EXPECT(!
amm.ammExists());
1176 testcase(
"test AMMClawback when issuing token for each other");
1177 using namespace jtx;
1181 Env env(*
this, features);
1183 Account const gw2{
"gateway2"};
1185 env.
fund(
XRP(1000000), gw, gw2, alice);
1188 env(
fset(gw, asfAllowTrustLineClawback));
1189 env(
fset(gw2, asfAllowTrustLineClawback));
1192 auto const usd = gw[
"USD"];
1193 env.
trust(usd(100000), gw2);
1194 env(
pay(gw, gw2, usd(5000)));
1195 env.
trust(usd(100000), alice);
1196 env(
pay(gw, alice, usd(5000)));
1201 .holders = {alice, gw},
1202 .pay = 40'000'000000,
1205 AMM amm(env, gw, usd(1000), btc(2000));
1208 amm.expectBalances(usd(1000), btc(2000),
IOUAmount{1414'213562373095, -12}));
1210 amm.deposit(gw2, usd(2000), btc(4000));
1212 amm.expectBalances(usd(3000), btc(6000),
IOUAmount{4242'640687119285, -12}));
1214 amm.deposit(alice, usd(3000), btc(6000));
1216 amm.expectBalances(usd(6000), btc(12000),
IOUAmount{8485'281374238570, -12}));
1218 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{1414'213562373095, -12}));
1219 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{2828'427124746190, -12}));
1220 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{4242'640687119285, -12}));
1222 auto aliceBTC = env.
balance(alice, btc);
1223 auto aliceUSD = env.
balance(alice, usd);
1224 auto gwBTC = env.
balance(gw, btc);
1225 auto gw2USD = env.
balance(gw2, usd);
1231 amm.expectBalances(usd(5000), btc(10000),
IOUAmount{7071'067811865474, -12}));
1232 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{1414'213562373095, -12}));
1233 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{1414'213562373094, -12}));
1234 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{4242'640687119285, -12}));
1244 amm.expectBalances(usd(4500), btc(9001),
IOUAmount{6363'961030678927, -12}));
1246 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{707'1067811865480, -13}));
1247 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{1414'213562373094, -12}));
1248 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{4242'640687119285, -12}));
1257 BEAST_EXPECT(
amm.expectBalances(
1258 STAmount{usd, UINT64_C(2500'222197533607), -12},
1262 BEAST_EXPECT(
amm.expectLPTokens(gw,
IOUAmount{707'1067811865480, -13}));
1263 BEAST_EXPECT(
amm.expectLPTokens(gw2,
IOUAmount{1414'213562373094, -12}));
1264 BEAST_EXPECT(
amm.expectLPTokens(alice,
IOUAmount{1414'527797138648, -12}));
1273 Env env(*
this, features);
1275 Account const gw2{
"gateway2"};
1277 env.
fund(
XRP(100000), gw, gw2, alice);
1280 env(
fset(gw, asfAllowTrustLineClawback));
1281 env(
fset(gw2, asfAllowTrustLineClawback));
1287 .holders = {gw2, alice},
1288 .pay = 40'000'000000,
1294 .holders = {gw, alice},
1295 .pay = 30'000'000000,
1298 AMM amm(env, gw, btc(10'000), eth(50'000));
1301 amm.expectBalances(btc(10'000), eth(50'000),
IOUAmount{22'360'67977499789, -11}));
1303 amm.deposit(gw2, btc(20'000), eth(100'000));
1305 amm.expectBalances(btc(30'000), eth(150'000),
IOUAmount{67'082'03932499367, -11}));
1307 amm.deposit(alice, btc(40'000), eth(200'000));
1309 amm.expectBalances(btc(70'000), eth(350'000),
IOUAmount{156'524'7584249852, -10}));
1311 auto aliceBTC = env.
balance(alice, btc);
1312 auto aliceETH = env.
balance(alice, eth);
1313 auto gw2BTC = env.
balance(gw2, btc);
1314 auto gwETH = env.
balance(gw, eth);
1320 amm.expectBalances(btc(69'001), eth(345'001),
IOUAmount{154'288'6904474855, -10}));
1330 amm.expectBalances(btc(59'001), eth(295'001),
IOUAmount{131'928'0106724876, -10}));
1340 amm.expectBalances(btc(19'001), eth(95'001),
IOUAmount{42'485'29157249607, -11}));
1351 testcase(
"test AMMClawback when asset is frozen or locked");
1352 using namespace jtx;
1356 Env env{*
this, features};
1359 env.
fund(
XRP(1'000'000), gw, alice);
1361 env(
fset(gw, asfAllowTrustLineClawback));
1363 auto const usd = gw[
"USD"];
1364 env.
trust(usd(1'000'000), alice);
1365 env(
pay(gw, alice, usd(500'000)));
1372 .flags = tfMPTCanClawback | tfMPTCanLock |
kMptDexFlags});
1373 AMM const ammAlice(env, alice, usd(10'000), btc(10'000));
1374 BEAST_EXPECT(ammAlice.expectBalances(usd(10'000), btc(10'000),
IOUAmount(10'000)));
1377 auto aliceBTC = env.
balance(alice,
MPT(btc));
1378 auto aliceUSD = env.
balance(alice, usd);
1382 btc.set({.flags = tfMPTLock});
1384 BEAST_EXPECT(ammAlice.expectBalances(usd(9'000), btc(9'000),
IOUAmount(9'000)));
1387 aliceUSD = env.
balance(alice, usd);
1390 btc.set({.flags = tfMPTUnlock});
1392 BEAST_EXPECT(ammAlice.expectBalances(
1393 STAmount(usd, UINT64_C(7'000'000000000001), -12), btc(7'001),
IOUAmount(7'000)));
1396 aliceUSD = env.
balance(alice, usd);
1400 env(
trust(gw, alice[
"USD"](0), tfSetFreeze));
1403 BEAST_EXPECT(ammAlice.expectBalances(
1404 STAmount(usd, UINT64_C(6000'000000000002), -12),
1413 env(
fset(gw, asfGlobalFreeze));
1416 BEAST_EXPECT(ammAlice.expectBalances(
1417 STAmount(usd, UINT64_C(4'000'000000000002), -12),
1427 Env env{*
this, features};
1430 env.
fund(
XRP(1'000'000), gw, alice);
1432 env(
fset(gw, asfAllowTrustLineClawback));
1434 auto const usd = gw[
"USD"];
1435 env.
trust(usd(1'000'000), alice);
1436 env(
pay(gw, alice, usd(500'000)));
1443 .flags = tfMPTCanClawback | tfMPTCanLock |
kMptDexFlags});
1444 AMM const ammAlice(env, alice, usd(10'000), btc(10'000));
1445 BEAST_EXPECT(ammAlice.expectBalances(usd(10'000), btc(10'000),
IOUAmount(10'000)));
1448 auto aliceBTC = env.
balance(alice,
MPT(btc));
1449 auto aliceUSD = env.
balance(alice, usd);
1452 btc.set({.holder = alice, .flags = tfMPTLock});
1454 BEAST_EXPECT(ammAlice.expectBalances(usd(8'000), btc(8'000),
IOUAmount(8'000)));
1457 aliceUSD = env.
balance(alice, usd);
1460 env(
trust(gw, alice[
"USD"](0), tfSetFreeze));
1463 BEAST_EXPECT(ammAlice.expectBalances(usd(7'000), btc(7'000),
IOUAmount(7'000)));
1469 btc.set({.holder = alice, .flags = tfMPTUnlock});
1471 BEAST_EXPECT(ammAlice.expectBalances(
1472 STAmount{usd, UINT64_C(4000'000000000001), -12}, btc(4'001),
IOUAmount(4'000)));
1475 aliceUSD = env.
balance(alice, usd);
1478 env(
trust(gw, alice[
"USD"](0), tfClearFreeze));
1481 BEAST_EXPECT(ammAlice.expectBalances(
1482 STAmount(usd, UINT64_C(3'000'000000000002), -12),
1547 testcase(
"test single depoit and clawback");
1548 using namespace jtx;
1552 Env env(*
this, features);
1555 env.
fund(
XRP(1000000000), gw, alice);
1562 .pay = 40'000'000000,
1568 BEAST_EXPECT(
amm.expectBalances(
XRP(100), btc(400),
IOUAmount(200000)));
1569 amm.deposit(alice, btc(400));
1570 BEAST_EXPECT(
amm.expectBalances(
XRP(100), btc(800),
IOUAmount{282842'712474619, -9}));
1572 auto aliceBTC = env.
balance(alice,
MPT(btc));
1577 BEAST_EXPECT(
amm.expectBalances(
1586 Env env(*
this, features);
1589 env.
fund(
XRP(1000000000), gw, alice);
1593 env(
fset(gw, asfAllowTrustLineClawback));
1598 auto const usd = gw[
"USD"];
1599 env.
trust(usd(100000), alice);
1600 env(
pay(gw, alice, usd(1000)));
1607 .pay = 40'000'000000,
1613 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(400),
IOUAmount(200)));
1614 amm.deposit(alice, btc(400));
1615 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(800),
IOUAmount{282'842712474619, -12}));
1617 auto aliceBTC = env.
balance(alice,
MPT(btc));
1618 auto aliceUSD = env.
balance(alice, usd);
1622 BEAST_EXPECT(
amm.expectBalances(
1623 STAmount{usd, UINT64_C(87'50000000000003), -14},
1629 aliceUSD = env.
balance(alice, usd);
1634 BEAST_EXPECT(
amm.expectBalances(
1644 Env env(*
this, features);
1647 env.
fund(
XRP(1000000000), gw, alice);
1654 .pay = 40'000'000000,
1661 .pay = 40'000'000000,
1667 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(400),
IOUAmount(200)));
1668 amm.deposit(alice, btc(400));
1669 BEAST_EXPECT(
amm.expectBalances(usd(100), btc(800),
IOUAmount{282'842712474619, -12}));
1671 auto aliceBTC = env.
balance(alice,
MPT(btc));
1672 auto aliceUSD = env.
balance(alice, usd);
1676 BEAST_EXPECT(
amm.expectBalances(usd(88), btc(701),
IOUAmount{247'4873734152917, -13}));
1680 aliceUSD = env.
balance(alice, usd);
1685 BEAST_EXPECT(
amm.expectBalances(usd(72), btc(567),
IOUAmount(200)));
1697 "test last holder's lptoken balance not equal to AMM's lptoken "
1698 "balance before clawback");
1699 using namespace jtx;
1705 Account const gw{
"gateway"}, alice{
"alice"}, bob{
"bob"};
1706 env.
fund(
XRP(100000), gw, alice, bob);
1708 env(
fset(gw, asfAllowTrustLineClawback));
1711 auto const usd = gw[
"USD"];
1712 env.
trust(usd(100000), alice);
1713 env(
pay(gw, alice, usd(50000)));
1714 env.
trust(usd(100000), bob);
1715 env(
pay(gw, bob, usd(40000)));
1721 .holders = {alice, bob},
1722 .pay = 40'000'000000,
1725 AMM amm(env, alice, usd(2), eur(1));
1728 amm.withdraw(alice,
IOUAmount{1'576123487565916, -15});
1729 amm.withdrawAll(bob);
1731 auto const lpToken =
1734 auto const lpTokenBalance =
1735 amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value].asString();
1738 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.4142135623741");
1742 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.414213562374");
1746 BEAST_EXPECT(res && res.value());
1748 if (features[fixAMMv1_3] && features[fixAMMClawbackRounding])
1751 BEAST_EXPECT(!
amm.ammExists());
1758 BEAST_EXPECT(
amm.ammExists());
1763 BEAST_EXPECT(
amm.ammExists());
1768 BEAST_EXPECT(
amm.ammExists());
1775 Account const gw{
"gateway"}, alice{
"alice"}, bob{
"bob"};
1776 env.
fund(
XRP(100000), gw, alice, bob);
1782 .holders = {alice, bob},
1783 .pay = 40'000'000000,
1789 .holders = {alice, bob},
1790 .pay = 40'000'000000,
1793 AMM amm(env, alice, usd(2), eur(1));
1796 amm.withdraw(alice,
IOUAmount{1'576123487565916, -15});
1797 amm.withdrawAll(bob);
1799 auto const lpToken =
1802 auto const lpTokenBalance =
1803 amm.ammRpcInfo()[jss::amm][jss::lp_token][jss::value].asString();
1806 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.414213562374");
1810 BEAST_EXPECT(lpToken ==
"1.414213562374011" && lpTokenBalance ==
"1.4142135623741");
1814 BEAST_EXPECT(res && res.value());
1816 if (features[fixAMMv1_3] && features[fixAMMClawbackRounding])
1819 BEAST_EXPECT(!
amm.ammExists());
1826 BEAST_EXPECT(
amm.ammExists());
1831 BEAST_EXPECT(
amm.ammExists());
1833 else if (features[featureMPTokensV2])
1836 BEAST_EXPECT(
amm.ammExists());
1844 testcase(
"claw asset check for MPT and IOU");
1845 using namespace jtx;
1849 Env env(*
this, features);
1852 env.
fund(
XRP(100000), gw, alice);
1855 env(
fset(gw, asfAllowTrustLineClawback));
1858 auto const usd = gw[
"USD"];
1859 env.
trust(usd(100000), alice);
1860 env(
pay(gw, alice, usd(1000)));
1864 MPTTester({.env = env, .issuer = gw, .holders = {alice}, .pay = 40'000});
1866 AMM const amm(env, alice, usd(200), btc(100));
1883 Env env(*
this, features);
1886 env.
fund(
XRP(100000), gw, alice);
1889 auto const usd = gw[
"USD"];
1890 env.
trust(usd(100000), alice);
1891 env(
pay(gw, alice, usd(1000)));
1902 AMM const amm(env, alice, usd(200), btc(100));
1919 Env env(*
this, features);
1921 Account const gw2{
"gateway2"};
1923 env.
fund(
XRP(100000), gw, gw2, alice);
1926 env(
fset(gw, asfAllowTrustLineClawback));
1929 auto const usd = gw[
"USD"];
1930 env.
trust(usd(100000), alice);
1931 env(
pay(gw, alice, usd(1000)));
1941 AMM const amm(env, alice, usd(200), btc(100));
1950 auto test = [&](
auto&& issue1,
auto&& issue2) {
1952 Account const gw(
"gateway"), alice(
"alice"), bob(
"bob");
1953 env.
fund(
XRP(30'000), alice, bob, gw);
1955 auto const usd = issue1(
1960 .
limit = 1'000'000});
1961 auto const btc = issue2(
1966 .limit = 1'000'000});
1967 env(
pay(gw, alice, usd(50000)));
1968 env(
pay(bob, alice, btc(50000)));
1971 auto ammAlice =
AMM(env, alice, usd(10000), btc(10100));
1980 auto test = [&](
auto&& issue1,
auto&& issue2) {
1982 Account const gw(
"gateway"), alice(
"alice"), bob(
"bob");
1983 env.
fund(
XRP(30'000), alice, bob, gw);
1985 auto const usd = issue1(
1990 .
limit = 1'000'000});
1991 auto const btc = issue2(
1996 .limit = 1'000'000});
1997 env(
pay(gw, alice, usd(50000)));
1998 env(
pay(bob, alice, btc(50000)));
2001 auto ammAlice =
AMM(env, alice, usd(10000), btc(10100));
2020 testcase(
"test AMMClawback after holder deletes zero-balance MPTokens");
2021 using namespace jtx;
2026 Env env(*
this, features);
2029 env.
fund(
XRP(100'000), gw, alice);
2048 AMM const amm(env, alice, btc(10'000), eth(10'000));
2050 BEAST_EXPECT(
amm.expectBalances(btc(10'000), eth(10'000),
IOUAmount{10'000}));
2052 auto aliceBTC = env.
balance(alice, btc);
2053 auto aliceETH = env.
balance(alice, eth);
2054 BEAST_EXPECT(aliceBTC == btc(0));
2055 BEAST_EXPECT(aliceETH == eth(0));
2058 btc.authorize({.account = alice, .flags = tfMPTUnauthorize});
2059 eth.authorize({.account = alice, .flags = tfMPTUnauthorize});
2074 BEAST_EXPECT(env.
balance(alice, eth) > aliceETH);
2077 BEAST_EXPECT(
amm.ammExists());
2083 Env env(*
this, features);
2086 env.
fund(
XRP(100'000), gw, alice);
2103 AMM const amm(env, alice, btc(10'000), eth(10'000));
2106 auto aliceBTC = env.
balance(alice, btc);
2107 auto aliceETH = env.
balance(alice, eth);
2109 btc.authorize({.account = alice, .flags = tfMPTUnauthorize});
2110 eth.authorize({.account = alice, .flags = tfMPTUnauthorize});
2119 BEAST_EXPECT(!
amm.ammExists());
2129 testcase(
"test AMMClawback recreates paired-issuer MPToken unauthorized");
2130 using namespace jtx;
2141 Env env(*
this, features);
2143 Account const gw2{
"gateway2"};
2145 env.
fund(
XRP(100'000), gw, gw2, alice);
2153 .flags = tfMPTCanClawback | tfMPTRequireAuth |
kMptDexFlags,
2154 .authHolder =
true});
2161 .flags = tfMPTCanClawback | tfMPTRequireAuth |
kMptDexFlags,
2162 .authHolder =
true});
2165 AMM const amm(env, alice, btc(10'000), eth(10'000));
2167 BEAST_EXPECT(
amm.expectBalances(btc(10'000), eth(10'000),
IOUAmount{10'000}));
2168 BEAST_EXPECT(env.
balance(alice, btc) == btc(0));
2169 BEAST_EXPECT(env.
balance(alice, eth) == eth(0));
2172 btc.authorize({.account = alice, .flags = tfMPTUnauthorize});
2173 eth.authorize({.account = alice, .flags = tfMPTUnauthorize});
2186 BEAST_EXPECT(sleBtc);
2187 BEAST_EXPECT(sleEth);
2191 BEAST_EXPECT(sleBtc && sleBtc->isFlag(lsfMPTAuthorized));
2196 BEAST_EXPECT(sleEth && !sleEth->isFlag(lsfMPTAuthorized));
2201 BEAST_EXPECT(sleBtc && sleBtc->getFieldU64(sfMPTAmount) == 0);
2202 BEAST_EXPECT(sleEth && sleEth->getFieldU64(sfMPTAmount) > 0);
2203 BEAST_EXPECT(
amm.ammExists());
2213 testcase(
"test clawback bypasses recipient reserve (MPT)");
2214 using namespace jtx;
2216 Env env(*
this, features);
2218 Account const gw2{
"gateway2"};
2222 auto const usd = gw[
"USD"];
2223 auto const baseFee = env.
current()->fees().base;
2225 env.
fund(
XRP(1'000'000), gw2, carol);
2227 env.
fund(env.
current()->fees().accountReserve(0, 1) + baseFee * 10, gw);
2229 env.
fund(env.
current()->fees().accountReserve(2, 1) + baseFee * 5, alice);
2232 env(
fset(gw, asfAllowTrustLineClawback));
2244 env.
trust(usd(1'000'000), carol);
2245 env(
pay(gw, carol, usd(100'000)));
2251 env.
trust(usd(100'000), alice);
2252 env(
pay(gw, alice, usd(1'000)));
2254 amm.deposit(alice, usd(100));
2266 if (features[fixCleanup3_4_0])
2274 BEAST_EXPECT(env.
balance(alice, btc) > btc(0));