1#include <test/jtx/AMM.h>
2#include <test/jtx/AMMTest.h>
3#include <test/jtx/Account.h>
4#include <test/jtx/Env.h>
5#include <test/jtx/TestHelpers.h>
6#include <test/jtx/amount.h>
7#include <test/jtx/balance.h>
8#include <test/jtx/credentials.h>
9#include <test/jtx/domain.h>
10#include <test/jtx/fee.h>
11#include <test/jtx/jtx_json.h>
12#include <test/jtx/ledgerStateFix.h>
13#include <test/jtx/offer.h>
14#include <test/jtx/owners.h>
15#include <test/jtx/paths.h>
16#include <test/jtx/pay.h>
17#include <test/jtx/permissioned_dex.h>
18#include <test/jtx/permissioned_domains.h>
19#include <test/jtx/sendmax.h>
20#include <test/jtx/ter.h>
21#include <test/jtx/trust.h>
22#include <test/jtx/txflags.h>
24#include <xrpl/basics/Slice.h>
25#include <xrpl/basics/base_uint.h>
26#include <xrpl/beast/unit_test/suite.h>
27#include <xrpl/beast/utility/Journal.h>
28#include <xrpl/ledger/OpenView.h>
29#include <xrpl/protocol/Book.h>
30#include <xrpl/protocol/Feature.h>
31#include <xrpl/protocol/Indexes.h>
32#include <xrpl/protocol/Issue.h>
33#include <xrpl/protocol/Keylet.h>
34#include <xrpl/protocol/LedgerFormats.h>
35#include <xrpl/protocol/SField.h>
36#include <xrpl/protocol/STAmount.h>
37#include <xrpl/protocol/STArray.h>
38#include <xrpl/protocol/STLedgerEntry.h>
39#include <xrpl/protocol/SeqProxy.h>
40#include <xrpl/protocol/TER.h>
41#include <xrpl/protocol/TxFlags.h>
42#include <xrpl/protocol/jss.h>
61 [[nodiscard]]
static bool
64 return static_cast<bool>(
68 [[nodiscard]]
static bool
75 uint32_t
const flags = 0,
76 bool const domainOffer =
false)
79 uint64_t
const pageIndex,
85 if (domain != (*page)[~sfDomainID])
88 auto const& indexes = page->getFieldV256(sfIndexes);
97 if (sle->getFieldAmount(sfTakerGets) != takerGets)
99 if (sle->getFieldAmount(sfTakerPays) != takerPays)
101 if (sle->getFlags() != flags)
103 if (domainOffer && !sle->isFieldPresent(sfDomainID))
105 if (!domainOffer && sle->isFieldPresent(sfDomainID))
108 sle->getFieldH256(sfBookDirectory),
109 sle->getFieldU64(sfBookNode),
110 (*sle)[~sfDomainID]))
113 if (sle->isFlag(lsfHybrid))
115 if (!sle->isFieldPresent(sfDomainID))
117 if (!sle->isFieldPresent(sfAdditionalBooks))
119 if (sle->getFieldArray(sfAdditionalBooks).size() != 1)
122 auto const& additionalBookDirs = sle->getFieldArray(sfAdditionalBooks);
124 for (
auto const& bookDir : additionalBookDirs)
126 auto const& dirIndex = bookDir.getFieldH256(sfBookDirectory);
127 auto const& dirNode = bookDir.getFieldU64(sfBookNode);
131 if (!offerInDir(dirIndex, dirNode, std::nullopt))
137 if (sle->isFieldPresent(sfAdditionalBooks))
154 return Keylet(ltDIR_NODE, (*sle)[sfBookDirectory]).
key;
159 [[nodiscard]]
static bool
167 auto const page = env.
le(
172 pageIndex = (*page)[~sfIndexNext];
173 dirCnt += (*page)[sfIndexes].size();
175 }
while (pageIndex.
value_or(0) != 0u);
177 return dirCnt == dirSize;
183 bool const fixEnabled = features[fixCleanup3_4_0];
186 << (fixEnabled ?
" (Cleanup3_4_0 enabled)" :
" (Cleanup3_4_0 disabled)");
190 Env env(*
this, features - featurePermissionedDEX);
191 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
207 if (features[fixCleanup3_2_0])
209 Env env(*
this, features);
210 auto const& [gw_, domainOwner, alice_, bob_, carol_, USD, domainID, credType] =
219 Env env(*
this, features);
220 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
227 env.
trust(USD(1000), devin);
229 env(
pay(gw, devin, USD(100)));
252 Env env(*
this, features);
253 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
260 env.
trust(USD(1000), devin);
262 env(
pay(gw, devin, USD(100)));
266 uint32_t
const t = env.
current()->header().parentCloseTime.time_since_epoch().count();
267 jv[sfExpiration.jsonName] = t + 20;
283 env(
offer(devin,
XRP(10), USD(10)),
Domain(domainID),
Ter(expectedExpiredCredTer));
289 Env env(*
this, features);
290 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
293 "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134"
303 Env env(*
this, features);
304 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
310 auto const bobOfferSeq{env.
seq(bob)};
314 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
320 Env env(*
this, features);
321 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
327 auto const bobOfferSeq{env.
seq(bob)};
331 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq, USD(10),
XRP(10), 0,
true));
336 Env env(*
this, features);
337 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
340 auto const bobOfferSeq{env.
seq(bob)};
344 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
348 env(
offer(carol, USD(10),
XRP(10)));
351 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
353 auto const aliceOfferSeq{env.
seq(alice)};
357 BEAST_EXPECT(!
offerExists(env, alice, aliceOfferSeq));
364 Env env(*
this, features);
365 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
371 for (
size_t i = 0; i <= 100; i++)
373 auto const bobOfferSeq{env.
seq(bob)};
378 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
381 for (
auto const offerSeq : offerSeqs)
397 Env env(*
this, features - featurePermissionedDEX);
398 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
401 env(
pay(bob, alice, USD(10)),
422 if (features[fixCleanup3_2_0])
424 Env env(*
this, features);
425 auto const& [gw_, domainOwner, alice_, bob_, carol_, USD, domainID, credType] =
428 env(
pay(bob_, alice_, USD(10)),
438 Env env(*
this, features);
439 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
442 "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134"
445 env(
pay(bob, alice, USD(10)),
455 Env env(*
this, features);
456 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
466 env.
trust(USD(1000), devin);
468 env(
pay(gw, devin, USD(100)));
472 env(
pay(alice, devin, USD(10)),
484 env(
pay(alice, devin, USD(10)),
501 Env env(*
this, features);
502 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
512 env.
trust(USD(1000), devin);
514 env(
pay(gw, devin, USD(100)));
518 env(
pay(devin, alice, USD(10)),
530 env(
pay(devin, alice, USD(10)),
547 Env env(*
this, features);
548 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
574 Env env(*
this, features);
575 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
579 auto const regularOfferSeq{env.
seq(bob)};
582 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq,
XRP(10), USD(10)));
585 BEAST_EXPECT(regularDirKey);
587 env, *regularDirKey, 1));
590 env(
pay(alice, carol, USD(10)),
598 auto const domainOfferSeq{env.
seq(bob)};
602 BEAST_EXPECT(
checkOffer(env, bob, domainOfferSeq,
XRP(10), USD(10), 0,
true));
605 BEAST_EXPECT(domainDirKey);
607 env, *domainDirKey, 1));
613 BEAST_EXPECT(!
offerExists(env, bob, domainOfferSeq));
614 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq,
XRP(10), USD(10)));
618 env, *domainDirKey, 0));
620 env, *regularDirKey, 1));
625 Env env(*
this, features);
626 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
629 auto const eur = gw[
"EUR"];
630 env.
trust(eur(1000), alice);
632 env.
trust(eur(1000), bob);
634 env.
trust(eur(1000), carol);
636 env(
pay(gw, bob, eur(100)));
640 auto const usdOfferSeq{env.
seq(bob)};
644 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(10), USD(10), 0,
true));
647 env(
pay(alice, carol, eur(10)),
653 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(10), USD(10), 0,
true));
656 auto const regularOfferSeq{env.
seq(bob)};
657 env(
offer(bob, USD(10), eur(10)));
659 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq, USD(10), eur(10)));
663 env(
pay(alice, carol, eur(10)),
671 auto const eurOfferSeq{env.
seq(bob)};
672 env(
offer(bob, USD(10), eur(10)),
Domain(domainID));
674 BEAST_EXPECT(
checkOffer(env, bob, eurOfferSeq, USD(10), eur(10), 0,
true));
680 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(5), USD(5), 0,
true));
681 BEAST_EXPECT(
checkOffer(env, bob, eurOfferSeq, USD(5), eur(5), 0,
true));
692 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq, USD(10), eur(10)));
697 Env env(*
this, features);
698 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
702 Account const badDomainOwner(
"badDomainOwner");
704 env.
fund(
XRP(1000), badDomainOwner, devin);
706 env.
trust(USD(1000), devin);
708 env(
pay(gw, devin, USD(100)));
711 auto const badCredType =
"badCred";
713 {.issuer = badDomainOwner, .credType = badCredType}};
717 auto const badDomainID = objects.begin()->first;
728 env(
pay(alice, carol, USD(10)),
736 auto const bobOfferSeq{env.
seq(bob)};
739 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
752 Env env(*
this, features);
753 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
778 Env env(*
this, features);
779 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
786 env.
trust(USD(1000), devin);
788 env(
pay(gw, devin, USD(100)));
792 uint32_t
const t = env.
current()->header().parentCloseTime.time_since_epoch().count();
793 jv[sfExpiration.jsonName] = t + 20;
800 auto const offerSeq{env.
seq(devin)};
807 BEAST_EXPECT(
checkOffer(env, devin, offerSeq,
XRP(5), USD(5), 0,
true));
813 env(
pay(alice, carol, USD(5)),
819 BEAST_EXPECT(
checkOffer(env, devin, offerSeq,
XRP(5), USD(5), 0,
true));
824 Env env(*
this, features);
825 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
828 auto const offerSeq{env.
seq(bob)};
835 BEAST_EXPECT(
checkOffer(env, bob, offerSeq,
XRP(5), USD(5), 0,
true));
842 env(
pay(alice, carol, USD(5)),
848 BEAST_EXPECT(
checkOffer(env, bob, offerSeq,
XRP(5), USD(5), 0,
true));
860 Env env(*
this, features);
861 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
864 auto const eura = alice[
"EUR"];
865 auto const eurb = bob[
"EUR"];
867 env.
trust(eura(100), bob);
868 env.
trust(eurb(100), carol);
882 env(
trust(carol, bob[
"EUR"](0), bob, tfSetNoRipple));
894 testcase(
"Offer token issuer in domain");
898 Env env(*
this, features);
899 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
903 auto const bobOffer1Seq{env.
seq(bob)};
908 auto const bobOffer2Seq{env.
seq(bob)};
912 BEAST_EXPECT(
checkOffer(env, bob, bobOffer1Seq,
XRP(10), USD(10), 0,
true));
913 BEAST_EXPECT(
checkOffer(env, bob, bobOffer2Seq, USD(10),
XRP(10), lsfPassive,
true));
923 BEAST_EXPECT(!
offerExists(env, bob, bobOffer1Seq));
929 BEAST_EXPECT(!
offerExists(env, bob, bobOffer2Seq));
939 Env env(*
this, features);
940 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
943 auto const aliceOfferSeq{env.
seq(alice)};
947 auto const bobOfferSeq{env.
seq(bob)};
951 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(20), USD(20), 0,
true));
952 BEAST_EXPECT(
checkOffer(env, alice, aliceOfferSeq,
XRP(100), USD(100), 0,
true));
955 BEAST_EXPECT(domainDirKey);
957 env, *domainDirKey, 2));
966 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
969 BEAST_EXPECT(!
offerExists(env, alice, aliceOfferSeq));
971 env, *domainDirKey, 1));
979 Env env(*
this, features);
980 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
982 AMM const amm(env, alice,
XRP(10), USD(50));
985 env(
pay(bob, carol, USD(5)),
997 auto [xrp, usd, lpt] =
amm.balances(
XRP, USD);
998 BEAST_EXPECT(usd == USD(45));
1004 bool const excludesAmmFromDomainQuality = features[fixCleanup3_3_0];
1006 testcase <<
"AMM quality not leaked into domain BookStep"
1007 << (excludesAmmFromDomainQuality ?
" (Cleanup3_3_0 enabled)"
1008 :
" (Cleanup3_3_0 disabled)");
1010 Env env(*
this, features);
1011 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1013 auto const eur = gw[
"EUR"];
1015 env.trust(eur(1000), bob, domainOwner);
1017 env(
pay(gw, bob, eur(100)));
1020 env(
pay(gw, alice, USD(500)));
1026 AMM const amm(env, alice,
XRP(10), USD(500));
1028 auto const directOfferSeq{env.seq(bob)};
1032 auto const xrpEurOfferSeq{env.seq(bob)};
1036 auto const eurUsdOfferSeq{env.seq(domainOwner)};
1037 env(
offer(domainOwner, eur(20), USD(20)),
Domain(domainID));
1040 auto const carolBalBefore = env.balance(carol, USD);
1047 env(
pay(alice, carol, USD(100)),
1051 Txflags(tfPartialPayment | tfNoRippleDirect),
1055 auto const delivered = env.balance(carol, USD) - carolBalBefore;
1056 if (excludesAmmFromDomainQuality)
1058 BEAST_EXPECT(delivered == USD(20));
1060 BEAST_EXPECT(
checkOffer(env, bob, directOfferSeq,
XRP(10), USD(10), 0,
true));
1061 BEAST_EXPECT(!
offerExists(env, bob, xrpEurOfferSeq));
1062 BEAST_EXPECT(!
offerExists(env, domainOwner, eurUsdOfferSeq));
1066 BEAST_EXPECT(delivered == USD(10));
1068 BEAST_EXPECT(!
offerExists(env, bob, directOfferSeq));
1069 BEAST_EXPECT(
checkOffer(env, bob, xrpEurOfferSeq,
XRP(10), eur(20), 0,
true));
1070 BEAST_EXPECT(
checkOffer(env, domainOwner, eurUsdOfferSeq, eur(20), USD(20), 0,
true));
1073 auto [xrp, usd, lpt] =
amm.balances(
XRP, USD);
1074 BEAST_EXPECT(xrp ==
XRP(10));
1075 BEAST_EXPECT(usd == USD(500));
1085 Env env(*
this, features - featurePermissionedDEX);
1086 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1106 auto const offerSeq{env.
seq(bob)};
1109 BEAST_EXPECT(
checkOffer(env, bob, offerSeq,
XRP(10), USD(10), lsfHybrid,
true));
1114 Env env(*
this, features);
1115 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1118 auto const bobOfferSeq{env.
seq(bob)};
1122 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), lsfHybrid,
true));
1126 auto const aliceOfferSeq{env.
seq(alice)};
1130 BEAST_EXPECT(!
offerExists(env, alice, aliceOfferSeq));
1131 BEAST_EXPECT(!
offerExists(env, bob, bobOfferSeq));
1137 Env env(*
this, features);
1138 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1141 auto const bobOfferSeq{env.
seq(bob)};
1147 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), lsfHybrid,
true));
1149 auto const aliceOfferSeq{env.
seq(alice)};
1150 env(
offer(alice, USD(10),
XRP(10)));
1153 BEAST_EXPECT(!
offerExists(env, alice, aliceOfferSeq));
1154 BEAST_EXPECT(!
offerExists(env, bob, bobOfferSeq));
1161 Env env(*
this, features);
1162 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1165 auto const bobOfferSeq{env.
seq(bob)};
1169 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
1173 auto const aliceOfferSeq{env.
seq(alice)};
1177 BEAST_EXPECT(!
offerExists(env, alice, aliceOfferSeq));
1178 BEAST_EXPECT(!
offerExists(env, bob, bobOfferSeq));
1185 Env env(*
this, features);
1186 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1189 auto const bobOfferSeq{env.
seq(bob)};
1193 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
false));
1197 auto const aliceOfferSeq{env.
seq(alice)};
1201 BEAST_EXPECT(
offerExists(env, alice, aliceOfferSeq));
1203 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
false));
1204 BEAST_EXPECT(
checkOffer(env, alice, aliceOfferSeq, USD(10),
XRP(10), lsfHybrid,
true));
1217 Env env(*
this, features);
1218 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1221 auto const hybridOfferSeq{env.
seq(bob)};
1231 env(
pay(alice, carol, USD(5)),
1237 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(50), USD(50), lsfHybrid,
true));
1239 if (features[fixCleanup3_3_0])
1243 auto const carolBalBefore = env.
balance(carol, USD);
1246 BEAST_EXPECT(env.
balance(carol, USD) - carolBalBefore == USD(5));
1247 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(45), USD(45), lsfHybrid,
true));
1250 auto const regularOfferSeq{env.
seq(bob)};
1253 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq,
XRP(10), USD(10)));
1255 auto const sleHybridOffer =
1257 if (!BEAST_EXPECT(sleHybridOffer))
1259 auto const openDir =
1260 sleHybridOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory);
1269 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(40), USD(40), lsfHybrid,
true));
1270 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq,
XRP(10), USD(10)));
1280 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(50), USD(50), lsfHybrid,
true));
1283 auto const regularOfferSeq{env.
seq(bob)};
1286 BEAST_EXPECT(
offerExists(env, bob, regularOfferSeq));
1287 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq,
XRP(10), USD(10)));
1289 auto const sleHybridOffer =
1291 if (!BEAST_EXPECT(sleHybridOffer))
1293 auto const openDir =
1294 sleHybridOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory);
1303 BEAST_EXPECT(!
offerExists(env, bob, hybridOfferSeq));
1304 BEAST_EXPECT(
checkOffer(env, bob, regularOfferSeq,
XRP(5), USD(5)));
1316 Env env(*
this, features);
1317 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1320 auto const hybridOfferSeq{env.
seq(bob)};
1326 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(5), USD(5), lsfHybrid,
true));
1332 BEAST_EXPECT(!
offerExists(env, bob, hybridOfferSeq));
1338 Env env(*
this, features);
1339 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1343 Account const badDomainOwner(
"badDomainOwner");
1345 env.
fund(
XRP(1000), badDomainOwner, devin);
1348 auto const badCredType =
"badCred";
1350 {.issuer = badDomainOwner, .credType = badCredType}};
1354 auto const badDomainID = objects.begin()->first;
1361 auto const hybridOfferSeq{env.
seq(bob)};
1366 env(
pay(devin, badDomainOwner, USD(5)),
1372 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(10), USD(10), lsfHybrid,
true));
1376 BEAST_EXPECT(
checkOffer(env, bob, hybridOfferSeq,
XRP(5), USD(5), lsfHybrid,
true));
1382 BEAST_EXPECT(!
offerExists(env, bob, hybridOfferSeq));
1387 Env env(*
this, features);
1388 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1391 auto const eur = gw[
"EUR"];
1392 env.
trust(eur(1000), alice);
1394 env.
trust(eur(1000), bob);
1396 env.
trust(eur(1000), carol);
1398 env(
pay(gw, bob, eur(100)));
1401 auto const usdOfferSeq{env.
seq(bob)};
1405 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(10), USD(10), 0,
true));
1408 env(
pay(alice, carol, eur(5)),
1414 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(10), USD(10), 0,
true));
1417 auto const eurOfferSeq{env.
seq(bob)};
1420 BEAST_EXPECT(
checkOffer(env, bob, eurOfferSeq, USD(10), eur(10), lsfHybrid,
true));
1426 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(5), USD(5), 0,
true));
1427 BEAST_EXPECT(
checkOffer(env, bob, eurOfferSeq, USD(5), eur(5), lsfHybrid,
true));
1432 Env env(*
this, features);
1433 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1436 auto const eur = gw[
"EUR"];
1437 env.
trust(eur(1000), alice);
1439 env.
trust(eur(1000), bob);
1441 env.
trust(eur(1000), carol);
1443 env(
pay(gw, bob, eur(100)));
1447 auto const usdOfferSeq{env.
seq(bob)};
1451 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(10), USD(10), 0,
false));
1454 auto const eurOfferSeq{env.
seq(bob)};
1457 BEAST_EXPECT(
checkOffer(env, bob, eurOfferSeq, USD(10), eur(10), lsfHybrid,
true));
1463 BEAST_EXPECT(
checkOffer(env, bob, usdOfferSeq,
XRP(5), USD(5), 0,
false));
1464 BEAST_EXPECT(
checkOffer(env, bob, eurOfferSeq, USD(5), eur(5), lsfHybrid,
true));
1475 testcase(
"Hybrid open book after credential expiry");
1477 Env env(*
this, features);
1478 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1484 env.
trust(USD(1000), devin);
1486 env(
pay(gw, devin, USD(100)));
1492 uint32_t
const t = env.
current()->header().parentCloseTime.time_since_epoch().count();
1493 jv[sfExpiration.jsonName] = t + 100;
1501 auto const hybridOfferSeq{env.
seq(devin)};
1505 BEAST_EXPECT(
checkOffer(env, devin, hybridOfferSeq,
XRP(10), USD(10), lsfHybrid,
true));
1509 auto carolBalance = env.
balance(carol, USD);
1512 BEAST_EXPECT(env.
balance(carol, USD) - carolBalance == USD(5));
1513 BEAST_EXPECT(
checkOffer(env, devin, hybridOfferSeq,
XRP(5), USD(5), lsfHybrid,
true));
1525 BEAST_EXPECT(
offerExists(env, devin, hybridOfferSeq));
1529 carolBalance = env.
balance(carol, USD);
1534 BEAST_EXPECT(env.
balance(carol, USD) - carolBalance == USD(2));
1536 BEAST_EXPECT(
checkOffer(env, devin, hybridOfferSeq,
XRP(3), USD(3), lsfHybrid,
true));
1541 env(
pay(alice, carol, USD(1)),
1550 BEAST_EXPECT(
checkOffer(env, devin, hybridOfferSeq,
XRP(3), USD(3), lsfHybrid,
true));
1553 carolBalance = env.
balance(carol, USD);
1556 BEAST_EXPECT(env.
balance(carol, USD) - carolBalance == USD(3));
1557 BEAST_EXPECT(!
offerExists(env, devin, hybridOfferSeq));
1563 Env env(*
this, features);
1564 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1576 size_t dirCnt = 100;
1578 for (
size_t i = 1; i <= dirCnt; i++)
1580 auto const bobOfferSeq{env.
seq(bob)};
1585 auto const sleOffer =
1587 BEAST_EXPECT(sleOffer);
1588 BEAST_EXPECT(sleOffer->getFieldH256(sfBookDirectory) == domainDir);
1589 BEAST_EXPECT(sleOffer->getFieldArray(sfAdditionalBooks).size() == 1);
1591 sleOffer->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory) ==
1594 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), lsfHybrid,
true));
1599 for (
auto const offerSeq : offerSeqs)
1615 Env env(*
this, features);
1616 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1618 auto const eur = gw[
"EUR"];
1620 for (
auto const& account : {alice, bob, carol})
1622 env(
trust(account, eur(10000)));
1626 env(
pay(gw, carol, eur(1)));
1629 auto const aliceOfferSeq{env.
seq(alice)};
1630 auto const bobOfferSeq{env.
seq(bob)};
1637 auto const carolOfferSeq{env.
seq(carol)};
1638 env(
offer(carol, USD(1), eur(1)),
Domain(domainID));
1641 BEAST_EXPECT(!
offerExists(env, bob, aliceOfferSeq));
1642 BEAST_EXPECT(!
offerExists(env, bob, bobOfferSeq));
1643 BEAST_EXPECT(!
offerExists(env, bob, carolOfferSeq));
1649 bool const fixEnabled = features[fixCleanup3_4_0];
1651 testcase <<
"Expired credential cleanup"
1652 << (fixEnabled ?
" (Cleanup3_4_0 enabled)" :
" (Cleanup3_4_0 disabled)");
1656 auto const fundAccount =
1660 env.
trust(usd(1000), account);
1662 env(
pay(gw, account, usd(100)));
1666 auto const fundDevin = [&](
Env& env,
Account const& gw,
IOU const& usd) {
1668 fundAccount(env, devin, gw, usd);
1672 auto const createExpiringCredential = [](
Env& env,
1677 uint32_t
const t = env.
current()->header().parentCloseTime.time_since_epoch().count();
1678 jv[sfExpiration.jsonName] = t + 20;
1686 auto const expectExpiredCredentialState = [&](
Env const& env,
Keylet const& credKey) {
1689 BEAST_EXPECT(!env.
le(credKey));
1693 BEAST_EXPECT(env.
le(credKey));
1699 Env env(*
this, features);
1700 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1704 "F10D0CC9A0F9A3CBF585B80BE09A186483668FDBDD39AA7E3370F3649CE134"
1710 env(
pay(alice, bob, USD(10)),
1720 Env env(*
this, features);
1721 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1724 Account const devin = fundDevin(env, gw, USD);
1725 auto const credKey = createExpiringCredential(env, devin, domainOwner, credType);
1726 BEAST_EXPECT(env.
le(credKey));
1730 env(
offer(devin,
XRP(10), USD(10)),
Domain(domainID),
Ter(expectedExpiredCredTer));
1733 expectExpiredCredentialState(env, credKey);
1738 Env env(*
this, features);
1739 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1742 Account const devin = fundDevin(env, gw, USD);
1743 auto const credKey = createExpiringCredential(env, devin, domainOwner, credType);
1745 auto const bobOfferSeq{env.
seq(bob)};
1746 auto const bobCredKey =
1751 BEAST_EXPECT(env.
le(credKey));
1752 BEAST_EXPECT(env.
le(bobCredKey));
1757 env(
pay(devin, alice, USD(10)),
1761 Ter(expectedExpiredCredTer));
1764 expectExpiredCredentialState(env, credKey);
1765 BEAST_EXPECT(env.
le(bobCredKey));
1771 Env env(*
this, features);
1772 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1775 Account const devin = fundDevin(env, gw, USD);
1776 auto const credKey = createExpiringCredential(env, devin, domainOwner, credType);
1778 auto const bobOfferSeq{env.
seq(bob)};
1779 auto const bobCredKey =
1784 BEAST_EXPECT(env.
le(credKey));
1785 BEAST_EXPECT(env.
le(bobCredKey));
1790 env(
pay(alice, devin, USD(10)),
1794 Ter(expectedExpiredCredTer));
1797 expectExpiredCredentialState(env, credKey);
1798 BEAST_EXPECT(env.
le(bobCredKey));
1804 Env env(*
this, features);
1805 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1808 Account const devin = fundDevin(env, gw, USD);
1810 fundAccount(env, erin, gw, USD);
1812 auto const devinCredKey = createExpiringCredential(env, devin, domainOwner, credType);
1813 auto const erinCredKey = createExpiringCredential(env, erin, domainOwner, credType);
1815 auto const bobOfferSeq{env.
seq(bob)};
1816 auto const bobCredKey =
1821 BEAST_EXPECT(env.
le(devinCredKey));
1822 BEAST_EXPECT(env.
le(erinCredKey));
1823 BEAST_EXPECT(env.
le(bobCredKey));
1828 env(
pay(devin, erin, USD(10)),
1832 Ter(expectedExpiredCredTer));
1835 expectExpiredCredentialState(env, devinCredKey);
1836 expectExpiredCredentialState(env, erinCredKey);
1837 BEAST_EXPECT(env.
le(bobCredKey));
1845 bool const fixEnabled = features[fixCleanup3_1_3];
1847 testcase <<
"Hybrid offer with empty AdditionalBooks"
1848 << (fixEnabled ?
" (fixCleanup3_1_3 enabled)" :
" (fixCleanup3_1_3 disabled)");
1865 Env env(*
this, features);
1866 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
1870 auto const bobOfferSeq{env.seq(bob)};
1880 auto const sle = view.
read(offerKey);
1884 replacement->setFieldArray(sfAdditionalBooks,
STArray{});
1893 env(
pay(alice, carol, USD(10)),
1911 bool const fixEnabled = features[fixCleanup3_2_0];
1912 testcase <<
"Hybrid offer crossing quality"
1913 << (fixEnabled ?
" (fixCleanup3_2_0)" :
" (pre-fix)");
1928 Env env(*
this, features);
1929 auto const& [gw_, domainOwner, alice_, bob_, carol_, USD, domainID, credType] =
1933 auto const bobOfferSeq{env.seq(bob_)};
1936 BEAST_EXPECT(
offerExists(env, bob_, bobOfferSeq));
1942 auto const aliceOfferSeq{env.seq(alice_)};
1949 BEAST_EXPECT(sle->isFieldPresent(sfAdditionalBooks));
1950 BEAST_EXPECT(sle->getFieldArray(sfAdditionalBooks).size() == 1);
1952 auto const domainDirKey = sle->getFieldH256(sfBookDirectory);
1953 auto const openDirKey =
1954 sle->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory);
1956 auto const domainQuality =
getQuality(domainDirKey);
1957 auto const openQuality =
getQuality(openDirKey);
1960 auto const domainDirSle = env.le(
Keylet(ltDIR_NODE, domainDirKey));
1961 auto const openDirSle = env.le(
Keylet(ltDIR_NODE, openDirKey));
1962 BEAST_EXPECT(domainDirSle);
1963 BEAST_EXPECT(openDirSle);
1965 auto const domainExRate = domainDirSle->getFieldU64(sfExchangeRate);
1966 auto const openExRate = openDirSle->getFieldU64(sfExchangeRate);
1967 auto const preCrossingQuality =
std::uint64_t{5623825668291712342ULL};
1968 auto const postCrossingQuality =
std::uint64_t{5623825668291712341ULL};
1972 BEAST_EXPECT(domainQuality == preCrossingQuality);
1973 BEAST_EXPECT(domainExRate == preCrossingQuality);
1974 BEAST_EXPECT(domainExRate == domainQuality);
1979 BEAST_EXPECT(openQuality == preCrossingQuality);
1980 BEAST_EXPECT(domainQuality == openQuality);
1983 BEAST_EXPECT(openExRate == preCrossingQuality);
1984 BEAST_EXPECT(openExRate == openQuality);
1990 BEAST_EXPECT(openQuality == postCrossingQuality);
1991 BEAST_EXPECT(domainQuality != openQuality);
1996 BEAST_EXPECT(openExRate == preCrossingQuality);
1997 BEAST_EXPECT(openExRate != openQuality);
1998 BEAST_EXPECT(openExRate == domainQuality);
2005 testcase(
"LedgerStateFix BookExchangeRate");
2022 Env env(*
this, features - fixCleanup3_2_0);
2034 Env env(*
this, features);
2042 missingBookDirectory.
removeMember(sfBookDirectory.jsonName);
2048 extraOwner[sfOwner.jsonName] = carol.
human();
2053 Env env(*
this, features);
2055 auto const fixFee =
drops(env.
current()->fees().increment);
2069 auto const ownerDirSle = env.
le(ownerDir);
2070 BEAST_EXPECT(ownerDirSle);
2071 BEAST_EXPECT(!ownerDirSle->isFieldPresent(sfExchangeRate));
2081 auto const bobOfferSeq{env.
seq(setup.bob)};
2082 env(
offer(setup.bob,
XRP(100), setup.usd(40)));
2089 auto const dirKey = sle->getFieldH256(sfBookDirectory);
2091 auto const dirSle = env.
le(
Keylet(ltDIR_NODE, dirKey));
2092 BEAST_EXPECT(dirSle);
2093 auto const exchangeRate = dirSle->getFieldU64(sfExchangeRate);
2095 BEAST_EXPECT(exchangeRate == quality);
2107 Env env(*
this, features - fixCleanup3_2_0);
2108 auto const& [gw_, domainOwner, alice_, bob_, carol_, USD, domainID, credType] =
2116 auto const aliceOfferSeq{env.
seq(alice_)};
2124 auto const openDirKey =
2125 sle->getFieldArray(sfAdditionalBooks)[0].getFieldH256(sfBookDirectory);
2127 auto const preCrossingQuality =
std::uint64_t{5623825668291712342ULL};
2128 auto const postCrossingQuality =
std::uint64_t{5623825668291712341ULL};
2132 auto const dirSle = env.
le(
Keylet(ltDIR_NODE, openDirKey));
2133 BEAST_EXPECT(dirSle);
2134 auto const exchangeRate = dirSle->getFieldU64(sfExchangeRate);
2136 BEAST_EXPECT(exchangeRate == preCrossingQuality);
2137 BEAST_EXPECT(quality == postCrossingQuality);
2138 BEAST_EXPECT(exchangeRate != quality);
2145 auto const fixFee =
drops(env.
current()->fees().increment);
2151 auto const dirSle = env.
le(
Keylet(ltDIR_NODE, openDirKey));
2152 BEAST_EXPECT(dirSle);
2153 auto const exchangeRate = dirSle->getFieldU64(sfExchangeRate);
2155 BEAST_EXPECT(exchangeRate == postCrossingQuality);
2156 BEAST_EXPECT(quality == postCrossingQuality);
2157 BEAST_EXPECT(exchangeRate == quality);
2170 bool const fixEnabled = features[fixCleanup3_2_0];
2172 testcase <<
"Cancel regular offer via domain OfferCreate"
2173 << (fixEnabled ?
" (fixCleanup3_2_0 enabled)" :
" (fixCleanup3_2_0 disabled)");
2184 Env env(*
this, features);
2185 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
2188 auto const regularSeq = env.seq(bob);
2191 BEAST_EXPECT(
checkOffer(env, bob, regularSeq,
XRP(10), USD(10), 0,
false));
2193 auto const domainSeq = env.seq(bob);
2198 Json(jss::OfferSequence, regularSeq));
2201 BEAST_EXPECT(
checkOffer(env, bob, domainSeq,
XRP(20), USD(20), 0,
true));
2207 Json(jss::OfferSequence, regularSeq),
2218 bool const fixEnabled = features[fixCleanup3_4_0];
2220 testcase <<
"Domain offer indexed in the wrong domain book"
2221 << (fixEnabled ?
" (fixCleanup3_4_0 enabled)" :
" (fixCleanup3_4_0 disabled)");
2235 Env env(*
this, features);
2236 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
2241 auto const domainID2 =
2245 auto const bobOfferSeq{env.seq(bob)};
2248 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
2254 auto const sle = view.
read(offerKey);
2258 replacement->setFieldH256(sfDomainID, domainID2);
2266 env(
pay(alice, carol, USD(10)),
2277 env(
pay(alice, carol, USD(10)),
2289 bool const fixEnabled = features[fixCleanup3_4_0];
2291 testcase <<
"Offer without a domain indexed in a domain book"
2292 << (fixEnabled ?
" (fixCleanup3_4_0 enabled)" :
" (fixCleanup3_4_0 disabled)");
2306 Env env(*
this, features);
2307 auto const& [gw, domainOwner, alice, bob, carol, USD, domainID, credType] =
2311 auto const bobOfferSeq{env.seq(bob)};
2314 BEAST_EXPECT(
checkOffer(env, bob, bobOfferSeq,
XRP(10), USD(10), 0,
true));
2320 auto const sle = view.
read(offerKey);
2324 replacement->makeFieldAbsent(sfDomainID);
2329 auto const carolBefore = env.balance(carol, USD);
2334 env(
pay(alice, carol, USD(10)),
2340 BEAST_EXPECT(env.balance(carol, USD) - carolBefore == USD(0));
2347 BEAST_EXPECT(!
offerExists(env, bob, bobOfferSeq));
2348 BEAST_EXPECT(env.balance(carol, USD) - carolBefore == USD(10));
2355 bool const fixEnabled = features[fixCleanup3_4_0];
2357 testcase <<
"Replace domain offer via OfferCreate"
2358 << (fixEnabled ?
" (fixCleanup3_4_0 enabled)" :
" (fixCleanup3_4_0 disabled)");
2360 Env env(*
this, features);
2361 auto const& [gw, domainOwner, alice, bob, carol, USD, domainA, credType] =
2364 Account const domainOwnerB(
"permdex-domainOwnerB");
2365 auto const domainB =
2366 setupDomain(env, {alice, bob, carol, gw}, domainOwnerB,
"permdex-other-domain");
2367 BEAST_EXPECT(domainA != domainB);
2369 auto const oldSeq = env.seq(alice);
2373 BEAST_EXPECT(
checkOffer(env, alice, oldSeq, USD(100),
XRP(1), 0,
true));
2375 if (!BEAST_EXPECT(oldOffer))
2377 BEAST_EXPECT(oldOffer->getFieldH256(sfDomainID) == domainA);
2379 auto const newSeq = env.seq(alice);
2384 env(
offer(alice, USD(100),
XRP(2)),
Domain(domainB),
Json(jss::OfferSequence, oldSeq));
2388 BEAST_EXPECT(
checkOffer(env, alice, newSeq, USD(100),
XRP(2), 0,
true));
2390 if (!BEAST_EXPECT(newOffer))
2392 BEAST_EXPECT(newOffer->getFieldH256(sfDomainID) == domainB);
2396 env(
offer(alice, USD(100),
XRP(2)),
2398 Json(jss::OfferSequence, oldSeq),
2402 BEAST_EXPECT(
checkOffer(env, alice, oldSeq, USD(100),
XRP(1), 0,
true));
A generic endpoint for log messages.
TestcaseT testcase
Memberspace for declaring test cases.
Value removeMember(char const *key)
Remove and return the named member.
A currency issued by an account.
Writable ledger view that accumulates state and tx changes.
void rawReplace(SLE::Ref sle) override
Unconditionally replace a state item.
SLE::const_pointer read(Keylet const &k) const override
Return the state item associated with a key.
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
void testRippling(FeatureBitset features)
static std::optional< UInt256 > getDefaultOfferDirKey(Env const &env, Account const &account, std::uint32_t offerSeq)
static bool checkDirectorySize(Env const &env, UInt256 directory, std::uint32_t dirSize)
void testOfferCreate(FeatureBitset features)
void testHybridOfferDirectories(FeatureBitset features)
static UInt256 getBookDirKey(Book const &book, STAmount const &takerPays, STAmount const &takerGets)
void testExpiredCredentialCleanup(FeatureBitset features)
void testHybridOfferCreate(FeatureBitset features)
void testCancelRegularOfferWithDomainCreate(FeatureBitset features)
void testHybridOpenBookAfterCredentialExpiry(FeatureBitset features)
void testHybridOfferCrossingQuality(FeatureBitset features)
void testAutoBridge(FeatureBitset features)
void testOfferTokenIssuerInDomain(FeatureBitset features)
void run() override
Runs the suite.
void testPayment(FeatureBitset features)
void testHybridBookStep(FeatureBitset features)
void testAmmNotUsed(FeatureBitset features)
void testBookStep(FeatureBitset features)
void testDomainOfferInWrongBook(FeatureBitset features)
static bool offerExists(Env const &env, Account const &account, std::uint32_t offerSeq)
void testAmmQualityNotLeaked(FeatureBitset features)
void testReplaceDomainOfferWithOtherDomainOffer(FeatureBitset features)
static bool checkOffer(Env const &env, Account const &account, std::uint32_t offerSeq, STAmount const &takerPays, STAmount const &takerGets, uint32_t const flags=0, bool const domainOffer=false)
void testDomainBookOfferMissingDomain(FeatureBitset features)
void testBookExchangeRateFix(FeatureBitset features)
void testHybridMalformedOffer(FeatureBitset features)
void testHybridInvalidOffer(FeatureBitset features)
void testRemoveUnfundedOffer(FeatureBitset features)
Convenience class to test AMM functionality.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
SLE::const_pointer le(Account const &account) const
Return an account root.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
void enableFeature(UInt256 const feature)
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Converts to IOU Issue or STAmount.
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.
T emplace_back(T... args)
Keylet quality(Keylet const &k, std::uint64_t const q) noexcept
The initial directory page for a specific quality.
Keylet offer(AccountID const &id, SeqProxy const &seq) noexcept
An offer from an account.
Keylet book(Book const &b)
The beginning of an order book.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet page(UInt256 const &root, std::uint64_t const index=0) noexcept
A page in a directory.
Keylet credential(AccountID const &subject, AccountID const &issuer, Slice const &credType) noexcept
json::Value deleteCred(jtx::Account const &acc, jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
json::Value accept(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
json::Value create(jtx::Account const &subject, jtx::Account const &issuer, std::string_view credType)
json::Value bookExchangeRate(jtx::Account const &acct, UInt256 const &bookDir)
Repair sfExchangeRate on a book directory's first page.
std::map< UInt256, json::Value > getObjects(Account const &account, Env &env, bool withType)
std::vector< Credential > Credentials
json::Value setTx(AccountID const &account, Credentials const &credentials, std::optional< UInt256 > domain)
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
json::Value offerCancel(Account const &account, std::uint32_t offerSeq)
Cancel an offer.
XrpT const XRP
Converts to XRP Issue or STAmount.
std::uint32_t ownerCount(Env const &env, Account const &account)
FeatureBitset testableAmendments()
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
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)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
BaseUInt< 256 > Domain
Domain is a 256-bit hash representing a specific domain.
std::uint64_t getQuality(UInt256 const &uBase)
Slice makeSlice(std::array< T, N > const &a)
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
TERSubset< CanCvtToTER > TER
A pair of SHAMap key and LedgerEntryType.