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();
49 auto feeDrops = env.current()->fees().base;
61 jvParams[jss::ledger_index] =
"current";
62 jvParams[jss::ripple_state][jss::currency] = currency;
64 jvParams[jss::ripple_state][jss::accounts].
append(acct_a.
human());
65 jvParams[jss::ripple_state][jss::accounts].
append(acct_b.
human());
67 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
74 jvParams[jss::ledger_index] =
"current";
75 jvParams[jss::account_root] = acct.
human();
77 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
87 jvParams[jss::offer][jss::account] = acct.
human();
88 jvParams[jss::offer][jss::seq] = offer_seq;
90 "json",
"ledger_entry",
to_string(jvParams))[jss::result];
96 Issue const& taker_pays,
97 Issue const& taker_gets)
100 jvbp[jss::ledger_index] =
"current";
105 return env.
rpc(
"json",
"book_offers",
to_string(jvbp))[jss::result];
112 testcase(
"Incorrect Removal of Funded Offers");
124 Env env{*
this, features};
126 auto const gw =
Account{
"gateway"};
127 auto const USD = gw[
"USD"];
128 auto const BTC = gw[
"BTC"];
133 env.fund(
XRP(10000), alice, bob, carol, gw);
134 env.trust(USD(1000), alice, bob, carol);
135 env.trust(BTC(1000), alice, bob, carol);
137 env(
pay(gw, alice, BTC(1000)));
139 env(
pay(gw, carol, USD(1000)));
140 env(
pay(gw, carol, BTC(1000)));
145 env(offer(carol, BTC(49),
XRP(49)));
146 env(offer(carol, BTC(51),
XRP(51)));
150 env(offer(carol,
XRP(50), USD(50)));
151 env(offer(carol,
XRP(50), USD(50)));
154 env(offer(carol, BTC(1), USD(100)));
158 env(
pay(alice, bob, USD(100)),
163 env.require(
balance(bob, USD(100)));
165 !
isOffer(env, carol, BTC(1), USD(100)) &&
172 testcase(
"Removing Canceled Offers");
175 Env env{*
this, features};
177 auto const gw =
Account{
"gateway"};
178 auto const alice =
Account{
"alice"};
179 auto const USD = gw[
"USD"];
181 env.fund(
XRP(10000), alice, gw);
183 env.trust(USD(100), alice);
186 env(
pay(gw, alice, USD(50)));
189 auto const offer1Seq = env.seq(alice);
194 BEAST_EXPECT(
isOffer(env, alice,
XRP(500), USD(100)));
197 auto const offer2Seq = env.seq(alice);
199 env(offer(alice,
XRP(300), USD(100)),
200 json(jss::OfferSequence, offer1Seq),
211 env(offer(alice,
XRP(400), USD(200)),
212 json(jss::OfferSequence, offer1Seq),
221 auto const offer4Seq = env.seq(alice);
225 BEAST_EXPECT(
isOffer(env, alice,
XRP(222), USD(111)));
228 BEAST_EXPECT(env.seq(alice) == offer4Seq + 2);
230 BEAST_EXPECT(!
isOffer(env, alice,
XRP(222), USD(111)));
234 env.require(
offers(alice, 2));
239 env(offer(alice,
XRP(5), USD(2)),
241 json(jss::OfferSequence, offer2Seq),
245 env.require(
offers(alice, 2));
246 BEAST_EXPECT(
isOffer(env, alice,
XRP(300), USD(100)));
247 BEAST_EXPECT(!
isOffer(env, alice,
XRP(5), USD(2)));
253 testcase(
"Tiny payments");
257 using namespace std::chrono_literals;
258 auto const alice =
Account{
"alice"};
259 auto const bob =
Account{
"bob"};
260 auto const carol =
Account{
"carol"};
263 auto const USD = gw[
"USD"];
264 auto const EUR = gw[
"EUR"];
266 Env env{*
this, features};
268 env.fund(
XRP(10000), alice, bob, carol, gw);
269 env.trust(USD(1000), alice, bob, carol);
270 env.trust(EUR(1000), alice, bob, carol);
271 env(
pay(gw, alice, USD(100)));
272 env(
pay(gw, carol, EUR(100)));
278 for (
int i = 0; i < 101; ++i)
279 env(offer(carol, USD(1), EUR(2)));
281 env(
pay(alice, bob, EUR(epsilon)),
path(~EUR),
sendmax(USD(100)));
287 testcase(
"XRP Tiny payments");
305 using namespace std::chrono_literals;
306 auto const alice =
Account{
"alice"};
307 auto const bob =
Account{
"bob"};
308 auto const carol =
Account{
"carol"};
309 auto const dan =
Account{
"dan"};
310 auto const erin =
Account{
"erin"};
313 auto const USD = gw[
"USD"];
314 Env env{*
this, features};
316 env.fund(
XRP(10000), alice, bob, carol, dan, erin, gw);
318 env.trust(USD(1000), alice, bob, carol, dan, erin);
320 env(
pay(gw, carol, USD(0.99999)));
321 env(
pay(gw, dan, USD(1)));
322 env(
pay(gw, erin, USD(1)));
330 env(offer(carol,
drops(1), USD(0.99999)));
333 env(offer(dan,
XRP(100), USD(1)));
342 env(offer(erin,
drops(2), USD(1)));
344 env(
pay(alice, bob, USD(1)),
359 testcase(
"Rm small increased q offers XRP");
367 using namespace std::chrono_literals;
368 auto const alice =
Account{
"alice"};
369 auto const bob =
Account{
"bob"};
370 auto const carol =
Account{
"carol"};
373 auto const USD = gw[
"USD"];
376 for (
auto crossBothOffers : {
false,
true})
378 Env env{*
this, features};
380 env.fund(
XRP(10000), alice, bob, carol, gw);
382 env.trust(USD(1000), alice, bob, carol);
384 auto initialCarolUSD = USD(0.499);
385 env(
pay(gw, carol, initialCarolUSD));
386 env(
pay(gw, bob, USD(100)));
389 env(offer(carol,
drops(1), USD(1)));
398 auto aliceTakerGets = crossBothOffers ?
drops(2) :
drops(1);
399 env(offer(alice, USD(1), aliceTakerGets));
437 for (
auto partialPayment : {
false,
true})
439 Env env{*
this, features};
441 env.fund(
XRP(10000), alice, bob, carol, gw);
443 env.trust(USD(1000), alice, bob, carol);
445 auto const initialCarolUSD = USD(0.999);
446 env(
pay(gw, carol, initialCarolUSD));
448 env(
pay(gw, bob, USD(100)));
450 env(offer(carol,
drops(1), USD(1)));
460 TER const expectedTer =
463 env(
pay(alice, bob, USD(5)),
474 env.require(
offers(carol, 0));
491 env.require(
offers(carol, 0));
507 testcase(
"Rm small increased q offers IOU");
515 using namespace std::chrono_literals;
516 auto const alice =
Account{
"alice"};
517 auto const bob =
Account{
"bob"};
518 auto const carol =
Account{
"carol"};
521 auto const USD = gw[
"USD"];
522 auto const EUR = gw[
"EUR"];
533 for (
auto crossBothOffers : {
false,
true})
535 Env env{*
this, features};
537 env.fund(
XRP(10000), alice, bob, carol, gw);
539 env.trust(USD(1000), alice, bob, carol);
540 env.trust(EUR(1000), alice, bob, carol);
542 auto initialCarolUSD = tinyAmount(USD);
543 env(
pay(gw, carol, initialCarolUSD));
544 env(
pay(gw, bob, USD(100)));
545 env(
pay(gw, alice, EUR(100)));
548 env(offer(carol, EUR(1), USD(10)));
551 env(offer(bob, EUR(1), USD(5),
tfPassive));
558 auto aliceTakerGets = crossBothOffers ? EUR(0.2) : EUR(0.1);
559 env(offer(alice, USD(1), aliceTakerGets));
597 for (
auto partialPayment : {
false,
true})
599 Env env{*
this, features};
601 env.fund(
XRP(10000), alice, bob, carol, gw);
603 env.trust(USD(1000), alice, bob, carol);
604 env.trust(EUR(1000), alice, bob, carol);
607 auto const initialCarolUSD = tinyAmount(USD);
608 env(
pay(gw, carol, initialCarolUSD));
609 env(
pay(gw, bob, USD(100)));
610 env(
pay(gw, alice, EUR(100)));
613 env(offer(carol, EUR(1), USD(2)));
615 env(offer(bob, EUR(2), USD(4),
tfPassive));
623 TER const expectedTer =
626 env(
pay(alice, bob, USD(5)),
637 env.require(
offers(carol, 0));
654 env.require(
offers(carol, 0));
661 BEAST_EXPECT(
isOffer(env, carol, EUR(1), USD(2)));
670 testcase(
"Enforce No Ripple");
674 auto const gw =
Account{
"gateway"};
675 auto const USD = gw[
"USD"];
676 auto const BTC = gw[
"BTC"];
677 auto const EUR = gw[
"EUR"];
685 Env env{*
this, features};
687 auto const gw1 =
Account{
"gw1"};
688 auto const USD1 = gw1[
"USD"];
689 auto const gw2 =
Account{
"gw2"};
690 auto const USD2 = gw2[
"USD"];
692 env.fund(
XRP(10000), alice,
noripple(bob), carol, dan, gw1, gw2);
693 env.trust(USD1(1000), alice, carol, dan);
695 env.trust(USD2(1000), alice, carol, dan);
698 env(
pay(gw1, dan, USD1(50)));
699 env(
pay(gw1, bob, USD1(50)));
700 env(
pay(gw2, bob, USD2(50)));
702 env(offer(dan,
XRP(50), USD1(50)));
704 env(
pay(alice, carol, USD2(50)),
712 Env env{*
this, features};
714 auto const gw1 =
Account{
"gw1"};
715 auto const USD1 = gw1[
"USD"];
716 auto const gw2 =
Account{
"gw2"};
717 auto const USD2 = gw2[
"USD"];
719 env.fund(
XRP(10000), alice, bob, carol, dan, gw1, gw2);
720 env.trust(USD1(1000), alice, bob, carol, dan);
721 env.trust(USD2(1000), alice, bob, carol, dan);
723 env(
pay(gw1, dan, USD1(50)));
724 env(
pay(gw1, bob, USD1(50)));
725 env(
pay(gw2, bob, USD2(50)));
727 env(offer(dan,
XRP(50), USD1(50)));
729 env(
pay(alice, carol, USD2(50)),
735 env.require(
balance(bob, USD1(100)));
736 env.require(
balance(bob, USD2(0)));
737 env.require(
balance(carol, USD2(50)));
744 testcase(
"Insufficient Reserve");
754 auto const gw =
Account{
"gateway"};
755 auto const alice =
Account{
"alice"};
756 auto const bob =
Account{
"bob"};
757 auto const carol =
Account{
"carol"};
758 auto const USD = gw[
"USD"];
760 auto const usdOffer = USD(1000);
761 auto const xrpOffer =
XRP(1000);
765 Env env{*
this, features};
767 env.fund(
XRP(1000000), gw);
769 auto const f = env.current()->fees().base;
770 auto const r =
reserve(env, 0);
772 env.fund(r + f, alice);
783 Env env{*
this, features};
785 env.fund(
XRP(1000000), gw);
787 auto const f = env.current()->fees().base;
788 auto const r =
reserve(env, 0);
790 auto const usdOffer2 = USD(500);
791 auto const xrpOffer2 =
XRP(500);
793 env.fund(r + f + xrpOffer, bob);
795 env.fund(r + f, alice);
801 balance(alice, r - f + xrpOffer2),
813 Env env{*
this, features};
815 env.fund(
XRP(1000000), gw);
817 auto const f = env.current()->fees().base;
818 auto const r =
reserve(env, 0);
820 auto const usdOffer2 = USD(500);
821 auto const xrpOffer2 =
XRP(500);
823 env.fund(r + f + xrpOffer, bob, carol);
827 env.fund(r + f, alice);
833 balance(alice, r - f + xrpOffer),
854 if (sle->getType() == ltOFFER)
855 result.push_back(sle);
863 testcase(
"Fill Modes");
867 auto const startBalance =
XRP(1000000);
868 auto const gw =
Account{
"gateway"};
869 auto const alice =
Account{
"alice"};
870 auto const bob =
Account{
"bob"};
871 auto const USD = gw[
"USD"];
879 for (
auto const& tweakedFeatures :
882 Env env{*
this, tweakedFeatures};
884 auto const f = env.
current()->fees().base;
886 env.fund(startBalance, gw, alice, bob);
889 env(offer(bob, USD(500),
XRP(500)),
907 TER const killedCode{
910 env(offer(alice,
XRP(1000), USD(1000)),
915 balance(alice, startBalance - (f * 2)),
919 balance(bob, startBalance - (f * 2)),
925 env(offer(alice,
XRP(500), USD(500)),
930 balance(alice, startBalance - (f * 3) +
XRP(500)),
934 balance(bob, startBalance - (f * 2) -
XRP(500)),
943 Env env{*
this, features};
945 auto const f = env.current()->fees().base;
947 env.fund(startBalance, gw, alice, bob);
957 env(offer(alice,
XRP(1000), USD(1000)),
963 balance(alice, startBalance - f - f),
970 env(offer(alice,
XRP(1000), USD(1000)),
975 balance(alice, startBalance - f - f - f +
XRP(50)),
986 env(offer(alice,
XRP(50), USD(50)),
991 balance(alice, startBalance - f - f - f - f +
XRP(100)),
995 balance(bob, startBalance - f - f -
XRP(100)),
1003 Env env(*
this, features);
1005 env.
fund(startBalance, gw, alice, bob);
1008 env(
trust(bob, USD(1000)));
1011 env(
pay(gw, bob, USD(1000)));
1014 env(offer(alice, USD(1000),
XRP(2000)));
1018 BEAST_EXPECT(aliceOffers.size() == 1);
1019 for (
auto offerPtr : aliceOffers)
1021 auto const& offer = *offerPtr;
1033 BEAST_EXPECT(bobOffers.size() == 1);
1034 for (
auto offerPtr : bobOffers)
1036 auto const& offer = *offerPtr;
1042 env(offer(gw,
XRP(2000), USD(1000)));
1048 env(offer(gw, USD(1000),
XRP(2000)));
1056 Env env(*
this, features);
1058 env.
fund(startBalance, gw,
"alice",
"bob");
1061 env(
trust(
"bob", USD(1000)));
1064 env(
pay(gw,
"bob", USD(1000)));
1065 env(offer(
"alice", USD(500),
XRP(1001)));
1068 env(offer(
"alice", USD(500),
XRP(1000)));
1072 BEAST_EXPECT(aliceOffers.size() == 2);
1082 BEAST_EXPECT(bobOffers.size() == 1);
1083 for (
auto offerPtr : bobOffers)
1085 auto const& offer = *offerPtr;
1095 testcase(
"Malformed Detection");
1097 using namespace jtx;
1099 auto const startBalance =
XRP(1000000);
1100 auto const gw =
Account{
"gateway"};
1101 auto const alice =
Account{
"alice"};
1102 auto const USD = gw[
"USD"];
1104 Env env{*
this, features};
1106 env.fund(startBalance, gw, alice);
1109 env(offer(alice, USD(1000),
XRP(1000)),
1116 env(offer(alice, USD(1000),
XRP(1000)),
1146 env(offer(alice, USD(1000),
XRP(1000)),
1154 env(offer(alice, USD(1000),
XRP(1000)),
1172 testcase(
"Offer Expiration");
1174 using namespace jtx;
1176 auto const gw =
Account{
"gateway"};
1177 auto const alice =
Account{
"alice"};
1178 auto const bob =
Account{
"bob"};
1179 auto const USD = gw[
"USD"];
1181 auto const startBalance =
XRP(1000000);
1182 auto const usdOffer = USD(1000);
1183 auto const xrpOffer =
XRP(1000);
1185 Env env{*
this, features};
1187 env.fund(startBalance, gw, alice, bob);
1190 auto const f = env.current()->fees().base;
1196 balance(alice, startBalance - f),
1205 env(offer(alice, xrpOffer, usdOffer),
1210 balance(alice, startBalance - f - f),
1217 env(offer(alice, xrpOffer, usdOffer),
1221 balance(alice, startBalance - f - f - f),
1229 balance(alice, startBalance - f - f - f),
1237 balance(alice, startBalance - f - f - f),
1241 balance(bob, startBalance - f),
1250 testcase(
"Unfunded Crossing");
1252 using namespace jtx;
1254 auto const gw =
Account{
"gateway"};
1255 auto const USD = gw[
"USD"];
1257 auto const usdOffer = USD(1000);
1258 auto const xrpOffer =
XRP(1000);
1260 Env env{*
this, features};
1262 env.fund(
XRP(1000000), gw);
1265 auto const f = env.current()->fees().base;
1269 env.fund(
reserve(env, 0),
"alice");
1275 env.fund(
reserve(env, 0) + f,
"bob");
1282 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1289 env.fund(
reserve(env, 1) + f,
"dan");
1295 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1306 (use_partner ?
", with partner account" :
""));
1308 using namespace jtx;
1310 auto const gw =
Account{
"gateway"};
1311 auto const partner =
Account{
"partner"};
1312 auto const USD = gw[
"USD"];
1313 auto const BTC = gw[
"BTC"];
1315 Env env{*
this, features};
1318 env.fund(
XRP(10000), gw);
1321 env.fund(
XRP(10000), partner);
1322 env(
trust(partner, USD(100)));
1323 env(
trust(partner, BTC(500)));
1324 env(
pay(gw, partner, USD(100)));
1325 env(
pay(gw, partner, BTC(500)));
1327 auto const& account_to_test = use_partner ? partner : gw;
1330 env.require(
offers(account_to_test, 0));
1335 env(offer(account_to_test, BTC(250),
XRP(1000)));
1336 env.require(
offers(account_to_test, 1));
1339 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1341 auto const secondLegSeq = env.seq(account_to_test);
1342 env(offer(account_to_test,
XRP(1000), USD(50)));
1343 env.require(
offers(account_to_test, 2));
1346 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1350 env(offer(account_to_test, USD(50), BTC(250)));
1353 BEAST_EXPECT(jrr[jss::offers].isArray());
1354 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1357 BEAST_EXPECT(jrr[jss::offers].isArray());
1358 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1369 bool const noStaleOffers{
1373 BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
1374 for (
auto const& offerPtr : acctOffers)
1376 auto const& offer = *offerPtr;
1387 env.require(
offers(account_to_test, 0));
1392 env(offer(account_to_test, BTC(250), USD(50)));
1393 env.require(
offers(account_to_test, 1));
1397 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1400 BEAST_EXPECT(jrr[jss::offers].isArray());
1401 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1405 env(offer(account_to_test, USD(50), BTC(250)));
1406 env.require(
offers(account_to_test, 1));
1411 BEAST_EXPECT(jrr[jss::offers].isArray());
1412 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1414 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1422 testcase(
"Negative Balance");
1424 using namespace jtx;
1426 Env env{*
this, features};
1428 auto const gw =
Account{
"gateway"};
1429 auto const alice =
Account{
"alice"};
1430 auto const bob =
Account{
"bob"};
1431 auto const USD = gw[
"USD"];
1432 auto const BTC = gw[
"BTC"];
1436 auto const gw_initial_balance =
drops(1149999730);
1437 auto const alice_initial_balance =
drops(499946999680);
1438 auto const bob_initial_balance =
drops(10199999920);
1439 auto const small_amount =
1440 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1442 env.fund(gw_initial_balance, gw);
1443 env.fund(alice_initial_balance, alice);
1444 env.fund(bob_initial_balance, bob);
1446 env(
rate(gw, 1.005));
1448 env(
trust(alice, USD(500)));
1449 env(
trust(bob, USD(50)));
1450 env(
trust(gw, alice[
"USD"](100)));
1452 env(
pay(gw, alice, alice[
"USD"](50)));
1453 env(
pay(gw, bob, small_amount));
1455 env(offer(alice, USD(50),
XRP(150000)));
1458 env(
pay(alice, gw, USD(100)));
1461 env(
trust(gw, alice[
"USD"](0)));
1470 "-2710505431213761e-33");
1473 env(offer(bob,
XRP(2000), USD(1)));
1482 auto const crossingDelta =
1489 alice_initial_balance - env.current()->fees().base * 3 -
1496 bob_initial_balance - env.current()->fees().base * 2 +
1505 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1507 using namespace jtx;
1509 Env env{*
this, features};
1511 auto const gw =
Account{
"gateway"};
1512 auto const alice =
Account{
"alice"};
1513 auto const bob =
Account{
"bob"};
1514 auto const USD = gw[
"USD"];
1516 env.fund(
XRP(10000), gw, alice, bob);
1518 env(
trust(alice, USD(1000)));
1519 env(
trust(bob, USD(1000)));
1521 env(
pay(gw, alice, alice[
"USD"](500)));
1524 env(offer(bob, USD(1),
XRP(4000)));
1526 env(offer(alice,
XRP(150000), USD(50)));
1529 env(offer(bob, USD(1),
XRP(4000)));
1541 env.current()->fees().base * 2)
1550 env.current()->fees().base * 2)
1557 testcase(
"Offer Crossing with Limit Override");
1559 using namespace jtx;
1561 Env env{*
this, features};
1563 auto const gw =
Account{
"gateway"};
1564 auto const alice =
Account{
"alice"};
1565 auto const bob =
Account{
"bob"};
1566 auto const USD = gw[
"USD"];
1568 env.fund(
XRP(100000), gw, alice, bob);
1570 env(
trust(alice, USD(1000)));
1572 env(
pay(gw, alice, alice[
"USD"](500)));
1574 env(offer(alice,
XRP(150000), USD(50)));
1575 env(offer(bob, USD(1),
XRP(3000)));
1597 testcase(
"Offer Accept then Cancel.");
1599 using namespace jtx;
1601 Env env{*
this, features};
1603 auto const USD = env.master[
"USD"];
1605 auto const nextOfferSeq = env.seq(env.master);
1606 env(offer(env.master,
XRP(500), USD(100)));
1610 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1615 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1621 testcase(
"Offer Cancel Past and Future Sequence.");
1623 using namespace jtx;
1625 Env env{*
this, features};
1627 auto const alice =
Account{
"alice"};
1629 auto const nextOfferSeq = env.seq(env.master);
1630 env.fund(
XRP(10000), alice);
1646 testcase(
"Currency Conversion: Entire Offer");
1648 using namespace jtx;
1650 Env env{*
this, features};
1652 auto const gw =
Account{
"gateway"};
1653 auto const alice =
Account{
"alice"};
1654 auto const bob =
Account{
"bob"};
1655 auto const USD = gw[
"USD"];
1657 env.fund(
XRP(10000), gw, alice, bob);
1658 env.require(
owners(bob, 0));
1660 env(
trust(alice, USD(100)));
1661 env(
trust(bob, USD(1000)));
1665 env(
pay(gw, alice, alice[
"USD"](100)));
1666 auto const bobOfferSeq = env.seq(bob);
1667 env(offer(bob, USD(100),
XRP(500)));
1672 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1674 jro[jss::node][jss::TakerPays] ==
1691 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1699 testcase(
"Currency Conversion: Offerer Into Debt");
1701 using namespace jtx;
1703 Env env{*
this, features};
1705 auto const alice =
Account{
"alice"};
1706 auto const bob =
Account{
"bob"};
1707 auto const carol =
Account{
"carol"};
1709 env.fund(
XRP(10000), alice, bob, carol);
1711 env(
trust(alice, carol[
"EUR"](2000)));
1712 env(
trust(bob, alice[
"USD"](100)));
1713 env(
trust(carol, bob[
"EUR"](1000)));
1715 auto const bobOfferSeq = env.seq(bob);
1716 env(offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1719 env(offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1722 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1728 testcase(
"Currency Conversion: In Parts");
1730 using namespace jtx;
1732 Env env{*
this, features};
1734 auto const gw =
Account{
"gateway"};
1735 auto const alice =
Account{
"alice"};
1736 auto const bob =
Account{
"bob"};
1737 auto const USD = gw[
"USD"];
1739 env.fund(
XRP(10000), gw, alice, bob);
1741 env(
trust(alice, USD(200)));
1742 env(
trust(bob, USD(1000)));
1744 env(
pay(gw, alice, alice[
"USD"](200)));
1746 auto const bobOfferSeq = env.seq(bob);
1747 env(offer(bob, USD(100),
XRP(500)));
1754 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1756 jro[jss::node][jss::TakerPays] ==
1776 env(
pay(alice, alice,
XRP(600)),
1782 env(
pay(alice, alice,
XRP(600)),
1788 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1801 env.current()->fees().base * 4)
1813 testcase(
"Cross Currency Payment: Start with XRP");
1815 using namespace jtx;
1817 Env env{*
this, features};
1819 auto const gw =
Account{
"gateway"};
1820 auto const alice =
Account{
"alice"};
1821 auto const bob =
Account{
"bob"};
1822 auto const carol =
Account{
"carol"};
1823 auto const USD = gw[
"USD"];
1825 env.fund(
XRP(10000), gw, alice, bob, carol);
1827 env(
trust(carol, USD(1000)));
1828 env(
trust(bob, USD(2000)));
1830 env(
pay(gw, carol, carol[
"USD"](500)));
1832 auto const carolOfferSeq = env.seq(carol);
1833 env(offer(carol,
XRP(500), USD(50)));
1845 jro[jss::node][jss::TakerGets] ==
1848 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1854 testcase(
"Cross Currency Payment: End with XRP");
1856 using namespace jtx;
1858 Env env{*
this, features};
1860 auto const gw =
Account{
"gateway"};
1861 auto const alice =
Account{
"alice"};
1862 auto const bob =
Account{
"bob"};
1863 auto const carol =
Account{
"carol"};
1864 auto const USD = gw[
"USD"];
1866 env.fund(
XRP(10000), gw, alice, bob, carol);
1868 env(
trust(alice, USD(1000)));
1869 env(
trust(carol, USD(2000)));
1871 env(
pay(gw, alice, alice[
"USD"](500)));
1873 auto const carolOfferSeq = env.seq(carol);
1874 env(offer(carol, USD(50),
XRP(500)));
1888 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1892 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1894 jro[jss::node][jss::TakerPays] ==
1901 testcase(
"Cross Currency Payment: Bridged");
1903 using namespace jtx;
1905 Env env{*
this, features};
1907 auto const gw1 =
Account{
"gateway_1"};
1908 auto const gw2 =
Account{
"gateway_2"};
1909 auto const alice =
Account{
"alice"};
1910 auto const bob =
Account{
"bob"};
1911 auto const carol =
Account{
"carol"};
1912 auto const dan =
Account{
"dan"};
1913 auto const USD = gw1[
"USD"];
1914 auto const EUR = gw2[
"EUR"];
1916 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1918 env(
trust(alice, USD(1000)));
1919 env(
trust(bob, EUR(1000)));
1920 env(
trust(carol, USD(1000)));
1921 env(
trust(dan, EUR(1000)));
1923 env(
pay(gw1, alice, alice[
"USD"](500)));
1924 env(
pay(gw2, dan, dan[
"EUR"](400)));
1926 auto const carolOfferSeq = env.seq(carol);
1927 env(offer(carol, USD(50),
XRP(500)));
1929 auto const danOfferSeq = env.seq(dan);
1930 env(offer(dan,
XRP(500), EUR(50)));
1933 jtp[0u][0u][jss::currency] =
"XRP";
1934 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1950 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1952 jro[jss::node][jss::TakerPays] ==
1957 jro[jss::node][jss::TakerGets] ==
1960 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1969 testcase(
"Auto Bridged Second Leg Dry");
1971 using namespace jtx;
1972 Env env(*
this, features);
1978 auto const USD = gw[
"USD"];
1979 auto const EUR = gw[
"EUR"];
1981 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1983 env.
trust(USD(10), alice);
1985 env(
pay(gw, alice, USD(10)));
1986 env.
trust(USD(10), carol);
1988 env(
pay(gw, carol, USD(3)));
1990 env(offer(alice, EUR(2),
XRP(1)));
1991 env(offer(alice, EUR(2),
XRP(1)));
1993 env(offer(alice,
XRP(1), USD(4)));
1994 env(offer(carol,
XRP(1), USD(3)));
2005 env.
trust(EUR(10), bob);
2007 env(
pay(gw, bob, EUR(10)));
2009 env(offer(bob, USD(10), EUR(10)));
2026 int const emptyOfferCount{
2038 testcase(
"Offer Fees Consume Funds");
2040 using namespace jtx;
2042 Env env{*
this, features};
2044 auto const gw1 =
Account{
"gateway_1"};
2045 auto const gw2 =
Account{
"gateway_2"};
2046 auto const gw3 =
Account{
"gateway_3"};
2047 auto const alice =
Account{
"alice"};
2048 auto const bob =
Account{
"bob"};
2049 auto const USD1 = gw1[
"USD"];
2050 auto const USD2 = gw2[
"USD"];
2051 auto const USD3 = gw3[
"USD"];
2059 auto const starting_xrp =
XRP(100) +
2060 env.current()->fees().accountReserve(3) +
2061 env.current()->fees().base * 4;
2063 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2065 env(
trust(alice, USD1(1000)));
2066 env(
trust(alice, USD2(1000)));
2067 env(
trust(alice, USD3(1000)));
2068 env(
trust(bob, USD1(1000)));
2069 env(
trust(bob, USD2(1000)));
2071 env(
pay(gw1, bob, bob[
"USD"](500)));
2073 env(offer(bob,
XRP(200), USD1(200)));
2076 env(offer(alice, USD1(200),
XRP(200)));
2092 testcase(
"Offer Create, then Cross");
2094 using namespace jtx;
2096 for (
auto NumberSwitchOver : {
false,
true})
2098 Env env{*
this, features};
2099 if (NumberSwitchOver)
2104 auto const gw =
Account{
"gateway"};
2105 auto const alice =
Account{
"alice"};
2106 auto const bob =
Account{
"bob"};
2107 auto const USD = gw[
"USD"];
2109 env.fund(
XRP(10000), gw, alice, bob);
2111 env(
rate(gw, 1.005));
2113 env(
trust(alice, USD(1000)));
2114 env(
trust(bob, USD(1000)));
2115 env(
trust(gw, alice[
"USD"](50)));
2117 env(
pay(gw, bob, bob[
"USD"](1)));
2118 env(
pay(alice, gw, USD(50)));
2120 env(
trust(gw, alice[
"USD"](0)));
2122 env(offer(alice, USD(50),
XRP(150000)));
2123 env(offer(bob,
XRP(100), USD(0.1)));
2128 "49.96666666666667");
2130 if (NumberSwitchOver)
2134 "-0.9665000000333333");
2140 "-0.966500000033334");
2148 testcase(
"Offer tfSell: Basic Sell");
2150 using namespace jtx;
2152 Env env{*
this, features};
2154 auto const gw =
Account{
"gateway"};
2155 auto const alice =
Account{
"alice"};
2156 auto const bob =
Account{
"bob"};
2157 auto const USD = gw[
"USD"];
2159 auto const starting_xrp =
XRP(100) +
2160 env.current()->fees().accountReserve(1) +
2161 env.current()->fees().base * 2;
2163 env.fund(starting_xrp, gw, alice, bob);
2165 env(
trust(alice, USD(1000)));
2166 env(
trust(bob, USD(1000)));
2168 env(
pay(gw, bob, bob[
"USD"](500)));
2170 env(offer(bob,
XRP(200), USD(200)),
json(jss::Flags,
tfSell));
2174 env(offer(alice, USD(200),
XRP(200)),
json(jss::Flags,
tfSell));
2190 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2192 using namespace jtx;
2194 Env env{*
this, features};
2196 auto const gw =
Account{
"gateway"};
2197 auto const alice =
Account{
"alice"};
2198 auto const bob =
Account{
"bob"};
2199 auto const USD = gw[
"USD"];
2201 auto const starting_xrp =
XRP(100) +
2202 env.current()->fees().accountReserve(1) +
2203 env.current()->fees().base * 2;
2205 env.fund(starting_xrp, gw, alice, bob);
2207 env(
trust(alice, USD(150)));
2208 env(
trust(bob, USD(1000)));
2210 env(
pay(gw, bob, bob[
"USD"](500)));
2212 env(offer(bob,
XRP(100), USD(200)));
2218 env(offer(alice, USD(100),
XRP(100)),
json(jss::Flags,
tfSell));
2234 testcase(
"Client Issue #535: Gateway Cross Currency");
2236 using namespace jtx;
2238 Env env{*
this, features};
2240 auto const gw =
Account{
"gateway"};
2241 auto const alice =
Account{
"alice"};
2242 auto const bob =
Account{
"bob"};
2243 auto const XTS = gw[
"XTS"];
2244 auto const XXX = gw[
"XXX"];
2246 auto const starting_xrp =
XRP(100.1) +
2247 env.current()->fees().accountReserve(1) +
2248 env.current()->fees().base * 2;
2250 env.fund(starting_xrp, gw, alice, bob);
2252 env(
trust(alice, XTS(1000)));
2253 env(
trust(alice, XXX(1000)));
2254 env(
trust(bob, XTS(1000)));
2255 env(
trust(bob, XXX(1000)));
2257 env(
pay(gw, alice, alice[
"XTS"](100)));
2258 env(
pay(gw, alice, alice[
"XXX"](100)));
2259 env(
pay(gw, bob, bob[
"XTS"](100)));
2260 env(
pay(gw, bob, bob[
"XXX"](100)));
2262 env(offer(alice, XTS(100), XXX(100)));
2269 payment[jss::id] = env.seq(bob);
2270 payment[jss::build_path] =
true;
2271 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2272 payment[jss::tx_json][jss::Sequence] =
2276 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2277 payment[jss::tx_json][jss::SendMax] =
2279 auto jrr = wsc->invoke(
"submit", payment);
2280 BEAST_EXPECT(jrr[jss::status] ==
"success");
2281 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2282 if (wsc->version() == 2)
2285 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2287 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2288 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2314 auto const sleTrust =
2316 BEAST_EXPECT(sleTrust);
2320 bool const accountLow = account.id() < issue.
account;
2325 low.setIssuer(accountLow ? account.id() : issue.
account);
2326 high.setIssuer(accountLow ? issue.
account : account.id());
2328 BEAST_EXPECT(sleTrust->getFieldAmount(
sfLowLimit) == low);
2329 BEAST_EXPECT(sleTrust->getFieldAmount(
sfHighLimit) == high);
2335 BEAST_EXPECT(actualBalance == expectBalance);
2345 testcase(
"Partial Crossing");
2347 using namespace jtx;
2349 auto const gw =
Account(
"gateway");
2350 auto const USD = gw[
"USD"];
2352 Env env{*
this, features};
2354 env.fund(
XRP(10000000), gw);
2357 auto const f = env.current()->fees().base;
2360 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2366 preTrustType preTrust;
2376 TestData
const tests[]{
2378 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2379 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2380 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2381 {
"deb",
reserve(env, 0) + 2 * f, 1, noPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 1},
2382 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2383 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2384 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2385 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2386 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2387 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2388 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2389 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2390 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2391 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2392 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2393 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2394 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2395 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2397 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2398 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2399 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2400 {
"dan",
reserve(env, 0) + 2 * f, 1, gwPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 0},
2401 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2402 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2403 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2404 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2406 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2407 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2408 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2409 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2410 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2411 {
"syd",
reserve(env, 1) + 3 * f, 1, acctPreTrust, 1000,
tesSUCCESS, 3 * f, USD(0.00001), 0, 1},
2412 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2413 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2414 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2415 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2416 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2420 for (
auto const& t : tests)
2422 auto const acct =
Account(t.account);
2423 env.fund(t.fundXrp, acct);
2427 env.require(
offers(gw, 0));
2430 auto const book = t.bookAmount;
2432 env(offer(gw,
XRP(book), USD(book)));
2437 if (t.preTrust == gwPreTrust)
2438 env(
trust(gw, acct[
"USD"](1)));
2443 if (t.preTrust == acctPreTrust)
2444 env(
trust(acct, USD(1)));
2450 auto const acctOffer = t.offerAmount;
2451 env(offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2456 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2458 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2459 env.require(
offers(acct, t.offers));
2460 env.require(
owners(acct, t.owners));
2463 BEAST_EXPECT(acctOffers.size() == t.offers);
2464 if (acctOffers.size() && t.offers)
2466 auto const& acctOffer = *(acctOffers.front());
2468 auto const leftover = t.offerAmount - t.bookAmount;
2470 BEAST_EXPECT(acctOffer[
sfTakerPays] == USD(leftover));
2473 if (t.preTrust == noPreTrust)
2475 if (t.balanceUsd.value().signum())
2483 auto const sleTrust =
2485 BEAST_EXPECT(!sleTrust);
2500 testcase(
"XRP Direct Crossing");
2502 using namespace jtx;
2504 auto const gw =
Account(
"gateway");
2505 auto const alice =
Account(
"alice");
2506 auto const bob =
Account(
"bob");
2507 auto const USD = gw[
"USD"];
2509 auto const usdOffer = USD(1000);
2510 auto const xrpOffer =
XRP(1000);
2512 Env env{*
this, features};
2514 env.fund(
XRP(1000000), gw, bob);
2518 auto const fee = env.current()->fees().base;
2525 env(
trust(alice, usdOffer));
2529 env(
pay(gw, alice, usdOffer));
2536 auto const alicesXRP = env.balance(alice);
2537 auto const bobsXRP = env.balance(bob);
2539 env(offer(alice, xrpOffer, usdOffer));
2541 env(offer(bob, usdOffer, xrpOffer));
2555 env(offer(alice, USD(999),
XRP(999)));
2556 env(offer(bob, xrpOffer, usdOffer));
2559 env.require(
balance(alice, USD(999)));
2560 env.require(
balance(bob, USD(1)));
2561 env.require(
offers(alice, 0));
2565 BEAST_EXPECT(bobsOffers.size() == 1);
2566 auto const& bobsOffer = *(bobsOffers.front());
2577 testcase(
"Direct Crossing");
2579 using namespace jtx;
2581 auto const gw =
Account(
"gateway");
2582 auto const alice =
Account(
"alice");
2583 auto const bob =
Account(
"bob");
2584 auto const USD = gw[
"USD"];
2585 auto const EUR = gw[
"EUR"];
2587 auto const usdOffer = USD(1000);
2588 auto const eurOffer = EUR(1000);
2590 Env env{*
this, features};
2592 env.fund(
XRP(1000000), gw);
2596 auto const fee = env.current()->fees().base;
2604 env(
trust(alice, usdOffer));
2605 env(
trust(bob, eurOffer));
2608 env(
pay(gw, alice, usdOffer));
2609 env(
pay(gw, bob, eurOffer));
2617 env(offer(alice, eurOffer, usdOffer));
2618 env(offer(bob, usdOffer, eurOffer));
2635 env(offer(bob, eurOffer, usdOffer));
2638 env(offer(alice, USD(999), eurOffer));
2641 env.require(
offers(alice, 0));
2642 env.require(
offers(bob, 1));
2644 env.require(
balance(alice, USD(999)));
2645 env.require(
balance(alice, EUR(1)));
2646 env.require(
balance(bob, USD(1)));
2647 env.require(
balance(bob, EUR(999)));
2651 if (BEAST_EXPECT(bobsOffers.size() == 1))
2653 auto const& bobsOffer = *(bobsOffers.front());
2661 env(offer(alice, USD(1), EUR(1)));
2664 env.require(
balance(alice, USD(1000)));
2667 env.require(
balance(bob, EUR(1000)));
2668 env.require(
offers(alice, 0));
2669 env.require(
offers(bob, 0));
2672 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2673 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2677 env(offer(alice, EUR(999), usdOffer));
2680 env(offer(bob, usdOffer, eurOffer));
2683 env.require(
offers(alice, 0));
2684 env.require(
offers(bob, 0));
2686 env.require(
balance(alice, USD(0)));
2687 env.require(
balance(alice, EUR(999)));
2688 env.require(
balance(bob, USD(1000)));
2689 env.require(
balance(bob, EUR(1)));
2695 testcase(
"Bridged Crossing");
2697 using namespace jtx;
2699 auto const gw =
Account(
"gateway");
2700 auto const alice =
Account(
"alice");
2701 auto const bob =
Account(
"bob");
2702 auto const carol =
Account(
"carol");
2703 auto const USD = gw[
"USD"];
2704 auto const EUR = gw[
"EUR"];
2706 auto const usdOffer = USD(1000);
2707 auto const eurOffer = EUR(1000);
2709 Env env{*
this, features};
2711 env.fund(
XRP(1000000), gw, alice, bob, carol);
2714 env(
trust(alice, usdOffer));
2715 env(
trust(carol, eurOffer));
2717 env(
pay(gw, alice, usdOffer));
2718 env(
pay(gw, carol, eurOffer));
2727 env(offer(alice,
XRP(1000), usdOffer));
2728 env(offer(bob, eurOffer,
XRP(1000)));
2729 auto const bobXrpBalance = env.balance(bob);
2733 env(offer(carol, USD(400), EUR(400)));
2746 BEAST_EXPECT(alicesOffers.size() == 1);
2747 auto const& alicesOffer = *(alicesOffers.front());
2750 BEAST_EXPECT(alicesOffer[
sfTakerGets] == USD(600));
2755 BEAST_EXPECT(bobsOffers.size() == 1);
2756 auto const& bobsOffer = *(bobsOffers.front());
2764 env(offer(carol, USD(600), EUR(600)));
2779 if (alicesOffers.size() != 0)
2781 BEAST_EXPECT(alicesOffers.size() == 1);
2782 auto const& alicesOffer = *(alicesOffers.front());
2796 testcase(
"Sell Offer");
2798 using namespace jtx;
2800 auto const gw =
Account(
"gateway");
2801 auto const USD = gw[
"USD"];
2803 Env env{*
this, features};
2805 env.fund(
XRP(10000000), gw);
2808 auto const f = env.current()->fees().base;
2811 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2845 : account(std::move(account_))
2850 , acctGets(acctGets_)
2851 , acctPays(acctPays_)
2853 , spentXrp(spentXrp_)
2854 , finalUsd(finalUsd_)
2857 , takerGets(takerGets_)
2858 , takerPays(takerPays_)
2877 std::move(account_),
2896 TestData
const tests[]{
2899 {
"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},
2900 {
"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)},
2901 {
"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},
2902 {
"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},
2903 {
"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},
2904 {
"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},
2905 {
"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},
2906 {
"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)},
2908 {
"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},
2909 {
"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)},
2910 {
"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},
2911 {
"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},
2912 {
"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},
2913 {
"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)},
2914 {
"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)},
2918 auto const zeroUsd = USD(0);
2919 for (
auto const& t : tests)
2922 env.require(
offers(gw, 0));
2924 auto const acct =
Account(t.account);
2926 env.fund(t.fundXrp, acct);
2932 if (t.fundUSD != zeroUsd)
2934 env(
trust(acct, t.fundUSD));
2936 env(
pay(gw, acct, t.fundUSD));
2940 env(offer(gw, t.gwGets, t.gwPays));
2945 env(offer(acct, t.acctGets, t.acctPays,
tfSell),
ter(t.tec));
2950 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2952 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2953 env.require(
offers(acct, t.offers));
2954 env.require(
owners(acct, t.owners));
2959 if (acctOffers.size() > 0)
2961 BEAST_EXPECT(acctOffers.size() == 1);
2962 auto const& acctOffer = *(acctOffers.front());
2965 BEAST_EXPECT(acctOffer[
sfTakerGets] == t.takerGets);
2966 BEAST_EXPECT(acctOffer[
sfTakerPays] == t.takerPays);
2983 testcase(
"Combine tfSell with tfFillOrKill");
2985 using namespace jtx;
2987 auto const gw =
Account(
"gateway");
2988 auto const alice =
Account(
"alice");
2989 auto const bob =
Account(
"bob");
2990 auto const USD = gw[
"USD"];
2992 Env env{*
this, features};
2994 env.fund(
XRP(10000000), gw, alice, bob);
2997 TER const killedCode{
3001 env(
trust(bob, USD(200)));
3003 env(
pay(gw, bob, USD(100)));
3005 env(offer(bob,
XRP(2000), USD(20)));
3013 env.require(
offers(alice, 0));
3014 env.require(
balance(bob, USD(100)));
3021 env.require(
balance(alice, USD(20)));
3022 env.require(
offers(alice, 0));
3023 env.require(
balance(bob, USD(80)));
3028 env(offer(bob,
XRP(2000), USD(20)));
3032 env.require(
balance(alice, USD(35)));
3033 env.require(
offers(alice, 0));
3034 env.require(
balance(bob, USD(65)));
3046 env.require(
balance(alice, USD(35)));
3047 env.require(
offers(alice, 0));
3048 env.require(
balance(bob, USD(65)));
3057 env.require(
balance(alice, USD(40)));
3058 env.require(
offers(alice, 0));
3059 env.require(
balance(bob, USD(60)));
3066 testcase(
"Transfer Rate Offer");
3068 using namespace jtx;
3070 auto const gw1 =
Account(
"gateway1");
3071 auto const USD = gw1[
"USD"];
3073 Env env{*
this, features};
3076 auto const fee = env.current()->fees().base;
3078 env.fund(
XRP(100000), gw1);
3081 env(
rate(gw1, 1.25));
3083 auto const ann =
Account(
"ann");
3084 auto const bob =
Account(
"bob");
3088 env(
trust(ann, USD(200)));
3089 env(
trust(bob, USD(200)));
3092 env(
pay(gw1, bob, USD(125)));
3101 env(offer(bob,
XRP(1), USD(100)));
3104 env(offer(ann, USD(100),
XRP(1)));
3107 env.require(
balance(ann, USD(100)));
3109 env.require(
offers(ann, 0));
3111 env.require(
balance(bob, USD(0)));
3113 env.require(
offers(bob, 0));
3118 auto const che =
Account(
"che");
3119 auto const deb =
Account(
"deb");
3123 env(
trust(che, USD(200)));
3124 env(
trust(deb, USD(200)));
3127 env(
pay(gw1, deb, USD(125)));
3130 env(offer(che, USD(100),
XRP(1)));
3133 env(offer(deb,
XRP(1), USD(100)));
3136 env.require(
balance(che, USD(100)));
3138 env.require(
offers(che, 0));
3140 env.require(
balance(deb, USD(0)));
3142 env.require(
offers(deb, 0));
3145 auto const eve =
Account(
"eve");
3146 auto const fyn =
Account(
"fyn");
3148 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3151 env(
trust(eve, USD(1000)));
3152 env(
trust(fyn, USD(1000)));
3155 env(
pay(gw1, eve, USD(100)));
3156 env(
pay(gw1, fyn, USD(100)));
3162 env(offer(eve, USD(10),
XRP(4000)));
3166 env(offer(fyn,
XRP(2000), USD(5)));
3169 env.require(
balance(eve, USD(105)));
3172 BEAST_EXPECT(evesOffers.size() == 1);
3173 if (evesOffers.size() != 0)
3175 auto const& evesOffer = *(evesOffers.front());
3182 env.require(
balance(fyn, USD(93.75)));
3184 env.require(
offers(fyn, 0));
3187 auto const gw2 =
Account(
"gateway2");
3188 auto const EUR = gw2[
"EUR"];
3190 env.fund(
XRP(100000), gw2);
3193 env(
rate(gw2, 1.5));
3198 auto const gay =
Account(
"gay");
3199 auto const hal =
Account(
"hal");
3200 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3203 env(
trust(gay, USD(200)));
3204 env(
trust(gay, EUR(200)));
3205 env(
trust(hal, USD(200)));
3206 env(
trust(hal, EUR(200)));
3209 env(
pay(gw1, gay, USD(125)));
3210 env(
pay(gw2, hal, EUR(150)));
3213 env(offer(gay, EUR(100), USD(100)));
3216 env(offer(hal, USD(100), EUR(100)));
3219 env.require(
balance(gay, USD(0)));
3220 env.require(
balance(gay, EUR(100)));
3222 env.require(
offers(gay, 0));
3224 env.require(
balance(hal, USD(100)));
3225 env.require(
balance(hal, EUR(0)));
3227 env.require(
offers(hal, 0));
3231 auto const ivy =
Account(
"ivy");
3232 auto const joe =
Account(
"joe");
3233 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3242 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3243 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3245 env.require(
balance(ivy, USD(300)));
3246 env.require(
balance(joe, EUR(250)));
3248 env(offer(ivy, EUR(100), USD(200)));
3251 env(offer(joe, USD(200), EUR(100)));
3254 env.require(
balance(ivy, USD(50)));
3255 env.require(
balance(ivy, EUR(100)));
3257 env.require(
offers(ivy, 0));
3259 env.require(
balance(joe, USD(200)));
3260 env.require(
balance(joe, EUR(100)));
3262 env.require(
offers(joe, 0));
3266 auto const kim =
Account(
"kim");
3267 auto const K_BUX = kim[
"BUX"];
3268 auto const lex =
Account(
"lex");
3269 auto const meg =
Account(
"meg");
3270 auto const ned =
Account(
"ned");
3271 auto const N_BUX = ned[
"BUX"];
3274 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3277 env(
trust(lex, K_BUX(400)));
3279 env(
trust(meg, N_BUX(100)));
3281 env(
pay(ned, lex, N_BUX(100)));
3283 env.require(
balance(lex, N_BUX(100)));
3285 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3290 env.require(
balance(lex, K_BUX(72)));
3291 env.require(
balance(lex, N_BUX(40)));
3293 env.require(
balance(meg, N_BUX(60)));
3298 env(offer(lex, K_BUX(30), N_BUX(30)));
3301 env(offer(kim, N_BUX(30), K_BUX(30)));
3305 env.require(
balance(kim, N_BUX(30)));
3306 env.require(
balance(lex, K_BUX(102)));
3307 env.require(
balance(lex, N_BUX(10)));
3309 env.require(
balance(meg, N_BUX(60)));
3310 env.require(
balance(ned, K_BUX(-30)));
3315 auto const ova =
Account(
"ova");
3316 auto const pat =
Account(
"pat");
3317 auto const qae =
Account(
"qae");
3318 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3324 env(
trust(ova, USD(200)));
3325 env(
trust(ova, EUR(200)));
3326 env(
trust(pat, USD(200)));
3327 env(
trust(pat, EUR(200)));
3328 env(
trust(qae, USD(200)));
3329 env(
trust(qae, EUR(200)));
3332 env(
pay(gw1, ova, USD(125)));
3333 env(
pay(gw2, qae, EUR(150)));
3336 env(offer(ova,
XRP(2), USD(100)));
3337 env(offer(pat, EUR(100),
XRP(2)));
3340 env(offer(qae, USD(100), EUR(100)));
3343 env.require(
balance(ova, USD(0)));
3344 env.require(
balance(ova, EUR(0)));
3349 if (ovasOffers.size() != 0)
3351 BEAST_EXPECT(ovasOffers.size() == 1);
3352 auto const& ovasOffer = *(ovasOffers.front());
3359 env.require(
balance(pat, USD(0)));
3360 env.require(
balance(pat, EUR(100)));
3362 env.require(
offers(pat, 0));
3364 env.require(
balance(qae, USD(100)));
3365 env.require(
balance(qae, EUR(0)));
3367 env.require(
offers(qae, 0));
3388 using namespace jtx;
3390 auto const gw =
Account(
"gateway");
3391 auto const USD = gw[
"USD"];
3393 Env env{*
this, features};
3396 auto const fee = env.current()->fees().base;
3397 auto const startBalance =
XRP(1000000);
3399 env.fund(startBalance + (
fee * 4), gw);
3402 env(offer(gw, USD(60),
XRP(600)));
3404 env(offer(gw, USD(60),
XRP(600)));
3406 env(offer(gw, USD(60),
XRP(600)));
3409 env.require(
owners(gw, 3));
3410 env.require(
balance(gw, startBalance +
fee));
3413 BEAST_EXPECT(gwOffers.size() == 3);
3414 for (
auto const& offerPtr : gwOffers)
3416 auto const& offer = *offerPtr;
3424 env(offer(gw,
XRP(1000), USD(100)));
3426 env.require(
owners(gw, 1));
3427 env.require(
offers(gw, 1));
3428 env.require(
balance(gw, startBalance));
3431 BEAST_EXPECT(gwOffers.size() == 1);
3432 for (
auto const& offerPtr : gwOffers)
3434 auto const& offer = *offerPtr;
3444 using namespace jtx;
3446 auto const gw1 =
Account(
"gateway1");
3447 auto const gw2 =
Account(
"gateway2");
3448 auto const alice =
Account(
"alice");
3449 auto const USD = gw1[
"USD"];
3450 auto const EUR = gw2[
"EUR"];
3452 Env env{*
this, features};
3454 env.fund(
XRP(1000000), gw1, gw2);
3458 auto const f = env.current()->fees().base;
3472 TestData
const tests[]{
3483 for (
auto const& t : tests)
3485 auto const acct =
Account{t.acct};
3486 env.fund(t.fundXRP, acct);
3489 env(
trust(acct, USD(1000)));
3490 env(
trust(acct, EUR(1000)));
3493 if (t.fundUSD > USD(0))
3494 env(
pay(gw1, acct, t.fundUSD));
3495 if (t.fundEUR > EUR(0))
3496 env(
pay(gw2, acct, t.fundEUR));
3499 env(offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3503 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3504 env.require(
owners(acct, 2 + offerCount));
3505 env.require(
balance(acct, t.fundUSD));
3506 env.require(
balance(acct, t.fundEUR));
3509 BEAST_EXPECT(acctOffers.size() == offerCount);
3510 for (
auto const& offerPtr : acctOffers)
3512 auto const& offer = *offerPtr;
3518 env(offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3522 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3523 env.require(
owners(acct, 2 + offerCount));
3524 env.require(
balance(acct, t.fundUSD));
3525 env.require(
balance(acct, t.fundEUR));
3528 BEAST_EXPECT(acctOffers.size() == offerCount);
3529 for (
auto const& offerPtr : acctOffers)
3531 auto const& offer = *offerPtr;
3556 testcase(
"Self Cross Offer");
3568 using namespace jtx;
3570 Env env{*
this, features};
3572 auto const alice =
Account(
"alice");
3573 auto const bob =
Account(
"bob");
3574 auto const USD = bob[
"USD"];
3575 auto const f = env.current()->fees().base;
3577 env.fund(
XRP(50000) + f, alice, bob);
3580 env(offer(alice, USD(5000),
XRP(50000)));
3584 env(offer(bob,
XRP(50000), USD(5000)));
3590 env.require(
owners(alice, 1));
3591 env.require(
lines(alice, 1));
3596 BEAST_EXPECT(bobOffers.size() == 1);
3597 for (
auto const& offerPtr : bobOffers)
3599 auto const& offer = *offerPtr;
3612 testcase(
"Bad path assert");
3614 using namespace jtx;
3621 auto const fee = env.current()->fees().base;
3624 auto const ann =
Account(
"ann");
3625 auto const A_BUX = ann[
"BUX"];
3626 auto const bob =
Account(
"bob");
3627 auto const cam =
Account(
"cam");
3628 auto const dan =
Account(
"dan");
3629 auto const D_BUX = dan[
"BUX"];
3632 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3635 env(
trust(bob, A_BUX(400)));
3637 env(
trust(cam, D_BUX(100)));
3639 env(
pay(dan, bob, D_BUX(100)));
3641 env.require(
balance(bob, D_BUX(100)));
3643 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3648 env.require(
balance(bob, A_BUX(72)));
3649 env.require(
balance(bob, D_BUX(40)));
3651 env.require(
balance(cam, D_BUX(60)));
3655 env(offer(bob, A_BUX(30), D_BUX(30)));
3658 env(
trust(ann, D_BUX(100)));
3662 env(
pay(ann, ann, D_BUX(30)),
3669 env.require(
balance(ann, D_BUX(0)));
3670 env.require(
balance(bob, A_BUX(72)));
3671 env.require(
balance(bob, D_BUX(40)));
3673 env.require(
balance(cam, D_BUX(60)));
3674 env.require(
balance(dan, A_BUX(0)));
3686 testcase(
"Direct to Direct path");
3688 using namespace jtx;
3690 Env env{*
this, features};
3692 auto const ann =
Account(
"ann");
3693 auto const bob =
Account(
"bob");
3694 auto const cam =
Account(
"cam");
3695 auto const A_BUX = ann[
"BUX"];
3696 auto const B_BUX = bob[
"BUX"];
3698 auto const fee = env.current()->fees().base;
3699 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3702 env(
trust(ann, B_BUX(40)));
3703 env(
trust(cam, A_BUX(40)));
3704 env(
trust(cam, B_BUX(40)));
3707 env(
pay(ann, cam, A_BUX(35)));
3708 env(
pay(bob, cam, B_BUX(35)));
3710 env(offer(bob, A_BUX(30), B_BUX(30)));
3716 env(offer(cam, A_BUX(29), B_BUX(30),
tfPassive));
3718 env.require(
balance(cam, A_BUX(35)));
3719 env.require(
balance(cam, B_BUX(35)));
3720 env.require(
offers(cam, 1));
3723 env(offer(cam, B_BUX(30), A_BUX(30)));
3726 env.require(
balance(bob, A_BUX(30)));
3727 env.require(
balance(cam, A_BUX(5)));
3728 env.require(
balance(cam, B_BUX(65)));
3729 env.require(
offers(cam, 0));
3738 testcase(
"Self crossing low quality offer");
3740 using namespace jtx;
3742 Env env{*
this, features};
3744 auto const ann =
Account(
"ann");
3745 auto const gw =
Account(
"gateway");
3746 auto const BTC = gw[
"BTC"];
3748 auto const fee = env.current()->fees().base;
3753 env(
rate(gw, 1.002));
3754 env(
trust(ann, BTC(10)));
3757 env(
pay(gw, ann, BTC(2.856)));
3760 env(offer(ann,
drops(365611702030), BTC(5.713)));
3764 env(offer(ann, BTC(0.687),
drops(20000000000)),
3775 testcase(
"Offer In Scaling");
3777 using namespace jtx;
3779 Env env{*
this, features};
3781 auto const gw =
Account(
"gateway");
3782 auto const alice =
Account(
"alice");
3783 auto const bob =
Account(
"bob");
3784 auto const CNY = gw[
"CNY"];
3786 auto const fee = env.current()->fees().base;
3791 env(
trust(bob, CNY(500)));
3794 env(
pay(gw, bob, CNY(300)));
3797 env(offer(bob,
drops(5400000000), CNY(216.054)));
3801 env(offer(alice, CNY(13562.0001),
drops(339000000000)));
3805 BEAST_EXPECT(aliceOffers.size() == 1);
3806 for (
auto const& offerPtr : aliceOffers)
3808 auto const& offer = *offerPtr;
3811 BEAST_EXPECT(offer[
sfTakerPays] == CNY(13345.9461));
3821 testcase(
"Offer In Scaling With Xfer Rate");
3823 using namespace jtx;
3825 Env env{*
this, features};
3827 auto const gw =
Account(
"gateway");
3828 auto const alice =
Account(
"alice");
3829 auto const bob =
Account(
"bob");
3830 auto const BTC = gw[
"BTC"];
3831 auto const JPY = gw[
"JPY"];
3833 auto const fee = env.current()->fees().base;
3838 env(
rate(gw, 1.002));
3839 env(
trust(alice, JPY(4000)));
3840 env(
trust(bob, BTC(2)));
3843 env(
pay(gw, alice, JPY(3699.034802280317)));
3844 env(
pay(gw, bob, BTC(1.156722559140311)));
3847 env(offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3851 env(offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3855 BEAST_EXPECT(aliceOffers.size() == 1);
3856 for (
auto const& offerPtr : aliceOffers)
3858 auto const& offer = *offerPtr;
3863 BEAST_EXPECT(offer[
sfTakerPays] == BTC(0.035378));
3873 testcase(
"Offer Threshold With Reduced Funds");
3875 using namespace jtx;
3877 Env env{*
this, features};
3879 auto const gw1 =
Account(
"gw1");
3880 auto const gw2 =
Account(
"gw2");
3881 auto const alice =
Account(
"alice");
3882 auto const bob =
Account(
"bob");
3883 auto const USD = gw1[
"USD"];
3884 auto const JPY = gw2[
"JPY"];
3886 auto const fee = env.current()->fees().base;
3888 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3891 env(
rate(gw1, 1.002));
3892 env(
trust(alice, USD(1000)));
3893 env(
trust(bob, JPY(100000)));
3920 BEAST_EXPECT(aliceOffers.size() == 1);
3921 for (
auto const& offerPtr : aliceOffers)
3923 auto const& offer = *offerPtr;
3937 testcase(
"Tiny Offer");
3939 using namespace jtx;
3941 Env env{*
this, features};
3943 auto const gw =
Account(
"gw");
3944 auto const alice =
Account(
"alice");
3945 auto const bob =
Account(
"bob");
3946 auto const CNY = gw[
"CNY"];
3947 auto const fee = env.current()->fees().base;
3948 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3950 env.fund(startXrpBalance, gw, alice, bob);
3953 env(
trust(bob, CNY(100000)));
3965 STAmount const bobsCnyStartBalance{
3967 env(
pay(gw, bob, bobsCnyStartBalance));
3976 env.require(
balance(alice, alicesCnyOffer));
3978 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
3985 testcase(
"Self Pay Xfer Fee");
4021 using namespace jtx;
4023 Env env{*
this, features};
4025 auto const gw =
Account(
"gw");
4026 auto const BTC = gw[
"BTC"];
4027 auto const USD = gw[
"USD"];
4028 auto const startXrpBalance =
XRP(4000000);
4030 env.fund(startXrpBalance, gw);
4033 env(
rate(gw, 1.25));
4059 TestData
const tests[]{
4061 {0, 0, 1, BTC(20), {{
"ann", 0,
drops(3899999999960), BTC(20.0), USD(3000)}, {
"abe", 0,
drops(4099999999970), BTC( 0), USD(750)}}},
4062 {0, 1, 0, BTC(20), {{
"bev", 0,
drops(4099999999960), BTC( 7.5), USD(2000)}, {
"bob", 0,
drops(3899999999970), BTC(10), USD( 0)}}},
4063 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(3999999999950), BTC(20.0), USD(2000)} }},
4064 {0, 1, 0, BTC( 5), {{
"deb", 1,
drops(4039999999960), BTC( 0.0), USD(2000)}, {
"dan", 1,
drops(3959999999970), BTC( 4), USD( 0)}}},
4068 for (
auto const& t : tests)
4070 Account const&
self = t.actors[t.self].acct;
4071 Account const& leg0 = t.actors[t.leg0].acct;
4072 Account const& leg1 = t.actors[t.leg1].acct;
4074 for (
auto const& actor : t.actors)
4076 env.fund(
XRP(4000000), actor.acct);
4079 env(
trust(actor.acct, BTC(40)));
4080 env(
trust(actor.acct, USD(8000)));
4084 env(
pay(gw,
self, t.btcStart));
4085 env(
pay(gw,
self, USD(2000)));
4086 if (
self.
id() != leg1.
id())
4087 env(
pay(gw, leg1, USD(2000)));
4101 env(offer(
self, USD(1000), BTC(10)));
4106 for (
auto const& actor : t.actors)
4112 actorOffers.begin(),
4114 actorOffers.begin(),
4117 return (*offer)[sfTakerGets].signum() == 0;
4119 BEAST_EXPECT(offerCount == actor.offers);
4121 env.require(
balance(actor.acct, actor.xrp));
4122 env.require(
balance(actor.acct, actor.btc));
4123 env.require(
balance(actor.acct, actor.usd));
4139 testcase(
"Self Pay Unlimited Funds");
4171 using namespace jtx;
4173 Env env{*
this, features};
4175 auto const gw =
Account(
"gw");
4176 auto const BTC = gw[
"BTC"];
4177 auto const USD = gw[
"USD"];
4178 auto const startXrpBalance =
XRP(4000000);
4180 env.fund(startXrpBalance, gw);
4183 env(
rate(gw, 1.25));
4209 TestData
const takerTests[]{
4211 {0, 0, 1, BTC(5), {{
"deb", 0,
drops(3899999999960), BTC(5), USD(3000)}, {
"dan", 0,
drops(4099999999970), BTC(0), USD(750)}}},
4212 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(3999999999950), BTC(5), USD(2000)} }}
4215 TestData
const flowTests[]{
4217 {0, 0, 1, BTC(5), {{
"gay", 1,
drops(3949999999960), BTC(5), USD(2500)}, {
"gar", 1,
drops(4049999999970), BTC(0), USD(1375)}}},
4218 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(3999999999950), BTC(5), USD(2000)} }}
4225 for (
auto const& t : tests)
4227 Account const&
self = t.actors[t.self].acct;
4228 Account const& leg0 = t.actors[t.leg0].acct;
4229 Account const& leg1 = t.actors[t.leg1].acct;
4231 for (
auto const& actor : t.actors)
4233 env.fund(
XRP(4000000), actor.acct);
4236 env(
trust(actor.acct, BTC(40)));
4237 env(
trust(actor.acct, USD(8000)));
4241 env(
pay(gw,
self, t.btcStart));
4242 env(
pay(gw,
self, USD(2000)));
4243 if (
self.
id() != leg1.
id())
4244 env(
pay(gw, leg1, USD(2000)));
4258 env(offer(
self, USD(1000), BTC(10)));
4263 for (
auto const& actor : t.actors)
4269 actorOffers.begin(),
4271 actorOffers.begin(),
4274 return (*offer)[sfTakerGets].signum() == 0;
4276 BEAST_EXPECT(offerCount == actor.offers);
4278 env.require(
balance(actor.acct, actor.xrp));
4279 env.require(
balance(actor.acct, actor.btc));
4280 env.require(
balance(actor.acct, actor.usd));
4296 testcase(
"lsfRequireAuth");
4298 using namespace jtx;
4300 Env env{*
this, features};
4302 auto const gw =
Account(
"gw");
4303 auto const alice =
Account(
"alice");
4304 auto const bob =
Account(
"bob");
4305 auto const gwUSD = gw[
"USD"];
4306 auto const aliceUSD = alice[
"USD"];
4307 auto const bobUSD = bob[
"USD"];
4309 env.fund(
XRP(400000), gw, alice, bob);
4318 env(
trust(bob, gwUSD(100)));
4320 env(
trust(alice, gwUSD(100)));
4322 env(offer(alice, gwUSD(40),
XRP(4000)));
4325 env.require(
offers(alice, 1));
4326 env.require(
balance(alice, gwUSD(0)));
4328 env(
pay(gw, bob, gwUSD(50)));
4331 env.require(
balance(bob, gwUSD(50)));
4334 env(offer(bob,
XRP(4000), gwUSD(40)));
4337 env.require(
offers(alice, 0));
4338 env.require(
balance(alice, gwUSD(40)));
4340 env.require(
offers(bob, 0));
4341 env.require(
balance(bob, gwUSD(10)));
4347 testcase(
"Missing Auth");
4367 using namespace jtx;
4369 Env env{*
this, features};
4371 auto const gw =
Account(
"gw");
4372 auto const alice =
Account(
"alice");
4373 auto const bob =
Account(
"bob");
4374 auto const gwUSD = gw[
"USD"];
4375 auto const aliceUSD = alice[
"USD"];
4376 auto const bobUSD = bob[
"USD"];
4378 env.fund(
XRP(400000), gw, alice, bob);
4381 env(offer(alice, gwUSD(40),
XRP(4000)));
4384 env.require(
offers(alice, 1));
4391 env(
trust(bob, gwUSD(100)));
4394 env(
pay(gw, bob, gwUSD(50)));
4396 env.require(
balance(bob, gwUSD(50)));
4404 env(offer(bob,
XRP(4000), gwUSD(40)));
4410 env.require(
offers(alice, 0));
4415 env.require(
offers(bob, 1));
4416 env.require(
balance(bob, gwUSD(50)));
4421 env.require(
balance(alice, gwUSD(40)));
4422 env.require(
offers(bob, 0));
4423 env.require(
balance(bob, gwUSD(10)));
4435 env.require(
offers(alice, 0));
4438 env.require(
offers(bob, 1));
4439 env.require(
balance(bob, gwUSD(50)));
4443 env(
trust(gw, aliceUSD(100)));
4449 env.require(
offers(alice, 0));
4450 env.require(
balance(alice, gwUSD(0)));
4452 env.require(
offers(bob, 1));
4453 env.require(
balance(bob, gwUSD(50)));
4458 env.require(
offers(bob, 0));
4466 env(offer(alice, gwUSD(40),
XRP(4000)));
4469 env.require(
offers(alice, 1));
4472 env(offer(bob,
XRP(4000), gwUSD(40)));
4475 env.require(
offers(alice, 0));
4476 env.require(
balance(alice, gwUSD(40)));
4478 env.require(
offers(bob, 0));
4479 env.require(
balance(bob, gwUSD(10)));
4485 testcase(
"RippleConnect Smoketest payment flow");
4486 using namespace jtx;
4488 Env env{*
this, features};
4498 auto const hotUS =
Account(
"hotUS");
4499 auto const coldUS =
Account(
"coldUS");
4500 auto const hotEU =
Account(
"hotEU");
4501 auto const coldEU =
Account(
"coldEU");
4502 auto const mm =
Account(
"mm");
4504 auto const USD = coldUS[
"USD"];
4505 auto const EUR = coldEU[
"EUR"];
4507 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4511 for (
auto const& cold : {coldUS, coldEU})
4534 env(
pay(coldUS, hotUS, USD(5000000)));
4535 env(
pay(coldEU, hotEU, EUR(5000000)));
4536 env(
pay(coldUS, mm, USD(5000000)));
4537 env(
pay(coldEU, mm, EUR(5000000)));
4541 float const rate = 0.9f;
4542 env(offer(mm, EUR(4000000 *
rate), USD(4000000)),
4545 float const reverseRate = 1.0f /
rate * 1.00101f;
4546 env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4553 jvParams[jss::destination_account] = coldEU.human();
4554 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4555 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4556 jvParams[jss::destination_amount][jss::value] = 10;
4557 jvParams[jss::source_account] = hotUS.human();
4560 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4562 BEAST_EXPECT(jrr[jss::status] ==
"success");
4564 jrr[jss::alternatives].isArray() &&
4565 jrr[jss::alternatives].size() > 0);
4568 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4574 testcase(
"Self Auth");
4576 using namespace jtx;
4578 Env env{*
this, features};
4580 auto const gw =
Account(
"gw");
4581 auto const alice =
Account(
"alice");
4582 auto const gwUSD = gw[
"USD"];
4583 auto const aliceUSD = alice[
"USD"];
4585 env.fund(
XRP(400000), gw, alice);
4589 env(offer(gw, gwUSD(40),
XRP(4000)));
4592 env.require(
offers(gw, 1));
4601 env.require(
offers(gw, 0));
4613 env(offer(gw, gwUSD(40),
XRP(4000)),
4617 env.require(
offers(gw, preauth ? 1 : 0));
4625 env(
trust(alice, gwUSD(100)));
4628 env(
pay(gw, alice, gwUSD(50)));
4631 env.require(
balance(alice, gwUSD(50)));
4634 env(offer(alice,
XRP(4000), gwUSD(40)));
4637 env.require(
offers(alice, 0));
4638 env.require(
balance(alice, gwUSD(10)));
4640 env.require(
offers(gw, 0));
4647 using namespace jtx;
4649 testcase(
"Deleted offer issuer");
4651 auto trustLineExists = [](
jtx::Env const& env,
4662 auto const USD = gw[
"USD"];
4663 auto const BUX = alice[
"BUX"];
4665 Env env{*
this, features};
4668 env.
trust(USD(1000), becky);
4669 env(
pay(gw, becky, USD(5)));
4671 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4682 env(
pay(becky, gw, USD(5)));
4683 env.
trust(USD(0), becky);
4685 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4686 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4687 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4694 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4696 if (gwSeq + 255 > openLedgerSeq)
4697 return gwSeq - openLedgerSeq + 255;
4701 for (
int i = 0; i < delta; ++i)
4718 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4719 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4725 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4726 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4731 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4735 env.
trust(BUX(1000), carol);
4736 env(
pay(alice, carol, BUX(2)));
4738 env(offer(alice, BUX(2),
XRP(2)));
4745 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4746 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4752 testcase(
"Tick Size");
4754 using namespace jtx;
4758 Env env{*
this, features};
4759 auto const gw =
Account{
"gateway"};
4760 env.fund(
XRP(10000), gw);
4762 auto txn =
noop(gw);
4768 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == Quality::minTickSize);
4773 BEAST_EXPECT(!env.le(gw)->isFieldPresent(
sfTickSize));
4778 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == Quality::maxTickSize - 1);
4786 BEAST_EXPECT(!env.le(gw)->isFieldPresent(
sfTickSize));
4789 Env env{*
this, features};
4790 auto const gw =
Account{
"gateway"};
4791 auto const alice =
Account{
"alice"};
4792 auto const XTS = gw[
"XTS"];
4793 auto const XXX = gw[
"XXX"];
4795 env.fund(
XRP(10000), gw, alice);
4799 auto txn =
noop(gw);
4802 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == 5);
4805 env(
trust(alice, XTS(1000)));
4806 env(
trust(alice, XXX(1000)));
4808 env(
pay(gw, alice, alice[
"XTS"](100)));
4809 env(
pay(gw, alice, alice[
"XXX"](100)));
4811 env(offer(alice, XTS(10), XXX(30)));
4812 env(offer(alice, XTS(30), XXX(10)));
4813 env(offer(alice, XTS(10), XXX(30)),
json(jss::Flags,
tfSell));
4814 env(offer(alice, XTS(30), XXX(10)),
json(jss::Flags,
tfSell));
4819 if (sle->getType() == ltOFFER)
4823 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4827 auto it =
offers.begin();
4828 BEAST_EXPECT(it !=
offers.end());
4830 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4831 it->second.second > XXX(29.9994));
4835 BEAST_EXPECT(it !=
offers.end());
4837 it->second.first == XTS(30) && it->second.second == XXX(10));
4841 BEAST_EXPECT(it !=
offers.end());
4843 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4848 BEAST_EXPECT(it !=
offers.end());
4850 it->second.first == XTS(30) && it->second.second == XXX(10));
4852 BEAST_EXPECT(++it ==
offers.end());
4866 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4874 testcase(
"Ticket Offers");
4876 using namespace jtx;
4884 Env env{*
this, features};
4885 auto const gw =
Account{
"gateway"};
4886 auto const alice =
Account{
"alice"};
4887 auto const bob =
Account{
"bob"};
4888 auto const USD = gw[
"USD"];
4890 env.fund(
XRP(10000), gw, alice, bob);
4893 env(
trust(alice, USD(1000)));
4894 env(
trust(bob, USD(1000)));
4897 env(
pay(gw, alice, USD(200)));
4904 env(offer(alice,
XRP(50), USD(50)));
4909 env(ticket::create(alice, 2));
4914 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4915 env(offer(alice,
XRP(50), USD(50)));
4931 BEAST_EXPECT(
offers.size() == 4);
4936 env.require(
balance(alice, USD(200)));
4937 env.require(
owners(alice, 5));
4941 env(offer(bob, USD(50),
XRP(50)));
4947 BEAST_EXPECT(
offers.size() == 3);
4954 env(offer(bob, USD(50),
XRP(50)));
4960 BEAST_EXPECT(
offers.size() == 2);
4966 env(offer(bob, USD(50),
XRP(50)));
4972 BEAST_EXPECT(
offers.size() == 1);
4977 env(offer(bob, USD(50),
XRP(50)));
4983 BEAST_EXPECT(
offers.size() == 0);
4985 env.require(
balance(alice, USD(0)));
4986 env.require(
owners(alice, 1));
4987 env.require(
balance(bob, USD(200)));
4988 env.require(
owners(bob, 1));
4994 testcase(
"Ticket Cancel Offers");
4996 using namespace jtx;
5000 Env env{*
this, features};
5001 auto const gw =
Account{
"gateway"};
5002 auto const alice =
Account{
"alice"};
5003 auto const USD = gw[
"USD"];
5005 env.fund(
XRP(10000), gw, alice);
5008 env(
trust(alice, USD(1000)));
5012 env(
pay(gw, alice, USD(200)));
5017 env(offer(alice,
XRP(50), USD(50)));
5023 env(ticket::create(alice, 4));
5029 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5030 env(offer(alice,
XRP(50), USD(50)));
5046 BEAST_EXPECT(
offers.size() == 4);
5051 env.require(
balance(alice, USD(200)));
5052 env.require(
owners(alice, 7));
5062 BEAST_EXPECT(
offers.size() == 3);
5075 BEAST_EXPECT(
offers.size() == 2);
5090 BEAST_EXPECT(
offers.size() == 1);
5108 testcase(
"incorrect assert fixed");
5109 using namespace jtx;
5112 auto const alice =
Account(
"alice");
5113 auto const USD = alice[
"USD"];
5115 env.fund(
XRP(10000), alice);
5117 env(offer(alice,
XRP(100000000000), USD(100000000)));
5187 using namespace jtx;
5194 testAll(
all - takerDryOffer - immediateOfferKilled);
5195 testAll(
all - flowCross - takerDryOffer - immediateOfferKilled);
5196 testAll(
all - flowCross - immediateOfferKilled);
5197 testAll(
all - rmSmallIncreasedQOffers - immediateOfferKilled);
5208 using namespace jtx;
5215 testAll(
all - flowCross - f1513 - immediateOfferKilled);
5216 testAll(
all - flowCross - immediateOfferKilled);