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 Account
const alice{
"alice"};
1578 Account
const becky{
"becky"};
1579 Account
const cheri{
"cheri"};
1580 Account
const gw(
"gw");
1581 IOU
const gwAUD(gw[
"AUD"]);
1582 IOU
const gwCAD(gw[
"CAD"]);
1583 IOU
const gwEUR(gw[
"EUR"]);
1588 for (
auto const& tweakedFeatures :
1592 Env env{*
this, tweakedFeatures};
1593 env.fund(XRP(1000), alice, becky, cheri, gw);
1597 env(trust(becky, gwAUD(1000)));
1598 env(trust(cheri, gwAUD(1000)));
1599 env(trust(becky, gwCAD(1000)));
1600 env(trust(cheri, gwCAD(1000)));
1601 env(trust(becky, gwEUR(1000)));
1602 env(trust(cheri, gwEUR(1000)));
1604 env(pay(gw, becky, gwAUD(500)));
1605 env(pay(gw, becky, gwCAD(500)));
1606 env(pay(gw, becky, gwEUR(500)));
1607 env(pay(gw, cheri, gwAUD(500)));
1608 env(pay(gw, cheri, gwCAD(500)));
1615 uint256 const nftNoAutoTrustID{
1617 env(token::mint(alice, 0u),
1618 token::xferFee(xferFee),
1623 uint256 const beckyBuyOfferIndex =
1625 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1626 token::owner(alice));
1628 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1632 TER const createOfferTER =
1634 uint256 const beckyOfferIndex =
1636 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1638 ter(createOfferTER));
1642 uint256 const cheriOfferIndex =
1644 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1645 token::owner(becky),
1646 ter(createOfferTER));
1650 env(token::cancelOffer(becky, {beckyOfferIndex}));
1651 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1659 uint256 const nftAutoTrustID{token::getNextID(
1670 env(token::mint(alice, 0u),
1671 token::xferFee(transferFee),
1682 uint256 const beckyBuyOfferIndex =
1684 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1685 token::owner(alice));
1687 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1691 uint256 const beckySellOfferIndex =
1693 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1696 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1700 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1703 uint256 const beckyBuyBackOfferIndex =
1705 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1706 token::owner(cheri));
1708 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1712 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1713 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1719 uint256 const nftNoAutoTrustID{token::getNextID(
1721 env(token::mint(alice, 0u),
1722 token::xferFee(transferFee),
1727 uint256 const aliceSellOfferIndex =
1729 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1732 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1738 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1741 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1745 uint256 const cheriSellOfferIndex =
1747 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1750 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1756 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1765 testcase(
"Mint flagTransferable");
1767 using namespace test::jtx;
1769 Env env{*
this, features};
1771 Account
const alice{
"alice"};
1772 Account
const becky{
"becky"};
1773 Account
const minter{
"minter"};
1775 env.fund(XRP(1000), alice, becky, minter);
1781 uint256 const nftAliceNoTransferID{
1782 token::getNextID(env, alice, 0u)};
1783 env(token::mint(alice, 0u), token::xferFee(0));
1789 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1790 token::owner(alice),
1794 uint256 const aliceSellOfferIndex =
1796 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1799 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1805 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1814 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1816 token::destination(alice),
1824 uint256 const aliceBuyOfferIndex =
1826 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1827 token::owner(becky));
1829 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1835 env(token::burn(alice, nftAliceNoTransferID));
1842 env(token::setMinter(alice, minter));
1846 uint256 const nftMinterNoTransferID{
1847 token::getNextID(env, alice, 0u)};
1848 env(token::mint(minter), token::issuer(alice));
1854 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1855 token::owner(minter),
1861 env(token::clearMinter(alice));
1866 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1874 for (
int i = 0; i < 10; ++i)
1877 env(token::setMinter(alice, minter));
1883 uint256 const minterSellOfferIndex =
1885 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1892 env(token::clearMinter(alice));
1898 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1904 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1912 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1913 token::owner(becky),
1920 uint256 const aliceBuyOfferIndex =
1922 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1923 token::owner(becky));
1929 for (
int i = 0; i < 10; ++i)
1932 env(token::setMinter(alice, minter));
1937 uint256 const minterBuyOfferIndex =
1939 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1940 token::owner(becky));
1946 env(token::clearMinter(alice));
1952 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1960 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
1962 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1979 uint256 const aliceSellOfferIndex =
1981 env(token::createOffer(alice, nftAliceID, XRP(20)),
1986 uint256 const beckyBuyOfferIndex =
1988 env(token::createOffer(becky, nftAliceID, XRP(21)),
1989 token::owner(alice));
1994 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
2000 uint256 const beckySellOfferIndex =
2002 env(token::createOffer(becky, nftAliceID, XRP(22)),
2010 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2017 uint256 const minterSellOfferIndex =
2019 env(token::createOffer(minter, nftAliceID, XRP(23)),
2027 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2035 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2043 env(token::burn(becky, nftAliceID));
2055 testcase(
"Mint transferFee");
2057 using namespace test::jtx;
2059 Env env{*
this, features};
2061 Account
const alice{
"alice"};
2062 Account
const becky{
"becky"};
2063 Account
const carol{
"carol"};
2064 Account
const minter{
"minter"};
2065 Account
const gw{
"gw"};
2066 IOU
const gwXAU(gw[
"XAU"]);
2068 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2071 env(trust(alice, gwXAU(2000)));
2072 env(trust(becky, gwXAU(2000)));
2073 env(trust(carol, gwXAU(2000)));
2074 env(trust(minter, gwXAU(2000)));
2076 env(pay(gw, alice, gwXAU(1000)));
2077 env(pay(gw, becky, gwXAU(1000)));
2078 env(pay(gw, carol, gwXAU(1000)));
2079 env(pay(gw, minter, gwXAU(1000)));
2084 env(token::setMinter(alice, minter));
2101 uint256 const beckyBuyOfferIndex =
2103 env(token::createOffer(becky, nftID, gwXAU(10)),
2104 token::owner(alice));
2106 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2107 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2109 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2111 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2112 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2115 uint256 const beckySellOfferIndex =
2117 env(token::createOffer(becky, nftID, gwXAU(10)),
2120 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2122 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2123 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2124 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2127 uint256 const minterBuyOfferIndex =
2129 env(token::createOffer(minter, nftID, gwXAU(10)),
2130 token::owner(carol));
2132 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
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(1000));
2137 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2141 uint256 const minterSellOfferIndex =
2143 env(token::createOffer(minter, nftID, gwXAU(10)),
2146 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2148 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2149 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2150 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2151 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2154 env(token::burn(alice, nftID));
2167 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2171 uint256 const beckyBuyOfferIndex =
2173 env(token::createOffer(becky, nftID, gwXAU(10)),
2174 token::owner(alice));
2176 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2177 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2179 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2181 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2182 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2185 uint256 const beckySellOfferIndex =
2187 env(token::createOffer(becky, nftID, gwXAU(10)),
2190 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2193 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2194 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2195 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2198 uint256 const minterBuyOfferIndex =
2200 env(token::createOffer(minter, nftID, gwXAU(10)),
2201 token::owner(carol));
2203 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2206 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2207 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2208 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2209 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2213 uint256 const minterSellOfferIndex =
2215 env(token::createOffer(minter, nftID, gwXAU(10)),
2218 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2220 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2221 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2222 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2223 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2227 env(pay(alice, becky, gwXAU(0.0001)));
2228 env(pay(alice, carol, gwXAU(0.0001)));
2231 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2232 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2233 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2234 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2237 env(token::burn(alice, nftID));
2248 env(token::mint(alice),
2255 uint256 const nftID = token::getNextID(
2257 env(token::mint(alice),
2263 uint256 const beckyBuyOfferIndex =
2265 env(token::createOffer(becky, nftID, gwXAU(10)),
2266 token::owner(alice));
2268 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2269 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2271 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2273 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2274 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2277 uint256 const beckySellOfferIndex =
2279 env(token::createOffer(becky, nftID, gwXAU(100)),
2282 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2285 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2286 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2287 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2290 uint256 const carolBuyOfferIndex =
2292 env(token::createOffer(carol, nftID, gwXAU(10)),
2293 token::owner(minter));
2295 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2298 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2299 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2300 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2301 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2305 uint256 const carolSellOfferIndex =
2307 env(token::createOffer(carol, nftID, gwXAU(10)),
2310 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2313 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2314 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2315 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2316 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2319 env(pay(alice, minter, gwXAU(55)));
2320 env(pay(becky, minter, gwXAU(40)));
2322 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2323 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2324 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2325 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2328 env(token::burn(alice, nftID));
2342 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2348 STAmount aliceBalance = env.balance(alice);
2349 STAmount minterBalance = env.balance(minter);
2350 uint256 const minterBuyOfferIndex =
2352 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2354 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2356 aliceBalance += XRP(1) - fee;
2357 minterBalance -= XRP(1) + fee;
2358 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2359 BEAST_EXPECT(env.balance(minter) == minterBalance);
2363 STAmount carolBalance = env.balance(carol);
2364 uint256 const minterSellOfferIndex =
2366 env(token::createOffer(minter, nftID, drops(99999)),
2369 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2371 minterBalance += drops(99999) - fee;
2372 carolBalance -= drops(99999) + fee;
2373 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2374 BEAST_EXPECT(env.balance(minter) == minterBalance);
2375 BEAST_EXPECT(env.balance(carol) == carolBalance);
2379 STAmount beckyBalance = env.balance(becky);
2380 uint256 const beckyBuyOfferIndex =
2382 env(token::createOffer(becky, nftID, drops(100000)),
2383 token::owner(carol));
2385 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2387 carolBalance += drops(99999) - fee;
2388 beckyBalance -= drops(100000) + fee;
2389 aliceBalance += drops(1);
2391 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2392 BEAST_EXPECT(env.balance(minter) == minterBalance);
2393 BEAST_EXPECT(env.balance(carol) == carolBalance);
2394 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2403 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2409 env(pay(alice, gw, env.balance(alice, gwXAU)));
2410 env(pay(minter, gw, env.balance(minter, gwXAU)));
2411 env(pay(becky, gw, env.balance(becky, gwXAU)));
2416 env(pay(gw, alice, startXAUBalance));
2417 env(pay(gw, minter, startXAUBalance));
2418 env(pay(gw, becky, startXAUBalance));
2427 STAmount aliceBalance = env.balance(alice, gwXAU);
2428 STAmount minterBalance = env.balance(minter, gwXAU);
2429 uint256 const minterBuyOfferIndex =
2431 env(token::createOffer(minter, nftID, tinyXAU),
2432 token::owner(alice));
2434 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2436 aliceBalance += tinyXAU;
2437 minterBalance -= tinyXAU;
2438 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2439 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2442 STAmount carolBalance = env.balance(carol, gwXAU);
2443 uint256 const minterSellOfferIndex =
2445 env(token::createOffer(minter, nftID, tinyXAU),
2448 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2451 minterBalance += tinyXAU;
2452 carolBalance -= tinyXAU;
2454 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2455 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2456 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2463 STAmount beckyBalance = env.balance(becky, gwXAU);
2464 uint256 const beckyBuyOfferIndex =
2466 env(token::createOffer(becky, nftID, cheapNFT),
2467 token::owner(carol));
2469 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2472 aliceBalance += tinyXAU;
2473 beckyBalance -= cheapNFT;
2474 carolBalance += cheapNFT - tinyXAU;
2475 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2476 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2477 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2478 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2486 testcase(
"Mint taxon");
2488 using namespace test::jtx;
2490 Env env{*
this, features};
2492 Account
const alice{
"alice"};
2493 Account
const becky{
"becky"};
2495 env.fund(XRP(1000), alice, becky);
2504 uint256 const nftID = token::getNextID(env, alice, 0u);
2511 uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2519 for (
int i = 0; i < 10; ++i)
2529 ss <<
"Taxon recovery failed from nftID "
2530 <<
to_string(nftID) <<
". Expected: " << taxon
2531 <<
"; got: " << gotTaxon;
2536 uint256 const nftAliceID = token::getID(
2539 rand_int<std::uint32_t>(),
2540 rand_int<std::uint16_t>(),
2541 rand_int<std::uint16_t>());
2542 check(taxon, nftAliceID);
2544 uint256 const nftBeckyID = token::getID(
2547 rand_int<std::uint32_t>(),
2548 rand_int<std::uint16_t>(),
2549 rand_int<std::uint16_t>());
2550 check(taxon, nftBeckyID);
2562 testcase(
"Mint URI");
2564 using namespace test::jtx;
2566 Env env{*
this, features};
2568 Account
const alice{
"alice"};
2569 Account
const becky{
"becky"};
2571 env.fund(XRP(10000), alice, becky);
2577 auto randURI = []() {
2599 : uri(std::move(uri_)), taxon(taxon_)
2607 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2610 for (Entry
const& entry : entries)
2612 if (entry.uri.empty())
2614 env(token::mint(alice, entry.taxon));
2618 env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2626 params[jss::account] = alice.human();
2627 params[jss::type] =
"state";
2628 return env.rpc(
"json",
"account_nfts",
to_string(params));
2632 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2633 if (!BEAST_EXPECT(nfts.
size() == entries.size()))
2646 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2651 Entry
const& entry = entries[i];
2654 if (entry.uri.empty())
2669 testcase(
"Create offer destination");
2671 using namespace test::jtx;
2673 Env env{*
this, features};
2675 Account
const issuer{
"issuer"};
2676 Account
const minter{
"minter"};
2677 Account
const buyer{
"buyer"};
2678 Account
const broker{
"broker"};
2680 env.fund(XRP(1000), issuer, minter, buyer, broker);
2684 env(token::setMinter(issuer, minter));
2689 env(token::mint(minter, 0),
2690 token::issuer(issuer),
2697 uint256 const offerMinterToIssuer =
2699 env(token::createOffer(minter, nftokenID, drops(1)),
2700 token::destination(issuer),
2703 uint256 const offerMinterToBuyer =
2705 env(token::createOffer(minter, nftokenID, drops(1)),
2706 token::destination(buyer),
2709 uint256 const offerIssuerToMinter =
2711 env(token::createOffer(issuer, nftokenID, drops(1)),
2712 token::owner(minter),
2713 token::destination(minter));
2715 uint256 const offerIssuerToBuyer =
2717 env(token::createOffer(issuer, nftokenID, drops(1)),
2718 token::owner(minter),
2719 token::destination(buyer));
2733 env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2735 env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2737 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2739 env(token::cancelOffer(minter, {offerIssuerToBuyer}),
2748 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2749 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2750 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2751 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2761 uint256 const offerMinterSellsToBuyer =
2763 env(token::createOffer(minter, nftokenID, drops(1)),
2764 token::destination(buyer),
2773 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer),
2781 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2791 uint256 const offerMinterBuysFromBuyer =
2793 env(token::createOffer(minter, nftokenID, drops(1)),
2794 token::owner(buyer),
2795 token::destination(buyer));
2803 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer),
2811 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2820 uint256 const offerBuyerBuysFromMinter =
2822 env(token::createOffer(buyer, nftokenID, drops(1)),
2823 token::owner(minter),
2824 token::destination(broker));
2830 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter),
2835 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2845 uint256 const offerMinterToBroker =
2847 env(token::createOffer(minter, nftokenID, drops(1)),
2848 token::destination(broker),
2851 uint256 const offerBuyerToMinter =
2853 env(token::createOffer(buyer, nftokenID, drops(1)),
2854 token::owner(minter));
2863 env(token::brokerOffers(
2864 issuer, offerBuyerToMinter, offerMinterToBroker),
2873 env(token::brokerOffers(
2874 broker, offerBuyerToMinter, offerMinterToBroker));
2885 uint256 const offerBuyerToMinter =
2887 env(token::createOffer(buyer, nftokenID, drops(1)),
2888 token::destination(minter),
2891 uint256 const offerMinterToBuyer =
2893 env(token::createOffer(minter, nftokenID, drops(1)),
2894 token::owner(buyer));
2896 uint256 const offerIssuerToBuyer =
2898 env(token::createOffer(issuer, nftokenID, drops(1)),
2899 token::owner(buyer));
2907 env(token::brokerOffers(
2908 broker, offerIssuerToBuyer, offerBuyerToMinter),
2916 env(token::brokerOffers(
2917 broker, offerMinterToBuyer, offerBuyerToMinter));
2924 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2934 uint256 const offerMinterToBroker =
2936 env(token::createOffer(minter, nftokenID, drops(1)),
2937 token::destination(broker),
2940 uint256 const offerBuyerToBroker =
2942 env(token::createOffer(buyer, nftokenID, drops(1)),
2943 token::owner(minter),
2944 token::destination(broker));
2948 env(token::brokerOffers(
2949 issuer, offerBuyerToBroker, offerMinterToBroker),
2957 env(token::brokerOffers(
2958 broker, offerBuyerToBroker, offerMinterToBroker));
2970 testcase(
"Create offer expiration");
2972 using namespace test::jtx;
2974 Env env{*
this, features};
2976 Account
const issuer{
"issuer"};
2977 Account
const minter{
"minter"};
2978 Account
const buyer{
"buyer"};
2980 env.fund(XRP(1000), issuer, minter, buyer);
2984 env(token::setMinter(issuer, minter));
2989 env(token::mint(minter, 0),
2990 token::issuer(issuer),
2996 env(token::mint(minter, 0),
2997 token::issuer(issuer),
3006 uint256 const offerMinterToIssuer =
3008 env(token::createOffer(minter, nftokenID0, drops(1)),
3009 token::destination(issuer),
3010 token::expiration(expiration),
3013 uint256 const offerMinterToAnyone =
3015 env(token::createOffer(minter, nftokenID0, drops(1)),
3016 token::expiration(expiration),
3019 uint256 const offerIssuerToMinter =
3021 env(token::createOffer(issuer, nftokenID0, drops(1)),
3022 token::owner(minter),
3023 token::expiration(expiration));
3025 uint256 const offerBuyerToMinter =
3027 env(token::createOffer(buyer, nftokenID0, drops(1)),
3028 token::owner(minter),
3029 token::expiration(expiration));
3041 env(token::cancelOffer(issuer, {offerMinterToAnyone}),
3043 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
3046 BEAST_EXPECT(
lastClose(env) < expiration);
3052 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3056 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3067 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3068 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3083 env(token::createOffer(minter, nftokenID0, drops(1)),
3084 token::expiration(expiration),
3089 env(token::createOffer(minter, nftokenID1, drops(1)),
3090 token::expiration(expiration),
3093 BEAST_EXPECT(
lastClose(env) < expiration);
3099 env(token::acceptSellOffer(buyer, offer0));
3110 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3111 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3120 env(token::cancelOffer(issuer, {offer1}));
3130 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3132 token::destination(minter));
3134 env(token::acceptSellOffer(minter, offerSellBack));
3148 env(token::createOffer(buyer, nftokenID0, drops(1)),
3149 token::owner(minter),
3150 token::expiration(expiration));
3153 env(token::createOffer(buyer, nftokenID1, drops(1)),
3154 token::owner(minter),
3155 token::expiration(expiration));
3157 BEAST_EXPECT(
lastClose(env) < expiration);
3163 env(token::acceptBuyOffer(minter, offer0));
3174 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3175 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3184 env(token::cancelOffer(issuer, {offer1}));
3194 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3196 token::destination(minter));
3198 env(token::acceptSellOffer(minter, offerSellBack));
3213 env(token::createOffer(minter, nftokenID0, drops(1)),
3214 token::expiration(expiration),
3219 env(token::createOffer(minter, nftokenID1, drops(1)),
3220 token::expiration(expiration),
3225 env(token::createOffer(buyer, nftokenID0, drops(1)),
3226 token::owner(minter));
3230 env(token::createOffer(buyer, nftokenID1, drops(1)),
3231 token::owner(minter));
3234 BEAST_EXPECT(
lastClose(env) < expiration);
3240 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3251 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3261 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3271 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3273 token::destination(minter));
3275 env(token::acceptSellOffer(minter, offerSellBack));
3290 env(token::createOffer(minter, nftokenID0, drops(1)),
3295 env(token::createOffer(minter, nftokenID1, drops(1)),
3300 env(token::createOffer(buyer, nftokenID0, drops(1)),
3301 token::expiration(expiration),
3302 token::owner(minter));
3306 env(token::createOffer(buyer, nftokenID1, drops(1)),
3307 token::expiration(expiration),
3308 token::owner(minter));
3311 BEAST_EXPECT(
lastClose(env) < expiration);
3317 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3328 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3338 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3348 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3350 token::destination(minter));
3352 env(token::acceptSellOffer(minter, offerSellBack));
3368 env(token::createOffer(minter, nftokenID0, drops(1)),
3369 token::expiration(expiration),
3374 env(token::createOffer(minter, nftokenID1, drops(1)),
3375 token::expiration(expiration),
3380 env(token::createOffer(buyer, nftokenID0, drops(1)),
3381 token::expiration(expiration),
3382 token::owner(minter));
3386 env(token::createOffer(buyer, nftokenID1, drops(1)),
3387 token::expiration(expiration),
3388 token::owner(minter));
3391 BEAST_EXPECT(
lastClose(env) < expiration);
3397 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3408 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3418 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3428 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3430 token::destination(minter));
3432 env(token::acceptSellOffer(minter, offerSellBack));
3444 testcase(
"Cancel offers");
3446 using namespace test::jtx;
3448 Env env{*
this, features};
3450 Account
const alice(
"alice");
3451 Account
const becky(
"becky");
3452 Account
const minter(
"minter");
3453 env.fund(XRP(50000), alice, becky, minter);
3457 env(token::setMinter(alice, minter));
3466 uint256 const expiredOfferIndex =
3469 env(token::createOffer(alice, nftokenID, XRP(1000)),
3471 token::expiration(
lastClose(env) + 13));
3476 env(token::cancelOffer(becky, {expiredOfferIndex}),
3484 env(token::cancelOffer(becky, {expiredOfferIndex}));
3490 uint256 const dest1OfferIndex =
3493 env(token::createOffer(alice, nftokenID, XRP(1000)),
3494 token::destination(becky),
3500 env(token::cancelOffer(minter, {dest1OfferIndex}),
3505 env(token::cancelOffer(becky, {dest1OfferIndex}));
3510 uint256 const dest2OfferIndex =
3513 env(token::createOffer(alice, nftokenID, XRP(1000)),
3514 token::destination(becky),
3519 env(token::cancelOffer(alice, {dest2OfferIndex}));
3526 uint256 const mintersNFTokenID =
3528 env(token::mint(minter, 0),
3529 token::issuer(alice),
3533 uint256 const minterOfferIndex =
3536 env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3542 env(token::cancelOffer(alice, {minterOfferIndex}),
3544 env(token::cancelOffer(becky, {minterOfferIndex}),
3549 env(token::cancelOffer(minter, {minterOfferIndex}));
3558 testcase(
"Cancel too many offers");
3560 using namespace test::jtx;
3562 Env env{*
this, features};
3577 Account
const alice(
"alice");
3578 env.fund(XRP(1000), alice);
3587 Account
const offerAcct(
3589 env.fund(XRP(1000), nftAcct, offerAcct);
3594 env(token::mint(nftAcct, 0),
3601 env(token::createOffer(offerAcct, nftokenID, drops(1)),
3602 token::owner(nftAcct),
3611 for (
uint256 const& offerIndex : offerIndexes)
3618 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3622 env(token::cancelOffer(alice, {offerIndexes.back()}));
3627 offerIndexes.pop_back();
3633 env(token::mint(alice, 0),
3639 env(token::createOffer(alice, nftokenID, drops(1)),
3648 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3652 env(token::burn(alice, nftokenID));
3658 offerIndexes.pop_back();
3663 env(token::cancelOffer(alice, offerIndexes));
3667 for (
uint256 const& offerIndex : offerIndexes)
3677 testcase(
"Brokered NFT offer accept");
3679 using namespace test::jtx;
3681 Env env{*
this, features};
3689 Account
const issuer{
"issuer"};
3690 Account
const minter{
"minter"};
3691 Account
const buyer{
"buyer"};
3692 Account
const broker{
"broker"};
3693 Account
const gw{
"gw"};
3694 IOU
const gwXAU(gw[
"XAU"]);
3696 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3699 env(trust(issuer, gwXAU(2000)));
3700 env(trust(minter, gwXAU(2000)));
3701 env(trust(buyer, gwXAU(2000)));
3702 env(trust(broker, gwXAU(2000)));
3705 env(token::setMinter(issuer, minter));
3709 auto checkOwnerCountIsOne =
3714 for (Account
const& acct : accounts)
3720 ss <<
"Account " << acct.human()
3721 <<
" expected ownerCount == 1. Got " <<
ownerCount;
3722 fail(ss.
str(), __FILE__, line);
3728 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3731 env(token::mint(minter, 0),
3732 token::issuer(issuer),
3733 token::xferFee(xferFee),
3745 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3747 uint256 const nftID = mintNFT();
3750 uint256 const minterOfferIndex =
3752 env(token::createOffer(minter, nftID, XRP(0)),
3760 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3763 auto const minterBalance = env.balance(minter);
3764 auto const buyerBalance = env.balance(buyer);
3765 auto const brokerBalance = env.balance(broker);
3766 auto const issuerBalance = env.balance(issuer);
3769 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3774 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
3775 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3776 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
3777 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3780 env(token::burn(buyer, nftID));
3790 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3792 uint256 const nftID = mintNFT();
3795 uint256 const minterOfferIndex =
3797 env(token::createOffer(minter, nftID, XRP(0)),
3805 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3809 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3810 token::brokerFee(XRP(1.1)),
3814 auto const minterBalance = env.balance(minter);
3815 auto const buyerBalance = env.balance(buyer);
3816 auto const brokerBalance = env.balance(broker);
3817 auto const issuerBalance = env.balance(issuer);
3820 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3821 token::brokerFee(XRP(0.5)));
3826 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3827 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3829 env.balance(broker) == brokerBalance + XRP(0.5) - drops(10));
3830 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3833 env(token::burn(buyer, nftID));
3843 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3848 uint256 const minterOfferIndex =
3850 env(token::createOffer(minter, nftID, XRP(0)),
3858 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3861 auto const minterBalance = env.balance(minter);
3862 auto const buyerBalance = env.balance(buyer);
3863 auto const brokerBalance = env.balance(broker);
3864 auto const issuerBalance = env.balance(issuer);
3867 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3872 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3873 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3874 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
3875 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
3878 env(token::burn(buyer, nftID));
3888 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3893 uint256 const minterOfferIndex =
3895 env(token::createOffer(minter, nftID, XRP(0)),
3903 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3906 auto const minterBalance = env.balance(minter);
3907 auto const buyerBalance = env.balance(buyer);
3908 auto const brokerBalance = env.balance(broker);
3909 auto const issuerBalance = env.balance(issuer);
3912 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3913 token::brokerFee(XRP(0.75)));
3919 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
3920 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3922 env.balance(broker) == brokerBalance + XRP(0.75) - drops(10));
3923 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
3926 env(token::burn(buyer, nftID));
3931 auto setXAUBalance_1000 =
3932 [
this, &gw, &gwXAU, &env](
3936 for (Account
const& acct : accounts)
3938 static const auto xau1000 = gwXAU(1000);
3939 auto const balance = env.balance(acct, gwXAU);
3940 if (balance < xau1000)
3942 env(pay(gw, acct, xau1000 - balance));
3945 else if (balance > xau1000)
3947 env(pay(acct, gw, balance - xau1000));
3950 if (env.balance(acct, gwXAU) != xau1000)
3953 ss <<
"Unable to set " << acct.human()
3954 <<
" account balance to gwXAU(1000)";
3955 this->fail(ss.
str(), __FILE__, line);
3963 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3964 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
3966 uint256 const nftID = mintNFT();
3969 uint256 const minterOfferIndex =
3971 env(token::createOffer(minter, nftID, gwXAU(1000)),
3979 env(token::createOffer(buyer, nftID, gwXAU(1001)),
3980 token::owner(minter));
3984 env(token::brokerOffers(
3985 broker, buyOfferIndex, minterOfferIndex),
3991 env(token::cancelOffer(buyer, {buyOfferIndex}));
3998 env(token::createOffer(buyer, nftID, gwXAU(999)),
3999 token::owner(minter));
4003 env(token::brokerOffers(
4004 broker, buyOfferIndex, minterOfferIndex),
4010 env(token::cancelOffer(buyer, {buyOfferIndex}));
4017 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4018 token::owner(minter));
4022 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4023 token::brokerFee(gwXAU(0.1)),
4028 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
4035 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4036 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4037 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4038 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4041 env(token::burn(buyer, nftID));
4048 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4049 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4054 uint256 const minterOfferIndex =
4056 env(token::createOffer(minter, nftID, gwXAU(900)),
4063 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4064 token::owner(minter));
4068 env(token::brokerOffers(
4069 broker, buyOfferIndex, minterOfferIndex),
4075 env(token::cancelOffer(buyer, {buyOfferIndex}));
4082 env(token::createOffer(buyer, nftID, gwXAU(899)),
4083 token::owner(minter));
4087 env(token::brokerOffers(
4088 broker, buyOfferIndex, minterOfferIndex),
4094 env(token::cancelOffer(buyer, {buyOfferIndex}));
4100 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4101 token::owner(minter));
4106 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4107 token::brokerFee(gwXAU(101)),
4113 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4114 token::brokerFee(gwXAU(100)));
4121 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4122 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4123 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4124 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4127 env(token::burn(buyer, nftID));
4134 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4135 setXAUBalance_1000({issuer, minter, buyer, broker}, __LINE__);
4140 uint256 const minterOfferIndex =
4142 env(token::createOffer(minter, nftID, gwXAU(900)),
4149 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4150 token::owner(minter));
4156 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4157 token::brokerFee(gwXAU(50)));
4164 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4165 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4166 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4167 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4170 env(token::burn(buyer, nftID));
4179 testcase(
"NFToken offer owner");
4181 using namespace test::jtx;
4183 Env env{*
this, features};
4185 Account
const issuer{
"issuer"};
4186 Account
const buyer1{
"buyer1"};
4187 Account
const buyer2{
"buyer2"};
4188 env.fund(XRP(10000), issuer, buyer1, buyer2);
4197 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4198 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4199 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4202 uint256 const buyer1OfferIndex =
4204 env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer));
4205 uint256 const buyer2OfferIndex =
4207 env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer));
4217 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4219 if (buyOffers.
isMember(jss::result) &&
4220 buyOffers[jss::result].
isMember(jss::offers))
4221 return buyOffers[jss::result][jss::offers].
size();
4227 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4230 env(token::acceptBuyOffer(issuer, buyer1OfferIndex));
4234 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4235 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4236 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4240 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4244 env(token::acceptBuyOffer(buyer1, buyer2OfferIndex));
4248 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4249 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4250 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4253 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4260 testcase(
"NFToken transactions with tickets");
4262 using namespace test::jtx;
4264 Env env{*
this, features};
4266 Account
const issuer{
"issuer"};
4267 Account
const buyer{
"buyer"};
4268 env.fund(XRP(10000), issuer, buyer);
4275 env(ticket::create(issuer, 10));
4281 env(ticket::create(buyer, 10));
4289 env(token::mint(issuer, 0u),
4291 ticket::use(issuerTicketSeq++));
4299 env(token::createOffer(buyer, nftId, XRP(1)),
4300 token::owner(issuer),
4301 ticket::use(buyerTicketSeq++));
4307 env(token::cancelOffer(buyer, {offerIndex0}),
4308 ticket::use(buyerTicketSeq++));
4315 env(token::createOffer(buyer, nftId, XRP(2)),
4316 token::owner(issuer),
4317 ticket::use(buyerTicketSeq++));
4323 env(token::acceptBuyOffer(issuer, offerIndex1),
4324 ticket::use(issuerTicketSeq++));
4331 env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4338 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4339 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4350 testcase(
"NFToken delete account");
4352 using namespace test::jtx;
4354 Env env{*
this, features};
4356 Account
const issuer{
"issuer"};
4357 Account
const minter{
"minter"};
4358 Account
const becky{
"becky"};
4359 Account
const carla{
"carla"};
4360 Account
const daria{
"daria"};
4362 env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4366 for (
int i = 0; i < 300; ++i)
4369 env(token::setMinter(issuer, minter));
4373 env(token::mint(minter, 0u),
4374 token::issuer(issuer),
4387 for (
int i = 0; i < 15; ++i)
4391 env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4394 uint256 const carlaOfferIndex =
4396 env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4401 env(acctdelete(becky, daria), fee(XRP(50)));
4405 env(token::acceptBuyOffer(minter, carlaOfferIndex));
4410 env(acctdelete(minter, daria), fee(XRP(50)));
4422 for (
int i = 0; i < 15; ++i)
4427 env(token::burn(carla, nftId));
4430 env(acctdelete(issuer, daria), fee(XRP(50)));
4431 env(acctdelete(carla, daria), fee(XRP(50)));
4438 testcase(
"nft_buy_offers and nft_sell_offers");
4447 using namespace test::jtx;
4449 Env env{*
this, features};
4451 Account
const issuer{
"issuer"};
4452 Account
const buyer{
"buyer"};
4455 env.fund(XRP(1000000), issuer, buyer);
4464 auto checkOffers = [
this, &env, &nftID](
4465 char const* request,
4467 int expectMarkerCount,
4469 int markerCount = 0;
4476 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4480 if (!marker.
empty())
4481 params[jss::marker] = marker;
4482 return env.rpc(
"json", request,
to_string(params));
4486 if (expectCount == 0)
4490 "expected \"result\"",
4495 nftOffers[jss::result].isMember(jss::error),
4496 "expected \"error\"",
4501 nftOffers[jss::result][jss::error].asString() ==
4503 "expected \"objectNotFound\"",
4514 "expected \"result\"",
4523 marker = result[jss::marker].
asString();
4528 "expected \"offers\"",
4534 allOffers.
append(someOffers[i]);
4537 }
while (!marker.
empty());
4541 allOffers.
size() == expectCount,
4542 "Unexpected returned offer count",
4546 markerCount == expectMarkerCount,
4547 "Unexpected marker count",
4557 globalFlags = offer[jss::flags].asInt();
4560 *globalFlags == offer[jss::flags].asInt(),
4561 "Inconsistent flags returned",
4567 offerIndexes.
insert(offer[jss::nft_offer_index].asString());
4568 amounts.
insert(offer[jss::amount].asString());
4572 offerIndexes.
size() == expectCount,
4573 "Duplicate indexes returned?",
4577 amounts.
size() == expectCount,
4578 "Duplicate amounts returned?",
4584 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4588 auto makeSellOffers =
4589 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4592 while (sellPrice < limit)
4594 sellPrice += XRP(1);
4595 env(token::createOffer(issuer, nftID, sellPrice),
4597 if (++offerCount % 10 == 0)
4604 makeSellOffers(XRP(1));
4605 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4608 makeSellOffers(XRP(250));
4609 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4612 makeSellOffers(XRP(251));
4613 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4616 makeSellOffers(XRP(500));
4617 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4620 makeSellOffers(XRP(501));
4621 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4624 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4628 auto makeBuyOffers =
4629 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4632 while (buyPrice < limit)
4635 env(token::createOffer(buyer, nftID, buyPrice),
4636 token::owner(issuer));
4637 if (++offerCount % 10 == 0)
4644 makeBuyOffers(XRP(1));
4645 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4648 makeBuyOffers(XRP(250));
4649 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4652 makeBuyOffers(XRP(251));
4653 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4656 makeBuyOffers(XRP(500));
4657 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4660 makeBuyOffers(XRP(501));
4661 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4668 using namespace test::jtx;
4670 testcase(
"fixNFTokenNegOffer");
4672 Account
const issuer{
"issuer"};
4673 Account
const buyer{
"buyer"};
4674 Account
const gw{
"gw"};
4675 IOU
const gwXAU(gw[
"XAU"]);
4678 for (
auto const& tweakedFeatures :
4685 Env env{*
this, tweakedFeatures};
4687 env.fund(XRP(1000000), issuer, buyer, gw);
4690 env(trust(issuer, gwXAU(2000)));
4691 env(trust(buyer, gwXAU(2000)));
4694 env(pay(gw, issuer, gwXAU(1000)));
4695 env(pay(gw, buyer, gwXAU(1000)));
4715 uint256 const sellNegXrpOfferIndex =
4717 env(token::createOffer(issuer, nftID0, XRP(-2)),
4719 ter(offerCreateTER));
4722 uint256 const sellNegIouOfferIndex =
4724 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
4726 ter(offerCreateTER));
4729 uint256 const buyNegXrpOfferIndex =
4731 env(token::createOffer(buyer, nftID0, XRP(-1)),
4732 token::owner(issuer),
4733 ter(offerCreateTER));
4736 uint256 const buyNegIouOfferIndex =
4738 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
4739 token::owner(issuer),
4740 ter(offerCreateTER));
4752 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
4753 ter(offerAcceptTER));
4755 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
4756 ter(offerAcceptTER));
4760 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
4761 ter(offerAcceptTER));
4763 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
4764 ter(offerAcceptTER));
4775 env(token::brokerOffers(
4776 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
4777 ter(offerAcceptTER));
4779 env(token::brokerOffers(
4780 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
4781 ter(offerAcceptTER));
4793 env.fund(XRP(1000000), issuer, buyer, gw);
4796 env(trust(issuer, gwXAU(2000)));
4797 env(trust(buyer, gwXAU(2000)));
4800 env(pay(gw, issuer, gwXAU(1000)));
4801 env(pay(gw, buyer, gwXAU(1000)));
4817 uint256 const sellNegXrpOfferIndex =
4819 env(token::createOffer(issuer, nftID0, XRP(-2)),
4823 uint256 const sellNegIouOfferIndex =
4825 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
4829 uint256 const buyNegXrpOfferIndex =
4831 env(token::createOffer(buyer, nftID0, XRP(-1)),
4832 token::owner(issuer));
4835 uint256 const buyNegIouOfferIndex =
4837 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
4838 token::owner(issuer));
4847 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
4850 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
4855 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
4858 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
4863 env(token::brokerOffers(
4864 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
4867 env(token::brokerOffers(
4868 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
4875 for (
auto const& tweakedFeatures :
4879 Env env{*
this, tweakedFeatures};
4881 env.fund(XRP(1000000), issuer, buyer);
4893 env(token::createOffer(buyer, nftID, drops(1)),
4894 token::owner(issuer),
4895 token::destination(issuer),
4896 ter(offerCreateTER));
4935 using namespace test::jtx;