21#include <test/jtx/PathSet.h>
22#include <test/jtx/WSClient.h>
24#include <xrpl/protocol/Feature.h>
25#include <xrpl/protocol/Quality.h>
26#include <xrpl/protocol/jss.h>
36 return env.
current()->fees().accountReserve(count);
42 return env.
current()->info().parentCloseTime.time_since_epoch().count();
52 jvParams[jss::offer][jss::account] = acct.
human();
53 jvParams[jss::offer][jss::seq] = offer_seq;
55 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
61 Issue const& taker_pays,
62 Issue const& taker_gets)
65 jvbp[jss::ledger_index] =
"current";
70 return env.
rpc(
"json",
"book_offers",
to_string(jvbp))[jss::result];
77 testcase(
"Incorrect Removal of Funded Offers");
89 Env env{*
this, features};
91 auto const gw =
Account{
"gateway"};
92 auto const USD = gw[
"USD"];
93 auto const BTC = gw[
"BTC"];
98 env.fund(
XRP(10000), alice, bob, carol, gw);
100 env.trust(USD(1000), alice, bob, carol);
101 env.trust(BTC(1000), alice, bob, carol);
103 env(
pay(gw, alice, BTC(1000)));
105 env(
pay(gw, carol, USD(1000)));
106 env(
pay(gw, carol, BTC(1000)));
111 env(
offer(carol, BTC(49),
XRP(49)));
112 env(
offer(carol, BTC(51),
XRP(51)));
116 env(
offer(carol,
XRP(50), USD(50)));
117 env(
offer(carol,
XRP(50), USD(50)));
120 env(
offer(carol, BTC(1), USD(100)));
124 env(
pay(alice, bob, USD(100)),
129 env.require(
balance(bob, USD(100)));
131 !
isOffer(env, carol, BTC(1), USD(100)) &&
138 testcase(
"Removing Canceled Offers");
141 Env env{*
this, features};
143 auto const gw =
Account{
"gateway"};
144 auto const alice =
Account{
"alice"};
145 auto const USD = gw[
"USD"];
147 env.fund(
XRP(10000), alice, gw);
149 env.trust(USD(100), alice);
152 env(
pay(gw, alice, USD(50)));
155 auto const offer1Seq = env.seq(alice);
160 BEAST_EXPECT(
isOffer(env, alice,
XRP(500), USD(100)));
163 auto const offer2Seq = env.seq(alice);
165 env(
offer(alice,
XRP(300), USD(100)),
166 json(jss::OfferSequence, offer1Seq),
177 env(
offer(alice,
XRP(400), USD(200)),
178 json(jss::OfferSequence, offer1Seq),
187 auto const offer4Seq = env.seq(alice);
191 BEAST_EXPECT(
isOffer(env, alice,
XRP(222), USD(111)));
194 BEAST_EXPECT(env.seq(alice) == offer4Seq + 2);
196 BEAST_EXPECT(!
isOffer(env, alice,
XRP(222), USD(111)));
200 env.require(
offers(alice, 2));
204 bool const featPreauth{features[featureDepositPreauth]};
207 json(jss::OfferSequence, offer2Seq),
211 env.require(
offers(alice, 2));
212 BEAST_EXPECT(
isOffer(env, alice,
XRP(300), USD(100)));
213 BEAST_EXPECT(!
isOffer(env, alice,
XRP(5), USD(2)));
223 using namespace std::chrono_literals;
224 auto const alice =
Account{
"alice"};
225 auto const bob =
Account{
"bob"};
226 auto const carol =
Account{
"carol"};
229 auto const USD = gw[
"USD"];
230 auto const EUR = gw[
"EUR"];
232 Env env{*
this, features};
234 env.fund(
XRP(10000), alice, bob, carol, gw);
236 env.trust(USD(1000), alice, bob, carol);
237 env.trust(EUR(1000), alice, bob, carol);
238 env(
pay(gw, alice, USD(100)));
239 env(
pay(gw, carol, EUR(100)));
245 for (
int i = 0; i < 101; ++i)
246 env(
offer(carol, USD(1), EUR(2)));
272 using namespace std::chrono_literals;
273 auto const alice =
Account{
"alice"};
274 auto const bob =
Account{
"bob"};
275 auto const carol =
Account{
"carol"};
276 auto const dan =
Account{
"dan"};
277 auto const erin =
Account{
"erin"};
280 auto const USD = gw[
"USD"];
281 Env env{*
this, features};
283 env.fund(
XRP(10000), alice, bob, carol, dan, erin, gw);
285 env.trust(USD(1000), alice, bob, carol, dan, erin);
287 env(
pay(gw, carol, USD(0.99999)));
288 env(
pay(gw, dan, USD(1)));
289 env(
pay(gw, erin, USD(1)));
311 env(
pay(alice, bob, USD(1)),
326 testcase(
"Rm small increased q offers XRP");
334 using namespace std::chrono_literals;
335 auto const alice =
Account{
"alice"};
336 auto const bob =
Account{
"bob"};
337 auto const carol =
Account{
"carol"};
340 auto const USD = gw[
"USD"];
343 for (
auto crossBothOffers : {
false,
true})
345 Env env{*
this, features};
347 env.fund(
XRP(10000), alice, bob, carol, gw);
349 env.trust(USD(1000), alice, bob, carol);
351 auto initialCarolUSD = USD(0.499);
352 env(
pay(gw, carol, initialCarolUSD));
353 env(
pay(gw, bob, USD(100)));
365 auto aliceTakerGets = crossBothOffers ?
drops(2) :
drops(1);
366 env(
offer(alice, USD(1), aliceTakerGets));
369 if (features[fixRmSmallIncreasedQOffers])
404 for (
auto partialPayment : {
false,
true})
406 Env env{*
this, features};
408 env.fund(
XRP(10000), alice, bob, carol, gw);
410 env.trust(USD(1000), alice, bob, carol);
412 auto const initialCarolUSD = USD(0.999);
413 env(
pay(gw, carol, initialCarolUSD));
415 env(
pay(gw, bob, USD(100)));
427 TER const expectedTer =
430 env(
pay(alice, bob, USD(5)),
437 if (features[fixRmSmallIncreasedQOffers])
441 env.require(
offers(carol, 0));
458 env.require(
offers(carol, 0));
474 testcase(
"Rm small increased q offers IOU");
482 using namespace std::chrono_literals;
483 auto const alice =
Account{
"alice"};
484 auto const bob =
Account{
"bob"};
485 auto const carol =
Account{
"carol"};
488 auto const USD = gw[
"USD"];
489 auto const EUR = gw[
"EUR"];
500 for (
auto crossBothOffers : {
false,
true})
502 Env env{*
this, features};
504 env.fund(
XRP(10000), alice, bob, carol, gw);
506 env.trust(USD(1000), alice, bob, carol);
507 env.trust(EUR(1000), alice, bob, carol);
509 auto initialCarolUSD = tinyAmount(USD);
510 env(
pay(gw, carol, initialCarolUSD));
511 env(
pay(gw, bob, USD(100)));
512 env(
pay(gw, alice, EUR(100)));
515 env(
offer(carol, EUR(1), USD(10)));
525 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
526 env(
offer(alice, USD(1), aliceTakerGets));
529 if (features[fixRmSmallIncreasedQOffers])
564 for (
auto partialPayment : {
false,
true})
566 Env env{*
this, features};
568 env.fund(
XRP(10000), alice, bob, carol, gw);
570 env.trust(USD(1000), alice, bob, carol);
571 env.trust(EUR(1000), alice, bob, carol);
574 auto const initialCarolUSD = tinyAmount(USD);
575 env(
pay(gw, carol, initialCarolUSD));
576 env(
pay(gw, bob, USD(100)));
577 env(
pay(gw, alice, EUR(100)));
580 env(
offer(carol, EUR(1), USD(2)));
590 TER const expectedTer =
593 env(
pay(alice, bob, USD(5)),
600 if (features[fixRmSmallIncreasedQOffers])
604 env.require(
offers(carol, 0));
621 env.require(
offers(carol, 0));
628 BEAST_EXPECT(
isOffer(env, carol, EUR(1), USD(2)));
641 auto const gw =
Account{
"gateway"};
642 auto const USD = gw[
"USD"];
643 auto const BTC = gw[
"BTC"];
644 auto const EUR = gw[
"EUR"];
652 Env env{*
this, features};
654 auto const gw1 =
Account{
"gw1"};
655 auto const USD1 = gw1[
"USD"];
656 auto const gw2 =
Account{
"gw2"};
657 auto const USD2 = gw2[
"USD"];
659 env.fund(
XRP(10000), alice,
noripple(bob), carol, dan, gw1, gw2);
661 env.trust(USD1(1000), alice, carol, dan);
663 env.trust(USD2(1000), alice, carol, dan);
666 env(
pay(gw1, dan, USD1(50)));
667 env(
pay(gw1, bob, USD1(50)));
668 env(
pay(gw2, bob, USD2(50)));
672 env(
pay(alice, carol, USD2(50)),
680 Env env{*
this, features};
682 auto const gw1 =
Account{
"gw1"};
683 auto const USD1 = gw1[
"USD"];
684 auto const gw2 =
Account{
"gw2"};
685 auto const USD2 = gw2[
"USD"];
687 env.fund(
XRP(10000), alice, bob, carol, dan, gw1, gw2);
689 env.trust(USD1(1000), alice, bob, carol, dan);
690 env.trust(USD2(1000), alice, bob, carol, dan);
692 env(
pay(gw1, dan, USD1(50)));
693 env(
pay(gw1, bob, USD1(50)));
694 env(
pay(gw2, bob, USD2(50)));
698 env(
pay(alice, carol, USD2(50)),
704 env.require(
balance(bob, USD1(100)));
705 env.require(
balance(bob, USD2(0)));
706 env.require(
balance(carol, USD2(50)));
723 auto const gw =
Account{
"gateway"};
724 auto const alice =
Account{
"alice"};
725 auto const bob =
Account{
"bob"};
726 auto const carol =
Account{
"carol"};
727 auto const USD = gw[
"USD"];
729 auto const usdOffer = USD(1000);
730 auto const xrpOffer =
XRP(1000);
734 Env env{*
this, features};
736 env.fund(
XRP(1000000), gw);
738 auto const f = env.current()->fees().base;
739 auto const r =
reserve(env, 0);
741 env.fund(r + f, alice);
752 Env env{*
this, features};
754 env.fund(
XRP(1000000), gw);
756 auto const f = env.current()->fees().base;
757 auto const r =
reserve(env, 0);
759 auto const usdOffer2 = USD(500);
760 auto const xrpOffer2 =
XRP(500);
762 env.fund(r + f + xrpOffer, bob);
765 env.fund(r + f, alice);
772 balance(alice, r - f + xrpOffer2),
784 Env env{*
this, features};
786 env.fund(
XRP(1000000), gw);
788 auto const f = env.current()->fees().base;
789 auto const r =
reserve(env, 0);
791 auto const usdOffer2 = USD(500);
792 auto const xrpOffer2 =
XRP(500);
794 env.fund(r + f + xrpOffer, bob, carol);
799 env.fund(r + f, alice);
806 balance(alice, r - f + xrpOffer),
827 if (sle->getType() == ltOFFER)
828 result.push_back(sle);
840 auto const startBalance =
XRP(1000000);
841 auto const gw =
Account{
"gateway"};
842 auto const alice =
Account{
"alice"};
843 auto const bob =
Account{
"bob"};
844 auto const USD = gw[
"USD"];
852 for (
auto const& tweakedFeatures :
853 {features - fix1578, features | fix1578})
855 Env env{*
this, tweakedFeatures};
857 auto const f = env.
current()->fees().base;
859 env.fund(startBalance, gw, alice, bob);
881 TER const killedCode{
884 env(
offer(alice,
XRP(1000), USD(1000)),
889 balance(alice, startBalance - (f * 2)),
893 balance(bob, startBalance - (f * 2)),
899 env(
offer(alice,
XRP(500), USD(500)),
904 balance(alice, startBalance - (f * 3) +
XRP(500)),
908 balance(bob, startBalance - (f * 2) -
XRP(500)),
917 Env env{*
this, features};
919 auto const f = env.current()->fees().base;
921 env.fund(startBalance, gw, alice, bob);
929 TER const expectedCode = features[featureImmediateOfferKilled]
932 env(
offer(alice,
XRP(1000), USD(1000)),
938 balance(alice, startBalance - f - f),
945 env(
offer(alice,
XRP(1000), USD(1000)),
950 balance(alice, startBalance - f - f - f +
XRP(50)),
966 balance(alice, startBalance - f - f - f - f +
XRP(100)),
970 balance(bob, startBalance - f - f -
XRP(100)),
978 Env env(*
this, features);
980 env.
fund(startBalance, gw, alice, bob);
983 env(
trust(bob, USD(1000)));
986 env(
pay(gw, bob, USD(1000)));
989 env(
offer(alice, USD(1000),
XRP(2000)));
993 BEAST_EXPECT(aliceOffers.size() == 1);
994 for (
auto offerPtr : aliceOffers)
996 auto const&
offer = *offerPtr;
997 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
998 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
1008 BEAST_EXPECT(bobOffers.size() == 1);
1009 for (
auto offerPtr : bobOffers)
1011 auto const&
offer = *offerPtr;
1012 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
1013 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
1017 env(
offer(gw,
XRP(2000), USD(1000)));
1023 env(
offer(gw, USD(1000),
XRP(2000)));
1031 Env env(*
this, features);
1033 env.
fund(startBalance, gw,
"alice",
"bob");
1036 env(
trust(
"bob", USD(1000)));
1039 env(
pay(gw,
"bob", USD(1000)));
1040 env(
offer(
"alice", USD(500),
XRP(1001)));
1043 env(
offer(
"alice", USD(500),
XRP(1000)));
1047 BEAST_EXPECT(aliceOffers.size() == 2);
1057 BEAST_EXPECT(bobOffers.size() == 1);
1058 for (
auto offerPtr : bobOffers)
1060 auto const&
offer = *offerPtr;
1061 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
1062 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
1072 using namespace jtx;
1074 auto const startBalance =
XRP(1000000);
1075 auto const gw =
Account{
"gateway"};
1076 auto const alice =
Account{
"alice"};
1077 auto const USD = gw[
"USD"];
1079 Env env{*
this, features};
1081 env.fund(startBalance, gw, alice);
1085 env(
offer(alice, USD(1000),
XRP(1000)),
1092 env(
offer(alice, USD(1000),
XRP(1000)),
1122 env(
offer(alice, USD(1000),
XRP(1000)),
1130 env(
offer(alice, USD(1000),
XRP(1000)),
1150 using namespace jtx;
1152 auto const gw =
Account{
"gateway"};
1153 auto const alice =
Account{
"alice"};
1154 auto const bob =
Account{
"bob"};
1155 auto const USD = gw[
"USD"];
1157 auto const startBalance =
XRP(1000000);
1158 auto const usdOffer = USD(1000);
1159 auto const xrpOffer =
XRP(1000);
1161 Env env{*
this, features};
1163 env.fund(startBalance, gw, alice, bob);
1166 auto const f = env.current()->fees().base;
1172 balance(alice, startBalance - f),
1179 bool const featPreauth{features[featureDepositPreauth]};
1181 env(
offer(alice, xrpOffer, usdOffer),
1186 balance(alice, startBalance - f - f),
1193 env(
offer(alice, xrpOffer, usdOffer),
1197 balance(alice, startBalance - f - f - f),
1205 balance(alice, startBalance - f - f - f),
1213 balance(alice, startBalance - f - f - f),
1217 balance(bob, startBalance - f),
1228 using namespace jtx;
1230 auto const gw =
Account{
"gateway"};
1231 auto const USD = gw[
"USD"];
1233 auto const usdOffer = USD(1000);
1234 auto const xrpOffer =
XRP(1000);
1236 Env env{*
this, features};
1238 env.fund(
XRP(1000000), gw);
1242 auto const f = env.current()->fees().base;
1246 env.fund(
reserve(env, 0),
"alice");
1253 env.fund(
reserve(env, 0) + f,
"bob");
1261 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1269 env.fund(
reserve(env, 1) + f,
"dan");
1276 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1288 (use_partner ?
", with partner account" :
""));
1290 using namespace jtx;
1292 auto const gw =
Account{
"gateway"};
1293 auto const partner =
Account{
"partner"};
1294 auto const USD = gw[
"USD"];
1295 auto const BTC = gw[
"BTC"];
1297 Env env{*
this, features};
1300 env.fund(
XRP(10000), gw);
1303 env.fund(
XRP(10000), partner);
1305 env(
trust(partner, USD(100)));
1306 env(
trust(partner, BTC(500)));
1308 env(
pay(gw, partner, USD(100)));
1309 env(
pay(gw, partner, BTC(500)));
1311 auto const& account_to_test = use_partner ? partner : gw;
1314 env.require(
offers(account_to_test, 0));
1319 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1320 env.require(
offers(account_to_test, 1));
1323 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1325 auto const secondLegSeq = env.seq(account_to_test);
1326 env(
offer(account_to_test,
XRP(1000), USD(50)));
1327 env.require(
offers(account_to_test, 2));
1330 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1334 env(
offer(account_to_test, USD(50), BTC(250)));
1337 BEAST_EXPECT(jrr[jss::offers].isArray());
1338 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1341 BEAST_EXPECT(jrr[jss::offers].isArray());
1342 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1353 bool const noStaleOffers{
1354 features[featureFlowCross] ||
1355 features[fixTakerDryOfferRemoval]};
1357 BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
1358 for (
auto const& offerPtr : acctOffers)
1360 auto const&
offer = *offerPtr;
1361 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1362 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1363 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1371 env.require(
offers(account_to_test, 0));
1376 env(
offer(account_to_test, BTC(250), USD(50)));
1377 env.require(
offers(account_to_test, 1));
1381 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1384 BEAST_EXPECT(jrr[jss::offers].isArray());
1385 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1389 env(
offer(account_to_test, USD(50), BTC(250)));
1390 env.require(
offers(account_to_test, 1));
1395 BEAST_EXPECT(jrr[jss::offers].isArray());
1396 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1398 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1408 using namespace jtx;
1413 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1415 Env env{*
this, localFeatures};
1417 auto const gw =
Account{
"gateway"};
1418 auto const alice =
Account{
"alice"};
1419 auto const bob =
Account{
"bob"};
1420 auto const USD = gw[
"USD"];
1421 auto const BTC = gw[
"BTC"];
1425 auto const gw_initial_balance =
drops(1149999730);
1426 auto const alice_initial_balance =
drops(499946999680);
1427 auto const bob_initial_balance =
drops(10199999920);
1428 auto const small_amount =
1429 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1431 env.fund(gw_initial_balance, gw);
1432 env.fund(alice_initial_balance, alice);
1433 env.fund(bob_initial_balance, bob);
1436 env(
rate(gw, 1.005));
1438 env(
trust(alice, USD(500)));
1439 env(
trust(bob, USD(50)));
1440 env(
trust(gw, alice[
"USD"](100)));
1442 env(
pay(gw, alice, alice[
"USD"](50)));
1443 env(
pay(gw, bob, small_amount));
1445 env(
offer(alice, USD(50),
XRP(150000)));
1448 env(
pay(alice, gw, USD(100)));
1451 env(
trust(gw, alice[
"USD"](0)));
1456 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1460 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1461 "-2710505431213761e-33");
1465 env(
offer(bob,
XRP(2000), USD(1)));
1467 if (localFeatures[featureFlowCross] &&
1468 localFeatures[fixReducedOffersV2])
1475 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1476 "-2710505431213761e-33");
1480 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1481 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1492 auto const crossingDelta =
1493 localFeatures[featureFlowCross] ?
drops(1) :
drops(0);
1497 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1500 alice_initial_balance - env.current()->fees().base * 3 -
1505 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1508 bob_initial_balance - env.current()->fees().base * 2 +
1518 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1520 using namespace jtx;
1522 Env env{*
this, features};
1524 auto const gw =
Account{
"gateway"};
1525 auto const alice =
Account{
"alice"};
1526 auto const bob =
Account{
"bob"};
1527 auto const USD = gw[
"USD"];
1529 env.fund(
XRP(10000), gw, alice, bob);
1532 env(
trust(alice, USD(1000)));
1533 env(
trust(bob, USD(1000)));
1535 env(
pay(gw, alice, alice[
"USD"](500)));
1538 env(
offer(bob, USD(1),
XRP(4000)));
1540 env(
offer(alice,
XRP(150000), USD(50)));
1543 env(
offer(bob, USD(1),
XRP(4000)));
1550 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1553 jrr[jss::node][sfBalance.fieldName] ==
1555 env.current()->fees().base * 2)
1559 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1562 jrr[jss::node][sfBalance.fieldName] ==
1564 env.current()->fees().base * 2)
1571 testcase(
"Offer Crossing with Limit Override");
1573 using namespace jtx;
1575 Env env{*
this, features};
1577 auto const gw =
Account{
"gateway"};
1578 auto const alice =
Account{
"alice"};
1579 auto const bob =
Account{
"bob"};
1580 auto const USD = gw[
"USD"];
1582 env.fund(
XRP(100000), gw, alice, bob);
1585 env(
trust(alice, USD(1000)));
1587 env(
pay(gw, alice, alice[
"USD"](500)));
1589 env(
offer(alice,
XRP(150000), USD(50)));
1590 env(
offer(bob, USD(1),
XRP(3000)));
1593 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1596 jrr[jss::node][sfBalance.fieldName] ==
1601 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1604 jrr[jss::node][sfBalance.fieldName] ==
1612 testcase(
"Offer Accept then Cancel.");
1614 using namespace jtx;
1616 Env env{*
this, features};
1618 auto const USD = env.master[
"USD"];
1620 auto const nextOfferSeq = env.seq(env.master);
1621 env(
offer(env.master,
XRP(500), USD(100)));
1625 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1630 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1636 testcase(
"Offer Cancel Past and Future Sequence.");
1638 using namespace jtx;
1640 Env env{*
this, features};
1642 auto const alice =
Account{
"alice"};
1644 auto const nextOfferSeq = env.seq(env.master);
1645 env.fund(
XRP(10000), alice);
1662 testcase(
"Currency Conversion: Entire Offer");
1664 using namespace jtx;
1666 Env env{*
this, features};
1668 auto const gw =
Account{
"gateway"};
1669 auto const alice =
Account{
"alice"};
1670 auto const bob =
Account{
"bob"};
1671 auto const USD = gw[
"USD"];
1673 env.fund(
XRP(10000), gw, alice, bob);
1675 env.require(
owners(bob, 0));
1677 env(
trust(alice, USD(100)));
1678 env(
trust(bob, USD(1000)));
1682 env(
pay(gw, alice, alice[
"USD"](100)));
1683 auto const bobOfferSeq = env.seq(bob);
1684 env(
offer(bob, USD(100),
XRP(500)));
1689 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1691 jro[jss::node][jss::TakerPays] ==
1697 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1700 jrr[jss::node][sfBalance.fieldName] ==
1705 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1708 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1716 testcase(
"Currency Conversion: Offerer Into Debt");
1718 using namespace jtx;
1720 Env env{*
this, features};
1722 auto const alice =
Account{
"alice"};
1723 auto const bob =
Account{
"bob"};
1724 auto const carol =
Account{
"carol"};
1726 env.fund(
XRP(10000), alice, bob, carol);
1729 env(
trust(alice, carol[
"EUR"](2000)));
1730 env(
trust(bob, alice[
"USD"](100)));
1731 env(
trust(carol, bob[
"EUR"](1000)));
1733 auto const bobOfferSeq = env.seq(bob);
1734 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1737 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1740 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1746 testcase(
"Currency Conversion: In Parts");
1748 using namespace jtx;
1750 Env env{*
this, features};
1752 auto const gw =
Account{
"gateway"};
1753 auto const alice =
Account{
"alice"};
1754 auto const bob =
Account{
"bob"};
1755 auto const USD = gw[
"USD"];
1757 env.fund(
XRP(10000), gw, alice, bob);
1760 env(
trust(alice, USD(200)));
1761 env(
trust(bob, USD(1000)));
1763 env(
pay(gw, alice, alice[
"USD"](200)));
1765 auto const bobOfferSeq = env.seq(bob);
1766 env(
offer(bob, USD(100),
XRP(500)));
1773 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1775 jro[jss::node][jss::TakerPays] ==
1781 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1785 jrr[jss::node][sfBalance.fieldName] ==
1791 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1795 env(
pay(alice, alice,
XRP(600)),
1801 env(
pay(alice, alice,
XRP(600)),
1807 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1815 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1818 jrr[jss::node][sfBalance.fieldName] ==
1820 env.current()->fees().base * 4)
1826 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1832 testcase(
"Cross Currency Payment: Start with XRP");
1834 using namespace jtx;
1836 Env env{*
this, features};
1838 auto const gw =
Account{
"gateway"};
1839 auto const alice =
Account{
"alice"};
1840 auto const bob =
Account{
"bob"};
1841 auto const carol =
Account{
"carol"};
1842 auto const USD = gw[
"USD"];
1844 env.fund(
XRP(10000), gw, alice, bob, carol);
1847 env(
trust(carol, USD(1000)));
1848 env(
trust(bob, USD(2000)));
1850 env(
pay(gw, carol, carol[
"USD"](500)));
1852 auto const carolOfferSeq = env.seq(carol);
1853 env(
offer(carol,
XRP(500), USD(50)));
1858 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1861 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1865 jro[jss::node][jss::TakerGets] ==
1868 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1874 testcase(
"Cross Currency Payment: End with XRP");
1876 using namespace jtx;
1878 Env env{*
this, features};
1880 auto const gw =
Account{
"gateway"};
1881 auto const alice =
Account{
"alice"};
1882 auto const bob =
Account{
"bob"};
1883 auto const carol =
Account{
"carol"};
1884 auto const USD = gw[
"USD"];
1886 env.fund(
XRP(10000), gw, alice, bob, carol);
1889 env(
trust(alice, USD(1000)));
1890 env(
trust(carol, USD(2000)));
1892 env(
pay(gw, alice, alice[
"USD"](500)));
1894 auto const carolOfferSeq = env.seq(carol);
1895 env(
offer(carol, USD(50),
XRP(500)));
1900 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1903 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1907 jrr[jss::node][sfBalance.fieldName] ==
1909 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1913 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1915 jro[jss::node][jss::TakerPays] ==
1922 testcase(
"Cross Currency Payment: Bridged");
1924 using namespace jtx;
1926 Env env{*
this, features};
1928 auto const gw1 =
Account{
"gateway_1"};
1929 auto const gw2 =
Account{
"gateway_2"};
1930 auto const alice =
Account{
"alice"};
1931 auto const bob =
Account{
"bob"};
1932 auto const carol =
Account{
"carol"};
1933 auto const dan =
Account{
"dan"};
1934 auto const USD = gw1[
"USD"];
1935 auto const EUR = gw2[
"EUR"];
1937 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1940 env(
trust(alice, USD(1000)));
1941 env(
trust(bob, EUR(1000)));
1942 env(
trust(carol, USD(1000)));
1943 env(
trust(dan, EUR(1000)));
1945 env(
pay(gw1, alice, alice[
"USD"](500)));
1946 env(
pay(gw2, dan, dan[
"EUR"](400)));
1948 auto const carolOfferSeq = env.seq(carol);
1949 env(
offer(carol, USD(50),
XRP(500)));
1951 auto const danOfferSeq = env.seq(dan);
1952 env(
offer(dan,
XRP(500), EUR(50)));
1955 jtp[0u][0u][jss::currency] =
"XRP";
1956 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1959 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1962 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1965 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1968 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1972 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1974 jro[jss::node][jss::TakerPays] ==
1979 jro[jss::node][jss::TakerGets] ==
1982 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1991 testcase(
"Auto Bridged Second Leg Dry");
1993 using namespace jtx;
1994 Env env(*
this, features);
2000 auto const USD = gw[
"USD"];
2001 auto const EUR = gw[
"EUR"];
2003 env.
fund(
XRP(100000000), alice, bob, carol, gw);
2006 env.
trust(USD(10), alice);
2008 env(
pay(gw, alice, USD(10)));
2009 env.
trust(USD(10), carol);
2011 env(
pay(gw, carol, USD(3)));
2028 env.
trust(EUR(10), bob);
2030 env(
pay(gw, bob, EUR(10)));
2032 env(
offer(bob, USD(10), EUR(10)));
2049 int const emptyOfferCount{
2050 features[featureFlowCross] || features[fixTakerDryOfferRemoval]
2061 testcase(
"Offer Fees Consume Funds");
2063 using namespace jtx;
2065 Env env{*
this, features};
2067 auto const gw1 =
Account{
"gateway_1"};
2068 auto const gw2 =
Account{
"gateway_2"};
2069 auto const gw3 =
Account{
"gateway_3"};
2070 auto const alice =
Account{
"alice"};
2071 auto const bob =
Account{
"bob"};
2072 auto const USD1 = gw1[
"USD"];
2073 auto const USD2 = gw2[
"USD"];
2074 auto const USD3 = gw3[
"USD"];
2082 auto const starting_xrp =
XRP(100) +
2083 env.current()->fees().accountReserve(3) +
2084 env.current()->fees().base * 4;
2086 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2089 env(
trust(alice, USD1(1000)));
2090 env(
trust(alice, USD2(1000)));
2091 env(
trust(alice, USD3(1000)));
2092 env(
trust(bob, USD1(1000)));
2093 env(
trust(bob, USD2(1000)));
2095 env(
pay(gw1, bob, bob[
"USD"](500)));
2097 env(
offer(bob,
XRP(200), USD1(200)));
2100 env(
offer(alice, USD1(200),
XRP(200)));
2103 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2106 jrr[jss::node][sfBalance.fieldName] ==
2110 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2116 testcase(
"Offer Create, then Cross");
2118 using namespace jtx;
2120 for (
auto NumberSwitchOver : {
false,
true})
2122 Env env{*
this, features};
2123 if (NumberSwitchOver)
2124 env.enableFeature(fixUniversalNumber);
2126 env.disableFeature(fixUniversalNumber);
2128 auto const gw =
Account{
"gateway"};
2129 auto const alice =
Account{
"alice"};
2130 auto const bob =
Account{
"bob"};
2131 auto const USD = gw[
"USD"];
2133 env.fund(
XRP(10000), gw, alice, bob);
2136 env(
rate(gw, 1.005));
2138 env(
trust(alice, USD(1000)));
2139 env(
trust(bob, USD(1000)));
2140 env(
trust(gw, alice[
"USD"](50)));
2142 env(
pay(gw, bob, bob[
"USD"](1)));
2143 env(
pay(alice, gw, USD(50)));
2145 env(
trust(gw, alice[
"USD"](0)));
2147 env(
offer(alice, USD(50),
XRP(150000)));
2148 env(
offer(bob,
XRP(100), USD(0.1)));
2152 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2153 "49.96666666666667");
2157 jrr[jss::node][sfBalance.fieldName][jss::value];
2158 if (!NumberSwitchOver)
2160 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2164 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2172 testcase(
"Offer tfSell: Basic Sell");
2174 using namespace jtx;
2176 Env env{*
this, features};
2178 auto const gw =
Account{
"gateway"};
2179 auto const alice =
Account{
"alice"};
2180 auto const bob =
Account{
"bob"};
2181 auto const USD = gw[
"USD"];
2183 auto const starting_xrp =
XRP(100) +
2184 env.current()->fees().accountReserve(1) +
2185 env.current()->fees().base * 2;
2187 env.fund(starting_xrp, gw, alice, bob);
2190 env(
trust(alice, USD(1000)));
2191 env(
trust(bob, USD(1000)));
2193 env(
pay(gw, bob, bob[
"USD"](500)));
2202 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2205 jrr[jss::node][sfBalance.fieldName] ==
2209 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2215 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2217 using namespace jtx;
2219 Env env{*
this, features};
2221 auto const gw =
Account{
"gateway"};
2222 auto const alice =
Account{
"alice"};
2223 auto const bob =
Account{
"bob"};
2224 auto const USD = gw[
"USD"];
2226 auto const starting_xrp =
XRP(100) +
2227 env.current()->fees().accountReserve(1) +
2228 env.current()->fees().base * 2;
2230 env.fund(starting_xrp, gw, alice, bob);
2233 env(
trust(alice, USD(150)));
2234 env(
trust(bob, USD(1000)));
2236 env(
pay(gw, bob, bob[
"USD"](500)));
2238 env(
offer(bob,
XRP(100), USD(200)));
2247 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2250 jrr[jss::node][sfBalance.fieldName] ==
2254 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2260 testcase(
"Client Issue #535: Gateway Cross Currency");
2262 using namespace jtx;
2264 Env env{*
this, features};
2266 auto const gw =
Account{
"gateway"};
2267 auto const alice =
Account{
"alice"};
2268 auto const bob =
Account{
"bob"};
2269 auto const XTS = gw[
"XTS"];
2270 auto const XXX = gw[
"XXX"];
2272 auto const starting_xrp =
XRP(100.1) +
2273 env.current()->fees().accountReserve(1) +
2274 env.current()->fees().base * 2;
2276 env.fund(starting_xrp, gw, alice, bob);
2279 env(
trust(alice, XTS(1000)));
2280 env(
trust(alice, XXX(1000)));
2281 env(
trust(bob, XTS(1000)));
2282 env(
trust(bob, XXX(1000)));
2284 env(
pay(gw, alice, alice[
"XTS"](100)));
2285 env(
pay(gw, alice, alice[
"XXX"](100)));
2286 env(
pay(gw, bob, bob[
"XTS"](100)));
2287 env(
pay(gw, bob, bob[
"XXX"](100)));
2289 env(
offer(alice, XTS(100), XXX(100)));
2296 payment[jss::id] = env.seq(bob);
2297 payment[jss::build_path] =
true;
2298 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2299 payment[jss::tx_json][jss::Sequence] =
2302 ->getFieldU32(sfSequence);
2303 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2304 payment[jss::tx_json][jss::SendMax] =
2306 auto jrr = wsc->invoke(
"submit", payment);
2307 BEAST_EXPECT(jrr[jss::status] ==
"success");
2308 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2309 if (wsc->version() == 2)
2312 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2314 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2315 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2319 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2321 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2324 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2326 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2341 auto const sleTrust =
2343 BEAST_EXPECT(sleTrust);
2347 bool const accountLow = account.id() < issue.
account;
2352 low.setIssuer(accountLow ? account.id() : issue.
account);
2353 high.setIssuer(accountLow ? issue.
account : account.id());
2355 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2356 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2358 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2362 BEAST_EXPECT(actualBalance == expectBalance);
2374 using namespace jtx;
2376 auto const gw =
Account(
"gateway");
2377 auto const USD = gw[
"USD"];
2379 Env env{*
this, features};
2381 env.fund(
XRP(10000000), gw);
2385 auto const f = env.current()->fees().base;
2388 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2394 preTrustType preTrust;
2404 TestData
const tests[]{
2406 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2407 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2408 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2409 {
"deb",
drops(10) +
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 1},
2410 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2411 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2412 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2413 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2414 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2415 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2416 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2417 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2418 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2419 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2420 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2421 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2422 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2423 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2425 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2426 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2427 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2428 {
"dan",
drops(10) +
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 0},
2429 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2430 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2431 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2432 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2434 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2435 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2436 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2437 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2438 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2439 {
"syd",
drops(10) +
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
drops(10) + 2 * f, USD(0.00001), 0, 1},
2440 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2441 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2442 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2443 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2444 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2448 for (
auto const& t : tests)
2450 auto const acct =
Account(t.account);
2451 env.fund(t.fundXrp, acct);
2455 env.require(
offers(gw, 0));
2458 auto const book = t.bookAmount;
2460 env(
offer(gw,
XRP(book), USD(book)));
2465 if (t.preTrust == gwPreTrust)
2466 env(
trust(gw, acct[
"USD"](1)));
2472 if (t.preTrust == acctPreTrust)
2473 env(
trust(acct, USD(1)));
2478 auto const acctOffer = t.offerAmount;
2479 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2484 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2486 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2487 env.require(
offers(acct, t.offers));
2488 env.require(
owners(acct, t.owners));
2491 BEAST_EXPECT(acctOffers.size() == t.offers);
2492 if (acctOffers.size() && t.offers)
2494 auto const& acctOffer = *(acctOffers.front());
2496 auto const leftover = t.offerAmount - t.bookAmount;
2497 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2498 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2501 if (t.preTrust == noPreTrust)
2503 if (t.balanceUsd.value().signum())
2511 auto const sleTrust =
2513 BEAST_EXPECT(!sleTrust);
2530 using namespace jtx;
2532 auto const gw =
Account(
"gateway");
2533 auto const alice =
Account(
"alice");
2534 auto const bob =
Account(
"bob");
2535 auto const USD = gw[
"USD"];
2537 auto const usdOffer = USD(1000);
2538 auto const xrpOffer =
XRP(1000);
2540 Env env{*
this, features};
2542 env.fund(
XRP(1000000), gw, bob);
2546 auto const fee = env.current()->fees().base;
2553 env(
trust(alice, usdOffer));
2557 env(
pay(gw, alice, usdOffer));
2564 auto const alicesXRP = env.balance(alice);
2565 auto const bobsXRP = env.balance(bob);
2567 env(
offer(alice, xrpOffer, usdOffer));
2569 env(
offer(bob, usdOffer, xrpOffer));
2583 env(
offer(alice, USD(999),
XRP(999)));
2584 env(
offer(bob, xrpOffer, usdOffer));
2587 env.require(
balance(alice, USD(999)));
2588 env.require(
balance(bob, USD(1)));
2589 env.require(
offers(alice, 0));
2593 BEAST_EXPECT(bobsOffers.size() == 1);
2594 auto const& bobsOffer = *(bobsOffers.front());
2596 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2597 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2598 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2607 using namespace jtx;
2609 auto const gw =
Account(
"gateway");
2610 auto const alice =
Account(
"alice");
2611 auto const bob =
Account(
"bob");
2612 auto const USD = gw[
"USD"];
2613 auto const EUR = gw[
"EUR"];
2615 auto const usdOffer = USD(1000);
2616 auto const eurOffer = EUR(1000);
2618 Env env{*
this, features};
2620 env.fund(
XRP(1000000), gw);
2624 auto const fee = env.current()->fees().base;
2632 env(
trust(alice, usdOffer));
2633 env(
trust(bob, eurOffer));
2636 env(
pay(gw, alice, usdOffer));
2637 env(
pay(gw, bob, eurOffer));
2645 env(
offer(alice, eurOffer, usdOffer));
2646 env(
offer(bob, usdOffer, eurOffer));
2663 env(
offer(bob, eurOffer, usdOffer));
2666 env(
offer(alice, USD(999), eurOffer));
2669 env.require(
offers(alice, 0));
2670 env.require(
offers(bob, 1));
2672 env.require(
balance(alice, USD(999)));
2673 env.require(
balance(alice, EUR(1)));
2674 env.require(
balance(bob, USD(1)));
2675 env.require(
balance(bob, EUR(999)));
2679 if (BEAST_EXPECT(bobsOffers.size() == 1))
2681 auto const& bobsOffer = *(bobsOffers.front());
2683 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2684 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2689 env(
offer(alice, USD(1), EUR(1)));
2692 env.require(
balance(alice, USD(1000)));
2695 env.require(
balance(bob, EUR(1000)));
2696 env.require(
offers(alice, 0));
2697 env.require(
offers(bob, 0));
2700 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2701 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2705 env(
offer(alice, EUR(999), usdOffer));
2708 env(
offer(bob, usdOffer, eurOffer));
2711 env.require(
offers(alice, 0));
2712 env.require(
offers(bob, 0));
2714 env.require(
balance(alice, USD(0)));
2715 env.require(
balance(alice, EUR(999)));
2716 env.require(
balance(bob, USD(1000)));
2717 env.require(
balance(bob, EUR(1)));
2725 using namespace jtx;
2727 auto const gw =
Account(
"gateway");
2728 auto const alice =
Account(
"alice");
2729 auto const bob =
Account(
"bob");
2730 auto const carol =
Account(
"carol");
2731 auto const USD = gw[
"USD"];
2732 auto const EUR = gw[
"EUR"];
2734 auto const usdOffer = USD(1000);
2735 auto const eurOffer = EUR(1000);
2737 Env env{*
this, features};
2739 env.fund(
XRP(1000000), gw, alice, bob, carol);
2742 env(
trust(alice, usdOffer));
2743 env(
trust(carol, eurOffer));
2745 env(
pay(gw, alice, usdOffer));
2746 env(
pay(gw, carol, eurOffer));
2755 env(
offer(alice,
XRP(1000), usdOffer));
2756 env(
offer(bob, eurOffer,
XRP(1000)));
2757 auto const bobXrpBalance = env.balance(bob);
2761 env(
offer(carol, USD(400), EUR(400)));
2774 BEAST_EXPECT(alicesOffers.size() == 1);
2775 auto const& alicesOffer = *(alicesOffers.front());
2777 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2778 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2779 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2783 BEAST_EXPECT(bobsOffers.size() == 1);
2784 auto const& bobsOffer = *(bobsOffers.front());
2786 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2787 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2788 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2792 env(
offer(carol, USD(600), EUR(600)));
2807 if (alicesOffers.size() != 0)
2809 BEAST_EXPECT(alicesOffers.size() == 1);
2810 auto const& alicesOffer = *(alicesOffers.front());
2812 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2813 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2814 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2826 using namespace jtx;
2828 auto const gw =
Account(
"gateway");
2829 auto const USD = gw[
"USD"];
2831 Env env{*
this, features};
2833 env.fund(
XRP(10000000), gw);
2837 auto const f = env.current()->fees().base;
2840 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2874 : account(std::move(account_))
2879 , acctGets(acctGets_)
2880 , acctPays(acctPays_)
2882 , spentXrp(spentXrp_)
2883 , finalUsd(finalUsd_)
2886 , takerGets(takerGets_)
2887 , takerPays(takerPays_)
2906 std::move(account_),
2925 TestData
const tests[]{
2928 {
"ann",
XRP(10) +
reserve(env, 0) + 1 * f, USD( 0),
XRP(10), USD( 5), USD(10),
XRP(10),
tecINSUF_RESERVE_OFFER,
XRP( 0) + (1 * f), USD( 0), 0, 0},
2929 {
"bev",
XRP(10) +
reserve(env, 1) + 1 * f, USD( 0),
XRP(10), USD( 5), USD(10),
XRP(10),
tesSUCCESS,
XRP( 0) + (1 * f), USD( 0), 1, 1,
XRP(10), USD(10)},
2930 {
"cam",
XRP(10) +
reserve(env, 0) + 1 * f, USD( 0),
XRP(10), USD(10), USD(10),
XRP(10),
tesSUCCESS,
XRP( 10) + (1 * f), USD(10), 0, 1},
2931 {
"deb",
XRP(10) +
reserve(env, 0) + 1 * f, USD( 0),
XRP(10), USD(20), USD(10),
XRP(10),
tesSUCCESS,
XRP( 10) + (1 * f), USD(20), 0, 1},
2932 {
"eve",
XRP(10) +
reserve(env, 0) + 1 * f, USD( 0),
XRP(10), USD(20), USD( 5),
XRP( 5),
tesSUCCESS,
XRP( 5) + (1 * f), USD(10), 0, 1},
2933 {
"flo",
XRP(10) +
reserve(env, 0) + 1 * f, USD( 0),
XRP(10), USD(20), USD(20),
XRP(20),
tesSUCCESS,
XRP( 10) + (1 * f), USD(20), 0, 1},
2934 {
"gay",
XRP(20) +
reserve(env, 1) + 1 * f, USD( 0),
XRP(10), USD(20), USD(20),
XRP(20),
tesSUCCESS,
XRP( 10) + (1 * f), USD(20), 0, 1},
2935 {
"hye",
XRP(20) +
reserve(env, 2) + 1 * f, USD( 0),
XRP(10), USD(20), USD(20),
XRP(20),
tesSUCCESS,
XRP( 10) + (1 * f), USD(20), 1, 2,
XRP(10), USD(10)},
2937 {
"meg",
reserve(env, 1) + 2 * f, USD(10), USD(10),
XRP( 5),
XRP(10), USD(10),
tecINSUF_RESERVE_OFFER,
XRP( 0) + (2 * f), USD(10), 0, 1},
2938 {
"nia",
reserve(env, 2) + 2 * f, USD(10), USD(10),
XRP( 5),
XRP(10), USD(10),
tesSUCCESS,
XRP( 0) + (2 * f), USD(10), 1, 2, USD(10),
XRP(10)},
2939 {
"ova",
reserve(env, 1) + 2 * f, USD(10), USD(10),
XRP(10),
XRP(10), USD(10),
tesSUCCESS,
XRP(-10) + (2 * f), USD( 0), 0, 1},
2940 {
"pam",
reserve(env, 1) + 2 * f, USD(10), USD(10),
XRP(20),
XRP(10), USD(10),
tesSUCCESS,
XRP(-20) + (2 * f), USD( 0), 0, 1},
2941 {
"qui",
reserve(env, 1) + 2 * f, USD(10), USD(20),
XRP(40),
XRP(10), USD(10),
tesSUCCESS,
XRP(-20) + (2 * f), USD( 0), 0, 1},
2942 {
"rae",
reserve(env, 2) + 2 * f, USD(10), USD( 5),
XRP( 5),
XRP(10), USD(10),
tesSUCCESS,
XRP( -5) + (2 * f), USD( 5), 1, 2, USD( 5),
XRP( 5)},
2943 {
"sue",
reserve(env, 2) + 2 * f, USD(10), USD( 5),
XRP(10),
XRP(10), USD(10),
tesSUCCESS,
XRP(-10) + (2 * f), USD( 5), 1, 2, USD( 5),
XRP( 5)},
2947 auto const zeroUsd = USD(0);
2948 for (
auto const& t : tests)
2951 env.require(
offers(gw, 0));
2953 auto const acct =
Account(t.account);
2955 env.fund(t.fundXrp, acct);
2961 if (t.fundUSD != zeroUsd)
2963 env(
trust(acct, t.fundUSD));
2965 env(
pay(gw, acct, t.fundUSD));
2969 env(
offer(gw, t.gwGets, t.gwPays));
2979 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2981 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2982 env.require(
offers(acct, t.offers));
2983 env.require(
owners(acct, t.owners));
2988 if (acctOffers.size() > 0)
2990 BEAST_EXPECT(acctOffers.size() == 1);
2991 auto const& acctOffer = *(acctOffers.front());
2993 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2994 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2995 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
3012 testcase(
"Combine tfSell with tfFillOrKill");
3014 using namespace jtx;
3016 auto const gw =
Account(
"gateway");
3017 auto const alice =
Account(
"alice");
3018 auto const bob =
Account(
"bob");
3019 auto const USD = gw[
"USD"];
3021 Env env{*
this, features};
3023 env.fund(
XRP(10000000), gw, alice, bob);
3027 TER const killedCode{
3031 env(
trust(bob, USD(200)));
3033 env(
pay(gw, bob, USD(100)));
3035 env(
offer(bob,
XRP(2000), USD(20)));
3043 env.require(
offers(alice, 0));
3044 env.require(
balance(bob, USD(100)));
3051 env.require(
balance(alice, USD(20)));
3052 env.require(
offers(alice, 0));
3053 env.require(
balance(bob, USD(80)));
3058 env(
offer(bob,
XRP(2000), USD(20)));
3062 env.require(
balance(alice, USD(35)));
3063 env.require(
offers(alice, 0));
3064 env.require(
balance(bob, USD(65)));
3076 env.require(
balance(alice, USD(35)));
3077 env.require(
offers(alice, 0));
3078 env.require(
balance(bob, USD(65)));
3087 env.require(
balance(alice, USD(40)));
3088 env.require(
offers(alice, 0));
3089 env.require(
balance(bob, USD(60)));
3098 using namespace jtx;
3100 auto const gw1 =
Account(
"gateway1");
3101 auto const USD = gw1[
"USD"];
3103 Env env{*
this, features};
3106 auto const fee = env.current()->fees().base;
3108 env.fund(
XRP(100000), gw1);
3111 env(
rate(gw1, 1.25));
3113 auto const ann =
Account(
"ann");
3114 auto const bob =
Account(
"bob");
3118 env(
trust(ann, USD(200)));
3119 env(
trust(bob, USD(200)));
3122 env(
pay(gw1, bob, USD(125)));
3137 env.require(
balance(ann, USD(100)));
3139 env.require(
offers(ann, 0));
3141 env.require(
balance(bob, USD(0)));
3143 env.require(
offers(bob, 0));
3148 auto const che =
Account(
"che");
3149 auto const deb =
Account(
"deb");
3153 env(
trust(che, USD(200)));
3154 env(
trust(deb, USD(200)));
3157 env(
pay(gw1, deb, USD(125)));
3166 env.require(
balance(che, USD(100)));
3168 env.require(
offers(che, 0));
3170 env.require(
balance(deb, USD(0)));
3172 env.require(
offers(deb, 0));
3175 auto const eve =
Account(
"eve");
3176 auto const fyn =
Account(
"fyn");
3178 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3181 env(
trust(eve, USD(1000)));
3182 env(
trust(fyn, USD(1000)));
3185 env(
pay(gw1, eve, USD(100)));
3186 env(
pay(gw1, fyn, USD(100)));
3192 env(
offer(eve, USD(10),
XRP(4000)));
3196 env(
offer(fyn,
XRP(2000), USD(5)));
3199 env.require(
balance(eve, USD(105)));
3202 BEAST_EXPECT(evesOffers.size() == 1);
3203 if (evesOffers.size() != 0)
3205 auto const& evesOffer = *(evesOffers.front());
3206 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3207 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3208 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3212 env.require(
balance(fyn, USD(93.75)));
3214 env.require(
offers(fyn, 0));
3217 auto const gw2 =
Account(
"gateway2");
3218 auto const EUR = gw2[
"EUR"];
3220 env.fund(
XRP(100000), gw2);
3223 env(
rate(gw2, 1.5));
3228 auto const gay =
Account(
"gay");
3229 auto const hal =
Account(
"hal");
3230 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3233 env(
trust(gay, USD(200)));
3234 env(
trust(gay, EUR(200)));
3235 env(
trust(hal, USD(200)));
3236 env(
trust(hal, EUR(200)));
3239 env(
pay(gw1, gay, USD(125)));
3240 env(
pay(gw2, hal, EUR(150)));
3243 env(
offer(gay, EUR(100), USD(100)));
3246 env(
offer(hal, USD(100), EUR(100)));
3249 env.require(
balance(gay, USD(0)));
3250 env.require(
balance(gay, EUR(100)));
3252 env.require(
offers(gay, 0));
3254 env.require(
balance(hal, USD(100)));
3255 env.require(
balance(hal, EUR(0)));
3257 env.require(
offers(hal, 0));
3261 auto const ivy =
Account(
"ivy");
3262 auto const joe =
Account(
"joe");
3263 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3272 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3273 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3275 env.require(
balance(ivy, USD(300)));
3276 env.require(
balance(joe, EUR(250)));
3278 env(
offer(ivy, EUR(100), USD(200)));
3281 env(
offer(joe, USD(200), EUR(100)));
3284 env.require(
balance(ivy, USD(50)));
3285 env.require(
balance(ivy, EUR(100)));
3287 env.require(
offers(ivy, 0));
3289 env.require(
balance(joe, USD(200)));
3290 env.require(
balance(joe, EUR(100)));
3292 env.require(
offers(joe, 0));
3296 auto const kim =
Account(
"kim");
3297 auto const K_BUX = kim[
"BUX"];
3298 auto const lex =
Account(
"lex");
3299 auto const meg =
Account(
"meg");
3300 auto const ned =
Account(
"ned");
3301 auto const N_BUX = ned[
"BUX"];
3304 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3307 env(
trust(lex, K_BUX(400)));
3309 env(
trust(meg, N_BUX(100)));
3311 env(
pay(ned, lex, N_BUX(100)));
3313 env.require(
balance(lex, N_BUX(100)));
3315 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3320 env.require(
balance(lex, K_BUX(72)));
3321 env.require(
balance(lex, N_BUX(40)));
3323 env.require(
balance(meg, N_BUX(60)));
3328 env(
offer(lex, K_BUX(30), N_BUX(30)));
3331 env(
offer(kim, N_BUX(30), K_BUX(30)));
3335 env.require(
balance(kim, N_BUX(30)));
3336 env.require(
balance(lex, K_BUX(102)));
3337 env.require(
balance(lex, N_BUX(10)));
3339 env.require(
balance(meg, N_BUX(60)));
3340 env.require(
balance(ned, K_BUX(-30)));
3345 auto const ova =
Account(
"ova");
3346 auto const pat =
Account(
"pat");
3347 auto const qae =
Account(
"qae");
3348 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3354 env(
trust(ova, USD(200)));
3355 env(
trust(ova, EUR(200)));
3356 env(
trust(pat, USD(200)));
3357 env(
trust(pat, EUR(200)));
3358 env(
trust(qae, USD(200)));
3359 env(
trust(qae, EUR(200)));
3362 env(
pay(gw1, ova, USD(125)));
3363 env(
pay(gw2, qae, EUR(150)));
3370 env(
offer(qae, USD(100), EUR(100)));
3373 env.require(
balance(ova, USD(0)));
3374 env.require(
balance(ova, EUR(0)));
3379 if (ovasOffers.size() != 0)
3381 BEAST_EXPECT(ovasOffers.size() == 1);
3382 auto const& ovasOffer = *(ovasOffers.front());
3384 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3385 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3386 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3389 env.require(
balance(pat, USD(0)));
3390 env.require(
balance(pat, EUR(100)));
3392 env.require(
offers(pat, 0));
3394 env.require(
balance(qae, USD(100)));
3395 env.require(
balance(qae, EUR(0)));
3397 env.require(
offers(qae, 0));
3418 using namespace jtx;
3420 auto const gw =
Account(
"gateway");
3421 auto const USD = gw[
"USD"];
3423 Env env{*
this, features};
3426 auto const fee = env.current()->fees().base;
3427 auto const startBalance =
XRP(1000000);
3429 env.fund(startBalance + (
fee * 4), gw);
3439 env.require(
owners(gw, 3));
3440 env.require(
balance(gw, startBalance +
fee));
3443 BEAST_EXPECT(gwOffers.size() == 3);
3444 for (
auto const& offerPtr : gwOffers)
3446 auto const&
offer = *offerPtr;
3447 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3448 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3449 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3454 env(
offer(gw,
XRP(1000), USD(100)));
3456 env.require(
owners(gw, 1));
3457 env.require(
offers(gw, 1));
3458 env.require(
balance(gw, startBalance));
3461 BEAST_EXPECT(gwOffers.size() == 1);
3462 for (
auto const& offerPtr : gwOffers)
3464 auto const&
offer = *offerPtr;
3465 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3466 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3467 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3474 using namespace jtx;
3476 auto const gw1 =
Account(
"gateway1");
3477 auto const gw2 =
Account(
"gateway2");
3478 auto const alice =
Account(
"alice");
3479 auto const USD = gw1[
"USD"];
3480 auto const EUR = gw2[
"EUR"];
3482 Env env{*
this, features};
3484 env.fund(
XRP(1000000), gw1, gw2);
3488 auto const f = env.current()->fees().base;
3502 TestData
const tests[]{
3513 for (
auto const& t : tests)
3515 auto const acct =
Account{t.acct};
3516 env.fund(t.fundXRP, acct);
3519 env(
trust(acct, USD(1000)));
3520 env(
trust(acct, EUR(1000)));
3523 if (t.fundUSD > USD(0))
3524 env(
pay(gw1, acct, t.fundUSD));
3525 if (t.fundEUR > EUR(0))
3526 env(
pay(gw2, acct, t.fundEUR));
3529 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3533 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3534 env.require(
owners(acct, 2 + offerCount));
3535 env.require(
balance(acct, t.fundUSD));
3536 env.require(
balance(acct, t.fundEUR));
3539 BEAST_EXPECT(acctOffers.size() == offerCount);
3540 for (
auto const& offerPtr : acctOffers)
3542 auto const&
offer = *offerPtr;
3543 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3544 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3545 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3548 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3552 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3553 env.require(
owners(acct, 2 + offerCount));
3554 env.require(
balance(acct, t.fundUSD));
3555 env.require(
balance(acct, t.fundEUR));
3558 BEAST_EXPECT(acctOffers.size() == offerCount);
3559 for (
auto const& offerPtr : acctOffers)
3561 auto const&
offer = *offerPtr;
3562 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3563 if (
offer[sfSequence] == firstOfferSeq)
3565 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3566 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3570 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3571 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3598 using namespace jtx;
3600 Env env{*
this, features};
3602 auto const alice =
Account(
"alice");
3603 auto const bob =
Account(
"bob");
3604 auto const USD = bob[
"USD"];
3605 auto const f = env.current()->fees().base;
3607 env.fund(
XRP(50000) + f, alice, bob);
3610 env(
offer(alice, USD(5000),
XRP(50000)));
3614 env(
offer(bob,
XRP(50000), USD(5000)));
3620 env.require(
owners(alice, 1));
3621 env.require(
lines(alice, 1));
3626 BEAST_EXPECT(bobOffers.size() == 1);
3627 for (
auto const& offerPtr : bobOffers)
3629 auto const&
offer = *offerPtr;
3630 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3631 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3632 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3644 using namespace jtx;
3646 Env env{*
this, features};
3649 auto const fee = env.current()->fees().base;
3652 auto const ann =
Account(
"ann");
3653 auto const A_BUX = ann[
"BUX"];
3654 auto const bob =
Account(
"bob");
3655 auto const cam =
Account(
"cam");
3656 auto const dan =
Account(
"dan");
3657 auto const D_BUX = dan[
"BUX"];
3660 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3663 env(
trust(bob, A_BUX(400)));
3665 env(
trust(cam, D_BUX(100)));
3667 env(
pay(dan, bob, D_BUX(100)));
3669 env.require(
balance(bob, D_BUX(100)));
3671 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3676 env.require(
balance(bob, A_BUX(72)));
3677 env.require(
balance(bob, D_BUX(40)));
3679 env.require(
balance(cam, D_BUX(60)));
3683 env(
offer(bob, A_BUX(30), D_BUX(30)));
3686 env(
trust(ann, D_BUX(100)));
3690 env(
pay(ann, ann, D_BUX(30)),
3697 env.require(
balance(ann, D_BUX(0)));
3698 env.require(
balance(bob, A_BUX(72)));
3699 env.require(
balance(bob, D_BUX(40)));
3701 env.require(
balance(cam, D_BUX(60)));
3702 env.require(
balance(dan, A_BUX(0)));
3716 using namespace jtx;
3718 Env env{*
this, features};
3720 auto const ann =
Account(
"ann");
3721 auto const bob =
Account(
"bob");
3722 auto const cam =
Account(
"cam");
3723 auto const A_BUX = ann[
"BUX"];
3724 auto const B_BUX = bob[
"BUX"];
3726 auto const fee = env.current()->fees().base;
3727 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3730 env(
trust(ann, B_BUX(40)));
3731 env(
trust(cam, A_BUX(40)));
3732 env(
trust(cam, B_BUX(40)));
3735 env(
pay(ann, cam, A_BUX(35)));
3736 env(
pay(bob, cam, B_BUX(35)));
3738 env(
offer(bob, A_BUX(30), B_BUX(30)));
3746 env.require(
balance(cam, A_BUX(35)));
3747 env.require(
balance(cam, B_BUX(35)));
3748 env.require(
offers(cam, 1));
3751 env(
offer(cam, B_BUX(30), A_BUX(30)));
3754 env.require(
balance(bob, A_BUX(30)));
3755 env.require(
balance(cam, A_BUX(5)));
3756 env.require(
balance(cam, B_BUX(65)));
3757 env.require(
offers(cam, 0));
3766 testcase(
"Self crossing low quality offer");
3768 using namespace jtx;
3770 Env env{*
this, features};
3772 auto const ann =
Account(
"ann");
3773 auto const gw =
Account(
"gateway");
3774 auto const BTC = gw[
"BTC"];
3776 auto const fee = env.current()->fees().base;
3781 env(
rate(gw, 1.002));
3782 env(
trust(ann, BTC(10)));
3785 env(
pay(gw, ann, BTC(2.856)));
3788 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3792 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3805 using namespace jtx;
3807 Env env{*
this, features};
3809 auto const gw =
Account(
"gateway");
3810 auto const alice =
Account(
"alice");
3811 auto const bob =
Account(
"bob");
3812 auto const CNY = gw[
"CNY"];
3814 auto const fee = env.current()->fees().base;
3819 env(
trust(bob, CNY(500)));
3822 env(
pay(gw, bob, CNY(300)));
3825 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3829 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3833 BEAST_EXPECT(aliceOffers.size() == 1);
3834 for (
auto const& offerPtr : aliceOffers)
3836 auto const&
offer = *offerPtr;
3837 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3838 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3839 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3849 testcase(
"Offer In Scaling With Xfer Rate");
3851 using namespace jtx;
3853 Env env{*
this, features};
3855 auto const gw =
Account(
"gateway");
3856 auto const alice =
Account(
"alice");
3857 auto const bob =
Account(
"bob");
3858 auto const BTC = gw[
"BTC"];
3859 auto const JPY = gw[
"JPY"];
3861 auto const fee = env.current()->fees().base;
3866 env(
rate(gw, 1.002));
3867 env(
trust(alice, JPY(4000)));
3868 env(
trust(bob, BTC(2)));
3871 env(
pay(gw, alice, JPY(3699.034802280317)));
3872 env(
pay(gw, bob, BTC(1.156722559140311)));
3875 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3879 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3883 BEAST_EXPECT(aliceOffers.size() == 1);
3884 for (
auto const& offerPtr : aliceOffers)
3886 auto const&
offer = *offerPtr;
3887 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3889 offer[sfTakerGets] ==
3891 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3901 testcase(
"Offer Threshold With Reduced Funds");
3903 using namespace jtx;
3905 Env env{*
this, features};
3907 auto const gw1 =
Account(
"gw1");
3908 auto const gw2 =
Account(
"gw2");
3909 auto const alice =
Account(
"alice");
3910 auto const bob =
Account(
"bob");
3911 auto const USD = gw1[
"USD"];
3912 auto const JPY = gw2[
"JPY"];
3914 auto const fee = env.current()->fees().base;
3916 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3919 env(
rate(gw1, 1.002));
3920 env(
trust(alice, USD(1000)));
3921 env(
trust(bob, JPY(100000)));
3948 BEAST_EXPECT(aliceOffers.size() == 1);
3949 for (
auto const& offerPtr : aliceOffers)
3951 auto const&
offer = *offerPtr;
3952 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3954 offer[sfTakerGets] ==
3957 offer[sfTakerPays] ==
3967 using namespace jtx;
3969 Env env{*
this, features};
3971 auto const gw =
Account(
"gw");
3972 auto const alice =
Account(
"alice");
3973 auto const bob =
Account(
"bob");
3974 auto const CNY = gw[
"CNY"];
3975 auto const fee = env.current()->fees().base;
3976 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3978 env.fund(startXrpBalance, gw, alice, bob);
3981 env(
trust(bob, CNY(100000)));
3993 STAmount const bobsCnyStartBalance{
3995 env(
pay(gw, bob, bobsCnyStartBalance));
4004 env.require(
balance(alice, alicesCnyOffer));
4006 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
4049 using namespace jtx;
4051 Env env{*
this, features};
4052 auto const baseFee = env.current()->fees().base.drops();
4054 auto const gw =
Account(
"gw");
4055 auto const BTC = gw[
"BTC"];
4056 auto const USD = gw[
"USD"];
4057 auto const startXrpBalance =
XRP(4000000);
4059 env.fund(startXrpBalance, gw);
4062 env(
rate(gw, 1.25));
4088 TestData
const tests[]{
4090 {0, 0, 1, BTC(20), {{
"ann", 0,
drops(3900000'000000 - 4 * baseFee), BTC(20.0), USD(3000)}, {
"abe", 0,
drops(4100000'000000 - 3 * baseFee), BTC( 0), USD(750)}}},
4091 {0, 1, 0, BTC(20), {{
"bev", 0,
drops(4100000'000000 - 4 * baseFee), BTC( 7.5), USD(2000)}, {
"bob", 0,
drops(3900000'000000 - 3 * baseFee), BTC(10), USD( 0)}}},
4092 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
4093 {0, 1, 0, BTC( 5), {{
"deb", 1,
drops(4040000'000000 - 4 * baseFee), BTC( 0.0), USD(2000)}, {
"dan", 1,
drops(3960000'000000 - 3 * baseFee), BTC( 4), USD( 0)}}},
4097 for (
auto const& t : tests)
4099 Account const& self = t.actors[t.self].acct;
4100 Account const& leg0 = t.actors[t.leg0].acct;
4101 Account const& leg1 = t.actors[t.leg1].acct;
4103 for (
auto const& actor : t.actors)
4105 env.fund(
XRP(4000000), actor.acct);
4108 env(
trust(actor.acct, BTC(40)));
4109 env(
trust(actor.acct, USD(8000)));
4113 env(
pay(gw, self, t.btcStart));
4114 env(
pay(gw, self, USD(2000)));
4115 if (self.
id() != leg1.
id())
4116 env(
pay(gw, leg1, USD(2000)));
4130 env(
offer(self, USD(1000), BTC(10)));
4135 for (
auto const& actor : t.actors)
4141 actorOffers.begin(),
4143 actorOffers.begin(),
4146 return (*offer)[sfTakerGets].signum() == 0;
4148 BEAST_EXPECT(offerCount == actor.offers);
4150 env.require(
balance(actor.acct, actor.xrp));
4151 env.require(
balance(actor.acct, actor.btc));
4152 env.require(
balance(actor.acct, actor.usd));
4168 testcase(
"Self Pay Unlimited Funds");
4200 using namespace jtx;
4202 Env env{*
this, features};
4203 auto const baseFee = env.current()->fees().base.drops();
4205 auto const gw =
Account(
"gw");
4206 auto const BTC = gw[
"BTC"];
4207 auto const USD = gw[
"USD"];
4208 auto const startXrpBalance =
XRP(4000000);
4210 env.fund(startXrpBalance, gw);
4213 env(
rate(gw, 1.25));
4239 TestData
const takerTests[]{
4241 {0, 0, 1, BTC(5), {{
"deb", 0,
drops(3900000'000000 - 4 * baseFee), BTC(5), USD(3000)}, {
"dan", 0,
drops(4100000'000000 - 3 * baseFee), BTC(0), USD(750)}}},
4242 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4245 TestData
const flowTests[]{
4247 {0, 0, 1, BTC(5), {{
"gay", 1,
drops(3950000'000000 - 4 * baseFee), BTC(5), USD(2500)}, {
"gar", 1,
drops(4050000'000000 - 3 * baseFee), BTC(0), USD(1375)}}},
4248 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4253 auto const& tests = features[featureFlowCross] ? flowTests : takerTests;
4255 for (
auto const& t : tests)
4257 Account const& self = t.actors[t.self].acct;
4258 Account const& leg0 = t.actors[t.leg0].acct;
4259 Account const& leg1 = t.actors[t.leg1].acct;
4261 for (
auto const& actor : t.actors)
4263 env.fund(
XRP(4000000), actor.acct);
4266 env(
trust(actor.acct, BTC(40)));
4267 env(
trust(actor.acct, USD(8000)));
4271 env(
pay(gw, self, t.btcStart));
4272 env(
pay(gw, self, USD(2000)));
4273 if (self.
id() != leg1.
id())
4274 env(
pay(gw, leg1, USD(2000)));
4288 env(
offer(self, USD(1000), BTC(10)));
4293 for (
auto const& actor : t.actors)
4299 actorOffers.begin(),
4301 actorOffers.begin(),
4304 return (*offer)[sfTakerGets].signum() == 0;
4306 BEAST_EXPECT(offerCount == actor.offers);
4308 env.require(
balance(actor.acct, actor.xrp));
4309 env.require(
balance(actor.acct, actor.btc));
4310 env.require(
balance(actor.acct, actor.usd));
4328 using namespace jtx;
4330 Env env{*
this, features};
4332 auto const gw =
Account(
"gw");
4333 auto const alice =
Account(
"alice");
4334 auto const bob =
Account(
"bob");
4335 auto const gwUSD = gw[
"USD"];
4336 auto const aliceUSD = alice[
"USD"];
4337 auto const bobUSD = bob[
"USD"];
4339 env.fund(
XRP(400000), gw, alice, bob);
4348 env(
trust(bob, gwUSD(100)));
4350 env(
trust(alice, gwUSD(100)));
4352 env(
offer(alice, gwUSD(40),
XRP(4000)));
4355 env.require(
offers(alice, 1));
4356 env.require(
balance(alice, gwUSD(0)));
4358 env(
pay(gw, bob, gwUSD(50)));
4361 env.require(
balance(bob, gwUSD(50)));
4364 env(
offer(bob,
XRP(4000), gwUSD(40)));
4367 env.require(
offers(alice, 0));
4368 env.require(
balance(alice, gwUSD(40)));
4370 env.require(
offers(bob, 0));
4371 env.require(
balance(bob, gwUSD(10)));
4397 using namespace jtx;
4399 Env env{*
this, features};
4401 auto const gw =
Account(
"gw");
4402 auto const alice =
Account(
"alice");
4403 auto const bob =
Account(
"bob");
4404 auto const gwUSD = gw[
"USD"];
4405 auto const aliceUSD = alice[
"USD"];
4406 auto const bobUSD = bob[
"USD"];
4408 env.fund(
XRP(400000), gw, alice, bob);
4411 env(
offer(alice, gwUSD(40),
XRP(4000)));
4414 env.require(
offers(alice, 1));
4421 env(
trust(bob, gwUSD(100)));
4424 env(
pay(gw, bob, gwUSD(50)));
4426 env.require(
balance(bob, gwUSD(50)));
4434 env(
offer(bob,
XRP(4000), gwUSD(40)));
4438 bool const flowCross = features[featureFlowCross];
4440 env.require(
offers(alice, 0));
4445 env.require(
offers(bob, 1));
4446 env.require(
balance(bob, gwUSD(50)));
4451 env.require(
balance(alice, gwUSD(40)));
4452 env.require(
offers(bob, 0));
4453 env.require(
balance(bob, gwUSD(10)));
4465 env.require(
offers(alice, 0));
4468 env.require(
offers(bob, 1));
4469 env.require(
balance(bob, gwUSD(50)));
4473 env(
trust(gw, aliceUSD(100)));
4479 env.require(
offers(alice, 0));
4480 env.require(
balance(alice, gwUSD(0)));
4482 env.require(
offers(bob, 1));
4483 env.require(
balance(bob, gwUSD(50)));
4488 env.require(
offers(bob, 0));
4496 env(
offer(alice, gwUSD(40),
XRP(4000)));
4499 env.require(
offers(alice, 1));
4502 env(
offer(bob,
XRP(4000), gwUSD(40)));
4505 env.require(
offers(alice, 0));
4506 env.require(
balance(alice, gwUSD(40)));
4508 env.require(
offers(bob, 0));
4509 env.require(
balance(bob, gwUSD(10)));
4515 testcase(
"RippleConnect Smoketest payment flow");
4516 using namespace jtx;
4518 Env env{*
this, features};
4528 auto const hotUS =
Account(
"hotUS");
4529 auto const coldUS =
Account(
"coldUS");
4530 auto const hotEU =
Account(
"hotEU");
4531 auto const coldEU =
Account(
"coldEU");
4532 auto const mm =
Account(
"mm");
4534 auto const USD = coldUS[
"USD"];
4535 auto const EUR = coldEU[
"EUR"];
4537 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4541 for (
auto const& cold : {coldUS, coldEU})
4564 env(
pay(coldUS, hotUS, USD(5000000)));
4565 env(
pay(coldEU, hotEU, EUR(5000000)));
4566 env(
pay(coldUS, mm, USD(5000000)));
4567 env(
pay(coldEU, mm, EUR(5000000)));
4571 float const rate = 0.9f;
4572 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4575 float const reverseRate = 1.0f /
rate * 1.00101f;
4576 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4583 jvParams[jss::destination_account] = coldEU.human();
4584 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4585 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4586 jvParams[jss::destination_amount][jss::value] = 10;
4587 jvParams[jss::source_account] = hotUS.human();
4590 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4592 BEAST_EXPECT(jrr[jss::status] ==
"success");
4594 jrr[jss::alternatives].isArray() &&
4595 jrr[jss::alternatives].size() > 0);
4598 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4606 using namespace jtx;
4608 Env env{*
this, features};
4610 auto const gw =
Account(
"gw");
4611 auto const alice =
Account(
"alice");
4612 auto const gwUSD = gw[
"USD"];
4613 auto const aliceUSD = alice[
"USD"];
4615 env.fund(
XRP(400000), gw, alice);
4619 env(
offer(gw, gwUSD(40),
XRP(4000)));
4622 env.require(
offers(gw, 1));
4631 env.require(
offers(gw, 0));
4638 bool const preauth = features[featureDepositPreauth];
4643 env(
offer(gw, gwUSD(40),
XRP(4000)),
4647 env.require(
offers(gw, preauth ? 1 : 0));
4655 env(
trust(alice, gwUSD(100)));
4658 env(
pay(gw, alice, gwUSD(50)));
4661 env.require(
balance(alice, gwUSD(50)));
4664 env(
offer(alice,
XRP(4000), gwUSD(40)));
4667 env.require(
offers(alice, 0));
4668 env.require(
balance(alice, gwUSD(10)));
4670 env.require(
offers(gw, 0));
4677 using namespace jtx;
4681 auto trustLineExists = [](
jtx::Env const& env,
4692 auto const USD = gw[
"USD"];
4693 auto const BUX = alice[
"BUX"];
4695 Env env{*
this, features};
4699 env.
trust(USD(1000), becky);
4700 env(
pay(gw, becky, USD(5)));
4702 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4713 env(
pay(becky, gw, USD(5)));
4714 env.
trust(USD(0), becky);
4716 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4717 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4718 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4725 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4727 if (gwSeq + 255 > openLedgerSeq)
4728 return gwSeq - openLedgerSeq + 255;
4732 for (
int i = 0; i < delta; ++i)
4749 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4750 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4756 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4757 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4762 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4766 env.
trust(BUX(1000), carol);
4767 env(
pay(alice, carol, BUX(2)));
4776 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4777 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4785 using namespace jtx;
4789 Env env{*
this, features};
4790 auto const gw =
Account{
"gateway"};
4791 env.fund(
XRP(10000), gw);
4794 auto txn =
noop(gw);
4795 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4798 txn[sfTickSize.fieldName] = Quality::minTickSize;
4800 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4803 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4805 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4808 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4810 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4813 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4816 txn[sfTickSize.fieldName] = 0;
4818 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4821 Env env{*
this, features};
4822 auto const gw =
Account{
"gateway"};
4823 auto const alice =
Account{
"alice"};
4824 auto const XTS = gw[
"XTS"];
4825 auto const XXX = gw[
"XXX"];
4827 env.fund(
XRP(10000), gw, alice);
4832 auto txn =
noop(gw);
4833 txn[sfTickSize.fieldName] = 5;
4835 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4838 env(
trust(alice, XTS(1000)));
4839 env(
trust(alice, XXX(1000)));
4841 env(
pay(gw, alice, alice[
"XTS"](100)));
4842 env(
pay(gw, alice, alice[
"XXX"](100)));
4844 env(
offer(alice, XTS(10), XXX(30)));
4845 env(
offer(alice, XTS(30), XXX(10)));
4852 if (sle->getType() == ltOFFER)
4856 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4860 auto it =
offers.begin();
4861 BEAST_EXPECT(it !=
offers.end());
4863 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4864 it->second.second > XXX(29.9994));
4868 BEAST_EXPECT(it !=
offers.end());
4870 it->second.first == XTS(30) && it->second.second == XXX(10));
4874 BEAST_EXPECT(it !=
offers.end());
4876 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4881 BEAST_EXPECT(it !=
offers.end());
4883 it->second.first == XTS(30) && it->second.second == XXX(10));
4885 BEAST_EXPECT(++it ==
offers.end());
4899 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4909 using namespace jtx;
4917 Env env{*
this, features};
4918 auto const gw =
Account{
"gateway"};
4919 auto const alice =
Account{
"alice"};
4920 auto const bob =
Account{
"bob"};
4921 auto const USD = gw[
"USD"];
4923 env.fund(
XRP(10000), gw, alice, bob);
4926 env(
trust(alice, USD(1000)));
4927 env(
trust(bob, USD(1000)));
4930 env(
pay(gw, alice, USD(200)));
4937 env(
offer(alice,
XRP(50), USD(50)));
4947 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4948 env(
offer(alice,
XRP(50), USD(50)));
4964 BEAST_EXPECT(
offers.size() == 4);
4965 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4966 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4967 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4968 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4969 env.require(
balance(alice, USD(200)));
4970 env.require(
owners(alice, 5));
4980 BEAST_EXPECT(
offers.size() == 3);
4981 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4982 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4983 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4993 BEAST_EXPECT(
offers.size() == 2);
4994 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4995 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
5005 BEAST_EXPECT(
offers.size() == 1);
5006 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
5016 BEAST_EXPECT(
offers.size() == 0);
5018 env.require(
balance(alice, USD(0)));
5019 env.require(
owners(alice, 1));
5020 env.require(
balance(bob, USD(200)));
5021 env.require(
owners(bob, 1));
5029 using namespace jtx;
5033 Env env{*
this, features};
5034 auto const gw =
Account{
"gateway"};
5035 auto const alice =
Account{
"alice"};
5036 auto const USD = gw[
"USD"];
5038 env.fund(
XRP(10000), gw, alice);
5041 env(
trust(alice, USD(1000)));
5045 env(
pay(gw, alice, USD(200)));
5050 env(
offer(alice,
XRP(50), USD(50)));
5062 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5063 env(
offer(alice,
XRP(50), USD(50)));
5079 BEAST_EXPECT(
offers.size() == 4);
5080 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
5081 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
5082 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
5083 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
5084 env.require(
balance(alice, USD(200)));
5085 env.require(
owners(alice, 7));
5095 BEAST_EXPECT(
offers.size() == 3);
5096 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5097 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
5098 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
5108 BEAST_EXPECT(
offers.size() == 2);
5109 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5110 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5123 BEAST_EXPECT(
offers.size() == 1);
5124 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5141 testcase(
"incorrect assert fixed");
5142 using namespace jtx;
5145 auto const alice =
Account(
"alice");
5146 auto const USD = alice[
"USD"];
5148 env.fund(
XRP(10000), alice);
5150 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5158 using namespace jtx;
5159 Env env(*
this, features);
5160 Account const issuer(
"issuer");
5163 auto const USD = issuer[
"USD"];
5164 auto const EUR = issuer[
"EUR"];
5167 env.
fund(
XRP(1'000), maker, taker);
5170 env.
trust(USD(1'000), maker, taker);
5171 env.
trust(EUR(1'000), maker, taker);
5174 env(
pay(issuer, maker, USD(1'000)));
5175 env(
pay(issuer, taker, USD(1'000)));
5176 env(
pay(issuer, maker, EUR(1'000)));
5179 auto makerUSDBalance = env.
balance(maker, USD).
value();
5180 auto takerUSDBalance = env.
balance(taker, USD).
value();
5181 auto makerEURBalance = env.
balance(maker, EUR).
value();
5182 auto takerEURBalance = env.
balance(taker, EUR).
value();
5189 features[fixFillOrKill] || !features[featureFlowCross]
5193 env(
offer(maker,
XRP(100), USD(100)));
5196 env(
offer(taker, USD(100),
XRP(101)),
5201 makerXRPBalance -=
txfee(env, 1);
5202 takerXRPBalance -=
txfee(env, 1);
5205 makerUSDBalance -= USD(100);
5206 takerUSDBalance += USD(100);
5207 makerXRPBalance +=
XRP(100).value();
5208 takerXRPBalance -=
XRP(100).value();
5212 env(
offer(maker, USD(100),
XRP(100)));
5215 env(
offer(taker,
XRP(100), USD(101)),
5220 makerXRPBalance -=
txfee(env, 1);
5221 takerXRPBalance -=
txfee(env, 1);
5224 makerUSDBalance += USD(100);
5225 takerUSDBalance -= USD(100);
5226 makerXRPBalance -=
XRP(100).value();
5227 takerXRPBalance +=
XRP(100).value();
5231 env(
offer(maker, USD(100), EUR(100)));
5234 env(
offer(taker, EUR(100), USD(101)),
5239 makerXRPBalance -=
txfee(env, 1);
5240 takerXRPBalance -=
txfee(env, 1);
5243 makerUSDBalance += USD(100);
5244 takerUSDBalance -= USD(100);
5245 makerEURBalance -= EUR(100);
5246 takerEURBalance += EUR(100);
5253 env(
offer(maker,
XRP(101), USD(101)));
5256 env(
offer(taker, USD(100),
XRP(101)),
5260 makerUSDBalance -= USD(101);
5261 takerUSDBalance += USD(101);
5262 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5263 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5266 env(
offer(maker, USD(101),
XRP(101)));
5269 env(
offer(taker,
XRP(100), USD(101)),
5273 makerUSDBalance += USD(101);
5274 takerUSDBalance -= USD(101);
5275 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5276 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5279 env(
offer(maker, USD(101), EUR(101)));
5282 env(
offer(taker, EUR(100), USD(101)),
5286 makerUSDBalance += USD(101);
5287 takerUSDBalance -= USD(101);
5288 makerEURBalance -= EUR(101);
5289 takerEURBalance += EUR(101);
5290 makerXRPBalance -=
txfee(env, 1);
5291 takerXRPBalance -=
txfee(env, 1);
5298 env(
offer(maker,
XRP(100), USD(100)));
5301 env(
offer(taker, USD(100),
XRP(99)),
5306 makerXRPBalance -=
txfee(env, 1);
5307 takerXRPBalance -=
txfee(env, 1);
5310 env(
offer(maker, USD(100),
XRP(100)));
5313 env(
offer(taker,
XRP(100), USD(99)),
5318 makerXRPBalance -=
txfee(env, 1);
5319 takerXRPBalance -=
txfee(env, 1);
5322 env(
offer(maker, USD(100), EUR(100)));
5325 env(
offer(taker, EUR(100), USD(99)),
5330 makerXRPBalance -=
txfee(env, 1);
5331 takerXRPBalance -=
txfee(env, 1);
5336 env.
balance(maker, USD) == makerUSDBalance &&
5337 env.
balance(taker, USD) == takerUSDBalance &&
5338 env.
balance(maker, EUR) == makerEURBalance &&
5339 env.
balance(taker, EUR) == takerEURBalance &&
5340 env.
balance(maker,
XRP) == makerXRPBalance &&
5411 using namespace jtx;
5414 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5416 fixRmSmallIncreasedQOffers};
5418 featureImmediateOfferKilled};
5423 all - takerDryOffer - immediateOfferKilled - permDEX,
5424 all - flowCross - takerDryOffer - immediateOfferKilled - permDEX,
5425 all - flowCross - immediateOfferKilled - permDEX,
5426 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
5428 all - fillOrKill - permDEX,
5432 if (BEAST_EXPECT(instance < feats.size()))
5436 BEAST_EXPECT(!
last || instance == feats.size() - 1);
5506 using namespace jtx;
5510 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5515 testAll(
all - flowCross - f1513 - immediateOfferKilled - permDEX);
5516 testAll(
all - flowCross - immediateOfferKilled - permDEX);
5517 testAll(
all - immediateOfferKilled - fillOrKill - permDEX);
5522 testAll(
all - flowCross - takerDryOffer - permDEX);
5526BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx,
ripple, 2);
5527BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx,
ripple, 2);
5528BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx,
ripple, 2);
5529BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx,
ripple, 2);
5530BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx,
ripple, 2);
5531BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, tx,
ripple, 2);
5532BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx,
ripple, 2);
5533BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, tx,
ripple, 20);
void pass()
Record a successful test condition.
testcase_t testcase
Memberspace for declaring test cases.
A currency issued by an account.
std::string getText() const override
Issue const & issue() const
void run() override
Runs the suite.
void testSelfCrossOffer2(FeatureBitset features)
void run() override
Runs the suite.
void testMissingAuth(FeatureBitset features)
void testSelfAuth(FeatureBitset features)
void testSelfCross(bool use_partner, FeatureBitset features)
void testCrossCurrencyBridged(FeatureBitset features)
void testAll(FeatureBitset features)
void testSelfIssueOffer(FeatureBitset features)
void testRCSmoketest(FeatureBitset features)
void testExpiration(FeatureBitset features)
void testUnfundedCross(FeatureBitset features)
void testCrossCurrencyStartXRP(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > offersOnAccount(jtx::Env &env, jtx::Account account)
void testRmSmallIncreasedQOffersIOU(FeatureBitset features)
void testSellWithFillOrKill(FeatureBitset features)
void testTinyOffer(FeatureBitset features)
void testInsufficientReserve(FeatureBitset features)
void testDirectCross(FeatureBitset features)
void testOfferThresholdWithReducedFunds(FeatureBitset features)
void testRequireAuth(FeatureBitset features)
void verifyDefaultTrustline(jtx::Env &env, jtx::Account const &account, jtx::PrettyAmount const &expectBalance)
void testRmSmallIncreasedQOffersXRP(FeatureBitset features)
void testDirectToDirectPath(FeatureBitset features)
void testRmFundedOffer(FeatureBitset features)
void testOfferFeesConsumeFunds(FeatureBitset features)
void testTickSize(FeatureBitset features)
void testTicketOffer(FeatureBitset features)
void testOfferCreateThenCross(FeatureBitset features)
void testFillOrKill(FeatureBitset features)
void testSelfPayUnlimitedFunds(FeatureBitset features)
void testOfferCancelPastAndFuture(FeatureBitset features)
void testSellFlagBasic(FeatureBitset features)
void testBridgedCross(FeatureBitset features)
void testXRPDirectCross(FeatureBitset features)
void testDeletedOfferIssuer(FeatureBitset features)
void testXRPTinyPayment(FeatureBitset features)
void testTransferRateOffer(FeatureBitset features)
void testPartialCross(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > sortedOffersOnAccount(jtx::Env &env, jtx::Account const &acct)
void testCurrencyConversionIntoDebt(FeatureBitset features)
void testMalformed(FeatureBitset features)
void run(std::uint32_t instance, bool last=false)
void testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
void testFillModes(FeatureBitset features)
void testOfferInScaling(FeatureBitset features)
void testOfferInScalingWithXferRate(FeatureBitset features)
static auto ledgerEntryOffer(jtx::Env &env, jtx::Account const &acct, std::uint32_t offer_seq)
void testCurrencyConversionEntire(FeatureBitset features)
void testSelfPayXferFeeOffer(FeatureBitset features)
void testCurrencyConversionInParts(FeatureBitset features)
void testBridgedSecondLegDry(FeatureBitset features)
void testSellOffer(FeatureBitset features)
void testCrossCurrencyEndXRP(FeatureBitset features)
void testGatewayCrossCurrency(FeatureBitset features)
void testNegativeBalance(FeatureBitset features)
static auto getBookOffers(jtx::Env &env, Issue const &taker_pays, Issue const &taker_gets)
void testSelfCrossOffer(FeatureBitset features)
std::uint32_t lastClose(jtx::Env &env)
void testSelfCrossOffer1(FeatureBitset features)
XRPAmount reserve(jtx::Env &env, std::uint32_t count)
void testOfferCrossWithLimitOverride(FeatureBitset features)
void testTicketCancelOffer(FeatureBitset features)
void testSelfCrossLowQualityOffer(FeatureBitset features)
void testOfferAcceptThenCancel(FeatureBitset features)
void testSellFlagExceedLimit(FeatureBitset features)
void testCanceledOffer(FeatureBitset features)
void testBadPathAssert(FeatureBitset features)
void testTinyPayment(FeatureBitset features)
void testEnforceNoRipple(FeatureBitset features)
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Converts to IOU Issue or STAmount.
Match the number of items in the account's owner directory.
Set Paths, SendMax on a JTx.
Sets the QualityIn on a trust JTx.
Sets the QualityOut on a trust JTx as a percentage.
Check a set of conditions.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
@ arrayValue
array value (ordered list)
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet account(AccountID const &id) noexcept
AccountID root.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
owner_count< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
Json::Value ledgerEntryRoot(Env &env, Account const &acct)
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
PrettyAmount xrpMinusFee(Env const &env, std::int64_t xrpAmount)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value ledgerEntryState(Env &env, Account const &acct_a, Account const &acct_b, std::string const ¤cy)
static epsilon_t const epsilon
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
XRPAmount txfee(Env const &env, std::uint16_t n)
FeatureBitset supported_amendments()
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
bool isOffer(jtx::Env &env, jtx::Account const &account, STAmount const &takerPays, STAmount const &takerGets)
An offer exists.
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint32_t tfFillOrKill
constexpr std::uint32_t tfPassive
constexpr std::uint32_t tfImmediateOrCancel
constexpr std::uint32_t tfPartialPayment
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t asfDefaultRipple
constexpr std::uint32_t tfNoRippleDirect
std::string to_string(base_uint< Bits, Tag > const &a)
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
constexpr std::uint32_t tfSell
constexpr std::uint32_t asfRequireAuth
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetNoRipple
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
STAmount const & value() const