3#include <xrpld/app/tx/detail/NFTokenUtils.h>
16 using namespace test::jtx;
19 env(token::mint(account, 0),
25 env(token::createOffer(account, nftID, currency),
36 testcase(
"Unauthorized seller tries to accept buy offer");
37 using namespace test::jtx;
39 Env env(*
this, features);
43 auto const USD{G1[
"USD"]};
45 env.fund(XRP(10000), G1, A1, A2);
49 auto const limit = USD(10000);
51 env(trust(A1, limit));
53 env(pay(G1, A1, USD(1000)));
60 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
62 if (features[fixEnforceNFTokenTrustlineV2])
65 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_LINE));
69 env(trust(A2, limit));
72 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_AUTH));
79 env(token::acceptBuyOffer(A2, buyIdx));
82 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
89 testcase(
"Unauthorized buyer tries to create buy offer");
90 using namespace test::jtx;
92 Env env(*
this, features);
96 auto const USD{G1[
"USD"]};
98 env.fund(XRP(10000), G1, A1, A2);
105 env(token::createOffer(A1, nftID, USD(10)),
113 auto const unauthTrustline = [&](
OpenView& view,
117 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
121 env.app().openLedger().modify(unauthTrustline);
123 if (features[fixEnforceNFTokenTrustlineV2])
126 env(token::createOffer(A1, nftID, USD(10)),
134 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
141 testcase(
"Seller tries to accept buy offer from unauth buyer");
142 using namespace test::jtx;
144 Env env(*
this, features);
148 auto const USD{G1[
"USD"]};
150 env.fund(XRP(10000), G1, A1, A2);
154 auto const limit = USD(10000);
159 env(trust(A1, limit));
161 env(pay(G1, A1, USD(10)));
162 env(trust(A2, limit));
164 env(pay(G1, A2, USD(10)));
168 env(token::createOffer(A1, nftID, USD(10)), token::owner(A2));
171 env(pay(A1, G1, USD(10)));
172 env(trust(A1, USD(0)));
173 env(trust(G1, A1[
"USD"](0)));
180 auto const unauthTrustline = [&](
OpenView& view,
184 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
188 env.app().openLedger().modify(unauthTrustline);
189 if (features[fixEnforceNFTokenTrustlineV2])
192 env(token::acceptBuyOffer(A2, buyIdx), ter(
tecNO_AUTH));
200 "Authorized buyer tries to accept sell offer from unauthorized "
202 using namespace test::jtx;
204 Env env(*
this, features);
208 auto const USD{G1[
"USD"]};
210 env.fund(XRP(10000), G1, A1, A2);
214 auto const limit = USD(10000);
216 env(trust(A1, limit));
218 env(pay(G1, A1, USD(1000)));
221 if (features[fixEnforceNFTokenTrustlineV2])
225 env(token::createOffer(A2, nftID, USD(10)),
229 env(trust(A2, limit));
231 env(token::createOffer(A2, nftID, USD(10)),
239 env(token::createOffer(A2, nftID, USD(10)), txflags(
tfSellNFToken));
245 env(trust(A2, USD(0)));
249 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_LINE));
253 env(trust(A2, limit));
257 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_AUTH));
265 env(token::createOffer(A2, nftID, USD(10)), txflags(
tfSellNFToken));
270 env(token::acceptSellOffer(A1, sellIdx));
273 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
280 testcase(
"Unauthorized buyer tries to accept sell offer");
281 using namespace test::jtx;
283 Env env(*
this, features);
287 auto const USD{G1[
"USD"]};
289 env.fund(XRP(10000), G1, A1, A2);
293 auto const limit = USD(10000);
295 env(trust(A2, limit));
306 auto const unauthTrustline = [&](
OpenView& view,
310 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
314 env.app().openLedger().modify(unauthTrustline);
315 if (features[fixEnforceNFTokenTrustlineV2])
317 env(token::acceptSellOffer(A1, sellIdx), ter(
tecNO_AUTH));
324 testcase(
"Unauthorized broker bridges authorized buyer and seller.");
325 using namespace test::jtx;
327 Env env(*
this, features);
331 Account broker{
"broker"};
332 auto const USD{G1[
"USD"]};
334 env.fund(XRP(10000), G1, A1, A2, broker);
338 auto const limit = USD(10000);
340 env(trust(A1, limit));
342 env(pay(G1, A1, USD(1000)));
343 env(trust(A2, limit));
345 env(pay(G1, A2, USD(1000)));
350 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
353 if (features[fixEnforceNFTokenTrustlineV2])
356 env(token::brokerOffers(broker, buyIdx, sellIdx),
357 token::brokerFee(USD(1)),
362 env(trust(broker, limit));
366 env(token::brokerOffers(broker, buyIdx, sellIdx),
367 token::brokerFee(USD(1)),
372 env(token::brokerOffers(broker, buyIdx, sellIdx));
378 env(token::brokerOffers(broker, buyIdx, sellIdx),
379 token::brokerFee(USD(1)));
382 BEAST_EXPECT(env.balance(broker, USD) == USD(1));
390 "Authorized broker tries to bridge offers from unauthorized "
392 using namespace test::jtx;
394 Env env(*
this, features);
398 Account broker{
"broker"};
399 auto const USD{G1[
"USD"]};
401 env.fund(XRP(10000), G1, A1, A2, broker);
405 auto const limit = USD(10000);
407 env(trust(A1, limit));
409 env(pay(G1, A1, USD(1000)));
410 env(trust(A2, limit));
412 env(pay(G1, A2, USD(1000)));
413 env(trust(broker, limit));
415 env(pay(G1, broker, USD(1000)));
420 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
424 env(pay(A1, G1, USD(1000)));
425 env(trust(A1, USD(0)));
428 auto const unauthTrustline = [&](
OpenView& view,
432 sleA1->setFieldAmount(sfBalance, A1[
"USD"](-1000));
436 env.app().openLedger().modify(unauthTrustline);
438 if (features[fixEnforceNFTokenTrustlineV2])
441 env(token::brokerOffers(broker, buyIdx, sellIdx),
442 token::brokerFee(USD(1)),
452 "Authorized broker tries to bridge offers from unauthorized "
454 using namespace test::jtx;
456 Env env(*
this, features);
460 Account broker{
"broker"};
461 auto const USD{G1[
"USD"]};
463 env.fund(XRP(10000), G1, A1, A2, broker);
467 auto const limit = USD(10000);
469 env(trust(A1, limit));
471 env(pay(G1, A1, USD(1000)));
472 env(trust(broker, limit));
474 env(pay(G1, broker, USD(1000)));
483 env(token::createOffer(A1, nftID, USD(11)), token::owner(A2));
488 env(trust(A2, USD(0)));
491 if (features[fixEnforceNFTokenTrustlineV2])
494 env(token::brokerOffers(broker, buyIdx, sellIdx),
495 token::brokerFee(USD(1)),
500 env(trust(A2, limit));
504 env(token::brokerOffers(broker, buyIdx, sellIdx),
505 token::brokerFee(USD(1)),
510 env(token::brokerOffers(broker, buyIdx, sellIdx), ter(
tecNO_AUTH));
516 env(token::brokerOffers(broker, buyIdx, sellIdx),
517 token::brokerFee(USD(1)));
520 BEAST_EXPECT(env.balance(A2, USD) == USD(10));
528 testcase(
"Unauthorized minter receives transfer fee.");
529 using namespace test::jtx;
531 Env env(*
this, features);
533 Account minter{
"minter"};
536 auto const USD{G1[
"USD"]};
538 env.fund(XRP(10000), G1, minter, A1, A2);
542 auto const limit = USD(10000);
544 env(trust(A1, limit));
546 env(pay(G1, A1, USD(1000)));
547 env(trust(A2, limit));
549 env(pay(G1, A2, USD(1000)));
551 env(trust(minter, limit));
556 auto const [nftID, minterSellIdx] =
558 env(token::acceptSellOffer(A1, minterSellIdx));
561 env(token::createOffer(A1, nftID, USD(100)), txflags(
tfSellNFToken));
563 if (features[fixEnforceNFTokenTrustlineV2])
566 env(token::acceptSellOffer(A2, sellIdx), ter(
tecNO_AUTH));
572 env(token::acceptSellOffer(A2, sellIdx));
575 BEAST_EXPECT(env.balance(minter, USD) == USD(0.001));
582 using namespace test::jtx;
586 all - fixEnforceNFTokenTrustlineV2,
all};
588 for (
auto const feature : features)
603BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAuth, app,
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 ...