21#include <test/jtx/AMM.h>
22#include <test/jtx/Env.h>
23#include <xrpld/app/tx/apply.h>
24#include <xrpld/app/tx/detail/ApplyContext.h>
25#include <xrpld/app/tx/detail/Transactor.h>
26#include <xrpl/beast/utility/Journal.h>
27#include <xrpl/protocol/InnerObjectFormats.h>
28#include <xrpl/protocol/STLedgerEntry.h>
30#include <boost/algorithm/string/predicate.hpp>
79 using namespace test::jtx;
84 Account
const A1{
"A1"};
85 Account
const A2{
"A2"};
86 env.fund(
XRP(1000), A1, A2);
88 BEAST_EXPECT(preclose(A1, A2, env));
91 OpenView ov{*env.current()};
99 env.current()->fees().base,
103 BEAST_EXPECT(precheck(A1, A2, ac));
106 if (!BEAST_EXPECT(ters.
size() == 2))
110 for (
TER const& terExpect : ters)
112 terActual = ac.checkInvariants(terActual, fee);
113 BEAST_EXPECT(terExpect == terActual);
115 sink.messages().str().starts_with(
"Invariant failed:") ||
116 sink.messages().str().starts_with(
117 "Transaction caused an exception"));
120 for (
auto const& m : expect_logs)
123 sink.messages().str().find(m) != std::string::npos);
131 using namespace test::jtx;
134 {{
"XRP net change was positive: 500"}},
135 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
140 auto amt = sle->getFieldAmount(sfBalance);
141 sle->setFieldAmount(sfBalance, amt +
STAmount{500});
142 ac.view().update(sle);
150 using namespace test::jtx;
155 {{
"an account root was deleted"}},
156 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
161 ac.view().erase(sle);
171 {{
"account deletion succeeded without deleting an account"}},
181 {{
"account deletion succeeded but deleted multiple accounts"}},
182 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
186 if (!sleA1 || !sleA2)
188 ac.view().erase(sleA1);
189 ac.view().erase(sleA2);
199 using namespace test::jtx;
200 testcase <<
"account root deletion left artifact";
208 if (!keyletInfo.includeInTests)
210 auto const& keyletfunc = keyletInfo.function;
211 auto const& type = keyletInfo.expectedLEName;
213 using namespace std::string_literals;
216 {{
"account deletion left behind a "s + type.c_str() +
218 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
221 auto const a1 = A1.id();
227 auto const newSLE = std::make_shared<SLE>(key);
228 ac.view().insert(newSLE);
229 ac.view().erase(sleA1);
239 {{
"account deletion left behind a NFTokenPage object"}},
240 [&](Account
const& A1, Account
const&,
ApplyContext& ac) {
245 ac.view().erase(sle);
251 [&](Account
const& A1, Account
const&, Env& env) {
254 env(token::mint(A1));
264 {{
"account deletion left behind a DirectoryNode object"}},
265 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
272 BEAST_EXPECT(sle->at(~sfAMMID));
273 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
275 ac.view().erase(sle);
282 [&](Account
const& A1, Account
const& A2, Env& env) {
285 AMM const amm(env, A1, XRP(100), A1[
"USD"](50));
286 ammAcctID = amm.ammAccount();
287 ammKey = amm.ammID();
288 ammIssue = amm.lptIssue();
292 {{
"account deletion left behind a AMM object"}},
293 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
301 BEAST_EXPECT(sle->at(~sfAMMID));
302 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
304 for (
auto const& trustKeylet :
308 if (
auto const line = ac.view().peek(trustKeylet); !line)
314 STAmount const lowLimit = line->at(sfLowLimit);
315 STAmount const highLimit = line->at(sfHighLimit);
326 auto const ammSle = ac.view().peek(
keylet::amm(ammKey));
327 if (!BEAST_EXPECT(ammSle))
331 BEAST_EXPECT(ac.view().dirRemove(
332 ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey,
false));
334 !ac.view().exists(ownerDirKeylet) ||
335 ac.view().emptyDirDelete(ownerDirKeylet));
337 ac.view().erase(sle);
344 [&](Account
const& A1, Account
const& A2, Env& env) {
347 AMM const amm(env, A1, XRP(100), A1[
"USD"](50));
348 ammAcctID = amm.ammAccount();
349 ammKey = amm.ammID();
350 ammIssue = amm.lptIssue();
358 using namespace test::jtx;
359 testcase <<
"ledger entry types don't match";
361 {{
"ledger entry type mismatch"},
362 {
"XRP net change of -1000000000 doesn't match fee 0"}},
363 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
368 auto const sleNew = std::make_shared<SLE>(ltTICKET, sle->key());
369 ac.rawView().rawReplace(sleNew);
374 {{
"invalid ledger entry type added"}},
375 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
384 auto const sleNew = std::make_shared<SLE>(
390 ac.view().insert(sleNew);
398 using namespace test::jtx;
399 testcase <<
"trust lines with XRP not allowed";
401 {{
"an XRP trust line was created"}},
402 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
404 auto const sleNew = std::make_shared<SLE>(
406 ac.view().insert(sleNew);
414 using namespace test::jtx;
415 testcase <<
"trust lines with deep freeze flag without freeze "
418 {{
"a trust line with deep freeze flag without normal freeze was "
420 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
421 auto const sleNew = std::make_shared<SLE>(
423 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
424 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
428 sleNew->setFieldU32(sfFlags, uFlags);
429 ac.view().insert(sleNew);
434 {{
"a trust line with deep freeze flag without normal freeze was "
436 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
437 auto const sleNew = std::make_shared<SLE>(
439 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
440 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
443 sleNew->setFieldU32(sfFlags, uFlags);
444 ac.view().insert(sleNew);
449 {{
"a trust line with deep freeze flag without normal freeze was "
451 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
452 auto const sleNew = std::make_shared<SLE>(
454 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
455 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
458 sleNew->setFieldU32(sfFlags, uFlags);
459 ac.view().insert(sleNew);
464 {{
"a trust line with deep freeze flag without normal freeze was "
466 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
467 auto const sleNew = std::make_shared<SLE>(
469 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
470 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
473 sleNew->setFieldU32(sfFlags, uFlags);
474 ac.view().insert(sleNew);
479 {{
"a trust line with deep freeze flag without normal freeze was "
481 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
482 auto const sleNew = std::make_shared<SLE>(
484 sleNew->setFieldAmount(sfLowLimit, A1[
"USD"](0));
485 sleNew->setFieldAmount(sfHighLimit, A1[
"USD"](0));
488 sleNew->setFieldU32(sfFlags, uFlags);
489 ac.view().insert(sleNew);
497 using namespace test::jtx;
498 testcase <<
"transfers when frozen";
502 auto const createTrustlines =
503 [&](Account
const& A1, Account
const& A2, Env& env) {
505 env.fund(XRP(1000), G1);
507 env.trust(G1[
"USD"](10000), A1);
508 env.trust(G1[
"USD"](10000), A2);
511 env(pay(G1, A1, G1[
"USD"](1000)));
512 env(pay(G1, A2, G1[
"USD"](1000)));
518 auto const A1FrozenByIssuer =
519 [&](Account
const& A1, Account
const& A2, Env& env) {
520 createTrustlines(A1, A2, env);
527 auto const A1DeepFrozenByIssuer =
528 [&](Account
const& A1, Account
const& A2, Env& env) {
529 A1FrozenByIssuer(A1, A2, env);
536 auto const changeBalances = [&](Account
const& A1,
541 auto const sleA1 = ac.view().peek(
keylet::line(A1, G1[
"USD"]));
542 auto const sleA2 = ac.view().peek(
keylet::line(A2, G1[
"USD"]));
544 sleA1->setFieldAmount(sfBalance, G1[
"USD"](A1Balance));
545 sleA2->setFieldAmount(sfBalance, G1[
"USD"](A2Balance));
547 ac.view().update(sleA1);
548 ac.view().update(sleA2);
553 {{
"Attempting to move frozen funds"}},
554 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
555 changeBalances(A1, A2, ac, -900, -1100);
565 {{
"Attempting to move frozen funds"}},
566 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
567 changeBalances(A1, A2, ac, -900, -1100);
573 A1DeepFrozenByIssuer);
577 {{
"Attempting to move frozen funds"}},
578 [&](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
579 changeBalances(A1, A2, ac, -1100, -900);
585 A1DeepFrozenByIssuer);
591 using namespace test::jtx;
595 {{
"Cannot return non-native STAmount as XRPAmount"}},
596 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
601 STAmount const nonNative(A2[
"USD"](51));
602 sle->setFieldAmount(sfBalance, nonNative);
603 ac.view().update(sle);
608 {{
"incorrect account XRP balance"},
609 {
"XRP net change was positive: 99999999000000001"}},
610 [
this](Account
const& A1, Account
const&,
ApplyContext& ac) {
617 sle->setFieldAmount(sfBalance,
INITIAL_XRP + drops(1));
618 BEAST_EXPECT(!sle->getFieldAmount(sfBalance).negative());
619 ac.view().update(sle);
624 {{
"incorrect account XRP balance"},
625 {
"XRP net change of -1000000001 doesn't match fee 0"}},
626 [
this](Account
const& A1, Account
const&,
ApplyContext& ac) {
631 sle->setFieldAmount(sfBalance,
STAmount{1,
true});
632 BEAST_EXPECT(sle->getFieldAmount(sfBalance).negative());
633 ac.view().update(sle);
641 using namespace test::jtx;
642 using namespace std::string_literals;
643 testcase <<
"Transaction fee checks";
646 {{
"fee paid was negative: -1"},
647 {
"XRP net change of 0 doesn't match fee -1"}},
648 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
653 {
"XRP net change of 0 doesn't match fee "s +
655 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
659 {{
"fee paid is 20 exceeds fee specified in transaction."},
660 {
"XRP net change of 0 doesn't match fee 20"}},
661 [](Account
const&, Account
const&,
ApplyContext&) {
return true; },
671 using namespace test::jtx;
675 {{
"offer with a bad amount"}},
676 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
681 auto sleNew = std::make_shared<SLE>(
683 sleNew->setAccountID(sfAccount, A1.id());
684 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
685 sleNew->setFieldAmount(sfTakerPays, XRP(-1));
686 ac.view().insert(sleNew);
691 {{
"offer with a bad amount"}},
692 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
697 auto sleNew = std::make_shared<SLE>(
699 sleNew->setAccountID(sfAccount, A1.id());
700 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
701 sleNew->setFieldAmount(sfTakerPays, A1[
"USD"](10));
702 sleNew->setFieldAmount(sfTakerGets, XRP(-1));
703 ac.view().insert(sleNew);
708 {{
"offer with a bad amount"}},
709 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
714 auto sleNew = std::make_shared<SLE>(
716 sleNew->setAccountID(sfAccount, A1.id());
717 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
718 sleNew->setFieldAmount(sfTakerPays, XRP(10));
719 sleNew->setFieldAmount(sfTakerGets, XRP(11));
720 ac.view().insert(sleNew);
728 using namespace test::jtx;
732 {{
"Cannot return non-native STAmount as XRPAmount"}},
733 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
738 auto sleNew = std::make_shared<SLE>(
741 sleNew->setFieldAmount(sfAmount, nonNative);
742 ac.view().insert(sleNew);
747 {{
"XRP net change of -1000000 doesn't match fee 0"},
748 {
"escrow specifies invalid amount"}},
749 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
754 auto sleNew = std::make_shared<SLE>(
756 sleNew->setFieldAmount(sfAmount, XRP(-1));
757 ac.view().insert(sleNew);
762 {{
"XRP net change was positive: 100000000000000001"},
763 {
"escrow specifies invalid amount"}},
764 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
769 auto sleNew = std::make_shared<SLE>(
773 sleNew->setFieldAmount(sfAmount,
INITIAL_XRP + drops(1));
774 ac.view().insert(sleNew);
782 using namespace test::jtx;
783 testcase <<
"valid new account root";
786 {{
"account root created by a non-Payment"}},
790 Account
const A3{
"A3"};
792 auto const sleNew = std::make_shared<SLE>(acctKeylet);
793 ac.view().insert(sleNew);
798 {{
"multiple accounts created in a single transaction"}},
802 Account
const A3{
"A3"};
804 auto const sleA3 = std::make_shared<SLE>(acctKeylet);
805 ac.view().insert(sleA3);
808 Account
const A4{
"A4"};
810 auto const sleA4 = std::make_shared<SLE>(acctKeylet);
811 ac.view().insert(sleA4);
817 {{
"account created with wrong starting sequence number"}},
820 Account
const A3{
"A3"};
822 auto const sleNew = std::make_shared<SLE>(acctKeylet);
823 sleNew->setFieldU32(sfSequence, ac.view().seq() + 1);
824 ac.view().insert(sleNew);
834 using namespace test::jtx;
839 "0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000");
840 auto makeNFTokenIDs = [&firstNFTID](
unsigned int nftCount) {
847 for (
int i = 0; i < nftCount; ++i)
850 *nfTokenTemplate, sfNFToken, [&nftID](
STObject&
object) {
851 object.setFieldH256(sfNFTokenID, nftID);
860 {{
"NFT page has invalid size"}},
864 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(0));
866 ac.view().insert(nftPage);
871 {{
"NFT page has invalid size"}},
875 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(33));
877 ac.view().insert(nftPage);
882 {{
"NFTs on page are not sorted"}},
885 STArray nfTokens = makeNFTokenIDs(2);
889 nftPage->setFieldArray(sfNFTokens, nfTokens);
891 ac.view().insert(nftPage);
896 {{
"NFT contains empty URI"}},
899 STArray nfTokens = makeNFTokenIDs(1);
900 nfTokens[0].setFieldVL(sfURI,
Blob{});
903 nftPage->setFieldArray(sfNFTokens, nfTokens);
905 ac.view().insert(nftPage);
910 {{
"NFT page is improperly linked"}},
914 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
915 nftPage->setFieldH256(
918 ac.view().insert(nftPage);
923 {{
"NFT page is improperly linked"}},
925 Account
const& A1, Account
const& A2,
ApplyContext& ac) {
927 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
928 nftPage->setFieldH256(
931 ac.view().insert(nftPage);
936 {{
"NFT page is improperly linked"}},
940 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
941 nftPage->setFieldH256(sfNextPageMin, nftPage->key());
943 ac.view().insert(nftPage);
948 {{
"NFT page is improperly linked"}},
950 Account
const& A1, Account
const& A2,
ApplyContext& ac) {
951 STArray nfTokens = makeNFTokenIDs(1);
954 ++(nfTokens[0].getFieldH256(sfNFTokenID))));
955 nftPage->setFieldArray(sfNFTokens, std::move(nfTokens));
956 nftPage->setFieldH256(
959 ac.view().insert(nftPage);
964 {{
"NFT found in incorrect page"}},
967 STArray nfTokens = makeNFTokenIDs(2);
970 (nfTokens[1].getFieldH256(sfNFTokenID))));
971 nftPage->setFieldArray(sfNFTokens, std::move(nfTokens));
973 ac.view().insert(nftPage);
981 using namespace test::jtx;
985 {{
"permissioned domain with no rules."}},
986 [](Account
const& A1, Account
const&,
ApplyContext& ac) {
988 auto slePd = std::make_shared<SLE>(pdKeylet);
989 slePd->setAccountID(sfOwner, A1);
990 slePd->setFieldU32(sfSequence, 10);
992 ac.view().insert(slePd);
1003 {{
"permissioned domain bad credentials size " +
1005 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1007 auto slePd = std::make_shared<SLE>(pdKeylet);
1008 slePd->setAccountID(sfOwner, A1);
1009 slePd->setFieldU32(sfSequence, 10);
1011 STArray credentials(sfAcceptedCredentials, tooBig);
1015 cred.setAccountID(sfIssuer, A2);
1020 Slice(credType.c_str(), credType.size()));
1023 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1024 ac.view().insert(slePd);
1031 testcase <<
"PermissionedDomain 3";
1033 {{
"permissioned domain credentials aren't sorted"}},
1034 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1036 auto slePd = std::make_shared<SLE>(pdKeylet);
1037 slePd->setAccountID(sfOwner, A1);
1038 slePd->setFieldU32(sfSequence, 10);
1040 STArray credentials(sfAcceptedCredentials, 2);
1044 cred.setAccountID(sfIssuer, A2);
1049 Slice(credType.c_str(), credType.size()));
1052 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1053 ac.view().insert(slePd);
1060 testcase <<
"PermissionedDomain 4";
1062 {{
"permissioned domain credentials aren't unique"}},
1063 [](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1065 auto slePd = std::make_shared<SLE>(pdKeylet);
1066 slePd->setAccountID(sfOwner, A1);
1067 slePd->setFieldU32(sfSequence, 10);
1069 STArray credentials(sfAcceptedCredentials, 2);
1073 cred.setAccountID(sfIssuer, A2);
1074 cred.setFieldVL(sfCredentialType,
Slice(
"cred_type", 9));
1077 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1078 ac.view().insert(slePd);
1088 Account
const& A2) {
1089 sle->setAccountID(sfOwner, A1);
1090 sle->setFieldU32(sfSequence, 10);
1092 STArray credentials(sfAcceptedCredentials, 2);
1096 cred.setAccountID(sfIssuer, A2);
1099 sfCredentialType,
Slice(credType.c_str(), credType.size()));
1102 sle->setFieldArray(sfAcceptedCredentials, credentials);
1106 testcase <<
"PermissionedDomain Set 1";
1108 {{
"permissioned domain with no rules."}},
1109 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1111 auto slePd = std::make_shared<SLE>(pdKeylet);
1114 createPD(ac, slePd, A1, A2);
1118 STArray credentials(sfAcceptedCredentials, 2);
1119 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1129 testcase <<
"PermissionedDomain Set 2";
1131 {{
"permissioned domain bad credentials size " +
1133 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1135 auto slePd = std::make_shared<SLE>(pdKeylet);
1138 createPD(ac, slePd, A1, A2);
1142 STArray credentials(sfAcceptedCredentials, tooBig);
1147 cred.setAccountID(sfIssuer, A2);
1151 Slice(credType.c_str(), credType.size()));
1155 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1165 testcase <<
"PermissionedDomain Set 3";
1167 {{
"permissioned domain credentials aren't sorted"}},
1168 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1170 auto slePd = std::make_shared<SLE>(pdKeylet);
1173 createPD(ac, slePd, A1, A2);
1177 STArray credentials(sfAcceptedCredentials, 2);
1181 cred.setAccountID(sfIssuer, A2);
1186 Slice(credType.c_str(), credType.size()));
1190 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1200 testcase <<
"PermissionedDomain Set 4";
1202 {{
"permissioned domain credentials aren't unique"}},
1203 [createPD](Account
const& A1, Account
const& A2,
ApplyContext& ac) {
1205 auto slePd = std::make_shared<SLE>(pdKeylet);
1208 createPD(ac, slePd, A1, A2);
1212 STArray credentials(sfAcceptedCredentials, 2);
1216 cred.setAccountID(sfIssuer, A2);
1218 sfCredentialType,
Slice(
"cred_type", 9));
1221 slePd->setFieldArray(sfAcceptedCredentials, credentials);
1253BEAST_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.