19#include <test/jtx/WSClient.h>
21#include <xrpld/rpc/detail/Tuning.h>
23#include <xrpl/beast/unit_test.h>
24#include <xrpl/protocol/Indexes.h>
25#include <xrpl/protocol/jss.h>
39 auto key = view->succ(uBookBase, uBookEnd);
42 auto sleOfferDir = view->read(
keylet::page(key.value()));
44 unsigned int bookEntry;
46 *view, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex);
48 dir =
to_string(sleOffer->getFieldH256(sfBookDirectory));
58 using namespace std::chrono_literals;
62 auto USD =
Account(
"alice")[
"USD"];
71 j[jss::snapshot] =
true;
72 j[jss::taker_gets][jss::currency] =
"XRP";
73 j[jss::taker_pays][jss::currency] =
"USD";
74 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
77 auto jv = wsc->invoke(
"subscribe", books);
78 if (wsc->version() == 2)
81 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
83 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
84 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
86 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
89 jv[jss::result].isMember(jss::offers) &&
90 jv[jss::result][jss::offers].size() == 0);
91 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
92 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
97 env(
offer(
"alice",
XRP(700), USD(100)),
102 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
103 auto const& t = jv[jss::transaction];
104 return t[jss::TransactionType] == jss::OfferCreate &&
106 USD(100).value().getJson(JsonOptions::none) &&
108 XRP(700).value().getJson(JsonOptions::none);
116 BEAST_EXPECT(!wsc->getMsg(10ms));
120 auto jv = wsc->invoke(
"unsubscribe", books);
121 BEAST_EXPECT(jv[jss::status] ==
"success");
122 if (wsc->version() == 2)
125 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
127 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
128 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
135 testcase(
"One Side Offers In Book");
136 using namespace std::chrono_literals;
140 auto USD =
Account(
"alice")[
"USD"];
156 j[jss::snapshot] =
true;
157 j[jss::taker_gets][jss::currency] =
"XRP";
158 j[jss::taker_pays][jss::currency] =
"USD";
159 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
162 auto jv = wsc->invoke(
"subscribe", books);
163 if (wsc->version() == 2)
166 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
168 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
169 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
171 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
174 jv[jss::result].isMember(jss::offers) &&
175 jv[jss::result][jss::offers].size() == 1);
177 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
180 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
182 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
183 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
188 env(
offer(
"alice",
XRP(700), USD(100)),
193 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
194 auto const& t = jv[jss::transaction];
195 return t[jss::TransactionType] == jss::OfferCreate &&
197 USD(100).value().getJson(JsonOptions::none) &&
199 XRP(700).value().getJson(JsonOptions::none);
207 BEAST_EXPECT(!wsc->getMsg(10ms));
211 auto jv = wsc->invoke(
"unsubscribe", books);
212 BEAST_EXPECT(jv[jss::status] ==
"success");
213 if (wsc->version() == 2)
216 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
218 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
219 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
227 using namespace std::chrono_literals;
231 auto USD =
Account(
"alice")[
"USD"];
240 j[jss::snapshot] =
true;
242 j[jss::taker_gets][jss::currency] =
"XRP";
243 j[jss::taker_pays][jss::currency] =
"USD";
244 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
247 auto jv = wsc->invoke(
"subscribe", books);
248 if (wsc->version() == 2)
251 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
253 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
254 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
256 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
259 jv[jss::result].isMember(jss::asks) &&
260 jv[jss::result][jss::asks].size() == 0);
262 jv[jss::result].isMember(jss::bids) &&
263 jv[jss::result][jss::bids].size() == 0);
264 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
269 env(
offer(
"alice",
XRP(700), USD(100)),
274 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
275 auto const& t = jv[jss::transaction];
276 return t[jss::TransactionType] == jss::OfferCreate &&
278 USD(100).value().getJson(JsonOptions::none) &&
280 XRP(700).value().getJson(JsonOptions::none);
290 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
291 auto const& t = jv[jss::transaction];
292 return t[jss::TransactionType] == jss::OfferCreate &&
294 XRP(75).value().getJson(JsonOptions::none) &&
296 USD(100).value().getJson(JsonOptions::none);
301 auto jv = wsc->invoke(
"unsubscribe", books);
302 BEAST_EXPECT(jv[jss::status] ==
"success");
303 if (wsc->version() == 2)
306 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
308 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
309 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
316 testcase(
"Both Sides Offers In Book");
317 using namespace std::chrono_literals;
321 auto USD =
Account(
"alice")[
"USD"];
337 j[jss::snapshot] =
true;
339 j[jss::taker_gets][jss::currency] =
"XRP";
340 j[jss::taker_pays][jss::currency] =
"USD";
341 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
344 auto jv = wsc->invoke(
"subscribe", books);
345 if (wsc->version() == 2)
348 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
350 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
351 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
353 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
356 jv[jss::result].isMember(jss::asks) &&
357 jv[jss::result][jss::asks].size() == 1);
359 jv[jss::result].isMember(jss::bids) &&
360 jv[jss::result][jss::bids].size() == 1);
362 jv[jss::result][jss::asks][0u][jss::TakerGets] ==
365 jv[jss::result][jss::asks][0u][jss::TakerPays] ==
368 jv[jss::result][jss::bids][0u][jss::TakerGets] ==
371 jv[jss::result][jss::bids][0u][jss::TakerPays] ==
373 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
378 env(
offer(
"alice",
XRP(700), USD(100)),
383 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
384 auto const& t = jv[jss::transaction];
385 return t[jss::TransactionType] == jss::OfferCreate &&
387 USD(100).value().getJson(JsonOptions::none) &&
389 XRP(700).value().getJson(JsonOptions::none);
399 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
400 auto const& t = jv[jss::transaction];
401 return t[jss::TransactionType] == jss::OfferCreate &&
403 XRP(75).value().getJson(JsonOptions::none) &&
405 USD(100).value().getJson(JsonOptions::none);
410 auto jv = wsc->invoke(
"unsubscribe", books);
411 BEAST_EXPECT(jv[jss::status] ==
"success");
412 if (wsc->version() == 2)
415 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
417 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
418 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
425 testcase(
"Multiple Books, One Side Empty");
426 using namespace std::chrono_literals;
430 auto USD =
Account(
"alice")[
"USD"];
431 auto CNY =
Account(
"alice")[
"CNY"];
432 auto JPY =
Account(
"alice")[
"JPY"];
441 j[jss::snapshot] =
true;
442 j[jss::taker_gets][jss::currency] =
"XRP";
443 j[jss::taker_pays][jss::currency] =
"USD";
444 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
448 j[jss::snapshot] =
true;
449 j[jss::taker_gets][jss::currency] =
"CNY";
450 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
451 j[jss::taker_pays][jss::currency] =
"JPY";
452 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
455 auto jv = wsc->invoke(
"subscribe", books);
456 if (wsc->version() == 2)
459 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
461 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
462 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
464 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
467 jv[jss::result].isMember(jss::offers) &&
468 jv[jss::result][jss::offers].size() == 0);
469 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
470 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
475 env(
offer(
"alice",
XRP(700), USD(100)),
480 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
481 auto const& t = jv[jss::transaction];
482 return t[jss::TransactionType] == jss::OfferCreate &&
484 USD(100).value().getJson(JsonOptions::none) &&
486 XRP(700).value().getJson(JsonOptions::none);
494 BEAST_EXPECT(!wsc->getMsg(10ms));
499 env(
offer(
"alice", CNY(700), JPY(100)),
504 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
505 auto const& t = jv[jss::transaction];
506 return t[jss::TransactionType] == jss::OfferCreate &&
508 JPY(100).value().getJson(JsonOptions::none) &&
510 CNY(700).value().getJson(JsonOptions::none);
518 BEAST_EXPECT(!wsc->getMsg(10ms));
522 auto jv = wsc->invoke(
"unsubscribe", books);
523 BEAST_EXPECT(jv[jss::status] ==
"success");
524 if (wsc->version() == 2)
527 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
529 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
530 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
537 testcase(
"Multiple Books, One Side Offers In Book");
538 using namespace std::chrono_literals;
542 auto USD =
Account(
"alice")[
"USD"];
543 auto CNY =
Account(
"alice")[
"CNY"];
544 auto JPY =
Account(
"alice")[
"JPY"];
566 j[jss::snapshot] =
true;
567 j[jss::taker_gets][jss::currency] =
"XRP";
568 j[jss::taker_pays][jss::currency] =
"USD";
569 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
573 j[jss::snapshot] =
true;
574 j[jss::taker_gets][jss::currency] =
"CNY";
575 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
576 j[jss::taker_pays][jss::currency] =
"JPY";
577 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
580 auto jv = wsc->invoke(
"subscribe", books);
581 if (wsc->version() == 2)
584 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
586 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
587 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
589 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
592 jv[jss::result].isMember(jss::offers) &&
593 jv[jss::result][jss::offers].size() == 2);
595 jv[jss::result][jss::offers][0u][jss::TakerGets] ==
598 jv[jss::result][jss::offers][0u][jss::TakerPays] ==
601 jv[jss::result][jss::offers][1u][jss::TakerGets] ==
604 jv[jss::result][jss::offers][1u][jss::TakerPays] ==
606 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
607 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
612 env(
offer(
"alice",
XRP(700), USD(100)),
617 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
618 auto const& t = jv[jss::transaction];
619 return t[jss::TransactionType] == jss::OfferCreate &&
621 USD(100).value().getJson(JsonOptions::none) &&
623 XRP(700).value().getJson(JsonOptions::none);
631 BEAST_EXPECT(!wsc->getMsg(10ms));
636 env(
offer(
"alice", CNY(700), JPY(100)),
641 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
642 auto const& t = jv[jss::transaction];
643 return t[jss::TransactionType] == jss::OfferCreate &&
645 JPY(100).value().getJson(JsonOptions::none) &&
647 CNY(700).value().getJson(JsonOptions::none);
655 BEAST_EXPECT(!wsc->getMsg(10ms));
659 auto jv = wsc->invoke(
"unsubscribe", books);
660 BEAST_EXPECT(jv[jss::status] ==
"success");
661 if (wsc->version() == 2)
664 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
666 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
667 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
674 testcase(
"Multiple Books, Both Sides Empty Book");
675 using namespace std::chrono_literals;
679 auto USD =
Account(
"alice")[
"USD"];
680 auto CNY =
Account(
"alice")[
"CNY"];
681 auto JPY =
Account(
"alice")[
"JPY"];
690 j[jss::snapshot] =
true;
692 j[jss::taker_gets][jss::currency] =
"XRP";
693 j[jss::taker_pays][jss::currency] =
"USD";
694 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
698 j[jss::snapshot] =
true;
700 j[jss::taker_gets][jss::currency] =
"CNY";
701 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
702 j[jss::taker_pays][jss::currency] =
"JPY";
703 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
706 auto jv = wsc->invoke(
"subscribe", books);
707 if (wsc->version() == 2)
710 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
712 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
713 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
715 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
718 jv[jss::result].isMember(jss::asks) &&
719 jv[jss::result][jss::asks].size() == 0);
721 jv[jss::result].isMember(jss::bids) &&
722 jv[jss::result][jss::bids].size() == 0);
723 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
728 env(
offer(
"alice",
XRP(700), USD(100)),
733 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
734 auto const& t = jv[jss::transaction];
735 return t[jss::TransactionType] == jss::OfferCreate &&
737 USD(100).value().getJson(JsonOptions::none) &&
739 XRP(700).value().getJson(JsonOptions::none);
749 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
750 auto const& t = jv[jss::transaction];
751 return t[jss::TransactionType] == jss::OfferCreate &&
753 XRP(75).value().getJson(JsonOptions::none) &&
755 USD(100).value().getJson(JsonOptions::none);
761 env(
offer(
"alice", CNY(700), JPY(100)),
766 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
767 auto const& t = jv[jss::transaction];
768 return t[jss::TransactionType] == jss::OfferCreate &&
770 JPY(100).value().getJson(JsonOptions::none) &&
772 CNY(700).value().getJson(JsonOptions::none);
782 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
783 auto const& t = jv[jss::transaction];
784 return t[jss::TransactionType] == jss::OfferCreate &&
786 CNY(75).value().getJson(JsonOptions::none) &&
788 JPY(100).value().getJson(JsonOptions::none);
793 auto jv = wsc->invoke(
"unsubscribe", books);
794 BEAST_EXPECT(jv[jss::status] ==
"success");
795 if (wsc->version() == 2)
798 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
800 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
801 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
808 testcase(
"Multiple Books, Both Sides Offers In Book");
809 using namespace std::chrono_literals;
813 auto USD =
Account(
"alice")[
"USD"];
814 auto CNY =
Account(
"alice")[
"CNY"];
815 auto JPY =
Account(
"alice")[
"JPY"];
837 j[jss::snapshot] =
true;
839 j[jss::taker_gets][jss::currency] =
"XRP";
840 j[jss::taker_pays][jss::currency] =
"USD";
841 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
846 j[jss::snapshot] =
true;
848 j[jss::taker_gets][jss::currency] =
"CNY";
849 j[jss::taker_gets][jss::issuer] =
Account(
"alice").
human();
850 j[jss::taker_pays][jss::currency] =
"JPY";
851 j[jss::taker_pays][jss::issuer] =
Account(
"alice").
human();
854 auto jv = wsc->invoke(
"subscribe", books);
855 if (wsc->version() == 2)
858 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
860 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
861 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
863 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
866 jv[jss::result].isMember(jss::asks) &&
867 jv[jss::result][jss::asks].size() == 2);
869 jv[jss::result].isMember(jss::bids) &&
870 jv[jss::result][jss::bids].size() == 2);
872 jv[jss::result][jss::asks][0u][jss::TakerGets] ==
875 jv[jss::result][jss::asks][0u][jss::TakerPays] ==
878 jv[jss::result][jss::asks][1u][jss::TakerGets] ==
881 jv[jss::result][jss::asks][1u][jss::TakerPays] ==
884 jv[jss::result][jss::bids][0u][jss::TakerGets] ==
887 jv[jss::result][jss::bids][0u][jss::TakerPays] ==
890 jv[jss::result][jss::bids][1u][jss::TakerGets] ==
893 jv[jss::result][jss::bids][1u][jss::TakerPays] ==
895 BEAST_EXPECT(!jv[jss::result].isMember(jss::offers));
900 env(
offer(
"alice",
XRP(700), USD(100)),
905 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
906 auto const& t = jv[jss::transaction];
907 return t[jss::TransactionType] == jss::OfferCreate &&
909 USD(100).value().getJson(JsonOptions::none) &&
911 XRP(700).value().getJson(JsonOptions::none);
921 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
922 auto const& t = jv[jss::transaction];
923 return t[jss::TransactionType] == jss::OfferCreate &&
925 XRP(75).value().getJson(JsonOptions::none) &&
927 USD(100).value().getJson(JsonOptions::none);
933 env(
offer(
"alice", CNY(700), JPY(100)),
938 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
939 auto const& t = jv[jss::transaction];
940 return t[jss::TransactionType] == jss::OfferCreate &&
942 JPY(100).value().getJson(JsonOptions::none) &&
944 CNY(700).value().getJson(JsonOptions::none);
954 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
955 auto const& t = jv[jss::transaction];
956 return t[jss::TransactionType] == jss::OfferCreate &&
958 CNY(75).value().getJson(JsonOptions::none) &&
960 JPY(100).value().getJson(JsonOptions::none);
965 auto jv = wsc->invoke(
"unsubscribe", books);
966 BEAST_EXPECT(jv[jss::status] ==
"success");
967 if (wsc->version() == 2)
970 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
972 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
973 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
987 env.
fund(
XRP(20000), alice, bob, gw);
989 auto USD = gw[
"USD"];
996 j[jss::snapshot] =
true;
997 j[jss::taker_gets][jss::currency] =
"XRP";
998 j[jss::taker_pays][jss::currency] =
"USD";
999 j[jss::taker_pays][jss::issuer] = gw.human();
1002 auto jv = wsc->invoke(
"subscribe", books);
1003 if (wsc->version() == 2)
1006 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1008 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1009 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1011 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1014 jv[jss::result].isMember(jss::offers) &&
1015 jv[jss::result][jss::offers].size() == 0);
1016 BEAST_EXPECT(!jv[jss::result].isMember(jss::asks));
1017 BEAST_EXPECT(!jv[jss::result].isMember(jss::bids));
1022 env.
trust(USD(1000), alice);
1023 env.
trust(USD(1000), bob);
1024 env(
pay(gw, alice, USD(100)));
1025 env(
pay(gw, bob, USD(50)));
1026 env(
offer(alice,
XRP(4000), USD(10)));
1031 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1032 jvParams[jss::ledger_index] =
"validated";
1033 jvParams[jss::taker_gets][jss::currency] =
"USD";
1034 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1036 auto jv = wsc->invoke(
"book_offers", jvParams);
1037 if (wsc->version() == 2)
1040 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1042 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1043 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1045 auto jrr = jv[jss::result];
1047 BEAST_EXPECT(jrr[jss::offers].isArray());
1048 BEAST_EXPECT(jrr[jss::offers].size() == 1);
1049 auto const jrOffer = jrr[jss::offers][0u];
1050 BEAST_EXPECT(jrOffer[sfAccount.fieldName] == alice.human());
1052 jrOffer[sfBookDirectory.fieldName] ==
1054 BEAST_EXPECT(jrOffer[sfBookNode.fieldName] ==
"0");
1055 BEAST_EXPECT(jrOffer[jss::Flags] == 0);
1056 BEAST_EXPECT(jrOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1057 BEAST_EXPECT(jrOffer[sfOwnerNode.fieldName] ==
"0");
1058 BEAST_EXPECT(jrOffer[sfSequence.fieldName] == 5);
1060 jrOffer[jss::TakerGets] ==
1063 jrOffer[jss::TakerPays] ==
1065 BEAST_EXPECT(jrOffer[jss::owner_funds] ==
"100");
1066 BEAST_EXPECT(jrOffer[jss::quality] ==
"400000000");
1068 using namespace std::chrono_literals;
1069 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
1070 auto const& t = jval[jss::transaction];
1071 return t[jss::TransactionType] == jss::OfferCreate &&
1072 t[jss::TakerGets] ==
1073 USD(10).value().getJson(JsonOptions::none) &&
1074 t[jss::owner_funds] ==
"100" &&
1075 t[jss::TakerPays] ==
1076 XRP(4000).value().getJson(JsonOptions::none);
1079 env(
offer(bob,
XRP(2000), USD(5)));
1082 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jval) {
1083 auto const& t = jval[jss::transaction];
1084 return t[jss::TransactionType] == jss::OfferCreate &&
1085 t[jss::TakerGets] ==
1086 USD(5).value().getJson(JsonOptions::none) &&
1087 t[jss::owner_funds] ==
"50" &&
1088 t[jss::TakerPays] ==
1089 XRP(2000).value().getJson(JsonOptions::none);
1092 jv = wsc->invoke(
"book_offers", jvParams);
1093 if (wsc->version() == 2)
1096 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1098 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1099 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1101 jrr = jv[jss::result];
1103 BEAST_EXPECT(jrr[jss::offers].isArray());
1104 BEAST_EXPECT(jrr[jss::offers].size() == 2);
1105 auto const jrNextOffer = jrr[jss::offers][1u];
1106 BEAST_EXPECT(jrNextOffer[sfAccount.fieldName] == bob.human());
1108 jrNextOffer[sfBookDirectory.fieldName] ==
1110 BEAST_EXPECT(jrNextOffer[sfBookNode.fieldName] ==
"0");
1111 BEAST_EXPECT(jrNextOffer[jss::Flags] == 0);
1112 BEAST_EXPECT(jrNextOffer[sfLedgerEntryType.fieldName] == jss::Offer);
1113 BEAST_EXPECT(jrNextOffer[sfOwnerNode.fieldName] ==
"0");
1114 BEAST_EXPECT(jrNextOffer[sfSequence.fieldName] == 5);
1116 jrNextOffer[jss::TakerGets] ==
1119 jrNextOffer[jss::TakerPays] ==
1121 BEAST_EXPECT(jrNextOffer[jss::owner_funds] ==
"50");
1122 BEAST_EXPECT(jrNextOffer[jss::quality] ==
"400000000");
1124 jv = wsc->invoke(
"unsubscribe", books);
1125 if (wsc->version() == 2)
1128 jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
1130 jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
1131 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
1133 BEAST_EXPECT(jv[jss::status] ==
"success");
1144 auto maybeJv = wsc->getMsg(timeout);
1149 if (!(*maybeJv).isMember(jss::transaction))
1151 auto const& t = (*maybeJv)[jss::transaction];
1152 if (t[jss::TransactionType] != jss::OfferCreate ||
1157 return wsc->getMsg(timeout) == std::nullopt;
1163 testcase(
"Crossing single book offer");
1169 using namespace jtx;
1176 auto const gw =
Account(
"gateway");
1177 auto const alice =
Account(
"alice");
1178 auto const bob =
Account(
"bob");
1179 auto const charlie =
Account(
"charlie");
1180 auto const USD = gw[
"USD"];
1182 env.
fund(
XRP(1000000), gw, alice, bob, charlie);
1185 env(
trust(alice, USD(500)));
1186 env(
trust(bob, USD(500)));
1189 env(
pay(gw, alice, USD(500)));
1190 env(
pay(gw, bob, USD(500)));
1194 env(
offer(alice,
XRP(500), USD(500)));
1195 env(
offer(bob,
XRP(500), USD(500)));
1205 j[jss::snapshot] =
false;
1206 j[jss::taker_gets][jss::currency] =
"XRP";
1207 j[jss::taker_pays][jss::currency] =
"USD";
1208 j[jss::taker_pays][jss::issuer] = gw.human();
1211 auto jv = wsc->invoke(
"subscribe", books);
1212 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1217 env(
offer(charlie, USD(1000),
XRP(1000)));
1220 using namespace std::chrono_literals;
1224 auto jv = wsc->invoke(
"unsubscribe", books);
1225 BEAST_EXPECT(jv[jss::status] ==
"success");
1231 testcase(
"Crossing multi-book offer");
1237 using namespace jtx;
1246 auto const gw =
Account(
"gateway");
1247 auto const alice =
Account(
"alice");
1248 auto const bob =
Account(
"bob");
1249 auto const charlie =
Account(
"charlie");
1250 auto const USD = gw[
"USD"];
1251 auto const EUR = gw[
"EUR"];
1253 env.
fund(
XRP(1000000), gw, alice, bob, charlie);
1256 for (
auto const& account : {alice, bob, charlie})
1258 for (
auto const& iou : {USD, EUR})
1260 env(
trust(account, iou(1)));
1265 env(
pay(gw, alice, USD(1)));
1266 env(
pay(gw, charlie, EUR(1)));
1269 env(
offer(alice,
XRP(100), USD(1)));
1281 j[jss::snapshot] =
false;
1282 j[jss::taker_gets][jss::currency] =
"XRP";
1283 j[jss::taker_pays][jss::currency] =
"USD";
1284 j[jss::taker_pays][jss::issuer] = gw.human();
1289 j[jss::snapshot] =
false;
1290 j[jss::taker_gets][jss::currency] =
"EUR";
1291 j[jss::taker_gets][jss::issuer] = gw.human();
1292 j[jss::taker_pays][jss::currency] =
"XRP";
1295 auto jv = wsc->invoke(
"subscribe", books);
1296 if (!BEAST_EXPECT(jv[jss::status] ==
"success"))
1301 env(
offer(charlie, USD(1), EUR(1)));
1303 using namespace std::chrono_literals;
1307 auto jv = wsc->invoke(
"unsubscribe", books);
1308 BEAST_EXPECT(jv[jss::status] ==
"success");
1315 using namespace jtx;
1319 env.
fund(
XRP(10000), alice, gw);
1321 auto USD = gw[
"USD"];
1325 jvParams[jss::ledger_index] = 10u;
1326 auto const jrr = env.
rpc(
1327 "json",
"book_offers",
to_string(jvParams))[jss::result];
1328 BEAST_EXPECT(jrr[jss::error] ==
"lgrNotFound");
1329 BEAST_EXPECT(jrr[jss::error_message] ==
"ledgerNotFound");
1334 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_pays'.");
1344 jvParams[jss::ledger_index] =
"validated";
1346 auto const jrr = env.
rpc(
1347 "json",
"book_offers",
to_string(jvParams))[jss::result];
1348 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1350 jrr[jss::error_message] ==
"Missing field 'taker_gets'.");
1355 jvParams[jss::ledger_index] =
"validated";
1356 jvParams[jss::taker_pays] =
"not an object";
1358 auto const jrr = env.
rpc(
1359 "json",
"book_offers",
to_string(jvParams))[jss::result];
1360 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1362 jrr[jss::error_message] ==
1363 "Invalid field 'taker_pays', not object.");
1368 jvParams[jss::ledger_index] =
"validated";
1370 jvParams[jss::taker_gets] =
"not an object";
1371 auto const jrr = env.
rpc(
1372 "json",
"book_offers",
to_string(jvParams))[jss::result];
1373 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1375 jrr[jss::error_message] ==
1376 "Invalid field 'taker_gets', not object.");
1381 jvParams[jss::ledger_index] =
"validated";
1384 auto const jrr = env.
rpc(
1385 "json",
"book_offers",
to_string(jvParams))[jss::result];
1386 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1388 jrr[jss::error_message] ==
1389 "Missing field 'taker_pays.currency'.");
1394 jvParams[jss::ledger_index] =
"validated";
1395 jvParams[jss::taker_pays][jss::currency] = 1;
1397 auto const jrr = env.
rpc(
1398 "json",
"book_offers",
to_string(jvParams))[jss::result];
1399 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1401 jrr[jss::error_message] ==
1402 "Invalid field 'taker_pays.currency', not string.");
1407 jvParams[jss::ledger_index] =
"validated";
1408 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1410 auto const jrr = env.
rpc(
1411 "json",
"book_offers",
to_string(jvParams))[jss::result];
1412 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1414 jrr[jss::error_message] ==
1415 "Missing field 'taker_gets.currency'.");
1420 jvParams[jss::ledger_index] =
"validated";
1421 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1422 jvParams[jss::taker_gets][jss::currency] = 1;
1423 auto const jrr = env.
rpc(
1424 "json",
"book_offers",
to_string(jvParams))[jss::result];
1425 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1427 jrr[jss::error_message] ==
1428 "Invalid field 'taker_gets.currency', not string.");
1433 jvParams[jss::ledger_index] =
"validated";
1434 jvParams[jss::taker_pays][jss::currency] =
"NOT_VALID";
1435 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1436 auto const jrr = env.
rpc(
1437 "json",
"book_offers",
to_string(jvParams))[jss::result];
1438 BEAST_EXPECT(jrr[jss::error] ==
"srcCurMalformed");
1440 jrr[jss::error_message] ==
1441 "Invalid field 'taker_pays.currency', bad currency.");
1446 jvParams[jss::ledger_index] =
"validated";
1447 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1448 jvParams[jss::taker_gets][jss::currency] =
"NOT_VALID";
1449 auto const jrr = env.
rpc(
1450 "json",
"book_offers",
to_string(jvParams))[jss::result];
1451 BEAST_EXPECT(jrr[jss::error] ==
"dstAmtMalformed");
1453 jrr[jss::error_message] ==
1454 "Invalid field 'taker_gets.currency', bad currency.");
1459 jvParams[jss::ledger_index] =
"validated";
1460 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1461 jvParams[jss::taker_gets][jss::currency] =
"USD";
1462 jvParams[jss::taker_gets][jss::issuer] = 1;
1463 auto const jrr = env.
rpc(
1464 "json",
"book_offers",
to_string(jvParams))[jss::result];
1465 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1467 jrr[jss::error_message] ==
1468 "Invalid field 'taker_gets.issuer', not string.");
1473 jvParams[jss::ledger_index] =
"validated";
1474 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1475 jvParams[jss::taker_pays][jss::issuer] = 1;
1476 jvParams[jss::taker_gets][jss::currency] =
"USD";
1477 auto const jrr = env.
rpc(
1478 "json",
"book_offers",
to_string(jvParams))[jss::result];
1479 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1481 jrr[jss::error_message] ==
1482 "Invalid field 'taker_pays.issuer', not string.");
1487 jvParams[jss::ledger_index] =
"validated";
1488 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1489 jvParams[jss::taker_pays][jss::issuer] = gw.human() +
"DEAD";
1490 jvParams[jss::taker_gets][jss::currency] =
"USD";
1491 auto const jrr = env.
rpc(
1492 "json",
"book_offers",
to_string(jvParams))[jss::result];
1493 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1495 jrr[jss::error_message] ==
1496 "Invalid field 'taker_pays.issuer', bad issuer.");
1501 jvParams[jss::ledger_index] =
"validated";
1502 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1504 jvParams[jss::taker_gets][jss::currency] =
"USD";
1505 auto const jrr = env.
rpc(
1506 "json",
"book_offers",
to_string(jvParams))[jss::result];
1507 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1509 jrr[jss::error_message] ==
1510 "Invalid field 'taker_pays.issuer', bad issuer account one.");
1515 jvParams[jss::ledger_index] =
"validated";
1516 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1517 jvParams[jss::taker_gets][jss::currency] =
"USD";
1518 jvParams[jss::taker_gets][jss::issuer] = gw.human() +
"DEAD";
1519 auto const jrr = env.
rpc(
1520 "json",
"book_offers",
to_string(jvParams))[jss::result];
1521 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1523 jrr[jss::error_message] ==
1524 "Invalid field 'taker_gets.issuer', bad issuer.");
1529 jvParams[jss::ledger_index] =
"validated";
1530 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1531 jvParams[jss::taker_gets][jss::currency] =
"USD";
1533 auto const jrr = env.
rpc(
1534 "json",
"book_offers",
to_string(jvParams))[jss::result];
1535 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1537 jrr[jss::error_message] ==
1538 "Invalid field 'taker_gets.issuer', bad issuer account one.");
1543 jvParams[jss::ledger_index] =
"validated";
1544 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1545 jvParams[jss::taker_pays][jss::issuer] = alice.human();
1546 jvParams[jss::taker_gets][jss::currency] =
"USD";
1547 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1548 auto const jrr = env.
rpc(
1549 "json",
"book_offers",
to_string(jvParams))[jss::result];
1550 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1552 jrr[jss::error_message] ==
1553 "Unneeded field 'taker_pays.issuer' "
1554 "for XRP currency specification.");
1559 jvParams[jss::ledger_index] =
"validated";
1560 jvParams[jss::taker_pays][jss::currency] =
"USD";
1562 jvParams[jss::taker_gets][jss::currency] =
"USD";
1563 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1564 auto const jrr = env.
rpc(
1565 "json",
"book_offers",
to_string(jvParams))[jss::result];
1566 BEAST_EXPECT(jrr[jss::error] ==
"srcIsrMalformed");
1568 jrr[jss::error_message] ==
1569 "Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
1574 jvParams[jss::ledger_index] =
"validated";
1575 jvParams[jss::taker] = 1;
1576 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1577 jvParams[jss::taker_gets][jss::currency] =
"USD";
1578 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1579 auto const jrr = env.
rpc(
1580 "json",
"book_offers",
to_string(jvParams))[jss::result];
1581 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1583 jrr[jss::error_message] ==
1584 "Invalid field 'taker', not string.");
1589 jvParams[jss::ledger_index] =
"validated";
1590 jvParams[jss::taker] = env.
master.
human() +
"DEAD";
1591 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1592 jvParams[jss::taker_gets][jss::currency] =
"USD";
1593 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1594 auto const jrr = env.
rpc(
1595 "json",
"book_offers",
to_string(jvParams))[jss::result];
1596 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1597 BEAST_EXPECT(jrr[jss::error_message] ==
"Invalid field 'taker'.");
1602 jvParams[jss::ledger_index] =
"validated";
1604 jvParams[jss::taker_pays][jss::currency] =
"USD";
1605 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1606 jvParams[jss::taker_gets][jss::currency] =
"USD";
1607 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1608 auto const jrr = env.
rpc(
1609 "json",
"book_offers",
to_string(jvParams))[jss::result];
1610 BEAST_EXPECT(jrr[jss::error] ==
"badMarket");
1611 BEAST_EXPECT(jrr[jss::error_message] ==
"No such market.");
1616 jvParams[jss::ledger_index] =
"validated";
1618 jvParams[jss::limit] =
"0";
1619 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1620 jvParams[jss::taker_gets][jss::currency] =
"USD";
1621 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1622 auto const jrr = env.
rpc(
1623 "json",
"book_offers",
to_string(jvParams))[jss::result];
1624 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1626 jrr[jss::error_message] ==
1627 "Invalid field 'limit', not unsigned integer.");
1632 jvParams[jss::ledger_index] =
"validated";
1633 jvParams[jss::taker_pays][jss::currency] =
"USD";
1634 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1635 jvParams[jss::taker_gets][jss::currency] =
"USD";
1636 auto const jrr = env.
rpc(
1637 "json",
"book_offers",
to_string(jvParams))[jss::result];
1638 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1640 jrr[jss::error_message] ==
1641 "Invalid field 'taker_gets.issuer', "
1642 "expected non-XRP issuer.");
1647 jvParams[jss::ledger_index] =
"validated";
1648 jvParams[jss::taker_pays][jss::currency] =
"USD";
1649 jvParams[jss::taker_pays][jss::issuer] = gw.human();
1650 jvParams[jss::taker_gets][jss::currency] =
"XRP";
1651 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1652 auto const jrr = env.
rpc(
1653 "json",
"book_offers",
to_string(jvParams))[jss::result];
1654 BEAST_EXPECT(jrr[jss::error] ==
"dstIsrMalformed");
1656 jrr[jss::error_message] ==
1657 "Unneeded field 'taker_gets.issuer' "
1658 "for XRP currency specification.");
1666 using namespace jtx;
1669 env.fund(
XRP(200000), gw);
1674 auto USD = gw[
"USD"];
1677 env(
offer(gw,
XRP(50 + 1 * i), USD(1.0 + 0.1 * i)));
1683 jvParams[jss::limit] = 1;
1684 jvParams[jss::ledger_index] =
"validated";
1685 jvParams[jss::taker_pays][jss::currency] =
"XRP";
1686 jvParams[jss::taker_gets][jss::currency] =
"USD";
1687 jvParams[jss::taker_gets][jss::issuer] = gw.human();
1689 env.rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1690 BEAST_EXPECT(jrr[jss::offers].isArray());
1691 BEAST_EXPECT(jrr[jss::offers].size() == (asAdmin ? 1u : 0u));
1694 jvParams[jss::limit] = 0u;
1695 jrr = env.rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1696 BEAST_EXPECT(jrr[jss::offers].isArray());
1697 BEAST_EXPECT(jrr[jss::offers].size() == 0u);
1700 jrr = env.rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1701 BEAST_EXPECT(jrr[jss::offers].isArray());
1703 jrr[jss::offers].size() ==
1707 jrr = env.rpc(
"json",
"book_offers",
to_string(jvParams))[jss::result];
1708 BEAST_EXPECT(jrr[jss::offers].isArray());
1710 jrr[jss::offers].size() ==
Value & append(Value const &value)
Append value to array at the end.
testcase_t testcase
Memberspace for declaring test cases.
virtual Config & config()=0
A currency issued by an account.
Json::Value getJson(JsonOptions) const override
void testMultipleBooksBothSidesOffersInBook()
void testMultipleBooksBothSidesEmptyBook()
void testBothSidesOffersInBook()
std::string getBookDir(jtx::Env &env, Issue const &in, Issue const &out)
void testCrossingMultiBookOffer()
void testOneSideOffersInBook()
void testBothSidesEmptyBook()
void testMultipleBooksOneSideEmptyBook()
void testBookOfferLimits(bool asAdmin)
void testOneSideEmptyBook()
void testBookOfferErrors()
void testMultipleBooksOneSideOffersInBook()
void run() override
Runs the suite.
void testCrossingSingleBookOffer()
static bool offerOnlyOnceInStream(std::unique_ptr< WSClient > const &wsc, std::chrono::milliseconds const &timeout, jtx::PrettyAmount const &takerGets, jtx::PrettyAmount const &takerPays)
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
void require(Args const &... args)
Check a set of requirements.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Match the number of items in the account's owner directory.
Check a set of conditions.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
static LimitRange constexpr bookOffers
Limits for the book_offers command.
Keylet page(uint256 const &root, std::uint64_t index=0) noexcept
A page in a directory.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
std::unique_ptr< Config > no_admin(std::unique_ptr< Config >)
adjust config so no admin ports are enabled
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
XRP_t const XRP
Converts to XRP Issue or STAmount.
std::unique_ptr< WSClient > makeWSClient(Config const &cfg, bool v2, unsigned rpc_version, std::unordered_map< std::string, std::string > const &headers)
Returns a client operating through WebSockets/S.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
AccountID const & noAccount()
A placeholder for empty accounts.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
bool cdirFirst(ReadView const &view, uint256 const &root, std::shared_ptr< SLE const > &page, unsigned int &index, uint256 &entry)
Returns the first entry in the directory, advancing the index.
AccountID const & xrpAccount()
Compute AccountID from public key.
uint256 getQualityNext(uint256 const &uBase)
std::string to_string(base_uint< Bits, Tag > const &a)
Json::Value getJson(LedgerFill const &fill)
Return a new Json::Value representing the ledger with given options.
uint256 getBookBase(Book const &book)
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...
STAmount const & value() const