526        testcase(
"Multiple Books, One Side Offers In Book");
 
  527        using namespace std::chrono_literals;
 
  531        auto USD = 
Account(
"alice")[
"USD"];
 
  532        auto CNY = 
Account(
"alice")[
"CNY"];
 
  533        auto JPY = 
Account(
"alice")[
"JPY"];
 
  555                j[jss::snapshot] = 
true;
 
  556                j[jss::taker_gets][jss::currency] = 
"XRP";
 
  557                j[jss::taker_pays][jss::currency] = 
"USD";
 
  558                j[jss::taker_pays][jss::issuer] = 
Account(
"alice").
human();
 
  562                j[jss::snapshot] = 
true;
 
  563                j[jss::taker_gets][jss::currency] = 
"CNY";
 
  564                j[jss::taker_gets][jss::issuer] = 
Account(
"alice").
human();
 
  565                j[jss::taker_pays][jss::currency] = 
"JPY";
 
  566                j[jss::taker_pays][jss::issuer] = 
Account(
"alice").
human();
 
  569            auto jv = wsc->invoke(
"subscribe", books);
 
  570            if (wsc->version() == 2)
 
  573                    jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  575                    jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  576                BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
  578            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
  581                jv[jss::result].isMember(jss::offers) &&
 
  582                jv[jss::result][jss::offers].size() == 2);
 
  584                jv[jss::result][jss::offers][0u][jss::TakerGets] ==
 
  587                jv[jss::result][jss::offers][0u][jss::TakerPays] ==
 
  590                jv[jss::result][jss::offers][1u][jss::TakerGets] ==
 
  593                jv[jss::result][jss::offers][1u][jss::TakerPays] ==
 
  595            BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
 
  596            BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
 
  601            env(
offer(
"alice", 
XRP(700), USD(100)),
 
  606            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  607                auto const& t = jv[jss::transaction];
 
  608                return t[jss::TransactionType] == jss::OfferCreate &&
 
  610                    USD(100).value().getJson(JsonOptions::none) &&
 
  612                    XRP(700).value().getJson(JsonOptions::none);
 
  620            BEAST_EXPECT(!wsc->getMsg(10ms));
 
  625            env(
offer(
"alice", CNY(700), JPY(100)),
 
  630            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  631                auto const& t = jv[jss::transaction];
 
  632                return t[jss::TransactionType] == jss::OfferCreate &&
 
  634                    JPY(100).value().getJson(JsonOptions::none) &&
 
  636                    CNY(700).value().getJson(JsonOptions::none);
 
  644            BEAST_EXPECT(!wsc->getMsg(10ms));
 
  648        auto jv = wsc->invoke(
"unsubscribe", books);
 
  649        BEAST_EXPECT(jv[jss::status] == 
"success");
 
  650        if (wsc->version() == 2)
 
  653                jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  655                jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  656            BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 
  663        testcase(
"Multiple Books, Both Sides Empty Book");
 
  664        using namespace std::chrono_literals;
 
  668        auto USD = 
Account(
"alice")[
"USD"];
 
  669        auto CNY = 
Account(
"alice")[
"CNY"];
 
  670        auto JPY = 
Account(
"alice")[
"JPY"];
 
  679                j[jss::snapshot] = 
true;
 
  681                j[jss::taker_gets][jss::currency] = 
"XRP";
 
  682                j[jss::taker_pays][jss::currency] = 
"USD";
 
  683                j[jss::taker_pays][jss::issuer] = 
Account(
"alice").
human();
 
  687                j[jss::snapshot] = 
true;
 
  689                j[jss::taker_gets][jss::currency] = 
"CNY";
 
  690                j[jss::taker_gets][jss::issuer] = 
Account(
"alice").
human();
 
  691                j[jss::taker_pays][jss::currency] = 
"JPY";
 
  692                j[jss::taker_pays][jss::issuer] = 
Account(
"alice").
human();
 
  695            auto jv = wsc->invoke(
"subscribe", books);
 
  696            if (wsc->version() == 2)
 
  699                    jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  701                    jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  702                BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
  704            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
  707                jv[jss::result].isMember(jss::asks) &&
 
  708                jv[jss::result][jss::asks].size() == 0);
 
  710                jv[jss::result].isMember(jss::bids) &&
 
  711                jv[jss::result][jss::bids].size() == 0);
 
  712            BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
 
  717            env(
offer(
"alice", 
XRP(700), USD(100)),
 
  722            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  723                auto const& t = jv[jss::transaction];
 
  724                return t[jss::TransactionType] == jss::OfferCreate &&
 
  726                    USD(100).value().getJson(JsonOptions::none) &&
 
  728                    XRP(700).value().getJson(JsonOptions::none);
 
  738            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  739                auto const& t = jv[jss::transaction];
 
  740                return t[jss::TransactionType] == jss::OfferCreate &&
 
  742                    XRP(75).value().getJson(JsonOptions::none) &&
 
  744                    USD(100).value().getJson(JsonOptions::none);
 
  750            env(
offer(
"alice", CNY(700), JPY(100)),
 
  755            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  756                auto const& t = jv[jss::transaction];
 
  757                return t[jss::TransactionType] == jss::OfferCreate &&
 
  759                    JPY(100).value().getJson(JsonOptions::none) &&
 
  761                    CNY(700).value().getJson(JsonOptions::none);
 
  771            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  772                auto const& t = jv[jss::transaction];
 
  773                return t[jss::TransactionType] == jss::OfferCreate &&
 
  775                    CNY(75).value().getJson(JsonOptions::none) &&
 
  777                    JPY(100).value().getJson(JsonOptions::none);
 
  782        auto jv = wsc->invoke(
"unsubscribe", books);
 
  783        BEAST_EXPECT(jv[jss::status] == 
"success");
 
  784        if (wsc->version() == 2)
 
  787                jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  789                jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  790            BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 
  797        testcase(
"Multiple Books, Both Sides Offers In Book");
 
  798        using namespace std::chrono_literals;
 
  802        auto USD = 
Account(
"alice")[
"USD"];
 
  803        auto CNY = 
Account(
"alice")[
"CNY"];
 
  804        auto JPY = 
Account(
"alice")[
"JPY"];
 
  826                j[jss::snapshot] = 
true;
 
  828                j[jss::taker_gets][jss::currency] = 
"XRP";
 
  829                j[jss::taker_pays][jss::currency] = 
"USD";
 
  830                j[jss::taker_pays][jss::issuer] = 
Account(
"alice").
human();
 
  835                j[jss::snapshot] = 
true;
 
  837                j[jss::taker_gets][jss::currency] = 
"CNY";
 
  838                j[jss::taker_gets][jss::issuer] = 
Account(
"alice").
human();
 
  839                j[jss::taker_pays][jss::currency] = 
"JPY";
 
  840                j[jss::taker_pays][jss::issuer] = 
Account(
"alice").
human();
 
  843            auto jv = wsc->invoke(
"subscribe", books);
 
  844            if (wsc->version() == 2)
 
  847                    jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  849                    jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  850                BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
  852            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
  855                jv[jss::result].isMember(jss::asks) &&
 
  856                jv[jss::result][jss::asks].size() == 2);
 
  858                jv[jss::result].isMember(jss::bids) &&
 
  859                jv[jss::result][jss::bids].size() == 2);
 
  861                jv[jss::result][jss::asks][0u][jss::TakerGets] ==
 
  864                jv[jss::result][jss::asks][0u][jss::TakerPays] ==
 
  867                jv[jss::result][jss::asks][1u][jss::TakerGets] ==
 
  870                jv[jss::result][jss::asks][1u][jss::TakerPays] ==
 
  873                jv[jss::result][jss::bids][0u][jss::TakerGets] ==
 
  876                jv[jss::result][jss::bids][0u][jss::TakerPays] ==
 
  879                jv[jss::result][jss::bids][1u][jss::TakerGets] ==
 
  882                jv[jss::result][jss::bids][1u][jss::TakerPays] ==
 
  884            BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
 
  889            env(
offer(
"alice", 
XRP(700), USD(100)),
 
  894            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  895                auto const& t = jv[jss::transaction];
 
  896                return t[jss::TransactionType] == jss::OfferCreate &&
 
  898                    USD(100).value().getJson(JsonOptions::none) &&
 
  900                    XRP(700).value().getJson(JsonOptions::none);
 
  910            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  911                auto const& t = jv[jss::transaction];
 
  912                return t[jss::TransactionType] == jss::OfferCreate &&
 
  914                    XRP(75).value().getJson(JsonOptions::none) &&
 
  916                    USD(100).value().getJson(JsonOptions::none);
 
  922            env(
offer(
"alice", CNY(700), JPY(100)),
 
  927            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  928                auto const& t = jv[jss::transaction];
 
  929                return t[jss::TransactionType] == jss::OfferCreate &&
 
  931                    JPY(100).value().getJson(JsonOptions::none) &&
 
  933                    CNY(700).value().getJson(JsonOptions::none);
 
  943            BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
 
  944                auto const& t = jv[jss::transaction];
 
  945                return t[jss::TransactionType] == jss::OfferCreate &&
 
  947                    CNY(75).value().getJson(JsonOptions::none) &&
 
  949                    JPY(100).value().getJson(JsonOptions::none);
 
  954        auto jv = wsc->invoke(
"unsubscribe", books);
 
  955        BEAST_EXPECT(jv[jss::status] == 
"success");
 
  956        if (wsc->version() == 2)
 
  959                jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  961                jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  962            BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 
  976        env.
fund(
XRP(20000), alice, bob, gw);
 
  978        auto USD = gw[
"USD"];
 
  985                j[jss::snapshot] = 
true;
 
  986                j[jss::taker_gets][jss::currency] = 
"XRP";
 
  987                j[jss::taker_pays][jss::currency] = 
"USD";
 
  988                j[jss::taker_pays][jss::issuer] = gw.human();
 
  991            auto jv = wsc->invoke(
"subscribe", books);
 
  992            if (wsc->version() == 2)
 
  995                    jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
  997                    jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
  998                BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 1000            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
 1003                jv[jss::result].isMember(jss::offers) &&
 
 1004                jv[jss::result][jss::offers].size() == 0);
 
 1005            BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
 
 1006            BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
 
 1011        env.
trust(USD(1000), alice);
 
 1012        env.
trust(USD(1000), bob);
 
 1013        env(
pay(gw, alice, USD(100)));
 
 1014        env(
pay(gw, bob, USD(50)));
 
 1015        env(
offer(alice, 
XRP(4000), USD(10)));
 
 1020        jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1021        jvParams[jss::ledger_index] = 
"validated";
 
 1022        jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1023        jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1025        auto jv = wsc->invoke(
"book_offers", jvParams);
 
 1026        if (wsc->version() == 2)
 
 1029                jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
 1031                jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
 1032            BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 1034        auto jrr = jv[jss::result];
 
 1036        BEAST_EXPECT(jrr[jss::offers].isArray());
 
 1037        BEAST_EXPECT(jrr[jss::offers].size() == 1);
 
 1038        auto const jrOffer = jrr[jss::offers][0u];
 
 1039        BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
 
 1041            jrOffer[sfBookDirectory.fieldName] ==
 
 1043        BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == 
"0");
 
 1044        BEAST_EXPECT(jrOffer[jss::Flags] == 0);
 
 1045        BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
 
 1046        BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == 
"0");
 
 1047        BEAST_EXPECT(jrOffer[sfSequence.fieldName] == 5);
 
 1049            jrOffer[jss::TakerGets] ==
 
 1052            jrOffer[jss::TakerPays] ==
 
 1054        BEAST_EXPECT(jrOffer[jss::owner_funds] == 
"100");
 
 1055        BEAST_EXPECT(jrOffer[jss::quality] == 
"400000000");
 
 1057        using namespace std::chrono_literals;
 
 1058        BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
 
 1059            auto const& t = jval[jss::transaction];
 
 1060            return t[jss::TransactionType] == jss::OfferCreate &&
 
 1061                t[jss::TakerGets] ==
 
 1062                USD(10).value().getJson(JsonOptions::none) &&
 
 1063                t[jss::owner_funds] == 
"100" &&
 
 1064                t[jss::TakerPays] ==
 
 1065                XRP(4000).value().getJson(JsonOptions::none);
 
 1068        env(
offer(bob, 
XRP(2000), USD(5)));
 
 1071        BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
 
 1072            auto const& t = jval[jss::transaction];
 
 1073            return t[jss::TransactionType] == jss::OfferCreate &&
 
 1074                t[jss::TakerGets] ==
 
 1075                USD(5).value().getJson(JsonOptions::none) &&
 
 1076                t[jss::owner_funds] == 
"50" &&
 
 1077                t[jss::TakerPays] ==
 
 1078                XRP(2000).value().getJson(JsonOptions::none);
 
 1081        jv = wsc->invoke(
"book_offers", jvParams);
 
 1082        if (wsc->version() == 2)
 
 1085                jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
 1087                jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
 1088            BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 1090        jrr = jv[jss::result];
 
 1092        BEAST_EXPECT(jrr[jss::offers].isArray());
 
 1093        BEAST_EXPECT(jrr[jss::offers].size() == 2);
 
 1094        auto const jrNextOffer = jrr[jss::offers][1u];
 
 1095        BEAST_EXPECT(jrNextOffer[sfAccount.fieldName] == bob.human());
 
 1097            jrNextOffer[sfBookDirectory.fieldName] ==
 
 1099        BEAST_EXPECT(jrNextOffer[sfBookNode.fieldName] == 
"0");
 
 1100        BEAST_EXPECT(jrNextOffer[jss::Flags] == 0);
 
 1101        BEAST_EXPECT(jrNextOffer[sfLedgerEntryType.fieldName] == jss::Offer);
 
 1102        BEAST_EXPECT(jrNextOffer[sfOwnerNode.fieldName] == 
"0");
 
 1103        BEAST_EXPECT(jrNextOffer[sfSequence.fieldName] == 5);
 
 1105            jrNextOffer[jss::TakerGets] ==
 
 1108            jrNextOffer[jss::TakerPays] ==
 
 1110        BEAST_EXPECT(jrNextOffer[jss::owner_funds] == 
"50");
 
 1111        BEAST_EXPECT(jrNextOffer[jss::quality] == 
"400000000");
 
 1113        jv = wsc->invoke(
"unsubscribe", books);
 
 1114        if (wsc->version() == 2)
 
 1117                jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] == 
"2.0");
 
 1119                jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] == 
"2.0");
 
 1120            BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
 
 1122        BEAST_EXPECT(jv[jss::status] == 
"success");
 
 
 1304        using namespace jtx;
 
 1308        env.
fund(
XRP(10000), alice, gw);
 
 1310        auto USD = gw[
"USD"];
 
 1314            jvParams[jss::ledger_index] = 10u;
 
 1315            auto const jrr = env.
rpc(
 
 1316                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1317            BEAST_EXPECT(jrr[jss::error] == 
"lgrNotFound");
 
 1318            BEAST_EXPECT(jrr[jss::error_message] == 
"ledgerNotFound");
 
 1323            jvParams[jss::ledger_index] = 
"validated";
 
 1324            auto const jrr = env.
rpc(
 
 1325                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1326            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1328                jrr[jss::error_message] == 
"Missing field 'taker_pays'.");
 
 1333            jvParams[jss::ledger_index] = 
"validated";
 
 1335            auto const jrr = env.
rpc(
 
 1336                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1337            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1339                jrr[jss::error_message] == 
"Missing field 'taker_gets'.");
 
 1344            jvParams[jss::ledger_index] = 
"validated";
 
 1345            jvParams[jss::taker_pays] = 
"not an object";
 
 1347            auto const jrr = env.
rpc(
 
 1348                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1349            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1351                jrr[jss::error_message] ==
 
 1352                "Invalid field 'taker_pays', not object.");
 
 1357            jvParams[jss::ledger_index] = 
"validated";
 
 1359            jvParams[jss::taker_gets] = 
"not an object";
 
 1360            auto const jrr = env.
rpc(
 
 1361                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1362            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1364                jrr[jss::error_message] ==
 
 1365                "Invalid field 'taker_gets', not object.");
 
 1370            jvParams[jss::ledger_index] = 
"validated";
 
 1373            auto const jrr = env.
rpc(
 
 1374                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1375            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1377                jrr[jss::error_message] ==
 
 1378                "Missing field 'taker_pays.currency'.");
 
 1383            jvParams[jss::ledger_index] = 
"validated";
 
 1384            jvParams[jss::taker_pays][jss::currency] = 1;
 
 1386            auto const jrr = env.
rpc(
 
 1387                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1388            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1390                jrr[jss::error_message] ==
 
 1391                "Invalid field 'taker_pays.currency', not string.");
 
 1396            jvParams[jss::ledger_index] = 
"validated";
 
 1397            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1399            auto const jrr = env.
rpc(
 
 1400                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1401            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1403                jrr[jss::error_message] ==
 
 1404                "Missing field 'taker_gets.currency'.");
 
 1409            jvParams[jss::ledger_index] = 
"validated";
 
 1410            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1411            jvParams[jss::taker_gets][jss::currency] = 1;
 
 1412            auto const jrr = env.
rpc(
 
 1413                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1414            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1416                jrr[jss::error_message] ==
 
 1417                "Invalid field 'taker_gets.currency', not string.");
 
 1422            jvParams[jss::ledger_index] = 
"validated";
 
 1423            jvParams[jss::taker_pays][jss::currency] = 
"NOT_VALID";
 
 1424            jvParams[jss::taker_gets][jss::currency] = 
"XRP";
 
 1425            auto const jrr = env.
rpc(
 
 1426                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1427            BEAST_EXPECT(jrr[jss::error] == 
"srcCurMalformed");
 
 1429                jrr[jss::error_message] ==
 
 1430                "Invalid field 'taker_pays.currency', bad currency.");
 
 1435            jvParams[jss::ledger_index] = 
"validated";
 
 1436            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1437            jvParams[jss::taker_gets][jss::currency] = 
"NOT_VALID";
 
 1438            auto const jrr = env.
rpc(
 
 1439                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1440            BEAST_EXPECT(jrr[jss::error] == 
"dstAmtMalformed");
 
 1442                jrr[jss::error_message] ==
 
 1443                "Invalid field 'taker_gets.currency', bad currency.");
 
 1448            jvParams[jss::ledger_index] = 
"validated";
 
 1449            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1450            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1451            jvParams[jss::taker_gets][jss::issuer] = 1;
 
 1452            auto const jrr = env.
rpc(
 
 1453                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1454            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1456                jrr[jss::error_message] ==
 
 1457                "Invalid field 'taker_gets.issuer', not string.");
 
 1462            jvParams[jss::ledger_index] = 
"validated";
 
 1463            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1464            jvParams[jss::taker_pays][jss::issuer] = 1;
 
 1465            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1466            auto const jrr = env.
rpc(
 
 1467                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1468            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1470                jrr[jss::error_message] ==
 
 1471                "Invalid field 'taker_pays.issuer', not string.");
 
 1476            jvParams[jss::ledger_index] = 
"validated";
 
 1477            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1478            jvParams[jss::taker_pays][jss::issuer] = gw.human() + 
"DEAD";
 
 1479            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1480            auto const jrr = env.
rpc(
 
 1481                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1482            BEAST_EXPECT(jrr[jss::error] == 
"srcIsrMalformed");
 
 1484                jrr[jss::error_message] ==
 
 1485                "Invalid field 'taker_pays.issuer', bad issuer.");
 
 1490            jvParams[jss::ledger_index] = 
"validated";
 
 1491            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1493            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1494            auto const jrr = env.
rpc(
 
 1495                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1496            BEAST_EXPECT(jrr[jss::error] == 
"srcIsrMalformed");
 
 1498                jrr[jss::error_message] ==
 
 1499                "Invalid field 'taker_pays.issuer', bad issuer account one.");
 
 1504            jvParams[jss::ledger_index] = 
"validated";
 
 1505            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1506            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1507            jvParams[jss::taker_gets][jss::issuer] = gw.human() + 
"DEAD";
 
 1508            auto const jrr = env.
rpc(
 
 1509                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1510            BEAST_EXPECT(jrr[jss::error] == 
"dstIsrMalformed");
 
 1512                jrr[jss::error_message] ==
 
 1513                "Invalid field 'taker_gets.issuer', bad issuer.");
 
 1518            jvParams[jss::ledger_index] = 
"validated";
 
 1519            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1520            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1522            auto const jrr = env.
rpc(
 
 1523                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1524            BEAST_EXPECT(jrr[jss::error] == 
"dstIsrMalformed");
 
 1526                jrr[jss::error_message] ==
 
 1527                "Invalid field 'taker_gets.issuer', bad issuer account one.");
 
 1532            jvParams[jss::ledger_index] = 
"validated";
 
 1533            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1534            jvParams[jss::taker_pays][jss::issuer] = alice.human();
 
 1535            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1536            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1537            auto const jrr = env.
rpc(
 
 1538                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1539            BEAST_EXPECT(jrr[jss::error] == 
"srcIsrMalformed");
 
 1541                jrr[jss::error_message] ==
 
 1542                "Unneeded field 'taker_pays.issuer' " 
 1543                "for XRP currency specification.");
 
 1548            jvParams[jss::ledger_index] = 
"validated";
 
 1549            jvParams[jss::taker_pays][jss::currency] = 
"USD";
 
 1551            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1552            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1553            auto const jrr = env.
rpc(
 
 1554                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1555            BEAST_EXPECT(jrr[jss::error] == 
"srcIsrMalformed");
 
 1557                jrr[jss::error_message] ==
 
 1558                "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
 
 1563            jvParams[jss::ledger_index] = 
"validated";
 
 1564            jvParams[jss::taker] = 1;
 
 1565            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1566            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1567            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1568            auto const jrr = env.
rpc(
 
 1569                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1570            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1572                jrr[jss::error_message] ==
 
 1573                "Invalid field 'taker', not string.");
 
 1578            jvParams[jss::ledger_index] = 
"validated";
 
 1579            jvParams[jss::taker] = env.
master.
human() + 
"DEAD";
 
 1580            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1581            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1582            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1583            auto const jrr = env.
rpc(
 
 1584                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1585            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1586            BEAST_EXPECT(jrr[jss::error_message] == 
"Invalid field 'taker'.");
 
 1591            jvParams[jss::ledger_index] = 
"validated";
 
 1593            jvParams[jss::taker_pays][jss::currency] = 
"USD";
 
 1594            jvParams[jss::taker_pays][jss::issuer] = gw.human();
 
 1595            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1596            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1597            auto const jrr = env.
rpc(
 
 1598                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1599            BEAST_EXPECT(jrr[jss::error] == 
"badMarket");
 
 1600            BEAST_EXPECT(jrr[jss::error_message] == 
"No such market.");
 
 1605            jvParams[jss::ledger_index] = 
"validated";
 
 1607            jvParams[jss::limit] = 
"0";  
 
 1608            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1609            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1610            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1611            auto const jrr = env.
rpc(
 
 1612                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1613            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1615                jrr[jss::error_message] ==
 
 1616                "Invalid field 'limit', not unsigned integer.");
 
 1621            jvParams[jss::ledger_index] = 
"validated";
 
 1623            jvParams[jss::limit] = 0;  
 
 1624            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1625            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1626            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1627            auto const jrr = env.
rpc(
 
 1628                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1629            BEAST_EXPECT(jrr[jss::error] == 
"invalidParams");
 
 1630            BEAST_EXPECT(jrr[jss::error_message] == 
"Invalid field 'limit'.");
 
 1635            jvParams[jss::ledger_index] = 
"validated";
 
 1636            jvParams[jss::taker_pays][jss::currency] = 
"USD";
 
 1637            jvParams[jss::taker_pays][jss::issuer] = gw.human();
 
 1638            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1639            auto const jrr = env.
rpc(
 
 1640                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1641            BEAST_EXPECT(jrr[jss::error] == 
"dstIsrMalformed");
 
 1643                jrr[jss::error_message] ==
 
 1644                "Invalid field 'taker_gets.issuer', " 
 1645                "expected non-XRP issuer.");
 
 1650            jvParams[jss::ledger_index] = 
"validated";
 
 1651            jvParams[jss::taker_pays][jss::currency] = 
"USD";
 
 1652            jvParams[jss::taker_pays][jss::issuer] = gw.human();
 
 1653            jvParams[jss::taker_gets][jss::currency] = 
"XRP";
 
 1654            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1655            auto const jrr = env.
rpc(
 
 1656                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1657            BEAST_EXPECT(jrr[jss::error] == 
"dstIsrMalformed");
 
 1659                jrr[jss::error_message] ==
 
 1660                "Unneeded field 'taker_gets.issuer' " 
 1661                "for XRP currency specification.");
 
 1665            jvParams[jss::ledger_index] = 
"validated";
 
 1666            jvParams[jss::taker_pays][jss::currency] = 
"USD";
 
 1667            jvParams[jss::taker_pays][jss::issuer] = gw.human();
 
 1668            jvParams[jss::taker_gets][jss::currency] = 
"EUR";
 
 1669            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1670            jvParams[jss::domain] = 
"badString";
 
 1671            auto const jrr = env.
rpc(
 
 1672                "json", 
"book_offers", 
to_string(jvParams))[jss::result];
 
 1673            BEAST_EXPECT(jrr[jss::error] == 
"domainMalformed");
 
 1674            BEAST_EXPECT(jrr[jss::error_message] == 
"Unable to parse domain.");
 
 
 1729        using namespace jtx;
 
 1733            featureCredentials | featurePermissionedDEX};
 
 1737        auto const alice = permDex.
alice;
 
 1738        auto const bob = permDex.
bob;
 
 1739        auto const carol = permDex.
carol;
 
 1740        auto const domainID = permDex.
domainID;
 
 1741        auto const gw = permDex.
gw;
 
 1742        auto const USD = permDex.
USD;
 
 1749        auto checkBookOffers = [&](
Json::Value const& jrr) {
 
 1750            BEAST_EXPECT(jrr[jss::offers].isArray());
 
 1751            BEAST_EXPECT(jrr[jss::offers].size() == 1);
 
 1752            auto const jrOffer = jrr[jss::offers][0u];
 
 1753            BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
 
 1755                jrOffer[sfBookDirectory.fieldName] ==
 
 1757            BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == 
"0");
 
 1758            BEAST_EXPECT(jrOffer[jss::Flags] == 0);
 
 1759            BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
 
 1760            BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == 
"0");
 
 1762                jrOffer[jss::TakerGets] ==
 
 1765                jrOffer[jss::TakerPays] ==
 
 1768                jrOffer[sfDomainID.jsonName].asString() == 
to_string(domainID));
 
 1775            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1776            jvParams[jss::ledger_index] = 
"validated";
 
 1777            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1778            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1780            auto jv = wsc->invoke(
"book_offers", jvParams);
 
 1781            auto jrr = jv[jss::result];
 
 1782            BEAST_EXPECT(jrr[jss::offers].isArray());
 
 1783            BEAST_EXPECT(jrr[jss::offers].size() == 0);
 
 1788                jv[jss::result].isMember(jss::offers) &&
 
 1789                jv[jss::result][jss::offers].size() == 1);
 
 1791                jv[jss::result][jss::offers][0u][jss::TakerGets] ==
 
 1794                jv[jss::result][jss::offers][0u][jss::TakerPays] ==
 
 1797                jv[jss::result][jss::offers][0u][sfDomainID.jsonName]
 
 1805            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1806            jvParams[jss::ledger_index] = 
"validated";
 
 1807            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1808            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1809            jvParams[jss::domain] = 
to_string(domainID);
 
 1811            auto jv = wsc->invoke(
"book_offers", jvParams);
 
 1812            auto jrr = jv[jss::result];
 
 1813            checkBookOffers(jrr);
 
 1822                j[jss::snapshot] = 
true;
 
 1823                j[jss::taker_pays][jss::currency] = 
"XRP";
 
 1824                j[jss::taker_gets][jss::currency] = 
"USD";
 
 1825                j[jss::taker_gets][jss::issuer] = gw.human();
 
 1829            auto jv = wsc->invoke(
"subscribe", books);
 
 1830            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
 1841                j[jss::snapshot] = 
true;
 
 1842                j[jss::taker_pays][jss::currency] = 
"XRP";
 
 1843                j[jss::taker_gets][jss::currency] = 
"USD";
 
 1844                j[jss::taker_gets][jss::issuer] = gw.human();
 
 1847            auto jv = wsc->invoke(
"subscribe", books);
 
 1848            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
 1851                jv[jss::result].isMember(jss::offers) &&
 
 1852                jv[jss::result][jss::offers].size() == 0);
 
 
 1860        using namespace jtx;
 
 1864            featureCredentials | featurePermissionedDEX};
 
 1868        auto const alice = permDex.
alice;
 
 1869        auto const bob = permDex.
bob;
 
 1870        auto const carol = permDex.
carol;
 
 1871        auto const domainID = permDex.
domainID;
 
 1872        auto const gw = permDex.
gw;
 
 1873        auto const USD = permDex.
USD;
 
 1877        env(
offer(alice, 
XRP(10), USD(10)),
 
 1882        auto checkBookOffers = [&](
Json::Value const& jrr) {
 
 1883            BEAST_EXPECT(jrr[jss::offers].isArray());
 
 1884            BEAST_EXPECT(jrr[jss::offers].size() == 1);
 
 1885            auto const jrOffer = jrr[jss::offers][0u];
 
 1886            BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
 
 1888                jrOffer[sfBookDirectory.fieldName] ==
 
 1890            BEAST_EXPECT(jrOffer[sfBookNode.fieldName] == 
"0");
 
 1891            BEAST_EXPECT(jrOffer[jss::Flags] == 
lsfHybrid);
 
 1892            BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
 
 1893            BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] == 
"0");
 
 1895                jrOffer[jss::TakerGets] ==
 
 1898                jrOffer[jss::TakerPays] ==
 
 1901                jrOffer[sfDomainID.jsonName].asString() == 
to_string(domainID));
 
 1902            BEAST_EXPECT(jrOffer[sfAdditionalBooks.jsonName].size() == 1);
 
 1909            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1910            jvParams[jss::ledger_index] = 
"validated";
 
 1911            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1912            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1914            auto jv = wsc->invoke(
"book_offers", jvParams);
 
 1915            auto jrr = jv[jss::result];
 
 1916            checkBookOffers(jrr);
 
 1921                jv[jss::result].isMember(jss::offers) &&
 
 1922                jv[jss::result][jss::offers].size() == 1);
 
 1924                jv[jss::result][jss::offers][0u][jss::TakerGets] ==
 
 1927                jv[jss::result][jss::offers][0u][jss::TakerPays] ==
 
 1930                jv[jss::result][jss::offers][0u][sfDomainID.jsonName]
 
 1938            jvParams[jss::taker_pays][jss::currency] = 
"XRP";
 
 1939            jvParams[jss::ledger_index] = 
"validated";
 
 1940            jvParams[jss::taker_gets][jss::currency] = 
"USD";
 
 1941            jvParams[jss::taker_gets][jss::issuer] = gw.human();
 
 1942            jvParams[jss::domain] = 
to_string(domainID);
 
 1944            auto jv = wsc->invoke(
"book_offers", jvParams);
 
 1945            auto jrr = jv[jss::result];
 
 1946            checkBookOffers(jrr);
 
 1955                j[jss::snapshot] = 
true;
 
 1956                j[jss::taker_pays][jss::currency] = 
"XRP";
 
 1957                j[jss::taker_gets][jss::currency] = 
"USD";
 
 1958                j[jss::taker_gets][jss::issuer] = gw.human();
 
 1962            auto jv = wsc->invoke(
"subscribe", books);
 
 1963            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))
 
 1968            auto unsubJv = wsc->invoke(
"unsubscribe", books);
 
 1969            if (wsc->version() == 2)
 
 1970                BEAST_EXPECT(unsubJv[jss::status] == 
"success");
 
 1979                j[jss::snapshot] = 
true;
 
 1980                j[jss::taker_pays][jss::currency] = 
"XRP";
 
 1981                j[jss::taker_gets][jss::currency] = 
"USD";
 
 1982                j[jss::taker_gets][jss::issuer] = gw.human();
 
 1985            auto jv = wsc->invoke(
"subscribe", books);
 
 1986            if (!BEAST_EXPECT(jv[jss::status] == 
"success"))