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"];
850 Env env{*
this, features};
852 auto const f = env.current()->fees().base;
854 env.fund(startBalance, gw, alice, bob);
877 env(
offer(alice,
XRP(1000), USD(1000)),
882 balance(alice, startBalance - (f * 2)),
886 balance(bob, startBalance - (f * 2)),
892 env(
offer(alice,
XRP(500), USD(500)),
897 balance(alice, startBalance - (f * 3) +
XRP(500)),
901 balance(bob, startBalance - (f * 2) -
XRP(500)),
910 Env env{*
this, features};
912 auto const f = env.current()->fees().base;
914 env.fund(startBalance, gw, alice, bob);
922 TER const expectedCode = features[featureImmediateOfferKilled]
925 env(
offer(alice,
XRP(1000), USD(1000)),
931 balance(alice, startBalance - f - f),
938 env(
offer(alice,
XRP(1000), USD(1000)),
943 balance(alice, startBalance - f - f - f +
XRP(50)),
959 balance(alice, startBalance - f - f - f - f +
XRP(100)),
963 balance(bob, startBalance - f - f -
XRP(100)),
971 Env env(*
this, features);
973 env.
fund(startBalance, gw, alice, bob);
976 env(
trust(bob, USD(1000)));
979 env(
pay(gw, bob, USD(1000)));
982 env(
offer(alice, USD(1000),
XRP(2000)));
986 BEAST_EXPECT(aliceOffers.size() == 1);
987 for (
auto offerPtr : aliceOffers)
989 auto const&
offer = *offerPtr;
990 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
991 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
1001 BEAST_EXPECT(bobOffers.size() == 1);
1002 for (
auto offerPtr : bobOffers)
1004 auto const&
offer = *offerPtr;
1005 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
1006 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
1010 env(
offer(gw,
XRP(2000), USD(1000)));
1016 env(
offer(gw, USD(1000),
XRP(2000)));
1024 Env env(*
this, features);
1026 env.
fund(startBalance, gw,
"alice",
"bob");
1029 env(
trust(
"bob", USD(1000)));
1032 env(
pay(gw,
"bob", USD(1000)));
1033 env(
offer(
"alice", USD(500),
XRP(1001)));
1036 env(
offer(
"alice", USD(500),
XRP(1000)));
1040 BEAST_EXPECT(aliceOffers.size() == 2);
1050 BEAST_EXPECT(bobOffers.size() == 1);
1051 for (
auto offerPtr : bobOffers)
1053 auto const&
offer = *offerPtr;
1054 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
1055 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
1065 using namespace jtx;
1067 auto const startBalance =
XRP(1000000);
1068 auto const gw =
Account{
"gateway"};
1069 auto const alice =
Account{
"alice"};
1070 auto const USD = gw[
"USD"];
1072 Env env{*
this, features};
1074 env.fund(startBalance, gw, alice);
1078 env(
offer(alice, USD(1000),
XRP(1000)),
1085 env(
offer(alice, USD(1000),
XRP(1000)),
1115 env(
offer(alice, USD(1000),
XRP(1000)),
1123 env(
offer(alice, USD(1000),
XRP(1000)),
1143 using namespace jtx;
1145 auto const gw =
Account{
"gateway"};
1146 auto const alice =
Account{
"alice"};
1147 auto const bob =
Account{
"bob"};
1148 auto const USD = gw[
"USD"];
1150 auto const startBalance =
XRP(1000000);
1151 auto const usdOffer = USD(1000);
1152 auto const xrpOffer =
XRP(1000);
1154 Env env{*
this, features};
1156 env.fund(startBalance, gw, alice, bob);
1159 auto const f = env.current()->fees().base;
1165 balance(alice, startBalance - f),
1172 bool const featPreauth{features[featureDepositPreauth]};
1174 env(
offer(alice, xrpOffer, usdOffer),
1179 balance(alice, startBalance - f - f),
1186 env(
offer(alice, xrpOffer, usdOffer),
1190 balance(alice, startBalance - f - f - f),
1198 balance(alice, startBalance - f - f - f),
1206 balance(alice, startBalance - f - f - f),
1210 balance(bob, startBalance - f),
1221 using namespace jtx;
1223 auto const gw =
Account{
"gateway"};
1224 auto const USD = gw[
"USD"];
1226 auto const usdOffer = USD(1000);
1227 auto const xrpOffer =
XRP(1000);
1229 Env env{*
this, features};
1231 env.fund(
XRP(1000000), gw);
1235 auto const f = env.current()->fees().base;
1239 env.fund(
reserve(env, 0),
"alice");
1246 env.fund(
reserve(env, 0) + f,
"bob");
1254 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1262 env.fund(
reserve(env, 1) + f,
"dan");
1269 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1281 (use_partner ?
", with partner account" :
""));
1283 using namespace jtx;
1285 auto const gw =
Account{
"gateway"};
1286 auto const partner =
Account{
"partner"};
1287 auto const USD = gw[
"USD"];
1288 auto const BTC = gw[
"BTC"];
1290 Env env{*
this, features};
1293 env.fund(
XRP(10000), gw);
1296 env.fund(
XRP(10000), partner);
1298 env(
trust(partner, USD(100)));
1299 env(
trust(partner, BTC(500)));
1301 env(
pay(gw, partner, USD(100)));
1302 env(
pay(gw, partner, BTC(500)));
1304 auto const& account_to_test = use_partner ? partner : gw;
1307 env.require(
offers(account_to_test, 0));
1312 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1313 env.require(
offers(account_to_test, 1));
1316 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1318 auto const secondLegSeq = env.seq(account_to_test);
1319 env(
offer(account_to_test,
XRP(1000), USD(50)));
1320 env.require(
offers(account_to_test, 2));
1323 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1327 env(
offer(account_to_test, USD(50), BTC(250)));
1330 BEAST_EXPECT(jrr[jss::offers].isArray());
1331 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1334 BEAST_EXPECT(jrr[jss::offers].isArray());
1335 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1342 BEAST_EXPECT(acctOffers.size() == 0);
1343 for (
auto const& offerPtr : acctOffers)
1345 auto const&
offer = *offerPtr;
1346 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1347 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1348 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1356 env.require(
offers(account_to_test, 0));
1361 env(
offer(account_to_test, BTC(250), USD(50)));
1362 env.require(
offers(account_to_test, 1));
1366 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1369 BEAST_EXPECT(jrr[jss::offers].isArray());
1370 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1374 env(
offer(account_to_test, USD(50), BTC(250)));
1375 env.require(
offers(account_to_test, 1));
1380 BEAST_EXPECT(jrr[jss::offers].isArray());
1381 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1383 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1393 using namespace jtx;
1398 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1400 Env env{*
this, localFeatures};
1402 auto const gw =
Account{
"gateway"};
1403 auto const alice =
Account{
"alice"};
1404 auto const bob =
Account{
"bob"};
1405 auto const USD = gw[
"USD"];
1406 auto const BTC = gw[
"BTC"];
1410 auto const gw_initial_balance =
drops(1149999730);
1411 auto const alice_initial_balance =
drops(499946999680);
1412 auto const bob_initial_balance =
drops(10199999920);
1413 auto const small_amount =
1414 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1416 env.fund(gw_initial_balance, gw);
1417 env.fund(alice_initial_balance, alice);
1418 env.fund(bob_initial_balance, bob);
1421 env(
rate(gw, 1.005));
1423 env(
trust(alice, USD(500)));
1424 env(
trust(bob, USD(50)));
1425 env(
trust(gw, alice[
"USD"](100)));
1427 env(
pay(gw, alice, alice[
"USD"](50)));
1428 env(
pay(gw, bob, small_amount));
1430 env(
offer(alice, USD(50),
XRP(150000)));
1433 env(
pay(alice, gw, USD(100)));
1436 env(
trust(gw, alice[
"USD"](0)));
1441 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1445 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1446 "-2710505431213761e-33");
1450 env(
offer(bob,
XRP(2000), USD(1)));
1452 if (localFeatures[fixReducedOffersV2])
1459 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1460 "-2710505431213761e-33");
1464 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1465 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1476 auto const crossingDelta =
drops(1);
1480 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1483 alice_initial_balance - env.current()->fees().base * 3 -
1488 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1491 bob_initial_balance - env.current()->fees().base * 2 +
1501 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1503 using namespace jtx;
1505 Env env{*
this, features};
1507 auto const gw =
Account{
"gateway"};
1508 auto const alice =
Account{
"alice"};
1509 auto const bob =
Account{
"bob"};
1510 auto const USD = gw[
"USD"];
1512 env.fund(
XRP(10000), gw, alice, bob);
1515 env(
trust(alice, USD(1000)));
1516 env(
trust(bob, USD(1000)));
1518 env(
pay(gw, alice, alice[
"USD"](500)));
1521 env(
offer(bob, USD(1),
XRP(4000)));
1523 env(
offer(alice,
XRP(150000), USD(50)));
1526 env(
offer(bob, USD(1),
XRP(4000)));
1533 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1536 jrr[jss::node][sfBalance.fieldName] ==
1538 env.current()->fees().base * 2)
1542 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1545 jrr[jss::node][sfBalance.fieldName] ==
1547 env.current()->fees().base * 2)
1554 testcase(
"Offer Crossing with Limit Override");
1556 using namespace jtx;
1558 Env env{*
this, features};
1560 auto const gw =
Account{
"gateway"};
1561 auto const alice =
Account{
"alice"};
1562 auto const bob =
Account{
"bob"};
1563 auto const USD = gw[
"USD"];
1565 env.fund(
XRP(100000), gw, alice, bob);
1568 env(
trust(alice, USD(1000)));
1570 env(
pay(gw, alice, alice[
"USD"](500)));
1572 env(
offer(alice,
XRP(150000), USD(50)));
1573 env(
offer(bob, USD(1),
XRP(3000)));
1576 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1579 jrr[jss::node][sfBalance.fieldName] ==
1584 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1587 jrr[jss::node][sfBalance.fieldName] ==
1595 testcase(
"Offer Accept then Cancel.");
1597 using namespace jtx;
1599 Env env{*
this, features};
1601 auto const USD = env.master[
"USD"];
1603 auto const nextOfferSeq = env.seq(env.master);
1604 env(
offer(env.master,
XRP(500), USD(100)));
1608 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1613 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1619 testcase(
"Offer Cancel Past and Future Sequence.");
1621 using namespace jtx;
1623 Env env{*
this, features};
1625 auto const alice =
Account{
"alice"};
1627 auto const nextOfferSeq = env.seq(env.master);
1628 env.fund(
XRP(10000), alice);
1645 testcase(
"Currency Conversion: Entire Offer");
1647 using namespace jtx;
1649 Env env{*
this, features};
1651 auto const gw =
Account{
"gateway"};
1652 auto const alice =
Account{
"alice"};
1653 auto const bob =
Account{
"bob"};
1654 auto const USD = gw[
"USD"];
1656 env.fund(
XRP(10000), gw, alice, bob);
1658 env.require(
owners(bob, 0));
1660 env(
trust(alice, USD(100)));
1661 env(
trust(bob, USD(1000)));
1665 env(
pay(gw, alice, alice[
"USD"](100)));
1666 auto const bobOfferSeq = env.seq(bob);
1667 env(
offer(bob, USD(100),
XRP(500)));
1672 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1674 jro[jss::node][jss::TakerPays] ==
1680 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1683 jrr[jss::node][sfBalance.fieldName] ==
1688 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1691 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1699 testcase(
"Currency Conversion: Offerer Into Debt");
1701 using namespace jtx;
1703 Env env{*
this, features};
1705 auto const alice =
Account{
"alice"};
1706 auto const bob =
Account{
"bob"};
1707 auto const carol =
Account{
"carol"};
1709 env.fund(
XRP(10000), alice, bob, carol);
1712 env(
trust(alice, carol[
"EUR"](2000)));
1713 env(
trust(bob, alice[
"USD"](100)));
1714 env(
trust(carol, bob[
"EUR"](1000)));
1716 auto const bobOfferSeq = env.seq(bob);
1717 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1720 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1723 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1729 testcase(
"Currency Conversion: In Parts");
1731 using namespace jtx;
1733 Env env{*
this, features};
1735 auto const gw =
Account{
"gateway"};
1736 auto const alice =
Account{
"alice"};
1737 auto const bob =
Account{
"bob"};
1738 auto const USD = gw[
"USD"];
1740 env.fund(
XRP(10000), gw, alice, bob);
1743 env(
trust(alice, USD(200)));
1744 env(
trust(bob, USD(1000)));
1746 env(
pay(gw, alice, alice[
"USD"](200)));
1748 auto const bobOfferSeq = env.seq(bob);
1749 env(
offer(bob, USD(100),
XRP(500)));
1756 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1758 jro[jss::node][jss::TakerPays] ==
1764 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1768 jrr[jss::node][sfBalance.fieldName] ==
1774 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1778 env(
pay(alice, alice,
XRP(600)),
1784 env(
pay(alice, alice,
XRP(600)),
1790 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1798 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1801 jrr[jss::node][sfBalance.fieldName] ==
1803 env.current()->fees().base * 4)
1809 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1815 testcase(
"Cross Currency Payment: Start with XRP");
1817 using namespace jtx;
1819 Env env{*
this, features};
1821 auto const gw =
Account{
"gateway"};
1822 auto const alice =
Account{
"alice"};
1823 auto const bob =
Account{
"bob"};
1824 auto const carol =
Account{
"carol"};
1825 auto const USD = gw[
"USD"];
1827 env.fund(
XRP(10000), gw, alice, bob, carol);
1830 env(
trust(carol, USD(1000)));
1831 env(
trust(bob, USD(2000)));
1833 env(
pay(gw, carol, carol[
"USD"](500)));
1835 auto const carolOfferSeq = env.seq(carol);
1836 env(
offer(carol,
XRP(500), USD(50)));
1841 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1844 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1848 jro[jss::node][jss::TakerGets] ==
1851 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1857 testcase(
"Cross Currency Payment: End with XRP");
1859 using namespace jtx;
1861 Env env{*
this, features};
1863 auto const gw =
Account{
"gateway"};
1864 auto const alice =
Account{
"alice"};
1865 auto const bob =
Account{
"bob"};
1866 auto const carol =
Account{
"carol"};
1867 auto const USD = gw[
"USD"];
1869 env.fund(
XRP(10000), gw, alice, bob, carol);
1872 env(
trust(alice, USD(1000)));
1873 env(
trust(carol, USD(2000)));
1875 env(
pay(gw, alice, alice[
"USD"](500)));
1877 auto const carolOfferSeq = env.seq(carol);
1878 env(
offer(carol, USD(50),
XRP(500)));
1883 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1886 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1890 jrr[jss::node][sfBalance.fieldName] ==
1892 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1896 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1898 jro[jss::node][jss::TakerPays] ==
1905 testcase(
"Cross Currency Payment: Bridged");
1907 using namespace jtx;
1909 Env env{*
this, features};
1911 auto const gw1 =
Account{
"gateway_1"};
1912 auto const gw2 =
Account{
"gateway_2"};
1913 auto const alice =
Account{
"alice"};
1914 auto const bob =
Account{
"bob"};
1915 auto const carol =
Account{
"carol"};
1916 auto const dan =
Account{
"dan"};
1917 auto const USD = gw1[
"USD"];
1918 auto const EUR = gw2[
"EUR"];
1920 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1923 env(
trust(alice, USD(1000)));
1924 env(
trust(bob, EUR(1000)));
1925 env(
trust(carol, USD(1000)));
1926 env(
trust(dan, EUR(1000)));
1928 env(
pay(gw1, alice, alice[
"USD"](500)));
1929 env(
pay(gw2, dan, dan[
"EUR"](400)));
1931 auto const carolOfferSeq = env.seq(carol);
1932 env(
offer(carol, USD(50),
XRP(500)));
1934 auto const danOfferSeq = env.seq(dan);
1935 env(
offer(dan,
XRP(500), EUR(50)));
1938 jtp[0u][0u][jss::currency] =
"XRP";
1939 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1942 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1945 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1948 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1951 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1955 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1957 jro[jss::node][jss::TakerPays] ==
1962 jro[jss::node][jss::TakerGets] ==
1965 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1974 testcase(
"Auto Bridged Second Leg Dry");
1976 using namespace jtx;
1977 Env env(*
this, features);
1983 auto const USD = gw[
"USD"];
1984 auto const EUR = gw[
"EUR"];
1986 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1989 env.
trust(USD(10), alice);
1991 env(
pay(gw, alice, USD(10)));
1992 env.
trust(USD(10), carol);
1994 env(
pay(gw, carol, USD(3)));
2011 env.
trust(EUR(10), bob);
2013 env(
pay(gw, bob, EUR(10)));
2015 env(
offer(bob, USD(10), EUR(10)));
2038 testcase(
"Offer Fees Consume Funds");
2040 using namespace jtx;
2042 Env env{*
this, features};
2044 auto const gw1 =
Account{
"gateway_1"};
2045 auto const gw2 =
Account{
"gateway_2"};
2046 auto const gw3 =
Account{
"gateway_3"};
2047 auto const alice =
Account{
"alice"};
2048 auto const bob =
Account{
"bob"};
2049 auto const USD1 = gw1[
"USD"];
2050 auto const USD2 = gw2[
"USD"];
2051 auto const USD3 = gw3[
"USD"];
2059 auto const starting_xrp =
XRP(100) +
2060 env.current()->fees().accountReserve(3) +
2061 env.current()->fees().base * 4;
2063 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2066 env(
trust(alice, USD1(1000)));
2067 env(
trust(alice, USD2(1000)));
2068 env(
trust(alice, USD3(1000)));
2069 env(
trust(bob, USD1(1000)));
2070 env(
trust(bob, USD2(1000)));
2072 env(
pay(gw1, bob, bob[
"USD"](500)));
2074 env(
offer(bob,
XRP(200), USD1(200)));
2077 env(
offer(alice, USD1(200),
XRP(200)));
2080 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2083 jrr[jss::node][sfBalance.fieldName] ==
2087 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2093 testcase(
"Offer Create, then Cross");
2095 using namespace jtx;
2097 for (
auto NumberSwitchOver : {
false,
true})
2099 Env env{*
this, features};
2100 if (NumberSwitchOver)
2101 env.enableFeature(fixUniversalNumber);
2103 env.disableFeature(fixUniversalNumber);
2105 auto const gw =
Account{
"gateway"};
2106 auto const alice =
Account{
"alice"};
2107 auto const bob =
Account{
"bob"};
2108 auto const USD = gw[
"USD"];
2110 env.fund(
XRP(10000), gw, alice, bob);
2113 env(
rate(gw, 1.005));
2115 env(
trust(alice, USD(1000)));
2116 env(
trust(bob, USD(1000)));
2117 env(
trust(gw, alice[
"USD"](50)));
2119 env(
pay(gw, bob, bob[
"USD"](1)));
2120 env(
pay(alice, gw, USD(50)));
2122 env(
trust(gw, alice[
"USD"](0)));
2124 env(
offer(alice, USD(50),
XRP(150000)));
2125 env(
offer(bob,
XRP(100), USD(0.1)));
2129 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2130 "49.96666666666667");
2134 jrr[jss::node][sfBalance.fieldName][jss::value];
2135 if (!NumberSwitchOver)
2137 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2141 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2149 testcase(
"Offer tfSell: Basic Sell");
2151 using namespace jtx;
2153 Env env{*
this, features};
2155 auto const gw =
Account{
"gateway"};
2156 auto const alice =
Account{
"alice"};
2157 auto const bob =
Account{
"bob"};
2158 auto const USD = gw[
"USD"];
2160 auto const starting_xrp =
XRP(100) +
2161 env.current()->fees().accountReserve(1) +
2162 env.current()->fees().base * 2;
2164 env.fund(starting_xrp, gw, alice, bob);
2167 env(
trust(alice, USD(1000)));
2168 env(
trust(bob, USD(1000)));
2170 env(
pay(gw, bob, bob[
"USD"](500)));
2179 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2182 jrr[jss::node][sfBalance.fieldName] ==
2186 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2192 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2194 using namespace jtx;
2196 Env env{*
this, features};
2198 auto const gw =
Account{
"gateway"};
2199 auto const alice =
Account{
"alice"};
2200 auto const bob =
Account{
"bob"};
2201 auto const USD = gw[
"USD"];
2203 auto const starting_xrp =
XRP(100) +
2204 env.current()->fees().accountReserve(1) +
2205 env.current()->fees().base * 2;
2207 env.fund(starting_xrp, gw, alice, bob);
2210 env(
trust(alice, USD(150)));
2211 env(
trust(bob, USD(1000)));
2213 env(
pay(gw, bob, bob[
"USD"](500)));
2215 env(
offer(bob,
XRP(100), USD(200)));
2224 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2227 jrr[jss::node][sfBalance.fieldName] ==
2231 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2237 testcase(
"Client Issue #535: Gateway Cross Currency");
2239 using namespace jtx;
2241 Env env{*
this, features};
2243 auto const gw =
Account{
"gateway"};
2244 auto const alice =
Account{
"alice"};
2245 auto const bob =
Account{
"bob"};
2246 auto const XTS = gw[
"XTS"];
2247 auto const XXX = gw[
"XXX"];
2249 auto const starting_xrp =
XRP(100.1) +
2250 env.current()->fees().accountReserve(1) +
2251 env.current()->fees().base * 2;
2253 env.fund(starting_xrp, gw, alice, bob);
2256 env(
trust(alice, XTS(1000)));
2257 env(
trust(alice, XXX(1000)));
2258 env(
trust(bob, XTS(1000)));
2259 env(
trust(bob, XXX(1000)));
2261 env(
pay(gw, alice, alice[
"XTS"](100)));
2262 env(
pay(gw, alice, alice[
"XXX"](100)));
2263 env(
pay(gw, bob, bob[
"XTS"](100)));
2264 env(
pay(gw, bob, bob[
"XXX"](100)));
2266 env(
offer(alice, XTS(100), XXX(100)));
2273 payment[jss::id] = env.seq(bob);
2274 payment[jss::build_path] =
true;
2275 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2276 payment[jss::tx_json][jss::Sequence] =
2279 ->getFieldU32(sfSequence);
2280 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2281 payment[jss::tx_json][jss::SendMax] =
2283 auto jrr = wsc->invoke(
"submit", payment);
2284 BEAST_EXPECT(jrr[jss::status] ==
"success");
2285 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2286 if (wsc->version() == 2)
2289 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2291 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2292 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2296 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2298 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2301 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2303 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2318 auto const sleTrust =
2320 BEAST_EXPECT(sleTrust);
2324 bool const accountLow = account.id() < issue.
account;
2329 low.setIssuer(accountLow ? account.id() : issue.
account);
2330 high.setIssuer(accountLow ? issue.
account : account.id());
2332 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2333 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2335 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2339 BEAST_EXPECT(actualBalance == expectBalance);
2351 using namespace jtx;
2353 auto const gw =
Account(
"gateway");
2354 auto const USD = gw[
"USD"];
2356 Env env{*
this, features};
2358 env.fund(
XRP(10000000), gw);
2362 auto const f = env.current()->fees().base;
2365 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2371 preTrustType preTrust;
2381 TestData
const tests[]{
2383 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2384 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2385 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2386 {
"deb",
drops(10) +
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 1},
2387 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2388 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2389 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2390 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2391 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2392 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2393 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2394 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2395 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2396 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2397 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2398 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2399 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2400 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2402 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2403 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2404 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2405 {
"dan",
drops(10) +
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 0},
2406 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2407 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2408 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2409 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2411 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2412 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2413 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2414 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2415 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2416 {
"syd",
drops(10) +
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
drops(10) + 2 * f, USD(0.00001), 0, 1},
2417 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2418 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2419 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2420 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2421 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2425 for (
auto const& t : tests)
2427 auto const acct =
Account(t.account);
2428 env.fund(t.fundXrp, acct);
2432 env.require(
offers(gw, 0));
2435 auto const book = t.bookAmount;
2437 env(
offer(gw,
XRP(book), USD(book)));
2442 if (t.preTrust == gwPreTrust)
2443 env(
trust(gw, acct[
"USD"](1)));
2449 if (t.preTrust == acctPreTrust)
2450 env(
trust(acct, USD(1)));
2455 auto const acctOffer = t.offerAmount;
2456 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2461 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2463 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2464 env.require(
offers(acct, t.offers));
2465 env.require(
owners(acct, t.owners));
2468 BEAST_EXPECT(acctOffers.size() == t.offers);
2469 if (acctOffers.size() && t.offers)
2471 auto const& acctOffer = *(acctOffers.front());
2473 auto const leftover = t.offerAmount - t.bookAmount;
2474 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2475 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2478 if (t.preTrust == noPreTrust)
2480 if (t.balanceUsd.value().signum())
2488 auto const sleTrust =
2490 BEAST_EXPECT(!sleTrust);
2507 using namespace jtx;
2509 auto const gw =
Account(
"gateway");
2510 auto const alice =
Account(
"alice");
2511 auto const bob =
Account(
"bob");
2512 auto const USD = gw[
"USD"];
2514 auto const usdOffer = USD(1000);
2515 auto const xrpOffer =
XRP(1000);
2517 Env env{*
this, features};
2519 env.fund(
XRP(1000000), gw, bob);
2523 auto const fee = env.current()->fees().base;
2530 env(
trust(alice, usdOffer));
2534 env(
pay(gw, alice, usdOffer));
2541 auto const alicesXRP = env.balance(alice);
2542 auto const bobsXRP = env.balance(bob);
2544 env(
offer(alice, xrpOffer, usdOffer));
2546 env(
offer(bob, usdOffer, xrpOffer));
2560 env(
offer(alice, USD(999),
XRP(999)));
2561 env(
offer(bob, xrpOffer, usdOffer));
2564 env.require(
balance(alice, USD(999)));
2565 env.require(
balance(bob, USD(1)));
2566 env.require(
offers(alice, 0));
2570 BEAST_EXPECT(bobsOffers.size() == 1);
2571 auto const& bobsOffer = *(bobsOffers.front());
2573 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2574 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2575 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2584 using namespace jtx;
2586 auto const gw =
Account(
"gateway");
2587 auto const alice =
Account(
"alice");
2588 auto const bob =
Account(
"bob");
2589 auto const USD = gw[
"USD"];
2590 auto const EUR = gw[
"EUR"];
2592 auto const usdOffer = USD(1000);
2593 auto const eurOffer = EUR(1000);
2595 Env env{*
this, features};
2597 env.fund(
XRP(1000000), gw);
2601 auto const fee = env.current()->fees().base;
2609 env(
trust(alice, usdOffer));
2610 env(
trust(bob, eurOffer));
2613 env(
pay(gw, alice, usdOffer));
2614 env(
pay(gw, bob, eurOffer));
2622 env(
offer(alice, eurOffer, usdOffer));
2623 env(
offer(bob, usdOffer, eurOffer));
2640 env(
offer(bob, eurOffer, usdOffer));
2643 env(
offer(alice, USD(999), eurOffer));
2646 env.require(
offers(alice, 0));
2647 env.require(
offers(bob, 1));
2649 env.require(
balance(alice, USD(999)));
2650 env.require(
balance(alice, EUR(1)));
2651 env.require(
balance(bob, USD(1)));
2652 env.require(
balance(bob, EUR(999)));
2656 if (BEAST_EXPECT(bobsOffers.size() == 1))
2658 auto const& bobsOffer = *(bobsOffers.front());
2660 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2661 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2666 env(
offer(alice, USD(1), EUR(1)));
2669 env.require(
balance(alice, USD(1000)));
2672 env.require(
balance(bob, EUR(1000)));
2673 env.require(
offers(alice, 0));
2674 env.require(
offers(bob, 0));
2677 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2678 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2682 env(
offer(alice, EUR(999), usdOffer));
2685 env(
offer(bob, usdOffer, eurOffer));
2688 env.require(
offers(alice, 0));
2689 env.require(
offers(bob, 0));
2691 env.require(
balance(alice, USD(0)));
2692 env.require(
balance(alice, EUR(999)));
2693 env.require(
balance(bob, USD(1000)));
2694 env.require(
balance(bob, EUR(1)));
2702 using namespace jtx;
2704 auto const gw =
Account(
"gateway");
2705 auto const alice =
Account(
"alice");
2706 auto const bob =
Account(
"bob");
2707 auto const carol =
Account(
"carol");
2708 auto const USD = gw[
"USD"];
2709 auto const EUR = gw[
"EUR"];
2711 auto const usdOffer = USD(1000);
2712 auto const eurOffer = EUR(1000);
2714 Env env{*
this, features};
2716 env.fund(
XRP(1000000), gw, alice, bob, carol);
2719 env(
trust(alice, usdOffer));
2720 env(
trust(carol, eurOffer));
2722 env(
pay(gw, alice, usdOffer));
2723 env(
pay(gw, carol, eurOffer));
2732 env(
offer(alice,
XRP(1000), usdOffer));
2733 env(
offer(bob, eurOffer,
XRP(1000)));
2734 auto const bobXrpBalance = env.balance(bob);
2738 env(
offer(carol, USD(400), EUR(400)));
2751 BEAST_EXPECT(alicesOffers.size() == 1);
2752 auto const& alicesOffer = *(alicesOffers.front());
2754 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2755 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2756 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2760 BEAST_EXPECT(bobsOffers.size() == 1);
2761 auto const& bobsOffer = *(bobsOffers.front());
2763 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2764 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2765 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2769 env(
offer(carol, USD(600), EUR(600)));
2784 if (alicesOffers.size() != 0)
2786 BEAST_EXPECT(alicesOffers.size() == 1);
2787 auto const& alicesOffer = *(alicesOffers.front());
2789 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2790 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2791 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2803 using namespace jtx;
2805 auto const gw =
Account(
"gateway");
2806 auto const USD = gw[
"USD"];
2808 Env env{*
this, features};
2810 env.fund(
XRP(10000000), gw);
2814 auto const f = env.current()->fees().base;
2817 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2851 : account(std::move(account_))
2856 , acctGets(acctGets_)
2857 , acctPays(acctPays_)
2859 , spentXrp(spentXrp_)
2860 , finalUsd(finalUsd_)
2863 , takerGets(takerGets_)
2864 , takerPays(takerPays_)
2883 std::move(account_),
2902 TestData
const tests[]{
2905 {
"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},
2906 {
"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)},
2907 {
"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},
2908 {
"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},
2909 {
"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},
2910 {
"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},
2911 {
"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},
2912 {
"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)},
2914 {
"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},
2915 {
"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)},
2916 {
"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},
2917 {
"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},
2918 {
"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},
2919 {
"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)},
2920 {
"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)},
2924 auto const zeroUsd = USD(0);
2925 for (
auto const& t : tests)
2928 env.require(
offers(gw, 0));
2930 auto const acct =
Account(t.account);
2932 env.fund(t.fundXrp, acct);
2938 if (t.fundUSD != zeroUsd)
2940 env(
trust(acct, t.fundUSD));
2942 env(
pay(gw, acct, t.fundUSD));
2946 env(
offer(gw, t.gwGets, t.gwPays));
2956 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2958 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2959 env.require(
offers(acct, t.offers));
2960 env.require(
owners(acct, t.owners));
2965 if (acctOffers.size() > 0)
2967 BEAST_EXPECT(acctOffers.size() == 1);
2968 auto const& acctOffer = *(acctOffers.front());
2970 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2971 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2972 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2989 testcase(
"Combine tfSell with tfFillOrKill");
2991 using namespace jtx;
2993 auto const gw =
Account(
"gateway");
2994 auto const alice =
Account(
"alice");
2995 auto const bob =
Account(
"bob");
2996 auto const USD = gw[
"USD"];
2998 Env env{*
this, features};
3000 env.fund(
XRP(10000000), gw, alice, bob);
3007 env(
trust(bob, USD(200)));
3009 env(
pay(gw, bob, USD(100)));
3011 env(
offer(bob,
XRP(2000), USD(20)));
3019 env.require(
offers(alice, 0));
3020 env.require(
balance(bob, USD(100)));
3027 env.require(
balance(alice, USD(20)));
3028 env.require(
offers(alice, 0));
3029 env.require(
balance(bob, USD(80)));
3034 env(
offer(bob,
XRP(2000), USD(20)));
3038 env.require(
balance(alice, USD(35)));
3039 env.require(
offers(alice, 0));
3040 env.require(
balance(bob, USD(65)));
3052 env.require(
balance(alice, USD(35)));
3053 env.require(
offers(alice, 0));
3054 env.require(
balance(bob, USD(65)));
3063 env.require(
balance(alice, USD(40)));
3064 env.require(
offers(alice, 0));
3065 env.require(
balance(bob, USD(60)));
3074 using namespace jtx;
3076 auto const gw1 =
Account(
"gateway1");
3077 auto const USD = gw1[
"USD"];
3079 Env env{*
this, features};
3082 auto const fee = env.current()->fees().base;
3084 env.fund(
XRP(100000), gw1);
3087 env(
rate(gw1, 1.25));
3089 auto const ann =
Account(
"ann");
3090 auto const bob =
Account(
"bob");
3094 env(
trust(ann, USD(200)));
3095 env(
trust(bob, USD(200)));
3098 env(
pay(gw1, bob, USD(125)));
3113 env.require(
balance(ann, USD(100)));
3115 env.require(
offers(ann, 0));
3117 env.require(
balance(bob, USD(0)));
3119 env.require(
offers(bob, 0));
3124 auto const che =
Account(
"che");
3125 auto const deb =
Account(
"deb");
3129 env(
trust(che, USD(200)));
3130 env(
trust(deb, USD(200)));
3133 env(
pay(gw1, deb, USD(125)));
3142 env.require(
balance(che, USD(100)));
3144 env.require(
offers(che, 0));
3146 env.require(
balance(deb, USD(0)));
3148 env.require(
offers(deb, 0));
3151 auto const eve =
Account(
"eve");
3152 auto const fyn =
Account(
"fyn");
3154 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3157 env(
trust(eve, USD(1000)));
3158 env(
trust(fyn, USD(1000)));
3161 env(
pay(gw1, eve, USD(100)));
3162 env(
pay(gw1, fyn, USD(100)));
3168 env(
offer(eve, USD(10),
XRP(4000)));
3172 env(
offer(fyn,
XRP(2000), USD(5)));
3175 env.require(
balance(eve, USD(105)));
3178 BEAST_EXPECT(evesOffers.size() == 1);
3179 if (evesOffers.size() != 0)
3181 auto const& evesOffer = *(evesOffers.front());
3182 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3183 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3184 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3188 env.require(
balance(fyn, USD(93.75)));
3190 env.require(
offers(fyn, 0));
3193 auto const gw2 =
Account(
"gateway2");
3194 auto const EUR = gw2[
"EUR"];
3196 env.fund(
XRP(100000), gw2);
3199 env(
rate(gw2, 1.5));
3204 auto const gay =
Account(
"gay");
3205 auto const hal =
Account(
"hal");
3206 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3209 env(
trust(gay, USD(200)));
3210 env(
trust(gay, EUR(200)));
3211 env(
trust(hal, USD(200)));
3212 env(
trust(hal, EUR(200)));
3215 env(
pay(gw1, gay, USD(125)));
3216 env(
pay(gw2, hal, EUR(150)));
3219 env(
offer(gay, EUR(100), USD(100)));
3222 env(
offer(hal, USD(100), EUR(100)));
3225 env.require(
balance(gay, USD(0)));
3226 env.require(
balance(gay, EUR(100)));
3228 env.require(
offers(gay, 0));
3230 env.require(
balance(hal, USD(100)));
3231 env.require(
balance(hal, EUR(0)));
3233 env.require(
offers(hal, 0));
3237 auto const ivy =
Account(
"ivy");
3238 auto const joe =
Account(
"joe");
3239 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3248 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3249 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3251 env.require(
balance(ivy, USD(300)));
3252 env.require(
balance(joe, EUR(250)));
3254 env(
offer(ivy, EUR(100), USD(200)));
3257 env(
offer(joe, USD(200), EUR(100)));
3260 env.require(
balance(ivy, USD(50)));
3261 env.require(
balance(ivy, EUR(100)));
3263 env.require(
offers(ivy, 0));
3265 env.require(
balance(joe, USD(200)));
3266 env.require(
balance(joe, EUR(100)));
3268 env.require(
offers(joe, 0));
3272 auto const kim =
Account(
"kim");
3273 auto const K_BUX = kim[
"BUX"];
3274 auto const lex =
Account(
"lex");
3275 auto const meg =
Account(
"meg");
3276 auto const ned =
Account(
"ned");
3277 auto const N_BUX = ned[
"BUX"];
3280 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3283 env(
trust(lex, K_BUX(400)));
3285 env(
trust(meg, N_BUX(100)));
3287 env(
pay(ned, lex, N_BUX(100)));
3289 env.require(
balance(lex, N_BUX(100)));
3291 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3296 env.require(
balance(lex, K_BUX(72)));
3297 env.require(
balance(lex, N_BUX(40)));
3299 env.require(
balance(meg, N_BUX(60)));
3304 env(
offer(lex, K_BUX(30), N_BUX(30)));
3307 env(
offer(kim, N_BUX(30), K_BUX(30)));
3311 env.require(
balance(kim, N_BUX(30)));
3312 env.require(
balance(lex, K_BUX(102)));
3313 env.require(
balance(lex, N_BUX(10)));
3315 env.require(
balance(meg, N_BUX(60)));
3316 env.require(
balance(ned, K_BUX(-30)));
3321 auto const ova =
Account(
"ova");
3322 auto const pat =
Account(
"pat");
3323 auto const qae =
Account(
"qae");
3324 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3330 env(
trust(ova, USD(200)));
3331 env(
trust(ova, EUR(200)));
3332 env(
trust(pat, USD(200)));
3333 env(
trust(pat, EUR(200)));
3334 env(
trust(qae, USD(200)));
3335 env(
trust(qae, EUR(200)));
3338 env(
pay(gw1, ova, USD(125)));
3339 env(
pay(gw2, qae, EUR(150)));
3346 env(
offer(qae, USD(100), EUR(100)));
3349 env.require(
balance(ova, USD(0)));
3350 env.require(
balance(ova, EUR(0)));
3355 if (ovasOffers.size() != 0)
3357 BEAST_EXPECT(ovasOffers.size() == 1);
3358 auto const& ovasOffer = *(ovasOffers.front());
3360 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3361 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3362 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3365 env.require(
balance(pat, USD(0)));
3366 env.require(
balance(pat, EUR(100)));
3368 env.require(
offers(pat, 0));
3370 env.require(
balance(qae, USD(100)));
3371 env.require(
balance(qae, EUR(0)));
3373 env.require(
offers(qae, 0));
3394 using namespace jtx;
3396 auto const gw =
Account(
"gateway");
3397 auto const USD = gw[
"USD"];
3399 Env env{*
this, features};
3402 auto const fee = env.current()->fees().base;
3403 auto const startBalance =
XRP(1000000);
3405 env.fund(startBalance + (
fee * 4), gw);
3415 env.require(
owners(gw, 3));
3416 env.require(
balance(gw, startBalance +
fee));
3419 BEAST_EXPECT(gwOffers.size() == 3);
3420 for (
auto const& offerPtr : gwOffers)
3422 auto const&
offer = *offerPtr;
3423 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3424 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3425 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3430 env(
offer(gw,
XRP(1000), USD(100)));
3432 env.require(
owners(gw, 1));
3433 env.require(
offers(gw, 1));
3434 env.require(
balance(gw, startBalance));
3437 BEAST_EXPECT(gwOffers.size() == 1);
3438 for (
auto const& offerPtr : gwOffers)
3440 auto const&
offer = *offerPtr;
3441 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3442 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3443 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3450 using namespace jtx;
3452 auto const gw1 =
Account(
"gateway1");
3453 auto const gw2 =
Account(
"gateway2");
3454 auto const alice =
Account(
"alice");
3455 auto const USD = gw1[
"USD"];
3456 auto const EUR = gw2[
"EUR"];
3458 Env env{*
this, features};
3460 env.fund(
XRP(1000000), gw1, gw2);
3464 auto const f = env.current()->fees().base;
3478 TestData
const tests[]{
3489 for (
auto const& t : tests)
3491 auto const acct =
Account{t.acct};
3492 env.fund(t.fundXRP, acct);
3495 env(
trust(acct, USD(1000)));
3496 env(
trust(acct, EUR(1000)));
3499 if (t.fundUSD > USD(0))
3500 env(
pay(gw1, acct, t.fundUSD));
3501 if (t.fundEUR > EUR(0))
3502 env(
pay(gw2, acct, t.fundEUR));
3505 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3509 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3510 env.require(
owners(acct, 2 + offerCount));
3511 env.require(
balance(acct, t.fundUSD));
3512 env.require(
balance(acct, t.fundEUR));
3515 BEAST_EXPECT(acctOffers.size() == offerCount);
3516 for (
auto const& offerPtr : acctOffers)
3518 auto const&
offer = *offerPtr;
3519 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3520 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3521 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3524 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3528 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3529 env.require(
owners(acct, 2 + offerCount));
3530 env.require(
balance(acct, t.fundUSD));
3531 env.require(
balance(acct, t.fundEUR));
3534 BEAST_EXPECT(acctOffers.size() == offerCount);
3535 for (
auto const& offerPtr : acctOffers)
3537 auto const&
offer = *offerPtr;
3538 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3539 if (
offer[sfSequence] == firstOfferSeq)
3541 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3542 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3546 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3547 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3574 using namespace jtx;
3576 Env env{*
this, features};
3578 auto const alice =
Account(
"alice");
3579 auto const bob =
Account(
"bob");
3580 auto const USD = bob[
"USD"];
3581 auto const f = env.current()->fees().base;
3583 env.fund(
XRP(50000) + f, alice, bob);
3586 env(
offer(alice, USD(5000),
XRP(50000)));
3590 env(
offer(bob,
XRP(50000), USD(5000)));
3596 env.require(
owners(alice, 1));
3597 env.require(
lines(alice, 1));
3602 BEAST_EXPECT(bobOffers.size() == 1);
3603 for (
auto const& offerPtr : bobOffers)
3605 auto const&
offer = *offerPtr;
3606 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3607 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3608 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3620 using namespace jtx;
3622 Env env{*
this, features};
3625 auto const fee = env.current()->fees().base;
3628 auto const ann =
Account(
"ann");
3629 auto const A_BUX = ann[
"BUX"];
3630 auto const bob =
Account(
"bob");
3631 auto const cam =
Account(
"cam");
3632 auto const dan =
Account(
"dan");
3633 auto const D_BUX = dan[
"BUX"];
3636 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3639 env(
trust(bob, A_BUX(400)));
3641 env(
trust(cam, D_BUX(100)));
3643 env(
pay(dan, bob, D_BUX(100)));
3645 env.require(
balance(bob, D_BUX(100)));
3647 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3652 env.require(
balance(bob, A_BUX(72)));
3653 env.require(
balance(bob, D_BUX(40)));
3655 env.require(
balance(cam, D_BUX(60)));
3659 env(
offer(bob, A_BUX(30), D_BUX(30)));
3662 env(
trust(ann, D_BUX(100)));
3666 env(
pay(ann, ann, D_BUX(30)),
3673 env.require(
balance(ann, D_BUX(0)));
3674 env.require(
balance(bob, A_BUX(72)));
3675 env.require(
balance(bob, D_BUX(40)));
3677 env.require(
balance(cam, D_BUX(60)));
3678 env.require(
balance(dan, A_BUX(0)));
3692 using namespace jtx;
3694 Env env{*
this, features};
3696 auto const ann =
Account(
"ann");
3697 auto const bob =
Account(
"bob");
3698 auto const cam =
Account(
"cam");
3699 auto const A_BUX = ann[
"BUX"];
3700 auto const B_BUX = bob[
"BUX"];
3702 auto const fee = env.current()->fees().base;
3703 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3706 env(
trust(ann, B_BUX(40)));
3707 env(
trust(cam, A_BUX(40)));
3708 env(
trust(cam, B_BUX(40)));
3711 env(
pay(ann, cam, A_BUX(35)));
3712 env(
pay(bob, cam, B_BUX(35)));
3714 env(
offer(bob, A_BUX(30), B_BUX(30)));
3722 env.require(
balance(cam, A_BUX(35)));
3723 env.require(
balance(cam, B_BUX(35)));
3724 env.require(
offers(cam, 1));
3727 env(
offer(cam, B_BUX(30), A_BUX(30)));
3730 env.require(
balance(bob, A_BUX(30)));
3731 env.require(
balance(cam, A_BUX(5)));
3732 env.require(
balance(cam, B_BUX(65)));
3733 env.require(
offers(cam, 0));
3742 testcase(
"Self crossing low quality offer");
3744 using namespace jtx;
3746 Env env{*
this, features};
3748 auto const ann =
Account(
"ann");
3749 auto const gw =
Account(
"gateway");
3750 auto const BTC = gw[
"BTC"];
3752 auto const fee = env.current()->fees().base;
3757 env(
rate(gw, 1.002));
3758 env(
trust(ann, BTC(10)));
3761 env(
pay(gw, ann, BTC(2.856)));
3764 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3768 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3781 using namespace jtx;
3783 Env env{*
this, features};
3785 auto const gw =
Account(
"gateway");
3786 auto const alice =
Account(
"alice");
3787 auto const bob =
Account(
"bob");
3788 auto const CNY = gw[
"CNY"];
3790 auto const fee = env.current()->fees().base;
3795 env(
trust(bob, CNY(500)));
3798 env(
pay(gw, bob, CNY(300)));
3801 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3805 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3809 BEAST_EXPECT(aliceOffers.size() == 1);
3810 for (
auto const& offerPtr : aliceOffers)
3812 auto const&
offer = *offerPtr;
3813 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3814 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3815 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3825 testcase(
"Offer In Scaling With Xfer Rate");
3827 using namespace jtx;
3829 Env env{*
this, features};
3831 auto const gw =
Account(
"gateway");
3832 auto const alice =
Account(
"alice");
3833 auto const bob =
Account(
"bob");
3834 auto const BTC = gw[
"BTC"];
3835 auto const JPY = gw[
"JPY"];
3837 auto const fee = env.current()->fees().base;
3842 env(
rate(gw, 1.002));
3843 env(
trust(alice, JPY(4000)));
3844 env(
trust(bob, BTC(2)));
3847 env(
pay(gw, alice, JPY(3699.034802280317)));
3848 env(
pay(gw, bob, BTC(1.156722559140311)));
3851 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3855 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3859 BEAST_EXPECT(aliceOffers.size() == 1);
3860 for (
auto const& offerPtr : aliceOffers)
3862 auto const&
offer = *offerPtr;
3863 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3865 offer[sfTakerGets] ==
3867 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3877 testcase(
"Offer Threshold With Reduced Funds");
3879 using namespace jtx;
3881 Env env{*
this, features};
3883 auto const gw1 =
Account(
"gw1");
3884 auto const gw2 =
Account(
"gw2");
3885 auto const alice =
Account(
"alice");
3886 auto const bob =
Account(
"bob");
3887 auto const USD = gw1[
"USD"];
3888 auto const JPY = gw2[
"JPY"];
3890 auto const fee = env.current()->fees().base;
3892 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3895 env(
rate(gw1, 1.002));
3896 env(
trust(alice, USD(1000)));
3897 env(
trust(bob, JPY(100000)));
3924 BEAST_EXPECT(aliceOffers.size() == 1);
3925 for (
auto const& offerPtr : aliceOffers)
3927 auto const&
offer = *offerPtr;
3928 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3930 offer[sfTakerGets] ==
3933 offer[sfTakerPays] ==
3943 using namespace jtx;
3945 Env env{*
this, features};
3947 auto const gw =
Account(
"gw");
3948 auto const alice =
Account(
"alice");
3949 auto const bob =
Account(
"bob");
3950 auto const CNY = gw[
"CNY"];
3951 auto const fee = env.current()->fees().base;
3952 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3954 env.fund(startXrpBalance, gw, alice, bob);
3957 env(
trust(bob, CNY(100000)));
3969 STAmount const bobsCnyStartBalance{
3971 env(
pay(gw, bob, bobsCnyStartBalance));
3980 env.require(
balance(alice, alicesCnyOffer));
3982 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
4025 using namespace jtx;
4027 Env env{*
this, features};
4028 auto const baseFee = env.current()->fees().base.drops();
4030 auto const gw =
Account(
"gw");
4031 auto const BTC = gw[
"BTC"];
4032 auto const USD = gw[
"USD"];
4033 auto const startXrpBalance =
XRP(4000000);
4035 env.fund(startXrpBalance, gw);
4038 env(
rate(gw, 1.25));
4064 TestData
const tests[]{
4066 {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)}}},
4067 {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)}}},
4068 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
4069 {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)}}},
4073 for (
auto const& t : tests)
4075 Account const& self = t.actors[t.self].acct;
4076 Account const& leg0 = t.actors[t.leg0].acct;
4077 Account const& leg1 = t.actors[t.leg1].acct;
4079 for (
auto const& actor : t.actors)
4081 env.fund(
XRP(4000000), actor.acct);
4084 env(
trust(actor.acct, BTC(40)));
4085 env(
trust(actor.acct, USD(8000)));
4089 env(
pay(gw, self, t.btcStart));
4090 env(
pay(gw, self, USD(2000)));
4091 if (self.
id() != leg1.
id())
4092 env(
pay(gw, leg1, USD(2000)));
4106 env(
offer(self, USD(1000), BTC(10)));
4111 for (
auto const& actor : t.actors)
4117 actorOffers.begin(),
4119 actorOffers.begin(),
4122 return (*offer)[sfTakerGets].signum() == 0;
4124 BEAST_EXPECT(offerCount == actor.offers);
4126 env.require(
balance(actor.acct, actor.xrp));
4127 env.require(
balance(actor.acct, actor.btc));
4128 env.require(
balance(actor.acct, actor.usd));
4144 testcase(
"Self Pay Unlimited Funds");
4176 using namespace jtx;
4178 Env env{*
this, features};
4179 auto const baseFee = env.current()->fees().base.drops();
4181 auto const gw =
Account(
"gw");
4182 auto const BTC = gw[
"BTC"];
4183 auto const USD = gw[
"USD"];
4184 auto const startXrpBalance =
XRP(4000000);
4186 env.fund(startXrpBalance, gw);
4189 env(
rate(gw, 1.25));
4215 TestData
const tests[]{
4217 {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)}}},
4218 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4222 for (
auto const& t : tests)
4224 Account const& self = t.actors[t.self].acct;
4225 Account const& leg0 = t.actors[t.leg0].acct;
4226 Account const& leg1 = t.actors[t.leg1].acct;
4228 for (
auto const& actor : t.actors)
4230 env.fund(
XRP(4000000), actor.acct);
4233 env(
trust(actor.acct, BTC(40)));
4234 env(
trust(actor.acct, USD(8000)));
4238 env(
pay(gw, self, t.btcStart));
4239 env(
pay(gw, self, USD(2000)));
4240 if (self.
id() != leg1.
id())
4241 env(
pay(gw, leg1, USD(2000)));
4255 env(
offer(self, USD(1000), BTC(10)));
4260 for (
auto const& actor : t.actors)
4266 actorOffers.begin(),
4268 actorOffers.begin(),
4271 return (*offer)[sfTakerGets].signum() == 0;
4273 BEAST_EXPECT(offerCount == actor.offers);
4275 env.require(
balance(actor.acct, actor.xrp));
4276 env.require(
balance(actor.acct, actor.btc));
4277 env.require(
balance(actor.acct, actor.usd));
4295 using namespace jtx;
4297 Env env{*
this, features};
4299 auto const gw =
Account(
"gw");
4300 auto const alice =
Account(
"alice");
4301 auto const bob =
Account(
"bob");
4302 auto const gwUSD = gw[
"USD"];
4303 auto const aliceUSD = alice[
"USD"];
4304 auto const bobUSD = bob[
"USD"];
4306 env.fund(
XRP(400000), gw, alice, bob);
4315 env(
trust(bob, gwUSD(100)));
4317 env(
trust(alice, gwUSD(100)));
4319 env(
offer(alice, gwUSD(40),
XRP(4000)));
4322 env.require(
offers(alice, 1));
4323 env.require(
balance(alice, gwUSD(0)));
4325 env(
pay(gw, bob, gwUSD(50)));
4328 env.require(
balance(bob, gwUSD(50)));
4331 env(
offer(bob,
XRP(4000), gwUSD(40)));
4334 env.require(
offers(alice, 0));
4335 env.require(
balance(alice, gwUSD(40)));
4337 env.require(
offers(bob, 0));
4338 env.require(
balance(bob, gwUSD(10)));
4363 using namespace jtx;
4365 Env env{*
this, features};
4367 auto const gw =
Account(
"gw");
4368 auto const alice =
Account(
"alice");
4369 auto const bob =
Account(
"bob");
4370 auto const gwUSD = gw[
"USD"];
4371 auto const aliceUSD = alice[
"USD"];
4372 auto const bobUSD = bob[
"USD"];
4374 env.fund(
XRP(400000), gw, alice, bob);
4377 env(
offer(alice, gwUSD(40),
XRP(4000)));
4380 env.require(
offers(alice, 1));
4387 env(
trust(bob, gwUSD(100)));
4390 env(
pay(gw, bob, gwUSD(50)));
4392 env.require(
balance(bob, gwUSD(50)));
4399 env(
offer(bob,
XRP(4000), gwUSD(40)));
4403 env.require(
offers(alice, 0));
4406 env.require(
offers(bob, 1));
4407 env.require(
balance(bob, gwUSD(50)));
4415 env.require(
offers(alice, 0));
4418 env.require(
offers(bob, 1));
4419 env.require(
balance(bob, gwUSD(50)));
4423 env(
trust(gw, aliceUSD(100)));
4429 env.require(
offers(alice, 0));
4430 env.require(
balance(alice, gwUSD(0)));
4432 env.require(
offers(bob, 1));
4433 env.require(
balance(bob, gwUSD(50)));
4438 env.require(
offers(bob, 0));
4446 env(
offer(alice, gwUSD(40),
XRP(4000)));
4449 env.require(
offers(alice, 1));
4452 env(
offer(bob,
XRP(4000), gwUSD(40)));
4455 env.require(
offers(alice, 0));
4456 env.require(
balance(alice, gwUSD(40)));
4458 env.require(
offers(bob, 0));
4459 env.require(
balance(bob, gwUSD(10)));
4465 testcase(
"RippleConnect Smoketest payment flow");
4466 using namespace jtx;
4468 Env env{*
this, features};
4478 auto const hotUS =
Account(
"hotUS");
4479 auto const coldUS =
Account(
"coldUS");
4480 auto const hotEU =
Account(
"hotEU");
4481 auto const coldEU =
Account(
"coldEU");
4482 auto const mm =
Account(
"mm");
4484 auto const USD = coldUS[
"USD"];
4485 auto const EUR = coldEU[
"EUR"];
4487 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4491 for (
auto const& cold : {coldUS, coldEU})
4514 env(
pay(coldUS, hotUS, USD(5000000)));
4515 env(
pay(coldEU, hotEU, EUR(5000000)));
4516 env(
pay(coldUS, mm, USD(5000000)));
4517 env(
pay(coldEU, mm, EUR(5000000)));
4521 float const rate = 0.9f;
4522 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4525 float const reverseRate = 1.0f /
rate * 1.00101f;
4526 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4533 jvParams[jss::destination_account] = coldEU.human();
4534 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4535 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4536 jvParams[jss::destination_amount][jss::value] = 10;
4537 jvParams[jss::source_account] = hotUS.human();
4540 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4542 BEAST_EXPECT(jrr[jss::status] ==
"success");
4544 jrr[jss::alternatives].isArray() &&
4545 jrr[jss::alternatives].size() > 0);
4548 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4556 using namespace jtx;
4558 Env env{*
this, features};
4560 auto const gw =
Account(
"gw");
4561 auto const alice =
Account(
"alice");
4562 auto const gwUSD = gw[
"USD"];
4563 auto const aliceUSD = alice[
"USD"];
4565 env.fund(
XRP(400000), gw, alice);
4569 env(
offer(gw, gwUSD(40),
XRP(4000)));
4572 env.require(
offers(gw, 1));
4581 env.require(
offers(gw, 0));
4588 bool const preauth = features[featureDepositPreauth];
4593 env(
offer(gw, gwUSD(40),
XRP(4000)),
4597 env.require(
offers(gw, preauth ? 1 : 0));
4605 env(
trust(alice, gwUSD(100)));
4608 env(
pay(gw, alice, gwUSD(50)));
4611 env.require(
balance(alice, gwUSD(50)));
4614 env(
offer(alice,
XRP(4000), gwUSD(40)));
4617 env.require(
offers(alice, 0));
4618 env.require(
balance(alice, gwUSD(10)));
4620 env.require(
offers(gw, 0));
4627 using namespace jtx;
4631 auto trustLineExists = [](
jtx::Env const& env,
4642 auto const USD = gw[
"USD"];
4643 auto const BUX = alice[
"BUX"];
4645 Env env{*
this, features};
4649 env.
trust(USD(1000), becky);
4650 env(
pay(gw, becky, USD(5)));
4652 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4663 env(
pay(becky, gw, USD(5)));
4664 env.
trust(USD(0), becky);
4666 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4667 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4668 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4675 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4677 if (gwSeq + 255 > openLedgerSeq)
4678 return gwSeq - openLedgerSeq + 255;
4682 for (
int i = 0; i < delta; ++i)
4699 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4700 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4706 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4707 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4712 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4716 env.
trust(BUX(1000), carol);
4717 env(
pay(alice, carol, BUX(2)));
4726 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4727 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4735 using namespace jtx;
4739 Env env{*
this, features};
4740 auto const gw =
Account{
"gateway"};
4741 env.fund(
XRP(10000), gw);
4744 auto txn =
noop(gw);
4745 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4748 txn[sfTickSize.fieldName] = Quality::minTickSize;
4750 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4753 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4755 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4758 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4760 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4763 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4766 txn[sfTickSize.fieldName] = 0;
4768 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4771 Env env{*
this, features};
4772 auto const gw =
Account{
"gateway"};
4773 auto const alice =
Account{
"alice"};
4774 auto const XTS = gw[
"XTS"];
4775 auto const XXX = gw[
"XXX"];
4777 env.fund(
XRP(10000), gw, alice);
4782 auto txn =
noop(gw);
4783 txn[sfTickSize.fieldName] = 5;
4785 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4788 env(
trust(alice, XTS(1000)));
4789 env(
trust(alice, XXX(1000)));
4791 env(
pay(gw, alice, alice[
"XTS"](100)));
4792 env(
pay(gw, alice, alice[
"XXX"](100)));
4794 env(
offer(alice, XTS(10), XXX(30)));
4795 env(
offer(alice, XTS(30), XXX(10)));
4802 if (sle->getType() == ltOFFER)
4806 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4810 auto it =
offers.begin();
4811 BEAST_EXPECT(it !=
offers.end());
4813 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4814 it->second.second > XXX(29.9994));
4818 BEAST_EXPECT(it !=
offers.end());
4820 it->second.first == XTS(30) && it->second.second == XXX(10));
4824 BEAST_EXPECT(it !=
offers.end());
4826 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4831 BEAST_EXPECT(it !=
offers.end());
4833 it->second.first == XTS(30) && it->second.second == XXX(10));
4835 BEAST_EXPECT(++it ==
offers.end());
4849 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4859 using namespace jtx;
4867 Env env{*
this, features};
4868 auto const gw =
Account{
"gateway"};
4869 auto const alice =
Account{
"alice"};
4870 auto const bob =
Account{
"bob"};
4871 auto const USD = gw[
"USD"];
4873 env.fund(
XRP(10000), gw, alice, bob);
4876 env(
trust(alice, USD(1000)));
4877 env(
trust(bob, USD(1000)));
4880 env(
pay(gw, alice, USD(200)));
4887 env(
offer(alice,
XRP(50), USD(50)));
4897 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4898 env(
offer(alice,
XRP(50), USD(50)));
4914 BEAST_EXPECT(
offers.size() == 4);
4915 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4916 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4917 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4918 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4919 env.require(
balance(alice, USD(200)));
4920 env.require(
owners(alice, 5));
4930 BEAST_EXPECT(
offers.size() == 3);
4931 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4932 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4933 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4943 BEAST_EXPECT(
offers.size() == 2);
4944 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4945 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4955 BEAST_EXPECT(
offers.size() == 1);
4956 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4966 BEAST_EXPECT(
offers.size() == 0);
4968 env.require(
balance(alice, USD(0)));
4969 env.require(
owners(alice, 1));
4970 env.require(
balance(bob, USD(200)));
4971 env.require(
owners(bob, 1));
4979 using namespace jtx;
4983 Env env{*
this, features};
4984 auto const gw =
Account{
"gateway"};
4985 auto const alice =
Account{
"alice"};
4986 auto const USD = gw[
"USD"];
4988 env.fund(
XRP(10000), gw, alice);
4991 env(
trust(alice, USD(1000)));
4995 env(
pay(gw, alice, USD(200)));
5000 env(
offer(alice,
XRP(50), USD(50)));
5012 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5013 env(
offer(alice,
XRP(50), USD(50)));
5029 BEAST_EXPECT(
offers.size() == 4);
5030 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
5031 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
5032 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
5033 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
5034 env.require(
balance(alice, USD(200)));
5035 env.require(
owners(alice, 7));
5045 BEAST_EXPECT(
offers.size() == 3);
5046 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5047 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
5048 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
5058 BEAST_EXPECT(
offers.size() == 2);
5059 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5060 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5073 BEAST_EXPECT(
offers.size() == 1);
5074 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5091 testcase(
"incorrect assert fixed");
5092 using namespace jtx;
5095 auto const alice =
Account(
"alice");
5096 auto const USD = alice[
"USD"];
5098 env.fund(
XRP(10000), alice);
5100 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5108 using namespace jtx;
5109 Env env(*
this, features);
5110 Account const issuer(
"issuer");
5113 auto const USD = issuer[
"USD"];
5114 auto const EUR = issuer[
"EUR"];
5117 env.
fund(
XRP(1'000), maker, taker);
5120 env.
trust(USD(1'000), maker, taker);
5121 env.
trust(EUR(1'000), maker, taker);
5124 env(
pay(issuer, maker, USD(1'000)));
5125 env(
pay(issuer, taker, USD(1'000)));
5126 env(
pay(issuer, maker, EUR(1'000)));
5129 auto makerUSDBalance = env.
balance(maker, USD).
value();
5130 auto takerUSDBalance = env.
balance(taker, USD).
value();
5131 auto makerEURBalance = env.
balance(maker, EUR).
value();
5132 auto takerEURBalance = env.
balance(taker, EUR).
value();
5141 env(
offer(maker,
XRP(100), USD(100)));
5144 env(
offer(taker, USD(100),
XRP(101)),
5149 makerXRPBalance -=
txfee(env, 1);
5150 takerXRPBalance -=
txfee(env, 1);
5153 makerUSDBalance -= USD(100);
5154 takerUSDBalance += USD(100);
5155 makerXRPBalance +=
XRP(100).value();
5156 takerXRPBalance -=
XRP(100).value();
5160 env(
offer(maker, USD(100),
XRP(100)));
5163 env(
offer(taker,
XRP(100), USD(101)),
5168 makerXRPBalance -=
txfee(env, 1);
5169 takerXRPBalance -=
txfee(env, 1);
5172 makerUSDBalance += USD(100);
5173 takerUSDBalance -= USD(100);
5174 makerXRPBalance -=
XRP(100).value();
5175 takerXRPBalance +=
XRP(100).value();
5179 env(
offer(maker, USD(100), EUR(100)));
5182 env(
offer(taker, EUR(100), USD(101)),
5187 makerXRPBalance -=
txfee(env, 1);
5188 takerXRPBalance -=
txfee(env, 1);
5191 makerUSDBalance += USD(100);
5192 takerUSDBalance -= USD(100);
5193 makerEURBalance -= EUR(100);
5194 takerEURBalance += EUR(100);
5201 env(
offer(maker,
XRP(101), USD(101)));
5204 env(
offer(taker, USD(100),
XRP(101)),
5208 makerUSDBalance -= USD(101);
5209 takerUSDBalance += USD(101);
5210 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5211 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5214 env(
offer(maker, USD(101),
XRP(101)));
5217 env(
offer(taker,
XRP(100), USD(101)),
5221 makerUSDBalance += USD(101);
5222 takerUSDBalance -= USD(101);
5223 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5224 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5227 env(
offer(maker, USD(101), EUR(101)));
5230 env(
offer(taker, EUR(100), USD(101)),
5234 makerUSDBalance += USD(101);
5235 takerUSDBalance -= USD(101);
5236 makerEURBalance -= EUR(101);
5237 takerEURBalance += EUR(101);
5238 makerXRPBalance -=
txfee(env, 1);
5239 takerXRPBalance -=
txfee(env, 1);
5246 env(
offer(maker,
XRP(100), USD(100)));
5249 env(
offer(taker, USD(100),
XRP(99)),
5254 makerXRPBalance -=
txfee(env, 1);
5255 takerXRPBalance -=
txfee(env, 1);
5258 env(
offer(maker, USD(100),
XRP(100)));
5261 env(
offer(taker,
XRP(100), USD(99)),
5266 makerXRPBalance -=
txfee(env, 1);
5267 takerXRPBalance -=
txfee(env, 1);
5270 env(
offer(maker, USD(100), EUR(100)));
5273 env(
offer(taker, EUR(100), USD(99)),
5278 makerXRPBalance -=
txfee(env, 1);
5279 takerXRPBalance -=
txfee(env, 1);
5284 env.
balance(maker, USD) == makerUSDBalance &&
5285 env.
balance(taker, USD) == takerUSDBalance &&
5286 env.
balance(maker, EUR) == makerEURBalance &&
5287 env.
balance(taker, EUR) == takerEURBalance &&
5288 env.
balance(maker,
XRP) == makerXRPBalance &&
5359 using namespace jtx;
5361 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5363 fixRmSmallIncreasedQOffers};
5365 featureImmediateOfferKilled};
5370 all - takerDryOffer - immediateOfferKilled - permDEX,
5371 all - immediateOfferKilled - permDEX,
5372 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill -
5374 all - fillOrKill - permDEX,
5378 if (BEAST_EXPECT(instance < feats.size()))
5382 BEAST_EXPECT(!
last || instance == feats.size() - 1);
5443 using namespace jtx;
5445 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5450 testAll(
all - immediateOfferKilled - permDEX);
5451 testAll(
all - immediateOfferKilled - fillOrKill - permDEX);
5460BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app,
ripple, 2);
5461BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, app,
ripple, 2);
5462BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app,
ripple, 2);
5463BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, app,
ripple, 2);
5464BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, app,
ripple, 2);
5465BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app,
ripple, 2);
5466BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, app,
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
FeatureBitset testable_amendments()
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)
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
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.
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)
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