20 #include <ripple/protocol/Feature.h>
21 #include <ripple/protocol/Quality.h>
22 #include <ripple/protocol/jss.h>
24 #include <test/jtx/PathSet.h>
25 #include <test/jtx/WSClient.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));
203 env(offer(alice,
XRP(5), USD(2)),
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)));
217 testcase(
"Tiny payments");
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)));
245 env(pay(alice, bob, EUR(epsilon)),
path(~EUR),
sendmax(USD(100)));
251 testcase(
"XRP Tiny payments");
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)));
294 env(offer(carol,
drops(1), USD(0.99999)));
297 env(offer(dan,
XRP(100), USD(1)));
306 env(offer(erin,
drops(2), 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)));
353 env(offer(carol,
drops(1), USD(1)));
362 auto aliceTakerGets = crossBothOffers ?
drops(2) :
drops(1);
363 env(offer(alice, USD(1), aliceTakerGets));
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)));
414 env(offer(carol,
drops(1), USD(1)));
424 TER const expectedTer =
427 env(pay(alice, bob, USD(5)),
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)));
515 env(offer(bob, EUR(1), USD(5),
tfPassive));
522 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
523 env(offer(alice, USD(1), aliceTakerGets));
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)));
579 env(offer(bob, EUR(2), USD(4),
tfPassive));
587 TER const expectedTer =
590 env(pay(alice, bob, USD(5)),
601 env.require(
offers(carol, 0));
618 env.require(
offers(carol, 0));
625 BEAST_EXPECT(
isOffer(env, carol, EUR(1), USD(2)));
634 testcase(
"Enforce No Ripple");
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)));
666 env(offer(dan,
XRP(50), USD1(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)));
691 env(offer(dan,
XRP(50), USD1(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)));
708 testcase(
"Insufficient Reserve");
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);
827 testcase(
"Fill Modes");
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 :
846 Env env{*
this, tweakedFeatures};
848 auto const f = env.
current()->fees().base;
850 env.fund(startBalance, gw, alice, bob);
853 env(offer(bob, USD(500),
XRP(500)),
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);
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)),
950 env(offer(alice,
XRP(50), USD(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;
997 BEAST_EXPECT(bobOffers.size() == 1);
998 for (
auto offerPtr : bobOffers)
1000 auto const& offer = *offerPtr;
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;
1059 testcase(
"Malformed Detection");
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)),
1136 testcase(
"Offer Expiration");
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),
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),
1214 testcase(
"Unfunded Crossing");
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{
1337 BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
1338 for (
auto const& offerPtr : acctOffers)
1340 auto const& offer = *offerPtr;
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)));
1386 testcase(
"Negative Balance");
1388 using namespace jtx;
1390 Env env{*
this, features};
1392 auto const gw =
Account{
"gateway"};
1393 auto const alice =
Account{
"alice"};
1394 auto const bob =
Account{
"bob"};
1395 auto const USD = gw[
"USD"];
1396 auto const BTC = gw[
"BTC"];
1400 auto const gw_initial_balance =
drops(1149999730);
1401 auto const alice_initial_balance =
drops(499946999680);
1402 auto const bob_initial_balance =
drops(10199999920);
1403 auto const small_amount =
1404 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1406 env.fund(gw_initial_balance, gw);
1407 env.fund(alice_initial_balance, alice);
1408 env.fund(bob_initial_balance, bob);
1410 env(
rate(gw, 1.005));
1412 env(trust(alice, USD(500)));
1413 env(trust(bob, USD(50)));
1414 env(trust(gw, alice[
"USD"](100)));
1416 env(pay(gw, alice, alice[
"USD"](50)));
1417 env(pay(gw, bob, small_amount));
1419 env(offer(alice, USD(50),
XRP(150000)));
1422 env(pay(alice, gw, USD(100)));
1425 env(trust(gw, alice[
"USD"](0)));
1434 "-2710505431213761e-33");
1437 env(offer(bob,
XRP(2000), USD(1)));
1446 auto const crossingDelta =
1453 alice_initial_balance - env.current()->fees().base * 3 -
1460 bob_initial_balance - env.current()->fees().base * 2 +
1469 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1471 using namespace jtx;
1473 Env env{*
this, features};
1475 auto const gw =
Account{
"gateway"};
1476 auto const alice =
Account{
"alice"};
1477 auto const bob =
Account{
"bob"};
1478 auto const USD = gw[
"USD"];
1480 env.fund(
XRP(10000), gw, alice, bob);
1482 env(trust(alice, USD(1000)));
1483 env(trust(bob, USD(1000)));
1485 env(pay(gw, alice, alice[
"USD"](500)));
1488 env(offer(bob, USD(1),
XRP(4000)));
1490 env(offer(alice,
XRP(150000), USD(50)));
1493 env(offer(bob, USD(1),
XRP(4000)));
1505 env.current()->fees().base * 2)
1514 env.current()->fees().base * 2)
1521 testcase(
"Offer Crossing with Limit Override");
1523 using namespace jtx;
1525 Env env{*
this, features};
1527 auto const gw =
Account{
"gateway"};
1528 auto const alice =
Account{
"alice"};
1529 auto const bob =
Account{
"bob"};
1530 auto const USD = gw[
"USD"];
1532 env.fund(
XRP(100000), gw, alice, bob);
1534 env(trust(alice, USD(1000)));
1536 env(pay(gw, alice, alice[
"USD"](500)));
1538 env(offer(alice,
XRP(150000), USD(50)));
1539 env(offer(bob, USD(1),
XRP(3000)));
1561 testcase(
"Offer Accept then Cancel.");
1563 using namespace jtx;
1565 Env env{*
this, features};
1567 auto const USD = env.master[
"USD"];
1569 auto const nextOfferSeq = env.seq(env.master);
1570 env(offer(env.master,
XRP(500), USD(100)));
1574 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1579 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1585 testcase(
"Offer Cancel Past and Future Sequence.");
1587 using namespace jtx;
1589 Env env{*
this, features};
1591 auto const alice =
Account{
"alice"};
1593 auto const nextOfferSeq = env.seq(env.master);
1594 env.fund(
XRP(10000), alice);
1610 testcase(
"Currency Conversion: Entire Offer");
1612 using namespace jtx;
1614 Env env{*
this, features};
1616 auto const gw =
Account{
"gateway"};
1617 auto const alice =
Account{
"alice"};
1618 auto const bob =
Account{
"bob"};
1619 auto const USD = gw[
"USD"];
1621 env.fund(
XRP(10000), gw, alice, bob);
1622 env.require(
owners(bob, 0));
1624 env(trust(alice, USD(100)));
1625 env(trust(bob, USD(1000)));
1629 env(pay(gw, alice, alice[
"USD"](100)));
1630 auto const bobOfferSeq = env.seq(bob);
1631 env(offer(bob, USD(100),
XRP(500)));
1636 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1638 jro[jss::node][jss::TakerPays] ==
1641 env(pay(alice, alice,
XRP(500)),
sendmax(USD(100)));
1655 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1663 testcase(
"Currency Conversion: Offerer Into Debt");
1665 using namespace jtx;
1667 Env env{*
this, features};
1669 auto const alice =
Account{
"alice"};
1670 auto const bob =
Account{
"bob"};
1671 auto const carol =
Account{
"carol"};
1673 env.fund(
XRP(10000), alice, bob, carol);
1675 env(trust(alice, carol[
"EUR"](2000)));
1676 env(trust(bob, alice[
"USD"](100)));
1677 env(trust(carol, bob[
"EUR"](1000)));
1679 auto const bobOfferSeq = env.seq(bob);
1680 env(offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1683 env(offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1686 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1692 testcase(
"Currency Conversion: In Parts");
1694 using namespace jtx;
1696 Env env{*
this, features};
1698 auto const gw =
Account{
"gateway"};
1699 auto const alice =
Account{
"alice"};
1700 auto const bob =
Account{
"bob"};
1701 auto const USD = gw[
"USD"];
1703 env.fund(
XRP(10000), gw, alice, bob);
1705 env(trust(alice, USD(200)));
1706 env(trust(bob, USD(1000)));
1708 env(pay(gw, alice, alice[
"USD"](200)));
1710 auto const bobOfferSeq = env.seq(bob);
1711 env(offer(bob, USD(100),
XRP(500)));
1713 env(pay(alice, alice,
XRP(200)),
sendmax(USD(100)));
1718 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1720 jro[jss::node][jss::TakerPays] ==
1740 env(pay(alice, alice,
XRP(600)),
1746 env(pay(alice, alice,
XRP(600)),
1752 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1765 env.current()->fees().base * 4)
1777 testcase(
"Cross Currency Payment: Start with XRP");
1779 using namespace jtx;
1781 Env env{*
this, features};
1783 auto const gw =
Account{
"gateway"};
1784 auto const alice =
Account{
"alice"};
1785 auto const bob =
Account{
"bob"};
1786 auto const carol =
Account{
"carol"};
1787 auto const USD = gw[
"USD"];
1789 env.fund(
XRP(10000), gw, alice, bob, carol);
1791 env(trust(carol, USD(1000)));
1792 env(trust(bob, USD(2000)));
1794 env(pay(gw, carol, carol[
"USD"](500)));
1796 auto const carolOfferSeq = env.seq(carol);
1797 env(offer(carol,
XRP(500), USD(50)));
1799 env(pay(alice, bob, USD(25)),
sendmax(
XRP(333)));
1809 jro[jss::node][jss::TakerGets] ==
1812 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1818 testcase(
"Cross Currency Payment: End with XRP");
1820 using namespace jtx;
1822 Env env{*
this, features};
1824 auto const gw =
Account{
"gateway"};
1825 auto const alice =
Account{
"alice"};
1826 auto const bob =
Account{
"bob"};
1827 auto const carol =
Account{
"carol"};
1828 auto const USD = gw[
"USD"];
1830 env.fund(
XRP(10000), gw, alice, bob, carol);
1832 env(trust(alice, USD(1000)));
1833 env(trust(carol, USD(2000)));
1835 env(pay(gw, alice, alice[
"USD"](500)));
1837 auto const carolOfferSeq = env.seq(carol);
1838 env(offer(carol, USD(50),
XRP(500)));
1840 env(pay(alice, bob,
XRP(250)),
sendmax(USD(333)));
1852 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1856 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1858 jro[jss::node][jss::TakerPays] ==
1865 testcase(
"Cross Currency Payment: Bridged");
1867 using namespace jtx;
1869 Env env{*
this, features};
1871 auto const gw1 =
Account{
"gateway_1"};
1872 auto const gw2 =
Account{
"gateway_2"};
1873 auto const alice =
Account{
"alice"};
1874 auto const bob =
Account{
"bob"};
1875 auto const carol =
Account{
"carol"};
1876 auto const dan =
Account{
"dan"};
1877 auto const USD = gw1[
"USD"];
1878 auto const EUR = gw2[
"EUR"];
1880 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1882 env(trust(alice, USD(1000)));
1883 env(trust(bob, EUR(1000)));
1884 env(trust(carol, USD(1000)));
1885 env(trust(dan, EUR(1000)));
1887 env(pay(gw1, alice, alice[
"USD"](500)));
1888 env(pay(gw2, dan, dan[
"EUR"](400)));
1890 auto const carolOfferSeq = env.seq(carol);
1891 env(offer(carol, USD(50),
XRP(500)));
1893 auto const danOfferSeq = env.seq(dan);
1894 env(offer(dan,
XRP(500), EUR(50)));
1897 jtp[0u][0u][jss::currency] =
"XRP";
1898 env(pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1914 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1916 jro[jss::node][jss::TakerPays] ==
1921 jro[jss::node][jss::TakerGets] ==
1924 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1933 testcase(
"Auto Bridged Second Leg Dry");
1935 using namespace jtx;
1936 Env env(*
this, features);
1942 auto const USD = gw[
"USD"];
1943 auto const EUR = gw[
"EUR"];
1945 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1947 env.
trust(USD(10), alice);
1949 env(pay(gw, alice, USD(10)));
1950 env.
trust(USD(10), carol);
1952 env(pay(gw, carol, USD(3)));
1954 env(offer(alice, EUR(2),
XRP(1)));
1955 env(offer(alice, EUR(2),
XRP(1)));
1957 env(offer(alice,
XRP(1), USD(4)));
1958 env(offer(carol,
XRP(1), USD(3)));
1969 env.
trust(EUR(10), bob);
1971 env(pay(gw, bob, EUR(10)));
1973 env(offer(bob, USD(10), EUR(10)));
1990 int const emptyOfferCount{
2002 testcase(
"Offer Fees Consume Funds");
2004 using namespace jtx;
2006 Env env{*
this, features};
2008 auto const gw1 =
Account{
"gateway_1"};
2009 auto const gw2 =
Account{
"gateway_2"};
2010 auto const gw3 =
Account{
"gateway_3"};
2011 auto const alice =
Account{
"alice"};
2012 auto const bob =
Account{
"bob"};
2013 auto const USD1 = gw1[
"USD"];
2014 auto const USD2 = gw2[
"USD"];
2015 auto const USD3 = gw3[
"USD"];
2023 auto const starting_xrp =
XRP(100) +
2024 env.current()->fees().accountReserve(3) +
2025 env.current()->fees().base * 4;
2027 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2029 env(trust(alice, USD1(1000)));
2030 env(trust(alice, USD2(1000)));
2031 env(trust(alice, USD3(1000)));
2032 env(trust(bob, USD1(1000)));
2033 env(trust(bob, USD2(1000)));
2035 env(pay(gw1, bob, bob[
"USD"](500)));
2037 env(offer(bob,
XRP(200), USD1(200)));
2040 env(offer(alice, USD1(200),
XRP(200)));
2056 testcase(
"Offer Create, then Cross");
2058 using namespace jtx;
2060 for (
auto NumberSwitchOver : {
false,
true})
2062 Env env{*
this, features};
2063 if (NumberSwitchOver)
2068 auto const gw =
Account{
"gateway"};
2069 auto const alice =
Account{
"alice"};
2070 auto const bob =
Account{
"bob"};
2071 auto const USD = gw[
"USD"];
2073 env.fund(
XRP(10000), gw, alice, bob);
2075 env(
rate(gw, 1.005));
2077 env(trust(alice, USD(1000)));
2078 env(trust(bob, USD(1000)));
2079 env(trust(gw, alice[
"USD"](50)));
2081 env(pay(gw, bob, bob[
"USD"](1)));
2082 env(pay(alice, gw, USD(50)));
2084 env(trust(gw, alice[
"USD"](0)));
2086 env(offer(alice, USD(50),
XRP(150000)));
2087 env(offer(bob,
XRP(100), USD(0.1)));
2092 "49.96666666666667");
2097 if (!NumberSwitchOver)
2099 BEAST_EXPECT(bobsUSD ==
"-0.966500000033334");
2103 BEAST_EXPECT(bobsUSD ==
"-0.9665000000333333");
2111 testcase(
"Offer tfSell: Basic Sell");
2113 using namespace jtx;
2115 Env env{*
this, features};
2117 auto const gw =
Account{
"gateway"};
2118 auto const alice =
Account{
"alice"};
2119 auto const bob =
Account{
"bob"};
2120 auto const USD = gw[
"USD"];
2122 auto const starting_xrp =
XRP(100) +
2123 env.current()->fees().accountReserve(1) +
2124 env.current()->fees().base * 2;
2126 env.fund(starting_xrp, gw, alice, bob);
2128 env(trust(alice, USD(1000)));
2129 env(trust(bob, USD(1000)));
2131 env(pay(gw, bob, bob[
"USD"](500)));
2133 env(offer(bob,
XRP(200), USD(200)),
json(jss::Flags,
tfSell));
2137 env(offer(alice, USD(200),
XRP(200)),
json(jss::Flags,
tfSell));
2153 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2155 using namespace jtx;
2157 Env env{*
this, features};
2159 auto const gw =
Account{
"gateway"};
2160 auto const alice =
Account{
"alice"};
2161 auto const bob =
Account{
"bob"};
2162 auto const USD = gw[
"USD"];
2164 auto const starting_xrp =
XRP(100) +
2165 env.current()->fees().accountReserve(1) +
2166 env.current()->fees().base * 2;
2168 env.fund(starting_xrp, gw, alice, bob);
2170 env(trust(alice, USD(150)));
2171 env(trust(bob, USD(1000)));
2173 env(pay(gw, bob, bob[
"USD"](500)));
2175 env(offer(bob,
XRP(100), USD(200)));
2181 env(offer(alice, USD(100),
XRP(100)),
json(jss::Flags,
tfSell));
2197 testcase(
"Client Issue #535: Gateway Cross Currency");
2199 using namespace jtx;
2201 Env env{*
this, features};
2203 auto const gw =
Account{
"gateway"};
2204 auto const alice =
Account{
"alice"};
2205 auto const bob =
Account{
"bob"};
2206 auto const XTS = gw[
"XTS"];
2207 auto const XXX = gw[
"XXX"];
2209 auto const starting_xrp =
XRP(100.1) +
2210 env.current()->fees().accountReserve(1) +
2211 env.current()->fees().base * 2;
2213 env.fund(starting_xrp, gw, alice, bob);
2215 env(trust(alice, XTS(1000)));
2216 env(trust(alice, XXX(1000)));
2217 env(trust(bob, XTS(1000)));
2218 env(trust(bob, XXX(1000)));
2220 env(pay(gw, alice, alice[
"XTS"](100)));
2221 env(pay(gw, alice, alice[
"XXX"](100)));
2222 env(pay(gw, bob, bob[
"XTS"](100)));
2223 env(pay(gw, bob, bob[
"XXX"](100)));
2225 env(offer(alice, XTS(100), XXX(100)));
2232 payment[jss::id] = env.seq(bob);
2233 payment[jss::build_path] =
true;
2234 payment[jss::tx_json] = pay(bob, bob, bob[
"XXX"](1));
2235 payment[jss::tx_json][jss::Sequence] =
2239 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2240 payment[jss::tx_json][jss::SendMax] =
2242 auto jrr = wsc->invoke(
"submit", payment);
2243 BEAST_EXPECT(jrr[jss::status] ==
"success");
2244 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2245 if (wsc->version() == 2)
2248 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2250 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2251 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2277 auto const sleTrust =
2279 BEAST_EXPECT(sleTrust);
2283 bool const accountLow = account.id() < issue.
account;
2288 low.setIssuer(accountLow ? account.id() : issue.
account);
2289 high.setIssuer(accountLow ? issue.
account : account.id());
2291 BEAST_EXPECT(sleTrust->getFieldAmount(
sfLowLimit) == low);
2292 BEAST_EXPECT(sleTrust->getFieldAmount(
sfHighLimit) == high);
2298 BEAST_EXPECT(actualBalance == expectBalance);
2308 testcase(
"Partial Crossing");
2310 using namespace jtx;
2312 auto const gw =
Account(
"gateway");
2313 auto const USD = gw[
"USD"];
2315 Env env{*
this, features};
2317 env.fund(
XRP(10000000), gw);
2320 auto const f = env.current()->fees().base;
2323 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2329 preTrustType preTrust;
2339 TestData
const tests[]{
2341 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2342 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2343 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2344 {
"deb",
reserve(env, 0) + 2 * f, 1, noPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 1},
2345 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2346 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2347 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2348 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2349 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2350 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2351 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2352 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2353 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2354 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2355 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2356 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2357 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2358 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2360 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2361 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2362 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2363 {
"dan",
reserve(env, 0) + 2 * f, 1, gwPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 0},
2364 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2365 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2366 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2367 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2369 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2370 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2371 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2372 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2373 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2374 {
"syd",
reserve(env, 1) + 3 * f, 1, acctPreTrust, 1000,
tesSUCCESS, 3 * f, USD(0.00001), 0, 1},
2375 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2376 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2377 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2378 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2379 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2383 for (
auto const& t : tests)
2385 auto const acct =
Account(t.account);
2386 env.fund(t.fundXrp, acct);
2390 env.require(
offers(gw, 0));
2393 auto const book = t.bookAmount;
2395 env(offer(gw,
XRP(book), USD(book)));
2400 if (t.preTrust == gwPreTrust)
2401 env(trust(gw, acct[
"USD"](1)));
2406 if (t.preTrust == acctPreTrust)
2407 env(trust(acct, USD(1)));
2413 auto const acctOffer = t.offerAmount;
2414 env(offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2419 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2421 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2422 env.require(
offers(acct, t.offers));
2423 env.require(
owners(acct, t.owners));
2426 BEAST_EXPECT(acctOffers.size() == t.offers);
2427 if (acctOffers.size() && t.offers)
2429 auto const& acctOffer = *(acctOffers.front());
2431 auto const leftover = t.offerAmount - t.bookAmount;
2433 BEAST_EXPECT(acctOffer[
sfTakerPays] == USD(leftover));
2436 if (t.preTrust == noPreTrust)
2438 if (t.balanceUsd.value().signum())
2446 auto const sleTrust =
2448 BEAST_EXPECT(!sleTrust);
2463 testcase(
"XRP Direct Crossing");
2465 using namespace jtx;
2467 auto const gw =
Account(
"gateway");
2468 auto const alice =
Account(
"alice");
2469 auto const bob =
Account(
"bob");
2470 auto const USD = gw[
"USD"];
2472 auto const usdOffer = USD(1000);
2473 auto const xrpOffer =
XRP(1000);
2475 Env env{*
this, features};
2477 env.fund(
XRP(1000000), gw, bob);
2481 auto const fee = env.current()->fees().base;
2488 env(trust(alice, usdOffer));
2492 env(pay(gw, alice, usdOffer));
2499 auto const alicesXRP = env.balance(alice);
2500 auto const bobsXRP = env.balance(bob);
2502 env(offer(alice, xrpOffer, usdOffer));
2504 env(offer(bob, usdOffer, xrpOffer));
2518 env(offer(alice, USD(999),
XRP(999)));
2519 env(offer(bob, xrpOffer, usdOffer));
2522 env.require(
balance(alice, USD(999)));
2523 env.require(
balance(bob, USD(1)));
2524 env.require(
offers(alice, 0));
2528 BEAST_EXPECT(bobsOffers.size() == 1);
2529 auto const& bobsOffer = *(bobsOffers.front());
2540 testcase(
"Direct Crossing");
2542 using namespace jtx;
2544 auto const gw =
Account(
"gateway");
2545 auto const alice =
Account(
"alice");
2546 auto const bob =
Account(
"bob");
2547 auto const USD = gw[
"USD"];
2548 auto const EUR = gw[
"EUR"];
2550 auto const usdOffer = USD(1000);
2551 auto const eurOffer = EUR(1000);
2553 Env env{*
this, features};
2555 env.fund(
XRP(1000000), gw);
2559 auto const fee = env.current()->fees().base;
2567 env(trust(alice, usdOffer));
2568 env(trust(bob, eurOffer));
2571 env(pay(gw, alice, usdOffer));
2572 env(pay(gw, bob, eurOffer));
2580 env(offer(alice, eurOffer, usdOffer));
2581 env(offer(bob, usdOffer, eurOffer));
2598 env(offer(bob, eurOffer, usdOffer));
2601 env(offer(alice, USD(999), eurOffer));
2604 env.require(
offers(alice, 0));
2605 env.require(
offers(bob, 1));
2607 env.require(
balance(alice, USD(999)));
2608 env.require(
balance(alice, EUR(1)));
2609 env.require(
balance(bob, USD(1)));
2610 env.require(
balance(bob, EUR(999)));
2614 if (BEAST_EXPECT(bobsOffers.size() == 1))
2616 auto const& bobsOffer = *(bobsOffers.front());
2624 env(offer(alice, USD(1), EUR(1)));
2627 env.require(
balance(alice, USD(1000)));
2630 env.require(
balance(bob, EUR(1000)));
2631 env.require(
offers(alice, 0));
2632 env.require(
offers(bob, 0));
2635 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2636 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2640 env(offer(alice, EUR(999), usdOffer));
2643 env(offer(bob, usdOffer, eurOffer));
2646 env.require(
offers(alice, 0));
2647 env.require(
offers(bob, 0));
2649 env.require(
balance(alice, USD(0)));
2650 env.require(
balance(alice, EUR(999)));
2651 env.require(
balance(bob, USD(1000)));
2652 env.require(
balance(bob, EUR(1)));
2658 testcase(
"Bridged Crossing");
2660 using namespace jtx;
2662 auto const gw =
Account(
"gateway");
2663 auto const alice =
Account(
"alice");
2664 auto const bob =
Account(
"bob");
2665 auto const carol =
Account(
"carol");
2666 auto const USD = gw[
"USD"];
2667 auto const EUR = gw[
"EUR"];
2669 auto const usdOffer = USD(1000);
2670 auto const eurOffer = EUR(1000);
2672 Env env{*
this, features};
2674 env.fund(
XRP(1000000), gw, alice, bob, carol);
2677 env(trust(alice, usdOffer));
2678 env(trust(carol, eurOffer));
2680 env(pay(gw, alice, usdOffer));
2681 env(pay(gw, carol, eurOffer));
2690 env(offer(alice,
XRP(1000), usdOffer));
2691 env(offer(bob, eurOffer,
XRP(1000)));
2692 auto const bobXrpBalance = env.balance(bob);
2696 env(offer(carol, USD(400), EUR(400)));
2709 BEAST_EXPECT(alicesOffers.size() == 1);
2710 auto const& alicesOffer = *(alicesOffers.front());
2713 BEAST_EXPECT(alicesOffer[
sfTakerGets] == USD(600));
2718 BEAST_EXPECT(bobsOffers.size() == 1);
2719 auto const& bobsOffer = *(bobsOffers.front());
2727 env(offer(carol, USD(600), EUR(600)));
2742 if (alicesOffers.size() != 0)
2744 BEAST_EXPECT(alicesOffers.size() == 1);
2745 auto const& alicesOffer = *(alicesOffers.front());
2759 testcase(
"Sell Offer");
2761 using namespace jtx;
2763 auto const gw =
Account(
"gateway");
2764 auto const USD = gw[
"USD"];
2766 Env env{*
this, features};
2768 env.fund(
XRP(10000000), gw);
2771 auto const f = env.current()->fees().base;
2774 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2808 : account(std::move(account_))
2813 , acctGets(acctGets_)
2814 , acctPays(acctPays_)
2816 , spentXrp(spentXrp_)
2817 , finalUsd(finalUsd_)
2820 , takerGets(takerGets_)
2821 , takerPays(takerPays_)
2840 std::move(account_),
2859 TestData
const tests[]{
2862 {
"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},
2863 {
"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)},
2864 {
"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},
2865 {
"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},
2866 {
"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},
2867 {
"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},
2868 {
"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},
2869 {
"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)},
2871 {
"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},
2872 {
"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)},
2873 {
"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},
2874 {
"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},
2875 {
"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},
2876 {
"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)},
2877 {
"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)},
2881 auto const zeroUsd = USD(0);
2882 for (
auto const& t : tests)
2885 env.require(
offers(gw, 0));
2887 auto const acct =
Account(t.account);
2889 env.fund(t.fundXrp, acct);
2895 if (t.fundUSD != zeroUsd)
2897 env(trust(acct, t.fundUSD));
2899 env(pay(gw, acct, t.fundUSD));
2903 env(offer(gw, t.gwGets, t.gwPays));
2908 env(offer(acct, t.acctGets, t.acctPays,
tfSell),
ter(t.tec));
2913 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2915 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2916 env.require(
offers(acct, t.offers));
2917 env.require(
owners(acct, t.owners));
2922 if (acctOffers.size() > 0)
2924 BEAST_EXPECT(acctOffers.size() == 1);
2925 auto const& acctOffer = *(acctOffers.front());
2928 BEAST_EXPECT(acctOffer[
sfTakerGets] == t.takerGets);
2929 BEAST_EXPECT(acctOffer[
sfTakerPays] == t.takerPays);
2946 testcase(
"Combine tfSell with tfFillOrKill");
2948 using namespace jtx;
2950 auto const gw =
Account(
"gateway");
2951 auto const alice =
Account(
"alice");
2952 auto const bob =
Account(
"bob");
2953 auto const USD = gw[
"USD"];
2955 Env env{*
this, features};
2957 env.fund(
XRP(10000000), gw, alice, bob);
2960 TER const killedCode{
2964 env(trust(bob, USD(200)));
2966 env(pay(gw, bob, USD(100)));
2968 env(offer(bob,
XRP(2000), USD(20)));
2976 env.require(
offers(alice, 0));
2977 env.require(
balance(bob, USD(100)));
2984 env.require(
balance(alice, USD(20)));
2985 env.require(
offers(alice, 0));
2986 env.require(
balance(bob, USD(80)));
2991 env(offer(bob,
XRP(2000), USD(20)));
2995 env.require(
balance(alice, USD(35)));
2996 env.require(
offers(alice, 0));
2997 env.require(
balance(bob, USD(65)));
3009 env.require(
balance(alice, USD(35)));
3010 env.require(
offers(alice, 0));
3011 env.require(
balance(bob, USD(65)));
3020 env.require(
balance(alice, USD(40)));
3021 env.require(
offers(alice, 0));
3022 env.require(
balance(bob, USD(60)));
3029 testcase(
"Transfer Rate Offer");
3031 using namespace jtx;
3033 auto const gw1 =
Account(
"gateway1");
3034 auto const USD = gw1[
"USD"];
3036 Env env{*
this, features};
3039 auto const fee = env.current()->fees().base;
3041 env.fund(
XRP(100000), gw1);
3044 env(
rate(gw1, 1.25));
3046 auto const ann =
Account(
"ann");
3047 auto const bob =
Account(
"bob");
3051 env(trust(ann, USD(200)));
3052 env(trust(bob, USD(200)));
3055 env(pay(gw1, bob, USD(125)));
3064 env(offer(bob,
XRP(1), USD(100)));
3067 env(offer(ann, USD(100),
XRP(1)));
3070 env.require(
balance(ann, USD(100)));
3072 env.require(
offers(ann, 0));
3074 env.require(
balance(bob, USD(0)));
3076 env.require(
offers(bob, 0));
3081 auto const che =
Account(
"che");
3082 auto const deb =
Account(
"deb");
3086 env(trust(che, USD(200)));
3087 env(trust(deb, USD(200)));
3090 env(pay(gw1, deb, USD(125)));
3093 env(offer(che, USD(100),
XRP(1)));
3096 env(offer(deb,
XRP(1), USD(100)));
3099 env.require(
balance(che, USD(100)));
3101 env.require(
offers(che, 0));
3103 env.require(
balance(deb, USD(0)));
3105 env.require(
offers(deb, 0));
3108 auto const eve =
Account(
"eve");
3109 auto const fyn =
Account(
"fyn");
3111 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3114 env(trust(eve, USD(1000)));
3115 env(trust(fyn, USD(1000)));
3118 env(pay(gw1, eve, USD(100)));
3119 env(pay(gw1, fyn, USD(100)));
3125 env(offer(eve, USD(10),
XRP(4000)));
3129 env(offer(fyn,
XRP(2000), USD(5)));
3132 env.require(
balance(eve, USD(105)));
3135 BEAST_EXPECT(evesOffers.size() == 1);
3136 if (evesOffers.size() != 0)
3138 auto const& evesOffer = *(evesOffers.front());
3145 env.require(
balance(fyn, USD(93.75)));
3147 env.require(
offers(fyn, 0));
3150 auto const gw2 =
Account(
"gateway2");
3151 auto const EUR = gw2[
"EUR"];
3153 env.fund(
XRP(100000), gw2);
3156 env(
rate(gw2, 1.5));
3161 auto const gay =
Account(
"gay");
3162 auto const hal =
Account(
"hal");
3163 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3166 env(trust(gay, USD(200)));
3167 env(trust(gay, EUR(200)));
3168 env(trust(hal, USD(200)));
3169 env(trust(hal, EUR(200)));
3172 env(pay(gw1, gay, USD(125)));
3173 env(pay(gw2, hal, EUR(150)));
3176 env(offer(gay, EUR(100), USD(100)));
3179 env(offer(hal, USD(100), EUR(100)));
3182 env.require(
balance(gay, USD(0)));
3183 env.require(
balance(gay, EUR(100)));
3185 env.require(
offers(gay, 0));
3187 env.require(
balance(hal, USD(100)));
3188 env.require(
balance(hal, EUR(0)));
3190 env.require(
offers(hal, 0));
3194 auto const ivy =
Account(
"ivy");
3195 auto const joe =
Account(
"joe");
3196 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3205 env(pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3206 env(pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3208 env.require(
balance(ivy, USD(300)));
3209 env.require(
balance(joe, EUR(250)));
3211 env(offer(ivy, EUR(100), USD(200)));
3214 env(offer(joe, USD(200), EUR(100)));
3217 env.require(
balance(ivy, USD(50)));
3218 env.require(
balance(ivy, EUR(100)));
3220 env.require(
offers(ivy, 0));
3222 env.require(
balance(joe, USD(200)));
3223 env.require(
balance(joe, EUR(100)));
3225 env.require(
offers(joe, 0));
3229 auto const kim =
Account(
"kim");
3230 auto const K_BUX = kim[
"BUX"];
3231 auto const lex =
Account(
"lex");
3232 auto const meg =
Account(
"meg");
3233 auto const ned =
Account(
"ned");
3234 auto const N_BUX = ned[
"BUX"];
3237 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3240 env(trust(lex, K_BUX(400)));
3242 env(trust(meg, N_BUX(100)));
3244 env(pay(ned, lex, N_BUX(100)));
3246 env.require(
balance(lex, N_BUX(100)));
3248 env(pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3253 env.require(
balance(lex, K_BUX(72)));
3254 env.require(
balance(lex, N_BUX(40)));
3256 env.require(
balance(meg, N_BUX(60)));
3261 env(offer(lex, K_BUX(30), N_BUX(30)));
3264 env(offer(kim, N_BUX(30), K_BUX(30)));
3268 env.require(
balance(kim, N_BUX(30)));
3269 env.require(
balance(lex, K_BUX(102)));
3270 env.require(
balance(lex, N_BUX(10)));
3272 env.require(
balance(meg, N_BUX(60)));
3273 env.require(
balance(ned, K_BUX(-30)));
3278 auto const ova =
Account(
"ova");
3279 auto const pat =
Account(
"pat");
3280 auto const qae =
Account(
"qae");
3281 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3287 env(trust(ova, USD(200)));
3288 env(trust(ova, EUR(200)));
3289 env(trust(pat, USD(200)));
3290 env(trust(pat, EUR(200)));
3291 env(trust(qae, USD(200)));
3292 env(trust(qae, EUR(200)));
3295 env(pay(gw1, ova, USD(125)));
3296 env(pay(gw2, qae, EUR(150)));
3299 env(offer(ova,
XRP(2), USD(100)));
3300 env(offer(pat, EUR(100),
XRP(2)));
3303 env(offer(qae, USD(100), EUR(100)));
3306 env.require(
balance(ova, USD(0)));
3307 env.require(
balance(ova, EUR(0)));
3312 if (ovasOffers.size() != 0)
3314 BEAST_EXPECT(ovasOffers.size() == 1);
3315 auto const& ovasOffer = *(ovasOffers.front());
3322 env.require(
balance(pat, USD(0)));
3323 env.require(
balance(pat, EUR(100)));
3325 env.require(
offers(pat, 0));
3327 env.require(
balance(qae, USD(100)));
3328 env.require(
balance(qae, EUR(0)));
3330 env.require(
offers(qae, 0));
3351 using namespace jtx;
3353 auto const gw =
Account(
"gateway");
3354 auto const USD = gw[
"USD"];
3356 Env env{*
this, features};
3359 auto const fee = env.current()->fees().base;
3360 auto const startBalance =
XRP(1000000);
3362 env.fund(startBalance + (
fee * 4), gw);
3365 env(offer(gw, USD(60),
XRP(600)));
3367 env(offer(gw, USD(60),
XRP(600)));
3369 env(offer(gw, USD(60),
XRP(600)));
3372 env.require(
owners(gw, 3));
3373 env.require(
balance(gw, startBalance +
fee));
3376 BEAST_EXPECT(gwOffers.size() == 3);
3377 for (
auto const& offerPtr : gwOffers)
3379 auto const& offer = *offerPtr;
3387 env(offer(gw,
XRP(1000), USD(100)));
3389 env.require(
owners(gw, 1));
3390 env.require(
offers(gw, 1));
3391 env.require(
balance(gw, startBalance));
3394 BEAST_EXPECT(gwOffers.size() == 1);
3395 for (
auto const& offerPtr : gwOffers)
3397 auto const& offer = *offerPtr;
3407 using namespace jtx;
3409 auto const gw1 =
Account(
"gateway1");
3410 auto const gw2 =
Account(
"gateway2");
3411 auto const alice =
Account(
"alice");
3412 auto const USD = gw1[
"USD"];
3413 auto const EUR = gw2[
"EUR"];
3415 Env env{*
this, features};
3417 env.fund(
XRP(1000000), gw1, gw2);
3421 auto const f = env.current()->fees().base;
3435 TestData
const tests[]{
3446 for (
auto const& t : tests)
3448 auto const acct =
Account{t.acct};
3449 env.fund(t.fundXRP, acct);
3452 env(trust(acct, USD(1000)));
3453 env(trust(acct, EUR(1000)));
3456 if (t.fundUSD > USD(0))
3457 env(pay(gw1, acct, t.fundUSD));
3458 if (t.fundEUR > EUR(0))
3459 env(pay(gw2, acct, t.fundEUR));
3462 env(offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3466 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3467 env.require(
owners(acct, 2 + offerCount));
3468 env.require(
balance(acct, t.fundUSD));
3469 env.require(
balance(acct, t.fundEUR));
3472 BEAST_EXPECT(acctOffers.size() == offerCount);
3473 for (
auto const& offerPtr : acctOffers)
3475 auto const& offer = *offerPtr;
3481 env(offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3485 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3486 env.require(
owners(acct, 2 + offerCount));
3487 env.require(
balance(acct, t.fundUSD));
3488 env.require(
balance(acct, t.fundEUR));
3491 BEAST_EXPECT(acctOffers.size() == offerCount);
3492 for (
auto const& offerPtr : acctOffers)
3494 auto const& offer = *offerPtr;
3519 testcase(
"Self Cross Offer");
3531 using namespace jtx;
3533 Env env{*
this, features};
3535 auto const alice =
Account(
"alice");
3536 auto const bob =
Account(
"bob");
3537 auto const USD = bob[
"USD"];
3538 auto const f = env.current()->fees().base;
3540 env.fund(
XRP(50000) + f, alice, bob);
3543 env(offer(alice, USD(5000),
XRP(50000)));
3547 env(offer(bob,
XRP(50000), USD(5000)));
3553 env.require(
owners(alice, 1));
3554 env.require(
lines(alice, 1));
3559 BEAST_EXPECT(bobOffers.size() == 1);
3560 for (
auto const& offerPtr : bobOffers)
3562 auto const& offer = *offerPtr;
3575 testcase(
"Bad path assert");
3577 using namespace jtx;
3584 auto const fee = env.current()->fees().base;
3587 auto const ann =
Account(
"ann");
3588 auto const A_BUX = ann[
"BUX"];
3589 auto const bob =
Account(
"bob");
3590 auto const cam =
Account(
"cam");
3591 auto const dan =
Account(
"dan");
3592 auto const D_BUX = dan[
"BUX"];
3595 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3598 env(trust(bob, A_BUX(400)));
3600 env(trust(cam, D_BUX(100)));
3602 env(pay(dan, bob, D_BUX(100)));
3604 env.require(
balance(bob, D_BUX(100)));
3606 env(pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3611 env.require(
balance(bob, A_BUX(72)));
3612 env.require(
balance(bob, D_BUX(40)));
3614 env.require(
balance(cam, D_BUX(60)));
3618 env(offer(bob, A_BUX(30), D_BUX(30)));
3621 env(trust(ann, D_BUX(100)));
3625 env(pay(ann, ann, D_BUX(30)),
3632 env.require(
balance(ann, D_BUX(0)));
3633 env.require(
balance(bob, A_BUX(72)));
3634 env.require(
balance(bob, D_BUX(40)));
3636 env.require(
balance(cam, D_BUX(60)));
3637 env.require(
balance(dan, A_BUX(0)));
3649 testcase(
"Direct to Direct path");
3651 using namespace jtx;
3653 Env env{*
this, features};
3655 auto const ann =
Account(
"ann");
3656 auto const bob =
Account(
"bob");
3657 auto const cam =
Account(
"cam");
3658 auto const A_BUX = ann[
"BUX"];
3659 auto const B_BUX = bob[
"BUX"];
3661 auto const fee = env.current()->fees().base;
3662 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3665 env(trust(ann, B_BUX(40)));
3666 env(trust(cam, A_BUX(40)));
3667 env(trust(cam, B_BUX(40)));
3670 env(pay(ann, cam, A_BUX(35)));
3671 env(pay(bob, cam, B_BUX(35)));
3673 env(offer(bob, A_BUX(30), B_BUX(30)));
3679 env(offer(cam, A_BUX(29), B_BUX(30),
tfPassive));
3681 env.require(
balance(cam, A_BUX(35)));
3682 env.require(
balance(cam, B_BUX(35)));
3683 env.require(
offers(cam, 1));
3686 env(offer(cam, B_BUX(30), A_BUX(30)));
3689 env.require(
balance(bob, A_BUX(30)));
3690 env.require(
balance(cam, A_BUX(5)));
3691 env.require(
balance(cam, B_BUX(65)));
3692 env.require(
offers(cam, 0));
3701 testcase(
"Self crossing low quality offer");
3703 using namespace jtx;
3705 Env env{*
this, features};
3707 auto const ann =
Account(
"ann");
3708 auto const gw =
Account(
"gateway");
3709 auto const BTC = gw[
"BTC"];
3711 auto const fee = env.current()->fees().base;
3716 env(
rate(gw, 1.002));
3717 env(trust(ann, BTC(10)));
3720 env(pay(gw, ann, BTC(2.856)));
3723 env(offer(ann,
drops(365611702030), BTC(5.713)));
3727 env(offer(ann, BTC(0.687),
drops(20000000000)),
3738 testcase(
"Offer In Scaling");
3740 using namespace jtx;
3742 Env env{*
this, features};
3744 auto const gw =
Account(
"gateway");
3745 auto const alice =
Account(
"alice");
3746 auto const bob =
Account(
"bob");
3747 auto const CNY = gw[
"CNY"];
3749 auto const fee = env.current()->fees().base;
3754 env(trust(bob, CNY(500)));
3757 env(pay(gw, bob, CNY(300)));
3760 env(offer(bob,
drops(5400000000), CNY(216.054)));
3764 env(offer(alice, CNY(13562.0001),
drops(339000000000)));
3768 BEAST_EXPECT(aliceOffers.size() == 1);
3769 for (
auto const& offerPtr : aliceOffers)
3771 auto const& offer = *offerPtr;
3774 BEAST_EXPECT(offer[
sfTakerPays] == CNY(13345.9461));
3784 testcase(
"Offer In Scaling With Xfer Rate");
3786 using namespace jtx;
3788 Env env{*
this, features};
3790 auto const gw =
Account(
"gateway");
3791 auto const alice =
Account(
"alice");
3792 auto const bob =
Account(
"bob");
3793 auto const BTC = gw[
"BTC"];
3794 auto const JPY = gw[
"JPY"];
3796 auto const fee = env.current()->fees().base;
3801 env(
rate(gw, 1.002));
3802 env(trust(alice, JPY(4000)));
3803 env(trust(bob, BTC(2)));
3806 env(pay(gw, alice, JPY(3699.034802280317)));
3807 env(pay(gw, bob, BTC(1.156722559140311)));
3810 env(offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3814 env(offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3818 BEAST_EXPECT(aliceOffers.size() == 1);
3819 for (
auto const& offerPtr : aliceOffers)
3821 auto const& offer = *offerPtr;
3826 BEAST_EXPECT(offer[
sfTakerPays] == BTC(0.035378));
3836 testcase(
"Offer Threshold With Reduced Funds");
3838 using namespace jtx;
3840 Env env{*
this, features};
3842 auto const gw1 =
Account(
"gw1");
3843 auto const gw2 =
Account(
"gw2");
3844 auto const alice =
Account(
"alice");
3845 auto const bob =
Account(
"bob");
3846 auto const USD = gw1[
"USD"];
3847 auto const JPY = gw2[
"JPY"];
3849 auto const fee = env.current()->fees().base;
3851 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3854 env(
rate(gw1, 1.002));
3855 env(trust(alice, USD(1000)));
3856 env(trust(bob, JPY(100000)));
3883 BEAST_EXPECT(aliceOffers.size() == 1);
3884 for (
auto const& offerPtr : aliceOffers)
3886 auto const& offer = *offerPtr;
3900 testcase(
"Tiny Offer");
3902 using namespace jtx;
3904 Env env{*
this, features};
3906 auto const gw =
Account(
"gw");
3907 auto const alice =
Account(
"alice");
3908 auto const bob =
Account(
"bob");
3909 auto const CNY = gw[
"CNY"];
3910 auto const fee = env.current()->fees().base;
3911 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3913 env.fund(startXrpBalance, gw, alice, bob);
3916 env(trust(bob, CNY(100000)));
3928 STAmount const bobsCnyStartBalance{
3930 env(pay(gw, bob, bobsCnyStartBalance));
3939 env.require(
balance(alice, alicesCnyOffer));
3941 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
3948 testcase(
"Self Pay Xfer Fee");
3984 using namespace jtx;
3986 Env env{*
this, features};
3988 auto const gw =
Account(
"gw");
3989 auto const BTC = gw[
"BTC"];
3990 auto const USD = gw[
"USD"];
3991 auto const startXrpBalance =
XRP(4000000);
3993 env.fund(startXrpBalance, gw);
3996 env(
rate(gw, 1.25));
4022 TestData
const tests[]{
4024 {0, 0, 1, BTC(20), {{
"ann", 0,
drops(3899999999960), BTC(20.0), USD(3000)}, {
"abe", 0,
drops(4099999999970), BTC( 0), USD(750)}}},
4025 {0, 1, 0, BTC(20), {{
"bev", 0,
drops(4099999999960), BTC( 7.5), USD(2000)}, {
"bob", 0,
drops(3899999999970), BTC(10), USD( 0)}}},
4026 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(3999999999950), BTC(20.0), USD(2000)} }},
4027 {0, 1, 0, BTC( 5), {{
"deb", 1,
drops(4039999999960), BTC( 0.0), USD(2000)}, {
"dan", 1,
drops(3959999999970), BTC( 4), USD( 0)}}},
4031 for (
auto const& t : tests)
4033 Account const&
self = t.actors[t.self].acct;
4034 Account const& leg0 = t.actors[t.leg0].acct;
4035 Account const& leg1 = t.actors[t.leg1].acct;
4037 for (
auto const& actor : t.actors)
4039 env.fund(
XRP(4000000), actor.acct);
4042 env(trust(actor.acct, BTC(40)));
4043 env(trust(actor.acct, USD(8000)));
4047 env(pay(gw,
self, t.btcStart));
4048 env(pay(gw,
self, USD(2000)));
4049 if (
self.
id() != leg1.
id())
4050 env(pay(gw, leg1, USD(2000)));
4064 env(offer(
self, USD(1000), BTC(10)));
4069 for (
auto const& actor : t.actors)
4075 actorOffers.begin(),
4077 actorOffers.begin(),
4080 return (*offer)[sfTakerGets].signum() == 0;
4082 BEAST_EXPECT(offerCount == actor.offers);
4084 env.require(
balance(actor.acct, actor.xrp));
4085 env.require(
balance(actor.acct, actor.btc));
4086 env.require(
balance(actor.acct, actor.usd));
4102 testcase(
"Self Pay Unlimited Funds");
4134 using namespace jtx;
4136 Env env{*
this, features};
4138 auto const gw =
Account(
"gw");
4139 auto const BTC = gw[
"BTC"];
4140 auto const USD = gw[
"USD"];
4141 auto const startXrpBalance =
XRP(4000000);
4143 env.fund(startXrpBalance, gw);
4146 env(
rate(gw, 1.25));
4172 TestData
const takerTests[]{
4174 {0, 0, 1, BTC(5), {{
"deb", 0,
drops(3899999999960), BTC(5), USD(3000)}, {
"dan", 0,
drops(4099999999970), BTC(0), USD(750)}}},
4175 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(3999999999950), BTC(5), USD(2000)} }}
4178 TestData
const flowTests[]{
4180 {0, 0, 1, BTC(5), {{
"gay", 1,
drops(3949999999960), BTC(5), USD(2500)}, {
"gar", 1,
drops(4049999999970), BTC(0), USD(1375)}}},
4181 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(3999999999950), BTC(5), USD(2000)} }}
4188 for (
auto const& t : tests)
4190 Account const&
self = t.actors[t.self].acct;
4191 Account const& leg0 = t.actors[t.leg0].acct;
4192 Account const& leg1 = t.actors[t.leg1].acct;
4194 for (
auto const& actor : t.actors)
4196 env.fund(
XRP(4000000), actor.acct);
4199 env(trust(actor.acct, BTC(40)));
4200 env(trust(actor.acct, USD(8000)));
4204 env(pay(gw,
self, t.btcStart));
4205 env(pay(gw,
self, USD(2000)));
4206 if (
self.
id() != leg1.
id())
4207 env(pay(gw, leg1, USD(2000)));
4221 env(offer(
self, USD(1000), BTC(10)));
4226 for (
auto const& actor : t.actors)
4232 actorOffers.begin(),
4234 actorOffers.begin(),
4237 return (*offer)[sfTakerGets].signum() == 0;
4239 BEAST_EXPECT(offerCount == actor.offers);
4241 env.require(
balance(actor.acct, actor.xrp));
4242 env.require(
balance(actor.acct, actor.btc));
4243 env.require(
balance(actor.acct, actor.usd));
4259 testcase(
"lsfRequireAuth");
4261 using namespace jtx;
4263 Env env{*
this, features};
4265 auto const gw =
Account(
"gw");
4266 auto const alice =
Account(
"alice");
4267 auto const bob =
Account(
"bob");
4268 auto const gwUSD = gw[
"USD"];
4269 auto const aliceUSD = alice[
"USD"];
4270 auto const bobUSD = bob[
"USD"];
4272 env.fund(
XRP(400000), gw, alice, bob);
4281 env(trust(bob, gwUSD(100)));
4283 env(trust(alice, gwUSD(100)));
4285 env(offer(alice, gwUSD(40),
XRP(4000)));
4288 env.require(
offers(alice, 1));
4289 env.require(
balance(alice, gwUSD(0)));
4291 env(pay(gw, bob, gwUSD(50)));
4294 env.require(
balance(bob, gwUSD(50)));
4297 env(offer(bob,
XRP(4000), gwUSD(40)));
4300 env.require(
offers(alice, 0));
4301 env.require(
balance(alice, gwUSD(40)));
4303 env.require(
offers(bob, 0));
4304 env.require(
balance(bob, gwUSD(10)));
4310 testcase(
"Missing Auth");
4330 using namespace jtx;
4332 Env env{*
this, features};
4334 auto const gw =
Account(
"gw");
4335 auto const alice =
Account(
"alice");
4336 auto const bob =
Account(
"bob");
4337 auto const gwUSD = gw[
"USD"];
4338 auto const aliceUSD = alice[
"USD"];
4339 auto const bobUSD = bob[
"USD"];
4341 env.fund(
XRP(400000), gw, alice, bob);
4344 env(offer(alice, gwUSD(40),
XRP(4000)));
4347 env.require(
offers(alice, 1));
4354 env(trust(bob, gwUSD(100)));
4357 env(pay(gw, bob, gwUSD(50)));
4359 env.require(
balance(bob, gwUSD(50)));
4367 env(offer(bob,
XRP(4000), gwUSD(40)));
4373 env.require(
offers(alice, 0));
4378 env.require(
offers(bob, 1));
4379 env.require(
balance(bob, gwUSD(50)));
4384 env.require(
balance(alice, gwUSD(40)));
4385 env.require(
offers(bob, 0));
4386 env.require(
balance(bob, gwUSD(10)));
4398 env.require(
offers(alice, 0));
4401 env.require(
offers(bob, 1));
4402 env.require(
balance(bob, gwUSD(50)));
4406 env(trust(gw, aliceUSD(100)));
4412 env.require(
offers(alice, 0));
4413 env.require(
balance(alice, gwUSD(0)));
4415 env.require(
offers(bob, 1));
4416 env.require(
balance(bob, gwUSD(50)));
4421 env.require(
offers(bob, 0));
4429 env(offer(alice, gwUSD(40),
XRP(4000)));
4432 env.require(
offers(alice, 1));
4435 env(offer(bob,
XRP(4000), gwUSD(40)));
4438 env.require(
offers(alice, 0));
4439 env.require(
balance(alice, gwUSD(40)));
4441 env.require(
offers(bob, 0));
4442 env.require(
balance(bob, gwUSD(10)));
4448 testcase(
"RippleConnect Smoketest payment flow");
4449 using namespace jtx;
4451 Env env{*
this, features};
4461 auto const hotUS =
Account(
"hotUS");
4462 auto const coldUS =
Account(
"coldUS");
4463 auto const hotEU =
Account(
"hotEU");
4464 auto const coldEU =
Account(
"coldEU");
4465 auto const mm =
Account(
"mm");
4467 auto const USD = coldUS[
"USD"];
4468 auto const EUR = coldEU[
"EUR"];
4470 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4474 for (
auto const& cold : {coldUS, coldEU})
4490 env(trust(coldUS, USD(0), hotUS,
tfSetfAuth));
4491 env(trust(coldEU, EUR(0), hotEU,
tfSetfAuth));
4497 env(pay(coldUS, hotUS, USD(5000000)));
4498 env(pay(coldEU, hotEU, EUR(5000000)));
4499 env(pay(coldUS, mm, USD(5000000)));
4500 env(pay(coldEU, mm, EUR(5000000)));
4504 float const rate = 0.9f;
4505 env(offer(mm, EUR(4000000 *
rate), USD(4000000)),
4508 float const reverseRate = 1.0f /
rate * 1.00101f;
4509 env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4516 jvParams[jss::destination_account] = coldEU.human();
4517 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4518 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4519 jvParams[jss::destination_amount][jss::value] = 10;
4520 jvParams[jss::source_account] = hotUS.human();
4523 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4525 BEAST_EXPECT(jrr[jss::status] ==
"success");
4527 jrr[jss::alternatives].isArray() &&
4528 jrr[jss::alternatives].size() > 0);
4531 env(pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4537 testcase(
"Self Auth");
4539 using namespace jtx;
4541 Env env{*
this, features};
4543 auto const gw =
Account(
"gw");
4544 auto const alice =
Account(
"alice");
4545 auto const gwUSD = gw[
"USD"];
4546 auto const aliceUSD = alice[
"USD"];
4548 env.fund(
XRP(400000), gw, alice);
4552 env(offer(gw, gwUSD(40),
XRP(4000)));
4555 env.require(
offers(gw, 1));
4564 env.require(
offers(gw, 0));
4576 env(offer(gw, gwUSD(40),
XRP(4000)),
4580 env.require(
offers(gw, preauth ? 1 : 0));
4588 env(trust(alice, gwUSD(100)));
4591 env(pay(gw, alice, gwUSD(50)));
4594 env.require(
balance(alice, gwUSD(50)));
4597 env(offer(alice,
XRP(4000), gwUSD(40)));
4600 env.require(
offers(alice, 0));
4601 env.require(
balance(alice, gwUSD(10)));
4603 env.require(
offers(gw, 0));
4610 using namespace jtx;
4612 testcase(
"Deleted offer issuer");
4614 auto trustLineExists = [](
jtx::Env const& env,
4625 auto const USD = gw[
"USD"];
4626 auto const BUX = alice[
"BUX"];
4628 Env env{*
this, features};
4631 env.
trust(USD(1000), becky);
4632 env(pay(gw, becky, USD(5)));
4634 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4645 env(pay(becky, gw, USD(5)));
4646 env.
trust(USD(0), becky);
4648 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4649 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4650 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4657 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4659 if (gwSeq + 255 > openLedgerSeq)
4660 return gwSeq - openLedgerSeq + 255;
4664 for (
int i = 0; i < delta; ++i)
4681 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4682 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4688 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4689 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4694 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4698 env.
trust(BUX(1000), carol);
4699 env(pay(alice, carol, BUX(2)));
4701 env(offer(alice, BUX(2),
XRP(2)));
4708 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4709 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4715 testcase(
"Tick Size");
4717 using namespace jtx;
4721 Env env{*
this, features};
4722 auto const gw =
Account{
"gateway"};
4723 env.fund(
XRP(10000), gw);
4725 auto txn =
noop(gw);
4731 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == Quality::minTickSize);
4736 BEAST_EXPECT(!env.le(gw)->isFieldPresent(
sfTickSize));
4741 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == Quality::maxTickSize - 1);
4749 BEAST_EXPECT(!env.le(gw)->isFieldPresent(
sfTickSize));
4752 Env env{*
this, features};
4753 auto const gw =
Account{
"gateway"};
4754 auto const alice =
Account{
"alice"};
4755 auto const XTS = gw[
"XTS"];
4756 auto const XXX = gw[
"XXX"];
4758 env.fund(
XRP(10000), gw, alice);
4762 auto txn =
noop(gw);
4765 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == 5);
4768 env(trust(alice, XTS(1000)));
4769 env(trust(alice, XXX(1000)));
4771 env(pay(gw, alice, alice[
"XTS"](100)));
4772 env(pay(gw, alice, alice[
"XXX"](100)));
4774 env(offer(alice, XTS(10), XXX(30)));
4775 env(offer(alice, XTS(30), XXX(10)));
4776 env(offer(alice, XTS(10), XXX(30)),
json(jss::Flags,
tfSell));
4777 env(offer(alice, XTS(30), XXX(10)),
json(jss::Flags,
tfSell));
4782 if (sle->getType() == ltOFFER)
4786 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4790 auto it =
offers.begin();
4791 BEAST_EXPECT(it !=
offers.end());
4793 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4794 it->second.second > XXX(29.9994));
4798 BEAST_EXPECT(it !=
offers.end());
4800 it->second.first == XTS(30) && it->second.second == XXX(10));
4804 BEAST_EXPECT(it !=
offers.end());
4806 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4811 BEAST_EXPECT(it !=
offers.end());
4813 it->second.first == XTS(30) && it->second.second == XXX(10));
4815 BEAST_EXPECT(++it ==
offers.end());
4829 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4837 testcase(
"Ticket Offers");
4839 using namespace jtx;
4847 Env env{*
this, features};
4848 auto const gw =
Account{
"gateway"};
4849 auto const alice =
Account{
"alice"};
4850 auto const bob =
Account{
"bob"};
4851 auto const USD = gw[
"USD"];
4853 env.fund(
XRP(10000), gw, alice, bob);
4856 env(trust(alice, USD(1000)));
4857 env(trust(bob, USD(1000)));
4860 env(pay(gw, alice, USD(200)));
4867 env(offer(alice,
XRP(50), USD(50)));
4872 env(ticket::create(alice, 2));
4877 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4878 env(offer(alice,
XRP(50), USD(50)));
4894 BEAST_EXPECT(
offers.size() == 4);
4899 env.require(
balance(alice, USD(200)));
4900 env.require(
owners(alice, 5));
4904 env(offer(bob, USD(50),
XRP(50)));
4910 BEAST_EXPECT(
offers.size() == 3);
4917 env(offer(bob, USD(50),
XRP(50)));
4923 BEAST_EXPECT(
offers.size() == 2);
4929 env(offer(bob, USD(50),
XRP(50)));
4935 BEAST_EXPECT(
offers.size() == 1);
4940 env(offer(bob, USD(50),
XRP(50)));
4946 BEAST_EXPECT(
offers.size() == 0);
4948 env.require(
balance(alice, USD(0)));
4949 env.require(
owners(alice, 1));
4950 env.require(
balance(bob, USD(200)));
4951 env.require(
owners(bob, 1));
4957 testcase(
"Ticket Cancel Offers");
4959 using namespace jtx;
4963 Env env{*
this, features};
4964 auto const gw =
Account{
"gateway"};
4965 auto const alice =
Account{
"alice"};
4966 auto const USD = gw[
"USD"];
4968 env.fund(
XRP(10000), gw, alice);
4971 env(trust(alice, USD(1000)));
4975 env(pay(gw, alice, USD(200)));
4980 env(offer(alice,
XRP(50), USD(50)));
4986 env(ticket::create(alice, 4));
4992 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
4993 env(offer(alice,
XRP(50), USD(50)));
5009 BEAST_EXPECT(
offers.size() == 4);
5014 env.require(
balance(alice, USD(200)));
5015 env.require(
owners(alice, 7));
5025 BEAST_EXPECT(
offers.size() == 3);
5038 BEAST_EXPECT(
offers.size() == 2);
5053 BEAST_EXPECT(
offers.size() == 1);
5071 testcase(
"incorrect assert fixed");
5072 using namespace jtx;
5075 auto const alice =
Account(
"alice");
5076 auto const USD = alice[
"USD"];
5078 env.fund(
XRP(10000), alice);
5080 env(offer(alice,
XRP(100000000000), USD(100000000)));
5150 using namespace jtx;
5157 testAll(
all - takerDryOffer - immediateOfferKilled);
5158 testAll(
all - flowCross - takerDryOffer - immediateOfferKilled);
5159 testAll(
all - flowCross - immediateOfferKilled);
5160 testAll(
all - rmSmallIncreasedQOffers - immediateOfferKilled);
5171 using namespace jtx;
5178 testAll(
all - flowCross - f1513 - immediateOfferKilled);
5179 testAll(
all - flowCross - immediateOfferKilled);