1#include <test/app/invariants/InvariantsBase.h>
2#include <test/jtx/AMM.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/pay.h>
8#include <test/jtx/token.h>
9#include <test/jtx/trust.h>
10#include <test/jtx/vault.h>
11#include <test/unit_test/SuiteJournal.h>
13#include <xrpl/basics/Number.h>
14#include <xrpl/basics/base_uint.h>
15#include <xrpl/basics/chrono.h>
16#include <xrpl/beast/unit_test/suite.h>
17#include <xrpl/beast/utility/Journal.h>
18#include <xrpl/beast/utility/Zero.h>
19#include <xrpl/ledger/ApplyView.h>
20#include <xrpl/ledger/OpenView.h>
21#include <xrpl/ledger/ReadView.h>
22#include <xrpl/ledger/helpers/AccountRootHelpers.h>
23#include <xrpl/ledger/helpers/RippleStateHelpers.h>
24#include <xrpl/protocol/AccountID.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/Indexes.h>
27#include <xrpl/protocol/Issue.h>
28#include <xrpl/protocol/Keylet.h>
29#include <xrpl/protocol/LedgerFormats.h>
30#include <xrpl/protocol/MPTIssue.h>
31#include <xrpl/protocol/Protocol.h>
32#include <xrpl/protocol/Rules.h>
33#include <xrpl/protocol/SField.h>
34#include <xrpl/protocol/STAmount.h>
35#include <xrpl/protocol/STLedgerEntry.h>
36#include <xrpl/protocol/STObject.h>
37#include <xrpl/protocol/STTx.h>
38#include <xrpl/protocol/SeqProxy.h>
39#include <xrpl/protocol/SystemParameters.h>
40#include <xrpl/protocol/TER.h>
41#include <xrpl/protocol/TxFormats.h>
42#include <xrpl/protocol/XRPAmount.h>
43#include <xrpl/tx/ApplyContext.h>
44#include <xrpl/tx/Transactor.h>
45#include <xrpl/tx/applySteps.h>
46#include <xrpl/tx/invariants/InvariantRunner.h>
71 {{
"XRP net change was positive: 500"}},
77 auto amt = sle->getFieldAmount(sfBalance);
78 sle->setFieldAmount(sfBalance, amt +
STAmount{500});
79 ac.view().update(sle);
92 {{
"an account root was deleted"}},
102 ac.view().erase(sle);
112 {{
"account deletion succeeded without deleting an account"}},
120 {{
"account deletion succeeded but deleted multiple accounts"}},
125 if (!sleA1 || !sleA2)
132 ac.view().erase(sleA1);
133 ac.view().erase(sleA2);
144 testcase <<
"account root deletion left artifact";
147 {{
"account deletion left behind a non-zero balance"}},
151 auto const a1 =
A1.id();
155 if (!BEAST_EXPECT(*sleA1->at(sfBalance) !=
beast::kZero))
158 ac.view().erase(sleA1);
166 {{
"account deletion left behind a non-zero owner count"}},
170 auto const a1 =
A1.id();
178 BEAST_EXPECT(sleA1->at(sfOwnerCount) == 0);
181 ac.view().erase(sleA1);
189 {{
"account deletion left behind a sponsorship field"}},
195 sleA1->setFieldU32(sfSponsoredOwnerCount, 1);
197 ac.view().erase(sleA1);
205 {{
"account deletion left behind a sponsorship field"}},
211 sleA1->setFieldU32(sfSponsoringOwnerCount, 1);
213 ac.view().erase(sleA1);
221 {{
"account deletion left behind a sponsorship field"}},
223 auto const a1Id = a1.
id();
228 sleA1->setFieldU32(sfSponsoringAccountCount, 1);
230 ac.view().erase(sleA1);
238 {{
"account deletion left behind a sponsorship field"}},
244 sleA1->setAccountID(sfSponsor, a2.id());
246 ac.view().erase(sleA1);
255 {{
"account deletion left behind a sponsorship field"}},
261 sleA1->setAccountID(sfSponsor, a2.id());
263 ac.view().erase(sleA1);
275 using namespace std::string_literals;
278 {{
"account deletion left behind a "s + type.cStr() +
" object"}},
283 auto const a1 =
A1.
id();
290 ac.view().insert(newSLE);
295 ac.view().erase(sleA1);
305 {{
"account deletion left behind a NFTokenPage object"}},
315 sle->at(sfOwnerCount) = 0;
316 ac.view().erase(sle);
335 {{
"account deletion left behind a DirectoryNode object"}},
343 BEAST_EXPECT(sle->at(~sfAMMID));
344 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
350 sle->at(sfOwnerCount) = 0;
351 ac.view().erase(sle);
361 AMM const amm(env, a1,
XRP(100), a1[
"USD"](50));
362 ammAcctID =
amm.ammAccount();
363 ammKey =
amm.ammID();
364 ammIssue =
amm.lptIssue();
368 {{
"account deletion left behind a AMM object"}},
377 BEAST_EXPECT(sle->at(~sfAMMID));
378 BEAST_EXPECT(sle->at(~sfAMMID) == ammKey);
380 for (
auto const& trustKeylet :
383 auto const line = ac.view().peek(trustKeylet);
389 STAmount const lowLimit = line->at(sfLowLimit);
390 STAmount const highLimit = line->at(sfHighLimit);
400 auto const ammSle = ac.view().peek(
keylet::amm(ammKey));
401 if (!BEAST_EXPECT(ammSle))
406 ac.view().dirRemove(ownerDirKeylet, ammSle->at(sfOwnerNode), ammKey,
false));
408 !ac.view().exists(ownerDirKeylet) || ac.view().emptyDirDelete(ownerDirKeylet));
414 sle->at(sfOwnerCount) = 0;
415 ac.view().erase(sle);
425 AMM const amm(env, a1,
XRP(100), a1[
"USD"](50));
426 ammAcctID =
amm.ammAccount();
427 ammKey =
amm.ammID();
428 ammIssue =
amm.lptIssue();
437 testcase <<
"ledger entry types don't match";
439 {{
"ledger entry type mismatch"}, {
"XRP net change of -1000000000 doesn't match fee 0"}},
446 ac.rawView().rawReplace(sleNew);
451 {{
"invalid ledger entry type added"}},
467 ac.view().insert(sleNew);
479 {{
"Cannot return non-native STAmount as XRPAmount"}},
485 STAmount const nonNative(a2[
"USD"](51));
486 sle->setFieldAmount(sfBalance, nonNative);
487 ac.view().update(sle);
492 {{
"incorrect account XRP balance"}, {
"XRP net change was positive: 99999999000000001"}},
501 BEAST_EXPECT(!sle->getFieldAmount(sfBalance).negative());
502 ac.view().update(sle);
507 {{
"incorrect account XRP balance"},
508 {
"XRP net change of -1000000001 doesn't match fee 0"}},
514 sle->setFieldAmount(sfBalance,
STAmount{1,
true});
515 BEAST_EXPECT(sle->getFieldAmount(sfBalance).negative());
516 ac.view().update(sle);
525 using namespace std::string_literals;
526 testcase <<
"Transaction fee checks";
529 {{
"fee paid was negative: -1"}, {
"XRP net change of 0 doesn't match fee -1"}},
540 {{
"fee paid is 20 exceeds fee specified in transaction."},
541 {
"XRP net change of 0 doesn't match fee 20"}},
561 sleNew->setAccountID(sfAccount, a1.
id());
562 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
563 sleNew->setFieldAmount(sfTakerPays,
XRP(-1));
564 ac.view().insert(sleNew);
576 sleNew->setAccountID(sfAccount, a1.
id());
577 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
578 sleNew->setFieldAmount(sfTakerPays, a1[
"USD"](10));
579 sleNew->setFieldAmount(sfTakerGets,
XRP(-1));
580 ac.view().insert(sleNew);
592 sleNew->setAccountID(sfAccount, a1.
id());
593 sleNew->setFieldU32(sfSequence, (*sle)[sfSequence]);
594 sleNew->setFieldAmount(sfTakerPays,
XRP(10));
595 sleNew->setFieldAmount(sfTakerGets,
XRP(11));
596 ac.view().insert(sleNew);
605 testcase <<
"valid new account root";
608 {{
"account root created illegally"}},
615 ac.view().insert(sleNew);
620 {{
"multiple accounts created in a single transaction"}},
627 ac.view().insert(sleA3);
633 ac.view().insert(sleA4);
639 {{
"account created with wrong starting sequence number"}},
645 sleNew->setFieldU32(sfSequence, ac.view().seq() + 1);
646 ac.view().insert(sleNew);
653 {{
"pseudo-account created by a wrong transaction type"}},
658 sleNew->setFieldU32(sfSequence, 0);
659 sleNew->setFieldH256(sfAMMID,
UInt256(1));
660 sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple);
661 ac.view().insert(sleNew);
668 {{
"account created with wrong starting sequence number"}},
673 sleNew->setFieldU32(sfSequence, ac.view().seq());
674 sleNew->setFieldH256(sfAMMID,
UInt256(1));
675 sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth);
676 ac.view().insert(sleNew);
683 {{
"pseudo-account created with wrong flags"}},
688 sleNew->setFieldU32(sfSequence, 0);
689 sleNew->setFieldH256(sfAMMID,
UInt256(1));
690 sleNew->setFieldU32(sfFlags, lsfDisableMaster | lsfDefaultRipple);
691 ac.view().insert(sleNew);
698 {{
"pseudo-account created with wrong flags"}},
703 sleNew->setFieldU32(sfSequence, 0);
704 sleNew->setFieldH256(sfAMMID,
UInt256(1));
707 lsfDisableMaster | lsfDefaultRipple | lsfDepositAuth | lsfRequireDestTag);
708 ac.view().insert(sleNew);
718 testcase(
"no modified unmodifiable fields");
727 return BEAST_EXPECT(env.le(loanBrokerKeylet));
736 [](
SLE::pointer& sle) { sle->at(sfAccount) = sle->at(sfOwner); },
737 [](
SLE::pointer& sle) { sle->at(sfOwner) = sle->at(sfAccount); },
738 [](
SLE::pointer& sle) { sle->at(sfManagementFeeRate) += 1; },
739 [](
SLE::pointer& sle) { sle->at(sfCoverRateMinimum) += 1; },
740 [](
SLE::pointer& sle) { sle->at(sfCoverRateLiquidation) += 1; },
741 [](
SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; },
742 [](
SLE::pointer& sle) { sle->at(sfLedgerIndex) = sle->at(sfVaultID).value(); },
745 for (
auto const& mod : mods)
748 {{
"changed an unchangeable field"}},
750 auto sle = ac.view().peek(loanBrokerKeylet);
754 ac.view().update(sle);
777 auto const cases = std::to_array<Case>({
778 {.before = lsfLoanOverpayment,
780 .expected =
"lsfLoanOverpayment flag toggled on immutable ledger entry"},
782 .after = lsfLoanOverpayment,
783 .expected =
"lsfLoanOverpayment flag toggled on immutable ledger entry"},
784 {.before = lsfLoanDefault,
786 .expected =
"lsfLoanDefault flag cleared on immutable ledger entry"},
789 for (
auto const& c : cases)
798 auto const brokerKeylet =
803 sleLoan->at(sfPrincipalOutstanding) =
Number(100);
804 sleLoan->at(sfTotalValueOutstanding) =
Number(150);
805 sleLoan->setFieldU32(sfPaymentRemaining, 1);
806 sleLoan->setFieldU32(sfFlags, c.before);
817 auto sleLoan = ac.
view().
peek(loanKeylet);
818 if (!BEAST_EXPECT(sleLoan))
820 sleLoan->setFieldU32(sfFlags, c.after);
824 if (!BEAST_EXPECT(transactor))
826 TER const result = transactor->checkInvariants(
829 BEAST_EXPECT(sink.
messages().
str().contains(c.expected));
839 auto const cases = std::to_array<std::pair<std::uint32_t, std::uint32_t>>({
840 {lsfLoanOverpayment, 0},
841 {0, lsfLoanOverpayment},
844 for (
auto const& [before,
after] : cases)
846 Env env{*
this,
all_ - featureLendingProtocolV1_1};
853 auto const brokerKeylet =
858 sleLoan->at(sfPrincipalOutstanding) =
Number(100);
859 sleLoan->at(sfTotalValueOutstanding) =
Number(150);
860 sleLoan->setFieldU32(sfPaymentRemaining, 1);
861 sleLoan->setFieldU32(sfFlags, before);
872 auto sleLoan = ac.
view().
peek(loanKeylet);
873 if (!BEAST_EXPECT(sleLoan))
875 sleLoan->setFieldU32(sfFlags,
after);
879 if (!BEAST_EXPECT(transactor))
881 TER const result = transactor->checkInvariants(
884 BEAST_EXPECT(sink.
messages().
str().contains(
"Loan Overpayment flag changed"));
900 bool expectFireIntegral;
901 bool expectFireTolerant;
906 auto const cases = std::to_array<Case>({
907 {.totalValue =
Number(100),
909 .managementFee =
Number(0),
910 .expectFireIntegral =
false,
911 .expectFireTolerant =
false},
912 {.totalValue =
Number(99),
914 .managementFee =
Number(0),
915 .expectFireIntegral =
true,
916 .expectFireTolerant =
false},
917 {.totalValue =
Number(100),
919 .managementFee =
Number(0),
920 .expectFireIntegral =
true,
921 .expectFireTolerant =
false},
922 {.totalValue =
Number(100),
924 .managementFee =
Number(1),
925 .expectFireIntegral =
true,
926 .expectFireTolerant =
false},
927 {.totalValue =
Number(98),
929 .managementFee =
Number(0),
930 .expectFireIntegral =
true,
931 .expectFireTolerant =
true},
934 for (
bool const integralAsset : {
true,
false})
936 for (
auto const& c : cases)
940 Account const issuer{
"issuer"};
941 env.
fund(
XRP(1000), a1, issuer);
951 env(
trust(a1, iouAsset(1000)));
952 env(
pay(issuer, a1, iouAsset(1000)));
958 if (!BEAST_EXPECT(env.
le(brokerKeylet)))
964 auto const loanKeylet =
970 sleLoan->at(sfPrincipalOutstanding) =
Number(100);
971 sleLoan->at(sfTotalValueOutstanding) =
Number(100);
972 sleLoan->at(sfManagementFeeOutstanding) =
Number(0);
973 sleLoan->at(sfLoanScale) = 0;
974 sleLoan->setFieldU32(sfPaymentRemaining, 1);
985 auto sleLoan = ac.
view().
peek(loanKeylet);
986 if (!BEAST_EXPECT(sleLoan))
988 sleLoan->at(sfTotalValueOutstanding) = c.totalValue;
989 sleLoan->at(sfPrincipalOutstanding) = c.principal;
990 sleLoan->at(sfManagementFeeOutstanding) = c.managementFee;
994 if (!BEAST_EXPECT(transactor))
996 TER const result = transactor->checkInvariants(
999 if (integralAsset ? c.expectFireIntegral : c.expectFireTolerant)
1002 BEAST_EXPECT(messages.contains(
"Loan interest due is negative"));
1008 BEAST_EXPECT(!messages.contains(
"Loan interest due is negative"));
1017 Preclose const createClosedEndedVault = [&,
this](
1019 auto const sub = env.now().time_since_epoch().count() + 60;
1021 Vault const vault{env};
1022 auto [tx,
keylet] = vault.create(
1026 .subscriptionDate = sub,
1027 .redemptionDate = red});
1029 closedEndedVaultKeylet =
keylet;
1030 return BEAST_EXPECT(env.le(closedEndedVaultKeylet));
1039 [](
SLE::pointer& sle) { sle->at(sfSubscriptionDate) += 1; },
1040 [](
SLE::pointer& sle) { sle->at(sfRedemptionDate) += 1; },
1043 for (
auto const& mod : mods)
1046 {{
"changed an unchangeable field"}},
1048 auto sle = ac.view().peek(closedEndedVaultKeylet);
1052 ac.view().update(sle);
1058 createClosedEndedVault);
1064 [](
SLE::pointer& sle) { sle->at(sfLedgerEntryType) += 1; },
1068 for (
auto const& mod : mods)
1071 {{
"changed an unchangeable field"}},
1077 ac.view().update(sle);
1088 bool const fixEnabled = features[fixCleanup3_1_3];
1096 auto const insertOrderedTrustLinePair = [](
ApplyContext& ac,
1100 auto const& badConfig,
1101 auto const& goodConfig) {
1102 char const*
const c1 =
"USD";
1103 char const*
const c2 =
"EUR";
1107 bool const k1First = k1.key < k2.key;
1108 auto const& badKey = k1First ? k1 : k2;
1109 auto const& goodKey = k1First ? k2 : k1;
1110 Issue const badIss{k1First ? a1[c1].currency : a1[c2].currency, a1.id()};
1111 Issue const goodIss{k1First ? a1[c2].currency : a1[c1].currency, a1.id()};
1114 badConfig(*sleBad, badIss);
1118 goodConfig(*sleGood, goodIss);
1134 insertOrderedTrustLinePair(
1152 fixEnabled ? failTers : passTers);
1159 "normal freeze was created"}}
1163 insertOrderedTrustLinePair(
1182 fixEnabled ? failTers : passTers);
1204 sleNew->setFieldU64(sfLockedAmount, 10);
1217 using namespace std::string_literals;
1220 auto const expectMessage =
1221 "SponsoredOwnerCount does not equal SponsoringOwnerCount delta.";
1228 sle->setFieldU32(sfSponsoredOwnerCount, 1);
1229 ac.view().update(sle);
1238 sle->setFieldU32(sfSponsoringOwnerCount, 1);
1239 ac.view().update(sle);
1245 auto const expectMessage =
1246 "OwnerCount must be greater than or equal to SponsoredOwnerCount.";
1253 sle->setFieldU32(sfOwnerCount, 0);
1254 sle->setFieldU32(sfSponsoredOwnerCount, 1);
1255 ac.view().update(sle);
1260 sle2->setFieldU32(sfSponsoringOwnerCount, 1);
1261 ac.view().update(sle2);
1267 auto const expectMessage =
1268 "SponsoredObjectOwnerCount does not equal SponsoredOwnerCount delta.";
1277 check->setAccountID(sfSponsor, a2.id());
1278 ac.view().update(
check);
1292 auto const expectMessage =
1293 "Invariant failed: Net delta of SponsoringAccountCount does "
1294 "not match net delta of sfSponsor presence.";
1301 sle->setFieldU32(sfSponsoringAccountCount, 1);
1302 ac.view().update(sle);
1311 sle->setAccountID(sfSponsor, a2.id());
1312 ac.view().update(sle);
1321 testcase <<
"object has pseudo-account";
1322 using namespace jtx;
1324 auto const amendments =
all_ | fixCleanup3_3_0;
1330 Env{*
this, amendments},
1331 {{
"deleted Vault without deleting its pseudo-account"}},
1333 auto sle = ac.view().peek(vaultKeylet);
1336 ac.view().erase(sle);
1343 Vault const vault{env};
1344 auto [tx,
keylet] = vault.create({.owner = a1, .asset =
xrpIssue()});
1356 Env{*
this, amendments},
1357 {{
"deleted AMM without deleting its pseudo-account"}},
1362 ac.view().erase(sle);
1369 env.fund(
XRP(1'000), gw);
1370 AMM const amm(env, gw,
XRP(100), gw[
"USD"](100));
1371 ammID =
amm.ammID();
1380 Env{*
this, amendments},
1381 {{
"deleted LoanBroker without deleting its pseudo-account"}},
1383 auto sle = ac.view().peek(loanBrokerKeylet);
1386 ac.view().erase(sle);
1395 return BEAST_EXPECT(env.le(loanBrokerKeylet));
1403 Env env{*
this, amendments};
1413 sleVault->makeFieldAbsent(sfAccount);
1423 auto sle = ac.
view().
peek(vaultKeylet);
1424 if (!BEAST_EXPECT(sle))
1429 if (!BEAST_EXPECT(transactor))
1431 TER const result = transactor->checkInvariants(
1434 BEAST_EXPECT(sink.
messages().
str().contains(
"is missing pseudo-account field"));
1442 using namespace jtx;
1449 enum class ThrowFrom { VisitEntry, Finalize };
1453 ThrowFrom
const throwFrom;
1455 explicit ThrowingTxInvariantCheck(ThrowFrom throwFrom) : throwFrom(throwFrom)
1462 if (throwFrom == ThrowFrom::VisitEntry)
1469 if (throwFrom == ThrowFrom::Finalize)
1475 for (
auto const throwFrom : {ThrowFrom::VisitEntry, ThrowFrom::Finalize})
1493 if (!BEAST_EXPECT(sle))
1495 sle->at(sfSequence) = sle->at(sfSequence) + 1;
1498 ThrowingTxInvariantCheck throwing{throwFrom};
1503 BEAST_EXPECT(terExpect == terActual);
1505 "Transaction caused an exception during invariant checks"));
1513 testcase <<
"txCheck finalize returns false";
1514 using namespace jtx;
1547 FailingTxInvariantCheck failing;
1552 BEAST_EXPECT(terExpect == terActual);
1554 "Transaction has failed one or more transaction invariants"));
1558 "Transaction has failed one or more global invariants"));
A generic endpoint for log messages.
TestcaseT testcase
Memberspace for declaring test cases.
State information when applying a tx.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void insert(SLE::Ref sle)=0
Insert a new state SLE.
virtual void erase(SLE::Ref sle)=0
Remove a peeked SLE.
virtual void update(SLE::Ref sle)=0
Indicate changes to a peeked SLE.
RAII class to set and restore the current transaction rules.
A currency issued by an account.
constexpr MPTID const & getMptID() const
Number is a floating point type that can represent a wide range of values.
Writable ledger view that accumulates state and tx changes.
void rawInsert(SLE::Ref sle) override
Unconditionally insert a state item.
Rules const & rules() const override
Returns the tx processing rules.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
AccountID const & getIssuer() const
std::shared_ptr< STLedgerEntry > pointer
std::shared_ptr< STLedgerEntry const > const & ConstRef
void setFieldU32(SField const &field, std::uint32_t)
void setFieldAmount(SField const &field, STAmount const &)
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Runtime interface for a transaction-specific invariant check.
Keylet createLoanBroker(jtx::Account const &a, jtx::Env &env, jtx::PrettyAsset const &asset)
test::jtx::Env makeEnv(FeatureBitset features)
void doInvariantCheck(std::vector< std::string > const &expectLogs, Precheck const &precheck, XRPAmount fee=XRPAmount{}, STTx tx=STTx{ttACCOUNT_SET, [](STObject &) {}}, std::initializer_list< TER > ters={tecINVARIANT_FAILED, tefINVARIANT_FAILED}, Preclose const &preclose={}, TxAccount setTxAccount=TxAccount::None, std::source_location const &loc=std::source_location::current(), TER initialResult=tesSUCCESS)
Run a specific test case to put the ledger into a state that will be detected by an invariant.
static SLE::pointer makeLoanSle(UInt256 const &loanBrokerID, std::uint32_t loanSeq, AccountID const &borrower)
std::function< bool(test::jtx::Account const &a, test::jtx::Account const &b, test::jtx::Env &env)> Preclose
void testXRPBalanceCheck()
void testTransactionFeeCheck()
void testNoModifiedUnmodifiableFields()
void testInvariantOverwrite(FeatureBitset features)
void testObjectHasPseudoAccount()
void testAccountRootsNotRemoved()
void testTxCheckException()
void testTxCheckFinalizeFalse()
void run() override
Runs the suite.
void testAccountRootsDeletedClean()
void testValidNewAccountRoot()
std::stringstream const & messages() const
Convenience class to test AMM functionality.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
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::shared_ptr< OpenView const > current() const
Returns the current ledger.
Keylet computation functions.
Keylet escrow(AccountID const &src, SeqProxy const &seq) noexcept
An escrow entry.
Keylet offer(AccountID const &id, SeqProxy const &seq) noexcept
An offer from an account.
Keylet const & amendments() noexcept
The index of the amendment table.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet check(AccountID const &id, SeqProxy const &seq) noexcept
A Check.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet vault(AccountID const &owner, SeqProxy const &seq) noexcept
Keylet loanBroker(AccountID const &owner, SeqProxy const &seq) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet loan(UInt256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
json::Value create(A const &account, A const &dest, STAmount const &sendMax)
Create a check.
json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
XrpT const XRP
Converts to XRP Issue or STAmount.
FeatureBitset testableAmendments()
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
constexpr XRPAmount
Convert XRP to drops (integral types).
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
void increaseOwnerCount(ApplyView &view, SLE::Ref accountSle, SLE::Ref sponsorSle, std::uint32_t count, beast::Journal j)
Increase owner-count fields when the caller supplies the sponsor.
std::string to_string(BaseUInt< Bits, Tag > const &a)
TER checkInvariants(ApplyContext &ctx, TER result, XRPAmount fee, std::optional< std::reference_wrapper< TxInvariantCheck > > txCheck)
Run all protocol invariant checks plus the transaction-specific check in a single pass over the modif...
std::unique_ptr< Transactor > makeTransactor(ApplyContext &ctx)
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
MPTID makeMptID(std::uint32_t const sequence, AccountID const &account)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TERSubset< CanCvtToTER > TER
LedgerEntryType
Identifiers for on-ledger objects.
constexpr std::uint64_t kMaxMpTokenAmount
The maximum amount of MPTokenIssuance.
constexpr XRPAmount kInitialXrp
Configure the native currency.
TER trustDelete(ApplyView &view, SLE::Ref sleRippleState, AccountID const &uLowAccountID, AccountID const &uHighAccountID, beast::Journal j)
std::array< KeyletDesc< AccountID const & >, 6 > const kDirectAccountKeylets
constexpr std::uint32_t kMinInvestmentPeriod
Bounds on the length of a closed-ended vault's Investment phase (RedemptionDate - SubscriptionDate).
A pair of SHAMap key and LedgerEntryType.