431 testcase(
"Multiple Books, One Side Empty");
432 using namespace std::chrono_literals;
436 auto USD =
Account(
"alice")[
"USD"];
437 auto CNY =
Account(
"alice")[
"CNY"];
438 auto JPY =
Account(
"alice")[
"JPY"];
447 j[jss::snapshot] =
true;
448 j[jss::taker_gets][jss::currency] =
"XRP";
449 j[jss::taker_pays][jss::currency] =
"USD";
450 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
454 j[jss::snapshot] =
true;
455 j[jss::taker_gets][jss::currency] =
"CNY";
456 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
457 j[jss::taker_pays][jss::currency] =
"JPY";
458 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
461 auto jv = wsc->invoke(
"subscribe", books);
462 if (wsc->version() == 2)
465 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
467 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
468 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
470 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
473 jv[jss::result].isMember(jss::offers) &&
474 jv[jss::result][jss::offers].size() == 0);
475 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
476 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
481 env(
offer(
"alice",
XRP(700), USD(100)),
486 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
487 auto const& t = jv[jss::transaction];
488 return t[jss::TransactionType] == jss::OfferCreate &&
490 USD(100).value().getJson(JsonOptions::none) &&
492 XRP(700).value().getJson(JsonOptions::none);
500 BEAST_EXPECT(!wsc->getMsg(10ms));
505 env(
offer(
"alice", CNY(700), JPY(100)),
510 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
511 auto const& t = jv[jss::transaction];
512 return t[jss::TransactionType] == jss::OfferCreate &&
514 JPY(100).value().getJson(JsonOptions::none) &&
516 CNY(700).value().getJson(JsonOptions::none);
524 BEAST_EXPECT(!wsc->getMsg(10ms));
528 auto jv = wsc->invoke(
"unsubscribe", books);
529 BEAST_EXPECT(jv[jss::status] ==
"success");
530 if (wsc->version() == 2)
533 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
535 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
536 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
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";
1639 jvParams[jss::taker_pays][jss::currency] =
"USD";
1640 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1641 jvParams[jss::taker_gets][jss::currency] =
"USD";
1642 auto const jrr = env.
rpc(
1643 "json",
"book_offers",
to_string(jvParams))[jss::result];
1644 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1646 jrr[jss::error_message] ==
1647 "Invalid field 'taker_gets.issuer', "
1648 "expected non-XRP issuer.");
1653 jvParams[jss::ledger_index] =
"validated";
1654 jvParams[jss::taker_pays][jss::currency] =
"USD";
1655 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1656 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1657 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1658 auto const jrr = env.
rpc(
1659 "json",
"book_offers",
to_string(jvParams))[jss::result];
1660 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1662 jrr[jss::error_message] ==
1663 "Unneeded field 'taker_gets.issuer' "
1664 "for XRP currency specification.");
1668 jvParams[jss::ledger_index] =
"validated";
1669 jvParams[jss::taker_pays][jss::currency] =
"USD";
1670 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1671 jvParams[jss::taker_gets][jss::currency] =
"EUR";
1672 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1673 jvParams[jss::domain] =
"badString";
1674 auto const jrr = env.
rpc(
1675 "json",
"book_offers",
to_string(jvParams))[jss::result];
1676 BEAST_EXPECT(jrr[jss::error] ==
"domainMalformed");
1677 BEAST_EXPECT(jrr[jss::error_message] ==
"Unable to parse domain.");
1737 using namespace jtx;
1741 featureCredentials | featurePermissionedDEX};
1745 auto const alice = permDex.
alice;
1746 auto const bob = permDex.
bob;
1747 auto const carol = permDex.
carol;
1748 auto const domainID = permDex.
domainID;
1749 auto const gw = permDex.
gw;
1750 auto const USD = permDex.
USD;
1757 auto checkBookOffers = [&](
Json::Value const& jrr) {
1758 BEAST_EXPECT(jrr[jss::offers].isArray());
1759 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1760 auto const jrOffer = jrr[jss::offers][0u];
1761 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1763 jrOffer[sfBookDirectory.fieldName] ==
1765 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1766 BEAST_EXPECT(jrOffer[jss::Flags] == 0);
1767 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1768 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1770 jrOffer[jss::TakerGets] ==
1773 jrOffer[jss::TakerPays] ==
1776 jrOffer[sfDomainID.jsonName].asString() ==
to_string(domainID));
1783 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1784 jvParams[jss::ledger_index] =
"validated";
1785 jvParams[jss::taker_gets][jss::currency] =
"USD";
1786 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1788 auto jv = wsc->invoke(
"book_offers", jvParams);
1789 auto jrr = jv[jss::result];
1790 BEAST_EXPECT(jrr[jss::offers].isArray());
1791 BEAST_EXPECT(jrr[jss::offers].size() == 0);
1796 jv[jss::result].isMember(jss::offers) &&
1797 jv[jss::result][jss::offers].size() == 1);
1799 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
1802 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
1805 jv[jss::result][jss::offers][0u][sfDomainID.jsonName]
1813 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1814 jvParams[jss::ledger_index] =
"validated";
1815 jvParams[jss::taker_gets][jss::currency] =
"USD";
1816 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1817 jvParams[jss::domain] =
to_string(domainID);
1819 auto jv = wsc->invoke(
"book_offers", jvParams);
1820 auto jrr = jv[jss::result];
1821 checkBookOffers(jrr);
1830 j[jss::snapshot] =
true;
1831 j[jss::taker_pays][jss::currency] =
"XRP";
1832 j[jss::taker_gets][jss::currency] =
"USD";
1833 j[jss::taker_gets][jss::issuer] = gw.human();
1837 auto jv = wsc->invoke(
"subscribe", books);
1838 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1849 j[jss::snapshot] =
true;
1850 j[jss::taker_pays][jss::currency] =
"XRP";
1851 j[jss::taker_gets][jss::currency] =
"USD";
1852 j[jss::taker_gets][jss::issuer] = gw.human();
1855 auto jv = wsc->invoke(
"subscribe", books);
1856 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1859 jv[jss::result].isMember(jss::offers) &&
1860 jv[jss::result][jss::offers].size() == 0);
1868 using namespace jtx;
1872 featureCredentials | featurePermissionedDEX};
1876 auto const alice = permDex.
alice;
1877 auto const bob = permDex.
bob;
1878 auto const carol = permDex.
carol;
1879 auto const domainID = permDex.
domainID;
1880 auto const gw = permDex.
gw;
1881 auto const USD = permDex.
USD;
1885 env(
offer(alice,
XRP(10), USD(10)),
1890 auto checkBookOffers = [&](
Json::Value const& jrr) {
1891 BEAST_EXPECT(jrr[jss::offers].isArray());
1892 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1893 auto const jrOffer = jrr[jss::offers][0u];
1894 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1896 jrOffer[sfBookDirectory.fieldName] ==
1898 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1899 BEAST_EXPECT(jrOffer[jss::Flags] ==
lsfHybrid);
1900 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1901 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1903 jrOffer[jss::TakerGets] ==
1906 jrOffer[jss::TakerPays] ==
1909 jrOffer[sfDomainID.jsonName].asString() ==
to_string(domainID));
1910 BEAST_EXPECT(jrOffer[sfAdditionalBooks.jsonName].size() == 1);
1917 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1918 jvParams[jss::ledger_index] =
"validated";
1919 jvParams[jss::taker_gets][jss::currency] =
"USD";
1920 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1922 auto jv = wsc->invoke(
"book_offers", jvParams);
1923 auto jrr = jv[jss::result];
1924 checkBookOffers(jrr);
1929 jv[jss::result].isMember(jss::offers) &&
1930 jv[jss::result][jss::offers].size() == 1);
1932 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
1935 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
1938 jv[jss::result][jss::offers][0u][sfDomainID.jsonName]
1946 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1947 jvParams[jss::ledger_index] =
"validated";
1948 jvParams[jss::taker_gets][jss::currency] =
"USD";
1949 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1950 jvParams[jss::domain] =
to_string(domainID);
1952 auto jv = wsc->invoke(
"book_offers", jvParams);
1953 auto jrr = jv[jss::result];
1954 checkBookOffers(jrr);
1963 j[jss::snapshot] =
true;
1964 j[jss::taker_pays][jss::currency] =
"XRP";
1965 j[jss::taker_gets][jss::currency] =
"USD";
1966 j[jss::taker_gets][jss::issuer] = gw.human();
1970 auto jv = wsc->invoke(
"subscribe", books);
1971 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1976 auto unsubJv = wsc->invoke(
"unsubscribe", books);
1977 if (wsc->version() == 2)
1978 BEAST_EXPECT(unsubJv[jss::status] ==
"success");
1987 j[jss::snapshot] =
true;
1988 j[jss::taker_pays][jss::currency] =
"XRP";
1989 j[jss::taker_gets][jss::currency] =
"USD";
1990 j[jss::taker_gets][jss::issuer] = gw.human();
1993 auto jv = wsc->invoke(
"subscribe", books);
1994 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))