3#include <xrpld/app/tx/detail/NFTokenUtils.h>
16 using namespace test::jtx;
17 auto const nftID{token::getNextID(env, account, 0u,
tfTransferable, xfee)};
18 env(token::mint(account, 0), token::xferFee(xfee), txflags(
tfTransferable));
22 env(token::createOffer(account, nftID, currency), txflags(
tfSellNFToken));
32 testcase(
"Unauthorized seller tries to accept buy offer");
33 using namespace test::jtx;
35 Env env(*
this, features);
39 auto const USD{G1[
"USD"]};
41 env.fund(XRP(10000), G1, A1, A2);
45 auto const limit = USD(10000);
47 env(trust(A1, limit));
49 env(pay(G1, A1, USD(1000)));
56 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
58 if (features[fixEnforceNFTokenTrustlineV2])
61 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_LINE));
65 env(trust(A2, limit));
68 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_AUTH));
75 env(token::acceptBuyOffer(A2, buyIdx));
78 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
85 testcase(
"Unauthorized buyer tries to create buy offer");
86 using namespace test::jtx;
88 Env env(*
this, features);
92 auto const USD{G1[
"USD"]};
94 env.fund(XRP(10000), G1, A1, A2);
101 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2), ter(
tecUNFUNDED_OFFER));
109 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
113 env.app().openLedger().modify(unauthTrustline);
115 if (features[fixEnforceNFTokenTrustlineV2])
118 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2), ter(
tecNO_AUTH));
124 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
131 testcase(
"Seller tries to accept buy offer from unauth buyer");
132 using namespace test::jtx;
134 Env env(*
this, features);
138 auto const USD{G1[
"USD"]};
140 env.fund(XRP(10000), G1, A1, A2);
144 auto const limit = USD(10000);
149 env(trust(A1, limit));
151 env(pay(G1, A1, USD(10)));
152 env(trust(A2, limit));
154 env(pay(G1, A2, USD(10)));
158 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
161 env(pay(A1, G1, USD(10)));
162 env(trust(A1, USD(0)));
163 env(trust(G1, A1[
"USD"](0)));
172 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
176 env.app().openLedger().modify(unauthTrustline);
177 if (features[fixEnforceNFTokenTrustlineV2])
180 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_AUTH));
188 "Authorized buyer tries to accept sell offer from unauthorized "
190 using namespace test::jtx;
192 Env env(*
this, features);
196 auto const USD{G1[
"USD"]};
198 env.fund(XRP(10000), G1, A1, A2);
202 auto const limit = USD(10000);
204 env(trust(A1, limit));
206 env(pay(G1, A1, USD(1000)));
209 if (features[fixEnforceNFTokenTrustlineV2])
215 env(trust(A2, limit));
223 env(token::createOffer(A2, nftID, USD(10)), txflags(
tfSellNFToken));
229 env(trust(A2, USD(0)));
233 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_LINE));
237 env(trust(A2, limit));
241 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_AUTH));
249 env(token::createOffer(A2, nftID, USD(10)), txflags(
tfSellNFToken));
254 env(token::acceptSellOffer(A1, sellIdx));
257 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
264 testcase(
"Unauthorized buyer tries to accept sell offer");
265 using namespace test::jtx;
267 Env env(*
this, features);
271 auto const USD{G1[
"USD"]};
273 env.fund(XRP(10000), G1, A1, A2);
277 auto const limit = USD(10000);
279 env(trust(A2, limit));
292 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
296 env.app().openLedger().modify(unauthTrustline);
297 if (features[fixEnforceNFTokenTrustlineV2])
299 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_AUTH));
306 testcase(
"Unauthorized broker bridges authorized buyer and seller.");
307 using namespace test::jtx;
309 Env env(*
this, features);
313 Account broker{
"broker"};
314 auto const USD{G1[
"USD"]};
316 env.fund(XRP(10000), G1, A1, A2, broker);
320 auto const limit = USD(10000);
322 env(trust(A1, limit));
324 env(pay(G1, A1, USD(1000)));
325 env(trust(A2, limit));
327 env(pay(G1, A2, USD(1000)));
332 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
335 if (features[fixEnforceNFTokenTrustlineV2])
338 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(
tecNO_LINE));
342 env(trust(broker, limit));
346 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(
tecNO_AUTH));
350 env(token::brokerOffers(broker, buyIdx, sellIdx));
356 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)));
359 BEAST_EXPECT(env.balance(broker, USD) == USD(1));
367 "Authorized broker tries to bridge offers from unauthorized "
369 using namespace test::jtx;
371 Env env(*
this, features);
375 Account broker{
"broker"};
376 auto const USD{G1[
"USD"]};
378 env.fund(XRP(10000), G1, A1, A2, broker);
382 auto const limit = USD(10000);
384 env(trust(A1, limit));
386 env(pay(G1, A1, USD(1000)));
387 env(trust(A2, limit));
389 env(pay(G1, A2, USD(1000)));
390 env(trust(broker, limit));
392 env(pay(G1, broker, USD(1000)));
397 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
401 env(pay(A1, G1, USD(1000)));
402 env(trust(A1, USD(0)));
407 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
411 env.app().openLedger().modify(unauthTrustline);
413 if (features[fixEnforceNFTokenTrustlineV2])
416 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(
tecNO_AUTH));
425 "Authorized broker tries to bridge offers from unauthorized "
427 using namespace test::jtx;
429 Env env(*
this, features);
433 Account broker{
"broker"};
434 auto const USD{G1[
"USD"]};
436 env.fund(XRP(10000), G1, A1, A2, broker);
440 auto const limit = USD(10000);
442 env(trust(A1, limit));
444 env(pay(G1, A1, USD(1000)));
445 env(trust(broker, limit));
447 env(pay(G1, broker, USD(1000)));
456 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
461 env(trust(A2, USD(0)));
464 if (features[fixEnforceNFTokenTrustlineV2])
467 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(
tecNO_LINE));
471 env(trust(A2, limit));
475 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)), ter(
tecNO_AUTH));
479 env(token::brokerOffers(broker, buyIdx, sellIdx), ter(
tecNO_AUTH));
485 env(token::brokerOffers(broker, buyIdx, sellIdx), token::brokerFee(USD(1)));
488 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
496 testcase(
"Unauthorized minter receives transfer fee.");
497 using namespace test::jtx;
499 Env env(*
this, features);
501 Account minter{
"minter"};
504 auto const USD{G1[
"USD"]};
506 env.fund(XRP(10000), G1, minter, A1, A2);
510 auto const limit = USD(10000);
512 env(trust(A1, limit));
514 env(pay(G1, A1, USD(1000)));
515 env(trust(A2, limit));
517 env(pay(G1, A2, USD(1000)));
519 env(trust(minter, limit));
524 auto const [nftID, minterSellIdx] =
mintAndOfferNFT(env, minter, drops(1), 1);
525 env(token::acceptSellOffer(A1, minterSellIdx));
528 env(token::createOffer(A1, nftID, USD(100)), txflags(
tfSellNFToken));
530 if (features[fixEnforceNFTokenTrustlineV2])
533 env(token::acceptSellOffer(A2, sellIdx), ter(
tecNO_AUTH));
539 env(token::acceptSellOffer(A2, sellIdx));
542 BEAST_EXPECT(env.balance(minter, USD) == USD(0.001));
549 using namespace test::jtx;
552 static std::array const features = {
all - fixEnforceNFTokenTrustlineV2,
all};
554 for (
auto const feature : features)
569BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, app,
xrpl, 2);
A generic endpoint for log messages.
testcase_t testcase
Memberspace for declaring test cases.
void testTransferFee_UnauthorizedMinter(FeatureBitset features)
void testBrokeredAcceptOffer_UnauthorizedBuyer(FeatureBitset features)
void testBrokeredAcceptOffer_UnauthorizedSeller(FeatureBitset features)
void testAcceptBuyOffer_UnauthorizedBuyer(FeatureBitset features)
void testCreateBuyOffer_UnauthorizedBuyer(FeatureBitset features)
void testBrokeredAcceptOffer_UnauthorizedBroker(FeatureBitset features)
void testSellOffer_UnauthorizedBuyer(FeatureBitset features)
void run() override
Runs the suite.
void testSellOffer_UnauthorizedSeller(FeatureBitset features)
auto mintAndOfferNFT(test::jtx::Env &env, test::jtx::Account const &account, test::jtx::PrettyAmount const ¤cy, uint32_t xfee=0u)
void testBuyOffer_UnauthorizedSeller(FeatureBitset features)
Writable ledger view that accumulates state and tx changes.
void rawInsert(std::shared_ptr< SLE > const &sle) override
Unconditionally insert a state item.
Immutable cryptographic account descriptor.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t const tfTransferable
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t asfRequireAuth
constexpr std::uint32_t const tfSellNFToken
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...