477 testcase(
"Multiple Books, One Side Offers In Book");
478 using namespace std::chrono_literals;
482 auto USD =
Account(
"alice")[
"USD"];
483 auto CNY =
Account(
"alice")[
"CNY"];
484 auto JPY =
Account(
"alice")[
"JPY"];
506 j[jss::snapshot] =
true;
507 j[jss::taker_gets][jss::currency] =
"XRP";
508 j[jss::taker_pays][jss::currency] =
"USD";
509 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
513 j[jss::snapshot] =
true;
514 j[jss::taker_gets][jss::currency] =
"CNY";
515 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
516 j[jss::taker_pays][jss::currency] =
"JPY";
517 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
520 auto jv = wsc->invoke(
"subscribe", books);
521 if (wsc->version() == 2)
523 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
524 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
525 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
527 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
530 jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 2);
532 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
535 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
538 jv[jss::result][jss::offers][1u][jss::TakerGets] ==
541 jv[jss::result][jss::offers][1u][jss::TakerPays] ==
543 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
544 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
553 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
554 auto const& t = jv[jss::transaction];
555 return t[jss::TransactionType] == jss::OfferCreate &&
556 t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) &&
557 t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none);
565 BEAST_EXPECT(!wsc->getMsg(10ms));
574 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
575 auto const& t = jv[jss::transaction];
576 return t[jss::TransactionType] == jss::OfferCreate &&
577 t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) &&
578 t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none);
586 BEAST_EXPECT(!wsc->getMsg(10ms));
590 auto jv = wsc->invoke(
"unsubscribe", books);
591 BEAST_EXPECT(jv[jss::status] ==
"success");
592 if (wsc->version() == 2)
594 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
595 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
596 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
603 testcase(
"Multiple Books, Both Sides Empty Book");
604 using namespace std::chrono_literals;
608 auto USD =
Account(
"alice")[
"USD"];
609 auto CNY =
Account(
"alice")[
"CNY"];
610 auto JPY =
Account(
"alice")[
"JPY"];
619 j[jss::snapshot] =
true;
621 j[jss::taker_gets][jss::currency] =
"XRP";
622 j[jss::taker_pays][jss::currency] =
"USD";
623 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
627 j[jss::snapshot] =
true;
629 j[jss::taker_gets][jss::currency] =
"CNY";
630 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
631 j[jss::taker_pays][jss::currency] =
"JPY";
632 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
635 auto jv = wsc->invoke(
"subscribe", books);
636 if (wsc->version() == 2)
638 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
639 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
640 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
642 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
645 jv[jss::result].isMember(jss::asks) && jv[jss::result][jss::asks].size() == 0);
647 jv[jss::result].isMember(jss::bids) && jv[jss::result][jss::bids].size() == 0);
648 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
657 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
658 auto const& t = jv[jss::transaction];
659 return t[jss::TransactionType] == jss::OfferCreate &&
660 t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) &&
661 t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none);
671 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
672 auto const& t = jv[jss::transaction];
673 return t[jss::TransactionType] == jss::OfferCreate &&
674 t[jss::TakerGets] == XRP(75).value().getJson(JsonOptions::none) &&
675 t[jss::TakerPays] == USD(100).value().getJson(JsonOptions::none);
685 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
686 auto const& t = jv[jss::transaction];
687 return t[jss::TransactionType] == jss::OfferCreate &&
688 t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) &&
689 t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none);
699 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
700 auto const& t = jv[jss::transaction];
701 return t[jss::TransactionType] == jss::OfferCreate &&
702 t[jss::TakerGets] == CNY(75).value().getJson(JsonOptions::none) &&
703 t[jss::TakerPays] == JPY(100).value().getJson(JsonOptions::none);
708 auto jv = wsc->invoke(
"unsubscribe", books);
709 BEAST_EXPECT(jv[jss::status] ==
"success");
710 if (wsc->version() == 2)
712 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
713 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
714 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
721 testcase(
"Multiple Books, Both Sides Offers In Book");
722 using namespace std::chrono_literals;
726 auto USD =
Account(
"alice")[
"USD"];
727 auto CNY =
Account(
"alice")[
"CNY"];
728 auto JPY =
Account(
"alice")[
"JPY"];
750 j[jss::snapshot] =
true;
752 j[jss::taker_gets][jss::currency] =
"XRP";
753 j[jss::taker_pays][jss::currency] =
"USD";
754 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
759 j[jss::snapshot] =
true;
761 j[jss::taker_gets][jss::currency] =
"CNY";
762 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
763 j[jss::taker_pays][jss::currency] =
"JPY";
764 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
767 auto jv = wsc->invoke(
"subscribe", books);
768 if (wsc->version() == 2)
770 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
771 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
772 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
774 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
777 jv[jss::result].isMember(jss::asks) && jv[jss::result][jss::asks].size() == 2);
779 jv[jss::result].isMember(jss::bids) && jv[jss::result][jss::bids].size() == 2);
781 jv[jss::result][jss::asks][0u][jss::TakerGets] ==
784 jv[jss::result][jss::asks][0u][jss::TakerPays] ==
787 jv[jss::result][jss::asks][1u][jss::TakerGets] ==
790 jv[jss::result][jss::asks][1u][jss::TakerPays] ==
793 jv[jss::result][jss::bids][0u][jss::TakerGets] ==
796 jv[jss::result][jss::bids][0u][jss::TakerPays] ==
799 jv[jss::result][jss::bids][1u][jss::TakerGets] ==
802 jv[jss::result][jss::bids][1u][jss::TakerPays] ==
804 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
813 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
814 auto const& t = jv[jss::transaction];
815 return t[jss::TransactionType] == jss::OfferCreate &&
816 t[jss::TakerGets] == USD(100).value().getJson(JsonOptions::none) &&
817 t[jss::TakerPays] == XRP(700).value().getJson(JsonOptions::none);
827 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
828 auto const& t = jv[jss::transaction];
829 return t[jss::TransactionType] == jss::OfferCreate &&
830 t[jss::TakerGets] == XRP(75).value().getJson(JsonOptions::none) &&
831 t[jss::TakerPays] == USD(100).value().getJson(JsonOptions::none);
841 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
842 auto const& t = jv[jss::transaction];
843 return t[jss::TransactionType] == jss::OfferCreate &&
844 t[jss::TakerGets] == JPY(100).value().getJson(JsonOptions::none) &&
845 t[jss::TakerPays] == CNY(700).value().getJson(JsonOptions::none);
855 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
856 auto const& t = jv[jss::transaction];
857 return t[jss::TransactionType] == jss::OfferCreate &&
858 t[jss::TakerGets] == CNY(75).value().getJson(JsonOptions::none) &&
859 t[jss::TakerPays] == JPY(100).value().getJson(JsonOptions::none);
864 auto jv = wsc->invoke(
"unsubscribe", books);
865 BEAST_EXPECT(jv[jss::status] ==
"success");
866 if (wsc->version() == 2)
868 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
869 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
870 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
884 env.
fund(
XRP(20000), alice, bob, gw);
886 auto USD = gw[
"USD"];
893 j[jss::snapshot] =
true;
894 j[jss::taker_gets][jss::currency] =
"XRP";
895 j[jss::taker_pays][jss::currency] =
"USD";
896 j[jss::taker_pays][jss::issuer] = gw.human();
899 auto jv = wsc->invoke(
"subscribe", books);
900 if (wsc->version() == 2)
902 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
903 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
904 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
906 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
909 jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 0);
910 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
911 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
916 env.
trust(USD(1000), alice);
917 env.
trust(USD(1000), bob);
918 env(
pay(gw, alice, USD(100)));
919 env(
pay(gw, bob, USD(50)));
920 env(
offer(alice,
XRP(4000), USD(10)));
925 jvParams[jss::taker_pays][jss::currency] =
"XRP";
926 jvParams[jss::ledger_index] =
"validated";
927 jvParams[jss::taker_gets][jss::currency] =
"USD";
928 jvParams[jss::taker_gets][jss::issuer] = gw.human();
930 auto jv = wsc->invoke(
"book_offers", jvParams);
931 if (wsc->version() == 2)
933 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
934 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
935 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
937 auto jrr = jv[jss::result];
939 BEAST_EXPECT(jrr[jss::offers].isArray());
940 BEAST_EXPECT(jrr[jss::offers].size() == 1);
941 auto const jrOffer = jrr[jss::offers][0u];
942 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
943 BEAST_EXPECT(jrOffer[sfBookDirectory.fieldName] ==
getBookDir(env,
XRP, USD.issue()));
944 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
945 BEAST_EXPECT(jrOffer[jss::Flags] == 0);
946 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
947 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
948 BEAST_EXPECT(jrOffer[sfSequence.fieldName] == 5);
951 BEAST_EXPECT(jrOffer[jss::owner_funds] ==
"100");
952 BEAST_EXPECT(jrOffer[jss::quality] ==
"400000000");
954 using namespace std::chrono_literals;
955 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
956 auto const& t = jval[jss::transaction];
957 return t[jss::TransactionType] == jss::OfferCreate &&
958 t[jss::TakerGets] == USD(10).value().getJson(JsonOptions::none) &&
959 t[jss::owner_funds] ==
"100" &&
960 t[jss::TakerPays] == XRP(4000).value().getJson(JsonOptions::none);
966 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
967 auto const& t = jval[jss::transaction];
968 return t[jss::TransactionType] == jss::OfferCreate &&
969 t[jss::TakerGets] == USD(5).value().getJson(JsonOptions::none) &&
970 t[jss::owner_funds] ==
"50" &&
971 t[jss::TakerPays] == XRP(2000).value().getJson(JsonOptions::none);
974 jv = wsc->invoke(
"book_offers", jvParams);
975 if (wsc->version() == 2)
977 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
978 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
979 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
981 jrr = jv[jss::result];
983 BEAST_EXPECT(jrr[jss::offers].isArray());
984 BEAST_EXPECT(jrr[jss::offers].size() == 2);
985 auto const jrNextOffer = jrr[jss::offers][1u];
986 BEAST_EXPECT(jrNextOffer[sfAccount.fieldName] == bob.human());
987 BEAST_EXPECT(jrNextOffer[sfBookDirectory.fieldName] ==
getBookDir(env,
XRP, USD.issue()));
988 BEAST_EXPECT(jrNextOffer[sfBookNode.fieldName] ==
"0");
989 BEAST_EXPECT(jrNextOffer[jss::Flags] == 0);
990 BEAST_EXPECT(jrNextOffer[sfLedgerEntryType.fieldName] == jss::Offer);
991 BEAST_EXPECT(jrNextOffer[sfOwnerNode.fieldName] ==
"0");
992 BEAST_EXPECT(jrNextOffer[sfSequence.fieldName] == 5);
995 BEAST_EXPECT(jrNextOffer[jss::owner_funds] ==
"50");
996 BEAST_EXPECT(jrNextOffer[jss::quality] ==
"400000000");
998 jv = wsc->invoke(
"unsubscribe", books);
999 if (wsc->version() == 2)
1001 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1002 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1003 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1005 BEAST_EXPECT(jv[jss::status] ==
"success");
1187 using namespace jtx;
1191 env.
fund(
XRP(10000), alice, gw);
1193 auto USD = gw[
"USD"];
1197 jvParams[jss::ledger_index] = 10u;
1198 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1199 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
1200 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
1205 jvParams[jss::ledger_index] =
"validated";
1206 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1207 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1208 BEAST_EXPECT(jrr[jss::error_message] ==
"Missing field 'taker_pays'.");
1213 jvParams[jss::ledger_index] =
"validated";
1215 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1216 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1217 BEAST_EXPECT(jrr[jss::error_message] ==
"Missing field 'taker_gets'.");
1222 jvParams[jss::ledger_index] =
"validated";
1223 jvParams[jss::taker_pays] =
"not an object";
1225 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1226 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1227 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'taker_pays', not object.");
1232 jvParams[jss::ledger_index] =
"validated";
1234 jvParams[jss::taker_gets] =
"not an object";
1235 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1236 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1237 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'taker_gets', not object.");
1242 jvParams[jss::ledger_index] =
"validated";
1245 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1246 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1247 BEAST_EXPECT(jrr[jss::error_message] ==
"Missing field 'taker_pays.currency'.");
1252 jvParams[jss::ledger_index] =
"validated";
1253 jvParams[jss::taker_pays][jss::currency] = 1;
1255 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1256 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1258 jrr[jss::error_message] ==
"Invalid field 'taker_pays.currency', not string.");
1263 jvParams[jss::ledger_index] =
"validated";
1264 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1266 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1267 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1268 BEAST_EXPECT(jrr[jss::error_message] ==
"Missing field 'taker_gets.currency'.");
1273 jvParams[jss::ledger_index] =
"validated";
1274 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1275 jvParams[jss::taker_gets][jss::currency] = 1;
1276 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1277 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1279 jrr[jss::error_message] ==
"Invalid field 'taker_gets.currency', not string.");
1284 jvParams[jss::ledger_index] =
"validated";
1285 jvParams[jss::taker_pays][jss::currency] =
"NOT_VALID";
1286 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1287 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1288 BEAST_EXPECT(jrr[jss::error] ==
"srcCurMalformed");
1290 jrr[jss::error_message] ==
"Invalid field 'taker_pays.currency', bad currency.");
1295 jvParams[jss::ledger_index] =
"validated";
1296 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1297 jvParams[jss::taker_gets][jss::currency] =
"NOT_VALID";
1298 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1299 BEAST_EXPECT(jrr[jss::error] ==
"dstAmtMalformed");
1301 jrr[jss::error_message] ==
"Invalid field 'taker_gets.currency', bad currency.");
1306 jvParams[jss::ledger_index] =
"validated";
1307 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1308 jvParams[jss::taker_gets][jss::currency] =
"USD";
1309 jvParams[jss::taker_gets][jss::issuer] = 1;
1310 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1311 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1313 jrr[jss::error_message] ==
"Invalid field 'taker_gets.issuer', not string.");
1318 jvParams[jss::ledger_index] =
"validated";
1319 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1320 jvParams[jss::taker_pays][jss::issuer] = 1;
1321 jvParams[jss::taker_gets][jss::currency] =
"USD";
1322 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1323 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1325 jrr[jss::error_message] ==
"Invalid field 'taker_pays.issuer', not string.");
1330 jvParams[jss::ledger_index] =
"validated";
1331 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1332 jvParams[jss::taker_pays][jss::issuer] = gw.human() +
"DEAD";
1333 jvParams[jss::taker_gets][jss::currency] =
"USD";
1334 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1335 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1337 jrr[jss::error_message] ==
"Invalid field 'taker_pays.issuer', bad issuer.");
1342 jvParams[jss::ledger_index] =
"validated";
1343 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1345 jvParams[jss::taker_gets][jss::currency] =
"USD";
1346 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1347 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1349 jrr[jss::error_message] ==
1350 "Invalid field 'taker_pays.issuer', bad issuer account one.");
1355 jvParams[jss::ledger_index] =
"validated";
1356 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1357 jvParams[jss::taker_gets][jss::currency] =
"USD";
1358 jvParams[jss::taker_gets][jss::issuer] = gw.human() +
"DEAD";
1359 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1360 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1362 jrr[jss::error_message] ==
"Invalid field 'taker_gets.issuer', bad issuer.");
1367 jvParams[jss::ledger_index] =
"validated";
1368 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1369 jvParams[jss::taker_gets][jss::currency] =
"USD";
1371 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1372 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1374 jrr[jss::error_message] ==
1375 "Invalid field 'taker_gets.issuer', bad issuer account one.");
1380 jvParams[jss::ledger_index] =
"validated";
1381 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1382 jvParams[jss::taker_pays][jss::issuer] = alice.human();
1383 jvParams[jss::taker_gets][jss::currency] =
"USD";
1384 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1385 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1386 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1388 jrr[jss::error_message] ==
1389 "Unneeded field 'taker_pays.issuer' "
1390 "for XRP currency specification.");
1395 jvParams[jss::ledger_index] =
"validated";
1396 jvParams[jss::taker_pays][jss::currency] =
"USD";
1398 jvParams[jss::taker_gets][jss::currency] =
"USD";
1399 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1400 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1401 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1403 jrr[jss::error_message] ==
1404 "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
1409 jvParams[jss::ledger_index] =
"validated";
1410 jvParams[jss::taker] = 1;
1411 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1412 jvParams[jss::taker_gets][jss::currency] =
"USD";
1413 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1414 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1415 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1416 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'taker', not string.");
1421 jvParams[jss::ledger_index] =
"validated";
1422 jvParams[jss::taker] = env.
master.
human() +
"DEAD";
1423 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1424 jvParams[jss::taker_gets][jss::currency] =
"USD";
1425 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1426 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1427 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1428 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'taker'.");
1433 jvParams[jss::ledger_index] =
"validated";
1435 jvParams[jss::taker_pays][jss::currency] =
"USD";
1436 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1437 jvParams[jss::taker_gets][jss::currency] =
"USD";
1438 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1439 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1440 BEAST_EXPECT(jrr[jss::error] ==
"badMarket");
1441 BEAST_EXPECT(jrr[jss::error_message] ==
"No such market.");
1446 jvParams[jss::ledger_index] =
"validated";
1448 jvParams[jss::limit] =
"0";
1449 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1450 jvParams[jss::taker_gets][jss::currency] =
"USD";
1451 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1452 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1453 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1454 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'limit', not unsigned integer.");
1459 jvParams[jss::ledger_index] =
"validated";
1461 jvParams[jss::limit] = 0;
1462 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1463 jvParams[jss::taker_gets][jss::currency] =
"USD";
1464 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1465 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1466 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1467 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'limit'.");
1472 jvParams[jss::ledger_index] =
"validated";
1473 jvParams[jss::taker_pays][jss::currency] =
"USD";
1474 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1475 jvParams[jss::taker_gets][jss::currency] =
"USD";
1476 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1477 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1479 jrr[jss::error_message] ==
1480 "Invalid field 'taker_gets.issuer', "
1481 "expected non-XRP issuer.");
1486 jvParams[jss::ledger_index] =
"validated";
1487 jvParams[jss::taker_pays][jss::currency] =
"USD";
1488 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1489 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1490 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1491 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1492 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1494 jrr[jss::error_message] ==
1495 "Unneeded field 'taker_gets.issuer' "
1496 "for XRP currency specification.");
1500 jvParams[jss::ledger_index] =
"validated";
1501 jvParams[jss::taker_pays][jss::currency] =
"USD";
1502 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1503 jvParams[jss::taker_gets][jss::currency] =
"EUR";
1504 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1505 jvParams[jss::domain] =
"badString";
1506 auto const jrr = env.
rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1507 BEAST_EXPECT(jrr[jss::error] ==
"domainMalformed");
1508 BEAST_EXPECT(jrr[jss::error_message] ==
"Unable to parse domain.");
1558 using namespace jtx;
1562 featurePermissionedDEX};
1564 Env env(*
this, all);
1566 auto const alice = permDex.
alice;
1567 auto const bob = permDex.
bob;
1568 auto const carol = permDex.
carol;
1569 auto const domainID = permDex.
domainID;
1570 auto const gw = permDex.
gw;
1571 auto const USD = permDex.
USD;
1578 auto checkBookOffers = [&](
Json::Value const& jrr) {
1579 BEAST_EXPECT(jrr[jss::offers].isArray());
1580 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1581 auto const jrOffer = jrr[jss::offers][0u];
1582 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1584 jrOffer[sfBookDirectory.fieldName] ==
getBookDir(env,
XRP, USD.issue(), domainID));
1585 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1586 BEAST_EXPECT(jrOffer[jss::Flags] == 0);
1587 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1588 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1591 BEAST_EXPECT(jrOffer[sfDomainID.jsonName].asString() ==
to_string(domainID));
1598 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1599 jvParams[jss::ledger_index] =
"validated";
1600 jvParams[jss::taker_gets][jss::currency] =
"USD";
1601 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1603 auto jv = wsc->invoke(
"book_offers", jvParams);
1604 auto jrr = jv[jss::result];
1605 BEAST_EXPECT(jrr[jss::offers].isArray());
1606 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1611 jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 1);
1613 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
1616 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
1619 jv[jss::result][jss::offers][0u][sfDomainID.jsonName].asString() ==
1627 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1628 jvParams[jss::ledger_index] =
"validated";
1629 jvParams[jss::taker_gets][jss::currency] =
"USD";
1630 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1631 jvParams[jss::domain] =
to_string(domainID);
1633 auto jv = wsc->invoke(
"book_offers", jvParams);
1634 auto jrr = jv[jss::result];
1635 checkBookOffers(jrr);
1644 j[jss::snapshot] =
true;
1645 j[jss::taker_pays][jss::currency] =
"XRP";
1646 j[jss::taker_gets][jss::currency] =
"USD";
1647 j[jss::taker_gets][jss::issuer] = gw.human();
1651 auto jv = wsc->invoke(
"subscribe", books);
1652 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1663 j[jss::snapshot] =
true;
1664 j[jss::taker_pays][jss::currency] =
"XRP";
1665 j[jss::taker_gets][jss::currency] =
"USD";
1666 j[jss::taker_gets][jss::issuer] = gw.human();
1669 auto jv = wsc->invoke(
"subscribe", books);
1670 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1673 jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 0);
1681 using namespace jtx;
1685 featurePermissionedDEX};
1687 Env env(*
this, all);
1689 auto const alice = permDex.
alice;
1690 auto const bob = permDex.
bob;
1691 auto const carol = permDex.
carol;
1692 auto const domainID = permDex.
domainID;
1693 auto const gw = permDex.
gw;
1694 auto const USD = permDex.
USD;
1701 auto checkBookOffers = [&](
Json::Value const& jrr) {
1702 BEAST_EXPECT(jrr[jss::offers].isArray());
1703 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1704 auto const jrOffer = jrr[jss::offers][0u];
1705 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1707 jrOffer[sfBookDirectory.fieldName] ==
getBookDir(env,
XRP, USD.issue(), domainID));
1708 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1709 BEAST_EXPECT(jrOffer[jss::Flags] == lsfHybrid);
1710 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1711 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1714 BEAST_EXPECT(jrOffer[sfDomainID.jsonName].asString() ==
to_string(domainID));
1715 BEAST_EXPECT(jrOffer[sfAdditionalBooks.jsonName].size() == 1);
1722 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1723 jvParams[jss::ledger_index] =
"validated";
1724 jvParams[jss::taker_gets][jss::currency] =
"USD";
1725 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1727 auto jv = wsc->invoke(
"book_offers", jvParams);
1728 auto jrr = jv[jss::result];
1729 checkBookOffers(jrr);
1734 jv[jss::result].isMember(jss::offers) && jv[jss::result][jss::offers].size() == 1);
1736 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
1739 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
1742 jv[jss::result][jss::offers][0u][sfDomainID.jsonName].asString() ==
1750 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1751 jvParams[jss::ledger_index] =
"validated";
1752 jvParams[jss::taker_gets][jss::currency] =
"USD";
1753 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1754 jvParams[jss::domain] =
to_string(domainID);
1756 auto jv = wsc->invoke(
"book_offers", jvParams);
1757 auto jrr = jv[jss::result];
1758 checkBookOffers(jrr);
1767 j[jss::snapshot] =
true;
1768 j[jss::taker_pays][jss::currency] =
"XRP";
1769 j[jss::taker_gets][jss::currency] =
"USD";
1770 j[jss::taker_gets][jss::issuer] = gw.human();
1774 auto jv = wsc->invoke(
"subscribe", books);
1775 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1780 auto unsubJv = wsc->invoke(
"unsubscribe", books);
1781 if (wsc->version() == 2)
1782 BEAST_EXPECT(unsubJv[jss::status] ==
"success");
1791 j[jss::snapshot] =
true;
1792 j[jss::taker_pays][jss::currency] =
"XRP";
1793 j[jss::taker_gets][jss::currency] =
"USD";
1794 j[jss::taker_gets][jss::issuer] = gw.human();
1797 auto jv = wsc->invoke(
"subscribe", books);
1798 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))