21#include <test/jtx/AMM.h>
22#include <test/jtx/Env.h>
24#include <xrpld/app/tx/apply.h>
25#include <xrpld/app/tx/detail/ApplyContext.h>
27#include <xrpl/beast/utility/Journal.h>
28#include <xrpl/protocol/InnerObjectFormats.h>
29#include <xrpl/protocol/STLedgerEntry.h>
31#include <boost/algorithm/string/predicate.hpp>
80 using namespace test::jtx;
85 Account
const A1{
"A1"};
86 Account
const A2{
"A2"};
87 env.fund(
XRP(1000), A1, A2);
89 BEAST_EXPECT(preclose(A1, A2, env));
92 OpenView ov{*env.current()};
100 env.current()->fees().base,
104 BEAST_EXPECT(precheck(A1, A2, ac));
107 if (!BEAST_EXPECT(ters.
size() == 2))
111 for (
TER const& terExpect : ters)
113 terActual = ac.checkInvariants(terActual, fee);
114 BEAST_EXPECT(terExpect == terActual);
116 sink.messages().str().starts_with(
"Invariant failed:") ||
117 sink.messages().str().starts_with(
118 "Transaction caused an exception"));
121 for (
auto const& m : expect_logs)
124 sink.messages().str().find(m) != std::string::npos);
132 using namespace test::jtx;
135 {{
"XRP net change was positive: 500"}},
136 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
141 auto amt = sle->getFieldAmount(sfBalance);
142 sle->setFieldAmount(sfBalance, amt +
STAmount{500});
143 ac.view().update(sle);
151 using namespace test::jtx;
156 {{
"an account root was deleted"}},
157 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
162 ac.view().erase(sle);
172 {{
"account deletion succeeded without deleting an account"}},
182 {{
"account deletion succeeded but deleted multiple accounts"}},
183 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
187 if (!sleA1 || !sleA2)
189 ac.view().erase(sleA1);
190 ac.view().erase(sleA2);
200 using namespace test::jtx;
201 testcase <<
"account root deletion left artifact";
209 if (!keyletInfo.includeInTests)
211 auto const& keyletfunc = keyletInfo.function;
212 auto const& type = keyletInfo.expectedLEName;
214 using namespace std::string_literals;
217 {{
"account deletion left behind a "s + type.c_str() +
219 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
222 auto const a1 = A1.id();
228 auto const newSLE = std::make_shared<SLE>(key);
229 ac.view().insert(newSLE);
230 ac.view().erase(sleA1);
240 {{
"account deletion left behind a NFTokenPage object"}},
241 [&](Account
const& A1, Account
const&,
ApplyContext& ac) {
246 ac.view().erase(sle);
252 [&](Account
const& A1, Account
const&, Env& env) {
255 env(token::mint(A1));
265 {{
"account deletion left behind a DirectoryNode object"}},
266 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
273 BEAST_EXPECT(sle->at(~sfAMMID));
274 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
276 ac.view().erase(sle);
283 [&](Account
const& A1, Account
const& A2, Env& env) {
286 AMM const amm(env, A1, XRP(100), A1[
"USD"](50));
287 ammAcctID = amm.ammAccount();
288 ammKey = amm.ammID();
289 ammIssue = amm.lptIssue();
293 {{
"account deletion left behind a AMM object"}},
294 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
302 BEAST_EXPECT(sle->at(~sfAMMID));
303 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
305 for (
auto const& trustKeylet :
309 if (
auto const line = ac.view().peek(trustKeylet); !line)
315 STAmount const lowLimit = line->at(sfLowLimit);
316 STAmount const highLimit = line->at(sfHighLimit);
327 auto const ammSle = ac.view().peek(
keylet::amm(ammKey));
328 if (!BEAST_EXPECT(ammSle))
332 BEAST_EXPECT(ac.view().dirRemove(
333 ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey,
false));
335 !ac.view().exists(ownerDirKeylet) ||
336 ac.view().emptyDirDelete(ownerDirKeylet));
338 ac.view().erase(sle);
345 [&](Account
const& A1, Account
const& A2, Env& env) {
348 AMM const amm(env, A1, XRP(100), A1[
"USD"](50));
349 ammAcctID = amm.ammAccount();
350 ammKey = amm.ammID();
351 ammIssue = amm.lptIssue();
359 using namespace test::jtx;
360 testcase <<
"ledger entry types don't match";
362 {{
"ledger entry type mismatch"},
363 {
"XRP net change of -1000000000 doesn't match fee 0"}},
364 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
369 auto const sleNew = std::make_shared<SLE>(ltTICKET, sle->key());
370 ac.rawView().rawReplace(sleNew);
375 {{
"invalid ledger entry type added"}},
376 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
385 auto const sleNew = std::make_shared<SLE>(
391 ac.view().insert(sleNew);
399 using namespace test::jtx;
400 testcase <<
"trust lines with XRP not allowed";
402 {{
"an XRP trust line was created"}},
403 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
405 auto const sleNew = std::make_shared<SLE>(
407 ac.view().insert(sleNew);
415 using namespace test::jtx;
416 testcase <<
"trust lines with deep freeze flag without freeze "
419 {{
"a trust line with deep freeze flag without normal freeze was "
421 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
422 auto const sleNew = std::make_shared<SLE>(
424 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
425 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
429 sleNew->setFieldU32(sfFlags, uFlags);
430 ac.view().insert(sleNew);
435 {{
"a trust line with deep freeze flag without normal freeze was "
437 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
438 auto const sleNew = std::make_shared<SLE>(
440 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
441 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
444 sleNew->setFieldU32(sfFlags, uFlags);
445 ac.view().insert(sleNew);
450 {{
"a trust line with deep freeze flag without normal freeze was "
452 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
453 auto const sleNew = std::make_shared<SLE>(
455 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
456 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
459 sleNew->setFieldU32(sfFlags, uFlags);
460 ac.view().insert(sleNew);
465 {{
"a trust line with deep freeze flag without normal freeze was "
467 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
468 auto const sleNew = std::make_shared<SLE>(
470 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
471 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
474 sleNew->setFieldU32(sfFlags, uFlags);
475 ac.view().insert(sleNew);
480 {{
"a trust line with deep freeze flag without normal freeze was "
482 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
483 auto const sleNew = std::make_shared<SLE>(
485 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
486 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
489 sleNew->setFieldU32(sfFlags, uFlags);
490 ac.view().insert(sleNew);
498 using namespace test::jtx;
499 testcase <<
"transfers when frozen";
503 auto const createTrustlines =
504 [&](Account
const& A1, Account
const& A2, Env& env) {
506 env.fund(XRP(1000), G1);
508 env.trust(G1[
"USD"](10000), A1);
509 env.trust(G1[
"USD"](10000), A2);
512 env(pay(G1, A1, G1[
"USD"](1000)));
513 env(pay(G1, A2, G1[
"USD"](1000)));
519 auto const A1FrozenByIssuer =
520 [&](Account
const& A1, Account
const& A2, Env& env) {
521 createTrustlines(A1, A2, env);
528 auto const A1DeepFrozenByIssuer =
529 [&](Account
const& A1, Account
const& A2, Env& env) {
530 A1FrozenByIssuer(A1, A2, env);
537 auto const changeBalances = [&](Account
const& A1,
542 auto const sleA1 = ac.view().peek(
keylet::line(A1, G1[
"USD"]));
543 auto const sleA2 = ac.view().peek(
keylet::line(A2, G1[
"USD"]));
545 sleA1->setFieldAmount(sfBalance, G1[
"USD"](A1Balance));
546 sleA2->setFieldAmount(sfBalance, G1[
"USD"](A2Balance));
548 ac.view().update(sleA1);
549 ac.view().update(sleA2);
554 {{
"Attempting to move frozen funds"}},
555 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
556 changeBalances(A1, A2, ac, -900, -1100);
566 {{
"Attempting to move frozen funds"}},
567 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
568 changeBalances(A1, A2, ac, -900, -1100);
574 A1DeepFrozenByIssuer);
578 {{
"Attempting to move frozen funds"}},
579 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
580 changeBalances(A1, A2, ac, -1100, -900);
586 A1DeepFrozenByIssuer);
592 using namespace test::jtx;
596 {{
"Cannot return non-native STAmount as XRPAmount"}},
597 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
602 STAmount const nonNative(A2[
"USD"](51));
603 sle->setFieldAmount(sfBalance, nonNative);
604 ac.view().update(sle);
609 {{
"incorrect account XRP balance"},
610 {
"XRP net change was positive: 99999999000000001"}},
611 [
this](Account
const& A1, Account
const&,
ApplyContext& ac) {
618 sle->setFieldAmount(sfBalance,
INITIAL_XRP + drops(1));
619 BEAST_EXPECT(!sle->getFieldAmount(sfBalance).negative());
620 ac.view().update(sle);
625 {{
"incorrect account XRP balance"},
626 {
"XRP net change of -1000000001 doesn't match fee 0"}},
627 [
this](Account
const& A1, Account
const&,
ApplyContext& ac) {
632 sle->setFieldAmount(sfBalance,
STAmount{1,
true});
633 BEAST_EXPECT(sle->getFieldAmount(sfBalance).negative());
634 ac.view().update(sle);
642 using namespace test::jtx;
643 using namespace std::string_literals;
644 testcase <<
"Transaction fee checks";
647 {{
"fee paid was negative: -1"},
648 {
"XRP net change of 0 doesn't match fee -1"}},
649 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
654 {
"XRP net change of 0 doesn't match fee "s +
656 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
660 {{
"fee paid is 20 exceeds fee specified in transaction."},
661 {
"XRP net change of 0 doesn't match fee 20"}},
662 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
672 using namespace test::jtx;
676 {{
"offer with a bad amount"}},
677 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
682 auto sleNew = std::make_shared<SLE>(
684 sleNew->setAccountID(sfAccount, A1.id());
685 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
686 sleNew->setFieldAmount(sfTakerPays, XRP(-1));
687 ac.view().insert(sleNew);
692 {{
"offer with a bad amount"}},
693 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
698 auto sleNew = std::make_shared<SLE>(
700 sleNew->setAccountID(sfAccount, A1.id());
701 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
702 sleNew->setFieldAmount(sfTakerPays, A1[
"USD"](10));
703 sleNew->setFieldAmount(sfTakerGets, XRP(-1));
704 ac.view().insert(sleNew);
709 {{
"offer with a bad amount"}},
710 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
715 auto sleNew = std::make_shared<SLE>(
717 sleNew->setAccountID(sfAccount, A1.id());
718 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
719 sleNew->setFieldAmount(sfTakerPays, XRP(10));
720 sleNew->setFieldAmount(sfTakerGets, XRP(11));
721 ac.view().insert(sleNew);
729 using namespace test::jtx;
733 {{
"Cannot return non-native STAmount as XRPAmount"}},
734 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
739 auto sleNew = std::make_shared<SLE>(
742 sleNew->setFieldAmount(sfAmount, nonNative);
743 ac.view().insert(sleNew);
748 {{
"XRP net change of -1000000 doesn't match fee 0"},
749 {
"escrow specifies invalid amount"}},
750 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
755 auto sleNew = std::make_shared<SLE>(
757 sleNew->setFieldAmount(sfAmount, XRP(-1));
758 ac.view().insert(sleNew);
763 {{
"XRP net change was positive: 100000000000000001"},
764 {
"escrow specifies invalid amount"}},
765 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
770 auto sleNew = std::make_shared<SLE>(
774 sleNew->setFieldAmount(sfAmount,
INITIAL_XRP + drops(1));
775 ac.view().insert(sleNew);
783 using namespace test::jtx;
784 testcase <<
"valid new account root";
787 {{
"account root created by a non-Payment"}},
791 Account
const A3{
"A3"};
793 auto const sleNew = std::make_shared<SLE>(acctKeylet);
794 ac.view().insert(sleNew);
799 {{
"multiple accounts created in a single transaction"}},
803 Account
const A3{
"A3"};
805 auto const sleA3 = std::make_shared<SLE>(acctKeylet);
806 ac.view().insert(sleA3);
809 Account
const A4{
"A4"};
811 auto const sleA4 = std::make_shared<SLE>(acctKeylet);
812 ac.view().insert(sleA4);
818 {{
"account created with wrong starting sequence number"}},
821 Account
const A3{
"A3"};
823 auto const sleNew = std::make_shared<SLE>(acctKeylet);
824 sleNew->setFieldU32(sfSequence, ac.view().seq() + 1);
825 ac.view().insert(sleNew);
835 using namespace test::jtx;
840 "0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000");
841 auto makeNFTokenIDs = [&firstNFTID](
unsigned int nftCount) {
848 for (
int i = 0; i < nftCount; ++i)
851 *nfTokenTemplate, sfNFToken, [&nftID](
STObject&
object) {
852 object.setFieldH256(sfNFTokenID, nftID);
861 {{
"NFT page has invalid size"}},
865 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(0));
867 ac.view().insert(nftPage);
872 {{
"NFT page has invalid size"}},
876 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(33));
878 ac.view().insert(nftPage);
883 {{
"NFTs on page are not sorted"}},
886 STArray nfTokens = makeNFTokenIDs(2);
890 nftPage->setFieldArray(sfNFTokens, nfTokens);
892 ac.view().insert(nftPage);
897 {{
"NFT contains empty URI"}},
900 STArray nfTokens = makeNFTokenIDs(1);
901 nfTokens[0].setFieldVL(sfURI,
Blob{});
904 nftPage->setFieldArray(sfNFTokens, nfTokens);
906 ac.view().insert(nftPage);
911 {{
"NFT page is improperly linked"}},
915 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
916 nftPage->setFieldH256(
919 ac.view().insert(nftPage);
924 {{
"NFT page is improperly linked"}},
926 Account
const& A1, Account
const& A2,
ApplyContext& ac) {
928 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
929 nftPage->setFieldH256(
932 ac.view().insert(nftPage);
937 {{
"NFT page is improperly linked"}},
941 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
942 nftPage->setFieldH256(sfNextPageMin, nftPage->key());
944 ac.view().insert(nftPage);
949 {{
"NFT page is improperly linked"}},
951 Account
const& A1, Account
const& A2,
ApplyContext& ac) {
952 STArray nfTokens = makeNFTokenIDs(1);
955 ++(nfTokens[0].getFieldH256(sfNFTokenID))));
956 nftPage->setFieldArray(sfNFTokens, std::move(nfTokens));
957 nftPage->setFieldH256(
960 ac.view().insert(nftPage);
965 {{
"NFT found in incorrect page"}},
968 STArray nfTokens = makeNFTokenIDs(2);
971 (nfTokens[1].getFieldH256(sfNFTokenID))));
972 nftPage->setFieldArray(sfNFTokens, std::move(nfTokens));
974 ac.view().insert(nftPage);
982 using namespace test::jtx;
986 {{
"permissioned domain with no rules."}},
987 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
989 auto slePd = std::make_shared<SLE>(pdKeylet);
990 slePd->setAccountID(sfOwner, A1);
991 slePd->setFieldU32(sfSequence, 10);
993 ac.view().insert(slePd);
1000 testcase <<
"PermissionedDomain 2";
1004 {{
"permissioned domain bad credentials size " +
1006 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1008 auto slePd = std::make_shared<SLE>(pdKeylet);
1009 slePd->setAccountID(sfOwner, A1);
1010 slePd->setFieldU32(sfSequence, 10);
1012 STArray credentials(sfAcceptedCredentials, tooBig);
1016 cred.setAccountID(sfIssuer, A2);
1021 Slice(credType.c_str(), credType.size()));
1024 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1025 ac.view().insert(slePd);
1032 testcase <<
"PermissionedDomain 3";
1034 {{
"permissioned domain credentials aren't sorted"}},
1035 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1037 auto slePd = std::make_shared<SLE>(pdKeylet);
1038 slePd->setAccountID(sfOwner, A1);
1039 slePd->setFieldU32(sfSequence, 10);
1041 STArray credentials(sfAcceptedCredentials, 2);
1045 cred.setAccountID(sfIssuer, A2);
1050 Slice(credType.c_str(), credType.size()));
1053 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1054 ac.view().insert(slePd);
1061 testcase <<
"PermissionedDomain 4";
1063 {{
"permissioned domain credentials aren't unique"}},
1064 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1066 auto slePd = std::make_shared<SLE>(pdKeylet);
1067 slePd->setAccountID(sfOwner, A1);
1068 slePd->setFieldU32(sfSequence, 10);
1070 STArray credentials(sfAcceptedCredentials, 2);
1074 cred.setAccountID(sfIssuer, A2);
1075 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1078 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1079 ac.view().insert(slePd);
1089 Account
const& A2) {
1090 sle->setAccountID(sfOwner, A1);
1091 sle->setFieldU32(sfSequence, 10);
1093 STArray credentials(sfAcceptedCredentials, 2);
1097 cred.setAccountID(sfIssuer, A2);
1100 sfCredentialType,
Slice(credType.c_str(), credType.size()));
1103 sle->setFieldArray(sfAcceptedCredentials, credentials);
1107 testcase <<
"PermissionedDomain Set 1";
1109 {{
"permissioned domain with no rules."}},
1110 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1112 auto slePd = std::make_shared<SLE>(pdKeylet);
1115 createPD(ac, slePd, A1, A2);
1119 STArray credentials(sfAcceptedCredentials, 2);
1120 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1130 testcase <<
"PermissionedDomain Set 2";
1132 {{
"permissioned domain bad credentials size " +
1134 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1136 auto slePd = std::make_shared<SLE>(pdKeylet);
1139 createPD(ac, slePd, A1, A2);
1143 STArray credentials(sfAcceptedCredentials, tooBig);
1148 cred.setAccountID(sfIssuer, A2);
1152 Slice(credType.c_str(), credType.size()));
1156 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1166 testcase <<
"PermissionedDomain Set 3";
1168 {{
"permissioned domain credentials aren't sorted"}},
1169 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1171 auto slePd = std::make_shared<SLE>(pdKeylet);
1174 createPD(ac, slePd, A1, A2);
1178 STArray credentials(sfAcceptedCredentials, 2);
1182 cred.setAccountID(sfIssuer, A2);
1187 Slice(credType.c_str(), credType.size()));
1191 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1201 testcase <<
"PermissionedDomain Set 4";
1203 {{
"permissioned domain credentials aren't unique"}},
1204 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1206 auto slePd = std::make_shared<SLE>(pdKeylet);
1209 createPD(ac, slePd, A1, A2);
1213 STArray credentials(sfAcceptedCredentials, 2);
1217 cred.setAccountID(sfIssuer, A2);
1219 sfCredentialType,
Slice(
"cred_type", 9));
1222 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1254BEAST_DEFINE_TESTSUITE(Invariants, ledger,
ripple);
A generic endpoint for log messages.
testcase_t testcase
Memberspace for declaring test cases.
State information when applying a tx.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
void testAccountRootsDeletedClean()
void testTransfersNotFrozen()
void testAccountRootsNotRemoved()
void testTransactionFeeCheck()
void doInvariantCheck(std::vector< std::string > const &expect_logs, Precheck const &precheck, XRPAmount fee=XRPAmount{}, STTx tx=STTx{ttACCOUNT_SET, [](STObject &) {}}, std::initializer_list< TER > ters={tecINVARIANT_FAILED, tefINVARIANT_FAILED}, Preclose const &preclose={})
Run a specific test case to put the ledger into a state that will be detected by an invariant.
void testValidNewAccountRoot()
void testXRPBalanceCheck()
std::function< bool(test::jtx::Account const &a, test::jtx::Account const &b, test::jtx::Env &env)> Preclose
void run() override
Runs the suite.
void testNFTokenPageInvariants()
void testNoDeepFreezeTrustLinesWithoutFreeze()
void testNoXRPTrustLine()
void testPermissionedDomainInvariants()
A currency issued by an account.
Defines the fields and their attributes within a STObject.
AccountID const & getIssuer() const
void push_back(STObject const &object)
void setFieldAmount(SField const &field, STAmount const &)
static STObject makeInnerObject(SField const &name)
An immutable linear range of bytes.
Immutable cryptographic account descriptor.
A transaction testing environment.
Keylet permissionedDomain(AccountID const &account, std::uint32_t seq) noexcept
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.
Keylet const & amendments() noexcept
The index of the amendment table.
Keylet nftpage(Keylet const &k, uint256 const &token)
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Keylet nftpage_min(AccountID const &owner)
NFT page keylets.
Keylet nftpage_max(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet offer(AccountID const &id, std::uint32_t seq) noexcept
An offer from an account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
constexpr std::uint32_t tfSetDeepFreeze
std::size_t constexpr maxPermissionedDomainCredentialsArraySize
The maximum number of credentials can be passed in array for permissioned domain.
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
std::array< keyletDesc< AccountID const & >, 6 > const directAccountKeylets
TER trustDelete(ApplyView &view, std::shared_ptr< SLE > const &sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
std::string to_string(base_uint< Bits, Tag > const &a)
LedgerEntryType
Identifiers for on-ledger objects.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetFreeze
A pair of SHAMap key and LedgerEntryType.