rippled
NFToken_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2021 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/tx/impl/details/NFTokenUtils.h>
21 #include <ripple/basics/random.h>
22 #include <ripple/protocol/Feature.h>
23 #include <ripple/protocol/jss.h>
24 #include <test/jtx.h>
25 
26 #include <initializer_list>
27 
28 namespace ripple {
29 
30 class NFToken_test : public beast::unit_test::suite
31 {
32  // Helper function that returns the owner count of an account root.
33  static std::uint32_t
34  ownerCount(test::jtx::Env const& env, test::jtx::Account const& acct)
35  {
36  std::uint32_t ret{0};
37  if (auto const sleAcct = env.le(acct))
38  ret = sleAcct->at(sfOwnerCount);
39  return ret;
40  }
41 
42  // Helper function that returns the number of NFTs minted by an issuer.
43  static std::uint32_t
44  mintedCount(test::jtx::Env const& env, test::jtx::Account const& issuer)
45  {
46  std::uint32_t ret{0};
47  if (auto const sleIssuer = env.le(issuer))
48  ret = sleIssuer->at(~sfMintedNFTokens).value_or(0);
49  return ret;
50  }
51 
52  // Helper function that returns the number of an issuer's burned NFTs.
53  static std::uint32_t
54  burnedCount(test::jtx::Env const& env, test::jtx::Account const& issuer)
55  {
56  std::uint32_t ret{0};
57  if (auto const sleIssuer = env.le(issuer))
58  ret = sleIssuer->at(~sfBurnedNFTokens).value_or(0);
59  return ret;
60  }
61 
62  // Helper function that returns the number of nfts owned by an account.
63  static std::uint32_t
65  {
66  Json::Value params;
67  params[jss::account] = acct.human();
68  params[jss::type] = "state";
69  Json::Value nfts = env.rpc("json", "account_nfts", to_string(params));
70  return nfts[jss::result][jss::account_nfts].size();
71  };
72 
73  // Helper function that returns the number of tickets held by an account.
74  static std::uint32_t
76  {
77  std::uint32_t ret{0};
78  if (auto const sleAcct = env.le(acct))
79  ret = sleAcct->at(~sfTicketCount).value_or(0);
80  return ret;
81  }
82 
83  // Helper function returns the close time of the parent ledger.
86  {
87  return env.current()->info().parentCloseTime.time_since_epoch().count();
88  }
89 
90  void
92  {
93  testcase("Enabled");
94 
95  using namespace test::jtx;
96  {
97  // If the NFT amendment is not enabled, you should not be able
98  // to create or burn NFTs.
99  Env env{*this, features - featureNonFungibleTokensV1};
100  Account const& master = env.master;
101 
102  BEAST_EXPECT(ownerCount(env, master) == 0);
103  BEAST_EXPECT(mintedCount(env, master) == 0);
104  BEAST_EXPECT(burnedCount(env, master) == 0);
105 
106  uint256 const nftId{token::getNextID(env, master, 0u)};
107  env(token::mint(master, 0u), ter(temDISABLED));
108  env.close();
109  BEAST_EXPECT(ownerCount(env, master) == 0);
110  BEAST_EXPECT(mintedCount(env, master) == 0);
111  BEAST_EXPECT(burnedCount(env, master) == 0);
112 
113  env(token::burn(master, nftId), ter(temDISABLED));
114  env.close();
115  BEAST_EXPECT(ownerCount(env, master) == 0);
116  BEAST_EXPECT(mintedCount(env, master) == 0);
117  BEAST_EXPECT(burnedCount(env, master) == 0);
118 
119  uint256 const offerIndex =
120  keylet::nftoffer(master, env.seq(master)).key;
121  env(token::createOffer(master, nftId, XRP(10)), ter(temDISABLED));
122  env.close();
123  BEAST_EXPECT(ownerCount(env, master) == 0);
124  BEAST_EXPECT(mintedCount(env, master) == 0);
125  BEAST_EXPECT(burnedCount(env, master) == 0);
126 
127  env(token::cancelOffer(master, {offerIndex}), ter(temDISABLED));
128  env.close();
129  BEAST_EXPECT(ownerCount(env, master) == 0);
130  BEAST_EXPECT(mintedCount(env, master) == 0);
131  BEAST_EXPECT(burnedCount(env, master) == 0);
132 
133  env(token::acceptBuyOffer(master, offerIndex), ter(temDISABLED));
134  env.close();
135  BEAST_EXPECT(ownerCount(env, master) == 0);
136  BEAST_EXPECT(mintedCount(env, master) == 0);
137  BEAST_EXPECT(burnedCount(env, master) == 0);
138  }
139  {
140  // If the NFT amendment is enabled all NFT-related
141  // facilities should be available.
142  Env env{*this, features};
143  Account const& master = env.master;
144 
145  BEAST_EXPECT(ownerCount(env, master) == 0);
146  BEAST_EXPECT(mintedCount(env, master) == 0);
147  BEAST_EXPECT(burnedCount(env, master) == 0);
148 
149  uint256 const nftId0{token::getNextID(env, env.master, 0u)};
150  env(token::mint(env.master, 0u));
151  env.close();
152  BEAST_EXPECT(ownerCount(env, master) == 1);
153  BEAST_EXPECT(mintedCount(env, master) == 1);
154  BEAST_EXPECT(burnedCount(env, master) == 0);
155 
156  env(token::burn(env.master, nftId0));
157  env.close();
158  BEAST_EXPECT(ownerCount(env, master) == 0);
159  BEAST_EXPECT(mintedCount(env, master) == 1);
160  BEAST_EXPECT(burnedCount(env, master) == 1);
161 
162  uint256 const nftId1{
163  token::getNextID(env, env.master, 0u, tfTransferable)};
164  env(token::mint(env.master, 0u), txflags(tfTransferable));
165  env.close();
166  BEAST_EXPECT(ownerCount(env, master) == 1);
167  BEAST_EXPECT(mintedCount(env, master) == 2);
168  BEAST_EXPECT(burnedCount(env, master) == 1);
169 
170  Account const alice{"alice"};
171  env.fund(XRP(10000), alice);
172  env.close();
173  uint256 const aliceOfferIndex =
174  keylet::nftoffer(alice, env.seq(alice)).key;
175  env(token::createOffer(alice, nftId1, XRP(1000)),
176  token::owner(master));
177  env.close();
178 
179  BEAST_EXPECT(ownerCount(env, master) == 1);
180  BEAST_EXPECT(mintedCount(env, master) == 2);
181  BEAST_EXPECT(burnedCount(env, master) == 1);
182 
183  BEAST_EXPECT(ownerCount(env, alice) == 1);
184  BEAST_EXPECT(mintedCount(env, alice) == 0);
185  BEAST_EXPECT(burnedCount(env, alice) == 0);
186 
187  env(token::acceptBuyOffer(master, aliceOfferIndex));
188  env.close();
189 
190  BEAST_EXPECT(ownerCount(env, master) == 0);
191  BEAST_EXPECT(mintedCount(env, master) == 2);
192  BEAST_EXPECT(burnedCount(env, master) == 1);
193 
194  BEAST_EXPECT(ownerCount(env, alice) == 1);
195  BEAST_EXPECT(mintedCount(env, alice) == 0);
196  BEAST_EXPECT(burnedCount(env, alice) == 0);
197  }
198  }
199 
200  void
202  {
203  // Verify that the reserve behaves as expected for minting.
204  testcase("Mint reserve");
205 
206  using namespace test::jtx;
207 
208  Env env{*this, features};
209  Account const alice{"alice"};
210  Account const minter{"minter"};
211 
212  // Fund alice and minter enough to exist, but not enough to meet
213  // the reserve for creating their first NFT. Account reserve for unit
214  // tests is 200 XRP, not 20.
215  env.fund(XRP(200), alice, minter);
216  env.close();
217  BEAST_EXPECT(env.balance(alice) == XRP(200));
218  BEAST_EXPECT(env.balance(minter) == XRP(200));
219  BEAST_EXPECT(ownerCount(env, alice) == 0);
220  BEAST_EXPECT(ownerCount(env, minter) == 0);
221 
222  // alice does not have enough XRP to cover the reserve for an NFT page.
223  env(token::mint(alice, 0u), ter(tecINSUFFICIENT_RESERVE));
224  env.close();
225  BEAST_EXPECT(ownerCount(env, alice) == 0);
226  BEAST_EXPECT(mintedCount(env, alice) == 0);
227  BEAST_EXPECT(burnedCount(env, alice) == 0);
228 
229  // Pay alice almost enough to make the reserve for an NFT page.
230  env(pay(env.master, alice, XRP(50) + drops(9)));
231  env.close();
232 
233  // A lambda that checks alice's ownerCount, mintedCount, and
234  // burnedCount all in one fell swoop.
235  auto checkAliceOwnerMintedBurned = [&env, this, &alice](
236  std::uint32_t owners,
237  std::uint32_t minted,
238  std::uint32_t burned,
239  int line) {
240  auto oneCheck =
241  [line, this](
242  char const* type, std::uint32_t found, std::uint32_t exp) {
243  if (found == exp)
244  pass();
245  else
246  {
248  ss << "Wrong " << type << " count. Found: " << found
249  << "; Expected: " << exp;
250  fail(ss.str(), __FILE__, line);
251  }
252  };
253  oneCheck("owner", ownerCount(env, alice), owners);
254  oneCheck("minted", mintedCount(env, alice), minted);
255  oneCheck("burned", burnedCount(env, alice), burned);
256  };
257 
258  // alice still does not have enough XRP for the reserve of an NFT page.
259  env(token::mint(alice, 0u), ter(tecINSUFFICIENT_RESERVE));
260  env.close();
261  checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
262 
263  // Pay alice enough to make the reserve for an NFT page.
264  env(pay(env.master, alice, drops(11)));
265  env.close();
266 
267  // Now alice can mint an NFT.
268  env(token::mint(alice));
269  env.close();
270  checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
271 
272  // Alice should be able to mint an additional 31 NFTs without
273  // any additional reserve requirements.
274  for (int i = 1; i < 32; ++i)
275  {
276  env(token::mint(alice));
277  checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
278  }
279 
280  // That NFT page is full. Creating an additional NFT page requires
281  // additional reserve.
282  env(token::mint(alice), ter(tecINSUFFICIENT_RESERVE));
283  env.close();
284  checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
285 
286  // Pay alice almost enough to make the reserve for an NFT page.
287  env(pay(env.master, alice, XRP(50) + drops(329)));
288  env.close();
289 
290  // alice still does not have enough XRP for the reserve of an NFT page.
291  env(token::mint(alice), ter(tecINSUFFICIENT_RESERVE));
292  env.close();
293  checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
294 
295  // Pay alice enough to make the reserve for an NFT page.
296  env(pay(env.master, alice, drops(11)));
297  env.close();
298 
299  // Now alice can mint an NFT.
300  env(token::mint(alice));
301  env.close();
302  checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
303 
304  // alice burns the NFTs she created: check that pages consolidate
305  std::uint32_t seq = 0;
306 
307  while (seq < 33)
308  {
309  env(token::burn(alice, token::getID(alice, 0, seq++)));
310  env.close();
311  checkAliceOwnerMintedBurned((33 - seq) ? 1 : 0, 33, seq, __LINE__);
312  }
313 
314  // alice burns a non-existent NFT.
315  env(token::burn(alice, token::getID(alice, 197, 5)), ter(tecNO_ENTRY));
316  env.close();
317  checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
318 
319  // That was fun! Now let's see what happens when we let someone else
320  // mint NFTs on alice's behalf. alice gives permission to minter.
321  env(token::setMinter(alice, minter));
322  env.close();
323  BEAST_EXPECT(
324  env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
325 
326  // A lambda that checks minter's and alice's ownerCount,
327  // mintedCount, and burnedCount all in one fell swoop.
328  auto checkMintersOwnerMintedBurned = [&env, this, &alice, &minter](
329  std::uint32_t aliceOwners,
330  std::uint32_t aliceMinted,
331  std::uint32_t aliceBurned,
332  std::uint32_t minterOwners,
333  std::uint32_t minterMinted,
334  std::uint32_t minterBurned,
335  int line) {
336  auto oneCheck = [this](
337  char const* type,
338  std::uint32_t found,
339  std::uint32_t exp,
340  int line) {
341  if (found == exp)
342  pass();
343  else
344  {
346  ss << "Wrong " << type << " count. Found: " << found
347  << "; Expected: " << exp;
348  fail(ss.str(), __FILE__, line);
349  }
350  };
351  oneCheck("alice owner", ownerCount(env, alice), aliceOwners, line);
352  oneCheck(
353  "alice minted", mintedCount(env, alice), aliceMinted, line);
354  oneCheck(
355  "alice burned", burnedCount(env, alice), aliceBurned, line);
356  oneCheck(
357  "minter owner", ownerCount(env, minter), minterOwners, line);
358  oneCheck(
359  "minter minted", mintedCount(env, minter), minterMinted, line);
360  oneCheck(
361  "minter burned", burnedCount(env, minter), minterBurned, line);
362  };
363 
364  std::uint32_t nftSeq = 33;
365 
366  // Pay minter almost enough to make the reserve for an NFT page.
367  env(pay(env.master, minter, XRP(50) - drops(1)));
368  env.close();
369  checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
370 
371  // minter still does not have enough XRP for the reserve of an NFT page.
372  // Just for grins (and code coverage), minter mints NFTs that include
373  // a URI.
374  env(token::mint(minter),
375  token::issuer(alice),
376  token::uri("uri"),
378  env.close();
379  checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
380 
381  // Pay minter enough to make the reserve for an NFT page.
382  env(pay(env.master, minter, drops(11)));
383  env.close();
384 
385  // Now minter can mint an NFT for alice.
386  env(token::mint(minter), token::issuer(alice), token::uri("uri"));
387  env.close();
388  checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
389 
390  // Minter should be able to mint an additional 31 NFTs for alice
391  // without any additional reserve requirements.
392  for (int i = 1; i < 32; ++i)
393  {
394  env(token::mint(minter), token::issuer(alice), token::uri("uri"));
395  checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
396  }
397 
398  // Pay minter almost enough for the reserve of an additional NFT page.
399  env(pay(env.master, minter, XRP(50) + drops(319)));
400  env.close();
401 
402  // That NFT page is full. Creating an additional NFT page requires
403  // additional reserve.
404  env(token::mint(minter),
405  token::issuer(alice),
406  token::uri("uri"),
408  env.close();
409  checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
410 
411  // Pay minter enough for the reserve of an additional NFT page.
412  env(pay(env.master, minter, drops(11)));
413  env.close();
414 
415  // Now minter can mint an NFT.
416  env(token::mint(minter), token::issuer(alice), token::uri("uri"));
417  env.close();
418  checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
419 
420  // minter burns the NFTs she created.
421  while (nftSeq < 65)
422  {
423  env(token::burn(minter, token::getID(alice, 0, nftSeq++)));
424  env.close();
425  checkMintersOwnerMintedBurned(
426  0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__);
427  }
428 
429  // minter has one more NFT to burn. Should take her owner count to 0.
430  env(token::burn(minter, token::getID(alice, 0, nftSeq++)));
431  env.close();
432  checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
433 
434  // minter burns a non-existent NFT.
435  env(token::burn(minter, token::getID(alice, 2009, 3)),
436  ter(tecNO_ENTRY));
437  env.close();
438  checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
439  }
440 
441  void
443  {
444  // Make sure that an account cannot cause the sfMintedNFTokens
445  // field to wrap by minting more than 0xFFFF'FFFF tokens.
446  testcase("Mint max tokens");
447 
448  using namespace test::jtx;
449 
450  Account const alice{"alice"};
451  Env env{*this, features};
452  env.fund(XRP(1000), alice);
453  env.close();
454 
455  // We're going to hack the ledger in order to avoid generating
456  // 4 billion or so NFTs. Because we're hacking the ledger we
457  // need alice's account to have non-zero sfMintedNFTokens and
458  // sfBurnedNFTokens fields. This prevents an exception when the
459  // AccountRoot template is applied.
460  {
461  uint256 const nftId0{token::getNextID(env, alice, 0u)};
462  env(token::mint(alice, 0u));
463  env.close();
464 
465  env(token::burn(alice, nftId0));
466  env.close();
467  }
468 
469  // Note that we're bypassing almost all of the ledger's safety
470  // checks with this modify() call. If you call close() between
471  // here and the end of the test all the effort will be lost.
472  env.app().openLedger().modify(
473  [&alice](OpenView& view, beast::Journal j) {
474  // Get the account root we want to hijack.
475  auto const sle = view.read(keylet::account(alice.id()));
476  if (!sle)
477  return false; // This would be really surprising!
478 
479  // Just for sanity's sake we'll check that the current value
480  // of sfMintedNFTokens matches what we expect.
481  auto replacement = std::make_shared<SLE>(*sle, sle->key());
482  if (replacement->getFieldU32(sfMintedNFTokens) != 1)
483  return false; // Unexpected test conditions.
484 
485  // Now replace the sfMintedNFTokens with its maximum value.
486  (*replacement)[sfMintedNFTokens] =
488  view.rawReplace(replacement);
489  return true;
490  });
491 
492  // alice should not be able to mint any tokens because she has already
493  // minted the maximum allowed by a single account.
494  env(token::mint(alice, 0u), ter(tecMAX_SEQUENCE_REACHED));
495  }
496 
497  void
499  {
500  // Explore many of the invalid ways to mint an NFT.
501  testcase("Mint invalid");
502 
503  using namespace test::jtx;
504 
505  Env env{*this, features};
506  Account const alice{"alice"};
507  Account const minter{"minter"};
508 
509  // Fund alice and minter enough to exist, but not enough to meet
510  // the reserve for creating their first NFT. Account reserve for unit
511  // tests is 200 XRP, not 20.
512  env.fund(XRP(200), alice, minter);
513  env.close();
514 
515  env(token::mint(alice, 0u), ter(tecINSUFFICIENT_RESERVE));
516  env.close();
517 
518  // Fund alice enough to start minting NFTs.
519  env(pay(env.master, alice, XRP(1000)));
520  env.close();
521 
522  //----------------------------------------------------------------------
523  // preflight
524 
525  // Set a negative fee.
526  env(token::mint(alice, 0u),
527  fee(STAmount(10ull, true)),
528  ter(temBAD_FEE));
529 
530  // Set an invalid flag.
531  env(token::mint(alice, 0u), txflags(0x00008000), ter(temINVALID_FLAG));
532 
533  // Can't set a transfer fee if the NFT does not have the tfTRANSFERABLE
534  // flag set.
535  env(token::mint(alice, 0u),
536  token::xferFee(maxTransferFee),
537  ter(temMALFORMED));
538 
539  // Set a bad transfer fee.
540  env(token::mint(alice, 0u),
541  token::xferFee(maxTransferFee + 1),
542  txflags(tfTransferable),
544 
545  // Account can't also be issuer.
546  env(token::mint(alice, 0u), token::issuer(alice), ter(temMALFORMED));
547 
548  // Invalid URI: zero length.
549  env(token::mint(alice, 0u), token::uri(""), ter(temMALFORMED));
550 
551  // Invalid URI: too long.
552  env(token::mint(alice, 0u),
553  token::uri(std::string(maxTokenURILength + 1, 'q')),
554  ter(temMALFORMED));
555 
556  //----------------------------------------------------------------------
557  // preflight
558 
559  // Non-existent issuer.
560  env(token::mint(alice, 0u),
561  token::issuer(Account("demon")),
562  ter(tecNO_ISSUER));
563 
564  //----------------------------------------------------------------------
565  // doApply
566 
567  // Existent issuer, but not given minting permission
568  env(token::mint(minter, 0u),
569  token::issuer(alice),
570  ter(tecNO_PERMISSION));
571  }
572 
573  void
575  {
576  // Explore many of the invalid ways to burn an NFT.
577  testcase("Burn invalid");
578 
579  using namespace test::jtx;
580 
581  Env env{*this, features};
582  Account const alice{"alice"};
583  Account const buyer{"buyer"};
584  Account const minter{"minter"};
585  Account const gw("gw");
586  IOU const gwAUD(gw["AUD"]);
587 
588  // Fund alice and minter enough to exist and create an NFT, but not
589  // enough to meet the reserve for creating their first NFTOffer.
590  // Account reserve for unit tests is 200 XRP, not 20.
591  env.fund(XRP(250), alice, buyer, minter, gw);
592  env.close();
593  BEAST_EXPECT(ownerCount(env, alice) == 0);
594 
595  uint256 const nftAlice0ID =
596  token::getNextID(env, alice, 0, tfTransferable);
597  env(token::mint(alice, 0u), txflags(tfTransferable));
598  env.close();
599  BEAST_EXPECT(ownerCount(env, alice) == 1);
600 
601  //----------------------------------------------------------------------
602  // preflight
603 
604  // Set a negative fee.
605  env(token::burn(alice, nftAlice0ID),
606  fee(STAmount(10ull, true)),
607  ter(temBAD_FEE));
608  env.close();
609  BEAST_EXPECT(ownerCount(env, alice) == 1);
610 
611  // Set an invalid flag.
612  env(token::burn(alice, nftAlice0ID),
613  txflags(0x00008000),
614  ter(temINVALID_FLAG));
615  env.close();
616  BEAST_EXPECT(ownerCount(env, buyer) == 0);
617 
618  //----------------------------------------------------------------------
619  // preclaim
620 
621  // Try to burn a token that doesn't exist.
622  env(token::burn(alice, token::getID(alice, 0, 1)), ter(tecNO_ENTRY));
623  env.close();
624  BEAST_EXPECT(ownerCount(env, buyer) == 0);
625 
626  // Can't burn a token with many buy or sell offers. But that is
627  // verified in testManyNftOffers().
628 
629  //----------------------------------------------------------------------
630  // doApply
631  }
632 
633  void
635  {
636  testcase("Invalid NFT offer create");
637 
638  using namespace test::jtx;
639 
640  Env env{*this, features};
641  Account const alice{"alice"};
642  Account const buyer{"buyer"};
643  Account const gw("gw");
644  IOU const gwAUD(gw["AUD"]);
645 
646  // Fund alice enough to exist and create an NFT, but not
647  // enough to meet the reserve for creating their first NFTOffer.
648  // Account reserve for unit tests is 200 XRP, not 20.
649  env.fund(XRP(250), alice, buyer, gw);
650  env.close();
651  BEAST_EXPECT(ownerCount(env, alice) == 0);
652 
653  uint256 const nftAlice0ID =
654  token::getNextID(env, alice, 0, tfTransferable, 10);
655  env(token::mint(alice, 0u),
656  txflags(tfTransferable),
657  token::xferFee(10));
658  env.close();
659  BEAST_EXPECT(ownerCount(env, alice) == 1);
660 
661  uint256 const nftXrpOnlyID =
662  token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable);
663  env(token::mint(alice, 0), txflags(tfOnlyXRP | tfTransferable));
664  env.close();
665  BEAST_EXPECT(ownerCount(env, alice) == 1);
666 
667  uint256 nftNoXferID = token::getNextID(env, alice, 0);
668  env(token::mint(alice, 0));
669  env.close();
670  BEAST_EXPECT(ownerCount(env, alice) == 1);
671 
672  //----------------------------------------------------------------------
673  // preflight
674 
675  // buyer burns a fee, so they no longer have enough XRP to cover the
676  // reserve for a token offer.
677  env(noop(buyer));
678  env.close();
679 
680  // buyer tries to create an NFTokenOffer, but doesn't have the reserve.
681  env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
682  token::owner(alice),
684  env.close();
685  BEAST_EXPECT(ownerCount(env, buyer) == 0);
686 
687  // Set a negative fee.
688  env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
689  fee(STAmount(10ull, true)),
690  ter(temBAD_FEE));
691  env.close();
692  BEAST_EXPECT(ownerCount(env, buyer) == 0);
693 
694  // Set an invalid flag.
695  env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
696  txflags(0x00008000),
697  ter(temINVALID_FLAG));
698  env.close();
699  BEAST_EXPECT(ownerCount(env, buyer) == 0);
700 
701  // Set an invalid amount.
702  env(token::createOffer(buyer, nftXrpOnlyID, buyer["USD"](1)),
703  ter(temBAD_AMOUNT));
704  env(token::createOffer(buyer, nftAlice0ID, buyer["USD"](0)),
705  ter(temBAD_AMOUNT));
706  env(token::createOffer(buyer, nftXrpOnlyID, drops(0)),
707  ter(temBAD_AMOUNT));
708  env.close();
709  BEAST_EXPECT(ownerCount(env, buyer) == 0);
710 
711  // Set a bad expiration.
712  env(token::createOffer(buyer, nftAlice0ID, buyer["USD"](1)),
713  token::expiration(0),
714  ter(temBAD_EXPIRATION));
715  env.close();
716  BEAST_EXPECT(ownerCount(env, buyer) == 0);
717 
718  // Invalid Owner field and tfSellToken flag relationships.
719  // A buy offer must specify the owner.
720  env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
721  ter(temMALFORMED));
722  env.close();
723  BEAST_EXPECT(ownerCount(env, buyer) == 0);
724 
725  // A sell offer must not specify the owner; the owner is implicit.
726  env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
727  token::owner(alice),
728  txflags(tfSellNFToken),
729  ter(temMALFORMED));
730  env.close();
731  BEAST_EXPECT(ownerCount(env, alice) == 1);
732 
733  // An owner may not offer to buy their own token.
734  env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
735  token::owner(alice),
736  ter(temMALFORMED));
737  env.close();
738  BEAST_EXPECT(ownerCount(env, alice) == 1);
739 
740  // The destination may not be the account submitting the transaction.
741  env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
742  token::destination(alice),
743  txflags(tfSellNFToken),
744  ter(temMALFORMED));
745  env.close();
746  BEAST_EXPECT(ownerCount(env, alice) == 1);
747 
748  // The destination must be an account already established in the ledger.
749  env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
750  token::destination(Account("demon")),
751  txflags(tfSellNFToken),
752  ter(tecNO_DST));
753  env.close();
754  BEAST_EXPECT(ownerCount(env, alice) == 1);
755 
756  //----------------------------------------------------------------------
757  // preclaim
758 
759  // The new NFTokenOffer may not have passed its expiration time.
760  env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
761  token::owner(alice),
762  token::expiration(lastClose(env)),
763  ter(tecEXPIRED));
764  env.close();
765  BEAST_EXPECT(ownerCount(env, buyer) == 0);
766 
767  // The nftID must be present in the ledger.
768  env(token::createOffer(buyer, token::getID(alice, 0, 1), XRP(1000)),
769  token::owner(alice),
770  ter(tecNO_ENTRY));
771  env.close();
772  BEAST_EXPECT(ownerCount(env, buyer) == 0);
773 
774  // The nftID must be present in the ledger of a sell offer too.
775  env(token::createOffer(alice, token::getID(alice, 0, 1), XRP(1000)),
776  txflags(tfSellNFToken),
777  ter(tecNO_ENTRY));
778  env.close();
779  BEAST_EXPECT(ownerCount(env, buyer) == 0);
780 
781  // buyer must have the funds to pay for their offer.
782  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
783  token::owner(alice),
784  ter(tecNO_LINE));
785  env.close();
786  BEAST_EXPECT(ownerCount(env, buyer) == 0);
787 
788  env(trust(buyer, gwAUD(1000)));
789  env.close();
790  BEAST_EXPECT(ownerCount(env, buyer) == 1);
791  env.close();
792 
793  // Issuer (alice) must have a trust line for the offered funds.
794  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
795  token::owner(alice),
796  ter(tecNO_LINE));
797  env.close();
798  BEAST_EXPECT(ownerCount(env, buyer) == 1);
799 
800  // Give alice the needed trust line, but freeze it.
801  env(trust(gw, alice["AUD"](999), tfSetFreeze));
802  env.close();
803 
804  // Issuer (alice) must have a trust line for the offered funds and
805  // the trust line may not be frozen.
806  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
807  token::owner(alice),
808  ter(tecFROZEN));
809  env.close();
810  BEAST_EXPECT(ownerCount(env, buyer) == 1);
811 
812  // Unfreeze alice's trustline.
813  env(trust(gw, alice["AUD"](999), tfClearFreeze));
814  env.close();
815 
816  // Can't transfer the NFT if the transferable flag is not set.
817  env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
818  token::owner(alice),
820  env.close();
821  BEAST_EXPECT(ownerCount(env, buyer) == 1);
822 
823  // Give buyer the needed trust line, but freeze it.
824  env(trust(gw, buyer["AUD"](999), tfSetFreeze));
825  env.close();
826 
827  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
828  token::owner(alice),
829  ter(tecFROZEN));
830  env.close();
831  BEAST_EXPECT(ownerCount(env, buyer) == 1);
832 
833  // Unfreeze buyer's trust line, but buyer has no actual gwAUD.
834  // to cover the offer.
835  env(trust(gw, buyer["AUD"](999), tfClearFreeze));
836  env(trust(buyer, gwAUD(1000)));
837  env.close();
838 
839  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
840  token::owner(alice),
841  ter(tecUNFUNDED_OFFER));
842  env.close();
843  BEAST_EXPECT(ownerCount(env, buyer) == 1); // the trust line.
844 
845  //----------------------------------------------------------------------
846  // doApply
847 
848  // Give buyer almost enough AUD to cover the offer...
849  env(pay(gw, buyer, gwAUD(999)));
850  env.close();
851 
852  // However buyer doesn't have enough XRP to cover the reserve for
853  // an NFT offer.
854  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
855  token::owner(alice),
857  env.close();
858  BEAST_EXPECT(ownerCount(env, buyer) == 1);
859 
860  // Give buyer almost enough XRP to cover the reserve.
861  env(pay(env.master, buyer, XRP(50) + drops(119)));
862  env.close();
863 
864  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
865  token::owner(alice),
867  env.close();
868  BEAST_EXPECT(ownerCount(env, buyer) == 1);
869 
870  // Give buyer just enough XRP to cover the reserve for the offer.
871  env(pay(env.master, buyer, drops(11)));
872  env.close();
873 
874  // We don't care whether the offer is fully funded until the offer is
875  // accepted. Success at last!
876  env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
877  token::owner(alice),
878  ter(tesSUCCESS));
879  env.close();
880  BEAST_EXPECT(ownerCount(env, buyer) == 2);
881  }
882 
883  void
885  {
886  testcase("Invalid NFT offer cancel");
887 
888  using namespace test::jtx;
889 
890  Env env{*this, features};
891  Account const alice{"alice"};
892  Account const buyer{"buyer"};
893  Account const gw("gw");
894  IOU const gwAUD(gw["AUD"]);
895 
896  env.fund(XRP(1000), alice, buyer, gw);
897  env.close();
898  BEAST_EXPECT(ownerCount(env, alice) == 0);
899 
900  uint256 const nftAlice0ID =
901  token::getNextID(env, alice, 0, tfTransferable);
902  env(token::mint(alice, 0u), txflags(tfTransferable));
903  env.close();
904  BEAST_EXPECT(ownerCount(env, alice) == 1);
905 
906  // This is the offer we'll try to cancel.
907  uint256 const buyerOfferIndex =
908  keylet::nftoffer(buyer, env.seq(buyer)).key;
909  env(token::createOffer(buyer, nftAlice0ID, XRP(1)),
910  token::owner(alice),
911  ter(tesSUCCESS));
912  env.close();
913  BEAST_EXPECT(ownerCount(env, buyer) == 1);
914 
915  //----------------------------------------------------------------------
916  // preflight
917 
918  // Set a negative fee.
919  env(token::cancelOffer(buyer, {buyerOfferIndex}),
920  fee(STAmount(10ull, true)),
921  ter(temBAD_FEE));
922  env.close();
923  BEAST_EXPECT(ownerCount(env, buyer) == 1);
924 
925  // Set an invalid flag.
926  env(token::cancelOffer(buyer, {buyerOfferIndex}),
927  txflags(0x00008000),
928  ter(temINVALID_FLAG));
929  env.close();
930  BEAST_EXPECT(ownerCount(env, buyer) == 1);
931 
932  // Empty list of tokens to delete.
933  {
934  Json::Value jv = token::cancelOffer(buyer);
936  env(jv, ter(temMALFORMED));
937  env.close();
938  BEAST_EXPECT(ownerCount(env, buyer) == 1);
939  }
940 
941  // List of tokens to delete is too long.
942  {
943  std::vector<uint256> offers(
944  maxTokenOfferCancelCount + 1, buyerOfferIndex);
945 
946  env(token::cancelOffer(buyer, offers), ter(temMALFORMED));
947  env.close();
948  BEAST_EXPECT(ownerCount(env, buyer) == 1);
949  }
950 
951  // Duplicate entries are not allowed in the list of offers to cancel.
952  env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}),
953  ter(temMALFORMED));
954  env.close();
955  BEAST_EXPECT(ownerCount(env, buyer) == 1);
956 
957  // Provide neither offers to cancel nor a root index.
958  env(token::cancelOffer(buyer), ter(temMALFORMED));
959  env.close();
960  BEAST_EXPECT(ownerCount(env, buyer) == 1);
961 
962  //----------------------------------------------------------------------
963  // preclaim
964 
965  // Make a non-root directory that we can pass as a root index.
966  env(pay(env.master, gw, XRP(5000)));
967  env.close();
968  for (std::uint32_t i = 1; i < 34; ++i)
969  {
970  env(offer(gw, XRP(i), gwAUD(1)));
971  env.close();
972  }
973 
974  {
975  // gw attempts to cancel a Check as through it is an NFTokenOffer.
976  auto const gwCheckId = keylet::check(gw, env.seq(gw)).key;
977  env(check::create(gw, env.master, XRP(300)));
978  env.close();
979 
980  env(token::cancelOffer(gw, {gwCheckId}), ter(tecNO_PERMISSION));
981  env.close();
982 
983  // Cancel the check so it doesn't mess up later tests.
984  env(check::cancel(gw, gwCheckId));
985  env.close();
986  }
987 
988  // gw attempts to cancel an offer they don't have permission to cancel.
989  env(token::cancelOffer(gw, {buyerOfferIndex}), ter(tecNO_PERMISSION));
990  env.close();
991  BEAST_EXPECT(ownerCount(env, buyer) == 1);
992 
993  //----------------------------------------------------------------------
994  // doApply
995  //
996  // The tefBAD_LEDGER conditions are too hard to test.
997  // But let's see a successful offer cancel.
998  env(token::cancelOffer(buyer, {buyerOfferIndex}));
999  env.close();
1000  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1001  }
1002 
1003  void
1005  {
1006  testcase("Invalid NFT offer accept");
1007 
1008  using namespace test::jtx;
1009 
1010  Env env{*this, features};
1011  Account const alice{"alice"};
1012  Account const buyer{"buyer"};
1013  Account const gw("gw");
1014  IOU const gwAUD(gw["AUD"]);
1015 
1016  env.fund(XRP(1000), alice, buyer, gw);
1017  env.close();
1018  BEAST_EXPECT(ownerCount(env, alice) == 0);
1019 
1020  uint256 const nftAlice0ID =
1021  token::getNextID(env, alice, 0, tfTransferable);
1022  env(token::mint(alice, 0u), txflags(tfTransferable));
1023  env.close();
1024  BEAST_EXPECT(ownerCount(env, alice) == 1);
1025 
1026  uint256 const nftXrpOnlyID =
1027  token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable);
1028  env(token::mint(alice, 0), txflags(tfOnlyXRP | tfTransferable));
1029  env.close();
1030  BEAST_EXPECT(ownerCount(env, alice) == 1);
1031 
1032  uint256 nftNoXferID = token::getNextID(env, alice, 0);
1033  env(token::mint(alice, 0));
1034  env.close();
1035  BEAST_EXPECT(ownerCount(env, alice) == 1);
1036 
1037  // alice creates sell offers for her nfts.
1038  uint256 const plainOfferIndex =
1039  keylet::nftoffer(alice, env.seq(alice)).key;
1040  env(token::createOffer(alice, nftAlice0ID, XRP(10)),
1041  txflags(tfSellNFToken));
1042  env.close();
1043  BEAST_EXPECT(ownerCount(env, alice) == 2);
1044 
1045  uint256 const audOfferIndex =
1046  keylet::nftoffer(alice, env.seq(alice)).key;
1047  env(token::createOffer(alice, nftAlice0ID, gwAUD(30)),
1048  txflags(tfSellNFToken));
1049  env.close();
1050  BEAST_EXPECT(ownerCount(env, alice) == 3);
1051 
1052  uint256 const xrpOnlyOfferIndex =
1053  keylet::nftoffer(alice, env.seq(alice)).key;
1054  env(token::createOffer(alice, nftXrpOnlyID, XRP(20)),
1055  txflags(tfSellNFToken));
1056  env.close();
1057  BEAST_EXPECT(ownerCount(env, alice) == 4);
1058 
1059  uint256 const noXferOfferIndex =
1060  keylet::nftoffer(alice, env.seq(alice)).key;
1061  env(token::createOffer(alice, nftNoXferID, XRP(30)),
1062  txflags(tfSellNFToken));
1063  env.close();
1064  BEAST_EXPECT(ownerCount(env, alice) == 5);
1065 
1066  // alice creates a sell offer that will expire soon.
1067  uint256 const aliceExpOfferIndex =
1068  keylet::nftoffer(alice, env.seq(alice)).key;
1069  env(token::createOffer(alice, nftNoXferID, XRP(40)),
1070  txflags(tfSellNFToken),
1071  token::expiration(lastClose(env) + 5));
1072  env.close();
1073  BEAST_EXPECT(ownerCount(env, alice) == 6);
1074 
1075  //----------------------------------------------------------------------
1076  // preflight
1077 
1078  // Set a negative fee.
1079  env(token::acceptSellOffer(buyer, noXferOfferIndex),
1080  fee(STAmount(10ull, true)),
1081  ter(temBAD_FEE));
1082  env.close();
1083  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1084 
1085  // Set an invalid flag.
1086  env(token::acceptSellOffer(buyer, noXferOfferIndex),
1087  txflags(0x00008000),
1088  ter(temINVALID_FLAG));
1089  env.close();
1090  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1091 
1092  // Supply nether an sfNFTokenBuyOffer nor an sfNFTokenSellOffer field.
1093  {
1094  Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1096  env(jv, ter(temMALFORMED));
1097  env.close();
1098  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1099  }
1100 
1101  // A buy offer may not contain a sfNFTokenBrokerFee field.
1102  {
1103  Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1106  env(jv, ter(temMALFORMED));
1107  env.close();
1108  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1109  }
1110 
1111  // A sell offer may not contain a sfNFTokenBrokerFee field.
1112  {
1113  Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1116  env(jv, ter(temMALFORMED));
1117  env.close();
1118  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1119  }
1120 
1121  // A brokered offer may not contain a negative or zero brokerFee.
1122  env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1123  token::brokerFee(gwAUD(0)),
1124  ter(temMALFORMED));
1125  env.close();
1126  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1127 
1128  //----------------------------------------------------------------------
1129  // preclaim
1130 
1131  // The buy offer must be present in the ledger.
1132  uint256 const missingOfferIndex = keylet::nftoffer(alice, 1).key;
1133  env(token::acceptBuyOffer(buyer, missingOfferIndex),
1134  ter(tecOBJECT_NOT_FOUND));
1135  env.close();
1136  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1137 
1138  // The buy offer must not have expired.
1139  env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(tecEXPIRED));
1140  env.close();
1141  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1142 
1143  // The sell offer must be present in the ledger.
1144  env(token::acceptSellOffer(buyer, missingOfferIndex),
1145  ter(tecOBJECT_NOT_FOUND));
1146  env.close();
1147  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1148 
1149  // The sell offer must not have expired.
1150  env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(tecEXPIRED));
1151  env.close();
1152  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1153 
1154  //----------------------------------------------------------------------
1155  // preclaim brokered
1156 
1157  // alice and buyer need trustlines before buyer can to create an
1158  // offer for gwAUD.
1159  env(trust(alice, gwAUD(1000)));
1160  env(trust(buyer, gwAUD(1000)));
1161  env.close();
1162  env(pay(gw, buyer, gwAUD(30)));
1163  env.close();
1164  BEAST_EXPECT(ownerCount(env, alice) == 7);
1165  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1166 
1167  // We're about to exercise offer brokering, so we need
1168  // corresponding buy and sell offers.
1169  {
1170  // buyer creates a buy offer for one of alice's nfts.
1171  uint256 const buyerOfferIndex =
1172  keylet::nftoffer(buyer, env.seq(buyer)).key;
1173  env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)),
1174  token::owner(alice));
1175  env.close();
1176  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1177 
1178  // gw attempts to broker offers that are not for the same token.
1179  env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1181  env.close();
1182  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1183 
1184  // gw attempts to broker offers that are not for the same currency.
1185  env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1187  env.close();
1188  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1189 
1190  // In a brokered offer, the buyer must offer greater than or
1191  // equal to the selling price.
1192  env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1194  env.close();
1195  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1196 
1197  // Remove buyer's offer.
1198  env(token::cancelOffer(buyer, {buyerOfferIndex}));
1199  env.close();
1200  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1201  }
1202  {
1203  // buyer creates a buy offer for one of alice's nfts.
1204  uint256 const buyerOfferIndex =
1205  keylet::nftoffer(buyer, env.seq(buyer)).key;
1206  env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)),
1207  token::owner(alice));
1208  env.close();
1209  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1210 
1211  // Broker sets their fee in a denomination other than the one
1212  // used by the offers
1213  env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1214  token::brokerFee(XRP(40)),
1216  env.close();
1217  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1218 
1219  // Broker fee way too big.
1220  env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1221  token::brokerFee(gwAUD(31)),
1223  env.close();
1224  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1225 
1226  // Broker fee is smaller, but still too big once the offer
1227  // seller's minimum is taken into account.
1228  env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1229  token::brokerFee(gwAUD(1.5)),
1231  env.close();
1232  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1233 
1234  // Remove buyer's offer.
1235  env(token::cancelOffer(buyer, {buyerOfferIndex}));
1236  env.close();
1237  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1238  }
1239  //----------------------------------------------------------------------
1240  // preclaim buy
1241  {
1242  // buyer creates a buy offer for one of alice's nfts.
1243  uint256 const buyerOfferIndex =
1244  keylet::nftoffer(buyer, env.seq(buyer)).key;
1245  env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)),
1246  token::owner(alice));
1247  env.close();
1248  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1249 
1250  // Don't accept a buy offer if the sell flag is set.
1251  env(token::acceptBuyOffer(buyer, plainOfferIndex),
1253  env.close();
1254  BEAST_EXPECT(ownerCount(env, alice) == 7);
1255 
1256  // An account can't accept its own offer.
1257  env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1259  env.close();
1260  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1261 
1262  // An offer acceptor must have enough funds to pay for the offer.
1263  env(pay(buyer, gw, gwAUD(30)));
1264  env.close();
1265  BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1266  env(token::acceptBuyOffer(alice, buyerOfferIndex),
1267  ter(tecINSUFFICIENT_FUNDS));
1268  env.close();
1269  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1270 
1271  // alice gives her NFT to gw, so alice no longer owns nftAlice0.
1272  {
1273  uint256 const offerIndex =
1274  keylet::nftoffer(alice, env.seq(alice)).key;
1275  env(token::createOffer(alice, nftAlice0ID, XRP(0)),
1276  txflags(tfSellNFToken));
1277  env.close();
1278  env(token::acceptSellOffer(gw, offerIndex));
1279  env.close();
1280  BEAST_EXPECT(ownerCount(env, alice) == 7);
1281  }
1282  env(pay(gw, buyer, gwAUD(30)));
1283  env.close();
1284 
1285  // alice can't accept a buy offer for an NFT she no longer owns.
1286  env(token::acceptBuyOffer(alice, buyerOfferIndex),
1287  ter(tecNO_PERMISSION));
1288  env.close();
1289  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1290 
1291  // Remove buyer's offer.
1292  env(token::cancelOffer(buyer, {buyerOfferIndex}));
1293  env.close();
1294  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1295  }
1296  //----------------------------------------------------------------------
1297  // preclaim sell
1298  {
1299  // buyer creates a buy offer for one of alice's nfts.
1300  uint256 const buyerOfferIndex =
1301  keylet::nftoffer(buyer, env.seq(buyer)).key;
1302  env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)),
1303  token::owner(alice));
1304  env.close();
1305  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1306 
1307  // Don't accept a sell offer without the sell flag set.
1308  env(token::acceptSellOffer(alice, buyerOfferIndex),
1310  env.close();
1311  BEAST_EXPECT(ownerCount(env, alice) == 7);
1312 
1313  // An account can't accept its own offer.
1314  env(token::acceptSellOffer(alice, plainOfferIndex),
1316  env.close();
1317  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1318 
1319  // The seller must currently be in possession of the token they
1320  // are selling. alice gave nftAlice0ID to gw.
1321  env(token::acceptSellOffer(buyer, plainOfferIndex),
1322  ter(tecNO_PERMISSION));
1323  env.close();
1324  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1325 
1326  // gw gives nftAlice0ID back to alice. That allows us to check
1327  // buyer attempting to accept one of alice's offers with
1328  // insufficient funds.
1329  {
1330  uint256 const offerIndex =
1331  keylet::nftoffer(gw, env.seq(gw)).key;
1332  env(token::createOffer(gw, nftAlice0ID, XRP(0)),
1333  txflags(tfSellNFToken));
1334  env.close();
1335  env(token::acceptSellOffer(alice, offerIndex));
1336  env.close();
1337  BEAST_EXPECT(ownerCount(env, alice) == 7);
1338  }
1339  env(pay(buyer, gw, gwAUD(30)));
1340  env.close();
1341  BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1342  env(token::acceptSellOffer(buyer, audOfferIndex),
1343  ter(tecINSUFFICIENT_FUNDS));
1344  env.close();
1345  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1346  }
1347 
1348  //----------------------------------------------------------------------
1349  // doApply
1350  //
1351  // As far as I can see none of the failure modes are accessible as
1352  // long as the preflight and preclaim conditions are met.
1353  }
1354 
1355  void
1357  {
1358  // Exercise NFTs with flagBurnable set and not set.
1359  testcase("Mint flagBurnable");
1360 
1361  using namespace test::jtx;
1362 
1363  Env env{*this, features};
1364  Account const alice{"alice"};
1365  Account const buyer{"buyer"};
1366  Account const minter1{"minter1"};
1367  Account const minter2{"minter2"};
1368 
1369  env.fund(XRP(1000), alice, buyer, minter1, minter2);
1370  env.close();
1371  BEAST_EXPECT(ownerCount(env, alice) == 0);
1372 
1373  // alice selects minter as her minter.
1374  env(token::setMinter(alice, minter1));
1375  env.close();
1376 
1377  // A lambda that...
1378  // 1. creates an alice nft
1379  // 2. minted by minter and
1380  // 3. transfers that nft to buyer.
1381  auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1382  std::uint32_t flags) {
1383  uint256 const nftID{token::getNextID(env, alice, 0u, flags)};
1384  env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags));
1385  env.close();
1386 
1387  uint256 const offerIndex =
1388  keylet::nftoffer(minter1, env.seq(minter1)).key;
1389  env(token::createOffer(minter1, nftID, XRP(0)),
1390  txflags(tfSellNFToken));
1391  env.close();
1392 
1393  env(token::acceptSellOffer(buyer, offerIndex));
1394  env.close();
1395 
1396  return nftID;
1397  };
1398 
1399  // An NFT without flagBurnable can only be burned by its owner.
1400  {
1401  uint256 const noBurnID = nftToBuyer(0);
1402  env(token::burn(alice, noBurnID),
1403  token::owner(buyer),
1404  ter(tecNO_PERMISSION));
1405  env.close();
1406  env(token::burn(minter1, noBurnID),
1407  token::owner(buyer),
1408  ter(tecNO_PERMISSION));
1409  env.close();
1410  env(token::burn(minter2, noBurnID),
1411  token::owner(buyer),
1412  ter(tecNO_PERMISSION));
1413  env.close();
1414 
1415  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1416  env(token::burn(buyer, noBurnID), token::owner(buyer));
1417  env.close();
1418  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1419  }
1420  // An NFT with flagBurnable can be burned by the issuer.
1421  {
1422  uint256 const burnableID = nftToBuyer(tfBurnable);
1423  env(token::burn(minter2, burnableID),
1424  token::owner(buyer),
1425  ter(tecNO_PERMISSION));
1426  env.close();
1427 
1428  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1429  env(token::burn(alice, burnableID), token::owner(buyer));
1430  env.close();
1431  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1432  }
1433  // An NFT with flagBurnable can be burned by the owner.
1434  {
1435  uint256 const burnableID = nftToBuyer(tfBurnable);
1436  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1437  env(token::burn(buyer, burnableID));
1438  env.close();
1439  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1440  }
1441  // An NFT with flagBurnable can be burned by the minter.
1442  {
1443  uint256 const burnableID = nftToBuyer(tfBurnable);
1444  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1445  env(token::burn(buyer, burnableID), token::owner(buyer));
1446  env.close();
1447  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1448  }
1449  // An nft with flagBurnable may be burned by the issuers' minter,
1450  // who may not be the original minter.
1451  {
1452  uint256 const burnableID = nftToBuyer(tfBurnable);
1453  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1454 
1455  env(token::setMinter(alice, minter2));
1456  env.close();
1457 
1458  // minter1 is no longer alice's minter, so no longer has
1459  // permisson to burn alice's nfts.
1460  env(token::burn(minter1, burnableID),
1461  token::owner(buyer),
1462  ter(tecNO_PERMISSION));
1463  env.close();
1464  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1465 
1466  // minter2, however, can burn alice's nfts.
1467  env(token::burn(minter2, burnableID), token::owner(buyer));
1468  env.close();
1469  BEAST_EXPECT(ownerCount(env, buyer) == 0);
1470  }
1471  }
1472 
1473  void
1475  {
1476  // Exercise NFTs with flagOnlyXRP set and not set.
1477  testcase("Mint flagOnlyXRP");
1478 
1479  using namespace test::jtx;
1480 
1481  Env env{*this, features};
1482  Account const alice{"alice"};
1483  Account const buyer{"buyer"};
1484  Account const gw("gw");
1485  IOU const gwAUD(gw["AUD"]);
1486 
1487  // Set trust lines so alice and buyer can use gwAUD.
1488  env.fund(XRP(1000), alice, buyer, gw);
1489  env.close();
1490  env(trust(alice, gwAUD(1000)));
1491  env(trust(buyer, gwAUD(1000)));
1492  env.close();
1493  env(pay(gw, buyer, gwAUD(100)));
1494 
1495  // Don't set flagOnlyXRP and offers can be made with IOUs.
1496  {
1497  uint256 const nftIOUsOkayID{
1498  token::getNextID(env, alice, 0u, tfTransferable)};
1499  env(token::mint(alice, 0u), txflags(tfTransferable));
1500  env.close();
1501 
1502  BEAST_EXPECT(ownerCount(env, alice) == 2);
1503  uint256 const aliceOfferIndex =
1504  keylet::nftoffer(alice, env.seq(alice)).key;
1505  env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)),
1506  txflags(tfSellNFToken));
1507  env.close();
1508  BEAST_EXPECT(ownerCount(env, alice) == 3);
1509 
1510  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1511  uint256 const buyerOfferIndex =
1512  keylet::nftoffer(buyer, env.seq(buyer)).key;
1513  env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)),
1514  token::owner(alice));
1515  env.close();
1516  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1517 
1518  // Cancel the two offers just to be tidy.
1519  env(token::cancelOffer(alice, {aliceOfferIndex}));
1520  env(token::cancelOffer(buyer, {buyerOfferIndex}));
1521  env.close();
1522  BEAST_EXPECT(ownerCount(env, alice) == 2);
1523  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1524 
1525  // Also burn alice's nft.
1526  env(token::burn(alice, nftIOUsOkayID));
1527  env.close();
1528  BEAST_EXPECT(ownerCount(env, alice) == 1);
1529  }
1530 
1531  // Set flagOnlyXRP and offers using IOUs are rejected.
1532  {
1533  uint256 const nftOnlyXRPID{
1534  token::getNextID(env, alice, 0u, tfOnlyXRP | tfTransferable)};
1535  env(token::mint(alice, 0u), txflags(tfOnlyXRP | tfTransferable));
1536  env.close();
1537 
1538  BEAST_EXPECT(ownerCount(env, alice) == 2);
1539  env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)),
1540  txflags(tfSellNFToken),
1541  ter(temBAD_AMOUNT));
1542  env.close();
1543  BEAST_EXPECT(ownerCount(env, alice) == 2);
1544 
1545  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1546  env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)),
1547  token::owner(alice),
1548  ter(temBAD_AMOUNT));
1549  env.close();
1550  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1551 
1552  // However offers for XRP are okay.
1553  BEAST_EXPECT(ownerCount(env, alice) == 2);
1554  env(token::createOffer(alice, nftOnlyXRPID, XRP(60)),
1555  txflags(tfSellNFToken));
1556  env.close();
1557  BEAST_EXPECT(ownerCount(env, alice) == 3);
1558 
1559  BEAST_EXPECT(ownerCount(env, buyer) == 1);
1560  env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)),
1561  token::owner(alice));
1562  env.close();
1563  BEAST_EXPECT(ownerCount(env, buyer) == 2);
1564  }
1565  }
1566 
1567  void
1569  {
1570  // Exercise NFTs with flagCreateTrustLines set and not set.
1571  testcase("Mint flagCreateTrustLines");
1572 
1573  using namespace test::jtx;
1574 
1575  Env env{*this, features};
1576  Account const alice{"alice"};
1577  Account const becky{"becky"};
1578  Account const cheri{"cheri"};
1579  Account const gw("gw");
1580  IOU const gwAUD(gw["AUD"]);
1581  IOU const gwCAD(gw["CAD"]);
1582  IOU const gwEUR(gw["EUR"]);
1583 
1584  env.fund(XRP(1000), alice, becky, cheri, gw);
1585  env.close();
1586 
1587  // Set trust lines so becky and cheri can use gw's currency.
1588  env(trust(becky, gwAUD(1000)));
1589  env(trust(cheri, gwAUD(1000)));
1590  env(trust(becky, gwCAD(1000)));
1591  env(trust(cheri, gwCAD(1000)));
1592  env(trust(becky, gwEUR(1000)));
1593  env(trust(cheri, gwEUR(1000)));
1594  env.close();
1595  env(pay(gw, becky, gwAUD(500)));
1596  env(pay(gw, becky, gwCAD(500)));
1597  env(pay(gw, becky, gwEUR(500)));
1598  env(pay(gw, cheri, gwAUD(500)));
1599  env(pay(gw, cheri, gwCAD(500)));
1600  env.close();
1601 
1602  // An nft without flagCreateTrustLines but with a non-zero transfer
1603  // fee will not allow creating offers that use IOUs for payment.
1604  for (std::uint32_t xferFee : {0, 1})
1605  {
1606  uint256 const nftNoAutoTrustID{
1607  token::getNextID(env, alice, 0u, tfTransferable, xferFee)};
1608  env(token::mint(alice, 0u),
1609  token::xferFee(xferFee),
1610  txflags(tfTransferable));
1611  env.close();
1612 
1613  // becky buys the nft for 1 drop.
1614  uint256 const beckyBuyOfferIndex =
1615  keylet::nftoffer(becky, env.seq(becky)).key;
1616  env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1617  token::owner(alice));
1618  env.close();
1619  env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1620  env.close();
1621 
1622  // becky attempts to sell the nft for AUD.
1623  TER const createOfferTER =
1624  xferFee ? TER(tecNO_LINE) : TER(tesSUCCESS);
1625  uint256 const beckyOfferIndex =
1626  keylet::nftoffer(becky, env.seq(becky)).key;
1627  env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1628  txflags(tfSellNFToken),
1629  ter(createOfferTER));
1630  env.close();
1631 
1632  // cheri offers to buy the nft for CAD.
1633  uint256 const cheriOfferIndex =
1634  keylet::nftoffer(cheri, env.seq(cheri)).key;
1635  env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1636  token::owner(becky),
1637  ter(createOfferTER));
1638  env.close();
1639 
1640  // To keep things tidy, cancel the offers.
1641  env(token::cancelOffer(becky, {beckyOfferIndex}));
1642  env(token::cancelOffer(cheri, {cheriOfferIndex}));
1643  env.close();
1644  }
1645  // An nft with flagCreateTrustLines but with a non-zero transfer
1646  // fee allows transfers using IOUs for payment.
1647  {
1648  std::uint16_t transferFee = 10000; // 10%
1649 
1650  uint256 const nftAutoTrustID{token::getNextID(
1651  env, alice, 0u, tfTransferable | tfTrustLine, transferFee)};
1652  env(token::mint(alice, 0u),
1653  token::xferFee(transferFee),
1654  txflags(tfTransferable | tfTrustLine));
1655  env.close();
1656 
1657  // becky buys the nft for 1 drop.
1658  uint256 const beckyBuyOfferIndex =
1659  keylet::nftoffer(becky, env.seq(becky)).key;
1660  env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1661  token::owner(alice));
1662  env.close();
1663  env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1664  env.close();
1665 
1666  // becky sells the nft for AUD.
1667  uint256 const beckySellOfferIndex =
1668  keylet::nftoffer(becky, env.seq(becky)).key;
1669  env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1670  txflags(tfSellNFToken));
1671  env.close();
1672  env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1673  env.close();
1674 
1675  // alice should now have a trust line for gwAUD.
1676  BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1677 
1678  // becky buys the nft back for CAD.
1679  uint256 const beckyBuyBackOfferIndex =
1680  keylet::nftoffer(becky, env.seq(becky)).key;
1681  env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1682  token::owner(cheri));
1683  env.close();
1684  env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1685  env.close();
1686 
1687  // alice should now have a trust line for gwAUD and gwCAD.
1688  BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1689  BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1690  }
1691  // Now that alice has trust lines already established, an nft without
1692  // flagCreateTrustLines will work for preestablished trust lines.
1693  {
1694  std::uint16_t transferFee = 5000; // 5%
1695  uint256 const nftNoAutoTrustID{
1696  token::getNextID(env, alice, 0u, tfTransferable, transferFee)};
1697  env(token::mint(alice, 0u),
1698  token::xferFee(transferFee),
1699  txflags(tfTransferable));
1700  env.close();
1701 
1702  // alice sells the nft using AUD.
1703  uint256 const aliceSellOfferIndex =
1704  keylet::nftoffer(alice, env.seq(alice)).key;
1705  env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1706  txflags(tfSellNFToken));
1707  env.close();
1708  env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1709  env.close();
1710 
1711  // alice should now have AUD(210):
1712  // o 200 for this sale and
1713  // o 10 for the previous sale's fee.
1714  BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1715 
1716  // cheri can't sell the NFT for EUR, but can for CAD.
1717  env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1718  txflags(tfSellNFToken),
1719  ter(tecNO_LINE));
1720  env.close();
1721  uint256 const cheriSellOfferIndex =
1722  keylet::nftoffer(cheri, env.seq(cheri)).key;
1723  env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1724  txflags(tfSellNFToken));
1725  env.close();
1726  env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1727  env.close();
1728 
1729  // alice should now have CAD(10):
1730  // o 5 from this sale's fee and
1731  // o 5 for the previous sale's fee.
1732  BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1733  }
1734  }
1735 
1736  void
1738  {
1739  // Exercise NFTs with flagTransferable set and not set.
1740  testcase("Mint flagTransferable");
1741 
1742  using namespace test::jtx;
1743 
1744  Env env{*this, features};
1745 
1746  Account const alice{"alice"};
1747  Account const becky{"becky"};
1748  Account const minter{"minter"};
1749 
1750  env.fund(XRP(1000), alice, becky, minter);
1751  env.close();
1752 
1753  // First try an nft made by alice without flagTransferable set.
1754  {
1755  BEAST_EXPECT(ownerCount(env, alice) == 0);
1756  uint256 const nftAliceNoTransferID{
1757  token::getNextID(env, alice, 0u)};
1758  env(token::mint(alice, 0u), token::xferFee(0));
1759  env.close();
1760  BEAST_EXPECT(ownerCount(env, alice) == 1);
1761 
1762  // becky tries to offer to buy alice's nft.
1763  BEAST_EXPECT(ownerCount(env, becky) == 0);
1764  env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1765  token::owner(alice),
1767 
1768  // alice offers to sell the nft and becky accepts the offer.
1769  uint256 const aliceSellOfferIndex =
1770  keylet::nftoffer(alice, env.seq(alice)).key;
1771  env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1772  txflags(tfSellNFToken));
1773  env.close();
1774  env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1775  env.close();
1776  BEAST_EXPECT(ownerCount(env, alice) == 0);
1777  BEAST_EXPECT(ownerCount(env, becky) == 1);
1778 
1779  // becky tries to offer the nft for sale.
1780  env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1781  txflags(tfSellNFToken),
1783  env.close();
1784  BEAST_EXPECT(ownerCount(env, alice) == 0);
1785  BEAST_EXPECT(ownerCount(env, becky) == 1);
1786 
1787  // becky tries to offer the nft for sale with alice as the
1788  // destination. That also doesn't work.
1789  env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1790  txflags(tfSellNFToken),
1791  token::destination(alice),
1793  env.close();
1794  BEAST_EXPECT(ownerCount(env, alice) == 0);
1795  BEAST_EXPECT(ownerCount(env, becky) == 1);
1796 
1797  // alice offers to buy the nft back from becky. becky accepts
1798  // the offer.
1799  uint256 const aliceBuyOfferIndex =
1800  keylet::nftoffer(alice, env.seq(alice)).key;
1801  env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1802  token::owner(becky));
1803  env.close();
1804  env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1805  env.close();
1806  BEAST_EXPECT(ownerCount(env, alice) == 1);
1807  BEAST_EXPECT(ownerCount(env, becky) == 0);
1808 
1809  // alice burns her nft so accounting is simpler below.
1810  env(token::burn(alice, nftAliceNoTransferID));
1811  env.close();
1812  BEAST_EXPECT(ownerCount(env, alice) == 0);
1813  BEAST_EXPECT(ownerCount(env, becky) == 0);
1814  }
1815  // Try an nft minted by minter for alice without flagTransferable set.
1816  {
1817  env(token::setMinter(alice, minter));
1818  env.close();
1819 
1820  BEAST_EXPECT(ownerCount(env, minter) == 0);
1821  uint256 const nftMinterNoTransferID{
1822  token::getNextID(env, alice, 0u)};
1823  env(token::mint(minter), token::issuer(alice));
1824  env.close();
1825  BEAST_EXPECT(ownerCount(env, minter) == 1);
1826 
1827  // becky tries to offer to buy minter's nft.
1828  BEAST_EXPECT(ownerCount(env, becky) == 0);
1829  env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1830  token::owner(minter),
1832  env.close();
1833  BEAST_EXPECT(ownerCount(env, becky) == 0);
1834 
1835  // alice removes authorization of minter.
1836  env(token::clearMinter(alice));
1837  env.close();
1838 
1839  // minter tries to offer their nft for sale.
1840  BEAST_EXPECT(ownerCount(env, minter) == 1);
1841  env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1842  txflags(tfSellNFToken),
1844  env.close();
1845  BEAST_EXPECT(ownerCount(env, minter) == 1);
1846 
1847  // Let enough ledgers pass that old transactions are no longer
1848  // retried, then alice gives authorization back to minter.
1849  for (int i = 0; i < 10; ++i)
1850  env.close();
1851 
1852  env(token::setMinter(alice, minter));
1853  env.close();
1854  BEAST_EXPECT(ownerCount(env, minter) == 1);
1855 
1856  // minter successfully offers their nft for sale.
1857  BEAST_EXPECT(ownerCount(env, minter) == 1);
1858  uint256 const minterSellOfferIndex =
1859  keylet::nftoffer(minter, env.seq(minter)).key;
1860  env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1861  txflags(tfSellNFToken));
1862  env.close();
1863  BEAST_EXPECT(ownerCount(env, minter) == 2);
1864 
1865  // alice removes authorization of minter so we can see whether
1866  // minter's pre-existing offer still works.
1867  env(token::clearMinter(alice));
1868  env.close();
1869 
1870  // becky buys minter's nft even though minter is no longer alice's
1871  // official minter.
1872  BEAST_EXPECT(ownerCount(env, becky) == 0);
1873  env(token::acceptSellOffer(becky, minterSellOfferIndex));
1874  env.close();
1875  BEAST_EXPECT(ownerCount(env, becky) == 1);
1876  BEAST_EXPECT(ownerCount(env, minter) == 0);
1877 
1878  // becky attempts to sell the nft.
1879  env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1880  txflags(tfSellNFToken),
1882  env.close();
1883 
1884  // Since minter is not, at the moment, alice's official minter
1885  // they cannot create an offer to buy the nft they minted.
1886  BEAST_EXPECT(ownerCount(env, minter) == 0);
1887  env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1888  token::owner(becky),
1890  env.close();
1891  BEAST_EXPECT(ownerCount(env, minter) == 0);
1892 
1893  // alice can create an offer to buy the nft.
1894  BEAST_EXPECT(ownerCount(env, alice) == 0);
1895  uint256 const aliceBuyOfferIndex =
1896  keylet::nftoffer(alice, env.seq(alice)).key;
1897  env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1898  token::owner(becky));
1899  env.close();
1900  BEAST_EXPECT(ownerCount(env, alice) == 1);
1901 
1902  // Let enough ledgers pass that old transactions are no longer
1903  // retried, then alice gives authorization back to minter.
1904  for (int i = 0; i < 10; ++i)
1905  env.close();
1906 
1907  env(token::setMinter(alice, minter));
1908  env.close();
1909 
1910  // Now minter can create an offer to buy the nft.
1911  BEAST_EXPECT(ownerCount(env, minter) == 0);
1912  uint256 const minterBuyOfferIndex =
1913  keylet::nftoffer(minter, env.seq(minter)).key;
1914  env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1915  token::owner(becky));
1916  env.close();
1917  BEAST_EXPECT(ownerCount(env, minter) == 1);
1918 
1919  // alice removes authorization of minter so we can see whether
1920  // minter's pre-existing buy offer still works.
1921  env(token::clearMinter(alice));
1922  env.close();
1923 
1924  // becky accepts minter's sell offer.
1925  BEAST_EXPECT(ownerCount(env, minter) == 1);
1926  BEAST_EXPECT(ownerCount(env, becky) == 1);
1927  env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1928  env.close();
1929  BEAST_EXPECT(ownerCount(env, minter) == 1);
1930  BEAST_EXPECT(ownerCount(env, becky) == 0);
1931  BEAST_EXPECT(ownerCount(env, alice) == 1);
1932 
1933  // minter burns their nft and alice cancels her offer so the
1934  // next tests can start with a clean slate.
1935  env(token::burn(minter, nftMinterNoTransferID), ter(tesSUCCESS));
1936  env.close();
1937  env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1938  env.close();
1939  BEAST_EXPECT(ownerCount(env, alice) == 0);
1940  BEAST_EXPECT(ownerCount(env, becky) == 0);
1941  BEAST_EXPECT(ownerCount(env, minter) == 0);
1942  }
1943  // nfts with flagTransferable set should be buyable and salable
1944  // by anybody.
1945  {
1946  BEAST_EXPECT(ownerCount(env, alice) == 0);
1947  uint256 const nftAliceID{
1948  token::getNextID(env, alice, 0u, tfTransferable)};
1949  env(token::mint(alice, 0u), txflags(tfTransferable));
1950  env.close();
1951  BEAST_EXPECT(ownerCount(env, alice) == 1);
1952 
1953  // Both alice and becky can make offers for alice's nft.
1954  uint256 const aliceSellOfferIndex =
1955  keylet::nftoffer(alice, env.seq(alice)).key;
1956  env(token::createOffer(alice, nftAliceID, XRP(20)),
1957  txflags(tfSellNFToken));
1958  env.close();
1959  BEAST_EXPECT(ownerCount(env, alice) == 2);
1960 
1961  uint256 const beckyBuyOfferIndex =
1962  keylet::nftoffer(becky, env.seq(becky)).key;
1963  env(token::createOffer(becky, nftAliceID, XRP(21)),
1964  token::owner(alice));
1965  env.close();
1966  BEAST_EXPECT(ownerCount(env, alice) == 2);
1967 
1968  // becky accepts alice's sell offer.
1969  env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1970  env.close();
1971  BEAST_EXPECT(ownerCount(env, alice) == 0);
1972  BEAST_EXPECT(ownerCount(env, becky) == 2);
1973 
1974  // becky offers to sell the nft.
1975  uint256 const beckySellOfferIndex =
1976  keylet::nftoffer(becky, env.seq(becky)).key;
1977  env(token::createOffer(becky, nftAliceID, XRP(22)),
1978  txflags(tfSellNFToken));
1979  env.close();
1980  BEAST_EXPECT(ownerCount(env, alice) == 0);
1981  BEAST_EXPECT(ownerCount(env, becky) == 3);
1982 
1983  // minter buys the nft (even though minter is not currently
1984  // alice's minter).
1985  env(token::acceptSellOffer(minter, beckySellOfferIndex));
1986  env.close();
1987  BEAST_EXPECT(ownerCount(env, alice) == 0);
1988  BEAST_EXPECT(ownerCount(env, becky) == 1);
1989  BEAST_EXPECT(ownerCount(env, minter) == 1);
1990 
1991  // minter offers to sell the nft.
1992  uint256 const minterSellOfferIndex =
1993  keylet::nftoffer(minter, env.seq(minter)).key;
1994  env(token::createOffer(minter, nftAliceID, XRP(23)),
1995  txflags(tfSellNFToken));
1996  env.close();
1997  BEAST_EXPECT(ownerCount(env, alice) == 0);
1998  BEAST_EXPECT(ownerCount(env, becky) == 1);
1999  BEAST_EXPECT(ownerCount(env, minter) == 2);
2000 
2001  // alice buys back the nft.
2002  env(token::acceptSellOffer(alice, minterSellOfferIndex));
2003  env.close();
2004  BEAST_EXPECT(ownerCount(env, alice) == 1);
2005  BEAST_EXPECT(ownerCount(env, becky) == 1);
2006  BEAST_EXPECT(ownerCount(env, minter) == 0);
2007 
2008  // Remember the buy offer that becky made for alice's token way
2009  // back when? It's still in the ledger, and alice accepts it.
2010  env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2011  env.close();
2012  BEAST_EXPECT(ownerCount(env, alice) == 0);
2013  BEAST_EXPECT(ownerCount(env, becky) == 1);
2014  BEAST_EXPECT(ownerCount(env, minter) == 0);
2015 
2016  // Just for tidyness, becky burns the token before shutting
2017  // things down.
2018  env(token::burn(becky, nftAliceID));
2019  env.close();
2020  BEAST_EXPECT(ownerCount(env, alice) == 0);
2021  BEAST_EXPECT(ownerCount(env, becky) == 0);
2022  BEAST_EXPECT(ownerCount(env, minter) == 0);
2023  }
2024  }
2025 
2026  void
2028  {
2029  // Exercise NFTs with and without a transferFee.
2030  testcase("Mint transferFee");
2031 
2032  using namespace test::jtx;
2033 
2034  Env env{*this, features};
2035 
2036  Account const alice{"alice"};
2037  Account const becky{"becky"};
2038  Account const carol{"carol"};
2039  Account const minter{"minter"};
2040  Account const gw{"gw"};
2041  IOU const gwXAU(gw["XAU"]);
2042 
2043  env.fund(XRP(1000), alice, becky, carol, minter, gw);
2044  env.close();
2045 
2046  env(trust(alice, gwXAU(2000)));
2047  env(trust(becky, gwXAU(2000)));
2048  env(trust(carol, gwXAU(2000)));
2049  env(trust(minter, gwXAU(2000)));
2050  env.close();
2051  env(pay(gw, alice, gwXAU(1000)));
2052  env(pay(gw, becky, gwXAU(1000)));
2053  env(pay(gw, carol, gwXAU(1000)));
2054  env(pay(gw, minter, gwXAU(1000)));
2055  env.close();
2056 
2057  // Giving alice a minter helps us see if transfer rates are affected
2058  // by that.
2059  env(token::setMinter(alice, minter));
2060  env.close();
2061 
2062  // If there is no transferFee, then alice gets nothing for the
2063  // transfer.
2064  {
2065  BEAST_EXPECT(ownerCount(env, alice) == 1);
2066  BEAST_EXPECT(ownerCount(env, becky) == 1);
2067  BEAST_EXPECT(ownerCount(env, carol) == 1);
2068  BEAST_EXPECT(ownerCount(env, minter) == 1);
2069 
2070  uint256 const nftID =
2071  token::getNextID(env, alice, 0u, tfTransferable);
2072  env(token::mint(alice), txflags(tfTransferable));
2073  env.close();
2074 
2075  // Becky buys the nft for XAU(10). Check balances.
2076  uint256 const beckyBuyOfferIndex =
2077  keylet::nftoffer(becky, env.seq(becky)).key;
2078  env(token::createOffer(becky, nftID, gwXAU(10)),
2079  token::owner(alice));
2080  env.close();
2081  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2082  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2083 
2084  env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2085  env.close();
2086  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2087  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2088 
2089  // becky sells nft to carol. alice's balance should not change.
2090  uint256 const beckySellOfferIndex =
2091  keylet::nftoffer(becky, env.seq(becky)).key;
2092  env(token::createOffer(becky, nftID, gwXAU(10)),
2093  txflags(tfSellNFToken));
2094  env.close();
2095  env(token::acceptSellOffer(carol, beckySellOfferIndex));
2096  env.close();
2097  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2098  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2099  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2100 
2101  // minter buys nft from carol. alice's balance should not change.
2102  uint256 const minterBuyOfferIndex =
2103  keylet::nftoffer(minter, env.seq(minter)).key;
2104  env(token::createOffer(minter, nftID, gwXAU(10)),
2105  token::owner(carol));
2106  env.close();
2107  env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2108  env.close();
2109  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2110  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2111  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2112  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2113 
2114  // minter sells the nft to alice. gwXAU balances should finish
2115  // where they started.
2116  uint256 const minterSellOfferIndex =
2117  keylet::nftoffer(minter, env.seq(minter)).key;
2118  env(token::createOffer(minter, nftID, gwXAU(10)),
2119  txflags(tfSellNFToken));
2120  env.close();
2121  env(token::acceptSellOffer(alice, minterSellOfferIndex));
2122  env.close();
2123  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2124  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2125  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2126  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2127 
2128  // alice burns the nft to make later tests easier to think about.
2129  env(token::burn(alice, nftID));
2130  env.close();
2131  BEAST_EXPECT(ownerCount(env, alice) == 1);
2132  BEAST_EXPECT(ownerCount(env, becky) == 1);
2133  BEAST_EXPECT(ownerCount(env, carol) == 1);
2134  BEAST_EXPECT(ownerCount(env, minter) == 1);
2135  }
2136 
2137  // Set the smallest possible transfer fee.
2138  {
2139  // An nft with a transfer fee of 1 basis point.
2140  uint256 const nftID =
2141  token::getNextID(env, alice, 0u, tfTransferable, 1);
2142  env(token::mint(alice), txflags(tfTransferable), token::xferFee(1));
2143  env.close();
2144 
2145  // Becky buys the nft for XAU(10). Check balances.
2146  uint256 const beckyBuyOfferIndex =
2147  keylet::nftoffer(becky, env.seq(becky)).key;
2148  env(token::createOffer(becky, nftID, gwXAU(10)),
2149  token::owner(alice));
2150  env.close();
2151  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2152  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2153 
2154  env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2155  env.close();
2156  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2157  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2158 
2159  // becky sells nft to carol. alice's balance goes up.
2160  uint256 const beckySellOfferIndex =
2161  keylet::nftoffer(becky, env.seq(becky)).key;
2162  env(token::createOffer(becky, nftID, gwXAU(10)),
2163  txflags(tfSellNFToken));
2164  env.close();
2165  env(token::acceptSellOffer(carol, beckySellOfferIndex));
2166  env.close();
2167 
2168  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2169  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2170  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2171 
2172  // minter buys nft from carol. alice's balance goes up.
2173  uint256 const minterBuyOfferIndex =
2174  keylet::nftoffer(minter, env.seq(minter)).key;
2175  env(token::createOffer(minter, nftID, gwXAU(10)),
2176  token::owner(carol));
2177  env.close();
2178  env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2179  env.close();
2180 
2181  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2182  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2183  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2184  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2185 
2186  // minter sells the nft to alice. Because alice is part of the
2187  // transaction no tranfer fee is removed.
2188  uint256 const minterSellOfferIndex =
2189  keylet::nftoffer(minter, env.seq(minter)).key;
2190  env(token::createOffer(minter, nftID, gwXAU(10)),
2191  txflags(tfSellNFToken));
2192  env.close();
2193  env(token::acceptSellOffer(alice, minterSellOfferIndex));
2194  env.close();
2195  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2196  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2197  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2198  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2199 
2200  // alice pays to becky and carol so subsequent tests are easier
2201  // to think about.
2202  env(pay(alice, becky, gwXAU(0.0001)));
2203  env(pay(alice, carol, gwXAU(0.0001)));
2204  env.close();
2205 
2206  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2207  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2208  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2209  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2210 
2211  // alice burns the nft to make later tests easier to think about.
2212  env(token::burn(alice, nftID));
2213  env.close();
2214  BEAST_EXPECT(ownerCount(env, alice) == 1);
2215  BEAST_EXPECT(ownerCount(env, becky) == 1);
2216  BEAST_EXPECT(ownerCount(env, carol) == 1);
2217  BEAST_EXPECT(ownerCount(env, minter) == 1);
2218  }
2219 
2220  // Set the largest allowed transfer fee.
2221  {
2222  // A transfer fee greater than 50% is not allowed.
2223  env(token::mint(alice),
2224  txflags(tfTransferable),
2225  token::xferFee(maxTransferFee + 1),
2227  env.close();
2228 
2229  // Make an nft with a transfer fee of 50%.
2230  uint256 const nftID = token::getNextID(
2231  env, alice, 0u, tfTransferable, maxTransferFee);
2232  env(token::mint(alice),
2233  txflags(tfTransferable),
2234  token::xferFee(maxTransferFee));
2235  env.close();
2236 
2237  // Becky buys the nft for XAU(10). Check balances.
2238  uint256 const beckyBuyOfferIndex =
2239  keylet::nftoffer(becky, env.seq(becky)).key;
2240  env(token::createOffer(becky, nftID, gwXAU(10)),
2241  token::owner(alice));
2242  env.close();
2243  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2244  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2245 
2246  env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2247  env.close();
2248  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2249  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2250 
2251  // becky sells nft to minter. alice's balance goes up.
2252  uint256 const beckySellOfferIndex =
2253  keylet::nftoffer(becky, env.seq(becky)).key;
2254  env(token::createOffer(becky, nftID, gwXAU(100)),
2255  txflags(tfSellNFToken));
2256  env.close();
2257  env(token::acceptSellOffer(minter, beckySellOfferIndex));
2258  env.close();
2259 
2260  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2261  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2262  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2263 
2264  // carol buys nft from minter. alice's balance goes up.
2265  uint256 const carolBuyOfferIndex =
2266  keylet::nftoffer(carol, env.seq(carol)).key;
2267  env(token::createOffer(carol, nftID, gwXAU(10)),
2268  token::owner(minter));
2269  env.close();
2270  env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2271  env.close();
2272 
2273  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2274  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2275  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2276  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2277 
2278  // carol sells the nft to alice. Because alice is part of the
2279  // transaction no tranfer fee is removed.
2280  uint256 const carolSellOfferIndex =
2281  keylet::nftoffer(carol, env.seq(carol)).key;
2282  env(token::createOffer(carol, nftID, gwXAU(10)),
2283  txflags(tfSellNFToken));
2284  env.close();
2285  env(token::acceptSellOffer(alice, carolSellOfferIndex));
2286  env.close();
2287 
2288  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2289  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2290  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2291  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2292 
2293  // rebalance so subsequent tests are easier to think about.
2294  env(pay(alice, minter, gwXAU(55)));
2295  env(pay(becky, minter, gwXAU(40)));
2296  env.close();
2297  BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2298  BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2299  BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2300  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2301 
2302  // alice burns the nft to make later tests easier to think about.
2303  env(token::burn(alice, nftID));
2304  env.close();
2305  BEAST_EXPECT(ownerCount(env, alice) == 1);
2306  BEAST_EXPECT(ownerCount(env, becky) == 1);
2307  BEAST_EXPECT(ownerCount(env, carol) == 1);
2308  BEAST_EXPECT(ownerCount(env, minter) == 1);
2309  }
2310 
2311  // See the impact of rounding when the nft is sold for small amounts
2312  // of drops.
2313  {
2314  // An nft with a transfer fee of 1 basis point.
2315  uint256 const nftID =
2316  token::getNextID(env, alice, 0u, tfTransferable, 1);
2317  env(token::mint(alice), txflags(tfTransferable), token::xferFee(1));
2318  env.close();
2319 
2320  // minter buys the nft for XRP(1). Since the transfer involves
2321  // alice there should be no transfer fee.
2322  STAmount fee = drops(10);
2323  STAmount aliceBalance = env.balance(alice);
2324  STAmount minterBalance = env.balance(minter);
2325  uint256 const minterBuyOfferIndex =
2326  keylet::nftoffer(minter, env.seq(minter)).key;
2327  env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2328  env.close();
2329  env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2330  env.close();
2331  aliceBalance += XRP(1) - fee;
2332  minterBalance -= XRP(1) + fee;
2333  BEAST_EXPECT(env.balance(alice) == aliceBalance);
2334  BEAST_EXPECT(env.balance(minter) == minterBalance);
2335 
2336  // minter sells to carol. The payment is just small enough that
2337  // alice does not get any transfer fee.
2338  STAmount carolBalance = env.balance(carol);
2339  uint256 const minterSellOfferIndex =
2340  keylet::nftoffer(minter, env.seq(minter)).key;
2341  env(token::createOffer(minter, nftID, drops(99999)),
2342  txflags(tfSellNFToken));
2343  env.close();
2344  env(token::acceptSellOffer(carol, minterSellOfferIndex));
2345  env.close();
2346  minterBalance += drops(99999) - fee;
2347  carolBalance -= drops(99999) + fee;
2348  BEAST_EXPECT(env.balance(alice) == aliceBalance);
2349  BEAST_EXPECT(env.balance(minter) == minterBalance);
2350  BEAST_EXPECT(env.balance(carol) == carolBalance);
2351 
2352  // carol sells to becky. This is the smallest amount to pay for a
2353  // transfer that enables a transfer fee of 1 basis point.
2354  STAmount beckyBalance = env.balance(becky);
2355  uint256 const beckyBuyOfferIndex =
2356  keylet::nftoffer(becky, env.seq(becky)).key;
2357  env(token::createOffer(becky, nftID, drops(100000)),
2358  token::owner(carol));
2359  env.close();
2360  env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2361  env.close();
2362  carolBalance += drops(99999) - fee;
2363  beckyBalance -= drops(100000) + fee;
2364  aliceBalance += drops(1);
2365 
2366  BEAST_EXPECT(env.balance(alice) == aliceBalance);
2367  BEAST_EXPECT(env.balance(minter) == minterBalance);
2368  BEAST_EXPECT(env.balance(carol) == carolBalance);
2369  BEAST_EXPECT(env.balance(becky) == beckyBalance);
2370  }
2371 
2372  // See the impact of rounding when the nft is sold for small amounts
2373  // of an IOU.
2374  {
2375  // An nft with a transfer fee of 1 basis point.
2376  uint256 const nftID =
2377  token::getNextID(env, alice, 0u, tfTransferable, 1);
2378  env(token::mint(alice), txflags(tfTransferable), token::xferFee(1));
2379  env.close();
2380 
2381  // Due to the floating point nature of IOUs we need to
2382  // significantly reduce the gwXAU balances of our accounts prior
2383  // to the iou transfer. Otherwise no transfers will happen.
2384  env(pay(alice, gw, env.balance(alice, gwXAU)));
2385  env(pay(minter, gw, env.balance(minter, gwXAU)));
2386  env(pay(becky, gw, env.balance(becky, gwXAU)));
2387  env.close();
2388 
2389  STAmount const startXAUBalance(
2390  gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset + 5);
2391  env(pay(gw, alice, startXAUBalance));
2392  env(pay(gw, minter, startXAUBalance));
2393  env(pay(gw, becky, startXAUBalance));
2394  env.close();
2395 
2396  // Here is the smallest expressible gwXAU amount.
2397  STAmount tinyXAU(
2398  gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset);
2399 
2400  // minter buys the nft for tinyXAU. Since the transfer involves
2401  // alice there should be no transfer fee.
2402  STAmount aliceBalance = env.balance(alice, gwXAU);
2403  STAmount minterBalance = env.balance(minter, gwXAU);
2404  uint256 const minterBuyOfferIndex =
2405  keylet::nftoffer(minter, env.seq(minter)).key;
2406  env(token::createOffer(minter, nftID, tinyXAU),
2407  token::owner(alice));
2408  env.close();
2409  env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2410  env.close();
2411  aliceBalance += tinyXAU;
2412  minterBalance -= tinyXAU;
2413  BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2414  BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2415 
2416  // minter sells to carol.
2417  STAmount carolBalance = env.balance(carol, gwXAU);
2418  uint256 const minterSellOfferIndex =
2419  keylet::nftoffer(minter, env.seq(minter)).key;
2420  env(token::createOffer(minter, nftID, tinyXAU),
2421  txflags(tfSellNFToken));
2422  env.close();
2423  env(token::acceptSellOffer(carol, minterSellOfferIndex));
2424  env.close();
2425 
2426  minterBalance += tinyXAU;
2427  carolBalance -= tinyXAU;
2428  // tiny XAU is so small that alice does not get a transfer fee.
2429  BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2430  BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2431  BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2432 
2433  // carol sells to becky. This is the smallest gwXAU amount
2434  // to pay for a transfer that enables a transfer fee of 1.
2435  STAmount const cheapNFT(
2436  gwXAU.issue(), STAmount::cMinValue, STAmount::cMinOffset + 5);
2437 
2438  STAmount beckyBalance = env.balance(becky, gwXAU);
2439  uint256 const beckyBuyOfferIndex =
2440  keylet::nftoffer(becky, env.seq(becky)).key;
2441  env(token::createOffer(becky, nftID, cheapNFT),
2442  token::owner(carol));
2443  env.close();
2444  env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2445  env.close();
2446 
2447  aliceBalance += tinyXAU;
2448  beckyBalance -= cheapNFT;
2449  carolBalance += cheapNFT - tinyXAU;
2450  BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2451  BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2452  BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2453  BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2454  }
2455  }
2456 
2457  void
2459  {
2460  // Exercise the NFT taxon field.
2461  testcase("Mint taxon");
2462 
2463  using namespace test::jtx;
2464 
2465  Env env{*this, features};
2466 
2467  Account const alice{"alice"};
2468  Account const becky{"becky"};
2469 
2470  env.fund(XRP(1000), alice, becky);
2471  env.close();
2472 
2473  // The taxon field is incorporated straight into the NFT ID. So
2474  // tests only need to operate on NFT IDs; we don't need to generate
2475  // any transactions.
2476 
2477  // The taxon value should be recoverable from the NFT ID.
2478  {
2479  uint256 const nftID = token::getNextID(env, alice, 0u);
2480  BEAST_EXPECT(nft::getTaxon(nftID) == nft::toTaxon(0));
2481  }
2482 
2483  // Make sure the full range of taxon values work. We just tried
2484  // the minimum. Now try the largest.
2485  {
2486  uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2487  BEAST_EXPECT(nft::getTaxon(nftID) == nft::toTaxon((0xFFFFFFFF)));
2488  }
2489 
2490  // Do some touch testing to show that the taxon is recoverable no
2491  // matter what else changes around it in the nft ID.
2492  {
2493  std::uint32_t const taxon = rand_int<std::uint32_t>();
2494  for (int i = 0; i < 10; ++i)
2495  {
2496  // lambda to produce a useful message on error.
2497  auto check = [this](std::uint32_t taxon, uint256 const& nftID) {
2498  nft::Taxon const gotTaxon = nft::getTaxon(nftID);
2499  if (nft::toTaxon(taxon) == gotTaxon)
2500  pass();
2501  else
2502  {
2503  std::stringstream ss;
2504  ss << "Taxon recovery failed from nftID "
2505  << to_string(nftID) << ". Expected: " << taxon
2506  << "; got: " << gotTaxon;
2507  fail(ss.str());
2508  }
2509  };
2510 
2511  uint256 const nftAliceID = token::getID(
2512  alice,
2513  taxon,
2514  rand_int<std::uint32_t>(),
2515  rand_int<std::uint16_t>(),
2516  rand_int<std::uint16_t>());
2517  check(taxon, nftAliceID);
2518 
2519  uint256 const nftBeckyID = token::getID(
2520  becky,
2521  taxon,
2522  rand_int<std::uint32_t>(),
2523  rand_int<std::uint16_t>(),
2524  rand_int<std::uint16_t>());
2525  check(taxon, nftBeckyID);
2526  }
2527  }
2528  }
2529 
2530  void
2532  {
2533  // Exercise the NFT URI field.
2534  // 1. Create a number of NFTs with and without URIs.
2535  // 2. Retrieve the NFTs from the server.
2536  // 3. Make sure the right URI is attached to each NFT.
2537  testcase("Mint URI");
2538 
2539  using namespace test::jtx;
2540 
2541  Env env{*this, features};
2542 
2543  Account const alice{"alice"};
2544  Account const becky{"becky"};
2545 
2546  env.fund(XRP(10000), alice, becky);
2547  env.close();
2548 
2549  // lambda that returns a randomly generated string which fits
2550  // the constraints of a URI. Empty strings may be returned.
2551  // In the empty string case do not add the URI to the nft.
2552  auto randURI = []() {
2553  std::string ret;
2554 
2555  // About 20% of the returned strings should be empty
2556  if (rand_int(4) == 0)
2557  return ret;
2558 
2559  std::size_t const strLen = rand_int(256);
2560  ret.reserve(strLen);
2561  for (std::size_t i = 0; i < strLen; ++i)
2562  ret.push_back(rand_byte());
2563 
2564  return ret;
2565  };
2566 
2567  // Make a list of URIs that we'll put in nfts.
2568  struct Entry
2569  {
2570  std::string uri;
2571  std::uint32_t taxon;
2572 
2573  Entry(std::string uri_, std::uint32_t taxon_)
2574  : uri(std::move(uri_)), taxon(taxon_)
2575  {
2576  }
2577  };
2578 
2579  std::vector<Entry> entries;
2580  entries.reserve(100);
2581  for (std::size_t i = 0; i < 100; ++i)
2582  entries.emplace_back(randURI(), rand_int<std::uint32_t>());
2583 
2584  // alice creates nfts using entries.
2585  for (Entry const& entry : entries)
2586  {
2587  if (entry.uri.empty())
2588  {
2589  env(token::mint(alice, entry.taxon));
2590  }
2591  else
2592  {
2593  env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2594  }
2595  env.close();
2596  }
2597 
2598  // Recover alice's nfts from the ledger.
2599  Json::Value aliceNFTs = [&env, &alice]() {
2600  Json::Value params;
2601  params[jss::account] = alice.human();
2602  params[jss::type] = "state";
2603  return env.rpc("json", "account_nfts", to_string(params));
2604  }();
2605 
2606  // Verify that the returned NFTs match what we sent.
2607  Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2608  if (!BEAST_EXPECT(nfts.size() == entries.size()))
2609  return;
2610 
2611  // Sort the returned NFTs by nft_serial so the are in the same order
2612  // as entries.
2613  std::vector<Json::Value> sortedNFTs;
2614  sortedNFTs.reserve(nfts.size());
2615  for (std::size_t i = 0; i < nfts.size(); ++i)
2616  sortedNFTs.push_back(nfts[i]);
2617  std::sort(
2618  sortedNFTs.begin(),
2619  sortedNFTs.end(),
2620  [](Json::Value const& lhs, Json::Value const& rhs) {
2621  return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2622  });
2623 
2624  for (std::size_t i = 0; i < entries.size(); ++i)
2625  {
2626  Entry const& entry = entries[i];
2627  Json::Value const& ret = sortedNFTs[i];
2628  BEAST_EXPECT(entry.taxon == ret[sfNFTokenTaxon.jsonName]);
2629  if (entry.uri.empty())
2630  {
2631  BEAST_EXPECT(!ret.isMember(sfURI.jsonName));
2632  }
2633  else
2634  {
2635  BEAST_EXPECT(strHex(entry.uri) == ret[sfURI.jsonName]);
2636  }
2637  }
2638  }
2639 
2640  void
2642  {
2643  // Explore the CreateOffer Destination field.
2644  testcase("Create offer destination");
2645 
2646  using namespace test::jtx;
2647 
2648  Env env{*this, features};
2649 
2650  Account const issuer{"issuer"};
2651  Account const minter{"minter"};
2652  Account const buyer{"buyer"};
2653  Account const broker{"broker"};
2654 
2655  env.fund(XRP(1000), issuer, minter, buyer, broker);
2656 
2657  // We want to explore how issuers vs minters fits into the permission
2658  // scheme. So issuer issues and minter mints.
2659  env(token::setMinter(issuer, minter));
2660  env.close();
2661 
2662  uint256 const nftokenID =
2663  token::getNextID(env, issuer, 0, tfTransferable);
2664  env(token::mint(minter, 0),
2665  token::issuer(issuer),
2666  txflags(tfTransferable));
2667  env.close();
2668 
2669  // Test how adding a Destination field to an offer affects permissions
2670  // for cancelling offers.
2671  {
2672  uint256 const offerMinterToIssuer =
2673  keylet::nftoffer(minter, env.seq(minter)).key;
2674  env(token::createOffer(minter, nftokenID, drops(1)),
2675  token::destination(issuer),
2676  txflags(tfSellNFToken));
2677 
2678  uint256 const offerMinterToBuyer =
2679  keylet::nftoffer(minter, env.seq(minter)).key;
2680  env(token::createOffer(minter, nftokenID, drops(1)),
2681  token::destination(buyer),
2682  txflags(tfSellNFToken));
2683 
2684  // buy offers cannot contain a Destination, so this attempt fails.
2685  env(token::createOffer(issuer, nftokenID, drops(1)),
2686  token::owner(minter),
2687  token::destination(minter),
2688  ter(temMALFORMED));
2689 
2690  env.close();
2691  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2692  BEAST_EXPECT(ownerCount(env, minter) == 3);
2693  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2694 
2695  // Test who gets to cancel the offers. Anyone outside of the
2696  // offer-owner/destination pair should not be able to cancel the
2697  // offers.
2698  //
2699  // Note that issuer does not have any special permissions regarding
2700  // offer cancellation. issuer cannot cancel an offer for an
2701  // NFToken they issued.
2702  env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2703  ter(tecNO_PERMISSION));
2704  env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2705  ter(tecNO_PERMISSION));
2706  env.close();
2707  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2708  BEAST_EXPECT(ownerCount(env, minter) == 3);
2709  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2710 
2711  // Both the offer creator and and destination should be able to
2712  // cancel the offers.
2713  env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2714  env(token::cancelOffer(minter, {offerMinterToIssuer}));
2715  env.close();
2716  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2717  BEAST_EXPECT(ownerCount(env, minter) == 1);
2718  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2719  }
2720 
2721  // Test how adding a Destination field to a sell offer affects
2722  // accepting that offer.
2723  {
2724  uint256 const offerMinterToBuyer =
2725  keylet::nftoffer(minter, env.seq(minter)).key;
2726  env(token::createOffer(minter, nftokenID, drops(1)),
2727  token::destination(buyer),
2728  txflags(tfSellNFToken));
2729  env.close();
2730  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2731  BEAST_EXPECT(ownerCount(env, minter) == 2);
2732  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2733 
2734  // issuer cannot accept a sell offer where they are not the
2735  // destination.
2736  env(token::acceptSellOffer(issuer, offerMinterToBuyer),
2737  ter(tecNO_PERMISSION));
2738  env.close();
2739  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2740  BEAST_EXPECT(ownerCount(env, minter) == 2);
2741  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2742 
2743  // However buyer can accept the sell offer.
2744  env(token::acceptSellOffer(buyer, offerMinterToBuyer));
2745  env.close();
2746  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2747  BEAST_EXPECT(ownerCount(env, minter) == 0);
2748  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2749  }
2750 
2751  // You can't add a Destination field to a buy offer.
2752  {
2753  env(token::createOffer(minter, nftokenID, drops(1)),
2754  token::owner(buyer),
2755  token::destination(buyer),
2756  ter(temMALFORMED));
2757  env.close();
2758  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2759  BEAST_EXPECT(ownerCount(env, minter) == 0);
2760  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2761 
2762  // However without the Destination the buy offer works fine.
2763  uint256 const offerMinterToBuyer =
2764  keylet::nftoffer(minter, env.seq(minter)).key;
2765  env(token::createOffer(minter, nftokenID, drops(1)),
2766  token::owner(buyer));
2767  env.close();
2768  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2769  BEAST_EXPECT(ownerCount(env, minter) == 1);
2770  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2771 
2772  // Buyer accepts minter's offer.
2773  env(token::acceptBuyOffer(buyer, offerMinterToBuyer));
2774  env.close();
2775  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2776  BEAST_EXPECT(ownerCount(env, minter) == 1);
2777  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2778  }
2779 
2780  // Show that a sell offer's Destination can broker that sell offer
2781  // to another account.
2782  {
2783  uint256 const offerMinterToBroker =
2784  keylet::nftoffer(minter, env.seq(minter)).key;
2785  env(token::createOffer(minter, nftokenID, drops(1)),
2786  token::destination(broker),
2787  txflags(tfSellNFToken));
2788 
2789  uint256 const offerBuyerToMinter =
2790  keylet::nftoffer(buyer, env.seq(buyer)).key;
2791  env(token::createOffer(buyer, nftokenID, drops(1)),
2792  token::owner(minter));
2793 
2794  env.close();
2795  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2796  BEAST_EXPECT(ownerCount(env, minter) == 2);
2797  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2798 
2799  // issuer cannot broker the offers, because they are not the
2800  // Destination.
2801  env(token::brokerOffers(
2802  issuer, offerBuyerToMinter, offerMinterToBroker),
2804  env.close();
2805  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2806  BEAST_EXPECT(ownerCount(env, minter) == 2);
2807  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2808 
2809  // Since broker is the sell offer's destination, they can broker
2810  // the two offers.
2811  env(token::brokerOffers(
2812  broker, offerBuyerToMinter, offerMinterToBroker));
2813  env.close();
2814  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2815  BEAST_EXPECT(ownerCount(env, minter) == 0);
2816  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2817  }
2818 
2819  // Show that brokered mode cannot complete a transfer where the
2820  // Destination doesn't match, but can complete if the Destination
2821  // does match.
2822  {
2823  uint256 const offerBuyerToMinter =
2824  keylet::nftoffer(buyer, env.seq(buyer)).key;
2825  env(token::createOffer(buyer, nftokenID, drops(1)),
2826  token::destination(minter),
2827  txflags(tfSellNFToken));
2828 
2829  uint256 const offerMinterToBuyer =
2830  keylet::nftoffer(minter, env.seq(minter)).key;
2831  env(token::createOffer(minter, nftokenID, drops(1)),
2832  token::owner(buyer));
2833 
2834  uint256 const offerIssuerToBuyer =
2835  keylet::nftoffer(issuer, env.seq(issuer)).key;
2836  env(token::createOffer(issuer, nftokenID, drops(1)),
2837  token::owner(buyer));
2838 
2839  env.close();
2840  BEAST_EXPECT(ownerCount(env, issuer) == 1);
2841  BEAST_EXPECT(ownerCount(env, minter) == 1);
2842  BEAST_EXPECT(ownerCount(env, buyer) == 2);
2843 
2844  // Cannot broker offers when the sell destination is not the buyer.
2845  env(token::brokerOffers(
2846  broker, offerIssuerToBuyer, offerBuyerToMinter),
2848  env.close();
2849  BEAST_EXPECT(ownerCount(env, issuer) == 1);
2850  BEAST_EXPECT(ownerCount(env, minter) == 1);
2851  BEAST_EXPECT(ownerCount(env, buyer) == 2);
2852 
2853  // Broker is successful when destination is buyer.
2854  env(token::brokerOffers(
2855  broker, offerMinterToBuyer, offerBuyerToMinter));
2856  env.close();
2857  BEAST_EXPECT(ownerCount(env, issuer) == 1);
2858  BEAST_EXPECT(ownerCount(env, minter) == 1);
2859  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2860  }
2861  }
2862 
2863  void
2865  {
2866  // Explore the CreateOffer Expiration field.
2867  testcase("Create offer expiration");
2868 
2869  using namespace test::jtx;
2870 
2871  Env env{*this, features};
2872 
2873  Account const issuer{"issuer"};
2874  Account const minter{"minter"};
2875  Account const buyer{"buyer"};
2876 
2877  env.fund(XRP(1000), issuer, minter, buyer);
2878 
2879  // We want to explore how issuers vs minters fits into the permission
2880  // scheme. So issuer issues and minter mints.
2881  env(token::setMinter(issuer, minter));
2882  env.close();
2883 
2884  uint256 const nftokenID0 =
2885  token::getNextID(env, issuer, 0, tfTransferable);
2886  env(token::mint(minter, 0),
2887  token::issuer(issuer),
2888  txflags(tfTransferable));
2889  env.close();
2890 
2891  uint256 const nftokenID1 =
2892  token::getNextID(env, issuer, 0, tfTransferable);
2893  env(token::mint(minter, 0),
2894  token::issuer(issuer),
2895  txflags(tfTransferable));
2896  env.close();
2897 
2898  // Test how adding an Expiration field to an offer affects permissions
2899  // for cancelling offers.
2900  {
2901  std::uint32_t const expiration = lastClose(env) + 25;
2902 
2903  uint256 const offerMinterToIssuer =
2904  keylet::nftoffer(minter, env.seq(minter)).key;
2905  env(token::createOffer(minter, nftokenID0, drops(1)),
2906  token::destination(issuer),
2907  token::expiration(expiration),
2908  txflags(tfSellNFToken));
2909 
2910  uint256 const offerMinterToAnyone =
2911  keylet::nftoffer(minter, env.seq(minter)).key;
2912  env(token::createOffer(minter, nftokenID0, drops(1)),
2913  token::expiration(expiration),
2914  txflags(tfSellNFToken));
2915 
2916  uint256 const offerIssuerToMinter =
2917  keylet::nftoffer(issuer, env.seq(issuer)).key;
2918  env(token::createOffer(issuer, nftokenID0, drops(1)),
2919  token::owner(minter),
2920  token::expiration(expiration));
2921 
2922  uint256 const offerBuyerToMinter =
2923  keylet::nftoffer(buyer, env.seq(buyer)).key;
2924  env(token::createOffer(buyer, nftokenID0, drops(1)),
2925  token::owner(minter),
2926  token::expiration(expiration));
2927  env.close();
2928  BEAST_EXPECT(ownerCount(env, issuer) == 1);
2929  BEAST_EXPECT(ownerCount(env, minter) == 3);
2930  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2931 
2932  // Test who gets to cancel the offers. Anyone outside of the
2933  // offer-owner/destination pair should not be able to cancel
2934  // unexpired offers.
2935  //
2936  // Note that these are tec responses, so these transactions will
2937  // not be retried by the ledger.
2938  env(token::cancelOffer(issuer, {offerMinterToAnyone}),
2939  ter(tecNO_PERMISSION));
2940  env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2941  ter(tecNO_PERMISSION));
2942  env.close();
2943  BEAST_EXPECT(lastClose(env) < expiration);
2944  BEAST_EXPECT(ownerCount(env, issuer) == 1);
2945  BEAST_EXPECT(ownerCount(env, minter) == 3);
2946  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2947 
2948  // The offer creator can cancel their own unexpired offer.
2949  env(token::cancelOffer(minter, {offerMinterToAnyone}));
2950 
2951  // The destination of a sell offer can cancel the NFT owner's
2952  // unexpired offer.
2953  env(token::cancelOffer(issuer, {offerMinterToIssuer}));
2954 
2955  // Close enough ledgers to get past the expiration.
2956  while (lastClose(env) < expiration)
2957  env.close();
2958 
2959  BEAST_EXPECT(ownerCount(env, issuer) == 1);
2960  BEAST_EXPECT(ownerCount(env, minter) == 1);
2961  BEAST_EXPECT(ownerCount(env, buyer) == 1);
2962 
2963  // Anyone can cancel expired offers.
2964  env(token::cancelOffer(issuer, {offerBuyerToMinter}));
2965  env(token::cancelOffer(buyer, {offerIssuerToMinter}));
2966  env.close();
2967  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2968  BEAST_EXPECT(ownerCount(env, minter) == 1);
2969  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2970  }
2971  // Show that:
2972  // 1. An unexpired sell offer with an expiration can be accepted.
2973  // 2. An expired sell offer cannot be accepted and remains
2974  // in ledger after the accept fails.
2975  {
2976  std::uint32_t const expiration = lastClose(env) + 25;
2977 
2978  uint256 const offer0 =
2979  keylet::nftoffer(minter, env.seq(minter)).key;
2980  env(token::createOffer(minter, nftokenID0, drops(1)),
2981  token::expiration(expiration),
2982  txflags(tfSellNFToken));
2983 
2984  uint256 const offer1 =
2985  keylet::nftoffer(minter, env.seq(minter)).key;
2986  env(token::createOffer(minter, nftokenID1, drops(1)),
2987  token::expiration(expiration),
2988  txflags(tfSellNFToken));
2989  env.close();
2990  BEAST_EXPECT(lastClose(env) < expiration);
2991  BEAST_EXPECT(ownerCount(env, issuer) == 0);
2992  BEAST_EXPECT(ownerCount(env, minter) == 3);
2993  BEAST_EXPECT(ownerCount(env, buyer) == 0);
2994 
2995  // Anyone can accept an unexpired sell offer.
2996  env(token::acceptSellOffer(buyer, offer0));
2997 
2998  // Close enough ledgers to get past the expiration.
2999  while (lastClose(env) < expiration)
3000  env.close();
3001 
3002  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3003  BEAST_EXPECT(ownerCount(env, minter) == 2);
3004  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3005 
3006  // No one can accept an expired sell offer.
3007  env(token::acceptSellOffer(buyer, offer1), ter(tecEXPIRED));
3008  env(token::acceptSellOffer(issuer, offer1), ter(tecEXPIRED));
3009  env.close();
3010 
3011  // The expired sell offer is still in the ledger.
3012  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3013  BEAST_EXPECT(ownerCount(env, minter) == 2);
3014  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3015 
3016  // Anyone can cancel the expired sell offer.
3017  env(token::cancelOffer(issuer, {offer1}));
3018  env.close();
3019  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3020  BEAST_EXPECT(ownerCount(env, minter) == 1);
3021  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3022 
3023  // Transfer nftokenID0 back to minter so we start the next test in
3024  // a simple place.
3025  uint256 const offerSellBack =
3026  keylet::nftoffer(buyer, env.seq(buyer)).key;
3027  env(token::createOffer(buyer, nftokenID0, XRP(0)),
3028  txflags(tfSellNFToken),
3029  token::destination(minter));
3030  env.close();
3031  env(token::acceptSellOffer(minter, offerSellBack));
3032  env.close();
3033  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3034  BEAST_EXPECT(ownerCount(env, minter) == 1);
3035  BEAST_EXPECT(ownerCount(env, buyer) == 0);
3036  }
3037  // Show that:
3038  // 1. An unexpired buy offer with an expiration can be accepted.
3039  // 2. An expired buy offer cannot be accepted and remains
3040  // in ledger after the accept fails.
3041  {
3042  std::uint32_t const expiration = lastClose(env) + 25;
3043 
3044  uint256 const offer0 = keylet::nftoffer(buyer, env.seq(buyer)).key;
3045  env(token::createOffer(buyer, nftokenID0, drops(1)),
3046  token::owner(minter),
3047  token::expiration(expiration));
3048 
3049  uint256 const offer1 = keylet::nftoffer(buyer, env.seq(buyer)).key;
3050  env(token::createOffer(buyer, nftokenID1, drops(1)),
3051  token::owner(minter),
3052  token::expiration(expiration));
3053  env.close();
3054  BEAST_EXPECT(lastClose(env) < expiration);
3055  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3056  BEAST_EXPECT(ownerCount(env, minter) == 1);
3057  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3058 
3059  // An unexpired buy offer can be accepted.
3060  env(token::acceptBuyOffer(minter, offer0));
3061 
3062  // Close enough ledgers to get past the expiration.
3063  while (lastClose(env) < expiration)
3064  env.close();
3065 
3066  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3067  BEAST_EXPECT(ownerCount(env, minter) == 1);
3068  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3069 
3070  // An expired buy offer cannot be accepted.
3071  env(token::acceptBuyOffer(minter, offer1), ter(tecEXPIRED));
3072  env(token::acceptBuyOffer(issuer, offer1), ter(tecEXPIRED));
3073  env.close();
3074 
3075  // The expired buy offer is still in the ledger.
3076  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3077  BEAST_EXPECT(ownerCount(env, minter) == 1);
3078  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3079 
3080  // Anyone can cancel the expired buy offer.
3081  env(token::cancelOffer(issuer, {offer1}));
3082  env.close();
3083  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3084  BEAST_EXPECT(ownerCount(env, minter) == 1);
3085  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3086 
3087  // Transfer nftokenID0 back to minter so we start the next test in
3088  // a simple place.
3089  uint256 const offerSellBack =
3090  keylet::nftoffer(buyer, env.seq(buyer)).key;
3091  env(token::createOffer(buyer, nftokenID0, XRP(0)),
3092  txflags(tfSellNFToken),
3093  token::destination(minter));
3094  env.close();
3095  env(token::acceptSellOffer(minter, offerSellBack));
3096  env.close();
3097  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3098  BEAST_EXPECT(ownerCount(env, minter) == 1);
3099  BEAST_EXPECT(ownerCount(env, buyer) == 0);
3100  }
3101  // Show that in brokered mode:
3102  // 1. An unexpired sell offer with an expiration can be accepted.
3103  // 2. An expired sell offer cannot be accepted and remains
3104  // in ledger after the accept fails.
3105  {
3106  std::uint32_t const expiration = lastClose(env) + 25;
3107 
3108  uint256 const sellOffer0 =
3109  keylet::nftoffer(minter, env.seq(minter)).key;
3110  env(token::createOffer(minter, nftokenID0, drops(1)),
3111  token::expiration(expiration),
3112  txflags(tfSellNFToken));
3113 
3114  uint256 const sellOffer1 =
3115  keylet::nftoffer(minter, env.seq(minter)).key;
3116  env(token::createOffer(minter, nftokenID1, drops(1)),
3117  token::expiration(expiration),
3118  txflags(tfSellNFToken));
3119 
3120  uint256 const buyOffer0 =
3121  keylet::nftoffer(buyer, env.seq(buyer)).key;
3122  env(token::createOffer(buyer, nftokenID0, drops(1)),
3123  token::owner(minter));
3124 
3125  uint256 const buyOffer1 =
3126  keylet::nftoffer(buyer, env.seq(buyer)).key;
3127  env(token::createOffer(buyer, nftokenID1, drops(1)),
3128  token::owner(minter));
3129 
3130  env.close();
3131  BEAST_EXPECT(lastClose(env) < expiration);
3132  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3133  BEAST_EXPECT(ownerCount(env, minter) == 3);
3134  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3135 
3136  // An unexpired offer can be brokered.
3137  env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3138 
3139  // Close enough ledgers to get past the expiration.
3140  while (lastClose(env) < expiration)
3141  env.close();
3142 
3143  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3144  BEAST_EXPECT(ownerCount(env, minter) == 2);
3145  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3146 
3147  // If the sell offer is expired it cannot be brokered.
3148  env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3149  ter(tecEXPIRED));
3150  env.close();
3151 
3152  // The expired sell offer is still in the ledger.
3153  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3154  BEAST_EXPECT(ownerCount(env, minter) == 2);
3155  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3156 
3157  // Anyone can cancel the expired sell offer.
3158  env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3159  env.close();
3160  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3161  BEAST_EXPECT(ownerCount(env, minter) == 1);
3162  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3163 
3164  // Transfer nftokenID0 back to minter so we start the next test in
3165  // a simple place.
3166  uint256 const offerSellBack =
3167  keylet::nftoffer(buyer, env.seq(buyer)).key;
3168  env(token::createOffer(buyer, nftokenID0, XRP(0)),
3169  txflags(tfSellNFToken),
3170  token::destination(minter));
3171  env.close();
3172  env(token::acceptSellOffer(minter, offerSellBack));
3173  env.close();
3174  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3175  BEAST_EXPECT(ownerCount(env, minter) == 1);
3176  BEAST_EXPECT(ownerCount(env, buyer) == 0);
3177  }
3178  // Show that in brokered mode:
3179  // 1. An unexpired buy offer with an expiration can be accepted.
3180  // 2. An expired buy offer cannot be accepted and remains
3181  // in ledger after the accept fails.
3182  {
3183  std::uint32_t const expiration = lastClose(env) + 25;
3184 
3185  uint256 const sellOffer0 =
3186  keylet::nftoffer(minter, env.seq(minter)).key;
3187  env(token::createOffer(minter, nftokenID0, drops(1)),
3188  txflags(tfSellNFToken));
3189 
3190  uint256 const sellOffer1 =
3191  keylet::nftoffer(minter, env.seq(minter)).key;
3192  env(token::createOffer(minter, nftokenID1, drops(1)),
3193  txflags(tfSellNFToken));
3194 
3195  uint256 const buyOffer0 =
3196  keylet::nftoffer(buyer, env.seq(buyer)).key;
3197  env(token::createOffer(buyer, nftokenID0, drops(1)),
3198  token::expiration(expiration),
3199  token::owner(minter));
3200 
3201  uint256 const buyOffer1 =
3202  keylet::nftoffer(buyer, env.seq(buyer)).key;
3203  env(token::createOffer(buyer, nftokenID1, drops(1)),
3204  token::expiration(expiration),
3205  token::owner(minter));
3206 
3207  env.close();
3208  BEAST_EXPECT(lastClose(env) < expiration);
3209  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3210  BEAST_EXPECT(ownerCount(env, minter) == 3);
3211  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3212 
3213  // An unexpired offer can be brokered.
3214  env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3215 
3216  // Close enough ledgers to get past the expiration.
3217  while (lastClose(env) < expiration)
3218  env.close();
3219 
3220  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3221  BEAST_EXPECT(ownerCount(env, minter) == 2);
3222  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3223 
3224  // If the buy offer is expired it cannot be brokered.
3225  env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3226  ter(tecEXPIRED));
3227  env.close();
3228 
3229  // The expired buy offer is still in the ledger.
3230  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3231  BEAST_EXPECT(ownerCount(env, minter) == 2);
3232  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3233 
3234  // Anyone can cancel the expired buy offer.
3235  env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3236  env.close();
3237  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3238  BEAST_EXPECT(ownerCount(env, minter) == 1);
3239  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3240 
3241  // Transfer nftokenID0 back to minter so we start the next test in
3242  // a simple place.
3243  uint256 const offerSellBack =
3244  keylet::nftoffer(buyer, env.seq(buyer)).key;
3245  env(token::createOffer(buyer, nftokenID0, XRP(0)),
3246  txflags(tfSellNFToken),
3247  token::destination(minter));
3248  env.close();
3249  env(token::acceptSellOffer(minter, offerSellBack));
3250  env.close();
3251  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3252  BEAST_EXPECT(ownerCount(env, minter) == 1);
3253  BEAST_EXPECT(ownerCount(env, buyer) == 0);
3254  }
3255  // Show that in brokered mode:
3256  // 1. An unexpired buy/sell offer pair with an expiration can be
3257  // accepted.
3258  // 2. An expired buy/sell offer pair cannot be accepted and they
3259  // remain in ledger after the accept fails.
3260  {
3261  std::uint32_t const expiration = lastClose(env) + 25;
3262 
3263  uint256 const sellOffer0 =
3264  keylet::nftoffer(minter, env.seq(minter)).key;
3265  env(token::createOffer(minter, nftokenID0, drops(1)),
3266  token::expiration(expiration),
3267  txflags(tfSellNFToken));
3268 
3269  uint256 const sellOffer1 =
3270  keylet::nftoffer(minter, env.seq(minter)).key;
3271  env(token::createOffer(minter, nftokenID1, drops(1)),
3272  token::expiration(expiration),
3273  txflags(tfSellNFToken));
3274 
3275  uint256 const buyOffer0 =
3276  keylet::nftoffer(buyer, env.seq(buyer)).key;
3277  env(token::createOffer(buyer, nftokenID0, drops(1)),
3278  token::expiration(expiration),
3279  token::owner(minter));
3280 
3281  uint256 const buyOffer1 =
3282  keylet::nftoffer(buyer, env.seq(buyer)).key;
3283  env(token::createOffer(buyer, nftokenID1, drops(1)),
3284  token::expiration(expiration),
3285  token::owner(minter));
3286 
3287  env.close();
3288  BEAST_EXPECT(lastClose(env) < expiration);
3289  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3290  BEAST_EXPECT(ownerCount(env, minter) == 3);
3291  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3292 
3293  // Unexpired offers can be brokered.
3294  env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3295 
3296  // Close enough ledgers to get past the expiration.
3297  while (lastClose(env) < expiration)
3298  env.close();
3299 
3300  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3301  BEAST_EXPECT(ownerCount(env, minter) == 2);
3302  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3303 
3304  // If the offers are expired they cannot be brokered.
3305  env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3306  ter(tecEXPIRED));
3307  env.close();
3308 
3309  // The expired offers are still in the ledger.
3310  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3311  BEAST_EXPECT(ownerCount(env, minter) == 2);
3312  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3313 
3314  // Anyone can cancel the expired offers.
3315  env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3316  env.close();
3317  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3318  BEAST_EXPECT(ownerCount(env, minter) == 1);
3319  BEAST_EXPECT(ownerCount(env, buyer) == 1);
3320 
3321  // Transfer nftokenID0 back to minter so we start the next test in
3322  // a simple place.
3323  uint256 const offerSellBack =
3324  keylet::nftoffer(buyer, env.seq(buyer)).key;
3325  env(token::createOffer(buyer, nftokenID0, XRP(0)),
3326  txflags(tfSellNFToken),
3327  token::destination(minter));
3328  env.close();
3329  env(token::acceptSellOffer(minter, offerSellBack));
3330  env.close();
3331  BEAST_EXPECT(ownerCount(env, issuer) == 0);
3332  BEAST_EXPECT(ownerCount(env, minter) == 1);
3333  BEAST_EXPECT(ownerCount(env, buyer) == 0);
3334  }
3335  }
3336 
3337  void
3339  {
3340  // Look at offer canceling.
3341  testcase("Cancel offers");
3342 
3343  using namespace test::jtx;
3344 
3345  Env env{*this, features};
3346 
3347  Account const alice("alice");
3348  Account const becky("becky");
3349  Account const minter("minter");
3350  env.fund(XRP(50000), alice, becky, minter);
3351  env.close();
3352 
3353  // alice has a minter to see if minters have offer canceling permission.
3354  env(token::setMinter(alice, minter));
3355  env.close();
3356 
3357  uint256 const nftokenID =
3358  token::getNextID(env, alice, 0, tfTransferable);
3359  env(token::mint(alice, 0), txflags(tfTransferable));
3360  env.close();
3361 
3362  // Anyone can cancel an expired offer.
3363  uint256 const expiredOfferIndex =
3364  keylet::nftoffer(alice, env.seq(alice)).key;
3365 
3366  env(token::createOffer(alice, nftokenID, XRP(1000)),
3367  txflags(tfSellNFToken),
3368  token::expiration(lastClose(env) + 13));
3369  env.close();
3370 
3371  // The offer has not expired yet, so becky can't cancel it now.
3372  BEAST_EXPECT(ownerCount(env, alice) == 2);
3373  env(token::cancelOffer(becky, {expiredOfferIndex}),
3374  ter(tecNO_PERMISSION));
3375  env.close();
3376 
3377  // Close a couple of ledgers and advance the time. Then becky
3378  // should be able to cancel the (now) expired offer.
3379  env.close();
3380  env.close();
3381  env(token::cancelOffer(becky, {expiredOfferIndex}));
3382  env.close();
3383  BEAST_EXPECT(ownerCount(env, alice) == 1);
3384 
3385  // Create a couple of offers with a destination. Those offers
3386  // should be cancellable by the creator and the destination.
3387  uint256 const dest1OfferIndex =
3388  keylet::nftoffer(alice, env.seq(alice)).key;
3389 
3390  env(token::createOffer(alice, nftokenID, XRP(1000)),
3391  token::destination(becky),
3392  txflags(tfSellNFToken));
3393  env.close();
3394  BEAST_EXPECT(ownerCount(env, alice) == 2);
3395 
3396  // Minter can't cancel that offer, but becky (the destination) can.
3397  env(token::cancelOffer(minter, {dest1OfferIndex}),
3398  ter(tecNO_PERMISSION));
3399  env.close();
3400  BEAST_EXPECT(ownerCount(env, alice) == 2);
3401 
3402  env(token::cancelOffer(becky, {dest1OfferIndex}));
3403  env.close();
3404  BEAST_EXPECT(ownerCount(env, alice) == 1);
3405 
3406  // alice can cancel her own offer, even if becky is the destination.
3407  uint256 const dest2OfferIndex =
3408  keylet::nftoffer(alice, env.seq(alice)).key;
3409 
3410  env(token::createOffer(alice, nftokenID, XRP(1000)),
3411  token::destination(becky),
3412  txflags(tfSellNFToken));
3413  env.close();
3414  BEAST_EXPECT(ownerCount(env, alice) == 2);
3415 
3416  env(token::cancelOffer(alice, {dest2OfferIndex}));
3417  env.close();
3418  BEAST_EXPECT(ownerCount(env, alice) == 1);
3419 
3420  // The issuer has no special permissions regarding offer cancellation.
3421  // Minter creates a token with alice as issuer. alice cannot cancel
3422  // minter's offer.
3423  uint256 const mintersNFTokenID =
3424  token::getNextID(env, alice, 0, tfTransferable);
3425  env(token::mint(minter, 0),
3426  token::issuer(alice),
3427  txflags(tfTransferable));
3428  env.close();
3429 
3430  uint256 const minterOfferIndex =
3431  keylet::nftoffer(minter, env.seq(minter)).key;
3432 
3433  env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3434  txflags(tfSellNFToken));
3435  env.close();
3436  BEAST_EXPECT(ownerCount(env, minter) == 2);
3437 
3438  // Nobody other than minter should be able to cancel minter's offer.
3439  env(token::cancelOffer(alice, {minterOfferIndex}),
3440  ter(tecNO_PERMISSION));
3441  env(token::cancelOffer(becky, {minterOfferIndex}),
3442  ter(tecNO_PERMISSION));
3443  env.close();
3444  BEAST_EXPECT(ownerCount(env, minter) == 2);
3445 
3446  env(token::cancelOffer(minter, {minterOfferIndex}));
3447  env.close();
3448  BEAST_EXPECT(ownerCount(env, minter) == 1);
3449  }
3450 
3451  void
3453  {
3454  // Look at the case where too many offers are passed in a cancel.
3455  testcase("Cancel too many offers");
3456 
3457  using namespace test::jtx;
3458 
3459  Env env{*this, features};
3460 
3461  // We want to maximize the metadata from a cancel offer transaction to
3462  // make sure we don't hit metadata limits. The way we'll do that is:
3463  //
3464  // 1. Generate twice as many separate funded accounts as we have
3465  // offers.
3466  // 2.
3467  // a. One of these accounts mints an NFT with a full URL.
3468  // b. The other account makes an offer that will expire soon.
3469  // 3. After all of these offers have expired, cancel all of the
3470  // expired offers in a single transaction.
3471  //
3472  // I can't think of any way to increase the metadata beyond this,
3473  // but I'm open to ideas.
3474  Account const alice("alice");
3475  env.fund(XRP(1000), alice);
3476  env.close();
3477 
3478  std::string const uri(maxTokenURILength, '?');
3479  std::vector<uint256> offerIndexes;
3480  offerIndexes.reserve(maxTokenOfferCancelCount + 1);
3481  for (uint32_t i = 0; i < maxTokenOfferCancelCount + 1; ++i)
3482  {
3483  Account const nftAcct(std::string("nftAcct") + std::to_string(i));
3484  Account const offerAcct(
3485  std::string("offerAcct") + std::to_string(i));
3486  env.fund(XRP(1000), nftAcct, offerAcct);
3487  env.close();
3488 
3489  uint256 const nftokenID =
3490  token::getNextID(env, nftAcct, 0, tfTransferable);
3491  env(token::mint(nftAcct, 0),
3492  token::uri(uri),
3493  txflags(tfTransferable));
3494  env.close();
3495 
3496  offerIndexes.push_back(
3497  keylet::nftoffer(offerAcct, env.seq(offerAcct)).key);
3498  env(token::createOffer(offerAcct, nftokenID, drops(1)),
3499  token::owner(nftAcct),
3500  token::expiration(lastClose(env) + 5));
3501  env.close();
3502  }
3503 
3504  // Close the ledger so the last of the offers expire.
3505  env.close();
3506 
3507  // All offers should be in the ledger.
3508  for (uint256 const& offerIndex : offerIndexes)
3509  {
3510  BEAST_EXPECT(env.le(keylet::nftoffer(offerIndex)));
3511  }
3512 
3513  // alice attempts to cancel all of the expired offers. There is one
3514  // too many so the request fails.
3515  env(token::cancelOffer(alice, offerIndexes), ter(temMALFORMED));
3516  env.close();
3517 
3518  // However alice can cancel just one of the offers.
3519  env(token::cancelOffer(alice, {offerIndexes.back()}));
3520  env.close();
3521 
3522  // Verify that offer is gone from the ledger.
3523  BEAST_EXPECT(!env.le(keylet::nftoffer(offerIndexes.back())));
3524  offerIndexes.pop_back();
3525 
3526  // But alice adds a sell offer to the list...
3527  {
3528  uint256 const nftokenID =
3529  token::getNextID(env, alice, 0, tfTransferable);
3530  env(token::mint(alice, 0),
3531  token::uri(uri),
3532  txflags(tfTransferable));
3533  env.close();
3534 
3535  offerIndexes.push_back(keylet::nftoffer(alice, env.seq(alice)).key);
3536  env(token::createOffer(alice, nftokenID, drops(1)),
3537  txflags(tfSellNFToken));
3538  env.close();
3539 
3540  // alice's owner count should now to 2 for the nft and the offer.
3541  BEAST_EXPECT(ownerCount(env, alice) == 2);
3542 
3543  // Because alice added the sell offer there are still too many
3544  // offers in the list to cancel.
3545  env(token::cancelOffer(alice, offerIndexes), ter(temMALFORMED));
3546  env.close();
3547 
3548  // alice burns her nft which removes the nft and the offer.
3549  env(token::burn(alice, nftokenID));
3550  env.close();
3551 
3552  // If alice's owner count is zero we can see that the offer
3553  // and nft are both gone.
3554  BEAST_EXPECT(ownerCount(env, alice) == 0);
3555  offerIndexes.pop_back();
3556  }
3557 
3558  // Now there are few enough offers in the list that they can all
3559  // be cancelled in a single transaction.
3560  env(token::cancelOffer(alice, offerIndexes));
3561  env.close();
3562 
3563  // Verify that remaining offers are gone from the ledger.
3564  for (uint256 const& offerIndex : offerIndexes)
3565  {
3566  BEAST_EXPECT(!env.le(keylet::nftoffer(offerIndex)));
3567  }
3568  }
3569 
3570  void
3572  {
3573  // Look at the case where too many offers are passed in a cancel.
3574  testcase("Brokered NFT offer accept");
3575 
3576  using namespace test::jtx;
3577 
3578  Env env{*this, features};
3579 
3580  // The most important thing to explore here is the way funds are
3581  // assigned from the buyer to...
3582  // o the Seller,
3583  // o the Broker, and
3584  // o the Issuer (in the case of a transfer fee).
3585 
3586  Account const issuer{"issuer"};
3587  Account const minter{"minter"};
3588  Account const buyer{"buyer"};
3589  Account const broker{"broker"};
3590  Account const gw{"gw"};
3591  IOU const gwXAU(gw["XAU"]);
3592 
3593  env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3594  env.close();
3595 
3596  env(trust(issuer, gwXAU(2000)));
3597  env(trust(minter, gwXAU(2000)));
3598  env(trust(buyer, gwXAU(2000)));
3599  env(trust(broker, gwXAU(2000)));
3600  env.close();
3601 
3602  env(token::setMinter(issuer, minter));
3603  env.close();
3604 
3605  // Lambda to check owner count of all accounts is one.
3606  auto checkOwnerCountIsOne =
3607  [this, &env](
3609  accounts,
3610  int line) {
3611  for (Account const& acct : accounts)
3612  {
3613  if (std::uint32_t ownerCount = this->ownerCount(env, acct);
3614  ownerCount != 1)
3615  {
3616  std::stringstream ss;
3617  ss << "Account " << acct.human()
3618  << " expected ownerCount == 1. Got " << ownerCount;
3619  fail(ss.str(), __FILE__, line);
3620  }
3621  }
3622  };
3623 
3624  // Lambda that mints an NFT and returns the nftID.
3625  auto mintNFT = [&env, &issuer, &minter](std::uint16_t xferFee = 0) {
3626  uint256 const nftID =
3627  token::getNextID(env, issuer, 0, tfTransferable, xferFee);
3628  env(token::mint(minter, 0),
3629  token::issuer(issuer),
3630  token::xferFee(xferFee),
3631  txflags(tfTransferable));
3632  env.close();
3633  return nftID;
3634  };
3635 
3636  // o Seller is selling for zero XRP.
3637  // o Broker charges no fee.
3638  // o No transfer fee.
3639  //
3640  // Since minter is selling for zero the currency must be XRP.
3641  {
3642  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3643 
3644  uint256 const nftID = mintNFT();
3645 
3646  // minter creates their offer.
3647  uint256 const minterOfferIndex =
3648  keylet::nftoffer(minter, env.seq(minter)).key;
3649  env(token::createOffer(minter, nftID, XRP(0)),
3650  txflags(tfSellNFToken));
3651  env.close();
3652 
3653  // buyer creates their offer. Note: a buy offer can never
3654  // offer zero.
3655  uint256 const buyOfferIndex =
3656  keylet::nftoffer(buyer, env.seq(buyer)).key;
3657  env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3658  env.close();
3659 
3660  auto const minterBalance = env.balance(minter);
3661  auto const buyerBalance = env.balance(buyer);
3662  auto const brokerBalance = env.balance(broker);
3663  auto const issuerBalance = env.balance(issuer);
3664 
3665  // Broker charges no brokerFee.
3666  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3667  env.close();
3668 
3669  // Note that minter's XRP balance goes up even though they
3670  // requested XRP(0).
3671  BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
3672  BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3673  BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
3674  BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3675 
3676  // Burn the NFT so the next test starts with a clean state.
3677  env(token::burn(buyer, nftID));
3678  env.close();
3679  }
3680 
3681  // o Seller is selling for zero XRP.
3682  // o Broker charges a fee.
3683  // o No transfer fee.
3684  //
3685  // Since minter is selling for zero the currency must be XRP.
3686  {
3687  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3688 
3689  uint256 const nftID = mintNFT();
3690 
3691  // minter creates their offer.
3692  uint256 const minterOfferIndex =
3693  keylet::nftoffer(minter, env.seq(minter)).key;
3694  env(token::createOffer(minter, nftID, XRP(0)),
3695  txflags(tfSellNFToken));
3696  env.close();
3697 
3698  // buyer creates their offer. Note: a buy offer can never
3699  // offer zero.
3700  uint256 const buyOfferIndex =
3701  keylet::nftoffer(buyer, env.seq(buyer)).key;
3702  env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3703  env.close();
3704 
3705  // Broker attempts to charge a 1.1 XRP brokerFee and fails.
3706  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3707  token::brokerFee(XRP(1.1)),
3709  env.close();
3710 
3711  auto const minterBalance = env.balance(minter);
3712  auto const buyerBalance = env.balance(buyer);
3713  auto const brokerBalance = env.balance(broker);
3714  auto const issuerBalance = env.balance(issuer);
3715 
3716  // Broker charges a 0.5 XRP brokerFee.
3717  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3718  token::brokerFee(XRP(0.5)));
3719  env.close();
3720 
3721  // Note that minter's XRP balance goes up even though they
3722  // requested XRP(0).
3723  BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3724  BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3725  BEAST_EXPECT(
3726  env.balance(broker) == brokerBalance + XRP(0.5) - drops(10));
3727  BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3728 
3729  // Burn the NFT so the next test starts with a clean state.
3730  env(token::burn(buyer, nftID));
3731  env.close();
3732  }
3733 
3734  // o Seller is selling for zero XRP.
3735  // o Broker charges no fee.
3736  // o 50% transfer fee.
3737  //
3738  // Since minter is selling for zero the currency must be XRP.
3739  {
3740  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3741 
3742  uint256 const nftID = mintNFT(maxTransferFee);
3743 
3744  // minter creates their offer.
3745  uint256 const minterOfferIndex =
3746  keylet::nftoffer(minter, env.seq(minter)).key;
3747  env(token::createOffer(minter, nftID, XRP(0)),
3748  txflags(tfSellNFToken));
3749  env.close();
3750 
3751  // buyer creates their offer. Note: a buy offer can never
3752  // offer zero.
3753  uint256 const buyOfferIndex =
3754  keylet::nftoffer(buyer, env.seq(buyer)).key;
3755  env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3756  env.close();
3757 
3758  auto const minterBalance = env.balance(minter);
3759  auto const buyerBalance = env.balance(buyer);
3760  auto const brokerBalance = env.balance(broker);
3761  auto const issuerBalance = env.balance(issuer);
3762 
3763  // Broker charges no brokerFee.
3764  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3765  env.close();
3766 
3767  // Note that minter's XRP balance goes up even though they
3768  // requested XRP(0).
3769  BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3770  BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3771  BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
3772  BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
3773 
3774  // Burn the NFT so the next test starts with a clean state.
3775  env(token::burn(buyer, nftID));
3776  env.close();
3777  }
3778 
3779  // o Seller is selling for zero XRP.
3780  // o Broker charges 0.5 XRP.
3781  // o 50% transfer fee.
3782  //
3783  // Since minter is selling for zero the currency must be XRP.
3784  {
3785  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3786 
3787  uint256 const nftID = mintNFT(maxTransferFee);
3788 
3789  // minter creates their offer.
3790  uint256 const minterOfferIndex =
3791  keylet::nftoffer(minter, env.seq(minter)).key;
3792  env(token::createOffer(minter, nftID, XRP(0)),
3793  txflags(tfSellNFToken));
3794  env.close();
3795 
3796  // buyer creates their offer. Note: a buy offer can never
3797  // offer zero.
3798  uint256 const buyOfferIndex =
3799  keylet::nftoffer(buyer, env.seq(buyer)).key;
3800  env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3801  env.close();
3802 
3803  auto const minterBalance = env.balance(minter);
3804  auto const buyerBalance = env.balance(buyer);
3805  auto const brokerBalance = env.balance(broker);
3806  auto const issuerBalance = env.balance(issuer);
3807 
3808  // Broker charges a 0.75 XRP brokerFee.
3809  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3810  token::brokerFee(XRP(0.75)));
3811  env.close();
3812 
3813  // Note that, with a 50% transfer fee, issuer gets 1/2 of what's
3814  // left _after_ broker takes their fee. minter gets the remainder
3815  // after both broker and minter take their cuts
3816  BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
3817  BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3818  BEAST_EXPECT(
3819  env.balance(broker) == brokerBalance + XRP(0.75) - drops(10));
3820  BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
3821 
3822  // Burn the NFT so the next test starts with a clean state.
3823  env(token::burn(buyer, nftID));
3824  env.close();
3825  }
3826 
3827  // Lambda to set the balance of all passed in accounts to gwXAU(1000).
3828  auto setXAUBalance_1000 =
3829  [this, &gw, &gwXAU, &env](
3831  accounts,
3832  int line) {
3833  for (Account const& acct : accounts)
3834  {
3835  static const auto xau1000 = gwXAU(1000);
3836  auto const balance = env.balance(acct, gwXAU);
3837  if (balance < xau1000)
3838  {
3839  env(pay(gw, acct, xau1000 - balance));
3840  env.close();
3841  }
3842  else if (balance > xau1000)
3843  {
3844  env(pay(acct, gw, balance - xau1000));
3845  env.close();
3846  }
3847  if (env.balance(acct, gwXAU) != xau1000)
3848  {
3849  std::stringstream ss;
3850  ss << "Unable to set " << acct.human()
3851  << " account balance to gwXAU(1000)";
3852  this->fail(ss.str(), __FILE__, line);
3853  }
3854  }
3855  };
3856 
3857  // The buyer and seller have identical amounts and there is no
3858  // transfer fee.
3859  {
3860  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3861  setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
3862 
3863  uint256 const nftID = mintNFT();
3864 
3865  // minter creates their offer.
3866  uint256 const minterOfferIndex =
3867  keylet::nftoffer(minter, env.seq(minter)).key;
3868  env(token::createOffer(minter, nftID, gwXAU(1000)),
3869  txflags(tfSellNFToken));
3870  env.close();
3871 
3872  {
3873  // buyer creates an offer for more XAU than they currently own.
3874  uint256 const buyOfferIndex =
3875  keylet::nftoffer(buyer, env.seq(buyer)).key;
3876  env(token::createOffer(buyer, nftID, gwXAU(1001)),
3877  token::owner(minter));
3878  env.close();
3879 
3880  // broker attempts to broker the offers but cannot.
3881  env(token::brokerOffers(
3882  broker, buyOfferIndex, minterOfferIndex),
3883  ter(tecINSUFFICIENT_FUNDS));
3884  env.close();
3885 
3886  // Cancel buyer's bad offer so the next test starts in a
3887  // clean state.
3888  env(token::cancelOffer(buyer, {buyOfferIndex}));
3889  env.close();
3890  }
3891  {
3892  // buyer creates an offer for less that what minter is asking.
3893  uint256 const buyOfferIndex =
3894  keylet::nftoffer(buyer, env.seq(buyer)).key;
3895  env(token::createOffer(buyer, nftID, gwXAU(999)),
3896  token::owner(minter));
3897  env.close();
3898 
3899  // broker attempts to broker the offers but cannot.
3900  env(token::brokerOffers(
3901  broker, buyOfferIndex, minterOfferIndex),
3903  env.close();
3904 
3905  // Cancel buyer's bad offer so the next test starts in a
3906  // clean state.
3907  env(token::cancelOffer(buyer, {buyOfferIndex}));
3908  env.close();
3909  }
3910 
3911  // buyer creates a large enough offer.
3912  uint256 const buyOfferIndex =
3913  keylet::nftoffer(buyer, env.seq(buyer)).key;
3914  env(token::createOffer(buyer, nftID, gwXAU(1000)),
3915  token::owner(minter));
3916  env.close();
3917 
3918  // Broker attempts to charge a brokerFee but cannot.
3919  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3920  token::brokerFee(gwXAU(0.1)),
3922  env.close();
3923 
3924  // broker charges no brokerFee and succeeds.
3925  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3926  env.close();
3927 
3928  BEAST_EXPECT(ownerCount(env, issuer) == 1);
3929  BEAST_EXPECT(ownerCount(env, minter) == 1);
3930  BEAST_EXPECT(ownerCount(env, buyer) == 2);
3931  BEAST_EXPECT(ownerCount(env, broker) == 1);
3932  BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
3933  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
3934  BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
3935  BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
3936 
3937  // Burn the NFT so the next test starts with a clean state.
3938  env(token::burn(buyer, nftID));
3939  env.close();
3940  }
3941 
3942  // seller offers more than buyer is asking.
3943  // There are both transfer and broker fees.
3944  {
3945  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3946  setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
3947 
3948  uint256 const nftID = mintNFT(maxTransferFee);
3949 
3950  // minter creates their offer.
3951  uint256 const minterOfferIndex =
3952  keylet::nftoffer(minter, env.seq(minter)).key;
3953  env(token::createOffer(minter, nftID, gwXAU(900)),
3954  txflags(tfSellNFToken));
3955  env.close();
3956  {
3957  // buyer creates an offer for more XAU than they currently own.
3958  uint256 const buyOfferIndex =
3959  keylet::nftoffer(buyer, env.seq(buyer)).key;
3960  env(token::createOffer(buyer, nftID, gwXAU(1001)),
3961  token::owner(minter));
3962  env.close();
3963 
3964  // broker attempts to broker the offers but cannot.
3965  env(token::brokerOffers(
3966  broker, buyOfferIndex, minterOfferIndex),
3967  ter(tecINSUFFICIENT_FUNDS));
3968  env.close();
3969 
3970  // Cancel buyer's bad offer so the next test starts in a
3971  // clean state.
3972  env(token::cancelOffer(buyer, {buyOfferIndex}));
3973  env.close();
3974  }
3975  {
3976  // buyer creates an offer for less that what minter is asking.
3977  uint256 const buyOfferIndex =
3978  keylet::nftoffer(buyer, env.seq(buyer)).key;
3979  env(token::createOffer(buyer, nftID, gwXAU(899)),
3980  token::owner(minter));
3981  env.close();
3982 
3983  // broker attempts to broker the offers but cannot.
3984  env(token::brokerOffers(
3985  broker, buyOfferIndex, minterOfferIndex),
3987  env.close();
3988 
3989  // Cancel buyer's bad offer so the next test starts in a
3990  // clean state.
3991  env(token::cancelOffer(buyer, {buyOfferIndex}));
3992  env.close();
3993  }
3994  // buyer creates a large enough offer.
3995  uint256 const buyOfferIndex =
3996  keylet::nftoffer(buyer, env.seq(buyer)).key;
3997  env(token::createOffer(buyer, nftID, gwXAU(1000)),
3998  token::owner(minter));
3999  env.close();
4000 
4001  // Broker attempts to charge a brokerFee larger than the
4002  // difference between the two offers but cannot.
4003  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4004  token::brokerFee(gwXAU(101)),
4006  env.close();
4007 
4008  // broker charges the full difference between the two offers and
4009  // succeeds.
4010  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4011  token::brokerFee(gwXAU(100)));
4012  env.close();
4013 
4014  BEAST_EXPECT(ownerCount(env, issuer) == 1);
4015  BEAST_EXPECT(ownerCount(env, minter) == 1);
4016  BEAST_EXPECT(ownerCount(env, buyer) == 2);
4017  BEAST_EXPECT(ownerCount(env, broker) == 1);
4018  BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4019  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4020  BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4021  BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4022 
4023  // Burn the NFT so the next test starts with a clean state.
4024  env(token::burn(buyer, nftID));
4025  env.close();
4026  }
4027  // seller offers more than buyer is asking.
4028  // There are both transfer and broker fees, but broker takes less than
4029  // the maximum.
4030  {
4031  checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4032  setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4033 
4034  uint256 const nftID = mintNFT(maxTransferFee / 2); // 25%
4035 
4036  // minter creates their offer.
4037  uint256 const minterOfferIndex =
4038  keylet::nftoffer(minter, env.seq(minter)).key;
4039  env(token::createOffer(minter, nftID, gwXAU(900)),
4040  txflags(tfSellNFToken));
4041  env.close();
4042 
4043  // buyer creates a large enough offer.
4044  uint256 const buyOfferIndex =
4045  keylet::nftoffer(buyer, env.seq(buyer)).key;
4046  env(token::createOffer(buyer, nftID, gwXAU(1000)),
4047  token::owner(minter));
4048  env.close();
4049 
4050  // broker charges half difference between the two offers and
4051  // succeeds. 25% of the remaining difference goes to issuer.
4052  // The rest goes to minter.
4053  env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4054  token::brokerFee(gwXAU(50)));
4055  env.close();
4056 
4057  BEAST_EXPECT(ownerCount(env, issuer) == 1);
4058  BEAST_EXPECT(ownerCount(env, minter) == 1);
4059  BEAST_EXPECT(ownerCount(env, buyer) == 2);
4060  BEAST_EXPECT(ownerCount(env, broker) == 1);
4061  BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4062  BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4063  BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4064  BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4065 
4066  // Burn the NFT so the next test starts with a clean state.
4067  env(token::burn(buyer, nftID));
4068  env.close();
4069  }
4070  }
4071 
4072  void
4074  {
4075  // Make sure all NFToken transactions work with tickets.
4076  testcase("NFToken transactions with tickets");
4077 
4078  using namespace test::jtx;
4079 
4080  Env env{*this, features};
4081 
4082  Account const issuer{"issuer"};
4083  Account const buyer{"buyer"};
4084  env.fund(XRP(10000), issuer, buyer);
4085  env.close();
4086 
4087  // issuer and buyer grab enough tickets for all of the following
4088  // transactions. Note that once the tickets are acquired issuer's
4089  // and buyer's account sequence numbers should not advance.
4090  std::uint32_t issuerTicketSeq{env.seq(issuer) + 1};
4091  env(ticket::create(issuer, 10));
4092  env.close();
4093  std::uint32_t const issuerSeq{env.seq(issuer)};
4094  BEAST_EXPECT(ticketCount(env, issuer) == 10);
4095 
4096  std::uint32_t buyerTicketSeq{env.seq(buyer) + 1};
4097  env(ticket::create(buyer, 10));
4098  env.close();
4099  std::uint32_t const buyerSeq{env.seq(buyer)};
4100  BEAST_EXPECT(ticketCount(env, buyer) == 10);
4101 
4102  // NFTokenMint
4103  BEAST_EXPECT(ownerCount(env, issuer) == 10);
4104  uint256 const nftId{token::getNextID(env, issuer, 0u, tfTransferable)};
4105  env(token::mint(issuer, 0u),
4106  txflags(tfTransferable),
4107  ticket::use(issuerTicketSeq++));
4108  env.close();
4109  BEAST_EXPECT(ownerCount(env, issuer) == 10);
4110  BEAST_EXPECT(ticketCount(env, issuer) == 9);
4111 
4112  // NFTokenCreateOffer
4113  BEAST_EXPECT(ownerCount(env, buyer) == 10);
4114  uint256 const offerIndex0 = keylet::nftoffer(buyer, buyerTicketSeq).key;
4115  env(token::createOffer(buyer, nftId, XRP(1)),
4116  token::owner(issuer),
4117  ticket::use(buyerTicketSeq++));
4118  env.close();
4119  BEAST_EXPECT(ownerCount(env, buyer) == 10);
4120  BEAST_EXPECT(ticketCount(env, buyer) == 9);
4121 
4122  // NFTokenCancelOffer
4123  env(token::cancelOffer(buyer, {offerIndex0}),
4124  ticket::use(buyerTicketSeq++));
4125  env.close();
4126  BEAST_EXPECT(ownerCount(env, buyer) == 8);
4127  BEAST_EXPECT(ticketCount(env, buyer) == 8);
4128 
4129  // NFTokenCreateOffer. buyer tries again.
4130  uint256 const offerIndex1 = keylet::nftoffer(buyer, buyerTicketSeq).key;
4131  env(token::createOffer(buyer, nftId, XRP(2)),
4132  token::owner(issuer),
4133  ticket::use(buyerTicketSeq++));
4134  env.close();
4135  BEAST_EXPECT(ownerCount(env, buyer) == 8);
4136  BEAST_EXPECT(ticketCount(env, buyer) == 7);
4137 
4138  // NFTokenAcceptOffer. issuer accepts buyer's offer.
4139  env(token::acceptBuyOffer(issuer, offerIndex1),
4140  ticket::use(issuerTicketSeq++));
4141  env.close();
4142  BEAST_EXPECT(ownerCount(env, issuer) == 8);
4143  BEAST_EXPECT(ownerCount(env, buyer) == 8);
4144  BEAST_EXPECT(ticketCount(env, issuer) == 8);
4145 
4146  // NFTokenBurn. buyer burns the token they just bought.
4147  env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4148  env.close();
4149  BEAST_EXPECT(ownerCount(env, issuer) == 8);
4150  BEAST_EXPECT(ownerCount(env, buyer) == 6);
4151  BEAST_EXPECT(ticketCount(env, buyer) == 6);
4152 
4153  // Verify that the account sequence numbers did not advance.
4154  BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4155  BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4156  }
4157 
4158  void
4160  {
4161  // Account deletion rules with NFTs:
4162  // 1. An account holding one or more NFT offers may be deleted.
4163  // 2. An NFT issuer with any NFTs they have issued still in the
4164  // ledger may not be deleted.
4165  // 3. An account holding one or more NFTs may not be deleted.
4166  testcase("NFToken delete account");
4167 
4168  using namespace test::jtx;
4169 
4170  Env env{*this, features};
4171 
4172  Account const issuer{"issuer"};
4173  Account const minter{"minter"};
4174  Account const becky{"becky"};
4175  Account const carla{"carla"};
4176  Account const daria{"daria"};
4177 
4178  env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4179  env.close();
4180 
4181  // Allow enough ledgers to pass so any of these accounts can be deleted.
4182  for (int i = 0; i < 300; ++i)
4183  env.close();
4184 
4185  env(token::setMinter(issuer, minter));
4186  env.close();
4187 
4188  uint256 const nftId{token::getNextID(env, issuer, 0u, tfTransferable)};
4189  env(token::mint(minter, 0u),
4190  token::issuer(issuer),
4191  txflags(tfTransferable));
4192  env.close();
4193 
4194  // At the momement issuer and minter cannot delete themselves.
4195  // o issuer has an issued NFT in the ledger.
4196  // o minter owns an NFT.
4197  env(acctdelete(issuer, daria), fee(XRP(50)), ter(tecHAS_OBLIGATIONS));
4198  env(acctdelete(minter, daria), fee(XRP(50)), ter(tecHAS_OBLIGATIONS));
4199  env.close();
4200 
4201  // Let enough ledgers pass so the account delete transactions are
4202  // not retried.
4203  for (int i = 0; i < 15; ++i)
4204  env.close();
4205 
4206  // becky and carla create offers for minter's NFT.
4207  env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4208  env.close();
4209 
4210  uint256 const carlaOfferIndex =
4211  keylet::nftoffer(carla, env.seq(carla)).key;
4212  env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4213  env.close();
4214 
4215  // It should be possible for becky to delete herself, even though
4216  // becky has an active NFT offer.
4217  env(acctdelete(becky, daria), fee(XRP(50)));
4218  env.close();
4219 
4220  // minter accepts carla's offer.
4221  env(token::acceptBuyOffer(minter, carlaOfferIndex));
4222  env.close();
4223 
4224  // Now it should be possible for minter to delete themselves since
4225  // they no longer own an NFT.
4226  env(acctdelete(minter, daria), fee(XRP(50)));
4227  env.close();
4228 
4229  // 1. issuer cannot delete themselves because they issued an NFT that
4230  // is still in the ledger.
4231  // 2. carla owns an NFT, so she cannot delete herself.
4232  env(acctdelete(issuer, daria), fee(XRP(50)), ter(tecHAS_OBLIGATIONS));
4233  env(acctdelete(carla, daria), fee(XRP(50)), ter(tecHAS_OBLIGATIONS));
4234  env.close();
4235 
4236  // Let enough ledgers pass so the account delete transactions are
4237  // not retried.
4238  for (int i = 0; i < 15; ++i)
4239  env.close();
4240 
4241  // carla burns her NFT. Since issuer's NFT is no longer in the
4242  // ledger, both issuer and carla can delete themselves.
4243  env(token::burn(carla, nftId));
4244  env.close();
4245 
4246  env(acctdelete(issuer, daria), fee(XRP(50)));
4247  env(acctdelete(carla, daria), fee(XRP(50)));
4248  env.close();
4249  }
4250 
4251  void
4253  {
4254  testEnabled(features);
4255  testMintReserve(features);
4256  testMintMaxTokens(features);
4257  testMintInvalid(features);
4258  testBurnInvalid(features);
4259  testCreateOfferInvalid(features);
4260  testCancelOfferInvalid(features);
4261  testAcceptOfferInvalid(features);
4262  testMintFlagBurnable(features);
4263  testMintFlagOnlyXRP(features);
4264  testMintFlagCreateTrustLine(features);
4265  testMintFlagTransferable(features);
4266  testMintTransferFee(features);
4267  testMintTaxon(features);
4268  testMintURI(features);
4269  testCreateOfferDestination(features);
4270  testCreateOfferExpiration(features);
4271  testCancelOffers(features);
4272  testCancelTooManyOffers(features);
4273  testBrokeredAccept(features);
4274  testNFTokenWithTickets(features);
4275  testNFTokenDeleteAccount(features);
4276  }
4277 
4278 public:
4279  void
4280  run() override
4281  {
4282  using namespace test::jtx;
4283  auto const sa = supported_amendments();
4284  testWithFeats(sa);
4285  }
4286 };
4287 
4288 BEAST_DEFINE_TESTSUITE_PRIO(NFToken, tx, ripple, 2);
4289 
4290 } // namespace ripple
ripple::NFToken_test::testNFTokenDeleteAccount
void testNFTokenDeleteAccount(FeatureBitset features)
Definition: NFToken_test.cpp:4159
ripple::tecUNFUNDED_OFFER
@ tecUNFUNDED_OFFER
Definition: TER.h:248
ripple::maxTransferFee
constexpr std::uint16_t maxTransferFee
The maximum token transfer fee allowed.
Definition: Protocol.h:81
ripple::sfOwnerCount
const SF_UINT32 sfOwnerCount
ripple::NFToken_test::testMintMaxTokens
void testMintMaxTokens(FeatureBitset features)
Definition: NFToken_test.cpp:442
ripple::NFToken_test::testBurnInvalid
void testBurnInvalid(FeatureBitset features)
Definition: NFToken_test.cpp:574
ripple::tecOBJECT_NOT_FOUND
@ tecOBJECT_NOT_FOUND
Definition: TER.h:290
ripple::tecFROZEN
@ tecFROZEN
Definition: TER.h:267
ripple::NFToken_test::testMintFlagBurnable
void testMintFlagBurnable(FeatureBitset features)
Definition: NFToken_test.cpp:1356
ripple::NFToken_test::testCreateOfferInvalid
void testCreateOfferInvalid(FeatureBitset features)
Definition: NFToken_test.cpp:634
ripple::tfTransferable
constexpr const std::uint32_t tfTransferable
Definition: TxFlags.h:121
ripple::NFToken_test::nftCount
static std::uint32_t nftCount(test::jtx::Env &env, test::jtx::Account const &acct)
Definition: NFToken_test.cpp:64
std::string
STL class.
ripple::STAmount::cMinValue
static const std::uint64_t cMinValue
Definition: STAmount.h:65
ripple::NFToken_test::testMintReserve
void testMintReserve(FeatureBitset features)
Definition: NFToken_test.cpp:201
ripple::NFToken_test::testCreateOfferExpiration
void testCreateOfferExpiration(FeatureBitset features)
Definition: NFToken_test.cpp:2864
ripple::sfNFTokenOffers
const SF_VECTOR256 sfNFTokenOffers
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::tecINSUFFICIENT_FUNDS
@ tecINSUFFICIENT_FUNDS
Definition: TER.h:289
std::string::reserve
T reserve(T... args)
ripple::OpenView
Writable ledger view that accumulates state and tx changes.
Definition: OpenView.h:55
std::vector
STL class.
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:614
ripple::sfMintedNFTokens
const SF_UINT32 sfMintedNFTokens
ripple::keylet::nftoffer
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Definition: Indexes.cpp:355
ripple::test::jtx::Account::human
std::string const & human() const
Returns the human readable public key.
Definition: Account.h:113
std::stringstream
STL class.
ripple::NFToken_test::testCancelTooManyOffers
void testCancelTooManyOffers(FeatureBitset features)
Definition: NFToken_test.cpp:3452
ripple::STAmount::cMinOffset
static const int cMinOffset
Definition: STAmount.h:61
ripple::NFToken_test::ownerCount
static std::uint32_t ownerCount(test::jtx::Env const &env, test::jtx::Account const &acct)
Definition: NFToken_test.cpp:34
ripple::tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
@ tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
Definition: TER.h:288
ripple::nft::toTaxon
Taxon toTaxon(std::uint32_t i)
Definition: NFTokenUtils.h:40
ripple::BEAST_DEFINE_TESTSUITE_PRIO
BEAST_DEFINE_TESTSUITE_PRIO(NFToken, tx, ripple, 2)
ripple::NFToken_test::testMintFlagOnlyXRP
void testMintFlagOnlyXRP(FeatureBitset features)
Definition: NFToken_test.cpp:1474
ripple::NFToken_test::testAcceptOfferInvalid
void testAcceptOfferInvalid(FeatureBitset features)
Definition: NFToken_test.cpp:1004
ripple::SField::jsonName
const Json::StaticString jsonName
Definition: SField.h:136
std::sort
T sort(T... args)
ripple::NFToken_test::ticketCount
static std::uint32_t ticketCount(test::jtx::Env const &env, test::jtx::Account const &acct)
Definition: NFToken_test.cpp:75
std::string::push_back
T push_back(T... args)
ripple::NFToken_test::testCancelOffers
void testCancelOffers(FeatureBitset features)
Definition: NFToken_test.cpp:3338
ripple::Keylet::key
uint256 key
Definition: Keylet.h:40
ripple::base_uint< 256 >
ripple::NFToken_test::testWithFeats
void testWithFeats(FeatureBitset features)
Definition: NFToken_test.cpp:4252
ripple::temINVALID_FLAG
@ temINVALID_FLAG
Definition: TER.h:106
ripple::tecNFTOKEN_OFFER_TYPE_MISMATCH
@ tecNFTOKEN_OFFER_TYPE_MISMATCH
Definition: TER.h:287
ripple::rand_int
std::enable_if_t< std::is_integral< Integral >::value &&detail::is_engine< Engine >::value, Integral > rand_int(Engine &engine, Integral min, Integral max)
Return a uniformly distributed random integer.
Definition: ripple/basics/random.h:115
ripple::tfBurnable
constexpr const std::uint32_t tfBurnable
Definition: TxFlags.h:118
ripple::keylet::account
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition: Indexes.cpp:133
ripple::tefNFTOKEN_IS_NOT_TRANSFERABLE
@ tefNFTOKEN_IS_NOT_TRANSFERABLE
Definition: TER.h:165
ripple::sfNFTokenMinter
const SF_ACCOUNT sfNFTokenMinter
ripple::NFToken_test::run
void run() override
Definition: NFToken_test.cpp:4280
ripple::OpenView::rawReplace
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Definition: OpenView.cpp:245
ripple::JsonOptions::none
@ none
ripple::TERSubset< CanCvtToTER >
ripple::NFToken_test::mintedCount
static std::uint32_t mintedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
Definition: NFToken_test.cpp:44
ripple::NFToken_test::testMintTaxon
void testMintTaxon(FeatureBitset features)
Definition: NFToken_test.cpp:2458
ripple::TER
TERSubset< CanCvtToTER > TER
Definition: TER.h:565
std::to_string
T to_string(T... args)
ripple::rand_byte
std::enable_if_t<(std::is_same< Byte, unsigned char >::value||std::is_same< Byte, std::uint8_t >::value) &&detail::is_engine< Engine >::value, Byte > rand_byte(Engine &engine)
Return a random byte.
Definition: ripple/basics/random.h:173
ripple::sfTicketCount
const SF_UINT32 sfTicketCount
ripple::NFToken_test::testMintInvalid
void testMintInvalid(FeatureBitset features)
Definition: NFToken_test.cpp:498
ripple::STAmount
Definition: STAmount.h:44
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::tfSellNFToken
constexpr const std::uint32_t tfSellNFToken
Definition: TxFlags.h:127
ripple::temBAD_AMOUNT
@ temBAD_AMOUNT
Definition: TER.h:84
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
ripple::maxTokenOfferCancelCount
constexpr std::size_t maxTokenOfferCancelCount
The maximum number of token offers that can be canceled at once.
Definition: Protocol.h:67
ripple::NFToken_test
Definition: NFToken_test.cpp:30
std::uint32_t
ripple::NFToken_test::burnedCount
static std::uint32_t burnedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
Definition: NFToken_test.cpp:54
ripple::NFToken_test::testMintTransferFee
void testMintTransferFee(FeatureBitset features)
Definition: NFToken_test.cpp:2027
ripple::temBAD_FEE
@ temBAD_FEE
Definition: TER.h:87
ripple::maxTokenURILength
constexpr std::size_t maxTokenURILength
The maximum length of a URI inside an NFT.
Definition: Protocol.h:84
ripple::NFToken_test::testMintFlagTransferable
void testMintFlagTransferable(FeatureBitset features)
Definition: NFToken_test.cpp:1737
ripple::sfURI
const SF_VL sfURI
ripple::NFToken_test::testCancelOfferInvalid
void testCancelOfferInvalid(FeatureBitset features)
Definition: NFToken_test.cpp:884
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::featureNonFungibleTokensV1
const uint256 featureNonFungibleTokensV1
Json::Value::removeMember
Value removeMember(const char *key)
Remove and return the named member.
Definition: json_value.cpp:907
ripple::tecNFTOKEN_BUY_SELL_MISMATCH
@ tecNFTOKEN_BUY_SELL_MISMATCH
Definition: TER.h:286
ripple::tecINSUFFICIENT_PAYMENT
@ tecINSUFFICIENT_PAYMENT
Definition: TER.h:291
ripple::NFToken_test::testBrokeredAccept
void testBrokeredAccept(FeatureBitset features)
Definition: NFToken_test.cpp:3571
ripple::tfSetFreeze
constexpr std::uint32_t tfSetFreeze
Definition: TxFlags.h:102
ripple::tecNO_LINE
@ tecNO_LINE
Definition: TER.h:265
ripple::tecEXPIRED
@ tecEXPIRED
Definition: TER.h:278
ripple::temDISABLED
@ temDISABLED
Definition: TER.h:109
ripple::NFToken_test::lastClose
std::uint32_t lastClose(test::jtx::Env &env)
Definition: NFToken_test.cpp:85
std::vector::begin
T begin(T... args)
ripple::test::jtx::Env::le
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Definition: Env.cpp:213
ripple::tecNO_ISSUER
@ tecNO_ISSUER
Definition: TER.h:263
ripple::tecHAS_OBLIGATIONS
@ tecHAS_OBLIGATIONS
Definition: TER.h:281
ripple::tecNO_PERMISSION
@ tecNO_PERMISSION
Definition: TER.h:269
ripple::tecMAX_SEQUENCE_REACHED
@ tecMAX_SEQUENCE_REACHED
Definition: TER.h:284
ripple::FeatureBitset
Definition: Feature.h:113
ripple::NFToken_test::testEnabled
void testEnabled(FeatureBitset features)
Definition: NFToken_test.cpp:91
ripple::NFToken_test::testMintFlagCreateTrustLine
void testMintFlagCreateTrustLine(FeatureBitset features)
Definition: NFToken_test.cpp:1568
ripple::tecINSUFFICIENT_RESERVE
@ tecINSUFFICIENT_RESERVE
Definition: TER.h:271
ripple::NFToken_test::testNFTokenWithTickets
void testNFTokenWithTickets(FeatureBitset features)
Definition: NFToken_test.cpp:4073
ripple::OpenView::read
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
Definition: OpenView.cpp:171
ripple::tfTrustLine
constexpr const std::uint32_t tfTrustLine
Definition: TxFlags.h:120
std::stringstream::str
T str(T... args)
std::size_t
ripple::tfClearFreeze
constexpr std::uint32_t tfClearFreeze
Definition: TxFlags.h:103
ripple::to_string
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
Definition: app/misc/impl/Manifest.cpp:41
ripple::tfOnlyXRP
constexpr const std::uint32_t tfOnlyXRP
Definition: TxFlags.h:119
ripple::sfNFTokenTaxon
const SF_UINT32 sfNFTokenTaxon
ripple::test::jtx::Account
Immutable cryptographic account descriptor.
Definition: Account.h:37
ripple::strHex
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:45
ripple::tecNO_ENTRY
@ tecNO_ENTRY
Definition: TER.h:270
std::vector::end
T end(T... args)
ripple::temMALFORMED
@ temMALFORMED
Definition: TER.h:82
ripple::tagged_integer
A type-safe wrap around standard integral types.
Definition: tagged_integer.h:44
std::numeric_limits::max
T max(T... args)
ripple::temBAD_EXPIRATION
@ temBAD_EXPIRATION
Definition: TER.h:86
ripple::sfBurnedNFTokens
const SF_UINT32 sfBurnedNFTokens
ripple::keylet::check
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Definition: Indexes.cpp:281
ripple::nft::getTaxon
Taxon getTaxon(uint256 const &id)
Definition: NFTokenUtils.h:165
ripple::NFToken_test::testMintURI
void testMintURI(FeatureBitset features)
Definition: NFToken_test.cpp:2531
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:219
ripple::NFToken_test::testCreateOfferDestination
void testCreateOfferDestination(FeatureBitset features)
Definition: NFToken_test.cpp:2641
ripple::temBAD_NFTOKEN_TRANSFER_FEE
@ temBAD_NFTOKEN_TRANSFER_FEE
Definition: TER.h:122
ripple::sfNFTokenSellOffer
const SF_UINT256 sfNFTokenSellOffer
ripple::test::jtx::Env::current
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition: Env.h:300
ripple::test::jtx::Env
A transaction testing environment.
Definition: Env.h:116
ripple::tecNO_DST
@ tecNO_DST
Definition: TER.h:254
ripple::test::jtx::Env::rpc
Json::Value rpc(std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition: Env.h:684
ripple::sfNFTokenBrokerFee
const SF_AMOUNT sfNFTokenBrokerFee
Json::Value
Represents a JSON value.
Definition: json_value.h:145
initializer_list