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);
953 env(offer(alice,
XRP(1000), USD(1000)),
958 balance(alice, startBalance - f - f),
965 env(offer(alice,
XRP(1000), USD(1000)),
970 balance(alice, startBalance - f - f - f +
XRP(50)),
981 env(offer(alice,
XRP(50), USD(50)),
986 balance(alice, startBalance - f - f - f - f +
XRP(100)),
990 balance(bob, startBalance - f - f -
XRP(100)),
998 Env env(*
this, features);
1000 env.
fund(startBalance, gw, alice, bob);
1003 env(
trust(bob, USD(1000)));
1006 env(
pay(gw, bob, USD(1000)));
1009 env(offer(alice, USD(1000),
XRP(2000)));
1013 BEAST_EXPECT(aliceOffers.size() == 1);
1014 for (
auto offerPtr : aliceOffers)
1016 auto const& offer = *offerPtr;
1028 BEAST_EXPECT(bobOffers.size() == 1);
1029 for (
auto offerPtr : bobOffers)
1031 auto const& offer = *offerPtr;
1037 env(offer(gw,
XRP(2000), USD(1000)));
1043 env(offer(gw, USD(1000),
XRP(2000)));
1051 Env env(*
this, features);
1053 env.
fund(startBalance, gw,
"alice",
"bob");
1056 env(
trust(
"bob", USD(1000)));
1059 env(
pay(gw,
"bob", USD(1000)));
1060 env(offer(
"alice", USD(500),
XRP(1001)));
1063 env(offer(
"alice", USD(500),
XRP(1000)));
1067 BEAST_EXPECT(aliceOffers.size() == 2);
1077 BEAST_EXPECT(bobOffers.size() == 1);
1078 for (
auto offerPtr : bobOffers)
1080 auto const& offer = *offerPtr;
1090 testcase(
"Malformed Detection");
1092 using namespace jtx;
1094 auto const startBalance =
XRP(1000000);
1095 auto const gw =
Account{
"gateway"};
1096 auto const alice =
Account{
"alice"};
1097 auto const USD = gw[
"USD"];
1099 Env env{*
this, features};
1101 env.fund(startBalance, gw, alice);
1104 env(offer(alice, USD(1000),
XRP(1000)),
1111 env(offer(alice, USD(1000),
XRP(1000)),
1141 env(offer(alice, USD(1000),
XRP(1000)),
1149 env(offer(alice, USD(1000),
XRP(1000)),
1167 testcase(
"Offer Expiration");
1169 using namespace jtx;
1171 auto const gw =
Account{
"gateway"};
1172 auto const alice =
Account{
"alice"};
1173 auto const bob =
Account{
"bob"};
1174 auto const USD = gw[
"USD"];
1176 auto const startBalance =
XRP(1000000);
1177 auto const usdOffer = USD(1000);
1178 auto const xrpOffer =
XRP(1000);
1180 Env env{*
this, features};
1182 env.fund(startBalance, gw, alice, bob);
1185 auto const f = env.current()->fees().
base;
1191 balance(alice, startBalance - f),
1200 env(offer(alice, xrpOffer, usdOffer),
1205 balance(alice, startBalance - f - f),
1212 env(offer(alice, xrpOffer, usdOffer),
1216 balance(alice, startBalance - f - f - f),
1224 balance(alice, startBalance - f - f - f),
1232 balance(alice, startBalance - f - f - f),
1236 balance(bob, startBalance - f),
1245 testcase(
"Unfunded Crossing");
1247 using namespace jtx;
1249 auto const gw =
Account{
"gateway"};
1250 auto const USD = gw[
"USD"];
1252 auto const usdOffer = USD(1000);
1253 auto const xrpOffer =
XRP(1000);
1255 Env env{*
this, features};
1257 env.fund(
XRP(1000000), gw);
1260 auto const f = env.current()->fees().
base;
1264 env.fund(
reserve(env, 0),
"alice");
1270 env.fund(
reserve(env, 0) + f,
"bob");
1277 env.fund(
reserve(env, 0) + f +
XRP(1),
"carol");
1284 env.fund(
reserve(env, 1) + f,
"dan");
1290 env.fund(
reserve(env, 1) + f + xrpOffer,
"eve");
1301 (use_partner ?
", with partner account" :
""));
1303 using namespace jtx;
1305 auto const gw =
Account{
"gateway"};
1306 auto const partner =
Account{
"partner"};
1307 auto const USD = gw[
"USD"];
1308 auto const BTC = gw[
"BTC"];
1310 Env env{*
this, features};
1313 env.fund(
XRP(10000), gw);
1316 env.fund(
XRP(10000), partner);
1317 env(
trust(partner, USD(100)));
1318 env(
trust(partner, BTC(500)));
1319 env(
pay(gw, partner, USD(100)));
1320 env(
pay(gw, partner, BTC(500)));
1322 auto const& account_to_test = use_partner ? partner : gw;
1325 env.require(
offers(account_to_test, 0));
1330 env(offer(account_to_test, BTC(250),
XRP(1000)));
1331 env.require(
offers(account_to_test, 1));
1334 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250),
XRP(1000)));
1336 auto const secondLegSeq = env.seq(account_to_test);
1337 env(offer(account_to_test,
XRP(1000), USD(50)));
1338 env.require(
offers(account_to_test, 2));
1341 BEAST_EXPECT(
isOffer(env, account_to_test,
XRP(1000), USD(50)));
1345 env(offer(account_to_test, USD(50), BTC(250)));
1348 BEAST_EXPECT(jrr[jss::offers].isArray());
1349 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1352 BEAST_EXPECT(jrr[jss::offers].isArray());
1353 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1364 bool const noStaleOffers{
1368 BEAST_EXPECT(acctOffers.size() == (noStaleOffers ? 0 : 1));
1369 for (
auto const& offerPtr : acctOffers)
1371 auto const& offer = *offerPtr;
1382 env.require(
offers(account_to_test, 0));
1387 env(offer(account_to_test, BTC(250), USD(50)));
1388 env.require(
offers(account_to_test, 1));
1392 BEAST_EXPECT(
isOffer(env, account_to_test, BTC(250), USD(50)));
1395 BEAST_EXPECT(jrr[jss::offers].isArray());
1396 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1400 env(offer(account_to_test, USD(50), BTC(250)));
1401 env.require(
offers(account_to_test, 1));
1406 BEAST_EXPECT(jrr[jss::offers].isArray());
1407 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1409 BEAST_EXPECT(
isOffer(env, account_to_test, USD(50), BTC(250)));
1417 testcase(
"Negative Balance");
1419 using namespace jtx;
1421 Env env{*
this, features};
1423 auto const gw =
Account{
"gateway"};
1424 auto const alice =
Account{
"alice"};
1425 auto const bob =
Account{
"bob"};
1426 auto const USD = gw[
"USD"];
1427 auto const BTC = gw[
"BTC"];
1431 auto const gw_initial_balance =
drops(1149999730);
1432 auto const alice_initial_balance =
drops(499946999680);
1433 auto const bob_initial_balance =
drops(10199999920);
1434 auto const small_amount =
1435 STAmount{bob[
"USD"].
issue(), UINT64_C(2710505431213761), -33};
1437 env.fund(gw_initial_balance, gw);
1438 env.fund(alice_initial_balance, alice);
1439 env.fund(bob_initial_balance, bob);
1441 env(
rate(gw, 1.005));
1443 env(
trust(alice, USD(500)));
1444 env(
trust(bob, USD(50)));
1445 env(
trust(gw, alice[
"USD"](100)));
1447 env(
pay(gw, alice, alice[
"USD"](50)));
1448 env(
pay(gw, bob, small_amount));
1450 env(offer(alice, USD(50),
XRP(150000)));
1453 env(
pay(alice, gw, USD(100)));
1456 env(
trust(gw, alice[
"USD"](0)));
1465 "-2710505431213761e-33");
1468 env(offer(bob,
XRP(2000), USD(1)));
1477 auto const crossingDelta =
1484 alice_initial_balance - env.current()->fees().base * 3 -
1491 bob_initial_balance - env.current()->fees().base * 2 +
1500 (reverse_order ?
"Reverse" :
"Normal") +
" order");
1502 using namespace jtx;
1504 Env env{*
this, features};
1506 auto const gw =
Account{
"gateway"};
1507 auto const alice =
Account{
"alice"};
1508 auto const bob =
Account{
"bob"};
1509 auto const USD = gw[
"USD"];
1511 env.fund(
XRP(10000), gw, alice, bob);
1513 env(
trust(alice, USD(1000)));
1514 env(
trust(bob, USD(1000)));
1516 env(
pay(gw, alice, alice[
"USD"](500)));
1519 env(offer(bob, USD(1),
XRP(4000)));
1521 env(offer(alice,
XRP(150000), USD(50)));
1524 env(offer(bob, USD(1),
XRP(4000)));
1536 env.current()->fees().base * 2)
1545 env.current()->fees().base * 2)
1552 testcase(
"Offer Crossing with Limit Override");
1554 using namespace jtx;
1556 Env env{*
this, features};
1558 auto const gw =
Account{
"gateway"};
1559 auto const alice =
Account{
"alice"};
1560 auto const bob =
Account{
"bob"};
1561 auto const USD = gw[
"USD"];
1563 env.fund(
XRP(100000), gw, alice, bob);
1565 env(
trust(alice, USD(1000)));
1567 env(
pay(gw, alice, alice[
"USD"](500)));
1569 env(offer(alice,
XRP(150000), USD(50)));
1570 env(offer(bob, USD(1),
XRP(3000)));
1592 testcase(
"Offer Accept then Cancel.");
1594 using namespace jtx;
1596 Env env{*
this, features};
1598 auto const USD = env.master[
"USD"];
1600 auto const nextOfferSeq = env.seq(env.master);
1601 env(offer(env.master,
XRP(500), USD(100)));
1605 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1610 BEAST_EXPECT(env.seq(env.master) == nextOfferSeq + 2);
1616 testcase(
"Offer Cancel Past and Future Sequence.");
1618 using namespace jtx;
1620 Env env{*
this, features};
1622 auto const alice =
Account{
"alice"};
1624 auto const nextOfferSeq = env.seq(env.master);
1625 env.fund(
XRP(10000), alice);
1641 testcase(
"Currency Conversion: Entire Offer");
1643 using namespace jtx;
1645 Env env{*
this, features};
1647 auto const gw =
Account{
"gateway"};
1648 auto const alice =
Account{
"alice"};
1649 auto const bob =
Account{
"bob"};
1650 auto const USD = gw[
"USD"];
1652 env.fund(
XRP(10000), gw, alice, bob);
1653 env.require(
owners(bob, 0));
1655 env(
trust(alice, USD(100)));
1656 env(
trust(bob, USD(1000)));
1660 env(
pay(gw, alice, alice[
"USD"](100)));
1661 auto const bobOfferSeq = env.seq(bob);
1662 env(offer(bob, USD(100),
XRP(500)));
1667 jro[jss::node][jss::TakerGets] ==
XRP(500).value().getText());
1669 jro[jss::node][jss::TakerPays] ==
1686 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1694 testcase(
"Currency Conversion: Offerer Into Debt");
1696 using namespace jtx;
1698 Env env{*
this, features};
1700 auto const alice =
Account{
"alice"};
1701 auto const bob =
Account{
"bob"};
1702 auto const carol =
Account{
"carol"};
1704 env.fund(
XRP(10000), alice, bob, carol);
1706 env(
trust(alice, carol[
"EUR"](2000)));
1707 env(
trust(bob, alice[
"USD"](100)));
1708 env(
trust(carol, bob[
"EUR"](1000)));
1710 auto const bobOfferSeq = env.seq(bob);
1711 env(offer(bob, alice[
"USD"](50), carol[
"EUR"](200)),
1714 env(offer(alice, carol[
"EUR"](200), alice[
"USD"](50)));
1717 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1723 testcase(
"Currency Conversion: In Parts");
1725 using namespace jtx;
1727 Env env{*
this, features};
1729 auto const gw =
Account{
"gateway"};
1730 auto const alice =
Account{
"alice"};
1731 auto const bob =
Account{
"bob"};
1732 auto const USD = gw[
"USD"];
1734 env.fund(
XRP(10000), gw, alice, bob);
1736 env(
trust(alice, USD(200)));
1737 env(
trust(bob, USD(1000)));
1739 env(
pay(gw, alice, alice[
"USD"](200)));
1741 auto const bobOfferSeq = env.seq(bob);
1742 env(offer(bob, USD(100),
XRP(500)));
1749 jro[jss::node][jss::TakerGets] ==
XRP(300).value().getText());
1751 jro[jss::node][jss::TakerPays] ==
1771 env(
pay(alice, alice,
XRP(600)),
1777 env(
pay(alice, alice,
XRP(600)),
1783 BEAST_EXPECT(jro[jss::error] ==
"entryNotFound");
1796 env.current()->fees().base * 4)
1808 testcase(
"Cross Currency Payment: Start with XRP");
1810 using namespace jtx;
1812 Env env{*
this, features};
1814 auto const gw =
Account{
"gateway"};
1815 auto const alice =
Account{
"alice"};
1816 auto const bob =
Account{
"bob"};
1817 auto const carol =
Account{
"carol"};
1818 auto const USD = gw[
"USD"];
1820 env.fund(
XRP(10000), gw, alice, bob, carol);
1822 env(
trust(carol, USD(1000)));
1823 env(
trust(bob, USD(2000)));
1825 env(
pay(gw, carol, carol[
"USD"](500)));
1827 auto const carolOfferSeq = env.seq(carol);
1828 env(offer(carol,
XRP(500), USD(50)));
1840 jro[jss::node][jss::TakerGets] ==
1843 jro[jss::node][jss::TakerPays] ==
XRP(250).value().getText());
1849 testcase(
"Cross Currency Payment: End with XRP");
1851 using namespace jtx;
1853 Env env{*
this, features};
1855 auto const gw =
Account{
"gateway"};
1856 auto const alice =
Account{
"alice"};
1857 auto const bob =
Account{
"bob"};
1858 auto const carol =
Account{
"carol"};
1859 auto const USD = gw[
"USD"];
1861 env.fund(
XRP(10000), gw, alice, bob, carol);
1863 env(
trust(alice, USD(1000)));
1864 env(
trust(carol, USD(2000)));
1866 env(
pay(gw, alice, alice[
"USD"](500)));
1868 auto const carolOfferSeq = env.seq(carol);
1869 env(offer(carol, USD(50),
XRP(500)));
1883 XRP(10000).value().mantissa() +
XRP(250).value().mantissa()));
1887 jro[jss::node][jss::TakerGets] ==
XRP(250).value().getText());
1889 jro[jss::node][jss::TakerPays] ==
1896 testcase(
"Cross Currency Payment: Bridged");
1898 using namespace jtx;
1900 Env env{*
this, features};
1902 auto const gw1 =
Account{
"gateway_1"};
1903 auto const gw2 =
Account{
"gateway_2"};
1904 auto const alice =
Account{
"alice"};
1905 auto const bob =
Account{
"bob"};
1906 auto const carol =
Account{
"carol"};
1907 auto const dan =
Account{
"dan"};
1908 auto const USD = gw1[
"USD"];
1909 auto const EUR = gw2[
"EUR"];
1911 env.fund(
XRP(10000), gw1, gw2, alice, bob, carol, dan);
1913 env(
trust(alice, USD(1000)));
1914 env(
trust(bob, EUR(1000)));
1915 env(
trust(carol, USD(1000)));
1916 env(
trust(dan, EUR(1000)));
1918 env(
pay(gw1, alice, alice[
"USD"](500)));
1919 env(
pay(gw2, dan, dan[
"EUR"](400)));
1921 auto const carolOfferSeq = env.seq(carol);
1922 env(offer(carol, USD(50),
XRP(500)));
1924 auto const danOfferSeq = env.seq(dan);
1925 env(offer(dan,
XRP(500), EUR(50)));
1928 jtp[0u][0u][jss::currency] =
"XRP";
1929 env(
pay(alice, bob, EUR(30)),
json(jss::Paths, jtp),
sendmax(USD(333)));
1945 jro[jss::node][jss::TakerGets] ==
XRP(200).value().getText());
1947 jro[jss::node][jss::TakerPays] ==
1952 jro[jss::node][jss::TakerGets] ==
1955 jro[jss::node][jss::TakerPays] ==
XRP(200).value().getText());
1964 testcase(
"Auto Bridged Second Leg Dry");
1966 using namespace jtx;
1967 Env env(*
this, features);
1973 auto const USD = gw[
"USD"];
1974 auto const EUR = gw[
"EUR"];
1976 env.
fund(
XRP(100000000), alice, bob, carol, gw);
1978 env.
trust(USD(10), alice);
1980 env(
pay(gw, alice, USD(10)));
1981 env.
trust(USD(10), carol);
1983 env(
pay(gw, carol, USD(3)));
1985 env(offer(alice, EUR(2),
XRP(1)));
1986 env(offer(alice, EUR(2),
XRP(1)));
1988 env(offer(alice,
XRP(1), USD(4)));
1989 env(offer(carol,
XRP(1), USD(3)));
2000 env.
trust(EUR(10), bob);
2002 env(
pay(gw, bob, EUR(10)));
2004 env(offer(bob, USD(10), EUR(10)));
2021 int const emptyOfferCount{
2033 testcase(
"Offer Fees Consume Funds");
2035 using namespace jtx;
2037 Env env{*
this, features};
2039 auto const gw1 =
Account{
"gateway_1"};
2040 auto const gw2 =
Account{
"gateway_2"};
2041 auto const gw3 =
Account{
"gateway_3"};
2042 auto const alice =
Account{
"alice"};
2043 auto const bob =
Account{
"bob"};
2044 auto const USD1 = gw1[
"USD"];
2045 auto const USD2 = gw2[
"USD"];
2046 auto const USD3 = gw3[
"USD"];
2054 auto const starting_xrp =
XRP(100) +
2055 env.current()->fees().accountReserve(3) +
2056 env.current()->fees().base * 4;
2058 env.fund(starting_xrp, gw1, gw2, gw3, alice, bob);
2060 env(
trust(alice, USD1(1000)));
2061 env(
trust(alice, USD2(1000)));
2062 env(
trust(alice, USD3(1000)));
2063 env(
trust(bob, USD1(1000)));
2064 env(
trust(bob, USD2(1000)));
2066 env(
pay(gw1, bob, bob[
"USD"](500)));
2068 env(offer(bob,
XRP(200), USD1(200)));
2071 env(offer(alice, USD1(200),
XRP(200)));
2086 testcase(
"Offer Create, then Cross");
2088 using namespace jtx;
2090 Env env{*
this, features};
2092 auto const gw =
Account{
"gateway"};
2093 auto const alice =
Account{
"alice"};
2094 auto const bob =
Account{
"bob"};
2095 auto const USD = gw[
"USD"];
2097 env.fund(
XRP(10000), gw, alice, bob);
2099 env(
rate(gw, 1.005));
2101 env(
trust(alice, USD(1000)));
2102 env(
trust(bob, USD(1000)));
2103 env(
trust(gw, alice[
"USD"](50)));
2105 env(
pay(gw, bob, bob[
"USD"](1)));
2106 env(
pay(alice, gw, USD(50)));
2108 env(
trust(gw, alice[
"USD"](0)));
2110 env(offer(alice, USD(50),
XRP(150000)));
2111 env(offer(bob,
XRP(100), USD(0.1)));
2116 "49.96666666666667");
2120 "-0.966500000033334");
2126 testcase(
"Offer tfSell: Basic Sell");
2128 using namespace jtx;
2130 Env env{*
this, features};
2132 auto const gw =
Account{
"gateway"};
2133 auto const alice =
Account{
"alice"};
2134 auto const bob =
Account{
"bob"};
2135 auto const USD = gw[
"USD"];
2137 auto const starting_xrp =
XRP(100) +
2138 env.current()->fees().accountReserve(1) +
2139 env.current()->fees().base * 2;
2141 env.fund(starting_xrp, gw, alice, bob);
2143 env(
trust(alice, USD(1000)));
2144 env(
trust(bob, USD(1000)));
2146 env(
pay(gw, bob, bob[
"USD"](500)));
2148 env(offer(bob,
XRP(200), USD(200)),
json(jss::Flags,
tfSell));
2152 env(offer(alice, USD(200),
XRP(200)),
json(jss::Flags,
tfSell));
2167 testcase(
"Offer tfSell: 2x Sell Exceed Limit");
2169 using namespace jtx;
2171 Env env{*
this, features};
2173 auto const gw =
Account{
"gateway"};
2174 auto const alice =
Account{
"alice"};
2175 auto const bob =
Account{
"bob"};
2176 auto const USD = gw[
"USD"];
2178 auto const starting_xrp =
XRP(100) +
2179 env.current()->fees().accountReserve(1) +
2180 env.current()->fees().base * 2;
2182 env.fund(starting_xrp, gw, alice, bob);
2184 env(
trust(alice, USD(150)));
2185 env(
trust(bob, USD(1000)));
2187 env(
pay(gw, bob, bob[
"USD"](500)));
2189 env(offer(bob,
XRP(100), USD(200)));
2195 env(offer(alice, USD(100),
XRP(100)),
json(jss::Flags,
tfSell));
2210 testcase(
"Client Issue #535: Gateway Cross Currency");
2212 using namespace jtx;
2214 Env env{*
this, features};
2216 auto const gw =
Account{
"gateway"};
2217 auto const alice =
Account{
"alice"};
2218 auto const bob =
Account{
"bob"};
2219 auto const XTS = gw[
"XTS"];
2220 auto const XXX = gw[
"XXX"];
2222 auto const starting_xrp =
XRP(100.1) +
2223 env.current()->fees().accountReserve(1) +
2224 env.current()->fees().base * 2;
2226 env.fund(starting_xrp, gw, alice, bob);
2228 env(
trust(alice, XTS(1000)));
2229 env(
trust(alice, XXX(1000)));
2230 env(
trust(bob, XTS(1000)));
2231 env(
trust(bob, XXX(1000)));
2233 env(
pay(gw, alice, alice[
"XTS"](100)));
2234 env(
pay(gw, alice, alice[
"XXX"](100)));
2235 env(
pay(gw, bob, bob[
"XTS"](100)));
2236 env(
pay(gw, bob, bob[
"XXX"](100)));
2238 env(offer(alice, XTS(100), XXX(100)));
2245 payment[jss::id] = env.seq(bob);
2246 payment[jss::build_path] =
true;
2247 payment[jss::tx_json] =
pay(bob, bob, bob[
"XXX"](1));
2248 payment[jss::tx_json][jss::Sequence] =
2252 payment[jss::tx_json][jss::Fee] =
to_string(env.current()->fees().base);
2253 payment[jss::tx_json][jss::SendMax] =
2255 auto jrr = wsc->invoke(
"submit", payment);
2256 BEAST_EXPECT(jrr[jss::status] ==
"success");
2257 BEAST_EXPECT(jrr[jss::result][jss::engine_result] ==
"tesSUCCESS");
2258 if (wsc->version() == 2)
2261 jrr.isMember(jss::jsonrpc) && jrr[jss::jsonrpc] ==
"2.0");
2263 jrr.isMember(jss::ripplerpc) && jrr[jss::ripplerpc] ==
"2.0");
2264 BEAST_EXPECT(jrr.isMember(jss::id) && jrr[jss::id] == 5);
2290 auto const sleTrust =
2292 BEAST_EXPECT(sleTrust);
2296 bool const accountLow = account.id() < issue.
account;
2301 low.setIssuer(accountLow ? account.id() : issue.
account);
2302 high.setIssuer(accountLow ? issue.
account : account.id());
2304 BEAST_EXPECT(sleTrust->getFieldAmount(
sfLowLimit) == low);
2305 BEAST_EXPECT(sleTrust->getFieldAmount(
sfHighLimit) == high);
2311 BEAST_EXPECT(actualBalance == expectBalance);
2321 testcase(
"Partial Crossing");
2323 using namespace jtx;
2325 auto const gw =
Account(
"gateway");
2326 auto const USD = gw[
"USD"];
2328 Env env{*
this, features};
2330 env.fund(
XRP(10000000), gw);
2333 auto const f = env.current()->fees().
base;
2336 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2342 preTrustType preTrust;
2352 TestData
const tests[]{
2354 {
"ann",
reserve(env, 0) + 0 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2355 {
"bev",
reserve(env, 0) + 1 * f, 1, noPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2356 {
"cam",
reserve(env, 0) + 2 * f, 0, noPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2357 {
"deb",
reserve(env, 0) + 2 * f, 1, noPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 1},
2358 {
"eve",
reserve(env, 1) + 0 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2359 {
"flo",
reserve(env, 1) + 0 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2360 {
"gay",
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 50) + f, USD( 50), 0, 1},
2361 {
"hye",
XRP(1000) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 800) + f, USD( 800), 0, 1},
2362 {
"ivy",
XRP( 1) +
reserve(env, 1) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 0, 1},
2363 {
"joy",
XRP( 1) +
reserve(env, 2) + 1 * f, 1, noPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 2},
2364 {
"kim",
XRP( 900) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2365 {
"liz",
XRP( 998) +
reserve(env, 0) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 998) + f, USD( 998), 0, 1},
2366 {
"meg",
XRP( 998) +
reserve(env, 1) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2367 {
"nia",
XRP( 998) +
reserve(env, 2) + 1 * f, 999, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 1, 2},
2368 {
"ova",
XRP( 999) +
reserve(env, 0) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP( 999) + f, USD( 999), 0, 1},
2369 {
"pam",
XRP( 999) +
reserve(env, 1) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2370 {
"rae",
XRP( 999) +
reserve(env, 2) + 1 * f, 1000, noPreTrust, 1000,
tesSUCCESS,
XRP(1000) + f, USD( 1000), 0, 1},
2371 {
"sue",
XRP(1000) +
reserve(env, 2) + 1 * f, 0, noPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2373 {
"abe",
reserve(env, 0) + 0 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2374 {
"bud",
reserve(env, 0) + 1 * f, 1, gwPreTrust, 1000,
tecUNFUNDED_OFFER, f, USD( 0), 0, 0},
2375 {
"che",
reserve(env, 0) + 2 * f, 0, gwPreTrust, 1000,
tecINSUF_RESERVE_OFFER, f, USD( 0), 0, 0},
2376 {
"dan",
reserve(env, 0) + 2 * f, 1, gwPreTrust, 1000,
tesSUCCESS, 2 * f, USD(0.00001), 0, 0},
2377 {
"eli",
XRP( 20) +
reserve(env, 0) + 1 * f, 1000, gwPreTrust, 1000,
tesSUCCESS,
XRP(20) + 1 * f, USD( 20), 0, 0},
2378 {
"fyn",
reserve(env, 1) + 0 * f, 0, gwPreTrust, 1000,
tesSUCCESS, f, USD( 0), 1, 1},
2379 {
"gar",
reserve(env, 1) + 0 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2380 {
"hal",
reserve(env, 1) + 1 * f, 1, gwPreTrust, 1000,
tesSUCCESS,
XRP( 1) + f, USD( 1), 1, 1},
2382 {
"ned",
reserve(env, 1) + 0 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2383 {
"ole",
reserve(env, 1) + 1 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2384 {
"pat",
reserve(env, 1) + 2 * f, 0, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2385 {
"quy",
reserve(env, 1) + 2 * f, 1, acctPreTrust, 1000,
tecUNFUNDED_OFFER, 2 * f, USD( 0), 0, 1},
2386 {
"ron",
reserve(env, 1) + 3 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2387 {
"syd",
reserve(env, 1) + 3 * f, 1, acctPreTrust, 1000,
tesSUCCESS, 3 * f, USD(0.00001), 0, 1},
2388 {
"ted",
XRP( 20) +
reserve(env, 1) + 2 * f, 1000, acctPreTrust, 1000,
tesSUCCESS,
XRP(20) + 2 * f, USD( 20), 0, 1},
2389 {
"uli",
reserve(env, 2) + 0 * f, 0, acctPreTrust, 1000,
tecINSUF_RESERVE_OFFER, 2 * f, USD( 0), 0, 1},
2390 {
"vic",
reserve(env, 2) + 0 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 0, 1},
2391 {
"wes",
reserve(env, 2) + 1 * f, 0, acctPreTrust, 1000,
tesSUCCESS, 2 * f, USD( 0), 1, 2},
2392 {
"xan",
reserve(env, 2) + 1 * f, 1, acctPreTrust, 1000,
tesSUCCESS,
XRP( 1) + 2 * f, USD( 1), 1, 2},
2396 for (
auto const& t : tests)
2398 auto const acct =
Account(t.account);
2399 env.fund(t.fundXrp, acct);
2403 env.require(
offers(gw, 0));
2406 auto const book = t.bookAmount;
2408 env(offer(gw,
XRP(book), USD(book)));
2413 if (t.preTrust == gwPreTrust)
2414 env(
trust(gw, acct[
"USD"](1)));
2419 if (t.preTrust == acctPreTrust)
2420 env(
trust(acct, USD(1)));
2426 auto const acctOffer = t.offerAmount;
2427 env(offer(acct, USD(acctOffer),
XRP(acctOffer)),
ter(t.tec));
2432 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.balanceUsd);
2434 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2435 env.require(
offers(acct, t.offers));
2436 env.require(
owners(acct, t.owners));
2439 BEAST_EXPECT(acctOffers.size() == t.offers);
2440 if (acctOffers.size() && t.offers)
2442 auto const& acctOffer = *(acctOffers.front());
2444 auto const leftover = t.offerAmount - t.bookAmount;
2446 BEAST_EXPECT(acctOffer[
sfTakerPays] == USD(leftover));
2449 if (t.preTrust == noPreTrust)
2451 if (t.balanceUsd.value().signum())
2459 auto const sleTrust =
2461 BEAST_EXPECT(!sleTrust);
2476 testcase(
"XRP Direct Crossing");
2478 using namespace jtx;
2480 auto const gw =
Account(
"gateway");
2481 auto const alice =
Account(
"alice");
2482 auto const bob =
Account(
"bob");
2483 auto const USD = gw[
"USD"];
2485 auto const usdOffer = USD(1000);
2486 auto const xrpOffer =
XRP(1000);
2488 Env env{*
this, features};
2490 env.fund(
XRP(1000000), gw, bob);
2494 auto const fee = env.current()->fees().base;
2501 env(
trust(alice, usdOffer));
2505 env(
pay(gw, alice, usdOffer));
2512 auto const alicesXRP = env.balance(alice);
2513 auto const bobsXRP = env.balance(bob);
2515 env(offer(alice, xrpOffer, usdOffer));
2517 env(offer(bob, usdOffer, xrpOffer));
2531 env(offer(alice, USD(999),
XRP(999)));
2532 env(offer(bob, xrpOffer, usdOffer));
2535 env.require(
balance(alice, USD(999)));
2536 env.require(
balance(bob, USD(1)));
2537 env.require(
offers(alice, 0));
2541 BEAST_EXPECT(bobsOffers.size() == 1);
2542 auto const& bobsOffer = *(bobsOffers.front());
2553 testcase(
"Direct Crossing");
2555 using namespace jtx;
2557 auto const gw =
Account(
"gateway");
2558 auto const alice =
Account(
"alice");
2559 auto const bob =
Account(
"bob");
2560 auto const USD = gw[
"USD"];
2561 auto const EUR = gw[
"EUR"];
2563 auto const usdOffer = USD(1000);
2564 auto const eurOffer = EUR(1000);
2566 Env env{*
this, features};
2568 env.fund(
XRP(1000000), gw);
2572 auto const fee = env.current()->fees().base;
2580 env(
trust(alice, usdOffer));
2581 env(
trust(bob, eurOffer));
2584 env(
pay(gw, alice, usdOffer));
2585 env(
pay(gw, bob, eurOffer));
2593 env(offer(alice, eurOffer, usdOffer));
2594 env(offer(bob, usdOffer, eurOffer));
2611 env(offer(bob, eurOffer, usdOffer));
2614 env(offer(alice, USD(999), eurOffer));
2617 env.require(
offers(alice, 0));
2618 env.require(
offers(bob, 1));
2620 env.require(
balance(alice, USD(999)));
2621 env.require(
balance(alice, EUR(1)));
2622 env.require(
balance(bob, USD(1)));
2623 env.require(
balance(bob, EUR(999)));
2627 if (BEAST_EXPECT(bobsOffers.size() == 1))
2629 auto const& bobsOffer = *(bobsOffers.front());
2637 env(offer(alice, USD(1), EUR(1)));
2640 env.require(
balance(alice, USD(1000)));
2643 env.require(
balance(bob, EUR(1000)));
2644 env.require(
offers(alice, 0));
2645 env.require(
offers(bob, 0));
2648 BEAST_EXPECT(!env.le(
keylet::line(alice.id(), EUR.issue())));
2649 BEAST_EXPECT(!env.le(
keylet::line(bob.id(), USD.issue())));
2653 env(offer(alice, EUR(999), usdOffer));
2656 env(offer(bob, usdOffer, eurOffer));
2659 env.require(
offers(alice, 0));
2660 env.require(
offers(bob, 0));
2662 env.require(
balance(alice, USD(0)));
2663 env.require(
balance(alice, EUR(999)));
2664 env.require(
balance(bob, USD(1000)));
2665 env.require(
balance(bob, EUR(1)));
2671 testcase(
"Bridged Crossing");
2673 using namespace jtx;
2675 auto const gw =
Account(
"gateway");
2676 auto const alice =
Account(
"alice");
2677 auto const bob =
Account(
"bob");
2678 auto const carol =
Account(
"carol");
2679 auto const USD = gw[
"USD"];
2680 auto const EUR = gw[
"EUR"];
2682 auto const usdOffer = USD(1000);
2683 auto const eurOffer = EUR(1000);
2685 Env env{*
this, features};
2687 env.fund(
XRP(1000000), gw, alice, bob, carol);
2690 env(
trust(alice, usdOffer));
2691 env(
trust(carol, eurOffer));
2693 env(
pay(gw, alice, usdOffer));
2694 env(
pay(gw, carol, eurOffer));
2703 env(offer(alice,
XRP(1000), usdOffer));
2704 env(offer(bob, eurOffer,
XRP(1000)));
2705 auto const bobXrpBalance = env.balance(bob);
2709 env(offer(carol, USD(400), EUR(400)));
2722 BEAST_EXPECT(alicesOffers.size() == 1);
2723 auto const& alicesOffer = *(alicesOffers.front());
2726 BEAST_EXPECT(alicesOffer[
sfTakerGets] == USD(600));
2731 BEAST_EXPECT(bobsOffers.size() == 1);
2732 auto const& bobsOffer = *(bobsOffers.front());
2740 env(offer(carol, USD(600), EUR(600)));
2755 if (alicesOffers.size() != 0)
2757 BEAST_EXPECT(alicesOffers.size() == 1);
2758 auto const& alicesOffer = *(alicesOffers.front());
2772 testcase(
"Sell Offer");
2774 using namespace jtx;
2776 auto const gw =
Account(
"gateway");
2777 auto const USD = gw[
"USD"];
2779 Env env{*
this, features};
2781 env.fund(
XRP(10000000), gw);
2784 auto const f = env.current()->fees().
base;
2787 enum preTrustType { noPreTrust, gwPreTrust, acctPreTrust };
2821 : account(std::move(account_))
2826 , acctGets(acctGets_)
2827 , acctPays(acctPays_)
2829 , spentXrp(spentXrp_)
2830 , finalUsd(finalUsd_)
2833 , takerGets(takerGets_)
2834 , takerPays(takerPays_)
2853 std::move(account_),
2872 TestData
const tests[]{
2875 {
"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},
2876 {
"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)},
2877 {
"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},
2878 {
"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},
2879 {
"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},
2880 {
"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},
2881 {
"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},
2882 {
"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)},
2884 {
"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},
2885 {
"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)},
2886 {
"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},
2887 {
"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},
2888 {
"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},
2889 {
"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)},
2890 {
"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)},
2894 auto const zeroUsd = USD(0);
2895 for (
auto const& t : tests)
2898 env.require(
offers(gw, 0));
2900 auto const acct =
Account(t.account);
2902 env.fund(t.fundXrp, acct);
2908 if (t.fundUSD != zeroUsd)
2910 env(
trust(acct, t.fundUSD));
2912 env(
pay(gw, acct, t.fundUSD));
2916 env(offer(gw, t.gwGets, t.gwPays));
2921 env(offer(acct, t.acctGets, t.acctPays,
tfSell),
ter(t.tec));
2926 BEAST_EXPECT(env.balance(acct, USD.issue()) == t.finalUsd);
2928 env.balance(acct,
xrpIssue()) == t.fundXrp - t.spentXrp);
2929 env.require(
offers(acct, t.offers));
2930 env.require(
owners(acct, t.owners));
2935 if (acctOffers.size() > 0)
2937 BEAST_EXPECT(acctOffers.size() == 1);
2938 auto const& acctOffer = *(acctOffers.front());
2941 BEAST_EXPECT(acctOffer[
sfTakerGets] == t.takerGets);
2942 BEAST_EXPECT(acctOffer[
sfTakerPays] == t.takerPays);
2959 testcase(
"Combine tfSell with tfFillOrKill");
2961 using namespace jtx;
2963 auto const gw =
Account(
"gateway");
2964 auto const alice =
Account(
"alice");
2965 auto const bob =
Account(
"bob");
2966 auto const USD = gw[
"USD"];
2968 Env env{*
this, features};
2970 env.fund(
XRP(10000000), gw, alice, bob);
2973 TER const killedCode{
2977 env(
trust(bob, USD(200)));
2979 env(
pay(gw, bob, USD(100)));
2981 env(offer(bob,
XRP(2000), USD(20)));
2989 env.require(
offers(alice, 0));
2990 env.require(
balance(bob, USD(100)));
2997 env.require(
balance(alice, USD(20)));
2998 env.require(
offers(alice, 0));
2999 env.require(
balance(bob, USD(80)));
3004 env(offer(bob,
XRP(2000), USD(20)));
3008 env.require(
balance(alice, USD(35)));
3009 env.require(
offers(alice, 0));
3010 env.require(
balance(bob, USD(65)));
3022 env.require(
balance(alice, USD(35)));
3023 env.require(
offers(alice, 0));
3024 env.require(
balance(bob, USD(65)));
3033 env.require(
balance(alice, USD(40)));
3034 env.require(
offers(alice, 0));
3035 env.require(
balance(bob, USD(60)));
3042 testcase(
"Transfer Rate Offer");
3044 using namespace jtx;
3046 auto const gw1 =
Account(
"gateway1");
3047 auto const USD = gw1[
"USD"];
3049 Env env{*
this, features};
3052 auto const fee = env.current()->fees().base;
3054 env.fund(
XRP(100000), gw1);
3057 env(
rate(gw1, 1.25));
3059 auto const ann =
Account(
"ann");
3060 auto const bob =
Account(
"bob");
3064 env(
trust(ann, USD(200)));
3065 env(
trust(bob, USD(200)));
3068 env(
pay(gw1, bob, USD(125)));
3077 env(offer(bob,
XRP(1), USD(100)));
3080 env(offer(ann, USD(100),
XRP(1)));
3083 env.require(
balance(ann, USD(100)));
3085 env.require(
offers(ann, 0));
3087 env.require(
balance(bob, USD(0)));
3089 env.require(
offers(bob, 0));
3094 auto const che =
Account(
"che");
3095 auto const deb =
Account(
"deb");
3099 env(
trust(che, USD(200)));
3100 env(
trust(deb, USD(200)));
3103 env(
pay(gw1, deb, USD(125)));
3106 env(offer(che, USD(100),
XRP(1)));
3109 env(offer(deb,
XRP(1), USD(100)));
3112 env.require(
balance(che, USD(100)));
3114 env.require(
offers(che, 0));
3116 env.require(
balance(deb, USD(0)));
3118 env.require(
offers(deb, 0));
3121 auto const eve =
Account(
"eve");
3122 auto const fyn =
Account(
"fyn");
3124 env.fund(
XRP(20000) + (
fee * 2), eve, fyn);
3127 env(
trust(eve, USD(1000)));
3128 env(
trust(fyn, USD(1000)));
3131 env(
pay(gw1, eve, USD(100)));
3132 env(
pay(gw1, fyn, USD(100)));
3138 env(offer(eve, USD(10),
XRP(4000)));
3142 env(offer(fyn,
XRP(2000), USD(5)));
3145 env.require(
balance(eve, USD(105)));
3148 BEAST_EXPECT(evesOffers.size() == 1);
3149 if (evesOffers.size() != 0)
3151 auto const& evesOffer = *(evesOffers.front());
3158 env.require(
balance(fyn, USD(93.75)));
3160 env.require(
offers(fyn, 0));
3163 auto const gw2 =
Account(
"gateway2");
3164 auto const EUR = gw2[
"EUR"];
3166 env.fund(
XRP(100000), gw2);
3169 env(
rate(gw2, 1.5));
3174 auto const gay =
Account(
"gay");
3175 auto const hal =
Account(
"hal");
3176 env.fund(
reserve(env, 3) + (
fee * 3), gay, hal);
3179 env(
trust(gay, USD(200)));
3180 env(
trust(gay, EUR(200)));
3181 env(
trust(hal, USD(200)));
3182 env(
trust(hal, EUR(200)));
3185 env(
pay(gw1, gay, USD(125)));
3186 env(
pay(gw2, hal, EUR(150)));
3189 env(offer(gay, EUR(100), USD(100)));
3192 env(offer(hal, USD(100), EUR(100)));
3195 env.require(
balance(gay, USD(0)));
3196 env.require(
balance(gay, EUR(100)));
3198 env.require(
offers(gay, 0));
3200 env.require(
balance(hal, USD(100)));
3201 env.require(
balance(hal, EUR(0)));
3203 env.require(
offers(hal, 0));
3207 auto const ivy =
Account(
"ivy");
3208 auto const joe =
Account(
"joe");
3209 env.fund(
reserve(env, 3) + (
fee * 3), ivy, joe);
3218 env(
pay(gw1, ivy, USD(270)),
sendmax(USD(500)));
3219 env(
pay(gw2, joe, EUR(150)),
sendmax(EUR(300)));
3221 env.require(
balance(ivy, USD(300)));
3222 env.require(
balance(joe, EUR(250)));
3224 env(offer(ivy, EUR(100), USD(200)));
3227 env(offer(joe, USD(200), EUR(100)));
3230 env.require(
balance(ivy, USD(50)));
3231 env.require(
balance(ivy, EUR(100)));
3233 env.require(
offers(ivy, 0));
3235 env.require(
balance(joe, USD(200)));
3236 env.require(
balance(joe, EUR(100)));
3238 env.require(
offers(joe, 0));
3242 auto const kim =
Account(
"kim");
3243 auto const K_BUX = kim[
"BUX"];
3244 auto const lex =
Account(
"lex");
3245 auto const meg =
Account(
"meg");
3246 auto const ned =
Account(
"ned");
3247 auto const N_BUX = ned[
"BUX"];
3250 env.fund(
reserve(env, 4) + (
fee * 4), kim, lex, meg, ned);
3253 env(
trust(lex, K_BUX(400)));
3255 env(
trust(meg, N_BUX(100)));
3257 env(
pay(ned, lex, N_BUX(100)));
3259 env.require(
balance(lex, N_BUX(100)));
3261 env(
pay(kim, meg, N_BUX(60)),
path(lex, ned),
sendmax(K_BUX(200)));
3266 env.require(
balance(lex, K_BUX(72)));
3267 env.require(
balance(lex, N_BUX(40)));
3269 env.require(
balance(meg, N_BUX(60)));
3274 env(offer(lex, K_BUX(30), N_BUX(30)));
3277 env(offer(kim, N_BUX(30), K_BUX(30)));
3281 env.require(
balance(kim, N_BUX(30)));
3282 env.require(
balance(lex, K_BUX(102)));
3283 env.require(
balance(lex, N_BUX(10)));
3285 env.require(
balance(meg, N_BUX(60)));
3286 env.require(
balance(ned, K_BUX(-30)));
3291 auto const ova =
Account(
"ova");
3292 auto const pat =
Account(
"pat");
3293 auto const qae =
Account(
"qae");
3294 env.fund(
XRP(2) +
reserve(env, 3) + (
fee * 3), ova, pat, qae);
3300 env(
trust(ova, USD(200)));
3301 env(
trust(ova, EUR(200)));
3302 env(
trust(pat, USD(200)));
3303 env(
trust(pat, EUR(200)));
3304 env(
trust(qae, USD(200)));
3305 env(
trust(qae, EUR(200)));
3308 env(
pay(gw1, ova, USD(125)));
3309 env(
pay(gw2, qae, EUR(150)));
3312 env(offer(ova,
XRP(2), USD(100)));
3313 env(offer(pat, EUR(100),
XRP(2)));
3316 env(offer(qae, USD(100), EUR(100)));
3319 env.require(
balance(ova, USD(0)));
3320 env.require(
balance(ova, EUR(0)));
3325 if (ovasOffers.size() != 0)
3327 BEAST_EXPECT(ovasOffers.size() == 1);
3328 auto const& ovasOffer = *(ovasOffers.front());
3335 env.require(
balance(pat, USD(0)));
3336 env.require(
balance(pat, EUR(100)));
3338 env.require(
offers(pat, 0));
3340 env.require(
balance(qae, USD(100)));
3341 env.require(
balance(qae, EUR(0)));
3343 env.require(
offers(qae, 0));
3364 using namespace jtx;
3366 auto const gw =
Account(
"gateway");
3367 auto const USD = gw[
"USD"];
3369 Env env{*
this, features};
3372 auto const fee = env.current()->fees().base;
3373 auto const startBalance =
XRP(1000000);
3375 env.fund(startBalance + (
fee * 4), gw);
3378 env(offer(gw, USD(60),
XRP(600)));
3380 env(offer(gw, USD(60),
XRP(600)));
3382 env(offer(gw, USD(60),
XRP(600)));
3385 env.require(
owners(gw, 3));
3386 env.require(
balance(gw, startBalance +
fee));
3389 BEAST_EXPECT(gwOffers.size() == 3);
3390 for (
auto const& offerPtr : gwOffers)
3392 auto const& offer = *offerPtr;
3400 env(offer(gw,
XRP(1000), USD(100)));
3402 env.require(
owners(gw, 1));
3403 env.require(
offers(gw, 1));
3404 env.require(
balance(gw, startBalance));
3407 BEAST_EXPECT(gwOffers.size() == 1);
3408 for (
auto const& offerPtr : gwOffers)
3410 auto const& offer = *offerPtr;
3420 using namespace jtx;
3422 auto const gw1 =
Account(
"gateway1");
3423 auto const gw2 =
Account(
"gateway2");
3424 auto const alice =
Account(
"alice");
3425 auto const USD = gw1[
"USD"];
3426 auto const EUR = gw2[
"EUR"];
3428 Env env{*
this, features};
3430 env.fund(
XRP(1000000), gw1, gw2);
3434 auto const f = env.current()->fees().
base;
3448 TestData
const tests[]{
3459 for (
auto const& t : tests)
3461 auto const acct =
Account{t.acct};
3462 env.fund(t.fundXRP, acct);
3465 env(
trust(acct, USD(1000)));
3466 env(
trust(acct, EUR(1000)));
3469 if (t.fundUSD > USD(0))
3470 env(
pay(gw1, acct, t.fundUSD));
3471 if (t.fundEUR > EUR(0))
3472 env(
pay(gw2, acct, t.fundEUR));
3475 env(offer(acct, USD(500), EUR(600)),
ter(t.firstOfferTec));
3479 int offerCount = t.firstOfferTec ==
tesSUCCESS ? 1 : 0;
3480 env.require(
owners(acct, 2 + offerCount));
3481 env.require(
balance(acct, t.fundUSD));
3482 env.require(
balance(acct, t.fundEUR));
3485 BEAST_EXPECT(acctOffers.size() == offerCount);
3486 for (
auto const& offerPtr : acctOffers)
3488 auto const& offer = *offerPtr;
3494 env(offer(acct, EUR(600), USD(500)),
ter(t.secondOfferTec));
3498 offerCount = t.secondOfferTec ==
tesSUCCESS ? 1 : offerCount;
3499 env.require(
owners(acct, 2 + offerCount));
3500 env.require(
balance(acct, t.fundUSD));
3501 env.require(
balance(acct, t.fundEUR));
3504 BEAST_EXPECT(acctOffers.size() == offerCount);
3505 for (
auto const& offerPtr : acctOffers)
3507 auto const& offer = *offerPtr;
3532 testcase(
"Self Cross Offer");
3544 using namespace jtx;
3546 Env env{*
this, features};
3548 auto const alice =
Account(
"alice");
3549 auto const bob =
Account(
"bob");
3550 auto const USD = bob[
"USD"];
3551 auto const f = env.current()->fees().base;
3553 env.fund(
XRP(50000) + f, alice, bob);
3556 env(offer(alice, USD(5000),
XRP(50000)));
3560 env(offer(bob,
XRP(50000), USD(5000)));
3566 env.require(
owners(alice, 1));
3567 env.require(
lines(alice, 1));
3572 BEAST_EXPECT(bobOffers.size() == 1);
3573 for (
auto const& offerPtr : bobOffers)
3575 auto const& offer = *offerPtr;
3588 testcase(
"Bad path assert");
3590 using namespace jtx;
3597 auto const fee = env.current()->fees().base;
3600 auto const ann =
Account(
"ann");
3601 auto const A_BUX = ann[
"BUX"];
3602 auto const bob =
Account(
"bob");
3603 auto const cam =
Account(
"cam");
3604 auto const dan =
Account(
"dan");
3605 auto const D_BUX = dan[
"BUX"];
3608 env.fund(
reserve(env, 4) + (
fee * 4), ann, bob, cam, dan);
3611 env(
trust(bob, A_BUX(400)));
3613 env(
trust(cam, D_BUX(100)));
3615 env(
pay(dan, bob, D_BUX(100)));
3617 env.require(
balance(bob, D_BUX(100)));
3619 env(
pay(ann, cam, D_BUX(60)),
path(bob, dan),
sendmax(A_BUX(200)));
3624 env.require(
balance(bob, A_BUX(72)));
3625 env.require(
balance(bob, D_BUX(40)));
3627 env.require(
balance(cam, D_BUX(60)));
3631 env(offer(bob, A_BUX(30), D_BUX(30)));
3634 env(
trust(ann, D_BUX(100)));
3638 env(
pay(ann, ann, D_BUX(30)),
3645 env.require(
balance(ann, D_BUX(0)));
3646 env.require(
balance(bob, A_BUX(72)));
3647 env.require(
balance(bob, D_BUX(40)));
3649 env.require(
balance(cam, D_BUX(60)));
3650 env.require(
balance(dan, A_BUX(0)));
3662 testcase(
"Direct to Direct path");
3664 using namespace jtx;
3666 Env env{*
this, features};
3668 auto const ann =
Account(
"ann");
3669 auto const bob =
Account(
"bob");
3670 auto const cam =
Account(
"cam");
3671 auto const A_BUX = ann[
"BUX"];
3672 auto const B_BUX = bob[
"BUX"];
3674 auto const fee = env.current()->fees().base;
3675 env.fund(
reserve(env, 4) + (
fee * 5), ann, bob, cam);
3678 env(
trust(ann, B_BUX(40)));
3679 env(
trust(cam, A_BUX(40)));
3680 env(
trust(cam, B_BUX(40)));
3683 env(
pay(ann, cam, A_BUX(35)));
3684 env(
pay(bob, cam, B_BUX(35)));
3686 env(offer(bob, A_BUX(30), B_BUX(30)));
3692 env(offer(cam, A_BUX(29), B_BUX(30),
tfPassive));
3694 env.require(
balance(cam, A_BUX(35)));
3695 env.require(
balance(cam, B_BUX(35)));
3696 env.require(
offers(cam, 1));
3699 env(offer(cam, B_BUX(30), A_BUX(30)));
3702 env.require(
balance(bob, A_BUX(30)));
3703 env.require(
balance(cam, A_BUX(5)));
3704 env.require(
balance(cam, B_BUX(65)));
3705 env.require(
offers(cam, 0));
3714 testcase(
"Self crossing low quality offer");
3716 using namespace jtx;
3718 Env env{*
this, features};
3720 auto const ann =
Account(
"ann");
3721 auto const gw =
Account(
"gateway");
3722 auto const BTC = gw[
"BTC"];
3724 auto const fee = env.current()->fees().base;
3729 env(
rate(gw, 1.002));
3730 env(
trust(ann, BTC(10)));
3733 env(
pay(gw, ann, BTC(2.856)));
3736 env(offer(ann,
drops(365611702030), BTC(5.713)));
3740 env(offer(ann, BTC(0.687),
drops(20000000000)),
3751 testcase(
"Offer In Scaling");
3753 using namespace jtx;
3755 Env env{*
this, features};
3757 auto const gw =
Account(
"gateway");
3758 auto const alice =
Account(
"alice");
3759 auto const bob =
Account(
"bob");
3760 auto const CNY = gw[
"CNY"];
3762 auto const fee = env.current()->fees().base;
3767 env(
trust(bob, CNY(500)));
3770 env(
pay(gw, bob, CNY(300)));
3773 env(offer(bob,
drops(5400000000), CNY(216.054)));
3777 env(offer(alice, CNY(13562.0001),
drops(339000000000)));
3781 BEAST_EXPECT(aliceOffers.size() == 1);
3782 for (
auto const& offerPtr : aliceOffers)
3784 auto const& offer = *offerPtr;
3787 BEAST_EXPECT(offer[
sfTakerPays] == CNY(13345.9461));
3797 testcase(
"Offer In Scaling With Xfer Rate");
3799 using namespace jtx;
3801 Env env{*
this, features};
3803 auto const gw =
Account(
"gateway");
3804 auto const alice =
Account(
"alice");
3805 auto const bob =
Account(
"bob");
3806 auto const BTC = gw[
"BTC"];
3807 auto const JPY = gw[
"JPY"];
3809 auto const fee = env.current()->fees().base;
3814 env(
rate(gw, 1.002));
3815 env(
trust(alice, JPY(4000)));
3816 env(
trust(bob, BTC(2)));
3819 env(
pay(gw, alice, JPY(3699.034802280317)));
3820 env(
pay(gw, bob, BTC(1.156722559140311)));
3823 env(offer(bob, JPY(1241.913390770747), BTC(0.01969825690469254)));
3827 env(offer(alice, BTC(0.05507568706427876), JPY(3472.696773391072)));
3831 BEAST_EXPECT(aliceOffers.size() == 1);
3832 for (
auto const& offerPtr : aliceOffers)
3834 auto const& offer = *offerPtr;
3839 BEAST_EXPECT(offer[
sfTakerPays] == BTC(0.035378));
3849 testcase(
"Offer Threshold With Reduced Funds");
3851 using namespace jtx;
3853 Env env{*
this, features};
3855 auto const gw1 =
Account(
"gw1");
3856 auto const gw2 =
Account(
"gw2");
3857 auto const alice =
Account(
"alice");
3858 auto const bob =
Account(
"bob");
3859 auto const USD = gw1[
"USD"];
3860 auto const JPY = gw2[
"JPY"];
3862 auto const fee = env.current()->fees().base;
3864 env.fund(
reserve(env, 2) + (
fee * 4), gw1, gw2);
3867 env(
rate(gw1, 1.002));
3868 env(
trust(alice, USD(1000)));
3869 env(
trust(bob, JPY(100000)));
3896 BEAST_EXPECT(aliceOffers.size() == 1);
3897 for (
auto const& offerPtr : aliceOffers)
3899 auto const& offer = *offerPtr;
3913 testcase(
"Tiny Offer");
3915 using namespace jtx;
3917 Env env{*
this, features};
3919 auto const gw =
Account(
"gw");
3920 auto const alice =
Account(
"alice");
3921 auto const bob =
Account(
"bob");
3922 auto const CNY = gw[
"CNY"];
3923 auto const fee = env.current()->fees().base;
3924 auto const startXrpBalance =
drops(400000000000) + (
fee * 2);
3926 env.fund(startXrpBalance, gw, alice, bob);
3929 env(
trust(bob, CNY(100000)));
3941 STAmount const bobsCnyStartBalance{
3943 env(
pay(gw, bob, bobsCnyStartBalance));
3952 env.require(
balance(alice, alicesCnyOffer));
3954 env.require(
balance(bob, bobsCnyStartBalance - alicesCnyOffer));
3961 testcase(
"Self Pay Xfer Fee");
3997 using namespace jtx;
3999 Env env{*
this, features};
4001 auto const gw =
Account(
"gw");
4002 auto const BTC = gw[
"BTC"];
4003 auto const USD = gw[
"USD"];
4004 auto const startXrpBalance =
XRP(4000000);
4006 env.fund(startXrpBalance, gw);
4009 env(
rate(gw, 1.25));
4035 TestData
const tests[]{
4037 {0, 0, 1, BTC(20), {{
"ann", 0,
drops(3899999999960), BTC(20.0), USD(3000)}, {
"abe", 0,
drops(4099999999970), BTC( 0), USD(750)}}},
4038 {0, 1, 0, BTC(20), {{
"bev", 0,
drops(4099999999960), BTC( 7.5), USD(2000)}, {
"bob", 0,
drops(3899999999970), BTC(10), USD( 0)}}},
4039 {0, 0, 0, BTC(20), {{
"cam", 0,
drops(3999999999950), BTC(20.0), USD(2000)} }},
4040 {0, 1, 0, BTC( 5), {{
"deb", 1,
drops(4039999999960), BTC( 0.0), USD(2000)}, {
"dan", 1,
drops(3959999999970), BTC( 4), USD( 0)}}},
4044 for (
auto const& t : tests)
4046 Account const&
self = t.actors[t.self].acct;
4047 Account const& leg0 = t.actors[t.leg0].acct;
4048 Account const& leg1 = t.actors[t.leg1].acct;
4050 for (
auto const& actor : t.actors)
4052 env.fund(
XRP(4000000), actor.acct);
4055 env(
trust(actor.acct, BTC(40)));
4056 env(
trust(actor.acct, USD(8000)));
4060 env(
pay(gw,
self, t.btcStart));
4061 env(
pay(gw,
self, USD(2000)));
4062 if (
self.
id() != leg1.
id())
4063 env(
pay(gw, leg1, USD(2000)));
4077 env(offer(
self, USD(1000), BTC(10)));
4082 for (
auto const& actor : t.actors)
4088 actorOffers.begin(),
4090 actorOffers.begin(),
4093 return (*offer)[sfTakerGets].signum() == 0;
4095 BEAST_EXPECT(offerCount == actor.offers);
4097 env.require(
balance(actor.acct, actor.xrp));
4098 env.require(
balance(actor.acct, actor.btc));
4099 env.require(
balance(actor.acct, actor.usd));
4115 testcase(
"Self Pay Unlimited Funds");
4147 using namespace jtx;
4149 Env env{*
this, features};
4151 auto const gw =
Account(
"gw");
4152 auto const BTC = gw[
"BTC"];
4153 auto const USD = gw[
"USD"];
4154 auto const startXrpBalance =
XRP(4000000);
4156 env.fund(startXrpBalance, gw);
4159 env(
rate(gw, 1.25));
4185 TestData
const takerTests[]{
4187 {0, 0, 1, BTC(5), {{
"deb", 0,
drops(3899999999960), BTC(5), USD(3000)}, {
"dan", 0,
drops(4099999999970), BTC(0), USD(750)}}},
4188 {0, 0, 0, BTC(5), {{
"flo", 0,
drops(3999999999950), BTC(5), USD(2000)} }}
4191 TestData
const flowTests[]{
4193 {0, 0, 1, BTC(5), {{
"gay", 1,
drops(3949999999960), BTC(5), USD(2500)}, {
"gar", 1,
drops(4049999999970), BTC(0), USD(1375)}}},
4194 {0, 0, 0, BTC(5), {{
"hye", 2,
drops(3999999999950), BTC(5), USD(2000)} }}
4201 for (
auto const& t : tests)
4203 Account const&
self = t.actors[t.self].acct;
4204 Account const& leg0 = t.actors[t.leg0].acct;
4205 Account const& leg1 = t.actors[t.leg1].acct;
4207 for (
auto const& actor : t.actors)
4209 env.fund(
XRP(4000000), actor.acct);
4212 env(
trust(actor.acct, BTC(40)));
4213 env(
trust(actor.acct, USD(8000)));
4217 env(
pay(gw,
self, t.btcStart));
4218 env(
pay(gw,
self, USD(2000)));
4219 if (
self.
id() != leg1.
id())
4220 env(
pay(gw, leg1, USD(2000)));
4234 env(offer(
self, USD(1000), BTC(10)));
4239 for (
auto const& actor : t.actors)
4245 actorOffers.begin(),
4247 actorOffers.begin(),
4250 return (*offer)[sfTakerGets].signum() == 0;
4252 BEAST_EXPECT(offerCount == actor.offers);
4254 env.require(
balance(actor.acct, actor.xrp));
4255 env.require(
balance(actor.acct, actor.btc));
4256 env.require(
balance(actor.acct, actor.usd));
4272 testcase(
"lsfRequireAuth");
4274 using namespace jtx;
4276 Env env{*
this, features};
4278 auto const gw =
Account(
"gw");
4279 auto const alice =
Account(
"alice");
4280 auto const bob =
Account(
"bob");
4281 auto const gwUSD = gw[
"USD"];
4282 auto const aliceUSD = alice[
"USD"];
4283 auto const bobUSD = bob[
"USD"];
4285 env.fund(
XRP(400000), gw, alice, bob);
4294 env(
trust(bob, gwUSD(100)));
4296 env(
trust(alice, gwUSD(100)));
4298 env(offer(alice, gwUSD(40),
XRP(4000)));
4301 env.require(
offers(alice, 1));
4302 env.require(
balance(alice, gwUSD(0)));
4304 env(
pay(gw, bob, gwUSD(50)));
4307 env.require(
balance(bob, gwUSD(50)));
4310 env(offer(bob,
XRP(4000), gwUSD(40)));
4313 env.require(
offers(alice, 0));
4314 env.require(
balance(alice, gwUSD(40)));
4316 env.require(
offers(bob, 0));
4317 env.require(
balance(bob, gwUSD(10)));
4323 testcase(
"Missing Auth");
4343 using namespace jtx;
4345 Env env{*
this, features};
4347 auto const gw =
Account(
"gw");
4348 auto const alice =
Account(
"alice");
4349 auto const bob =
Account(
"bob");
4350 auto const gwUSD = gw[
"USD"];
4351 auto const aliceUSD = alice[
"USD"];
4352 auto const bobUSD = bob[
"USD"];
4354 env.fund(
XRP(400000), gw, alice, bob);
4357 env(offer(alice, gwUSD(40),
XRP(4000)));
4360 env.require(
offers(alice, 1));
4367 env(
trust(bob, gwUSD(100)));
4370 env(
pay(gw, bob, gwUSD(50)));
4372 env.require(
balance(bob, gwUSD(50)));
4380 env(offer(bob,
XRP(4000), gwUSD(40)));
4386 env.require(
offers(alice, 0));
4391 env.require(
offers(bob, 1));
4392 env.require(
balance(bob, gwUSD(50)));
4397 env.require(
balance(alice, gwUSD(40)));
4398 env.require(
offers(bob, 0));
4399 env.require(
balance(bob, gwUSD(10)));
4411 env.require(
offers(alice, 0));
4414 env.require(
offers(bob, 1));
4415 env.require(
balance(bob, gwUSD(50)));
4419 env(
trust(gw, aliceUSD(100)));
4425 env.require(
offers(alice, 0));
4426 env.require(
balance(alice, gwUSD(0)));
4428 env.require(
offers(bob, 1));
4429 env.require(
balance(bob, gwUSD(50)));
4434 env.require(
offers(bob, 0));
4442 env(offer(alice, gwUSD(40),
XRP(4000)));
4445 env.require(
offers(alice, 1));
4448 env(offer(bob,
XRP(4000), gwUSD(40)));
4451 env.require(
offers(alice, 0));
4452 env.require(
balance(alice, gwUSD(40)));
4454 env.require(
offers(bob, 0));
4455 env.require(
balance(bob, gwUSD(10)));
4461 testcase(
"RippleConnect Smoketest payment flow");
4462 using namespace jtx;
4464 Env env{*
this, features};
4474 auto const hotUS =
Account(
"hotUS");
4475 auto const coldUS =
Account(
"coldUS");
4476 auto const hotEU =
Account(
"hotEU");
4477 auto const coldEU =
Account(
"coldEU");
4478 auto const mm =
Account(
"mm");
4480 auto const USD = coldUS[
"USD"];
4481 auto const EUR = coldEU[
"EUR"];
4483 env.fund(
XRP(100000), hotUS, coldUS, hotEU, coldEU, mm);
4487 for (
auto const& cold : {coldUS, coldEU})
4510 env(
pay(coldUS, hotUS, USD(5000000)));
4511 env(
pay(coldEU, hotEU, EUR(5000000)));
4512 env(
pay(coldUS, mm, USD(5000000)));
4513 env(
pay(coldEU, mm, EUR(5000000)));
4517 float const rate = 0.9f;
4518 env(offer(mm, EUR(4000000 *
rate), USD(4000000)),
4521 float const reverseRate = 1.0f /
rate * 1.00101f;
4522 env(offer(mm, USD(4000000 * reverseRate), EUR(4000000)),
4529 jvParams[jss::destination_account] = coldEU.human();
4530 jvParams[jss::destination_amount][jss::issuer] = coldEU.human();
4531 jvParams[jss::destination_amount][jss::currency] =
"EUR";
4532 jvParams[jss::destination_amount][jss::value] = 10;
4533 jvParams[jss::source_account] = hotUS.human();
4536 "json",
"ripple_path_find",
to_string(jvParams))[jss::result]};
4538 BEAST_EXPECT(jrr[jss::status] ==
"success");
4540 jrr[jss::alternatives].isArray() &&
4541 jrr[jss::alternatives].size() > 0);
4544 env(
pay(hotUS, coldEU, EUR(10)),
sendmax(USD(11.1223326)));
4550 testcase(
"Self Auth");
4552 using namespace jtx;
4554 Env env{*
this, features};
4556 auto const gw =
Account(
"gw");
4557 auto const alice =
Account(
"alice");
4558 auto const gwUSD = gw[
"USD"];
4559 auto const aliceUSD = alice[
"USD"];
4561 env.fund(
XRP(400000), gw, alice);
4565 env(offer(gw, gwUSD(40),
XRP(4000)));
4568 env.require(
offers(gw, 1));
4577 env.require(
offers(gw, 0));
4589 env(offer(gw, gwUSD(40),
XRP(4000)),
4593 env.require(
offers(gw, preauth ? 1 : 0));
4601 env(
trust(alice, gwUSD(100)));
4604 env(
pay(gw, alice, gwUSD(50)));
4607 env.require(
balance(alice, gwUSD(50)));
4610 env(offer(alice,
XRP(4000), gwUSD(40)));
4613 env.require(
offers(alice, 0));
4614 env.require(
balance(alice, gwUSD(10)));
4616 env.require(
offers(gw, 0));
4623 using namespace jtx;
4625 testcase(
"Deleted offer issuer");
4627 auto trustLineExists = [](
jtx::Env const& env,
4638 auto const USD = gw[
"USD"];
4639 auto const BUX = alice[
"BUX"];
4641 Env env{*
this, features};
4644 env.
trust(USD(1000), becky);
4645 env(
pay(gw, becky, USD(5)));
4647 BEAST_EXPECT(trustLineExists(env, gw, becky, USD.currency));
4658 env(
pay(becky, gw, USD(5)));
4659 env.
trust(USD(0), becky);
4661 BEAST_EXPECT(!trustLineExists(env, gw, becky, USD.currency));
4662 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4663 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4670 [&env, &gw, openLedgerSeq = env.
current()->seq()]() ->
int {
4672 if (gwSeq + 255 > openLedgerSeq)
4673 return gwSeq - openLedgerSeq + 255;
4677 for (
int i = 0; i < delta; ++i)
4694 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4695 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4701 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4702 BEAST_EXPECT(
isOffer(env, becky, BUX(3), USD(3)));
4707 BEAST_EXPECT(!
isOffer(env, becky, BUX(3), USD(3)));
4711 env.
trust(BUX(1000), carol);
4712 env(
pay(alice, carol, BUX(2)));
4714 env(offer(alice, BUX(2),
XRP(2)));
4721 BEAST_EXPECT(
isOffer(env, alice, BUX(2),
XRP(2)));
4722 BEAST_EXPECT(
isOffer(env, becky,
XRP(2), USD(2)));
4728 testcase(
"Tick Size");
4730 using namespace jtx;
4734 Env env{*
this, features};
4735 auto const gw =
Account{
"gateway"};
4736 env.fund(
XRP(10000), gw);
4738 auto txn =
noop(gw);
4744 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == Quality::minTickSize);
4749 BEAST_EXPECT(!env.le(gw)->isFieldPresent(
sfTickSize));
4754 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == Quality::maxTickSize - 1);
4762 BEAST_EXPECT(!env.le(gw)->isFieldPresent(
sfTickSize));
4765 Env env{*
this, features};
4766 auto const gw =
Account{
"gateway"};
4767 auto const alice =
Account{
"alice"};
4768 auto const XTS = gw[
"XTS"];
4769 auto const XXX = gw[
"XXX"];
4771 env.fund(
XRP(10000), gw, alice);
4775 auto txn =
noop(gw);
4778 BEAST_EXPECT((*env.le(gw))[
sfTickSize] == 5);
4781 env(
trust(alice, XTS(1000)));
4782 env(
trust(alice, XXX(1000)));
4784 env(
pay(gw, alice, alice[
"XTS"](100)));
4785 env(
pay(gw, alice, alice[
"XXX"](100)));
4787 env(offer(alice, XTS(10), XXX(30)));
4788 env(offer(alice, XTS(30), XXX(10)));
4789 env(offer(alice, XTS(10), XXX(30)),
json(jss::Flags,
tfSell));
4790 env(offer(alice, XTS(30), XXX(10)),
json(jss::Flags,
tfSell));
4795 if (sle->getType() == ltOFFER)
4799 (*sle)[sfTakerPays], (*sle)[sfTakerGets]));
4803 auto it =
offers.begin();
4804 BEAST_EXPECT(it !=
offers.end());
4806 it->second.first == XTS(10) && it->second.second < XXX(30) &&
4807 it->second.second > XXX(29.9994));
4811 BEAST_EXPECT(it !=
offers.end());
4813 it->second.first == XTS(30) && it->second.second == XXX(10));
4817 BEAST_EXPECT(it !=
offers.end());
4819 it->second.first == XTS(10.0002) && it->second.second == XXX(30));
4824 BEAST_EXPECT(it !=
offers.end());
4826 it->second.first == XTS(30) && it->second.second == XXX(10));
4828 BEAST_EXPECT(++it ==
offers.end());
4842 return (*rhs)[sfSequence] < (*lhs)[sfSequence];
4850 testcase(
"Ticket Offers");
4852 using namespace jtx;
4860 Env env{*
this, features};
4861 auto const gw =
Account{
"gateway"};
4862 auto const alice =
Account{
"alice"};
4863 auto const bob =
Account{
"bob"};
4864 auto const USD = gw[
"USD"];
4866 env.fund(
XRP(10000), gw, alice, bob);
4869 env(
trust(alice, USD(1000)));
4870 env(
trust(bob, USD(1000)));
4873 env(
pay(gw, alice, USD(200)));
4880 env(offer(alice,
XRP(50), USD(50)));
4885 env(ticket::create(alice, 2));
4890 BEAST_EXPECT(offerId_1 == offerId_0 + 4);
4891 env(offer(alice,
XRP(50), USD(50)));
4907 BEAST_EXPECT(
offers.size() == 4);
4912 env.require(
balance(alice, USD(200)));
4913 env.require(
owners(alice, 5));
4917 env(offer(bob, USD(50),
XRP(50)));
4923 BEAST_EXPECT(
offers.size() == 3);
4930 env(offer(bob, USD(50),
XRP(50)));
4936 BEAST_EXPECT(
offers.size() == 2);
4942 env(offer(bob, USD(50),
XRP(50)));
4948 BEAST_EXPECT(
offers.size() == 1);
4953 env(offer(bob, USD(50),
XRP(50)));
4959 BEAST_EXPECT(
offers.size() == 0);
4961 env.require(
balance(alice, USD(0)));
4962 env.require(
owners(alice, 1));
4963 env.require(
balance(bob, USD(200)));
4964 env.require(
owners(bob, 1));
4970 testcase(
"Ticket Cancel Offers");
4972 using namespace jtx;
4976 Env env{*
this, features};
4977 auto const gw =
Account{
"gateway"};
4978 auto const alice =
Account{
"alice"};
4979 auto const USD = gw[
"USD"];
4981 env.fund(
XRP(10000), gw, alice);
4984 env(
trust(alice, USD(1000)));
4988 env(
pay(gw, alice, USD(200)));
4993 env(offer(alice,
XRP(50), USD(50)));
4999 env(ticket::create(alice, 4));
5005 BEAST_EXPECT(offerSeqId_1 == offerSeqId_0 + 6);
5006 env(offer(alice,
XRP(50), USD(50)));
5022 BEAST_EXPECT(
offers.size() == 4);
5027 env.require(
balance(alice, USD(200)));
5028 env.require(
owners(alice, 7));
5038 BEAST_EXPECT(
offers.size() == 3);
5051 BEAST_EXPECT(
offers.size() == 2);
5066 BEAST_EXPECT(
offers.size() == 1);
5084 testcase(
"incorrect assert fixed");
5085 using namespace jtx;
5088 auto const alice =
Account(
"alice");
5089 auto const USD = alice[
"USD"];
5091 env.fund(
XRP(10000), alice);
5093 env(offer(alice,
XRP(100000000000), USD(100000000)));
5163 using namespace jtx;
5183 using namespace jtx;