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);
1349 BEAST_EXPECT(acctOffers.size() == 0);
1350 for (
auto const& offerPtr : acctOffers)
1352 auto const&
offer = *offerPtr;
1353 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1354 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1355 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1363 env.require(
offers(account_to_test, 0));
1368 env(
offer(account_to_test, BTC(250), USD(50)));
1369 env.require(
offers(account_to_test, 1));
1373 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1376 BEAST_EXPECT(jrr[jss::offers].isArray());
1377 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1381 env(
offer(account_to_test, USD(50), BTC(250)));
1382 env.require(
offers(account_to_test, 1));
1387 BEAST_EXPECT(jrr[jss::offers].isArray());
1388 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1390 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1400 using namespace jtx;
1405 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1407 Env env{*
this, localFeatures};
1409 auto const gw =
Account{
"gateway"};
1410 auto const alice =
Account{
"alice"};
1411 auto const bob =
Account{
"bob"};
1412 auto const USD = gw[
"USD"];
1413 auto const BTC = gw[
"BTC"];
1417 auto const gw_initial_balance =
drops(1149999730);
1418 auto const alice_initial_balance =
drops(499946999680);
1419 auto const bob_initial_balance =
drops(10199999920);
1420 auto const small_amount =
1421 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1423 env.fund(gw_initial_balance, gw);
1424 env.fund(alice_initial_balance, alice);
1425 env.fund(bob_initial_balance, bob);
1428 env(
rate(gw, 1.005));
1430 env(
trust(alice, USD(500)));
1431 env(
trust(bob, USD(50)));
1432 env(
trust(gw, alice[
"USD"](100)));
1434 env(
pay(gw, alice, alice[
"USD"](50)));
1435 env(
pay(gw, bob, small_amount));
1437 env(
offer(alice, USD(50),
XRP(150000)));
1440 env(
pay(alice, gw, USD(100)));
1443 env(
trust(gw, alice[
"USD"](0)));
1448 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1452 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1453 "-2710505431213761e-33");
1457 env(
offer(bob,
XRP(2000), USD(1)));
1459 if (localFeatures[fixReducedOffersV2])
1466 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1467 "-2710505431213761e-33");
1471 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1472 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1483 auto const crossingDelta =
drops(1);
1487 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1490 alice_initial_balance - env.current()->fees().base * 3 -
1495 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1498 bob_initial_balance - env.current()->fees().base * 2 +
1508 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1510 using namespace jtx;
1512 Env env{*
this, features};
1514 auto const gw =
Account{
"gateway"};
1515 auto const alice =
Account{
"alice"};
1516 auto const bob =
Account{
"bob"};
1517 auto const USD = gw[
"USD"];
1519 env.fund(
XRP(10000), gw, alice, bob);
1522 env(
trust(alice, USD(1000)));
1523 env(
trust(bob, USD(1000)));
1525 env(
pay(gw, alice, alice[
"USD"](500)));
1528 env(
offer(bob, USD(1),
XRP(4000)));
1530 env(
offer(alice,
XRP(150000), USD(50)));
1533 env(
offer(bob, USD(1),
XRP(4000)));
1540 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1543 jrr[jss::node][sfBalance.fieldName] ==
1545 env.current()->fees().base * 2)
1549 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1552 jrr[jss::node][sfBalance.fieldName] ==
1554 env.current()->fees().base * 2)
1561 testcase(
"Offer Crossing with Limit Override");
1563 using namespace jtx;
1565 Env env{*
this, features};
1567 auto const gw =
Account{
"gateway"};
1568 auto const alice =
Account{
"alice"};
1569 auto const bob =
Account{
"bob"};
1570 auto const USD = gw[
"USD"];
1572 env.fund(
XRP(100000), gw, alice, bob);
1575 env(
trust(alice, USD(1000)));
1577 env(
pay(gw, alice, alice[
"USD"](500)));
1579 env(
offer(alice,
XRP(150000), USD(50)));
1580 env(
offer(bob, USD(1),
XRP(3000)));
1583 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1586 jrr[jss::node][sfBalance.fieldName] ==
1591 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1594 jrr[jss::node][sfBalance.fieldName] ==
1602 testcase(
"Offer Accept then Cancel.");
1604 using namespace jtx;
1606 Env env{*
this, features};
1608 auto const USD = env.master[
"USD"];
1610 auto const nextOfferSeq = env.seq(env.master);
1611 env(
offer(env.master,
XRP(500), USD(100)));
1615 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1620 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1626 testcase(
"Offer Cancel Past and Future Sequence.");
1628 using namespace jtx;
1630 Env env{*
this, features};
1632 auto const alice =
Account{
"alice"};
1634 auto const nextOfferSeq = env.seq(env.master);
1635 env.fund(
XRP(10000), alice);
1652 testcase(
"Currency Conversion: Entire Offer");
1654 using namespace jtx;
1656 Env env{*
this, features};
1658 auto const gw =
Account{
"gateway"};
1659 auto const alice =
Account{
"alice"};
1660 auto const bob =
Account{
"bob"};
1661 auto const USD = gw[
"USD"];
1663 env.fund(
XRP(10000), gw, alice, bob);
1665 env.require(
owners(bob, 0));
1667 env(
trust(alice, USD(100)));
1668 env(
trust(bob, USD(1000)));
1672 env(
pay(gw, alice, alice[
"USD"](100)));
1673 auto const bobOfferSeq = env.seq(bob);
1674 env(
offer(bob, USD(100),
XRP(500)));
1679 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1681 jro[jss::node][jss::TakerPays] ==
1687 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1690 jrr[jss::node][sfBalance.fieldName] ==
1695 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1698 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1706 testcase(
"Currency Conversion: Offerer Into Debt");
1708 using namespace jtx;
1710 Env env{*
this, features};
1712 auto const alice =
Account{
"alice"};
1713 auto const bob =
Account{
"bob"};
1714 auto const carol =
Account{
"carol"};
1716 env.fund(
XRP(10000), alice, bob, carol);
1719 env(
trust(alice, carol[
"EUR"](2000)));
1720 env(
trust(bob, alice[
"USD"](100)));
1721 env(
trust(carol, bob[
"EUR"](1000)));
1723 auto const bobOfferSeq = env.seq(bob);
1724 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1727 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1730 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1736 testcase(
"Currency Conversion: In Parts");
1738 using namespace jtx;
1740 Env env{*
this, features};
1742 auto const gw =
Account{
"gateway"};
1743 auto const alice =
Account{
"alice"};
1744 auto const bob =
Account{
"bob"};
1745 auto const USD = gw[
"USD"];
1747 env.fund(
XRP(10000), gw, alice, bob);
1750 env(
trust(alice, USD(200)));
1751 env(
trust(bob, USD(1000)));
1753 env(
pay(gw, alice, alice[
"USD"](200)));
1755 auto const bobOfferSeq = env.seq(bob);
1756 env(
offer(bob, USD(100),
XRP(500)));
1763 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1765 jro[jss::node][jss::TakerPays] ==
1771 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1775 jrr[jss::node][sfBalance.fieldName] ==
1781 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1785 env(
pay(alice, alice,
XRP(600)),
1791 env(
pay(alice, alice,
XRP(600)),
1797 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1805 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1808 jrr[jss::node][sfBalance.fieldName] ==
1810 env.current()->fees().base * 4)
1816 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1822 testcase(
"Cross Currency Payment: Start with XRP");
1824 using namespace jtx;
1826 Env env{*
this, features};
1828 auto const gw =
Account{
"gateway"};
1829 auto const alice =
Account{
"alice"};
1830 auto const bob =
Account{
"bob"};
1831 auto const carol =
Account{
"carol"};
1832 auto const USD = gw[
"USD"];
1834 env.fund(
XRP(10000), gw, alice, bob, carol);
1837 env(
trust(carol, USD(1000)));
1838 env(
trust(bob, USD(2000)));
1840 env(
pay(gw, carol, carol[
"USD"](500)));
1842 auto const carolOfferSeq = env.seq(carol);
1843 env(
offer(carol,
XRP(500), USD(50)));
1848 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1851 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1855 jro[jss::node][jss::TakerGets] ==
1858 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1864 testcase(
"Cross Currency Payment: End with XRP");
1866 using namespace jtx;
1868 Env env{*
this, features};
1870 auto const gw =
Account{
"gateway"};
1871 auto const alice =
Account{
"alice"};
1872 auto const bob =
Account{
"bob"};
1873 auto const carol =
Account{
"carol"};
1874 auto const USD = gw[
"USD"];
1876 env.fund(
XRP(10000), gw, alice, bob, carol);
1879 env(
trust(alice, USD(1000)));
1880 env(
trust(carol, USD(2000)));
1882 env(
pay(gw, alice, alice[
"USD"](500)));
1884 auto const carolOfferSeq = env.seq(carol);
1885 env(
offer(carol, USD(50),
XRP(500)));
1890 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1893 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1897 jrr[jss::node][sfBalance.fieldName] ==
1899 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1903 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1905 jro[jss::node][jss::TakerPays] ==
1912 testcase(
"Cross Currency Payment: Bridged");
1914 using namespace jtx;
1916 Env env{*
this, features};
1918 auto const gw1 =
Account{
"gateway_1"};
1919 auto const gw2 =
Account{
"gateway_2"};
1920 auto const alice =
Account{
"alice"};
1921 auto const bob =
Account{
"bob"};
1922 auto const carol =
Account{
"carol"};
1923 auto const dan =
Account{
"dan"};
1924 auto const USD = gw1[
"USD"];
1925 auto const EUR = gw2[
"EUR"];
1927 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1930 env(
trust(alice, USD(1000)));
1931 env(
trust(bob, EUR(1000)));
1932 env(
trust(carol, USD(1000)));
1933 env(
trust(dan, EUR(1000)));
1935 env(
pay(gw1, alice, alice[
"USD"](500)));
1936 env(
pay(gw2, dan, dan[
"EUR"](400)));
1938 auto const carolOfferSeq = env.seq(carol);
1939 env(
offer(carol, USD(50),
XRP(500)));
1941 auto const danOfferSeq = env.seq(dan);
1942 env(
offer(dan,
XRP(500), EUR(50)));
1945 jtp[0u][0u][jss::currency] =
"XRP";
1946 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1949 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1952 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1955 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1958 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1962 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1964 jro[jss::node][jss::TakerPays] ==
1969 jro[jss::node][jss::TakerGets] ==
1972 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1981 testcase(
"Auto Bridged Second Leg Dry");
1983 using namespace jtx;
1984 Env env(*
this, features);
1990 auto const USD = gw[
"USD"];
1991 auto const EUR = gw[
"EUR"];
1993 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1996 env.
trust(USD(10), alice);
1998 env(
pay(gw, alice, USD(10)));
1999 env.
trust(USD(10), carol);
2001 env(
pay(gw, carol, USD(3)));
2018 env.
trust(EUR(10), bob);
2020 env(
pay(gw, bob, EUR(10)));
2022 env(
offer(bob, USD(10), EUR(10)));
2045 testcase(
"Offer Fees Consume Funds");
2047 using namespace jtx;
2049 Env env{*
this, features};
2051 auto const gw1 =
Account{
"gateway_1"};
2052 auto const gw2 =
Account{
"gateway_2"};
2053 auto const gw3 =
Account{
"gateway_3"};
2054 auto const alice =
Account{
"alice"};
2055 auto const bob =
Account{
"bob"};
2056 auto const USD1 = gw1[
"USD"];
2057 auto const USD2 = gw2[
"USD"];
2058 auto const USD3 = gw3[
"USD"];
2066 auto const starting_xrp =
XRP(100) +
2067 env.current()->fees().accountReserve(3) +
2068 env.current()->fees().base * 4;
2070 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2073 env(
trust(alice, USD1(1000)));
2074 env(
trust(alice, USD2(1000)));
2075 env(
trust(alice, USD3(1000)));
2076 env(
trust(bob, USD1(1000)));
2077 env(
trust(bob, USD2(1000)));
2079 env(
pay(gw1, bob, bob[
"USD"](500)));
2081 env(
offer(bob,
XRP(200), USD1(200)));
2084 env(
offer(alice, USD1(200),
XRP(200)));
2087 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2090 jrr[jss::node][sfBalance.fieldName] ==
2094 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2100 testcase(
"Offer Create, then Cross");
2102 using namespace jtx;
2104 for (
auto NumberSwitchOver : {
false,
true})
2106 Env env{*
this, features};
2107 if (NumberSwitchOver)
2108 env.enableFeature(fixUniversalNumber);
2110 env.disableFeature(fixUniversalNumber);
2112 auto const gw =
Account{
"gateway"};
2113 auto const alice =
Account{
"alice"};
2114 auto const bob =
Account{
"bob"};
2115 auto const USD = gw[
"USD"];
2117 env.fund(
XRP(10000), gw, alice, bob);
2120 env(
rate(gw, 1.005));
2122 env(
trust(alice, USD(1000)));
2123 env(
trust(bob, USD(1000)));
2124 env(
trust(gw, alice[
"USD"](50)));
2126 env(
pay(gw, bob, bob[
"USD"](1)));
2127 env(
pay(alice, gw, USD(50)));
2129 env(
trust(gw, alice[
"USD"](0)));
2131 env(
offer(alice, USD(50),
XRP(150000)));
2132 env(
offer(bob,
XRP(100), USD(0.1)));
2136 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2137 "49.96666666666667");
2141 jrr[jss::node][sfBalance.fieldName][jss::value];
2142 if (!NumberSwitchOver)
2144 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2148 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2156 testcase(
"Offer tfSell: Basic Sell");
2158 using namespace jtx;
2160 Env env{*
this, features};
2162 auto const gw =
Account{
"gateway"};
2163 auto const alice =
Account{
"alice"};
2164 auto const bob =
Account{
"bob"};
2165 auto const USD = gw[
"USD"];
2167 auto const starting_xrp =
XRP(100) +
2168 env.current()->fees().accountReserve(1) +
2169 env.current()->fees().base * 2;
2171 env.fund(starting_xrp, gw, alice, bob);
2174 env(
trust(alice, USD(1000)));
2175 env(
trust(bob, USD(1000)));
2177 env(
pay(gw, bob, bob[
"USD"](500)));
2186 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2189 jrr[jss::node][sfBalance.fieldName] ==
2193 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2199 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2201 using namespace jtx;
2203 Env env{*
this, features};
2205 auto const gw =
Account{
"gateway"};
2206 auto const alice =
Account{
"alice"};
2207 auto const bob =
Account{
"bob"};
2208 auto const USD = gw[
"USD"];
2210 auto const starting_xrp =
XRP(100) +
2211 env.current()->fees().accountReserve(1) +
2212 env.current()->fees().base * 2;
2214 env.fund(starting_xrp, gw, alice, bob);
2217 env(
trust(alice, USD(150)));
2218 env(
trust(bob, USD(1000)));
2220 env(
pay(gw, bob, bob[
"USD"](500)));
2222 env(
offer(bob,
XRP(100), USD(200)));
2231 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2234 jrr[jss::node][sfBalance.fieldName] ==
2238 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2244 testcase(
"Client Issue #535: Gateway Cross Currency");
2246 using namespace jtx;
2248 Env env{*
this, features};
2250 auto const gw =
Account{
"gateway"};
2251 auto const alice =
Account{
"alice"};
2252 auto const bob =
Account{
"bob"};
2253 auto const XTS = gw[
"XTS"];
2254 auto const XXX = gw[
"XXX"];
2256 auto const starting_xrp =
XRP(100.1) +
2257 env.current()->fees().accountReserve(1) +
2258 env.current()->fees().base * 2;
2260 env.fund(starting_xrp, gw, alice, bob);
2263 env(
trust(alice, XTS(1000)));
2264 env(
trust(alice, XXX(1000)));
2265 env(
trust(bob, XTS(1000)));
2266 env(
trust(bob, XXX(1000)));
2268 env(
pay(gw, alice, alice[
"XTS"](100)));
2269 env(
pay(gw, alice, alice[
"XXX"](100)));
2270 env(
pay(gw, bob, bob[
"XTS"](100)));
2271 env(
pay(gw, bob, bob[
"XXX"](100)));
2273 env(
offer(alice, XTS(100), XXX(100)));
2280 payment[jss::id] = env.seq(bob);
2281 payment[jss::build_path] =
true;
2282 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2283 payment[jss::tx_json][jss::Sequence] =
2286 ->getFieldU32(sfSequence);
2287 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2288 payment[jss::tx_json][jss::SendMax] =
2290 auto jrr = wsc->invoke(
"submit", payment);
2291 BEAST_EXPECT(jrr[jss::status] ==
"success");
2292 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2293 if (wsc->version() == 2)
2296 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2298 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2299 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2303 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2305 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2308 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2310 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2325 auto const sleTrust =
2327 BEAST_EXPECT(sleTrust);
2331 bool const accountLow = account.id() < issue.
account;
2336 low.setIssuer(accountLow ? account.id() : issue.
account);
2337 high.setIssuer(accountLow ? issue.
account : account.id());
2339 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2340 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2342 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2346 BEAST_EXPECT(actualBalance == expectBalance);
2358 using namespace jtx;
2360 auto const gw =
Account(
"gateway");
2361 auto const USD = gw[
"USD"];
2363 Env env{*
this, features};
2365 env.fund(
XRP(10000000), gw);
2369 auto const f = env.current()->fees().base;
2372 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2378 preTrustType preTrust;
2388 TestData
const tests[]{
2390 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2391 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2392 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2393 {
"deb",
drops(10) +
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 1},
2394 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2395 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2396 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2397 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2398 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2399 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2400 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2401 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2402 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2403 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2404 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2405 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2406 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2407 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2409 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2410 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2411 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2412 {
"dan",
drops(10) +
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 0},
2413 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2414 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2415 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2416 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2418 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2419 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2420 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2421 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2422 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2423 {
"syd",
drops(10) +
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
drops(10) + 2 * f, USD(0.00001), 0, 1},
2424 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2425 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2426 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2427 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2428 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2432 for (
auto const& t : tests)
2434 auto const acct =
Account(t.account);
2435 env.fund(t.fundXrp, acct);
2439 env.require(
offers(gw, 0));
2442 auto const book = t.bookAmount;
2444 env(
offer(gw,
XRP(book), USD(book)));
2449 if (t.preTrust == gwPreTrust)
2450 env(
trust(gw, acct[
"USD"](1)));
2456 if (t.preTrust == acctPreTrust)
2457 env(
trust(acct, USD(1)));
2462 auto const acctOffer = t.offerAmount;
2463 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2468 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2470 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2471 env.require(
offers(acct, t.offers));
2472 env.require(
owners(acct, t.owners));
2475 BEAST_EXPECT(acctOffers.size() == t.offers);
2476 if (acctOffers.size() && t.offers)
2478 auto const& acctOffer = *(acctOffers.front());
2480 auto const leftover = t.offerAmount - t.bookAmount;
2481 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2482 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2485 if (t.preTrust == noPreTrust)
2487 if (t.balanceUsd.value().signum())
2495 auto const sleTrust =
2497 BEAST_EXPECT(!sleTrust);
2514 using namespace jtx;
2516 auto const gw =
Account(
"gateway");
2517 auto const alice =
Account(
"alice");
2518 auto const bob =
Account(
"bob");
2519 auto const USD = gw[
"USD"];
2521 auto const usdOffer = USD(1000);
2522 auto const xrpOffer =
XRP(1000);
2524 Env env{*
this, features};
2526 env.fund(
XRP(1000000), gw, bob);
2530 auto const fee = env.current()->fees().base;
2537 env(
trust(alice, usdOffer));
2541 env(
pay(gw, alice, usdOffer));
2548 auto const alicesXRP = env.balance(alice);
2549 auto const bobsXRP = env.balance(bob);
2551 env(
offer(alice, xrpOffer, usdOffer));
2553 env(
offer(bob, usdOffer, xrpOffer));
2567 env(
offer(alice, USD(999),
XRP(999)));
2568 env(
offer(bob, xrpOffer, usdOffer));
2571 env.require(
balance(alice, USD(999)));
2572 env.require(
balance(bob, USD(1)));
2573 env.require(
offers(alice, 0));
2577 BEAST_EXPECT(bobsOffers.size() == 1);
2578 auto const& bobsOffer = *(bobsOffers.front());
2580 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2581 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2582 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2591 using namespace jtx;
2593 auto const gw =
Account(
"gateway");
2594 auto const alice =
Account(
"alice");
2595 auto const bob =
Account(
"bob");
2596 auto const USD = gw[
"USD"];
2597 auto const EUR = gw[
"EUR"];
2599 auto const usdOffer = USD(1000);
2600 auto const eurOffer = EUR(1000);
2602 Env env{*
this, features};
2604 env.fund(
XRP(1000000), gw);
2608 auto const fee = env.current()->fees().base;
2616 env(
trust(alice, usdOffer));
2617 env(
trust(bob, eurOffer));
2620 env(
pay(gw, alice, usdOffer));
2621 env(
pay(gw, bob, eurOffer));
2629 env(
offer(alice, eurOffer, usdOffer));
2630 env(
offer(bob, usdOffer, eurOffer));
2647 env(
offer(bob, eurOffer, usdOffer));
2650 env(
offer(alice, USD(999), eurOffer));
2653 env.require(
offers(alice, 0));
2654 env.require(
offers(bob, 1));
2656 env.require(
balance(alice, USD(999)));
2657 env.require(
balance(alice, EUR(1)));
2658 env.require(
balance(bob, USD(1)));
2659 env.require(
balance(bob, EUR(999)));
2663 if (BEAST_EXPECT(bobsOffers.size() == 1))
2665 auto const& bobsOffer = *(bobsOffers.front());
2667 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2668 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2673 env(
offer(alice, USD(1), EUR(1)));
2676 env.require(
balance(alice, USD(1000)));
2679 env.require(
balance(bob, EUR(1000)));
2680 env.require(
offers(alice, 0));
2681 env.require(
offers(bob, 0));
2684 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2685 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2689 env(
offer(alice, EUR(999), usdOffer));
2692 env(
offer(bob, usdOffer, eurOffer));
2695 env.require(
offers(alice, 0));
2696 env.require(
offers(bob, 0));
2698 env.require(
balance(alice, USD(0)));
2699 env.require(
balance(alice, EUR(999)));
2700 env.require(
balance(bob, USD(1000)));
2701 env.require(
balance(bob, EUR(1)));
2709 using namespace jtx;
2711 auto const gw =
Account(
"gateway");
2712 auto const alice =
Account(
"alice");
2713 auto const bob =
Account(
"bob");
2714 auto const carol =
Account(
"carol");
2715 auto const USD = gw[
"USD"];
2716 auto const EUR = gw[
"EUR"];
2718 auto const usdOffer = USD(1000);
2719 auto const eurOffer = EUR(1000);
2721 Env env{*
this, features};
2723 env.fund(
XRP(1000000), gw, alice, bob, carol);
2726 env(
trust(alice, usdOffer));
2727 env(
trust(carol, eurOffer));
2729 env(
pay(gw, alice, usdOffer));
2730 env(
pay(gw, carol, eurOffer));
2739 env(
offer(alice,
XRP(1000), usdOffer));
2740 env(
offer(bob, eurOffer,
XRP(1000)));
2741 auto const bobXrpBalance = env.balance(bob);
2745 env(
offer(carol, USD(400), EUR(400)));
2758 BEAST_EXPECT(alicesOffers.size() == 1);
2759 auto const& alicesOffer = *(alicesOffers.front());
2761 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2762 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2763 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2767 BEAST_EXPECT(bobsOffers.size() == 1);
2768 auto const& bobsOffer = *(bobsOffers.front());
2770 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2771 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2772 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2776 env(
offer(carol, USD(600), EUR(600)));
2791 if (alicesOffers.size() != 0)
2793 BEAST_EXPECT(alicesOffers.size() == 1);
2794 auto const& alicesOffer = *(alicesOffers.front());
2796 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2797 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2798 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2810 using namespace jtx;
2812 auto const gw =
Account(
"gateway");
2813 auto const USD = gw[
"USD"];
2815 Env env{*
this, features};
2817 env.fund(
XRP(10000000), gw);
2821 auto const f = env.current()->fees().base;
2824 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2858 : account(std::move(account_))
2863 , acctGets(acctGets_)
2864 , acctPays(acctPays_)
2866 , spentXrp(spentXrp_)
2867 , finalUsd(finalUsd_)
2870 , takerGets(takerGets_)
2871 , takerPays(takerPays_)
2890 std::move(account_),
2909 TestData
const tests[]{
2912 {
"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},
2913 {
"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)},
2914 {
"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},
2915 {
"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},
2916 {
"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},
2917 {
"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},
2918 {
"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},
2919 {
"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)},
2921 {
"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},
2922 {
"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)},
2923 {
"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},
2924 {
"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},
2925 {
"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},
2926 {
"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)},
2927 {
"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)},
2931 auto const zeroUsd = USD(0);
2932 for (
auto const& t : tests)
2935 env.require(
offers(gw, 0));
2937 auto const acct =
Account(t.account);
2939 env.fund(t.fundXrp, acct);
2945 if (t.fundUSD != zeroUsd)
2947 env(
trust(acct, t.fundUSD));
2949 env(
pay(gw, acct, t.fundUSD));
2953 env(
offer(gw, t.gwGets, t.gwPays));
2963 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2965 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2966 env.require(
offers(acct, t.offers));
2967 env.require(
owners(acct, t.owners));
2972 if (acctOffers.size() > 0)
2974 BEAST_EXPECT(acctOffers.size() == 1);
2975 auto const& acctOffer = *(acctOffers.front());
2977 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2978 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2979 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2996 testcase(
"Combine tfSell with tfFillOrKill");
2998 using namespace jtx;
3000 auto const gw =
Account(
"gateway");
3001 auto const alice =
Account(
"alice");
3002 auto const bob =
Account(
"bob");
3003 auto const USD = gw[
"USD"];
3005 Env env{*
this, features};
3007 env.fund(
XRP(10000000), gw, alice, bob);
3011 TER const killedCode{
3015 env(
trust(bob, USD(200)));
3017 env(
pay(gw, bob, USD(100)));
3019 env(
offer(bob,
XRP(2000), USD(20)));
3027 env.require(
offers(alice, 0));
3028 env.require(
balance(bob, USD(100)));
3035 env.require(
balance(alice, USD(20)));
3036 env.require(
offers(alice, 0));
3037 env.require(
balance(bob, USD(80)));
3042 env(
offer(bob,
XRP(2000), USD(20)));
3046 env.require(
balance(alice, USD(35)));
3047 env.require(
offers(alice, 0));
3048 env.require(
balance(bob, USD(65)));
3060 env.require(
balance(alice, USD(35)));
3061 env.require(
offers(alice, 0));
3062 env.require(
balance(bob, USD(65)));
3071 env.require(
balance(alice, USD(40)));
3072 env.require(
offers(alice, 0));
3073 env.require(
balance(bob, USD(60)));
3082 using namespace jtx;
3084 auto const gw1 =
Account(
"gateway1");
3085 auto const USD = gw1[
"USD"];
3087 Env env{*
this, features};
3090 auto const fee = env.current()->fees().base;
3092 env.fund(
XRP(100000), gw1);
3095 env(
rate(gw1, 1.25));
3097 auto const ann =
Account(
"ann");
3098 auto const bob =
Account(
"bob");
3102 env(
trust(ann, USD(200)));
3103 env(
trust(bob, USD(200)));
3106 env(
pay(gw1, bob, USD(125)));
3121 env.require(
balance(ann, USD(100)));
3123 env.require(
offers(ann, 0));
3125 env.require(
balance(bob, USD(0)));
3127 env.require(
offers(bob, 0));
3132 auto const che =
Account(
"che");
3133 auto const deb =
Account(
"deb");
3137 env(
trust(che, USD(200)));
3138 env(
trust(deb, USD(200)));
3141 env(
pay(gw1, deb, USD(125)));
3150 env.require(
balance(che, USD(100)));
3152 env.require(
offers(che, 0));
3154 env.require(
balance(deb, USD(0)));
3156 env.require(
offers(deb, 0));
3159 auto const eve =
Account(
"eve");
3160 auto const fyn =
Account(
"fyn");
3162 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3165 env(
trust(eve, USD(1000)));
3166 env(
trust(fyn, USD(1000)));
3169 env(
pay(gw1, eve, USD(100)));
3170 env(
pay(gw1, fyn, USD(100)));
3176 env(
offer(eve, USD(10),
XRP(4000)));
3180 env(
offer(fyn,
XRP(2000), USD(5)));
3183 env.require(
balance(eve, USD(105)));
3186 BEAST_EXPECT(evesOffers.size() == 1);
3187 if (evesOffers.size() != 0)
3189 auto const& evesOffer = *(evesOffers.front());
3190 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3191 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3192 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3196 env.require(
balance(fyn, USD(93.75)));
3198 env.require(
offers(fyn, 0));
3201 auto const gw2 =
Account(
"gateway2");
3202 auto const EUR = gw2[
"EUR"];
3204 env.fund(
XRP(100000), gw2);
3207 env(
rate(gw2, 1.5));
3212 auto const gay =
Account(
"gay");
3213 auto const hal =
Account(
"hal");
3214 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3217 env(
trust(gay, USD(200)));
3218 env(
trust(gay, EUR(200)));
3219 env(
trust(hal, USD(200)));
3220 env(
trust(hal, EUR(200)));
3223 env(
pay(gw1, gay, USD(125)));
3224 env(
pay(gw2, hal, EUR(150)));
3227 env(
offer(gay, EUR(100), USD(100)));
3230 env(
offer(hal, USD(100), EUR(100)));
3233 env.require(
balance(gay, USD(0)));
3234 env.require(
balance(gay, EUR(100)));
3236 env.require(
offers(gay, 0));
3238 env.require(
balance(hal, USD(100)));
3239 env.require(
balance(hal, EUR(0)));
3241 env.require(
offers(hal, 0));
3245 auto const ivy =
Account(
"ivy");
3246 auto const joe =
Account(
"joe");
3247 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3256 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3257 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3259 env.require(
balance(ivy, USD(300)));
3260 env.require(
balance(joe, EUR(250)));
3262 env(
offer(ivy, EUR(100), USD(200)));
3265 env(
offer(joe, USD(200), EUR(100)));
3268 env.require(
balance(ivy, USD(50)));
3269 env.require(
balance(ivy, EUR(100)));
3271 env.require(
offers(ivy, 0));
3273 env.require(
balance(joe, USD(200)));
3274 env.require(
balance(joe, EUR(100)));
3276 env.require(
offers(joe, 0));
3280 auto const kim =
Account(
"kim");
3281 auto const K_BUX = kim[
"BUX"];
3282 auto const lex =
Account(
"lex");
3283 auto const meg =
Account(
"meg");
3284 auto const ned =
Account(
"ned");
3285 auto const N_BUX = ned[
"BUX"];
3288 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3291 env(
trust(lex, K_BUX(400)));
3293 env(
trust(meg, N_BUX(100)));
3295 env(
pay(ned, lex, N_BUX(100)));
3297 env.require(
balance(lex, N_BUX(100)));
3299 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3304 env.require(
balance(lex, K_BUX(72)));
3305 env.require(
balance(lex, N_BUX(40)));
3307 env.require(
balance(meg, N_BUX(60)));
3312 env(
offer(lex, K_BUX(30), N_BUX(30)));
3315 env(
offer(kim, N_BUX(30), K_BUX(30)));
3319 env.require(
balance(kim, N_BUX(30)));
3320 env.require(
balance(lex, K_BUX(102)));
3321 env.require(
balance(lex, N_BUX(10)));
3323 env.require(
balance(meg, N_BUX(60)));
3324 env.require(
balance(ned, K_BUX(-30)));
3329 auto const ova =
Account(
"ova");
3330 auto const pat =
Account(
"pat");
3331 auto const qae =
Account(
"qae");
3332 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3338 env(
trust(ova, USD(200)));
3339 env(
trust(ova, EUR(200)));
3340 env(
trust(pat, USD(200)));
3341 env(
trust(pat, EUR(200)));
3342 env(
trust(qae, USD(200)));
3343 env(
trust(qae, EUR(200)));
3346 env(
pay(gw1, ova, USD(125)));
3347 env(
pay(gw2, qae, EUR(150)));
3354 env(
offer(qae, USD(100), EUR(100)));
3357 env.require(
balance(ova, USD(0)));
3358 env.require(
balance(ova, EUR(0)));
3363 if (ovasOffers.size() != 0)
3365 BEAST_EXPECT(ovasOffers.size() == 1);
3366 auto const& ovasOffer = *(ovasOffers.front());
3368 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3369 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3370 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3373 env.require(
balance(pat, USD(0)));
3374 env.require(
balance(pat, EUR(100)));
3376 env.require(
offers(pat, 0));
3378 env.require(
balance(qae, USD(100)));
3379 env.require(
balance(qae, EUR(0)));
3381 env.require(
offers(qae, 0));
3402 using namespace jtx;
3404 auto const gw =
Account(
"gateway");
3405 auto const USD = gw[
"USD"];
3407 Env env{*
this, features};
3410 auto const fee = env.current()->fees().base;
3411 auto const startBalance =
XRP(1000000);
3413 env.fund(startBalance + (
fee * 4), gw);
3423 env.require(
owners(gw, 3));
3424 env.require(
balance(gw, startBalance +
fee));
3427 BEAST_EXPECT(gwOffers.size() == 3);
3428 for (
auto const& offerPtr : gwOffers)
3430 auto const&
offer = *offerPtr;
3431 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3432 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3433 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3438 env(
offer(gw,
XRP(1000), USD(100)));
3440 env.require(
owners(gw, 1));
3441 env.require(
offers(gw, 1));
3442 env.require(
balance(gw, startBalance));
3445 BEAST_EXPECT(gwOffers.size() == 1);
3446 for (
auto const& offerPtr : gwOffers)
3448 auto const&
offer = *offerPtr;
3449 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3450 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3451 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3458 using namespace jtx;
3460 auto const gw1 =
Account(
"gateway1");
3461 auto const gw2 =
Account(
"gateway2");
3462 auto const alice =
Account(
"alice");
3463 auto const USD = gw1[
"USD"];
3464 auto const EUR = gw2[
"EUR"];
3466 Env env{*
this, features};
3468 env.fund(
XRP(1000000), gw1, gw2);
3472 auto const f = env.current()->fees().base;
3486 TestData
const tests[]{
3497 for (
auto const& t : tests)
3499 auto const acct =
Account{t.acct};
3500 env.fund(t.fundXRP, acct);
3503 env(
trust(acct, USD(1000)));
3504 env(
trust(acct, EUR(1000)));
3507 if (t.fundUSD > USD(0))
3508 env(
pay(gw1, acct, t.fundUSD));
3509 if (t.fundEUR > EUR(0))
3510 env(
pay(gw2, acct, t.fundEUR));
3513 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3517 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3518 env.require(
owners(acct, 2 + offerCount));
3519 env.require(
balance(acct, t.fundUSD));
3520 env.require(
balance(acct, t.fundEUR));
3523 BEAST_EXPECT(acctOffers.size() == offerCount);
3524 for (
auto const& offerPtr : acctOffers)
3526 auto const&
offer = *offerPtr;
3527 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3528 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3529 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3532 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3536 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3537 env.require(
owners(acct, 2 + offerCount));
3538 env.require(
balance(acct, t.fundUSD));
3539 env.require(
balance(acct, t.fundEUR));
3542 BEAST_EXPECT(acctOffers.size() == offerCount);
3543 for (
auto const& offerPtr : acctOffers)
3545 auto const&
offer = *offerPtr;
3546 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3547 if (
offer[sfSequence] == firstOfferSeq)
3549 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3550 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3554 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3555 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3582 using namespace jtx;
3584 Env env{*
this, features};
3586 auto const alice =
Account(
"alice");
3587 auto const bob =
Account(
"bob");
3588 auto const USD = bob[
"USD"];
3589 auto const f = env.current()->fees().base;
3591 env.fund(
XRP(50000) + f, alice, bob);
3594 env(
offer(alice, USD(5000),
XRP(50000)));
3598 env(
offer(bob,
XRP(50000), USD(5000)));
3604 env.require(
owners(alice, 1));
3605 env.require(
lines(alice, 1));
3610 BEAST_EXPECT(bobOffers.size() == 1);
3611 for (
auto const& offerPtr : bobOffers)
3613 auto const&
offer = *offerPtr;
3614 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3615 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3616 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3628 using namespace jtx;
3630 Env env{*
this, features};
3633 auto const fee = env.current()->fees().base;
3636 auto const ann =
Account(
"ann");
3637 auto const A_BUX = ann[
"BUX"];
3638 auto const bob =
Account(
"bob");
3639 auto const cam =
Account(
"cam");
3640 auto const dan =
Account(
"dan");
3641 auto const D_BUX = dan[
"BUX"];
3644 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3647 env(
trust(bob, A_BUX(400)));
3649 env(
trust(cam, D_BUX(100)));
3651 env(
pay(dan, bob, D_BUX(100)));
3653 env.require(
balance(bob, D_BUX(100)));
3655 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3660 env.require(
balance(bob, A_BUX(72)));
3661 env.require(
balance(bob, D_BUX(40)));
3663 env.require(
balance(cam, D_BUX(60)));
3667 env(
offer(bob, A_BUX(30), D_BUX(30)));
3670 env(
trust(ann, D_BUX(100)));
3674 env(
pay(ann, ann, D_BUX(30)),
3681 env.require(
balance(ann, D_BUX(0)));
3682 env.require(
balance(bob, A_BUX(72)));
3683 env.require(
balance(bob, D_BUX(40)));
3685 env.require(
balance(cam, D_BUX(60)));
3686 env.require(
balance(dan, A_BUX(0)));
3700 using namespace jtx;
3702 Env env{*
this, features};
3704 auto const ann =
Account(
"ann");
3705 auto const bob =
Account(
"bob");
3706 auto const cam =
Account(
"cam");
3707 auto const A_BUX = ann[
"BUX"];
3708 auto const B_BUX = bob[
"BUX"];
3710 auto const fee = env.current()->fees().base;
3711 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3714 env(
trust(ann, B_BUX(40)));
3715 env(
trust(cam, A_BUX(40)));
3716 env(
trust(cam, B_BUX(40)));
3719 env(
pay(ann, cam, A_BUX(35)));
3720 env(
pay(bob, cam, B_BUX(35)));
3722 env(
offer(bob, A_BUX(30), B_BUX(30)));
3730 env.require(
balance(cam, A_BUX(35)));
3731 env.require(
balance(cam, B_BUX(35)));
3732 env.require(
offers(cam, 1));
3735 env(
offer(cam, B_BUX(30), A_BUX(30)));
3738 env.require(
balance(bob, A_BUX(30)));
3739 env.require(
balance(cam, A_BUX(5)));
3740 env.require(
balance(cam, B_BUX(65)));
3741 env.require(
offers(cam, 0));
3750 testcase(
"Self crossing low quality offer");
3752 using namespace jtx;
3754 Env env{*
this, features};
3756 auto const ann =
Account(
"ann");
3757 auto const gw =
Account(
"gateway");
3758 auto const BTC = gw[
"BTC"];
3760 auto const fee = env.current()->fees().base;
3765 env(
rate(gw, 1.002));
3766 env(
trust(ann, BTC(10)));
3769 env(
pay(gw, ann, BTC(2.856)));
3772 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3776 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3789 using namespace jtx;
3791 Env env{*
this, features};
3793 auto const gw =
Account(
"gateway");
3794 auto const alice =
Account(
"alice");
3795 auto const bob =
Account(
"bob");
3796 auto const CNY = gw[
"CNY"];
3798 auto const fee = env.current()->fees().base;
3803 env(
trust(bob, CNY(500)));
3806 env(
pay(gw, bob, CNY(300)));
3809 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3813 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3817 BEAST_EXPECT(aliceOffers.size() == 1);
3818 for (
auto const& offerPtr : aliceOffers)
3820 auto const&
offer = *offerPtr;
3821 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3822 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3823 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3833 testcase(
"Offer In Scaling With Xfer Rate");
3835 using namespace jtx;
3837 Env env{*
this, features};
3839 auto const gw =
Account(
"gateway");
3840 auto const alice =
Account(
"alice");
3841 auto const bob =
Account(
"bob");
3842 auto const BTC = gw[
"BTC"];
3843 auto const JPY = gw[
"JPY"];
3845 auto const fee = env.current()->fees().base;
3850 env(
rate(gw, 1.002));
3851 env(
trust(alice, JPY(4000)));
3852 env(
trust(bob, BTC(2)));
3855 env(
pay(gw, alice, JPY(3699.034802280317)));
3856 env(
pay(gw, bob, BTC(1.156722559140311)));
3859 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3863 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3867 BEAST_EXPECT(aliceOffers.size() == 1);
3868 for (
auto const& offerPtr : aliceOffers)
3870 auto const&
offer = *offerPtr;
3871 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3873 offer[sfTakerGets] ==
3875 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3885 testcase(
"Offer Threshold With Reduced Funds");
3887 using namespace jtx;
3889 Env env{*
this, features};
3891 auto const gw1 =
Account(
"gw1");
3892 auto const gw2 =
Account(
"gw2");
3893 auto const alice =
Account(
"alice");
3894 auto const bob =
Account(
"bob");
3895 auto const USD = gw1[
"USD"];
3896 auto const JPY = gw2[
"JPY"];
3898 auto const fee = env.current()->fees().base;
3900 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3903 env(
rate(gw1, 1.002));
3904 env(
trust(alice, USD(1000)));
3905 env(
trust(bob, JPY(100000)));
3932 BEAST_EXPECT(aliceOffers.size() == 1);
3933 for (
auto const& offerPtr : aliceOffers)
3935 auto const&
offer = *offerPtr;
3936 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3938 offer[sfTakerGets] ==
3941 offer[sfTakerPays] ==
3951 using namespace jtx;
3953 Env env{*
this, features};
3955 auto const gw =
Account(
"gw");
3956 auto const alice =
Account(
"alice");
3957 auto const bob =
Account(
"bob");
3958 auto const CNY = gw[
"CNY"];
3959 auto const fee = env.current()->fees().base;
3960 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3962 env.fund(startXrpBalance, gw, alice, bob);
3965 env(
trust(bob, CNY(100000)));
3977 STAmount const bobsCnyStartBalance{
3979 env(
pay(gw, bob, bobsCnyStartBalance));
3988 env.require(
balance(alice, alicesCnyOffer));
3990 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
4033 using namespace jtx;
4035 Env env{*
this, features};
4036 auto const baseFee = env.current()->fees().base.drops();
4038 auto const gw =
Account(
"gw");
4039 auto const BTC = gw[
"BTC"];
4040 auto const USD = gw[
"USD"];
4041 auto const startXrpBalance =
XRP(4000000);
4043 env.fund(startXrpBalance, gw);
4046 env(
rate(gw, 1.25));
4072 TestData
const tests[]{
4074 {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)}}},
4075 {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)}}},
4076 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
4077 {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)}}},
4081 for (
auto const& t : tests)
4083 Account const& self = t.actors[t.self].acct;
4084 Account const& leg0 = t.actors[t.leg0].acct;
4085 Account const& leg1 = t.actors[t.leg1].acct;
4087 for (
auto const& actor : t.actors)
4089 env.fund(
XRP(4000000), actor.acct);
4092 env(
trust(actor.acct, BTC(40)));
4093 env(
trust(actor.acct, USD(8000)));
4097 env(
pay(gw, self, t.btcStart));
4098 env(
pay(gw, self, USD(2000)));
4099 if (self.
id() != leg1.
id())
4100 env(
pay(gw, leg1, USD(2000)));
4114 env(
offer(self, USD(1000), BTC(10)));
4119 for (
auto const& actor : t.actors)
4125 actorOffers.begin(),
4127 actorOffers.begin(),
4130 return (*offer)[sfTakerGets].signum() == 0;
4132 BEAST_EXPECT(offerCount == actor.offers);
4134 env.require(
balance(actor.acct, actor.xrp));
4135 env.require(
balance(actor.acct, actor.btc));
4136 env.require(
balance(actor.acct, actor.usd));
4152 testcase(
"Self Pay Unlimited Funds");
4184 using namespace jtx;
4186 Env env{*
this, features};
4187 auto const baseFee = env.current()->fees().base.drops();
4189 auto const gw =
Account(
"gw");
4190 auto const BTC = gw[
"BTC"];
4191 auto const USD = gw[
"USD"];
4192 auto const startXrpBalance =
XRP(4000000);
4194 env.fund(startXrpBalance, gw);
4197 env(
rate(gw, 1.25));
4223 TestData
const tests[]{
4225 {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)}}},
4226 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4230 for (
auto const& t : tests)
4232 Account const& self = t.actors[t.self].acct;
4233 Account const& leg0 = t.actors[t.leg0].acct;
4234 Account const& leg1 = t.actors[t.leg1].acct;
4236 for (
auto const& actor : t.actors)
4238 env.fund(
XRP(4000000), actor.acct);
4241 env(
trust(actor.acct, BTC(40)));
4242 env(
trust(actor.acct, USD(8000)));
4246 env(
pay(gw, self, t.btcStart));
4247 env(
pay(gw, self, USD(2000)));
4248 if (self.
id() != leg1.
id())
4249 env(
pay(gw, leg1, USD(2000)));
4263 env(
offer(self, USD(1000), BTC(10)));
4268 for (
auto const& actor : t.actors)
4274 actorOffers.begin(),
4276 actorOffers.begin(),
4279 return (*offer)[sfTakerGets].signum() == 0;
4281 BEAST_EXPECT(offerCount == actor.offers);
4283 env.require(
balance(actor.acct, actor.xrp));
4284 env.require(
balance(actor.acct, actor.btc));
4285 env.require(
balance(actor.acct, actor.usd));
4303 using namespace jtx;
4305 Env env{*
this, features};
4307 auto const gw =
Account(
"gw");
4308 auto const alice =
Account(
"alice");
4309 auto const bob =
Account(
"bob");
4310 auto const gwUSD = gw[
"USD"];
4311 auto const aliceUSD = alice[
"USD"];
4312 auto const bobUSD = bob[
"USD"];
4314 env.fund(
XRP(400000), gw, alice, bob);
4323 env(
trust(bob, gwUSD(100)));
4325 env(
trust(alice, gwUSD(100)));
4327 env(
offer(alice, gwUSD(40),
XRP(4000)));
4330 env.require(
offers(alice, 1));
4331 env.require(
balance(alice, gwUSD(0)));
4333 env(
pay(gw, bob, gwUSD(50)));
4336 env.require(
balance(bob, gwUSD(50)));
4339 env(
offer(bob,
XRP(4000), gwUSD(40)));
4342 env.require(
offers(alice, 0));
4343 env.require(
balance(alice, gwUSD(40)));
4345 env.require(
offers(bob, 0));
4346 env.require(
balance(bob, gwUSD(10)));
4371 using namespace jtx;
4373 Env env{*
this, features};
4375 auto const gw =
Account(
"gw");
4376 auto const alice =
Account(
"alice");
4377 auto const bob =
Account(
"bob");
4378 auto const gwUSD = gw[
"USD"];
4379 auto const aliceUSD = alice[
"USD"];
4380 auto const bobUSD = bob[
"USD"];
4382 env.fund(
XRP(400000), gw, alice, bob);
4385 env(
offer(alice, gwUSD(40),
XRP(4000)));
4388 env.require(
offers(alice, 1));
4395 env(
trust(bob, gwUSD(100)));
4398 env(
pay(gw, bob, gwUSD(50)));
4400 env.require(
balance(bob, gwUSD(50)));
4407 env(
offer(bob,
XRP(4000), gwUSD(40)));
4411 env.require(
offers(alice, 0));
4414 env.require(
offers(bob, 1));
4415 env.require(
balance(bob, gwUSD(50)));
4423 env.require(
offers(alice, 0));
4426 env.require(
offers(bob, 1));
4427 env.require(
balance(bob, gwUSD(50)));
4431 env(
trust(gw, aliceUSD(100)));
4437 env.require(
offers(alice, 0));
4438 env.require(
balance(alice, gwUSD(0)));
4440 env.require(
offers(bob, 1));
4441 env.require(
balance(bob, gwUSD(50)));
4446 env.require(
offers(bob, 0));
4454 env(
offer(alice, gwUSD(40),
XRP(4000)));
4457 env.require(
offers(alice, 1));
4460 env(
offer(bob,
XRP(4000), gwUSD(40)));
4463 env.require(
offers(alice, 0));
4464 env.require(
balance(alice, gwUSD(40)));
4466 env.require(
offers(bob, 0));
4467 env.require(
balance(bob, gwUSD(10)));
4473 testcase(
"RippleConnect Smoketest payment flow");
4474 using namespace jtx;
4476 Env env{*
this, features};
4486 auto const hotUS =
Account(
"hotUS");
4487 auto const coldUS =
Account(
"coldUS");
4488 auto const hotEU =
Account(
"hotEU");
4489 auto const coldEU =
Account(
"coldEU");
4490 auto const mm =
Account(
"mm");
4492 auto const USD = coldUS[
"USD"];
4493 auto const EUR = coldEU[
"EUR"];
4495 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4499 for (
auto const& cold : {coldUS, coldEU})
4522 env(
pay(coldUS, hotUS, USD(5000000)));
4523 env(
pay(coldEU, hotEU, EUR(5000000)));
4524 env(
pay(coldUS, mm, USD(5000000)));
4525 env(
pay(coldEU, mm, EUR(5000000)));
4529 float const rate = 0.9f;
4530 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4533 float const reverseRate = 1.0f /
rate * 1.00101f;
4534 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4541 jvParams[jss::destination_account] = coldEU.human();
4542 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4543 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4544 jvParams[jss::destination_amount][jss::value] = 10;
4545 jvParams[jss::source_account] = hotUS.human();
4548 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4550 BEAST_EXPECT(jrr[jss::status] ==
"success");
4552 jrr[jss::alternatives].isArray() &&
4553 jrr[jss::alternatives].size() > 0);
4556 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4564 using namespace jtx;
4566 Env env{*
this, features};
4568 auto const gw =
Account(
"gw");
4569 auto const alice =
Account(
"alice");
4570 auto const gwUSD = gw[
"USD"];
4571 auto const aliceUSD = alice[
"USD"];
4573 env.fund(
XRP(400000), gw, alice);
4577 env(
offer(gw, gwUSD(40),
XRP(4000)));
4580 env.require(
offers(gw, 1));
4589 env.require(
offers(gw, 0));
4596 bool const preauth = features[featureDepositPreauth];
4601 env(
offer(gw, gwUSD(40),
XRP(4000)),
4605 env.require(
offers(gw, preauth ? 1 : 0));
4613 env(
trust(alice, gwUSD(100)));
4616 env(
pay(gw, alice, gwUSD(50)));
4619 env.require(
balance(alice, gwUSD(50)));
4622 env(
offer(alice,
XRP(4000), gwUSD(40)));
4625 env.require(
offers(alice, 0));
4626 env.require(
balance(alice, gwUSD(10)));
4628 env.require(
offers(gw, 0));
4635 using namespace jtx;
4639 auto trustLineExists = [](
jtx::Env const& env,
4650 auto const USD = gw[
"USD"];
4651 auto const BUX = alice[
"BUX"];
4653 Env env{*
this, features};
4657 env.
trust(USD(1000), becky);
4658 env(
pay(gw, becky, USD(5)));
4660 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4671 env(
pay(becky, gw, USD(5)));
4672 env.
trust(USD(0), becky);
4674 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4675 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4676 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4683 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4685 if (gwSeq + 255 > openLedgerSeq)
4686 return gwSeq - openLedgerSeq + 255;
4690 for (
int i = 0; i < delta; ++i)
4707 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4708 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4714 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4715 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4720 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4724 env.
trust(BUX(1000), carol);
4725 env(
pay(alice, carol, BUX(2)));
4734 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4735 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4743 using namespace jtx;
4747 Env env{*
this, features};
4748 auto const gw =
Account{
"gateway"};
4749 env.fund(
XRP(10000), gw);
4752 auto txn =
noop(gw);
4753 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4756 txn[sfTickSize.fieldName] = Quality::minTickSize;
4758 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4761 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4763 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4766 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4768 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4771 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4774 txn[sfTickSize.fieldName] = 0;
4776 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4779 Env env{*
this, features};
4780 auto const gw =
Account{
"gateway"};
4781 auto const alice =
Account{
"alice"};
4782 auto const XTS = gw[
"XTS"];
4783 auto const XXX = gw[
"XXX"];
4785 env.fund(
XRP(10000), gw, alice);
4790 auto txn =
noop(gw);
4791 txn[sfTickSize.fieldName] = 5;
4793 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4796 env(
trust(alice, XTS(1000)));
4797 env(
trust(alice, XXX(1000)));
4799 env(
pay(gw, alice, alice[
"XTS"](100)));
4800 env(
pay(gw, alice, alice[
"XXX"](100)));
4802 env(
offer(alice, XTS(10), XXX(30)));
4803 env(
offer(alice, XTS(30), XXX(10)));
4810 if (sle->getType() == ltOFFER)
4814 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4818 auto it =
offers.begin();
4819 BEAST_EXPECT(it !=
offers.end());
4821 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4822 it->second.second > XXX(29.9994));
4826 BEAST_EXPECT(it !=
offers.end());
4828 it->second.first == XTS(30) && it->second.second == XXX(10));
4832 BEAST_EXPECT(it !=
offers.end());
4834 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4839 BEAST_EXPECT(it !=
offers.end());
4841 it->second.first == XTS(30) && it->second.second == XXX(10));
4843 BEAST_EXPECT(++it ==
offers.end());
4857 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4867 using namespace jtx;
4875 Env env{*
this, features};
4876 auto const gw =
Account{
"gateway"};
4877 auto const alice =
Account{
"alice"};
4878 auto const bob =
Account{
"bob"};
4879 auto const USD = gw[
"USD"];
4881 env.fund(
XRP(10000), gw, alice, bob);
4884 env(
trust(alice, USD(1000)));
4885 env(
trust(bob, USD(1000)));
4888 env(
pay(gw, alice, USD(200)));
4895 env(
offer(alice,
XRP(50), USD(50)));
4905 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4906 env(
offer(alice,
XRP(50), USD(50)));
4922 BEAST_EXPECT(
offers.size() == 4);
4923 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4924 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4925 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4926 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4927 env.require(
balance(alice, USD(200)));
4928 env.require(
owners(alice, 5));
4938 BEAST_EXPECT(
offers.size() == 3);
4939 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4940 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4941 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4951 BEAST_EXPECT(
offers.size() == 2);
4952 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4953 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4963 BEAST_EXPECT(
offers.size() == 1);
4964 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4974 BEAST_EXPECT(
offers.size() == 0);
4976 env.require(
balance(alice, USD(0)));
4977 env.require(
owners(alice, 1));
4978 env.require(
balance(bob, USD(200)));
4979 env.require(
owners(bob, 1));
4987 using namespace jtx;
4991 Env env{*
this, features};
4992 auto const gw =
Account{
"gateway"};
4993 auto const alice =
Account{
"alice"};
4994 auto const USD = gw[
"USD"];
4996 env.fund(
XRP(10000), gw, alice);
4999 env(
trust(alice, USD(1000)));
5003 env(
pay(gw, alice, USD(200)));
5008 env(
offer(alice,
XRP(50), USD(50)));
5020 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5021 env(
offer(alice,
XRP(50), USD(50)));
5037 BEAST_EXPECT(
offers.size() == 4);
5038 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
5039 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
5040 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
5041 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
5042 env.require(
balance(alice, USD(200)));
5043 env.require(
owners(alice, 7));
5053 BEAST_EXPECT(
offers.size() == 3);
5054 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5055 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
5056 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
5066 BEAST_EXPECT(
offers.size() == 2);
5067 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5068 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5081 BEAST_EXPECT(
offers.size() == 1);
5082 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5099 testcase(
"incorrect assert fixed");
5100 using namespace jtx;
5103 auto const alice =
Account(
"alice");
5104 auto const USD = alice[
"USD"];
5106 env.fund(
XRP(10000), alice);
5108 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5116 using namespace jtx;
5117 Env env(*
this, features);
5118 Account const issuer(
"issuer");
5121 auto const USD = issuer[
"USD"];
5122 auto const EUR = issuer[
"EUR"];
5125 env.
fund(
XRP(1'000), maker, taker);
5128 env.
trust(USD(1'000), maker, taker);
5129 env.
trust(EUR(1'000), maker, taker);
5132 env(
pay(issuer, maker, USD(1'000)));
5133 env(
pay(issuer, taker, USD(1'000)));
5134 env(
pay(issuer, maker, EUR(1'000)));
5137 auto makerUSDBalance = env.
balance(maker, USD).
value();
5138 auto takerUSDBalance = env.
balance(taker, USD).
value();
5139 auto makerEURBalance = env.
balance(maker, EUR).
value();
5140 auto takerEURBalance = env.
balance(taker, EUR).
value();
5149 env(
offer(maker,
XRP(100), USD(100)));
5152 env(
offer(taker, USD(100),
XRP(101)),
5157 makerXRPBalance -=
txfee(env, 1);
5158 takerXRPBalance -=
txfee(env, 1);
5161 makerUSDBalance -= USD(100);
5162 takerUSDBalance += USD(100);
5163 makerXRPBalance +=
XRP(100).value();
5164 takerXRPBalance -=
XRP(100).value();
5168 env(
offer(maker, USD(100),
XRP(100)));
5171 env(
offer(taker,
XRP(100), USD(101)),
5176 makerXRPBalance -=
txfee(env, 1);
5177 takerXRPBalance -=
txfee(env, 1);
5180 makerUSDBalance += USD(100);
5181 takerUSDBalance -= USD(100);
5182 makerXRPBalance -=
XRP(100).value();
5183 takerXRPBalance +=
XRP(100).value();
5187 env(
offer(maker, USD(100), EUR(100)));
5190 env(
offer(taker, EUR(100), USD(101)),
5195 makerXRPBalance -=
txfee(env, 1);
5196 takerXRPBalance -=
txfee(env, 1);
5199 makerUSDBalance += USD(100);
5200 takerUSDBalance -= USD(100);
5201 makerEURBalance -= EUR(100);
5202 takerEURBalance += EUR(100);
5209 env(
offer(maker,
XRP(101), USD(101)));
5212 env(
offer(taker, USD(100),
XRP(101)),
5216 makerUSDBalance -= USD(101);
5217 takerUSDBalance += USD(101);
5218 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5219 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5222 env(
offer(maker, USD(101),
XRP(101)));
5225 env(
offer(taker,
XRP(100), USD(101)),
5229 makerUSDBalance += USD(101);
5230 takerUSDBalance -= USD(101);
5231 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5232 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5235 env(
offer(maker, USD(101), EUR(101)));
5238 env(
offer(taker, EUR(100), USD(101)),
5242 makerUSDBalance += USD(101);
5243 takerUSDBalance -= USD(101);
5244 makerEURBalance -= EUR(101);
5245 takerEURBalance += EUR(101);
5246 makerXRPBalance -=
txfee(env, 1);
5247 takerXRPBalance -=
txfee(env, 1);
5254 env(
offer(maker,
XRP(100), USD(100)));
5257 env(
offer(taker, USD(100),
XRP(99)),
5262 makerXRPBalance -=
txfee(env, 1);
5263 takerXRPBalance -=
txfee(env, 1);
5266 env(
offer(maker, USD(100),
XRP(100)));
5269 env(
offer(taker,
XRP(100), USD(99)),
5274 makerXRPBalance -=
txfee(env, 1);
5275 takerXRPBalance -=
txfee(env, 1);
5278 env(
offer(maker, USD(100), EUR(100)));
5281 env(
offer(taker, EUR(100), USD(99)),
5286 makerXRPBalance -=
txfee(env, 1);
5287 takerXRPBalance -=
txfee(env, 1);
5292 env.
balance(maker, USD) == makerUSDBalance &&
5293 env.
balance(taker, USD) == takerUSDBalance &&
5294 env.
balance(maker, EUR) == makerEURBalance &&
5295 env.
balance(taker, EUR) == takerEURBalance &&
5296 env.
balance(maker,
XRP) == makerXRPBalance &&
5367 using namespace jtx;
5369 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5371 fixRmSmallIncreasedQOffers};
5373 featureImmediateOfferKilled};
5378 all - takerDryOffer - immediateOfferKilled - permDEX,
5379 all - immediateOfferKilled - permDEX,
5380 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
5382 all - fillOrKill - permDEX,
5386 if (BEAST_EXPECT(instance < feats.size()))
5390 BEAST_EXPECT(!
last || instance == feats.size() - 1);
5451 using namespace jtx;
5454 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5459 testAll(
all - f1513 - immediateOfferKilled - permDEX);
5460 testAll(
all - immediateOfferKilled - fillOrKill - permDEX);
5469BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx,
ripple, 2);
5470BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx,
ripple, 2);
5471BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx,
ripple, 2);
5472BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx,
ripple, 2);
5473BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, tx,
ripple, 2);
5474BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx,
ripple, 2);
5475BEAST_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