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);
99 env.trust(USD(1000), alice, bob, carol);
100 env.trust(BTC(1000), alice, bob, carol);
102 env(
pay(gw, alice, BTC(1000)));
104 env(
pay(gw, carol, USD(1000)));
105 env(
pay(gw, carol, BTC(1000)));
110 env(
offer(carol, BTC(49),
XRP(49)));
111 env(
offer(carol, BTC(51),
XRP(51)));
115 env(
offer(carol,
XRP(50), USD(50)));
116 env(
offer(carol,
XRP(50), USD(50)));
119 env(
offer(carol, BTC(1), USD(100)));
123 env(
pay(alice, bob, USD(100)),
128 env.require(
balance(bob, USD(100)));
130 !
isOffer(env, carol, BTC(1), USD(100)) &&
137 testcase(
"Removing Canceled Offers");
140 Env env{*
this, features};
142 auto const gw =
Account{
"gateway"};
143 auto const alice =
Account{
"alice"};
144 auto const USD = gw[
"USD"];
146 env.fund(
XRP(10000), alice, gw);
148 env.trust(USD(100), alice);
151 env(
pay(gw, alice, USD(50)));
154 auto const offer1Seq = env.seq(alice);
159 BEAST_EXPECT(
isOffer(env, alice,
XRP(500), USD(100)));
162 auto const offer2Seq = env.seq(alice);
164 env(
offer(alice,
XRP(300), USD(100)),
165 json(jss::OfferSequence, offer1Seq),
176 env(
offer(alice,
XRP(400), USD(200)),
177 json(jss::OfferSequence, offer1Seq),
186 auto const offer4Seq = env.seq(alice);
190 BEAST_EXPECT(
isOffer(env, alice,
XRP(222), USD(111)));
193 BEAST_EXPECT(env.seq(alice) == offer4Seq + 2);
195 BEAST_EXPECT(!
isOffer(env, alice,
XRP(222), USD(111)));
199 env.require(
offers(alice, 2));
203 bool const featPreauth{features[featureDepositPreauth]};
206 json(jss::OfferSequence, offer2Seq),
210 env.require(
offers(alice, 2));
211 BEAST_EXPECT(
isOffer(env, alice,
XRP(300), USD(100)));
212 BEAST_EXPECT(!
isOffer(env, alice,
XRP(5), USD(2)));
222 using namespace std::chrono_literals;
223 auto const alice =
Account{
"alice"};
224 auto const bob =
Account{
"bob"};
225 auto const carol =
Account{
"carol"};
228 auto const USD = gw[
"USD"];
229 auto const EUR = gw[
"EUR"];
231 Env env{*
this, features};
233 env.fund(
XRP(10000), alice, bob, carol, gw);
234 env.trust(USD(1000), alice, bob, carol);
235 env.trust(EUR(1000), alice, bob, carol);
236 env(
pay(gw, alice, USD(100)));
237 env(
pay(gw, carol, EUR(100)));
243 for (
int i = 0; i < 101; ++i)
244 env(
offer(carol, USD(1), EUR(2)));
270 using namespace std::chrono_literals;
271 auto const alice =
Account{
"alice"};
272 auto const bob =
Account{
"bob"};
273 auto const carol =
Account{
"carol"};
274 auto const dan =
Account{
"dan"};
275 auto const erin =
Account{
"erin"};
278 auto const USD = gw[
"USD"];
279 Env env{*
this, features};
281 env.fund(
XRP(10000), alice, bob, carol, dan, erin, gw);
283 env.trust(USD(1000), alice, bob, carol, dan, erin);
285 env(
pay(gw, carol, USD(0.99999)));
286 env(
pay(gw, dan, USD(1)));
287 env(
pay(gw, erin, USD(1)));
309 env(
pay(alice, bob, USD(1)),
324 testcase(
"Rm small increased q offers XRP");
332 using namespace std::chrono_literals;
333 auto const alice =
Account{
"alice"};
334 auto const bob =
Account{
"bob"};
335 auto const carol =
Account{
"carol"};
338 auto const USD = gw[
"USD"];
341 for (
auto crossBothOffers : {
false,
true})
343 Env env{*
this, features};
345 env.fund(
XRP(10000), alice, bob, carol, gw);
347 env.trust(USD(1000), alice, bob, carol);
349 auto initialCarolUSD = USD(0.499);
350 env(
pay(gw, carol, initialCarolUSD));
351 env(
pay(gw, bob, USD(100)));
363 auto aliceTakerGets = crossBothOffers ?
drops(2) :
drops(1);
364 env(
offer(alice, USD(1), aliceTakerGets));
367 if (features[fixRmSmallIncreasedQOffers])
402 for (
auto partialPayment : {
false,
true})
404 Env env{*
this, features};
406 env.fund(
XRP(10000), alice, bob, carol, gw);
408 env.trust(USD(1000), alice, bob, carol);
410 auto const initialCarolUSD = USD(0.999);
411 env(
pay(gw, carol, initialCarolUSD));
413 env(
pay(gw, bob, USD(100)));
425 TER const expectedTer =
428 env(
pay(alice, bob, USD(5)),
435 if (features[fixRmSmallIncreasedQOffers])
439 env.require(
offers(carol, 0));
456 env.require(
offers(carol, 0));
472 testcase(
"Rm small increased q offers IOU");
480 using namespace std::chrono_literals;
481 auto const alice =
Account{
"alice"};
482 auto const bob =
Account{
"bob"};
483 auto const carol =
Account{
"carol"};
486 auto const USD = gw[
"USD"];
487 auto const EUR = gw[
"EUR"];
498 for (
auto crossBothOffers : {
false,
true})
500 Env env{*
this, features};
502 env.fund(
XRP(10000), alice, bob, carol, gw);
504 env.trust(USD(1000), alice, bob, carol);
505 env.trust(EUR(1000), alice, bob, carol);
507 auto initialCarolUSD = tinyAmount(USD);
508 env(
pay(gw, carol, initialCarolUSD));
509 env(
pay(gw, bob, USD(100)));
510 env(
pay(gw, alice, EUR(100)));
513 env(
offer(carol, EUR(1), USD(10)));
523 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
524 env(
offer(alice, USD(1), aliceTakerGets));
527 if (features[fixRmSmallIncreasedQOffers])
562 for (
auto partialPayment : {
false,
true})
564 Env env{*
this, features};
566 env.fund(
XRP(10000), alice, bob, carol, gw);
568 env.trust(USD(1000), alice, bob, carol);
569 env.trust(EUR(1000), alice, bob, carol);
572 auto const initialCarolUSD = tinyAmount(USD);
573 env(
pay(gw, carol, initialCarolUSD));
574 env(
pay(gw, bob, USD(100)));
575 env(
pay(gw, alice, EUR(100)));
578 env(
offer(carol, EUR(1), USD(2)));
588 TER const expectedTer =
591 env(
pay(alice, bob, USD(5)),
598 if (features[fixRmSmallIncreasedQOffers])
602 env.require(
offers(carol, 0));
619 env.require(
offers(carol, 0));
626 BEAST_EXPECT(
isOffer(env, carol, EUR(1), USD(2)));
639 auto const gw =
Account{
"gateway"};
640 auto const USD = gw[
"USD"];
641 auto const BTC = gw[
"BTC"];
642 auto const EUR = gw[
"EUR"];
650 Env env{*
this, features};
652 auto const gw1 =
Account{
"gw1"};
653 auto const USD1 = gw1[
"USD"];
654 auto const gw2 =
Account{
"gw2"};
655 auto const USD2 = gw2[
"USD"];
657 env.fund(
XRP(10000), alice,
noripple(bob), carol, dan, gw1, gw2);
658 env.trust(USD1(1000), alice, carol, dan);
660 env.trust(USD2(1000), alice, carol, dan);
663 env(
pay(gw1, dan, USD1(50)));
664 env(
pay(gw1, bob, USD1(50)));
665 env(
pay(gw2, bob, USD2(50)));
669 env(
pay(alice, carol, USD2(50)),
677 Env env{*
this, features};
679 auto const gw1 =
Account{
"gw1"};
680 auto const USD1 = gw1[
"USD"];
681 auto const gw2 =
Account{
"gw2"};
682 auto const USD2 = gw2[
"USD"];
684 env.fund(
XRP(10000), alice, bob, carol, dan, gw1, gw2);
685 env.trust(USD1(1000), alice, bob, carol, dan);
686 env.trust(USD2(1000), alice, bob, carol, dan);
688 env(
pay(gw1, dan, USD1(50)));
689 env(
pay(gw1, bob, USD1(50)));
690 env(
pay(gw2, bob, USD2(50)));
694 env(
pay(alice, carol, USD2(50)),
700 env.require(
balance(bob, USD1(100)));
701 env.require(
balance(bob, USD2(0)));
702 env.require(
balance(carol, USD2(50)));
719 auto const gw =
Account{
"gateway"};
720 auto const alice =
Account{
"alice"};
721 auto const bob =
Account{
"bob"};
722 auto const carol =
Account{
"carol"};
723 auto const USD = gw[
"USD"];
725 auto const usdOffer = USD(1000);
726 auto const xrpOffer =
XRP(1000);
730 Env env{*
this, features};
732 env.fund(
XRP(1000000), gw);
734 auto const f = env.current()->fees().base;
735 auto const r =
reserve(env, 0);
737 env.fund(r + f, alice);
748 Env env{*
this, features};
750 env.fund(
XRP(1000000), gw);
752 auto const f = env.current()->fees().base;
753 auto const r =
reserve(env, 0);
755 auto const usdOffer2 = USD(500);
756 auto const xrpOffer2 =
XRP(500);
758 env.fund(r + f + xrpOffer, bob);
760 env.fund(r + f, alice);
766 balance(alice, r - f + xrpOffer2),
778 Env env{*
this, features};
780 env.fund(
XRP(1000000), gw);
782 auto const f = env.current()->fees().base;
783 auto const r =
reserve(env, 0);
785 auto const usdOffer2 = USD(500);
786 auto const xrpOffer2 =
XRP(500);
788 env.fund(r + f + xrpOffer, bob, carol);
792 env.fund(r + f, alice);
798 balance(alice, r - f + xrpOffer),
819 if (sle->getType() == ltOFFER)
820 result.push_back(sle);
832 auto const startBalance =
XRP(1000000);
833 auto const gw =
Account{
"gateway"};
834 auto const alice =
Account{
"alice"};
835 auto const bob =
Account{
"bob"};
836 auto const USD = gw[
"USD"];
844 for (
auto const& tweakedFeatures :
845 {features - fix1578, features | fix1578})
847 Env env{*
this, tweakedFeatures};
849 auto const f = env.
current()->fees().base;
851 env.fund(startBalance, gw, alice, bob);
872 TER const killedCode{
875 env(
offer(alice,
XRP(1000), USD(1000)),
880 balance(alice, startBalance - (f * 2)),
884 balance(bob, startBalance - (f * 2)),
890 env(
offer(alice,
XRP(500), USD(500)),
895 balance(alice, startBalance - (f * 3) +
XRP(500)),
899 balance(bob, startBalance - (f * 2) -
XRP(500)),
908 Env env{*
this, features};
910 auto const f = env.current()->fees().base;
912 env.fund(startBalance, gw, alice, bob);
919 TER const expectedCode = features[featureImmediateOfferKilled]
922 env(
offer(alice,
XRP(1000), USD(1000)),
928 balance(alice, startBalance - f - f),
935 env(
offer(alice,
XRP(1000), USD(1000)),
940 balance(alice, startBalance - f - f - f +
XRP(50)),
956 balance(alice, startBalance - f - f - f - f +
XRP(100)),
960 balance(bob, startBalance - f - f -
XRP(100)),
968 Env env(*
this, features);
970 env.
fund(startBalance, gw, alice, bob);
973 env(
trust(bob, USD(1000)));
976 env(
pay(gw, bob, USD(1000)));
979 env(
offer(alice, USD(1000),
XRP(2000)));
983 BEAST_EXPECT(aliceOffers.size() == 1);
984 for (
auto offerPtr : aliceOffers)
986 auto const&
offer = *offerPtr;
987 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
988 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
998 BEAST_EXPECT(bobOffers.size() == 1);
999 for (
auto offerPtr : bobOffers)
1001 auto const&
offer = *offerPtr;
1002 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
1003 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
1007 env(
offer(gw,
XRP(2000), USD(1000)));
1013 env(
offer(gw, USD(1000),
XRP(2000)));
1021 Env env(*
this, features);
1023 env.
fund(startBalance, gw,
"alice",
"bob");
1026 env(
trust(
"bob", USD(1000)));
1029 env(
pay(gw,
"bob", USD(1000)));
1030 env(
offer(
"alice", USD(500),
XRP(1001)));
1033 env(
offer(
"alice", USD(500),
XRP(1000)));
1037 BEAST_EXPECT(aliceOffers.size() == 2);
1047 BEAST_EXPECT(bobOffers.size() == 1);
1048 for (
auto offerPtr : bobOffers)
1050 auto const&
offer = *offerPtr;
1051 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
1052 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
1062 using namespace jtx;
1064 auto const startBalance =
XRP(1000000);
1065 auto const gw =
Account{
"gateway"};
1066 auto const alice =
Account{
"alice"};
1067 auto const USD = gw[
"USD"];
1069 Env env{*
this, features};
1071 env.fund(startBalance, gw, alice);
1074 env(
offer(alice, USD(1000),
XRP(1000)),
1081 env(
offer(alice, USD(1000),
XRP(1000)),
1111 env(
offer(alice, USD(1000),
XRP(1000)),
1119 env(
offer(alice, USD(1000),
XRP(1000)),
1139 using namespace jtx;
1141 auto const gw =
Account{
"gateway"};
1142 auto const alice =
Account{
"alice"};
1143 auto const bob =
Account{
"bob"};
1144 auto const USD = gw[
"USD"];
1146 auto const startBalance =
XRP(1000000);
1147 auto const usdOffer = USD(1000);
1148 auto const xrpOffer =
XRP(1000);
1150 Env env{*
this, features};
1152 env.fund(startBalance, gw, alice, bob);
1155 auto const f = env.current()->fees().base;
1161 balance(alice, startBalance - f),
1168 bool const featPreauth{features[featureDepositPreauth]};
1170 env(
offer(alice, xrpOffer, usdOffer),
1175 balance(alice, startBalance - f - f),
1182 env(
offer(alice, xrpOffer, usdOffer),
1186 balance(alice, startBalance - f - f - f),
1194 balance(alice, startBalance - f - f - f),
1202 balance(alice, startBalance - f - f - f),
1206 balance(bob, startBalance - f),
1217 using namespace jtx;
1219 auto const gw =
Account{
"gateway"};
1220 auto const USD = gw[
"USD"];
1222 auto const usdOffer = USD(1000);
1223 auto const xrpOffer =
XRP(1000);
1225 Env env{*
this, features};
1227 env.fund(
XRP(1000000), gw);
1230 auto const f = env.current()->fees().base;
1234 env.fund(
reserve(env, 0),
"alice");
1240 env.fund(
reserve(env, 0) + f,
"bob");
1247 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1254 env.fund(
reserve(env, 1) + f,
"dan");
1260 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1271 (use_partner ?
", with partner account" :
""));
1273 using namespace jtx;
1275 auto const gw =
Account{
"gateway"};
1276 auto const partner =
Account{
"partner"};
1277 auto const USD = gw[
"USD"];
1278 auto const BTC = gw[
"BTC"];
1280 Env env{*
this, features};
1283 env.fund(
XRP(10000), gw);
1286 env.fund(
XRP(10000), partner);
1287 env(
trust(partner, USD(100)));
1288 env(
trust(partner, BTC(500)));
1289 env(
pay(gw, partner, USD(100)));
1290 env(
pay(gw, partner, BTC(500)));
1292 auto const& account_to_test = use_partner ? partner : gw;
1295 env.require(
offers(account_to_test, 0));
1300 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1301 env.require(
offers(account_to_test, 1));
1304 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1306 auto const secondLegSeq = env.seq(account_to_test);
1307 env(
offer(account_to_test,
XRP(1000), USD(50)));
1308 env.require(
offers(account_to_test, 2));
1311 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1315 env(
offer(account_to_test, USD(50), BTC(250)));
1318 BEAST_EXPECT(jrr[jss::offers].isArray());
1319 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1322 BEAST_EXPECT(jrr[jss::offers].isArray());
1323 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1334 bool const noStaleOffers{
1335 features[featureFlowCross] ||
1336 features[fixTakerDryOfferRemoval]};
1338 BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
1339 for (
auto const& offerPtr : acctOffers)
1341 auto const&
offer = *offerPtr;
1342 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1343 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1344 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1352 env.require(
offers(account_to_test, 0));
1357 env(
offer(account_to_test, BTC(250), USD(50)));
1358 env.require(
offers(account_to_test, 1));
1362 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1365 BEAST_EXPECT(jrr[jss::offers].isArray());
1366 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1370 env(
offer(account_to_test, USD(50), BTC(250)));
1371 env.require(
offers(account_to_test, 1));
1376 BEAST_EXPECT(jrr[jss::offers].isArray());
1377 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1379 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1389 using namespace jtx;
1394 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1396 Env env{*
this, localFeatures};
1398 auto const gw =
Account{
"gateway"};
1399 auto const alice =
Account{
"alice"};
1400 auto const bob =
Account{
"bob"};
1401 auto const USD = gw[
"USD"];
1402 auto const BTC = gw[
"BTC"];
1406 auto const gw_initial_balance =
drops(1149999730);
1407 auto const alice_initial_balance =
drops(499946999680);
1408 auto const bob_initial_balance =
drops(10199999920);
1409 auto const small_amount =
1410 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1412 env.fund(gw_initial_balance, gw);
1413 env.fund(alice_initial_balance, alice);
1414 env.fund(bob_initial_balance, bob);
1416 env(
rate(gw, 1.005));
1418 env(
trust(alice, USD(500)));
1419 env(
trust(bob, USD(50)));
1420 env(
trust(gw, alice[
"USD"](100)));
1422 env(
pay(gw, alice, alice[
"USD"](50)));
1423 env(
pay(gw, bob, small_amount));
1425 env(
offer(alice, USD(50),
XRP(150000)));
1428 env(
pay(alice, gw, USD(100)));
1431 env(
trust(gw, alice[
"USD"](0)));
1436 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1440 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1441 "-2710505431213761e-33");
1445 env(
offer(bob,
XRP(2000), USD(1)));
1447 if (localFeatures[featureFlowCross] &&
1448 localFeatures[fixReducedOffersV2])
1455 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1456 "-2710505431213761e-33");
1460 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1461 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1472 auto const crossingDelta =
1473 localFeatures[featureFlowCross] ?
drops(1) :
drops(0);
1477 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1480 alice_initial_balance - env.current()->fees().base * 3 -
1485 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1488 bob_initial_balance - env.current()->fees().base * 2 +
1498 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1500 using namespace jtx;
1502 Env env{*
this, features};
1504 auto const gw =
Account{
"gateway"};
1505 auto const alice =
Account{
"alice"};
1506 auto const bob =
Account{
"bob"};
1507 auto const USD = gw[
"USD"];
1509 env.fund(
XRP(10000), gw, alice, bob);
1511 env(
trust(alice, USD(1000)));
1512 env(
trust(bob, USD(1000)));
1514 env(
pay(gw, alice, alice[
"USD"](500)));
1517 env(
offer(bob, USD(1),
XRP(4000)));
1519 env(
offer(alice,
XRP(150000), USD(50)));
1522 env(
offer(bob, USD(1),
XRP(4000)));
1529 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1532 jrr[jss::node][sfBalance.fieldName] ==
1534 env.current()->fees().base * 2)
1538 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1541 jrr[jss::node][sfBalance.fieldName] ==
1543 env.current()->fees().base * 2)
1550 testcase(
"Offer Crossing with Limit Override");
1552 using namespace jtx;
1554 Env env{*
this, features};
1556 auto const gw =
Account{
"gateway"};
1557 auto const alice =
Account{
"alice"};
1558 auto const bob =
Account{
"bob"};
1559 auto const USD = gw[
"USD"];
1561 env.fund(
XRP(100000), gw, alice, bob);
1563 env(
trust(alice, USD(1000)));
1565 env(
pay(gw, alice, alice[
"USD"](500)));
1567 env(
offer(alice,
XRP(150000), USD(50)));
1568 env(
offer(bob, USD(1),
XRP(3000)));
1571 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1574 jrr[jss::node][sfBalance.fieldName] ==
1579 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1582 jrr[jss::node][sfBalance.fieldName] ==
1590 testcase(
"Offer Accept then Cancel.");
1592 using namespace jtx;
1594 Env env{*
this, features};
1596 auto const USD = env.master[
"USD"];
1598 auto const nextOfferSeq = env.seq(env.master);
1599 env(
offer(env.master,
XRP(500), USD(100)));
1603 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1608 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1614 testcase(
"Offer Cancel Past and Future Sequence.");
1616 using namespace jtx;
1618 Env env{*
this, features};
1620 auto const alice =
Account{
"alice"};
1622 auto const nextOfferSeq = env.seq(env.master);
1623 env.fund(
XRP(10000), alice);
1639 testcase(
"Currency Conversion: Entire Offer");
1641 using namespace jtx;
1643 Env env{*
this, features};
1645 auto const gw =
Account{
"gateway"};
1646 auto const alice =
Account{
"alice"};
1647 auto const bob =
Account{
"bob"};
1648 auto const USD = gw[
"USD"];
1650 env.fund(
XRP(10000), gw, alice, bob);
1651 env.require(
owners(bob, 0));
1653 env(
trust(alice, USD(100)));
1654 env(
trust(bob, USD(1000)));
1658 env(
pay(gw, alice, alice[
"USD"](100)));
1659 auto const bobOfferSeq = env.seq(bob);
1660 env(
offer(bob, USD(100),
XRP(500)));
1665 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1667 jro[jss::node][jss::TakerPays] ==
1673 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1676 jrr[jss::node][sfBalance.fieldName] ==
1681 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1684 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1692 testcase(
"Currency Conversion: Offerer Into Debt");
1694 using namespace jtx;
1696 Env env{*
this, features};
1698 auto const alice =
Account{
"alice"};
1699 auto const bob =
Account{
"bob"};
1700 auto const carol =
Account{
"carol"};
1702 env.fund(
XRP(10000), alice, bob, carol);
1704 env(
trust(alice, carol[
"EUR"](2000)));
1705 env(
trust(bob, alice[
"USD"](100)));
1706 env(
trust(carol, bob[
"EUR"](1000)));
1708 auto const bobOfferSeq = env.seq(bob);
1709 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1712 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1715 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1721 testcase(
"Currency Conversion: In Parts");
1723 using namespace jtx;
1725 Env env{*
this, features};
1727 auto const gw =
Account{
"gateway"};
1728 auto const alice =
Account{
"alice"};
1729 auto const bob =
Account{
"bob"};
1730 auto const USD = gw[
"USD"];
1732 env.fund(
XRP(10000), gw, alice, bob);
1734 env(
trust(alice, USD(200)));
1735 env(
trust(bob, USD(1000)));
1737 env(
pay(gw, alice, alice[
"USD"](200)));
1739 auto const bobOfferSeq = env.seq(bob);
1740 env(
offer(bob, USD(100),
XRP(500)));
1747 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1749 jro[jss::node][jss::TakerPays] ==
1755 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1759 jrr[jss::node][sfBalance.fieldName] ==
1765 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1769 env(
pay(alice, alice,
XRP(600)),
1775 env(
pay(alice, alice,
XRP(600)),
1781 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1789 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1792 jrr[jss::node][sfBalance.fieldName] ==
1794 env.current()->fees().base * 4)
1800 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1806 testcase(
"Cross Currency Payment: Start with XRP");
1808 using namespace jtx;
1810 Env env{*
this, features};
1812 auto const gw =
Account{
"gateway"};
1813 auto const alice =
Account{
"alice"};
1814 auto const bob =
Account{
"bob"};
1815 auto const carol =
Account{
"carol"};
1816 auto const USD = gw[
"USD"];
1818 env.fund(
XRP(10000), gw, alice, bob, carol);
1820 env(
trust(carol, USD(1000)));
1821 env(
trust(bob, USD(2000)));
1823 env(
pay(gw, carol, carol[
"USD"](500)));
1825 auto const carolOfferSeq = env.seq(carol);
1826 env(
offer(carol,
XRP(500), USD(50)));
1831 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1834 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1838 jro[jss::node][jss::TakerGets] ==
1841 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1847 testcase(
"Cross Currency Payment: End with XRP");
1849 using namespace jtx;
1851 Env env{*
this, features};
1853 auto const gw =
Account{
"gateway"};
1854 auto const alice =
Account{
"alice"};
1855 auto const bob =
Account{
"bob"};
1856 auto const carol =
Account{
"carol"};
1857 auto const USD = gw[
"USD"];
1859 env.fund(
XRP(10000), gw, alice, bob, carol);
1861 env(
trust(alice, USD(1000)));
1862 env(
trust(carol, USD(2000)));
1864 env(
pay(gw, alice, alice[
"USD"](500)));
1866 auto const carolOfferSeq = env.seq(carol);
1867 env(
offer(carol, USD(50),
XRP(500)));
1872 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1875 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1879 jrr[jss::node][sfBalance.fieldName] ==
1881 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1885 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1887 jro[jss::node][jss::TakerPays] ==
1894 testcase(
"Cross Currency Payment: Bridged");
1896 using namespace jtx;
1898 Env env{*
this, features};
1900 auto const gw1 =
Account{
"gateway_1"};
1901 auto const gw2 =
Account{
"gateway_2"};
1902 auto const alice =
Account{
"alice"};
1903 auto const bob =
Account{
"bob"};
1904 auto const carol =
Account{
"carol"};
1905 auto const dan =
Account{
"dan"};
1906 auto const USD = gw1[
"USD"];
1907 auto const EUR = gw2[
"EUR"];
1909 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1911 env(
trust(alice, USD(1000)));
1912 env(
trust(bob, EUR(1000)));
1913 env(
trust(carol, USD(1000)));
1914 env(
trust(dan, EUR(1000)));
1916 env(
pay(gw1, alice, alice[
"USD"](500)));
1917 env(
pay(gw2, dan, dan[
"EUR"](400)));
1919 auto const carolOfferSeq = env.seq(carol);
1920 env(
offer(carol, USD(50),
XRP(500)));
1922 auto const danOfferSeq = env.seq(dan);
1923 env(
offer(dan,
XRP(500), EUR(50)));
1926 jtp[0u][0u][jss::currency] =
"XRP";
1927 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1930 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1933 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1936 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1939 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1943 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1945 jro[jss::node][jss::TakerPays] ==
1950 jro[jss::node][jss::TakerGets] ==
1953 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1962 testcase(
"Auto Bridged Second Leg Dry");
1964 using namespace jtx;
1965 Env env(*
this, features);
1971 auto const USD = gw[
"USD"];
1972 auto const EUR = gw[
"EUR"];
1974 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1976 env.
trust(USD(10), alice);
1978 env(
pay(gw, alice, USD(10)));
1979 env.
trust(USD(10), carol);
1981 env(
pay(gw, carol, USD(3)));
1998 env.
trust(EUR(10), bob);
2000 env(
pay(gw, bob, EUR(10)));
2002 env(
offer(bob, USD(10), EUR(10)));
2019 int const emptyOfferCount{
2020 features[featureFlowCross] || features[fixTakerDryOfferRemoval]
2031 testcase(
"Offer Fees Consume Funds");
2033 using namespace jtx;
2035 Env env{*
this, features};
2037 auto const gw1 =
Account{
"gateway_1"};
2038 auto const gw2 =
Account{
"gateway_2"};
2039 auto const gw3 =
Account{
"gateway_3"};
2040 auto const alice =
Account{
"alice"};
2041 auto const bob =
Account{
"bob"};
2042 auto const USD1 = gw1[
"USD"];
2043 auto const USD2 = gw2[
"USD"];
2044 auto const USD3 = gw3[
"USD"];
2052 auto const starting_xrp =
XRP(100) +
2053 env.current()->fees().accountReserve(3) +
2054 env.current()->fees().base * 4;
2056 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2058 env(
trust(alice, USD1(1000)));
2059 env(
trust(alice, USD2(1000)));
2060 env(
trust(alice, USD3(1000)));
2061 env(
trust(bob, USD1(1000)));
2062 env(
trust(bob, USD2(1000)));
2064 env(
pay(gw1, bob, bob[
"USD"](500)));
2066 env(
offer(bob,
XRP(200), USD1(200)));
2069 env(
offer(alice, USD1(200),
XRP(200)));
2072 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2075 jrr[jss::node][sfBalance.fieldName] ==
2079 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2085 testcase(
"Offer Create, then Cross");
2087 using namespace jtx;
2089 for (
auto NumberSwitchOver : {
false,
true})
2091 Env env{*
this, features};
2092 if (NumberSwitchOver)
2093 env.enableFeature(fixUniversalNumber);
2095 env.disableFeature(fixUniversalNumber);
2097 auto const gw =
Account{
"gateway"};
2098 auto const alice =
Account{
"alice"};
2099 auto const bob =
Account{
"bob"};
2100 auto const USD = gw[
"USD"];
2102 env.fund(
XRP(10000), gw, alice, bob);
2104 env(
rate(gw, 1.005));
2106 env(
trust(alice, USD(1000)));
2107 env(
trust(bob, USD(1000)));
2108 env(
trust(gw, alice[
"USD"](50)));
2110 env(
pay(gw, bob, bob[
"USD"](1)));
2111 env(
pay(alice, gw, USD(50)));
2113 env(
trust(gw, alice[
"USD"](0)));
2115 env(
offer(alice, USD(50),
XRP(150000)));
2116 env(
offer(bob,
XRP(100), USD(0.1)));
2120 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2121 "49.96666666666667");
2125 jrr[jss::node][sfBalance.fieldName][jss::value];
2126 if (!NumberSwitchOver)
2128 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2132 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2140 testcase(
"Offer tfSell: Basic Sell");
2142 using namespace jtx;
2144 Env env{*
this, features};
2146 auto const gw =
Account{
"gateway"};
2147 auto const alice =
Account{
"alice"};
2148 auto const bob =
Account{
"bob"};
2149 auto const USD = gw[
"USD"];
2151 auto const starting_xrp =
XRP(100) +
2152 env.current()->fees().accountReserve(1) +
2153 env.current()->fees().base * 2;
2155 env.fund(starting_xrp, gw, alice, bob);
2157 env(
trust(alice, USD(1000)));
2158 env(
trust(bob, USD(1000)));
2160 env(
pay(gw, bob, bob[
"USD"](500)));
2169 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2172 jrr[jss::node][sfBalance.fieldName] ==
2176 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2182 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2184 using namespace jtx;
2186 Env env{*
this, features};
2188 auto const gw =
Account{
"gateway"};
2189 auto const alice =
Account{
"alice"};
2190 auto const bob =
Account{
"bob"};
2191 auto const USD = gw[
"USD"];
2193 auto const starting_xrp =
XRP(100) +
2194 env.current()->fees().accountReserve(1) +
2195 env.current()->fees().base * 2;
2197 env.fund(starting_xrp, gw, alice, bob);
2199 env(
trust(alice, USD(150)));
2200 env(
trust(bob, USD(1000)));
2202 env(
pay(gw, bob, bob[
"USD"](500)));
2204 env(
offer(bob,
XRP(100), USD(200)));
2213 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2216 jrr[jss::node][sfBalance.fieldName] ==
2220 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2226 testcase(
"Client Issue #535: Gateway Cross Currency");
2228 using namespace jtx;
2230 Env env{*
this, features};
2232 auto const gw =
Account{
"gateway"};
2233 auto const alice =
Account{
"alice"};
2234 auto const bob =
Account{
"bob"};
2235 auto const XTS = gw[
"XTS"];
2236 auto const XXX = gw[
"XXX"];
2238 auto const starting_xrp =
XRP(100.1) +
2239 env.current()->fees().accountReserve(1) +
2240 env.current()->fees().base * 2;
2242 env.fund(starting_xrp, gw, alice, bob);
2244 env(
trust(alice, XTS(1000)));
2245 env(
trust(alice, XXX(1000)));
2246 env(
trust(bob, XTS(1000)));
2247 env(
trust(bob, XXX(1000)));
2249 env(
pay(gw, alice, alice[
"XTS"](100)));
2250 env(
pay(gw, alice, alice[
"XXX"](100)));
2251 env(
pay(gw, bob, bob[
"XTS"](100)));
2252 env(
pay(gw, bob, bob[
"XXX"](100)));
2254 env(
offer(alice, XTS(100), XXX(100)));
2261 payment[jss::id] = env.seq(bob);
2262 payment[jss::build_path] =
true;
2263 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2264 payment[jss::tx_json][jss::Sequence] =
2267 ->getFieldU32(sfSequence);
2268 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2269 payment[jss::tx_json][jss::SendMax] =
2271 auto jrr = wsc->invoke(
"submit", payment);
2272 BEAST_EXPECT(jrr[jss::status] ==
"success");
2273 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2274 if (wsc->version() == 2)
2277 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2279 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2280 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2284 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2286 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2289 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2291 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2306 auto const sleTrust =
2308 BEAST_EXPECT(sleTrust);
2312 bool const accountLow = account.id() < issue.
account;
2317 low.setIssuer(accountLow ? account.id() : issue.
account);
2318 high.setIssuer(accountLow ? issue.
account : account.id());
2320 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2321 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2323 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2327 BEAST_EXPECT(actualBalance == expectBalance);
2339 using namespace jtx;
2341 auto const gw =
Account(
"gateway");
2342 auto const USD = gw[
"USD"];
2344 Env env{*
this, features};
2346 env.fund(
XRP(10000000), gw);
2349 auto const f = env.current()->fees().base;
2352 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2358 preTrustType preTrust;
2368 TestData
const tests[]{
2370 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2371 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2372 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2373 {
"deb",
reserve(env, 0) + 2 * f, 1, noPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 1},
2374 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2375 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2376 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2377 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2378 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2379 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2380 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2381 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2382 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2383 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2384 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2385 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2386 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2387 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2389 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2390 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2391 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2392 {
"dan",
reserve(env, 0) + 2 * f, 1, gwPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 0},
2393 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2394 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2395 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2396 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2398 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2399 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2400 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2401 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2402 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2403 {
"syd",
reserve(env, 1) + 3 * f, 1, acctPreTrust, 1000,
tesSUCCESS, 3 * f, USD(0.00001), 0, 1},
2404 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2405 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2406 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2407 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2408 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2412 for (
auto const& t : tests)
2414 auto const acct =
Account(t.account);
2415 env.fund(t.fundXrp, acct);
2419 env.require(
offers(gw, 0));
2422 auto const book = t.bookAmount;
2424 env(
offer(gw,
XRP(book), USD(book)));
2429 if (t.preTrust == gwPreTrust)
2430 env(
trust(gw, acct[
"USD"](1)));
2435 if (t.preTrust == acctPreTrust)
2436 env(
trust(acct, USD(1)));
2442 auto const acctOffer = t.offerAmount;
2443 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2448 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2450 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2451 env.require(
offers(acct, t.offers));
2452 env.require(
owners(acct, t.owners));
2455 BEAST_EXPECT(acctOffers.size() == t.offers);
2456 if (acctOffers.size() && t.offers)
2458 auto const& acctOffer = *(acctOffers.front());
2460 auto const leftover = t.offerAmount - t.bookAmount;
2461 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2462 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2465 if (t.preTrust == noPreTrust)
2467 if (t.balanceUsd.value().signum())
2475 auto const sleTrust =
2477 BEAST_EXPECT(!sleTrust);
2494 using namespace jtx;
2496 auto const gw =
Account(
"gateway");
2497 auto const alice =
Account(
"alice");
2498 auto const bob =
Account(
"bob");
2499 auto const USD = gw[
"USD"];
2501 auto const usdOffer = USD(1000);
2502 auto const xrpOffer =
XRP(1000);
2504 Env env{*
this, features};
2506 env.fund(
XRP(1000000), gw, bob);
2510 auto const fee = env.current()->fees().base;
2517 env(
trust(alice, usdOffer));
2521 env(
pay(gw, alice, usdOffer));
2528 auto const alicesXRP = env.balance(alice);
2529 auto const bobsXRP = env.balance(bob);
2531 env(
offer(alice, xrpOffer, usdOffer));
2533 env(
offer(bob, usdOffer, xrpOffer));
2547 env(
offer(alice, USD(999),
XRP(999)));
2548 env(
offer(bob, xrpOffer, usdOffer));
2551 env.require(
balance(alice, USD(999)));
2552 env.require(
balance(bob, USD(1)));
2553 env.require(
offers(alice, 0));
2557 BEAST_EXPECT(bobsOffers.size() == 1);
2558 auto const& bobsOffer = *(bobsOffers.front());
2560 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2561 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2562 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2571 using namespace jtx;
2573 auto const gw =
Account(
"gateway");
2574 auto const alice =
Account(
"alice");
2575 auto const bob =
Account(
"bob");
2576 auto const USD = gw[
"USD"];
2577 auto const EUR = gw[
"EUR"];
2579 auto const usdOffer = USD(1000);
2580 auto const eurOffer = EUR(1000);
2582 Env env{*
this, features};
2584 env.fund(
XRP(1000000), gw);
2588 auto const fee = env.current()->fees().base;
2596 env(
trust(alice, usdOffer));
2597 env(
trust(bob, eurOffer));
2600 env(
pay(gw, alice, usdOffer));
2601 env(
pay(gw, bob, eurOffer));
2609 env(
offer(alice, eurOffer, usdOffer));
2610 env(
offer(bob, usdOffer, eurOffer));
2627 env(
offer(bob, eurOffer, usdOffer));
2630 env(
offer(alice, USD(999), eurOffer));
2633 env.require(
offers(alice, 0));
2634 env.require(
offers(bob, 1));
2636 env.require(
balance(alice, USD(999)));
2637 env.require(
balance(alice, EUR(1)));
2638 env.require(
balance(bob, USD(1)));
2639 env.require(
balance(bob, EUR(999)));
2643 if (BEAST_EXPECT(bobsOffers.size() == 1))
2645 auto const& bobsOffer = *(bobsOffers.front());
2647 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2648 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2653 env(
offer(alice, USD(1), EUR(1)));
2656 env.require(
balance(alice, USD(1000)));
2659 env.require(
balance(bob, EUR(1000)));
2660 env.require(
offers(alice, 0));
2661 env.require(
offers(bob, 0));
2664 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2665 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2669 env(
offer(alice, EUR(999), usdOffer));
2672 env(
offer(bob, usdOffer, eurOffer));
2675 env.require(
offers(alice, 0));
2676 env.require(
offers(bob, 0));
2678 env.require(
balance(alice, USD(0)));
2679 env.require(
balance(alice, EUR(999)));
2680 env.require(
balance(bob, USD(1000)));
2681 env.require(
balance(bob, EUR(1)));
2689 using namespace jtx;
2691 auto const gw =
Account(
"gateway");
2692 auto const alice =
Account(
"alice");
2693 auto const bob =
Account(
"bob");
2694 auto const carol =
Account(
"carol");
2695 auto const USD = gw[
"USD"];
2696 auto const EUR = gw[
"EUR"];
2698 auto const usdOffer = USD(1000);
2699 auto const eurOffer = EUR(1000);
2701 Env env{*
this, features};
2703 env.fund(
XRP(1000000), gw, alice, bob, carol);
2706 env(
trust(alice, usdOffer));
2707 env(
trust(carol, eurOffer));
2709 env(
pay(gw, alice, usdOffer));
2710 env(
pay(gw, carol, eurOffer));
2719 env(
offer(alice,
XRP(1000), usdOffer));
2720 env(
offer(bob, eurOffer,
XRP(1000)));
2721 auto const bobXrpBalance = env.balance(bob);
2725 env(
offer(carol, USD(400), EUR(400)));
2738 BEAST_EXPECT(alicesOffers.size() == 1);
2739 auto const& alicesOffer = *(alicesOffers.front());
2741 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2742 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2743 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2747 BEAST_EXPECT(bobsOffers.size() == 1);
2748 auto const& bobsOffer = *(bobsOffers.front());
2750 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2751 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2752 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2756 env(
offer(carol, USD(600), EUR(600)));
2771 if (alicesOffers.size() != 0)
2773 BEAST_EXPECT(alicesOffers.size() == 1);
2774 auto const& alicesOffer = *(alicesOffers.front());
2776 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2777 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2778 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2790 using namespace jtx;
2792 auto const gw =
Account(
"gateway");
2793 auto const USD = gw[
"USD"];
2795 Env env{*
this, features};
2797 env.fund(
XRP(10000000), gw);
2800 auto const f = env.current()->fees().base;
2803 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2837 : account(std::move(account_))
2842 , acctGets(acctGets_)
2843 , acctPays(acctPays_)
2845 , spentXrp(spentXrp_)
2846 , finalUsd(finalUsd_)
2849 , takerGets(takerGets_)
2850 , takerPays(takerPays_)
2869 std::move(account_),
2888 TestData
const tests[]{
2891 {
"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},
2892 {
"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)},
2893 {
"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},
2894 {
"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},
2895 {
"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},
2896 {
"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},
2897 {
"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},
2898 {
"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)},
2900 {
"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},
2901 {
"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)},
2902 {
"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},
2903 {
"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},
2904 {
"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},
2905 {
"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)},
2906 {
"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)},
2910 auto const zeroUsd = USD(0);
2911 for (
auto const& t : tests)
2914 env.require(
offers(gw, 0));
2916 auto const acct =
Account(t.account);
2918 env.fund(t.fundXrp, acct);
2924 if (t.fundUSD != zeroUsd)
2926 env(
trust(acct, t.fundUSD));
2928 env(
pay(gw, acct, t.fundUSD));
2932 env(
offer(gw, t.gwGets, t.gwPays));
2942 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2944 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2945 env.require(
offers(acct, t.offers));
2946 env.require(
owners(acct, t.owners));
2951 if (acctOffers.size() > 0)
2953 BEAST_EXPECT(acctOffers.size() == 1);
2954 auto const& acctOffer = *(acctOffers.front());
2956 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2957 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2958 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2975 testcase(
"Combine tfSell with tfFillOrKill");
2977 using namespace jtx;
2979 auto const gw =
Account(
"gateway");
2980 auto const alice =
Account(
"alice");
2981 auto const bob =
Account(
"bob");
2982 auto const USD = gw[
"USD"];
2984 Env env{*
this, features};
2986 env.fund(
XRP(10000000), gw, alice, bob);
2989 TER const killedCode{
2993 env(
trust(bob, USD(200)));
2995 env(
pay(gw, bob, USD(100)));
2997 env(
offer(bob,
XRP(2000), USD(20)));
3005 env.require(
offers(alice, 0));
3006 env.require(
balance(bob, USD(100)));
3013 env.require(
balance(alice, USD(20)));
3014 env.require(
offers(alice, 0));
3015 env.require(
balance(bob, USD(80)));
3020 env(
offer(bob,
XRP(2000), USD(20)));
3024 env.require(
balance(alice, USD(35)));
3025 env.require(
offers(alice, 0));
3026 env.require(
balance(bob, USD(65)));
3038 env.require(
balance(alice, USD(35)));
3039 env.require(
offers(alice, 0));
3040 env.require(
balance(bob, USD(65)));
3049 env.require(
balance(alice, USD(40)));
3050 env.require(
offers(alice, 0));
3051 env.require(
balance(bob, USD(60)));
3060 using namespace jtx;
3062 auto const gw1 =
Account(
"gateway1");
3063 auto const USD = gw1[
"USD"];
3065 Env env{*
this, features};
3068 auto const fee = env.current()->fees().base;
3070 env.fund(
XRP(100000), gw1);
3073 env(
rate(gw1, 1.25));
3075 auto const ann =
Account(
"ann");
3076 auto const bob =
Account(
"bob");
3080 env(
trust(ann, USD(200)));
3081 env(
trust(bob, USD(200)));
3084 env(
pay(gw1, bob, USD(125)));
3099 env.require(
balance(ann, USD(100)));
3101 env.require(
offers(ann, 0));
3103 env.require(
balance(bob, USD(0)));
3105 env.require(
offers(bob, 0));
3110 auto const che =
Account(
"che");
3111 auto const deb =
Account(
"deb");
3115 env(
trust(che, USD(200)));
3116 env(
trust(deb, USD(200)));
3119 env(
pay(gw1, deb, USD(125)));
3128 env.require(
balance(che, USD(100)));
3130 env.require(
offers(che, 0));
3132 env.require(
balance(deb, USD(0)));
3134 env.require(
offers(deb, 0));
3137 auto const eve =
Account(
"eve");
3138 auto const fyn =
Account(
"fyn");
3140 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3143 env(
trust(eve, USD(1000)));
3144 env(
trust(fyn, USD(1000)));
3147 env(
pay(gw1, eve, USD(100)));
3148 env(
pay(gw1, fyn, USD(100)));
3154 env(
offer(eve, USD(10),
XRP(4000)));
3158 env(
offer(fyn,
XRP(2000), USD(5)));
3161 env.require(
balance(eve, USD(105)));
3164 BEAST_EXPECT(evesOffers.size() == 1);
3165 if (evesOffers.size() != 0)
3167 auto const& evesOffer = *(evesOffers.front());
3168 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3169 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3170 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3174 env.require(
balance(fyn, USD(93.75)));
3176 env.require(
offers(fyn, 0));
3179 auto const gw2 =
Account(
"gateway2");
3180 auto const EUR = gw2[
"EUR"];
3182 env.fund(
XRP(100000), gw2);
3185 env(
rate(gw2, 1.5));
3190 auto const gay =
Account(
"gay");
3191 auto const hal =
Account(
"hal");
3192 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3195 env(
trust(gay, USD(200)));
3196 env(
trust(gay, EUR(200)));
3197 env(
trust(hal, USD(200)));
3198 env(
trust(hal, EUR(200)));
3201 env(
pay(gw1, gay, USD(125)));
3202 env(
pay(gw2, hal, EUR(150)));
3205 env(
offer(gay, EUR(100), USD(100)));
3208 env(
offer(hal, USD(100), EUR(100)));
3211 env.require(
balance(gay, USD(0)));
3212 env.require(
balance(gay, EUR(100)));
3214 env.require(
offers(gay, 0));
3216 env.require(
balance(hal, USD(100)));
3217 env.require(
balance(hal, EUR(0)));
3219 env.require(
offers(hal, 0));
3223 auto const ivy =
Account(
"ivy");
3224 auto const joe =
Account(
"joe");
3225 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3234 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3235 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3237 env.require(
balance(ivy, USD(300)));
3238 env.require(
balance(joe, EUR(250)));
3240 env(
offer(ivy, EUR(100), USD(200)));
3243 env(
offer(joe, USD(200), EUR(100)));
3246 env.require(
balance(ivy, USD(50)));
3247 env.require(
balance(ivy, EUR(100)));
3249 env.require(
offers(ivy, 0));
3251 env.require(
balance(joe, USD(200)));
3252 env.require(
balance(joe, EUR(100)));
3254 env.require(
offers(joe, 0));
3258 auto const kim =
Account(
"kim");
3259 auto const K_BUX = kim[
"BUX"];
3260 auto const lex =
Account(
"lex");
3261 auto const meg =
Account(
"meg");
3262 auto const ned =
Account(
"ned");
3263 auto const N_BUX = ned[
"BUX"];
3266 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3269 env(
trust(lex, K_BUX(400)));
3271 env(
trust(meg, N_BUX(100)));
3273 env(
pay(ned, lex, N_BUX(100)));
3275 env.require(
balance(lex, N_BUX(100)));
3277 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3282 env.require(
balance(lex, K_BUX(72)));
3283 env.require(
balance(lex, N_BUX(40)));
3285 env.require(
balance(meg, N_BUX(60)));
3290 env(
offer(lex, K_BUX(30), N_BUX(30)));
3293 env(
offer(kim, N_BUX(30), K_BUX(30)));
3297 env.require(
balance(kim, N_BUX(30)));
3298 env.require(
balance(lex, K_BUX(102)));
3299 env.require(
balance(lex, N_BUX(10)));
3301 env.require(
balance(meg, N_BUX(60)));
3302 env.require(
balance(ned, K_BUX(-30)));
3307 auto const ova =
Account(
"ova");
3308 auto const pat =
Account(
"pat");
3309 auto const qae =
Account(
"qae");
3310 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3316 env(
trust(ova, USD(200)));
3317 env(
trust(ova, EUR(200)));
3318 env(
trust(pat, USD(200)));
3319 env(
trust(pat, EUR(200)));
3320 env(
trust(qae, USD(200)));
3321 env(
trust(qae, EUR(200)));
3324 env(
pay(gw1, ova, USD(125)));
3325 env(
pay(gw2, qae, EUR(150)));
3332 env(
offer(qae, USD(100), EUR(100)));
3335 env.require(
balance(ova, USD(0)));
3336 env.require(
balance(ova, EUR(0)));
3341 if (ovasOffers.size() != 0)
3343 BEAST_EXPECT(ovasOffers.size() == 1);
3344 auto const& ovasOffer = *(ovasOffers.front());
3346 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3347 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3348 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3351 env.require(
balance(pat, USD(0)));
3352 env.require(
balance(pat, EUR(100)));
3354 env.require(
offers(pat, 0));
3356 env.require(
balance(qae, USD(100)));
3357 env.require(
balance(qae, EUR(0)));
3359 env.require(
offers(qae, 0));
3380 using namespace jtx;
3382 auto const gw =
Account(
"gateway");
3383 auto const USD = gw[
"USD"];
3385 Env env{*
this, features};
3388 auto const fee = env.current()->fees().base;
3389 auto const startBalance =
XRP(1000000);
3391 env.fund(startBalance + (
fee * 4), gw);
3401 env.require(
owners(gw, 3));
3402 env.require(
balance(gw, startBalance +
fee));
3405 BEAST_EXPECT(gwOffers.size() == 3);
3406 for (
auto const& offerPtr : gwOffers)
3408 auto const&
offer = *offerPtr;
3409 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3410 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3411 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3416 env(
offer(gw,
XRP(1000), USD(100)));
3418 env.require(
owners(gw, 1));
3419 env.require(
offers(gw, 1));
3420 env.require(
balance(gw, startBalance));
3423 BEAST_EXPECT(gwOffers.size() == 1);
3424 for (
auto const& offerPtr : gwOffers)
3426 auto const&
offer = *offerPtr;
3427 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3428 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3429 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3436 using namespace jtx;
3438 auto const gw1 =
Account(
"gateway1");
3439 auto const gw2 =
Account(
"gateway2");
3440 auto const alice =
Account(
"alice");
3441 auto const USD = gw1[
"USD"];
3442 auto const EUR = gw2[
"EUR"];
3444 Env env{*
this, features};
3446 env.fund(
XRP(1000000), gw1, gw2);
3450 auto const f = env.current()->fees().base;
3464 TestData
const tests[]{
3475 for (
auto const& t : tests)
3477 auto const acct =
Account{t.acct};
3478 env.fund(t.fundXRP, acct);
3481 env(
trust(acct, USD(1000)));
3482 env(
trust(acct, EUR(1000)));
3485 if (t.fundUSD > USD(0))
3486 env(
pay(gw1, acct, t.fundUSD));
3487 if (t.fundEUR > EUR(0))
3488 env(
pay(gw2, acct, t.fundEUR));
3491 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3495 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3496 env.require(
owners(acct, 2 + offerCount));
3497 env.require(
balance(acct, t.fundUSD));
3498 env.require(
balance(acct, t.fundEUR));
3501 BEAST_EXPECT(acctOffers.size() == offerCount);
3502 for (
auto const& offerPtr : acctOffers)
3504 auto const&
offer = *offerPtr;
3505 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3506 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3507 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3510 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3514 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3515 env.require(
owners(acct, 2 + offerCount));
3516 env.require(
balance(acct, t.fundUSD));
3517 env.require(
balance(acct, t.fundEUR));
3520 BEAST_EXPECT(acctOffers.size() == offerCount);
3521 for (
auto const& offerPtr : acctOffers)
3523 auto const&
offer = *offerPtr;
3524 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3525 if (
offer[sfSequence] == firstOfferSeq)
3527 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3528 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3532 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3533 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3560 using namespace jtx;
3562 Env env{*
this, features};
3564 auto const alice =
Account(
"alice");
3565 auto const bob =
Account(
"bob");
3566 auto const USD = bob[
"USD"];
3567 auto const f = env.current()->fees().base;
3569 env.fund(
XRP(50000) + f, alice, bob);
3572 env(
offer(alice, USD(5000),
XRP(50000)));
3576 env(
offer(bob,
XRP(50000), USD(5000)));
3582 env.require(
owners(alice, 1));
3583 env.require(
lines(alice, 1));
3588 BEAST_EXPECT(bobOffers.size() == 1);
3589 for (
auto const& offerPtr : bobOffers)
3591 auto const&
offer = *offerPtr;
3592 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3593 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3594 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3606 using namespace jtx;
3610 Env env{*
this, features | featureOwnerPaysFee};
3613 auto const fee = env.current()->fees().base;
3616 auto const ann =
Account(
"ann");
3617 auto const A_BUX = ann[
"BUX"];
3618 auto const bob =
Account(
"bob");
3619 auto const cam =
Account(
"cam");
3620 auto const dan =
Account(
"dan");
3621 auto const D_BUX = dan[
"BUX"];
3624 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3627 env(
trust(bob, A_BUX(400)));
3629 env(
trust(cam, D_BUX(100)));
3631 env(
pay(dan, bob, D_BUX(100)));
3633 env.require(
balance(bob, D_BUX(100)));
3635 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3640 env.require(
balance(bob, A_BUX(72)));
3641 env.require(
balance(bob, D_BUX(40)));
3643 env.require(
balance(cam, D_BUX(60)));
3647 env(
offer(bob, A_BUX(30), D_BUX(30)));
3650 env(
trust(ann, D_BUX(100)));
3654 env(
pay(ann, ann, D_BUX(30)),
3661 env.require(
balance(ann, D_BUX(0)));
3662 env.require(
balance(bob, A_BUX(72)));
3663 env.require(
balance(bob, D_BUX(40)));
3665 env.require(
balance(cam, D_BUX(60)));
3666 env.require(
balance(dan, A_BUX(0)));
3680 using namespace jtx;
3682 Env env{*
this, features};
3684 auto const ann =
Account(
"ann");
3685 auto const bob =
Account(
"bob");
3686 auto const cam =
Account(
"cam");
3687 auto const A_BUX = ann[
"BUX"];
3688 auto const B_BUX = bob[
"BUX"];
3690 auto const fee = env.current()->fees().base;
3691 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3694 env(
trust(ann, B_BUX(40)));
3695 env(
trust(cam, A_BUX(40)));
3696 env(
trust(cam, B_BUX(40)));
3699 env(
pay(ann, cam, A_BUX(35)));
3700 env(
pay(bob, cam, B_BUX(35)));
3702 env(
offer(bob, A_BUX(30), B_BUX(30)));
3710 env.require(
balance(cam, A_BUX(35)));
3711 env.require(
balance(cam, B_BUX(35)));
3712 env.require(
offers(cam, 1));
3715 env(
offer(cam, B_BUX(30), A_BUX(30)));
3718 env.require(
balance(bob, A_BUX(30)));
3719 env.require(
balance(cam, A_BUX(5)));
3720 env.require(
balance(cam, B_BUX(65)));
3721 env.require(
offers(cam, 0));
3730 testcase(
"Self crossing low quality offer");
3732 using namespace jtx;
3734 Env env{*
this, features};
3736 auto const ann =
Account(
"ann");
3737 auto const gw =
Account(
"gateway");
3738 auto const BTC = gw[
"BTC"];
3740 auto const fee = env.current()->fees().base;
3745 env(
rate(gw, 1.002));
3746 env(
trust(ann, BTC(10)));
3749 env(
pay(gw, ann, BTC(2.856)));
3752 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3756 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3769 using namespace jtx;
3771 Env env{*
this, features};
3773 auto const gw =
Account(
"gateway");
3774 auto const alice =
Account(
"alice");
3775 auto const bob =
Account(
"bob");
3776 auto const CNY = gw[
"CNY"];
3778 auto const fee = env.current()->fees().base;
3783 env(
trust(bob, CNY(500)));
3786 env(
pay(gw, bob, CNY(300)));
3789 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3793 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3797 BEAST_EXPECT(aliceOffers.size() == 1);
3798 for (
auto const& offerPtr : aliceOffers)
3800 auto const&
offer = *offerPtr;
3801 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3802 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3803 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3813 testcase(
"Offer In Scaling With Xfer Rate");
3815 using namespace jtx;
3817 Env env{*
this, features};
3819 auto const gw =
Account(
"gateway");
3820 auto const alice =
Account(
"alice");
3821 auto const bob =
Account(
"bob");
3822 auto const BTC = gw[
"BTC"];
3823 auto const JPY = gw[
"JPY"];
3825 auto const fee = env.current()->fees().base;
3830 env(
rate(gw, 1.002));
3831 env(
trust(alice, JPY(4000)));
3832 env(
trust(bob, BTC(2)));
3835 env(
pay(gw, alice, JPY(3699.034802280317)));
3836 env(
pay(gw, bob, BTC(1.156722559140311)));
3839 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3843 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3847 BEAST_EXPECT(aliceOffers.size() == 1);
3848 for (
auto const& offerPtr : aliceOffers)
3850 auto const&
offer = *offerPtr;
3851 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3853 offer[sfTakerGets] ==
3855 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3865 testcase(
"Offer Threshold With Reduced Funds");
3867 using namespace jtx;
3869 Env env{*
this, features};
3871 auto const gw1 =
Account(
"gw1");
3872 auto const gw2 =
Account(
"gw2");
3873 auto const alice =
Account(
"alice");
3874 auto const bob =
Account(
"bob");
3875 auto const USD = gw1[
"USD"];
3876 auto const JPY = gw2[
"JPY"];
3878 auto const fee = env.current()->fees().base;
3880 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3883 env(
rate(gw1, 1.002));
3884 env(
trust(alice, USD(1000)));
3885 env(
trust(bob, JPY(100000)));
3912 BEAST_EXPECT(aliceOffers.size() == 1);
3913 for (
auto const& offerPtr : aliceOffers)
3915 auto const&
offer = *offerPtr;
3916 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3918 offer[sfTakerGets] ==
3921 offer[sfTakerPays] ==
3931 using namespace jtx;
3933 Env env{*
this, features};
3935 auto const gw =
Account(
"gw");
3936 auto const alice =
Account(
"alice");
3937 auto const bob =
Account(
"bob");
3938 auto const CNY = gw[
"CNY"];
3939 auto const fee = env.current()->fees().base;
3940 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3942 env.fund(startXrpBalance, gw, alice, bob);
3945 env(
trust(bob, CNY(100000)));
3957 STAmount const bobsCnyStartBalance{
3959 env(
pay(gw, bob, bobsCnyStartBalance));
3968 env.require(
balance(alice, alicesCnyOffer));
3970 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
4013 using namespace jtx;
4015 Env env{*
this, features};
4017 auto const gw =
Account(
"gw");
4018 auto const BTC = gw[
"BTC"];
4019 auto const USD = gw[
"USD"];
4020 auto const startXrpBalance =
XRP(4000000);
4022 env.fund(startXrpBalance, gw);
4025 env(
rate(gw, 1.25));
4051 TestData
const tests[]{
4053 {0, 0, 1, BTC(20), {{
"ann", 0,
drops(3899999999960), BTC(20.0), USD(3000)}, {
"abe", 0,
drops(4099999999970), BTC( 0), USD(750)}}},
4054 {0, 1, 0, BTC(20), {{
"bev", 0,
drops(4099999999960), BTC( 7.5), USD(2000)}, {
"bob", 0,
drops(3899999999970), BTC(10), USD( 0)}}},
4055 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(3999999999950), BTC(20.0), USD(2000)} }},
4056 {0, 1, 0, BTC( 5), {{
"deb", 1,
drops(4039999999960), BTC( 0.0), USD(2000)}, {
"dan", 1,
drops(3959999999970), BTC( 4), USD( 0)}}},
4060 for (
auto const& t : tests)
4062 Account const& self = t.actors[t.self].acct;
4063 Account const& leg0 = t.actors[t.leg0].acct;
4064 Account const& leg1 = t.actors[t.leg1].acct;
4066 for (
auto const& actor : t.actors)
4068 env.fund(
XRP(4000000), actor.acct);
4071 env(
trust(actor.acct, BTC(40)));
4072 env(
trust(actor.acct, USD(8000)));
4076 env(
pay(gw, self, t.btcStart));
4077 env(
pay(gw, self, USD(2000)));
4078 if (self.
id() != leg1.
id())
4079 env(
pay(gw, leg1, USD(2000)));
4093 env(
offer(self, USD(1000), BTC(10)));
4098 for (
auto const& actor : t.actors)
4104 actorOffers.begin(),
4106 actorOffers.begin(),
4109 return (*offer)[sfTakerGets].signum() == 0;
4111 BEAST_EXPECT(offerCount == actor.offers);
4113 env.require(
balance(actor.acct, actor.xrp));
4114 env.require(
balance(actor.acct, actor.btc));
4115 env.require(
balance(actor.acct, actor.usd));
4131 testcase(
"Self Pay Unlimited Funds");
4163 using namespace jtx;
4165 Env env{*
this, features};
4167 auto const gw =
Account(
"gw");
4168 auto const BTC = gw[
"BTC"];
4169 auto const USD = gw[
"USD"];
4170 auto const startXrpBalance =
XRP(4000000);
4172 env.fund(startXrpBalance, gw);
4175 env(
rate(gw, 1.25));
4201 TestData
const takerTests[]{
4203 {0, 0, 1, BTC(5), {{
"deb", 0,
drops(3899999999960), BTC(5), USD(3000)}, {
"dan", 0,
drops(4099999999970), BTC(0), USD(750)}}},
4204 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(3999999999950), BTC(5), USD(2000)} }}
4207 TestData
const flowTests[]{
4209 {0, 0, 1, BTC(5), {{
"gay", 1,
drops(3949999999960), BTC(5), USD(2500)}, {
"gar", 1,
drops(4049999999970), BTC(0), USD(1375)}}},
4210 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(3999999999950), BTC(5), USD(2000)} }}
4215 auto const& tests = features[featureFlowCross] ? flowTests : takerTests;
4217 for (
auto const& t : tests)
4219 Account const& self = t.actors[t.self].acct;
4220 Account const& leg0 = t.actors[t.leg0].acct;
4221 Account const& leg1 = t.actors[t.leg1].acct;
4223 for (
auto const& actor : t.actors)
4225 env.fund(
XRP(4000000), actor.acct);
4228 env(
trust(actor.acct, BTC(40)));
4229 env(
trust(actor.acct, USD(8000)));
4233 env(
pay(gw, self, t.btcStart));
4234 env(
pay(gw, self, USD(2000)));
4235 if (self.
id() != leg1.
id())
4236 env(
pay(gw, leg1, USD(2000)));
4250 env(
offer(self, USD(1000), BTC(10)));
4255 for (
auto const& actor : t.actors)
4261 actorOffers.begin(),
4263 actorOffers.begin(),
4266 return (*offer)[sfTakerGets].signum() == 0;
4268 BEAST_EXPECT(offerCount == actor.offers);
4270 env.require(
balance(actor.acct, actor.xrp));
4271 env.require(
balance(actor.acct, actor.btc));
4272 env.require(
balance(actor.acct, actor.usd));
4290 using namespace jtx;
4292 Env env{*
this, features};
4294 auto const gw =
Account(
"gw");
4295 auto const alice =
Account(
"alice");
4296 auto const bob =
Account(
"bob");
4297 auto const gwUSD = gw[
"USD"];
4298 auto const aliceUSD = alice[
"USD"];
4299 auto const bobUSD = bob[
"USD"];
4301 env.fund(
XRP(400000), gw, alice, bob);
4310 env(
trust(bob, gwUSD(100)));
4312 env(
trust(alice, gwUSD(100)));
4314 env(
offer(alice, gwUSD(40),
XRP(4000)));
4317 env.require(
offers(alice, 1));
4318 env.require(
balance(alice, gwUSD(0)));
4320 env(
pay(gw, bob, gwUSD(50)));
4323 env.require(
balance(bob, gwUSD(50)));
4326 env(
offer(bob,
XRP(4000), gwUSD(40)));
4329 env.require(
offers(alice, 0));
4330 env.require(
balance(alice, gwUSD(40)));
4332 env.require(
offers(bob, 0));
4333 env.require(
balance(bob, gwUSD(10)));
4359 using namespace jtx;
4361 Env env{*
this, features};
4363 auto const gw =
Account(
"gw");
4364 auto const alice =
Account(
"alice");
4365 auto const bob =
Account(
"bob");
4366 auto const gwUSD = gw[
"USD"];
4367 auto const aliceUSD = alice[
"USD"];
4368 auto const bobUSD = bob[
"USD"];
4370 env.fund(
XRP(400000), gw, alice, bob);
4373 env(
offer(alice, gwUSD(40),
XRP(4000)));
4376 env.require(
offers(alice, 1));
4383 env(
trust(bob, gwUSD(100)));
4386 env(
pay(gw, bob, gwUSD(50)));
4388 env.require(
balance(bob, gwUSD(50)));
4396 env(
offer(bob,
XRP(4000), gwUSD(40)));
4400 bool const flowCross = features[featureFlowCross];
4402 env.require(
offers(alice, 0));
4407 env.require(
offers(bob, 1));
4408 env.require(
balance(bob, gwUSD(50)));
4413 env.require(
balance(alice, gwUSD(40)));
4414 env.require(
offers(bob, 0));
4415 env.require(
balance(bob, gwUSD(10)));
4427 env.require(
offers(alice, 0));
4430 env.require(
offers(bob, 1));
4431 env.require(
balance(bob, gwUSD(50)));
4435 env(
trust(gw, aliceUSD(100)));
4441 env.require(
offers(alice, 0));
4442 env.require(
balance(alice, gwUSD(0)));
4444 env.require(
offers(bob, 1));
4445 env.require(
balance(bob, gwUSD(50)));
4450 env.require(
offers(bob, 0));
4458 env(
offer(alice, gwUSD(40),
XRP(4000)));
4461 env.require(
offers(alice, 1));
4464 env(
offer(bob,
XRP(4000), gwUSD(40)));
4467 env.require(
offers(alice, 0));
4468 env.require(
balance(alice, gwUSD(40)));
4470 env.require(
offers(bob, 0));
4471 env.require(
balance(bob, gwUSD(10)));
4477 testcase(
"RippleConnect Smoketest payment flow");
4478 using namespace jtx;
4480 Env env{*
this, features};
4490 auto const hotUS =
Account(
"hotUS");
4491 auto const coldUS =
Account(
"coldUS");
4492 auto const hotEU =
Account(
"hotEU");
4493 auto const coldEU =
Account(
"coldEU");
4494 auto const mm =
Account(
"mm");
4496 auto const USD = coldUS[
"USD"];
4497 auto const EUR = coldEU[
"EUR"];
4499 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4503 for (
auto const& cold : {coldUS, coldEU})
4526 env(
pay(coldUS, hotUS, USD(5000000)));
4527 env(
pay(coldEU, hotEU, EUR(5000000)));
4528 env(
pay(coldUS, mm, USD(5000000)));
4529 env(
pay(coldEU, mm, EUR(5000000)));
4533 float const rate = 0.9f;
4534 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4537 float const reverseRate = 1.0f /
rate * 1.00101f;
4538 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4545 jvParams[jss::destination_account] = coldEU.human();
4546 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4547 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4548 jvParams[jss::destination_amount][jss::value] = 10;
4549 jvParams[jss::source_account] = hotUS.human();
4552 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4554 BEAST_EXPECT(jrr[jss::status] ==
"success");
4556 jrr[jss::alternatives].isArray() &&
4557 jrr[jss::alternatives].size() > 0);
4560 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4568 using namespace jtx;
4570 Env env{*
this, features};
4572 auto const gw =
Account(
"gw");
4573 auto const alice =
Account(
"alice");
4574 auto const gwUSD = gw[
"USD"];
4575 auto const aliceUSD = alice[
"USD"];
4577 env.fund(
XRP(400000), gw, alice);
4581 env(
offer(gw, gwUSD(40),
XRP(4000)));
4584 env.require(
offers(gw, 1));
4593 env.require(
offers(gw, 0));
4600 bool const preauth = features[featureDepositPreauth];
4605 env(
offer(gw, gwUSD(40),
XRP(4000)),
4609 env.require(
offers(gw, preauth ? 1 : 0));
4617 env(
trust(alice, gwUSD(100)));
4620 env(
pay(gw, alice, gwUSD(50)));
4623 env.require(
balance(alice, gwUSD(50)));
4626 env(
offer(alice,
XRP(4000), gwUSD(40)));
4629 env.require(
offers(alice, 0));
4630 env.require(
balance(alice, gwUSD(10)));
4632 env.require(
offers(gw, 0));
4639 using namespace jtx;
4643 auto trustLineExists = [](
jtx::Env const& env,
4654 auto const USD = gw[
"USD"];
4655 auto const BUX = alice[
"BUX"];
4657 Env env{*
this, features};
4660 env.
trust(USD(1000), becky);
4661 env(
pay(gw, becky, USD(5)));
4663 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4674 env(
pay(becky, gw, USD(5)));
4675 env.
trust(USD(0), becky);
4677 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4678 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4679 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4686 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4688 if (gwSeq + 255 > openLedgerSeq)
4689 return gwSeq - openLedgerSeq + 255;
4693 for (
int i = 0; i < delta; ++i)
4710 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4711 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4717 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4718 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4723 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4727 env.
trust(BUX(1000), carol);
4728 env(
pay(alice, carol, BUX(2)));
4737 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4738 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4746 using namespace jtx;
4750 Env env{*
this, features};
4751 auto const gw =
Account{
"gateway"};
4752 env.fund(
XRP(10000), gw);
4754 auto txn =
noop(gw);
4755 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4758 txn[sfTickSize.fieldName] = Quality::minTickSize;
4760 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4763 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4765 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4768 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4770 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4773 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4776 txn[sfTickSize.fieldName] = 0;
4778 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4781 Env env{*
this, features};
4782 auto const gw =
Account{
"gateway"};
4783 auto const alice =
Account{
"alice"};
4784 auto const XTS = gw[
"XTS"];
4785 auto const XXX = gw[
"XXX"];
4787 env.fund(
XRP(10000), gw, alice);
4791 auto txn =
noop(gw);
4792 txn[sfTickSize.fieldName] = 5;
4794 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4797 env(
trust(alice, XTS(1000)));
4798 env(
trust(alice, XXX(1000)));
4800 env(
pay(gw, alice, alice[
"XTS"](100)));
4801 env(
pay(gw, alice, alice[
"XXX"](100)));
4803 env(
offer(alice, XTS(10), XXX(30)));
4804 env(
offer(alice, XTS(30), XXX(10)));
4811 if (sle->getType() == ltOFFER)
4815 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4819 auto it =
offers.begin();
4820 BEAST_EXPECT(it !=
offers.end());
4822 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4823 it->second.second > XXX(29.9994));
4827 BEAST_EXPECT(it !=
offers.end());
4829 it->second.first == XTS(30) && it->second.second == XXX(10));
4833 BEAST_EXPECT(it !=
offers.end());
4835 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4840 BEAST_EXPECT(it !=
offers.end());
4842 it->second.first == XTS(30) && it->second.second == XXX(10));
4844 BEAST_EXPECT(++it ==
offers.end());
4858 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4868 using namespace jtx;
4876 Env env{*
this, features};
4877 auto const gw =
Account{
"gateway"};
4878 auto const alice =
Account{
"alice"};
4879 auto const bob =
Account{
"bob"};
4880 auto const USD = gw[
"USD"];
4882 env.fund(
XRP(10000), gw, alice, bob);
4885 env(
trust(alice, USD(1000)));
4886 env(
trust(bob, USD(1000)));
4889 env(
pay(gw, alice, USD(200)));
4896 env(
offer(alice,
XRP(50), USD(50)));
4906 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4907 env(
offer(alice,
XRP(50), USD(50)));
4923 BEAST_EXPECT(
offers.size() == 4);
4924 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4925 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4926 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4927 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4928 env.require(
balance(alice, USD(200)));
4929 env.require(
owners(alice, 5));
4939 BEAST_EXPECT(
offers.size() == 3);
4940 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4941 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4942 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4952 BEAST_EXPECT(
offers.size() == 2);
4953 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4954 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4964 BEAST_EXPECT(
offers.size() == 1);
4965 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4975 BEAST_EXPECT(
offers.size() == 0);
4977 env.require(
balance(alice, USD(0)));
4978 env.require(
owners(alice, 1));
4979 env.require(
balance(bob, USD(200)));
4980 env.require(
owners(bob, 1));
4988 using namespace jtx;
4992 Env env{*
this, features};
4993 auto const gw =
Account{
"gateway"};
4994 auto const alice =
Account{
"alice"};
4995 auto const USD = gw[
"USD"];
4997 env.fund(
XRP(10000), gw, alice);
5000 env(
trust(alice, USD(1000)));
5004 env(
pay(gw, alice, USD(200)));
5009 env(
offer(alice,
XRP(50), USD(50)));
5021 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5022 env(
offer(alice,
XRP(50), USD(50)));
5038 BEAST_EXPECT(
offers.size() == 4);
5039 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
5040 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
5041 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
5042 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
5043 env.require(
balance(alice, USD(200)));
5044 env.require(
owners(alice, 7));
5054 BEAST_EXPECT(
offers.size() == 3);
5055 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5056 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
5057 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
5067 BEAST_EXPECT(
offers.size() == 2);
5068 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5069 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5082 BEAST_EXPECT(
offers.size() == 1);
5083 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5100 testcase(
"incorrect assert fixed");
5101 using namespace jtx;
5104 auto const alice =
Account(
"alice");
5105 auto const USD = alice[
"USD"];
5107 env.fund(
XRP(10000), alice);
5109 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5117 using namespace jtx;
5118 Env env(*
this, features);
5119 Account const issuer(
"issuer");
5122 auto const USD = issuer[
"USD"];
5123 auto const EUR = issuer[
"EUR"];
5126 env.
fund(
XRP(1'000), maker, taker);
5129 env.
trust(USD(1'000), maker, taker);
5130 env.
trust(EUR(1'000), maker, taker);
5133 env(
pay(issuer, maker, USD(1'000)));
5134 env(
pay(issuer, taker, USD(1'000)));
5135 env(
pay(issuer, maker, EUR(1'000)));
5138 auto makerUSDBalance = env.
balance(maker, USD).
value();
5139 auto takerUSDBalance = env.
balance(taker, USD).
value();
5140 auto makerEURBalance = env.
balance(maker, EUR).
value();
5141 auto takerEURBalance = env.
balance(taker, EUR).
value();
5148 features[fixFillOrKill] || !features[featureFlowCross]
5152 env(
offer(maker,
XRP(100), USD(100)));
5155 env(
offer(taker, USD(100),
XRP(101)),
5160 makerXRPBalance -=
txfee(env, 1);
5161 takerXRPBalance -=
txfee(env, 1);
5164 makerUSDBalance -= USD(100);
5165 takerUSDBalance += USD(100);
5166 makerXRPBalance +=
XRP(100).value();
5167 takerXRPBalance -=
XRP(100).value();
5171 env(
offer(maker, USD(100),
XRP(100)));
5174 env(
offer(taker,
XRP(100), USD(101)),
5179 makerXRPBalance -=
txfee(env, 1);
5180 takerXRPBalance -=
txfee(env, 1);
5183 makerUSDBalance += USD(100);
5184 takerUSDBalance -= USD(100);
5185 makerXRPBalance -=
XRP(100).value();
5186 takerXRPBalance +=
XRP(100).value();
5190 env(
offer(maker, USD(100), EUR(100)));
5193 env(
offer(taker, EUR(100), USD(101)),
5198 makerXRPBalance -=
txfee(env, 1);
5199 takerXRPBalance -=
txfee(env, 1);
5202 makerUSDBalance += USD(100);
5203 takerUSDBalance -= USD(100);
5204 makerEURBalance -= EUR(100);
5205 takerEURBalance += EUR(100);
5212 env(
offer(maker,
XRP(101), USD(101)));
5215 env(
offer(taker, USD(100),
XRP(101)),
5219 makerUSDBalance -= USD(101);
5220 takerUSDBalance += USD(101);
5221 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5222 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5225 env(
offer(maker, USD(101),
XRP(101)));
5228 env(
offer(taker,
XRP(100), USD(101)),
5232 makerUSDBalance += USD(101);
5233 takerUSDBalance -= USD(101);
5234 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5235 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5238 env(
offer(maker, USD(101), EUR(101)));
5241 env(
offer(taker, EUR(100), USD(101)),
5245 makerUSDBalance += USD(101);
5246 takerUSDBalance -= USD(101);
5247 makerEURBalance -= EUR(101);
5248 takerEURBalance += EUR(101);
5249 makerXRPBalance -=
txfee(env, 1);
5250 takerXRPBalance -=
txfee(env, 1);
5257 env(
offer(maker,
XRP(100), USD(100)));
5260 env(
offer(taker, USD(100),
XRP(99)),
5265 makerXRPBalance -=
txfee(env, 1);
5266 takerXRPBalance -=
txfee(env, 1);
5269 env(
offer(maker, USD(100),
XRP(100)));
5272 env(
offer(taker,
XRP(100), USD(99)),
5277 makerXRPBalance -=
txfee(env, 1);
5278 takerXRPBalance -=
txfee(env, 1);
5281 env(
offer(maker, USD(100), EUR(100)));
5284 env(
offer(taker, EUR(100), USD(99)),
5289 makerXRPBalance -=
txfee(env, 1);
5290 takerXRPBalance -=
txfee(env, 1);
5295 env.
balance(maker, USD) == makerUSDBalance &&
5296 env.
balance(taker, USD) == takerUSDBalance &&
5297 env.
balance(maker, EUR) == makerEURBalance &&
5298 env.
balance(taker, EUR) == takerEURBalance &&
5299 env.
balance(maker,
XRP) == makerXRPBalance &&
5370 using namespace jtx;
5373 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5375 fixRmSmallIncreasedQOffers};
5377 featureImmediateOfferKilled};
5381 all - takerDryOffer - immediateOfferKilled,
5382 all - flowCross - takerDryOffer - immediateOfferKilled,
5383 all - flowCross - immediateOfferKilled,
5384 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill,
5388 if (BEAST_EXPECT(instance < feats.size()))
5392 BEAST_EXPECT(!last || instance == feats.size() - 1);
5453 using namespace jtx;
5457 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5461 testAll(
all - flowCross - f1513 - immediateOfferKilled);
5462 testAll(
all - flowCross - immediateOfferKilled);
5463 testAll(
all - immediateOfferKilled - fillOrKill);
5471BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx,
ripple, 2);
5472BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx,
ripple, 2);
5473BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx,
ripple, 2);
5474BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx,
ripple, 2);
5475BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx,
ripple, 2);
5476BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx,
ripple, 2);
5477BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Offer_manual, tx,
ripple, 20);
void pass()
Record a successful test condition.
testcase_t testcase
Memberspace for declaring test cases.
A currency issued by an account.
std::string getText() const override
Issue const & issue() const
void run() override
Runs the suite.
void testSelfCrossOffer2(FeatureBitset features)
void run() override
Runs the suite.
void testMissingAuth(FeatureBitset features)
void testSelfAuth(FeatureBitset features)
void testSelfCross(bool use_partner, FeatureBitset features)
void testCrossCurrencyBridged(FeatureBitset features)
void testAll(FeatureBitset features)
void testSelfIssueOffer(FeatureBitset features)
void testRCSmoketest(FeatureBitset features)
void testExpiration(FeatureBitset features)
void testUnfundedCross(FeatureBitset features)
void testCrossCurrencyStartXRP(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > offersOnAccount(jtx::Env &env, jtx::Account account)
void testRmSmallIncreasedQOffersIOU(FeatureBitset features)
void testSellWithFillOrKill(FeatureBitset features)
void testTinyOffer(FeatureBitset features)
void testInsufficientReserve(FeatureBitset features)
void testDirectCross(FeatureBitset features)
void testOfferThresholdWithReducedFunds(FeatureBitset features)
void testRequireAuth(FeatureBitset features)
void verifyDefaultTrustline(jtx::Env &env, jtx::Account const &account, jtx::PrettyAmount const &expectBalance)
void testRmSmallIncreasedQOffersXRP(FeatureBitset features)
void testDirectToDirectPath(FeatureBitset features)
void testRmFundedOffer(FeatureBitset features)
void testOfferFeesConsumeFunds(FeatureBitset features)
void testTickSize(FeatureBitset features)
void testTicketOffer(FeatureBitset features)
void testOfferCreateThenCross(FeatureBitset features)
void testFillOrKill(FeatureBitset features)
void testSelfPayUnlimitedFunds(FeatureBitset features)
void testOfferCancelPastAndFuture(FeatureBitset features)
void testSellFlagBasic(FeatureBitset features)
void testBridgedCross(FeatureBitset features)
void testXRPDirectCross(FeatureBitset features)
void testDeletedOfferIssuer(FeatureBitset features)
void testXRPTinyPayment(FeatureBitset features)
void testTransferRateOffer(FeatureBitset features)
void testPartialCross(FeatureBitset features)
static std::vector< std::shared_ptr< SLE const > > sortedOffersOnAccount(jtx::Env &env, jtx::Account const &acct)
void testCurrencyConversionIntoDebt(FeatureBitset features)
void testMalformed(FeatureBitset features)
void run(std::uint32_t instance, bool last=false)
void testOfferCrossWithXRP(bool reverse_order, FeatureBitset features)
void testFillModes(FeatureBitset features)
void testOfferInScaling(FeatureBitset features)
void testOfferInScalingWithXferRate(FeatureBitset features)
static auto ledgerEntryOffer(jtx::Env &env, jtx::Account const &acct, std::uint32_t offer_seq)
void testCurrencyConversionEntire(FeatureBitset features)
void testSelfPayXferFeeOffer(FeatureBitset features)
void testCurrencyConversionInParts(FeatureBitset features)
void testBridgedSecondLegDry(FeatureBitset features)
void testSellOffer(FeatureBitset features)
void testCrossCurrencyEndXRP(FeatureBitset features)
void testGatewayCrossCurrency(FeatureBitset features)
void testNegativeBalance(FeatureBitset features)
static auto getBookOffers(jtx::Env &env, Issue const &taker_pays, Issue const &taker_gets)
void testSelfCrossOffer(FeatureBitset features)
std::uint32_t lastClose(jtx::Env &env)
void testSelfCrossOffer1(FeatureBitset features)
XRPAmount reserve(jtx::Env &env, std::uint32_t count)
void testOfferCrossWithLimitOverride(FeatureBitset features)
void testTicketCancelOffer(FeatureBitset features)
void testSelfCrossLowQualityOffer(FeatureBitset features)
void testOfferAcceptThenCancel(FeatureBitset features)
void testSellFlagExceedLimit(FeatureBitset features)
void testCanceledOffer(FeatureBitset features)
void testBadPathAssert(FeatureBitset features)
void testTinyPayment(FeatureBitset features)
void testEnforceNoRipple(FeatureBitset features)
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Converts to IOU Issue or STAmount.
Match the number of items in the account's owner directory.
Set Paths, SendMax on a JTx.
Sets the QualityIn on a trust JTx.
Sets the QualityOut on a trust JTx as a percentage.
Check a set of conditions.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
@ arrayValue
array value (ordered list)
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet account(AccountID const &id) noexcept
AccountID root.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
owner_count< ltRIPPLE_STATE > lines
Match the number of trust lines in the account's owner directory.
Json::Value ledgerEntryRoot(Env &env, Account const &acct)
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
PrettyAmount xrpMinusFee(Env const &env, std::int64_t xrpAmount)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value ledgerEntryState(Env &env, Account const &acct_a, Account const &acct_b, std::string const ¤cy)
static epsilon_t const epsilon
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Json::Value noop(Account const &account)
The null transaction.
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
owner_count< ltTICKET > tickets
Match the number of tickets on the account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
XRPAmount txfee(Env const &env, std::uint16_t n)
FeatureBitset supported_amendments()
Json::Value offer_cancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
bool isOffer(jtx::Env &env, jtx::Account const &account, STAmount const &takerPays, STAmount const &takerGets)
An offer exists.
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr std::uint32_t tfFillOrKill
constexpr std::uint32_t tfPassive
constexpr std::uint32_t tfImmediateOrCancel
constexpr std::uint32_t tfPartialPayment
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t asfDefaultRipple
constexpr std::uint32_t tfNoRippleDirect
std::string to_string(base_uint< Bits, Tag > const &a)
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(std::shared_ptr< SLE const > const &)> const &f)
Iterate all items in the given directory.
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
constexpr std::uint32_t tfSell
constexpr std::uint32_t asfRequireAuth
Seed generateSeed(std::string const &passPhrase)
Generate a seed deterministically.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetNoRipple
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
STAmount const & value() const