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));
389 for (
auto partialPayment : {
false,
true})
391 Env env{*
this, features};
393 env.fund(
XRP(10000), alice, bob, carol, gw);
395 env.trust(USD(1000), alice, bob, carol);
397 auto const initialCarolUSD = USD(0.999);
398 env(
pay(gw, carol, initialCarolUSD));
400 env(
pay(gw, bob, USD(100)));
412 TER const expectedTer =
415 env(
pay(alice, bob, USD(5)),
424 env.require(
offers(carol, 0));
442 testcase(
"Rm small increased q offers IOU");
450 using namespace std::chrono_literals;
451 auto const alice =
Account{
"alice"};
452 auto const bob =
Account{
"bob"};
453 auto const carol =
Account{
"carol"};
456 auto const USD = gw[
"USD"];
457 auto const EUR = gw[
"EUR"];
468 for (
auto crossBothOffers : {
false,
true})
470 Env env{*
this, features};
472 env.fund(
XRP(10000), alice, bob, carol, gw);
474 env.trust(USD(1000), alice, bob, carol);
475 env.trust(EUR(1000), alice, bob, carol);
477 auto initialCarolUSD = tinyAmount(USD);
478 env(
pay(gw, carol, initialCarolUSD));
479 env(
pay(gw, bob, USD(100)));
480 env(
pay(gw, alice, EUR(100)));
483 env(
offer(carol, EUR(1), USD(10)));
493 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
494 env(
offer(alice, USD(1), aliceTakerGets));
517 for (
auto partialPayment : {
false,
true})
519 Env env{*
this, features};
521 env.fund(
XRP(10000), alice, bob, carol, gw);
523 env.trust(USD(1000), alice, bob, carol);
524 env.trust(EUR(1000), alice, bob, carol);
527 auto const initialCarolUSD = tinyAmount(USD);
528 env(
pay(gw, carol, initialCarolUSD));
529 env(
pay(gw, bob, USD(100)));
530 env(
pay(gw, alice, EUR(100)));
533 env(
offer(carol, EUR(1), USD(2)));
543 TER const expectedTer =
546 env(
pay(alice, bob, USD(5)),
555 env.require(
offers(carol, 0));
577 auto const gw =
Account{
"gateway"};
578 auto const USD = gw[
"USD"];
579 auto const BTC = gw[
"BTC"];
580 auto const EUR = gw[
"EUR"];
588 Env env{*
this, features};
590 auto const gw1 =
Account{
"gw1"};
591 auto const USD1 = gw1[
"USD"];
592 auto const gw2 =
Account{
"gw2"};
593 auto const USD2 = gw2[
"USD"];
595 env.fund(
XRP(10000), alice,
noripple(bob), carol, dan, gw1, gw2);
597 env.trust(USD1(1000), alice, carol, dan);
599 env.trust(USD2(1000), alice, carol, dan);
602 env(
pay(gw1, dan, USD1(50)));
603 env(
pay(gw1, bob, USD1(50)));
604 env(
pay(gw2, bob, USD2(50)));
608 env(
pay(alice, carol, USD2(50)),
616 Env env{*
this, features};
618 auto const gw1 =
Account{
"gw1"};
619 auto const USD1 = gw1[
"USD"];
620 auto const gw2 =
Account{
"gw2"};
621 auto const USD2 = gw2[
"USD"];
623 env.fund(
XRP(10000), alice, bob, carol, dan, gw1, gw2);
625 env.trust(USD1(1000), alice, bob, carol, dan);
626 env.trust(USD2(1000), alice, bob, carol, dan);
628 env(
pay(gw1, dan, USD1(50)));
629 env(
pay(gw1, bob, USD1(50)));
630 env(
pay(gw2, bob, USD2(50)));
634 env(
pay(alice, carol, USD2(50)),
640 env.require(
balance(bob, USD1(100)));
641 env.require(
balance(bob, USD2(0)));
642 env.require(
balance(carol, USD2(50)));
659 auto const gw =
Account{
"gateway"};
660 auto const alice =
Account{
"alice"};
661 auto const bob =
Account{
"bob"};
662 auto const carol =
Account{
"carol"};
663 auto const USD = gw[
"USD"];
665 auto const usdOffer = USD(1000);
666 auto const xrpOffer =
XRP(1000);
670 Env env{*
this, features};
672 env.fund(
XRP(1000000), gw);
674 auto const f = env.current()->fees().base;
675 auto const r =
reserve(env, 0);
677 env.fund(r + f, alice);
688 Env env{*
this, features};
690 env.fund(
XRP(1000000), gw);
692 auto const f = env.current()->fees().base;
693 auto const r =
reserve(env, 0);
695 auto const usdOffer2 = USD(500);
696 auto const xrpOffer2 =
XRP(500);
698 env.fund(r + f + xrpOffer, bob);
701 env.fund(r + f, alice);
708 balance(alice, r - f + xrpOffer2),
720 Env env{*
this, features};
722 env.fund(
XRP(1000000), gw);
724 auto const f = env.current()->fees().base;
725 auto const r =
reserve(env, 0);
727 auto const usdOffer2 = USD(500);
728 auto const xrpOffer2 =
XRP(500);
730 env.fund(r + f + xrpOffer, bob, carol);
735 env.fund(r + f, alice);
742 balance(alice, r - f + xrpOffer),
763 if (sle->getType() == ltOFFER)
764 result.push_back(sle);
776 auto const startBalance =
XRP(1000000);
777 auto const gw =
Account{
"gateway"};
778 auto const alice =
Account{
"alice"};
779 auto const bob =
Account{
"bob"};
780 auto const USD = gw[
"USD"];
786 Env env{*
this, features};
788 auto const f = env.current()->fees().base;
790 env.fund(startBalance, gw, alice, bob);
813 env(
offer(alice,
XRP(1000), USD(1000)),
818 balance(alice, startBalance - (f * 2)),
822 balance(bob, startBalance - (f * 2)),
828 env(
offer(alice,
XRP(500), USD(500)),
833 balance(alice, startBalance - (f * 3) +
XRP(500)),
837 balance(bob, startBalance - (f * 2) -
XRP(500)),
846 Env env{*
this, features};
848 auto const f = env.current()->fees().base;
850 env.fund(startBalance, gw, alice, bob);
858 TER const expectedCode = features[featureImmediateOfferKilled]
861 env(
offer(alice,
XRP(1000), USD(1000)),
867 balance(alice, startBalance - f - f),
874 env(
offer(alice,
XRP(1000), USD(1000)),
879 balance(alice, startBalance - f - f - f +
XRP(50)),
895 balance(alice, startBalance - f - f - f - f +
XRP(100)),
899 balance(bob, startBalance - f - f -
XRP(100)),
907 Env env(*
this, features);
909 env.
fund(startBalance, gw, alice, bob);
912 env(
trust(bob, USD(1000)));
915 env(
pay(gw, bob, USD(1000)));
918 env(
offer(alice, USD(1000),
XRP(2000)));
922 BEAST_EXPECT(aliceOffers.size() == 1);
923 for (
auto offerPtr : aliceOffers)
925 auto const&
offer = *offerPtr;
926 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
927 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
937 BEAST_EXPECT(bobOffers.size() == 1);
938 for (
auto offerPtr : bobOffers)
940 auto const&
offer = *offerPtr;
941 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
942 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
946 env(
offer(gw,
XRP(2000), USD(1000)));
952 env(
offer(gw, USD(1000),
XRP(2000)));
960 Env env(*
this, features);
962 env.
fund(startBalance, gw,
"alice",
"bob");
965 env(
trust(
"bob", USD(1000)));
968 env(
pay(gw,
"bob", USD(1000)));
969 env(
offer(
"alice", USD(500),
XRP(1001)));
972 env(
offer(
"alice", USD(500),
XRP(1000)));
976 BEAST_EXPECT(aliceOffers.size() == 2);
986 BEAST_EXPECT(bobOffers.size() == 1);
987 for (
auto offerPtr : bobOffers)
989 auto const&
offer = *offerPtr;
990 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
991 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
1001 using namespace jtx;
1003 auto const startBalance =
XRP(1000000);
1004 auto const gw =
Account{
"gateway"};
1005 auto const alice =
Account{
"alice"};
1006 auto const USD = gw[
"USD"];
1008 Env env{*
this, features};
1010 env.fund(startBalance, gw, alice);
1014 env(
offer(alice, USD(1000),
XRP(1000)),
1021 env(
offer(alice, USD(1000),
XRP(1000)),
1051 env(
offer(alice, USD(1000),
XRP(1000)),
1059 env(
offer(alice, USD(1000),
XRP(1000)),
1079 using namespace jtx;
1081 auto const gw =
Account{
"gateway"};
1082 auto const alice =
Account{
"alice"};
1083 auto const bob =
Account{
"bob"};
1084 auto const USD = gw[
"USD"];
1086 auto const startBalance =
XRP(1000000);
1087 auto const usdOffer = USD(1000);
1088 auto const xrpOffer =
XRP(1000);
1090 Env env{*
this, features};
1092 env.fund(startBalance, gw, alice, bob);
1095 auto const f = env.current()->fees().base;
1101 balance(alice, startBalance - f),
1108 bool const featPreauth{features[featureDepositPreauth]};
1110 env(
offer(alice, xrpOffer, usdOffer),
1115 balance(alice, startBalance - f - f),
1122 env(
offer(alice, xrpOffer, usdOffer),
1126 balance(alice, startBalance - f - f - f),
1134 balance(alice, startBalance - f - f - f),
1142 balance(alice, startBalance - f - f - f),
1146 balance(bob, startBalance - f),
1157 using namespace jtx;
1159 auto const gw =
Account{
"gateway"};
1160 auto const USD = gw[
"USD"];
1162 auto const usdOffer = USD(1000);
1163 auto const xrpOffer =
XRP(1000);
1165 Env env{*
this, features};
1167 env.fund(
XRP(1000000), gw);
1171 auto const f = env.current()->fees().base;
1175 env.fund(
reserve(env, 0),
"alice");
1182 env.fund(
reserve(env, 0) + f,
"bob");
1190 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1198 env.fund(
reserve(env, 1) + f,
"dan");
1205 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1217 (use_partner ?
", with partner account" :
""));
1219 using namespace jtx;
1221 auto const gw =
Account{
"gateway"};
1222 auto const partner =
Account{
"partner"};
1223 auto const USD = gw[
"USD"];
1224 auto const BTC = gw[
"BTC"];
1226 Env env{*
this, features};
1229 env.fund(
XRP(10000), gw);
1232 env.fund(
XRP(10000), partner);
1234 env(
trust(partner, USD(100)));
1235 env(
trust(partner, BTC(500)));
1237 env(
pay(gw, partner, USD(100)));
1238 env(
pay(gw, partner, BTC(500)));
1240 auto const& account_to_test = use_partner ? partner : gw;
1243 env.require(
offers(account_to_test, 0));
1248 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1249 env.require(
offers(account_to_test, 1));
1252 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1254 auto const secondLegSeq = env.seq(account_to_test);
1255 env(
offer(account_to_test,
XRP(1000), USD(50)));
1256 env.require(
offers(account_to_test, 2));
1259 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1263 env(
offer(account_to_test, USD(50), BTC(250)));
1266 BEAST_EXPECT(jrr[jss::offers].isArray());
1267 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1270 BEAST_EXPECT(jrr[jss::offers].isArray());
1271 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1278 BEAST_EXPECT(acctOffers.size() == 0);
1279 for (
auto const& offerPtr : acctOffers)
1281 auto const&
offer = *offerPtr;
1282 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1283 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1284 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1292 env.require(
offers(account_to_test, 0));
1297 env(
offer(account_to_test, BTC(250), USD(50)));
1298 env.require(
offers(account_to_test, 1));
1302 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1305 BEAST_EXPECT(jrr[jss::offers].isArray());
1306 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1310 env(
offer(account_to_test, USD(50), BTC(250)));
1311 env.require(
offers(account_to_test, 1));
1316 BEAST_EXPECT(jrr[jss::offers].isArray());
1317 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1319 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1329 using namespace jtx;
1334 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1336 Env env{*
this, localFeatures};
1338 auto const gw =
Account{
"gateway"};
1339 auto const alice =
Account{
"alice"};
1340 auto const bob =
Account{
"bob"};
1341 auto const USD = gw[
"USD"];
1342 auto const BTC = gw[
"BTC"];
1346 auto const gw_initial_balance =
drops(1149999730);
1347 auto const alice_initial_balance =
drops(499946999680);
1348 auto const bob_initial_balance =
drops(10199999920);
1349 auto const small_amount =
1350 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1352 env.fund(gw_initial_balance, gw);
1353 env.fund(alice_initial_balance, alice);
1354 env.fund(bob_initial_balance, bob);
1357 env(
rate(gw, 1.005));
1359 env(
trust(alice, USD(500)));
1360 env(
trust(bob, USD(50)));
1361 env(
trust(gw, alice[
"USD"](100)));
1363 env(
pay(gw, alice, alice[
"USD"](50)));
1364 env(
pay(gw, bob, small_amount));
1366 env(
offer(alice, USD(50),
XRP(150000)));
1369 env(
pay(alice, gw, USD(100)));
1372 env(
trust(gw, alice[
"USD"](0)));
1377 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1381 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1382 "-2710505431213761e-33");
1386 env(
offer(bob,
XRP(2000), USD(1)));
1388 if (localFeatures[fixReducedOffersV2])
1395 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1396 "-2710505431213761e-33");
1400 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1401 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1412 auto const crossingDelta =
drops(1);
1416 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1419 alice_initial_balance - env.current()->fees().base * 3 -
1424 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1427 bob_initial_balance - env.current()->fees().base * 2 +
1437 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1439 using namespace jtx;
1441 Env env{*
this, features};
1443 auto const gw =
Account{
"gateway"};
1444 auto const alice =
Account{
"alice"};
1445 auto const bob =
Account{
"bob"};
1446 auto const USD = gw[
"USD"];
1448 env.fund(
XRP(10000), gw, alice, bob);
1451 env(
trust(alice, USD(1000)));
1452 env(
trust(bob, USD(1000)));
1454 env(
pay(gw, alice, alice[
"USD"](500)));
1457 env(
offer(bob, USD(1),
XRP(4000)));
1459 env(
offer(alice,
XRP(150000), USD(50)));
1462 env(
offer(bob, USD(1),
XRP(4000)));
1469 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1472 jrr[jss::node][sfBalance.fieldName] ==
1474 env.current()->fees().base * 2)
1478 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1481 jrr[jss::node][sfBalance.fieldName] ==
1483 env.current()->fees().base * 2)
1490 testcase(
"Offer Crossing with Limit Override");
1492 using namespace jtx;
1494 Env env{*
this, features};
1496 auto const gw =
Account{
"gateway"};
1497 auto const alice =
Account{
"alice"};
1498 auto const bob =
Account{
"bob"};
1499 auto const USD = gw[
"USD"];
1501 env.fund(
XRP(100000), gw, alice, bob);
1504 env(
trust(alice, USD(1000)));
1506 env(
pay(gw, alice, alice[
"USD"](500)));
1508 env(
offer(alice,
XRP(150000), USD(50)));
1509 env(
offer(bob, USD(1),
XRP(3000)));
1512 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1515 jrr[jss::node][sfBalance.fieldName] ==
1520 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1523 jrr[jss::node][sfBalance.fieldName] ==
1531 testcase(
"Offer Accept then Cancel.");
1533 using namespace jtx;
1535 Env env{*
this, features};
1537 auto const USD = env.master[
"USD"];
1539 auto const nextOfferSeq = env.seq(env.master);
1540 env(
offer(env.master,
XRP(500), USD(100)));
1544 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1549 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1555 testcase(
"Offer Cancel Past and Future Sequence.");
1557 using namespace jtx;
1559 Env env{*
this, features};
1561 auto const alice =
Account{
"alice"};
1563 auto const nextOfferSeq = env.seq(env.master);
1564 env.fund(
XRP(10000), alice);
1581 testcase(
"Currency Conversion: Entire Offer");
1583 using namespace jtx;
1585 Env env{*
this, features};
1587 auto const gw =
Account{
"gateway"};
1588 auto const alice =
Account{
"alice"};
1589 auto const bob =
Account{
"bob"};
1590 auto const USD = gw[
"USD"];
1592 env.fund(
XRP(10000), gw, alice, bob);
1594 env.require(
owners(bob, 0));
1596 env(
trust(alice, USD(100)));
1597 env(
trust(bob, USD(1000)));
1601 env(
pay(gw, alice, alice[
"USD"](100)));
1602 auto const bobOfferSeq = env.seq(bob);
1603 env(
offer(bob, USD(100),
XRP(500)));
1608 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1610 jro[jss::node][jss::TakerPays] ==
1616 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1619 jrr[jss::node][sfBalance.fieldName] ==
1624 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1627 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1635 testcase(
"Currency Conversion: Offerer Into Debt");
1637 using namespace jtx;
1639 Env env{*
this, features};
1641 auto const alice =
Account{
"alice"};
1642 auto const bob =
Account{
"bob"};
1643 auto const carol =
Account{
"carol"};
1645 env.fund(
XRP(10000), alice, bob, carol);
1648 env(
trust(alice, carol[
"EUR"](2000)));
1649 env(
trust(bob, alice[
"USD"](100)));
1650 env(
trust(carol, bob[
"EUR"](1000)));
1652 auto const bobOfferSeq = env.seq(bob);
1653 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1656 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1659 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1665 testcase(
"Currency Conversion: In Parts");
1667 using namespace jtx;
1669 Env env{*
this, features};
1671 auto const gw =
Account{
"gateway"};
1672 auto const alice =
Account{
"alice"};
1673 auto const bob =
Account{
"bob"};
1674 auto const USD = gw[
"USD"];
1676 env.fund(
XRP(10000), gw, alice, bob);
1679 env(
trust(alice, USD(200)));
1680 env(
trust(bob, USD(1000)));
1682 env(
pay(gw, alice, alice[
"USD"](200)));
1684 auto const bobOfferSeq = env.seq(bob);
1685 env(
offer(bob, USD(100),
XRP(500)));
1692 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1694 jro[jss::node][jss::TakerPays] ==
1700 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1704 jrr[jss::node][sfBalance.fieldName] ==
1710 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1714 env(
pay(alice, alice,
XRP(600)),
1720 env(
pay(alice, alice,
XRP(600)),
1726 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1734 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1737 jrr[jss::node][sfBalance.fieldName] ==
1739 env.current()->fees().base * 4)
1745 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1751 testcase(
"Cross Currency Payment: Start with XRP");
1753 using namespace jtx;
1755 Env env{*
this, features};
1757 auto const gw =
Account{
"gateway"};
1758 auto const alice =
Account{
"alice"};
1759 auto const bob =
Account{
"bob"};
1760 auto const carol =
Account{
"carol"};
1761 auto const USD = gw[
"USD"];
1763 env.fund(
XRP(10000), gw, alice, bob, carol);
1766 env(
trust(carol, USD(1000)));
1767 env(
trust(bob, USD(2000)));
1769 env(
pay(gw, carol, carol[
"USD"](500)));
1771 auto const carolOfferSeq = env.seq(carol);
1772 env(
offer(carol,
XRP(500), USD(50)));
1777 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1780 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1784 jro[jss::node][jss::TakerGets] ==
1787 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1793 testcase(
"Cross Currency Payment: End with XRP");
1795 using namespace jtx;
1797 Env env{*
this, features};
1799 auto const gw =
Account{
"gateway"};
1800 auto const alice =
Account{
"alice"};
1801 auto const bob =
Account{
"bob"};
1802 auto const carol =
Account{
"carol"};
1803 auto const USD = gw[
"USD"];
1805 env.fund(
XRP(10000), gw, alice, bob, carol);
1808 env(
trust(alice, USD(1000)));
1809 env(
trust(carol, USD(2000)));
1811 env(
pay(gw, alice, alice[
"USD"](500)));
1813 auto const carolOfferSeq = env.seq(carol);
1814 env(
offer(carol, USD(50),
XRP(500)));
1819 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1822 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1826 jrr[jss::node][sfBalance.fieldName] ==
1828 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1832 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1834 jro[jss::node][jss::TakerPays] ==
1841 testcase(
"Cross Currency Payment: Bridged");
1843 using namespace jtx;
1845 Env env{*
this, features};
1847 auto const gw1 =
Account{
"gateway_1"};
1848 auto const gw2 =
Account{
"gateway_2"};
1849 auto const alice =
Account{
"alice"};
1850 auto const bob =
Account{
"bob"};
1851 auto const carol =
Account{
"carol"};
1852 auto const dan =
Account{
"dan"};
1853 auto const USD = gw1[
"USD"];
1854 auto const EUR = gw2[
"EUR"];
1856 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1859 env(
trust(alice, USD(1000)));
1860 env(
trust(bob, EUR(1000)));
1861 env(
trust(carol, USD(1000)));
1862 env(
trust(dan, EUR(1000)));
1864 env(
pay(gw1, alice, alice[
"USD"](500)));
1865 env(
pay(gw2, dan, dan[
"EUR"](400)));
1867 auto const carolOfferSeq = env.seq(carol);
1868 env(
offer(carol, USD(50),
XRP(500)));
1870 auto const danOfferSeq = env.seq(dan);
1871 env(
offer(dan,
XRP(500), EUR(50)));
1874 jtp[0u][0u][jss::currency] =
"XRP";
1875 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1878 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1881 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1884 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1887 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1891 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1893 jro[jss::node][jss::TakerPays] ==
1898 jro[jss::node][jss::TakerGets] ==
1901 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1910 testcase(
"Auto Bridged Second Leg Dry");
1912 using namespace jtx;
1913 Env env(*
this, features);
1919 auto const USD = gw[
"USD"];
1920 auto const EUR = gw[
"EUR"];
1922 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1925 env.
trust(USD(10), alice);
1927 env(
pay(gw, alice, USD(10)));
1928 env.
trust(USD(10), carol);
1930 env(
pay(gw, carol, USD(3)));
1947 env.
trust(EUR(10), bob);
1949 env(
pay(gw, bob, EUR(10)));
1951 env(
offer(bob, USD(10), EUR(10)));
1974 testcase(
"Offer Fees Consume Funds");
1976 using namespace jtx;
1978 Env env{*
this, features};
1980 auto const gw1 =
Account{
"gateway_1"};
1981 auto const gw2 =
Account{
"gateway_2"};
1982 auto const gw3 =
Account{
"gateway_3"};
1983 auto const alice =
Account{
"alice"};
1984 auto const bob =
Account{
"bob"};
1985 auto const USD1 = gw1[
"USD"];
1986 auto const USD2 = gw2[
"USD"];
1987 auto const USD3 = gw3[
"USD"];
1995 auto const starting_xrp =
XRP(100) +
1996 env.current()->fees().accountReserve(3) +
1997 env.current()->fees().base * 4;
1999 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2002 env(
trust(alice, USD1(1000)));
2003 env(
trust(alice, USD2(1000)));
2004 env(
trust(alice, USD3(1000)));
2005 env(
trust(bob, USD1(1000)));
2006 env(
trust(bob, USD2(1000)));
2008 env(
pay(gw1, bob, bob[
"USD"](500)));
2010 env(
offer(bob,
XRP(200), USD1(200)));
2013 env(
offer(alice, USD1(200),
XRP(200)));
2016 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2019 jrr[jss::node][sfBalance.fieldName] ==
2023 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2029 testcase(
"Offer Create, then Cross");
2031 using namespace jtx;
2033 for (
auto NumberSwitchOver : {
false,
true})
2035 Env env{*
this, features};
2036 if (NumberSwitchOver)
2037 env.enableFeature(fixUniversalNumber);
2039 env.disableFeature(fixUniversalNumber);
2041 auto const gw =
Account{
"gateway"};
2042 auto const alice =
Account{
"alice"};
2043 auto const bob =
Account{
"bob"};
2044 auto const USD = gw[
"USD"];
2046 env.fund(
XRP(10000), gw, alice, bob);
2049 env(
rate(gw, 1.005));
2051 env(
trust(alice, USD(1000)));
2052 env(
trust(bob, USD(1000)));
2053 env(
trust(gw, alice[
"USD"](50)));
2055 env(
pay(gw, bob, bob[
"USD"](1)));
2056 env(
pay(alice, gw, USD(50)));
2058 env(
trust(gw, alice[
"USD"](0)));
2060 env(
offer(alice, USD(50),
XRP(150000)));
2061 env(
offer(bob,
XRP(100), USD(0.1)));
2065 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2066 "49.96666666666667");
2070 jrr[jss::node][sfBalance.fieldName][jss::value];
2071 if (!NumberSwitchOver)
2073 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2077 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2085 testcase(
"Offer tfSell: Basic Sell");
2087 using namespace jtx;
2089 Env env{*
this, features};
2091 auto const gw =
Account{
"gateway"};
2092 auto const alice =
Account{
"alice"};
2093 auto const bob =
Account{
"bob"};
2094 auto const USD = gw[
"USD"];
2096 auto const starting_xrp =
XRP(100) +
2097 env.current()->fees().accountReserve(1) +
2098 env.current()->fees().base * 2;
2100 env.fund(starting_xrp, gw, alice, bob);
2103 env(
trust(alice, USD(1000)));
2104 env(
trust(bob, USD(1000)));
2106 env(
pay(gw, bob, bob[
"USD"](500)));
2115 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2118 jrr[jss::node][sfBalance.fieldName] ==
2122 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2128 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2130 using namespace jtx;
2132 Env env{*
this, features};
2134 auto const gw =
Account{
"gateway"};
2135 auto const alice =
Account{
"alice"};
2136 auto const bob =
Account{
"bob"};
2137 auto const USD = gw[
"USD"];
2139 auto const starting_xrp =
XRP(100) +
2140 env.current()->fees().accountReserve(1) +
2141 env.current()->fees().base * 2;
2143 env.fund(starting_xrp, gw, alice, bob);
2146 env(
trust(alice, USD(150)));
2147 env(
trust(bob, USD(1000)));
2149 env(
pay(gw, bob, bob[
"USD"](500)));
2151 env(
offer(bob,
XRP(100), USD(200)));
2160 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2163 jrr[jss::node][sfBalance.fieldName] ==
2167 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2173 testcase(
"Client Issue #535: Gateway Cross Currency");
2175 using namespace jtx;
2177 Env env{*
this, features};
2179 auto const gw =
Account{
"gateway"};
2180 auto const alice =
Account{
"alice"};
2181 auto const bob =
Account{
"bob"};
2182 auto const XTS = gw[
"XTS"];
2183 auto const XXX = gw[
"XXX"];
2185 auto const starting_xrp =
XRP(100.1) +
2186 env.current()->fees().accountReserve(1) +
2187 env.current()->fees().base * 2;
2189 env.fund(starting_xrp, gw, alice, bob);
2192 env(
trust(alice, XTS(1000)));
2193 env(
trust(alice, XXX(1000)));
2194 env(
trust(bob, XTS(1000)));
2195 env(
trust(bob, XXX(1000)));
2197 env(
pay(gw, alice, alice[
"XTS"](100)));
2198 env(
pay(gw, alice, alice[
"XXX"](100)));
2199 env(
pay(gw, bob, bob[
"XTS"](100)));
2200 env(
pay(gw, bob, bob[
"XXX"](100)));
2202 env(
offer(alice, XTS(100), XXX(100)));
2209 payment[jss::id] = env.seq(bob);
2210 payment[jss::build_path] =
true;
2211 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2212 payment[jss::tx_json][jss::Sequence] =
2215 ->getFieldU32(sfSequence);
2216 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2217 payment[jss::tx_json][jss::SendMax] =
2219 auto jrr = wsc->invoke(
"submit", payment);
2220 BEAST_EXPECT(jrr[jss::status] ==
"success");
2221 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2222 if (wsc->version() == 2)
2225 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2227 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2228 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2232 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2234 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2237 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2239 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2254 auto const sleTrust =
2256 BEAST_EXPECT(sleTrust);
2260 bool const accountLow = account.id() < issue.
account;
2265 low.setIssuer(accountLow ? account.id() : issue.
account);
2266 high.setIssuer(accountLow ? issue.
account : account.id());
2268 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2269 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2271 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2275 BEAST_EXPECT(actualBalance == expectBalance);
2287 using namespace jtx;
2289 auto const gw =
Account(
"gateway");
2290 auto const USD = gw[
"USD"];
2292 Env env{*
this, features};
2294 env.fund(
XRP(10000000), gw);
2298 auto const f = env.current()->fees().base;
2301 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2307 preTrustType preTrust;
2317 TestData
const tests[]{
2319 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2320 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2321 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2322 {
"deb",
drops(10) +
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 1},
2323 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2324 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2325 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2326 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2327 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2328 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2329 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2330 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2331 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2332 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2333 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2334 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2335 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2336 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2338 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2339 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2340 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2341 {
"dan",
drops(10) +
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 0},
2342 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2343 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2344 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2345 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2347 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2348 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2349 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2350 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2351 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2352 {
"syd",
drops(10) +
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
drops(10) + 2 * f, USD(0.00001), 0, 1},
2353 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2354 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2355 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2356 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2357 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2361 for (
auto const& t : tests)
2363 auto const acct =
Account(t.account);
2364 env.fund(t.fundXrp, acct);
2368 env.require(
offers(gw, 0));
2371 auto const book = t.bookAmount;
2373 env(
offer(gw,
XRP(book), USD(book)));
2378 if (t.preTrust == gwPreTrust)
2379 env(
trust(gw, acct[
"USD"](1)));
2385 if (t.preTrust == acctPreTrust)
2386 env(
trust(acct, USD(1)));
2391 auto const acctOffer = t.offerAmount;
2392 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2397 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2399 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2400 env.require(
offers(acct, t.offers));
2401 env.require(
owners(acct, t.owners));
2404 BEAST_EXPECT(acctOffers.size() == t.offers);
2405 if (acctOffers.size() && t.offers)
2407 auto const& acctOffer = *(acctOffers.front());
2409 auto const leftover = t.offerAmount - t.bookAmount;
2410 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2411 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2414 if (t.preTrust == noPreTrust)
2416 if (t.balanceUsd.value().signum())
2424 auto const sleTrust =
2426 BEAST_EXPECT(!sleTrust);
2443 using namespace jtx;
2445 auto const gw =
Account(
"gateway");
2446 auto const alice =
Account(
"alice");
2447 auto const bob =
Account(
"bob");
2448 auto const USD = gw[
"USD"];
2450 auto const usdOffer = USD(1000);
2451 auto const xrpOffer =
XRP(1000);
2453 Env env{*
this, features};
2455 env.fund(
XRP(1000000), gw, bob);
2459 auto const fee = env.current()->fees().base;
2466 env(
trust(alice, usdOffer));
2470 env(
pay(gw, alice, usdOffer));
2477 auto const alicesXRP = env.balance(alice);
2478 auto const bobsXRP = env.balance(bob);
2480 env(
offer(alice, xrpOffer, usdOffer));
2482 env(
offer(bob, usdOffer, xrpOffer));
2496 env(
offer(alice, USD(999),
XRP(999)));
2497 env(
offer(bob, xrpOffer, usdOffer));
2500 env.require(
balance(alice, USD(999)));
2501 env.require(
balance(bob, USD(1)));
2502 env.require(
offers(alice, 0));
2506 BEAST_EXPECT(bobsOffers.size() == 1);
2507 auto const& bobsOffer = *(bobsOffers.front());
2509 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2510 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2511 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2520 using namespace jtx;
2522 auto const gw =
Account(
"gateway");
2523 auto const alice =
Account(
"alice");
2524 auto const bob =
Account(
"bob");
2525 auto const USD = gw[
"USD"];
2526 auto const EUR = gw[
"EUR"];
2528 auto const usdOffer = USD(1000);
2529 auto const eurOffer = EUR(1000);
2531 Env env{*
this, features};
2533 env.fund(
XRP(1000000), gw);
2537 auto const fee = env.current()->fees().base;
2545 env(
trust(alice, usdOffer));
2546 env(
trust(bob, eurOffer));
2549 env(
pay(gw, alice, usdOffer));
2550 env(
pay(gw, bob, eurOffer));
2558 env(
offer(alice, eurOffer, usdOffer));
2559 env(
offer(bob, usdOffer, eurOffer));
2576 env(
offer(bob, eurOffer, usdOffer));
2579 env(
offer(alice, USD(999), eurOffer));
2582 env.require(
offers(alice, 0));
2583 env.require(
offers(bob, 1));
2585 env.require(
balance(alice, USD(999)));
2586 env.require(
balance(alice, EUR(1)));
2587 env.require(
balance(bob, USD(1)));
2588 env.require(
balance(bob, EUR(999)));
2592 if (BEAST_EXPECT(bobsOffers.size() == 1))
2594 auto const& bobsOffer = *(bobsOffers.front());
2596 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2597 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2602 env(
offer(alice, USD(1), EUR(1)));
2605 env.require(
balance(alice, USD(1000)));
2608 env.require(
balance(bob, EUR(1000)));
2609 env.require(
offers(alice, 0));
2610 env.require(
offers(bob, 0));
2613 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2614 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2618 env(
offer(alice, EUR(999), usdOffer));
2621 env(
offer(bob, usdOffer, eurOffer));
2624 env.require(
offers(alice, 0));
2625 env.require(
offers(bob, 0));
2627 env.require(
balance(alice, USD(0)));
2628 env.require(
balance(alice, EUR(999)));
2629 env.require(
balance(bob, USD(1000)));
2630 env.require(
balance(bob, EUR(1)));
2638 using namespace jtx;
2640 auto const gw =
Account(
"gateway");
2641 auto const alice =
Account(
"alice");
2642 auto const bob =
Account(
"bob");
2643 auto const carol =
Account(
"carol");
2644 auto const USD = gw[
"USD"];
2645 auto const EUR = gw[
"EUR"];
2647 auto const usdOffer = USD(1000);
2648 auto const eurOffer = EUR(1000);
2650 Env env{*
this, features};
2652 env.fund(
XRP(1000000), gw, alice, bob, carol);
2655 env(
trust(alice, usdOffer));
2656 env(
trust(carol, eurOffer));
2658 env(
pay(gw, alice, usdOffer));
2659 env(
pay(gw, carol, eurOffer));
2668 env(
offer(alice,
XRP(1000), usdOffer));
2669 env(
offer(bob, eurOffer,
XRP(1000)));
2670 auto const bobXrpBalance = env.balance(bob);
2674 env(
offer(carol, USD(400), EUR(400)));
2687 BEAST_EXPECT(alicesOffers.size() == 1);
2688 auto const& alicesOffer = *(alicesOffers.front());
2690 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2691 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2692 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2696 BEAST_EXPECT(bobsOffers.size() == 1);
2697 auto const& bobsOffer = *(bobsOffers.front());
2699 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2700 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2701 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2705 env(
offer(carol, USD(600), EUR(600)));
2720 if (alicesOffers.size() != 0)
2722 BEAST_EXPECT(alicesOffers.size() == 1);
2723 auto const& alicesOffer = *(alicesOffers.front());
2725 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2726 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2727 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2739 using namespace jtx;
2741 auto const gw =
Account(
"gateway");
2742 auto const USD = gw[
"USD"];
2744 Env env{*
this, features};
2746 env.fund(
XRP(10000000), gw);
2750 auto const f = env.current()->fees().base;
2753 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2787 : account(std::move(account_))
2792 , acctGets(acctGets_)
2793 , acctPays(acctPays_)
2795 , spentXrp(spentXrp_)
2796 , finalUsd(finalUsd_)
2799 , takerGets(takerGets_)
2800 , takerPays(takerPays_)
2819 std::move(account_),
2838 TestData
const tests[]{
2841 {
"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},
2842 {
"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)},
2843 {
"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},
2844 {
"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},
2845 {
"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},
2846 {
"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},
2847 {
"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},
2848 {
"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)},
2850 {
"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},
2851 {
"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)},
2852 {
"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},
2853 {
"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},
2854 {
"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},
2855 {
"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)},
2856 {
"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)},
2860 auto const zeroUsd = USD(0);
2861 for (
auto const& t : tests)
2864 env.require(
offers(gw, 0));
2866 auto const acct =
Account(t.account);
2868 env.fund(t.fundXrp, acct);
2874 if (t.fundUSD != zeroUsd)
2876 env(
trust(acct, t.fundUSD));
2878 env(
pay(gw, acct, t.fundUSD));
2882 env(
offer(gw, t.gwGets, t.gwPays));
2892 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2894 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2895 env.require(
offers(acct, t.offers));
2896 env.require(
owners(acct, t.owners));
2901 if (acctOffers.size() > 0)
2903 BEAST_EXPECT(acctOffers.size() == 1);
2904 auto const& acctOffer = *(acctOffers.front());
2906 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2907 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2908 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2925 testcase(
"Combine tfSell with tfFillOrKill");
2927 using namespace jtx;
2929 auto const gw =
Account(
"gateway");
2930 auto const alice =
Account(
"alice");
2931 auto const bob =
Account(
"bob");
2932 auto const USD = gw[
"USD"];
2934 Env env{*
this, features};
2936 env.fund(
XRP(10000000), gw, alice, bob);
2943 env(
trust(bob, USD(200)));
2945 env(
pay(gw, bob, USD(100)));
2947 env(
offer(bob,
XRP(2000), USD(20)));
2955 env.require(
offers(alice, 0));
2956 env.require(
balance(bob, USD(100)));
2963 env.require(
balance(alice, USD(20)));
2964 env.require(
offers(alice, 0));
2965 env.require(
balance(bob, USD(80)));
2970 env(
offer(bob,
XRP(2000), USD(20)));
2974 env.require(
balance(alice, USD(35)));
2975 env.require(
offers(alice, 0));
2976 env.require(
balance(bob, USD(65)));
2988 env.require(
balance(alice, USD(35)));
2989 env.require(
offers(alice, 0));
2990 env.require(
balance(bob, USD(65)));
2999 env.require(
balance(alice, USD(40)));
3000 env.require(
offers(alice, 0));
3001 env.require(
balance(bob, USD(60)));
3010 using namespace jtx;
3012 auto const gw1 =
Account(
"gateway1");
3013 auto const USD = gw1[
"USD"];
3015 Env env{*
this, features};
3018 auto const fee = env.current()->fees().base;
3020 env.fund(
XRP(100000), gw1);
3023 env(
rate(gw1, 1.25));
3025 auto const ann =
Account(
"ann");
3026 auto const bob =
Account(
"bob");
3030 env(
trust(ann, USD(200)));
3031 env(
trust(bob, USD(200)));
3034 env(
pay(gw1, bob, USD(125)));
3049 env.require(
balance(ann, USD(100)));
3051 env.require(
offers(ann, 0));
3053 env.require(
balance(bob, USD(0)));
3055 env.require(
offers(bob, 0));
3060 auto const che =
Account(
"che");
3061 auto const deb =
Account(
"deb");
3065 env(
trust(che, USD(200)));
3066 env(
trust(deb, USD(200)));
3069 env(
pay(gw1, deb, USD(125)));
3078 env.require(
balance(che, USD(100)));
3080 env.require(
offers(che, 0));
3082 env.require(
balance(deb, USD(0)));
3084 env.require(
offers(deb, 0));
3087 auto const eve =
Account(
"eve");
3088 auto const fyn =
Account(
"fyn");
3090 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3093 env(
trust(eve, USD(1000)));
3094 env(
trust(fyn, USD(1000)));
3097 env(
pay(gw1, eve, USD(100)));
3098 env(
pay(gw1, fyn, USD(100)));
3104 env(
offer(eve, USD(10),
XRP(4000)));
3108 env(
offer(fyn,
XRP(2000), USD(5)));
3111 env.require(
balance(eve, USD(105)));
3114 BEAST_EXPECT(evesOffers.size() == 1);
3115 if (evesOffers.size() != 0)
3117 auto const& evesOffer = *(evesOffers.front());
3118 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3119 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3120 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3124 env.require(
balance(fyn, USD(93.75)));
3126 env.require(
offers(fyn, 0));
3129 auto const gw2 =
Account(
"gateway2");
3130 auto const EUR = gw2[
"EUR"];
3132 env.fund(
XRP(100000), gw2);
3135 env(
rate(gw2, 1.5));
3140 auto const gay =
Account(
"gay");
3141 auto const hal =
Account(
"hal");
3142 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3145 env(
trust(gay, USD(200)));
3146 env(
trust(gay, EUR(200)));
3147 env(
trust(hal, USD(200)));
3148 env(
trust(hal, EUR(200)));
3151 env(
pay(gw1, gay, USD(125)));
3152 env(
pay(gw2, hal, EUR(150)));
3155 env(
offer(gay, EUR(100), USD(100)));
3158 env(
offer(hal, USD(100), EUR(100)));
3161 env.require(
balance(gay, USD(0)));
3162 env.require(
balance(gay, EUR(100)));
3164 env.require(
offers(gay, 0));
3166 env.require(
balance(hal, USD(100)));
3167 env.require(
balance(hal, EUR(0)));
3169 env.require(
offers(hal, 0));
3173 auto const ivy =
Account(
"ivy");
3174 auto const joe =
Account(
"joe");
3175 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3184 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3185 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3187 env.require(
balance(ivy, USD(300)));
3188 env.require(
balance(joe, EUR(250)));
3190 env(
offer(ivy, EUR(100), USD(200)));
3193 env(
offer(joe, USD(200), EUR(100)));
3196 env.require(
balance(ivy, USD(50)));
3197 env.require(
balance(ivy, EUR(100)));
3199 env.require(
offers(ivy, 0));
3201 env.require(
balance(joe, USD(200)));
3202 env.require(
balance(joe, EUR(100)));
3204 env.require(
offers(joe, 0));
3208 auto const kim =
Account(
"kim");
3209 auto const K_BUX = kim[
"BUX"];
3210 auto const lex =
Account(
"lex");
3211 auto const meg =
Account(
"meg");
3212 auto const ned =
Account(
"ned");
3213 auto const N_BUX = ned[
"BUX"];
3216 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3219 env(
trust(lex, K_BUX(400)));
3221 env(
trust(meg, N_BUX(100)));
3223 env(
pay(ned, lex, N_BUX(100)));
3225 env.require(
balance(lex, N_BUX(100)));
3227 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3232 env.require(
balance(lex, K_BUX(72)));
3233 env.require(
balance(lex, N_BUX(40)));
3235 env.require(
balance(meg, N_BUX(60)));
3240 env(
offer(lex, K_BUX(30), N_BUX(30)));
3243 env(
offer(kim, N_BUX(30), K_BUX(30)));
3247 env.require(
balance(kim, N_BUX(30)));
3248 env.require(
balance(lex, K_BUX(102)));
3249 env.require(
balance(lex, N_BUX(10)));
3251 env.require(
balance(meg, N_BUX(60)));
3252 env.require(
balance(ned, K_BUX(-30)));
3257 auto const ova =
Account(
"ova");
3258 auto const pat =
Account(
"pat");
3259 auto const qae =
Account(
"qae");
3260 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3266 env(
trust(ova, USD(200)));
3267 env(
trust(ova, EUR(200)));
3268 env(
trust(pat, USD(200)));
3269 env(
trust(pat, EUR(200)));
3270 env(
trust(qae, USD(200)));
3271 env(
trust(qae, EUR(200)));
3274 env(
pay(gw1, ova, USD(125)));
3275 env(
pay(gw2, qae, EUR(150)));
3282 env(
offer(qae, USD(100), EUR(100)));
3285 env.require(
balance(ova, USD(0)));
3286 env.require(
balance(ova, EUR(0)));
3291 if (ovasOffers.size() != 0)
3293 BEAST_EXPECT(ovasOffers.size() == 1);
3294 auto const& ovasOffer = *(ovasOffers.front());
3296 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3297 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3298 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3301 env.require(
balance(pat, USD(0)));
3302 env.require(
balance(pat, EUR(100)));
3304 env.require(
offers(pat, 0));
3306 env.require(
balance(qae, USD(100)));
3307 env.require(
balance(qae, EUR(0)));
3309 env.require(
offers(qae, 0));
3330 using namespace jtx;
3332 auto const gw =
Account(
"gateway");
3333 auto const USD = gw[
"USD"];
3335 Env env{*
this, features};
3338 auto const fee = env.current()->fees().base;
3339 auto const startBalance =
XRP(1000000);
3341 env.fund(startBalance + (
fee * 4), gw);
3351 env.require(
owners(gw, 3));
3352 env.require(
balance(gw, startBalance +
fee));
3355 BEAST_EXPECT(gwOffers.size() == 3);
3356 for (
auto const& offerPtr : gwOffers)
3358 auto const&
offer = *offerPtr;
3359 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3360 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3361 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3366 env(
offer(gw,
XRP(1000), USD(100)));
3368 env.require(
owners(gw, 1));
3369 env.require(
offers(gw, 1));
3370 env.require(
balance(gw, startBalance));
3373 BEAST_EXPECT(gwOffers.size() == 1);
3374 for (
auto const& offerPtr : gwOffers)
3376 auto const&
offer = *offerPtr;
3377 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3378 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3379 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3386 using namespace jtx;
3388 auto const gw1 =
Account(
"gateway1");
3389 auto const gw2 =
Account(
"gateway2");
3390 auto const alice =
Account(
"alice");
3391 auto const USD = gw1[
"USD"];
3392 auto const EUR = gw2[
"EUR"];
3394 Env env{*
this, features};
3396 env.fund(
XRP(1000000), gw1, gw2);
3400 auto const f = env.current()->fees().base;
3414 TestData
const tests[]{
3425 for (
auto const& t : tests)
3427 auto const acct =
Account{t.acct};
3428 env.fund(t.fundXRP, acct);
3431 env(
trust(acct, USD(1000)));
3432 env(
trust(acct, EUR(1000)));
3435 if (t.fundUSD > USD(0))
3436 env(
pay(gw1, acct, t.fundUSD));
3437 if (t.fundEUR > EUR(0))
3438 env(
pay(gw2, acct, t.fundEUR));
3441 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3445 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3446 env.require(
owners(acct, 2 + offerCount));
3447 env.require(
balance(acct, t.fundUSD));
3448 env.require(
balance(acct, t.fundEUR));
3451 BEAST_EXPECT(acctOffers.size() == offerCount);
3452 for (
auto const& offerPtr : acctOffers)
3454 auto const&
offer = *offerPtr;
3455 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3456 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3457 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3460 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3464 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3465 env.require(
owners(acct, 2 + offerCount));
3466 env.require(
balance(acct, t.fundUSD));
3467 env.require(
balance(acct, t.fundEUR));
3470 BEAST_EXPECT(acctOffers.size() == offerCount);
3471 for (
auto const& offerPtr : acctOffers)
3473 auto const&
offer = *offerPtr;
3474 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3475 if (
offer[sfSequence] == firstOfferSeq)
3477 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3478 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3482 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3483 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3510 using namespace jtx;
3512 Env env{*
this, features};
3514 auto const alice =
Account(
"alice");
3515 auto const bob =
Account(
"bob");
3516 auto const USD = bob[
"USD"];
3517 auto const f = env.current()->fees().base;
3519 env.fund(
XRP(50000) + f, alice, bob);
3522 env(
offer(alice, USD(5000),
XRP(50000)));
3526 env(
offer(bob,
XRP(50000), USD(5000)));
3532 env.require(
owners(alice, 1));
3533 env.require(
lines(alice, 1));
3538 BEAST_EXPECT(bobOffers.size() == 1);
3539 for (
auto const& offerPtr : bobOffers)
3541 auto const&
offer = *offerPtr;
3542 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3543 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3544 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3556 using namespace jtx;
3558 Env env{*
this, features};
3561 auto const fee = env.current()->fees().base;
3564 auto const ann =
Account(
"ann");
3565 auto const A_BUX = ann[
"BUX"];
3566 auto const bob =
Account(
"bob");
3567 auto const cam =
Account(
"cam");
3568 auto const dan =
Account(
"dan");
3569 auto const D_BUX = dan[
"BUX"];
3572 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3575 env(
trust(bob, A_BUX(400)));
3577 env(
trust(cam, D_BUX(100)));
3579 env(
pay(dan, bob, D_BUX(100)));
3581 env.require(
balance(bob, D_BUX(100)));
3583 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3588 env.require(
balance(bob, A_BUX(72)));
3589 env.require(
balance(bob, D_BUX(40)));
3591 env.require(
balance(cam, D_BUX(60)));
3595 env(
offer(bob, A_BUX(30), D_BUX(30)));
3598 env(
trust(ann, D_BUX(100)));
3602 env(
pay(ann, ann, D_BUX(30)),
3609 env.require(
balance(ann, D_BUX(0)));
3610 env.require(
balance(bob, A_BUX(72)));
3611 env.require(
balance(bob, D_BUX(40)));
3613 env.require(
balance(cam, D_BUX(60)));
3614 env.require(
balance(dan, A_BUX(0)));
3628 using namespace jtx;
3630 Env env{*
this, features};
3632 auto const ann =
Account(
"ann");
3633 auto const bob =
Account(
"bob");
3634 auto const cam =
Account(
"cam");
3635 auto const A_BUX = ann[
"BUX"];
3636 auto const B_BUX = bob[
"BUX"];
3638 auto const fee = env.current()->fees().base;
3639 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3642 env(
trust(ann, B_BUX(40)));
3643 env(
trust(cam, A_BUX(40)));
3644 env(
trust(cam, B_BUX(40)));
3647 env(
pay(ann, cam, A_BUX(35)));
3648 env(
pay(bob, cam, B_BUX(35)));
3650 env(
offer(bob, A_BUX(30), B_BUX(30)));
3658 env.require(
balance(cam, A_BUX(35)));
3659 env.require(
balance(cam, B_BUX(35)));
3660 env.require(
offers(cam, 1));
3663 env(
offer(cam, B_BUX(30), A_BUX(30)));
3666 env.require(
balance(bob, A_BUX(30)));
3667 env.require(
balance(cam, A_BUX(5)));
3668 env.require(
balance(cam, B_BUX(65)));
3669 env.require(
offers(cam, 0));
3678 testcase(
"Self crossing low quality offer");
3680 using namespace jtx;
3682 Env env{*
this, features};
3684 auto const ann =
Account(
"ann");
3685 auto const gw =
Account(
"gateway");
3686 auto const BTC = gw[
"BTC"];
3688 auto const fee = env.current()->fees().base;
3693 env(
rate(gw, 1.002));
3694 env(
trust(ann, BTC(10)));
3697 env(
pay(gw, ann, BTC(2.856)));
3700 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3704 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3717 using namespace jtx;
3719 Env env{*
this, features};
3721 auto const gw =
Account(
"gateway");
3722 auto const alice =
Account(
"alice");
3723 auto const bob =
Account(
"bob");
3724 auto const CNY = gw[
"CNY"];
3726 auto const fee = env.current()->fees().base;
3731 env(
trust(bob, CNY(500)));
3734 env(
pay(gw, bob, CNY(300)));
3737 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3741 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3745 BEAST_EXPECT(aliceOffers.size() == 1);
3746 for (
auto const& offerPtr : aliceOffers)
3748 auto const&
offer = *offerPtr;
3749 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3750 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3751 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3761 testcase(
"Offer In Scaling With Xfer Rate");
3763 using namespace jtx;
3765 Env env{*
this, features};
3767 auto const gw =
Account(
"gateway");
3768 auto const alice =
Account(
"alice");
3769 auto const bob =
Account(
"bob");
3770 auto const BTC = gw[
"BTC"];
3771 auto const JPY = gw[
"JPY"];
3773 auto const fee = env.current()->fees().base;
3778 env(
rate(gw, 1.002));
3779 env(
trust(alice, JPY(4000)));
3780 env(
trust(bob, BTC(2)));
3783 env(
pay(gw, alice, JPY(3699.034802280317)));
3784 env(
pay(gw, bob, BTC(1.156722559140311)));
3787 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3791 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3795 BEAST_EXPECT(aliceOffers.size() == 1);
3796 for (
auto const& offerPtr : aliceOffers)
3798 auto const&
offer = *offerPtr;
3799 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3801 offer[sfTakerGets] ==
3803 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3813 testcase(
"Offer Threshold With Reduced Funds");
3815 using namespace jtx;
3817 Env env{*
this, features};
3819 auto const gw1 =
Account(
"gw1");
3820 auto const gw2 =
Account(
"gw2");
3821 auto const alice =
Account(
"alice");
3822 auto const bob =
Account(
"bob");
3823 auto const USD = gw1[
"USD"];
3824 auto const JPY = gw2[
"JPY"];
3826 auto const fee = env.current()->fees().base;
3828 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3831 env(
rate(gw1, 1.002));
3832 env(
trust(alice, USD(1000)));
3833 env(
trust(bob, JPY(100000)));
3860 BEAST_EXPECT(aliceOffers.size() == 1);
3861 for (
auto const& offerPtr : aliceOffers)
3863 auto const&
offer = *offerPtr;
3864 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3866 offer[sfTakerGets] ==
3869 offer[sfTakerPays] ==
3879 using namespace jtx;
3881 Env env{*
this, features};
3883 auto const gw =
Account(
"gw");
3884 auto const alice =
Account(
"alice");
3885 auto const bob =
Account(
"bob");
3886 auto const CNY = gw[
"CNY"];
3887 auto const fee = env.current()->fees().base;
3888 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3890 env.fund(startXrpBalance, gw, alice, bob);
3893 env(
trust(bob, CNY(100000)));
3905 STAmount const bobsCnyStartBalance{
3907 env(
pay(gw, bob, bobsCnyStartBalance));
3916 env.require(
balance(alice, alicesCnyOffer));
3918 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
3961 using namespace jtx;
3963 Env env{*
this, features};
3964 auto const baseFee = env.current()->fees().base.drops();
3966 auto const gw =
Account(
"gw");
3967 auto const BTC = gw[
"BTC"];
3968 auto const USD = gw[
"USD"];
3969 auto const startXrpBalance =
XRP(4000000);
3971 env.fund(startXrpBalance, gw);
3974 env(
rate(gw, 1.25));
4000 TestData
const tests[]{
4002 {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)}}},
4003 {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)}}},
4004 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
4005 {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)}}},
4009 for (
auto const& t : tests)
4011 Account const& self = t.actors[t.self].acct;
4012 Account const& leg0 = t.actors[t.leg0].acct;
4013 Account const& leg1 = t.actors[t.leg1].acct;
4015 for (
auto const& actor : t.actors)
4017 env.fund(
XRP(4000000), actor.acct);
4020 env(
trust(actor.acct, BTC(40)));
4021 env(
trust(actor.acct, USD(8000)));
4025 env(
pay(gw, self, t.btcStart));
4026 env(
pay(gw, self, USD(2000)));
4027 if (self.
id() != leg1.
id())
4028 env(
pay(gw, leg1, USD(2000)));
4042 env(
offer(self, USD(1000), BTC(10)));
4047 for (
auto const& actor : t.actors)
4053 actorOffers.begin(),
4055 actorOffers.begin(),
4058 return (*offer)[sfTakerGets].signum() == 0;
4060 BEAST_EXPECT(offerCount == actor.offers);
4062 env.require(
balance(actor.acct, actor.xrp));
4063 env.require(
balance(actor.acct, actor.btc));
4064 env.require(
balance(actor.acct, actor.usd));
4080 testcase(
"Self Pay Unlimited Funds");
4112 using namespace jtx;
4114 Env env{*
this, features};
4115 auto const baseFee = env.current()->fees().base.drops();
4117 auto const gw =
Account(
"gw");
4118 auto const BTC = gw[
"BTC"];
4119 auto const USD = gw[
"USD"];
4120 auto const startXrpBalance =
XRP(4000000);
4122 env.fund(startXrpBalance, gw);
4125 env(
rate(gw, 1.25));
4151 TestData
const tests[]{
4153 {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)}}},
4154 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4158 for (
auto const& t : tests)
4160 Account const& self = t.actors[t.self].acct;
4161 Account const& leg0 = t.actors[t.leg0].acct;
4162 Account const& leg1 = t.actors[t.leg1].acct;
4164 for (
auto const& actor : t.actors)
4166 env.fund(
XRP(4000000), actor.acct);
4169 env(
trust(actor.acct, BTC(40)));
4170 env(
trust(actor.acct, USD(8000)));
4174 env(
pay(gw, self, t.btcStart));
4175 env(
pay(gw, self, USD(2000)));
4176 if (self.
id() != leg1.
id())
4177 env(
pay(gw, leg1, USD(2000)));
4191 env(
offer(self, USD(1000), BTC(10)));
4196 for (
auto const& actor : t.actors)
4202 actorOffers.begin(),
4204 actorOffers.begin(),
4207 return (*offer)[sfTakerGets].signum() == 0;
4209 BEAST_EXPECT(offerCount == actor.offers);
4211 env.require(
balance(actor.acct, actor.xrp));
4212 env.require(
balance(actor.acct, actor.btc));
4213 env.require(
balance(actor.acct, actor.usd));
4231 using namespace jtx;
4233 Env env{*
this, features};
4235 auto const gw =
Account(
"gw");
4236 auto const alice =
Account(
"alice");
4237 auto const bob =
Account(
"bob");
4238 auto const gwUSD = gw[
"USD"];
4239 auto const aliceUSD = alice[
"USD"];
4240 auto const bobUSD = bob[
"USD"];
4242 env.fund(
XRP(400000), gw, alice, bob);
4251 env(
trust(bob, gwUSD(100)));
4253 env(
trust(alice, gwUSD(100)));
4255 env(
offer(alice, gwUSD(40),
XRP(4000)));
4258 env.require(
offers(alice, 1));
4259 env.require(
balance(alice, gwUSD(0)));
4261 env(
pay(gw, bob, gwUSD(50)));
4264 env.require(
balance(bob, gwUSD(50)));
4267 env(
offer(bob,
XRP(4000), gwUSD(40)));
4270 env.require(
offers(alice, 0));
4271 env.require(
balance(alice, gwUSD(40)));
4273 env.require(
offers(bob, 0));
4274 env.require(
balance(bob, gwUSD(10)));
4299 using namespace jtx;
4301 Env env{*
this, features};
4303 auto const gw =
Account(
"gw");
4304 auto const alice =
Account(
"alice");
4305 auto const bob =
Account(
"bob");
4306 auto const gwUSD = gw[
"USD"];
4307 auto const aliceUSD = alice[
"USD"];
4308 auto const bobUSD = bob[
"USD"];
4310 env.fund(
XRP(400000), gw, alice, bob);
4313 env(
offer(alice, gwUSD(40),
XRP(4000)));
4316 env.require(
offers(alice, 1));
4323 env(
trust(bob, gwUSD(100)));
4326 env(
pay(gw, bob, gwUSD(50)));
4328 env.require(
balance(bob, gwUSD(50)));
4335 env(
offer(bob,
XRP(4000), gwUSD(40)));
4339 env.require(
offers(alice, 0));
4342 env.require(
offers(bob, 1));
4343 env.require(
balance(bob, gwUSD(50)));
4351 env.require(
offers(alice, 0));
4354 env.require(
offers(bob, 1));
4355 env.require(
balance(bob, gwUSD(50)));
4359 env(
trust(gw, aliceUSD(100)));
4365 env.require(
offers(alice, 0));
4366 env.require(
balance(alice, gwUSD(0)));
4368 env.require(
offers(bob, 1));
4369 env.require(
balance(bob, gwUSD(50)));
4374 env.require(
offers(bob, 0));
4382 env(
offer(alice, gwUSD(40),
XRP(4000)));
4385 env.require(
offers(alice, 1));
4388 env(
offer(bob,
XRP(4000), gwUSD(40)));
4391 env.require(
offers(alice, 0));
4392 env.require(
balance(alice, gwUSD(40)));
4394 env.require(
offers(bob, 0));
4395 env.require(
balance(bob, gwUSD(10)));
4401 testcase(
"RippleConnect Smoketest payment flow");
4402 using namespace jtx;
4404 Env env{*
this, features};
4414 auto const hotUS =
Account(
"hotUS");
4415 auto const coldUS =
Account(
"coldUS");
4416 auto const hotEU =
Account(
"hotEU");
4417 auto const coldEU =
Account(
"coldEU");
4418 auto const mm =
Account(
"mm");
4420 auto const USD = coldUS[
"USD"];
4421 auto const EUR = coldEU[
"EUR"];
4423 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4427 for (
auto const& cold : {coldUS, coldEU})
4450 env(
pay(coldUS, hotUS, USD(5000000)));
4451 env(
pay(coldEU, hotEU, EUR(5000000)));
4452 env(
pay(coldUS, mm, USD(5000000)));
4453 env(
pay(coldEU, mm, EUR(5000000)));
4457 float const rate = 0.9f;
4458 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4461 float const reverseRate = 1.0f /
rate * 1.00101f;
4462 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4469 jvParams[jss::destination_account] = coldEU.human();
4470 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4471 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4472 jvParams[jss::destination_amount][jss::value] = 10;
4473 jvParams[jss::source_account] = hotUS.human();
4476 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4478 BEAST_EXPECT(jrr[jss::status] ==
"success");
4480 jrr[jss::alternatives].isArray() &&
4481 jrr[jss::alternatives].size() > 0);
4484 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4492 using namespace jtx;
4494 Env env{*
this, features};
4496 auto const gw =
Account(
"gw");
4497 auto const alice =
Account(
"alice");
4498 auto const gwUSD = gw[
"USD"];
4499 auto const aliceUSD = alice[
"USD"];
4501 env.fund(
XRP(400000), gw, alice);
4505 env(
offer(gw, gwUSD(40),
XRP(4000)));
4508 env.require(
offers(gw, 1));
4517 env.require(
offers(gw, 0));
4524 bool const preauth = features[featureDepositPreauth];
4529 env(
offer(gw, gwUSD(40),
XRP(4000)),
4533 env.require(
offers(gw, preauth ? 1 : 0));
4541 env(
trust(alice, gwUSD(100)));
4544 env(
pay(gw, alice, gwUSD(50)));
4547 env.require(
balance(alice, gwUSD(50)));
4550 env(
offer(alice,
XRP(4000), gwUSD(40)));
4553 env.require(
offers(alice, 0));
4554 env.require(
balance(alice, gwUSD(10)));
4556 env.require(
offers(gw, 0));
4563 using namespace jtx;
4567 auto trustLineExists = [](
jtx::Env const& env,
4578 auto const USD = gw[
"USD"];
4579 auto const BUX = alice[
"BUX"];
4581 Env env{*
this, features};
4585 env.
trust(USD(1000), becky);
4586 env(
pay(gw, becky, USD(5)));
4588 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4599 env(
pay(becky, gw, USD(5)));
4600 env.
trust(USD(0), becky);
4602 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4603 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4604 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4611 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4613 if (gwSeq + 255 > openLedgerSeq)
4614 return gwSeq - openLedgerSeq + 255;
4618 for (
int i = 0; i < delta; ++i)
4635 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4636 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4642 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4643 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4648 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4652 env.
trust(BUX(1000), carol);
4653 env(
pay(alice, carol, BUX(2)));
4662 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4663 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4671 using namespace jtx;
4675 Env env{*
this, features};
4676 auto const gw =
Account{
"gateway"};
4677 env.fund(
XRP(10000), gw);
4680 auto txn =
noop(gw);
4681 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4684 txn[sfTickSize.fieldName] = Quality::minTickSize;
4686 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4689 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4691 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4694 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4696 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4699 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4702 txn[sfTickSize.fieldName] = 0;
4704 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4707 Env env{*
this, features};
4708 auto const gw =
Account{
"gateway"};
4709 auto const alice =
Account{
"alice"};
4710 auto const XTS = gw[
"XTS"];
4711 auto const XXX = gw[
"XXX"];
4713 env.fund(
XRP(10000), gw, alice);
4718 auto txn =
noop(gw);
4719 txn[sfTickSize.fieldName] = 5;
4721 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4724 env(
trust(alice, XTS(1000)));
4725 env(
trust(alice, XXX(1000)));
4727 env(
pay(gw, alice, alice[
"XTS"](100)));
4728 env(
pay(gw, alice, alice[
"XXX"](100)));
4730 env(
offer(alice, XTS(10), XXX(30)));
4731 env(
offer(alice, XTS(30), XXX(10)));
4738 if (sle->getType() == ltOFFER)
4742 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4746 auto it =
offers.begin();
4747 BEAST_EXPECT(it !=
offers.end());
4749 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4750 it->second.second > XXX(29.9994));
4754 BEAST_EXPECT(it !=
offers.end());
4756 it->second.first == XTS(30) && it->second.second == XXX(10));
4760 BEAST_EXPECT(it !=
offers.end());
4762 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4767 BEAST_EXPECT(it !=
offers.end());
4769 it->second.first == XTS(30) && it->second.second == XXX(10));
4771 BEAST_EXPECT(++it ==
offers.end());
4785 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4795 using namespace jtx;
4803 Env env{*
this, features};
4804 auto const gw =
Account{
"gateway"};
4805 auto const alice =
Account{
"alice"};
4806 auto const bob =
Account{
"bob"};
4807 auto const USD = gw[
"USD"];
4809 env.fund(
XRP(10000), gw, alice, bob);
4812 env(
trust(alice, USD(1000)));
4813 env(
trust(bob, USD(1000)));
4816 env(
pay(gw, alice, USD(200)));
4823 env(
offer(alice,
XRP(50), USD(50)));
4833 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4834 env(
offer(alice,
XRP(50), USD(50)));
4850 BEAST_EXPECT(
offers.size() == 4);
4851 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4852 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4853 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4854 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4855 env.require(
balance(alice, USD(200)));
4856 env.require(
owners(alice, 5));
4866 BEAST_EXPECT(
offers.size() == 3);
4867 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4868 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4869 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4879 BEAST_EXPECT(
offers.size() == 2);
4880 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4881 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4891 BEAST_EXPECT(
offers.size() == 1);
4892 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4902 BEAST_EXPECT(
offers.size() == 0);
4904 env.require(
balance(alice, USD(0)));
4905 env.require(
owners(alice, 1));
4906 env.require(
balance(bob, USD(200)));
4907 env.require(
owners(bob, 1));
4915 using namespace jtx;
4919 Env env{*
this, features};
4920 auto const gw =
Account{
"gateway"};
4921 auto const alice =
Account{
"alice"};
4922 auto const USD = gw[
"USD"];
4924 env.fund(
XRP(10000), gw, alice);
4927 env(
trust(alice, USD(1000)));
4931 env(
pay(gw, alice, USD(200)));
4936 env(
offer(alice,
XRP(50), USD(50)));
4948 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
4949 env(
offer(alice,
XRP(50), USD(50)));
4965 BEAST_EXPECT(
offers.size() == 4);
4966 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
4967 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
4968 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
4969 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
4970 env.require(
balance(alice, USD(200)));
4971 env.require(
owners(alice, 7));
4981 BEAST_EXPECT(
offers.size() == 3);
4982 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
4983 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
4984 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
4994 BEAST_EXPECT(
offers.size() == 2);
4995 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
4996 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5009 BEAST_EXPECT(
offers.size() == 1);
5010 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5027 testcase(
"incorrect assert fixed");
5028 using namespace jtx;
5031 auto const alice =
Account(
"alice");
5032 auto const USD = alice[
"USD"];
5034 env.fund(
XRP(10000), alice);
5036 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5044 using namespace jtx;
5045 Env env(*
this, features);
5046 Account const issuer(
"issuer");
5049 auto const USD = issuer[
"USD"];
5050 auto const EUR = issuer[
"EUR"];
5053 env.
fund(
XRP(1'000), maker, taker);
5056 env.
trust(USD(1'000), maker, taker);
5057 env.
trust(EUR(1'000), maker, taker);
5060 env(
pay(issuer, maker, USD(1'000)));
5061 env(
pay(issuer, taker, USD(1'000)));
5062 env(
pay(issuer, maker, EUR(1'000)));
5065 auto makerUSDBalance = env.
balance(maker, USD).
value();
5066 auto takerUSDBalance = env.
balance(taker, USD).
value();
5067 auto makerEURBalance = env.
balance(maker, EUR).
value();
5068 auto takerEURBalance = env.
balance(taker, EUR).
value();
5077 env(
offer(maker,
XRP(100), USD(100)));
5080 env(
offer(taker, USD(100),
XRP(101)),
5085 makerXRPBalance -=
txfee(env, 1);
5086 takerXRPBalance -=
txfee(env, 1);
5089 makerUSDBalance -= USD(100);
5090 takerUSDBalance += USD(100);
5091 makerXRPBalance +=
XRP(100).value();
5092 takerXRPBalance -=
XRP(100).value();
5096 env(
offer(maker, USD(100),
XRP(100)));
5099 env(
offer(taker,
XRP(100), USD(101)),
5104 makerXRPBalance -=
txfee(env, 1);
5105 takerXRPBalance -=
txfee(env, 1);
5108 makerUSDBalance += USD(100);
5109 takerUSDBalance -= USD(100);
5110 makerXRPBalance -=
XRP(100).value();
5111 takerXRPBalance +=
XRP(100).value();
5115 env(
offer(maker, USD(100), EUR(100)));
5118 env(
offer(taker, EUR(100), USD(101)),
5123 makerXRPBalance -=
txfee(env, 1);
5124 takerXRPBalance -=
txfee(env, 1);
5127 makerUSDBalance += USD(100);
5128 takerUSDBalance -= USD(100);
5129 makerEURBalance -= EUR(100);
5130 takerEURBalance += EUR(100);
5137 env(
offer(maker,
XRP(101), USD(101)));
5140 env(
offer(taker, USD(100),
XRP(101)),
5144 makerUSDBalance -= USD(101);
5145 takerUSDBalance += USD(101);
5146 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5147 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5150 env(
offer(maker, USD(101),
XRP(101)));
5153 env(
offer(taker,
XRP(100), USD(101)),
5157 makerUSDBalance += USD(101);
5158 takerUSDBalance -= USD(101);
5159 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5160 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5163 env(
offer(maker, USD(101), EUR(101)));
5166 env(
offer(taker, EUR(100), USD(101)),
5170 makerUSDBalance += USD(101);
5171 takerUSDBalance -= USD(101);
5172 makerEURBalance -= EUR(101);
5173 takerEURBalance += EUR(101);
5174 makerXRPBalance -=
txfee(env, 1);
5175 takerXRPBalance -=
txfee(env, 1);
5182 env(
offer(maker,
XRP(100), USD(100)));
5185 env(
offer(taker, USD(100),
XRP(99)),
5190 makerXRPBalance -=
txfee(env, 1);
5191 takerXRPBalance -=
txfee(env, 1);
5194 env(
offer(maker, USD(100),
XRP(100)));
5197 env(
offer(taker,
XRP(100), USD(99)),
5202 makerXRPBalance -=
txfee(env, 1);
5203 takerXRPBalance -=
txfee(env, 1);
5206 env(
offer(maker, USD(100), EUR(100)));
5209 env(
offer(taker, EUR(100), USD(99)),
5214 makerXRPBalance -=
txfee(env, 1);
5215 takerXRPBalance -=
txfee(env, 1);
5220 env.
balance(maker, USD) == makerUSDBalance &&
5221 env.
balance(taker, USD) == takerUSDBalance &&
5222 env.
balance(maker, EUR) == makerEURBalance &&
5223 env.
balance(taker, EUR) == takerEURBalance &&
5224 env.
balance(maker,
XRP) == makerXRPBalance &&
5295 using namespace jtx;
5297 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5299 featureImmediateOfferKilled};
5304 all - takerDryOffer - immediateOfferKilled - permDEX,
5305 all - immediateOfferKilled - permDEX,
5306 all - immediateOfferKilled - fillOrKill - permDEX,
5307 all - fillOrKill - permDEX,
5311 if (BEAST_EXPECT(instance < feats.size()))
5315 BEAST_EXPECT(!
last || instance == feats.size() - 1);
5376 using namespace jtx;
5378 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5383 testAll(
all - immediateOfferKilled - permDEX);
5384 testAll(
all - immediateOfferKilled - fillOrKill - permDEX);
5393BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app,
ripple, 2);
5394BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, app,
ripple, 2);
5395BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app,
ripple, 2);
5396BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, app,
ripple, 2);
5397BEAST_DEFINE_TESTSUITE_PRIO(OfferWOPermDEX, app,
ripple, 2);
5398BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app,
ripple, 2);
5399BEAST_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