1#include <test/app/invariants/InvariantsBase.h>
2#include <test/jtx/Account.h>
3#include <test/jtx/amount.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/beast/unit_test/suite.h>
7#include <xrpl/ledger/ApplyView.h>
8#include <xrpl/protocol/AccountID.h>
9#include <xrpl/protocol/Indexes.h>
10#include <xrpl/protocol/InnerObjectFormats.h>
11#include <xrpl/protocol/Issue.h>
12#include <xrpl/protocol/Keylet.h>
13#include <xrpl/protocol/MPTIssue.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/SOTemplate.h>
16#include <xrpl/protocol/STAmount.h>
17#include <xrpl/protocol/STArray.h>
18#include <xrpl/protocol/STLedgerEntry.h>
19#include <xrpl/protocol/STObject.h>
20#include <xrpl/protocol/SeqProxy.h>
21#include <xrpl/protocol/SystemParameters.h>
22#include <xrpl/protocol/UintTypes.h>
23#include <xrpl/tx/ApplyContext.h>
44 {{
"XRP net change of -1000000 doesn't match fee 0"},
45 {
"escrow specifies invalid amount"}},
53 sleNew->setFieldAmount(sfAmount,
XRP(-1));
54 ac.view().insert(sleNew);
59 {{
"XRP net change was positive: 100000000000000001"},
60 {
"escrow specifies invalid amount"}},
71 ac.view().insert(sleNew);
77 {{
"escrow specifies invalid amount"}},
88 sleNew->setFieldAmount(sfAmount, amt);
89 ac.view().insert(sleNew);
95 {{
"escrow specifies invalid amount"}},
106 sleNew->setFieldAmount(sfAmount, amt);
107 ac.view().insert(sleNew);
113 {{
"escrow specifies invalid amount"}},
124 sleNew->setFieldAmount(sfAmount, amt);
125 ac.view().insert(sleNew);
131 {{
"escrow specifies invalid amount"}},
141 ac.view().insert(sleNew);
147 {{
"escrow specifies invalid amount"}},
157 ac.view().insert(sleNew);
163 {{
"escrow specifies invalid amount"}},
172 sleNew->setFieldU64(sfOutstandingAmount, 1);
173 sleNew->setFieldU64(sfLockedAmount, 10);
174 ac.view().insert(sleNew);
180 {{
"escrow specifies invalid amount"}},
190 ac.view().insert(sleNew);
196 {{
"escrow specifies invalid amount"}},
206 ac.view().insert(sleNew);
219 "0000000000000000000000000000000000000001FFFFFFFFFFFFFFFF00000000");
220 auto makeNFTokenIDs = [&firstNFTID](
unsigned int nftCount) {
226 for (
int i = 0; i < nftCount; ++i)
228 STObject newNFToken(*nfTokenTemplate, sfNFToken, [&nftID](
STObject&
object) {
229 object.setFieldH256(sfNFTokenID, nftID);
231 ret.
pushBack(std::move(newNFToken));
238 {{
"NFT page has invalid size"}},
241 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(0));
243 ac.view().insert(nftPage);
248 {{
"NFT page has invalid size"}},
251 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(33));
253 ac.view().insert(nftPage);
258 {{
"NFTs on page are not sorted"}},
260 STArray nfTokens = makeNFTokenIDs(2);
264 nftPage->setFieldArray(sfNFTokens, nfTokens);
266 ac.view().insert(nftPage);
271 {{
"NFT contains empty URI"}},
273 STArray nfTokens = makeNFTokenIDs(1);
274 nfTokens[0].setFieldVL(sfURI,
Blob{});
277 nftPage->setFieldArray(sfNFTokens, nfTokens);
279 ac.view().insert(nftPage);
284 {{
"NFT page is improperly linked"}},
287 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
290 ac.view().insert(nftPage);
295 {{
"NFT page is improperly linked"}},
298 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
301 ac.view().insert(nftPage);
306 {{
"NFT page is improperly linked"}},
309 nftPage->setFieldArray(sfNFTokens, makeNFTokenIDs(1));
310 nftPage->setFieldH256(sfNextPageMin, nftPage->key());
312 ac.view().insert(nftPage);
317 {{
"NFT page is improperly linked"}},
319 STArray nfTokens = makeNFTokenIDs(1);
322 nftPage->setFieldArray(sfNFTokens, nfTokens);
325 ac.view().insert(nftPage);
330 {{
"NFT found in incorrect page"}},
332 STArray nfTokens = makeNFTokenIDs(2);
335 nftPage->setFieldArray(sfNFTokens, nfTokens);
337 ac.view().insert(nftPage);
TestcaseT testcase
Memberspace for declaring test cases.
State information when applying a tx.
A currency issued by an account.
constexpr MPTID const & getMptID() const
Defines the fields and their attributes within a STObject.
void pushBack(STObject const &object)
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
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.
void testNFTokenPageInvariants()
void run() override
Runs the suite.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
Keylet escrow(AccountID const &src, SeqProxy const &seq) noexcept
An escrow entry.
Keylet nftokenPage(Keylet const &k, UInt256 const &token)
Keylet nftokenPageMin(AccountID const &owner)
NFT page keylets.
Keylet nftokenPageMax(AccountID const &owner)
A keylet for the owner's last possible NFT page.
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
XrpT const XRP
Converts to XRP Issue or STAmount.
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< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
MPTID makeMptID(std::uint32_t const sequence, AccountID const &account)
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
std::vector< unsigned char > Blob
Storage for linear binary data.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr XRPAmount kInitialXrp
Configure the native currency.