22#include <xrpld/app/tx/detail/NFTokenUtils.h>
24#include <xrpl/basics/random.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/jss.h>
41 if (
auto const sleIssuer = env.
le(issuer))
42 ret = sleIssuer->at(~sfMintedNFTokens).value_or(0);
51 if (
auto const sleIssuer = env.
le(issuer))
52 ret = sleIssuer->at(~sfBurnedNFTokens).value_or(0);
61 params[jss::account] = acct.
human();
62 params[jss::type] =
"state";
64 return nfts[jss::result][jss::account_nfts].
size();
72 if (
auto const sleAcct = env.
le(acct))
73 ret = sleAcct->at(~sfTicketCount).value_or(0);
81 return env.
current()->info().parentCloseTime.time_since_epoch().count();
89 using namespace test::jtx;
95 features - featureNonFungibleTokensV1 -
96 featureNonFungibleTokensV1_1};
97 Account
const& master = env.master;
99 BEAST_EXPECT(ownerCount(env, master) == 0);
103 uint256 const nftId{token::getNextID(env, master, 0u)};
106 BEAST_EXPECT(ownerCount(env, master) == 0);
112 BEAST_EXPECT(ownerCount(env, master) == 0);
118 env(token::createOffer(master, nftId, XRP(10)), ter(
temDISABLED));
120 BEAST_EXPECT(ownerCount(env, master) == 0);
124 env(token::cancelOffer(master, {offerIndex}), ter(
temDISABLED));
126 BEAST_EXPECT(ownerCount(env, master) == 0);
130 env(token::acceptBuyOffer(master, offerIndex), ter(
temDISABLED));
132 BEAST_EXPECT(ownerCount(env, master) == 0);
139 Env env{*
this, features};
140 Account
const& master = env.master;
142 BEAST_EXPECT(ownerCount(env, master) == 0);
146 uint256 const nftId0{token::getNextID(env, env.master, 0u)};
147 env(token::mint(env.master, 0u));
149 BEAST_EXPECT(ownerCount(env, master) == 1);
153 env(token::burn(env.master, nftId0));
155 BEAST_EXPECT(ownerCount(env, master) == 0);
163 BEAST_EXPECT(ownerCount(env, master) == 1);
167 Account
const alice{
"alice"};
168 env.fund(XRP(10000), alice);
170 uint256 const aliceOfferIndex =
172 env(token::createOffer(alice, nftId1, XRP(1000)),
173 token::owner(master));
176 BEAST_EXPECT(ownerCount(env, master) == 1);
180 BEAST_EXPECT(ownerCount(env, alice) == 1);
184 env(token::acceptBuyOffer(master, aliceOfferIndex));
187 BEAST_EXPECT(ownerCount(env, master) == 0);
191 BEAST_EXPECT(ownerCount(env, alice) == 1);
203 using namespace test::jtx;
205 Env env{*
this, features};
206 Account
const alice{
"alice"};
207 Account
const minter{
"minter"};
211 auto const acctReserve = env.current()->fees().accountReserve(0);
212 auto const incReserve = env.current()->fees().increment;
213 env.fund(acctReserve, alice, minter);
215 BEAST_EXPECT(env.balance(alice) == acctReserve);
216 BEAST_EXPECT(env.balance(minter) == acctReserve);
217 BEAST_EXPECT(ownerCount(env, alice) == 0);
218 BEAST_EXPECT(ownerCount(env, minter) == 0);
224 BEAST_EXPECT(ownerCount(env, alice) == 0);
229 env(pay(env.master, alice, incReserve + drops(9)));
234 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
247 ss <<
"Wrong " << type <<
" count. Found: " << found
248 <<
"; Expected: " << exp;
249 fail(ss.
str(), __FILE__, line);
252 oneCheck(
"owner", ownerCount(env, alice), owners);
253 oneCheck(
"minted",
mintedCount(env, alice), minted);
254 oneCheck(
"burned",
burnedCount(env, alice), burned);
261 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
264 env(pay(env.master, alice, drops(11)));
268 env(token::mint(alice));
270 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
274 for (
int i = 1; i < 32; ++i)
276 env(token::mint(alice));
277 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
284 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
287 env(pay(env.master, alice, XRP(50) + drops(329)));
294 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
297 env(pay(env.master, alice, drops(11)));
301 env(token::mint(alice));
303 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
310 env(token::burn(alice, token::getID(env, alice, 0, seq++)));
312 checkAliceOwnerMintedBurned((33 - seq) ? 1 : 0, 33, seq, __LINE__);
316 env(token::burn(alice, token::getID(env, alice, 197, 5)),
319 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
324 env(token::setMinter(alice, minter));
327 env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
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__);
403 env(pay(env.master, minter, XRP(50) + drops(319)));
408 env(token::mint(minter),
409 token::issuer(alice),
413 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
416 env(pay(env.master, minter, drops(11)));
420 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
422 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
427 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
429 checkMintersOwnerMintedBurned(
430 0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__);
435 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
437 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
440 env(token::burn(minter, token::getID(env, alice, 2009, 3)),
443 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
453 using namespace test::jtx;
455 Account
const alice{
"alice"};
456 Env env{*
this, features};
457 env.fund(XRP(1000), alice);
466 uint256 const nftId0{token::getNextID(env, alice, 0u)};
467 env(token::mint(alice, 0u));
470 env(token::burn(alice, nftId0));
477 env.app().openLedger().modify(
486 auto replacement = std::make_shared<SLE>(*sle, sle->key());
487 if (replacement->getFieldU32(sfMintedNFTokens) != 1)
490 if (env.current()->rules().enabled(fixNFTokenRemint))
498 (*replacement)[sfFirstNFTokenSequence] = 0xFFFF'FFFE;
499 (*replacement)[sfMintedNFTokens] = 0x0000'0000;
505 (*replacement)[sfMintedNFTokens] = 0xFFFF'FFFE;
522 using namespace test::jtx;
524 Env env{*
this, features};
525 Account
const alice{
"alice"};
526 Account
const minter{
"minter"};
531 env.fund(XRP(200), alice, minter);
538 env(pay(env.master, alice, XRP(1000)));
545 env(token::mint(alice, 0u),
550 env(token::mint(alice, 0u), txflags(0x00008000), ter(
temINVALID_FLAG));
554 env(token::mint(alice, 0u),
559 env(token::mint(alice, 0u),
565 env(token::mint(alice, 0u), token::issuer(alice), ter(
temMALFORMED));
568 env(token::mint(alice, 0u), token::uri(
""), ter(
temMALFORMED));
571 env(token::mint(alice, 0u),
579 env(token::mint(alice, 0u),
580 token::issuer(Account(
"demon")),
587 env(token::mint(minter, 0u),
588 token::issuer(alice),
598 using namespace test::jtx;
600 Env env{*
this, features};
601 Account
const alice{
"alice"};
602 Account
const buyer{
"buyer"};
603 Account
const minter{
"minter"};
604 Account
const gw(
"gw");
605 IOU
const gwAUD(gw[
"AUD"]);
610 env.fund(XRP(250), alice, buyer, minter, gw);
612 BEAST_EXPECT(ownerCount(env, alice) == 0);
618 BEAST_EXPECT(ownerCount(env, alice) == 1);
624 env(token::burn(alice, nftAlice0ID),
628 BEAST_EXPECT(ownerCount(env, alice) == 1);
631 env(token::burn(alice, nftAlice0ID),
635 BEAST_EXPECT(ownerCount(env, buyer) == 0);
641 env(token::burn(alice, token::getID(env, alice, 0, 1)),
644 BEAST_EXPECT(ownerCount(env, buyer) == 0);
656 testcase(
"Invalid NFT offer create");
658 using namespace test::jtx;
660 Env env{*
this, features};
661 Account
const alice{
"alice"};
662 Account
const buyer{
"buyer"};
663 Account
const gw(
"gw");
664 IOU
const gwAUD(gw[
"AUD"]);
669 env.fund(XRP(250), alice, buyer, gw);
671 BEAST_EXPECT(ownerCount(env, alice) == 0);
675 env(token::mint(alice, 0u),
679 BEAST_EXPECT(ownerCount(env, alice) == 1);
685 BEAST_EXPECT(ownerCount(env, alice) == 1);
687 uint256 nftNoXferID = token::getNextID(env, alice, 0);
688 env(token::mint(alice, 0));
690 BEAST_EXPECT(ownerCount(env, alice) == 1);
701 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
705 BEAST_EXPECT(ownerCount(env, buyer) == 0);
708 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
712 BEAST_EXPECT(ownerCount(env, buyer) == 0);
715 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
719 BEAST_EXPECT(ownerCount(env, buyer) == 0);
722 env(token::createOffer(buyer, nftXrpOnlyID, buyer[
"USD"](1)),
724 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](0)),
726 env(token::createOffer(buyer, nftXrpOnlyID, drops(0)),
729 BEAST_EXPECT(ownerCount(env, buyer) == 0);
732 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](1)),
733 token::expiration(0),
736 BEAST_EXPECT(ownerCount(env, buyer) == 0);
740 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
743 BEAST_EXPECT(ownerCount(env, buyer) == 0);
746 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
751 BEAST_EXPECT(ownerCount(env, alice) == 1);
754 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
758 BEAST_EXPECT(ownerCount(env, alice) == 1);
761 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
762 token::destination(alice),
766 BEAST_EXPECT(ownerCount(env, alice) == 1);
769 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
770 token::destination(Account(
"demon")),
774 BEAST_EXPECT(ownerCount(env, alice) == 1);
780 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
785 BEAST_EXPECT(ownerCount(env, buyer) == 0);
788 env(token::createOffer(
789 buyer, token::getID(env, alice, 0, 1), XRP(1000)),
793 BEAST_EXPECT(ownerCount(env, buyer) == 0);
796 env(token::createOffer(
797 alice, token::getID(env, alice, 0, 1), XRP(1000)),
801 BEAST_EXPECT(ownerCount(env, buyer) == 0);
804 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
808 BEAST_EXPECT(ownerCount(env, buyer) == 0);
810 env(trust(buyer, gwAUD(1000)));
812 BEAST_EXPECT(ownerCount(env, buyer) == 1);
816 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
820 BEAST_EXPECT(ownerCount(env, buyer) == 1);
828 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
832 BEAST_EXPECT(ownerCount(env, buyer) == 1);
839 env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
843 BEAST_EXPECT(ownerCount(env, buyer) == 1);
849 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
853 BEAST_EXPECT(ownerCount(env, buyer) == 1);
858 env(trust(buyer, gwAUD(1000)));
861 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
865 BEAST_EXPECT(ownerCount(env, buyer) == 1);
871 env(pay(gw, buyer, gwAUD(999)));
876 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
880 BEAST_EXPECT(ownerCount(env, buyer) == 1);
883 env(pay(env.master, buyer, XRP(50) + drops(119)));
886 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
890 BEAST_EXPECT(ownerCount(env, buyer) == 1);
893 env(pay(env.master, buyer, drops(11)));
898 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
902 BEAST_EXPECT(ownerCount(env, buyer) == 2);
908 testcase(
"Invalid NFT offer cancel");
910 using namespace test::jtx;
912 Env env{*
this, features};
913 Account
const alice{
"alice"};
914 Account
const buyer{
"buyer"};
915 Account
const gw(
"gw");
916 IOU
const gwAUD(gw[
"AUD"]);
918 env.fund(XRP(1000), alice, buyer, gw);
920 BEAST_EXPECT(ownerCount(env, alice) == 0);
926 BEAST_EXPECT(ownerCount(env, alice) == 1);
929 uint256 const buyerOfferIndex =
931 env(token::createOffer(buyer, nftAlice0ID, XRP(1)),
935 BEAST_EXPECT(ownerCount(env, buyer) == 1);
941 env(token::cancelOffer(buyer, {buyerOfferIndex}),
945 BEAST_EXPECT(ownerCount(env, buyer) == 1);
948 env(token::cancelOffer(buyer, {buyerOfferIndex}),
952 BEAST_EXPECT(ownerCount(env, buyer) == 1);
960 BEAST_EXPECT(ownerCount(env, buyer) == 1);
968 env(token::cancelOffer(buyer, offers), ter(
temMALFORMED));
970 BEAST_EXPECT(ownerCount(env, buyer) == 1);
974 env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}),
977 BEAST_EXPECT(ownerCount(env, buyer) == 1);
982 BEAST_EXPECT(ownerCount(env, buyer) == 1);
988 env(pay(env.master, gw, XRP(5000)));
992 env(offer(gw, XRP(i), gwAUD(1)));
999 env(check::create(gw, env.master, XRP(300)));
1006 env(check::cancel(gw, gwCheckId));
1013 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1020 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1022 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1028 testcase(
"Invalid NFT offer accept");
1030 using namespace test::jtx;
1032 Env env{*
this, features};
1033 Account
const alice{
"alice"};
1034 Account
const buyer{
"buyer"};
1035 Account
const gw(
"gw");
1036 IOU
const gwAUD(gw[
"AUD"]);
1038 env.fund(XRP(1000), alice, buyer, gw);
1040 BEAST_EXPECT(ownerCount(env, alice) == 0);
1046 BEAST_EXPECT(ownerCount(env, alice) == 1);
1052 BEAST_EXPECT(ownerCount(env, alice) == 1);
1054 uint256 nftNoXferID = token::getNextID(env, alice, 0);
1055 env(token::mint(alice, 0));
1057 BEAST_EXPECT(ownerCount(env, alice) == 1);
1060 uint256 const plainOfferIndex =
1062 env(token::createOffer(alice, nftAlice0ID, XRP(10)),
1065 BEAST_EXPECT(ownerCount(env, alice) == 2);
1069 env(token::createOffer(alice, nftAlice0ID, gwAUD(30)),
1072 BEAST_EXPECT(ownerCount(env, alice) == 3);
1074 uint256 const xrpOnlyOfferIndex =
1076 env(token::createOffer(alice, nftXrpOnlyID, XRP(20)),
1079 BEAST_EXPECT(ownerCount(env, alice) == 4);
1081 uint256 const noXferOfferIndex =
1083 env(token::createOffer(alice, nftNoXferID, XRP(30)),
1086 BEAST_EXPECT(ownerCount(env, alice) == 5);
1089 uint256 const aliceExpOfferIndex =
1091 env(token::createOffer(alice, nftNoXferID, XRP(40)),
1095 BEAST_EXPECT(ownerCount(env, alice) == 6);
1101 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1105 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1108 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1109 txflags(0x00008000),
1112 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1116 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1120 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1125 Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1126 jv[sfNFTokenBrokerFee.jsonName] =
1130 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1135 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1136 jv[sfNFTokenBrokerFee.jsonName] =
1140 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1144 env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1145 token::brokerFee(gwAUD(0)),
1148 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1154 env(token::acceptBuyOffer(buyer, beast::zero),
1157 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1161 env(token::acceptBuyOffer(buyer, missingOfferIndex),
1164 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1167 env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1169 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1172 env(token::acceptSellOffer(buyer, beast::zero),
1175 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1178 env(token::acceptSellOffer(buyer, missingOfferIndex),
1181 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1184 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1186 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1193 env(trust(alice, gwAUD(1000)));
1194 env(trust(buyer, gwAUD(1000)));
1196 env(pay(gw, buyer, gwAUD(30)));
1198 BEAST_EXPECT(ownerCount(env, alice) == 7);
1199 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1205 uint256 const buyerOfferIndex =
1207 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)),
1208 token::owner(alice));
1210 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1213 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1216 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1219 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1222 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1226 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1229 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1232 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1234 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1238 uint256 const buyerOfferIndex =
1240 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)),
1241 token::owner(alice));
1243 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1247 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1248 token::brokerFee(XRP(40)),
1251 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1254 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1255 token::brokerFee(gwAUD(31)),
1258 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1262 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1263 token::brokerFee(gwAUD(1.5)),
1266 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1269 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1271 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1277 uint256 const buyerOfferIndex =
1279 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)),
1280 token::owner(alice));
1282 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1285 env(token::acceptBuyOffer(buyer, plainOfferIndex),
1288 BEAST_EXPECT(ownerCount(env, alice) == 7);
1291 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1294 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1297 env(pay(buyer, gw, gwAUD(30)));
1299 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1300 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1303 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1309 env(token::createOffer(alice, nftAlice0ID, XRP(0)),
1312 env(token::acceptSellOffer(gw, offerIndex));
1314 BEAST_EXPECT(ownerCount(env, alice) == 7);
1316 env(pay(gw, buyer, gwAUD(30)));
1320 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1323 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1326 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1328 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1334 uint256 const buyerOfferIndex =
1336 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)),
1337 token::owner(alice));
1339 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1342 env(token::acceptSellOffer(alice, buyerOfferIndex),
1345 BEAST_EXPECT(ownerCount(env, alice) == 7);
1348 env(token::acceptSellOffer(alice, plainOfferIndex),
1351 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1355 env(token::acceptSellOffer(buyer, plainOfferIndex),
1358 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1366 env(token::createOffer(gw, nftAlice0ID, XRP(0)),
1369 env(token::acceptSellOffer(alice, offerIndex));
1371 BEAST_EXPECT(ownerCount(env, alice) == 7);
1373 env(pay(buyer, gw, gwAUD(30)));
1375 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1376 env(token::acceptSellOffer(buyer, audOfferIndex),
1379 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1395 using namespace test::jtx;
1397 Env env{*
this, features};
1398 Account
const alice{
"alice"};
1399 Account
const buyer{
"buyer"};
1400 Account
const minter1{
"minter1"};
1401 Account
const minter2{
"minter2"};
1403 env.fund(XRP(1000), alice, buyer, minter1, minter2);
1405 BEAST_EXPECT(ownerCount(env, alice) == 0);
1408 env(token::setMinter(alice, minter1));
1415 auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1417 uint256 const nftID{token::getNextID(env, alice, 0u, flags)};
1418 env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags));
1423 env(token::createOffer(minter1, nftID, XRP(0)),
1427 env(token::acceptSellOffer(buyer, offerIndex));
1435 uint256 const noBurnID = nftToBuyer(0);
1436 env(token::burn(alice, noBurnID),
1437 token::owner(buyer),
1440 env(token::burn(minter1, noBurnID),
1441 token::owner(buyer),
1444 env(token::burn(minter2, noBurnID),
1445 token::owner(buyer),
1449 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1450 env(token::burn(buyer, noBurnID), token::owner(buyer));
1452 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1457 env(token::burn(minter2, burnableID),
1458 token::owner(buyer),
1462 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1463 env(token::burn(alice, burnableID), token::owner(buyer));
1465 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1470 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1471 env(token::burn(buyer, burnableID));
1473 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1478 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1479 env(token::burn(buyer, burnableID), token::owner(buyer));
1481 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1487 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1489 env(token::setMinter(alice, minter2));
1494 env(token::burn(minter1, burnableID),
1495 token::owner(buyer),
1498 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1501 env(token::burn(minter2, burnableID), token::owner(buyer));
1503 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1513 using namespace test::jtx;
1515 Env env{*
this, features};
1516 Account
const alice{
"alice"};
1517 Account
const buyer{
"buyer"};
1518 Account
const gw(
"gw");
1519 IOU
const gwAUD(gw[
"AUD"]);
1522 env.fund(XRP(1000), alice, buyer, gw);
1524 env(trust(alice, gwAUD(1000)));
1525 env(trust(buyer, gwAUD(1000)));
1527 env(pay(gw, buyer, gwAUD(100)));
1536 BEAST_EXPECT(ownerCount(env, alice) == 2);
1537 uint256 const aliceOfferIndex =
1539 env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)),
1542 BEAST_EXPECT(ownerCount(env, alice) == 3);
1544 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1545 uint256 const buyerOfferIndex =
1547 env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)),
1548 token::owner(alice));
1550 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1553 env(token::cancelOffer(alice, {aliceOfferIndex}));
1554 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1556 BEAST_EXPECT(ownerCount(env, alice) == 2);
1557 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1560 env(token::burn(alice, nftIOUsOkayID));
1562 BEAST_EXPECT(ownerCount(env, alice) == 1);
1572 BEAST_EXPECT(ownerCount(env, alice) == 2);
1573 env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)),
1577 BEAST_EXPECT(ownerCount(env, alice) == 2);
1579 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1580 env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)),
1581 token::owner(alice),
1584 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1587 BEAST_EXPECT(ownerCount(env, alice) == 2);
1588 env(token::createOffer(alice, nftOnlyXRPID, XRP(60)),
1591 BEAST_EXPECT(ownerCount(env, alice) == 3);
1593 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1594 env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)),
1595 token::owner(alice));
1597 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1605 testcase(
"Mint flagCreateTrustLines");
1607 using namespace test::jtx;
1609 Account
const alice{
"alice"};
1610 Account
const becky{
"becky"};
1611 Account
const cheri{
"cheri"};
1612 Account
const gw(
"gw");
1613 IOU
const gwAUD(gw[
"AUD"]);
1614 IOU
const gwCAD(gw[
"CAD"]);
1615 IOU
const gwEUR(gw[
"EUR"]);
1620 for (
auto const& tweakedFeatures :
1621 {features - fixRemoveNFTokenAutoTrustLine,
1622 features | fixRemoveNFTokenAutoTrustLine})
1624 Env env{*
this, tweakedFeatures};
1625 env.fund(XRP(1000), alice, becky, cheri, gw);
1629 env(trust(becky, gwAUD(1000)));
1630 env(trust(cheri, gwAUD(1000)));
1631 env(trust(becky, gwCAD(1000)));
1632 env(trust(cheri, gwCAD(1000)));
1633 env(trust(becky, gwEUR(1000)));
1634 env(trust(cheri, gwEUR(1000)));
1636 env(pay(gw, becky, gwAUD(500)));
1637 env(pay(gw, becky, gwCAD(500)));
1638 env(pay(gw, becky, gwEUR(500)));
1639 env(pay(gw, cheri, gwAUD(500)));
1640 env(pay(gw, cheri, gwCAD(500)));
1647 uint256 const nftNoAutoTrustID{
1649 env(token::mint(alice, 0u),
1650 token::xferFee(xferFee),
1655 uint256 const beckyBuyOfferIndex =
1657 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1658 token::owner(alice));
1660 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1664 TER const createOfferTER =
1666 uint256 const beckyOfferIndex =
1668 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1670 ter(createOfferTER));
1674 uint256 const cheriOfferIndex =
1676 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1677 token::owner(becky),
1678 ter(createOfferTER));
1682 env(token::cancelOffer(becky, {beckyOfferIndex}));
1683 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1691 uint256 const nftAutoTrustID{token::getNextID(
1698 tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
1702 env(token::mint(alice, 0u),
1703 token::xferFee(transferFee),
1710 if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
1714 uint256 const beckyBuyOfferIndex =
1716 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1717 token::owner(alice));
1719 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1723 uint256 const beckySellOfferIndex =
1725 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1728 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1732 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1735 uint256 const beckyBuyBackOfferIndex =
1737 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1738 token::owner(cheri));
1740 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1744 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1745 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1751 uint256 const nftNoAutoTrustID{token::getNextID(
1753 env(token::mint(alice, 0u),
1754 token::xferFee(transferFee),
1759 uint256 const aliceSellOfferIndex =
1761 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1764 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1770 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1773 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1777 uint256 const cheriSellOfferIndex =
1779 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1782 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1788 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1799 using namespace test::jtx;
1801 Env env{*
this, features};
1803 Account
const alice{
"alice"};
1804 Account
const becky{
"becky"};
1805 Account
const minter{
"minter"};
1807 env.fund(XRP(1000), alice, becky, minter);
1812 BEAST_EXPECT(ownerCount(env, alice) == 0);
1813 uint256 const nftAliceNoTransferID{
1814 token::getNextID(env, alice, 0u)};
1815 env(token::mint(alice, 0u), token::xferFee(0));
1817 BEAST_EXPECT(ownerCount(env, alice) == 1);
1820 BEAST_EXPECT(ownerCount(env, becky) == 0);
1821 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1822 token::owner(alice),
1826 uint256 const aliceSellOfferIndex =
1828 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1831 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1833 BEAST_EXPECT(ownerCount(env, alice) == 0);
1834 BEAST_EXPECT(ownerCount(env, becky) == 1);
1837 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1841 BEAST_EXPECT(ownerCount(env, alice) == 0);
1842 BEAST_EXPECT(ownerCount(env, becky) == 1);
1846 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1848 token::destination(alice),
1851 BEAST_EXPECT(ownerCount(env, alice) == 0);
1852 BEAST_EXPECT(ownerCount(env, becky) == 1);
1856 uint256 const aliceBuyOfferIndex =
1858 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1859 token::owner(becky));
1861 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1863 BEAST_EXPECT(ownerCount(env, alice) == 1);
1864 BEAST_EXPECT(ownerCount(env, becky) == 0);
1867 env(token::burn(alice, nftAliceNoTransferID));
1869 BEAST_EXPECT(ownerCount(env, alice) == 0);
1870 BEAST_EXPECT(ownerCount(env, becky) == 0);
1874 env(token::setMinter(alice, minter));
1877 BEAST_EXPECT(ownerCount(env, minter) == 0);
1878 uint256 const nftMinterNoTransferID{
1879 token::getNextID(env, alice, 0u)};
1880 env(token::mint(minter), token::issuer(alice));
1882 BEAST_EXPECT(ownerCount(env, minter) == 1);
1885 BEAST_EXPECT(ownerCount(env, becky) == 0);
1886 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1887 token::owner(minter),
1890 BEAST_EXPECT(ownerCount(env, becky) == 0);
1893 env(token::clearMinter(alice));
1897 BEAST_EXPECT(ownerCount(env, minter) == 1);
1898 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1902 BEAST_EXPECT(ownerCount(env, minter) == 1);
1906 for (
int i = 0; i < 10; ++i)
1909 env(token::setMinter(alice, minter));
1911 BEAST_EXPECT(ownerCount(env, minter) == 1);
1914 BEAST_EXPECT(ownerCount(env, minter) == 1);
1915 uint256 const minterSellOfferIndex =
1917 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1920 BEAST_EXPECT(ownerCount(env, minter) == 2);
1924 env(token::clearMinter(alice));
1929 BEAST_EXPECT(ownerCount(env, becky) == 0);
1930 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1932 BEAST_EXPECT(ownerCount(env, becky) == 1);
1933 BEAST_EXPECT(ownerCount(env, minter) == 0);
1936 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1943 BEAST_EXPECT(ownerCount(env, minter) == 0);
1944 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1945 token::owner(becky),
1948 BEAST_EXPECT(ownerCount(env, minter) == 0);
1951 BEAST_EXPECT(ownerCount(env, alice) == 0);
1952 uint256 const aliceBuyOfferIndex =
1954 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1955 token::owner(becky));
1957 BEAST_EXPECT(ownerCount(env, alice) == 1);
1961 for (
int i = 0; i < 10; ++i)
1964 env(token::setMinter(alice, minter));
1968 BEAST_EXPECT(ownerCount(env, minter) == 0);
1969 uint256 const minterBuyOfferIndex =
1971 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1972 token::owner(becky));
1974 BEAST_EXPECT(ownerCount(env, minter) == 1);
1978 env(token::clearMinter(alice));
1982 BEAST_EXPECT(ownerCount(env, minter) == 1);
1983 BEAST_EXPECT(ownerCount(env, becky) == 1);
1984 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1986 BEAST_EXPECT(ownerCount(env, minter) == 1);
1987 BEAST_EXPECT(ownerCount(env, becky) == 0);
1988 BEAST_EXPECT(ownerCount(env, alice) == 1);
1992 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
1994 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1996 BEAST_EXPECT(ownerCount(env, alice) == 0);
1997 BEAST_EXPECT(ownerCount(env, becky) == 0);
1998 BEAST_EXPECT(ownerCount(env, minter) == 0);
2003 BEAST_EXPECT(ownerCount(env, alice) == 0);
2008 BEAST_EXPECT(ownerCount(env, alice) == 1);
2011 uint256 const aliceSellOfferIndex =
2013 env(token::createOffer(alice, nftAliceID, XRP(20)),
2016 BEAST_EXPECT(ownerCount(env, alice) == 2);
2018 uint256 const beckyBuyOfferIndex =
2020 env(token::createOffer(becky, nftAliceID, XRP(21)),
2021 token::owner(alice));
2023 BEAST_EXPECT(ownerCount(env, alice) == 2);
2026 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
2028 BEAST_EXPECT(ownerCount(env, alice) == 0);
2029 BEAST_EXPECT(ownerCount(env, becky) == 2);
2032 uint256 const beckySellOfferIndex =
2034 env(token::createOffer(becky, nftAliceID, XRP(22)),
2037 BEAST_EXPECT(ownerCount(env, alice) == 0);
2038 BEAST_EXPECT(ownerCount(env, becky) == 3);
2042 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2044 BEAST_EXPECT(ownerCount(env, alice) == 0);
2045 BEAST_EXPECT(ownerCount(env, becky) == 1);
2046 BEAST_EXPECT(ownerCount(env, minter) == 1);
2049 uint256 const minterSellOfferIndex =
2051 env(token::createOffer(minter, nftAliceID, XRP(23)),
2054 BEAST_EXPECT(ownerCount(env, alice) == 0);
2055 BEAST_EXPECT(ownerCount(env, becky) == 1);
2056 BEAST_EXPECT(ownerCount(env, minter) == 2);
2059 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2061 BEAST_EXPECT(ownerCount(env, alice) == 1);
2062 BEAST_EXPECT(ownerCount(env, becky) == 1);
2063 BEAST_EXPECT(ownerCount(env, minter) == 0);
2067 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2069 BEAST_EXPECT(ownerCount(env, alice) == 0);
2070 BEAST_EXPECT(ownerCount(env, becky) == 1);
2071 BEAST_EXPECT(ownerCount(env, minter) == 0);
2075 env(token::burn(becky, nftAliceID));
2077 BEAST_EXPECT(ownerCount(env, alice) == 0);
2078 BEAST_EXPECT(ownerCount(env, becky) == 0);
2079 BEAST_EXPECT(ownerCount(env, minter) == 0);
2089 using namespace test::jtx;
2091 Env env{*
this, features};
2093 Account
const alice{
"alice"};
2094 Account
const becky{
"becky"};
2095 Account
const carol{
"carol"};
2096 Account
const minter{
"minter"};
2097 Account
const gw{
"gw"};
2098 IOU
const gwXAU(gw[
"XAU"]);
2100 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2103 env(trust(alice, gwXAU(2000)));
2104 env(trust(becky, gwXAU(2000)));
2105 env(trust(carol, gwXAU(2000)));
2106 env(trust(minter, gwXAU(2000)));
2108 env(pay(gw, alice, gwXAU(1000)));
2109 env(pay(gw, becky, gwXAU(1000)));
2110 env(pay(gw, carol, gwXAU(1000)));
2111 env(pay(gw, minter, gwXAU(1000)));
2116 env(token::setMinter(alice, minter));
2122 BEAST_EXPECT(ownerCount(env, alice) == 1);
2123 BEAST_EXPECT(ownerCount(env, becky) == 1);
2124 BEAST_EXPECT(ownerCount(env, carol) == 1);
2125 BEAST_EXPECT(ownerCount(env, minter) == 1);
2133 uint256 const beckyBuyOfferIndex =
2135 env(token::createOffer(becky, nftID, gwXAU(10)),
2136 token::owner(alice));
2138 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2139 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2141 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2143 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2144 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2147 uint256 const beckySellOfferIndex =
2149 env(token::createOffer(becky, nftID, gwXAU(10)),
2152 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2154 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2155 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2156 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2159 uint256 const minterBuyOfferIndex =
2161 env(token::createOffer(minter, nftID, gwXAU(10)),
2162 token::owner(carol));
2164 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2166 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2167 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2168 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2169 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2173 uint256 const minterSellOfferIndex =
2175 env(token::createOffer(minter, nftID, gwXAU(10)),
2178 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2180 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2181 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2182 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2183 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2186 env(token::burn(alice, nftID));
2188 BEAST_EXPECT(ownerCount(env, alice) == 1);
2189 BEAST_EXPECT(ownerCount(env, becky) == 1);
2190 BEAST_EXPECT(ownerCount(env, carol) == 1);
2191 BEAST_EXPECT(ownerCount(env, minter) == 1);
2199 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2203 uint256 const beckyBuyOfferIndex =
2205 env(token::createOffer(becky, nftID, gwXAU(10)),
2206 token::owner(alice));
2208 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2209 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2211 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2213 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2214 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2217 uint256 const beckySellOfferIndex =
2219 env(token::createOffer(becky, nftID, gwXAU(10)),
2222 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2225 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2226 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2227 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2230 uint256 const minterBuyOfferIndex =
2232 env(token::createOffer(minter, nftID, gwXAU(10)),
2233 token::owner(carol));
2235 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2238 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2239 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2240 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2241 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2245 uint256 const minterSellOfferIndex =
2247 env(token::createOffer(minter, nftID, gwXAU(10)),
2250 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2252 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2253 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2254 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2255 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2259 env(pay(alice, becky, gwXAU(0.0001)));
2260 env(pay(alice, carol, gwXAU(0.0001)));
2263 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2264 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2265 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2266 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2269 env(token::burn(alice, nftID));
2271 BEAST_EXPECT(ownerCount(env, alice) == 1);
2272 BEAST_EXPECT(ownerCount(env, becky) == 1);
2273 BEAST_EXPECT(ownerCount(env, carol) == 1);
2274 BEAST_EXPECT(ownerCount(env, minter) == 1);
2280 env(token::mint(alice),
2287 uint256 const nftID = token::getNextID(
2289 env(token::mint(alice),
2295 uint256 const beckyBuyOfferIndex =
2297 env(token::createOffer(becky, nftID, gwXAU(10)),
2298 token::owner(alice));
2300 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2301 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2303 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2305 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2306 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2309 uint256 const beckySellOfferIndex =
2311 env(token::createOffer(becky, nftID, gwXAU(100)),
2314 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2317 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2318 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2319 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2322 uint256 const carolBuyOfferIndex =
2324 env(token::createOffer(carol, nftID, gwXAU(10)),
2325 token::owner(minter));
2327 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2330 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2331 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2332 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2333 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2337 uint256 const carolSellOfferIndex =
2339 env(token::createOffer(carol, nftID, gwXAU(10)),
2342 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2345 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2346 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2347 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2348 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2351 env(pay(alice, minter, gwXAU(55)));
2352 env(pay(becky, minter, gwXAU(40)));
2354 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2355 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2356 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2357 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2360 env(token::burn(alice, nftID));
2362 BEAST_EXPECT(ownerCount(env, alice) == 1);
2363 BEAST_EXPECT(ownerCount(env, becky) == 1);
2364 BEAST_EXPECT(ownerCount(env, carol) == 1);
2365 BEAST_EXPECT(ownerCount(env, minter) == 1);
2370 for (
auto NumberSwitchOver : {
true})
2372 if (NumberSwitchOver)
2373 env.enableFeature(fixUniversalNumber);
2375 env.disableFeature(fixUniversalNumber);
2380 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2386 STAmount aliceBalance = env.balance(alice);
2387 STAmount minterBalance = env.balance(minter);
2388 uint256 const minterBuyOfferIndex =
2390 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2392 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2394 aliceBalance += XRP(1) - fee;
2395 minterBalance -= XRP(1) + fee;
2396 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2397 BEAST_EXPECT(env.balance(minter) == minterBalance);
2401 auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
2402 STAmount carolBalance = env.balance(carol);
2403 uint256 const minterSellOfferIndex =
2405 env(token::createOffer(minter, nftID, pmt), txflags(
tfSellNFToken));
2407 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2409 minterBalance += pmt - fee;
2410 carolBalance -= pmt + fee;
2411 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2412 BEAST_EXPECT(env.balance(minter) == minterBalance);
2413 BEAST_EXPECT(env.balance(carol) == carolBalance);
2417 STAmount beckyBalance = env.balance(becky);
2418 uint256 const beckyBuyOfferIndex =
2420 pmt = NumberSwitchOver ? drops(50001) : drops(100000);
2421 env(token::createOffer(becky, nftID, pmt), token::owner(carol));
2423 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2425 carolBalance += pmt - drops(1) - fee;
2426 beckyBalance -= pmt + fee;
2427 aliceBalance += drops(1);
2429 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2430 BEAST_EXPECT(env.balance(minter) == minterBalance);
2431 BEAST_EXPECT(env.balance(carol) == carolBalance);
2432 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2441 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2447 env(pay(alice, gw, env.balance(alice, gwXAU)));
2448 env(pay(minter, gw, env.balance(minter, gwXAU)));
2449 env(pay(becky, gw, env.balance(becky, gwXAU)));
2454 env(pay(gw, alice, startXAUBalance));
2455 env(pay(gw, minter, startXAUBalance));
2456 env(pay(gw, becky, startXAUBalance));
2465 STAmount aliceBalance = env.balance(alice, gwXAU);
2466 STAmount minterBalance = env.balance(minter, gwXAU);
2467 uint256 const minterBuyOfferIndex =
2469 env(token::createOffer(minter, nftID, tinyXAU),
2470 token::owner(alice));
2472 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2474 aliceBalance += tinyXAU;
2475 minterBalance -= tinyXAU;
2476 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2477 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2480 STAmount carolBalance = env.balance(carol, gwXAU);
2481 uint256 const minterSellOfferIndex =
2483 env(token::createOffer(minter, nftID, tinyXAU),
2486 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2489 minterBalance += tinyXAU;
2490 carolBalance -= tinyXAU;
2492 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2493 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2494 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2501 STAmount beckyBalance = env.balance(becky, gwXAU);
2502 uint256 const beckyBuyOfferIndex =
2504 env(token::createOffer(becky, nftID, cheapNFT),
2505 token::owner(carol));
2507 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2510 aliceBalance += tinyXAU;
2511 beckyBalance -= cheapNFT;
2512 carolBalance += cheapNFT - tinyXAU;
2513 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2514 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2515 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2516 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2526 using namespace test::jtx;
2528 Env env{*
this, features};
2530 Account
const alice{
"alice"};
2531 Account
const becky{
"becky"};
2533 env.fund(XRP(1000), alice, becky);
2542 uint256 const nftID = token::getNextID(env, alice, 0u);
2549 uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2557 for (
int i = 0; i < 10; ++i)
2567 ss <<
"Taxon recovery failed from nftID "
2568 <<
to_string(nftID) <<
". Expected: " << taxon
2569 <<
"; got: " << gotTaxon;
2574 uint256 const nftAliceID = token::getID(
2578 rand_int<std::uint32_t>(),
2579 rand_int<std::uint16_t>(),
2580 rand_int<std::uint16_t>());
2581 check(taxon, nftAliceID);
2583 uint256 const nftBeckyID = token::getID(
2587 rand_int<std::uint32_t>(),
2588 rand_int<std::uint16_t>(),
2589 rand_int<std::uint16_t>());
2590 check(taxon, nftBeckyID);
2604 using namespace test::jtx;
2606 Env env{*
this, features};
2608 Account
const alice{
"alice"};
2609 Account
const becky{
"becky"};
2611 env.fund(XRP(10000), alice, becky);
2617 auto randURI = []() {
2639 : uri(std::move(uri_)), taxon(taxon_)
2647 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2650 for (Entry
const& entry : entries)
2652 if (entry.uri.empty())
2654 env(token::mint(alice, entry.taxon));
2658 env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2666 params[jss::account] = alice.human();
2667 params[jss::type] =
"state";
2668 return env.rpc(
"json",
"account_nfts",
to_string(params));
2672 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2673 if (!BEAST_EXPECT(nfts.
size() == entries.
size()))
2686 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2691 Entry
const& entry = entries[i];
2693 BEAST_EXPECT(entry.taxon == ret[sfNFTokenTaxon.jsonName]);
2694 if (entry.uri.empty())
2696 BEAST_EXPECT(!ret.
isMember(sfURI.jsonName));
2700 BEAST_EXPECT(
strHex(entry.uri) == ret[sfURI.jsonName]);
2709 testcase(
"Create offer destination");
2711 using namespace test::jtx;
2713 Env env{*
this, features};
2715 Account
const issuer{
"issuer"};
2716 Account
const minter{
"minter"};
2717 Account
const buyer{
"buyer"};
2718 Account
const broker{
"broker"};
2720 env.fund(XRP(1000), issuer, minter, buyer, broker);
2724 env(token::setMinter(issuer, minter));
2729 env(token::mint(minter, 0),
2730 token::issuer(issuer),
2737 uint256 const offerMinterToIssuer =
2739 env(token::createOffer(minter, nftokenID, drops(1)),
2740 token::destination(issuer),
2743 uint256 const offerMinterToBuyer =
2745 env(token::createOffer(minter, nftokenID, drops(1)),
2746 token::destination(buyer),
2749 uint256 const offerIssuerToMinter =
2751 env(token::createOffer(issuer, nftokenID, drops(1)),
2752 token::owner(minter),
2753 token::destination(minter));
2755 uint256 const offerIssuerToBuyer =
2757 env(token::createOffer(issuer, nftokenID, drops(1)),
2758 token::owner(minter),
2759 token::destination(buyer));
2762 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2763 BEAST_EXPECT(ownerCount(env, minter) == 3);
2764 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2773 env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2775 env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2777 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2779 env(token::cancelOffer(minter, {offerIssuerToBuyer}),
2782 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2783 BEAST_EXPECT(ownerCount(env, minter) == 3);
2784 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2788 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2789 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2790 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2791 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2793 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2794 BEAST_EXPECT(ownerCount(env, minter) == 1);
2795 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2801 uint256 const offerMinterSellsToBuyer =
2803 env(token::createOffer(minter, nftokenID, drops(1)),
2804 token::destination(buyer),
2807 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2808 BEAST_EXPECT(ownerCount(env, minter) == 2);
2809 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2813 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer),
2816 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2817 BEAST_EXPECT(ownerCount(env, minter) == 2);
2818 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2821 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2823 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2824 BEAST_EXPECT(ownerCount(env, minter) == 0);
2825 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2831 uint256 const offerMinterBuysFromBuyer =
2833 env(token::createOffer(minter, nftokenID, drops(1)),
2834 token::owner(buyer),
2835 token::destination(buyer));
2837 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2838 BEAST_EXPECT(ownerCount(env, minter) == 1);
2839 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2843 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer),
2846 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2847 BEAST_EXPECT(ownerCount(env, minter) == 1);
2848 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2851 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2853 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2854 BEAST_EXPECT(ownerCount(env, minter) == 1);
2855 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2860 uint256 const offerBuyerBuysFromMinter =
2862 env(token::createOffer(buyer, nftokenID, drops(1)),
2863 token::owner(minter),
2864 token::destination(broker));
2866 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2867 BEAST_EXPECT(ownerCount(env, minter) == 1);
2868 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2870 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter),
2875 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2877 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2878 BEAST_EXPECT(ownerCount(env, minter) == 1);
2879 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2885 uint256 const offerMinterToBroker =
2887 env(token::createOffer(minter, nftokenID, drops(1)),
2888 token::destination(broker),
2891 uint256 const offerBuyerToMinter =
2893 env(token::createOffer(buyer, nftokenID, drops(1)),
2894 token::owner(minter));
2897 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2898 BEAST_EXPECT(ownerCount(env, minter) == 2);
2899 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2904 TER const expectTer = features[fixNonFungibleTokensV1_2]
2907 env(token::brokerOffers(
2908 issuer, offerBuyerToMinter, offerMinterToBroker),
2911 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2912 BEAST_EXPECT(ownerCount(env, minter) == 2);
2913 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2918 env(token::brokerOffers(
2919 broker, offerBuyerToMinter, offerMinterToBroker));
2921 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2922 BEAST_EXPECT(ownerCount(env, minter) == 0);
2923 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2930 uint256 const offerBuyerToMinter =
2932 env(token::createOffer(buyer, nftokenID, drops(1)),
2933 token::destination(minter),
2936 uint256 const offerMinterToBuyer =
2938 env(token::createOffer(minter, nftokenID, drops(1)),
2939 token::owner(buyer));
2941 uint256 const offerIssuerToBuyer =
2943 env(token::createOffer(issuer, nftokenID, drops(1)),
2944 token::owner(buyer));
2947 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2948 BEAST_EXPECT(ownerCount(env, minter) == 1);
2949 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2954 TER const expectTer = features[fixNonFungibleTokensV1_2]
2957 env(token::brokerOffers(
2958 broker, offerIssuerToBuyer, offerBuyerToMinter),
2962 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2963 BEAST_EXPECT(ownerCount(env, minter) == 1);
2964 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2968 TER const eexpectTer = features[fixNonFungibleTokensV1_2]
2971 env(token::brokerOffers(
2972 broker, offerMinterToBuyer, offerBuyerToMinter),
2976 if (features[fixNonFungibleTokensV1_2])
2978 env(token::acceptBuyOffer(buyer, offerMinterToBuyer));
2982 env(token::cancelOffer(buyer, {offerBuyerToMinter}));
2985 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2986 BEAST_EXPECT(ownerCount(env, minter) == 1);
2987 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2990 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2992 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2993 BEAST_EXPECT(ownerCount(env, minter) == 1);
2994 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3002 uint256 const offerMinterToBroker =
3004 env(token::createOffer(minter, nftokenID, drops(1)),
3005 token::destination(broker),
3008 uint256 const offerBuyerToBroker =
3010 env(token::createOffer(buyer, nftokenID, drops(1)),
3011 token::owner(minter),
3012 token::destination(broker));
3017 TER const expectTer = features[fixNonFungibleTokensV1_2]
3020 env(token::brokerOffers(
3021 issuer, offerBuyerToBroker, offerMinterToBroker),
3024 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3025 BEAST_EXPECT(ownerCount(env, minter) == 2);
3026 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3030 env(token::brokerOffers(
3031 broker, offerBuyerToBroker, offerMinterToBroker));
3033 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3034 BEAST_EXPECT(ownerCount(env, minter) == 0);
3035 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3042 testcase(
"Create offer destination disallow incoming");
3044 using namespace test::jtx;
3049 Account
const alice{
"alice"};
3050 env.fund(XRP(10000), alice);
3053 auto const sle = env.le(alice);
3054 uint32_t flags = sle->getFlags();
3060 Account
const issuer{
"issuer"};
3061 Account
const minter{
"minter"};
3062 Account
const buyer{
"buyer"};
3063 Account
const alice{
"alice"};
3065 env.fund(XRP(1000), issuer, minter, buyer, alice);
3067 env(token::setMinter(issuer, minter));
3072 env(token::mint(minter, 0),
3073 token::issuer(issuer),
3083 env(token::createOffer(minter, nftokenID, drops(1)),
3084 token::destination(buyer),
3088 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3089 BEAST_EXPECT(ownerCount(env, minter) == 1);
3090 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3102 env(token::createOffer(minter, nftokenID, drops(1)),
3103 token::destination(buyer),
3107 env(token::cancelOffer(minter, {offerIndex}));
3116 env(token::createOffer(minter, nftokenID, drops(1)),
3117 token::destination(buyer),
3124 env(token::cancelOffer(minter, {offerIndex}));
3136 env(token::createOffer(minter, nftokenID, drops(1)),
3137 token::destination(buyer),
3141 env(token::acceptSellOffer(buyer, offerIndex));
3153 env(token::createOffer(alice, nftokenID, drops(1)),
3154 token::owner(buyer),
3161 env(token::createOffer(minter, nftokenID, drops(1)),
3162 token::owner(buyer),
3168 if (features[featureNFTokenMintOffer])
3173 env(token::mint(minter),
3174 token::amount(drops(1)),
3175 token::destination(buyer),
3181 env(token::mint(minter),
3182 token::amount(drops(1)),
3183 token::destination(buyer));
3192 testcase(
"Create offer expiration");
3194 using namespace test::jtx;
3196 Env env{*
this, features};
3198 Account
const issuer{
"issuer"};
3199 Account
const minter{
"minter"};
3200 Account
const buyer{
"buyer"};
3202 env.fund(XRP(1000), issuer, minter, buyer);
3206 env(token::setMinter(issuer, minter));
3211 env(token::mint(minter, 0),
3212 token::issuer(issuer),
3218 env(token::mint(minter, 0),
3219 token::issuer(issuer),
3228 uint256 const offerMinterToIssuer =
3230 env(token::createOffer(minter, nftokenID0, drops(1)),
3231 token::destination(issuer),
3232 token::expiration(expiration),
3235 uint256 const offerMinterToAnyone =
3237 env(token::createOffer(minter, nftokenID0, drops(1)),
3238 token::expiration(expiration),
3241 uint256 const offerIssuerToMinter =
3243 env(token::createOffer(issuer, nftokenID0, drops(1)),
3244 token::owner(minter),
3245 token::expiration(expiration));
3247 uint256 const offerBuyerToMinter =
3249 env(token::createOffer(buyer, nftokenID0, drops(1)),
3250 token::owner(minter),
3251 token::expiration(expiration));
3253 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3254 BEAST_EXPECT(ownerCount(env, minter) == 3);
3255 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3263 env(token::cancelOffer(issuer, {offerMinterToAnyone}),
3265 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
3268 BEAST_EXPECT(
lastClose(env) < expiration);
3269 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3270 BEAST_EXPECT(ownerCount(env, minter) == 3);
3271 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3274 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3278 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3284 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3285 BEAST_EXPECT(ownerCount(env, minter) == 1);
3286 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3289 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3290 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3292 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3293 BEAST_EXPECT(ownerCount(env, minter) == 1);
3294 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3305 env(token::createOffer(minter, nftokenID0, drops(1)),
3306 token::expiration(expiration),
3311 env(token::createOffer(minter, nftokenID1, drops(1)),
3312 token::expiration(expiration),
3315 BEAST_EXPECT(
lastClose(env) < expiration);
3316 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3317 BEAST_EXPECT(ownerCount(env, minter) == 3);
3318 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3321 env(token::acceptSellOffer(buyer, offer0));
3327 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3328 BEAST_EXPECT(ownerCount(env, minter) == 2);
3329 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3332 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3333 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3337 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3338 BEAST_EXPECT(ownerCount(env, minter) == 2);
3339 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3342 env(token::cancelOffer(issuer, {offer1}));
3344 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3345 BEAST_EXPECT(ownerCount(env, minter) == 1);
3346 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3352 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3354 token::destination(minter));
3356 env(token::acceptSellOffer(minter, offerSellBack));
3358 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3359 BEAST_EXPECT(ownerCount(env, minter) == 1);
3360 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3370 env(token::createOffer(buyer, nftokenID0, drops(1)),
3371 token::owner(minter),
3372 token::expiration(expiration));
3375 env(token::createOffer(buyer, nftokenID1, drops(1)),
3376 token::owner(minter),
3377 token::expiration(expiration));
3379 BEAST_EXPECT(
lastClose(env) < expiration);
3380 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3381 BEAST_EXPECT(ownerCount(env, minter) == 1);
3382 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3385 env(token::acceptBuyOffer(minter, offer0));
3391 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3392 BEAST_EXPECT(ownerCount(env, minter) == 1);
3393 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3396 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3397 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3401 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3402 BEAST_EXPECT(ownerCount(env, minter) == 1);
3403 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3406 env(token::cancelOffer(issuer, {offer1}));
3408 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3409 BEAST_EXPECT(ownerCount(env, minter) == 1);
3410 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3416 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3418 token::destination(minter));
3420 env(token::acceptSellOffer(minter, offerSellBack));
3422 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3423 BEAST_EXPECT(ownerCount(env, minter) == 1);
3424 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3435 env(token::createOffer(minter, nftokenID0, drops(1)),
3436 token::expiration(expiration),
3441 env(token::createOffer(minter, nftokenID1, drops(1)),
3442 token::expiration(expiration),
3447 env(token::createOffer(buyer, nftokenID0, drops(1)),
3448 token::owner(minter));
3452 env(token::createOffer(buyer, nftokenID1, drops(1)),
3453 token::owner(minter));
3456 BEAST_EXPECT(
lastClose(env) < expiration);
3457 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3458 BEAST_EXPECT(ownerCount(env, minter) == 3);
3459 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3462 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3468 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3469 BEAST_EXPECT(ownerCount(env, minter) == 2);
3470 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3473 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3478 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3479 BEAST_EXPECT(ownerCount(env, minter) == 2);
3480 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3483 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3485 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3486 BEAST_EXPECT(ownerCount(env, minter) == 1);
3487 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3493 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3495 token::destination(minter));
3497 env(token::acceptSellOffer(minter, offerSellBack));
3499 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3500 BEAST_EXPECT(ownerCount(env, minter) == 1);
3501 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3512 env(token::createOffer(minter, nftokenID0, drops(1)),
3517 env(token::createOffer(minter, nftokenID1, drops(1)),
3522 env(token::createOffer(buyer, nftokenID0, drops(1)),
3523 token::expiration(expiration),
3524 token::owner(minter));
3528 env(token::createOffer(buyer, nftokenID1, drops(1)),
3529 token::expiration(expiration),
3530 token::owner(minter));
3533 BEAST_EXPECT(
lastClose(env) < expiration);
3534 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3535 BEAST_EXPECT(ownerCount(env, minter) == 3);
3536 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3539 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3545 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3546 BEAST_EXPECT(ownerCount(env, minter) == 2);
3547 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3550 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3555 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3556 BEAST_EXPECT(ownerCount(env, minter) == 2);
3557 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3560 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3562 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3563 BEAST_EXPECT(ownerCount(env, minter) == 1);
3564 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3570 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3572 token::destination(minter));
3574 env(token::acceptSellOffer(minter, offerSellBack));
3576 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3577 BEAST_EXPECT(ownerCount(env, minter) == 1);
3578 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3590 env(token::createOffer(minter, nftokenID0, drops(1)),
3591 token::expiration(expiration),
3596 env(token::createOffer(minter, nftokenID1, drops(1)),
3597 token::expiration(expiration),
3602 env(token::createOffer(buyer, nftokenID0, drops(1)),
3603 token::expiration(expiration),
3604 token::owner(minter));
3608 env(token::createOffer(buyer, nftokenID1, drops(1)),
3609 token::expiration(expiration),
3610 token::owner(minter));
3613 BEAST_EXPECT(
lastClose(env) < expiration);
3614 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3615 BEAST_EXPECT(ownerCount(env, minter) == 3);
3616 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3619 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3625 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3626 BEAST_EXPECT(ownerCount(env, minter) == 2);
3627 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3630 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3635 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3636 BEAST_EXPECT(ownerCount(env, minter) == 2);
3637 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3640 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3642 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3643 BEAST_EXPECT(ownerCount(env, minter) == 1);
3644 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3650 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3652 token::destination(minter));
3654 env(token::acceptSellOffer(minter, offerSellBack));
3656 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3657 BEAST_EXPECT(ownerCount(env, minter) == 1);
3658 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3668 using namespace test::jtx;
3670 Env env{*
this, features};
3672 Account
const alice(
"alice");
3673 Account
const becky(
"becky");
3674 Account
const minter(
"minter");
3675 env.fund(XRP(50000), alice, becky, minter);
3679 env(token::setMinter(alice, minter));
3688 uint256 const expiredOfferIndex =
3691 env(token::createOffer(alice, nftokenID, XRP(1000)),
3693 token::expiration(
lastClose(env) + 13));
3697 BEAST_EXPECT(ownerCount(env, alice) == 2);
3698 env(token::cancelOffer(becky, {expiredOfferIndex}),
3706 env(token::cancelOffer(becky, {expiredOfferIndex}));
3708 BEAST_EXPECT(ownerCount(env, alice) == 1);
3712 uint256 const dest1OfferIndex =
3715 env(token::createOffer(alice, nftokenID, XRP(1000)),
3716 token::destination(becky),
3719 BEAST_EXPECT(ownerCount(env, alice) == 2);
3722 env(token::cancelOffer(minter, {dest1OfferIndex}),
3725 BEAST_EXPECT(ownerCount(env, alice) == 2);
3727 env(token::cancelOffer(becky, {dest1OfferIndex}));
3729 BEAST_EXPECT(ownerCount(env, alice) == 1);
3732 uint256 const dest2OfferIndex =
3735 env(token::createOffer(alice, nftokenID, XRP(1000)),
3736 token::destination(becky),
3739 BEAST_EXPECT(ownerCount(env, alice) == 2);
3741 env(token::cancelOffer(alice, {dest2OfferIndex}));
3743 BEAST_EXPECT(ownerCount(env, alice) == 1);
3748 uint256 const mintersNFTokenID =
3750 env(token::mint(minter, 0),
3751 token::issuer(alice),
3755 uint256 const minterOfferIndex =
3758 env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3761 BEAST_EXPECT(ownerCount(env, minter) == 2);
3764 env(token::cancelOffer(alice, {minterOfferIndex}),
3766 env(token::cancelOffer(becky, {minterOfferIndex}),
3769 BEAST_EXPECT(ownerCount(env, minter) == 2);
3771 env(token::cancelOffer(minter, {minterOfferIndex}));
3773 BEAST_EXPECT(ownerCount(env, minter) == 1);
3780 testcase(
"Cancel too many offers");
3782 using namespace test::jtx;
3784 Env env{*
this, features};
3799 Account
const alice(
"alice");
3800 env.fund(XRP(1000), alice);
3809 Account
const offerAcct(
3811 env.fund(XRP(1000), nftAcct, offerAcct);
3816 env(token::mint(nftAcct, 0),
3823 env(token::createOffer(offerAcct, nftokenID, drops(1)),
3824 token::owner(nftAcct),
3833 for (
uint256 const& offerIndex : offerIndexes)
3840 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3844 env(token::cancelOffer(alice, {offerIndexes.
back()}));
3855 env(token::mint(alice, 0),
3861 env(token::createOffer(alice, nftokenID, drops(1)),
3866 BEAST_EXPECT(ownerCount(env, alice) == 2);
3870 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3874 env(token::burn(alice, nftokenID));
3879 BEAST_EXPECT(ownerCount(env, alice) == 0);
3885 env(token::cancelOffer(alice, offerIndexes));
3889 for (
uint256 const& offerIndex : offerIndexes)
3899 testcase(
"Brokered NFT offer accept");
3901 using namespace test::jtx;
3903 for (
auto const& tweakedFeatures :
3904 {features - fixNonFungibleTokensV1_2,
3905 features | fixNonFungibleTokensV1_2})
3907 Env env{*
this, tweakedFeatures};
3915 Account
const issuer{
"issuer"};
3916 Account
const minter{
"minter"};
3917 Account
const buyer{
"buyer"};
3918 Account
const broker{
"broker"};
3919 Account
const gw{
"gw"};
3920 IOU
const gwXAU(gw[
"XAU"]);
3922 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3925 env(trust(issuer, gwXAU(2000)));
3926 env(trust(minter, gwXAU(2000)));
3927 env(trust(buyer, gwXAU(2000)));
3928 env(trust(broker, gwXAU(2000)));
3931 env(token::setMinter(issuer, minter));
3935 auto checkOwnerCountIsOne =
3940 for (Account
const& acct : accounts)
3947 ss <<
"Account " << acct.human()
3948 <<
" expected ownerCount == 1. Got "
3950 fail(ss.
str(), __FILE__, line);
3956 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3959 env(token::mint(minter, 0),
3960 token::issuer(issuer),
3961 token::xferFee(xferFee),
3973 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3975 uint256 const nftID = mintNFT();
3978 uint256 const minterOfferIndex =
3980 env(token::createOffer(minter, nftID, XRP(0)),
3988 env(token::createOffer(buyer, nftID, XRP(1)),
3989 token::owner(minter));
3992 auto const minterBalance = env.balance(minter);
3993 auto const buyerBalance = env.balance(buyer);
3994 auto const brokerBalance = env.balance(broker);
3995 auto const issuerBalance = env.balance(issuer);
3998 env(token::brokerOffers(
3999 broker, buyOfferIndex, minterOfferIndex));
4004 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
4005 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4006 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
4007 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4010 env(token::burn(buyer, nftID));
4020 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4022 uint256 const nftID = mintNFT();
4025 uint256 const minterOfferIndex =
4027 env(token::createOffer(minter, nftID, XRP(0)),
4035 env(token::createOffer(buyer, nftID, XRP(1)),
4036 token::owner(minter));
4040 env(token::brokerOffers(
4041 broker, buyOfferIndex, minterOfferIndex),
4042 token::brokerFee(XRP(1.1)),
4046 auto const minterBalance = env.balance(minter);
4047 auto const buyerBalance = env.balance(buyer);
4048 auto const brokerBalance = env.balance(broker);
4049 auto const issuerBalance = env.balance(issuer);
4052 env(token::brokerOffers(
4053 broker, buyOfferIndex, minterOfferIndex),
4054 token::brokerFee(XRP(0.5)));
4059 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4060 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4062 env.balance(broker) ==
4063 brokerBalance + XRP(0.5) - drops(10));
4064 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4067 env(token::burn(buyer, nftID));
4077 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4082 uint256 const minterOfferIndex =
4084 env(token::createOffer(minter, nftID, XRP(0)),
4092 env(token::createOffer(buyer, nftID, XRP(1)),
4093 token::owner(minter));
4096 auto const minterBalance = env.balance(minter);
4097 auto const buyerBalance = env.balance(buyer);
4098 auto const brokerBalance = env.balance(broker);
4099 auto const issuerBalance = env.balance(issuer);
4102 env(token::brokerOffers(
4103 broker, buyOfferIndex, minterOfferIndex));
4108 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4109 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4110 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
4111 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
4114 env(token::burn(buyer, nftID));
4124 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4129 uint256 const minterOfferIndex =
4131 env(token::createOffer(minter, nftID, XRP(0)),
4139 env(token::createOffer(buyer, nftID, XRP(1)),
4140 token::owner(minter));
4143 auto const minterBalance = env.balance(minter);
4144 auto const buyerBalance = env.balance(buyer);
4145 auto const brokerBalance = env.balance(broker);
4146 auto const issuerBalance = env.balance(issuer);
4149 env(token::brokerOffers(
4150 broker, buyOfferIndex, minterOfferIndex),
4151 token::brokerFee(XRP(0.75)));
4157 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
4158 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4160 env.balance(broker) ==
4161 brokerBalance + XRP(0.75) - drops(10));
4162 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
4165 env(token::burn(buyer, nftID));
4171 auto setXAUBalance =
4172 [
this, &gw, &gwXAU, &env](
4177 for (Account
const& acct : accounts)
4179 auto const xauAmt = gwXAU(amount);
4180 auto const balance = env.balance(acct, gwXAU);
4181 if (balance < xauAmt)
4183 env(pay(gw, acct, xauAmt - balance));
4186 else if (balance > xauAmt)
4188 env(pay(acct, gw, balance - xauAmt));
4191 if (env.balance(acct, gwXAU) != xauAmt)
4194 ss <<
"Unable to set " << acct.human()
4195 <<
" account balance to gwXAU(" << amount <<
")";
4196 this->
fail(ss.
str(), __FILE__, line);
4204 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4205 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4207 uint256 const nftID = mintNFT();
4210 uint256 const minterOfferIndex =
4212 env(token::createOffer(minter, nftID, gwXAU(1000)),
4221 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4222 token::owner(minter));
4226 env(token::brokerOffers(
4227 broker, buyOfferIndex, minterOfferIndex),
4233 env(token::cancelOffer(buyer, {buyOfferIndex}));
4241 env(token::createOffer(buyer, nftID, gwXAU(999)),
4242 token::owner(minter));
4246 env(token::brokerOffers(
4247 broker, buyOfferIndex, minterOfferIndex),
4253 env(token::cancelOffer(buyer, {buyOfferIndex}));
4260 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4261 token::owner(minter));
4265 env(token::brokerOffers(
4266 broker, buyOfferIndex, minterOfferIndex),
4267 token::brokerFee(gwXAU(0.1)),
4272 env(token::brokerOffers(
4273 broker, buyOfferIndex, minterOfferIndex));
4276 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4277 BEAST_EXPECT(ownerCount(env, minter) == 1);
4278 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4279 BEAST_EXPECT(ownerCount(env, broker) == 1);
4280 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4281 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4282 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4283 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4286 env(token::burn(buyer, nftID));
4293 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4294 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4299 uint256 const minterOfferIndex =
4301 env(token::createOffer(minter, nftID, gwXAU(900)),
4309 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4310 token::owner(minter));
4314 env(token::brokerOffers(
4315 broker, buyOfferIndex, minterOfferIndex),
4321 env(token::cancelOffer(buyer, {buyOfferIndex}));
4329 env(token::createOffer(buyer, nftID, gwXAU(899)),
4330 token::owner(minter));
4334 env(token::brokerOffers(
4335 broker, buyOfferIndex, minterOfferIndex),
4341 env(token::cancelOffer(buyer, {buyOfferIndex}));
4347 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4348 token::owner(minter));
4353 env(token::brokerOffers(
4354 broker, buyOfferIndex, minterOfferIndex),
4355 token::brokerFee(gwXAU(101)),
4361 env(token::brokerOffers(
4362 broker, buyOfferIndex, minterOfferIndex),
4363 token::brokerFee(gwXAU(100)));
4366 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4367 BEAST_EXPECT(ownerCount(env, minter) == 1);
4368 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4369 BEAST_EXPECT(ownerCount(env, broker) == 1);
4370 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4371 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4372 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4373 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4376 env(token::burn(buyer, nftID));
4383 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4384 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4389 uint256 const minterOfferIndex =
4391 env(token::createOffer(minter, nftID, gwXAU(900)),
4398 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4399 token::owner(minter));
4405 env(token::brokerOffers(
4406 broker, buyOfferIndex, minterOfferIndex),
4407 token::brokerFee(gwXAU(50)));
4410 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4411 BEAST_EXPECT(ownerCount(env, minter) == 1);
4412 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4413 BEAST_EXPECT(ownerCount(env, broker) == 1);
4414 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4415 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4416 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4417 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4420 env(token::burn(buyer, nftID));
4425 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4426 setXAUBalance({issuer, minter, buyer}, 1000, __LINE__);
4427 setXAUBalance({broker}, 500, __LINE__);
4431 uint256 const minterOfferIndex =
4433 env(token::createOffer(minter, nftID, gwXAU(900)),
4440 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4441 token::owner(minter));
4444 if (tweakedFeatures[fixNonFungibleTokensV1_2])
4446 env(token::brokerOffers(
4447 broker, buyOfferIndex, minterOfferIndex),
4448 token::brokerFee(gwXAU(50)));
4450 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4451 BEAST_EXPECT(ownerCount(env, minter) == 1);
4452 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4453 BEAST_EXPECT(ownerCount(env, broker) == 1);
4454 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4455 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4456 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4457 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(550));
4460 env(token::burn(buyer, nftID));
4465 env(token::brokerOffers(
4466 broker, buyOfferIndex, minterOfferIndex),
4467 token::brokerFee(gwXAU(50)),
4470 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4471 BEAST_EXPECT(ownerCount(env, minter) == 3);
4472 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4473 BEAST_EXPECT(ownerCount(env, broker) == 1);
4474 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4475 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4476 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
4477 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(500));
4480 env(token::burn(minter, nftID));
4493 using namespace test::jtx;
4495 Env env{*
this, features};
4497 Account
const issuer{
"issuer"};
4498 Account
const buyer1{
"buyer1"};
4499 Account
const buyer2{
"buyer2"};
4500 env.fund(XRP(10000), issuer, buyer1, buyer2);
4509 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4510 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4511 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4514 uint256 const buyer1OfferIndex =
4516 env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer));
4517 uint256 const buyer2OfferIndex =
4519 env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer));
4529 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4531 if (buyOffers.
isMember(jss::result) &&
4532 buyOffers[jss::result].
isMember(jss::offers))
4533 return buyOffers[jss::result][jss::offers].
size();
4539 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4542 env(token::acceptBuyOffer(issuer, buyer1OfferIndex));
4546 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4547 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4548 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4552 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4556 env(token::acceptBuyOffer(buyer1, buyer2OfferIndex));
4560 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4561 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4562 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4565 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4572 testcase(
"NFToken transactions with tickets");
4574 using namespace test::jtx;
4576 Env env{*
this, features};
4578 Account
const issuer{
"issuer"};
4579 Account
const buyer{
"buyer"};
4580 env.fund(XRP(10000), issuer, buyer);
4587 env(ticket::create(issuer, 10));
4593 env(ticket::create(buyer, 10));
4599 BEAST_EXPECT(ownerCount(env, issuer) == 10);
4601 env(token::mint(issuer, 0u),
4603 ticket::use(issuerTicketSeq++));
4605 BEAST_EXPECT(ownerCount(env, issuer) == 10);
4609 BEAST_EXPECT(ownerCount(env, buyer) == 10);
4611 env(token::createOffer(buyer, nftId, XRP(1)),
4612 token::owner(issuer),
4613 ticket::use(buyerTicketSeq++));
4615 BEAST_EXPECT(ownerCount(env, buyer) == 10);
4619 env(token::cancelOffer(buyer, {offerIndex0}),
4620 ticket::use(buyerTicketSeq++));
4622 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4627 env(token::createOffer(buyer, nftId, XRP(2)),
4628 token::owner(issuer),
4629 ticket::use(buyerTicketSeq++));
4631 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4635 env(token::acceptBuyOffer(issuer, offerIndex1),
4636 ticket::use(issuerTicketSeq++));
4638 BEAST_EXPECT(ownerCount(env, issuer) == 8);
4639 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4643 env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4645 BEAST_EXPECT(ownerCount(env, issuer) == 8);
4646 BEAST_EXPECT(ownerCount(env, buyer) == 6);
4650 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4651 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4662 testcase(
"NFToken delete account");
4664 using namespace test::jtx;
4666 Env env{*
this, features};
4668 Account
const issuer{
"issuer"};
4669 Account
const minter{
"minter"};
4670 Account
const becky{
"becky"};
4671 Account
const carla{
"carla"};
4672 Account
const daria{
"daria"};
4674 env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4678 for (
int i = 0; i < 300; ++i)
4681 env(token::setMinter(issuer, minter));
4685 env(token::mint(minter, 0u),
4686 token::issuer(issuer),
4699 for (
int i = 0; i < 15; ++i)
4703 env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4706 uint256 const carlaOfferIndex =
4708 env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4713 env(acctdelete(becky, daria), fee(XRP(50)));
4717 env(token::acceptBuyOffer(minter, carlaOfferIndex));
4722 env(acctdelete(minter, daria), fee(XRP(50)));
4734 for (
int i = 0; i < 15; ++i)
4739 env(token::burn(carla, nftId));
4742 env(acctdelete(issuer, daria), fee(XRP(50)));
4743 env(acctdelete(carla, daria), fee(XRP(50)));
4750 testcase(
"nft_buy_offers and nft_sell_offers");
4759 using namespace test::jtx;
4761 Env env{*
this, features};
4763 Account
const issuer{
"issuer"};
4764 Account
const buyer{
"buyer"};
4767 env.fund(XRP(1000000), issuer, buyer);
4776 auto checkOffers = [
this, &env, &nftID](
4777 char const* request,
4779 int expectMarkerCount,
4781 int markerCount = 0;
4788 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4792 if (!marker.
empty())
4793 params[jss::marker] = marker;
4794 return env.rpc(
"json", request,
to_string(params));
4798 if (expectCount == 0)
4802 "expected \"result\"",
4807 nftOffers[jss::result].isMember(jss::error),
4808 "expected \"error\"",
4813 nftOffers[jss::result][jss::error].asString() ==
4815 "expected \"objectNotFound\"",
4826 "expected \"result\"",
4835 marker = result[jss::marker].
asString();
4840 "expected \"offers\"",
4846 allOffers.
append(someOffers[i]);
4849 }
while (!marker.
empty());
4853 allOffers.
size() == expectCount,
4854 "Unexpected returned offer count",
4858 markerCount == expectMarkerCount,
4859 "Unexpected marker count",
4869 globalFlags = offer[jss::flags].asInt();
4872 *globalFlags == offer[jss::flags].asInt(),
4873 "Inconsistent flags returned",
4879 offerIndexes.
insert(offer[jss::nft_offer_index].asString());
4880 amounts.
insert(offer[jss::amount].asString());
4884 offerIndexes.
size() == expectCount,
4885 "Duplicate indexes returned?",
4889 amounts.
size() == expectCount,
4890 "Duplicate amounts returned?",
4896 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4900 auto makeSellOffers =
4901 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4904 while (sellPrice < limit)
4906 sellPrice += XRP(1);
4907 env(token::createOffer(issuer, nftID, sellPrice),
4909 if (++offerCount % 10 == 0)
4916 makeSellOffers(XRP(1));
4917 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4920 makeSellOffers(XRP(250));
4921 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4924 makeSellOffers(XRP(251));
4925 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4928 makeSellOffers(XRP(500));
4929 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4932 makeSellOffers(XRP(501));
4933 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4936 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4940 auto makeBuyOffers =
4941 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4944 while (buyPrice < limit)
4947 env(token::createOffer(buyer, nftID, buyPrice),
4948 token::owner(issuer));
4949 if (++offerCount % 10 == 0)
4956 makeBuyOffers(XRP(1));
4957 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4960 makeBuyOffers(XRP(250));
4961 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4964 makeBuyOffers(XRP(251));
4965 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4968 makeBuyOffers(XRP(500));
4969 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4972 makeBuyOffers(XRP(501));
4973 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4980 using namespace test::jtx;
4984 Account
const issuer{
"issuer"};
4985 Account
const buyer{
"buyer"};
4986 Account
const gw{
"gw"};
4987 IOU
const gwXAU(gw[
"XAU"]);
4993 for (
auto const& tweakedFeatures :
4994 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1 -
4995 fixNonFungibleTokensV1_2,
4996 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
4997 features | fixNFTokenNegOffer})
5002 Env env{*
this, tweakedFeatures};
5004 env.fund(XRP(1000000), issuer, buyer, gw);
5007 env(trust(issuer, gwXAU(2000)));
5008 env(trust(buyer, gwXAU(2000)));
5011 env(pay(gw, issuer, gwXAU(1000)));
5012 env(pay(gw, buyer, gwXAU(1000)));
5027 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5032 uint256 const sellNegXrpOfferIndex =
5034 env(token::createOffer(issuer, nftID0, XRP(-2)),
5036 ter(offerCreateTER));
5039 uint256 const sellNegIouOfferIndex =
5041 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
5043 ter(offerCreateTER));
5046 uint256 const buyNegXrpOfferIndex =
5048 env(token::createOffer(buyer, nftID0, XRP(-1)),
5049 token::owner(issuer),
5050 ter(offerCreateTER));
5053 uint256 const buyNegIouOfferIndex =
5055 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
5056 token::owner(issuer),
5057 ter(offerCreateTER));
5064 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5069 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
5070 ter(offerAcceptTER));
5072 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
5073 ter(offerAcceptTER));
5077 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
5078 ter(offerAcceptTER));
5080 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
5081 ter(offerAcceptTER));
5089 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5094 env(token::brokerOffers(
5095 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5096 ter(offerAcceptTER));
5098 env(token::brokerOffers(
5099 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5100 ter(offerAcceptTER));
5110 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1};
5112 env.fund(XRP(1000000), issuer, buyer, gw);
5115 env(trust(issuer, gwXAU(2000)));
5116 env(trust(buyer, gwXAU(2000)));
5119 env(pay(gw, issuer, gwXAU(1000)));
5120 env(pay(gw, buyer, gwXAU(1000)));
5136 uint256 const sellNegXrpOfferIndex =
5138 env(token::createOffer(issuer, nftID0, XRP(-2)),
5142 uint256 const sellNegIouOfferIndex =
5144 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
5148 uint256 const buyNegXrpOfferIndex =
5150 env(token::createOffer(buyer, nftID0, XRP(-1)),
5151 token::owner(issuer));
5154 uint256 const buyNegIouOfferIndex =
5156 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
5157 token::owner(issuer));
5161 env.enableFeature(fixNFTokenNegOffer);
5166 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
5169 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
5174 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
5177 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
5182 env(token::brokerOffers(
5183 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5186 env(token::brokerOffers(
5187 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5194 for (
auto const& tweakedFeatures :
5195 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
5196 features | fixNFTokenNegOffer})
5198 Env env{*
this, tweakedFeatures};
5200 env.fund(XRP(1000000), issuer, buyer);
5208 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5212 env(token::createOffer(buyer, nftID, drops(1)),
5213 token::owner(issuer),
5214 token::destination(issuer),
5215 ter(offerCreateTER));
5223 using namespace test::jtx;
5225 testcase(
"Payments with IOU transfer fees");
5227 for (
auto const& tweakedFeatures :
5228 {features - fixNonFungibleTokensV1_2,
5229 features | fixNonFungibleTokensV1_2})
5231 Env env{*
this, tweakedFeatures};
5233 Account
const minter{
"minter"};
5234 Account
const secondarySeller{
"seller"};
5235 Account
const buyer{
"buyer"};
5236 Account
const gw{
"gateway"};
5237 Account
const broker{
"broker"};
5238 IOU
const gwXAU(gw[
"XAU"]);
5239 IOU
const gwXPB(gw[
"XPB"]);
5241 env.fund(XRP(1000), gw, minter, secondarySeller, buyer, broker);
5244 env(trust(minter, gwXAU(2000)));
5245 env(trust(secondarySeller, gwXAU(2000)));
5246 env(trust(broker, gwXAU(10000)));
5247 env(trust(buyer, gwXAU(2000)));
5248 env(trust(buyer, gwXPB(2000)));
5252 env(rate(gw, 1.02));
5255 auto expectInitialState = [
this,
5268 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
5269 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(0));
5270 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(0));
5271 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(0));
5272 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(0));
5273 BEAST_EXPECT(env.balance(secondarySeller, gwXPB) == gwXPB(0));
5274 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5000));
5275 BEAST_EXPECT(env.balance(broker, gwXPB) == gwXPB(0));
5276 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-1000));
5277 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(0));
5278 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(0));
5279 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(0));
5281 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(0));
5283 env.balance(gw, secondarySeller[
"XPB"]) == gwXPB(0));
5284 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5000));
5285 BEAST_EXPECT(env.balance(gw, broker[
"XPB"]) == gwXPB(0));
5288 auto reinitializeTrustLineBalances = [&expectInitialState,
5297 if (
auto const difference =
5298 gwXAU(1000) - env.balance(buyer, gwXAU);
5299 difference > gwXAU(0))
5300 env(pay(gw, buyer, difference));
5301 if (env.balance(buyer, gwXPB) > gwXPB(0))
5302 env(pay(buyer, gw, env.balance(buyer, gwXPB)));
5303 if (env.balance(minter, gwXAU) > gwXAU(0))
5304 env(pay(minter, gw, env.balance(minter, gwXAU)));
5305 if (env.balance(minter, gwXPB) > gwXPB(0))
5306 env(pay(minter, gw, env.balance(minter, gwXPB)));
5307 if (env.balance(secondarySeller, gwXAU) > gwXAU(0))
5309 pay(secondarySeller,
5311 env.balance(secondarySeller, gwXAU)));
5312 if (env.balance(secondarySeller, gwXPB) > gwXPB(0))
5314 pay(secondarySeller,
5316 env.balance(secondarySeller, gwXPB)));
5317 auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU);
5318 if (brokerDiff > gwXAU(0))
5319 env(pay(gw, broker, brokerDiff));
5320 else if (brokerDiff < gwXAU(0))
5322 brokerDiff.negate();
5323 env(pay(broker, gw, brokerDiff));
5325 if (env.balance(broker, gwXPB) > gwXPB(0))
5326 env(pay(broker, gw, env.balance(broker, gwXPB)));
5328 expectInitialState();
5331 auto mintNFT = [&env](Account
const& minter,
int transferFee = 0) {
5332 uint256 const nftID = token::getNextID(
5334 env(token::mint(minter),
5335 token::xferFee(transferFee),
5341 auto createBuyOffer =
5343 Account
const& offerer,
5344 Account
const& owner,
5350 env(token::createOffer(offerer, nftID, amount),
5351 token::owner(owner),
5352 terCode ? ter(*terCode)
5358 auto createSellOffer =
5360 Account
const& offerer,
5366 env(token::createOffer(offerer, nftID, amount),
5368 terCode ? ter(*terCode)
5377 reinitializeTrustLineBalances();
5378 auto const nftID = mintNFT(minter);
5379 auto const offerID =
5380 createSellOffer(minter, nftID, gwXAU(1000));
5381 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5384 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5387 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5388 expectInitialState();
5391 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5392 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5394 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5395 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5401 reinitializeTrustLineBalances();
5402 auto const nftID = mintNFT(minter);
5403 auto const offerID =
5404 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5405 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5408 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5411 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5412 expectInitialState();
5415 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5416 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5418 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5419 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5426 reinitializeTrustLineBalances();
5427 auto const nftID = mintNFT(minter);
5428 auto const offerID = createSellOffer(minter, nftID, gwXAU(995));
5429 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5432 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5435 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5436 expectInitialState();
5439 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5440 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5441 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5442 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5449 reinitializeTrustLineBalances();
5450 auto const nftID = mintNFT(minter);
5451 auto const offerID =
5452 createBuyOffer(buyer, minter, nftID, gwXAU(995));
5453 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5456 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5459 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5460 expectInitialState();
5463 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5464 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5465 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5466 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5474 reinitializeTrustLineBalances();
5475 auto const nftID = mintNFT(minter);
5476 auto const offerID = createSellOffer(minter, nftID, gwXAU(900));
5477 env(token::acceptSellOffer(buyer, offerID));
5480 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5481 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5482 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5483 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5490 reinitializeTrustLineBalances();
5491 auto const nftID = mintNFT(minter);
5492 auto const offerID =
5493 createBuyOffer(buyer, minter, nftID, gwXAU(900));
5494 env(token::acceptBuyOffer(minter, offerID));
5497 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5498 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5499 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5500 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5507 reinitializeTrustLineBalances();
5510 env(pay(gw, buyer, gwXAU(20)));
5513 auto const nftID = mintNFT(minter);
5514 auto const offerID =
5515 createSellOffer(minter, nftID, gwXAU(1000));
5516 env(token::acceptSellOffer(buyer, offerID));
5519 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5520 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5521 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5522 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5529 reinitializeTrustLineBalances();
5532 env(pay(gw, buyer, gwXAU(20)));
5535 auto const nftID = mintNFT(minter);
5536 auto const offerID =
5537 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5538 env(token::acceptBuyOffer(minter, offerID));
5541 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5542 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5543 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5544 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5549 reinitializeTrustLineBalances();
5551 auto const nftID = mintNFT(minter);
5552 auto const offerID =
5553 createSellOffer(minter, nftID, gwXAU(1000));
5554 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5557 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5560 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5562 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5564 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5567 expectInitialState();
5572 reinitializeTrustLineBalances();
5574 auto const nftID = mintNFT(minter);
5575 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5578 auto const offerID =
5579 createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER});
5580 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5583 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5586 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5588 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5590 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5593 expectInitialState();
5598 reinitializeTrustLineBalances();
5599 auto const nftID = mintNFT(minter);
5600 auto const offerID =
5601 createSellOffer(minter, nftID, gwXAU(5000));
5602 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5605 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5608 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5610 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5612 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5615 expectInitialState();
5620 reinitializeTrustLineBalances();
5622 auto const nftID = mintNFT(minter);
5623 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5626 auto const offerID =
5627 createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER});
5628 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5631 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5634 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5636 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5638 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5641 expectInitialState();
5647 reinitializeTrustLineBalances();
5648 auto const nftID = mintNFT(gw);
5649 auto const offerID = createSellOffer(gw, nftID, gwXAU(1000));
5650 env(token::acceptSellOffer(buyer, offerID));
5653 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5654 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5660 reinitializeTrustLineBalances();
5662 auto const nftID = mintNFT(gw);
5663 auto const offerID =
5664 createBuyOffer(buyer, gw, nftID, gwXAU(1000));
5665 env(token::acceptBuyOffer(gw, offerID));
5668 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5669 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5675 reinitializeTrustLineBalances();
5676 auto const nftID = mintNFT(gw);
5677 auto const offerID = createSellOffer(gw, nftID, gwXAU(2000));
5678 env(token::acceptSellOffer(buyer, offerID),
5681 expectInitialState();
5687 reinitializeTrustLineBalances();
5688 auto const nftID = mintNFT(gw);
5689 auto const offerID =
5690 createBuyOffer(buyer, gw, nftID, gwXAU(2000));
5691 env(token::acceptBuyOffer(gw, offerID),
5694 expectInitialState();
5699 reinitializeTrustLineBalances();
5700 auto const nftID = mintNFT(minter);
5701 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5702 env(token::acceptSellOffer(buyer, offerID),
5705 expectInitialState();
5710 reinitializeTrustLineBalances();
5711 auto const nftID = mintNFT(minter);
5712 auto const offerID = createBuyOffer(
5718 env(token::acceptBuyOffer(minter, offerID),
5721 expectInitialState();
5727 reinitializeTrustLineBalances();
5728 env(pay(gw, buyer, gwXPB(100)));
5731 auto const nftID = mintNFT(minter);
5732 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5733 env(token::acceptSellOffer(buyer, offerID));
5736 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5737 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5738 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5739 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5745 reinitializeTrustLineBalances();
5746 env(pay(gw, buyer, gwXPB(100)));
5749 auto const nftID = mintNFT(minter);
5750 auto const offerID =
5751 createBuyOffer(buyer, minter, nftID, gwXPB(10));
5752 env(token::acceptBuyOffer(minter, offerID));
5755 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5756 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5757 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5758 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5763 reinitializeTrustLineBalances();
5767 auto const nftID = mintNFT(minter, 3000);
5768 auto const primaryOfferID =
5769 createSellOffer(minter, nftID, XRP(0));
5770 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5774 auto const offerID =
5775 createSellOffer(secondarySeller, nftID, gwXAU(1000));
5776 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5779 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5782 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5783 expectInitialState();
5786 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5788 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5789 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5790 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5792 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5793 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5799 reinitializeTrustLineBalances();
5803 auto const nftID = mintNFT(minter, 3000);
5804 auto const primaryOfferID =
5805 createSellOffer(minter, nftID, XRP(0));
5806 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5810 auto const offerID =
5811 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000));
5812 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5815 env(token::acceptBuyOffer(secondarySeller, offerID),
5819 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5820 expectInitialState();
5823 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5825 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5826 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5827 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5829 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5830 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5836 reinitializeTrustLineBalances();
5840 auto const nftID = mintNFT(minter, 3000);
5841 auto const primaryOfferID =
5842 createSellOffer(minter, nftID, XRP(0));
5843 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5847 auto const offerID =
5848 createSellOffer(secondarySeller, nftID, gwXAU(900));
5849 env(token::acceptSellOffer(buyer, offerID));
5852 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5853 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5854 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5855 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5857 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5858 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5863 reinitializeTrustLineBalances();
5867 auto const nftID = mintNFT(minter, 3000);
5868 auto const primaryOfferID =
5869 createSellOffer(minter, nftID, XRP(0));
5870 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5874 auto const offerID =
5875 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900));
5876 env(token::acceptBuyOffer(secondarySeller, offerID));
5880 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5882 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5884 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5885 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5887 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5888 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5906 reinitializeTrustLineBalances();
5908 auto const nftID = mintNFT(minter);
5909 auto const sellOffer =
5910 createSellOffer(minter, nftID, gwXAU(300));
5911 auto const buyOffer =
5912 createBuyOffer(buyer, minter, nftID, gwXAU(500));
5913 env(token::brokerOffers(broker, buyOffer, sellOffer),
5914 token::brokerFee(gwXAU(100)));
5917 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400));
5918 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5919 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5920 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-400));
5921 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5922 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5940 reinitializeTrustLineBalances();
5944 auto const nftID = mintNFT(minter, 3000);
5945 auto const primaryOfferID =
5946 createSellOffer(minter, nftID, XRP(0));
5947 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5951 auto const sellOffer =
5952 createSellOffer(secondarySeller, nftID, gwXAU(300));
5953 auto const buyOffer =
5954 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500));
5955 env(token::brokerOffers(broker, buyOffer, sellOffer),
5956 token::brokerFee(gwXAU(100)));
5959 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12));
5960 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5961 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(388));
5962 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5963 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-12));
5964 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5966 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-388));
5967 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5989 using namespace test::jtx;
5991 Account
const alice{
"alice"};
5992 Account
const bob{
"bob"};
5993 Account
const broker{
"broker"};
5995 Env env{*
this, features};
5996 env.fund(XRP(10000), alice, bob, broker);
6022 uint256 const bobBuyOfferIndex =
6024 env(token::createOffer(bob, nftId, XRP(5)), token::owner(alice));
6026 uint256 const aliceSellOfferIndex =
6028 env(token::createOffer(alice, nftId, XRP(0)),
6029 token::destination(bob),
6034 env(token::acceptSellOffer(bob, aliceSellOfferIndex));
6041 uint256 const bobSellOfferIndex =
6043 env(token::createOffer(bob, nftId, XRP(4)), txflags(
tfSellNFToken));
6048 BEAST_EXPECT(
nftCount(env, bob) == 1);
6049 auto const bobsPriorBalance = env.balance(bob);
6050 auto const brokersPriorBalance = env.balance(broker);
6051 TER expectTer = features[fixNonFungibleTokensV1_2]
6054 env(token::brokerOffers(broker, bobBuyOfferIndex, bobSellOfferIndex),
6055 token::brokerFee(XRP(1)),
6064 BEAST_EXPECT(
nftCount(env, bob) == 1);
6065 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance - XRP(1));
6067 env.balance(broker) ==
6068 brokersPriorBalance + XRP(1) - drops(10));
6074 BEAST_EXPECT(
nftCount(env, bob) == 1);
6075 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance);
6077 env.balance(broker) == brokersPriorBalance - drops(10));
6084 using namespace test::jtx;
6089 auto openLedgerSeq = [](Env& env) {
return env.current()->seq(); };
6094 auto incLgrSeqForAcctDel = [&](Env& env, Account
const& acct) {
6095 int const delta = [&]() ->
int {
6096 if (env.seq(acct) + 255 > openLedgerSeq(env))
6097 return env.seq(acct) - openLedgerSeq(env) + 255;
6100 BEAST_EXPECT(delta >= 0);
6101 for (
int i = 0; i < delta; ++i)
6103 BEAST_EXPECT(openLedgerSeq(env) == env.seq(acct) + 255);
6109 auto incLgrSeqForFixNftRemint = [&](Env& env, Account
const& acct) {
6111 auto const deletableLgrSeq =
6112 (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) +
6113 (*env.le(acct))[sfMintedNFTokens] + 255;
6115 if (deletableLgrSeq > openLedgerSeq(env))
6116 delta = deletableLgrSeq - openLedgerSeq(env);
6118 BEAST_EXPECT(delta >= 0);
6119 for (
int i = 0; i < delta; ++i)
6121 BEAST_EXPECT(openLedgerSeq(env) == deletableLgrSeq);
6127 Env env{*
this, features};
6128 Account
const alice(
"alice");
6129 Account
const becky(
"becky");
6131 env.fund(XRP(10000), alice, becky);
6135 uint256 const prevNFTokenID = token::getNextID(env, alice, 0u);
6136 env(token::mint(alice));
6138 env(token::burn(alice, prevNFTokenID));
6142 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 1);
6145 incLgrSeqForAcctDel(env, alice);
6149 auto const acctDelFee{drops(env.current()->fees().increment)};
6150 env(acctdelete(alice, becky), fee(acctDelFee));
6155 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6156 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6159 env.fund(XRP(10000), alice);
6163 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6164 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6165 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6168 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6169 env(token::mint(alice));
6173 env(token::burn(alice, remintNFTokenID));
6176 if (features[fixNFTokenRemint])
6178 BEAST_EXPECT(remintNFTokenID != prevNFTokenID);
6181 BEAST_EXPECT(remintNFTokenID == prevNFTokenID);
6187 Env env{*
this, features};
6188 Account
const alice(
"alice");
6189 Account
const becky(
"becky");
6190 Account
const minter{
"minter"};
6192 env.fund(XRP(10000), alice, becky, minter);
6196 env(token::setMinter(alice, minter));
6202 for (
int i = 0; i < 500; i++)
6204 uint256 const nftokenID = token::getNextID(env, alice, 0u);
6206 env(token::mint(minter), token::issuer(alice));
6211 for (
auto const nftokenID : nftIDs)
6213 env(token::burn(minter, nftokenID));
6219 incLgrSeqForAcctDel(env, alice);
6223 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6224 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6226 auto const acctDelFee{drops(env.current()->fees().increment)};
6228 if (!features[fixNFTokenRemint])
6231 env(acctdelete(alice, becky), fee(acctDelFee));
6233 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6236 env.fund(XRP(10000), alice);
6240 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6241 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6242 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6246 uint256 const remintNFTokenID =
6247 token::getNextID(env, alice, 0u);
6248 env(token::mint(alice));
6252 env(token::burn(alice, remintNFTokenID));
6261 else if (features[fixNFTokenRemint])
6270 env(acctdelete(alice, becky),
6276 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6281 incLgrSeqForFixNftRemint(env, alice);
6284 env(acctdelete(alice, becky), fee(acctDelFee));
6289 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6290 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6293 env.fund(XRP(10000), alice);
6297 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6298 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6299 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6303 uint256 const remintNFTokenID =
6304 token::getNextID(env, alice, 0u);
6305 env(token::mint(alice));
6309 env(token::burn(alice, remintNFTokenID));
6323 Env env{*
this, features};
6325 Account
const alice{
"alice"};
6326 Account
const becky{
"becky"};
6327 env.fund(XRP(10000), alice, becky);
6334 env(ticket::create(alice, 100));
6338 BEAST_EXPECT(ownerCount(env, alice) == 100);
6343 for (
int i = 0; i < 50; i++)
6345 nftIDs.
push_back(token::getNextID(env, alice, 0u));
6346 env(token::mint(alice, 0u), ticket::use(aliceTicketSeq++));
6351 for (
auto const nftokenID : nftIDs)
6353 env(token::burn(alice, nftokenID),
6354 ticket::use(aliceTicketSeq++));
6362 incLgrSeqForAcctDel(env, alice);
6366 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6367 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6369 auto const acctDelFee{drops(env.current()->fees().increment)};
6371 if (!features[fixNFTokenRemint])
6374 env(acctdelete(alice, becky), fee(acctDelFee));
6379 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6380 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6383 env.fund(XRP(10000), alice);
6387 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6388 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6389 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6393 uint256 const remintNFTokenID =
6394 token::getNextID(env, alice, 0u);
6395 env(token::mint(alice));
6399 env(token::burn(alice, remintNFTokenID));
6408 else if (features[fixNFTokenRemint])
6417 env(acctdelete(alice, becky),
6423 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6428 incLgrSeqForFixNftRemint(env, alice);
6431 env(acctdelete(alice, becky), fee(acctDelFee));
6436 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6437 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6440 env.fund(XRP(10000), alice);
6444 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6445 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6446 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6450 uint256 const remintNFTokenID =
6451 token::getNextID(env, alice, 0u);
6452 env(token::mint(alice));
6456 env(token::burn(alice, remintNFTokenID));
6472 if (features[fixNFTokenRemint])
6474 Env env{*
this, features};
6475 Account
const alice(
"alice");
6476 Account
const becky(
"becky");
6477 Account
const minter{
"minter"};
6479 env.fund(XRP(10000), alice, becky, minter);
6483 env(token::setMinter(alice, minter));
6488 env(ticket::create(minter, 100));
6492 BEAST_EXPECT(ownerCount(env, minter) == 100);
6497 for (
int i = 0; i < 50; i++)
6499 uint256 const nftokenID = token::getNextID(env, alice, 0u);
6501 env(token::mint(minter),
6502 token::issuer(alice),
6503 ticket::use(minterTicketSeq++));
6508 for (
auto const nftokenID : nftIDs)
6510 env(token::burn(minter, nftokenID),
6511 ticket::use(minterTicketSeq++));
6519 incLgrSeqForAcctDel(env, alice);
6523 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6524 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6533 auto const acctDelFee{drops(env.current()->fees().increment)};
6534 env(acctdelete(alice, becky), fee(acctDelFee), ter(
tecTOO_SOON));
6538 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6543 incLgrSeqForFixNftRemint(env, alice);
6546 env(acctdelete(alice, becky), fee(acctDelFee));
6551 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6552 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6555 env.fund(XRP(10000), alice);
6559 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6560 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6561 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6565 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6566 env(token::mint(alice));
6570 env(token::burn(alice, remintNFTokenID));
6584 testcase(
"NFTokenMint with Create NFTokenOffer");
6586 using namespace test::jtx;
6588 if (!features[featureNFTokenMintOffer])
6590 Env env{*
this, features};
6591 Account
const alice(
"alice");
6592 Account
const buyer(
"buyer");
6594 env.fund(XRP(10000), alice, buyer);
6597 env(token::mint(alice),
6598 token::amount(XRP(10000)),
6602 env(token::mint(alice),
6603 token::destination(
"buyer"),
6607 env(token::mint(alice),
6617 Env env{*
this, features};
6618 Account
const alice(
"alice");
6619 Account
const buyer{
"buyer"};
6620 Account
const gw(
"gw");
6621 Account
const issuer(
"issuer");
6622 Account
const minter(
"minter");
6623 Account
const bob(
"bob");
6624 IOU
const gwAUD(gw[
"AUD"]);
6626 env.fund(XRP(10000), alice, buyer, gw, issuer, minter);
6631 env(token::mint(alice),
6632 token::destination(buyer),
6635 BEAST_EXPECT(ownerCount(env, alice) == 0);
6638 env(token::mint(alice),
6642 BEAST_EXPECT(ownerCount(env, buyer) == 0);
6648 env(token::mint(alice),
6649 token::amount(XRP(1000)),
6650 token::destination(alice),
6653 BEAST_EXPECT(ownerCount(env, alice) == 0);
6657 env(token::mint(alice),
6658 token::amount(XRP(1000)),
6659 token::destination(Account(
"demon")),
6662 BEAST_EXPECT(ownerCount(env, alice) == 0);
6667 env(token::mint(alice),
6668 token::amount(XRP(1000)),
6669 token::expiration(0),
6672 BEAST_EXPECT(ownerCount(env, alice) == 0);
6675 env(token::mint(alice),
6676 token::amount(XRP(1000)),
6680 BEAST_EXPECT(ownerCount(env, alice) == 0);
6685 env(token::mint(alice),
6686 token::amount(buyer[
"USD"](1)),
6689 env(token::mint(alice),
6690 token::amount(buyer[
"USD"](0)),
6693 BEAST_EXPECT(ownerCount(env, alice) == 0);
6696 env(token::mint(alice),
6697 token::amount(gwAUD(1000)),
6702 BEAST_EXPECT(ownerCount(env, alice) == 0);
6707 env(token::mint(gw),
6708 token::amount(gwAUD(1000)),
6710 token::xferFee(10));
6719 env(token::mint(alice),
6720 token::amount(gwAUD(1000)),
6725 BEAST_EXPECT(ownerCount(env, alice) == 0);
6728 env(token::mint(alice),
6729 token::amount(gwAUD(1000)),
6732 BEAST_EXPECT(ownerCount(env, alice) == 0);
6741 auto const acctReserve =
6742 env.current()->fees().accountReserve(0);
6743 auto const incReserve = env.current()->fees().increment;
6745 env.fund(acctReserve + incReserve, bob);
6749 env(token::mint(bob),
6750 token::amount(XRP(0)),
6755 env(pay(env.master, bob, incReserve + drops(10)));
6757 env(token::mint(bob), token::amount(XRP(0)));
6761 env(pay(env.master, bob, drops(10)));
6763 env(token::mint(bob),
6764 token::amount(XRP(0)),
6769 env(pay(env.master, bob, incReserve + drops(10)));
6771 env(token::mint(bob), token::amount(XRP(0)));
6776 BEAST_EXPECT(ownerCount(env, alice) == 0);
6777 env(token::mint(alice), token::amount(XRP(10)));
6778 BEAST_EXPECT(ownerCount(env, alice) == 2);
6782 env(token::mint(alice),
6783 token::amount(XRP(10)),
6784 token::destination(buyer),
6785 token::expiration(
lastClose(env) + 25));
6789 env(trust(alice, gwAUD(1000)));
6791 env(token::mint(alice),
6792 token::amount(gwAUD(1)),
6793 token::destination(buyer),
6796 token::xferFee(10));
6800 env(token::mint(alice),
6801 token::amount(XRP(10)),
6802 token::destination(buyer),
6803 token::expiration(
lastClose(env) + 25));
6804 uint256 const offerAliceSellsToBuyer =
6806 env(token::cancelOffer(alice, {offerAliceSellsToBuyer}));
6810 env(token::mint(buyer),
6811 token::amount(XRP(10)),
6812 token::destination(alice),
6813 token::expiration(
lastClose(env) + 25));
6814 uint256 const offerBuyerSellsToAlice =
6816 env(token::cancelOffer(alice, {offerBuyerSellsToAlice}));
6819 env(token::setMinter(issuer, minter));
6823 BEAST_EXPECT(ownerCount(env, minter) == 0);
6824 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6825 env(token::mint(minter),
6826 token::issuer(issuer),
6827 token::amount(drops(1)));
6829 BEAST_EXPECT(ownerCount(env, minter) == 2);
6830 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6835 for (
auto const& tweakedFeatures :
6836 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
6837 features | fixNFTokenNegOffer})
6839 Env env{*
this, tweakedFeatures};
6840 Account
const alice(
"alice");
6842 env.fund(XRP(1000000), alice);
6844 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
6849 env(token::mint(alice),
6850 token::amount(XRP(-2)),
6851 ter(offerCreateTER));
6870 testcase(
"Test synthetic fields from JSON response");
6872 using namespace test::jtx;
6874 Account
const alice{
"alice"};
6875 Account
const bob{
"bob"};
6876 Account
const broker{
"broker"};
6878 Env env{*
this, features};
6879 env.fund(XRP(10000), alice, bob, broker);
6885 auto verifyNFTokenID = [&](
uint256 const& actualNftID) {
6892 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6895 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_id)))
6902 BEAST_EXPECT(nftID == actualNftID);
6907 auto verifyNFTokenIDsInCancelOffer =
6915 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6918 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_ids)))
6924 meta[jss::nftoken_ids].begin(),
6925 meta[jss::nftoken_ids].end(),
6929 BEAST_EXPECT(nftID.
parseHex(
id.asString()));
6935 std::sort(actualNftIDs.begin(), actualNftIDs.end());
6938 BEAST_EXPECT(metaIDs.
size() == actualNftIDs.size());
6942 for (
size_t i = 0; i < metaIDs.
size(); ++i)
6943 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
6948 auto verifyNFTokenOfferID = [&](
uint256 const& offerID) {
6955 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6958 if (!BEAST_EXPECT(meta.
isMember(jss::offer_id)))
6963 BEAST_EXPECT(metaOfferID == offerID);
6974 verifyNFTokenID(nftId1);
6980 verifyNFTokenID(nftId2);
6985 uint256 const aliceOfferIndex1 =
6987 env(token::createOffer(alice, nftId1, drops(1)),
6990 verifyNFTokenOfferID(aliceOfferIndex1);
6992 uint256 const aliceOfferIndex2 =
6994 env(token::createOffer(alice, nftId2, drops(1)),
6997 verifyNFTokenOfferID(aliceOfferIndex2);
7002 env(token::cancelOffer(
7003 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7005 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
7009 auto const bobBuyOfferIndex =
7011 env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice));
7013 verifyNFTokenOfferID(bobBuyOfferIndex);
7017 env(token::acceptBuyOffer(alice, bobBuyOfferIndex));
7019 verifyNFTokenID(nftId1);
7029 verifyNFTokenID(nftId);
7032 uint256 const offerAliceToBroker =
7034 env(token::createOffer(alice, nftId, drops(1)),
7035 token::destination(broker),
7038 verifyNFTokenOfferID(offerAliceToBroker);
7041 uint256 const offerBobToBroker =
7043 env(token::createOffer(bob, nftId, drops(1)), token::owner(alice));
7045 verifyNFTokenOfferID(offerBobToBroker);
7048 env(token::brokerOffers(
7049 broker, offerBobToBroker, offerAliceToBroker));
7051 verifyNFTokenID(nftId);
7062 verifyNFTokenID(nftId);
7065 uint256 const aliceOfferIndex1 =
7067 env(token::createOffer(alice, nftId, drops(1)),
7070 verifyNFTokenOfferID(aliceOfferIndex1);
7072 uint256 const aliceOfferIndex2 =
7074 env(token::createOffer(alice, nftId, drops(1)),
7077 verifyNFTokenOfferID(aliceOfferIndex2);
7081 env(token::cancelOffer(
7082 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7084 verifyNFTokenIDsInCancelOffer({nftId});
7087 if (features[featureNFTokenMintOffer])
7089 uint256 const aliceMintWithOfferIndex1 =
7091 env(token::mint(alice), token::amount(XRP(0)));
7093 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
7100 testcase(
"Test buyer reserve when accepting an offer");
7102 using namespace test::jtx;
7115 uint256 const sellOfferIndex =
7117 env(token::createOffer(acct, nftId, amt), txflags(
tfSellNFToken));
7120 return sellOfferIndex;
7127 Account
const alice{
"alice"};
7128 Account
const bob{
"bob"};
7130 Env env{*
this, features};
7131 auto const acctReserve = env.
current()->fees().accountReserve(0);
7132 auto const incReserve = env.
current()->fees().increment;
7134 env.
fund(XRP(10000), alice);
7138 env.
fund(acctReserve, bob);
7142 auto const sellOfferIndex =
7143 mintAndCreateSellOffer(env, alice, XRP(0));
7146 BEAST_EXPECT(ownerCount(env, bob) == 0);
7150 if (!features[fixNFTokenReserve])
7153 env(token::acceptSellOffer(bob, sellOfferIndex));
7157 BEAST_EXPECT(ownerCount(env, bob) == 1);
7172 env(token::acceptSellOffer(bob, sellOfferIndex),
7179 BEAST_EXPECT(ownerCount(env, bob) == 0);
7184 env(pay(env.
master, bob, incReserve + drops(10)));
7189 env(token::acceptSellOffer(bob, sellOfferIndex),
7195 env(pay(env.
master, bob, drops(20)));
7199 env(token::acceptSellOffer(bob, sellOfferIndex));
7202 BEAST_EXPECT(ownerCount(env, bob) == 1);
7209 Account
const alice{
"alice"};
7210 Account
const bob{
"bob"};
7212 Env env{*
this, features};
7213 auto const acctReserve = env.
current()->fees().accountReserve(0);
7214 auto const incReserve = env.
current()->fees().increment;
7216 env.
fund(XRP(10000), alice);
7219 env.
fund(acctReserve + XRP(1), bob);
7222 if (!features[fixNFTokenReserve])
7225 for (
size_t i = 0; i < 200; i++)
7228 auto const sellOfferIndex =
7229 mintAndCreateSellOffer(env, alice, XRP(0));
7232 env(token::acceptSellOffer(bob, sellOfferIndex));
7239 auto const sellOfferIndex1 =
7240 mintAndCreateSellOffer(env, alice, XRP(0));
7244 env(token::acceptSellOffer(bob, sellOfferIndex1),
7249 env(pay(env.
master, bob, drops(incReserve)));
7252 BEAST_EXPECT(ownerCount(env, bob) == 0);
7255 env(token::acceptSellOffer(bob, sellOfferIndex1));
7258 BEAST_EXPECT(ownerCount(env, bob) == 1);
7262 for (
size_t i = 0; i < 31; i++)
7265 auto const sellOfferIndex =
7266 mintAndCreateSellOffer(env, alice, XRP(0));
7270 env(token::acceptSellOffer(bob, sellOfferIndex));
7274 BEAST_EXPECT(ownerCount(env, bob) == 1);
7278 auto const sellOfferIndex33 =
7279 mintAndCreateSellOffer(env, alice, XRP(0));
7283 env(token::acceptSellOffer(bob, sellOfferIndex33),
7288 env(pay(env.
master, bob, drops(incReserve)));
7293 env(token::acceptSellOffer(bob, sellOfferIndex33));
7296 BEAST_EXPECT(ownerCount(env, bob) == 2);
7306 Account
const alice{
"alice"};
7307 Account
const bob{
"bob"};
7309 Env env{*
this, features};
7310 auto const acctReserve = env.
current()->fees().accountReserve(0);
7311 auto const incReserve = env.
current()->fees().increment;
7313 env.
fund(XRP(10000), alice);
7319 env.
fund(acctReserve + incReserve + XRP(1), bob);
7330 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
7336 env(token::acceptBuyOffer(alice, buyOfferIndex),
7341 env(pay(env.
master, bob, drops(10)));
7345 env(token::acceptBuyOffer(alice, buyOfferIndex));
7355 Account
const alice{
"alice"};
7356 Account
const bob{
"bob"};
7357 Account
const broker{
"broker"};
7359 Env env{*
this, features};
7360 auto const acctReserve = env.
current()->fees().accountReserve(0);
7361 auto const incReserve = env.
current()->fees().increment;
7363 env.
fund(XRP(10000), alice, broker);
7368 env.
fund(acctReserve + incReserve + XRP(1), bob);
7378 uint256 const offerAliceToBroker =
7380 env(token::createOffer(alice, nftId, XRP(1)),
7381 token::destination(broker),
7386 uint256 const offerBobToBroker =
7388 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
7395 env(token::brokerOffers(
7396 broker, offerBobToBroker, offerAliceToBroker),
7401 env(pay(env.
master, bob, drops(10)));
7405 env(token::brokerOffers(
7406 broker, offerBobToBroker, offerAliceToBroker));
7414 testcase(
"Test fix unasked for auto-trustline.");
7416 using namespace test::jtx;
7418 Account
const issuer{
"issuer"};
7419 Account
const becky{
"becky"};
7420 Account
const cheri{
"cheri"};
7421 Account
const gw(
"gw");
7422 IOU
const gwAUD(gw[
"AUD"]);
7452 features - fixRemoveNFTokenAutoTrustLine;
7454 {localFeatures - fixEnforceNFTokenTrustline,
7455 localFeatures | fixEnforceNFTokenTrustline})
7457 Env env{*
this, feats};
7458 env.fund(XRP(1000), issuer, becky, cheri, gw);
7462 env(trust(becky, gwAUD(1000)));
7463 env(trust(cheri, gwAUD(1000)));
7465 env(pay(gw, cheri, gwAUD(500)));
7470 uint256 const nftAutoTrustID{token::getNextID(
7472 env(token::mint(issuer, 0u),
7473 token::xferFee(xferFee),
7477 uint256 const nftNoAutoTrustID{
7479 env(token::mint(issuer, 0u),
7480 token::xferFee(xferFee),
7486 uint256 const beckyBuyOfferIndex1 =
7488 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
7489 token::owner(issuer));
7491 uint256 const beckyBuyOfferIndex2 =
7493 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
7494 token::owner(issuer));
7497 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1));
7498 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2));
7503 uint256 const beckyAutoTrustOfferIndex =
7505 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
7511 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
7518 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7519 env(trust(issuer, gwAUD(1000)));
7521 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7523 uint256 const beckyNoAutoTrustOfferIndex =
7525 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
7530 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7531 env(trust(issuer, gwAUD(0)));
7533 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7537 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7541 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7542 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7545 env(pay(issuer, gw, gwAUD(5)));
7547 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7551 if (feats[fixEnforceNFTokenTrustline])
7556 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex),
7562 env(trust(issuer, gwAUD(1000)));
7564 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7566 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7573 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7576 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7577 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7584 testcase(
"Test fix NFT issuer is IOU issuer");
7586 using namespace test::jtx;
7588 Account
const issuer{
"issuer"};
7589 Account
const becky{
"becky"};
7590 Account
const cheri{
"cheri"};
7591 IOU
const isISU(issuer[
"ISU"]);
7623 features - fixRemoveNFTokenAutoTrustLine;
7625 Env env{*
this, localFeatures};
7626 env.fund(XRP(1000), issuer, becky, cheri);
7630 env(trust(becky, isISU(1000)));
7631 env(trust(cheri, isISU(1000)));
7633 env(pay(issuer, cheri, isISU(500)));
7638 uint256 const nftAutoTrustID{token::getNextID(
7640 env(token::mint(issuer, 0u),
7641 token::xferFee(xferFee),
7645 uint256 const nftNoAutoTrustID{
7647 env(token::mint(issuer, 0u),
7648 token::xferFee(xferFee),
7654 uint256 const beckyBuyOfferIndex1 =
7656 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
7657 token::owner(issuer));
7659 uint256 const beckyBuyOfferIndex2 =
7661 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
7662 token::owner(issuer));
7665 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1));
7666 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2));
7672 if (!localFeatures[featureNFTokenMintOffer])
7677 env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)),
7688 uint256 const beckyAutoTrustOfferIndex =
7690 env(token::createOffer(becky, nftAutoTrustID, isISU(100)),
7695 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7700 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7701 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7707 uint256 const beckyNoAutoTrustOfferIndex =
7709 env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)),
7712 uint256 const beckyAutoTrustOfferIndex =
7714 env(token::createOffer(becky, nftAutoTrustID, isISU(100)),
7720 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7725 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7726 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7728 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7734 BEAST_EXPECT(env.balance(becky, isISU) == isISU(190));
7735 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(300));
7744 using namespace test::jtx;
7746 Account
const issuer{
"issuer"};
7747 Account
const alice(
"alice");
7748 Account
const bob(
"bob");
7750 bool const modifyEnabled = features[featureDynamicNFT];
7754 Env env{*
this, features};
7755 env.fund(XRP(10000), issuer);
7758 auto const expectedTer =
7760 env(token::mint(issuer, 0u), txflags(
tfMutable), ter(expectedTer));
7764 Env env{*
this, features};
7765 env.fund(XRP(10000), issuer);
7772 env(token::mint(issuer, 0u), txflags(
tfMutable));
7774 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7775 env(token::modify(issuer, nftId));
7776 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7780 env(token::mint(issuer, 0u));
7782 env(token::modify(issuer, nftId), ter(
temDISABLED));
7790 Env env{*
this, features};
7791 env.fund(XRP(10000), issuer);
7795 env(token::mint(issuer, 0u), txflags(
tfMutable));
7799 env(token::modify(issuer, nftId),
7805 env(token::modify(issuer, nftId),
7806 txflags(0x00000001),
7810 env(token::modify(issuer, nftId),
7811 token::owner(issuer),
7816 env(token::modify(issuer, nftId),
7822 env(token::modify(issuer, nftId),
7828 Env env{*
this, features};
7829 env.fund(XRP(10000), issuer, alice, bob);
7835 token::getNextID(env, issuer, 0u,
tfMutable)};
7838 env(token::modify(issuer, nftIDNotExists), ter(
tecNO_ENTRY));
7843 uint256 const nftIDNotModifiable{
7844 token::getNextID(env, issuer, 0u)};
7845 env(token::mint(issuer, 0u));
7848 env(token::modify(issuer, nftIDNotModifiable),
7855 token::getNextID(env, issuer, 0u,
tfMutable)};
7856 env(token::mint(issuer, 0u), txflags(
tfMutable));
7859 env(token::modify(bob, nftId),
7860 token::owner(issuer),
7864 env(token::setMinter(issuer, alice));
7867 env(token::modify(bob, nftId),
7868 token::owner(issuer),
7874 Env env{*
this, features};
7875 env.fund(XRP(10000), issuer, alice, bob);
7880 env(token::mint(issuer, 0u), txflags(
tfMutable), token::uri(
"uri"));
7887 Env env{*
this, features};
7888 env.fund(XRP(10000), issuer, alice, bob);
7892 auto accountNFTs = [&env](Account
const& acct) {
7894 params[jss::account] = acct.human();
7895 params[jss::type] =
"state";
7897 env.rpc(
"json",
"account_nfts",
to_string(params));
7898 return response[jss::result][jss::account_nfts];
7902 auto checkURI = [&accountNFTs,
this](
7903 Account
const& acct,
7906 auto const nfts = accountNFTs(acct);
7907 if (nfts.size() == 1)
7912 text <<
"checkURI: unexpected NFT count on line " << line;
7913 fail(text.
str(), __FILE__, line);
7919 if (!nfts[0u].isMember(sfURI.jsonName))
7924 text <<
"checkURI: unexpected URI present on line "
7926 fail(text.
str(), __FILE__, line);
7936 text <<
"checkURI: unexpected URI contents on line "
7938 fail(text.
str(), __FILE__, line);
7945 env(token::mint(issuer, 0u), txflags(
tfMutable), token::uri(
"uri"));
7947 checkURI(issuer,
"uri", __LINE__);
7950 env(token::modify(issuer, nftId), token::uri(
"new_uri"));
7952 checkURI(issuer,
"new_uri", __LINE__);
7955 env(token::modify(issuer, nftId));
7957 checkURI(issuer,
nullptr, __LINE__);
7960 env(token::modify(issuer, nftId), token::uri(
"uri"));
7962 checkURI(issuer,
"uri", __LINE__);
7967 env(token::createOffer(issuer, nftId, XRP(0)),
7970 env(token::acceptSellOffer(alice, offerID));
7972 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7973 BEAST_EXPECT(ownerCount(env, alice) == 1);
7974 checkURI(alice,
"uri", __LINE__);
7977 env(token::modify(alice, nftId),
7978 token::uri(
"new_uri"),
7981 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7982 BEAST_EXPECT(ownerCount(env, alice) == 1);
7983 checkURI(alice,
"uri", __LINE__);
7985 env(token::modify(issuer, nftId),
7986 token::owner(alice),
7987 token::uri(
"new_uri"));
7989 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7990 BEAST_EXPECT(ownerCount(env, alice) == 1);
7991 checkURI(alice,
"new_uri", __LINE__);
7993 env(token::modify(issuer, nftId), token::owner(alice));
7995 checkURI(alice,
nullptr, __LINE__);
7997 env(token::modify(issuer, nftId),
7998 token::owner(alice),
8001 checkURI(alice,
"uri", __LINE__);
8004 env(token::setMinter(issuer, bob));
8006 env(token::modify(bob, nftId),
8007 token::owner(alice),
8008 token::uri(
"new_uri"));
8010 checkURI(alice,
"new_uri", __LINE__);
8012 env(token::modify(bob, nftId), token::owner(alice));
8014 checkURI(alice,
nullptr, __LINE__);
8016 env(token::modify(bob, nftId),
8017 token::owner(alice),
8020 checkURI(alice,
"uri", __LINE__);
8068 using namespace test::jtx;
8073 all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8074 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8076 fixNFTokenRemint - fixNFTokenReserve - featureNFTokenMintOffer -
8078 all - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8079 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8080 all - fixNFTokenRemint - fixNFTokenReserve -
8081 featureNFTokenMintOffer - featureDynamicNFT,
8082 all - fixNFTokenReserve - featureNFTokenMintOffer -
8084 all - featureNFTokenMintOffer - featureDynamicNFT,
8085 all - featureDynamicNFT,
8088 if (BEAST_EXPECT(instance < feats.size()))
8092 BEAST_EXPECT(!last || instance == feats.size() - 1);
8165BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, tx,
ripple, 2);
8166BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx,
ripple, 2);
8167BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx,
ripple, 2);
8168BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx,
ripple, 2);
8169BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx,
ripple, 2);
8170BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx,
ripple, 2);
8171BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx,
ripple, 2);
8172BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx,
ripple, 2);
T back_inserter(T... args)
UInt size() const
Number of values in array or object.
Value & append(const Value &value)
Append value to array at the end.
Value removeMember(const char *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
bool isMember(const char *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
void pass()
Record a successful test condition.
testcase_t testcase
Memberspace for declaring test cases.
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
void fail(String const &reason, char const *file, int line)
Record a failure.
void run() override
Runs the suite.
void testCreateOfferDestination(FeatureBitset features)
void testFixNFTokenRemint(FeatureBitset features)
std::uint32_t lastClose(test::jtx::Env &env)
void testMintInvalid(FeatureBitset features)
void testAcceptOfferInvalid(FeatureBitset features)
void testMintFlagTransferable(FeatureBitset features)
void testCancelOffers(FeatureBitset features)
void testNFTIssuerIsIOUIssuer(FeatureBitset features)
void testMintTaxon(FeatureBitset features)
void testNFTokenModify(FeatureBitset features)
void testNFTokenDeleteAccount(FeatureBitset features)
void testUnaskedForAutoTrustline(FeatureBitset features)
FeatureBitset const disallowIncoming
void testFixNFTokenBuyerReserve(FeatureBitset features)
void testFixNFTokenNegOffer(FeatureBitset features)
void run(std::uint32_t instance, bool last=false)
void testWithFeats(FeatureBitset features)
void testNFTokenOfferOwner(FeatureBitset features)
void testNFTokenWithTickets(FeatureBitset features)
void testCreateOfferDestinationDisallowIncoming(FeatureBitset features)
void testCreateOfferExpiration(FeatureBitset features)
void testMintMaxTokens(FeatureBitset features)
void testMintFlagCreateTrustLine(FeatureBitset features)
void testMintTransferFee(FeatureBitset features)
void testTxJsonMetaFields(FeatureBitset features)
void testNftXxxOffers(FeatureBitset features)
void testEnabled(FeatureBitset features)
void testMintURI(FeatureBitset features)
void testCancelTooManyOffers(FeatureBitset features)
void testMintFlagBurnable(FeatureBitset features)
void testMintFlagOnlyXRP(FeatureBitset features)
void testMintReserve(FeatureBitset features)
static std::uint32_t nftCount(test::jtx::Env &env, test::jtx::Account const &acct)
static std::uint32_t ticketCount(test::jtx::Env const &env, test::jtx::Account const &acct)
void testBrokeredSaleToSelf(FeatureBitset features)
void testIOUWithTransferFee(FeatureBitset features)
static std::uint32_t burnedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
void testCreateOfferInvalid(FeatureBitset features)
static std::uint32_t mintedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
void testCancelOfferInvalid(FeatureBitset features)
void testBrokeredAccept(FeatureBitset features)
void testFeatMintWithOffer(FeatureBitset features)
void run() override
Runs the suite.
void testBurnInvalid(FeatureBitset features)
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
Writable ledger view that accumulates state and tx changes.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Json::Value getJson(JsonOptions) const override
static const std::uint64_t cMinValue
static const int cMinOffset
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
A type-safe wrap around standard integral types.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
T emplace_back(T... args)
@ arrayValue
array value (ordered list)
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Taxon getTaxon(uint256 const &id)
Taxon toTaxon(std::uint32_t i)
std::uint32_t ownerCount(Env const &env, Account const &account)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::enable_if_t<(std::is_same< Byte, unsigned char >::value||std::is_same< Byte, std::uint8_t >::value), Byte > rand_byte()
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
constexpr std::uint32_t const tfOnlyXRP
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer
constexpr std::uint32_t const tfSellNFToken
std::size_t constexpr maxTokenOfferCancelCount
The maximum number of token offers that can be canceled at once.
@ lsfDisallowIncomingNFTokenOffer
std::uint16_t constexpr maxTransferFee
The maximum token transfer fee allowed.
constexpr std::uint32_t const tfBurnable
@ tefNFTOKEN_IS_NOT_TRANSFERABLE
constexpr std::uint32_t const tfTrustLine
std::string strHex(FwdIt begin, FwdIt end)
std::size_t constexpr maxTokenURILength
The maximum length of a URI inside an NFT.
constexpr std::uint32_t tfClearFreeze
@ tecNFTOKEN_OFFER_TYPE_MISMATCH
@ tecNFTOKEN_BUY_SELL_MISMATCH
@ tecMAX_SEQUENCE_REACHED
@ tecINSUFFICIENT_PAYMENT
@ tecINSUFFICIENT_RESERVE
@ tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t const tfMutable
constexpr std::uint32_t const tfTransferable
@ temBAD_NFTOKEN_TRANSFER_FEE
A pair of SHAMap key and LedgerEntryType.