2#include <test/jtx/AMM.h>
3#include <test/jtx/AMMTest.h>
4#include <test/jtx/envconfig.h>
5#include <test/jtx/permissioned_dex.h>
7#include <xrpld/core/JobQueue.h>
8#include <xrpld/rpc/RPCHandler.h>
9#include <xrpld/rpc/detail/Tuning.h>
11#include <xrpl/beast/unit_test.h>
12#include <xrpl/json/json_reader.h>
13#include <xrpl/protocol/ApiVersion.h>
14#include <xrpl/protocol/STParsedJSON.h>
15#include <xrpl/protocol/TxFlags.h>
16#include <xrpl/protocol/jss.h>
17#include <xrpl/resource/Fees.h>
35 jv[jss::command] =
"ripple_path_find";
36 jv[jss::source_account] =
toBase58(src);
50 jv[jss::destination_account] = d;
53 j[jss::currency] =
"USD";
54 j[jss::value] =
"0.01";
72 cfg->PATH_SEARCH_OLD = 7;
74 cfg->PATH_SEARCH_MAX = 10;
90 template <
class Rep,
class Period>
121 auto& app = env.
app();
130 app.getLedgerMaster(),
140 params[jss::command] =
"ripple_path_find";
141 params[jss::source_account] =
toBase58(src);
142 params[jss::destination_account] =
toBase58(dst);
143 params[jss::destination_amount] =
151 j[jss::currency] =
to_string(saSrcCurrency.value());
159 app.getJobQueue().postCoro(
160 jtCLIENT,
"RPC-Client", [&](
auto const& coro) {
161 context.params = std::move(params);
167 using namespace std::chrono_literals;
169 BEAST_EXPECT(!result.
isMember(jss::error));
184 env, src, dst, saDstAmount, saSendMax, saSrcCurrency,
domain);
185 BEAST_EXPECT(!result.
isMember(jss::error));
188 if (result.
isMember(jss::destination_amount))
193 if (result.
isMember(jss::alternatives))
195 auto const& alts = result[jss::alternatives];
198 auto const&
path = alts[0u];
200 if (
path.isMember(jss::source_amount))
203 if (
path.isMember(jss::destination_amount))
207 if (
path.isMember(jss::paths_computed))
210 p[
"Paths"] =
path[jss::paths_computed];
224 using namespace std::chrono_literals;
227 auto const gw =
Account(
"gateway");
228 env.
fund(
XRP(10000),
"alice",
"bob", gw);
230 env.
trust(gw[
"USD"](100),
"alice",
"bob");
233 auto& app = env.
app();
242 app.getLedgerMaster(),
253 app.getJobQueue().postCoro(
254 jtCLIENT,
"RPC-Client", [&](
auto const& coro) {
255 context.params =
rpf(
262 BEAST_EXPECT(!result.
isMember(jss::error));
265 app.getJobQueue().postCoro(
266 jtCLIENT,
"RPC-Client", [&](
auto const& coro) {
276 BEAST_EXPECT(result.
isMember(jss::error));
281 app.getJobQueue().postCoro(
282 jtCLIENT,
"RPC-Client", [&](
auto const& coro) {
289 BEAST_EXPECT(!result.
isMember(jss::error));
293 app.getJobQueue().postCoro(
294 jtCLIENT,
"RPC-Client", [&](
auto const& coro) {
301 BEAST_EXPECT(result.
isMember(jss::error));
307 testcase(
"no direct path no intermediary no alternatives");
310 env.
fund(
XRP(10000),
"alice",
"bob");
321 testcase(
"direct path no intermediary");
324 env.
fund(
XRP(10000),
"alice",
"bob");
332 BEAST_EXPECT(st.
empty());
342 auto const gw =
Account(
"gateway");
343 auto const USD = gw[
"USD"];
344 env.
fund(
XRP(10000),
"alice",
"bob", gw);
346 env.
trust(USD(600),
"alice");
347 env.
trust(USD(700),
"bob");
348 env(
pay(gw,
"alice", USD(70)));
349 env(
pay(
"alice",
"bob", USD(24)));
360 std::string(
"path find") + (domainEnabled ?
" w/ " :
" w/o ") +
364 auto const gw =
Account(
"gateway");
365 auto const USD = gw[
"USD"];
366 env.
fund(
XRP(10000),
"alice",
"bob", gw);
368 env.
trust(USD(600),
"alice");
369 env.
trust(USD(700),
"bob");
370 env(
pay(gw,
"alice", USD(70)));
371 env(
pay(gw,
"bob", USD(50)));
396 std::string(
"XRP to XRP") + (domainEnabled ?
" w/ " :
" w/o ") +
399 env.
fund(
XRP(10000),
"alice",
"bob");
416 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
421 env.
fund(
XRP(10000),
"alice",
"bob",
"carol",
"dan",
"edward");
432 env, {
"alice",
"bob",
"carol",
"dan",
"edward"});
452 auto const gw =
Account(
"gateway");
453 auto const USD = gw[
"USD"];
454 env.
fund(
XRP(10000),
"alice",
"bob",
"carol", gw);
456 env.
trust(USD(100),
"bob",
"carol");
458 env(
pay(gw,
"carol", USD(100)));
465 setupDomain(env, {
"alice",
"bob",
"carol",
"gateway"});
470 env(
offer(
"carol",
XRP(100), USD(100)));
485 BEAST_EXPECT(st.
empty());
494 BEAST_EXPECT(sa ==
XRP(100));
509 BEAST_EXPECT(st.
empty());
519 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
522 auto const gw =
Account(
"gateway");
523 auto const USD = gw[
"USD"];
524 auto const gw2 =
Account(
"gateway2");
525 auto const gw2_USD = gw2[
"USD"];
526 env.
fund(
XRP(10000),
"alice",
"bob", gw, gw2);
528 env.
trust(USD(600),
"alice");
529 env.
trust(gw2_USD(800),
"alice");
530 env.
trust(USD(700),
"bob");
531 env.
trust(gw2_USD(900),
"bob");
537 setupDomain(env, {
"alice",
"bob",
"gateway",
"gateway2"});
538 env(
pay(gw,
"alice", USD(70)),
domain(*domainID));
539 env(
pay(gw2,
"alice", gw2_USD(70)),
domain(*domainID));
540 env(
pay(
"alice",
"bob",
Account(
"bob")[
"USD"](140)),
546 env(
pay(gw,
"alice", USD(70)));
547 env(
pay(gw2,
"alice", gw2_USD(70)));
548 env(
pay(
"alice",
"bob",
Account(
"bob")[
"USD"](140)),
566 std::string(
"alternative paths consume best transfer") +
567 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
570 auto const gw =
Account(
"gateway");
571 auto const USD = gw[
"USD"];
572 auto const gw2 =
Account(
"gateway2");
573 auto const gw2_USD = gw2[
"USD"];
574 env.
fund(
XRP(10000),
"alice",
"bob", gw, gw2);
577 env.
trust(USD(600),
"alice");
578 env.
trust(gw2_USD(800),
"alice");
579 env.
trust(USD(700),
"bob");
580 env.
trust(gw2_USD(900),
"bob");
586 setupDomain(env, {
"alice",
"bob",
"gateway",
"gateway2"});
587 env(
pay(gw,
"alice", USD(70)),
domain(*domainID));
588 env(
pay(gw2,
"alice", gw2_USD(70)),
domain(*domainID));
589 env(
pay(
"alice",
"bob", USD(70)),
domain(*domainID));
593 env(
pay(gw,
"alice", USD(70)));
594 env(
pay(gw2,
"alice", gw2_USD(70)));
595 env(
pay(
"alice",
"bob", USD(70)));
610 testcase(
"alternative paths - consume best transfer first");
613 auto const gw =
Account(
"gateway");
614 auto const USD = gw[
"USD"];
615 auto const gw2 =
Account(
"gateway2");
616 auto const gw2_USD = gw2[
"USD"];
617 env.
fund(
XRP(10000),
"alice",
"bob", gw, gw2);
620 env.
trust(USD(600),
"alice");
621 env.
trust(gw2_USD(800),
"alice");
622 env.
trust(USD(700),
"bob");
623 env.
trust(gw2_USD(900),
"bob");
624 env(
pay(gw,
"alice", USD(70)));
625 env(
pay(gw2,
"alice", gw2_USD(70)));
626 env(
pay(
"alice",
"bob",
Account(
"bob")[
"USD"](77)),
641 bool const domainEnabled)
645 "alternative paths - limit returned paths to best quality") +
646 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
649 auto const gw =
Account(
"gateway");
650 auto const USD = gw[
"USD"];
651 auto const gw2 =
Account(
"gateway2");
652 auto const gw2_USD = gw2[
"USD"];
653 env.
fund(
XRP(10000),
"alice",
"bob",
"carol",
"dan", gw, gw2);
655 env(
rate(
"carol", 1.1));
656 env.
trust(
Account(
"carol")[
"USD"](800),
"alice",
"bob");
658 env.
trust(USD(800),
"alice",
"bob");
659 env.
trust(gw2_USD(800),
"alice",
"bob");
663 env(
pay(gw2,
"alice", gw2_USD(100)));
665 env(
pay(
"carol",
"alice",
Account(
"carol")[
"USD"](100)));
667 env(
pay(gw,
"alice", USD(100)));
674 setupDomain(env, {
"alice",
"bob",
"carol",
"dan", gw, gw2});
701 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
704 env.
fund(
XRP(10000),
"alice",
"bob",
"carol",
"dan");
706 env.
trust(
Account(
"bob")[
"USD"](100),
"alice",
"carol",
"dan");
709 env(
pay(
"bob",
"carol",
Account(
"bob")[
"USD"](75)));
717 domainID =
setupDomain(env, {
"alice",
"bob",
"carol",
"dan"});
761 testcase(
"path negative: ripple-client issue #23: smaller");
764 env.
fund(
XRP(10000),
"alice",
"bob",
"carol",
"dan");
770 env(
pay(
"alice",
"bob",
Account(
"bob")[
"USD"](55)),
781 testcase(
"path negative: ripple-client issue #23: larger");
784 env.
fund(
XRP(10000),
"alice",
"bob",
"carol",
"dan",
"edward");
791 env(
pay(
"alice",
"bob",
Account(
"bob")[
"USD"](50)),
810 std::string(
"via gateway") + (domainEnabled ?
" w/ " :
" w/o ") +
814 auto const gw =
Account(
"gateway");
815 auto const AUD = gw[
"AUD"];
816 env.
fund(
XRP(10000),
"alice",
"bob",
"carol", gw);
820 env.
trust(AUD(100),
"bob",
"carol");
822 env(
pay(gw,
"carol", AUD(50)));
828 domainID =
setupDomain(env, {
"alice",
"bob",
"carol", gw});
831 env(
pay(
"alice",
"bob", AUD(10)),
839 env(
offer(
"carol",
XRP(50), AUD(50)));
865 env.
fund(
XRP(10000),
"alice",
"bob",
"carol");
884 env.
fund(
XRP(10000),
"alice",
"bob");
887 json(
"{\"" + sfQualityIn.fieldName +
"\": 2000}"),
888 json(
"{\"" + sfQualityOut.fieldName +
"\": 1400000000}"));
895 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
901 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
905 "HighQualityIn" : 2000,
906 "HighQualityOut" : 1400000000,
907 "LedgerEntryType" : "RippleState",
910 "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
921 for (
auto it = jv.
begin(); it != jv.
end(); ++it)
922 BEAST_EXPECT(*it == jv_l[it.memberName()]);
931 env.
fund(
XRP(10000),
"alice",
"bob");
941 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
947 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
951 "LedgerEntryType" : "RippleState",
954 "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
965 for (
auto it = jv.
begin(); it != jv.
end(); ++it)
966 BEAST_EXPECT(*it == jv_l[it.memberName()]);
982 env.
fund(
XRP(10000),
"alice",
"bob");
985 env(
pay(
"bob",
"alice",
Account(
"bob")[
"USD"](50)));
994 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
1001 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
1005 "LedgerEntryType" : "RippleState",
1009 "issuer" : "rG1QQv2nh2gr7RCZ1P8YYcBUKCCN633jCn",
1020 for (
auto it = jv.
begin(); it != jv.
end(); ++it)
1021 BEAST_EXPECT(*it == jv_l[it.memberName()]);
1023 env(
pay(
"alice",
"bob",
Account(
"alice")[
"USD"](50)));
1034 std::string(
"Path Find: XRP -> XRP and XRP -> IOU") +
1035 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
1036 using namespace jtx;
1046 env.fund(
XRP(100000), A1);
1047 env.fund(
XRP(10000), A2);
1048 env.fund(
XRP(1000), A3, G1, G2, G3, M1);
1051 env.trust(G1[
"XYZ"](5000), A1);
1052 env.trust(G3[
"ABC"](5000), A1);
1053 env.trust(G2[
"XYZ"](5000), A2);
1054 env.trust(G3[
"ABC"](5000), A2);
1055 env.trust(A2[
"ABC"](1000), A3);
1056 env.trust(G1[
"XYZ"](100000), M1);
1057 env.trust(G2[
"XYZ"](100000), M1);
1058 env.trust(G3[
"ABC"](100000), M1);
1061 env(
pay(G1, A1, G1[
"XYZ"](3500)));
1062 env(
pay(G3, A1, G3[
"ABC"](1200)));
1063 env(
pay(G2, M1, G2[
"XYZ"](25000)));
1064 env(
pay(G3, M1, G3[
"ABC"](25000)));
1070 domainID =
setupDomain(env, {A1, A2, A3, G1, G2, G3, M1});
1071 env(
offer(M1, G1[
"XYZ"](1000), G2[
"XYZ"](1000)), domain(*domainID));
1072 env(
offer(M1,
XRP(10000), G3[
"ABC"](1000)), domain(*domainID));
1077 env(
offer(M1, G1[
"XYZ"](1000), G2[
"XYZ"](1000)));
1078 env(
offer(M1,
XRP(10000), G3[
"ABC"](1000)));
1086 auto const& send_amt =
XRP(10);
1089 BEAST_EXPECT(
equal(da, send_amt));
1090 BEAST_EXPECT(st.
empty());
1096 auto const& send_amt =
XRP(200);
1105 BEAST_EXPECT(
equal(da, send_amt));
1106 BEAST_EXPECT(st.
empty());
1110 auto const& send_amt = G3[
"ABC"](10);
1113 BEAST_EXPECT(
equal(da, send_amt));
1119 auto const& send_amt = A2[
"ABC"](1);
1122 BEAST_EXPECT(
equal(da, send_amt));
1128 auto const& send_amt = A3[
"ABC"](1);
1131 BEAST_EXPECT(
equal(da, send_amt));
1142 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
1143 using namespace jtx;
1150 env.
fund(
XRP(1000), A1, A2, G3);
1154 env.
trust(G3[
"ABC"](1000), A1, A2);
1155 env.
trust(G3[
"ABC"](100000), M1);
1158 env(
pay(G3, A1, G3[
"ABC"](1000)));
1159 env(
pay(G3, A2, G3[
"ABC"](1000)));
1160 env(
pay(G3, M1, G3[
"ABC"](1200)));
1171 env(
offer(M1, G3[
"ABC"](1000),
XRP(10000)));
1176 auto const& send_amt =
XRP(10);
1187 BEAST_EXPECT(
equal(da, send_amt));
1188 BEAST_EXPECT(
equal(sa, A1[
"ABC"](1)));
1197 env, A1, A2, send_amt,
std::nullopt, A2[
"ABC"].currency);
1198 BEAST_EXPECT(
equal(da, send_amt));
1199 BEAST_EXPECT(st.
empty());
1208 "Path Find: Bitstamp and SnapSwap, liquidity with no offers") +
1209 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
1210 using namespace jtx;
1214 Account G1BS{
"G1BS"};
1215 Account G2SW{
"G2SW"};
1218 env.
fund(
XRP(1000), G1BS, G2SW, A1, A2);
1222 env.
trust(G1BS[
"HKD"](2000), A1);
1223 env.
trust(G2SW[
"HKD"](2000), A2);
1224 env.
trust(G1BS[
"HKD"](100000), M1);
1225 env.
trust(G2SW[
"HKD"](100000), M1);
1228 env(
pay(G1BS, A1, G1BS[
"HKD"](1000)));
1229 env(
pay(G2SW, A2, G2SW[
"HKD"](1000)));
1233 env(
pay(G1BS, M1, G1BS[
"HKD"](1200)));
1234 env(
pay(G2SW, M1, G2SW[
"HKD"](5000)));
1239 domainID =
setupDomain(env, {A1, A2, G1BS, G2SW, M1});
1245 auto const& send_amt = A2[
"HKD"](10);
1254 BEAST_EXPECT(
equal(da, send_amt));
1255 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1260 auto const& send_amt = A1[
"HKD"](10);
1269 BEAST_EXPECT(
equal(da, send_amt));
1270 BEAST_EXPECT(
equal(sa, A2[
"HKD"](10)));
1271 BEAST_EXPECT(
same(st,
stpath(G2SW, M1, G1BS)));
1275 auto const& send_amt = A2[
"HKD"](10);
1284 BEAST_EXPECT(
equal(da, send_amt));
1285 BEAST_EXPECT(
equal(sa, G1BS[
"HKD"](10)));
1290 auto const& send_amt = M1[
"HKD"](10);
1299 BEAST_EXPECT(
equal(da, send_amt));
1300 BEAST_EXPECT(
equal(sa, M1[
"HKD"](10)));
1301 BEAST_EXPECT(st.empty());
1305 auto const& send_amt = A1[
"HKD"](10);
1314 BEAST_EXPECT(
equal(da, send_amt));
1315 BEAST_EXPECT(
equal(sa, G2SW[
"HKD"](10)));
1324 std::string(
"Path Find: non-XRP -> non-XRP, same currency") +
1325 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
1326 using namespace jtx;
1339 env.fund(
XRP(1000), A1, A2, A3, G1, G2, G3, G4);
1340 env.fund(
XRP(10000), A4);
1341 env.fund(
XRP(11000), M1, M2);
1344 env.trust(G1[
"HKD"](2000), A1);
1345 env.trust(G2[
"HKD"](2000), A2);
1346 env.trust(G1[
"HKD"](2000), A3);
1347 env.trust(G1[
"HKD"](100000), M1);
1348 env.trust(G2[
"HKD"](100000), M1);
1349 env.trust(G1[
"HKD"](100000), M2);
1350 env.trust(G2[
"HKD"](100000), M2);
1353 env(
pay(G1, A1, G1[
"HKD"](1000)));
1354 env(
pay(G2, A2, G2[
"HKD"](1000)));
1355 env(
pay(G1, A3, G1[
"HKD"](1000)));
1356 env(
pay(G1, M1, G1[
"HKD"](1200)));
1357 env(
pay(G2, M1, G2[
"HKD"](5000)));
1358 env(
pay(G1, M2, G1[
"HKD"](1200)));
1359 env(
pay(G2, M2, G2[
"HKD"](5000)));
1366 setupDomain(env, {A1, A2, A3, A4, G1, G2, G3, G4, M1, M2});
1367 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)), domain(*domainID));
1368 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)), domain(*domainID));
1369 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)), domain(*domainID));
1373 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)));
1374 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)));
1375 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)));
1384 auto const& send_amt = G1[
"HKD"](10);
1393 BEAST_EXPECT(st.empty());
1394 BEAST_EXPECT(
equal(da, send_amt));
1395 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1401 auto const& send_amt = A1[
"HKD"](10);
1410 BEAST_EXPECT(st.empty());
1411 BEAST_EXPECT(
equal(da, send_amt));
1412 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1418 auto const& send_amt = A3[
"HKD"](10);
1427 BEAST_EXPECT(
equal(da, send_amt));
1428 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1435 auto const& send_amt = G2[
"HKD"](10);
1444 BEAST_EXPECT(
equal(da, send_amt));
1445 BEAST_EXPECT(
equal(sa, G1[
"HKD"](10)));
1457 auto const& send_amt = G2[
"HKD"](10);
1466 BEAST_EXPECT(
equal(da, send_amt));
1467 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1480 auto const& send_amt = A2[
"HKD"](10);
1489 BEAST_EXPECT(
equal(da, send_amt));
1490 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1504 std::string(
"Path Find: non-XRP -> non-XRP, same currency)") +
1505 (domainEnabled ?
" w/ " :
" w/o ") +
"domain");
1506 using namespace jtx;
1515 env.fund(
XRP(11000), M1);
1516 env.fund(
XRP(1000), A1, A2, A3, G1, G2);
1519 env.trust(G1[
"HKD"](2000), A1);
1520 env.trust(G2[
"HKD"](2000), A2);
1521 env.trust(A2[
"HKD"](2000), A3);
1522 env.trust(G1[
"HKD"](100000), M1);
1523 env.trust(G2[
"HKD"](100000), M1);
1526 env(
pay(G1, A1, G1[
"HKD"](1000)));
1527 env(
pay(G2, A2, G2[
"HKD"](1000)));
1528 env(
pay(G1, M1, G1[
"HKD"](5000)));
1529 env(
pay(G2, M1, G2[
"HKD"](5000)));
1535 domainID =
setupDomain(env, {A1, A2, A3, G1, G2, M1});
1536 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)), domain(*domainID));
1540 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)));
1545 auto const& send_amt = A2[
"HKD"](10);
1549 env, G1, A2, send_amt,
std::nullopt, G1[
"HKD"].currency, domainID);
1550 BEAST_EXPECT(
equal(da, send_amt));
1551 BEAST_EXPECT(
equal(sa, G1[
"HKD"](10)));
1559 std::string(
"Receive max") + (domainEnabled ?
" w/ " :
" w/o ") +
1562 using namespace jtx;
1563 auto const alice = Account(
"alice");
1564 auto const bob = Account(
"bob");
1565 auto const charlie = Account(
"charlie");
1566 auto const gw = Account(
"gw");
1567 auto const USD = gw[
"USD"];
1571 env.fund(
XRP(10000), alice, bob, charlie, gw);
1573 env.trust(USD(100), alice, bob, charlie);
1575 env(
pay(gw, charlie, USD(10)));
1581 domainID =
setupDomain(env, {alice, bob, charlie, gw});
1582 env(
offer(charlie,
XRP(10), USD(10)), domain(*domainID));
1587 env(
offer(charlie,
XRP(10), USD(10)));
1599 BEAST_EXPECT(sa ==
XRP(10));
1600 BEAST_EXPECT(
equal(da, USD(10)));
1601 if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1))
1603 auto const& pathElem = st[0][0];
1605 pathElem.isOffer() && pathElem.getIssuerID() == gw.id() &&
1606 pathElem.getCurrency() == USD.currency);
1612 env.fund(
XRP(10000), alice, bob, charlie, gw);
1614 env.trust(USD(100), alice, bob, charlie);
1616 env(
pay(gw, alice, USD(10)));
1622 domainID =
setupDomain(env, {alice, bob, charlie, gw});
1623 env(
offer(charlie, USD(10),
XRP(10)), domain(*domainID));
1628 env(
offer(charlie, USD(10),
XRP(10)));
1640 BEAST_EXPECT(sa == USD(10));
1642 if (BEAST_EXPECT(st.size() == 1 && st[0].size() == 1))
1644 auto const& pathElem = st[0][0];
1646 pathElem.isOffer() &&
1656 using namespace jtx;
1661 auto const alice =
Account(
"alice");
1662 auto const bob =
Account(
"bob");
1663 auto const george =
Account(
"george");
1664 auto const USD = george[
"USD"];
1691 env(
pay(george, alice, USD(70)));
1696 BEAST_EXPECT(
equal(da, bob[
"USD"](5)));
1700 BEAST_EXPECT(st.size() == 1);
1702 BEAST_EXPECT(
equal(sa, alice[
"USD"](5)));
1706 BEAST_EXPECT(st.size() == 0);
1710 test(
"ripple -> ripple",
true,
true,
true);
1711 test(
"ripple -> no ripple",
true,
false,
true);
1712 test(
"no ripple -> ripple",
false,
true,
true);
1713 test(
"no ripple -> no ripple",
false,
false,
false);
1720 using namespace jtx;
1725 auto testPathfind = [&](
auto func,
bool const domainEnabled =
false) {
1738 env.
fund(
XRP(1000), A1, A2, A3, G1, G2, G3, G4);
1743 env.
trust(G1[
"HKD"](2000), A1);
1744 env.
trust(G2[
"HKD"](2000), A2);
1745 env.
trust(G1[
"HKD"](2000), A3);
1746 env.
trust(G1[
"HKD"](100000), M1);
1747 env.
trust(G2[
"HKD"](100000), M1);
1748 env.
trust(G1[
"HKD"](100000), M2);
1749 env.
trust(G2[
"HKD"](100000), M2);
1752 env(
pay(G1, A1, G1[
"HKD"](1000)));
1753 env(
pay(G2, A2, G2[
"HKD"](1000)));
1754 env(
pay(G1, A3, G1[
"HKD"](1000)));
1755 env(
pay(G1, M1, G1[
"HKD"](1200)));
1756 env(
pay(G2, M1, G2[
"HKD"](5000)));
1757 env(
pay(G1, M2, G1[
"HKD"](1200)));
1758 env(
pay(G2, M2, G2[
"HKD"](5000)));
1762 setupDomain(env, {A1, A2, A3, A4, G1, G2, G3, G4, M1, M2});
1763 BEAST_EXPECT(domainID);
1765 func(env, M1, M2, G1, G2, *domainID);
1773 auto const& send_amt = G1[
"HKD"](10);
1781 domainEnabled ? domainID :
std::nullopt);
1782 BEAST_EXPECT(st.empty());
1783 BEAST_EXPECT(
equal(da, send_amt));
1784 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1790 auto const& send_amt = A1[
"HKD"](10);
1798 domainEnabled ? domainID :
std::nullopt);
1799 BEAST_EXPECT(st.empty());
1800 BEAST_EXPECT(
equal(da, send_amt));
1801 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1807 auto const& send_amt = A3[
"HKD"](10);
1815 domainEnabled ? domainID :
std::nullopt);
1816 BEAST_EXPECT(
equal(da, send_amt));
1817 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1824 auto const& send_amt = G2[
"HKD"](10);
1832 domainEnabled ? domainID :
std::nullopt);
1833 BEAST_EXPECT(
equal(da, send_amt));
1834 BEAST_EXPECT(
equal(sa, G1[
"HKD"](10)));
1846 auto const& send_amt = G2[
"HKD"](10);
1854 domainEnabled ? domainID :
std::nullopt);
1855 BEAST_EXPECT(
equal(da, send_amt));
1856 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1869 auto const& send_amt = A2[
"HKD"](10);
1877 domainEnabled ? domainID :
std::nullopt);
1878 BEAST_EXPECT(
equal(da, send_amt));
1879 BEAST_EXPECT(
equal(sa, A1[
"HKD"](10)));
1893 testPathfind([](Env& env,
1899 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
1902 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)));
1903 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)));
1906 testPathfind([](Env& env,
1912 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
1915 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
1918 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)));
1921 testPathfind([](Env& env,
1927 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
1930 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
1933 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
1938 testPathfind([](Env& env,
1944 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)));
1945 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)));
1946 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
1951 testPathfind([](Env& env,
1957 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)));
1958 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
1961 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
1978 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
1981 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
1983 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
1995 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
1998 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
2001 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
2013 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
2015 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
2017 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
2030 env(
offer(M1, G1[
"HKD"](1000), G2[
"HKD"](1000)),
2032 env(
offer(M2,
XRP(10000), G2[
"HKD"](1000)),
2035 env(
offer(M2, G1[
"HKD"](1000),
XRP(10000)),
2046 testcase(
"AMM not used in domain path");
2047 using namespace jtx;
2049 PermissionedDEX permDex(env);
2050 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
2057 auto const& send_amt =
XRP(1);
2061 env, bob, carol, send_amt,
std::nullopt, USD.currency, domainID);
2062 BEAST_EXPECT(st.empty());
2086 for (
bool const domainEnabled : {
false,
true})
Unserialize a JSON document into a Value.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
const_iterator begin() const
const_iterator end() const
bool isMember(char const *key) const
Return true if the object has a member named key.
testcase_t testcase
Memberspace for declaring test cases.
An endpoint that consumes resources.
Json::Value getJson(JsonOptions=JsonOptions::none) const override
Holds the serialized result of parsing an input JSON object.
std::optional< STObject > object
The STObject if the parse was successful.
std::condition_variable cv_
bool wait_for(std::chrono::duration< Rep, Period > const &rel_time)
void noripple_combinations()
void path_find_consume_all(bool const domainEnabled)
void trust_auto_clear_trust_normal_clear()
void alternative_path_consume_both(bool const domainEnabled)
void payment_auto_path_find()
void indirect_paths_path_find()
void via_offers_via_gateway(bool const domainEnabled)
void issues_path_negative_issue(bool const domainEnabled)
void trust_auto_clear_trust_auto_clear()
void direct_path_no_intermediary()
void receive_max(bool const domainEnabled)
void path_find_02(bool const domainEnabled)
void issues_path_negative_ripple_client_issue_23_larger()
void alternative_paths_consume_best_transfer(bool const domainEnabled)
std::tuple< STPathSet, STAmount, STAmount > find_paths(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax=std::nullopt, std::optional< Currency > const &saSrcCurrency=std::nullopt, std::optional< uint256 > const &domain=std::nullopt)
void alternative_paths_limit_returned_paths_to_best_quality(bool const domainEnabled)
void source_currencies_limit()
void path_find_04(bool const domainEnabled)
auto find_paths_request(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax=std::nullopt, std::optional< Currency > const &saSrcCurrency=std::nullopt, std::optional< uint256 > const &domain=std::nullopt)
void issues_path_negative_ripple_client_issue_23_smaller()
void alternative_paths_consume_best_transfer_first()
void path_find_05(bool const domainEnabled)
void path_find_01(bool const domainEnabled)
void path_find_06(bool const domainEnabled)
void quality_paths_quality_set_and_test()
void xrp_to_xrp(bool const domainEnabled)
void run() override
Runs the suite.
void path_find(bool const domainEnabled)
void no_direct_path_no_intermediary_no_alternatives()
Immutable cryptographic account descriptor.
A transaction testing environment.
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.
beast::Journal const journal
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Set Paths, SendMax on a JTx.
Sets the SendMax on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
static int constexpr max_src_cur
Maximum number of source currencies allowed in a path find request.
static int constexpr max_auto_src_cur
Maximum number of auto source currencies in a path find request.
Status doCommand(RPC::JsonContext &context, Json::Value &result)
Execute an RPC command and store the results in a Json::Value.
static constexpr auto apiVersionIfUnspecified
Charge const feeReferenceRPC
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
uint256 setupDomain(jtx::Env &env, std::vector< jtx::Account > const &accounts, jtx::Account const &domainOwner, std::string const &credType)
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
bool same(STPathSet const &st1, Args const &... args)
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.
STPathElement IPE(Issue const &iss)
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.
STPath stpath(Args const &... args)
Json::Value rpf(jtx::Account const &src, jtx::Account const &dst, std::uint32_t num_src)
bool equal(std::unique_ptr< Step > const &s1, DirectStepInfo const &dsi)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
AccountID const & xrpAccount()
Compute AccountID from public key.
STAmount amountFromJson(SField const &name, Json::Value const &v)
constexpr std::uint32_t tfHybrid
constexpr std::uint32_t tfClearNoRipple
Currency const & xrpCurrency()
XRP currency.
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfSetNoRipple