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;
3648 Env env{*
this, features | featureOwnerPaysFee};
3651 auto const fee = env.current()->fees().base;
3654 auto const ann =
Account(
"ann");
3655 auto const A_BUX = ann[
"BUX"];
3656 auto const bob =
Account(
"bob");
3657 auto const cam =
Account(
"cam");
3658 auto const dan =
Account(
"dan");
3659 auto const D_BUX = dan[
"BUX"];
3662 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3665 env(
trust(bob, A_BUX(400)));
3667 env(
trust(cam, D_BUX(100)));
3669 env(
pay(dan, bob, D_BUX(100)));
3671 env.require(
balance(bob, D_BUX(100)));
3673 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3678 env.require(
balance(bob, A_BUX(72)));
3679 env.require(
balance(bob, D_BUX(40)));
3681 env.require(
balance(cam, D_BUX(60)));
3685 env(
offer(bob, A_BUX(30), D_BUX(30)));
3688 env(
trust(ann, D_BUX(100)));
3692 env(
pay(ann, ann, D_BUX(30)),
3699 env.require(
balance(ann, D_BUX(0)));
3700 env.require(
balance(bob, A_BUX(72)));
3701 env.require(
balance(bob, D_BUX(40)));
3703 env.require(
balance(cam, D_BUX(60)));
3704 env.require(
balance(dan, A_BUX(0)));
3718 using namespace jtx;
3720 Env env{*
this, features};
3722 auto const ann =
Account(
"ann");
3723 auto const bob =
Account(
"bob");
3724 auto const cam =
Account(
"cam");
3725 auto const A_BUX = ann[
"BUX"];
3726 auto const B_BUX = bob[
"BUX"];
3728 auto const fee = env.current()->fees().base;
3729 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3732 env(
trust(ann, B_BUX(40)));
3733 env(
trust(cam, A_BUX(40)));
3734 env(
trust(cam, B_BUX(40)));
3737 env(
pay(ann, cam, A_BUX(35)));
3738 env(
pay(bob, cam, B_BUX(35)));
3740 env(
offer(bob, A_BUX(30), B_BUX(30)));
3748 env.require(
balance(cam, A_BUX(35)));
3749 env.require(
balance(cam, B_BUX(35)));
3750 env.require(
offers(cam, 1));
3753 env(
offer(cam, B_BUX(30), A_BUX(30)));
3756 env.require(
balance(bob, A_BUX(30)));
3757 env.require(
balance(cam, A_BUX(5)));
3758 env.require(
balance(cam, B_BUX(65)));
3759 env.require(
offers(cam, 0));
3768 testcase(
"Self crossing low quality offer");
3770 using namespace jtx;
3772 Env env{*
this, features};
3774 auto const ann =
Account(
"ann");
3775 auto const gw =
Account(
"gateway");
3776 auto const BTC = gw[
"BTC"];
3778 auto const fee = env.current()->fees().base;
3783 env(
rate(gw, 1.002));
3784 env(
trust(ann, BTC(10)));
3787 env(
pay(gw, ann, BTC(2.856)));
3790 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3794 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3807 using namespace jtx;
3809 Env env{*
this, features};
3811 auto const gw =
Account(
"gateway");
3812 auto const alice =
Account(
"alice");
3813 auto const bob =
Account(
"bob");
3814 auto const CNY = gw[
"CNY"];
3816 auto const fee = env.current()->fees().base;
3821 env(
trust(bob, CNY(500)));
3824 env(
pay(gw, bob, CNY(300)));
3827 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3831 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3835 BEAST_EXPECT(aliceOffers.size() == 1);
3836 for (
auto const& offerPtr : aliceOffers)
3838 auto const&
offer = *offerPtr;
3839 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3840 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3841 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3851 testcase(
"Offer In Scaling With Xfer Rate");
3853 using namespace jtx;
3855 Env env{*
this, features};
3857 auto const gw =
Account(
"gateway");
3858 auto const alice =
Account(
"alice");
3859 auto const bob =
Account(
"bob");
3860 auto const BTC = gw[
"BTC"];
3861 auto const JPY = gw[
"JPY"];
3863 auto const fee = env.current()->fees().base;
3868 env(
rate(gw, 1.002));
3869 env(
trust(alice, JPY(4000)));
3870 env(
trust(bob, BTC(2)));
3873 env(
pay(gw, alice, JPY(3699.034802280317)));
3874 env(
pay(gw, bob, BTC(1.156722559140311)));
3877 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3881 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3885 BEAST_EXPECT(aliceOffers.size() == 1);
3886 for (
auto const& offerPtr : aliceOffers)
3888 auto const&
offer = *offerPtr;
3889 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3891 offer[sfTakerGets] ==
3893 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3903 testcase(
"Offer Threshold With Reduced Funds");
3905 using namespace jtx;
3907 Env env{*
this, features};
3909 auto const gw1 =
Account(
"gw1");
3910 auto const gw2 =
Account(
"gw2");
3911 auto const alice =
Account(
"alice");
3912 auto const bob =
Account(
"bob");
3913 auto const USD = gw1[
"USD"];
3914 auto const JPY = gw2[
"JPY"];
3916 auto const fee = env.current()->fees().base;
3918 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3921 env(
rate(gw1, 1.002));
3922 env(
trust(alice, USD(1000)));
3923 env(
trust(bob, JPY(100000)));
3950 BEAST_EXPECT(aliceOffers.size() == 1);
3951 for (
auto const& offerPtr : aliceOffers)
3953 auto const&
offer = *offerPtr;
3954 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3956 offer[sfTakerGets] ==
3959 offer[sfTakerPays] ==
3969 using namespace jtx;
3971 Env env{*
this, features};
3973 auto const gw =
Account(
"gw");
3974 auto const alice =
Account(
"alice");
3975 auto const bob =
Account(
"bob");
3976 auto const CNY = gw[
"CNY"];
3977 auto const fee = env.current()->fees().base;
3978 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3980 env.fund(startXrpBalance, gw, alice, bob);
3983 env(
trust(bob, CNY(100000)));
3995 STAmount const bobsCnyStartBalance{
3997 env(
pay(gw, bob, bobsCnyStartBalance));
4006 env.require(
balance(alice, alicesCnyOffer));
4008 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
4051 using namespace jtx;
4053 Env env{*
this, features};
4054 auto const baseFee = env.current()->fees().base.drops();
4056 auto const gw =
Account(
"gw");
4057 auto const BTC = gw[
"BTC"];
4058 auto const USD = gw[
"USD"];
4059 auto const startXrpBalance =
XRP(4000000);
4061 env.fund(startXrpBalance, gw);
4064 env(
rate(gw, 1.25));
4090 TestData
const tests[]{
4092 {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)}}},
4093 {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)}}},
4094 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
4095 {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)}}},
4099 for (
auto const& t : tests)
4101 Account const& self = t.actors[t.self].acct;
4102 Account const& leg0 = t.actors[t.leg0].acct;
4103 Account const& leg1 = t.actors[t.leg1].acct;
4105 for (
auto const& actor : t.actors)
4107 env.fund(
XRP(4000000), actor.acct);
4110 env(
trust(actor.acct, BTC(40)));
4111 env(
trust(actor.acct, USD(8000)));
4115 env(
pay(gw, self, t.btcStart));
4116 env(
pay(gw, self, USD(2000)));
4117 if (self.
id() != leg1.
id())
4118 env(
pay(gw, leg1, USD(2000)));
4132 env(
offer(self, USD(1000), BTC(10)));
4137 for (
auto const& actor : t.actors)
4143 actorOffers.begin(),
4145 actorOffers.begin(),
4148 return (*offer)[sfTakerGets].signum() == 0;
4150 BEAST_EXPECT(offerCount == actor.offers);
4152 env.require(
balance(actor.acct, actor.xrp));
4153 env.require(
balance(actor.acct, actor.btc));
4154 env.require(
balance(actor.acct, actor.usd));
4170 testcase(
"Self Pay Unlimited Funds");
4202 using namespace jtx;
4204 Env env{*
this, features};
4205 auto const baseFee = env.current()->fees().base.drops();
4207 auto const gw =
Account(
"gw");
4208 auto const BTC = gw[
"BTC"];
4209 auto const USD = gw[
"USD"];
4210 auto const startXrpBalance =
XRP(4000000);
4212 env.fund(startXrpBalance, gw);
4215 env(
rate(gw, 1.25));
4241 TestData
const takerTests[]{
4243 {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)}}},
4244 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4247 TestData
const flowTests[]{
4249 {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)}}},
4250 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4255 auto const& tests = features[featureFlowCross] ? flowTests : takerTests;
4257 for (
auto const& t : tests)
4259 Account const& self = t.actors[t.self].acct;
4260 Account const& leg0 = t.actors[t.leg0].acct;
4261 Account const& leg1 = t.actors[t.leg1].acct;
4263 for (
auto const& actor : t.actors)
4265 env.fund(
XRP(4000000), actor.acct);
4268 env(
trust(actor.acct, BTC(40)));
4269 env(
trust(actor.acct, USD(8000)));
4273 env(
pay(gw, self, t.btcStart));
4274 env(
pay(gw, self, USD(2000)));
4275 if (self.
id() != leg1.
id())
4276 env(
pay(gw, leg1, USD(2000)));
4290 env(
offer(self, USD(1000), BTC(10)));
4295 for (
auto const& actor : t.actors)
4301 actorOffers.begin(),
4303 actorOffers.begin(),
4306 return (*offer)[sfTakerGets].signum() == 0;
4308 BEAST_EXPECT(offerCount == actor.offers);
4310 env.require(
balance(actor.acct, actor.xrp));
4311 env.require(
balance(actor.acct, actor.btc));
4312 env.require(
balance(actor.acct, actor.usd));
4330 using namespace jtx;
4332 Env env{*
this, features};
4334 auto const gw =
Account(
"gw");
4335 auto const alice =
Account(
"alice");
4336 auto const bob =
Account(
"bob");
4337 auto const gwUSD = gw[
"USD"];
4338 auto const aliceUSD = alice[
"USD"];
4339 auto const bobUSD = bob[
"USD"];
4341 env.fund(
XRP(400000), gw, alice, bob);
4350 env(
trust(bob, gwUSD(100)));
4352 env(
trust(alice, gwUSD(100)));
4354 env(
offer(alice, gwUSD(40),
XRP(4000)));
4357 env.require(
offers(alice, 1));
4358 env.require(
balance(alice, gwUSD(0)));
4360 env(
pay(gw, bob, gwUSD(50)));
4363 env.require(
balance(bob, gwUSD(50)));
4366 env(
offer(bob,
XRP(4000), gwUSD(40)));
4369 env.require(
offers(alice, 0));
4370 env.require(
balance(alice, gwUSD(40)));
4372 env.require(
offers(bob, 0));
4373 env.require(
balance(bob, gwUSD(10)));
4399 using namespace jtx;
4401 Env env{*
this, features};
4403 auto const gw =
Account(
"gw");
4404 auto const alice =
Account(
"alice");
4405 auto const bob =
Account(
"bob");
4406 auto const gwUSD = gw[
"USD"];
4407 auto const aliceUSD = alice[
"USD"];
4408 auto const bobUSD = bob[
"USD"];
4410 env.fund(
XRP(400000), gw, alice, bob);
4413 env(
offer(alice, gwUSD(40),
XRP(4000)));
4416 env.require(
offers(alice, 1));
4423 env(
trust(bob, gwUSD(100)));
4426 env(
pay(gw, bob, gwUSD(50)));
4428 env.require(
balance(bob, gwUSD(50)));
4436 env(
offer(bob,
XRP(4000), gwUSD(40)));
4440 bool const flowCross = features[featureFlowCross];
4442 env.require(
offers(alice, 0));
4447 env.require(
offers(bob, 1));
4448 env.require(
balance(bob, gwUSD(50)));
4453 env.require(
balance(alice, gwUSD(40)));
4454 env.require(
offers(bob, 0));
4455 env.require(
balance(bob, gwUSD(10)));
4467 env.require(
offers(alice, 0));
4470 env.require(
offers(bob, 1));
4471 env.require(
balance(bob, gwUSD(50)));
4475 env(
trust(gw, aliceUSD(100)));
4481 env.require(
offers(alice, 0));
4482 env.require(
balance(alice, gwUSD(0)));
4484 env.require(
offers(bob, 1));
4485 env.require(
balance(bob, gwUSD(50)));
4490 env.require(
offers(bob, 0));
4498 env(
offer(alice, gwUSD(40),
XRP(4000)));
4501 env.require(
offers(alice, 1));
4504 env(
offer(bob,
XRP(4000), gwUSD(40)));
4507 env.require(
offers(alice, 0));
4508 env.require(
balance(alice, gwUSD(40)));
4510 env.require(
offers(bob, 0));
4511 env.require(
balance(bob, gwUSD(10)));
4517 testcase(
"RippleConnect Smoketest payment flow");
4518 using namespace jtx;
4520 Env env{*
this, features};
4530 auto const hotUS =
Account(
"hotUS");
4531 auto const coldUS =
Account(
"coldUS");
4532 auto const hotEU =
Account(
"hotEU");
4533 auto const coldEU =
Account(
"coldEU");
4534 auto const mm =
Account(
"mm");
4536 auto const USD = coldUS[
"USD"];
4537 auto const EUR = coldEU[
"EUR"];
4539 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4543 for (
auto const& cold : {coldUS, coldEU})
4566 env(
pay(coldUS, hotUS, USD(5000000)));
4567 env(
pay(coldEU, hotEU, EUR(5000000)));
4568 env(
pay(coldUS, mm, USD(5000000)));
4569 env(
pay(coldEU, mm, EUR(5000000)));
4573 float const rate = 0.9f;
4574 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4577 float const reverseRate = 1.0f /
rate * 1.00101f;
4578 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4585 jvParams[jss::destination_account] = coldEU.human();
4586 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4587 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4588 jvParams[jss::destination_amount][jss::value] = 10;
4589 jvParams[jss::source_account] = hotUS.human();
4592 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4594 BEAST_EXPECT(jrr[jss::status] ==
"success");
4596 jrr[jss::alternatives].isArray() &&
4597 jrr[jss::alternatives].size() > 0);
4600 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4608 using namespace jtx;
4610 Env env{*
this, features};
4612 auto const gw =
Account(
"gw");
4613 auto const alice =
Account(
"alice");
4614 auto const gwUSD = gw[
"USD"];
4615 auto const aliceUSD = alice[
"USD"];
4617 env.fund(
XRP(400000), gw, alice);
4621 env(
offer(gw, gwUSD(40),
XRP(4000)));
4624 env.require(
offers(gw, 1));
4633 env.require(
offers(gw, 0));
4640 bool const preauth = features[featureDepositPreauth];
4645 env(
offer(gw, gwUSD(40),
XRP(4000)),
4649 env.require(
offers(gw, preauth ? 1 : 0));
4657 env(
trust(alice, gwUSD(100)));
4660 env(
pay(gw, alice, gwUSD(50)));
4663 env.require(
balance(alice, gwUSD(50)));
4666 env(
offer(alice,
XRP(4000), gwUSD(40)));
4669 env.require(
offers(alice, 0));
4670 env.require(
balance(alice, gwUSD(10)));
4672 env.require(
offers(gw, 0));
4679 using namespace jtx;
4683 auto trustLineExists = [](
jtx::Env const& env,
4694 auto const USD = gw[
"USD"];
4695 auto const BUX = alice[
"BUX"];
4697 Env env{*
this, features};
4701 env.
trust(USD(1000), becky);
4702 env(
pay(gw, becky, USD(5)));
4704 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4715 env(
pay(becky, gw, USD(5)));
4716 env.
trust(USD(0), becky);
4718 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4719 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4720 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4727 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4729 if (gwSeq + 255 > openLedgerSeq)
4730 return gwSeq - openLedgerSeq + 255;
4734 for (
int i = 0; i < delta; ++i)
4751 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4752 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4758 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4759 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4764 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4768 env.
trust(BUX(1000), carol);
4769 env(
pay(alice, carol, BUX(2)));
4778 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4779 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4787 using namespace jtx;
4791 Env env{*
this, features};
4792 auto const gw =
Account{
"gateway"};
4793 env.fund(
XRP(10000), gw);
4796 auto txn =
noop(gw);
4797 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4800 txn[sfTickSize.fieldName] = Quality::minTickSize;
4802 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4805 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4807 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4810 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4812 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4815 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4818 txn[sfTickSize.fieldName] = 0;
4820 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4823 Env env{*
this, features};
4824 auto const gw =
Account{
"gateway"};
4825 auto const alice =
Account{
"alice"};
4826 auto const XTS = gw[
"XTS"];
4827 auto const XXX = gw[
"XXX"];
4829 env.fund(
XRP(10000), gw, alice);
4834 auto txn =
noop(gw);
4835 txn[sfTickSize.fieldName] = 5;
4837 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4840 env(
trust(alice, XTS(1000)));
4841 env(
trust(alice, XXX(1000)));
4843 env(
pay(gw, alice, alice[
"XTS"](100)));
4844 env(
pay(gw, alice, alice[
"XXX"](100)));
4846 env(
offer(alice, XTS(10), XXX(30)));
4847 env(
offer(alice, XTS(30), XXX(10)));
4854 if (sle->getType() == ltOFFER)
4858 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4862 auto it =
offers.begin();
4863 BEAST_EXPECT(it !=
offers.end());
4865 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4866 it->second.second > XXX(29.9994));
4870 BEAST_EXPECT(it !=
offers.end());
4872 it->second.first == XTS(30) && it->second.second == XXX(10));
4876 BEAST_EXPECT(it !=
offers.end());
4878 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4883 BEAST_EXPECT(it !=
offers.end());
4885 it->second.first == XTS(30) && it->second.second == XXX(10));
4887 BEAST_EXPECT(++it ==
offers.end());
4901 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4911 using namespace jtx;
4919 Env env{*
this, features};
4920 auto const gw =
Account{
"gateway"};
4921 auto const alice =
Account{
"alice"};
4922 auto const bob =
Account{
"bob"};
4923 auto const USD = gw[
"USD"];
4925 env.fund(
XRP(10000), gw, alice, bob);
4928 env(
trust(alice, USD(1000)));
4929 env(
trust(bob, USD(1000)));
4932 env(
pay(gw, alice, USD(200)));
4939 env(
offer(alice,
XRP(50), USD(50)));
4949 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4950 env(
offer(alice,
XRP(50), USD(50)));
4966 BEAST_EXPECT(
offers.size() == 4);
4967 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4968 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4969 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4970 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4971 env.require(
balance(alice, USD(200)));
4972 env.require(
owners(alice, 5));
4982 BEAST_EXPECT(
offers.size() == 3);
4983 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4984 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4985 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4995 BEAST_EXPECT(
offers.size() == 2);
4996 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4997 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
5007 BEAST_EXPECT(
offers.size() == 1);
5008 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
5018 BEAST_EXPECT(
offers.size() == 0);
5020 env.require(
balance(alice, USD(0)));
5021 env.require(
owners(alice, 1));
5022 env.require(
balance(bob, USD(200)));
5023 env.require(
owners(bob, 1));
5031 using namespace jtx;
5035 Env env{*
this, features};
5036 auto const gw =
Account{
"gateway"};
5037 auto const alice =
Account{
"alice"};
5038 auto const USD = gw[
"USD"];
5040 env.fund(
XRP(10000), gw, alice);
5043 env(
trust(alice, USD(1000)));
5047 env(
pay(gw, alice, USD(200)));
5052 env(
offer(alice,
XRP(50), USD(50)));
5064 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5065 env(
offer(alice,
XRP(50), USD(50)));
5081 BEAST_EXPECT(
offers.size() == 4);
5082 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
5083 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
5084 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
5085 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
5086 env.require(
balance(alice, USD(200)));
5087 env.require(
owners(alice, 7));
5097 BEAST_EXPECT(
offers.size() == 3);
5098 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5099 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
5100 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
5110 BEAST_EXPECT(
offers.size() == 2);
5111 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5112 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5125 BEAST_EXPECT(
offers.size() == 1);
5126 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5143 testcase(
"incorrect assert fixed");
5144 using namespace jtx;
5147 auto const alice =
Account(
"alice");
5148 auto const USD = alice[
"USD"];
5150 env.fund(
XRP(10000), alice);
5152 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5160 using namespace jtx;
5161 Env env(*
this, features);
5162 Account const issuer(
"issuer");
5165 auto const USD = issuer[
"USD"];
5166 auto const EUR = issuer[
"EUR"];
5169 env.
fund(
XRP(1'000), maker, taker);
5172 env.
trust(USD(1'000), maker, taker);
5173 env.
trust(EUR(1'000), maker, taker);
5176 env(
pay(issuer, maker, USD(1'000)));
5177 env(
pay(issuer, taker, USD(1'000)));
5178 env(
pay(issuer, maker, EUR(1'000)));
5181 auto makerUSDBalance = env.
balance(maker, USD).
value();
5182 auto takerUSDBalance = env.
balance(taker, USD).
value();
5183 auto makerEURBalance = env.
balance(maker, EUR).
value();
5184 auto takerEURBalance = env.
balance(taker, EUR).
value();
5191 features[fixFillOrKill] || !features[featureFlowCross]
5195 env(
offer(maker,
XRP(100), USD(100)));
5198 env(
offer(taker, USD(100),
XRP(101)),
5203 makerXRPBalance -=
txfee(env, 1);
5204 takerXRPBalance -=
txfee(env, 1);
5207 makerUSDBalance -= USD(100);
5208 takerUSDBalance += USD(100);
5209 makerXRPBalance +=
XRP(100).value();
5210 takerXRPBalance -=
XRP(100).value();
5214 env(
offer(maker, USD(100),
XRP(100)));
5217 env(
offer(taker,
XRP(100), USD(101)),
5222 makerXRPBalance -=
txfee(env, 1);
5223 takerXRPBalance -=
txfee(env, 1);
5226 makerUSDBalance += USD(100);
5227 takerUSDBalance -= USD(100);
5228 makerXRPBalance -=
XRP(100).value();
5229 takerXRPBalance +=
XRP(100).value();
5233 env(
offer(maker, USD(100), EUR(100)));
5236 env(
offer(taker, EUR(100), USD(101)),
5241 makerXRPBalance -=
txfee(env, 1);
5242 takerXRPBalance -=
txfee(env, 1);
5245 makerUSDBalance += USD(100);
5246 takerUSDBalance -= USD(100);
5247 makerEURBalance -= EUR(100);
5248 takerEURBalance += EUR(100);
5255 env(
offer(maker,
XRP(101), USD(101)));
5258 env(
offer(taker, USD(100),
XRP(101)),
5262 makerUSDBalance -= USD(101);
5263 takerUSDBalance += USD(101);
5264 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5265 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5268 env(
offer(maker, USD(101),
XRP(101)));
5271 env(
offer(taker,
XRP(100), USD(101)),
5275 makerUSDBalance += USD(101);
5276 takerUSDBalance -= USD(101);
5277 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5278 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5281 env(
offer(maker, USD(101), EUR(101)));
5284 env(
offer(taker, EUR(100), USD(101)),
5288 makerUSDBalance += USD(101);
5289 takerUSDBalance -= USD(101);
5290 makerEURBalance -= EUR(101);
5291 takerEURBalance += EUR(101);
5292 makerXRPBalance -=
txfee(env, 1);
5293 takerXRPBalance -=
txfee(env, 1);
5300 env(
offer(maker,
XRP(100), USD(100)));
5303 env(
offer(taker, USD(100),
XRP(99)),
5308 makerXRPBalance -=
txfee(env, 1);
5309 takerXRPBalance -=
txfee(env, 1);
5312 env(
offer(maker, USD(100),
XRP(100)));
5315 env(
offer(taker,
XRP(100), USD(99)),
5320 makerXRPBalance -=
txfee(env, 1);
5321 takerXRPBalance -=
txfee(env, 1);
5324 env(
offer(maker, USD(100), EUR(100)));
5327 env(
offer(taker, EUR(100), USD(99)),
5332 makerXRPBalance -=
txfee(env, 1);
5333 takerXRPBalance -=
txfee(env, 1);
5338 env.
balance(maker, USD) == makerUSDBalance &&
5339 env.
balance(taker, USD) == takerUSDBalance &&
5340 env.
balance(maker, EUR) == makerEURBalance &&
5341 env.
balance(taker, EUR) == takerEURBalance &&
5342 env.
balance(maker,
XRP) == makerXRPBalance &&
5413 using namespace jtx;
5416 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5418 fixRmSmallIncreasedQOffers};
5420 featureImmediateOfferKilled};
5424 all - takerDryOffer - immediateOfferKilled,
5425 all - flowCross - takerDryOffer - immediateOfferKilled,
5426 all - flowCross - immediateOfferKilled,
5427 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill,
5431 if (BEAST_EXPECT(instance < feats.size()))
5435 BEAST_EXPECT(!last || instance == feats.size() - 1);
5496 using namespace jtx;
5500 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5504 testAll(
all - flowCross - f1513 - immediateOfferKilled);
5505 testAll(
all - flowCross - immediateOfferKilled);
5506 testAll(
all - immediateOfferKilled - fillOrKill);
5514BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx,
ripple, 2);
5515BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx,
ripple, 2);
5516BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx,
ripple, 2);
5517BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx,
ripple, 2);
5518BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx,
ripple, 2);
5519BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx,
ripple, 2);
5520BEAST_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.
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