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)),
1135 env(token::acceptBuyOffer(buyer, missingOfferIndex),
1141 env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1146 env(token::acceptSellOffer(buyer, missingOfferIndex),
1152 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1161 env(trust(alice, gwAUD(1000)));
1162 env(trust(buyer, gwAUD(1000)));
1164 env(pay(gw, buyer, gwAUD(30)));
1173 uint256 const buyerOfferIndex =
1175 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)),
1176 token::owner(alice));
1181 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1187 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1194 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1200 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1206 uint256 const buyerOfferIndex =
1208 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)),
1209 token::owner(alice));
1215 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1216 token::brokerFee(XRP(40)),
1222 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1223 token::brokerFee(gwAUD(31)),
1230 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1231 token::brokerFee(gwAUD(1.5)),
1237 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1245 uint256 const buyerOfferIndex =
1247 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)),
1248 token::owner(alice));
1253 env(token::acceptBuyOffer(buyer, plainOfferIndex),
1259 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1265 env(pay(buyer, gw, gwAUD(30)));
1267 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1268 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1277 env(token::createOffer(alice, nftAlice0ID, XRP(0)),
1280 env(token::acceptSellOffer(gw, offerIndex));
1284 env(pay(gw, buyer, gwAUD(30)));
1288 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1294 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1302 uint256 const buyerOfferIndex =
1304 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)),
1305 token::owner(alice));
1310 env(token::acceptSellOffer(alice, buyerOfferIndex),
1316 env(token::acceptSellOffer(alice, plainOfferIndex),
1323 env(token::acceptSellOffer(buyer, plainOfferIndex),
1334 env(token::createOffer(gw, nftAlice0ID, XRP(0)),
1337 env(token::acceptSellOffer(alice, offerIndex));
1341 env(pay(buyer, gw, gwAUD(30)));
1343 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1344 env(token::acceptSellOffer(buyer, audOfferIndex),
1361 testcase(
"Mint flagBurnable");
1363 using namespace test::jtx;
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"};
1371 env.fund(XRP(1000), alice, buyer, minter1, minter2);
1376 env(token::setMinter(alice, minter1));
1383 auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1385 uint256 const nftID{token::getNextID(env, alice, 0u, flags)};
1386 env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags));
1391 env(token::createOffer(minter1, nftID, XRP(0)),
1395 env(token::acceptSellOffer(buyer, offerIndex));
1403 uint256 const noBurnID = nftToBuyer(0);
1404 env(token::burn(alice, noBurnID),
1405 token::owner(buyer),
1408 env(token::burn(minter1, noBurnID),
1409 token::owner(buyer),
1412 env(token::burn(minter2, noBurnID),
1413 token::owner(buyer),
1418 env(token::burn(buyer, noBurnID), token::owner(buyer));
1425 env(token::burn(minter2, burnableID),
1426 token::owner(buyer),
1431 env(token::burn(alice, burnableID), token::owner(buyer));
1439 env(token::burn(buyer, burnableID));
1447 env(token::burn(buyer, burnableID), token::owner(buyer));
1457 env(token::setMinter(alice, minter2));
1462 env(token::burn(minter1, burnableID),
1463 token::owner(buyer),
1469 env(token::burn(minter2, burnableID), token::owner(buyer));
1479 testcase(
"Mint flagOnlyXRP");
1481 using namespace test::jtx;
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"]);
1490 env.fund(XRP(1000), alice, buyer, gw);
1492 env(trust(alice, gwAUD(1000)));
1493 env(trust(buyer, gwAUD(1000)));
1495 env(pay(gw, buyer, gwAUD(100)));
1505 uint256 const aliceOfferIndex =
1507 env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)),
1513 uint256 const buyerOfferIndex =
1515 env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)),
1516 token::owner(alice));
1521 env(token::cancelOffer(alice, {aliceOfferIndex}));
1522 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1528 env(token::burn(alice, nftIOUsOkayID));
1541 env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)),
1548 env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)),
1549 token::owner(alice),
1556 env(token::createOffer(alice, nftOnlyXRPID, XRP(60)),
1562 env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)),
1563 token::owner(alice));
1573 testcase(
"Mint flagCreateTrustLines");
1575 using namespace test::jtx;
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"]);
1586 env.fund(XRP(1000), alice, becky, cheri, gw);
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)));
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)));
1608 uint256 const nftNoAutoTrustID{
1610 env(token::mint(alice, 0u),
1611 token::xferFee(xferFee),
1616 uint256 const beckyBuyOfferIndex =
1618 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1619 token::owner(alice));
1621 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1625 TER const createOfferTER =
1627 uint256 const beckyOfferIndex =
1629 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1631 ter(createOfferTER));
1635 uint256 const cheriOfferIndex =
1637 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1638 token::owner(becky),
1639 ter(createOfferTER));
1643 env(token::cancelOffer(becky, {beckyOfferIndex}));
1644 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1652 uint256 const nftAutoTrustID{token::getNextID(
1654 env(token::mint(alice, 0u),
1655 token::xferFee(transferFee),
1660 uint256 const beckyBuyOfferIndex =
1662 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1663 token::owner(alice));
1665 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1669 uint256 const beckySellOfferIndex =
1671 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1674 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1678 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1681 uint256 const beckyBuyBackOfferIndex =
1683 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1684 token::owner(cheri));
1686 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1690 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1691 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1697 uint256 const nftNoAutoTrustID{
1699 env(token::mint(alice, 0u),
1700 token::xferFee(transferFee),
1705 uint256 const aliceSellOfferIndex =
1707 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1710 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1716 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1719 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1723 uint256 const cheriSellOfferIndex =
1725 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1728 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1734 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1742 testcase(
"Mint flagTransferable");
1744 using namespace test::jtx;
1746 Env env{*
this, features};
1748 Account
const alice{
"alice"};
1749 Account
const becky{
"becky"};
1750 Account
const minter{
"minter"};
1752 env.fund(XRP(1000), alice, becky, minter);
1758 uint256 const nftAliceNoTransferID{
1759 token::getNextID(env, alice, 0u)};
1760 env(token::mint(alice, 0u), token::xferFee(0));
1766 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1767 token::owner(alice),
1771 uint256 const aliceSellOfferIndex =
1773 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1776 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1782 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1791 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1793 token::destination(alice),
1801 uint256 const aliceBuyOfferIndex =
1803 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1804 token::owner(becky));
1806 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1812 env(token::burn(alice, nftAliceNoTransferID));
1819 env(token::setMinter(alice, minter));
1823 uint256 const nftMinterNoTransferID{
1824 token::getNextID(env, alice, 0u)};
1825 env(token::mint(minter), token::issuer(alice));
1831 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1832 token::owner(minter),
1838 env(token::clearMinter(alice));
1843 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1851 for (
int i = 0; i < 10; ++i)
1854 env(token::setMinter(alice, minter));
1860 uint256 const minterSellOfferIndex =
1862 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1869 env(token::clearMinter(alice));
1875 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1881 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1889 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1890 token::owner(becky),
1897 uint256 const aliceBuyOfferIndex =
1899 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1900 token::owner(becky));
1906 for (
int i = 0; i < 10; ++i)
1909 env(token::setMinter(alice, minter));
1914 uint256 const minterBuyOfferIndex =
1916 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1917 token::owner(becky));
1923 env(token::clearMinter(alice));
1929 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1937 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
1939 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1956 uint256 const aliceSellOfferIndex =
1958 env(token::createOffer(alice, nftAliceID, XRP(20)),
1963 uint256 const beckyBuyOfferIndex =
1965 env(token::createOffer(becky, nftAliceID, XRP(21)),
1966 token::owner(alice));
1971 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1977 uint256 const beckySellOfferIndex =
1979 env(token::createOffer(becky, nftAliceID, XRP(22)),
1987 env(token::acceptSellOffer(minter, beckySellOfferIndex));
1994 uint256 const minterSellOfferIndex =
1996 env(token::createOffer(minter, nftAliceID, XRP(23)),
2004 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2012 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2020 env(token::burn(becky, nftAliceID));
2032 testcase(
"Mint transferFee");
2034 using namespace test::jtx;
2036 Env env{*
this, features};
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"]);
2045 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2048 env(trust(alice, gwXAU(2000)));
2049 env(trust(becky, gwXAU(2000)));
2050 env(trust(carol, gwXAU(2000)));
2051 env(trust(minter, gwXAU(2000)));
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)));
2061 env(token::setMinter(alice, minter));
2078 uint256 const beckyBuyOfferIndex =
2080 env(token::createOffer(becky, nftID, gwXAU(10)),
2081 token::owner(alice));
2083 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2084 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2086 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2088 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2089 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2092 uint256 const beckySellOfferIndex =
2094 env(token::createOffer(becky, nftID, gwXAU(10)),
2097 env(token::acceptSellOffer(carol, beckySellOfferIndex));
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));
2104 uint256 const minterBuyOfferIndex =
2106 env(token::createOffer(minter, nftID, gwXAU(10)),
2107 token::owner(carol));
2109 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
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));
2118 uint256 const minterSellOfferIndex =
2120 env(token::createOffer(minter, nftID, gwXAU(10)),
2123 env(token::acceptSellOffer(alice, minterSellOfferIndex));
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));
2131 env(token::burn(alice, nftID));
2144 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2148 uint256 const beckyBuyOfferIndex =
2150 env(token::createOffer(becky, nftID, gwXAU(10)),
2151 token::owner(alice));
2153 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2154 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2156 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2158 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2159 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2162 uint256 const beckySellOfferIndex =
2164 env(token::createOffer(becky, nftID, gwXAU(10)),
2167 env(token::acceptSellOffer(carol, beckySellOfferIndex));
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));
2175 uint256 const minterBuyOfferIndex =
2177 env(token::createOffer(minter, nftID, gwXAU(10)),
2178 token::owner(carol));
2180 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
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));
2190 uint256 const minterSellOfferIndex =
2192 env(token::createOffer(minter, nftID, gwXAU(10)),
2195 env(token::acceptSellOffer(alice, minterSellOfferIndex));
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));
2204 env(pay(alice, becky, gwXAU(0.0001)));
2205 env(pay(alice, carol, gwXAU(0.0001)));
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));
2214 env(token::burn(alice, nftID));
2225 env(token::mint(alice),
2232 uint256 const nftID = token::getNextID(
2234 env(token::mint(alice),
2240 uint256 const beckyBuyOfferIndex =
2242 env(token::createOffer(becky, nftID, gwXAU(10)),
2243 token::owner(alice));
2245 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2246 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2248 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2250 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2251 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2254 uint256 const beckySellOfferIndex =
2256 env(token::createOffer(becky, nftID, gwXAU(100)),
2259 env(token::acceptSellOffer(minter, beckySellOfferIndex));
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));
2267 uint256 const carolBuyOfferIndex =
2269 env(token::createOffer(carol, nftID, gwXAU(10)),
2270 token::owner(minter));
2272 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
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));
2282 uint256 const carolSellOfferIndex =
2284 env(token::createOffer(carol, nftID, gwXAU(10)),
2287 env(token::acceptSellOffer(alice, carolSellOfferIndex));
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));
2296 env(pay(alice, minter, gwXAU(55)));
2297 env(pay(becky, minter, gwXAU(40)));
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));
2305 env(token::burn(alice, nftID));
2319 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2325 STAmount aliceBalance = env.balance(alice);
2326 STAmount minterBalance = env.balance(minter);
2327 uint256 const minterBuyOfferIndex =
2329 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2331 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2333 aliceBalance += XRP(1) - fee;
2334 minterBalance -= XRP(1) + fee;
2335 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2336 BEAST_EXPECT(env.balance(minter) == minterBalance);
2340 STAmount carolBalance = env.balance(carol);
2341 uint256 const minterSellOfferIndex =
2343 env(token::createOffer(minter, nftID, drops(99999)),
2346 env(token::acceptSellOffer(carol, minterSellOfferIndex));
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);
2356 STAmount beckyBalance = env.balance(becky);
2357 uint256 const beckyBuyOfferIndex =
2359 env(token::createOffer(becky, nftID, drops(100000)),
2360 token::owner(carol));
2362 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2364 carolBalance += drops(99999) - fee;
2365 beckyBalance -= drops(100000) + fee;
2366 aliceBalance += drops(1);
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);
2380 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
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)));
2393 env(pay(gw, alice, startXAUBalance));
2394 env(pay(gw, minter, startXAUBalance));
2395 env(pay(gw, becky, startXAUBalance));
2404 STAmount aliceBalance = env.balance(alice, gwXAU);
2405 STAmount minterBalance = env.balance(minter, gwXAU);
2406 uint256 const minterBuyOfferIndex =
2408 env(token::createOffer(minter, nftID, tinyXAU),
2409 token::owner(alice));
2411 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2413 aliceBalance += tinyXAU;
2414 minterBalance -= tinyXAU;
2415 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2416 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2419 STAmount carolBalance = env.balance(carol, gwXAU);
2420 uint256 const minterSellOfferIndex =
2422 env(token::createOffer(minter, nftID, tinyXAU),
2425 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2428 minterBalance += tinyXAU;
2429 carolBalance -= tinyXAU;
2431 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2432 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2433 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2440 STAmount beckyBalance = env.balance(becky, gwXAU);
2441 uint256 const beckyBuyOfferIndex =
2443 env(token::createOffer(becky, nftID, cheapNFT),
2444 token::owner(carol));
2446 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
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);
2463 testcase(
"Mint taxon");
2465 using namespace test::jtx;
2467 Env env{*
this, features};
2469 Account
const alice{
"alice"};
2470 Account
const becky{
"becky"};
2472 env.fund(XRP(1000), alice, becky);
2481 uint256 const nftID = token::getNextID(env, alice, 0u);
2488 uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2496 for (
int i = 0; i < 10; ++i)
2506 ss <<
"Taxon recovery failed from nftID "
2507 <<
to_string(nftID) <<
". Expected: " << taxon
2508 <<
"; got: " << gotTaxon;
2513 uint256 const nftAliceID = token::getID(
2516 rand_int<std::uint32_t>(),
2517 rand_int<std::uint16_t>(),
2518 rand_int<std::uint16_t>());
2519 check(taxon, nftAliceID);
2521 uint256 const nftBeckyID = token::getID(
2524 rand_int<std::uint32_t>(),
2525 rand_int<std::uint16_t>(),
2526 rand_int<std::uint16_t>());
2527 check(taxon, nftBeckyID);
2539 testcase(
"Mint URI");
2541 using namespace test::jtx;
2543 Env env{*
this, features};
2545 Account
const alice{
"alice"};
2546 Account
const becky{
"becky"};
2548 env.fund(XRP(10000), alice, becky);
2554 auto randURI = []() {
2576 : uri(std::move(uri_)), taxon(taxon_)
2584 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2587 for (Entry
const& entry : entries)
2589 if (entry.uri.empty())
2591 env(token::mint(alice, entry.taxon));
2595 env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2603 params[jss::account] = alice.human();
2604 params[jss::type] =
"state";
2605 return env.rpc(
"json",
"account_nfts",
to_string(params));
2609 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2610 if (!BEAST_EXPECT(nfts.
size() == entries.size()))
2623 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2628 Entry
const& entry = entries[i];
2631 if (entry.uri.empty())
2646 testcase(
"Create offer destination");
2648 using namespace test::jtx;
2650 Env env{*
this, features};
2652 Account
const issuer{
"issuer"};
2653 Account
const minter{
"minter"};
2654 Account
const buyer{
"buyer"};
2655 Account
const broker{
"broker"};
2657 env.fund(XRP(1000), issuer, minter, buyer, broker);
2661 env(token::setMinter(issuer, minter));
2666 env(token::mint(minter, 0),
2667 token::issuer(issuer),
2674 uint256 const offerMinterToIssuer =
2676 env(token::createOffer(minter, nftokenID, drops(1)),
2677 token::destination(issuer),
2680 uint256 const offerMinterToBuyer =
2682 env(token::createOffer(minter, nftokenID, drops(1)),
2683 token::destination(buyer),
2686 uint256 const offerIssuerToMinter =
2688 env(token::createOffer(issuer, nftokenID, drops(1)),
2689 token::owner(minter),
2690 token::destination(minter));
2692 uint256 const offerIssuerToBuyer =
2694 env(token::createOffer(issuer, nftokenID, drops(1)),
2695 token::owner(minter),
2696 token::destination(buyer));
2710 env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2712 env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2714 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2716 env(token::cancelOffer(minter, {offerIssuerToBuyer}),
2725 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2726 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2727 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2728 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2738 uint256 const offerMinterSellsToBuyer =
2740 env(token::createOffer(minter, nftokenID, drops(1)),
2741 token::destination(buyer),
2750 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer),
2758 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2768 uint256 const offerMinterBuysFromBuyer =
2770 env(token::createOffer(minter, nftokenID, drops(1)),
2771 token::owner(buyer),
2772 token::destination(buyer));
2780 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer),
2788 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2797 uint256 const offerBuyerBuysFromMinter =
2799 env(token::createOffer(buyer, nftokenID, drops(1)),
2800 token::owner(minter),
2801 token::destination(broker));
2807 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter),
2812 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2822 uint256 const offerMinterToBroker =
2824 env(token::createOffer(minter, nftokenID, drops(1)),
2825 token::destination(broker),
2828 uint256 const offerBuyerToMinter =
2830 env(token::createOffer(buyer, nftokenID, drops(1)),
2831 token::owner(minter));
2840 env(token::brokerOffers(
2841 issuer, offerBuyerToMinter, offerMinterToBroker),
2850 env(token::brokerOffers(
2851 broker, offerBuyerToMinter, offerMinterToBroker));
2862 uint256 const offerBuyerToMinter =
2864 env(token::createOffer(buyer, nftokenID, drops(1)),
2865 token::destination(minter),
2868 uint256 const offerMinterToBuyer =
2870 env(token::createOffer(minter, nftokenID, drops(1)),
2871 token::owner(buyer));
2873 uint256 const offerIssuerToBuyer =
2875 env(token::createOffer(issuer, nftokenID, drops(1)),
2876 token::owner(buyer));
2884 env(token::brokerOffers(
2885 broker, offerIssuerToBuyer, offerBuyerToMinter),
2893 env(token::brokerOffers(
2894 broker, offerMinterToBuyer, offerBuyerToMinter));
2901 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2911 uint256 const offerMinterToBroker =
2913 env(token::createOffer(minter, nftokenID, drops(1)),
2914 token::destination(broker),
2917 uint256 const offerBuyerToBroker =
2919 env(token::createOffer(buyer, nftokenID, drops(1)),
2920 token::owner(minter),
2921 token::destination(broker));
2925 env(token::brokerOffers(
2926 issuer, offerBuyerToBroker, offerMinterToBroker),
2934 env(token::brokerOffers(
2935 broker, offerBuyerToBroker, offerMinterToBroker));
2947 testcase(
"Create offer expiration");
2949 using namespace test::jtx;
2951 Env env{*
this, features};
2953 Account
const issuer{
"issuer"};
2954 Account
const minter{
"minter"};
2955 Account
const buyer{
"buyer"};
2957 env.fund(XRP(1000), issuer, minter, buyer);
2961 env(token::setMinter(issuer, minter));
2966 env(token::mint(minter, 0),
2967 token::issuer(issuer),
2973 env(token::mint(minter, 0),
2974 token::issuer(issuer),
2983 uint256 const offerMinterToIssuer =
2985 env(token::createOffer(minter, nftokenID0, drops(1)),
2986 token::destination(issuer),
2987 token::expiration(expiration),
2990 uint256 const offerMinterToAnyone =
2992 env(token::createOffer(minter, nftokenID0, drops(1)),
2993 token::expiration(expiration),
2996 uint256 const offerIssuerToMinter =
2998 env(token::createOffer(issuer, nftokenID0, drops(1)),
2999 token::owner(minter),
3000 token::expiration(expiration));
3002 uint256 const offerBuyerToMinter =
3004 env(token::createOffer(buyer, nftokenID0, drops(1)),
3005 token::owner(minter),
3006 token::expiration(expiration));
3018 env(token::cancelOffer(issuer, {offerMinterToAnyone}),
3020 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
3023 BEAST_EXPECT(
lastClose(env) < expiration);
3029 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3033 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3044 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3045 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3060 env(token::createOffer(minter, nftokenID0, drops(1)),
3061 token::expiration(expiration),
3066 env(token::createOffer(minter, nftokenID1, drops(1)),
3067 token::expiration(expiration),
3070 BEAST_EXPECT(
lastClose(env) < expiration);
3076 env(token::acceptSellOffer(buyer, offer0));
3087 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3088 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3097 env(token::cancelOffer(issuer, {offer1}));
3107 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3109 token::destination(minter));
3111 env(token::acceptSellOffer(minter, offerSellBack));
3125 env(token::createOffer(buyer, nftokenID0, drops(1)),
3126 token::owner(minter),
3127 token::expiration(expiration));
3130 env(token::createOffer(buyer, nftokenID1, drops(1)),
3131 token::owner(minter),
3132 token::expiration(expiration));
3134 BEAST_EXPECT(
lastClose(env) < expiration);
3140 env(token::acceptBuyOffer(minter, offer0));
3151 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3152 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3161 env(token::cancelOffer(issuer, {offer1}));
3171 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3173 token::destination(minter));
3175 env(token::acceptSellOffer(minter, offerSellBack));
3190 env(token::createOffer(minter, nftokenID0, drops(1)),
3191 token::expiration(expiration),
3196 env(token::createOffer(minter, nftokenID1, drops(1)),
3197 token::expiration(expiration),
3202 env(token::createOffer(buyer, nftokenID0, drops(1)),
3203 token::owner(minter));
3207 env(token::createOffer(buyer, nftokenID1, drops(1)),
3208 token::owner(minter));
3211 BEAST_EXPECT(
lastClose(env) < expiration);
3217 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3228 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3238 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3248 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3250 token::destination(minter));
3252 env(token::acceptSellOffer(minter, offerSellBack));
3267 env(token::createOffer(minter, nftokenID0, drops(1)),
3272 env(token::createOffer(minter, nftokenID1, drops(1)),
3277 env(token::createOffer(buyer, nftokenID0, drops(1)),
3278 token::expiration(expiration),
3279 token::owner(minter));
3283 env(token::createOffer(buyer, nftokenID1, drops(1)),
3284 token::expiration(expiration),
3285 token::owner(minter));
3288 BEAST_EXPECT(
lastClose(env) < expiration);
3294 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3305 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3315 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3325 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3327 token::destination(minter));
3329 env(token::acceptSellOffer(minter, offerSellBack));
3345 env(token::createOffer(minter, nftokenID0, drops(1)),
3346 token::expiration(expiration),
3351 env(token::createOffer(minter, nftokenID1, drops(1)),
3352 token::expiration(expiration),
3357 env(token::createOffer(buyer, nftokenID0, drops(1)),
3358 token::expiration(expiration),
3359 token::owner(minter));
3363 env(token::createOffer(buyer, nftokenID1, drops(1)),
3364 token::expiration(expiration),
3365 token::owner(minter));
3368 BEAST_EXPECT(
lastClose(env) < expiration);
3374 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3385 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3395 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3405 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3407 token::destination(minter));
3409 env(token::acceptSellOffer(minter, offerSellBack));
3421 testcase(
"Cancel offers");
3423 using namespace test::jtx;
3425 Env env{*
this, features};
3427 Account
const alice(
"alice");
3428 Account
const becky(
"becky");
3429 Account
const minter(
"minter");
3430 env.fund(XRP(50000), alice, becky, minter);
3434 env(token::setMinter(alice, minter));
3443 uint256 const expiredOfferIndex =
3446 env(token::createOffer(alice, nftokenID, XRP(1000)),
3448 token::expiration(
lastClose(env) + 13));
3453 env(token::cancelOffer(becky, {expiredOfferIndex}),
3461 env(token::cancelOffer(becky, {expiredOfferIndex}));
3467 uint256 const dest1OfferIndex =
3470 env(token::createOffer(alice, nftokenID, XRP(1000)),
3471 token::destination(becky),
3477 env(token::cancelOffer(minter, {dest1OfferIndex}),
3482 env(token::cancelOffer(becky, {dest1OfferIndex}));
3487 uint256 const dest2OfferIndex =
3490 env(token::createOffer(alice, nftokenID, XRP(1000)),
3491 token::destination(becky),
3496 env(token::cancelOffer(alice, {dest2OfferIndex}));
3503 uint256 const mintersNFTokenID =
3505 env(token::mint(minter, 0),
3506 token::issuer(alice),
3510 uint256 const minterOfferIndex =
3513 env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3519 env(token::cancelOffer(alice, {minterOfferIndex}),
3521 env(token::cancelOffer(becky, {minterOfferIndex}),
3526 env(token::cancelOffer(minter, {minterOfferIndex}));
3535 testcase(
"Cancel too many offers");
3537 using namespace test::jtx;
3539 Env env{*
this, features};
3554 Account
const alice(
"alice");
3555 env.fund(XRP(1000), alice);
3564 Account
const offerAcct(
3566 env.fund(XRP(1000), nftAcct, offerAcct);
3571 env(token::mint(nftAcct, 0),
3578 env(token::createOffer(offerAcct, nftokenID, drops(1)),
3579 token::owner(nftAcct),
3588 for (
uint256 const& offerIndex : offerIndexes)
3595 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3599 env(token::cancelOffer(alice, {offerIndexes.back()}));
3604 offerIndexes.pop_back();
3610 env(token::mint(alice, 0),
3616 env(token::createOffer(alice, nftokenID, drops(1)),
3625 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3629 env(token::burn(alice, nftokenID));
3635 offerIndexes.pop_back();
3640 env(token::cancelOffer(alice, offerIndexes));
3644 for (
uint256 const& offerIndex : offerIndexes)
3654 testcase(
"Brokered NFT offer accept");
3656 using namespace test::jtx;
3658 Env env{*
this, features};
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"]);
3673 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3676 env(trust(issuer, gwXAU(2000)));
3677 env(trust(minter, gwXAU(2000)));
3678 env(trust(buyer, gwXAU(2000)));
3679 env(trust(broker, gwXAU(2000)));
3682 env(token::setMinter(issuer, minter));
3686 auto checkOwnerCountIsOne =
3691 for (Account
const& acct : accounts)
3697 ss <<
"Account " << acct.human()
3698 <<
" expected ownerCount == 1. Got " <<
ownerCount;
3699 fail(ss.
str(), __FILE__, line);
3705 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3708 env(token::mint(minter, 0),
3709 token::issuer(issuer),
3710 token::xferFee(xferFee),
3722 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3724 uint256 const nftID = mintNFT();
3727 uint256 const minterOfferIndex =
3729 env(token::createOffer(minter, nftID, XRP(0)),
3737 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
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);
3746 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
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);
3757 env(token::burn(buyer, nftID));
3767 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3769 uint256 const nftID = mintNFT();
3772 uint256 const minterOfferIndex =
3774 env(token::createOffer(minter, nftID, XRP(0)),
3782 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3786 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3787 token::brokerFee(XRP(1.1)),
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);
3797 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3798 token::brokerFee(XRP(0.5)));
3803 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3804 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3806 env.balance(broker) == brokerBalance + XRP(0.5) - drops(10));
3807 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3810 env(token::burn(buyer, nftID));
3820 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3825 uint256 const minterOfferIndex =
3827 env(token::createOffer(minter, nftID, XRP(0)),
3835 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
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);
3844 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
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));
3855 env(token::burn(buyer, nftID));
3865 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3870 uint256 const minterOfferIndex =
3872 env(token::createOffer(minter, nftID, XRP(0)),
3880 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
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);
3889 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3890 token::brokerFee(XRP(0.75)));
3896 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
3897 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3899 env.balance(broker) == brokerBalance + XRP(0.75) - drops(10));
3900 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
3903 env(token::burn(buyer, nftID));
3908 auto setXAUBalance_1000 =
3909 [
this, &gw, &gwXAU, &env](
3913 for (Account
const& acct : accounts)
3915 static const auto xau1000 = gwXAU(1000);
3916 auto const balance = env.balance(acct, gwXAU);
3917 if (balance < xau1000)
3919 env(pay(gw, acct, xau1000 - balance));
3922 else if (balance > xau1000)
3924 env(pay(acct, gw, balance - xau1000));
3927 if (env.balance(acct, gwXAU) != xau1000)
3930 ss <<
"Unable to set " << acct.human()
3931 <<
" account balance to gwXAU(1000)";
3932 this->fail(ss.
str(), __FILE__, line);
3940 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3941 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
3943 uint256 const nftID = mintNFT();
3946 uint256 const minterOfferIndex =
3948 env(token::createOffer(minter, nftID, gwXAU(1000)),
3956 env(token::createOffer(buyer, nftID, gwXAU(1001)),
3957 token::owner(minter));
3961 env(token::brokerOffers(
3962 broker, buyOfferIndex, minterOfferIndex),
3968 env(token::cancelOffer(buyer, {buyOfferIndex}));
3975 env(token::createOffer(buyer, nftID, gwXAU(999)),
3976 token::owner(minter));
3980 env(token::brokerOffers(
3981 broker, buyOfferIndex, minterOfferIndex),
3987 env(token::cancelOffer(buyer, {buyOfferIndex}));
3994 env(token::createOffer(buyer, nftID, gwXAU(1000)),
3995 token::owner(minter));
3999 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4000 token::brokerFee(gwXAU(0.1)),
4005 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
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));
4018 env(token::burn(buyer, nftID));
4025 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4026 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4031 uint256 const minterOfferIndex =
4033 env(token::createOffer(minter, nftID, gwXAU(900)),
4040 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4041 token::owner(minter));
4045 env(token::brokerOffers(
4046 broker, buyOfferIndex, minterOfferIndex),
4052 env(token::cancelOffer(buyer, {buyOfferIndex}));
4059 env(token::createOffer(buyer, nftID, gwXAU(899)),
4060 token::owner(minter));
4064 env(token::brokerOffers(
4065 broker, buyOfferIndex, minterOfferIndex),
4071 env(token::cancelOffer(buyer, {buyOfferIndex}));
4077 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4078 token::owner(minter));
4083 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4084 token::brokerFee(gwXAU(101)),
4090 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4091 token::brokerFee(gwXAU(100)));
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));
4104 env(token::burn(buyer, nftID));
4111 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4112 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4117 uint256 const minterOfferIndex =
4119 env(token::createOffer(minter, nftID, gwXAU(900)),
4126 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4127 token::owner(minter));
4133 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4134 token::brokerFee(gwXAU(50)));
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));
4147 env(token::burn(buyer, nftID));
4156 testcase(
"NFToken offer owner");
4158 using namespace test::jtx;
4160 Env env{*
this, features};
4162 Account
const issuer{
"issuer"};
4163 Account
const buyer1{
"buyer1"};
4164 Account
const buyer2{
"buyer2"};
4165 env.fund(XRP(10000), issuer, buyer1, buyer2);
4174 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4175 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4176 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4179 uint256 const buyer1OfferIndex =
4181 env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer));
4182 uint256 const buyer2OfferIndex =
4184 env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer));
4194 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4196 if (buyOffers.
isMember(jss::result) &&
4197 buyOffers[jss::result].
isMember(jss::offers))
4198 return buyOffers[jss::result][jss::offers].
size();
4204 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4207 env(token::acceptBuyOffer(issuer, buyer1OfferIndex));
4211 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4212 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4213 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4217 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4221 env(token::acceptBuyOffer(buyer1, buyer2OfferIndex));
4225 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4226 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4227 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4230 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4237 testcase(
"NFToken transactions with tickets");
4239 using namespace test::jtx;
4241 Env env{*
this, features};
4243 Account
const issuer{
"issuer"};
4244 Account
const buyer{
"buyer"};
4245 env.fund(XRP(10000), issuer, buyer);
4252 env(ticket::create(issuer, 10));
4258 env(ticket::create(buyer, 10));
4266 env(token::mint(issuer, 0u),
4268 ticket::use(issuerTicketSeq++));
4276 env(token::createOffer(buyer, nftId, XRP(1)),
4277 token::owner(issuer),
4278 ticket::use(buyerTicketSeq++));
4284 env(token::cancelOffer(buyer, {offerIndex0}),
4285 ticket::use(buyerTicketSeq++));
4292 env(token::createOffer(buyer, nftId, XRP(2)),
4293 token::owner(issuer),
4294 ticket::use(buyerTicketSeq++));
4300 env(token::acceptBuyOffer(issuer, offerIndex1),
4301 ticket::use(issuerTicketSeq++));
4308 env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4315 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4316 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4327 testcase(
"NFToken delete account");
4329 using namespace test::jtx;
4331 Env env{*
this, features};
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"};
4339 env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4343 for (
int i = 0; i < 300; ++i)
4346 env(token::setMinter(issuer, minter));
4350 env(token::mint(minter, 0u),
4351 token::issuer(issuer),
4364 for (
int i = 0; i < 15; ++i)
4368 env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4371 uint256 const carlaOfferIndex =
4373 env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4378 env(acctdelete(becky, daria), fee(XRP(50)));
4382 env(token::acceptBuyOffer(minter, carlaOfferIndex));
4387 env(acctdelete(minter, daria), fee(XRP(50)));
4399 for (
int i = 0; i < 15; ++i)
4404 env(token::burn(carla, nftId));
4407 env(acctdelete(issuer, daria), fee(XRP(50)));
4408 env(acctdelete(carla, daria), fee(XRP(50)));
4415 testcase(
"nft_buy_offers and nft_sell_offers");
4424 using namespace test::jtx;
4426 Env env{*
this, features};
4428 Account
const issuer{
"issuer"};
4429 Account
const buyer{
"buyer"};
4432 env.fund(XRP(1000000), issuer, buyer);
4441 auto checkOffers = [
this, &env, &nftID](
4442 char const* request,
4444 int expectMarkerCount,
4446 int markerCount = 0;
4453 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4457 if (!marker.
empty())
4458 params[jss::marker] = marker;
4459 return env.rpc(
"json", request,
to_string(params));
4463 if (expectCount == 0)
4467 "expected \"result\"",
4472 nftOffers[jss::result].isMember(jss::error),
4473 "expected \"error\"",
4478 nftOffers[jss::result][jss::error].asString() ==
4480 "expected \"objectNotFound\"",
4491 "expected \"result\"",
4500 marker = result[jss::marker].
asString();
4505 "expected \"offers\"",
4511 allOffers.
append(someOffers[i]);
4514 }
while (!marker.
empty());
4518 allOffers.
size() == expectCount,
4519 "Unexpected returned offer count",
4523 markerCount == expectMarkerCount,
4524 "Unexpected marker count",
4534 globalFlags = offer[jss::flags].asInt();
4537 *globalFlags == offer[jss::flags].asInt(),
4538 "Inconsistent flags returned",
4544 offerIndexes.
insert(offer[jss::nft_offer_index].asString());
4545 amounts.
insert(offer[jss::amount].asString());
4549 offerIndexes.
size() == expectCount,
4550 "Duplicate indexes returned?",
4554 amounts.
size() == expectCount,
4555 "Duplicate amounts returned?",
4561 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4565 auto makeSellOffers =
4566 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4569 while (sellPrice < limit)
4571 sellPrice += XRP(1);
4572 env(token::createOffer(issuer, nftID, sellPrice),
4574 if (++offerCount % 10 == 0)
4581 makeSellOffers(XRP(1));
4582 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4585 makeSellOffers(XRP(250));
4586 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4589 makeSellOffers(XRP(251));
4590 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4593 makeSellOffers(XRP(500));
4594 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4597 makeSellOffers(XRP(501));
4598 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4601 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4605 auto makeBuyOffers =
4606 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4609 while (buyPrice < limit)
4612 env(token::createOffer(buyer, nftID, buyPrice),
4613 token::owner(issuer));
4614 if (++offerCount % 10 == 0)
4621 makeBuyOffers(XRP(1));
4622 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4625 makeBuyOffers(XRP(250));
4626 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4629 makeBuyOffers(XRP(251));
4630 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4633 makeBuyOffers(XRP(500));
4634 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4637 makeBuyOffers(XRP(501));
4638 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4645 using namespace test::jtx;
4647 testcase(
"fixNFTokenNegOffer");
4649 Account
const issuer{
"issuer"};
4650 Account
const buyer{
"buyer"};
4651 Account
const gw{
"gw"};
4652 IOU
const gwXAU(gw[
"XAU"]);
4655 for (
auto const& tweakedFeatures :
4662 Env env{*
this, tweakedFeatures};
4664 env.fund(XRP(1000000), issuer, buyer, gw);
4667 env(trust(issuer, gwXAU(2000)));
4668 env(trust(buyer, gwXAU(2000)));
4671 env(pay(gw, issuer, gwXAU(1000)));
4672 env(pay(gw, buyer, gwXAU(1000)));
4692 uint256 const sellNegXrpOfferIndex =
4694 env(token::createOffer(issuer, nftID0, XRP(-2)),
4696 ter(offerCreateTER));
4699 uint256 const sellNegIouOfferIndex =
4701 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
4703 ter(offerCreateTER));
4706 uint256 const buyNegXrpOfferIndex =
4708 env(token::createOffer(buyer, nftID0, XRP(-1)),
4709 token::owner(issuer),
4710 ter(offerCreateTER));
4713 uint256 const buyNegIouOfferIndex =
4715 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
4716 token::owner(issuer),
4717 ter(offerCreateTER));
4729 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
4730 ter(offerAcceptTER));
4732 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
4733 ter(offerAcceptTER));
4737 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
4738 ter(offerAcceptTER));
4740 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
4741 ter(offerAcceptTER));
4752 env(token::brokerOffers(
4753 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
4754 ter(offerAcceptTER));
4756 env(token::brokerOffers(
4757 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
4758 ter(offerAcceptTER));
4770 env.fund(XRP(1000000), issuer, buyer, gw);
4773 env(trust(issuer, gwXAU(2000)));
4774 env(trust(buyer, gwXAU(2000)));
4777 env(pay(gw, issuer, gwXAU(1000)));
4778 env(pay(gw, buyer, gwXAU(1000)));
4794 uint256 const sellNegXrpOfferIndex =
4796 env(token::createOffer(issuer, nftID0, XRP(-2)),
4800 uint256 const sellNegIouOfferIndex =
4802 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
4806 uint256 const buyNegXrpOfferIndex =
4808 env(token::createOffer(buyer, nftID0, XRP(-1)),
4809 token::owner(issuer));
4812 uint256 const buyNegIouOfferIndex =
4814 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
4815 token::owner(issuer));
4824 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
4827 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
4832 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
4835 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
4840 env(token::brokerOffers(
4841 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
4844 env(token::brokerOffers(
4845 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
4852 for (
auto const& tweakedFeatures :
4856 Env env{*
this, tweakedFeatures};
4858 env.fund(XRP(1000000), issuer, buyer);
4870 env(token::createOffer(buyer, nftID, drops(1)),
4871 token::owner(issuer),
4872 token::destination(issuer),
4873 ter(offerCreateTER));
4912 using namespace test::jtx;