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