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"))