22#include <xrpld/app/tx/detail/NFTokenUtils.h>
35 using namespace test::jtx;
38 env(token::mint(account, 0),
44 env(token::createOffer(account, nftID, currency),
55 testcase(
"Unauthorized seller tries to accept buy offer");
56 using namespace test::jtx;
58 Env env(*
this, features);
62 auto const USD{G1[
"USD"]};
64 env.fund(XRP(10000), G1, A1, A2);
68 auto const limit = USD(10000);
70 env(trust(A1, limit));
72 env(pay(G1, A1, USD(1000)));
79 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
81 if (features[fixEnforceNFTokenTrustlineV2])
84 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_LINE));
88 env(trust(A2, limit));
91 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_AUTH));
98 env(token::acceptBuyOffer(A2, buyIdx));
101 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
108 testcase(
"Unauthorized buyer tries to create buy offer");
109 using namespace test::jtx;
111 Env env(*
this, features);
115 auto const USD{G1[
"USD"]};
117 env.fund(XRP(10000), G1, A1, A2);
124 env(token::createOffer(A1, nftID, USD(10)),
132 auto const unauthTrustline = [&](
OpenView& view,
135 std::make_shared<SLE>(
keylet::line(A1, G1, G1[
"USD"].currency));
136 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
140 env.app().openLedger().modify(unauthTrustline);
142 if (features[fixEnforceNFTokenTrustlineV2])
145 env(token::createOffer(A1, nftID, USD(10)),
153 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
160 testcase(
"Seller tries to accept buy offer from unauth buyer");
161 using namespace test::jtx;
163 Env env(*
this, features);
167 auto const USD{G1[
"USD"]};
169 env.fund(XRP(10000), G1, A1, A2);
173 auto const limit = USD(10000);
178 env(trust(A1, limit));
180 env(pay(G1, A1, USD(10)));
181 env(trust(A2, limit));
183 env(pay(G1, A2, USD(10)));
187 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
190 env(pay(A1, G1, USD(10)));
191 env(trust(A1, USD(0)));
192 env(trust(G1, A1[
"USD"](0)));
199 auto const unauthTrustline = [&](
OpenView& view,
202 std::make_shared<SLE>(
keylet::line(A1, G1, G1[
"USD"].currency));
203 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
207 env.app().openLedger().modify(unauthTrustline);
208 if (features[fixEnforceNFTokenTrustlineV2])
211 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_AUTH));
219 "Authorized buyer tries to accept sell offer from unauthorized "
221 using namespace test::jtx;
223 Env env(*
this, features);
227 auto const USD{G1[
"USD"]};
229 env.fund(XRP(10000), G1, A1, A2);
233 auto const limit = USD(10000);
235 env(trust(A1, limit));
237 env(pay(G1, A1, USD(1000)));
240 if (features[fixEnforceNFTokenTrustlineV2])
244 env(token::createOffer(A2, nftID, USD(10)),
248 env(trust(A2, limit));
250 env(token::createOffer(A2, nftID, USD(10)),
258 env(token::createOffer(A2, nftID, USD(10)), txflags(
tfSellNFToken));
264 env(trust(A2, USD(0)));
268 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_LINE));
272 env(trust(A2, limit));
276 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_AUTH));
284 env(token::createOffer(A2, nftID, USD(10)), txflags(
tfSellNFToken));
289 env(token::acceptSellOffer(A1, sellIdx));
292 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
299 testcase(
"Unauthorized buyer tries to accept sell offer");
300 using namespace test::jtx;
302 Env env(*
this, features);
306 auto const USD{G1[
"USD"]};
308 env.fund(XRP(10000), G1, A1, A2);
312 auto const limit = USD(10000);
314 env(trust(A2, limit));
325 auto const unauthTrustline = [&](
OpenView& view,
328 std::make_shared<SLE>(
keylet::line(A1, G1, G1[
"USD"].currency));
329 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
333 env.app().openLedger().modify(unauthTrustline);
334 if (features[fixEnforceNFTokenTrustlineV2])
336 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_AUTH));
343 testcase(
"Unauthorized broker bridges authorized buyer and seller.");
344 using namespace test::jtx;
346 Env env(*
this, features);
350 Account broker{
"broker"};
351 auto const USD{G1[
"USD"]};
353 env.fund(XRP(10000), G1, A1, A2, broker);
357 auto const limit = USD(10000);
359 env(trust(A1, limit));
361 env(pay(G1, A1, USD(1000)));
362 env(trust(A2, limit));
364 env(pay(G1, A2, USD(1000)));
369 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
372 if (features[fixEnforceNFTokenTrustlineV2])
375 env(token::brokerOffers(broker, buyIdx, sellIdx),
376 token::brokerFee(USD(1)),
381 env(trust(broker, limit));
385 env(token::brokerOffers(broker, buyIdx, sellIdx),
386 token::brokerFee(USD(1)),
391 env(token::brokerOffers(broker, buyIdx, sellIdx));
397 env(token::brokerOffers(broker, buyIdx, sellIdx),
398 token::brokerFee(USD(1)));
401 BEAST_EXPECT(env.balance(broker, USD) == USD(1));
409 "Authorized broker tries to bridge offers from unauthorized "
411 using namespace test::jtx;
413 Env env(*
this, features);
417 Account broker{
"broker"};
418 auto const USD{G1[
"USD"]};
420 env.fund(XRP(10000), G1, A1, A2, broker);
424 auto const limit = USD(10000);
426 env(trust(A1, limit));
428 env(pay(G1, A1, USD(1000)));
429 env(trust(A2, limit));
431 env(pay(G1, A2, USD(1000)));
432 env(trust(broker, limit));
434 env(pay(G1, broker, USD(1000)));
439 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
443 env(pay(A1, G1, USD(1000)));
444 env(trust(A1, USD(0)));
447 auto const unauthTrustline = [&](
OpenView& view,
450 std::make_shared<SLE>(
keylet::line(A1, G1, G1[
"USD"].currency));
451 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
455 env.app().openLedger().modify(unauthTrustline);
457 if (features[fixEnforceNFTokenTrustlineV2])
460 env(token::brokerOffers(broker, buyIdx, sellIdx),
461 token::brokerFee(USD(1)),
471 "Authorized broker tries to bridge offers from unauthorized "
473 using namespace test::jtx;
475 Env env(*
this, features);
479 Account broker{
"broker"};
480 auto const USD{G1[
"USD"]};
482 env.fund(XRP(10000), G1, A1, A2, broker);
486 auto const limit = USD(10000);
488 env(trust(A1, limit));
490 env(pay(G1, A1, USD(1000)));
491 env(trust(broker, limit));
493 env(pay(G1, broker, USD(1000)));
502 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
507 env(trust(A2, USD(0)));
510 if (features[fixEnforceNFTokenTrustlineV2])
513 env(token::brokerOffers(broker, buyIdx, sellIdx),
514 token::brokerFee(USD(1)),
519 env(trust(A2, limit));
523 env(token::brokerOffers(broker, buyIdx, sellIdx),
524 token::brokerFee(USD(1)),
529 env(token::brokerOffers(broker, buyIdx, sellIdx), ter(
tecNO_AUTH));
535 env(token::brokerOffers(broker, buyIdx, sellIdx),
536 token::brokerFee(USD(1)));
539 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
547 testcase(
"Unauthorized minter receives transfer fee.");
548 using namespace test::jtx;
550 Env env(*
this, features);
552 Account minter{
"minter"};
555 auto const USD{G1[
"USD"]};
557 env.fund(XRP(10000), G1, minter, A1, A2);
561 auto const limit = USD(10000);
563 env(trust(A1, limit));
565 env(pay(G1, A1, USD(1000)));
566 env(trust(A2, limit));
568 env(pay(G1, A2, USD(1000)));
570 env(trust(minter, limit));
575 auto const [nftID, minterSellIdx] =
577 env(token::acceptSellOffer(A1, minterSellIdx));
580 env(token::createOffer(A1, nftID, USD(100)), txflags(
tfSellNFToken));
582 if (features[fixEnforceNFTokenTrustlineV2])
585 env(token::acceptSellOffer(A2, sellIdx), ter(
tecNO_AUTH));
591 env(token::acceptSellOffer(A2, sellIdx));
594 BEAST_EXPECT(env.balance(minter, USD) == USD(0.001));
601 using namespace test::jtx;
605 all - fixEnforceNFTokenTrustlineV2,
all};
607 for (
auto const feature : features)
622BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, tx,
ripple, 2);
A generic endpoint for log messages.
testcase_t testcase
Memberspace for declaring test cases.
void testSellOffer_UnauthorizedBuyer(FeatureBitset features)
void run() override
Runs the suite.
void testCreateBuyOffer_UnauthorizedBuyer(FeatureBitset features)
void testBrokeredAcceptOffer_UnauthorizedBroker(FeatureBitset features)
void testBrokeredAcceptOffer_UnauthorizedSeller(FeatureBitset features)
void testTransferFee_UnauthorizedMinter(FeatureBitset features)
void testSellOffer_UnauthorizedSeller(FeatureBitset features)
void testBuyOffer_UnauthorizedSeller(FeatureBitset features)
auto mintAndOfferNFT(test::jtx::Env &env, test::jtx::Account const &account, test::jtx::PrettyAmount const ¤cy, uint32_t xfee=0u)
void testBrokeredAcceptOffer_UnauthorizedBuyer(FeatureBitset features)
void testAcceptBuyOffer_UnauthorizedBuyer(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.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t const tfSellNFToken
constexpr std::uint32_t tfSetfAuth
constexpr std::uint32_t asfRequireAuth
constexpr std::uint32_t const tfTransferable
Represents an XRP or IOU quantity This customizes the string conversion and supports XRP conversions ...