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/amount.h>
6#include <test/jtx/mpt.h>
7#include <test/jtx/vault.h>
8#include <test/unit_test/SuiteJournal.h>
10#include <xrpl/basics/base_uint.h>
11#include <xrpl/beast/unit_test/suite.h>
12#include <xrpl/beast/utility/Journal.h>
13#include <xrpl/ledger/ApplyView.h>
14#include <xrpl/protocol/AccountID.h>
15#include <xrpl/protocol/Feature.h>
16#include <xrpl/protocol/Indexes.h>
17#include <xrpl/protocol/Issue.h>
18#include <xrpl/protocol/SField.h>
19#include <xrpl/protocol/STAmount.h>
20#include <xrpl/protocol/STLedgerEntry.h>
21#include <xrpl/protocol/STObject.h>
22#include <xrpl/protocol/STTx.h>
23#include <xrpl/protocol/TER.h>
24#include <xrpl/protocol/TxFormats.h>
25#include <xrpl/protocol/UintTypes.h>
26#include <xrpl/protocol/XRPAmount.h>
27#include <xrpl/tx/ApplyContext.h>
28#include <xrpl/tx/applySteps.h>
29#include <xrpl/tx/invariants/AMMInvariant.h>
49 bool const enforceAMMDelete = features[fixCleanup3_3_0];
52 Env env(*
this, features);
56 STAmount const nonZeroLP{lptIssue, 1};
58 auto const makeAMM = [](
STAmount const& lptBalance) {
60 sleAMM->setFieldAmount(sfLPTokenBalance, lptBalance);
64 auto const checkInvariant = [&](
TxType txType,
74 invariant.
visitEntry(
true, makeAMM(*deletedLPBalance),
nullptr);
76 bool const actual = invariant.
finalize(
79 BEAST_EXPECTS(actual == expected,
"unexpected AMM delete invariant result");
81 auto const expectedLogWhenEnforced = enforceAMMDelete ? expectedLog :
"";
82 if (!expectedLogWhenEnforced.empty())
84 BEAST_EXPECTS(messages.contains(expectedLogWhenEnforced), expectedLogWhenEnforced);
88 BEAST_EXPECTS(messages.empty(), messages);
97 "Invariant failed: AMM failed, unexpected AMM deletion by");
103 "Invariant failed: AMMDelete failed, AMM object remained on tesSUCCESS");
109 "Invariant failed: AMMDelete failed, AMM object deleted with non-zero LP balance");
115 "Invariant failed: AMMDelete failed, AMM object deleted when result is not tesSUCCESS");
117 checkInvariant(ttAMM_WITHDRAW,
tesSUCCESS, nonZeroLP,
true,
"");
118 checkInvariant(ttAMM_CLAWBACK,
tesSUCCESS, nonZeroLP,
true,
"");
120 checkInvariant(ttAMM_DELETE,
tesSUCCESS, zeroLP,
true,
"");
121 checkInvariant(ttAMM_WITHDRAW,
tesSUCCESS, zeroLP,
true,
"");
122 checkInvariant(ttAMM_CLAWBACK,
tesSUCCESS, zeroLP,
true,
"");
150 sle->setFieldAmount(sfLPTokenBalance,
STAmount{lptIssue, amount});
154 auto updateLPTokensBadAmount = [&](
ApplyContext& ac, bool) {
155 return updateLPTokensBalance(ac, -1);
157 auto updateLPTokensBadBalance = [&](
ApplyContext& ac, bool) {
158 return updateLPTokensBalance(ac, 200'000'000);
160 auto updateAMM = [&](
ApplyContext& ac, bool) {
return updateLPTokensBalance(ac, 10); };
162 auto updateAMMPool = [&](
ApplyContext& ac,
bool isMPT) {
168 sle->setFieldU64(sfMPTAmount, 1);
175 sle->setFieldAmount(sfBalance,
XRP(1));
180 auto test = [&](
auto const txType,
191 env.fund(
XRP(1'000), gw);
201 AMM const amm(env, gw,
XRP(100), poolAsset(100));
202 ammAccountID =
amm.ammAccount();
204 lptIssue =
amm.lptIssue();
209 for (
bool const isMPT : {
false,
true})
214 for (
auto txType : {ttAMM_CREATE, ttAMM_DEPOSIT, ttAMM_CLAWBACK, ttAMM_WITHDRAW})
217 test(txType, updateLPTokensBadAmount, isMPT);
218 test(txType, updateLPTokensBadBalance, isMPT);
220 for (
auto txType : {ttAMM_BID, ttAMM_VOTE})
222 test(txType, updateAMMPool, isMPT, error);
223 test(txType, updateLPTokensBadAmount, isMPT);
224 test(txType, updateLPTokensBadBalance, isMPT);
226 for (
auto txType : {ttAMM_DELETE, ttCHECK_CASH, ttOFFER_CREATE, ttPAYMENT})
228 test(txType, updateAMM, isMPT);
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 erase(SLE::Ref sle)=0
Remove a peeked SLE.
virtual void update(SLE::Ref sle)=0
Indicate changes to a peeked SLE.
A currency issued by an account.
bool finalize(STTx const &, TER const, XRPAmount const, ReadView const &, beast::Journal const &)
void visitEntry(bool, SLE::ConstRef, SLE::ConstRef)
void run() override
Runs the suite.
void testAMMDeleteInvariants(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.
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.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Test helper for creating, mutating, and asserting MPT and confidential MPT ledger state.
Converts to MPT Issue or STAmount.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
XrpT const XRP
Converts to XRP Issue or STAmount.
FeatureBitset testableAmendments()
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.
TxType
Transaction type identifiers.
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
TER deleteAMMAccount(Sandbox &view, Asset const &asset, Asset const &asset2, beast::Journal j)
Delete trustlines to AMM.
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TERSubset< CanCvtToTER > TER