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);
859 env(
offer(alice,
XRP(1000), USD(1000)),
865 balance(alice, startBalance - f - f),
872 env(
offer(alice,
XRP(1000), USD(1000)),
877 balance(alice, startBalance - f - f - f +
XRP(50)),
893 balance(alice, startBalance - f - f - f - f +
XRP(100)),
897 balance(bob, startBalance - f - f -
XRP(100)),
905 Env env(*
this, features);
907 env.
fund(startBalance, gw, alice, bob);
910 env(
trust(bob, USD(1000)));
913 env(
pay(gw, bob, USD(1000)));
916 env(
offer(alice, USD(1000),
XRP(2000)));
920 BEAST_EXPECT(aliceOffers.size() == 1);
921 for (
auto offerPtr : aliceOffers)
923 auto const&
offer = *offerPtr;
924 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
925 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
935 BEAST_EXPECT(bobOffers.size() == 1);
936 for (
auto offerPtr : bobOffers)
938 auto const&
offer = *offerPtr;
939 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
940 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
944 env(
offer(gw,
XRP(2000), USD(1000)));
950 env(
offer(gw, USD(1000),
XRP(2000)));
958 Env env(*
this, features);
960 env.
fund(startBalance, gw,
"alice",
"bob");
963 env(
trust(
"bob", USD(1000)));
966 env(
pay(gw,
"bob", USD(1000)));
967 env(
offer(
"alice", USD(500),
XRP(1001)));
970 env(
offer(
"alice", USD(500),
XRP(1000)));
974 BEAST_EXPECT(aliceOffers.size() == 2);
984 BEAST_EXPECT(bobOffers.size() == 1);
985 for (
auto offerPtr : bobOffers)
987 auto const&
offer = *offerPtr;
988 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
989 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
1001 auto const startBalance =
XRP(1000000);
1002 auto const gw =
Account{
"gateway"};
1003 auto const alice =
Account{
"alice"};
1004 auto const USD = gw[
"USD"];
1006 Env env{*
this, features};
1008 env.fund(startBalance, gw, alice);
1012 env(
offer(alice, USD(1000),
XRP(1000)),
1019 env(
offer(alice, USD(1000),
XRP(1000)),
1049 env(
offer(alice, USD(1000),
XRP(1000)),
1057 env(
offer(alice, USD(1000),
XRP(1000)),
1077 using namespace jtx;
1079 auto const gw =
Account{
"gateway"};
1080 auto const alice =
Account{
"alice"};
1081 auto const bob =
Account{
"bob"};
1082 auto const USD = gw[
"USD"];
1084 auto const startBalance =
XRP(1000000);
1085 auto const usdOffer = USD(1000);
1086 auto const xrpOffer =
XRP(1000);
1088 Env env{*
this, features};
1090 env.fund(startBalance, gw, alice, bob);
1093 auto const f = env.current()->fees().base;
1099 balance(alice, startBalance - f),
1106 bool const featPreauth{features[featureDepositPreauth]};
1108 env(
offer(alice, xrpOffer, usdOffer),
1113 balance(alice, startBalance - f - f),
1120 env(
offer(alice, xrpOffer, usdOffer),
1124 balance(alice, startBalance - f - f - f),
1132 balance(alice, startBalance - f - f - f),
1140 balance(alice, startBalance - f - f - f),
1144 balance(bob, startBalance - f),
1155 using namespace jtx;
1157 auto const gw =
Account{
"gateway"};
1158 auto const USD = gw[
"USD"];
1160 auto const usdOffer = USD(1000);
1161 auto const xrpOffer =
XRP(1000);
1163 Env env{*
this, features};
1165 env.fund(
XRP(1000000), gw);
1169 auto const f = env.current()->fees().base;
1173 env.fund(
reserve(env, 0),
"alice");
1180 env.fund(
reserve(env, 0) + f,
"bob");
1188 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1196 env.fund(
reserve(env, 1) + f,
"dan");
1203 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1215 (use_partner ?
", with partner account" :
""));
1217 using namespace jtx;
1219 auto const gw =
Account{
"gateway"};
1220 auto const partner =
Account{
"partner"};
1221 auto const USD = gw[
"USD"];
1222 auto const BTC = gw[
"BTC"];
1224 Env env{*
this, features};
1227 env.fund(
XRP(10000), gw);
1230 env.fund(
XRP(10000), partner);
1232 env(
trust(partner, USD(100)));
1233 env(
trust(partner, BTC(500)));
1235 env(
pay(gw, partner, USD(100)));
1236 env(
pay(gw, partner, BTC(500)));
1238 auto const& account_to_test = use_partner ? partner : gw;
1241 env.require(
offers(account_to_test, 0));
1246 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1247 env.require(
offers(account_to_test, 1));
1250 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1252 auto const secondLegSeq = env.seq(account_to_test);
1253 env(
offer(account_to_test,
XRP(1000), USD(50)));
1254 env.require(
offers(account_to_test, 2));
1257 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1261 env(
offer(account_to_test, USD(50), BTC(250)));
1264 BEAST_EXPECT(jrr[jss::offers].isArray());
1265 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1268 BEAST_EXPECT(jrr[jss::offers].isArray());
1269 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1276 BEAST_EXPECT(acctOffers.size() == 0);
1277 for (
auto const& offerPtr : acctOffers)
1279 auto const&
offer = *offerPtr;
1280 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1281 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1282 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1290 env.require(
offers(account_to_test, 0));
1295 env(
offer(account_to_test, BTC(250), USD(50)));
1296 env.require(
offers(account_to_test, 1));
1300 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1303 BEAST_EXPECT(jrr[jss::offers].isArray());
1304 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1308 env(
offer(account_to_test, USD(50), BTC(250)));
1309 env.require(
offers(account_to_test, 1));
1314 BEAST_EXPECT(jrr[jss::offers].isArray());
1315 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1317 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1327 using namespace jtx;
1332 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1334 Env env{*
this, localFeatures};
1336 auto const gw =
Account{
"gateway"};
1337 auto const alice =
Account{
"alice"};
1338 auto const bob =
Account{
"bob"};
1339 auto const USD = gw[
"USD"];
1340 auto const BTC = gw[
"BTC"];
1344 auto const gw_initial_balance =
drops(1149999730);
1345 auto const alice_initial_balance =
drops(499946999680);
1346 auto const bob_initial_balance =
drops(10199999920);
1347 auto const small_amount =
1348 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1350 env.fund(gw_initial_balance, gw);
1351 env.fund(alice_initial_balance, alice);
1352 env.fund(bob_initial_balance, bob);
1355 env(
rate(gw, 1.005));
1357 env(
trust(alice, USD(500)));
1358 env(
trust(bob, USD(50)));
1359 env(
trust(gw, alice[
"USD"](100)));
1361 env(
pay(gw, alice, alice[
"USD"](50)));
1362 env(
pay(gw, bob, small_amount));
1364 env(
offer(alice, USD(50),
XRP(150000)));
1367 env(
pay(alice, gw, USD(100)));
1370 env(
trust(gw, alice[
"USD"](0)));
1375 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1379 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1380 "-2710505431213761e-33");
1384 env(
offer(bob,
XRP(2000), USD(1)));
1386 if (localFeatures[fixReducedOffersV2])
1393 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1394 "-2710505431213761e-33");
1398 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1399 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1410 auto const crossingDelta =
drops(1);
1414 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1417 alice_initial_balance - env.current()->fees().base * 3 -
1422 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1425 bob_initial_balance - env.current()->fees().base * 2 +
1435 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1437 using namespace jtx;
1439 Env env{*
this, features};
1441 auto const gw =
Account{
"gateway"};
1442 auto const alice =
Account{
"alice"};
1443 auto const bob =
Account{
"bob"};
1444 auto const USD = gw[
"USD"];
1446 env.fund(
XRP(10000), gw, alice, bob);
1449 env(
trust(alice, USD(1000)));
1450 env(
trust(bob, USD(1000)));
1452 env(
pay(gw, alice, alice[
"USD"](500)));
1455 env(
offer(bob, USD(1),
XRP(4000)));
1457 env(
offer(alice,
XRP(150000), USD(50)));
1460 env(
offer(bob, USD(1),
XRP(4000)));
1467 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1470 jrr[jss::node][sfBalance.fieldName] ==
1472 env.current()->fees().base * 2)
1476 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1479 jrr[jss::node][sfBalance.fieldName] ==
1481 env.current()->fees().base * 2)
1488 testcase(
"Offer Crossing with Limit Override");
1490 using namespace jtx;
1492 Env env{*
this, features};
1494 auto const gw =
Account{
"gateway"};
1495 auto const alice =
Account{
"alice"};
1496 auto const bob =
Account{
"bob"};
1497 auto const USD = gw[
"USD"];
1499 env.fund(
XRP(100000), gw, alice, bob);
1502 env(
trust(alice, USD(1000)));
1504 env(
pay(gw, alice, alice[
"USD"](500)));
1506 env(
offer(alice,
XRP(150000), USD(50)));
1507 env(
offer(bob, USD(1),
XRP(3000)));
1510 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1513 jrr[jss::node][sfBalance.fieldName] ==
1518 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1521 jrr[jss::node][sfBalance.fieldName] ==
1529 testcase(
"Offer Accept then Cancel.");
1531 using namespace jtx;
1533 Env env{*
this, features};
1535 auto const USD = env.master[
"USD"];
1537 auto const nextOfferSeq = env.seq(env.master);
1538 env(
offer(env.master,
XRP(500), USD(100)));
1542 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1547 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1553 testcase(
"Offer Cancel Past and Future Sequence.");
1555 using namespace jtx;
1557 Env env{*
this, features};
1559 auto const alice =
Account{
"alice"};
1561 auto const nextOfferSeq = env.seq(env.master);
1562 env.fund(
XRP(10000), alice);
1579 testcase(
"Currency Conversion: Entire Offer");
1581 using namespace jtx;
1583 Env env{*
this, features};
1585 auto const gw =
Account{
"gateway"};
1586 auto const alice =
Account{
"alice"};
1587 auto const bob =
Account{
"bob"};
1588 auto const USD = gw[
"USD"];
1590 env.fund(
XRP(10000), gw, alice, bob);
1592 env.require(
owners(bob, 0));
1594 env(
trust(alice, USD(100)));
1595 env(
trust(bob, USD(1000)));
1599 env(
pay(gw, alice, alice[
"USD"](100)));
1600 auto const bobOfferSeq = env.seq(bob);
1601 env(
offer(bob, USD(100),
XRP(500)));
1606 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1608 jro[jss::node][jss::TakerPays] ==
1614 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1617 jrr[jss::node][sfBalance.fieldName] ==
1622 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1625 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1633 testcase(
"Currency Conversion: Offerer Into Debt");
1635 using namespace jtx;
1637 Env env{*
this, features};
1639 auto const alice =
Account{
"alice"};
1640 auto const bob =
Account{
"bob"};
1641 auto const carol =
Account{
"carol"};
1643 env.fund(
XRP(10000), alice, bob, carol);
1646 env(
trust(alice, carol[
"EUR"](2000)));
1647 env(
trust(bob, alice[
"USD"](100)));
1648 env(
trust(carol, bob[
"EUR"](1000)));
1650 auto const bobOfferSeq = env.seq(bob);
1651 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1654 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1657 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1663 testcase(
"Currency Conversion: In Parts");
1665 using namespace jtx;
1667 Env env{*
this, features};
1669 auto const gw =
Account{
"gateway"};
1670 auto const alice =
Account{
"alice"};
1671 auto const bob =
Account{
"bob"};
1672 auto const USD = gw[
"USD"];
1674 env.fund(
XRP(10000), gw, alice, bob);
1677 env(
trust(alice, USD(200)));
1678 env(
trust(bob, USD(1000)));
1680 env(
pay(gw, alice, alice[
"USD"](200)));
1682 auto const bobOfferSeq = env.seq(bob);
1683 env(
offer(bob, USD(100),
XRP(500)));
1690 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1692 jro[jss::node][jss::TakerPays] ==
1698 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1702 jrr[jss::node][sfBalance.fieldName] ==
1708 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1712 env(
pay(alice, alice,
XRP(600)),
1718 env(
pay(alice, alice,
XRP(600)),
1724 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1732 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1735 jrr[jss::node][sfBalance.fieldName] ==
1737 env.current()->fees().base * 4)
1743 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1749 testcase(
"Cross Currency Payment: Start with XRP");
1751 using namespace jtx;
1753 Env env{*
this, features};
1755 auto const gw =
Account{
"gateway"};
1756 auto const alice =
Account{
"alice"};
1757 auto const bob =
Account{
"bob"};
1758 auto const carol =
Account{
"carol"};
1759 auto const USD = gw[
"USD"];
1761 env.fund(
XRP(10000), gw, alice, bob, carol);
1764 env(
trust(carol, USD(1000)));
1765 env(
trust(bob, USD(2000)));
1767 env(
pay(gw, carol, carol[
"USD"](500)));
1769 auto const carolOfferSeq = env.seq(carol);
1770 env(
offer(carol,
XRP(500), USD(50)));
1775 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1778 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1782 jro[jss::node][jss::TakerGets] ==
1785 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1791 testcase(
"Cross Currency Payment: End with XRP");
1793 using namespace jtx;
1795 Env env{*
this, features};
1797 auto const gw =
Account{
"gateway"};
1798 auto const alice =
Account{
"alice"};
1799 auto const bob =
Account{
"bob"};
1800 auto const carol =
Account{
"carol"};
1801 auto const USD = gw[
"USD"];
1803 env.fund(
XRP(10000), gw, alice, bob, carol);
1806 env(
trust(alice, USD(1000)));
1807 env(
trust(carol, USD(2000)));
1809 env(
pay(gw, alice, alice[
"USD"](500)));
1811 auto const carolOfferSeq = env.seq(carol);
1812 env(
offer(carol, USD(50),
XRP(500)));
1817 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1820 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1824 jrr[jss::node][sfBalance.fieldName] ==
1826 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1830 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1832 jro[jss::node][jss::TakerPays] ==
1839 testcase(
"Cross Currency Payment: Bridged");
1841 using namespace jtx;
1843 Env env{*
this, features};
1845 auto const gw1 =
Account{
"gateway_1"};
1846 auto const gw2 =
Account{
"gateway_2"};
1847 auto const alice =
Account{
"alice"};
1848 auto const bob =
Account{
"bob"};
1849 auto const carol =
Account{
"carol"};
1850 auto const dan =
Account{
"dan"};
1851 auto const USD = gw1[
"USD"];
1852 auto const EUR = gw2[
"EUR"];
1854 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1857 env(
trust(alice, USD(1000)));
1858 env(
trust(bob, EUR(1000)));
1859 env(
trust(carol, USD(1000)));
1860 env(
trust(dan, EUR(1000)));
1862 env(
pay(gw1, alice, alice[
"USD"](500)));
1863 env(
pay(gw2, dan, dan[
"EUR"](400)));
1865 auto const carolOfferSeq = env.seq(carol);
1866 env(
offer(carol, USD(50),
XRP(500)));
1868 auto const danOfferSeq = env.seq(dan);
1869 env(
offer(dan,
XRP(500), EUR(50)));
1872 jtp[0u][0u][jss::currency] =
"XRP";
1873 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1876 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1879 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1882 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1885 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1889 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1891 jro[jss::node][jss::TakerPays] ==
1896 jro[jss::node][jss::TakerGets] ==
1899 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1908 testcase(
"Auto Bridged Second Leg Dry");
1910 using namespace jtx;
1911 Env env(*
this, features);
1917 auto const USD = gw[
"USD"];
1918 auto const EUR = gw[
"EUR"];
1920 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1923 env.
trust(USD(10), alice);
1925 env(
pay(gw, alice, USD(10)));
1926 env.
trust(USD(10), carol);
1928 env(
pay(gw, carol, USD(3)));
1945 env.
trust(EUR(10), bob);
1947 env(
pay(gw, bob, EUR(10)));
1949 env(
offer(bob, USD(10), EUR(10)));
1972 testcase(
"Offer Fees Consume Funds");
1974 using namespace jtx;
1976 Env env{*
this, features};
1978 auto const gw1 =
Account{
"gateway_1"};
1979 auto const gw2 =
Account{
"gateway_2"};
1980 auto const gw3 =
Account{
"gateway_3"};
1981 auto const alice =
Account{
"alice"};
1982 auto const bob =
Account{
"bob"};
1983 auto const USD1 = gw1[
"USD"];
1984 auto const USD2 = gw2[
"USD"];
1985 auto const USD3 = gw3[
"USD"];
1993 auto const starting_xrp =
XRP(100) +
1994 env.current()->fees().accountReserve(3) +
1995 env.current()->fees().base * 4;
1997 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2000 env(
trust(alice, USD1(1000)));
2001 env(
trust(alice, USD2(1000)));
2002 env(
trust(alice, USD3(1000)));
2003 env(
trust(bob, USD1(1000)));
2004 env(
trust(bob, USD2(1000)));
2006 env(
pay(gw1, bob, bob[
"USD"](500)));
2008 env(
offer(bob,
XRP(200), USD1(200)));
2011 env(
offer(alice, USD1(200),
XRP(200)));
2014 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2017 jrr[jss::node][sfBalance.fieldName] ==
2021 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2027 testcase(
"Offer Create, then Cross");
2029 using namespace jtx;
2031 for (
auto NumberSwitchOver : {
false,
true})
2033 Env env{*
this, features};
2034 if (NumberSwitchOver)
2035 env.enableFeature(fixUniversalNumber);
2037 env.disableFeature(fixUniversalNumber);
2039 auto const gw =
Account{
"gateway"};
2040 auto const alice =
Account{
"alice"};
2041 auto const bob =
Account{
"bob"};
2042 auto const USD = gw[
"USD"];
2044 env.fund(
XRP(10000), gw, alice, bob);
2047 env(
rate(gw, 1.005));
2049 env(
trust(alice, USD(1000)));
2050 env(
trust(bob, USD(1000)));
2051 env(
trust(gw, alice[
"USD"](50)));
2053 env(
pay(gw, bob, bob[
"USD"](1)));
2054 env(
pay(alice, gw, USD(50)));
2056 env(
trust(gw, alice[
"USD"](0)));
2058 env(
offer(alice, USD(50),
XRP(150000)));
2059 env(
offer(bob,
XRP(100), USD(0.1)));
2063 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2064 "49.96666666666667");
2068 jrr[jss::node][sfBalance.fieldName][jss::value];
2069 if (!NumberSwitchOver)
2071 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2075 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2083 testcase(
"Offer tfSell: Basic Sell");
2085 using namespace jtx;
2087 Env env{*
this, features};
2089 auto const gw =
Account{
"gateway"};
2090 auto const alice =
Account{
"alice"};
2091 auto const bob =
Account{
"bob"};
2092 auto const USD = gw[
"USD"];
2094 auto const starting_xrp =
XRP(100) +
2095 env.current()->fees().accountReserve(1) +
2096 env.current()->fees().base * 2;
2098 env.fund(starting_xrp, gw, alice, bob);
2101 env(
trust(alice, USD(1000)));
2102 env(
trust(bob, USD(1000)));
2104 env(
pay(gw, bob, bob[
"USD"](500)));
2113 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2116 jrr[jss::node][sfBalance.fieldName] ==
2120 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2126 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2128 using namespace jtx;
2130 Env env{*
this, features};
2132 auto const gw =
Account{
"gateway"};
2133 auto const alice =
Account{
"alice"};
2134 auto const bob =
Account{
"bob"};
2135 auto const USD = gw[
"USD"];
2137 auto const starting_xrp =
XRP(100) +
2138 env.current()->fees().accountReserve(1) +
2139 env.current()->fees().base * 2;
2141 env.fund(starting_xrp, gw, alice, bob);
2144 env(
trust(alice, USD(150)));
2145 env(
trust(bob, USD(1000)));
2147 env(
pay(gw, bob, bob[
"USD"](500)));
2149 env(
offer(bob,
XRP(100), USD(200)));
2158 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2161 jrr[jss::node][sfBalance.fieldName] ==
2165 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2171 testcase(
"Client Issue #535: Gateway Cross Currency");
2173 using namespace jtx;
2175 Env env{*
this, features};
2177 auto const gw =
Account{
"gateway"};
2178 auto const alice =
Account{
"alice"};
2179 auto const bob =
Account{
"bob"};
2180 auto const XTS = gw[
"XTS"];
2181 auto const XXX = gw[
"XXX"];
2183 auto const starting_xrp =
XRP(100.1) +
2184 env.current()->fees().accountReserve(1) +
2185 env.current()->fees().base * 2;
2187 env.fund(starting_xrp, gw, alice, bob);
2190 env(
trust(alice, XTS(1000)));
2191 env(
trust(alice, XXX(1000)));
2192 env(
trust(bob, XTS(1000)));
2193 env(
trust(bob, XXX(1000)));
2195 env(
pay(gw, alice, alice[
"XTS"](100)));
2196 env(
pay(gw, alice, alice[
"XXX"](100)));
2197 env(
pay(gw, bob, bob[
"XTS"](100)));
2198 env(
pay(gw, bob, bob[
"XXX"](100)));
2200 env(
offer(alice, XTS(100), XXX(100)));
2207 payment[jss::id] = env.seq(bob);
2208 payment[jss::build_path] =
true;
2209 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2210 payment[jss::tx_json][jss::Sequence] =
2213 ->getFieldU32(sfSequence);
2214 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2215 payment[jss::tx_json][jss::SendMax] =
2217 auto jrr = wsc->invoke(
"submit", payment);
2218 BEAST_EXPECT(jrr[jss::status] ==
"success");
2219 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2220 if (wsc->version() == 2)
2223 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2225 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2226 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2230 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2232 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2235 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2237 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2252 auto const sleTrust =
2254 BEAST_EXPECT(sleTrust);
2258 bool const accountLow = account.id() < issue.
account;
2263 low.setIssuer(accountLow ? account.id() : issue.
account);
2264 high.setIssuer(accountLow ? issue.
account : account.id());
2266 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2267 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2269 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2273 BEAST_EXPECT(actualBalance == expectBalance);
2285 using namespace jtx;
2287 auto const gw =
Account(
"gateway");
2288 auto const USD = gw[
"USD"];
2290 Env env{*
this, features};
2292 env.fund(
XRP(10000000), gw);
2296 auto const f = env.current()->fees().base;
2299 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2305 preTrustType preTrust;
2315 TestData
const tests[]{
2317 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2318 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2319 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2320 {
"deb",
drops(10) +
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 1},
2321 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2322 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2323 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2324 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2325 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2326 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2327 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2328 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2329 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2330 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2331 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2332 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2333 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2334 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2336 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2337 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2338 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2339 {
"dan",
drops(10) +
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
drops(10) + f, USD(0.00001), 0, 0},
2340 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2341 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2342 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2343 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2345 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2346 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2347 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2348 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2349 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2350 {
"syd",
drops(10) +
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
drops(10) + 2 * f, USD(0.00001), 0, 1},
2351 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2352 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2353 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2354 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2355 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2359 for (
auto const& t : tests)
2361 auto const acct =
Account(t.account);
2362 env.fund(t.fundXrp, acct);
2366 env.require(
offers(gw, 0));
2369 auto const book = t.bookAmount;
2371 env(
offer(gw,
XRP(book), USD(book)));
2376 if (t.preTrust == gwPreTrust)
2377 env(
trust(gw, acct[
"USD"](1)));
2383 if (t.preTrust == acctPreTrust)
2384 env(
trust(acct, USD(1)));
2389 auto const acctOffer = t.offerAmount;
2390 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2395 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2397 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2398 env.require(
offers(acct, t.offers));
2399 env.require(
owners(acct, t.owners));
2402 BEAST_EXPECT(acctOffers.size() == t.offers);
2403 if (acctOffers.size() && t.offers)
2405 auto const& acctOffer = *(acctOffers.front());
2407 auto const leftover = t.offerAmount - t.bookAmount;
2408 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2409 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2412 if (t.preTrust == noPreTrust)
2414 if (t.balanceUsd.value().signum())
2422 auto const sleTrust =
2424 BEAST_EXPECT(!sleTrust);
2441 using namespace jtx;
2443 auto const gw =
Account(
"gateway");
2444 auto const alice =
Account(
"alice");
2445 auto const bob =
Account(
"bob");
2446 auto const USD = gw[
"USD"];
2448 auto const usdOffer = USD(1000);
2449 auto const xrpOffer =
XRP(1000);
2451 Env env{*
this, features};
2453 env.fund(
XRP(1000000), gw, bob);
2457 auto const fee = env.current()->fees().base;
2464 env(
trust(alice, usdOffer));
2468 env(
pay(gw, alice, usdOffer));
2475 auto const alicesXRP = env.balance(alice);
2476 auto const bobsXRP = env.balance(bob);
2478 env(
offer(alice, xrpOffer, usdOffer));
2480 env(
offer(bob, usdOffer, xrpOffer));
2494 env(
offer(alice, USD(999),
XRP(999)));
2495 env(
offer(bob, xrpOffer, usdOffer));
2498 env.require(
balance(alice, USD(999)));
2499 env.require(
balance(bob, USD(1)));
2500 env.require(
offers(alice, 0));
2504 BEAST_EXPECT(bobsOffers.size() == 1);
2505 auto const& bobsOffer = *(bobsOffers.front());
2507 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2508 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2509 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2518 using namespace jtx;
2520 auto const gw =
Account(
"gateway");
2521 auto const alice =
Account(
"alice");
2522 auto const bob =
Account(
"bob");
2523 auto const USD = gw[
"USD"];
2524 auto const EUR = gw[
"EUR"];
2526 auto const usdOffer = USD(1000);
2527 auto const eurOffer = EUR(1000);
2529 Env env{*
this, features};
2531 env.fund(
XRP(1000000), gw);
2535 auto const fee = env.current()->fees().base;
2543 env(
trust(alice, usdOffer));
2544 env(
trust(bob, eurOffer));
2547 env(
pay(gw, alice, usdOffer));
2548 env(
pay(gw, bob, eurOffer));
2556 env(
offer(alice, eurOffer, usdOffer));
2557 env(
offer(bob, usdOffer, eurOffer));
2574 env(
offer(bob, eurOffer, usdOffer));
2577 env(
offer(alice, USD(999), eurOffer));
2580 env.require(
offers(alice, 0));
2581 env.require(
offers(bob, 1));
2583 env.require(
balance(alice, USD(999)));
2584 env.require(
balance(alice, EUR(1)));
2585 env.require(
balance(bob, USD(1)));
2586 env.require(
balance(bob, EUR(999)));
2590 if (BEAST_EXPECT(bobsOffers.size() == 1))
2592 auto const& bobsOffer = *(bobsOffers.front());
2594 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2595 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2600 env(
offer(alice, USD(1), EUR(1)));
2603 env.require(
balance(alice, USD(1000)));
2606 env.require(
balance(bob, EUR(1000)));
2607 env.require(
offers(alice, 0));
2608 env.require(
offers(bob, 0));
2611 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2612 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2616 env(
offer(alice, EUR(999), usdOffer));
2619 env(
offer(bob, usdOffer, eurOffer));
2622 env.require(
offers(alice, 0));
2623 env.require(
offers(bob, 0));
2625 env.require(
balance(alice, USD(0)));
2626 env.require(
balance(alice, EUR(999)));
2627 env.require(
balance(bob, USD(1000)));
2628 env.require(
balance(bob, EUR(1)));
2636 using namespace jtx;
2638 auto const gw =
Account(
"gateway");
2639 auto const alice =
Account(
"alice");
2640 auto const bob =
Account(
"bob");
2641 auto const carol =
Account(
"carol");
2642 auto const USD = gw[
"USD"];
2643 auto const EUR = gw[
"EUR"];
2645 auto const usdOffer = USD(1000);
2646 auto const eurOffer = EUR(1000);
2648 Env env{*
this, features};
2650 env.fund(
XRP(1000000), gw, alice, bob, carol);
2653 env(
trust(alice, usdOffer));
2654 env(
trust(carol, eurOffer));
2656 env(
pay(gw, alice, usdOffer));
2657 env(
pay(gw, carol, eurOffer));
2666 env(
offer(alice,
XRP(1000), usdOffer));
2667 env(
offer(bob, eurOffer,
XRP(1000)));
2668 auto const bobXrpBalance = env.balance(bob);
2672 env(
offer(carol, USD(400), EUR(400)));
2685 BEAST_EXPECT(alicesOffers.size() == 1);
2686 auto const& alicesOffer = *(alicesOffers.front());
2688 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2689 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2690 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2694 BEAST_EXPECT(bobsOffers.size() == 1);
2695 auto const& bobsOffer = *(bobsOffers.front());
2697 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2698 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2699 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2703 env(
offer(carol, USD(600), EUR(600)));
2718 if (alicesOffers.size() != 0)
2720 BEAST_EXPECT(alicesOffers.size() == 1);
2721 auto const& alicesOffer = *(alicesOffers.front());
2723 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2724 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2725 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2737 using namespace jtx;
2739 auto const gw =
Account(
"gateway");
2740 auto const USD = gw[
"USD"];
2742 Env env{*
this, features};
2744 env.fund(
XRP(10000000), gw);
2748 auto const f = env.current()->fees().base;
2751 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2785 : account(std::move(account_))
2790 , acctGets(acctGets_)
2791 , acctPays(acctPays_)
2793 , spentXrp(spentXrp_)
2794 , finalUsd(finalUsd_)
2797 , takerGets(takerGets_)
2798 , takerPays(takerPays_)
2817 std::move(account_),
2836 TestData
const tests[]{
2839 {
"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},
2840 {
"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)},
2841 {
"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},
2842 {
"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},
2843 {
"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},
2844 {
"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},
2845 {
"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},
2846 {
"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)},
2848 {
"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},
2849 {
"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)},
2850 {
"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},
2851 {
"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},
2852 {
"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},
2853 {
"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)},
2854 {
"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)},
2858 auto const zeroUsd = USD(0);
2859 for (
auto const& t : tests)
2862 env.require(
offers(gw, 0));
2864 auto const acct =
Account(t.account);
2866 env.fund(t.fundXrp, acct);
2872 if (t.fundUSD != zeroUsd)
2874 env(
trust(acct, t.fundUSD));
2876 env(
pay(gw, acct, t.fundUSD));
2880 env(
offer(gw, t.gwGets, t.gwPays));
2890 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2892 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2893 env.require(
offers(acct, t.offers));
2894 env.require(
owners(acct, t.owners));
2899 if (acctOffers.size() > 0)
2901 BEAST_EXPECT(acctOffers.size() == 1);
2902 auto const& acctOffer = *(acctOffers.front());
2904 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2905 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2906 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2923 testcase(
"Combine tfSell with tfFillOrKill");
2925 using namespace jtx;
2927 auto const gw =
Account(
"gateway");
2928 auto const alice =
Account(
"alice");
2929 auto const bob =
Account(
"bob");
2930 auto const USD = gw[
"USD"];
2932 Env env{*
this, features};
2934 env.fund(
XRP(10000000), gw, alice, bob);
2941 env(
trust(bob, USD(200)));
2943 env(
pay(gw, bob, USD(100)));
2945 env(
offer(bob,
XRP(2000), USD(20)));
2953 env.require(
offers(alice, 0));
2954 env.require(
balance(bob, USD(100)));
2961 env.require(
balance(alice, USD(20)));
2962 env.require(
offers(alice, 0));
2963 env.require(
balance(bob, USD(80)));
2968 env(
offer(bob,
XRP(2000), USD(20)));
2972 env.require(
balance(alice, USD(35)));
2973 env.require(
offers(alice, 0));
2974 env.require(
balance(bob, USD(65)));
2986 env.require(
balance(alice, USD(35)));
2987 env.require(
offers(alice, 0));
2988 env.require(
balance(bob, USD(65)));
2997 env.require(
balance(alice, USD(40)));
2998 env.require(
offers(alice, 0));
2999 env.require(
balance(bob, USD(60)));
3008 using namespace jtx;
3010 auto const gw1 =
Account(
"gateway1");
3011 auto const USD = gw1[
"USD"];
3013 Env env{*
this, features};
3016 auto const fee = env.current()->fees().base;
3018 env.fund(
XRP(100000), gw1);
3021 env(
rate(gw1, 1.25));
3023 auto const ann =
Account(
"ann");
3024 auto const bob =
Account(
"bob");
3028 env(
trust(ann, USD(200)));
3029 env(
trust(bob, USD(200)));
3032 env(
pay(gw1, bob, USD(125)));
3047 env.require(
balance(ann, USD(100)));
3049 env.require(
offers(ann, 0));
3051 env.require(
balance(bob, USD(0)));
3053 env.require(
offers(bob, 0));
3058 auto const che =
Account(
"che");
3059 auto const deb =
Account(
"deb");
3063 env(
trust(che, USD(200)));
3064 env(
trust(deb, USD(200)));
3067 env(
pay(gw1, deb, USD(125)));
3076 env.require(
balance(che, USD(100)));
3078 env.require(
offers(che, 0));
3080 env.require(
balance(deb, USD(0)));
3082 env.require(
offers(deb, 0));
3085 auto const eve =
Account(
"eve");
3086 auto const fyn =
Account(
"fyn");
3088 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3091 env(
trust(eve, USD(1000)));
3092 env(
trust(fyn, USD(1000)));
3095 env(
pay(gw1, eve, USD(100)));
3096 env(
pay(gw1, fyn, USD(100)));
3102 env(
offer(eve, USD(10),
XRP(4000)));
3106 env(
offer(fyn,
XRP(2000), USD(5)));
3109 env.require(
balance(eve, USD(105)));
3112 BEAST_EXPECT(evesOffers.size() == 1);
3113 if (evesOffers.size() != 0)
3115 auto const& evesOffer = *(evesOffers.front());
3116 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3117 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3118 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3122 env.require(
balance(fyn, USD(93.75)));
3124 env.require(
offers(fyn, 0));
3127 auto const gw2 =
Account(
"gateway2");
3128 auto const EUR = gw2[
"EUR"];
3130 env.fund(
XRP(100000), gw2);
3133 env(
rate(gw2, 1.5));
3138 auto const gay =
Account(
"gay");
3139 auto const hal =
Account(
"hal");
3140 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3143 env(
trust(gay, USD(200)));
3144 env(
trust(gay, EUR(200)));
3145 env(
trust(hal, USD(200)));
3146 env(
trust(hal, EUR(200)));
3149 env(
pay(gw1, gay, USD(125)));
3150 env(
pay(gw2, hal, EUR(150)));
3153 env(
offer(gay, EUR(100), USD(100)));
3156 env(
offer(hal, USD(100), EUR(100)));
3159 env.require(
balance(gay, USD(0)));
3160 env.require(
balance(gay, EUR(100)));
3162 env.require(
offers(gay, 0));
3164 env.require(
balance(hal, USD(100)));
3165 env.require(
balance(hal, EUR(0)));
3167 env.require(
offers(hal, 0));
3171 auto const ivy =
Account(
"ivy");
3172 auto const joe =
Account(
"joe");
3173 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3182 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3183 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3185 env.require(
balance(ivy, USD(300)));
3186 env.require(
balance(joe, EUR(250)));
3188 env(
offer(ivy, EUR(100), USD(200)));
3191 env(
offer(joe, USD(200), EUR(100)));
3194 env.require(
balance(ivy, USD(50)));
3195 env.require(
balance(ivy, EUR(100)));
3197 env.require(
offers(ivy, 0));
3199 env.require(
balance(joe, USD(200)));
3200 env.require(
balance(joe, EUR(100)));
3202 env.require(
offers(joe, 0));
3206 auto const kim =
Account(
"kim");
3207 auto const K_BUX = kim[
"BUX"];
3208 auto const lex =
Account(
"lex");
3209 auto const meg =
Account(
"meg");
3210 auto const ned =
Account(
"ned");
3211 auto const N_BUX = ned[
"BUX"];
3214 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3217 env(
trust(lex, K_BUX(400)));
3219 env(
trust(meg, N_BUX(100)));
3221 env(
pay(ned, lex, N_BUX(100)));
3223 env.require(
balance(lex, N_BUX(100)));
3225 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3230 env.require(
balance(lex, K_BUX(72)));
3231 env.require(
balance(lex, N_BUX(40)));
3233 env.require(
balance(meg, N_BUX(60)));
3238 env(
offer(lex, K_BUX(30), N_BUX(30)));
3241 env(
offer(kim, N_BUX(30), K_BUX(30)));
3245 env.require(
balance(kim, N_BUX(30)));
3246 env.require(
balance(lex, K_BUX(102)));
3247 env.require(
balance(lex, N_BUX(10)));
3249 env.require(
balance(meg, N_BUX(60)));
3250 env.require(
balance(ned, K_BUX(-30)));
3255 auto const ova =
Account(
"ova");
3256 auto const pat =
Account(
"pat");
3257 auto const qae =
Account(
"qae");
3258 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3264 env(
trust(ova, USD(200)));
3265 env(
trust(ova, EUR(200)));
3266 env(
trust(pat, USD(200)));
3267 env(
trust(pat, EUR(200)));
3268 env(
trust(qae, USD(200)));
3269 env(
trust(qae, EUR(200)));
3272 env(
pay(gw1, ova, USD(125)));
3273 env(
pay(gw2, qae, EUR(150)));
3280 env(
offer(qae, USD(100), EUR(100)));
3283 env.require(
balance(ova, USD(0)));
3284 env.require(
balance(ova, EUR(0)));
3289 if (ovasOffers.size() != 0)
3291 BEAST_EXPECT(ovasOffers.size() == 1);
3292 auto const& ovasOffer = *(ovasOffers.front());
3294 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3295 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3296 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3299 env.require(
balance(pat, USD(0)));
3300 env.require(
balance(pat, EUR(100)));
3302 env.require(
offers(pat, 0));
3304 env.require(
balance(qae, USD(100)));
3305 env.require(
balance(qae, EUR(0)));
3307 env.require(
offers(qae, 0));
3328 using namespace jtx;
3330 auto const gw =
Account(
"gateway");
3331 auto const USD = gw[
"USD"];
3333 Env env{*
this, features};
3336 auto const fee = env.current()->fees().base;
3337 auto const startBalance =
XRP(1000000);
3339 env.fund(startBalance + (
fee * 4), gw);
3349 env.require(
owners(gw, 3));
3350 env.require(
balance(gw, startBalance +
fee));
3353 BEAST_EXPECT(gwOffers.size() == 3);
3354 for (
auto const& offerPtr : gwOffers)
3356 auto const&
offer = *offerPtr;
3357 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3358 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3359 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3364 env(
offer(gw,
XRP(1000), USD(100)));
3366 env.require(
owners(gw, 1));
3367 env.require(
offers(gw, 1));
3368 env.require(
balance(gw, startBalance));
3371 BEAST_EXPECT(gwOffers.size() == 1);
3372 for (
auto const& offerPtr : gwOffers)
3374 auto const&
offer = *offerPtr;
3375 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3376 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3377 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3384 using namespace jtx;
3386 auto const gw1 =
Account(
"gateway1");
3387 auto const gw2 =
Account(
"gateway2");
3388 auto const alice =
Account(
"alice");
3389 auto const USD = gw1[
"USD"];
3390 auto const EUR = gw2[
"EUR"];
3392 Env env{*
this, features};
3394 env.fund(
XRP(1000000), gw1, gw2);
3398 auto const f = env.current()->fees().base;
3412 TestData
const tests[]{
3423 for (
auto const& t : tests)
3425 auto const acct =
Account{t.acct};
3426 env.fund(t.fundXRP, acct);
3429 env(
trust(acct, USD(1000)));
3430 env(
trust(acct, EUR(1000)));
3433 if (t.fundUSD > USD(0))
3434 env(
pay(gw1, acct, t.fundUSD));
3435 if (t.fundEUR > EUR(0))
3436 env(
pay(gw2, acct, t.fundEUR));
3439 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3443 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3444 env.require(
owners(acct, 2 + offerCount));
3445 env.require(
balance(acct, t.fundUSD));
3446 env.require(
balance(acct, t.fundEUR));
3449 BEAST_EXPECT(acctOffers.size() == offerCount);
3450 for (
auto const& offerPtr : acctOffers)
3452 auto const&
offer = *offerPtr;
3453 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3454 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3455 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3458 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3462 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3463 env.require(
owners(acct, 2 + offerCount));
3464 env.require(
balance(acct, t.fundUSD));
3465 env.require(
balance(acct, t.fundEUR));
3468 BEAST_EXPECT(acctOffers.size() == offerCount);
3469 for (
auto const& offerPtr : acctOffers)
3471 auto const&
offer = *offerPtr;
3472 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3473 if (
offer[sfSequence] == firstOfferSeq)
3475 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3476 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3480 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3481 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3508 using namespace jtx;
3510 Env env{*
this, features};
3512 auto const alice =
Account(
"alice");
3513 auto const bob =
Account(
"bob");
3514 auto const USD = bob[
"USD"];
3515 auto const f = env.current()->fees().base;
3517 env.fund(
XRP(50000) + f, alice, bob);
3520 env(
offer(alice, USD(5000),
XRP(50000)));
3524 env(
offer(bob,
XRP(50000), USD(5000)));
3530 env.require(
owners(alice, 1));
3531 env.require(
lines(alice, 1));
3536 BEAST_EXPECT(bobOffers.size() == 1);
3537 for (
auto const& offerPtr : bobOffers)
3539 auto const&
offer = *offerPtr;
3540 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3541 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3542 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3554 using namespace jtx;
3556 Env env{*
this, features};
3559 auto const fee = env.current()->fees().base;
3562 auto const ann =
Account(
"ann");
3563 auto const A_BUX = ann[
"BUX"];
3564 auto const bob =
Account(
"bob");
3565 auto const cam =
Account(
"cam");
3566 auto const dan =
Account(
"dan");
3567 auto const D_BUX = dan[
"BUX"];
3570 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3573 env(
trust(bob, A_BUX(400)));
3575 env(
trust(cam, D_BUX(100)));
3577 env(
pay(dan, bob, D_BUX(100)));
3579 env.require(
balance(bob, D_BUX(100)));
3581 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3586 env.require(
balance(bob, A_BUX(72)));
3587 env.require(
balance(bob, D_BUX(40)));
3589 env.require(
balance(cam, D_BUX(60)));
3593 env(
offer(bob, A_BUX(30), D_BUX(30)));
3596 env(
trust(ann, D_BUX(100)));
3600 env(
pay(ann, ann, D_BUX(30)),
3607 env.require(
balance(ann, D_BUX(0)));
3608 env.require(
balance(bob, A_BUX(72)));
3609 env.require(
balance(bob, D_BUX(40)));
3611 env.require(
balance(cam, D_BUX(60)));
3612 env.require(
balance(dan, A_BUX(0)));
3626 using namespace jtx;
3628 Env env{*
this, features};
3630 auto const ann =
Account(
"ann");
3631 auto const bob =
Account(
"bob");
3632 auto const cam =
Account(
"cam");
3633 auto const A_BUX = ann[
"BUX"];
3634 auto const B_BUX = bob[
"BUX"];
3636 auto const fee = env.current()->fees().base;
3637 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3640 env(
trust(ann, B_BUX(40)));
3641 env(
trust(cam, A_BUX(40)));
3642 env(
trust(cam, B_BUX(40)));
3645 env(
pay(ann, cam, A_BUX(35)));
3646 env(
pay(bob, cam, B_BUX(35)));
3648 env(
offer(bob, A_BUX(30), B_BUX(30)));
3656 env.require(
balance(cam, A_BUX(35)));
3657 env.require(
balance(cam, B_BUX(35)));
3658 env.require(
offers(cam, 1));
3661 env(
offer(cam, B_BUX(30), A_BUX(30)));
3664 env.require(
balance(bob, A_BUX(30)));
3665 env.require(
balance(cam, A_BUX(5)));
3666 env.require(
balance(cam, B_BUX(65)));
3667 env.require(
offers(cam, 0));
3676 testcase(
"Self crossing low quality offer");
3678 using namespace jtx;
3680 Env env{*
this, features};
3682 auto const ann =
Account(
"ann");
3683 auto const gw =
Account(
"gateway");
3684 auto const BTC = gw[
"BTC"];
3686 auto const fee = env.current()->fees().base;
3691 env(
rate(gw, 1.002));
3692 env(
trust(ann, BTC(10)));
3695 env(
pay(gw, ann, BTC(2.856)));
3698 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3702 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3715 using namespace jtx;
3717 Env env{*
this, features};
3719 auto const gw =
Account(
"gateway");
3720 auto const alice =
Account(
"alice");
3721 auto const bob =
Account(
"bob");
3722 auto const CNY = gw[
"CNY"];
3724 auto const fee = env.current()->fees().base;
3729 env(
trust(bob, CNY(500)));
3732 env(
pay(gw, bob, CNY(300)));
3735 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3739 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3743 BEAST_EXPECT(aliceOffers.size() == 1);
3744 for (
auto const& offerPtr : aliceOffers)
3746 auto const&
offer = *offerPtr;
3747 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3748 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3749 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3759 testcase(
"Offer In Scaling With Xfer Rate");
3761 using namespace jtx;
3763 Env env{*
this, features};
3765 auto const gw =
Account(
"gateway");
3766 auto const alice =
Account(
"alice");
3767 auto const bob =
Account(
"bob");
3768 auto const BTC = gw[
"BTC"];
3769 auto const JPY = gw[
"JPY"];
3771 auto const fee = env.current()->fees().base;
3776 env(
rate(gw, 1.002));
3777 env(
trust(alice, JPY(4000)));
3778 env(
trust(bob, BTC(2)));
3781 env(
pay(gw, alice, JPY(3699.034802280317)));
3782 env(
pay(gw, bob, BTC(1.156722559140311)));
3785 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3789 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3793 BEAST_EXPECT(aliceOffers.size() == 1);
3794 for (
auto const& offerPtr : aliceOffers)
3796 auto const&
offer = *offerPtr;
3797 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3799 offer[sfTakerGets] ==
3801 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3811 testcase(
"Offer Threshold With Reduced Funds");
3813 using namespace jtx;
3815 Env env{*
this, features};
3817 auto const gw1 =
Account(
"gw1");
3818 auto const gw2 =
Account(
"gw2");
3819 auto const alice =
Account(
"alice");
3820 auto const bob =
Account(
"bob");
3821 auto const USD = gw1[
"USD"];
3822 auto const JPY = gw2[
"JPY"];
3824 auto const fee = env.current()->fees().base;
3826 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3829 env(
rate(gw1, 1.002));
3830 env(
trust(alice, USD(1000)));
3831 env(
trust(bob, JPY(100000)));
3858 BEAST_EXPECT(aliceOffers.size() == 1);
3859 for (
auto const& offerPtr : aliceOffers)
3861 auto const&
offer = *offerPtr;
3862 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3864 offer[sfTakerGets] ==
3867 offer[sfTakerPays] ==
3877 using namespace jtx;
3879 Env env{*
this, features};
3881 auto const gw =
Account(
"gw");
3882 auto const alice =
Account(
"alice");
3883 auto const bob =
Account(
"bob");
3884 auto const CNY = gw[
"CNY"];
3885 auto const fee = env.current()->fees().base;
3886 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3888 env.fund(startXrpBalance, gw, alice, bob);
3891 env(
trust(bob, CNY(100000)));
3903 STAmount const bobsCnyStartBalance{
3905 env(
pay(gw, bob, bobsCnyStartBalance));
3914 env.require(
balance(alice, alicesCnyOffer));
3916 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
3959 using namespace jtx;
3961 Env env{*
this, features};
3962 auto const baseFee = env.current()->fees().base.drops();
3964 auto const gw =
Account(
"gw");
3965 auto const BTC = gw[
"BTC"];
3966 auto const USD = gw[
"USD"];
3967 auto const startXrpBalance =
XRP(4000000);
3969 env.fund(startXrpBalance, gw);
3972 env(
rate(gw, 1.25));
3998 TestData
const tests[]{
4000 {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)}}},
4001 {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)}}},
4002 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(4000000'000000 - 5 * baseFee), BTC(20.0), USD(2000)} }},
4003 {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)}}},
4007 for (
auto const& t : tests)
4009 Account const& self = t.actors[t.self].acct;
4010 Account const& leg0 = t.actors[t.leg0].acct;
4011 Account const& leg1 = t.actors[t.leg1].acct;
4013 for (
auto const& actor : t.actors)
4015 env.fund(
XRP(4000000), actor.acct);
4018 env(
trust(actor.acct, BTC(40)));
4019 env(
trust(actor.acct, USD(8000)));
4023 env(
pay(gw, self, t.btcStart));
4024 env(
pay(gw, self, USD(2000)));
4025 if (self.
id() != leg1.
id())
4026 env(
pay(gw, leg1, USD(2000)));
4040 env(
offer(self, USD(1000), BTC(10)));
4045 for (
auto const& actor : t.actors)
4051 actorOffers.begin(),
4053 actorOffers.begin(),
4056 return (*offer)[sfTakerGets].signum() == 0;
4058 BEAST_EXPECT(offerCount == actor.offers);
4060 env.require(
balance(actor.acct, actor.xrp));
4061 env.require(
balance(actor.acct, actor.btc));
4062 env.require(
balance(actor.acct, actor.usd));
4078 testcase(
"Self Pay Unlimited Funds");
4110 using namespace jtx;
4112 Env env{*
this, features};
4113 auto const baseFee = env.current()->fees().base.drops();
4115 auto const gw =
Account(
"gw");
4116 auto const BTC = gw[
"BTC"];
4117 auto const USD = gw[
"USD"];
4118 auto const startXrpBalance =
XRP(4000000);
4120 env.fund(startXrpBalance, gw);
4123 env(
rate(gw, 1.25));
4149 TestData
const tests[]{
4151 {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)}}},
4152 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(4000000'000000 - 5 * baseFee), BTC(5), USD(2000)} }}
4156 for (
auto const& t : tests)
4158 Account const& self = t.actors[t.self].acct;
4159 Account const& leg0 = t.actors[t.leg0].acct;
4160 Account const& leg1 = t.actors[t.leg1].acct;
4162 for (
auto const& actor : t.actors)
4164 env.fund(
XRP(4000000), actor.acct);
4167 env(
trust(actor.acct, BTC(40)));
4168 env(
trust(actor.acct, USD(8000)));
4172 env(
pay(gw, self, t.btcStart));
4173 env(
pay(gw, self, USD(2000)));
4174 if (self.
id() != leg1.
id())
4175 env(
pay(gw, leg1, USD(2000)));
4189 env(
offer(self, USD(1000), BTC(10)));
4194 for (
auto const& actor : t.actors)
4200 actorOffers.begin(),
4202 actorOffers.begin(),
4205 return (*offer)[sfTakerGets].signum() == 0;
4207 BEAST_EXPECT(offerCount == actor.offers);
4209 env.require(
balance(actor.acct, actor.xrp));
4210 env.require(
balance(actor.acct, actor.btc));
4211 env.require(
balance(actor.acct, actor.usd));
4229 using namespace jtx;
4231 Env env{*
this, features};
4233 auto const gw =
Account(
"gw");
4234 auto const alice =
Account(
"alice");
4235 auto const bob =
Account(
"bob");
4236 auto const gwUSD = gw[
"USD"];
4237 auto const aliceUSD = alice[
"USD"];
4238 auto const bobUSD = bob[
"USD"];
4240 env.fund(
XRP(400000), gw, alice, bob);
4249 env(
trust(bob, gwUSD(100)));
4251 env(
trust(alice, gwUSD(100)));
4253 env(
offer(alice, gwUSD(40),
XRP(4000)));
4256 env.require(
offers(alice, 1));
4257 env.require(
balance(alice, gwUSD(0)));
4259 env(
pay(gw, bob, gwUSD(50)));
4262 env.require(
balance(bob, gwUSD(50)));
4265 env(
offer(bob,
XRP(4000), gwUSD(40)));
4268 env.require(
offers(alice, 0));
4269 env.require(
balance(alice, gwUSD(40)));
4271 env.require(
offers(bob, 0));
4272 env.require(
balance(bob, gwUSD(10)));
4297 using namespace jtx;
4299 Env env{*
this, features};
4301 auto const gw =
Account(
"gw");
4302 auto const alice =
Account(
"alice");
4303 auto const bob =
Account(
"bob");
4304 auto const gwUSD = gw[
"USD"];
4305 auto const aliceUSD = alice[
"USD"];
4306 auto const bobUSD = bob[
"USD"];
4308 env.fund(
XRP(400000), gw, alice, bob);
4311 env(
offer(alice, gwUSD(40),
XRP(4000)));
4314 env.require(
offers(alice, 1));
4321 env(
trust(bob, gwUSD(100)));
4324 env(
pay(gw, bob, gwUSD(50)));
4326 env.require(
balance(bob, gwUSD(50)));
4333 env(
offer(bob,
XRP(4000), gwUSD(40)));
4337 env.require(
offers(alice, 0));
4340 env.require(
offers(bob, 1));
4341 env.require(
balance(bob, gwUSD(50)));
4349 env.require(
offers(alice, 0));
4352 env.require(
offers(bob, 1));
4353 env.require(
balance(bob, gwUSD(50)));
4357 env(
trust(gw, aliceUSD(100)));
4363 env.require(
offers(alice, 0));
4364 env.require(
balance(alice, gwUSD(0)));
4366 env.require(
offers(bob, 1));
4367 env.require(
balance(bob, gwUSD(50)));
4372 env.require(
offers(bob, 0));
4380 env(
offer(alice, gwUSD(40),
XRP(4000)));
4383 env.require(
offers(alice, 1));
4386 env(
offer(bob,
XRP(4000), gwUSD(40)));
4389 env.require(
offers(alice, 0));
4390 env.require(
balance(alice, gwUSD(40)));
4392 env.require(
offers(bob, 0));
4393 env.require(
balance(bob, gwUSD(10)));
4399 testcase(
"RippleConnect Smoketest payment flow");
4400 using namespace jtx;
4402 Env env{*
this, features};
4412 auto const hotUS =
Account(
"hotUS");
4413 auto const coldUS =
Account(
"coldUS");
4414 auto const hotEU =
Account(
"hotEU");
4415 auto const coldEU =
Account(
"coldEU");
4416 auto const mm =
Account(
"mm");
4418 auto const USD = coldUS[
"USD"];
4419 auto const EUR = coldEU[
"EUR"];
4421 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4425 for (
auto const& cold : {coldUS, coldEU})
4448 env(
pay(coldUS, hotUS, USD(5000000)));
4449 env(
pay(coldEU, hotEU, EUR(5000000)));
4450 env(
pay(coldUS, mm, USD(5000000)));
4451 env(
pay(coldEU, mm, EUR(5000000)));
4455 float const rate = 0.9f;
4456 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4459 float const reverseRate = 1.0f /
rate * 1.00101f;
4460 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4467 jvParams[jss::destination_account] = coldEU.human();
4468 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4469 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4470 jvParams[jss::destination_amount][jss::value] = 10;
4471 jvParams[jss::source_account] = hotUS.human();
4474 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4476 BEAST_EXPECT(jrr[jss::status] ==
"success");
4478 jrr[jss::alternatives].isArray() &&
4479 jrr[jss::alternatives].size() > 0);
4482 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4490 using namespace jtx;
4492 Env env{*
this, features};
4494 auto const gw =
Account(
"gw");
4495 auto const alice =
Account(
"alice");
4496 auto const gwUSD = gw[
"USD"];
4497 auto const aliceUSD = alice[
"USD"];
4499 env.fund(
XRP(400000), gw, alice);
4503 env(
offer(gw, gwUSD(40),
XRP(4000)));
4506 env.require(
offers(gw, 1));
4515 env.require(
offers(gw, 0));
4522 bool const preauth = features[featureDepositPreauth];
4527 env(
offer(gw, gwUSD(40),
XRP(4000)),
4531 env.require(
offers(gw, preauth ? 1 : 0));
4539 env(
trust(alice, gwUSD(100)));
4542 env(
pay(gw, alice, gwUSD(50)));
4545 env.require(
balance(alice, gwUSD(50)));
4548 env(
offer(alice,
XRP(4000), gwUSD(40)));
4551 env.require(
offers(alice, 0));
4552 env.require(
balance(alice, gwUSD(10)));
4554 env.require(
offers(gw, 0));
4561 using namespace jtx;
4565 auto trustLineExists = [](
jtx::Env const& env,
4576 auto const USD = gw[
"USD"];
4577 auto const BUX = alice[
"BUX"];
4579 Env env{*
this, features};
4583 env.
trust(USD(1000), becky);
4584 env(
pay(gw, becky, USD(5)));
4586 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4597 env(
pay(becky, gw, USD(5)));
4598 env.
trust(USD(0), becky);
4600 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4601 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4602 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4609 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4611 if (gwSeq + 255 > openLedgerSeq)
4612 return gwSeq - openLedgerSeq + 255;
4616 for (
int i = 0; i < delta; ++i)
4633 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4634 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4640 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4641 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4646 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4650 env.
trust(BUX(1000), carol);
4651 env(
pay(alice, carol, BUX(2)));
4660 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4661 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4669 using namespace jtx;
4673 Env env{*
this, features};
4674 auto const gw =
Account{
"gateway"};
4675 env.fund(
XRP(10000), gw);
4678 auto txn =
noop(gw);
4679 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4682 txn[sfTickSize.fieldName] = Quality::minTickSize;
4684 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4687 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4689 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4692 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4694 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4697 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4700 txn[sfTickSize.fieldName] = 0;
4702 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4705 Env env{*
this, features};
4706 auto const gw =
Account{
"gateway"};
4707 auto const alice =
Account{
"alice"};
4708 auto const XTS = gw[
"XTS"];
4709 auto const XXX = gw[
"XXX"];
4711 env.fund(
XRP(10000), gw, alice);
4716 auto txn =
noop(gw);
4717 txn[sfTickSize.fieldName] = 5;
4719 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4722 env(
trust(alice, XTS(1000)));
4723 env(
trust(alice, XXX(1000)));
4725 env(
pay(gw, alice, alice[
"XTS"](100)));
4726 env(
pay(gw, alice, alice[
"XXX"](100)));
4728 env(
offer(alice, XTS(10), XXX(30)));
4729 env(
offer(alice, XTS(30), XXX(10)));
4736 if (sle->getType() == ltOFFER)
4740 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4744 auto it =
offers.begin();
4745 BEAST_EXPECT(it !=
offers.end());
4747 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4748 it->second.second > XXX(29.9994));
4752 BEAST_EXPECT(it !=
offers.end());
4754 it->second.first == XTS(30) && it->second.second == XXX(10));
4758 BEAST_EXPECT(it !=
offers.end());
4760 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4765 BEAST_EXPECT(it !=
offers.end());
4767 it->second.first == XTS(30) && it->second.second == XXX(10));
4769 BEAST_EXPECT(++it ==
offers.end());
4783 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4793 using namespace jtx;
4801 Env env{*
this, features};
4802 auto const gw =
Account{
"gateway"};
4803 auto const alice =
Account{
"alice"};
4804 auto const bob =
Account{
"bob"};
4805 auto const USD = gw[
"USD"];
4807 env.fund(
XRP(10000), gw, alice, bob);
4810 env(
trust(alice, USD(1000)));
4811 env(
trust(bob, USD(1000)));
4814 env(
pay(gw, alice, USD(200)));
4821 env(
offer(alice,
XRP(50), USD(50)));
4831 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4832 env(
offer(alice,
XRP(50), USD(50)));
4848 BEAST_EXPECT(
offers.size() == 4);
4849 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4850 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4851 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4852 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4853 env.require(
balance(alice, USD(200)));
4854 env.require(
owners(alice, 5));
4864 BEAST_EXPECT(
offers.size() == 3);
4865 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4866 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4867 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4877 BEAST_EXPECT(
offers.size() == 2);
4878 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4879 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4889 BEAST_EXPECT(
offers.size() == 1);
4890 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4900 BEAST_EXPECT(
offers.size() == 0);
4902 env.require(
balance(alice, USD(0)));
4903 env.require(
owners(alice, 1));
4904 env.require(
balance(bob, USD(200)));
4905 env.require(
owners(bob, 1));
4913 using namespace jtx;
4917 Env env{*
this, features};
4918 auto const gw =
Account{
"gateway"};
4919 auto const alice =
Account{
"alice"};
4920 auto const USD = gw[
"USD"];
4922 env.fund(
XRP(10000), gw, alice);
4925 env(
trust(alice, USD(1000)));
4929 env(
pay(gw, alice, USD(200)));
4934 env(
offer(alice,
XRP(50), USD(50)));
4946 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
4947 env(
offer(alice,
XRP(50), USD(50)));
4963 BEAST_EXPECT(
offers.size() == 4);
4964 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
4965 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
4966 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
4967 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
4968 env.require(
balance(alice, USD(200)));
4969 env.require(
owners(alice, 7));
4979 BEAST_EXPECT(
offers.size() == 3);
4980 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
4981 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
4982 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
4992 BEAST_EXPECT(
offers.size() == 2);
4993 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
4994 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5007 BEAST_EXPECT(
offers.size() == 1);
5008 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5025 testcase(
"incorrect assert fixed");
5026 using namespace jtx;
5029 auto const alice =
Account(
"alice");
5030 auto const USD = alice[
"USD"];
5032 env.fund(
XRP(10000), alice);
5034 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5042 using namespace jtx;
5043 Env env(*
this, features);
5044 Account const issuer(
"issuer");
5047 auto const USD = issuer[
"USD"];
5048 auto const EUR = issuer[
"EUR"];
5051 env.
fund(
XRP(1'000), maker, taker);
5054 env.
trust(USD(1'000), maker, taker);
5055 env.
trust(EUR(1'000), maker, taker);
5058 env(
pay(issuer, maker, USD(1'000)));
5059 env(
pay(issuer, taker, USD(1'000)));
5060 env(
pay(issuer, maker, EUR(1'000)));
5063 auto makerUSDBalance = env.
balance(maker, USD).
value();
5064 auto takerUSDBalance = env.
balance(taker, USD).
value();
5065 auto makerEURBalance = env.
balance(maker, EUR).
value();
5066 auto takerEURBalance = env.
balance(taker, EUR).
value();
5075 env(
offer(maker,
XRP(100), USD(100)));
5078 env(
offer(taker, USD(100),
XRP(101)),
5083 makerXRPBalance -=
txfee(env, 1);
5084 takerXRPBalance -=
txfee(env, 1);
5087 makerUSDBalance -= USD(100);
5088 takerUSDBalance += USD(100);
5089 makerXRPBalance +=
XRP(100).value();
5090 takerXRPBalance -=
XRP(100).value();
5094 env(
offer(maker, USD(100),
XRP(100)));
5097 env(
offer(taker,
XRP(100), USD(101)),
5102 makerXRPBalance -=
txfee(env, 1);
5103 takerXRPBalance -=
txfee(env, 1);
5106 makerUSDBalance += USD(100);
5107 takerUSDBalance -= USD(100);
5108 makerXRPBalance -=
XRP(100).value();
5109 takerXRPBalance +=
XRP(100).value();
5113 env(
offer(maker, USD(100), EUR(100)));
5116 env(
offer(taker, EUR(100), USD(101)),
5121 makerXRPBalance -=
txfee(env, 1);
5122 takerXRPBalance -=
txfee(env, 1);
5125 makerUSDBalance += USD(100);
5126 takerUSDBalance -= USD(100);
5127 makerEURBalance -= EUR(100);
5128 takerEURBalance += EUR(100);
5135 env(
offer(maker,
XRP(101), USD(101)));
5138 env(
offer(taker, USD(100),
XRP(101)),
5142 makerUSDBalance -= USD(101);
5143 takerUSDBalance += USD(101);
5144 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5145 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5148 env(
offer(maker, USD(101),
XRP(101)));
5151 env(
offer(taker,
XRP(100), USD(101)),
5155 makerUSDBalance += USD(101);
5156 takerUSDBalance -= USD(101);
5157 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5158 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5161 env(
offer(maker, USD(101), EUR(101)));
5164 env(
offer(taker, EUR(100), USD(101)),
5168 makerUSDBalance += USD(101);
5169 takerUSDBalance -= USD(101);
5170 makerEURBalance -= EUR(101);
5171 takerEURBalance += EUR(101);
5172 makerXRPBalance -=
txfee(env, 1);
5173 takerXRPBalance -=
txfee(env, 1);
5180 env(
offer(maker,
XRP(100), USD(100)));
5183 env(
offer(taker, USD(100),
XRP(99)),
5188 makerXRPBalance -=
txfee(env, 1);
5189 takerXRPBalance -=
txfee(env, 1);
5192 env(
offer(maker, USD(100),
XRP(100)));
5195 env(
offer(taker,
XRP(100), USD(99)),
5200 makerXRPBalance -=
txfee(env, 1);
5201 takerXRPBalance -=
txfee(env, 1);
5204 env(
offer(maker, USD(100), EUR(100)));
5207 env(
offer(taker, EUR(100), USD(99)),
5212 makerXRPBalance -=
txfee(env, 1);
5213 takerXRPBalance -=
txfee(env, 1);
5218 env.
balance(maker, USD) == makerUSDBalance &&
5219 env.
balance(taker, USD) == takerUSDBalance &&
5220 env.
balance(maker, EUR) == makerEURBalance &&
5221 env.
balance(taker, EUR) == takerEURBalance &&
5222 env.
balance(maker,
XRP) == makerXRPBalance &&
5323 using namespace jtx;
5334BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, app,
ripple, 2);
5335BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, app,
ripple, 2);
5336BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, app,
ripple, 2);
5337BEAST_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 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)
FeatureBitset const allFeatures
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.
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