543 testcase(
"Multiple Books, One Side Offers In Book");
544 using namespace std::chrono_literals;
548 auto USD =
Account(
"alice")[
"USD"];
549 auto CNY =
Account(
"alice")[
"CNY"];
550 auto JPY =
Account(
"alice")[
"JPY"];
572 j[jss::snapshot] =
true;
573 j[jss::taker_gets][jss::currency] =
"XRP";
574 j[jss::taker_pays][jss::currency] =
"USD";
575 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
579 j[jss::snapshot] =
true;
580 j[jss::taker_gets][jss::currency] =
"CNY";
581 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
582 j[jss::taker_pays][jss::currency] =
"JPY";
583 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
586 auto jv = wsc->invoke(
"subscribe", books);
587 if (wsc->version() == 2)
590 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
592 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
593 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
595 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
598 jv[jss::result].isMember(jss::offers) &&
599 jv[jss::result][jss::offers].size() == 2);
601 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
604 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
607 jv[jss::result][jss::offers][1u][jss::TakerGets] ==
610 jv[jss::result][jss::offers][1u][jss::TakerPays] ==
612 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
613 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
618 env(
offer(
"alice",
XRP(700), USD(100)),
623 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
624 auto const& t = jv[jss::transaction];
625 return t[jss::TransactionType] == jss::OfferCreate &&
627 USD(100).value().getJson(JsonOptions::none) &&
629 XRP(700).value().getJson(JsonOptions::none);
637 BEAST_EXPECT(!wsc->getMsg(10ms));
642 env(
offer(
"alice", CNY(700), JPY(100)),
647 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
648 auto const& t = jv[jss::transaction];
649 return t[jss::TransactionType] == jss::OfferCreate &&
651 JPY(100).value().getJson(JsonOptions::none) &&
653 CNY(700).value().getJson(JsonOptions::none);
661 BEAST_EXPECT(!wsc->getMsg(10ms));
665 auto jv = wsc->invoke(
"unsubscribe", books);
666 BEAST_EXPECT(jv[jss::status] ==
"success");
667 if (wsc->version() == 2)
670 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
672 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
673 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
680 testcase(
"Multiple Books, Both Sides Empty Book");
681 using namespace std::chrono_literals;
685 auto USD =
Account(
"alice")[
"USD"];
686 auto CNY =
Account(
"alice")[
"CNY"];
687 auto JPY =
Account(
"alice")[
"JPY"];
696 j[jss::snapshot] =
true;
698 j[jss::taker_gets][jss::currency] =
"XRP";
699 j[jss::taker_pays][jss::currency] =
"USD";
700 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
704 j[jss::snapshot] =
true;
706 j[jss::taker_gets][jss::currency] =
"CNY";
707 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
708 j[jss::taker_pays][jss::currency] =
"JPY";
709 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
712 auto jv = wsc->invoke(
"subscribe", books);
713 if (wsc->version() == 2)
716 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
718 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
719 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
721 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
724 jv[jss::result].isMember(jss::asks) &&
725 jv[jss::result][jss::asks].size() == 0);
727 jv[jss::result].isMember(jss::bids) &&
728 jv[jss::result][jss::bids].size() == 0);
729 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
734 env(
offer(
"alice",
XRP(700), USD(100)),
739 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
740 auto const& t = jv[jss::transaction];
741 return t[jss::TransactionType] == jss::OfferCreate &&
743 USD(100).value().getJson(JsonOptions::none) &&
745 XRP(700).value().getJson(JsonOptions::none);
755 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
756 auto const& t = jv[jss::transaction];
757 return t[jss::TransactionType] == jss::OfferCreate &&
759 XRP(75).value().getJson(JsonOptions::none) &&
761 USD(100).value().getJson(JsonOptions::none);
767 env(
offer(
"alice", CNY(700), JPY(100)),
772 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
773 auto const& t = jv[jss::transaction];
774 return t[jss::TransactionType] == jss::OfferCreate &&
776 JPY(100).value().getJson(JsonOptions::none) &&
778 CNY(700).value().getJson(JsonOptions::none);
788 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
789 auto const& t = jv[jss::transaction];
790 return t[jss::TransactionType] == jss::OfferCreate &&
792 CNY(75).value().getJson(JsonOptions::none) &&
794 JPY(100).value().getJson(JsonOptions::none);
799 auto jv = wsc->invoke(
"unsubscribe", books);
800 BEAST_EXPECT(jv[jss::status] ==
"success");
801 if (wsc->version() == 2)
804 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
806 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
807 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
814 testcase(
"Multiple Books, Both Sides Offers In Book");
815 using namespace std::chrono_literals;
819 auto USD =
Account(
"alice")[
"USD"];
820 auto CNY =
Account(
"alice")[
"CNY"];
821 auto JPY =
Account(
"alice")[
"JPY"];
843 j[jss::snapshot] =
true;
845 j[jss::taker_gets][jss::currency] =
"XRP";
846 j[jss::taker_pays][jss::currency] =
"USD";
847 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
852 j[jss::snapshot] =
true;
854 j[jss::taker_gets][jss::currency] =
"CNY";
855 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
856 j[jss::taker_pays][jss::currency] =
"JPY";
857 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
860 auto jv = wsc->invoke(
"subscribe", books);
861 if (wsc->version() == 2)
864 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
866 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
867 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
869 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
872 jv[jss::result].isMember(jss::asks) &&
873 jv[jss::result][jss::asks].size() == 2);
875 jv[jss::result].isMember(jss::bids) &&
876 jv[jss::result][jss::bids].size() == 2);
878 jv[jss::result][jss::asks][0u][jss::TakerGets] ==
881 jv[jss::result][jss::asks][0u][jss::TakerPays] ==
884 jv[jss::result][jss::asks][1u][jss::TakerGets] ==
887 jv[jss::result][jss::asks][1u][jss::TakerPays] ==
890 jv[jss::result][jss::bids][0u][jss::TakerGets] ==
893 jv[jss::result][jss::bids][0u][jss::TakerPays] ==
896 jv[jss::result][jss::bids][1u][jss::TakerGets] ==
899 jv[jss::result][jss::bids][1u][jss::TakerPays] ==
901 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
906 env(
offer(
"alice",
XRP(700), USD(100)),
911 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
912 auto const& t = jv[jss::transaction];
913 return t[jss::TransactionType] == jss::OfferCreate &&
915 USD(100).value().getJson(JsonOptions::none) &&
917 XRP(700).value().getJson(JsonOptions::none);
927 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
928 auto const& t = jv[jss::transaction];
929 return t[jss::TransactionType] == jss::OfferCreate &&
931 XRP(75).value().getJson(JsonOptions::none) &&
933 USD(100).value().getJson(JsonOptions::none);
939 env(
offer(
"alice", CNY(700), JPY(100)),
944 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
945 auto const& t = jv[jss::transaction];
946 return t[jss::TransactionType] == jss::OfferCreate &&
948 JPY(100).value().getJson(JsonOptions::none) &&
950 CNY(700).value().getJson(JsonOptions::none);
960 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
961 auto const& t = jv[jss::transaction];
962 return t[jss::TransactionType] == jss::OfferCreate &&
964 CNY(75).value().getJson(JsonOptions::none) &&
966 JPY(100).value().getJson(JsonOptions::none);
971 auto jv = wsc->invoke(
"unsubscribe", books);
972 BEAST_EXPECT(jv[jss::status] ==
"success");
973 if (wsc->version() == 2)
976 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
978 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
979 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
993 env.
fund(
XRP(20000), alice, bob, gw);
995 auto USD = gw[
"USD"];
1002 j[jss::snapshot] =
true;
1003 j[jss::taker_gets][jss::currency] =
"XRP";
1004 j[jss::taker_pays][jss::currency] =
"USD";
1005 j[jss::taker_pays][jss::issuer] = gw.human();
1008 auto jv = wsc->invoke(
"subscribe", books);
1009 if (wsc->version() == 2)
1012 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1014 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1015 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1017 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1020 jv[jss::result].isMember(jss::offers) &&
1021 jv[jss::result][jss::offers].size() == 0);
1022 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
1023 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
1028 env.
trust(USD(1000), alice);
1029 env.
trust(USD(1000), bob);
1030 env(
pay(gw, alice, USD(100)));
1031 env(
pay(gw, bob, USD(50)));
1032 env(
offer(alice,
XRP(4000), USD(10)));
1037 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1038 jvParams[jss::ledger_index] =
"validated";
1039 jvParams[jss::taker_gets][jss::currency] =
"USD";
1040 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1042 auto jv = wsc->invoke(
"book_offers", jvParams);
1043 if (wsc->version() == 2)
1046 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1048 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1049 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1051 auto jrr = jv[jss::result];
1053 BEAST_EXPECT(jrr[jss::offers].isArray());
1054 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1055 auto const jrOffer = jrr[jss::offers][0u];
1056 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1058 jrOffer[sfBookDirectory.fieldName] ==
1060 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1061 BEAST_EXPECT(jrOffer[jss::Flags] == 0);
1062 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1063 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1064 BEAST_EXPECT(jrOffer[sfSequence.fieldName] == 5);
1066 jrOffer[jss::TakerGets] ==
1069 jrOffer[jss::TakerPays] ==
1071 BEAST_EXPECT(jrOffer[jss::owner_funds] ==
"100");
1072 BEAST_EXPECT(jrOffer[jss::quality] ==
"400000000");
1074 using namespace std::chrono_literals;
1075 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
1076 auto const& t = jval[jss::transaction];
1077 return t[jss::TransactionType] == jss::OfferCreate &&
1078 t[jss::TakerGets] ==
1079 USD(10).value().getJson(JsonOptions::none) &&
1080 t[jss::owner_funds] ==
"100" &&
1081 t[jss::TakerPays] ==
1082 XRP(4000).value().getJson(JsonOptions::none);
1085 env(
offer(bob,
XRP(2000), USD(5)));
1088 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
1089 auto const& t = jval[jss::transaction];
1090 return t[jss::TransactionType] == jss::OfferCreate &&
1091 t[jss::TakerGets] ==
1092 USD(5).value().getJson(JsonOptions::none) &&
1093 t[jss::owner_funds] ==
"50" &&
1094 t[jss::TakerPays] ==
1095 XRP(2000).value().getJson(JsonOptions::none);
1098 jv = wsc->invoke(
"book_offers", jvParams);
1099 if (wsc->version() == 2)
1102 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1104 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1105 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1107 jrr = jv[jss::result];
1109 BEAST_EXPECT(jrr[jss::offers].isArray());
1110 BEAST_EXPECT(jrr[jss::offers].size() == 2);
1111 auto const jrNextOffer = jrr[jss::offers][1u];
1112 BEAST_EXPECT(jrNextOffer[sfAccount.fieldName] == bob.human());
1114 jrNextOffer[sfBookDirectory.fieldName] ==
1116 BEAST_EXPECT(jrNextOffer[sfBookNode.fieldName] ==
"0");
1117 BEAST_EXPECT(jrNextOffer[jss::Flags] == 0);
1118 BEAST_EXPECT(jrNextOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1119 BEAST_EXPECT(jrNextOffer[sfOwnerNode.fieldName] ==
"0");
1120 BEAST_EXPECT(jrNextOffer[sfSequence.fieldName] == 5);
1122 jrNextOffer[jss::TakerGets] ==
1125 jrNextOffer[jss::TakerPays] ==
1127 BEAST_EXPECT(jrNextOffer[jss::owner_funds] ==
"50");
1128 BEAST_EXPECT(jrNextOffer[jss::quality] ==
"400000000");
1130 jv = wsc->invoke(
"unsubscribe", books);
1131 if (wsc->version() == 2)
1134 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1136 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1137 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1139 BEAST_EXPECT(jv[jss::status] ==
"success");
1321 using namespace jtx;
1325 env.
fund(
XRP(10000), alice, gw);
1327 auto USD = gw[
"USD"];
1331 jvParams[jss::ledger_index] = 10u;
1332 auto const jrr = env.
rpc(
1333 "json",
"book_offers",
to_string(jvParams))[jss::result];
1334 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
1335 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
1340 jvParams[jss::ledger_index] =
"validated";
1341 auto const jrr = env.
rpc(
1342 "json",
"book_offers",
to_string(jvParams))[jss::result];
1343 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1345 jrr[jss::error_message] ==
"Missing field 'taker_pays'.");
1350 jvParams[jss::ledger_index] =
"validated";
1352 auto const jrr = env.
rpc(
1353 "json",
"book_offers",
to_string(jvParams))[jss::result];
1354 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1356 jrr[jss::error_message] ==
"Missing field 'taker_gets'.");
1361 jvParams[jss::ledger_index] =
"validated";
1362 jvParams[jss::taker_pays] =
"not an object";
1364 auto const jrr = env.
rpc(
1365 "json",
"book_offers",
to_string(jvParams))[jss::result];
1366 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1368 jrr[jss::error_message] ==
1369 "Invalid field 'taker_pays', not object.");
1374 jvParams[jss::ledger_index] =
"validated";
1376 jvParams[jss::taker_gets] =
"not an object";
1377 auto const jrr = env.
rpc(
1378 "json",
"book_offers",
to_string(jvParams))[jss::result];
1379 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1381 jrr[jss::error_message] ==
1382 "Invalid field 'taker_gets', not object.");
1387 jvParams[jss::ledger_index] =
"validated";
1390 auto const jrr = env.
rpc(
1391 "json",
"book_offers",
to_string(jvParams))[jss::result];
1392 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1394 jrr[jss::error_message] ==
1395 "Missing field 'taker_pays.currency'.");
1400 jvParams[jss::ledger_index] =
"validated";
1401 jvParams[jss::taker_pays][jss::currency] = 1;
1403 auto const jrr = env.
rpc(
1404 "json",
"book_offers",
to_string(jvParams))[jss::result];
1405 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1407 jrr[jss::error_message] ==
1408 "Invalid field 'taker_pays.currency', not string.");
1413 jvParams[jss::ledger_index] =
"validated";
1414 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1416 auto const jrr = env.
rpc(
1417 "json",
"book_offers",
to_string(jvParams))[jss::result];
1418 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1420 jrr[jss::error_message] ==
1421 "Missing field 'taker_gets.currency'.");
1426 jvParams[jss::ledger_index] =
"validated";
1427 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1428 jvParams[jss::taker_gets][jss::currency] = 1;
1429 auto const jrr = env.
rpc(
1430 "json",
"book_offers",
to_string(jvParams))[jss::result];
1431 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1433 jrr[jss::error_message] ==
1434 "Invalid field 'taker_gets.currency', not string.");
1439 jvParams[jss::ledger_index] =
"validated";
1440 jvParams[jss::taker_pays][jss::currency] =
"NOT_VALID";
1441 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1442 auto const jrr = env.
rpc(
1443 "json",
"book_offers",
to_string(jvParams))[jss::result];
1444 BEAST_EXPECT(jrr[jss::error] ==
"srcCurMalformed");
1446 jrr[jss::error_message] ==
1447 "Invalid field 'taker_pays.currency', bad currency.");
1452 jvParams[jss::ledger_index] =
"validated";
1453 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1454 jvParams[jss::taker_gets][jss::currency] =
"NOT_VALID";
1455 auto const jrr = env.
rpc(
1456 "json",
"book_offers",
to_string(jvParams))[jss::result];
1457 BEAST_EXPECT(jrr[jss::error] ==
"dstAmtMalformed");
1459 jrr[jss::error_message] ==
1460 "Invalid field 'taker_gets.currency', bad currency.");
1465 jvParams[jss::ledger_index] =
"validated";
1466 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1467 jvParams[jss::taker_gets][jss::currency] =
"USD";
1468 jvParams[jss::taker_gets][jss::issuer] = 1;
1469 auto const jrr = env.
rpc(
1470 "json",
"book_offers",
to_string(jvParams))[jss::result];
1471 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1473 jrr[jss::error_message] ==
1474 "Invalid field 'taker_gets.issuer', not string.");
1479 jvParams[jss::ledger_index] =
"validated";
1480 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1481 jvParams[jss::taker_pays][jss::issuer] = 1;
1482 jvParams[jss::taker_gets][jss::currency] =
"USD";
1483 auto const jrr = env.
rpc(
1484 "json",
"book_offers",
to_string(jvParams))[jss::result];
1485 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1487 jrr[jss::error_message] ==
1488 "Invalid field 'taker_pays.issuer', not string.");
1493 jvParams[jss::ledger_index] =
"validated";
1494 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1495 jvParams[jss::taker_pays][jss::issuer] = gw.human() +
"DEAD";
1496 jvParams[jss::taker_gets][jss::currency] =
"USD";
1497 auto const jrr = env.
rpc(
1498 "json",
"book_offers",
to_string(jvParams))[jss::result];
1499 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1501 jrr[jss::error_message] ==
1502 "Invalid field 'taker_pays.issuer', bad issuer.");
1507 jvParams[jss::ledger_index] =
"validated";
1508 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1510 jvParams[jss::taker_gets][jss::currency] =
"USD";
1511 auto const jrr = env.
rpc(
1512 "json",
"book_offers",
to_string(jvParams))[jss::result];
1513 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1515 jrr[jss::error_message] ==
1516 "Invalid field 'taker_pays.issuer', bad issuer account one.");
1521 jvParams[jss::ledger_index] =
"validated";
1522 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1523 jvParams[jss::taker_gets][jss::currency] =
"USD";
1524 jvParams[jss::taker_gets][jss::issuer] = gw.human() +
"DEAD";
1525 auto const jrr = env.
rpc(
1526 "json",
"book_offers",
to_string(jvParams))[jss::result];
1527 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1529 jrr[jss::error_message] ==
1530 "Invalid field 'taker_gets.issuer', bad issuer.");
1535 jvParams[jss::ledger_index] =
"validated";
1536 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1537 jvParams[jss::taker_gets][jss::currency] =
"USD";
1539 auto const jrr = env.
rpc(
1540 "json",
"book_offers",
to_string(jvParams))[jss::result];
1541 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1543 jrr[jss::error_message] ==
1544 "Invalid field 'taker_gets.issuer', bad issuer account one.");
1549 jvParams[jss::ledger_index] =
"validated";
1550 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1551 jvParams[jss::taker_pays][jss::issuer] = alice.human();
1552 jvParams[jss::taker_gets][jss::currency] =
"USD";
1553 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1554 auto const jrr = env.
rpc(
1555 "json",
"book_offers",
to_string(jvParams))[jss::result];
1556 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1558 jrr[jss::error_message] ==
1559 "Unneeded field 'taker_pays.issuer' "
1560 "for XRP currency specification.");
1565 jvParams[jss::ledger_index] =
"validated";
1566 jvParams[jss::taker_pays][jss::currency] =
"USD";
1568 jvParams[jss::taker_gets][jss::currency] =
"USD";
1569 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1570 auto const jrr = env.
rpc(
1571 "json",
"book_offers",
to_string(jvParams))[jss::result];
1572 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1574 jrr[jss::error_message] ==
1575 "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
1580 jvParams[jss::ledger_index] =
"validated";
1581 jvParams[jss::taker] = 1;
1582 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1583 jvParams[jss::taker_gets][jss::currency] =
"USD";
1584 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1585 auto const jrr = env.
rpc(
1586 "json",
"book_offers",
to_string(jvParams))[jss::result];
1587 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1589 jrr[jss::error_message] ==
1590 "Invalid field 'taker', not string.");
1595 jvParams[jss::ledger_index] =
"validated";
1596 jvParams[jss::taker] = env.
master.
human() +
"DEAD";
1597 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1598 jvParams[jss::taker_gets][jss::currency] =
"USD";
1599 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1600 auto const jrr = env.
rpc(
1601 "json",
"book_offers",
to_string(jvParams))[jss::result];
1602 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1603 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'taker'.");
1608 jvParams[jss::ledger_index] =
"validated";
1610 jvParams[jss::taker_pays][jss::currency] =
"USD";
1611 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1612 jvParams[jss::taker_gets][jss::currency] =
"USD";
1613 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1614 auto const jrr = env.
rpc(
1615 "json",
"book_offers",
to_string(jvParams))[jss::result];
1616 BEAST_EXPECT(jrr[jss::error] ==
"badMarket");
1617 BEAST_EXPECT(jrr[jss::error_message] ==
"No such market.");
1622 jvParams[jss::ledger_index] =
"validated";
1624 jvParams[jss::limit] =
"0";
1625 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1626 jvParams[jss::taker_gets][jss::currency] =
"USD";
1627 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1628 auto const jrr = env.
rpc(
1629 "json",
"book_offers",
to_string(jvParams))[jss::result];
1630 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1632 jrr[jss::error_message] ==
1633 "Invalid field 'limit', not unsigned integer.");
1638 jvParams[jss::ledger_index] =
"validated";
1640 jvParams[jss::limit] = 0;
1641 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1642 jvParams[jss::taker_gets][jss::currency] =
"USD";
1643 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1644 auto const jrr = env.
rpc(
1645 "json",
"book_offers",
to_string(jvParams))[jss::result];
1646 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1647 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'limit'.");
1652 jvParams[jss::ledger_index] =
"validated";
1653 jvParams[jss::taker_pays][jss::currency] =
"USD";
1654 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1655 jvParams[jss::taker_gets][jss::currency] =
"USD";
1656 auto const jrr = env.
rpc(
1657 "json",
"book_offers",
to_string(jvParams))[jss::result];
1658 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1660 jrr[jss::error_message] ==
1661 "Invalid field 'taker_gets.issuer', "
1662 "expected non-XRP issuer.");
1667 jvParams[jss::ledger_index] =
"validated";
1668 jvParams[jss::taker_pays][jss::currency] =
"USD";
1669 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1670 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1671 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1672 auto const jrr = env.
rpc(
1673 "json",
"book_offers",
to_string(jvParams))[jss::result];
1674 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1676 jrr[jss::error_message] ==
1677 "Unneeded field 'taker_gets.issuer' "
1678 "for XRP currency specification.");
1682 jvParams[jss::ledger_index] =
"validated";
1683 jvParams[jss::taker_pays][jss::currency] =
"USD";
1684 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1685 jvParams[jss::taker_gets][jss::currency] =
"EUR";
1686 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1687 jvParams[jss::domain] =
"badString";
1688 auto const jrr = env.
rpc(
1689 "json",
"book_offers",
to_string(jvParams))[jss::result];
1690 BEAST_EXPECT(jrr[jss::error] ==
"domainMalformed");
1691 BEAST_EXPECT(jrr[jss::error_message] ==
"Unable to parse domain.");
1746 using namespace jtx;
1750 featureCredentials | featurePermissionedDEX};
1754 auto const alice = permDex.
alice;
1755 auto const bob = permDex.
bob;
1756 auto const carol = permDex.
carol;
1757 auto const domainID = permDex.
domainID;
1758 auto const gw = permDex.
gw;
1759 auto const USD = permDex.
USD;
1766 auto checkBookOffers = [&](
Json::Value const& jrr) {
1767 BEAST_EXPECT(jrr[jss::offers].isArray());
1768 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1769 auto const jrOffer = jrr[jss::offers][0u];
1770 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1772 jrOffer[sfBookDirectory.fieldName] ==
1774 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1775 BEAST_EXPECT(jrOffer[jss::Flags] == 0);
1776 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1777 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1779 jrOffer[jss::TakerGets] ==
1782 jrOffer[jss::TakerPays] ==
1785 jrOffer[sfDomainID.jsonName].asString() ==
to_string(domainID));
1792 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1793 jvParams[jss::ledger_index] =
"validated";
1794 jvParams[jss::taker_gets][jss::currency] =
"USD";
1795 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1797 auto jv = wsc->invoke(
"book_offers", jvParams);
1798 auto jrr = jv[jss::result];
1799 BEAST_EXPECT(jrr[jss::offers].isArray());
1800 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1805 jv[jss::result].isMember(jss::offers) &&
1806 jv[jss::result][jss::offers].size() == 1);
1808 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
1811 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
1814 jv[jss::result][jss::offers][0u][sfDomainID.jsonName]
1822 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1823 jvParams[jss::ledger_index] =
"validated";
1824 jvParams[jss::taker_gets][jss::currency] =
"USD";
1825 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1826 jvParams[jss::domain] =
to_string(domainID);
1828 auto jv = wsc->invoke(
"book_offers", jvParams);
1829 auto jrr = jv[jss::result];
1830 checkBookOffers(jrr);
1839 j[jss::snapshot] =
true;
1840 j[jss::taker_pays][jss::currency] =
"XRP";
1841 j[jss::taker_gets][jss::currency] =
"USD";
1842 j[jss::taker_gets][jss::issuer] = gw.human();
1846 auto jv = wsc->invoke(
"subscribe", books);
1847 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1858 j[jss::snapshot] =
true;
1859 j[jss::taker_pays][jss::currency] =
"XRP";
1860 j[jss::taker_gets][jss::currency] =
"USD";
1861 j[jss::taker_gets][jss::issuer] = gw.human();
1864 auto jv = wsc->invoke(
"subscribe", books);
1865 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1868 jv[jss::result].isMember(jss::offers) &&
1869 jv[jss::result][jss::offers].size() == 0);
1877 using namespace jtx;
1881 featureCredentials | featurePermissionedDEX};
1885 auto const alice = permDex.
alice;
1886 auto const bob = permDex.
bob;
1887 auto const carol = permDex.
carol;
1888 auto const domainID = permDex.
domainID;
1889 auto const gw = permDex.
gw;
1890 auto const USD = permDex.
USD;
1894 env(
offer(alice,
XRP(10), USD(10)),
1899 auto checkBookOffers = [&](
Json::Value const& jrr) {
1900 BEAST_EXPECT(jrr[jss::offers].isArray());
1901 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1902 auto const jrOffer = jrr[jss::offers][0u];
1903 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1905 jrOffer[sfBookDirectory.fieldName] ==
1907 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1908 BEAST_EXPECT(jrOffer[jss::Flags] ==
lsfHybrid);
1909 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1910 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1912 jrOffer[jss::TakerGets] ==
1915 jrOffer[jss::TakerPays] ==
1918 jrOffer[sfDomainID.jsonName].asString() ==
to_string(domainID));
1919 BEAST_EXPECT(jrOffer[sfAdditionalBooks.jsonName].size() == 1);
1926 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1927 jvParams[jss::ledger_index] =
"validated";
1928 jvParams[jss::taker_gets][jss::currency] =
"USD";
1929 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1931 auto jv = wsc->invoke(
"book_offers", jvParams);
1932 auto jrr = jv[jss::result];
1933 checkBookOffers(jrr);
1938 jv[jss::result].isMember(jss::offers) &&
1939 jv[jss::result][jss::offers].size() == 1);
1941 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
1944 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
1947 jv[jss::result][jss::offers][0u][sfDomainID.jsonName]
1955 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1956 jvParams[jss::ledger_index] =
"validated";
1957 jvParams[jss::taker_gets][jss::currency] =
"USD";
1958 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1959 jvParams[jss::domain] =
to_string(domainID);
1961 auto jv = wsc->invoke(
"book_offers", jvParams);
1962 auto jrr = jv[jss::result];
1963 checkBookOffers(jrr);
1972 j[jss::snapshot] =
true;
1973 j[jss::taker_pays][jss::currency] =
"XRP";
1974 j[jss::taker_gets][jss::currency] =
"USD";
1975 j[jss::taker_gets][jss::issuer] = gw.human();
1979 auto jv = wsc->invoke(
"subscribe", books);
1980 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1985 auto unsubJv = wsc->invoke(
"unsubscribe", books);
1986 if (wsc->version() == 2)
1987 BEAST_EXPECT(unsubJv[jss::status] ==
"success");
1996 j[jss::snapshot] =
true;
1997 j[jss::taker_pays][jss::currency] =
"XRP";
1998 j[jss::taker_gets][jss::currency] =
"USD";
1999 j[jss::taker_gets][jss::issuer] = gw.human();
2002 auto jv = wsc->invoke(
"subscribe", books);
2003 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))