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>
37 if (
auto const sleAcct = env.
le(acct))
47 if (
auto const sleIssuer = env.
le(issuer))
57 if (
auto const sleIssuer = env.
le(issuer))
67 params[jss::account] = acct.
human();
68 params[jss::type] =
"state";
70 return nfts[jss::result][jss::account_nfts].
size();
78 if (
auto const sleAcct = env.
le(acct))
87 return env.
current()->info().parentCloseTime.time_since_epoch().count();
95 using namespace test::jtx;
103 Account
const& master = env.master;
109 uint256 const nftId{token::getNextID(env, master, 0u)};
124 env(token::createOffer(master, nftId, XRP(10)), ter(
temDISABLED));
130 env(token::cancelOffer(master, {offerIndex}), ter(
temDISABLED));
136 env(token::acceptBuyOffer(master, offerIndex), ter(
temDISABLED));
145 Env env{*
this, features};
146 Account
const& master = env.master;
152 uint256 const nftId0{token::getNextID(env, env.master, 0u)};
153 env(token::mint(env.master, 0u));
159 env(token::burn(env.master, nftId0));
173 Account
const alice{
"alice"};
174 env.fund(XRP(10000), alice);
176 uint256 const aliceOfferIndex =
178 env(token::createOffer(alice, nftId1, XRP(1000)),
179 token::owner(master));
190 env(token::acceptBuyOffer(master, aliceOfferIndex));
207 testcase(
"Mint reserve");
209 using namespace test::jtx;
211 Env env{*
this, features};
212 Account
const alice{
"alice"};
213 Account
const minter{
"minter"};
218 env.fund(XRP(200), alice, minter);
220 BEAST_EXPECT(env.balance(alice) == XRP(200));
221 BEAST_EXPECT(env.balance(minter) == XRP(200));
233 env(pay(env.master, alice, XRP(50) + drops(9)));
238 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
251 ss <<
"Wrong " << type <<
" count. Found: " << found
252 <<
"; Expected: " << exp;
253 fail(ss.
str(), __FILE__, line);
256 oneCheck(
"owner",
ownerCount(env, alice), owners);
257 oneCheck(
"minted",
mintedCount(env, alice), minted);
258 oneCheck(
"burned",
burnedCount(env, alice), burned);
264 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
267 env(pay(env.master, alice, drops(11)));
271 env(token::mint(alice));
273 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
277 for (
int i = 1; i < 32; ++i)
279 env(token::mint(alice));
280 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
287 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
290 env(pay(env.master, alice, XRP(50) + drops(329)));
296 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
299 env(pay(env.master, alice, drops(11)));
303 env(token::mint(alice));
305 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
312 env(token::burn(alice, token::getID(alice, 0, seq++)));
314 checkAliceOwnerMintedBurned((33 - seq) ? 1 : 0, 33, seq, __LINE__);
318 env(token::burn(alice, token::getID(alice, 197, 5)), ter(
tecNO_ENTRY));
320 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
324 env(token::setMinter(alice, minter));
331 auto checkMintersOwnerMintedBurned = [&env,
this, &alice, &minter](
339 auto oneCheck = [
this](
349 ss <<
"Wrong " << type <<
" count. Found: " << found
350 <<
"; Expected: " << exp;
351 fail(ss.
str(), __FILE__, line);
354 oneCheck(
"alice owner",
ownerCount(env, alice), aliceOwners, line);
356 "alice minted",
mintedCount(env, alice), aliceMinted, line);
358 "alice burned",
burnedCount(env, alice), aliceBurned, line);
360 "minter owner",
ownerCount(env, minter), minterOwners, line);
362 "minter minted",
mintedCount(env, minter), minterMinted, line);
364 "minter burned",
burnedCount(env, minter), minterBurned, line);
370 env(pay(env.master, minter, XRP(50) - drops(1)));
372 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
377 env(token::mint(minter),
378 token::issuer(alice),
382 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
385 env(pay(env.master, minter, drops(11)));
389 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
391 checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
395 for (
int i = 1; i < 32; ++i)
397 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
398 checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
402 env(pay(env.master, minter, XRP(50) + drops(319)));
407 env(token::mint(minter),
408 token::issuer(alice),
412 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
415 env(pay(env.master, minter, drops(11)));
419 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
421 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
426 env(token::burn(minter, token::getID(alice, 0, nftSeq++)));
428 checkMintersOwnerMintedBurned(
429 0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__);
433 env(token::burn(minter, token::getID(alice, 0, nftSeq++)));
435 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
438 env(token::burn(minter, token::getID(alice, 2009, 3)),
441 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
449 testcase(
"Mint max tokens");
451 using namespace test::jtx;
453 Account
const alice{
"alice"};
454 Env env{*
this, features};
455 env.fund(XRP(1000), alice);
464 uint256 const nftId0{token::getNextID(env, alice, 0u)};
465 env(token::mint(alice, 0u));
468 env(token::burn(alice, nftId0));
475 env.app().openLedger().modify(
484 auto replacement = std::make_shared<SLE>(*sle, sle->key());
490 view.rawReplace(replacement);
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));
500 testMintInvalid(FeatureBitset features)
502 // Explore many of the invalid ways to mint an NFT.
503 testcase("Mint invalid");
505 using namespace test::jtx;
507 Env env{*this, features};
508 Account const alice{"alice"};
509 Account const minter{"minter"};
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);
517 env(token::mint(alice, 0u), ter(tecINSUFFICIENT_RESERVE));
520 // Fund alice enough to start minting NFTs.
521 env(pay(env.master, alice, XRP(1000)));
524 //----------------------------------------------------------------------
527 // Set a negative fee.
528 env(token::mint(alice, 0u),
529 fee(STAmount(10ull, true)),
532 // Set an invalid flag.
533 env(token::mint(alice, 0u), txflags(0x00008000), ter(temINVALID_FLAG));
535 // Can't
set a transfer fee
if the NFT does not have the tfTRANSFERABLE
537 env(token::mint(alice, 0u),
542 env(token::mint(alice, 0u),
548 env(token::mint(alice, 0u), token::issuer(alice), ter(
temMALFORMED));
551 env(token::mint(alice, 0u), token::uri(
""), ter(
temMALFORMED));
554 env(token::mint(alice, 0u),
562 env(token::mint(alice, 0u),
563 token::issuer(Account(
"demon")),
570 env(token::mint(minter, 0u),
571 token::issuer(alice),
579 testcase(
"Burn invalid");
581 using namespace test::jtx;
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"]);
593 env.fund(XRP(250), alice, buyer, minter, gw);
607 env(token::burn(alice, nftAlice0ID),
614 env(token::burn(alice, nftAlice0ID),
624 env(token::burn(alice, token::getID(alice, 0, 1)), ter(
tecNO_ENTRY));
638 testcase(
"Invalid NFT offer create");
640 using namespace test::jtx;
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"]);
651 env.fund(XRP(250), alice, buyer, gw);
657 env(token::mint(alice, 0u),
669 uint256 nftNoXferID = token::getNextID(env, alice, 0);
670 env(token::mint(alice, 0));
683 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
690 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
697 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
704 env(token::createOffer(buyer, nftXrpOnlyID, buyer[
"USD"](1)),
706 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](0)),
708 env(token::createOffer(buyer, nftXrpOnlyID, drops(0)),
714 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](1)),
715 token::expiration(0),
722 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
728 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
736 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
743 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
744 token::destination(alice),
751 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
752 token::destination(Account(
"demon")),
762 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
770 env(token::createOffer(buyer, token::getID(alice, 0, 1), XRP(1000)),
777 env(token::createOffer(alice, token::getID(alice, 0, 1), XRP(1000)),
784 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
790 env(trust(buyer, gwAUD(1000)));
796 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
808 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
819 env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
829 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
838 env(trust(buyer, gwAUD(1000)));
841 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
851 env(pay(gw, buyer, gwAUD(999)));
856 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
863 env(pay(env.master, buyer, XRP(50) + drops(119)));
866 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
873 env(pay(env.master, buyer, drops(11)));
878 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
888 testcase(
"Invalid NFT offer cancel");
890 using namespace test::jtx;
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"]);
898 env.fund(XRP(1000), alice, buyer, gw);
909 uint256 const buyerOfferIndex =
911 env(token::createOffer(buyer, nftAlice0ID, XRP(1)),
921 env(token::cancelOffer(buyer, {buyerOfferIndex}),
928 env(token::cancelOffer(buyer, {buyerOfferIndex}),
948 env(token::cancelOffer(buyer, offers), ter(
temMALFORMED));
954 env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}),
968 env(pay(env.master, gw, XRP(5000)));
972 env(offer(gw, XRP(i), gwAUD(1)));
979 env(check::create(gw, env.master, XRP(300)));
986 env(check::cancel(gw, gwCheckId));
1000 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1008 testcase(
"Invalid NFT offer accept");
1010 using namespace test::jtx;
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"]);
1018 env.fund(XRP(1000), alice, buyer, gw);
1034 uint256 nftNoXferID = token::getNextID(env, alice, 0);
1035 env(token::mint(alice, 0));
1040 uint256 const plainOfferIndex =
1042 env(token::createOffer(alice, nftAlice0ID, XRP(10)),
1049 env(token::createOffer(alice, nftAlice0ID, gwAUD(30)),
1054 uint256 const xrpOnlyOfferIndex =
1056 env(token::createOffer(alice, nftXrpOnlyID, XRP(20)),
1061 uint256 const noXferOfferIndex =
1063 env(token::createOffer(alice, nftNoXferID, XRP(30)),
1069 uint256 const aliceExpOfferIndex =
1071 env(token::createOffer(alice, nftNoXferID, XRP(40)),
1081 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1088 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1089 txflags(0x00008000),
1096 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1105 Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1115 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1124 env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1125 token::brokerFee(gwAUD(0)),
1134 env(token::acceptBuyOffer(buyer, beast::zero),
1141 env(token::acceptBuyOffer(buyer, missingOfferIndex),
1147 env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1152 env(token::acceptSellOffer(buyer, beast::zero),
1158 env(token::acceptSellOffer(buyer, missingOfferIndex),
1164 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1173 env(trust(alice, gwAUD(1000)));
1174 env(trust(buyer, gwAUD(1000)));
1176 env(pay(gw, buyer, gwAUD(30)));
1185 uint256 const buyerOfferIndex =
1187 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)),
1188 token::owner(alice));
1193 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1199 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1206 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1212 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1218 uint256 const buyerOfferIndex =
1220 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)),
1221 token::owner(alice));
1227 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1228 token::brokerFee(XRP(40)),
1234 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1235 token::brokerFee(gwAUD(31)),
1242 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1243 token::brokerFee(gwAUD(1.5)),
1249 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1257 uint256 const buyerOfferIndex =
1259 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)),
1260 token::owner(alice));
1265 env(token::acceptBuyOffer(buyer, plainOfferIndex),
1271 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1277 env(pay(buyer, gw, gwAUD(30)));
1279 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1280 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1289 env(token::createOffer(alice, nftAlice0ID, XRP(0)),
1292 env(token::acceptSellOffer(gw, offerIndex));
1296 env(pay(gw, buyer, gwAUD(30)));
1300 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1306 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1314 uint256 const buyerOfferIndex =
1316 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)),
1317 token::owner(alice));
1322 env(token::acceptSellOffer(alice, buyerOfferIndex),
1328 env(token::acceptSellOffer(alice, plainOfferIndex),
1335 env(token::acceptSellOffer(buyer, plainOfferIndex),
1346 env(token::createOffer(gw, nftAlice0ID, XRP(0)),
1349 env(token::acceptSellOffer(alice, offerIndex));
1353 env(pay(buyer, gw, gwAUD(30)));
1355 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1356 env(token::acceptSellOffer(buyer, audOfferIndex),
1373 testcase(
"Mint flagBurnable");
1375 using namespace test::jtx;
1377 Env env{*
this, features};
1378 Account
const alice{
"alice"};
1379 Account
const buyer{
"buyer"};
1380 Account
const minter1{
"minter1"};
1381 Account
const minter2{
"minter2"};
1383 env.fund(XRP(1000), alice, buyer, minter1, minter2);
1388 env(token::setMinter(alice, minter1));
1395 auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1397 uint256 const nftID{token::getNextID(env, alice, 0u, flags)};
1398 env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags));
1403 env(token::createOffer(minter1, nftID, XRP(0)),
1407 env(token::acceptSellOffer(buyer, offerIndex));
1415 uint256 const noBurnID = nftToBuyer(0);
1416 env(token::burn(alice, noBurnID),
1417 token::owner(buyer),
1420 env(token::burn(minter1, noBurnID),
1421 token::owner(buyer),
1424 env(token::burn(minter2, noBurnID),
1425 token::owner(buyer),
1430 env(token::burn(buyer, noBurnID), token::owner(buyer));
1437 env(token::burn(minter2, burnableID),
1438 token::owner(buyer),
1443 env(token::burn(alice, burnableID), token::owner(buyer));
1451 env(token::burn(buyer, burnableID));
1459 env(token::burn(buyer, burnableID), token::owner(buyer));
1469 env(token::setMinter(alice, minter2));
1474 env(token::burn(minter1, burnableID),
1475 token::owner(buyer),
1481 env(token::burn(minter2, burnableID), token::owner(buyer));
1491 testcase(
"Mint flagOnlyXRP");
1493 using namespace test::jtx;
1495 Env env{*
this, features};
1496 Account
const alice{
"alice"};
1497 Account
const buyer{
"buyer"};
1498 Account
const gw(
"gw");
1499 IOU
const gwAUD(gw[
"AUD"]);
1502 env.fund(XRP(1000), alice, buyer, gw);
1504 env(trust(alice, gwAUD(1000)));
1505 env(trust(buyer, gwAUD(1000)));
1507 env(pay(gw, buyer, gwAUD(100)));
1517 uint256 const aliceOfferIndex =
1519 env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)),
1525 uint256 const buyerOfferIndex =
1527 env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)),
1528 token::owner(alice));
1533 env(token::cancelOffer(alice, {aliceOfferIndex}));
1534 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1540 env(token::burn(alice, nftIOUsOkayID));
1553 env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)),
1560 env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)),
1561 token::owner(alice),
1568 env(token::createOffer(alice, nftOnlyXRPID, XRP(60)),
1574 env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)),
1575 token::owner(alice));
1585 testcase(
"Mint flagCreateTrustLines");
1587 using namespace test::jtx;
1589 Account
const alice{
"alice"};
1590 Account
const becky{
"becky"};
1591 Account
const cheri{
"cheri"};
1592 Account
const gw(
"gw");
1593 IOU
const gwAUD(gw[
"AUD"]);
1594 IOU
const gwCAD(gw[
"CAD"]);
1595 IOU
const gwEUR(gw[
"EUR"]);
1600 for (
auto const& tweakedFeatures :
1604 Env env{*
this, tweakedFeatures};
1605 env.fund(XRP(1000), alice, becky, cheri, gw);
1609 env(trust(becky, gwAUD(1000)));
1610 env(trust(cheri, gwAUD(1000)));
1611 env(trust(becky, gwCAD(1000)));
1612 env(trust(cheri, gwCAD(1000)));
1613 env(trust(becky, gwEUR(1000)));
1614 env(trust(cheri, gwEUR(1000)));
1616 env(pay(gw, becky, gwAUD(500)));
1617 env(pay(gw, becky, gwCAD(500)));
1618 env(pay(gw, becky, gwEUR(500)));
1619 env(pay(gw, cheri, gwAUD(500)));
1620 env(pay(gw, cheri, gwCAD(500)));
1627 uint256 const nftNoAutoTrustID{
1629 env(token::mint(alice, 0u),
1630 token::xferFee(xferFee),
1635 uint256 const beckyBuyOfferIndex =
1637 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1638 token::owner(alice));
1640 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1644 TER const createOfferTER =
1646 uint256 const beckyOfferIndex =
1648 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1650 ter(createOfferTER));
1654 uint256 const cheriOfferIndex =
1656 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1657 token::owner(becky),
1658 ter(createOfferTER));
1662 env(token::cancelOffer(becky, {beckyOfferIndex}));
1663 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1671 uint256 const nftAutoTrustID{token::getNextID(
1682 env(token::mint(alice, 0u),
1683 token::xferFee(transferFee),
1694 uint256 const beckyBuyOfferIndex =
1696 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1697 token::owner(alice));
1699 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1703 uint256 const beckySellOfferIndex =
1705 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1708 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1712 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1715 uint256 const beckyBuyBackOfferIndex =
1717 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1718 token::owner(cheri));
1720 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1724 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1725 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1731 uint256 const nftNoAutoTrustID{token::getNextID(
1733 env(token::mint(alice, 0u),
1734 token::xferFee(transferFee),
1739 uint256 const aliceSellOfferIndex =
1741 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1744 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1750 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1753 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1757 uint256 const cheriSellOfferIndex =
1759 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1762 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1768 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1777 testcase(
"Mint flagTransferable");
1779 using namespace test::jtx;
1781 Env env{*
this, features};
1783 Account
const alice{
"alice"};
1784 Account
const becky{
"becky"};
1785 Account
const minter{
"minter"};
1787 env.fund(XRP(1000), alice, becky, minter);
1793 uint256 const nftAliceNoTransferID{
1794 token::getNextID(env, alice, 0u)};
1795 env(token::mint(alice, 0u), token::xferFee(0));
1801 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1802 token::owner(alice),
1806 uint256 const aliceSellOfferIndex =
1808 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1811 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1817 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1826 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1828 token::destination(alice),
1836 uint256 const aliceBuyOfferIndex =
1838 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1839 token::owner(becky));
1841 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1847 env(token::burn(alice, nftAliceNoTransferID));
1854 env(token::setMinter(alice, minter));
1858 uint256 const nftMinterNoTransferID{
1859 token::getNextID(env, alice, 0u)};
1860 env(token::mint(minter), token::issuer(alice));
1866 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1867 token::owner(minter),
1873 env(token::clearMinter(alice));
1878 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1886 for (
int i = 0; i < 10; ++i)
1889 env(token::setMinter(alice, minter));
1895 uint256 const minterSellOfferIndex =
1897 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1904 env(token::clearMinter(alice));
1910 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1916 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1924 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1925 token::owner(becky),
1932 uint256 const aliceBuyOfferIndex =
1934 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1935 token::owner(becky));
1941 for (
int i = 0; i < 10; ++i)
1944 env(token::setMinter(alice, minter));
1949 uint256 const minterBuyOfferIndex =
1951 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1952 token::owner(becky));
1958 env(token::clearMinter(alice));
1964 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1972 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
1974 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1991 uint256 const aliceSellOfferIndex =
1993 env(token::createOffer(alice, nftAliceID, XRP(20)),
1998 uint256 const beckyBuyOfferIndex =
2000 env(token::createOffer(becky, nftAliceID, XRP(21)),
2001 token::owner(alice));
2006 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
2012 uint256 const beckySellOfferIndex =
2014 env(token::createOffer(becky, nftAliceID, XRP(22)),
2022 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2029 uint256 const minterSellOfferIndex =
2031 env(token::createOffer(minter, nftAliceID, XRP(23)),
2039 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2047 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2055 env(token::burn(becky, nftAliceID));
2067 testcase(
"Mint transferFee");
2069 using namespace test::jtx;
2071 Env env{*
this, features};
2073 Account
const alice{
"alice"};
2074 Account
const becky{
"becky"};
2075 Account
const carol{
"carol"};
2076 Account
const minter{
"minter"};
2077 Account
const gw{
"gw"};
2078 IOU
const gwXAU(gw[
"XAU"]);
2080 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2083 env(trust(alice, gwXAU(2000)));
2084 env(trust(becky, gwXAU(2000)));
2085 env(trust(carol, gwXAU(2000)));
2086 env(trust(minter, gwXAU(2000)));
2088 env(pay(gw, alice, gwXAU(1000)));
2089 env(pay(gw, becky, gwXAU(1000)));
2090 env(pay(gw, carol, gwXAU(1000)));
2091 env(pay(gw, minter, gwXAU(1000)));
2096 env(token::setMinter(alice, minter));
2113 uint256 const beckyBuyOfferIndex =
2115 env(token::createOffer(becky, nftID, gwXAU(10)),
2116 token::owner(alice));
2118 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2119 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2121 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2123 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2124 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2127 uint256 const beckySellOfferIndex =
2129 env(token::createOffer(becky, nftID, gwXAU(10)),
2132 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2134 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2135 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2136 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2139 uint256 const minterBuyOfferIndex =
2141 env(token::createOffer(minter, nftID, gwXAU(10)),
2142 token::owner(carol));
2144 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2146 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2147 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2148 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2149 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2153 uint256 const minterSellOfferIndex =
2155 env(token::createOffer(minter, nftID, gwXAU(10)),
2158 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2160 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2161 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2162 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2163 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2166 env(token::burn(alice, nftID));
2179 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2183 uint256 const beckyBuyOfferIndex =
2185 env(token::createOffer(becky, nftID, gwXAU(10)),
2186 token::owner(alice));
2188 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2189 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2191 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2193 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2194 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2197 uint256 const beckySellOfferIndex =
2199 env(token::createOffer(becky, nftID, gwXAU(10)),
2202 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2205 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2206 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2207 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2210 uint256 const minterBuyOfferIndex =
2212 env(token::createOffer(minter, nftID, gwXAU(10)),
2213 token::owner(carol));
2215 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2218 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2219 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2220 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2221 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2225 uint256 const minterSellOfferIndex =
2227 env(token::createOffer(minter, nftID, gwXAU(10)),
2230 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2232 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2233 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2234 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2235 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2239 env(pay(alice, becky, gwXAU(0.0001)));
2240 env(pay(alice, carol, gwXAU(0.0001)));
2243 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2244 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2245 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2246 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2249 env(token::burn(alice, nftID));
2260 env(token::mint(alice),
2267 uint256 const nftID = token::getNextID(
2269 env(token::mint(alice),
2275 uint256 const beckyBuyOfferIndex =
2277 env(token::createOffer(becky, nftID, gwXAU(10)),
2278 token::owner(alice));
2280 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2281 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2283 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2285 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2286 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2289 uint256 const beckySellOfferIndex =
2291 env(token::createOffer(becky, nftID, gwXAU(100)),
2294 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2297 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2298 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2299 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2302 uint256 const carolBuyOfferIndex =
2304 env(token::createOffer(carol, nftID, gwXAU(10)),
2305 token::owner(minter));
2307 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2310 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2311 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2312 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2313 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2317 uint256 const carolSellOfferIndex =
2319 env(token::createOffer(carol, nftID, gwXAU(10)),
2322 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2325 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2326 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2327 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2328 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2331 env(pay(alice, minter, gwXAU(55)));
2332 env(pay(becky, minter, gwXAU(40)));
2334 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2335 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2336 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2337 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2340 env(token::burn(alice, nftID));
2354 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2360 STAmount aliceBalance = env.balance(alice);
2361 STAmount minterBalance = env.balance(minter);
2362 uint256 const minterBuyOfferIndex =
2364 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2366 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2368 aliceBalance += XRP(1) - fee;
2369 minterBalance -= XRP(1) + fee;
2370 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2371 BEAST_EXPECT(env.balance(minter) == minterBalance);
2375 STAmount carolBalance = env.balance(carol);
2376 uint256 const minterSellOfferIndex =
2378 env(token::createOffer(minter, nftID, drops(99999)),
2381 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2383 minterBalance += drops(99999) - fee;
2384 carolBalance -= drops(99999) + fee;
2385 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2386 BEAST_EXPECT(env.balance(minter) == minterBalance);
2387 BEAST_EXPECT(env.balance(carol) == carolBalance);
2391 STAmount beckyBalance = env.balance(becky);
2392 uint256 const beckyBuyOfferIndex =
2394 env(token::createOffer(becky, nftID, drops(100000)),
2395 token::owner(carol));
2397 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2399 carolBalance += drops(99999) - fee;
2400 beckyBalance -= drops(100000) + fee;
2401 aliceBalance += drops(1);
2403 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2404 BEAST_EXPECT(env.balance(minter) == minterBalance);
2405 BEAST_EXPECT(env.balance(carol) == carolBalance);
2406 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2415 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2421 env(pay(alice, gw, env.balance(alice, gwXAU)));
2422 env(pay(minter, gw, env.balance(minter, gwXAU)));
2423 env(pay(becky, gw, env.balance(becky, gwXAU)));
2428 env(pay(gw, alice, startXAUBalance));
2429 env(pay(gw, minter, startXAUBalance));
2430 env(pay(gw, becky, startXAUBalance));
2439 STAmount aliceBalance = env.balance(alice, gwXAU);
2440 STAmount minterBalance = env.balance(minter, gwXAU);
2441 uint256 const minterBuyOfferIndex =
2443 env(token::createOffer(minter, nftID, tinyXAU),
2444 token::owner(alice));
2446 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2448 aliceBalance += tinyXAU;
2449 minterBalance -= tinyXAU;
2450 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2451 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2454 STAmount carolBalance = env.balance(carol, gwXAU);
2455 uint256 const minterSellOfferIndex =
2457 env(token::createOffer(minter, nftID, tinyXAU),
2460 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2463 minterBalance += tinyXAU;
2464 carolBalance -= tinyXAU;
2466 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2467 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2468 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2475 STAmount beckyBalance = env.balance(becky, gwXAU);
2476 uint256 const beckyBuyOfferIndex =
2478 env(token::createOffer(becky, nftID, cheapNFT),
2479 token::owner(carol));
2481 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2484 aliceBalance += tinyXAU;
2485 beckyBalance -= cheapNFT;
2486 carolBalance += cheapNFT - tinyXAU;
2487 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2488 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2489 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2490 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2498 testcase(
"Mint taxon");
2500 using namespace test::jtx;
2502 Env env{*
this, features};
2504 Account
const alice{
"alice"};
2505 Account
const becky{
"becky"};
2507 env.fund(XRP(1000), alice, becky);
2516 uint256 const nftID = token::getNextID(env, alice, 0u);
2523 uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2531 for (
int i = 0; i < 10; ++i)
2541 ss <<
"Taxon recovery failed from nftID "
2542 <<
to_string(nftID) <<
". Expected: " << taxon
2543 <<
"; got: " << gotTaxon;
2548 uint256 const nftAliceID = token::getID(
2551 rand_int<std::uint32_t>(),
2552 rand_int<std::uint16_t>(),
2553 rand_int<std::uint16_t>());
2554 check(taxon, nftAliceID);
2556 uint256 const nftBeckyID = token::getID(
2559 rand_int<std::uint32_t>(),
2560 rand_int<std::uint16_t>(),
2561 rand_int<std::uint16_t>());
2562 check(taxon, nftBeckyID);
2574 testcase(
"Mint URI");
2576 using namespace test::jtx;
2578 Env env{*
this, features};
2580 Account
const alice{
"alice"};
2581 Account
const becky{
"becky"};
2583 env.fund(XRP(10000), alice, becky);
2589 auto randURI = []() {
2611 : uri(std::move(uri_)), taxon(taxon_)
2619 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2622 for (Entry
const& entry : entries)
2624 if (entry.uri.empty())
2626 env(token::mint(alice, entry.taxon));
2630 env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2638 params[jss::account] = alice.human();
2639 params[jss::type] =
"state";
2640 return env.rpc(
"json",
"account_nfts",
to_string(params));
2644 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2645 if (!BEAST_EXPECT(nfts.
size() == entries.size()))
2658 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2663 Entry
const& entry = entries[i];
2666 if (entry.uri.empty())
2681 testcase(
"Create offer destination");
2683 using namespace test::jtx;
2685 Env env{*
this, features};
2687 Account
const issuer{
"issuer"};
2688 Account
const minter{
"minter"};
2689 Account
const buyer{
"buyer"};
2690 Account
const broker{
"broker"};
2692 env.fund(XRP(1000), issuer, minter, buyer, broker);
2696 env(token::setMinter(issuer, minter));
2701 env(token::mint(minter, 0),
2702 token::issuer(issuer),
2709 uint256 const offerMinterToIssuer =
2711 env(token::createOffer(minter, nftokenID, drops(1)),
2712 token::destination(issuer),
2715 uint256 const offerMinterToBuyer =
2717 env(token::createOffer(minter, nftokenID, drops(1)),
2718 token::destination(buyer),
2721 uint256 const offerIssuerToMinter =
2723 env(token::createOffer(issuer, nftokenID, drops(1)),
2724 token::owner(minter),
2725 token::destination(minter));
2727 uint256 const offerIssuerToBuyer =
2729 env(token::createOffer(issuer, nftokenID, drops(1)),
2730 token::owner(minter),
2731 token::destination(buyer));
2745 env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2747 env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2749 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2751 env(token::cancelOffer(minter, {offerIssuerToBuyer}),
2760 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2761 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2762 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2763 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2773 uint256 const offerMinterSellsToBuyer =
2775 env(token::createOffer(minter, nftokenID, drops(1)),
2776 token::destination(buyer),
2785 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer),
2793 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2803 uint256 const offerMinterBuysFromBuyer =
2805 env(token::createOffer(minter, nftokenID, drops(1)),
2806 token::owner(buyer),
2807 token::destination(buyer));
2815 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer),
2823 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2832 uint256 const offerBuyerBuysFromMinter =
2834 env(token::createOffer(buyer, nftokenID, drops(1)),
2835 token::owner(minter),
2836 token::destination(broker));
2842 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter),
2847 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2857 uint256 const offerMinterToBroker =
2859 env(token::createOffer(minter, nftokenID, drops(1)),
2860 token::destination(broker),
2863 uint256 const offerBuyerToMinter =
2865 env(token::createOffer(buyer, nftokenID, drops(1)),
2866 token::owner(minter));
2875 env(token::brokerOffers(
2876 issuer, offerBuyerToMinter, offerMinterToBroker),
2885 env(token::brokerOffers(
2886 broker, offerBuyerToMinter, offerMinterToBroker));
2897 uint256 const offerBuyerToMinter =
2899 env(token::createOffer(buyer, nftokenID, drops(1)),
2900 token::destination(minter),
2903 uint256 const offerMinterToBuyer =
2905 env(token::createOffer(minter, nftokenID, drops(1)),
2906 token::owner(buyer));
2908 uint256 const offerIssuerToBuyer =
2910 env(token::createOffer(issuer, nftokenID, drops(1)),
2911 token::owner(buyer));
2919 env(token::brokerOffers(
2920 broker, offerIssuerToBuyer, offerBuyerToMinter),
2928 env(token::brokerOffers(
2929 broker, offerMinterToBuyer, offerBuyerToMinter));
2936 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2946 uint256 const offerMinterToBroker =
2948 env(token::createOffer(minter, nftokenID, drops(1)),
2949 token::destination(broker),
2952 uint256 const offerBuyerToBroker =
2954 env(token::createOffer(buyer, nftokenID, drops(1)),
2955 token::owner(minter),
2956 token::destination(broker));
2960 env(token::brokerOffers(
2961 issuer, offerBuyerToBroker, offerMinterToBroker),
2969 env(token::brokerOffers(
2970 broker, offerBuyerToBroker, offerMinterToBroker));
2982 testcase(
"Create offer expiration");
2984 using namespace test::jtx;
2986 Env env{*
this, features};
2988 Account
const issuer{
"issuer"};
2989 Account
const minter{
"minter"};
2990 Account
const buyer{
"buyer"};
2992 env.fund(XRP(1000), issuer, minter, buyer);
2996 env(token::setMinter(issuer, minter));
3001 env(token::mint(minter, 0),
3002 token::issuer(issuer),
3008 env(token::mint(minter, 0),
3009 token::issuer(issuer),
3018 uint256 const offerMinterToIssuer =
3020 env(token::createOffer(minter, nftokenID0, drops(1)),
3021 token::destination(issuer),
3022 token::expiration(expiration),
3025 uint256 const offerMinterToAnyone =
3027 env(token::createOffer(minter, nftokenID0, drops(1)),
3028 token::expiration(expiration),
3031 uint256 const offerIssuerToMinter =
3033 env(token::createOffer(issuer, nftokenID0, drops(1)),
3034 token::owner(minter),
3035 token::expiration(expiration));
3037 uint256 const offerBuyerToMinter =
3039 env(token::createOffer(buyer, nftokenID0, drops(1)),
3040 token::owner(minter),
3041 token::expiration(expiration));
3053 env(token::cancelOffer(issuer, {offerMinterToAnyone}),
3055 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
3058 BEAST_EXPECT(
lastClose(env) < expiration);
3064 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3068 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3079 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3080 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3095 env(token::createOffer(minter, nftokenID0, drops(1)),
3096 token::expiration(expiration),
3101 env(token::createOffer(minter, nftokenID1, drops(1)),
3102 token::expiration(expiration),
3105 BEAST_EXPECT(
lastClose(env) < expiration);
3111 env(token::acceptSellOffer(buyer, offer0));
3122 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3123 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3132 env(token::cancelOffer(issuer, {offer1}));
3142 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3144 token::destination(minter));
3146 env(token::acceptSellOffer(minter, offerSellBack));
3160 env(token::createOffer(buyer, nftokenID0, drops(1)),
3161 token::owner(minter),
3162 token::expiration(expiration));
3165 env(token::createOffer(buyer, nftokenID1, drops(1)),
3166 token::owner(minter),
3167 token::expiration(expiration));
3169 BEAST_EXPECT(
lastClose(env) < expiration);
3175 env(token::acceptBuyOffer(minter, offer0));
3186 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3187 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3196 env(token::cancelOffer(issuer, {offer1}));
3206 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3208 token::destination(minter));
3210 env(token::acceptSellOffer(minter, offerSellBack));
3225 env(token::createOffer(minter, nftokenID0, drops(1)),
3226 token::expiration(expiration),
3231 env(token::createOffer(minter, nftokenID1, drops(1)),
3232 token::expiration(expiration),
3237 env(token::createOffer(buyer, nftokenID0, drops(1)),
3238 token::owner(minter));
3242 env(token::createOffer(buyer, nftokenID1, drops(1)),
3243 token::owner(minter));
3246 BEAST_EXPECT(
lastClose(env) < expiration);
3252 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3263 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3273 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3283 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3285 token::destination(minter));
3287 env(token::acceptSellOffer(minter, offerSellBack));
3302 env(token::createOffer(minter, nftokenID0, drops(1)),
3307 env(token::createOffer(minter, nftokenID1, drops(1)),
3312 env(token::createOffer(buyer, nftokenID0, drops(1)),
3313 token::expiration(expiration),
3314 token::owner(minter));
3318 env(token::createOffer(buyer, nftokenID1, drops(1)),
3319 token::expiration(expiration),
3320 token::owner(minter));
3323 BEAST_EXPECT(
lastClose(env) < expiration);
3329 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3340 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3350 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3360 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3362 token::destination(minter));
3364 env(token::acceptSellOffer(minter, offerSellBack));
3380 env(token::createOffer(minter, nftokenID0, drops(1)),
3381 token::expiration(expiration),
3386 env(token::createOffer(minter, nftokenID1, drops(1)),
3387 token::expiration(expiration),
3392 env(token::createOffer(buyer, nftokenID0, drops(1)),
3393 token::expiration(expiration),
3394 token::owner(minter));
3398 env(token::createOffer(buyer, nftokenID1, drops(1)),
3399 token::expiration(expiration),
3400 token::owner(minter));
3403 BEAST_EXPECT(
lastClose(env) < expiration);
3409 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3420 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3430 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3440 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3442 token::destination(minter));
3444 env(token::acceptSellOffer(minter, offerSellBack));
3456 testcase(
"Cancel offers");
3458 using namespace test::jtx;
3460 Env env{*
this, features};
3462 Account
const alice(
"alice");
3463 Account
const becky(
"becky");
3464 Account
const minter(
"minter");
3465 env.fund(XRP(50000), alice, becky, minter);
3469 env(token::setMinter(alice, minter));
3478 uint256 const expiredOfferIndex =
3481 env(token::createOffer(alice, nftokenID, XRP(1000)),
3483 token::expiration(
lastClose(env) + 13));
3488 env(token::cancelOffer(becky, {expiredOfferIndex}),
3496 env(token::cancelOffer(becky, {expiredOfferIndex}));
3502 uint256 const dest1OfferIndex =
3505 env(token::createOffer(alice, nftokenID, XRP(1000)),
3506 token::destination(becky),
3512 env(token::cancelOffer(minter, {dest1OfferIndex}),
3517 env(token::cancelOffer(becky, {dest1OfferIndex}));
3522 uint256 const dest2OfferIndex =
3525 env(token::createOffer(alice, nftokenID, XRP(1000)),
3526 token::destination(becky),
3531 env(token::cancelOffer(alice, {dest2OfferIndex}));
3538 uint256 const mintersNFTokenID =
3540 env(token::mint(minter, 0),
3541 token::issuer(alice),
3545 uint256 const minterOfferIndex =
3548 env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3554 env(token::cancelOffer(alice, {minterOfferIndex}),
3556 env(token::cancelOffer(becky, {minterOfferIndex}),
3561 env(token::cancelOffer(minter, {minterOfferIndex}));
3570 testcase(
"Cancel too many offers");
3572 using namespace test::jtx;
3574 Env env{*
this, features};
3589 Account
const alice(
"alice");
3590 env.fund(XRP(1000), alice);
3599 Account
const offerAcct(
3601 env.fund(XRP(1000), nftAcct, offerAcct);
3606 env(token::mint(nftAcct, 0),
3613 env(token::createOffer(offerAcct, nftokenID, drops(1)),
3614 token::owner(nftAcct),
3623 for (
uint256 const& offerIndex : offerIndexes)
3630 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3634 env(token::cancelOffer(alice, {offerIndexes.back()}));
3639 offerIndexes.pop_back();
3645 env(token::mint(alice, 0),
3651 env(token::createOffer(alice, nftokenID, drops(1)),
3660 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3664 env(token::burn(alice, nftokenID));
3670 offerIndexes.pop_back();
3675 env(token::cancelOffer(alice, offerIndexes));
3679 for (
uint256 const& offerIndex : offerIndexes)
3689 testcase(
"Brokered NFT offer accept");
3691 using namespace test::jtx;
3693 Env env{*
this, features};
3701 Account
const issuer{
"issuer"};
3702 Account
const minter{
"minter"};
3703 Account
const buyer{
"buyer"};
3704 Account
const broker{
"broker"};
3705 Account
const gw{
"gw"};
3706 IOU
const gwXAU(gw[
"XAU"]);
3708 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3711 env(trust(issuer, gwXAU(2000)));
3712 env(trust(minter, gwXAU(2000)));
3713 env(trust(buyer, gwXAU(2000)));
3714 env(trust(broker, gwXAU(2000)));
3717 env(token::setMinter(issuer, minter));
3721 auto checkOwnerCountIsOne =
3726 for (Account
const& acct : accounts)
3732 ss <<
"Account " << acct.human()
3733 <<
" expected ownerCount == 1. Got " <<
ownerCount;
3734 fail(ss.
str(), __FILE__, line);
3740 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3743 env(token::mint(minter, 0),
3744 token::issuer(issuer),
3745 token::xferFee(xferFee),
3757 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3759 uint256 const nftID = mintNFT();
3762 uint256 const minterOfferIndex =
3764 env(token::createOffer(minter, nftID, XRP(0)),
3772 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3775 auto const minterBalance = env.balance(minter);
3776 auto const buyerBalance = env.balance(buyer);
3777 auto const brokerBalance = env.balance(broker);
3778 auto const issuerBalance = env.balance(issuer);
3781 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3786 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
3787 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3788 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
3789 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3792 env(token::burn(buyer, nftID));
3802 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3804 uint256 const nftID = mintNFT();
3807 uint256 const minterOfferIndex =
3809 env(token::createOffer(minter, nftID, XRP(0)),
3817 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3821 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3822 token::brokerFee(XRP(1.1)),
3826 auto const minterBalance = env.balance(minter);
3827 auto const buyerBalance = env.balance(buyer);
3828 auto const brokerBalance = env.balance(broker);
3829 auto const issuerBalance = env.balance(issuer);
3832 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3833 token::brokerFee(XRP(0.5)));
3838 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3839 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3841 env.balance(broker) == brokerBalance + XRP(0.5) - drops(10));
3842 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3845 env(token::burn(buyer, nftID));
3855 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3860 uint256 const minterOfferIndex =
3862 env(token::createOffer(minter, nftID, XRP(0)),
3870 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3873 auto const minterBalance = env.balance(minter);
3874 auto const buyerBalance = env.balance(buyer);
3875 auto const brokerBalance = env.balance(broker);
3876 auto const issuerBalance = env.balance(issuer);
3879 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3884 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3885 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3886 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
3887 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
3890 env(token::burn(buyer, nftID));
3900 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3905 uint256 const minterOfferIndex =
3907 env(token::createOffer(minter, nftID, XRP(0)),
3915 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3918 auto const minterBalance = env.balance(minter);
3919 auto const buyerBalance = env.balance(buyer);
3920 auto const brokerBalance = env.balance(broker);
3921 auto const issuerBalance = env.balance(issuer);
3924 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3925 token::brokerFee(XRP(0.75)));
3931 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
3932 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3934 env.balance(broker) == brokerBalance + XRP(0.75) - drops(10));
3935 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
3938 env(token::burn(buyer, nftID));
3943 auto setXAUBalance_1000 =
3944 [
this, &gw, &gwXAU, &env](
3948 for (Account
const& acct : accounts)
3950 static const auto xau1000 = gwXAU(1000);
3951 auto const balance = env.balance(acct, gwXAU);
3952 if (balance < xau1000)
3954 env(pay(gw, acct, xau1000 - balance));
3957 else if (balance > xau1000)
3959 env(pay(acct, gw, balance - xau1000));
3962 if (env.balance(acct, gwXAU) != xau1000)
3965 ss <<
"Unable to set " << acct.human()
3966 <<
" account balance to gwXAU(1000)";
3967 this->fail(ss.
str(), __FILE__, line);
3975 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3976 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
3978 uint256 const nftID = mintNFT();
3981 uint256 const minterOfferIndex =
3983 env(token::createOffer(minter, nftID, gwXAU(1000)),
3991 env(token::createOffer(buyer, nftID, gwXAU(1001)),
3992 token::owner(minter));
3996 env(token::brokerOffers(
3997 broker, buyOfferIndex, minterOfferIndex),
4003 env(token::cancelOffer(buyer, {buyOfferIndex}));
4010 env(token::createOffer(buyer, nftID, gwXAU(999)),
4011 token::owner(minter));
4015 env(token::brokerOffers(
4016 broker, buyOfferIndex, minterOfferIndex),
4022 env(token::cancelOffer(buyer, {buyOfferIndex}));
4029 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4030 token::owner(minter));
4034 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4035 token::brokerFee(gwXAU(0.1)),
4040 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
4047 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4048 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4049 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4050 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4053 env(token::burn(buyer, nftID));
4060 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4061 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4066 uint256 const minterOfferIndex =
4068 env(token::createOffer(minter, nftID, gwXAU(900)),
4075 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4076 token::owner(minter));
4080 env(token::brokerOffers(
4081 broker, buyOfferIndex, minterOfferIndex),
4087 env(token::cancelOffer(buyer, {buyOfferIndex}));
4094 env(token::createOffer(buyer, nftID, gwXAU(899)),
4095 token::owner(minter));
4099 env(token::brokerOffers(
4100 broker, buyOfferIndex, minterOfferIndex),
4106 env(token::cancelOffer(buyer, {buyOfferIndex}));
4112 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4113 token::owner(minter));
4118 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4119 token::brokerFee(gwXAU(101)),
4125 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4126 token::brokerFee(gwXAU(100)));
4133 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4134 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4135 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4136 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4139 env(token::burn(buyer, nftID));
4146 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4147 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4152 uint256 const minterOfferIndex =
4154 env(token::createOffer(minter, nftID, gwXAU(900)),
4161 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4162 token::owner(minter));
4168 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4169 token::brokerFee(gwXAU(50)));
4176 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4177 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4178 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4179 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4182 env(token::burn(buyer, nftID));
4191 testcase(
"NFToken offer owner");
4193 using namespace test::jtx;
4195 Env env{*
this, features};
4197 Account
const issuer{
"issuer"};
4198 Account
const buyer1{
"buyer1"};
4199 Account
const buyer2{
"buyer2"};
4200 env.fund(XRP(10000), issuer, buyer1, buyer2);
4209 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4210 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4211 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4214 uint256 const buyer1OfferIndex =
4216 env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer));
4217 uint256 const buyer2OfferIndex =
4219 env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer));
4229 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4231 if (buyOffers.
isMember(jss::result) &&
4232 buyOffers[jss::result].
isMember(jss::offers))
4233 return buyOffers[jss::result][jss::offers].
size();
4239 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4242 env(token::acceptBuyOffer(issuer, buyer1OfferIndex));
4246 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4247 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4248 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4252 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4256 env(token::acceptBuyOffer(buyer1, buyer2OfferIndex));
4260 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4261 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4262 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4265 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4272 testcase(
"NFToken transactions with tickets");
4274 using namespace test::jtx;
4276 Env env{*
this, features};
4278 Account
const issuer{
"issuer"};
4279 Account
const buyer{
"buyer"};
4280 env.fund(XRP(10000), issuer, buyer);
4287 env(ticket::create(issuer, 10));
4293 env(ticket::create(buyer, 10));
4301 env(token::mint(issuer, 0u),
4303 ticket::use(issuerTicketSeq++));
4311 env(token::createOffer(buyer, nftId, XRP(1)),
4312 token::owner(issuer),
4313 ticket::use(buyerTicketSeq++));
4319 env(token::cancelOffer(buyer, {offerIndex0}),
4320 ticket::use(buyerTicketSeq++));
4327 env(token::createOffer(buyer, nftId, XRP(2)),
4328 token::owner(issuer),
4329 ticket::use(buyerTicketSeq++));
4335 env(token::acceptBuyOffer(issuer, offerIndex1),
4336 ticket::use(issuerTicketSeq++));
4343 env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4350 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4351 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4362 testcase(
"NFToken delete account");
4364 using namespace test::jtx;
4366 Env env{*
this, features};
4368 Account
const issuer{
"issuer"};
4369 Account
const minter{
"minter"};
4370 Account
const becky{
"becky"};
4371 Account
const carla{
"carla"};
4372 Account
const daria{
"daria"};
4374 env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4378 for (
int i = 0; i < 300; ++i)
4381 env(token::setMinter(issuer, minter));
4385 env(token::mint(minter, 0u),
4386 token::issuer(issuer),
4399 for (
int i = 0; i < 15; ++i)
4403 env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4406 uint256 const carlaOfferIndex =
4408 env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4413 env(acctdelete(becky, daria), fee(XRP(50)));
4417 env(token::acceptBuyOffer(minter, carlaOfferIndex));
4422 env(acctdelete(minter, daria), fee(XRP(50)));
4434 for (
int i = 0; i < 15; ++i)
4439 env(token::burn(carla, nftId));
4442 env(acctdelete(issuer, daria), fee(XRP(50)));
4443 env(acctdelete(carla, daria), fee(XRP(50)));
4450 testcase(
"nft_buy_offers and nft_sell_offers");
4459 using namespace test::jtx;
4461 Env env{*
this, features};
4463 Account
const issuer{
"issuer"};
4464 Account
const buyer{
"buyer"};
4467 env.fund(XRP(1000000), issuer, buyer);
4476 auto checkOffers = [
this, &env, &nftID](
4477 char const* request,
4479 int expectMarkerCount,
4481 int markerCount = 0;
4488 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4492 if (!marker.
empty())
4493 params[jss::marker] = marker;
4494 return env.rpc(
"json", request,
to_string(params));
4498 if (expectCount == 0)
4502 "expected \"result\"",
4507 nftOffers[jss::result].isMember(jss::error),
4508 "expected \"error\"",
4513 nftOffers[jss::result][jss::error].asString() ==
4515 "expected \"objectNotFound\"",
4526 "expected \"result\"",
4535 marker = result[jss::marker].
asString();
4540 "expected \"offers\"",
4546 allOffers.
append(someOffers[i]);
4549 }
while (!marker.
empty());
4553 allOffers.
size() == expectCount,
4554 "Unexpected returned offer count",
4558 markerCount == expectMarkerCount,
4559 "Unexpected marker count",
4569 globalFlags = offer[jss::flags].asInt();
4572 *globalFlags == offer[jss::flags].asInt(),
4573 "Inconsistent flags returned",
4579 offerIndexes.
insert(offer[jss::nft_offer_index].asString());
4580 amounts.
insert(offer[jss::amount].asString());
4584 offerIndexes.
size() == expectCount,
4585 "Duplicate indexes returned?",
4589 amounts.
size() == expectCount,
4590 "Duplicate amounts returned?",
4596 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4600 auto makeSellOffers =
4601 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4604 while (sellPrice < limit)
4606 sellPrice += XRP(1);
4607 env(token::createOffer(issuer, nftID, sellPrice),
4609 if (++offerCount % 10 == 0)
4616 makeSellOffers(XRP(1));
4617 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4620 makeSellOffers(XRP(250));
4621 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4624 makeSellOffers(XRP(251));
4625 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4628 makeSellOffers(XRP(500));
4629 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4632 makeSellOffers(XRP(501));
4633 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4636 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4640 auto makeBuyOffers =
4641 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4644 while (buyPrice < limit)
4647 env(token::createOffer(buyer, nftID, buyPrice),
4648 token::owner(issuer));
4649 if (++offerCount % 10 == 0)
4656 makeBuyOffers(XRP(1));
4657 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4660 makeBuyOffers(XRP(250));
4661 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4664 makeBuyOffers(XRP(251));
4665 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4668 makeBuyOffers(XRP(500));
4669 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4672 makeBuyOffers(XRP(501));
4673 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4680 using namespace test::jtx;
4682 testcase(
"fixNFTokenNegOffer");
4684 Account
const issuer{
"issuer"};
4685 Account
const buyer{
"buyer"};
4686 Account
const gw{
"gw"};
4687 IOU
const gwXAU(gw[
"XAU"]);
4690 for (
auto const& tweakedFeatures :
4697 Env env{*
this, tweakedFeatures};
4699 env.fund(XRP(1000000), issuer, buyer, gw);
4702 env(trust(issuer, gwXAU(2000)));
4703 env(trust(buyer, gwXAU(2000)));
4706 env(pay(gw, issuer, gwXAU(1000)));
4707 env(pay(gw, buyer, gwXAU(1000)));
4727 uint256 const sellNegXrpOfferIndex =
4729 env(token::createOffer(issuer, nftID0, XRP(-2)),
4731 ter(offerCreateTER));
4734 uint256 const sellNegIouOfferIndex =
4736 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
4738 ter(offerCreateTER));
4741 uint256 const buyNegXrpOfferIndex =
4743 env(token::createOffer(buyer, nftID0, XRP(-1)),
4744 token::owner(issuer),
4745 ter(offerCreateTER));
4748 uint256 const buyNegIouOfferIndex =
4750 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
4751 token::owner(issuer),
4752 ter(offerCreateTER));
4764 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
4765 ter(offerAcceptTER));
4767 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
4768 ter(offerAcceptTER));
4772 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
4773 ter(offerAcceptTER));
4775 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
4776 ter(offerAcceptTER));
4787 env(token::brokerOffers(
4788 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
4789 ter(offerAcceptTER));
4791 env(token::brokerOffers(
4792 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
4793 ter(offerAcceptTER));
4805 env.fund(XRP(1000000), issuer, buyer, gw);
4808 env(trust(issuer, gwXAU(2000)));
4809 env(trust(buyer, gwXAU(2000)));
4812 env(pay(gw, issuer, gwXAU(1000)));
4813 env(pay(gw, buyer, gwXAU(1000)));
4829 uint256 const sellNegXrpOfferIndex =
4831 env(token::createOffer(issuer, nftID0, XRP(-2)),
4835 uint256 const sellNegIouOfferIndex =
4837 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
4841 uint256 const buyNegXrpOfferIndex =
4843 env(token::createOffer(buyer, nftID0, XRP(-1)),
4844 token::owner(issuer));
4847 uint256 const buyNegIouOfferIndex =
4849 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
4850 token::owner(issuer));
4859 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
4862 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
4867 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
4870 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
4875 env(token::brokerOffers(
4876 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
4879 env(token::brokerOffers(
4880 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
4887 for (
auto const& tweakedFeatures :
4891 Env env{*
this, tweakedFeatures};
4893 env.fund(XRP(1000000), issuer, buyer);
4905 env(token::createOffer(buyer, nftID, drops(1)),
4906 token::owner(issuer),
4907 token::destination(issuer),
4908 ter(offerCreateTER));
4947 using namespace test::jtx;