21#include <test/jtx/PathSet.h>
22#include <test/jtx/WSClient.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/Quality.h>
25#include <xrpl/protocol/jss.h>
35 return env.
current()->fees().accountReserve(count);
41 return env.
current()->info().parentCloseTime.time_since_epoch().count();
51 jvParams[jss::offer][jss::account] = acct.
human();
52 jvParams[jss::offer][jss::seq] = offer_seq;
54 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
60 Issue const& taker_pays,
61 Issue const& taker_gets)
64 jvbp[jss::ledger_index] =
"current";
69 return env.
rpc(
"json",
"book_offers",
to_string(jvbp))[jss::result];
76 testcase(
"Incorrect Removal of Funded Offers");
88 Env env{*
this, features};
90 auto const gw =
Account{
"gateway"};
91 auto const USD = gw[
"USD"];
92 auto const BTC = gw[
"BTC"];
97 env.fund(
XRP(10000), alice, bob, carol, gw);
98 env.trust(USD(1000), alice, bob, carol);
99 env.trust(BTC(1000), alice, bob, carol);
101 env(
pay(gw, alice, BTC(1000)));
103 env(
pay(gw, carol, USD(1000)));
104 env(
pay(gw, carol, BTC(1000)));
109 env(
offer(carol, BTC(49),
XRP(49)));
110 env(
offer(carol, BTC(51),
XRP(51)));
114 env(
offer(carol,
XRP(50), USD(50)));
115 env(
offer(carol,
XRP(50), USD(50)));
118 env(
offer(carol, BTC(1), USD(100)));
122 env(
pay(alice, bob, USD(100)),
127 env.require(
balance(bob, USD(100)));
129 !
isOffer(env, carol, BTC(1), USD(100)) &&
136 testcase(
"Removing Canceled Offers");
139 Env env{*
this, features};
141 auto const gw =
Account{
"gateway"};
142 auto const alice =
Account{
"alice"};
143 auto const USD = gw[
"USD"];
145 env.fund(
XRP(10000), alice, gw);
147 env.trust(USD(100), alice);
150 env(
pay(gw, alice, USD(50)));
153 auto const offer1Seq = env.seq(alice);
158 BEAST_EXPECT(
isOffer(env, alice,
XRP(500), USD(100)));
161 auto const offer2Seq = env.seq(alice);
163 env(
offer(alice,
XRP(300), USD(100)),
164 json(jss::OfferSequence, offer1Seq),
175 env(
offer(alice,
XRP(400), USD(200)),
176 json(jss::OfferSequence, offer1Seq),
185 auto const offer4Seq = env.seq(alice);
189 BEAST_EXPECT(
isOffer(env, alice,
XRP(222), USD(111)));
192 BEAST_EXPECT(env.seq(alice) == offer4Seq + 2);
194 BEAST_EXPECT(!
isOffer(env, alice,
XRP(222), USD(111)));
198 env.require(
offers(alice, 2));
202 bool const featPreauth{features[featureDepositPreauth]};
205 json(jss::OfferSequence, offer2Seq),
209 env.require(
offers(alice, 2));
210 BEAST_EXPECT(
isOffer(env, alice,
XRP(300), USD(100)));
211 BEAST_EXPECT(!
isOffer(env, alice,
XRP(5), USD(2)));
221 using namespace std::chrono_literals;
222 auto const alice =
Account{
"alice"};
223 auto const bob =
Account{
"bob"};
224 auto const carol =
Account{
"carol"};
227 auto const USD = gw[
"USD"];
228 auto const EUR = gw[
"EUR"];
230 Env env{*
this, features};
232 env.fund(
XRP(10000), alice, bob, carol, gw);
233 env.trust(USD(1000), alice, bob, carol);
234 env.trust(EUR(1000), alice, bob, carol);
235 env(
pay(gw, alice, USD(100)));
236 env(
pay(gw, carol, EUR(100)));
242 for (
int i = 0; i < 101; ++i)
243 env(
offer(carol, USD(1), EUR(2)));
269 using namespace std::chrono_literals;
270 auto const alice =
Account{
"alice"};
271 auto const bob =
Account{
"bob"};
272 auto const carol =
Account{
"carol"};
273 auto const dan =
Account{
"dan"};
274 auto const erin =
Account{
"erin"};
277 auto const USD = gw[
"USD"];
278 Env env{*
this, features};
280 env.fund(
XRP(10000), alice, bob, carol, dan, erin, gw);
282 env.trust(USD(1000), alice, bob, carol, dan, erin);
284 env(
pay(gw, carol, USD(0.99999)));
285 env(
pay(gw, dan, USD(1)));
286 env(
pay(gw, erin, USD(1)));
308 env(
pay(alice, bob, USD(1)),
323 testcase(
"Rm small increased q offers XRP");
331 using namespace std::chrono_literals;
332 auto const alice =
Account{
"alice"};
333 auto const bob =
Account{
"bob"};
334 auto const carol =
Account{
"carol"};
337 auto const USD = gw[
"USD"];
340 for (
auto crossBothOffers : {
false,
true})
342 Env env{*
this, features};
344 env.fund(
XRP(10000), alice, bob, carol, gw);
346 env.trust(USD(1000), alice, bob, carol);
348 auto initialCarolUSD = USD(0.499);
349 env(
pay(gw, carol, initialCarolUSD));
350 env(
pay(gw, bob, USD(100)));
362 auto aliceTakerGets = crossBothOffers ?
drops(2) :
drops(1);
363 env(
offer(alice, USD(1), aliceTakerGets));
366 if (features[fixRmSmallIncreasedQOffers])
401 for (
auto partialPayment : {
false,
true})
403 Env env{*
this, features};
405 env.fund(
XRP(10000), alice, bob, carol, gw);
407 env.trust(USD(1000), alice, bob, carol);
409 auto const initialCarolUSD = USD(0.999);
410 env(
pay(gw, carol, initialCarolUSD));
412 env(
pay(gw, bob, USD(100)));
424 TER const expectedTer =
427 env(
pay(alice, bob, USD(5)),
434 if (features[fixRmSmallIncreasedQOffers])
438 env.require(
offers(carol, 0));
455 env.require(
offers(carol, 0));
471 testcase(
"Rm small increased q offers IOU");
479 using namespace std::chrono_literals;
480 auto const alice =
Account{
"alice"};
481 auto const bob =
Account{
"bob"};
482 auto const carol =
Account{
"carol"};
485 auto const USD = gw[
"USD"];
486 auto const EUR = gw[
"EUR"];
497 for (
auto crossBothOffers : {
false,
true})
499 Env env{*
this, features};
501 env.fund(
XRP(10000), alice, bob, carol, gw);
503 env.trust(USD(1000), alice, bob, carol);
504 env.trust(EUR(1000), alice, bob, carol);
506 auto initialCarolUSD = tinyAmount(USD);
507 env(
pay(gw, carol, initialCarolUSD));
508 env(
pay(gw, bob, USD(100)));
509 env(
pay(gw, alice, EUR(100)));
512 env(
offer(carol, EUR(1), USD(10)));
522 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
523 env(
offer(alice, USD(1), aliceTakerGets));
526 if (features[fixRmSmallIncreasedQOffers])
561 for (
auto partialPayment : {
false,
true})
563 Env env{*
this, features};
565 env.fund(
XRP(10000), alice, bob, carol, gw);
567 env.trust(USD(1000), alice, bob, carol);
568 env.trust(EUR(1000), alice, bob, carol);
571 auto const initialCarolUSD = tinyAmount(USD);
572 env(
pay(gw, carol, initialCarolUSD));
573 env(
pay(gw, bob, USD(100)));
574 env(
pay(gw, alice, EUR(100)));
577 env(
offer(carol, EUR(1), USD(2)));
587 TER const expectedTer =
590 env(
pay(alice, bob, USD(5)),
597 if (features[fixRmSmallIncreasedQOffers])
601 env.require(
offers(carol, 0));
618 env.require(
offers(carol, 0));
625 BEAST_EXPECT(
isOffer(env, carol, EUR(1), USD(2)));
638 auto const gw =
Account{
"gateway"};
639 auto const USD = gw[
"USD"];
640 auto const BTC = gw[
"BTC"];
641 auto const EUR = gw[
"EUR"];
649 Env env{*
this, features};
651 auto const gw1 =
Account{
"gw1"};
652 auto const USD1 = gw1[
"USD"];
653 auto const gw2 =
Account{
"gw2"};
654 auto const USD2 = gw2[
"USD"];
656 env.fund(
XRP(10000), alice,
noripple(bob), carol, dan, gw1, gw2);
657 env.trust(USD1(1000), alice, carol, dan);
659 env.trust(USD2(1000), alice, carol, dan);
662 env(
pay(gw1, dan, USD1(50)));
663 env(
pay(gw1, bob, USD1(50)));
664 env(
pay(gw2, bob, USD2(50)));
668 env(
pay(alice, carol, USD2(50)),
676 Env env{*
this, features};
678 auto const gw1 =
Account{
"gw1"};
679 auto const USD1 = gw1[
"USD"];
680 auto const gw2 =
Account{
"gw2"};
681 auto const USD2 = gw2[
"USD"];
683 env.fund(
XRP(10000), alice, bob, carol, dan, gw1, gw2);
684 env.trust(USD1(1000), alice, bob, carol, dan);
685 env.trust(USD2(1000), alice, bob, carol, dan);
687 env(
pay(gw1, dan, USD1(50)));
688 env(
pay(gw1, bob, USD1(50)));
689 env(
pay(gw2, bob, USD2(50)));
693 env(
pay(alice, carol, USD2(50)),
699 env.require(
balance(bob, USD1(100)));
700 env.require(
balance(bob, USD2(0)));
701 env.require(
balance(carol, USD2(50)));
718 auto const gw =
Account{
"gateway"};
719 auto const alice =
Account{
"alice"};
720 auto const bob =
Account{
"bob"};
721 auto const carol =
Account{
"carol"};
722 auto const USD = gw[
"USD"];
724 auto const usdOffer = USD(1000);
725 auto const xrpOffer =
XRP(1000);
729 Env env{*
this, features};
731 env.fund(
XRP(1000000), gw);
733 auto const f = env.current()->fees().base;
734 auto const r =
reserve(env, 0);
736 env.fund(r + f, alice);
747 Env env{*
this, features};
749 env.fund(
XRP(1000000), gw);
751 auto const f = env.current()->fees().base;
752 auto const r =
reserve(env, 0);
754 auto const usdOffer2 = USD(500);
755 auto const xrpOffer2 =
XRP(500);
757 env.fund(r + f + xrpOffer, bob);
759 env.fund(r + f, alice);
765 balance(alice, r - f + xrpOffer2),
777 Env env{*
this, features};
779 env.fund(
XRP(1000000), gw);
781 auto const f = env.current()->fees().base;
782 auto const r =
reserve(env, 0);
784 auto const usdOffer2 = USD(500);
785 auto const xrpOffer2 =
XRP(500);
787 env.fund(r + f + xrpOffer, bob, carol);
791 env.fund(r + f, alice);
797 balance(alice, r - f + xrpOffer),
818 if (sle->getType() == ltOFFER)
819 result.push_back(sle);
831 auto const startBalance =
XRP(1000000);
832 auto const gw =
Account{
"gateway"};
833 auto const alice =
Account{
"alice"};
834 auto const bob =
Account{
"bob"};
835 auto const USD = gw[
"USD"];
843 for (
auto const& tweakedFeatures :
844 {features - fix1578, features | fix1578})
846 Env env{*
this, tweakedFeatures};
848 auto const f = env.
current()->fees().base;
850 env.fund(startBalance, gw, alice, bob);
871 TER const killedCode{
874 env(
offer(alice,
XRP(1000), USD(1000)),
879 balance(alice, startBalance - (f * 2)),
883 balance(bob, startBalance - (f * 2)),
889 env(
offer(alice,
XRP(500), USD(500)),
894 balance(alice, startBalance - (f * 3) +
XRP(500)),
898 balance(bob, startBalance - (f * 2) -
XRP(500)),
907 Env env{*
this, features};
909 auto const f = env.current()->fees().base;
911 env.fund(startBalance, gw, alice, bob);
918 TER const expectedCode = features[featureImmediateOfferKilled]
921 env(
offer(alice,
XRP(1000), USD(1000)),
927 balance(alice, startBalance - f - f),
934 env(
offer(alice,
XRP(1000), USD(1000)),
939 balance(alice, startBalance - f - f - f +
XRP(50)),
955 balance(alice, startBalance - f - f - f - f +
XRP(100)),
959 balance(bob, startBalance - f - f -
XRP(100)),
967 Env env(*
this, features);
969 env.
fund(startBalance, gw, alice, bob);
972 env(
trust(bob, USD(1000)));
975 env(
pay(gw, bob, USD(1000)));
978 env(
offer(alice, USD(1000),
XRP(2000)));
982 BEAST_EXPECT(aliceOffers.size() == 1);
983 for (
auto offerPtr : aliceOffers)
985 auto const&
offer = *offerPtr;
986 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(2000));
987 BEAST_EXPECT(
offer[sfTakerPays] == USD(1000));
997 BEAST_EXPECT(bobOffers.size() == 1);
998 for (
auto offerPtr : bobOffers)
1000 auto const&
offer = *offerPtr;
1001 BEAST_EXPECT(
offer[sfTakerGets] == USD(1000));
1002 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(2000));
1006 env(
offer(gw,
XRP(2000), USD(1000)));
1012 env(
offer(gw, USD(1000),
XRP(2000)));
1020 Env env(*
this, features);
1022 env.
fund(startBalance, gw,
"alice",
"bob");
1025 env(
trust(
"bob", USD(1000)));
1028 env(
pay(gw,
"bob", USD(1000)));
1029 env(
offer(
"alice", USD(500),
XRP(1001)));
1032 env(
offer(
"alice", USD(500),
XRP(1000)));
1036 BEAST_EXPECT(aliceOffers.size() == 2);
1046 BEAST_EXPECT(bobOffers.size() == 1);
1047 for (
auto offerPtr : bobOffers)
1049 auto const&
offer = *offerPtr;
1050 BEAST_EXPECT(
offer[sfTakerGets] == USD(499.5));
1051 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(999));
1061 using namespace jtx;
1063 auto const startBalance =
XRP(1000000);
1064 auto const gw =
Account{
"gateway"};
1065 auto const alice =
Account{
"alice"};
1066 auto const USD = gw[
"USD"];
1068 Env env{*
this, features};
1070 env.fund(startBalance, gw, alice);
1073 env(
offer(alice, USD(1000),
XRP(1000)),
1080 env(
offer(alice, USD(1000),
XRP(1000)),
1110 env(
offer(alice, USD(1000),
XRP(1000)),
1118 env(
offer(alice, USD(1000),
XRP(1000)),
1138 using namespace jtx;
1140 auto const gw =
Account{
"gateway"};
1141 auto const alice =
Account{
"alice"};
1142 auto const bob =
Account{
"bob"};
1143 auto const USD = gw[
"USD"];
1145 auto const startBalance =
XRP(1000000);
1146 auto const usdOffer = USD(1000);
1147 auto const xrpOffer =
XRP(1000);
1149 Env env{*
this, features};
1151 env.fund(startBalance, gw, alice, bob);
1154 auto const f = env.current()->fees().base;
1160 balance(alice, startBalance - f),
1167 bool const featPreauth{features[featureDepositPreauth]};
1169 env(
offer(alice, xrpOffer, usdOffer),
1174 balance(alice, startBalance - f - f),
1181 env(
offer(alice, xrpOffer, usdOffer),
1185 balance(alice, startBalance - f - f - f),
1193 balance(alice, startBalance - f - f - f),
1201 balance(alice, startBalance - f - f - f),
1205 balance(bob, startBalance - f),
1216 using namespace jtx;
1218 auto const gw =
Account{
"gateway"};
1219 auto const USD = gw[
"USD"];
1221 auto const usdOffer = USD(1000);
1222 auto const xrpOffer =
XRP(1000);
1224 Env env{*
this, features};
1226 env.fund(
XRP(1000000), gw);
1229 auto const f = env.current()->fees().base;
1233 env.fund(
reserve(env, 0),
"alice");
1239 env.fund(
reserve(env, 0) + f,
"bob");
1246 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1253 env.fund(
reserve(env, 1) + f,
"dan");
1259 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1270 (use_partner ?
", with partner account" :
""));
1272 using namespace jtx;
1274 auto const gw =
Account{
"gateway"};
1275 auto const partner =
Account{
"partner"};
1276 auto const USD = gw[
"USD"];
1277 auto const BTC = gw[
"BTC"];
1279 Env env{*
this, features};
1282 env.fund(
XRP(10000), gw);
1285 env.fund(
XRP(10000), partner);
1286 env(
trust(partner, USD(100)));
1287 env(
trust(partner, BTC(500)));
1288 env(
pay(gw, partner, USD(100)));
1289 env(
pay(gw, partner, BTC(500)));
1291 auto const& account_to_test = use_partner ? partner : gw;
1294 env.require(
offers(account_to_test, 0));
1299 env(
offer(account_to_test, BTC(250),
XRP(1000)));
1300 env.require(
offers(account_to_test, 1));
1303 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1305 auto const secondLegSeq = env.seq(account_to_test);
1306 env(
offer(account_to_test,
XRP(1000), USD(50)));
1307 env.require(
offers(account_to_test, 2));
1310 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1314 env(
offer(account_to_test, USD(50), BTC(250)));
1317 BEAST_EXPECT(jrr[jss::offers].isArray());
1318 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1321 BEAST_EXPECT(jrr[jss::offers].isArray());
1322 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1333 bool const noStaleOffers{
1334 features[featureFlowCross] ||
1335 features[fixTakerDryOfferRemoval]};
1337 BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
1338 for (
auto const& offerPtr : acctOffers)
1340 auto const&
offer = *offerPtr;
1341 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
1342 BEAST_EXPECT(
offer[sfTakerGets] == USD(0));
1343 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(0));
1351 env.require(
offers(account_to_test, 0));
1356 env(
offer(account_to_test, BTC(250), USD(50)));
1357 env.require(
offers(account_to_test, 1));
1361 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1364 BEAST_EXPECT(jrr[jss::offers].isArray());
1365 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1369 env(
offer(account_to_test, USD(50), BTC(250)));
1370 env.require(
offers(account_to_test, 1));
1375 BEAST_EXPECT(jrr[jss::offers].isArray());
1376 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1378 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1388 using namespace jtx;
1393 {features - fixReducedOffersV2, features | fixReducedOffersV2})
1395 Env env{*
this, localFeatures};
1397 auto const gw =
Account{
"gateway"};
1398 auto const alice =
Account{
"alice"};
1399 auto const bob =
Account{
"bob"};
1400 auto const USD = gw[
"USD"];
1401 auto const BTC = gw[
"BTC"];
1405 auto const gw_initial_balance =
drops(1149999730);
1406 auto const alice_initial_balance =
drops(499946999680);
1407 auto const bob_initial_balance =
drops(10199999920);
1408 auto const small_amount =
1409 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1411 env.fund(gw_initial_balance, gw);
1412 env.fund(alice_initial_balance, alice);
1413 env.fund(bob_initial_balance, bob);
1415 env(
rate(gw, 1.005));
1417 env(
trust(alice, USD(500)));
1418 env(
trust(bob, USD(50)));
1419 env(
trust(gw, alice[
"USD"](100)));
1421 env(
pay(gw, alice, alice[
"USD"](50)));
1422 env(
pay(gw, bob, small_amount));
1424 env(
offer(alice, USD(50),
XRP(150000)));
1427 env(
pay(alice, gw, USD(100)));
1430 env(
trust(gw, alice[
"USD"](0)));
1435 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1439 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1440 "-2710505431213761e-33");
1444 env(
offer(bob,
XRP(2000), USD(1)));
1446 if (localFeatures[featureFlowCross] &&
1447 localFeatures[fixReducedOffersV2])
1454 jrr[jss::node][sfBalance.fieldName][jss::value] ==
1455 "-2710505431213761e-33");
1459 BEAST_EXPECT(bobOffer[sfTakerGets.jsonName][jss::value] ==
"1");
1460 BEAST_EXPECT(bobOffer[sfTakerPays.jsonName] ==
"2000000000");
1471 auto const crossingDelta =
1472 localFeatures[featureFlowCross] ?
drops(1) :
drops(0);
1476 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"50");
1479 alice_initial_balance - env.current()->fees().base * 3 -
1484 jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1487 bob_initial_balance - env.current()->fees().base * 2 +
1497 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1499 using namespace jtx;
1501 Env env{*
this, features};
1503 auto const gw =
Account{
"gateway"};
1504 auto const alice =
Account{
"alice"};
1505 auto const bob =
Account{
"bob"};
1506 auto const USD = gw[
"USD"];
1508 env.fund(
XRP(10000), gw, alice, bob);
1510 env(
trust(alice, USD(1000)));
1511 env(
trust(bob, USD(1000)));
1513 env(
pay(gw, alice, alice[
"USD"](500)));
1516 env(
offer(bob, USD(1),
XRP(4000)));
1518 env(
offer(alice,
XRP(150000), USD(50)));
1521 env(
offer(bob, USD(1),
XRP(4000)));
1528 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1531 jrr[jss::node][sfBalance.fieldName] ==
1533 env.current()->fees().base * 2)
1537 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1540 jrr[jss::node][sfBalance.fieldName] ==
1542 env.current()->fees().base * 2)
1549 testcase(
"Offer Crossing with Limit Override");
1551 using namespace jtx;
1553 Env env{*
this, features};
1555 auto const gw =
Account{
"gateway"};
1556 auto const alice =
Account{
"alice"};
1557 auto const bob =
Account{
"bob"};
1558 auto const USD = gw[
"USD"];
1560 env.fund(
XRP(100000), gw, alice, bob);
1562 env(
trust(alice, USD(1000)));
1564 env(
pay(gw, alice, alice[
"USD"](500)));
1566 env(
offer(alice,
XRP(150000), USD(50)));
1567 env(
offer(bob, USD(1),
XRP(3000)));
1570 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-1");
1573 jrr[jss::node][sfBalance.fieldName] ==
1578 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-499");
1581 jrr[jss::node][sfBalance.fieldName] ==
1589 testcase(
"Offer Accept then Cancel.");
1591 using namespace jtx;
1593 Env env{*
this, features};
1595 auto const USD = env.master[
"USD"];
1597 auto const nextOfferSeq = env.seq(env.master);
1598 env(
offer(env.master,
XRP(500), USD(100)));
1602 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1607 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1613 testcase(
"Offer Cancel Past and Future Sequence.");
1615 using namespace jtx;
1617 Env env{*
this, features};
1619 auto const alice =
Account{
"alice"};
1621 auto const nextOfferSeq = env.seq(env.master);
1622 env.fund(
XRP(10000), alice);
1638 testcase(
"Currency Conversion: Entire Offer");
1640 using namespace jtx;
1642 Env env{*
this, features};
1644 auto const gw =
Account{
"gateway"};
1645 auto const alice =
Account{
"alice"};
1646 auto const bob =
Account{
"bob"};
1647 auto const USD = gw[
"USD"];
1649 env.fund(
XRP(10000), gw, alice, bob);
1650 env.require(
owners(bob, 0));
1652 env(
trust(alice, USD(100)));
1653 env(
trust(bob, USD(1000)));
1657 env(
pay(gw, alice, alice[
"USD"](100)));
1658 auto const bobOfferSeq = env.seq(bob);
1659 env(
offer(bob, USD(100),
XRP(500)));
1664 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1666 jro[jss::node][jss::TakerPays] ==
1672 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"0");
1675 jrr[jss::node][sfBalance.fieldName] ==
1680 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1683 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1691 testcase(
"Currency Conversion: Offerer Into Debt");
1693 using namespace jtx;
1695 Env env{*
this, features};
1697 auto const alice =
Account{
"alice"};
1698 auto const bob =
Account{
"bob"};
1699 auto const carol =
Account{
"carol"};
1701 env.fund(
XRP(10000), alice, bob, carol);
1703 env(
trust(alice, carol[
"EUR"](2000)));
1704 env(
trust(bob, alice[
"USD"](100)));
1705 env(
trust(carol, bob[
"EUR"](1000)));
1707 auto const bobOfferSeq = env.seq(bob);
1708 env(
offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1711 env(
offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1714 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1720 testcase(
"Currency Conversion: In Parts");
1722 using namespace jtx;
1724 Env env{*
this, features};
1726 auto const gw =
Account{
"gateway"};
1727 auto const alice =
Account{
"alice"};
1728 auto const bob =
Account{
"bob"};
1729 auto const USD = gw[
"USD"];
1731 env.fund(
XRP(10000), gw, alice, bob);
1733 env(
trust(alice, USD(200)));
1734 env(
trust(bob, USD(1000)));
1736 env(
pay(gw, alice, alice[
"USD"](200)));
1738 auto const bobOfferSeq = env.seq(bob);
1739 env(
offer(bob, USD(100),
XRP(500)));
1746 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1748 jro[jss::node][jss::TakerPays] ==
1754 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-160");
1758 jrr[jss::node][sfBalance.fieldName] ==
1764 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-40");
1768 env(
pay(alice, alice,
XRP(600)),
1774 env(
pay(alice, alice,
XRP(600)),
1780 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1788 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1791 jrr[jss::node][sfBalance.fieldName] ==
1793 env.current()->fees().base * 4)
1799 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
1805 testcase(
"Cross Currency Payment: Start with XRP");
1807 using namespace jtx;
1809 Env env{*
this, features};
1811 auto const gw =
Account{
"gateway"};
1812 auto const alice =
Account{
"alice"};
1813 auto const bob =
Account{
"bob"};
1814 auto const carol =
Account{
"carol"};
1815 auto const USD = gw[
"USD"];
1817 env.fund(
XRP(10000), gw, alice, bob, carol);
1819 env(
trust(carol, USD(1000)));
1820 env(
trust(bob, USD(2000)));
1822 env(
pay(gw, carol, carol[
"USD"](500)));
1824 auto const carolOfferSeq = env.seq(carol);
1825 env(
offer(carol,
XRP(500), USD(50)));
1830 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1833 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1837 jro[jss::node][jss::TakerGets] ==
1840 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1846 testcase(
"Cross Currency Payment: End with XRP");
1848 using namespace jtx;
1850 Env env{*
this, features};
1852 auto const gw =
Account{
"gateway"};
1853 auto const alice =
Account{
"alice"};
1854 auto const bob =
Account{
"bob"};
1855 auto const carol =
Account{
"carol"};
1856 auto const USD = gw[
"USD"];
1858 env.fund(
XRP(10000), gw, alice, bob, carol);
1860 env(
trust(alice, USD(1000)));
1861 env(
trust(carol, USD(2000)));
1863 env(
pay(gw, alice, alice[
"USD"](500)));
1865 auto const carolOfferSeq = env.seq(carol);
1866 env(
offer(carol, USD(50),
XRP(500)));
1871 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-475");
1874 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-25");
1878 jrr[jss::node][sfBalance.fieldName] ==
1880 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1884 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1886 jro[jss::node][jss::TakerPays] ==
1893 testcase(
"Cross Currency Payment: Bridged");
1895 using namespace jtx;
1897 Env env{*
this, features};
1899 auto const gw1 =
Account{
"gateway_1"};
1900 auto const gw2 =
Account{
"gateway_2"};
1901 auto const alice =
Account{
"alice"};
1902 auto const bob =
Account{
"bob"};
1903 auto const carol =
Account{
"carol"};
1904 auto const dan =
Account{
"dan"};
1905 auto const USD = gw1[
"USD"];
1906 auto const EUR = gw2[
"EUR"];
1908 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1910 env(
trust(alice, USD(1000)));
1911 env(
trust(bob, EUR(1000)));
1912 env(
trust(carol, USD(1000)));
1913 env(
trust(dan, EUR(1000)));
1915 env(
pay(gw1, alice, alice[
"USD"](500)));
1916 env(
pay(gw2, dan, dan[
"EUR"](400)));
1918 auto const carolOfferSeq = env.seq(carol);
1919 env(
offer(carol, USD(50),
XRP(500)));
1921 auto const danOfferSeq = env.seq(dan);
1922 env(
offer(dan,
XRP(500), EUR(50)));
1925 jtp[0u][0u][jss::currency] =
"XRP";
1926 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1929 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"470");
1932 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1935 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-30");
1938 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-370");
1942 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1944 jro[jss::node][jss::TakerPays] ==
1949 jro[jss::node][jss::TakerGets] ==
1952 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1961 testcase(
"Auto Bridged Second Leg Dry");
1963 using namespace jtx;
1964 Env env(*
this, features);
1970 auto const USD = gw[
"USD"];
1971 auto const EUR = gw[
"EUR"];
1973 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1975 env.
trust(USD(10), alice);
1977 env(
pay(gw, alice, USD(10)));
1978 env.
trust(USD(10), carol);
1980 env(
pay(gw, carol, USD(3)));
1997 env.
trust(EUR(10), bob);
1999 env(
pay(gw, bob, EUR(10)));
2001 env(
offer(bob, USD(10), EUR(10)));
2018 int const emptyOfferCount{
2019 features[featureFlowCross] || features[fixTakerDryOfferRemoval]
2030 testcase(
"Offer Fees Consume Funds");
2032 using namespace jtx;
2034 Env env{*
this, features};
2036 auto const gw1 =
Account{
"gateway_1"};
2037 auto const gw2 =
Account{
"gateway_2"};
2038 auto const gw3 =
Account{
"gateway_3"};
2039 auto const alice =
Account{
"alice"};
2040 auto const bob =
Account{
"bob"};
2041 auto const USD1 = gw1[
"USD"];
2042 auto const USD2 = gw2[
"USD"];
2043 auto const USD3 = gw3[
"USD"];
2051 auto const starting_xrp =
XRP(100) +
2052 env.current()->fees().accountReserve(3) +
2053 env.current()->fees().base * 4;
2055 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2057 env(
trust(alice, USD1(1000)));
2058 env(
trust(alice, USD2(1000)));
2059 env(
trust(alice, USD3(1000)));
2060 env(
trust(bob, USD1(1000)));
2061 env(
trust(bob, USD2(1000)));
2063 env(
pay(gw1, bob, bob[
"USD"](500)));
2065 env(
offer(bob,
XRP(200), USD1(200)));
2068 env(
offer(alice, USD1(200),
XRP(200)));
2071 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"100");
2074 jrr[jss::node][sfBalance.fieldName] ==
2078 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2084 testcase(
"Offer Create, then Cross");
2086 using namespace jtx;
2088 for (
auto NumberSwitchOver : {
false,
true})
2090 Env env{*
this, features};
2091 if (NumberSwitchOver)
2092 env.enableFeature(fixUniversalNumber);
2094 env.disableFeature(fixUniversalNumber);
2096 auto const gw =
Account{
"gateway"};
2097 auto const alice =
Account{
"alice"};
2098 auto const bob =
Account{
"bob"};
2099 auto const USD = gw[
"USD"];
2101 env.fund(
XRP(10000), gw, alice, bob);
2103 env(
rate(gw, 1.005));
2105 env(
trust(alice, USD(1000)));
2106 env(
trust(bob, USD(1000)));
2107 env(
trust(gw, alice[
"USD"](50)));
2109 env(
pay(gw, bob, bob[
"USD"](1)));
2110 env(
pay(alice, gw, USD(50)));
2112 env(
trust(gw, alice[
"USD"](0)));
2114 env(
offer(alice, USD(50),
XRP(150000)));
2115 env(
offer(bob,
XRP(100), USD(0.1)));
2119 jrr[jss::node][sfBalance.fieldName][jss::value] ==
2120 "49.96666666666667");
2124 jrr[jss::node][sfBalance.fieldName][jss::value];
2125 if (!NumberSwitchOver)
2127 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2131 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2139 testcase(
"Offer tfSell: Basic Sell");
2141 using namespace jtx;
2143 Env env{*
this, features};
2145 auto const gw =
Account{
"gateway"};
2146 auto const alice =
Account{
"alice"};
2147 auto const bob =
Account{
"bob"};
2148 auto const USD = gw[
"USD"];
2150 auto const starting_xrp =
XRP(100) +
2151 env.current()->fees().accountReserve(1) +
2152 env.current()->fees().base * 2;
2154 env.fund(starting_xrp, gw, alice, bob);
2156 env(
trust(alice, USD(1000)));
2157 env(
trust(bob, USD(1000)));
2159 env(
pay(gw, bob, bob[
"USD"](500)));
2168 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-100");
2171 jrr[jss::node][sfBalance.fieldName] ==
2175 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-400");
2181 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2183 using namespace jtx;
2185 Env env{*
this, features};
2187 auto const gw =
Account{
"gateway"};
2188 auto const alice =
Account{
"alice"};
2189 auto const bob =
Account{
"bob"};
2190 auto const USD = gw[
"USD"];
2192 auto const starting_xrp =
XRP(100) +
2193 env.current()->fees().accountReserve(1) +
2194 env.current()->fees().base * 2;
2196 env.fund(starting_xrp, gw, alice, bob);
2198 env(
trust(alice, USD(150)));
2199 env(
trust(bob, USD(1000)));
2201 env(
pay(gw, bob, bob[
"USD"](500)));
2203 env(
offer(bob,
XRP(100), USD(200)));
2212 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-200");
2215 jrr[jss::node][sfBalance.fieldName] ==
2219 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-300");
2225 testcase(
"Client Issue #535: Gateway Cross Currency");
2227 using namespace jtx;
2229 Env env{*
this, features};
2231 auto const gw =
Account{
"gateway"};
2232 auto const alice =
Account{
"alice"};
2233 auto const bob =
Account{
"bob"};
2234 auto const XTS = gw[
"XTS"];
2235 auto const XXX = gw[
"XXX"];
2237 auto const starting_xrp =
XRP(100.1) +
2238 env.current()->fees().accountReserve(1) +
2239 env.current()->fees().base * 2;
2241 env.fund(starting_xrp, gw, alice, bob);
2243 env(
trust(alice, XTS(1000)));
2244 env(
trust(alice, XXX(1000)));
2245 env(
trust(bob, XTS(1000)));
2246 env(
trust(bob, XXX(1000)));
2248 env(
pay(gw, alice, alice[
"XTS"](100)));
2249 env(
pay(gw, alice, alice[
"XXX"](100)));
2250 env(
pay(gw, bob, bob[
"XTS"](100)));
2251 env(
pay(gw, bob, bob[
"XXX"](100)));
2253 env(
offer(alice, XTS(100), XXX(100)));
2260 payment[jss::id] = env.seq(bob);
2261 payment[jss::build_path] =
true;
2262 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2263 payment[jss::tx_json][jss::Sequence] =
2266 ->getFieldU32(sfSequence);
2267 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2268 payment[jss::tx_json][jss::SendMax] =
2270 auto jrr = wsc->invoke(
"submit", payment);
2271 BEAST_EXPECT(jrr[jss::status] ==
"success");
2272 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2273 if (wsc->version() == 2)
2276 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2278 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2279 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2283 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2285 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2288 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-99");
2290 BEAST_EXPECT(jrr[jss::node][sfBalance.fieldName][jss::value] ==
"-101");
2305 auto const sleTrust =
2307 BEAST_EXPECT(sleTrust);
2311 bool const accountLow = account.id() < issue.
account;
2316 low.setIssuer(accountLow ? account.id() : issue.
account);
2317 high.setIssuer(accountLow ? issue.
account : account.id());
2319 BEAST_EXPECT(sleTrust->getFieldAmount(sfLowLimit) == low);
2320 BEAST_EXPECT(sleTrust->getFieldAmount(sfHighLimit) == high);
2322 STAmount actualBalance{sleTrust->getFieldAmount(sfBalance)};
2326 BEAST_EXPECT(actualBalance == expectBalance);
2338 using namespace jtx;
2340 auto const gw =
Account(
"gateway");
2341 auto const USD = gw[
"USD"];
2343 Env env{*
this, features};
2345 env.fund(
XRP(10000000), gw);
2348 auto const f = env.current()->fees().base;
2351 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2357 preTrustType preTrust;
2367 TestData
const tests[]{
2369 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2370 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2371 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2372 {
"deb",
reserve(env, 0) + 2 * f, 1, noPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 1},
2373 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2374 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2375 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2376 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2377 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2378 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2379 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2380 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2381 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2382 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2383 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2384 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2385 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2386 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2388 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2389 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2390 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2391 {
"dan",
reserve(env, 0) + 2 * f, 1, gwPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 0},
2392 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2393 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2394 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2395 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2397 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2398 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2399 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2400 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2401 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2402 {
"syd",
reserve(env, 1) + 3 * f, 1, acctPreTrust, 1000,
tesSUCCESS, 3 * f, USD(0.00001), 0, 1},
2403 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2404 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2405 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2406 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2407 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2411 for (
auto const& t : tests)
2413 auto const acct =
Account(t.account);
2414 env.fund(t.fundXrp, acct);
2418 env.require(
offers(gw, 0));
2421 auto const book = t.bookAmount;
2423 env(
offer(gw,
XRP(book), USD(book)));
2428 if (t.preTrust == gwPreTrust)
2429 env(
trust(gw, acct[
"USD"](1)));
2434 if (t.preTrust == acctPreTrust)
2435 env(
trust(acct, USD(1)));
2441 auto const acctOffer = t.offerAmount;
2442 env(
offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2447 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2449 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2450 env.require(
offers(acct, t.offers));
2451 env.require(
owners(acct, t.owners));
2454 BEAST_EXPECT(acctOffers.size() == t.offers);
2455 if (acctOffers.size() && t.offers)
2457 auto const& acctOffer = *(acctOffers.front());
2459 auto const leftover = t.offerAmount - t.bookAmount;
2460 BEAST_EXPECT(acctOffer[sfTakerGets] ==
XRP(leftover));
2461 BEAST_EXPECT(acctOffer[sfTakerPays] == USD(leftover));
2464 if (t.preTrust == noPreTrust)
2466 if (t.balanceUsd.value().signum())
2474 auto const sleTrust =
2476 BEAST_EXPECT(!sleTrust);
2493 using namespace jtx;
2495 auto const gw =
Account(
"gateway");
2496 auto const alice =
Account(
"alice");
2497 auto const bob =
Account(
"bob");
2498 auto const USD = gw[
"USD"];
2500 auto const usdOffer = USD(1000);
2501 auto const xrpOffer =
XRP(1000);
2503 Env env{*
this, features};
2505 env.fund(
XRP(1000000), gw, bob);
2509 auto const fee = env.current()->fees().base;
2516 env(
trust(alice, usdOffer));
2520 env(
pay(gw, alice, usdOffer));
2527 auto const alicesXRP = env.balance(alice);
2528 auto const bobsXRP = env.balance(bob);
2530 env(
offer(alice, xrpOffer, usdOffer));
2532 env(
offer(bob, usdOffer, xrpOffer));
2546 env(
offer(alice, USD(999),
XRP(999)));
2547 env(
offer(bob, xrpOffer, usdOffer));
2550 env.require(
balance(alice, USD(999)));
2551 env.require(
balance(bob, USD(1)));
2552 env.require(
offers(alice, 0));
2556 BEAST_EXPECT(bobsOffers.size() == 1);
2557 auto const& bobsOffer = *(bobsOffers.front());
2559 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2560 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2561 BEAST_EXPECT(bobsOffer[sfTakerPays] ==
XRP(1));
2570 using namespace jtx;
2572 auto const gw =
Account(
"gateway");
2573 auto const alice =
Account(
"alice");
2574 auto const bob =
Account(
"bob");
2575 auto const USD = gw[
"USD"];
2576 auto const EUR = gw[
"EUR"];
2578 auto const usdOffer = USD(1000);
2579 auto const eurOffer = EUR(1000);
2581 Env env{*
this, features};
2583 env.fund(
XRP(1000000), gw);
2587 auto const fee = env.current()->fees().base;
2595 env(
trust(alice, usdOffer));
2596 env(
trust(bob, eurOffer));
2599 env(
pay(gw, alice, usdOffer));
2600 env(
pay(gw, bob, eurOffer));
2608 env(
offer(alice, eurOffer, usdOffer));
2609 env(
offer(bob, usdOffer, eurOffer));
2626 env(
offer(bob, eurOffer, usdOffer));
2629 env(
offer(alice, USD(999), eurOffer));
2632 env.require(
offers(alice, 0));
2633 env.require(
offers(bob, 1));
2635 env.require(
balance(alice, USD(999)));
2636 env.require(
balance(alice, EUR(1)));
2637 env.require(
balance(bob, USD(1)));
2638 env.require(
balance(bob, EUR(999)));
2642 if (BEAST_EXPECT(bobsOffers.size() == 1))
2644 auto const& bobsOffer = *(bobsOffers.front());
2646 BEAST_EXPECT(bobsOffer[sfTakerGets] == USD(1));
2647 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(1));
2652 env(
offer(alice, USD(1), EUR(1)));
2655 env.require(
balance(alice, USD(1000)));
2658 env.require(
balance(bob, EUR(1000)));
2659 env.require(
offers(alice, 0));
2660 env.require(
offers(bob, 0));
2663 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2664 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2668 env(
offer(alice, EUR(999), usdOffer));
2671 env(
offer(bob, usdOffer, eurOffer));
2674 env.require(
offers(alice, 0));
2675 env.require(
offers(bob, 0));
2677 env.require(
balance(alice, USD(0)));
2678 env.require(
balance(alice, EUR(999)));
2679 env.require(
balance(bob, USD(1000)));
2680 env.require(
balance(bob, EUR(1)));
2688 using namespace jtx;
2690 auto const gw =
Account(
"gateway");
2691 auto const alice =
Account(
"alice");
2692 auto const bob =
Account(
"bob");
2693 auto const carol =
Account(
"carol");
2694 auto const USD = gw[
"USD"];
2695 auto const EUR = gw[
"EUR"];
2697 auto const usdOffer = USD(1000);
2698 auto const eurOffer = EUR(1000);
2700 Env env{*
this, features};
2702 env.fund(
XRP(1000000), gw, alice, bob, carol);
2705 env(
trust(alice, usdOffer));
2706 env(
trust(carol, eurOffer));
2708 env(
pay(gw, alice, usdOffer));
2709 env(
pay(gw, carol, eurOffer));
2718 env(
offer(alice,
XRP(1000), usdOffer));
2719 env(
offer(bob, eurOffer,
XRP(1000)));
2720 auto const bobXrpBalance = env.balance(bob);
2724 env(
offer(carol, USD(400), EUR(400)));
2737 BEAST_EXPECT(alicesOffers.size() == 1);
2738 auto const& alicesOffer = *(alicesOffers.front());
2740 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2741 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(600));
2742 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(600));
2746 BEAST_EXPECT(bobsOffers.size() == 1);
2747 auto const& bobsOffer = *(bobsOffers.front());
2749 BEAST_EXPECT(bobsOffer[sfLedgerEntryType] == ltOFFER);
2750 BEAST_EXPECT(bobsOffer[sfTakerGets] ==
XRP(600));
2751 BEAST_EXPECT(bobsOffer[sfTakerPays] == EUR(600));
2755 env(
offer(carol, USD(600), EUR(600)));
2770 if (alicesOffers.size() != 0)
2772 BEAST_EXPECT(alicesOffers.size() == 1);
2773 auto const& alicesOffer = *(alicesOffers.front());
2775 BEAST_EXPECT(alicesOffer[sfLedgerEntryType] == ltOFFER);
2776 BEAST_EXPECT(alicesOffer[sfTakerGets] == USD(0));
2777 BEAST_EXPECT(alicesOffer[sfTakerPays] ==
XRP(0));
2789 using namespace jtx;
2791 auto const gw =
Account(
"gateway");
2792 auto const USD = gw[
"USD"];
2794 Env env{*
this, features};
2796 env.fund(
XRP(10000000), gw);
2799 auto const f = env.current()->fees().base;
2802 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2836 : account(std::move(account_))
2841 , acctGets(acctGets_)
2842 , acctPays(acctPays_)
2844 , spentXrp(spentXrp_)
2845 , finalUsd(finalUsd_)
2848 , takerGets(takerGets_)
2849 , takerPays(takerPays_)
2868 std::move(account_),
2887 TestData
const tests[]{
2890 {
"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},
2891 {
"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)},
2892 {
"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},
2893 {
"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},
2894 {
"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},
2895 {
"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},
2896 {
"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},
2897 {
"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)},
2899 {
"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},
2900 {
"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)},
2901 {
"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},
2902 {
"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},
2903 {
"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},
2904 {
"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)},
2905 {
"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)},
2909 auto const zeroUsd = USD(0);
2910 for (
auto const& t : tests)
2913 env.require(
offers(gw, 0));
2915 auto const acct =
Account(t.account);
2917 env.fund(t.fundXrp, acct);
2923 if (t.fundUSD != zeroUsd)
2925 env(
trust(acct, t.fundUSD));
2927 env(
pay(gw, acct, t.fundUSD));
2931 env(
offer(gw, t.gwGets, t.gwPays));
2941 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2943 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2944 env.require(
offers(acct, t.offers));
2945 env.require(
owners(acct, t.owners));
2950 if (acctOffers.size() > 0)
2952 BEAST_EXPECT(acctOffers.size() == 1);
2953 auto const& acctOffer = *(acctOffers.front());
2955 BEAST_EXPECT(acctOffer[sfLedgerEntryType] == ltOFFER);
2956 BEAST_EXPECT(acctOffer[sfTakerGets] == t.takerGets);
2957 BEAST_EXPECT(acctOffer[sfTakerPays] == t.takerPays);
2974 testcase(
"Combine tfSell with tfFillOrKill");
2976 using namespace jtx;
2978 auto const gw =
Account(
"gateway");
2979 auto const alice =
Account(
"alice");
2980 auto const bob =
Account(
"bob");
2981 auto const USD = gw[
"USD"];
2983 Env env{*
this, features};
2985 env.fund(
XRP(10000000), gw, alice, bob);
2988 TER const killedCode{
2992 env(
trust(bob, USD(200)));
2994 env(
pay(gw, bob, USD(100)));
2996 env(
offer(bob,
XRP(2000), USD(20)));
3004 env.require(
offers(alice, 0));
3005 env.require(
balance(bob, USD(100)));
3012 env.require(
balance(alice, USD(20)));
3013 env.require(
offers(alice, 0));
3014 env.require(
balance(bob, USD(80)));
3019 env(
offer(bob,
XRP(2000), USD(20)));
3023 env.require(
balance(alice, USD(35)));
3024 env.require(
offers(alice, 0));
3025 env.require(
balance(bob, USD(65)));
3037 env.require(
balance(alice, USD(35)));
3038 env.require(
offers(alice, 0));
3039 env.require(
balance(bob, USD(65)));
3048 env.require(
balance(alice, USD(40)));
3049 env.require(
offers(alice, 0));
3050 env.require(
balance(bob, USD(60)));
3059 using namespace jtx;
3061 auto const gw1 =
Account(
"gateway1");
3062 auto const USD = gw1[
"USD"];
3064 Env env{*
this, features};
3067 auto const fee = env.current()->fees().base;
3069 env.fund(
XRP(100000), gw1);
3072 env(
rate(gw1, 1.25));
3074 auto const ann =
Account(
"ann");
3075 auto const bob =
Account(
"bob");
3079 env(
trust(ann, USD(200)));
3080 env(
trust(bob, USD(200)));
3083 env(
pay(gw1, bob, USD(125)));
3098 env.require(
balance(ann, USD(100)));
3100 env.require(
offers(ann, 0));
3102 env.require(
balance(bob, USD(0)));
3104 env.require(
offers(bob, 0));
3109 auto const che =
Account(
"che");
3110 auto const deb =
Account(
"deb");
3114 env(
trust(che, USD(200)));
3115 env(
trust(deb, USD(200)));
3118 env(
pay(gw1, deb, USD(125)));
3127 env.require(
balance(che, USD(100)));
3129 env.require(
offers(che, 0));
3131 env.require(
balance(deb, USD(0)));
3133 env.require(
offers(deb, 0));
3136 auto const eve =
Account(
"eve");
3137 auto const fyn =
Account(
"fyn");
3139 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3142 env(
trust(eve, USD(1000)));
3143 env(
trust(fyn, USD(1000)));
3146 env(
pay(gw1, eve, USD(100)));
3147 env(
pay(gw1, fyn, USD(100)));
3153 env(
offer(eve, USD(10),
XRP(4000)));
3157 env(
offer(fyn,
XRP(2000), USD(5)));
3160 env.require(
balance(eve, USD(105)));
3163 BEAST_EXPECT(evesOffers.size() == 1);
3164 if (evesOffers.size() != 0)
3166 auto const& evesOffer = *(evesOffers.front());
3167 BEAST_EXPECT(evesOffer[sfLedgerEntryType] == ltOFFER);
3168 BEAST_EXPECT(evesOffer[sfTakerGets] ==
XRP(2000));
3169 BEAST_EXPECT(evesOffer[sfTakerPays] == USD(5));
3173 env.require(
balance(fyn, USD(93.75)));
3175 env.require(
offers(fyn, 0));
3178 auto const gw2 =
Account(
"gateway2");
3179 auto const EUR = gw2[
"EUR"];
3181 env.fund(
XRP(100000), gw2);
3184 env(
rate(gw2, 1.5));
3189 auto const gay =
Account(
"gay");
3190 auto const hal =
Account(
"hal");
3191 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3194 env(
trust(gay, USD(200)));
3195 env(
trust(gay, EUR(200)));
3196 env(
trust(hal, USD(200)));
3197 env(
trust(hal, EUR(200)));
3200 env(
pay(gw1, gay, USD(125)));
3201 env(
pay(gw2, hal, EUR(150)));
3204 env(
offer(gay, EUR(100), USD(100)));
3207 env(
offer(hal, USD(100), EUR(100)));
3210 env.require(
balance(gay, USD(0)));
3211 env.require(
balance(gay, EUR(100)));
3213 env.require(
offers(gay, 0));
3215 env.require(
balance(hal, USD(100)));
3216 env.require(
balance(hal, EUR(0)));
3218 env.require(
offers(hal, 0));
3222 auto const ivy =
Account(
"ivy");
3223 auto const joe =
Account(
"joe");
3224 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3233 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3234 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3236 env.require(
balance(ivy, USD(300)));
3237 env.require(
balance(joe, EUR(250)));
3239 env(
offer(ivy, EUR(100), USD(200)));
3242 env(
offer(joe, USD(200), EUR(100)));
3245 env.require(
balance(ivy, USD(50)));
3246 env.require(
balance(ivy, EUR(100)));
3248 env.require(
offers(ivy, 0));
3250 env.require(
balance(joe, USD(200)));
3251 env.require(
balance(joe, EUR(100)));
3253 env.require(
offers(joe, 0));
3257 auto const kim =
Account(
"kim");
3258 auto const K_BUX = kim[
"BUX"];
3259 auto const lex =
Account(
"lex");
3260 auto const meg =
Account(
"meg");
3261 auto const ned =
Account(
"ned");
3262 auto const N_BUX = ned[
"BUX"];
3265 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3268 env(
trust(lex, K_BUX(400)));
3270 env(
trust(meg, N_BUX(100)));
3272 env(
pay(ned, lex, N_BUX(100)));
3274 env.require(
balance(lex, N_BUX(100)));
3276 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3281 env.require(
balance(lex, K_BUX(72)));
3282 env.require(
balance(lex, N_BUX(40)));
3284 env.require(
balance(meg, N_BUX(60)));
3289 env(
offer(lex, K_BUX(30), N_BUX(30)));
3292 env(
offer(kim, N_BUX(30), K_BUX(30)));
3296 env.require(
balance(kim, N_BUX(30)));
3297 env.require(
balance(lex, K_BUX(102)));
3298 env.require(
balance(lex, N_BUX(10)));
3300 env.require(
balance(meg, N_BUX(60)));
3301 env.require(
balance(ned, K_BUX(-30)));
3306 auto const ova =
Account(
"ova");
3307 auto const pat =
Account(
"pat");
3308 auto const qae =
Account(
"qae");
3309 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3315 env(
trust(ova, USD(200)));
3316 env(
trust(ova, EUR(200)));
3317 env(
trust(pat, USD(200)));
3318 env(
trust(pat, EUR(200)));
3319 env(
trust(qae, USD(200)));
3320 env(
trust(qae, EUR(200)));
3323 env(
pay(gw1, ova, USD(125)));
3324 env(
pay(gw2, qae, EUR(150)));
3331 env(
offer(qae, USD(100), EUR(100)));
3334 env.require(
balance(ova, USD(0)));
3335 env.require(
balance(ova, EUR(0)));
3340 if (ovasOffers.size() != 0)
3342 BEAST_EXPECT(ovasOffers.size() == 1);
3343 auto const& ovasOffer = *(ovasOffers.front());
3345 BEAST_EXPECT(ovasOffer[sfLedgerEntryType] == ltOFFER);
3346 BEAST_EXPECT(ovasOffer[sfTakerGets] == USD(0));
3347 BEAST_EXPECT(ovasOffer[sfTakerPays] ==
XRP(0));
3350 env.require(
balance(pat, USD(0)));
3351 env.require(
balance(pat, EUR(100)));
3353 env.require(
offers(pat, 0));
3355 env.require(
balance(qae, USD(100)));
3356 env.require(
balance(qae, EUR(0)));
3358 env.require(
offers(qae, 0));
3379 using namespace jtx;
3381 auto const gw =
Account(
"gateway");
3382 auto const USD = gw[
"USD"];
3384 Env env{*
this, features};
3387 auto const fee = env.current()->fees().base;
3388 auto const startBalance =
XRP(1000000);
3390 env.fund(startBalance + (
fee * 4), gw);
3400 env.require(
owners(gw, 3));
3401 env.require(
balance(gw, startBalance +
fee));
3404 BEAST_EXPECT(gwOffers.size() == 3);
3405 for (
auto const& offerPtr : gwOffers)
3407 auto const&
offer = *offerPtr;
3408 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3409 BEAST_EXPECT(
offer[sfTakerGets] ==
XRP(600));
3410 BEAST_EXPECT(
offer[sfTakerPays] == USD(60));
3415 env(
offer(gw,
XRP(1000), USD(100)));
3417 env.require(
owners(gw, 1));
3418 env.require(
offers(gw, 1));
3419 env.require(
balance(gw, startBalance));
3422 BEAST_EXPECT(gwOffers.size() == 1);
3423 for (
auto const& offerPtr : gwOffers)
3425 auto const&
offer = *offerPtr;
3426 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3427 BEAST_EXPECT(
offer[sfTakerGets] == USD(100));
3428 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(1000));
3435 using namespace jtx;
3437 auto const gw1 =
Account(
"gateway1");
3438 auto const gw2 =
Account(
"gateway2");
3439 auto const alice =
Account(
"alice");
3440 auto const USD = gw1[
"USD"];
3441 auto const EUR = gw2[
"EUR"];
3443 Env env{*
this, features};
3445 env.fund(
XRP(1000000), gw1, gw2);
3449 auto const f = env.current()->fees().base;
3463 TestData
const tests[]{
3474 for (
auto const& t : tests)
3476 auto const acct =
Account{t.acct};
3477 env.fund(t.fundXRP, acct);
3480 env(
trust(acct, USD(1000)));
3481 env(
trust(acct, EUR(1000)));
3484 if (t.fundUSD > USD(0))
3485 env(
pay(gw1, acct, t.fundUSD));
3486 if (t.fundEUR > EUR(0))
3487 env(
pay(gw2, acct, t.fundEUR));
3490 env(
offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3494 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3495 env.require(
owners(acct, 2 + offerCount));
3496 env.require(
balance(acct, t.fundUSD));
3497 env.require(
balance(acct, t.fundEUR));
3500 BEAST_EXPECT(acctOffers.size() == offerCount);
3501 for (
auto const& offerPtr : acctOffers)
3503 auto const&
offer = *offerPtr;
3504 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3505 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3506 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3509 env(
offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3513 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3514 env.require(
owners(acct, 2 + offerCount));
3515 env.require(
balance(acct, t.fundUSD));
3516 env.require(
balance(acct, t.fundEUR));
3519 BEAST_EXPECT(acctOffers.size() == offerCount);
3520 for (
auto const& offerPtr : acctOffers)
3522 auto const&
offer = *offerPtr;
3523 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3524 if (
offer[sfSequence] == firstOfferSeq)
3526 BEAST_EXPECT(
offer[sfTakerGets] == EUR(600));
3527 BEAST_EXPECT(
offer[sfTakerPays] == USD(500));
3531 BEAST_EXPECT(
offer[sfTakerGets] == USD(500));
3532 BEAST_EXPECT(
offer[sfTakerPays] == EUR(600));
3559 using namespace jtx;
3561 Env env{*
this, features};
3563 auto const alice =
Account(
"alice");
3564 auto const bob =
Account(
"bob");
3565 auto const USD = bob[
"USD"];
3566 auto const f = env.current()->fees().base;
3568 env.fund(
XRP(50000) + f, alice, bob);
3571 env(
offer(alice, USD(5000),
XRP(50000)));
3575 env(
offer(bob,
XRP(50000), USD(5000)));
3581 env.require(
owners(alice, 1));
3582 env.require(
lines(alice, 1));
3587 BEAST_EXPECT(bobOffers.size() == 1);
3588 for (
auto const& offerPtr : bobOffers)
3590 auto const&
offer = *offerPtr;
3591 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3592 BEAST_EXPECT(
offer[sfTakerGets] == USD(25));
3593 BEAST_EXPECT(
offer[sfTakerPays] ==
XRP(250));
3605 using namespace jtx;
3609 Env env{*
this, features | featureOwnerPaysFee};
3612 auto const fee = env.current()->fees().base;
3615 auto const ann =
Account(
"ann");
3616 auto const A_BUX = ann[
"BUX"];
3617 auto const bob =
Account(
"bob");
3618 auto const cam =
Account(
"cam");
3619 auto const dan =
Account(
"dan");
3620 auto const D_BUX = dan[
"BUX"];
3623 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3626 env(
trust(bob, A_BUX(400)));
3628 env(
trust(cam, D_BUX(100)));
3630 env(
pay(dan, bob, D_BUX(100)));
3632 env.require(
balance(bob, D_BUX(100)));
3634 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3639 env.require(
balance(bob, A_BUX(72)));
3640 env.require(
balance(bob, D_BUX(40)));
3642 env.require(
balance(cam, D_BUX(60)));
3646 env(
offer(bob, A_BUX(30), D_BUX(30)));
3649 env(
trust(ann, D_BUX(100)));
3653 env(
pay(ann, ann, D_BUX(30)),
3660 env.require(
balance(ann, D_BUX(0)));
3661 env.require(
balance(bob, A_BUX(72)));
3662 env.require(
balance(bob, D_BUX(40)));
3664 env.require(
balance(cam, D_BUX(60)));
3665 env.require(
balance(dan, A_BUX(0)));
3679 using namespace jtx;
3681 Env env{*
this, features};
3683 auto const ann =
Account(
"ann");
3684 auto const bob =
Account(
"bob");
3685 auto const cam =
Account(
"cam");
3686 auto const A_BUX = ann[
"BUX"];
3687 auto const B_BUX = bob[
"BUX"];
3689 auto const fee = env.current()->fees().base;
3690 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3693 env(
trust(ann, B_BUX(40)));
3694 env(
trust(cam, A_BUX(40)));
3695 env(
trust(cam, B_BUX(40)));
3698 env(
pay(ann, cam, A_BUX(35)));
3699 env(
pay(bob, cam, B_BUX(35)));
3701 env(
offer(bob, A_BUX(30), B_BUX(30)));
3709 env.require(
balance(cam, A_BUX(35)));
3710 env.require(
balance(cam, B_BUX(35)));
3711 env.require(
offers(cam, 1));
3714 env(
offer(cam, B_BUX(30), A_BUX(30)));
3717 env.require(
balance(bob, A_BUX(30)));
3718 env.require(
balance(cam, A_BUX(5)));
3719 env.require(
balance(cam, B_BUX(65)));
3720 env.require(
offers(cam, 0));
3729 testcase(
"Self crossing low quality offer");
3731 using namespace jtx;
3733 Env env{*
this, features};
3735 auto const ann =
Account(
"ann");
3736 auto const gw =
Account(
"gateway");
3737 auto const BTC = gw[
"BTC"];
3739 auto const fee = env.current()->fees().base;
3744 env(
rate(gw, 1.002));
3745 env(
trust(ann, BTC(10)));
3748 env(
pay(gw, ann, BTC(2.856)));
3751 env(
offer(ann,
drops(365611702030), BTC(5.713)));
3755 env(
offer(ann, BTC(0.687),
drops(20000000000)),
3768 using namespace jtx;
3770 Env env{*
this, features};
3772 auto const gw =
Account(
"gateway");
3773 auto const alice =
Account(
"alice");
3774 auto const bob =
Account(
"bob");
3775 auto const CNY = gw[
"CNY"];
3777 auto const fee = env.current()->fees().base;
3782 env(
trust(bob, CNY(500)));
3785 env(
pay(gw, bob, CNY(300)));
3788 env(
offer(bob,
drops(5400000000), CNY(216.054)));
3792 env(
offer(alice, CNY(13562.0001),
drops(339000000000)));
3796 BEAST_EXPECT(aliceOffers.size() == 1);
3797 for (
auto const& offerPtr : aliceOffers)
3799 auto const&
offer = *offerPtr;
3800 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3801 BEAST_EXPECT(
offer[sfTakerGets] ==
drops(333599446582));
3802 BEAST_EXPECT(
offer[sfTakerPays] == CNY(13345.9461));
3812 testcase(
"Offer In Scaling With Xfer Rate");
3814 using namespace jtx;
3816 Env env{*
this, features};
3818 auto const gw =
Account(
"gateway");
3819 auto const alice =
Account(
"alice");
3820 auto const bob =
Account(
"bob");
3821 auto const BTC = gw[
"BTC"];
3822 auto const JPY = gw[
"JPY"];
3824 auto const fee = env.current()->fees().base;
3829 env(
rate(gw, 1.002));
3830 env(
trust(alice, JPY(4000)));
3831 env(
trust(bob, BTC(2)));
3834 env(
pay(gw, alice, JPY(3699.034802280317)));
3835 env(
pay(gw, bob, BTC(1.156722559140311)));
3838 env(
offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3842 env(
offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3846 BEAST_EXPECT(aliceOffers.size() == 1);
3847 for (
auto const& offerPtr : aliceOffers)
3849 auto const&
offer = *offerPtr;
3850 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3852 offer[sfTakerGets] ==
3854 BEAST_EXPECT(
offer[sfTakerPays] == BTC(0.035378));
3864 testcase(
"Offer Threshold With Reduced Funds");
3866 using namespace jtx;
3868 Env env{*
this, features};
3870 auto const gw1 =
Account(
"gw1");
3871 auto const gw2 =
Account(
"gw2");
3872 auto const alice =
Account(
"alice");
3873 auto const bob =
Account(
"bob");
3874 auto const USD = gw1[
"USD"];
3875 auto const JPY = gw2[
"JPY"];
3877 auto const fee = env.current()->fees().base;
3879 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3882 env(
rate(gw1, 1.002));
3883 env(
trust(alice, USD(1000)));
3884 env(
trust(bob, JPY(100000)));
3911 BEAST_EXPECT(aliceOffers.size() == 1);
3912 for (
auto const& offerPtr : aliceOffers)
3914 auto const&
offer = *offerPtr;
3915 BEAST_EXPECT(
offer[sfLedgerEntryType] == ltOFFER);
3917 offer[sfTakerGets] ==
3920 offer[sfTakerPays] ==
3930 using namespace jtx;
3932 Env env{*
this, features};
3934 auto const gw =
Account(
"gw");
3935 auto const alice =
Account(
"alice");
3936 auto const bob =
Account(
"bob");
3937 auto const CNY = gw[
"CNY"];
3938 auto const fee = env.current()->fees().base;
3939 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3941 env.fund(startXrpBalance, gw, alice, bob);
3944 env(
trust(bob, CNY(100000)));
3956 STAmount const bobsCnyStartBalance{
3958 env(
pay(gw, bob, bobsCnyStartBalance));
3967 env.require(
balance(alice, alicesCnyOffer));
3969 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
4012 using namespace jtx;
4014 Env env{*
this, features};
4016 auto const gw =
Account(
"gw");
4017 auto const BTC = gw[
"BTC"];
4018 auto const USD = gw[
"USD"];
4019 auto const startXrpBalance =
XRP(4000000);
4021 env.fund(startXrpBalance, gw);
4024 env(
rate(gw, 1.25));
4050 TestData
const tests[]{
4052 {0, 0, 1, BTC(20), {{
"ann", 0,
drops(3899999999960), BTC(20.0), USD(3000)}, {
"abe", 0,
drops(4099999999970), BTC( 0), USD(750)}}},
4053 {0, 1, 0, BTC(20), {{
"bev", 0,
drops(4099999999960), BTC( 7.5), USD(2000)}, {
"bob", 0,
drops(3899999999970), BTC(10), USD( 0)}}},
4054 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(3999999999950), BTC(20.0), USD(2000)} }},
4055 {0, 1, 0, BTC( 5), {{
"deb", 1,
drops(4039999999960), BTC( 0.0), USD(2000)}, {
"dan", 1,
drops(3959999999970), BTC( 4), USD( 0)}}},
4059 for (
auto const& t : tests)
4061 Account const& self = t.actors[t.self].acct;
4062 Account const& leg0 = t.actors[t.leg0].acct;
4063 Account const& leg1 = t.actors[t.leg1].acct;
4065 for (
auto const& actor : t.actors)
4067 env.fund(
XRP(4000000), actor.acct);
4070 env(
trust(actor.acct, BTC(40)));
4071 env(
trust(actor.acct, USD(8000)));
4075 env(
pay(gw, self, t.btcStart));
4076 env(
pay(gw, self, USD(2000)));
4077 if (self.
id() != leg1.
id())
4078 env(
pay(gw, leg1, USD(2000)));
4092 env(
offer(self, USD(1000), BTC(10)));
4097 for (
auto const& actor : t.actors)
4103 actorOffers.begin(),
4105 actorOffers.begin(),
4108 return (*offer)[sfTakerGets].signum() == 0;
4110 BEAST_EXPECT(offerCount == actor.offers);
4112 env.require(
balance(actor.acct, actor.xrp));
4113 env.require(
balance(actor.acct, actor.btc));
4114 env.require(
balance(actor.acct, actor.usd));
4130 testcase(
"Self Pay Unlimited Funds");
4162 using namespace jtx;
4164 Env env{*
this, features};
4166 auto const gw =
Account(
"gw");
4167 auto const BTC = gw[
"BTC"];
4168 auto const USD = gw[
"USD"];
4169 auto const startXrpBalance =
XRP(4000000);
4171 env.fund(startXrpBalance, gw);
4174 env(
rate(gw, 1.25));
4200 TestData
const takerTests[]{
4202 {0, 0, 1, BTC(5), {{
"deb", 0,
drops(3899999999960), BTC(5), USD(3000)}, {
"dan", 0,
drops(4099999999970), BTC(0), USD(750)}}},
4203 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(3999999999950), BTC(5), USD(2000)} }}
4206 TestData
const flowTests[]{
4208 {0, 0, 1, BTC(5), {{
"gay", 1,
drops(3949999999960), BTC(5), USD(2500)}, {
"gar", 1,
drops(4049999999970), BTC(0), USD(1375)}}},
4209 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(3999999999950), BTC(5), USD(2000)} }}
4214 auto const& tests = features[featureFlowCross] ? flowTests : takerTests;
4216 for (
auto const& t : tests)
4218 Account const& self = t.actors[t.self].acct;
4219 Account const& leg0 = t.actors[t.leg0].acct;
4220 Account const& leg1 = t.actors[t.leg1].acct;
4222 for (
auto const& actor : t.actors)
4224 env.fund(
XRP(4000000), actor.acct);
4227 env(
trust(actor.acct, BTC(40)));
4228 env(
trust(actor.acct, USD(8000)));
4232 env(
pay(gw, self, t.btcStart));
4233 env(
pay(gw, self, USD(2000)));
4234 if (self.
id() != leg1.
id())
4235 env(
pay(gw, leg1, USD(2000)));
4249 env(
offer(self, USD(1000), BTC(10)));
4254 for (
auto const& actor : t.actors)
4260 actorOffers.begin(),
4262 actorOffers.begin(),
4265 return (*offer)[sfTakerGets].signum() == 0;
4267 BEAST_EXPECT(offerCount == actor.offers);
4269 env.require(
balance(actor.acct, actor.xrp));
4270 env.require(
balance(actor.acct, actor.btc));
4271 env.require(
balance(actor.acct, actor.usd));
4289 using namespace jtx;
4291 Env env{*
this, features};
4293 auto const gw =
Account(
"gw");
4294 auto const alice =
Account(
"alice");
4295 auto const bob =
Account(
"bob");
4296 auto const gwUSD = gw[
"USD"];
4297 auto const aliceUSD = alice[
"USD"];
4298 auto const bobUSD = bob[
"USD"];
4300 env.fund(
XRP(400000), gw, alice, bob);
4309 env(
trust(bob, gwUSD(100)));
4311 env(
trust(alice, gwUSD(100)));
4313 env(
offer(alice, gwUSD(40),
XRP(4000)));
4316 env.require(
offers(alice, 1));
4317 env.require(
balance(alice, gwUSD(0)));
4319 env(
pay(gw, bob, gwUSD(50)));
4322 env.require(
balance(bob, gwUSD(50)));
4325 env(
offer(bob,
XRP(4000), gwUSD(40)));
4328 env.require(
offers(alice, 0));
4329 env.require(
balance(alice, gwUSD(40)));
4331 env.require(
offers(bob, 0));
4332 env.require(
balance(bob, gwUSD(10)));
4358 using namespace jtx;
4360 Env env{*
this, features};
4362 auto const gw =
Account(
"gw");
4363 auto const alice =
Account(
"alice");
4364 auto const bob =
Account(
"bob");
4365 auto const gwUSD = gw[
"USD"];
4366 auto const aliceUSD = alice[
"USD"];
4367 auto const bobUSD = bob[
"USD"];
4369 env.fund(
XRP(400000), gw, alice, bob);
4372 env(
offer(alice, gwUSD(40),
XRP(4000)));
4375 env.require(
offers(alice, 1));
4382 env(
trust(bob, gwUSD(100)));
4385 env(
pay(gw, bob, gwUSD(50)));
4387 env.require(
balance(bob, gwUSD(50)));
4395 env(
offer(bob,
XRP(4000), gwUSD(40)));
4399 bool const flowCross = features[featureFlowCross];
4401 env.require(
offers(alice, 0));
4406 env.require(
offers(bob, 1));
4407 env.require(
balance(bob, gwUSD(50)));
4412 env.require(
balance(alice, gwUSD(40)));
4413 env.require(
offers(bob, 0));
4414 env.require(
balance(bob, gwUSD(10)));
4426 env.require(
offers(alice, 0));
4429 env.require(
offers(bob, 1));
4430 env.require(
balance(bob, gwUSD(50)));
4434 env(
trust(gw, aliceUSD(100)));
4440 env.require(
offers(alice, 0));
4441 env.require(
balance(alice, gwUSD(0)));
4443 env.require(
offers(bob, 1));
4444 env.require(
balance(bob, gwUSD(50)));
4449 env.require(
offers(bob, 0));
4457 env(
offer(alice, gwUSD(40),
XRP(4000)));
4460 env.require(
offers(alice, 1));
4463 env(
offer(bob,
XRP(4000), gwUSD(40)));
4466 env.require(
offers(alice, 0));
4467 env.require(
balance(alice, gwUSD(40)));
4469 env.require(
offers(bob, 0));
4470 env.require(
balance(bob, gwUSD(10)));
4476 testcase(
"RippleConnect Smoketest payment flow");
4477 using namespace jtx;
4479 Env env{*
this, features};
4489 auto const hotUS =
Account(
"hotUS");
4490 auto const coldUS =
Account(
"coldUS");
4491 auto const hotEU =
Account(
"hotEU");
4492 auto const coldEU =
Account(
"coldEU");
4493 auto const mm =
Account(
"mm");
4495 auto const USD = coldUS[
"USD"];
4496 auto const EUR = coldEU[
"EUR"];
4498 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4502 for (
auto const& cold : {coldUS, coldEU})
4525 env(
pay(coldUS, hotUS, USD(5000000)));
4526 env(
pay(coldEU, hotEU, EUR(5000000)));
4527 env(
pay(coldUS, mm, USD(5000000)));
4528 env(
pay(coldEU, mm, EUR(5000000)));
4532 float const rate = 0.9f;
4533 env(
offer(mm, EUR(4000000 *
rate), USD(4000000)),
4536 float const reverseRate = 1.0f /
rate * 1.00101f;
4537 env(
offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4544 jvParams[jss::destination_account] = coldEU.human();
4545 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4546 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4547 jvParams[jss::destination_amount][jss::value] = 10;
4548 jvParams[jss::source_account] = hotUS.human();
4551 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4553 BEAST_EXPECT(jrr[jss::status] ==
"success");
4555 jrr[jss::alternatives].isArray() &&
4556 jrr[jss::alternatives].size() > 0);
4559 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4567 using namespace jtx;
4569 Env env{*
this, features};
4571 auto const gw =
Account(
"gw");
4572 auto const alice =
Account(
"alice");
4573 auto const gwUSD = gw[
"USD"];
4574 auto const aliceUSD = alice[
"USD"];
4576 env.fund(
XRP(400000), gw, alice);
4580 env(
offer(gw, gwUSD(40),
XRP(4000)));
4583 env.require(
offers(gw, 1));
4592 env.require(
offers(gw, 0));
4599 bool const preauth = features[featureDepositPreauth];
4604 env(
offer(gw, gwUSD(40),
XRP(4000)),
4608 env.require(
offers(gw, preauth ? 1 : 0));
4616 env(
trust(alice, gwUSD(100)));
4619 env(
pay(gw, alice, gwUSD(50)));
4622 env.require(
balance(alice, gwUSD(50)));
4625 env(
offer(alice,
XRP(4000), gwUSD(40)));
4628 env.require(
offers(alice, 0));
4629 env.require(
balance(alice, gwUSD(10)));
4631 env.require(
offers(gw, 0));
4638 using namespace jtx;
4642 auto trustLineExists = [](
jtx::Env const& env,
4653 auto const USD = gw[
"USD"];
4654 auto const BUX = alice[
"BUX"];
4656 Env env{*
this, features};
4659 env.
trust(USD(1000), becky);
4660 env(
pay(gw, becky, USD(5)));
4662 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4673 env(
pay(becky, gw, USD(5)));
4674 env.
trust(USD(0), becky);
4676 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4677 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4678 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4685 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4687 if (gwSeq + 255 > openLedgerSeq)
4688 return gwSeq - openLedgerSeq + 255;
4692 for (
int i = 0; i < delta; ++i)
4709 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4710 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4716 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4717 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4722 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4726 env.
trust(BUX(1000), carol);
4727 env(
pay(alice, carol, BUX(2)));
4736 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4737 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4745 using namespace jtx;
4749 Env env{*
this, features};
4750 auto const gw =
Account{
"gateway"};
4751 env.fund(
XRP(10000), gw);
4753 auto txn =
noop(gw);
4754 txn[sfTickSize.fieldName] = Quality::minTickSize - 1;
4757 txn[sfTickSize.fieldName] = Quality::minTickSize;
4759 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::minTickSize);
4762 txn[sfTickSize.fieldName] = Quality::maxTickSize;
4764 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4767 txn[sfTickSize.fieldName] = Quality::maxTickSize - 1;
4769 BEAST_EXPECT((*env.le(gw))[sfTickSize] == Quality::maxTickSize - 1);
4772 txn[sfTickSize.fieldName] = Quality::maxTickSize + 1;
4775 txn[sfTickSize.fieldName] = 0;
4777 BEAST_EXPECT(!env.le(gw)->isFieldPresent(sfTickSize));
4780 Env env{*
this, features};
4781 auto const gw =
Account{
"gateway"};
4782 auto const alice =
Account{
"alice"};
4783 auto const XTS = gw[
"XTS"];
4784 auto const XXX = gw[
"XXX"];
4786 env.fund(
XRP(10000), gw, alice);
4790 auto txn =
noop(gw);
4791 txn[sfTickSize.fieldName] = 5;
4793 BEAST_EXPECT((*env.le(gw))[sfTickSize] == 5);
4796 env(
trust(alice, XTS(1000)));
4797 env(
trust(alice, XXX(1000)));
4799 env(
pay(gw, alice, alice[
"XTS"](100)));
4800 env(
pay(gw, alice, alice[
"XXX"](100)));
4802 env(
offer(alice, XTS(10), XXX(30)));
4803 env(
offer(alice, XTS(30), XXX(10)));
4810 if (sle->getType() == ltOFFER)
4814 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4818 auto it =
offers.begin();
4819 BEAST_EXPECT(it !=
offers.end());
4821 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4822 it->second.second > XXX(29.9994));
4826 BEAST_EXPECT(it !=
offers.end());
4828 it->second.first == XTS(30) && it->second.second == XXX(10));
4832 BEAST_EXPECT(it !=
offers.end());
4834 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4839 BEAST_EXPECT(it !=
offers.end());
4841 it->second.first == XTS(30) && it->second.second == XXX(10));
4843 BEAST_EXPECT(++it ==
offers.end());
4857 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4867 using namespace jtx;
4875 Env env{*
this, features};
4876 auto const gw =
Account{
"gateway"};
4877 auto const alice =
Account{
"alice"};
4878 auto const bob =
Account{
"bob"};
4879 auto const USD = gw[
"USD"];
4881 env.fund(
XRP(10000), gw, alice, bob);
4884 env(
trust(alice, USD(1000)));
4885 env(
trust(bob, USD(1000)));
4888 env(
pay(gw, alice, USD(200)));
4895 env(
offer(alice,
XRP(50), USD(50)));
4905 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4906 env(
offer(alice,
XRP(50), USD(50)));
4922 BEAST_EXPECT(
offers.size() == 4);
4923 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_0);
4924 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_3);
4925 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_2);
4926 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerId_1);
4927 env.require(
balance(alice, USD(200)));
4928 env.require(
owners(alice, 5));
4938 BEAST_EXPECT(
offers.size() == 3);
4939 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4940 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4941 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerId_1);
4951 BEAST_EXPECT(
offers.size() == 2);
4952 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4953 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerId_2);
4963 BEAST_EXPECT(
offers.size() == 1);
4964 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerId_3);
4974 BEAST_EXPECT(
offers.size() == 0);
4976 env.require(
balance(alice, USD(0)));
4977 env.require(
owners(alice, 1));
4978 env.require(
balance(bob, USD(200)));
4979 env.require(
owners(bob, 1));
4987 using namespace jtx;
4991 Env env{*
this, features};
4992 auto const gw =
Account{
"gateway"};
4993 auto const alice =
Account{
"alice"};
4994 auto const USD = gw[
"USD"];
4996 env.fund(
XRP(10000), gw, alice);
4999 env(
trust(alice, USD(1000)));
5003 env(
pay(gw, alice, USD(200)));
5008 env(
offer(alice,
XRP(50), USD(50)));
5020 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5021 env(
offer(alice,
XRP(50), USD(50)));
5037 BEAST_EXPECT(
offers.size() == 4);
5038 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_0);
5039 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_1);
5040 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerTixId_0);
5041 BEAST_EXPECT(
offers[3]->getFieldU32(sfSequence) == offerSeqId_1);
5042 env.require(
balance(alice, USD(200)));
5043 env.require(
owners(alice, 7));
5053 BEAST_EXPECT(
offers.size() == 3);
5054 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5055 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerTixId_0);
5056 BEAST_EXPECT(
offers[2]->getFieldU32(sfSequence) == offerSeqId_1);
5066 BEAST_EXPECT(
offers.size() == 2);
5067 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerTixId_1);
5068 BEAST_EXPECT(
offers[1]->getFieldU32(sfSequence) == offerSeqId_1);
5081 BEAST_EXPECT(
offers.size() == 1);
5082 BEAST_EXPECT(
offers[0]->getFieldU32(sfSequence) == offerSeqId_1);
5099 testcase(
"incorrect assert fixed");
5100 using namespace jtx;
5103 auto const alice =
Account(
"alice");
5104 auto const USD = alice[
"USD"];
5106 env.fund(
XRP(10000), alice);
5108 env(
offer(alice,
XRP(100000000000), USD(100000000)));
5116 using namespace jtx;
5117 Env env(*
this, features);
5118 Account const issuer(
"issuer");
5121 auto const USD = issuer[
"USD"];
5122 auto const EUR = issuer[
"EUR"];
5125 env.
fund(
XRP(1'000), maker, taker);
5128 env.
trust(USD(1'000), maker, taker);
5129 env.
trust(EUR(1'000), maker, taker);
5132 env(
pay(issuer, maker, USD(1'000)));
5133 env(
pay(issuer, taker, USD(1'000)));
5134 env(
pay(issuer, maker, EUR(1'000)));
5137 auto makerUSDBalance = env.
balance(maker, USD).
value();
5138 auto takerUSDBalance = env.
balance(taker, USD).
value();
5139 auto makerEURBalance = env.
balance(maker, EUR).
value();
5140 auto takerEURBalance = env.
balance(taker, EUR).
value();
5147 features[fixFillOrKill] || !features[featureFlowCross]
5151 env(
offer(maker,
XRP(100), USD(100)));
5154 env(
offer(taker, USD(100),
XRP(101)),
5159 makerXRPBalance -=
txfee(env, 1);
5160 takerXRPBalance -=
txfee(env, 1);
5163 makerUSDBalance -= USD(100);
5164 takerUSDBalance += USD(100);
5165 makerXRPBalance +=
XRP(100).value();
5166 takerXRPBalance -=
XRP(100).value();
5170 env(
offer(maker, USD(100),
XRP(100)));
5173 env(
offer(taker,
XRP(100), USD(101)),
5178 makerXRPBalance -=
txfee(env, 1);
5179 takerXRPBalance -=
txfee(env, 1);
5182 makerUSDBalance += USD(100);
5183 takerUSDBalance -= USD(100);
5184 makerXRPBalance -=
XRP(100).value();
5185 takerXRPBalance +=
XRP(100).value();
5189 env(
offer(maker, USD(100), EUR(100)));
5192 env(
offer(taker, EUR(100), USD(101)),
5197 makerXRPBalance -=
txfee(env, 1);
5198 takerXRPBalance -=
txfee(env, 1);
5201 makerUSDBalance += USD(100);
5202 takerUSDBalance -= USD(100);
5203 makerEURBalance -= EUR(100);
5204 takerEURBalance += EUR(100);
5211 env(
offer(maker,
XRP(101), USD(101)));
5214 env(
offer(taker, USD(100),
XRP(101)),
5218 makerUSDBalance -= USD(101);
5219 takerUSDBalance += USD(101);
5220 makerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5221 takerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5224 env(
offer(maker, USD(101),
XRP(101)));
5227 env(
offer(taker,
XRP(100), USD(101)),
5231 makerUSDBalance += USD(101);
5232 takerUSDBalance -= USD(101);
5233 makerXRPBalance -=
XRP(101).value() +
txfee(env, 1);
5234 takerXRPBalance +=
XRP(101).value() -
txfee(env, 1);
5237 env(
offer(maker, USD(101), EUR(101)));
5240 env(
offer(taker, EUR(100), USD(101)),
5244 makerUSDBalance += USD(101);
5245 takerUSDBalance -= USD(101);
5246 makerEURBalance -= EUR(101);
5247 takerEURBalance += EUR(101);
5248 makerXRPBalance -=
txfee(env, 1);
5249 takerXRPBalance -=
txfee(env, 1);
5256 env(
offer(maker,
XRP(100), USD(100)));
5259 env(
offer(taker, USD(100),
XRP(99)),
5264 makerXRPBalance -=
txfee(env, 1);
5265 takerXRPBalance -=
txfee(env, 1);
5268 env(
offer(maker, USD(100),
XRP(100)));
5271 env(
offer(taker,
XRP(100), USD(99)),
5276 makerXRPBalance -=
txfee(env, 1);
5277 takerXRPBalance -=
txfee(env, 1);
5280 env(
offer(maker, USD(100), EUR(100)));
5283 env(
offer(taker, EUR(100), USD(99)),
5288 makerXRPBalance -=
txfee(env, 1);
5289 takerXRPBalance -=
txfee(env, 1);
5294 env.
balance(maker, USD) == makerUSDBalance &&
5295 env.
balance(taker, USD) == takerUSDBalance &&
5296 env.
balance(maker, EUR) == makerEURBalance &&
5297 env.
balance(taker, EUR) == takerEURBalance &&
5298 env.
balance(maker,
XRP) == makerXRPBalance &&
5369 using namespace jtx;
5372 static FeatureBitset const takerDryOffer{fixTakerDryOfferRemoval};
5374 fixRmSmallIncreasedQOffers};
5376 featureImmediateOfferKilled};
5380 all - takerDryOffer - immediateOfferKilled,
5381 all - flowCross - takerDryOffer - immediateOfferKilled,
5382 all - flowCross - immediateOfferKilled,
5383 all - rmSmallIncreasedQOffers - immediateOfferKilled - fillOrKill,
5387 if (BEAST_EXPECT(instance < feats.size()))
5391 BEAST_EXPECT(!last || instance == feats.size() - 1);
5452 using namespace jtx;
5456 FeatureBitset const immediateOfferKilled{featureImmediateOfferKilled};
5460 testAll(
all - flowCross - f1513 - immediateOfferKilled);
5461 testAll(
all - flowCross - immediateOfferKilled);
5462 testAll(
all - immediateOfferKilled - fillOrKill);
5470BEAST_DEFINE_TESTSUITE_PRIO(OfferBaseUtil, tx,
ripple, 2);
5471BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFlowCross, tx,
ripple, 2);
5472BEAST_DEFINE_TESTSUITE_PRIO(OfferWTakerDryOffer, tx,
ripple, 2);
5473BEAST_DEFINE_TESTSUITE_PRIO(OfferWOSmallQOffers, tx,
ripple, 2);
5474BEAST_DEFINE_TESTSUITE_PRIO(OfferWOFillOrKill, tx,
ripple, 2);
5475BEAST_DEFINE_TESTSUITE_PRIO(OfferAllFeatures, tx,
ripple, 2);
5476BEAST_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