2#include <test/jtx/PathSet.h>
3#include <test/jtx/WSClient.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/Quality.h>
7#include <xrpl/protocol/jss.h>
17 return env.
current()->fees().accountReserve(count);
25 .parentCloseTime.time_since_epoch()
36 jvParams[jss::offer][jss::account] = acct.
human();
37 jvParams[jss::offer][jss::seq] = offer_seq;
39 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
45 Issue const& taker_pays,
46 Issue const& taker_gets)
49 jvbp[jss::ledger_index] =
"current";
54 return env.
rpc(
"json",
"book_offers",
to_string(jvbp))[jss::result];
61 testcase(
"Incorrect Removal of Funded Offers");
73 Env env{*
this, features};
75 auto const gw =
Account{
"gateway"};
76 auto const USD = gw[
"USD"];
77 auto const BTC = gw[
"BTC"];
82 env.fund(
XRP(10000), alice, bob, carol, gw);
84 env.trust(USD(1000), alice, bob, carol);
85 env.trust(BTC(1000), alice, bob, carol);
87 env(
pay(gw, alice, BTC(1000)));
89 env(
pay(gw, carol, USD(1000)));
90 env(
pay(gw, carol, BTC(1000)));
100 env(
offer(carol,
XRP(50), USD(50)));
101 env(
offer(carol,
XRP(50), USD(50)));
104 env(
offer(carol, BTC(1), USD(100)));
108 env(
pay(alice, bob, USD(100)),
113 env.require(
balance(bob, USD(100)));
115 !
isOffer(env, carol, BTC(1), USD(100)) &&
122 testcase(
"Removing Canceled Offers");
125 Env env{*
this, features};
127 auto const gw =
Account{
"gateway"};
128 auto const alice =
Account{
"alice"};
129 auto const USD = gw[
"USD"];
131 env.fund(
XRP(10000), alice, gw);
133 env.trust(USD(100), alice);
136 env(
pay(gw, alice, USD(50)));
139 auto const offer1Seq = env.seq(alice);
144 BEAST_EXPECT(
isOffer(env, alice,
XRP(500), USD(100)));
147 auto const offer2Seq = env.seq(alice);
149 env(
offer(alice,
XRP(300), USD(100)),
150 json(jss::OfferSequence, offer1Seq),
161 env(
offer(alice,
XRP(400), USD(200)),
162 json(jss::OfferSequence, offer1Seq),
171 auto const offer4Seq = env.seq(alice);
175 BEAST_EXPECT(
isOffer(env, alice,
XRP(222), USD(111)));
178 BEAST_EXPECT(env.seq(alice) == offer4Seq + 2);
180 BEAST_EXPECT(!
isOffer(env, alice,
XRP(222), USD(111)));
184 env.require(
offers(alice, 2));
188 json(jss::OfferSequence, offer2Seq),
192 env.require(
offers(alice, 2));
193 BEAST_EXPECT(
isOffer(env, alice,
XRP(300), USD(100)));
194 BEAST_EXPECT(!
isOffer(env, alice,
XRP(5), USD(2)));
204 using namespace std::chrono_literals;
205 auto const alice =
Account{
"alice"};
206 auto const bob =
Account{
"bob"};
207 auto const carol =
Account{
"carol"};
210 auto const USD = gw[
"USD"];
211 auto const EUR = gw[
"EUR"];
213 Env env{*
this, features};
215 env.fund(
XRP(10000), alice, bob, carol, gw);
217 env.trust(USD(1000), alice, bob, carol);
218 env.trust(EUR(1000), alice, bob, carol);
219 env(
pay(gw, alice, USD(100)));
220 env(
pay(gw, carol, EUR(100)));
226 for (
int i = 0; i < 101; ++i)
227 env(
offer(carol, USD(1), EUR(2)));
253 using namespace std::chrono_literals;
254 auto const alice =
Account{
"alice"};
255 auto const bob =
Account{
"bob"};
256 auto const carol =
Account{
"carol"};
257 auto const dan =
Account{
"dan"};
258 auto const erin =
Account{
"erin"};
261 auto const USD = gw[
"USD"];
262 Env env{*
this, features};
264 env.fund(
XRP(10000), alice, bob, carol, dan, erin, gw);
266 env.trust(USD(1000), alice, bob, carol, dan, erin);
268 env(
pay(gw, carol, USD(0.99999)));
269 env(
pay(gw, dan, USD(1)));
270 env(
pay(gw, erin, USD(1)));
292 env(
pay(alice, bob, USD(1)),
307 testcase(
"Rm small increased q offers XRP");
315 using namespace std::chrono_literals;
316 auto const alice =
Account{
"alice"};
317 auto const bob =
Account{
"bob"};
318 auto const carol =
Account{
"carol"};
321 auto const USD = gw[
"USD"];
324 for (
auto crossBothOffers : {
false,
true})
326 Env env{*
this, features};
328 env.fund(
XRP(10000), alice, bob, carol, gw);
330 env.trust(USD(1000), alice, bob, carol);
332 auto initialCarolUSD = USD(0.499);
333 env(
pay(gw, carol, initialCarolUSD));
334 env(
pay(gw, bob, USD(100)));
346 auto aliceTakerGets = crossBothOffers ?
drops(2) :
drops(1);
347 env(
offer(alice, USD(1), aliceTakerGets));
370 for (
auto partialPayment : {
false,
true})
372 Env env{*
this, features};
374 env.fund(
XRP(10000), alice, bob, carol, gw);
376 env.trust(USD(1000), alice, bob, carol);
378 auto const initialCarolUSD = USD(0.999);
379 env(
pay(gw, carol, initialCarolUSD));
381 env(
pay(gw, bob, USD(100)));
393 TER const expectedTer =
396 env(
pay(alice, bob, USD(5)),
405 env.require(
offers(carol, 0));
423 testcase(
"Rm small increased q offers IOU");
431 using namespace std::chrono_literals;
432 auto const alice =
Account{
"alice"};
433 auto const bob =
Account{
"bob"};
434 auto const carol =
Account{
"carol"};
437 auto const USD = gw[
"USD"];
438 auto const EUR = gw[
"EUR"];
449 for (
auto crossBothOffers : {
false,
true})
451 Env env{*
this, features};
453 env.fund(
XRP(10000), alice, bob, carol, gw);
455 env.trust(USD(1000), alice, bob, carol);
456 env.trust(EUR(1000), alice, bob, carol);
458 auto initialCarolUSD = tinyAmount(USD);
459 env(
pay(gw, carol, initialCarolUSD));
460 env(
pay(gw, bob, USD(100)));
461 env(
pay(gw, alice, EUR(100)));
464 env(
offer(carol, EUR(1), USD(10)));
474 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
475 env(
offer(alice, USD(1), aliceTakerGets));
498 for (
auto partialPayment : {
false,
true})
500 Env env{*
this, features};
502 env.fund(
XRP(10000), alice, bob, carol, gw);
504 env.trust(USD(1000), alice, bob, carol);
505 env.trust(EUR(1000), alice, bob, carol);
508 auto const initialCarolUSD = tinyAmount(USD);
509 env(
pay(gw, carol, initialCarolUSD));
510 env(
pay(gw, bob, USD(100)));
511 env(
pay(gw, alice, EUR(100)));
514 env(
offer(carol, EUR(1), USD(2)));
524 TER const expectedTer =
527 env(
pay(alice, bob, USD(5)),
536 env.require(
offers(carol, 0));
558 auto const gw =
Account{
"gateway"};
559 auto const USD = gw[
"USD"];
560 auto const BTC = gw[
"BTC"];
561 auto const EUR = gw[
"EUR"];
569 Env env{*
this, features};
571 auto const gw1 =
Account{
"gw1"};
572 auto const USD1 = gw1[
"USD"];
573 auto const gw2 =
Account{
"gw2"};
574 auto const USD2 = gw2[
"USD"];
576 env.fund(
XRP(10000), alice,
noripple(bob), carol, dan, gw1, gw2);
578 env.trust(USD1(1000), alice, carol, dan);
580 env.trust(USD2(1000), alice, carol, dan);
583 env(
pay(gw1, dan, USD1(50)));
584 env(
pay(gw1, bob, USD1(50)));
585 env(
pay(gw2, bob, USD2(50)));
589 env(
pay(alice, carol, USD2(50)),
597 Env env{*
this, features};
599 auto const gw1 =
Account{
"gw1"};
600 auto const USD1 = gw1[
"USD"];
601 auto const gw2 =
Account{
"gw2"};
602 auto const USD2 = gw2[
"USD"];
604 env.fund(
XRP(10000), alice, bob, carol, dan, gw1, gw2);
606 env.trust(USD1(1000), alice, bob, carol, dan);
607 env.trust(USD2(1000), alice, bob, carol, dan);
609 env(
pay(gw1, dan, USD1(50)));
610 env(
pay(gw1, bob, USD1(50)));
611 env(
pay(gw2, bob, USD2(50)));
615 env(
pay(alice, carol, USD2(50)),
621 env.require(
balance(bob, USD1(100)));
622 env.require(
balance(bob, USD2(0)));
623 env.require(
balance(carol, USD2(50)));
640 auto const gw =
Account{
"gateway"};
641 auto const alice =
Account{
"alice"};
642 auto const bob =
Account{
"bob"};
643 auto const carol =
Account{
"carol"};
644 auto const USD = gw[
"USD"];
646 auto const usdOffer = USD(1000);
647 auto const xrpOffer =
XRP(1000);
651 Env env{*
this, features};
653 env.fund(
XRP(1000000), gw);
655 auto const f = env.current()->fees().base;
656 auto const r =
reserve(env, 0);
658 env.fund(r + f, alice);
669 Env env{*
this, features};
671 env.fund(
XRP(1000000), gw);
673 auto const f = env.current()->fees().base;
674 auto const r =
reserve(env, 0);
676 auto const usdOffer2 = USD(500);
677 auto const xrpOffer2 =
XRP(500);
679 env.fund(r + f + xrpOffer, bob);
682 env.fund(r + f, alice);
689 balance(alice, r - f + xrpOffer2),
701 Env env{*
this, features};
703 env.fund(
XRP(1000000), gw);
705 auto const f = env.current()->fees().base;
706 auto const r =
reserve(env, 0);
708 auto const usdOffer2 = USD(500);
709 auto const xrpOffer2 =
XRP(500);
711 env.fund(r + f + xrpOffer, bob, carol);
716 env.fund(r + f, alice);
723 balance(alice, r - f + xrpOffer),
744 if (sle->getType() == ltOFFER)
745 result.push_back(sle);
757 auto const startBalance =
XRP(1000000);
758 auto const gw =
Account{
"gateway"};
759 auto const alice =
Account{
"alice"};
760 auto const bob =
Account{
"bob"};
761 auto const USD = gw[
"USD"];
767 Env env{*
this, features};
769 auto const f = env.current()->fees().base;
771 env.fund(startBalance, gw, alice, bob);
794 env(
offer(alice,
XRP(1000), USD(1000)),
799 balance(alice, startBalance - (f * 2)),
803 balance(bob, startBalance - (f * 2)),
809 env(
offer(alice,
XRP(500), USD(500)),
814 balance(alice, startBalance - (f * 3) +
XRP(500)),
818 balance(bob, startBalance - (f * 2) -
XRP(500)),
827 Env env{*
this, features};
829 auto const f = env.current()->fees().base;
831 env.fund(startBalance, gw, alice, bob);
840 env(
offer(alice,
XRP(1000), USD(1000)),
846 balance(alice, startBalance - f - f),
853 env(
offer(alice,
XRP(1000), USD(1000)),
858 balance(alice, startBalance - f - f - f +
XRP(50)),
874 balance(alice, startBalance - f - f - f - f +
XRP(100)),
878 balance(bob, startBalance - f - f -
XRP(100)),
886 Env env(*
this, features);
888 env.
fund(startBalance, gw, alice, bob);
891 env(
trust(bob, USD(1000)));
894 env(
pay(gw, bob, USD(1000)));
897 env(
offer(alice, USD(1000),
XRP(2000)));
901 BEAST_EXPECT(aliceOffers.size() == 1);
902 for (
auto offerPtr : aliceOffers)
904 auto const&
offer = *offerPtr;
905 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
906 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
916 BEAST_EXPECT(bobOffers.size() == 1);
917 for (
auto offerPtr : bobOffers)
919 auto const&
offer = *offerPtr;
920 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
921 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
925 env(
offer(gw,
XRP(2000), USD(1000)));
931 env(
offer(gw, USD(1000),
XRP(2000)));
939 Env env(*
this, features);
941 env.
fund(startBalance, gw,
"alice",
"bob");
944 env(
trust(
"bob", USD(1000)));
947 env(
pay(gw,
"bob", USD(1000)));
948 env(
offer(
"alice", USD(500),
XRP(1001)));
951 env(
offer(
"alice", USD(500),
XRP(1000)));
955 BEAST_EXPECT(aliceOffers.size() == 2);
965 BEAST_EXPECT(bobOffers.size() == 1);
966 for (
auto offerPtr : bobOffers)
968 auto const&
offer = *offerPtr;
969 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
970 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
982 auto const startBalance =
XRP(1000000);
983 auto const gw =
Account{
"gateway"};
984 auto const alice =
Account{
"alice"};
985 auto const USD = gw[
"USD"];
987 Env env{*
this, features};
989 env.fund(startBalance, gw, alice);
993 env(
offer(alice, USD(1000),
XRP(1000)),
1000 env(
offer(alice, USD(1000),
XRP(1000)),
1030 env(
offer(alice, USD(1000),
XRP(1000)),
1038 env(
offer(alice, USD(1000),
XRP(1000)),
1058 using namespace jtx;
1060 auto const gw =
Account{
"gateway"};
1061 auto const alice =
Account{
"alice"};
1062 auto const bob =
Account{
"bob"};
1063 auto const USD = gw[
"USD"];
1065 auto const startBalance =
XRP(1000000);
1066 auto const usdOffer = USD(1000);
1067 auto const xrpOffer =
XRP(1000);
1069 Env env{*
this, features};
1071 env.fund(startBalance, gw, alice, bob);
1074 auto const f = env.current()->fees().base;
1080 balance(alice, startBalance - f),
1085 env(
offer(alice, xrpOffer, usdOffer),
1090 balance(alice, startBalance - f - f),
1097 env(
offer(alice, xrpOffer, usdOffer),
1101 balance(alice, startBalance - f - f - f),
1109 balance(alice, startBalance - f - f - f),
1117 balance(alice, startBalance - f - f - f),
1121 balance(bob, startBalance - f),
1132 using namespace jtx;
1134 auto const gw =
Account{
"gateway"};
1135 auto const USD = gw[
"USD"];
1137 auto const usdOffer = USD(1000);
1138 auto const xrpOffer =
XRP(1000);
1140 Env env{*
this, features};
1142 env.fund(
XRP(1000000), gw);
1146 auto const f = env.current()->fees().base;
1150 env.fund(
reserve(env, 0),
"alice");
1157 env.fund(
reserve(env, 0) + f,
"bob");
1165 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1173 env.fund(
reserve(env, 1) + f,
"dan");
1180 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1192 (use_partner ?
", with partner account" :
""));
1194 using namespace jtx;
1196 auto const gw =
Account{
"gateway"};
1197 auto const partner =
Account{
"partner"};
1198 auto const USD = gw[
"USD"];
1199 auto const BTC = gw[
"BTC"];
1201 Env env{*
this, features};
1204 env.fund(
XRP(10000), gw);
1207 env.fund(
XRP(10000), partner);
1209 env(
trust(partner, USD(100)));
1210 env(
trust(partner, BTC(500)));
1212 env(
pay(gw, partner, USD(100)));
1213 env(
pay(gw, partner, BTC(500)));
1215 auto const& account_to_test = use_partner ? partner : gw;
1218 env.require(
offers(account_to_test, 0));
1223 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1224 env.require(
offers(account_to_test, 1));
1227 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1229 auto const secondLegSeq = env.seq(account_to_test);
1230 env(
offer(account_to_test,
XRP(1000), USD(50)));
1231 env.require(
offers(account_to_test, 2));
1234 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1238 env(
offer(account_to_test, USD(50), BTC(250)));
1241 BEAST_EXPECT(jrr[jss::offers].isArray());
1242 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1245 BEAST_EXPECT(jrr[jss::offers].isArray());
1246 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1253 BEAST_EXPECT(acctOffers.size() == 0);
1254 for (
auto const& offerPtr : acctOffers)
1256 auto const&
offer = *offerPtr;
1257 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1258 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1259 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1267 env.require(
offers(account_to_test, 0));
1272 env(
offer(account_to_test, BTC(250), USD(50)));
1273 env.require(
offers(account_to_test, 1));
1277 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1280 BEAST_EXPECT(jrr[jss::offers].isArray());
1281 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1285 env(
offer(account_to_test, USD(50), BTC(250)));
1286 env.require(
offers(account_to_test, 1));
1291 BEAST_EXPECT(jrr[jss::offers].isArray());
1292 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1294 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1304 using namespace jtx;
1309 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1311 Env env{*
this, localFeatures};
1313 auto const gw =
Account{
"gateway"};
1314 auto const alice =
Account{
"alice"};
1315 auto const bob =
Account{
"bob"};
1316 auto const USD = gw[
"USD"];
1317 auto const BTC = gw[
"BTC"];
1321 auto const gw_initial_balance =
drops(1149999730);
1322 auto const alice_initial_balance =
drops(499946999680);
1323 auto const bob_initial_balance =
drops(10199999920);
1324 auto const small_amount =
1325 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1327 env.fund(gw_initial_balance, gw);
1328 env.fund(alice_initial_balance, alice);
1329 env.fund(bob_initial_balance, bob);
1332 env(
rate(gw, 1.005));
1334 env(
trust(alice, USD(500)));
1335 env(
trust(bob, USD(50)));
1336 env(
trust(gw, alice[
"USD"](100)));
1338 env(
pay(gw, alice, alice[
"USD"](50)));
1339 env(
pay(gw, bob, small_amount));
1341 env(
offer(alice, USD(50),
XRP(150000)));
1344 env(
pay(alice, gw, USD(100)));
1347 env(
trust(gw, alice[
"USD"](0)));
1352 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1356 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1357 "-2710505431213761e-33");
1361 env(
offer(bob,
XRP(2000), USD(1)));
1363 if (localFeatures[fixReducedOffersV2])
1370 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1371 "-2710505431213761e-33");
1375 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1376 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1387 auto const crossingDelta =
drops(1);
1391 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1394 alice_initial_balance - env.current()->fees().base * 3 -
1399 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1402 bob_initial_balance - env.current()->fees().base * 2 +
1412 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1414 using namespace jtx;
1416 Env env{*
this, features};
1418 auto const gw =
Account{
"gateway"};
1419 auto const alice =
Account{
"alice"};
1420 auto const bob =
Account{
"bob"};
1421 auto const USD = gw[
"USD"];
1423 env.fund(
XRP(10000), gw, alice, bob);
1426 env(
trust(alice, USD(1000)));
1427 env(
trust(bob, USD(1000)));
1429 env(
pay(gw, alice, alice[
"USD"](500)));
1432 env(
offer(bob, USD(1),
XRP(4000)));
1434 env(
offer(alice,
XRP(150000), USD(50)));
1437 env(
offer(bob, USD(1),
XRP(4000)));
1444 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1447 jrr[jss::node][sfBalance.fieldName] ==
1449 env.current()->fees().base * 2)
1453 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1456 jrr[jss::node][sfBalance.fieldName] ==
1458 env.current()->fees().base * 2)
1465 testcase(
"Offer Crossing with Limit Override");
1467 using namespace jtx;
1469 Env env{*
this, features};
1471 auto const gw =
Account{
"gateway"};
1472 auto const alice =
Account{
"alice"};
1473 auto const bob =
Account{
"bob"};
1474 auto const USD = gw[
"USD"];
1476 env.fund(
XRP(100000), gw, alice, bob);
1479 env(
trust(alice, USD(1000)));
1481 env(
pay(gw, alice, alice[
"USD"](500)));
1483 env(
offer(alice,
XRP(150000), USD(50)));
1484 env(
offer(bob, USD(1),
XRP(3000)));
1487 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1490 jrr[jss::node][sfBalance.fieldName] ==
1495 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1498 jrr[jss::node][sfBalance.fieldName] ==
1506 testcase(
"Offer Accept then Cancel.");
1508 using namespace jtx;
1510 Env env{*
this, features};
1512 auto const USD = env.master[
"USD"];
1514 auto const nextOfferSeq = env.seq(env.master);
1515 env(
offer(env.master,
XRP(500), USD(100)));
1519 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1524 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1530 testcase(
"Offer Cancel Past and Future Sequence.");
1532 using namespace jtx;
1534 Env env{*
this, features};
1536 auto const alice =
Account{
"alice"};
1538 auto const nextOfferSeq = env.seq(env.master);
1539 env.fund(
XRP(10000), alice);
1556 testcase(
"Currency Conversion: Entire Offer");
1558 using namespace jtx;
1560 Env env{*
this, features};
1562 auto const gw =
Account{
"gateway"};
1563 auto const alice =
Account{
"alice"};
1564 auto const bob =
Account{
"bob"};
1565 auto const USD = gw[
"USD"];
1567 env.fund(
XRP(10000), gw, alice, bob);
1569 env.require(
owners(bob, 0));
1571 env(
trust(alice, USD(100)));
1572 env(
trust(bob, USD(1000)));
1576 env(
pay(gw, alice, alice[
"USD"](100)));
1577 auto const bobOfferSeq = env.seq(bob);
1578 env(
offer(bob, USD(100),
XRP(500)));
1583 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1585 jro[jss::node][jss::TakerPays] ==
1591 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1594 jrr[jss::node][sfBalance.fieldName] ==
1599 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1602 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1610 testcase(
"Currency Conversion: Offerer Into Debt");
1612 using namespace jtx;
1614 Env env{*
this, features};
1616 auto const alice =
Account{
"alice"};
1617 auto const bob =
Account{
"bob"};
1618 auto const carol =
Account{
"carol"};
1620 env.fund(
XRP(10000), alice, bob, carol);
1623 env(
trust(alice, carol[
"EUR"](2000)));
1624 env(
trust(bob, alice[
"USD"](100)));
1625 env(
trust(carol, bob[
"EUR"](1000)));
1627 auto const bobOfferSeq = env.seq(bob);
1628 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1631 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1634 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1640 testcase(
"Currency Conversion: In Parts");
1642 using namespace jtx;
1644 Env env{*
this, features};
1646 auto const gw =
Account{
"gateway"};
1647 auto const alice =
Account{
"alice"};
1648 auto const bob =
Account{
"bob"};
1649 auto const USD = gw[
"USD"];
1651 env.fund(
XRP(10000), gw, alice, bob);
1654 env(
trust(alice, USD(200)));
1655 env(
trust(bob, USD(1000)));
1657 env(
pay(gw, alice, alice[
"USD"](200)));
1659 auto const bobOfferSeq = env.seq(bob);
1660 env(
offer(bob, USD(100),
XRP(500)));
1667 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1669 jro[jss::node][jss::TakerPays] ==
1675 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1679 jrr[jss::node][sfBalance.fieldName] ==
1685 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1689 env(
pay(alice, alice,
XRP(600)),
1695 env(
pay(alice, alice,
XRP(600)),
1701 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1709 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1712 jrr[jss::node][sfBalance.fieldName] ==
1714 env.current()->fees().base * 4)
1720 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1726 testcase(
"Cross Currency Payment: Start with XRP");
1728 using namespace jtx;
1730 Env env{*
this, features};
1732 auto const gw =
Account{
"gateway"};
1733 auto const alice =
Account{
"alice"};
1734 auto const bob =
Account{
"bob"};
1735 auto const carol =
Account{
"carol"};
1736 auto const USD = gw[
"USD"];
1738 env.fund(
XRP(10000), gw, alice, bob, carol);
1741 env(
trust(carol, USD(1000)));
1742 env(
trust(bob, USD(2000)));
1744 env(
pay(gw, carol, carol[
"USD"](500)));
1746 auto const carolOfferSeq = env.seq(carol);
1747 env(
offer(carol,
XRP(500), USD(50)));
1752 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1755 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1759 jro[jss::node][jss::TakerGets] ==
1762 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1768 testcase(
"Cross Currency Payment: End with XRP");
1770 using namespace jtx;
1772 Env env{*
this, features};
1774 auto const gw =
Account{
"gateway"};
1775 auto const alice =
Account{
"alice"};
1776 auto const bob =
Account{
"bob"};
1777 auto const carol =
Account{
"carol"};
1778 auto const USD = gw[
"USD"];
1780 env.fund(
XRP(10000), gw, alice, bob, carol);
1783 env(
trust(alice, USD(1000)));
1784 env(
trust(carol, USD(2000)));
1786 env(
pay(gw, alice, alice[
"USD"](500)));
1788 auto const carolOfferSeq = env.seq(carol);
1789 env(
offer(carol, USD(50),
XRP(500)));
1794 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1797 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1801 jrr[jss::node][sfBalance.fieldName] ==
1803 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1807 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1809 jro[jss::node][jss::TakerPays] ==
1816 testcase(
"Cross Currency Payment: Bridged");
1818 using namespace jtx;
1820 Env env{*
this, features};
1822 auto const gw1 =
Account{
"gateway_1"};
1823 auto const gw2 =
Account{
"gateway_2"};
1824 auto const alice =
Account{
"alice"};
1825 auto const bob =
Account{
"bob"};
1826 auto const carol =
Account{
"carol"};
1827 auto const dan =
Account{
"dan"};
1828 auto const USD = gw1[
"USD"];
1829 auto const EUR = gw2[
"EUR"];
1831 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1834 env(
trust(alice, USD(1000)));
1835 env(
trust(bob, EUR(1000)));
1836 env(
trust(carol, USD(1000)));
1837 env(
trust(dan, EUR(1000)));
1839 env(
pay(gw1, alice, alice[
"USD"](500)));
1840 env(
pay(gw2, dan, dan[
"EUR"](400)));
1842 auto const carolOfferSeq = env.seq(carol);
1843 env(
offer(carol, USD(50),
XRP(500)));
1845 auto const danOfferSeq = env.seq(dan);
1846 env(
offer(dan,
XRP(500), EUR(50)));
1849 jtp[0u][0u][jss::currency] =
"XRP";
1850 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1853 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1856 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1859 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1862 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1866 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1868 jro[jss::node][jss::TakerPays] ==
1873 jro[jss::node][jss::TakerGets] ==
1876 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1885 testcase(
"Auto Bridged Second Leg Dry");
1887 using namespace jtx;
1888 Env env(*
this, features);
1894 auto const USD = gw[
"USD"];
1895 auto const EUR = gw[
"EUR"];
1897 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1900 env.
trust(USD(10), alice);
1902 env(
pay(gw, alice, USD(10)));
1903 env.
trust(USD(10), carol);
1905 env(
pay(gw, carol, USD(3)));
1922 env.
trust(EUR(10), bob);
1924 env(
pay(gw, bob, EUR(10)));
1926 env(
offer(bob, USD(10), EUR(10)));
1949 testcase(
"Offer Fees Consume Funds");
1951 using namespace jtx;
1953 Env env{*
this, features};
1955 auto const gw1 =
Account{
"gateway_1"};
1956 auto const gw2 =
Account{
"gateway_2"};
1957 auto const gw3 =
Account{
"gateway_3"};
1958 auto const alice =
Account{
"alice"};
1959 auto const bob =
Account{
"bob"};
1960 auto const USD1 = gw1[
"USD"];
1961 auto const USD2 = gw2[
"USD"];
1962 auto const USD3 = gw3[
"USD"];
1970 auto const starting_xrp =
XRP(100) +
1971 env.current()->fees().accountReserve(3) +
1972 env.current()->fees().base * 4;
1974 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
1977 env(
trust(alice, USD1(1000)));
1978 env(
trust(alice, USD2(1000)));
1979 env(
trust(alice, USD3(1000)));
1980 env(
trust(bob, USD1(1000)));
1981 env(
trust(bob, USD2(1000)));
1983 env(
pay(gw1, bob, bob[
"USD"](500)));
1985 env(
offer(bob,
XRP(200), USD1(200)));
1988 env(
offer(alice, USD1(200),
XRP(200)));
1991 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
1994 jrr[jss::node][sfBalance.fieldName] ==
1998 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2004 testcase(
"Offer Create, then Cross");
2006 using namespace jtx;
2008 for (
auto NumberSwitchOver : {
false,
true})
2010 Env env{*
this, features};
2011 if (NumberSwitchOver)
2012 env.enableFeature(fixUniversalNumber);
2014 env.disableFeature(fixUniversalNumber);
2016 auto const gw =
Account{
"gateway"};
2017 auto const alice =
Account{
"alice"};
2018 auto const bob =
Account{
"bob"};
2019 auto const USD = gw[
"USD"];
2021 env.fund(
XRP(10000), gw, alice, bob);
2024 env(
rate(gw, 1.005));
2026 env(
trust(alice, USD(1000)));
2027 env(
trust(bob, USD(1000)));
2028 env(
trust(gw, alice[
"USD"](50)));
2030 env(
pay(gw, bob, bob[
"USD"](1)));
2031 env(
pay(alice, gw, USD(50)));
2033 env(
trust(gw, alice[
"USD"](0)));
2035 env(
offer(alice, USD(50),
XRP(150000)));
2036 env(
offer(bob,
XRP(100), USD(0.1)));
2040 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2041 "49.96666666666667");
2045 jrr[jss::node][sfBalance.fieldName][jss::value];
2046 if (!NumberSwitchOver)
2048 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2052 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2060 testcase(
"Offer tfSell: Basic Sell");
2062 using namespace jtx;
2064 Env env{*
this, features};
2066 auto const gw =
Account{
"gateway"};
2067 auto const alice =
Account{
"alice"};
2068 auto const bob =
Account{
"bob"};
2069 auto const USD = gw[
"USD"];
2071 auto const starting_xrp =
XRP(100) +
2072 env.current()->fees().accountReserve(1) +
2073 env.current()->fees().base * 2;
2075 env.fund(starting_xrp, gw, alice, bob);
2078 env(
trust(alice, USD(1000)));
2079 env(
trust(bob, USD(1000)));
2081 env(
pay(gw, bob, bob[
"USD"](500)));
2090 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2093 jrr[jss::node][sfBalance.fieldName] ==
2097 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2103 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2105 using namespace jtx;
2107 Env env{*
this, features};
2109 auto const gw =
Account{
"gateway"};
2110 auto const alice =
Account{
"alice"};
2111 auto const bob =
Account{
"bob"};
2112 auto const USD = gw[
"USD"];
2114 auto const starting_xrp =
XRP(100) +
2115 env.current()->fees().accountReserve(1) +
2116 env.current()->fees().base * 2;
2118 env.fund(starting_xrp, gw, alice, bob);
2121 env(
trust(alice, USD(150)));
2122 env(
trust(bob, USD(1000)));
2124 env(
pay(gw, bob, bob[
"USD"](500)));
2126 env(
offer(bob,
XRP(100), USD(200)));
2135 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2138 jrr[jss::node][sfBalance.fieldName] ==
2142 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2148 testcase(
"Client Issue #535: Gateway Cross Currency");
2150 using namespace jtx;
2152 Env env{*
this, features};
2154 auto const gw =
Account{
"gateway"};
2155 auto const alice =
Account{
"alice"};
2156 auto const bob =
Account{
"bob"};
2157 auto const XTS = gw[
"XTS"];
2158 auto const XXX = gw[
"XXX"];
2160 auto const starting_xrp =
XRP(100.1) +
2161 env.current()->fees().accountReserve(1) +
2162 env.current()->fees().base * 2;
2164 env.fund(starting_xrp, gw, alice, bob);
2167 env(
trust(alice, XTS(1000)));
2168 env(
trust(alice, XXX(1000)));
2169 env(
trust(bob, XTS(1000)));
2170 env(
trust(bob, XXX(1000)));
2172 env(
pay(gw, alice, alice[
"XTS"](100)));
2173 env(
pay(gw, alice, alice[
"XXX"](100)));
2174 env(
pay(gw, bob, bob[
"XTS"](100)));
2175 env(
pay(gw, bob, bob[
"XXX"](100)));
2177 env(
offer(alice, XTS(100), XXX(100)));
2184 payment[jss::id] = env.seq(bob);
2185 payment[jss::build_path] =
true;
2186 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2187 payment[jss::tx_json][jss::Sequence] =
2190 ->getFieldU32(sfSequence);
2191 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2192 payment[jss::tx_json][jss::SendMax] =
2194 auto jrr = wsc->invoke(
"submit", payment);
2195 BEAST_EXPECT(jrr[jss::status] ==
"success");
2196 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2197 if (wsc->version() == 2)
2200 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2202 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2203 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2207 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2209 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2212 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2214 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2229 auto const sleTrust =
2231 BEAST_EXPECT(sleTrust);
2235 bool const accountLow = account.id() < issue.
account;
2240 low.setIssuer(accountLow ? account.id() : issue.
account);
2241 high.setIssuer(accountLow ? issue.
account : account.id());
2243 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2244 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2246 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2250 BEAST_EXPECT(actualBalance == expectBalance);
2262 using namespace jtx;
2264 auto const gw =
Account(
"gateway");
2265 auto const USD = gw[
"USD"];
2267 Env env{*
this, features};
2269 env.fund(
XRP(10000000), gw);
2273 auto const f = env.current()->fees().base;
2276 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2282 preTrustType preTrust;
2292 TestData
const tests[]{
2294 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2295 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2296 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2297 {
"deb",
drops(10) +
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 1},
2298 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2299 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2300 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2301 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2302 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2303 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2304 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2305 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2306 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2307 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2308 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2309 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2310 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2311 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2313 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2314 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2315 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2316 {
"dan",
drops(10) +
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 0},
2317 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2318 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2319 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2320 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2322 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2323 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2324 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2325 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2326 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2327 {
"syd",
drops(10) +
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
drops(10) + 2 * f, USD(0.00001), 0, 1},
2328 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2329 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2330 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2331 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2332 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2336 for (
auto const& t : tests)
2338 auto const acct =
Account(t.account);
2339 env.fund(t.fundXrp, acct);
2343 env.require(
offers(gw, 0));
2346 auto const book = t.bookAmount;
2348 env(
offer(gw,
XRP(book), USD(book)));
2353 if (t.preTrust == gwPreTrust)
2354 env(
trust(gw, acct[
"USD"](1)));
2360 if (t.preTrust == acctPreTrust)
2361 env(
trust(acct, USD(1)));
2366 auto const acctOffer = t.offerAmount;
2367 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2372 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2374 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2375 env.require(
offers(acct, t.offers));
2376 env.require(
owners(acct, t.owners));
2379 BEAST_EXPECT(acctOffers.size() == t.offers);
2380 if (acctOffers.size() && t.offers)
2382 auto const& acctOffer = *(acctOffers.front());
2384 auto const leftover = t.offerAmount - t.bookAmount;
2385 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2386 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2389 if (t.preTrust == noPreTrust)
2391 if (t.balanceUsd.value().signum())
2399 auto const sleTrust =
2401 BEAST_EXPECT(!sleTrust);
2418 using namespace jtx;
2420 auto const gw =
Account(
"gateway");
2421 auto const alice =
Account(
"alice");
2422 auto const bob =
Account(
"bob");
2423 auto const USD = gw[
"USD"];
2425 auto const usdOffer = USD(1000);
2426 auto const xrpOffer =
XRP(1000);
2428 Env env{*
this, features};
2430 env.fund(
XRP(1000000), gw, bob);
2434 auto const fee = env.current()->fees().base;
2441 env(
trust(alice, usdOffer));
2445 env(
pay(gw, alice, usdOffer));
2452 auto const alicesXRP = env.balance(alice);
2453 auto const bobsXRP = env.balance(bob);
2455 env(
offer(alice, xrpOffer, usdOffer));
2457 env(
offer(bob, usdOffer, xrpOffer));
2471 env(
offer(alice, USD(999),
XRP(999)));
2472 env(
offer(bob, xrpOffer, usdOffer));
2475 env.require(
balance(alice, USD(999)));
2476 env.require(
balance(bob, USD(1)));
2477 env.require(
offers(alice, 0));
2481 BEAST_EXPECT(bobsOffers.size() == 1);
2482 auto const& bobsOffer = *(bobsOffers.front());
2484 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2485 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2486 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2495 using namespace jtx;
2497 auto const gw =
Account(
"gateway");
2498 auto const alice =
Account(
"alice");
2499 auto const bob =
Account(
"bob");
2500 auto const USD = gw[
"USD"];
2501 auto const EUR = gw[
"EUR"];
2503 auto const usdOffer = USD(1000);
2504 auto const eurOffer = EUR(1000);
2506 Env env{*
this, features};
2508 env.fund(
XRP(1000000), gw);
2512 auto const fee = env.current()->fees().base;
2520 env(
trust(alice, usdOffer));
2521 env(
trust(bob, eurOffer));
2524 env(
pay(gw, alice, usdOffer));
2525 env(
pay(gw, bob, eurOffer));
2533 env(
offer(alice, eurOffer, usdOffer));
2534 env(
offer(bob, usdOffer, eurOffer));
2551 env(
offer(bob, eurOffer, usdOffer));
2554 env(
offer(alice, USD(999), eurOffer));
2557 env.require(
offers(alice, 0));
2558 env.require(
offers(bob, 1));
2560 env.require(
balance(alice, USD(999)));
2561 env.require(
balance(alice, EUR(1)));
2562 env.require(
balance(bob, USD(1)));
2563 env.require(
balance(bob, EUR(999)));
2567 if (BEAST_EXPECT(bobsOffers.size() == 1))
2569 auto const& bobsOffer = *(bobsOffers.front());
2571 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2572 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2577 env(
offer(alice, USD(1), EUR(1)));
2580 env.require(
balance(alice, USD(1000)));
2583 env.require(
balance(bob, EUR(1000)));
2584 env.require(
offers(alice, 0));
2585 env.require(
offers(bob, 0));
2588 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2589 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2593 env(
offer(alice, EUR(999), usdOffer));
2596 env(
offer(bob, usdOffer, eurOffer));
2599 env.require(
offers(alice, 0));
2600 env.require(
offers(bob, 0));
2602 env.require(
balance(alice, USD(0)));
2603 env.require(
balance(alice, EUR(999)));
2604 env.require(
balance(bob, USD(1000)));
2605 env.require(
balance(bob, EUR(1)));
2613 using namespace jtx;
2615 auto const gw =
Account(
"gateway");
2616 auto const alice =
Account(
"alice");
2617 auto const bob =
Account(
"bob");
2618 auto const carol =
Account(
"carol");
2619 auto const USD = gw[
"USD"];
2620 auto const EUR = gw[
"EUR"];
2622 auto const usdOffer = USD(1000);
2623 auto const eurOffer = EUR(1000);
2625 Env env{*
this, features};
2627 env.fund(
XRP(1000000), gw, alice, bob, carol);
2630 env(
trust(alice, usdOffer));
2631 env(
trust(carol, eurOffer));
2633 env(
pay(gw, alice, usdOffer));
2634 env(
pay(gw, carol, eurOffer));
2643 env(
offer(alice,
XRP(1000), usdOffer));
2644 env(
offer(bob, eurOffer,
XRP(1000)));
2645 auto const bobXrpBalance = env.balance(bob);
2649 env(
offer(carol, USD(400), EUR(400)));
2662 BEAST_EXPECT(alicesOffers.size() == 1);
2663 auto const& alicesOffer = *(alicesOffers.front());
2665 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2666 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2667 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2671 BEAST_EXPECT(bobsOffers.size() == 1);
2672 auto const& bobsOffer = *(bobsOffers.front());
2674 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2675 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2676 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2680 env(
offer(carol, USD(600), EUR(600)));
2695 if (alicesOffers.size() != 0)
2697 BEAST_EXPECT(alicesOffers.size() == 1);
2698 auto const& alicesOffer = *(alicesOffers.front());
2700 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2701 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2702 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2714 using namespace jtx;
2716 auto const gw =
Account(
"gateway");
2717 auto const USD = gw[
"USD"];
2719 Env env{*
this, features};
2721 env.fund(
XRP(10000000), gw);
2725 auto const f = env.current()->fees().base;
2728 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2762 : account(std::move(account_))
2767 , acctGets(acctGets_)
2768 , acctPays(acctPays_)
2770 , spentXrp(spentXrp_)
2771 , finalUsd(finalUsd_)
2774 , takerGets(takerGets_)
2775 , takerPays(takerPays_)
2794 std::move(account_),
2813 TestData
const tests[]{
2816 {
"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},
2817 {
"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)},
2818 {
"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},
2819 {
"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},
2820 {
"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},
2821 {
"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},
2822 {
"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},
2823 {
"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)},
2825 {
"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},
2826 {
"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)},
2827 {
"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},
2828 {
"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},
2829 {
"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},
2830 {
"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)},
2831 {
"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)},
2835 auto const zeroUsd = USD(0);
2836 for (
auto const& t : tests)
2839 env.require(
offers(gw, 0));
2841 auto const acct =
Account(t.account);
2843 env.fund(t.fundXrp, acct);
2849 if (t.fundUSD != zeroUsd)
2851 env(
trust(acct, t.fundUSD));
2853 env(
pay(gw, acct, t.fundUSD));
2857 env(
offer(gw, t.gwGets, t.gwPays));
2867 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2869 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2870 env.require(
offers(acct, t.offers));
2871 env.require(
owners(acct, t.owners));
2876 if (acctOffers.size() > 0)
2878 BEAST_EXPECT(acctOffers.size() == 1);
2879 auto const& acctOffer = *(acctOffers.front());
2881 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2882 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2883 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2900 testcase(
"Combine tfSell with tfFillOrKill");
2902 using namespace jtx;
2904 auto const gw =
Account(
"gateway");
2905 auto const alice =
Account(
"alice");
2906 auto const bob =
Account(
"bob");
2907 auto const USD = gw[
"USD"];
2909 Env env{*
this, features};
2911 env.fund(
XRP(10000000), gw, alice, bob);
2918 env(
trust(bob, USD(200)));
2920 env(
pay(gw, bob, USD(100)));
2922 env(
offer(bob,
XRP(2000), USD(20)));
2930 env.require(
offers(alice, 0));
2931 env.require(
balance(bob, USD(100)));
2938 env.require(
balance(alice, USD(20)));
2939 env.require(
offers(alice, 0));
2940 env.require(
balance(bob, USD(80)));
2945 env(
offer(bob,
XRP(2000), USD(20)));
2949 env.require(
balance(alice, USD(35)));
2950 env.require(
offers(alice, 0));
2951 env.require(
balance(bob, USD(65)));
2963 env.require(
balance(alice, USD(35)));
2964 env.require(
offers(alice, 0));
2965 env.require(
balance(bob, USD(65)));
2974 env.require(
balance(alice, USD(40)));
2975 env.require(
offers(alice, 0));
2976 env.require(
balance(bob, USD(60)));
2985 using namespace jtx;
2987 auto const gw1 =
Account(
"gateway1");
2988 auto const USD = gw1[
"USD"];
2990 Env env{*
this, features};
2993 auto const fee = env.current()->fees().base;
2995 env.fund(
XRP(100000), gw1);
2998 env(
rate(gw1, 1.25));
3000 auto const ann =
Account(
"ann");
3001 auto const bob =
Account(
"bob");
3005 env(
trust(ann, USD(200)));
3006 env(
trust(bob, USD(200)));
3009 env(
pay(gw1, bob, USD(125)));
3024 env.require(
balance(ann, USD(100)));
3026 env.require(
offers(ann, 0));
3028 env.require(
balance(bob, USD(0)));
3030 env.require(
offers(bob, 0));
3035 auto const che =
Account(
"che");
3036 auto const deb =
Account(
"deb");
3040 env(
trust(che, USD(200)));
3041 env(
trust(deb, USD(200)));
3044 env(
pay(gw1, deb, USD(125)));
3053 env.require(
balance(che, USD(100)));
3055 env.require(
offers(che, 0));
3057 env.require(
balance(deb, USD(0)));
3059 env.require(
offers(deb, 0));
3062 auto const eve =
Account(
"eve");
3063 auto const fyn =
Account(
"fyn");
3065 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3068 env(
trust(eve, USD(1000)));
3069 env(
trust(fyn, USD(1000)));
3072 env(
pay(gw1, eve, USD(100)));
3073 env(
pay(gw1, fyn, USD(100)));
3079 env(
offer(eve, USD(10),
XRP(4000)));
3083 env(
offer(fyn,
XRP(2000), USD(5)));
3086 env.require(
balance(eve, USD(105)));
3089 BEAST_EXPECT(evesOffers.size() == 1);
3090 if (evesOffers.size() != 0)
3092 auto const& evesOffer = *(evesOffers.front());
3093 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3094 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3095 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3099 env.require(
balance(fyn, USD(93.75)));
3101 env.require(
offers(fyn, 0));
3104 auto const gw2 =
Account(
"gateway2");
3105 auto const EUR = gw2[
"EUR"];
3107 env.fund(
XRP(100000), gw2);
3110 env(
rate(gw2, 1.5));
3115 auto const gay =
Account(
"gay");
3116 auto const hal =
Account(
"hal");
3117 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3120 env(
trust(gay, USD(200)));
3121 env(
trust(gay, EUR(200)));
3122 env(
trust(hal, USD(200)));
3123 env(
trust(hal, EUR(200)));
3126 env(
pay(gw1, gay, USD(125)));
3127 env(
pay(gw2, hal, EUR(150)));
3130 env(
offer(gay, EUR(100), USD(100)));
3133 env(
offer(hal, USD(100), EUR(100)));
3136 env.require(
balance(gay, USD(0)));
3137 env.require(
balance(gay, EUR(100)));
3139 env.require(
offers(gay, 0));
3141 env.require(
balance(hal, USD(100)));
3142 env.require(
balance(hal, EUR(0)));
3144 env.require(
offers(hal, 0));
3148 auto const ivy =
Account(
"ivy");
3149 auto const joe =
Account(
"joe");
3150 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3159 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3160 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3162 env.require(
balance(ivy, USD(300)));
3163 env.require(
balance(joe, EUR(250)));
3165 env(
offer(ivy, EUR(100), USD(200)));
3168 env(
offer(joe, USD(200), EUR(100)));
3171 env.require(
balance(ivy, USD(50)));
3172 env.require(
balance(ivy, EUR(100)));
3174 env.require(
offers(ivy, 0));
3176 env.require(
balance(joe, USD(200)));
3177 env.require(
balance(joe, EUR(100)));
3179 env.require(
offers(joe, 0));
3183 auto const kim =
Account(
"kim");
3184 auto const K_BUX = kim[
"BUX"];
3185 auto const lex =
Account(
"lex");
3186 auto const meg =
Account(
"meg");
3187 auto const ned =
Account(
"ned");
3188 auto const N_BUX = ned[
"BUX"];
3191 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3194 env(
trust(lex, K_BUX(400)));
3196 env(
trust(meg, N_BUX(100)));
3198 env(
pay(ned, lex, N_BUX(100)));
3200 env.require(
balance(lex, N_BUX(100)));
3202 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3207 env.require(
balance(lex, K_BUX(72)));
3208 env.require(
balance(lex, N_BUX(40)));
3210 env.require(
balance(meg, N_BUX(60)));
3215 env(
offer(lex, K_BUX(30), N_BUX(30)));
3218 env(
offer(kim, N_BUX(30), K_BUX(30)));
3222 env.require(
balance(kim, N_BUX(30)));
3223 env.require(
balance(lex, K_BUX(102)));
3224 env.require(
balance(lex, N_BUX(10)));
3226 env.require(
balance(meg, N_BUX(60)));
3227 env.require(
balance(ned, K_BUX(-30)));
3232 auto const ova =
Account(
"ova");
3233 auto const pat =
Account(
"pat");
3234 auto const qae =
Account(
"qae");
3235 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3241 env(
trust(ova, USD(200)));
3242 env(
trust(ova, EUR(200)));
3243 env(
trust(pat, USD(200)));
3244 env(
trust(pat, EUR(200)));
3245 env(
trust(qae, USD(200)));
3246 env(
trust(qae, EUR(200)));
3249 env(
pay(gw1, ova, USD(125)));
3250 env(
pay(gw2, qae, EUR(150)));
3257 env(
offer(qae, USD(100), EUR(100)));
3260 env.require(
balance(ova, USD(0)));
3261 env.require(
balance(ova, EUR(0)));
3266 if (ovasOffers.size() != 0)
3268 BEAST_EXPECT(ovasOffers.size() == 1);
3269 auto const& ovasOffer = *(ovasOffers.front());
3271 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3272 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3273 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3276 env.require(
balance(pat, USD(0)));
3277 env.require(
balance(pat, EUR(100)));
3279 env.require(
offers(pat, 0));
3281 env.require(
balance(qae, USD(100)));
3282 env.require(
balance(qae, EUR(0)));
3284 env.require(
offers(qae, 0));
3305 using namespace jtx;
3307 auto const gw =
Account(
"gateway");
3308 auto const USD = gw[
"USD"];
3310 Env env{*
this, features};
3313 auto const fee = env.current()->fees().base;
3314 auto const startBalance =
XRP(1000000);
3316 env.fund(startBalance + (
fee * 4), gw);
3326 env.require(
owners(gw, 3));
3327 env.require(
balance(gw, startBalance +
fee));
3330 BEAST_EXPECT(gwOffers.size() == 3);
3331 for (
auto const& offerPtr : gwOffers)
3333 auto const&
offer = *offerPtr;
3334 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3335 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3336 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3341 env(
offer(gw,
XRP(1000), USD(100)));
3343 env.require(
owners(gw, 1));
3344 env.require(
offers(gw, 1));
3345 env.require(
balance(gw, startBalance));
3348 BEAST_EXPECT(gwOffers.size() == 1);
3349 for (
auto const& offerPtr : gwOffers)
3351 auto const&
offer = *offerPtr;
3352 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3353 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3354 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3361 using namespace jtx;
3363 auto const gw1 =
Account(
"gateway1");
3364 auto const gw2 =
Account(
"gateway2");
3365 auto const alice =
Account(
"alice");
3366 auto const USD = gw1[
"USD"];
3367 auto const EUR = gw2[
"EUR"];
3369 Env env{*
this, features};
3371 env.fund(
XRP(1000000), gw1, gw2);
3375 auto const f = env.current()->fees().base;
3389 TestData
const tests[]{
3400 for (
auto const& t : tests)
3402 auto const acct =
Account{t.acct};
3403 env.fund(t.fundXRP, acct);
3406 env(
trust(acct, USD(1000)));
3407 env(
trust(acct, EUR(1000)));
3410 if (t.fundUSD > USD(0))
3411 env(
pay(gw1, acct, t.fundUSD));
3412 if (t.fundEUR > EUR(0))
3413 env(
pay(gw2, acct, t.fundEUR));
3416 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3420 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3421 env.require(
owners(acct, 2 + offerCount));
3422 env.require(
balance(acct, t.fundUSD));
3423 env.require(
balance(acct, t.fundEUR));
3426 BEAST_EXPECT(acctOffers.size() == offerCount);
3427 for (
auto const& offerPtr : acctOffers)
3429 auto const&
offer = *offerPtr;
3430 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3431 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3432 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3435 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3439 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3440 env.require(
owners(acct, 2 + offerCount));
3441 env.require(
balance(acct, t.fundUSD));
3442 env.require(
balance(acct, t.fundEUR));
3445 BEAST_EXPECT(acctOffers.size() == offerCount);
3446 for (
auto const& offerPtr : acctOffers)
3448 auto const&
offer = *offerPtr;
3449 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3450 if (
offer[sfSequence] == firstOfferSeq)
3452 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3453 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3457 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3458 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3485 using namespace jtx;
3487 Env env{*
this, features};
3489 auto const alice =
Account(
"alice");
3490 auto const bob =
Account(
"bob");
3491 auto const USD = bob[
"USD"];
3492 auto const f = env.current()->fees().base;
3494 env.fund(
XRP(50000) + f, alice, bob);
3497 env(
offer(alice, USD(5000),
XRP(50000)));
3501 env(
offer(bob,
XRP(50000), USD(5000)));
3507 env.require(
owners(alice, 1));
3508 env.require(
lines(alice, 1));
3513 BEAST_EXPECT(bobOffers.size() == 1);
3514 for (
auto const& offerPtr : bobOffers)
3516 auto const&
offer = *offerPtr;
3517 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3518 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3519 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3531 using namespace jtx;
3533 Env env{*
this, features};
3536 auto const fee = env.current()->fees().base;
3539 auto const ann =
Account(
"ann");
3540 auto const A_BUX = ann[
"BUX"];
3541 auto const bob =
Account(
"bob");
3542 auto const cam =
Account(
"cam");
3543 auto const dan =
Account(
"dan");
3544 auto const D_BUX = dan[
"BUX"];
3547 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3550 env(
trust(bob, A_BUX(400)));
3552 env(
trust(cam, D_BUX(100)));
3554 env(
pay(dan, bob, D_BUX(100)));
3556 env.require(
balance(bob, D_BUX(100)));
3558 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3563 env.require(
balance(bob, A_BUX(72)));
3564 env.require(
balance(bob, D_BUX(40)));
3566 env.require(
balance(cam, D_BUX(60)));
3570 env(
offer(bob, A_BUX(30), D_BUX(30)));
3573 env(
trust(ann, D_BUX(100)));
3577 env(
pay(ann, ann, D_BUX(30)),
3584 env.require(
balance(ann, D_BUX(0)));
3585 env.require(
balance(bob, A_BUX(72)));
3586 env.require(
balance(bob, D_BUX(40)));
3588 env.require(
balance(cam, D_BUX(60)));
3589 env.require(
balance(dan, A_BUX(0)));
3603 using namespace jtx;
3605 Env env{*
this, features};
3607 auto const ann =
Account(
"ann");
3608 auto const bob =
Account(
"bob");
3609 auto const cam =
Account(
"cam");
3610 auto const A_BUX = ann[
"BUX"];
3611 auto const B_BUX = bob[
"BUX"];
3613 auto const fee = env.current()->fees().base;
3614 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3617 env(
trust(ann, B_BUX(40)));
3618 env(
trust(cam, A_BUX(40)));
3619 env(
trust(cam, B_BUX(40)));
3622 env(
pay(ann, cam, A_BUX(35)));
3623 env(
pay(bob, cam, B_BUX(35)));
3625 env(
offer(bob, A_BUX(30), B_BUX(30)));
3633 env.require(
balance(cam, A_BUX(35)));
3634 env.require(
balance(cam, B_BUX(35)));
3635 env.require(
offers(cam, 1));
3638 env(
offer(cam, B_BUX(30), A_BUX(30)));
3641 env.require(
balance(bob, A_BUX(30)));
3642 env.require(
balance(cam, A_BUX(5)));
3643 env.require(
balance(cam, B_BUX(65)));
3644 env.require(
offers(cam, 0));
3653 testcase(
"Self crossing low quality offer");
3655 using namespace jtx;
3657 Env env{*
this, features};
3659 auto const ann =
Account(
"ann");
3660 auto const gw =
Account(
"gateway");
3661 auto const BTC = gw[
"BTC"];
3663 auto const fee = env.current()->fees().base;
3668 env(
rate(gw, 1.002));
3669 env(
trust(ann, BTC(10)));
3672 env(
pay(gw, ann, BTC(2.856)));
3675 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3679 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3692 using namespace jtx;
3694 Env env{*
this, features};
3696 auto const gw =
Account(
"gateway");
3697 auto const alice =
Account(
"alice");
3698 auto const bob =
Account(
"bob");
3699 auto const CNY = gw[
"CNY"];
3701 auto const fee = env.current()->fees().base;
3706 env(
trust(bob, CNY(500)));
3709 env(
pay(gw, bob, CNY(300)));
3712 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3716 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3720 BEAST_EXPECT(aliceOffers.size() == 1);
3721 for (
auto const& offerPtr : aliceOffers)
3723 auto const&
offer = *offerPtr;
3724 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3725 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3726 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3736 testcase(
"Offer In Scaling With Xfer Rate");
3738 using namespace jtx;
3740 Env env{*
this, features};
3742 auto const gw =
Account(
"gateway");
3743 auto const alice =
Account(
"alice");
3744 auto const bob =
Account(
"bob");
3745 auto const BTC = gw[
"BTC"];
3746 auto const JPY = gw[
"JPY"];
3748 auto const fee = env.current()->fees().base;
3753 env(
rate(gw, 1.002));
3754 env(
trust(alice, JPY(4000)));
3755 env(
trust(bob, BTC(2)));
3758 env(
pay(gw, alice, JPY(3699.034802280317)));
3759 env(
pay(gw, bob, BTC(1.156722559140311)));
3762 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3766 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3770 BEAST_EXPECT(aliceOffers.size() == 1);
3771 for (
auto const& offerPtr : aliceOffers)
3773 auto const&
offer = *offerPtr;
3774 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3776 offer[sfTakerGets] ==
3778 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3788 testcase(
"Offer Threshold With Reduced Funds");
3790 using namespace jtx;
3792 Env env{*
this, features};
3794 auto const gw1 =
Account(
"gw1");
3795 auto const gw2 =
Account(
"gw2");
3796 auto const alice =
Account(
"alice");
3797 auto const bob =
Account(
"bob");
3798 auto const USD = gw1[
"USD"];
3799 auto const JPY = gw2[
"JPY"];
3801 auto const fee = env.current()->fees().base;
3803 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3806 env(
rate(gw1, 1.002));
3807 env(
trust(alice, USD(1000)));
3808 env(
trust(bob, JPY(100000)));
3835 BEAST_EXPECT(aliceOffers.size() == 1);
3836 for (
auto const& offerPtr : aliceOffers)
3838 auto const&
offer = *offerPtr;
3839 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3841 offer[sfTakerGets] ==
3844 offer[sfTakerPays] ==
3854 using namespace jtx;
3856 Env env{*
this, features};
3858 auto const gw =
Account(
"gw");
3859 auto const alice =
Account(
"alice");
3860 auto const bob =
Account(
"bob");
3861 auto const CNY = gw[
"CNY"];
3862 auto const fee = env.current()->fees().base;
3863 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3865 env.fund(startXrpBalance, gw, alice, bob);
3868 env(
trust(bob, CNY(100000)));
3880 STAmount const bobsCnyStartBalance{
3882 env(
pay(gw, bob, bobsCnyStartBalance));
3891 env.require(
balance(alice, alicesCnyOffer));
3893 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
3936 using namespace jtx;
3938 Env env{*
this, features};
3939 auto const baseFee = env.current()->fees().base.drops();
3941 auto const gw =
Account(
"gw");
3942 auto const BTC = gw[
"BTC"];
3943 auto const USD = gw[
"USD"];
3944 auto const startXrpBalance =
XRP(4000000);
3946 env.fund(startXrpBalance, gw);
3949 env(
rate(gw, 1.25));
3975 TestData
const tests[]{
3977 {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)}}},
3978 {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)}}},
3979 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
3980 {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)}}},
3984 for (
auto const& t : tests)
3986 Account const& self = t.actors[t.self].acct;
3987 Account const& leg0 = t.actors[t.leg0].acct;
3988 Account const& leg1 = t.actors[t.leg1].acct;
3990 for (
auto const& actor : t.actors)
3992 env.fund(
XRP(4000000), actor.acct);
3995 env(
trust(actor.acct, BTC(40)));
3996 env(
trust(actor.acct, USD(8000)));
4000 env(
pay(gw, self, t.btcStart));
4001 env(
pay(gw, self, USD(2000)));
4002 if (self.
id() != leg1.
id())
4003 env(
pay(gw, leg1, USD(2000)));
4017 env(
offer(self, USD(1000), BTC(10)));
4022 for (
auto const& actor : t.actors)
4028 actorOffers.begin(),
4030 actorOffers.begin(),
4033 return (*offer)[sfTakerGets].signum() == 0;
4035 BEAST_EXPECT(offerCount == actor.offers);
4037 env.require(
balance(actor.acct, actor.xrp));
4038 env.require(
balance(actor.acct, actor.btc));
4039 env.require(
balance(actor.acct, actor.usd));
4055 testcase(
"Self Pay Unlimited Funds");
4087 using namespace jtx;
4089 Env env{*
this, features};
4090 auto const baseFee = env.current()->fees().base.drops();
4092 auto const gw =
Account(
"gw");
4093 auto const BTC = gw[
"BTC"];
4094 auto const USD = gw[
"USD"];
4095 auto const startXrpBalance =
XRP(4000000);
4097 env.fund(startXrpBalance, gw);
4100 env(
rate(gw, 1.25));
4126 TestData
const tests[]{
4128 {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)}}},
4129 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4133 for (
auto const& t : tests)
4135 Account const& self = t.actors[t.self].acct;
4136 Account const& leg0 = t.actors[t.leg0].acct;
4137 Account const& leg1 = t.actors[t.leg1].acct;
4139 for (
auto const& actor : t.actors)
4141 env.fund(
XRP(4000000), actor.acct);
4144 env(
trust(actor.acct, BTC(40)));
4145 env(
trust(actor.acct, USD(8000)));
4149 env(
pay(gw, self, t.btcStart));
4150 env(
pay(gw, self, USD(2000)));
4151 if (self.
id() != leg1.
id())
4152 env(
pay(gw, leg1, USD(2000)));
4166 env(
offer(self, USD(1000), BTC(10)));
4171 for (
auto const& actor : t.actors)
4177 actorOffers.begin(),
4179 actorOffers.begin(),
4182 return (*offer)[sfTakerGets].signum() == 0;
4184 BEAST_EXPECT(offerCount == actor.offers);
4186 env.require(
balance(actor.acct, actor.xrp));
4187 env.require(
balance(actor.acct, actor.btc));
4188 env.require(
balance(actor.acct, actor.usd));
4206 using namespace jtx;
4208 Env env{*
this, features};
4210 auto const gw =
Account(
"gw");
4211 auto const alice =
Account(
"alice");
4212 auto const bob =
Account(
"bob");
4213 auto const gwUSD = gw[
"USD"];
4214 auto const aliceUSD = alice[
"USD"];
4215 auto const bobUSD = bob[
"USD"];
4217 env.fund(
XRP(400000), gw, alice, bob);
4226 env(
trust(bob, gwUSD(100)));
4228 env(
trust(alice, gwUSD(100)));
4230 env(
offer(alice, gwUSD(40),
XRP(4000)));
4233 env.require(
offers(alice, 1));
4234 env.require(
balance(alice, gwUSD(0)));
4236 env(
pay(gw, bob, gwUSD(50)));
4239 env.require(
balance(bob, gwUSD(50)));
4242 env(
offer(bob,
XRP(4000), gwUSD(40)));
4245 env.require(
offers(alice, 0));
4246 env.require(
balance(alice, gwUSD(40)));
4248 env.require(
offers(bob, 0));
4249 env.require(
balance(bob, gwUSD(10)));
4274 using namespace jtx;
4276 Env env{*
this, features};
4278 auto const gw =
Account(
"gw");
4279 auto const alice =
Account(
"alice");
4280 auto const bob =
Account(
"bob");
4281 auto const gwUSD = gw[
"USD"];
4282 auto const aliceUSD = alice[
"USD"];
4283 auto const bobUSD = bob[
"USD"];
4285 env.fund(
XRP(400000), gw, alice, bob);
4288 env(
offer(alice, gwUSD(40),
XRP(4000)));
4291 env.require(
offers(alice, 1));
4298 env(
trust(bob, gwUSD(100)));
4301 env(
pay(gw, bob, gwUSD(50)));
4303 env.require(
balance(bob, gwUSD(50)));
4310 env(
offer(bob,
XRP(4000), gwUSD(40)));
4314 env.require(
offers(alice, 0));
4317 env.require(
offers(bob, 1));
4318 env.require(
balance(bob, gwUSD(50)));
4326 env.require(
offers(alice, 0));
4329 env.require(
offers(bob, 1));
4330 env.require(
balance(bob, gwUSD(50)));
4334 env(
trust(gw, aliceUSD(100)));
4340 env.require(
offers(alice, 0));
4341 env.require(
balance(alice, gwUSD(0)));
4343 env.require(
offers(bob, 1));
4344 env.require(
balance(bob, gwUSD(50)));
4349 env.require(
offers(bob, 0));
4357 env(
offer(alice, gwUSD(40),
XRP(4000)));
4360 env.require(
offers(alice, 1));
4363 env(
offer(bob,
XRP(4000), gwUSD(40)));
4366 env.require(
offers(alice, 0));
4367 env.require(
balance(alice, gwUSD(40)));
4369 env.require(
offers(bob, 0));
4370 env.require(
balance(bob, gwUSD(10)));
4376 testcase(
"RippleConnect Smoketest payment flow");
4377 using namespace jtx;
4379 Env env{*
this, features};
4389 auto const hotUS =
Account(
"hotUS");
4390 auto const coldUS =
Account(
"coldUS");
4391 auto const hotEU =
Account(
"hotEU");
4392 auto const coldEU =
Account(
"coldEU");
4393 auto const mm =
Account(
"mm");
4395 auto const USD = coldUS[
"USD"];
4396 auto const EUR = coldEU[
"EUR"];
4398 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4402 for (
auto const& cold : {coldUS, coldEU})
4425 env(
pay(coldUS, hotUS, USD(5000000)));
4426 env(
pay(coldEU, hotEU, EUR(5000000)));
4427 env(
pay(coldUS, mm, USD(5000000)));
4428 env(
pay(coldEU, mm, EUR(5000000)));
4432 float const rate = 0.9f;
4433 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4436 float const reverseRate = 1.0f /
rate * 1.00101f;
4437 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4444 jvParams[jss::destination_account] = coldEU.human();
4445 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4446 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4447 jvParams[jss::destination_amount][jss::value] = 10;
4448 jvParams[jss::source_account] = hotUS.human();
4451 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4453 BEAST_EXPECT(jrr[jss::status] ==
"success");
4455 jrr[jss::alternatives].isArray() &&
4456 jrr[jss::alternatives].size() > 0);
4459 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4467 using namespace jtx;
4469 Env env{*
this, features};
4471 auto const gw =
Account(
"gw");
4472 auto const alice =
Account(
"alice");
4473 auto const gwUSD = gw[
"USD"];
4474 auto const aliceUSD = alice[
"USD"];
4476 env.fund(
XRP(400000), gw, alice);
4480 env(
offer(gw, gwUSD(40),
XRP(4000)));
4483 env.require(
offers(gw, 1));
4492 env.require(
offers(gw, 0));
4504 env.require(
offers(gw, 1));
4508 env(
trust(alice, gwUSD(100)));
4511 env(
pay(gw, alice, gwUSD(50)));
4514 env.require(
balance(alice, gwUSD(50)));
4517 env(
offer(alice,
XRP(4000), gwUSD(40)));
4520 env.require(
offers(alice, 0));
4521 env.require(
balance(alice, gwUSD(10)));
4523 env.require(
offers(gw, 0));
4530 using namespace jtx;
4534 auto trustLineExists = [](
jtx::Env const& env,
4545 auto const USD = gw[
"USD"];
4546 auto const BUX = alice[
"BUX"];
4548 Env env{*
this, features};
4552 env.
trust(USD(1000), becky);
4553 env(
pay(gw, becky, USD(5)));
4555 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4566 env(
pay(becky, gw, USD(5)));
4567 env.
trust(USD(0), becky);
4569 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4570 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4571 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4578 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4580 if (gwSeq + 255 > openLedgerSeq)
4581 return gwSeq - openLedgerSeq + 255;
4585 for (
int i = 0; i < delta; ++i)
4602 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4603 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4609 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4610 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4615 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4619 env.
trust(BUX(1000), carol);
4620 env(
pay(alice, carol, BUX(2)));
4629 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4630 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4638 using namespace jtx;
4642 Env env{*
this, features};
4643 auto const gw =
Account{
"gateway"};
4644 env.fund(
XRP(10000), gw);
4647 auto txn =
noop(gw);
4648 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4651 txn[sfTickSize.fieldName] = Quality::minTickSize;
4653 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4656 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4658 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4661 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4663 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4666 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4669 txn[sfTickSize.fieldName] = 0;
4671 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4674 Env env{*
this, features};
4675 auto const gw =
Account{
"gateway"};
4676 auto const alice =
Account{
"alice"};
4677 auto const XTS = gw[
"XTS"];
4678 auto const XXX = gw[
"XXX"];
4680 env.fund(
XRP(10000), gw, alice);
4685 auto txn =
noop(gw);
4686 txn[sfTickSize.fieldName] = 5;
4688 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4691 env(
trust(alice, XTS(1000)));
4692 env(
trust(alice, XXX(1000)));
4694 env(
pay(gw, alice, alice[
"XTS"](100)));
4695 env(
pay(gw, alice, alice[
"XXX"](100)));
4697 env(
offer(alice, XTS(10), XXX(30)));
4698 env(
offer(alice, XTS(30), XXX(10)));
4705 if (sle->getType() == ltOFFER)
4709 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4713 auto it =
offers.begin();
4714 BEAST_EXPECT(it !=
offers.end());
4716 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4717 it->second.second > XXX(29.9994));
4721 BEAST_EXPECT(it !=
offers.end());
4723 it->second.first == XTS(30) && it->second.second == XXX(10));
4727 BEAST_EXPECT(it !=
offers.end());
4729 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4734 BEAST_EXPECT(it !=
offers.end());
4736 it->second.first == XTS(30) && it->second.second == XXX(10));
4738 BEAST_EXPECT(++it ==
offers.end());
4752 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4762 using namespace jtx;
4770 Env env{*
this, features};
4771 auto const gw =
Account{
"gateway"};
4772 auto const alice =
Account{
"alice"};
4773 auto const bob =
Account{
"bob"};
4774 auto const USD = gw[
"USD"];
4776 env.fund(
XRP(10000), gw, alice, bob);
4779 env(
trust(alice, USD(1000)));
4780 env(
trust(bob, USD(1000)));
4783 env(
pay(gw, alice, USD(200)));
4790 env(
offer(alice,
XRP(50), USD(50)));
4800 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4801 env(
offer(alice,
XRP(50), USD(50)));
4817 BEAST_EXPECT(
offers.size() == 4);
4818 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4819 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4820 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4821 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4822 env.require(
balance(alice, USD(200)));
4823 env.require(
owners(alice, 5));
4833 BEAST_EXPECT(
offers.size() == 3);
4834 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4835 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4836 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4846 BEAST_EXPECT(
offers.size() == 2);
4847 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4848 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4858 BEAST_EXPECT(
offers.size() == 1);
4859 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4869 BEAST_EXPECT(
offers.size() == 0);
4871 env.require(
balance(alice, USD(0)));
4872 env.require(
owners(alice, 1));
4873 env.require(
balance(bob, USD(200)));
4874 env.require(
owners(bob, 1));
4882 using namespace jtx;
4886 Env env{*
this, features};
4887 auto const gw =
Account{
"gateway"};
4888 auto const alice =
Account{
"alice"};
4889 auto const USD = gw[
"USD"];
4891 env.fund(
XRP(10000), gw, alice);
4894 env(
trust(alice, USD(1000)));
4898 env(
pay(gw, alice, USD(200)));
4903 env(
offer(alice,
XRP(50), USD(50)));
4915 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
4916 env(
offer(alice,
XRP(50), USD(50)));
4932 BEAST_EXPECT(
offers.size() == 4);
4933 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
4934 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
4935 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
4936 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
4937 env.require(
balance(alice, USD(200)));
4938 env.require(
owners(alice, 7));
4948 BEAST_EXPECT(
offers.size() == 3);
4949 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
4950 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
4951 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
4961 BEAST_EXPECT(
offers.size() == 2);
4962 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
4963 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
4976 BEAST_EXPECT(
offers.size() == 1);
4977 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
4994 testcase(
"incorrect assert fixed");
4995 using namespace jtx;
4998 auto const alice =
Account(
"alice");
4999 auto const USD = alice[
"USD"];
5001 env.fund(
XRP(10000), alice);
5003 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5011 using namespace jtx;
5012 Env env(*
this, features);
5013 Account const issuer(
"issuer");
5016 auto const USD = issuer[
"USD"];
5017 auto const EUR = issuer[
"EUR"];
5020 env.
fund(
XRP(1'000), maker, taker);
5023 env.
trust(USD(1'000), maker, taker);
5024 env.
trust(EUR(1'000), maker, taker);
5027 env(
pay(issuer, maker, USD(1'000)));
5028 env(
pay(issuer, taker, USD(1'000)));
5029 env(
pay(issuer, maker, EUR(1'000)));
5032 auto makerUSDBalance = env.
balance(maker, USD).
value();
5033 auto takerUSDBalance = env.
balance(taker, USD).
value();
5034 auto makerEURBalance = env.
balance(maker, EUR).
value();
5035 auto takerEURBalance = env.
balance(taker, EUR).
value();
5044 env(
offer(maker,
XRP(100), USD(100)));
5047 env(
offer(taker, USD(100),
XRP(101)),
5052 makerXRPBalance -=
txfee(env, 1);
5053 takerXRPBalance -=
txfee(env, 1);
5056 makerUSDBalance -= USD(100);
5057 takerUSDBalance += USD(100);
5058 makerXRPBalance +=
XRP(100).value();
5059 takerXRPBalance -=
XRP(100).value();
5063 env(
offer(maker, USD(100),
XRP(100)));
5066 env(
offer(taker,
XRP(100), USD(101)),
5071 makerXRPBalance -=
txfee(env, 1);
5072 takerXRPBalance -=
txfee(env, 1);
5075 makerUSDBalance += USD(100);
5076 takerUSDBalance -= USD(100);
5077 makerXRPBalance -=
XRP(100).value();
5078 takerXRPBalance +=
XRP(100).value();
5082 env(
offer(maker, USD(100), EUR(100)));
5085 env(
offer(taker, EUR(100), USD(101)),
5090 makerXRPBalance -=
txfee(env, 1);
5091 takerXRPBalance -=
txfee(env, 1);
5094 makerUSDBalance += USD(100);
5095 takerUSDBalance -= USD(100);
5096 makerEURBalance -= EUR(100);
5097 takerEURBalance += EUR(100);
5104 env(
offer(maker,
XRP(101), USD(101)));
5107 env(
offer(taker, USD(100),
XRP(101)),
5111 makerUSDBalance -= USD(101);
5112 takerUSDBalance += USD(101);
5113 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5114 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5117 env(
offer(maker, USD(101),
XRP(101)));
5120 env(
offer(taker,
XRP(100), USD(101)),
5124 makerUSDBalance += USD(101);
5125 takerUSDBalance -= USD(101);
5126 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5127 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5130 env(
offer(maker, USD(101), EUR(101)));
5133 env(
offer(taker, EUR(100), USD(101)),
5137 makerUSDBalance += USD(101);
5138 takerUSDBalance -= USD(101);
5139 makerEURBalance -= EUR(101);
5140 takerEURBalance += EUR(101);
5141 makerXRPBalance -=
txfee(env, 1);
5142 takerXRPBalance -=
txfee(env, 1);
5149 env(
offer(maker,
XRP(100), USD(100)));
5152 env(
offer(taker, USD(100),
XRP(99)),
5157 makerXRPBalance -=
txfee(env, 1);
5158 takerXRPBalance -=
txfee(env, 1);
5161 env(
offer(maker, USD(100),
XRP(100)));
5164 env(
offer(taker,
XRP(100), USD(99)),
5169 makerXRPBalance -=
txfee(env, 1);
5170 takerXRPBalance -=
txfee(env, 1);
5173 env(
offer(maker, USD(100), EUR(100)));
5176 env(
offer(taker, EUR(100), USD(99)),
5181 makerXRPBalance -=
txfee(env, 1);
5182 takerXRPBalance -=
txfee(env, 1);
5187 env.
balance(maker, USD) == makerUSDBalance &&
5188 env.
balance(taker, USD) == takerUSDBalance &&
5189 env.
balance(maker, EUR) == makerEURBalance &&
5190 env.
balance(taker, EUR) == takerEURBalance &&
5191 env.
balance(maker,
XRP) == makerXRPBalance &&
5292 using namespace jtx;
5303BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app,
xrpl, 2);
5304BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app,
xrpl, 2);
5305BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app,
xrpl, 2);
5306BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app,
xrpl, 20);
void pass()
Record a successful test condition.
testcase_t testcase
Memberspace for declaring test cases.
A currency issued by an account.
Issue const & issue() const
std::string getText() const override
void run() override
Runs the suite.
static std::vector< std::shared_ptr< SLE const > > sortedOffersOnAccount(jtx::Env &env, jtx::Account const &acct)
void testRequireAuth(FeatureBitset features)
void testCrossCurrencyEndXRP(FeatureBitset features)
void testXRPDirectCross(FeatureBitset features)
void testNegativeBalance(FeatureBitset features)
void testGatewayCrossCurrency(FeatureBitset features)
void testXRPTinyPayment(FeatureBitset features)
void testTicketOffer(FeatureBitset features)
void testCurrencyConversionIntoDebt(FeatureBitset features)
void testCanceledOffer(FeatureBitset features)
void testDirectToDirectPath(FeatureBitset features)
void testMissingAuth(FeatureBitset features)
void run() override
Runs the suite.
XRPAmount reserve(jtx::Env &env, std::uint32_t count)
void testCrossCurrencyStartXRP(FeatureBitset features)
void testRmFundedOffer(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > offersOnAccount(jtx::Env &env, jtx::Account account)
void testSelfCrossOffer1(FeatureBitset features)
void testSellWithFillOrKill(FeatureBitset features)
void testRCSmoketest(FeatureBitset features)
void testAll(FeatureBitset features)
void testSellOffer(FeatureBitset features)
void testOfferFeesConsumeFunds(FeatureBitset features)
void testSellFlagBasic(FeatureBitset features)
void testTinyOffer(FeatureBitset features)
void testSelfCrossOffer(FeatureBitset features)
void testSelfCrossLowQualityOffer(FeatureBitset features)
void testRmSmallIncreasedQOffersXRP(FeatureBitset features)
void verifyDefaultTrustline(jtx::Env &env, jtx::Account const &account, jtx::PrettyAmount const &expectBalance)
void testFillModes(FeatureBitset features)
void testTicketCancelOffer(FeatureBitset features)
void testTickSize(FeatureBitset features)
static auto getBookOffers(jtx::Env &env, Issue const &taker_pays, Issue const &taker_gets)
void testOfferAcceptThenCancel(FeatureBitset features)
void testExpiration(FeatureBitset features)
void testRmSmallIncreasedQOffersIOU(FeatureBitset features)
void testSelfPayUnlimitedFunds(FeatureBitset features)
void testMalformed(FeatureBitset features)
void testDeletedOfferIssuer(FeatureBitset features)
void testOfferCreateThenCross(FeatureBitset features)
void testTinyPayment(FeatureBitset features)
void testSellFlagExceedLimit(FeatureBitset features)
void testTransferRateOffer(FeatureBitset features)
void testOfferThresholdWithReducedFunds(FeatureBitset features)
void testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
std::uint32_t lastClose(jtx::Env &env)
void testInsufficientReserve(FeatureBitset features)
void testCrossCurrencyBridged(FeatureBitset features)
void testUnfundedCross(FeatureBitset features)
void testBridgedSecondLegDry(FeatureBitset features)
void testBadPathAssert(FeatureBitset features)
void testOfferInScalingWithXferRate(FeatureBitset features)
void testOfferCrossWithLimitOverride(FeatureBitset features)
void testSelfPayXferFeeOffer(FeatureBitset features)
void testSelfAuth(FeatureBitset features)
FeatureBitset const allFeatures
void testSelfIssueOffer(FeatureBitset features)
void testPartialCross(FeatureBitset features)
void testBridgedCross(FeatureBitset features)
void testCurrencyConversionEntire(FeatureBitset features)
void testCurrencyConversionInParts(FeatureBitset features)
void testSelfCrossOffer2(FeatureBitset features)
void testOfferInScaling(FeatureBitset features)
static auto ledgerEntryOffer(jtx::Env &env, jtx::Account const &acct, std::uint32_t offer_seq)
void testOfferCancelPastAndFuture(FeatureBitset features)
void testFillOrKill(FeatureBitset features)
void testDirectCross(FeatureBitset features)
void testSelfCross(bool use_partner, FeatureBitset features)
void testEnforceNoRipple(FeatureBitset features)
void run() override
Runs the suite.
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
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 require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
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.
PrettyAmount xrpMinusFee(Env const &env, std::int64_t xrpAmount)
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
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.
XRPAmount txfee(Env const &env, std::uint16_t n)
XRP_t const XRP
Converts to XRP Issue or STAmount.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value ledgerEntryRoot(Env &env, Account const &acct)
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
FeatureBitset testable_amendments()
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
owner_count< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
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.
bool isOffer(jtx::Env &env, jtx::Account const &account, STAmount const &takerPays, STAmount const &takerGets)
An offer exists.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t tfSell
constexpr std::uint32_t tfPassive
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr std::uint32_t tfImmediateOrCancel
constexpr std::uint32_t tfFillOrKill
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfSetNoRipple
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.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
constexpr std::uint32_t asfDefaultRipple
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfNoRippleDirect
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t asfRequireAuth
constexpr std::uint32_t tfPartialPayment
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
STAmount const & value() const