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 auto const baseFee = env.current()->fees().base;
215 env.fund(acctReserve, alice, minter);
218 BEAST_EXPECT(env.balance(alice) == acctReserve);
219 BEAST_EXPECT(env.balance(minter) == acctReserve);
220 BEAST_EXPECT(ownerCount(env, alice) == 0);
221 BEAST_EXPECT(ownerCount(env, minter) == 0);
228 BEAST_EXPECT(ownerCount(env, alice) == 0);
233 env(pay(env.master, alice, incReserve + drops(baseFee - 1)));
238 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
251 ss <<
"Wrong " << type <<
" count. Found: " << found
252 <<
"; Expected: " << exp;
253 fail(ss.
str(), __FILE__, line);
256 oneCheck(
"owner", ownerCount(env, alice), owners);
257 oneCheck(
"minted",
mintedCount(env, alice), minted);
258 oneCheck(
"burned",
burnedCount(env, alice), burned);
266 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
269 env(pay(env.master, alice, drops(baseFee + 1)));
273 env(token::mint(alice));
276 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
280 for (
int i = 1; i < 32; ++i)
282 env(token::mint(alice));
283 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
290 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
293 env(pay(env.master, alice, incReserve + drops(baseFee * 33 - 1)));
300 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
303 env(pay(env.master, alice, drops(baseFee + 1)));
307 env(token::mint(alice));
309 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
316 env(token::burn(alice, token::getID(env, alice, 0, seq++)));
318 checkAliceOwnerMintedBurned((33 - seq) ? 1 : 0, 33, seq, __LINE__);
322 env(token::burn(alice, token::getID(env, alice, 197, 5)),
325 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
330 env(token::setMinter(alice, minter));
333 env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
337 auto checkMintersOwnerMintedBurned = [&env,
this, &alice, &minter](
345 auto oneCheck = [
this](
355 ss <<
"Wrong " << type <<
" count. Found: " << found
356 <<
"; Expected: " << exp;
357 fail(ss.
str(), __FILE__, line);
360 oneCheck(
"alice owner", ownerCount(env, alice), aliceOwners, line);
362 "alice minted",
mintedCount(env, alice), aliceMinted, line);
364 "alice burned",
burnedCount(env, alice), aliceBurned, line);
366 "minter owner", ownerCount(env, minter), minterOwners, line);
368 "minter minted",
mintedCount(env, minter), minterMinted, line);
370 "minter burned",
burnedCount(env, minter), minterBurned, line);
376 env(pay(env.master, minter, incReserve - drops(1)));
378 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
383 env(token::mint(minter),
384 token::issuer(alice),
388 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
391 env(pay(env.master, minter, drops(baseFee + 1)));
395 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
397 checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
401 for (
int i = 1; i < 32; ++i)
403 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
404 checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
409 env(pay(env.master, minter, incReserve + drops(baseFee * 32 - 1)));
414 env(token::mint(minter),
415 token::issuer(alice),
419 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
422 env(pay(env.master, minter, drops(baseFee + 1)));
426 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
428 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
433 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
435 checkMintersOwnerMintedBurned(
436 0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__);
441 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
443 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
446 env(token::burn(minter, token::getID(env, alice, 2009, 3)),
449 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
459 using namespace test::jtx;
461 Account
const alice{
"alice"};
462 Env env{*
this, features};
463 env.fund(XRP(1000), alice);
472 uint256 const nftId0{token::getNextID(env, alice, 0u)};
473 env(token::mint(alice, 0u));
476 env(token::burn(alice, nftId0));
483 env.app().openLedger().modify(
492 auto replacement = std::make_shared<SLE>(*sle, sle->key());
493 if (replacement->getFieldU32(sfMintedNFTokens) != 1)
496 if (env.current()->rules().enabled(fixNFTokenRemint))
504 (*replacement)[sfFirstNFTokenSequence] = 0xFFFF'FFFE;
505 (*replacement)[sfMintedNFTokens] = 0x0000'0000;
511 (*replacement)[sfMintedNFTokens] = 0xFFFF'FFFE;
528 using namespace test::jtx;
530 Env env{*
this, features};
531 Account
const alice{
"alice"};
532 Account
const minter{
"minter"};
537 env.fund(XRP(200), alice, minter);
544 env(pay(env.master, alice, XRP(1000)));
551 env(token::mint(alice, 0u),
556 env(token::mint(alice, 0u), txflags(0x00008000), ter(
temINVALID_FLAG));
560 env(token::mint(alice, 0u),
565 env(token::mint(alice, 0u),
571 env(token::mint(alice, 0u), token::issuer(alice), ter(
temMALFORMED));
574 env(token::mint(alice, 0u), token::uri(
""), ter(
temMALFORMED));
577 env(token::mint(alice, 0u),
585 env(token::mint(alice, 0u),
586 token::issuer(Account(
"demon")),
593 env(token::mint(minter, 0u),
594 token::issuer(alice),
604 using namespace test::jtx;
606 Env env{*
this, features};
607 Account
const alice{
"alice"};
608 Account
const buyer{
"buyer"};
609 Account
const minter{
"minter"};
610 Account
const gw(
"gw");
611 IOU
const gwAUD(gw[
"AUD"]);
616 env.fund(XRP(250), alice, buyer, minter, gw);
618 BEAST_EXPECT(ownerCount(env, alice) == 0);
624 BEAST_EXPECT(ownerCount(env, alice) == 1);
630 env(token::burn(alice, nftAlice0ID),
634 BEAST_EXPECT(ownerCount(env, alice) == 1);
637 env(token::burn(alice, nftAlice0ID),
641 BEAST_EXPECT(ownerCount(env, buyer) == 0);
647 env(token::burn(alice, token::getID(env, alice, 0, 1)),
650 BEAST_EXPECT(ownerCount(env, buyer) == 0);
662 testcase(
"Invalid NFT offer create");
664 using namespace test::jtx;
666 Env env{*
this, features};
667 Account
const alice{
"alice"};
668 Account
const buyer{
"buyer"};
669 Account
const gw(
"gw");
670 IOU
const gwAUD(gw[
"AUD"]);
675 env.fund(XRP(250), alice, buyer, gw);
677 BEAST_EXPECT(ownerCount(env, alice) == 0);
681 env(token::mint(alice, 0u),
685 BEAST_EXPECT(ownerCount(env, alice) == 1);
691 BEAST_EXPECT(ownerCount(env, alice) == 1);
693 uint256 nftNoXferID = token::getNextID(env, alice, 0);
694 env(token::mint(alice, 0));
696 BEAST_EXPECT(ownerCount(env, alice) == 1);
707 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
711 BEAST_EXPECT(ownerCount(env, buyer) == 0);
714 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
718 BEAST_EXPECT(ownerCount(env, buyer) == 0);
721 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
725 BEAST_EXPECT(ownerCount(env, buyer) == 0);
728 env(token::createOffer(buyer, nftXrpOnlyID, buyer[
"USD"](1)),
730 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](0)),
732 env(token::createOffer(buyer, nftXrpOnlyID, drops(0)),
735 BEAST_EXPECT(ownerCount(env, buyer) == 0);
738 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](1)),
739 token::expiration(0),
742 BEAST_EXPECT(ownerCount(env, buyer) == 0);
746 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
749 BEAST_EXPECT(ownerCount(env, buyer) == 0);
752 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
757 BEAST_EXPECT(ownerCount(env, alice) == 1);
760 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
764 BEAST_EXPECT(ownerCount(env, alice) == 1);
767 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
768 token::destination(alice),
772 BEAST_EXPECT(ownerCount(env, alice) == 1);
775 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
776 token::destination(Account(
"demon")),
780 BEAST_EXPECT(ownerCount(env, alice) == 1);
786 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
791 BEAST_EXPECT(ownerCount(env, buyer) == 0);
794 env(token::createOffer(
795 buyer, token::getID(env, alice, 0, 1), XRP(1000)),
799 BEAST_EXPECT(ownerCount(env, buyer) == 0);
802 env(token::createOffer(
803 alice, token::getID(env, alice, 0, 1), XRP(1000)),
807 BEAST_EXPECT(ownerCount(env, buyer) == 0);
810 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
814 BEAST_EXPECT(ownerCount(env, buyer) == 0);
816 env(trust(buyer, gwAUD(1000)));
818 BEAST_EXPECT(ownerCount(env, buyer) == 1);
822 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
826 BEAST_EXPECT(ownerCount(env, buyer) == 1);
834 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
838 BEAST_EXPECT(ownerCount(env, buyer) == 1);
845 env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
849 BEAST_EXPECT(ownerCount(env, buyer) == 1);
855 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
859 BEAST_EXPECT(ownerCount(env, buyer) == 1);
864 env(trust(buyer, gwAUD(1000)));
867 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
871 BEAST_EXPECT(ownerCount(env, buyer) == 1);
877 env(pay(gw, buyer, gwAUD(999)));
882 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
886 BEAST_EXPECT(ownerCount(env, buyer) == 1);
889 auto const baseFee = env.current()->fees().base;
890 env(pay(env.master, buyer, XRP(50) + drops(baseFee * 12 - 1)));
893 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
897 BEAST_EXPECT(ownerCount(env, buyer) == 1);
900 env(pay(env.master, buyer, drops(baseFee + 1)));
905 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
909 BEAST_EXPECT(ownerCount(env, buyer) == 2);
915 testcase(
"Invalid NFT offer cancel");
917 using namespace test::jtx;
919 Env env{*
this, features};
920 Account
const alice{
"alice"};
921 Account
const buyer{
"buyer"};
922 Account
const gw(
"gw");
923 IOU
const gwAUD(gw[
"AUD"]);
925 env.fund(XRP(1000), alice, buyer, gw);
927 BEAST_EXPECT(ownerCount(env, alice) == 0);
933 BEAST_EXPECT(ownerCount(env, alice) == 1);
936 uint256 const buyerOfferIndex =
938 env(token::createOffer(buyer, nftAlice0ID, XRP(1)),
942 BEAST_EXPECT(ownerCount(env, buyer) == 1);
948 env(token::cancelOffer(buyer, {buyerOfferIndex}),
952 BEAST_EXPECT(ownerCount(env, buyer) == 1);
955 env(token::cancelOffer(buyer, {buyerOfferIndex}),
959 BEAST_EXPECT(ownerCount(env, buyer) == 1);
967 BEAST_EXPECT(ownerCount(env, buyer) == 1);
975 env(token::cancelOffer(buyer, offers), ter(
temMALFORMED));
977 BEAST_EXPECT(ownerCount(env, buyer) == 1);
981 env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}),
984 BEAST_EXPECT(ownerCount(env, buyer) == 1);
989 BEAST_EXPECT(ownerCount(env, buyer) == 1);
995 env(pay(env.master, gw, XRP(5000)));
999 env(offer(gw, XRP(i), gwAUD(1)));
1006 env(check::create(gw, env.master, XRP(300)));
1013 env(check::cancel(gw, gwCheckId));
1020 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1027 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1029 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1035 testcase(
"Invalid NFT offer accept");
1037 using namespace test::jtx;
1039 Env env{*
this, features};
1040 Account
const alice{
"alice"};
1041 Account
const buyer{
"buyer"};
1042 Account
const gw(
"gw");
1043 IOU
const gwAUD(gw[
"AUD"]);
1045 env.fund(XRP(1000), alice, buyer, gw);
1047 BEAST_EXPECT(ownerCount(env, alice) == 0);
1053 BEAST_EXPECT(ownerCount(env, alice) == 1);
1059 BEAST_EXPECT(ownerCount(env, alice) == 1);
1061 uint256 nftNoXferID = token::getNextID(env, alice, 0);
1062 env(token::mint(alice, 0));
1064 BEAST_EXPECT(ownerCount(env, alice) == 1);
1067 uint256 const plainOfferIndex =
1069 env(token::createOffer(alice, nftAlice0ID, XRP(10)),
1072 BEAST_EXPECT(ownerCount(env, alice) == 2);
1076 env(token::createOffer(alice, nftAlice0ID, gwAUD(30)),
1079 BEAST_EXPECT(ownerCount(env, alice) == 3);
1081 uint256 const xrpOnlyOfferIndex =
1083 env(token::createOffer(alice, nftXrpOnlyID, XRP(20)),
1086 BEAST_EXPECT(ownerCount(env, alice) == 4);
1088 uint256 const noXferOfferIndex =
1090 env(token::createOffer(alice, nftNoXferID, XRP(30)),
1093 BEAST_EXPECT(ownerCount(env, alice) == 5);
1096 uint256 const aliceExpOfferIndex =
1098 env(token::createOffer(alice, nftNoXferID, XRP(40)),
1102 BEAST_EXPECT(ownerCount(env, alice) == 6);
1108 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1112 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1115 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1116 txflags(0x00008000),
1119 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1123 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1127 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1132 Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1133 jv[sfNFTokenBrokerFee.jsonName] =
1137 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1142 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1143 jv[sfNFTokenBrokerFee.jsonName] =
1147 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1151 env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1152 token::brokerFee(gwAUD(0)),
1155 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1161 env(token::acceptBuyOffer(buyer, beast::zero),
1164 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1168 env(token::acceptBuyOffer(buyer, missingOfferIndex),
1171 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1174 env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1176 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1179 env(token::acceptSellOffer(buyer, beast::zero),
1182 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1185 env(token::acceptSellOffer(buyer, missingOfferIndex),
1188 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1191 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1193 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1200 env(trust(alice, gwAUD(1000)));
1201 env(trust(buyer, gwAUD(1000)));
1203 env(pay(gw, buyer, gwAUD(30)));
1205 BEAST_EXPECT(ownerCount(env, alice) == 7);
1206 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1212 uint256 const buyerOfferIndex =
1214 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)),
1215 token::owner(alice));
1217 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1220 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1223 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1226 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1229 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1233 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1236 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1239 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1241 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1245 uint256 const buyerOfferIndex =
1247 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)),
1248 token::owner(alice));
1250 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1254 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1255 token::brokerFee(XRP(40)),
1258 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1261 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1262 token::brokerFee(gwAUD(31)),
1265 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1269 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1270 token::brokerFee(gwAUD(1.5)),
1273 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1276 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1278 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1284 uint256 const buyerOfferIndex =
1286 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)),
1287 token::owner(alice));
1289 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1292 env(token::acceptBuyOffer(buyer, plainOfferIndex),
1295 BEAST_EXPECT(ownerCount(env, alice) == 7);
1298 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1301 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1304 env(pay(buyer, gw, gwAUD(30)));
1306 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1307 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1310 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1316 env(token::createOffer(alice, nftAlice0ID, XRP(0)),
1319 env(token::acceptSellOffer(gw, offerIndex));
1321 BEAST_EXPECT(ownerCount(env, alice) == 7);
1323 env(pay(gw, buyer, gwAUD(30)));
1327 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1330 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1333 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1335 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1341 uint256 const buyerOfferIndex =
1343 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)),
1344 token::owner(alice));
1346 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1349 env(token::acceptSellOffer(alice, buyerOfferIndex),
1352 BEAST_EXPECT(ownerCount(env, alice) == 7);
1355 env(token::acceptSellOffer(alice, plainOfferIndex),
1358 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1362 env(token::acceptSellOffer(buyer, plainOfferIndex),
1365 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1373 env(token::createOffer(gw, nftAlice0ID, XRP(0)),
1376 env(token::acceptSellOffer(alice, offerIndex));
1378 BEAST_EXPECT(ownerCount(env, alice) == 7);
1380 env(pay(buyer, gw, gwAUD(30)));
1382 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1383 env(token::acceptSellOffer(buyer, audOfferIndex),
1386 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1402 using namespace test::jtx;
1404 Env env{*
this, features};
1405 Account
const alice{
"alice"};
1406 Account
const buyer{
"buyer"};
1407 Account
const minter1{
"minter1"};
1408 Account
const minter2{
"minter2"};
1410 env.fund(XRP(1000), alice, buyer, minter1, minter2);
1412 BEAST_EXPECT(ownerCount(env, alice) == 0);
1415 env(token::setMinter(alice, minter1));
1422 auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1424 uint256 const nftID{token::getNextID(env, alice, 0u, flags)};
1425 env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags));
1430 env(token::createOffer(minter1, nftID, XRP(0)),
1434 env(token::acceptSellOffer(buyer, offerIndex));
1442 uint256 const noBurnID = nftToBuyer(0);
1443 env(token::burn(alice, noBurnID),
1444 token::owner(buyer),
1447 env(token::burn(minter1, noBurnID),
1448 token::owner(buyer),
1451 env(token::burn(minter2, noBurnID),
1452 token::owner(buyer),
1456 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1457 env(token::burn(buyer, noBurnID), token::owner(buyer));
1459 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1464 env(token::burn(minter2, burnableID),
1465 token::owner(buyer),
1469 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1470 env(token::burn(alice, burnableID), token::owner(buyer));
1472 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1477 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1478 env(token::burn(buyer, burnableID));
1480 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1485 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1486 env(token::burn(buyer, burnableID), token::owner(buyer));
1488 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1494 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1496 env(token::setMinter(alice, minter2));
1501 env(token::burn(minter1, burnableID),
1502 token::owner(buyer),
1505 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1508 env(token::burn(minter2, burnableID), token::owner(buyer));
1510 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1520 using namespace test::jtx;
1522 Env env{*
this, features};
1523 Account
const alice{
"alice"};
1524 Account
const buyer{
"buyer"};
1525 Account
const gw(
"gw");
1526 IOU
const gwAUD(gw[
"AUD"]);
1529 env.fund(XRP(1000), alice, buyer, gw);
1531 env(trust(alice, gwAUD(1000)));
1532 env(trust(buyer, gwAUD(1000)));
1534 env(pay(gw, buyer, gwAUD(100)));
1543 BEAST_EXPECT(ownerCount(env, alice) == 2);
1544 uint256 const aliceOfferIndex =
1546 env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)),
1549 BEAST_EXPECT(ownerCount(env, alice) == 3);
1551 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1552 uint256 const buyerOfferIndex =
1554 env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)),
1555 token::owner(alice));
1557 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1560 env(token::cancelOffer(alice, {aliceOfferIndex}));
1561 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1563 BEAST_EXPECT(ownerCount(env, alice) == 2);
1564 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1567 env(token::burn(alice, nftIOUsOkayID));
1569 BEAST_EXPECT(ownerCount(env, alice) == 1);
1579 BEAST_EXPECT(ownerCount(env, alice) == 2);
1580 env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)),
1584 BEAST_EXPECT(ownerCount(env, alice) == 2);
1586 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1587 env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)),
1588 token::owner(alice),
1591 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1594 BEAST_EXPECT(ownerCount(env, alice) == 2);
1595 env(token::createOffer(alice, nftOnlyXRPID, XRP(60)),
1598 BEAST_EXPECT(ownerCount(env, alice) == 3);
1600 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1601 env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)),
1602 token::owner(alice));
1604 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1612 testcase(
"Mint flagCreateTrustLines");
1614 using namespace test::jtx;
1616 Account
const alice{
"alice"};
1617 Account
const becky{
"becky"};
1618 Account
const cheri{
"cheri"};
1619 Account
const gw(
"gw");
1620 IOU
const gwAUD(gw[
"AUD"]);
1621 IOU
const gwCAD(gw[
"CAD"]);
1622 IOU
const gwEUR(gw[
"EUR"]);
1627 for (
auto const& tweakedFeatures :
1628 {features - fixRemoveNFTokenAutoTrustLine,
1629 features | fixRemoveNFTokenAutoTrustLine})
1631 Env env{*
this, tweakedFeatures};
1632 env.fund(XRP(1000), alice, becky, cheri, gw);
1636 env(trust(becky, gwAUD(1000)));
1637 env(trust(cheri, gwAUD(1000)));
1638 env(trust(becky, gwCAD(1000)));
1639 env(trust(cheri, gwCAD(1000)));
1640 env(trust(becky, gwEUR(1000)));
1641 env(trust(cheri, gwEUR(1000)));
1643 env(pay(gw, becky, gwAUD(500)));
1644 env(pay(gw, becky, gwCAD(500)));
1645 env(pay(gw, becky, gwEUR(500)));
1646 env(pay(gw, cheri, gwAUD(500)));
1647 env(pay(gw, cheri, gwCAD(500)));
1654 uint256 const nftNoAutoTrustID{
1656 env(token::mint(alice, 0u),
1657 token::xferFee(xferFee),
1662 uint256 const beckyBuyOfferIndex =
1664 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1665 token::owner(alice));
1667 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1671 TER const createOfferTER =
1673 uint256 const beckyOfferIndex =
1675 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1677 ter(createOfferTER));
1681 uint256 const cheriOfferIndex =
1683 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1684 token::owner(becky),
1685 ter(createOfferTER));
1689 env(token::cancelOffer(becky, {beckyOfferIndex}));
1690 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1698 uint256 const nftAutoTrustID{token::getNextID(
1705 tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
1709 env(token::mint(alice, 0u),
1710 token::xferFee(transferFee),
1717 if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
1721 uint256 const beckyBuyOfferIndex =
1723 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1724 token::owner(alice));
1726 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1730 uint256 const beckySellOfferIndex =
1732 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1735 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1739 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1742 uint256 const beckyBuyBackOfferIndex =
1744 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1745 token::owner(cheri));
1747 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1751 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1752 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1758 uint256 const nftNoAutoTrustID{token::getNextID(
1760 env(token::mint(alice, 0u),
1761 token::xferFee(transferFee),
1766 uint256 const aliceSellOfferIndex =
1768 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1771 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1777 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1780 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1784 uint256 const cheriSellOfferIndex =
1786 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1789 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1795 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1806 using namespace test::jtx;
1808 Env env{*
this, features};
1810 Account
const alice{
"alice"};
1811 Account
const becky{
"becky"};
1812 Account
const minter{
"minter"};
1814 env.fund(XRP(1000), alice, becky, minter);
1819 BEAST_EXPECT(ownerCount(env, alice) == 0);
1820 uint256 const nftAliceNoTransferID{
1821 token::getNextID(env, alice, 0u)};
1822 env(token::mint(alice, 0u), token::xferFee(0));
1824 BEAST_EXPECT(ownerCount(env, alice) == 1);
1827 BEAST_EXPECT(ownerCount(env, becky) == 0);
1828 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1829 token::owner(alice),
1833 uint256 const aliceSellOfferIndex =
1835 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1838 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1840 BEAST_EXPECT(ownerCount(env, alice) == 0);
1841 BEAST_EXPECT(ownerCount(env, becky) == 1);
1844 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1848 BEAST_EXPECT(ownerCount(env, alice) == 0);
1849 BEAST_EXPECT(ownerCount(env, becky) == 1);
1853 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1855 token::destination(alice),
1858 BEAST_EXPECT(ownerCount(env, alice) == 0);
1859 BEAST_EXPECT(ownerCount(env, becky) == 1);
1863 uint256 const aliceBuyOfferIndex =
1865 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1866 token::owner(becky));
1868 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1870 BEAST_EXPECT(ownerCount(env, alice) == 1);
1871 BEAST_EXPECT(ownerCount(env, becky) == 0);
1874 env(token::burn(alice, nftAliceNoTransferID));
1876 BEAST_EXPECT(ownerCount(env, alice) == 0);
1877 BEAST_EXPECT(ownerCount(env, becky) == 0);
1881 env(token::setMinter(alice, minter));
1884 BEAST_EXPECT(ownerCount(env, minter) == 0);
1885 uint256 const nftMinterNoTransferID{
1886 token::getNextID(env, alice, 0u)};
1887 env(token::mint(minter), token::issuer(alice));
1889 BEAST_EXPECT(ownerCount(env, minter) == 1);
1892 BEAST_EXPECT(ownerCount(env, becky) == 0);
1893 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1894 token::owner(minter),
1897 BEAST_EXPECT(ownerCount(env, becky) == 0);
1900 env(token::clearMinter(alice));
1904 BEAST_EXPECT(ownerCount(env, minter) == 1);
1905 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1909 BEAST_EXPECT(ownerCount(env, minter) == 1);
1913 for (
int i = 0; i < 10; ++i)
1916 env(token::setMinter(alice, minter));
1918 BEAST_EXPECT(ownerCount(env, minter) == 1);
1921 BEAST_EXPECT(ownerCount(env, minter) == 1);
1922 uint256 const minterSellOfferIndex =
1924 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1927 BEAST_EXPECT(ownerCount(env, minter) == 2);
1931 env(token::clearMinter(alice));
1936 BEAST_EXPECT(ownerCount(env, becky) == 0);
1937 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1939 BEAST_EXPECT(ownerCount(env, becky) == 1);
1940 BEAST_EXPECT(ownerCount(env, minter) == 0);
1943 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1950 BEAST_EXPECT(ownerCount(env, minter) == 0);
1951 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1952 token::owner(becky),
1955 BEAST_EXPECT(ownerCount(env, minter) == 0);
1958 BEAST_EXPECT(ownerCount(env, alice) == 0);
1959 uint256 const aliceBuyOfferIndex =
1961 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1962 token::owner(becky));
1964 BEAST_EXPECT(ownerCount(env, alice) == 1);
1968 for (
int i = 0; i < 10; ++i)
1971 env(token::setMinter(alice, minter));
1975 BEAST_EXPECT(ownerCount(env, minter) == 0);
1976 uint256 const minterBuyOfferIndex =
1978 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1979 token::owner(becky));
1981 BEAST_EXPECT(ownerCount(env, minter) == 1);
1985 env(token::clearMinter(alice));
1989 BEAST_EXPECT(ownerCount(env, minter) == 1);
1990 BEAST_EXPECT(ownerCount(env, becky) == 1);
1991 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1993 BEAST_EXPECT(ownerCount(env, minter) == 1);
1994 BEAST_EXPECT(ownerCount(env, becky) == 0);
1995 BEAST_EXPECT(ownerCount(env, alice) == 1);
1999 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
2001 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
2003 BEAST_EXPECT(ownerCount(env, alice) == 0);
2004 BEAST_EXPECT(ownerCount(env, becky) == 0);
2005 BEAST_EXPECT(ownerCount(env, minter) == 0);
2010 BEAST_EXPECT(ownerCount(env, alice) == 0);
2015 BEAST_EXPECT(ownerCount(env, alice) == 1);
2018 uint256 const aliceSellOfferIndex =
2020 env(token::createOffer(alice, nftAliceID, XRP(20)),
2023 BEAST_EXPECT(ownerCount(env, alice) == 2);
2025 uint256 const beckyBuyOfferIndex =
2027 env(token::createOffer(becky, nftAliceID, XRP(21)),
2028 token::owner(alice));
2030 BEAST_EXPECT(ownerCount(env, alice) == 2);
2033 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
2035 BEAST_EXPECT(ownerCount(env, alice) == 0);
2036 BEAST_EXPECT(ownerCount(env, becky) == 2);
2039 uint256 const beckySellOfferIndex =
2041 env(token::createOffer(becky, nftAliceID, XRP(22)),
2044 BEAST_EXPECT(ownerCount(env, alice) == 0);
2045 BEAST_EXPECT(ownerCount(env, becky) == 3);
2049 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2051 BEAST_EXPECT(ownerCount(env, alice) == 0);
2052 BEAST_EXPECT(ownerCount(env, becky) == 1);
2053 BEAST_EXPECT(ownerCount(env, minter) == 1);
2056 uint256 const minterSellOfferIndex =
2058 env(token::createOffer(minter, nftAliceID, XRP(23)),
2061 BEAST_EXPECT(ownerCount(env, alice) == 0);
2062 BEAST_EXPECT(ownerCount(env, becky) == 1);
2063 BEAST_EXPECT(ownerCount(env, minter) == 2);
2066 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2068 BEAST_EXPECT(ownerCount(env, alice) == 1);
2069 BEAST_EXPECT(ownerCount(env, becky) == 1);
2070 BEAST_EXPECT(ownerCount(env, minter) == 0);
2074 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2076 BEAST_EXPECT(ownerCount(env, alice) == 0);
2077 BEAST_EXPECT(ownerCount(env, becky) == 1);
2078 BEAST_EXPECT(ownerCount(env, minter) == 0);
2082 env(token::burn(becky, nftAliceID));
2084 BEAST_EXPECT(ownerCount(env, alice) == 0);
2085 BEAST_EXPECT(ownerCount(env, becky) == 0);
2086 BEAST_EXPECT(ownerCount(env, minter) == 0);
2096 using namespace test::jtx;
2098 Env env{*
this, features};
2099 auto const baseFee = env.current()->fees().base;
2101 Account
const alice{
"alice"};
2102 Account
const becky{
"becky"};
2103 Account
const carol{
"carol"};
2104 Account
const minter{
"minter"};
2105 Account
const gw{
"gw"};
2106 IOU
const gwXAU(gw[
"XAU"]);
2108 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2111 env(trust(alice, gwXAU(2000)));
2112 env(trust(becky, gwXAU(2000)));
2113 env(trust(carol, gwXAU(2000)));
2114 env(trust(minter, gwXAU(2000)));
2116 env(pay(gw, alice, gwXAU(1000)));
2117 env(pay(gw, becky, gwXAU(1000)));
2118 env(pay(gw, carol, gwXAU(1000)));
2119 env(pay(gw, minter, gwXAU(1000)));
2124 env(token::setMinter(alice, minter));
2130 BEAST_EXPECT(ownerCount(env, alice) == 1);
2131 BEAST_EXPECT(ownerCount(env, becky) == 1);
2132 BEAST_EXPECT(ownerCount(env, carol) == 1);
2133 BEAST_EXPECT(ownerCount(env, minter) == 1);
2141 uint256 const beckyBuyOfferIndex =
2143 env(token::createOffer(becky, nftID, gwXAU(10)),
2144 token::owner(alice));
2146 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2147 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2149 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2151 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2152 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2155 uint256 const beckySellOfferIndex =
2157 env(token::createOffer(becky, nftID, gwXAU(10)),
2160 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2162 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2163 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2164 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2167 uint256 const minterBuyOfferIndex =
2169 env(token::createOffer(minter, nftID, gwXAU(10)),
2170 token::owner(carol));
2172 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2174 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2175 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2176 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2177 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2181 uint256 const minterSellOfferIndex =
2183 env(token::createOffer(minter, nftID, gwXAU(10)),
2186 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2188 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2189 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2190 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2191 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2194 env(token::burn(alice, nftID));
2196 BEAST_EXPECT(ownerCount(env, alice) == 1);
2197 BEAST_EXPECT(ownerCount(env, becky) == 1);
2198 BEAST_EXPECT(ownerCount(env, carol) == 1);
2199 BEAST_EXPECT(ownerCount(env, minter) == 1);
2207 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2211 uint256 const beckyBuyOfferIndex =
2213 env(token::createOffer(becky, nftID, gwXAU(10)),
2214 token::owner(alice));
2216 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2217 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2219 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2221 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2222 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2225 uint256 const beckySellOfferIndex =
2227 env(token::createOffer(becky, nftID, gwXAU(10)),
2230 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2233 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2234 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2235 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2238 uint256 const minterBuyOfferIndex =
2240 env(token::createOffer(minter, nftID, gwXAU(10)),
2241 token::owner(carol));
2243 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2246 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2247 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2248 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2249 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2253 uint256 const minterSellOfferIndex =
2255 env(token::createOffer(minter, nftID, gwXAU(10)),
2258 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2260 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2261 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2262 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2263 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2267 env(pay(alice, becky, gwXAU(0.0001)));
2268 env(pay(alice, carol, gwXAU(0.0001)));
2271 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2272 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2273 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2274 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2277 env(token::burn(alice, nftID));
2279 BEAST_EXPECT(ownerCount(env, alice) == 1);
2280 BEAST_EXPECT(ownerCount(env, becky) == 1);
2281 BEAST_EXPECT(ownerCount(env, carol) == 1);
2282 BEAST_EXPECT(ownerCount(env, minter) == 1);
2288 env(token::mint(alice),
2295 uint256 const nftID = token::getNextID(
2297 env(token::mint(alice),
2303 uint256 const beckyBuyOfferIndex =
2305 env(token::createOffer(becky, nftID, gwXAU(10)),
2306 token::owner(alice));
2308 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2309 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2311 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2313 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2314 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2317 uint256 const beckySellOfferIndex =
2319 env(token::createOffer(becky, nftID, gwXAU(100)),
2322 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2325 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2326 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2327 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2330 uint256 const carolBuyOfferIndex =
2332 env(token::createOffer(carol, nftID, gwXAU(10)),
2333 token::owner(minter));
2335 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2338 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2339 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2340 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2341 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2345 uint256 const carolSellOfferIndex =
2347 env(token::createOffer(carol, nftID, gwXAU(10)),
2350 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2353 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2354 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2355 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2356 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2359 env(pay(alice, minter, gwXAU(55)));
2360 env(pay(becky, minter, gwXAU(40)));
2362 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2363 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2364 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2365 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2368 env(token::burn(alice, nftID));
2370 BEAST_EXPECT(ownerCount(env, alice) == 1);
2371 BEAST_EXPECT(ownerCount(env, becky) == 1);
2372 BEAST_EXPECT(ownerCount(env, carol) == 1);
2373 BEAST_EXPECT(ownerCount(env, minter) == 1);
2378 for (
auto NumberSwitchOver : {
true})
2380 if (NumberSwitchOver)
2381 env.enableFeature(fixUniversalNumber);
2383 env.disableFeature(fixUniversalNumber);
2388 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2393 STAmount aliceBalance = env.balance(alice);
2394 STAmount minterBalance = env.balance(minter);
2395 uint256 const minterBuyOfferIndex =
2397 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2399 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2401 aliceBalance += XRP(1) - baseFee;
2402 minterBalance -= XRP(1) + baseFee;
2403 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2404 BEAST_EXPECT(env.balance(minter) == minterBalance);
2408 auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
2409 STAmount carolBalance = env.balance(carol);
2410 uint256 const minterSellOfferIndex =
2412 env(token::createOffer(minter, nftID, pmt), txflags(
tfSellNFToken));
2414 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2416 minterBalance += pmt - baseFee;
2417 carolBalance -= pmt + baseFee;
2418 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2419 BEAST_EXPECT(env.balance(minter) == minterBalance);
2420 BEAST_EXPECT(env.balance(carol) == carolBalance);
2424 STAmount beckyBalance = env.balance(becky);
2425 uint256 const beckyBuyOfferIndex =
2427 pmt = NumberSwitchOver ? drops(50001) : drops(100000);
2428 env(token::createOffer(becky, nftID, pmt), token::owner(carol));
2430 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2432 carolBalance += pmt - drops(1) - baseFee;
2433 beckyBalance -= pmt + baseFee;
2434 aliceBalance += drops(1);
2436 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2437 BEAST_EXPECT(env.balance(minter) == minterBalance);
2438 BEAST_EXPECT(env.balance(carol) == carolBalance);
2439 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2448 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2454 env(pay(alice, gw, env.balance(alice, gwXAU)));
2455 env(pay(minter, gw, env.balance(minter, gwXAU)));
2456 env(pay(becky, gw, env.balance(becky, gwXAU)));
2461 env(pay(gw, alice, startXAUBalance));
2462 env(pay(gw, minter, startXAUBalance));
2463 env(pay(gw, becky, startXAUBalance));
2472 STAmount aliceBalance = env.balance(alice, gwXAU);
2473 STAmount minterBalance = env.balance(minter, gwXAU);
2474 uint256 const minterBuyOfferIndex =
2476 env(token::createOffer(minter, nftID, tinyXAU),
2477 token::owner(alice));
2479 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2481 aliceBalance += tinyXAU;
2482 minterBalance -= tinyXAU;
2483 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2484 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2487 STAmount carolBalance = env.balance(carol, gwXAU);
2488 uint256 const minterSellOfferIndex =
2490 env(token::createOffer(minter, nftID, tinyXAU),
2493 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2496 minterBalance += tinyXAU;
2497 carolBalance -= tinyXAU;
2499 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2500 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2501 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2508 STAmount beckyBalance = env.balance(becky, gwXAU);
2509 uint256 const beckyBuyOfferIndex =
2511 env(token::createOffer(becky, nftID, cheapNFT),
2512 token::owner(carol));
2514 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2517 aliceBalance += tinyXAU;
2518 beckyBalance -= cheapNFT;
2519 carolBalance += cheapNFT - tinyXAU;
2520 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2521 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2522 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2523 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2533 using namespace test::jtx;
2535 Env env{*
this, features};
2537 Account
const alice{
"alice"};
2538 Account
const becky{
"becky"};
2540 env.fund(XRP(1000), alice, becky);
2549 uint256 const nftID = token::getNextID(env, alice, 0u);
2556 uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2564 for (
int i = 0; i < 10; ++i)
2574 ss <<
"Taxon recovery failed from nftID "
2575 <<
to_string(nftID) <<
". Expected: " << taxon
2576 <<
"; got: " << gotTaxon;
2581 uint256 const nftAliceID = token::getID(
2585 rand_int<std::uint32_t>(),
2586 rand_int<std::uint16_t>(),
2587 rand_int<std::uint16_t>());
2588 check(taxon, nftAliceID);
2590 uint256 const nftBeckyID = token::getID(
2594 rand_int<std::uint32_t>(),
2595 rand_int<std::uint16_t>(),
2596 rand_int<std::uint16_t>());
2597 check(taxon, nftBeckyID);
2611 using namespace test::jtx;
2613 Env env{*
this, features};
2615 Account
const alice{
"alice"};
2616 Account
const becky{
"becky"};
2618 env.fund(XRP(10000), alice, becky);
2624 auto randURI = []() {
2646 : uri(std::move(uri_)), taxon(taxon_)
2654 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2657 for (Entry
const& entry : entries)
2659 if (entry.uri.empty())
2661 env(token::mint(alice, entry.taxon));
2665 env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2673 params[jss::account] = alice.human();
2674 params[jss::type] =
"state";
2675 return env.rpc(
"json",
"account_nfts",
to_string(params));
2679 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2680 if (!BEAST_EXPECT(nfts.
size() == entries.
size()))
2693 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2698 Entry
const& entry = entries[i];
2700 BEAST_EXPECT(entry.taxon == ret[sfNFTokenTaxon.jsonName]);
2701 if (entry.uri.empty())
2703 BEAST_EXPECT(!ret.
isMember(sfURI.jsonName));
2707 BEAST_EXPECT(
strHex(entry.uri) == ret[sfURI.jsonName]);
2716 testcase(
"Create offer destination");
2718 using namespace test::jtx;
2720 Env env{*
this, features};
2722 Account
const issuer{
"issuer"};
2723 Account
const minter{
"minter"};
2724 Account
const buyer{
"buyer"};
2725 Account
const broker{
"broker"};
2727 env.fund(XRP(1000), issuer, minter, buyer, broker);
2731 env(token::setMinter(issuer, minter));
2736 env(token::mint(minter, 0),
2737 token::issuer(issuer),
2744 uint256 const offerMinterToIssuer =
2746 env(token::createOffer(minter, nftokenID, drops(1)),
2747 token::destination(issuer),
2750 uint256 const offerMinterToBuyer =
2752 env(token::createOffer(minter, nftokenID, drops(1)),
2753 token::destination(buyer),
2756 uint256 const offerIssuerToMinter =
2758 env(token::createOffer(issuer, nftokenID, drops(1)),
2759 token::owner(minter),
2760 token::destination(minter));
2762 uint256 const offerIssuerToBuyer =
2764 env(token::createOffer(issuer, nftokenID, drops(1)),
2765 token::owner(minter),
2766 token::destination(buyer));
2769 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2770 BEAST_EXPECT(ownerCount(env, minter) == 3);
2771 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2780 env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2782 env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2784 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2786 env(token::cancelOffer(minter, {offerIssuerToBuyer}),
2789 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2790 BEAST_EXPECT(ownerCount(env, minter) == 3);
2791 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2795 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2796 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2797 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2798 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2800 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2801 BEAST_EXPECT(ownerCount(env, minter) == 1);
2802 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2808 uint256 const offerMinterSellsToBuyer =
2810 env(token::createOffer(minter, nftokenID, drops(1)),
2811 token::destination(buyer),
2814 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2815 BEAST_EXPECT(ownerCount(env, minter) == 2);
2816 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2820 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer),
2823 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2824 BEAST_EXPECT(ownerCount(env, minter) == 2);
2825 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2828 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2830 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2831 BEAST_EXPECT(ownerCount(env, minter) == 0);
2832 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2838 uint256 const offerMinterBuysFromBuyer =
2840 env(token::createOffer(minter, nftokenID, drops(1)),
2841 token::owner(buyer),
2842 token::destination(buyer));
2844 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2845 BEAST_EXPECT(ownerCount(env, minter) == 1);
2846 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2850 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer),
2853 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2854 BEAST_EXPECT(ownerCount(env, minter) == 1);
2855 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2858 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2860 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2861 BEAST_EXPECT(ownerCount(env, minter) == 1);
2862 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2867 uint256 const offerBuyerBuysFromMinter =
2869 env(token::createOffer(buyer, nftokenID, drops(1)),
2870 token::owner(minter),
2871 token::destination(broker));
2873 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2874 BEAST_EXPECT(ownerCount(env, minter) == 1);
2875 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2877 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter),
2882 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2884 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2885 BEAST_EXPECT(ownerCount(env, minter) == 1);
2886 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2892 uint256 const offerMinterToBroker =
2894 env(token::createOffer(minter, nftokenID, drops(1)),
2895 token::destination(broker),
2898 uint256 const offerBuyerToMinter =
2900 env(token::createOffer(buyer, nftokenID, drops(1)),
2901 token::owner(minter));
2904 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2905 BEAST_EXPECT(ownerCount(env, minter) == 2);
2906 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2911 TER const expectTer = features[fixNonFungibleTokensV1_2]
2914 env(token::brokerOffers(
2915 issuer, offerBuyerToMinter, offerMinterToBroker),
2918 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2919 BEAST_EXPECT(ownerCount(env, minter) == 2);
2920 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2925 env(token::brokerOffers(
2926 broker, offerBuyerToMinter, offerMinterToBroker));
2928 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2929 BEAST_EXPECT(ownerCount(env, minter) == 0);
2930 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2937 uint256 const offerBuyerToMinter =
2939 env(token::createOffer(buyer, nftokenID, drops(1)),
2940 token::destination(minter),
2943 uint256 const offerMinterToBuyer =
2945 env(token::createOffer(minter, nftokenID, drops(1)),
2946 token::owner(buyer));
2948 uint256 const offerIssuerToBuyer =
2950 env(token::createOffer(issuer, nftokenID, drops(1)),
2951 token::owner(buyer));
2954 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2955 BEAST_EXPECT(ownerCount(env, minter) == 1);
2956 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2961 TER const expectTer = features[fixNonFungibleTokensV1_2]
2964 env(token::brokerOffers(
2965 broker, offerIssuerToBuyer, offerBuyerToMinter),
2969 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2970 BEAST_EXPECT(ownerCount(env, minter) == 1);
2971 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2975 TER const eexpectTer = features[fixNonFungibleTokensV1_2]
2978 env(token::brokerOffers(
2979 broker, offerMinterToBuyer, offerBuyerToMinter),
2983 if (features[fixNonFungibleTokensV1_2])
2985 env(token::acceptBuyOffer(buyer, offerMinterToBuyer));
2989 env(token::cancelOffer(buyer, {offerBuyerToMinter}));
2992 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2993 BEAST_EXPECT(ownerCount(env, minter) == 1);
2994 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2997 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2999 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3000 BEAST_EXPECT(ownerCount(env, minter) == 1);
3001 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3009 uint256 const offerMinterToBroker =
3011 env(token::createOffer(minter, nftokenID, drops(1)),
3012 token::destination(broker),
3015 uint256 const offerBuyerToBroker =
3017 env(token::createOffer(buyer, nftokenID, drops(1)),
3018 token::owner(minter),
3019 token::destination(broker));
3024 TER const expectTer = features[fixNonFungibleTokensV1_2]
3027 env(token::brokerOffers(
3028 issuer, offerBuyerToBroker, offerMinterToBroker),
3031 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3032 BEAST_EXPECT(ownerCount(env, minter) == 2);
3033 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3037 env(token::brokerOffers(
3038 broker, offerBuyerToBroker, offerMinterToBroker));
3040 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3041 BEAST_EXPECT(ownerCount(env, minter) == 0);
3042 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3049 testcase(
"Create offer destination disallow incoming");
3051 using namespace test::jtx;
3056 Account
const alice{
"alice"};
3057 env.fund(XRP(10000), alice);
3060 auto const sle = env.le(alice);
3061 uint32_t flags = sle->getFlags();
3067 Account
const issuer{
"issuer"};
3068 Account
const minter{
"minter"};
3069 Account
const buyer{
"buyer"};
3070 Account
const alice{
"alice"};
3072 env.fund(XRP(1000), issuer, minter, buyer, alice);
3074 env(token::setMinter(issuer, minter));
3079 env(token::mint(minter, 0),
3080 token::issuer(issuer),
3090 env(token::createOffer(minter, nftokenID, drops(1)),
3091 token::destination(buyer),
3095 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3096 BEAST_EXPECT(ownerCount(env, minter) == 1);
3097 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3109 env(token::createOffer(minter, nftokenID, drops(1)),
3110 token::destination(buyer),
3114 env(token::cancelOffer(minter, {offerIndex}));
3123 env(token::createOffer(minter, nftokenID, drops(1)),
3124 token::destination(buyer),
3131 env(token::cancelOffer(minter, {offerIndex}));
3143 env(token::createOffer(minter, nftokenID, drops(1)),
3144 token::destination(buyer),
3148 env(token::acceptSellOffer(buyer, offerIndex));
3160 env(token::createOffer(alice, nftokenID, drops(1)),
3161 token::owner(buyer),
3168 env(token::createOffer(minter, nftokenID, drops(1)),
3169 token::owner(buyer),
3175 if (features[featureNFTokenMintOffer])
3180 env(token::mint(minter),
3181 token::amount(drops(1)),
3182 token::destination(buyer),
3188 env(token::mint(minter),
3189 token::amount(drops(1)),
3190 token::destination(buyer));
3199 testcase(
"Create offer expiration");
3201 using namespace test::jtx;
3203 Env env{*
this, features};
3205 Account
const issuer{
"issuer"};
3206 Account
const minter{
"minter"};
3207 Account
const buyer{
"buyer"};
3209 env.fund(XRP(1000), issuer, minter, buyer);
3213 env(token::setMinter(issuer, minter));
3218 env(token::mint(minter, 0),
3219 token::issuer(issuer),
3225 env(token::mint(minter, 0),
3226 token::issuer(issuer),
3235 uint256 const offerMinterToIssuer =
3237 env(token::createOffer(minter, nftokenID0, drops(1)),
3238 token::destination(issuer),
3239 token::expiration(expiration),
3242 uint256 const offerMinterToAnyone =
3244 env(token::createOffer(minter, nftokenID0, drops(1)),
3245 token::expiration(expiration),
3248 uint256 const offerIssuerToMinter =
3250 env(token::createOffer(issuer, nftokenID0, drops(1)),
3251 token::owner(minter),
3252 token::expiration(expiration));
3254 uint256 const offerBuyerToMinter =
3256 env(token::createOffer(buyer, nftokenID0, drops(1)),
3257 token::owner(minter),
3258 token::expiration(expiration));
3260 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3261 BEAST_EXPECT(ownerCount(env, minter) == 3);
3262 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3270 env(token::cancelOffer(issuer, {offerMinterToAnyone}),
3272 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
3275 BEAST_EXPECT(
lastClose(env) < expiration);
3276 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3277 BEAST_EXPECT(ownerCount(env, minter) == 3);
3278 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3281 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3285 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3291 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3292 BEAST_EXPECT(ownerCount(env, minter) == 1);
3293 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3296 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3297 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3299 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3300 BEAST_EXPECT(ownerCount(env, minter) == 1);
3301 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3312 env(token::createOffer(minter, nftokenID0, drops(1)),
3313 token::expiration(expiration),
3318 env(token::createOffer(minter, nftokenID1, drops(1)),
3319 token::expiration(expiration),
3322 BEAST_EXPECT(
lastClose(env) < expiration);
3323 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3324 BEAST_EXPECT(ownerCount(env, minter) == 3);
3325 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3328 env(token::acceptSellOffer(buyer, offer0));
3334 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3335 BEAST_EXPECT(ownerCount(env, minter) == 2);
3336 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3339 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3340 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3344 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3345 BEAST_EXPECT(ownerCount(env, minter) == 2);
3346 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3349 env(token::cancelOffer(issuer, {offer1}));
3351 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3352 BEAST_EXPECT(ownerCount(env, minter) == 1);
3353 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3359 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3361 token::destination(minter));
3363 env(token::acceptSellOffer(minter, offerSellBack));
3365 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3366 BEAST_EXPECT(ownerCount(env, minter) == 1);
3367 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3377 env(token::createOffer(buyer, nftokenID0, drops(1)),
3378 token::owner(minter),
3379 token::expiration(expiration));
3382 env(token::createOffer(buyer, nftokenID1, drops(1)),
3383 token::owner(minter),
3384 token::expiration(expiration));
3386 BEAST_EXPECT(
lastClose(env) < expiration);
3387 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3388 BEAST_EXPECT(ownerCount(env, minter) == 1);
3389 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3392 env(token::acceptBuyOffer(minter, offer0));
3398 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3399 BEAST_EXPECT(ownerCount(env, minter) == 1);
3400 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3403 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3404 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3408 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3409 BEAST_EXPECT(ownerCount(env, minter) == 1);
3410 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3413 env(token::cancelOffer(issuer, {offer1}));
3415 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3416 BEAST_EXPECT(ownerCount(env, minter) == 1);
3417 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3423 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3425 token::destination(minter));
3427 env(token::acceptSellOffer(minter, offerSellBack));
3429 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3430 BEAST_EXPECT(ownerCount(env, minter) == 1);
3431 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3442 env(token::createOffer(minter, nftokenID0, drops(1)),
3443 token::expiration(expiration),
3448 env(token::createOffer(minter, nftokenID1, drops(1)),
3449 token::expiration(expiration),
3454 env(token::createOffer(buyer, nftokenID0, drops(1)),
3455 token::owner(minter));
3459 env(token::createOffer(buyer, nftokenID1, drops(1)),
3460 token::owner(minter));
3463 BEAST_EXPECT(
lastClose(env) < expiration);
3464 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3465 BEAST_EXPECT(ownerCount(env, minter) == 3);
3466 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3469 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3475 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3476 BEAST_EXPECT(ownerCount(env, minter) == 2);
3477 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3480 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3485 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3486 BEAST_EXPECT(ownerCount(env, minter) == 2);
3487 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3490 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3492 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3493 BEAST_EXPECT(ownerCount(env, minter) == 1);
3494 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3500 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3502 token::destination(minter));
3504 env(token::acceptSellOffer(minter, offerSellBack));
3506 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3507 BEAST_EXPECT(ownerCount(env, minter) == 1);
3508 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3519 env(token::createOffer(minter, nftokenID0, drops(1)),
3524 env(token::createOffer(minter, nftokenID1, drops(1)),
3529 env(token::createOffer(buyer, nftokenID0, drops(1)),
3530 token::expiration(expiration),
3531 token::owner(minter));
3535 env(token::createOffer(buyer, nftokenID1, drops(1)),
3536 token::expiration(expiration),
3537 token::owner(minter));
3540 BEAST_EXPECT(
lastClose(env) < expiration);
3541 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3542 BEAST_EXPECT(ownerCount(env, minter) == 3);
3543 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3546 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3552 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3553 BEAST_EXPECT(ownerCount(env, minter) == 2);
3554 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3557 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3562 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3563 BEAST_EXPECT(ownerCount(env, minter) == 2);
3564 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3567 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3569 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3570 BEAST_EXPECT(ownerCount(env, minter) == 1);
3571 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3577 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3579 token::destination(minter));
3581 env(token::acceptSellOffer(minter, offerSellBack));
3583 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3584 BEAST_EXPECT(ownerCount(env, minter) == 1);
3585 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3597 env(token::createOffer(minter, nftokenID0, drops(1)),
3598 token::expiration(expiration),
3603 env(token::createOffer(minter, nftokenID1, drops(1)),
3604 token::expiration(expiration),
3609 env(token::createOffer(buyer, nftokenID0, drops(1)),
3610 token::expiration(expiration),
3611 token::owner(minter));
3615 env(token::createOffer(buyer, nftokenID1, drops(1)),
3616 token::expiration(expiration),
3617 token::owner(minter));
3620 BEAST_EXPECT(
lastClose(env) < expiration);
3621 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3622 BEAST_EXPECT(ownerCount(env, minter) == 3);
3623 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3626 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3632 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3633 BEAST_EXPECT(ownerCount(env, minter) == 2);
3634 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3637 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3642 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3643 BEAST_EXPECT(ownerCount(env, minter) == 2);
3644 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3647 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3649 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3650 BEAST_EXPECT(ownerCount(env, minter) == 1);
3651 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3657 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3659 token::destination(minter));
3661 env(token::acceptSellOffer(minter, offerSellBack));
3663 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3664 BEAST_EXPECT(ownerCount(env, minter) == 1);
3665 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3675 using namespace test::jtx;
3677 Env env{*
this, features};
3679 Account
const alice(
"alice");
3680 Account
const becky(
"becky");
3681 Account
const minter(
"minter");
3682 env.fund(XRP(50000), alice, becky, minter);
3686 env(token::setMinter(alice, minter));
3695 uint256 const expiredOfferIndex =
3698 env(token::createOffer(alice, nftokenID, XRP(1000)),
3700 token::expiration(
lastClose(env) + 13));
3704 BEAST_EXPECT(ownerCount(env, alice) == 2);
3705 env(token::cancelOffer(becky, {expiredOfferIndex}),
3713 env(token::cancelOffer(becky, {expiredOfferIndex}));
3715 BEAST_EXPECT(ownerCount(env, alice) == 1);
3719 uint256 const dest1OfferIndex =
3722 env(token::createOffer(alice, nftokenID, XRP(1000)),
3723 token::destination(becky),
3726 BEAST_EXPECT(ownerCount(env, alice) == 2);
3729 env(token::cancelOffer(minter, {dest1OfferIndex}),
3732 BEAST_EXPECT(ownerCount(env, alice) == 2);
3734 env(token::cancelOffer(becky, {dest1OfferIndex}));
3736 BEAST_EXPECT(ownerCount(env, alice) == 1);
3739 uint256 const dest2OfferIndex =
3742 env(token::createOffer(alice, nftokenID, XRP(1000)),
3743 token::destination(becky),
3746 BEAST_EXPECT(ownerCount(env, alice) == 2);
3748 env(token::cancelOffer(alice, {dest2OfferIndex}));
3750 BEAST_EXPECT(ownerCount(env, alice) == 1);
3755 uint256 const mintersNFTokenID =
3757 env(token::mint(minter, 0),
3758 token::issuer(alice),
3762 uint256 const minterOfferIndex =
3765 env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3768 BEAST_EXPECT(ownerCount(env, minter) == 2);
3771 env(token::cancelOffer(alice, {minterOfferIndex}),
3773 env(token::cancelOffer(becky, {minterOfferIndex}),
3776 BEAST_EXPECT(ownerCount(env, minter) == 2);
3778 env(token::cancelOffer(minter, {minterOfferIndex}));
3780 BEAST_EXPECT(ownerCount(env, minter) == 1);
3787 testcase(
"Cancel too many offers");
3789 using namespace test::jtx;
3791 Env env{*
this, features};
3806 Account
const alice(
"alice");
3807 env.fund(XRP(1000), alice);
3816 Account
const offerAcct(
3818 env.fund(XRP(1000), nftAcct, offerAcct);
3823 env(token::mint(nftAcct, 0),
3830 env(token::createOffer(offerAcct, nftokenID, drops(1)),
3831 token::owner(nftAcct),
3840 for (
uint256 const& offerIndex : offerIndexes)
3847 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3851 env(token::cancelOffer(alice, {offerIndexes.
back()}));
3862 env(token::mint(alice, 0),
3868 env(token::createOffer(alice, nftokenID, drops(1)),
3873 BEAST_EXPECT(ownerCount(env, alice) == 2);
3877 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3881 env(token::burn(alice, nftokenID));
3886 BEAST_EXPECT(ownerCount(env, alice) == 0);
3892 env(token::cancelOffer(alice, offerIndexes));
3896 for (
uint256 const& offerIndex : offerIndexes)
3906 testcase(
"Brokered NFT offer accept");
3908 using namespace test::jtx;
3910 for (
auto const& tweakedFeatures :
3911 {features - fixNonFungibleTokensV1_2,
3912 features | fixNonFungibleTokensV1_2})
3914 Env env{*
this, tweakedFeatures};
3915 auto const baseFee = env.current()->fees().base;
3923 Account
const issuer{
"issuer"};
3924 Account
const minter{
"minter"};
3925 Account
const buyer{
"buyer"};
3926 Account
const broker{
"broker"};
3927 Account
const gw{
"gw"};
3928 IOU
const gwXAU(gw[
"XAU"]);
3930 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3933 env(trust(issuer, gwXAU(2000)));
3934 env(trust(minter, gwXAU(2000)));
3935 env(trust(buyer, gwXAU(2000)));
3936 env(trust(broker, gwXAU(2000)));
3939 env(token::setMinter(issuer, minter));
3943 auto checkOwnerCountIsOne =
3948 for (Account
const& acct : accounts)
3955 ss <<
"Account " << acct.human()
3956 <<
" expected ownerCount == 1. Got "
3958 fail(ss.
str(), __FILE__, line);
3964 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3967 env(token::mint(minter, 0),
3968 token::issuer(issuer),
3969 token::xferFee(xferFee),
3981 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3983 uint256 const nftID = mintNFT();
3986 uint256 const minterOfferIndex =
3988 env(token::createOffer(minter, nftID, XRP(0)),
3996 env(token::createOffer(buyer, nftID, XRP(1)),
3997 token::owner(minter));
4000 auto const minterBalance = env.balance(minter);
4001 auto const buyerBalance = env.balance(buyer);
4002 auto const brokerBalance = env.balance(broker);
4003 auto const issuerBalance = env.balance(issuer);
4006 env(token::brokerOffers(
4007 broker, buyOfferIndex, minterOfferIndex));
4012 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
4013 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4014 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
4015 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4018 env(token::burn(buyer, nftID));
4028 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4030 uint256 const nftID = mintNFT();
4033 uint256 const minterOfferIndex =
4035 env(token::createOffer(minter, nftID, XRP(0)),
4043 env(token::createOffer(buyer, nftID, XRP(1)),
4044 token::owner(minter));
4048 env(token::brokerOffers(
4049 broker, buyOfferIndex, minterOfferIndex),
4050 token::brokerFee(XRP(1.1)),
4054 auto const minterBalance = env.balance(minter);
4055 auto const buyerBalance = env.balance(buyer);
4056 auto const brokerBalance = env.balance(broker);
4057 auto const issuerBalance = env.balance(issuer);
4060 env(token::brokerOffers(
4061 broker, buyOfferIndex, minterOfferIndex),
4062 token::brokerFee(XRP(0.5)));
4067 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4068 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4070 env.balance(broker) == brokerBalance + XRP(0.5) - baseFee);
4071 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4074 env(token::burn(buyer, nftID));
4084 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4089 uint256 const minterOfferIndex =
4091 env(token::createOffer(minter, nftID, XRP(0)),
4099 env(token::createOffer(buyer, nftID, XRP(1)),
4100 token::owner(minter));
4103 auto const minterBalance = env.balance(minter);
4104 auto const buyerBalance = env.balance(buyer);
4105 auto const brokerBalance = env.balance(broker);
4106 auto const issuerBalance = env.balance(issuer);
4109 env(token::brokerOffers(
4110 broker, buyOfferIndex, minterOfferIndex));
4115 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4116 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4117 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
4118 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
4121 env(token::burn(buyer, nftID));
4131 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4136 uint256 const minterOfferIndex =
4138 env(token::createOffer(minter, nftID, XRP(0)),
4146 env(token::createOffer(buyer, nftID, XRP(1)),
4147 token::owner(minter));
4150 auto const minterBalance = env.balance(minter);
4151 auto const buyerBalance = env.balance(buyer);
4152 auto const brokerBalance = env.balance(broker);
4153 auto const issuerBalance = env.balance(issuer);
4156 env(token::brokerOffers(
4157 broker, buyOfferIndex, minterOfferIndex),
4158 token::brokerFee(XRP(0.75)));
4164 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
4165 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4167 env.balance(broker) == brokerBalance + XRP(0.75) - baseFee);
4168 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
4171 env(token::burn(buyer, nftID));
4177 auto setXAUBalance =
4178 [
this, &gw, &gwXAU, &env](
4183 for (Account
const& acct : accounts)
4185 auto const xauAmt = gwXAU(amount);
4186 auto const balance = env.balance(acct, gwXAU);
4187 if (balance < xauAmt)
4189 env(pay(gw, acct, xauAmt - balance));
4192 else if (balance > xauAmt)
4194 env(pay(acct, gw, balance - xauAmt));
4197 if (env.balance(acct, gwXAU) != xauAmt)
4200 ss <<
"Unable to set " << acct.human()
4201 <<
" account balance to gwXAU(" << amount <<
")";
4202 this->
fail(ss.
str(), __FILE__, line);
4210 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4211 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4213 uint256 const nftID = mintNFT();
4216 uint256 const minterOfferIndex =
4218 env(token::createOffer(minter, nftID, gwXAU(1000)),
4227 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4228 token::owner(minter));
4232 env(token::brokerOffers(
4233 broker, buyOfferIndex, minterOfferIndex),
4239 env(token::cancelOffer(buyer, {buyOfferIndex}));
4247 env(token::createOffer(buyer, nftID, gwXAU(999)),
4248 token::owner(minter));
4252 env(token::brokerOffers(
4253 broker, buyOfferIndex, minterOfferIndex),
4259 env(token::cancelOffer(buyer, {buyOfferIndex}));
4266 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4267 token::owner(minter));
4271 env(token::brokerOffers(
4272 broker, buyOfferIndex, minterOfferIndex),
4273 token::brokerFee(gwXAU(0.1)),
4278 env(token::brokerOffers(
4279 broker, buyOfferIndex, minterOfferIndex));
4282 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4283 BEAST_EXPECT(ownerCount(env, minter) == 1);
4284 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4285 BEAST_EXPECT(ownerCount(env, broker) == 1);
4286 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4287 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4288 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4289 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4292 env(token::burn(buyer, nftID));
4299 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4300 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4305 uint256 const minterOfferIndex =
4307 env(token::createOffer(minter, nftID, gwXAU(900)),
4315 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4316 token::owner(minter));
4320 env(token::brokerOffers(
4321 broker, buyOfferIndex, minterOfferIndex),
4327 env(token::cancelOffer(buyer, {buyOfferIndex}));
4335 env(token::createOffer(buyer, nftID, gwXAU(899)),
4336 token::owner(minter));
4340 env(token::brokerOffers(
4341 broker, buyOfferIndex, minterOfferIndex),
4347 env(token::cancelOffer(buyer, {buyOfferIndex}));
4353 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4354 token::owner(minter));
4359 env(token::brokerOffers(
4360 broker, buyOfferIndex, minterOfferIndex),
4361 token::brokerFee(gwXAU(101)),
4367 env(token::brokerOffers(
4368 broker, buyOfferIndex, minterOfferIndex),
4369 token::brokerFee(gwXAU(100)));
4372 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4373 BEAST_EXPECT(ownerCount(env, minter) == 1);
4374 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4375 BEAST_EXPECT(ownerCount(env, broker) == 1);
4376 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4377 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4378 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4379 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4382 env(token::burn(buyer, nftID));
4389 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4390 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4395 uint256 const minterOfferIndex =
4397 env(token::createOffer(minter, nftID, gwXAU(900)),
4404 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4405 token::owner(minter));
4411 env(token::brokerOffers(
4412 broker, buyOfferIndex, minterOfferIndex),
4413 token::brokerFee(gwXAU(50)));
4416 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4417 BEAST_EXPECT(ownerCount(env, minter) == 1);
4418 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4419 BEAST_EXPECT(ownerCount(env, broker) == 1);
4420 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4421 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4422 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4423 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4426 env(token::burn(buyer, nftID));
4431 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4432 setXAUBalance({issuer, minter, buyer}, 1000, __LINE__);
4433 setXAUBalance({broker}, 500, __LINE__);
4437 uint256 const minterOfferIndex =
4439 env(token::createOffer(minter, nftID, gwXAU(900)),
4446 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4447 token::owner(minter));
4450 if (tweakedFeatures[fixNonFungibleTokensV1_2])
4452 env(token::brokerOffers(
4453 broker, buyOfferIndex, minterOfferIndex),
4454 token::brokerFee(gwXAU(50)));
4456 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4457 BEAST_EXPECT(ownerCount(env, minter) == 1);
4458 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4459 BEAST_EXPECT(ownerCount(env, broker) == 1);
4460 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4461 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4462 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4463 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(550));
4466 env(token::burn(buyer, nftID));
4471 env(token::brokerOffers(
4472 broker, buyOfferIndex, minterOfferIndex),
4473 token::brokerFee(gwXAU(50)),
4476 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4477 BEAST_EXPECT(ownerCount(env, minter) == 3);
4478 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4479 BEAST_EXPECT(ownerCount(env, broker) == 1);
4480 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4481 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4482 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
4483 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(500));
4486 env(token::burn(minter, nftID));
4499 using namespace test::jtx;
4501 Env env{*
this, features};
4503 Account
const issuer{
"issuer"};
4504 Account
const buyer1{
"buyer1"};
4505 Account
const buyer2{
"buyer2"};
4506 env.fund(XRP(10000), issuer, buyer1, buyer2);
4515 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4516 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4517 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4520 uint256 const buyer1OfferIndex =
4522 env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer));
4523 uint256 const buyer2OfferIndex =
4525 env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer));
4535 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4537 if (buyOffers.
isMember(jss::result) &&
4538 buyOffers[jss::result].
isMember(jss::offers))
4539 return buyOffers[jss::result][jss::offers].
size();
4545 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4548 env(token::acceptBuyOffer(issuer, buyer1OfferIndex));
4552 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4553 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4554 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4558 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4562 env(token::acceptBuyOffer(buyer1, buyer2OfferIndex));
4566 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4567 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4568 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4571 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4578 testcase(
"NFToken transactions with tickets");
4580 using namespace test::jtx;
4582 Env env{*
this, features};
4584 Account
const issuer{
"issuer"};
4585 Account
const buyer{
"buyer"};
4586 env.fund(XRP(10000), issuer, buyer);
4593 env(ticket::create(issuer, 10));
4599 env(ticket::create(buyer, 10));
4605 BEAST_EXPECT(ownerCount(env, issuer) == 10);
4607 env(token::mint(issuer, 0u),
4609 ticket::use(issuerTicketSeq++));
4611 BEAST_EXPECT(ownerCount(env, issuer) == 10);
4615 BEAST_EXPECT(ownerCount(env, buyer) == 10);
4617 env(token::createOffer(buyer, nftId, XRP(1)),
4618 token::owner(issuer),
4619 ticket::use(buyerTicketSeq++));
4621 BEAST_EXPECT(ownerCount(env, buyer) == 10);
4625 env(token::cancelOffer(buyer, {offerIndex0}),
4626 ticket::use(buyerTicketSeq++));
4628 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4633 env(token::createOffer(buyer, nftId, XRP(2)),
4634 token::owner(issuer),
4635 ticket::use(buyerTicketSeq++));
4637 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4641 env(token::acceptBuyOffer(issuer, offerIndex1),
4642 ticket::use(issuerTicketSeq++));
4644 BEAST_EXPECT(ownerCount(env, issuer) == 8);
4645 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4649 env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4651 BEAST_EXPECT(ownerCount(env, issuer) == 8);
4652 BEAST_EXPECT(ownerCount(env, buyer) == 6);
4656 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4657 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4668 testcase(
"NFToken delete account");
4670 using namespace test::jtx;
4672 Env env{*
this, features};
4674 Account
const issuer{
"issuer"};
4675 Account
const minter{
"minter"};
4676 Account
const becky{
"becky"};
4677 Account
const carla{
"carla"};
4678 Account
const daria{
"daria"};
4680 env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4684 for (
int i = 0; i < 300; ++i)
4687 env(token::setMinter(issuer, minter));
4691 env(token::mint(minter, 0u),
4692 token::issuer(issuer),
4705 for (
int i = 0; i < 15; ++i)
4709 env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4712 uint256 const carlaOfferIndex =
4714 env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4719 env(acctdelete(becky, daria), fee(XRP(50)));
4723 env(token::acceptBuyOffer(minter, carlaOfferIndex));
4728 env(acctdelete(minter, daria), fee(XRP(50)));
4740 for (
int i = 0; i < 15; ++i)
4745 env(token::burn(carla, nftId));
4748 env(acctdelete(issuer, daria), fee(XRP(50)));
4749 env(acctdelete(carla, daria), fee(XRP(50)));
4756 testcase(
"nft_buy_offers and nft_sell_offers");
4765 using namespace test::jtx;
4767 Env env{*
this, features};
4769 Account
const issuer{
"issuer"};
4770 Account
const buyer{
"buyer"};
4773 env.fund(XRP(1000000), issuer, buyer);
4782 auto checkOffers = [
this, &env, &nftID](
4783 char const* request,
4785 int expectMarkerCount,
4787 int markerCount = 0;
4794 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4798 if (!marker.
empty())
4799 params[jss::marker] = marker;
4800 return env.rpc(
"json", request,
to_string(params));
4804 if (expectCount == 0)
4808 "expected \"result\"",
4813 nftOffers[jss::result].isMember(jss::error),
4814 "expected \"error\"",
4819 nftOffers[jss::result][jss::error].asString() ==
4821 "expected \"objectNotFound\"",
4832 "expected \"result\"",
4841 marker = result[jss::marker].
asString();
4846 "expected \"offers\"",
4852 allOffers.
append(someOffers[i]);
4855 }
while (!marker.
empty());
4859 allOffers.
size() == expectCount,
4860 "Unexpected returned offer count",
4864 markerCount == expectMarkerCount,
4865 "Unexpected marker count",
4875 globalFlags = offer[jss::flags].asInt();
4878 *globalFlags == offer[jss::flags].asInt(),
4879 "Inconsistent flags returned",
4885 offerIndexes.
insert(offer[jss::nft_offer_index].asString());
4886 amounts.
insert(offer[jss::amount].asString());
4890 offerIndexes.
size() == expectCount,
4891 "Duplicate indexes returned?",
4895 amounts.
size() == expectCount,
4896 "Duplicate amounts returned?",
4902 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4906 auto makeSellOffers =
4907 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4910 while (sellPrice < limit)
4912 sellPrice += XRP(1);
4913 env(token::createOffer(issuer, nftID, sellPrice),
4915 if (++offerCount % 10 == 0)
4922 makeSellOffers(XRP(1));
4923 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4926 makeSellOffers(XRP(250));
4927 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4930 makeSellOffers(XRP(251));
4931 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4934 makeSellOffers(XRP(500));
4935 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4938 makeSellOffers(XRP(501));
4939 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4942 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4946 auto makeBuyOffers =
4947 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4950 while (buyPrice < limit)
4953 env(token::createOffer(buyer, nftID, buyPrice),
4954 token::owner(issuer));
4955 if (++offerCount % 10 == 0)
4962 makeBuyOffers(XRP(1));
4963 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4966 makeBuyOffers(XRP(250));
4967 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4970 makeBuyOffers(XRP(251));
4971 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4974 makeBuyOffers(XRP(500));
4975 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4978 makeBuyOffers(XRP(501));
4979 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4986 using namespace test::jtx;
4990 Account
const issuer{
"issuer"};
4991 Account
const buyer{
"buyer"};
4992 Account
const gw{
"gw"};
4993 IOU
const gwXAU(gw[
"XAU"]);
4999 for (
auto const& tweakedFeatures :
5000 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1 -
5001 fixNonFungibleTokensV1_2,
5002 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
5003 features | fixNFTokenNegOffer})
5008 Env env{*
this, tweakedFeatures};
5010 env.fund(XRP(1000000), issuer, buyer, gw);
5013 env(trust(issuer, gwXAU(2000)));
5014 env(trust(buyer, gwXAU(2000)));
5017 env(pay(gw, issuer, gwXAU(1000)));
5018 env(pay(gw, buyer, gwXAU(1000)));
5033 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5038 uint256 const sellNegXrpOfferIndex =
5040 env(token::createOffer(issuer, nftID0, XRP(-2)),
5042 ter(offerCreateTER));
5045 uint256 const sellNegIouOfferIndex =
5047 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
5049 ter(offerCreateTER));
5052 uint256 const buyNegXrpOfferIndex =
5054 env(token::createOffer(buyer, nftID0, XRP(-1)),
5055 token::owner(issuer),
5056 ter(offerCreateTER));
5059 uint256 const buyNegIouOfferIndex =
5061 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
5062 token::owner(issuer),
5063 ter(offerCreateTER));
5070 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5075 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
5076 ter(offerAcceptTER));
5078 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
5079 ter(offerAcceptTER));
5083 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
5084 ter(offerAcceptTER));
5086 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
5087 ter(offerAcceptTER));
5095 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5100 env(token::brokerOffers(
5101 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5102 ter(offerAcceptTER));
5104 env(token::brokerOffers(
5105 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5106 ter(offerAcceptTER));
5116 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1};
5118 env.fund(XRP(1000000), issuer, buyer, gw);
5121 env(trust(issuer, gwXAU(2000)));
5122 env(trust(buyer, gwXAU(2000)));
5125 env(pay(gw, issuer, gwXAU(1000)));
5126 env(pay(gw, buyer, gwXAU(1000)));
5142 uint256 const sellNegXrpOfferIndex =
5144 env(token::createOffer(issuer, nftID0, XRP(-2)),
5148 uint256 const sellNegIouOfferIndex =
5150 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
5154 uint256 const buyNegXrpOfferIndex =
5156 env(token::createOffer(buyer, nftID0, XRP(-1)),
5157 token::owner(issuer));
5160 uint256 const buyNegIouOfferIndex =
5162 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
5163 token::owner(issuer));
5167 env.enableFeature(fixNFTokenNegOffer);
5172 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
5175 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
5180 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
5183 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
5188 env(token::brokerOffers(
5189 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5192 env(token::brokerOffers(
5193 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5200 for (
auto const& tweakedFeatures :
5201 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
5202 features | fixNFTokenNegOffer})
5204 Env env{*
this, tweakedFeatures};
5206 env.fund(XRP(1000000), issuer, buyer);
5214 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5218 env(token::createOffer(buyer, nftID, drops(1)),
5219 token::owner(issuer),
5220 token::destination(issuer),
5221 ter(offerCreateTER));
5229 using namespace test::jtx;
5231 testcase(
"Payments with IOU transfer fees");
5233 for (
auto const& tweakedFeatures :
5234 {features - fixNonFungibleTokensV1_2,
5235 features | fixNonFungibleTokensV1_2})
5237 Env env{*
this, tweakedFeatures};
5239 Account
const minter{
"minter"};
5240 Account
const secondarySeller{
"seller"};
5241 Account
const buyer{
"buyer"};
5242 Account
const gw{
"gateway"};
5243 Account
const broker{
"broker"};
5244 IOU
const gwXAU(gw[
"XAU"]);
5245 IOU
const gwXPB(gw[
"XPB"]);
5247 env.fund(XRP(1000), gw, minter, secondarySeller, buyer, broker);
5250 env(trust(minter, gwXAU(2000)));
5251 env(trust(secondarySeller, gwXAU(2000)));
5252 env(trust(broker, gwXAU(10000)));
5253 env(trust(buyer, gwXAU(2000)));
5254 env(trust(buyer, gwXPB(2000)));
5258 env(rate(gw, 1.02));
5261 auto expectInitialState = [
this,
5274 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
5275 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(0));
5276 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(0));
5277 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(0));
5278 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(0));
5279 BEAST_EXPECT(env.balance(secondarySeller, gwXPB) == gwXPB(0));
5280 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5000));
5281 BEAST_EXPECT(env.balance(broker, gwXPB) == gwXPB(0));
5282 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-1000));
5283 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(0));
5284 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(0));
5285 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(0));
5287 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(0));
5289 env.balance(gw, secondarySeller[
"XPB"]) == gwXPB(0));
5290 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5000));
5291 BEAST_EXPECT(env.balance(gw, broker[
"XPB"]) == gwXPB(0));
5294 auto reinitializeTrustLineBalances = [&expectInitialState,
5303 if (
auto const difference =
5304 gwXAU(1000) - env.balance(buyer, gwXAU);
5305 difference > gwXAU(0))
5306 env(pay(gw, buyer, difference));
5307 if (env.balance(buyer, gwXPB) > gwXPB(0))
5308 env(pay(buyer, gw, env.balance(buyer, gwXPB)));
5309 if (env.balance(minter, gwXAU) > gwXAU(0))
5310 env(pay(minter, gw, env.balance(minter, gwXAU)));
5311 if (env.balance(minter, gwXPB) > gwXPB(0))
5312 env(pay(minter, gw, env.balance(minter, gwXPB)));
5313 if (env.balance(secondarySeller, gwXAU) > gwXAU(0))
5315 pay(secondarySeller,
5317 env.balance(secondarySeller, gwXAU)));
5318 if (env.balance(secondarySeller, gwXPB) > gwXPB(0))
5320 pay(secondarySeller,
5322 env.balance(secondarySeller, gwXPB)));
5323 auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU);
5324 if (brokerDiff > gwXAU(0))
5325 env(pay(gw, broker, brokerDiff));
5326 else if (brokerDiff < gwXAU(0))
5328 brokerDiff.negate();
5329 env(pay(broker, gw, brokerDiff));
5331 if (env.balance(broker, gwXPB) > gwXPB(0))
5332 env(pay(broker, gw, env.balance(broker, gwXPB)));
5334 expectInitialState();
5337 auto mintNFT = [&env](Account
const& minter,
int transferFee = 0) {
5338 uint256 const nftID = token::getNextID(
5340 env(token::mint(minter),
5341 token::xferFee(transferFee),
5347 auto createBuyOffer =
5349 Account
const& offerer,
5350 Account
const& owner,
5356 env(token::createOffer(offerer, nftID, amount),
5357 token::owner(owner),
5358 terCode ? ter(*terCode)
5364 auto createSellOffer =
5366 Account
const& offerer,
5372 env(token::createOffer(offerer, nftID, amount),
5374 terCode ? ter(*terCode)
5383 reinitializeTrustLineBalances();
5384 auto const nftID = mintNFT(minter);
5385 auto const offerID =
5386 createSellOffer(minter, nftID, gwXAU(1000));
5387 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5390 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5393 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5394 expectInitialState();
5397 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5398 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5400 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5401 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5407 reinitializeTrustLineBalances();
5408 auto const nftID = mintNFT(minter);
5409 auto const offerID =
5410 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5411 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5414 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5417 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5418 expectInitialState();
5421 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5422 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5424 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5425 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5432 reinitializeTrustLineBalances();
5433 auto const nftID = mintNFT(minter);
5434 auto const offerID = createSellOffer(minter, nftID, gwXAU(995));
5435 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5438 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5441 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5442 expectInitialState();
5445 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5446 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5447 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5448 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5455 reinitializeTrustLineBalances();
5456 auto const nftID = mintNFT(minter);
5457 auto const offerID =
5458 createBuyOffer(buyer, minter, nftID, gwXAU(995));
5459 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5462 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5465 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5466 expectInitialState();
5469 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5470 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5471 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5472 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5480 reinitializeTrustLineBalances();
5481 auto const nftID = mintNFT(minter);
5482 auto const offerID = createSellOffer(minter, nftID, gwXAU(900));
5483 env(token::acceptSellOffer(buyer, offerID));
5486 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5487 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5488 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5489 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5496 reinitializeTrustLineBalances();
5497 auto const nftID = mintNFT(minter);
5498 auto const offerID =
5499 createBuyOffer(buyer, minter, nftID, gwXAU(900));
5500 env(token::acceptBuyOffer(minter, offerID));
5503 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5504 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5505 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5506 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5513 reinitializeTrustLineBalances();
5516 env(pay(gw, buyer, gwXAU(20)));
5519 auto const nftID = mintNFT(minter);
5520 auto const offerID =
5521 createSellOffer(minter, nftID, gwXAU(1000));
5522 env(token::acceptSellOffer(buyer, offerID));
5525 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5526 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5527 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5528 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5535 reinitializeTrustLineBalances();
5538 env(pay(gw, buyer, gwXAU(20)));
5541 auto const nftID = mintNFT(minter);
5542 auto const offerID =
5543 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5544 env(token::acceptBuyOffer(minter, offerID));
5547 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5548 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5549 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5550 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5555 reinitializeTrustLineBalances();
5557 auto const nftID = mintNFT(minter);
5558 auto const offerID =
5559 createSellOffer(minter, nftID, gwXAU(1000));
5560 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5563 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5566 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5568 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5570 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5573 expectInitialState();
5578 reinitializeTrustLineBalances();
5580 auto const nftID = mintNFT(minter);
5581 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5584 auto const offerID =
5585 createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER});
5586 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5589 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5592 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5594 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5596 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5599 expectInitialState();
5604 reinitializeTrustLineBalances();
5605 auto const nftID = mintNFT(minter);
5606 auto const offerID =
5607 createSellOffer(minter, nftID, gwXAU(5000));
5608 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5611 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5614 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5616 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5618 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5621 expectInitialState();
5626 reinitializeTrustLineBalances();
5628 auto const nftID = mintNFT(minter);
5629 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5632 auto const offerID =
5633 createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER});
5634 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5637 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5640 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5642 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5644 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5647 expectInitialState();
5653 reinitializeTrustLineBalances();
5654 auto const nftID = mintNFT(gw);
5655 auto const offerID = createSellOffer(gw, nftID, gwXAU(1000));
5656 env(token::acceptSellOffer(buyer, offerID));
5659 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5660 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5666 reinitializeTrustLineBalances();
5668 auto const nftID = mintNFT(gw);
5669 auto const offerID =
5670 createBuyOffer(buyer, gw, nftID, gwXAU(1000));
5671 env(token::acceptBuyOffer(gw, offerID));
5674 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5675 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5681 reinitializeTrustLineBalances();
5682 auto const nftID = mintNFT(gw);
5683 auto const offerID = createSellOffer(gw, nftID, gwXAU(2000));
5684 env(token::acceptSellOffer(buyer, offerID),
5687 expectInitialState();
5693 reinitializeTrustLineBalances();
5694 auto const nftID = mintNFT(gw);
5695 auto const offerID =
5696 createBuyOffer(buyer, gw, nftID, gwXAU(2000));
5697 env(token::acceptBuyOffer(gw, offerID),
5700 expectInitialState();
5705 reinitializeTrustLineBalances();
5706 auto const nftID = mintNFT(minter);
5707 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5708 env(token::acceptSellOffer(buyer, offerID),
5711 expectInitialState();
5716 reinitializeTrustLineBalances();
5717 auto const nftID = mintNFT(minter);
5718 auto const offerID = createBuyOffer(
5724 env(token::acceptBuyOffer(minter, offerID),
5727 expectInitialState();
5733 reinitializeTrustLineBalances();
5734 env(pay(gw, buyer, gwXPB(100)));
5737 auto const nftID = mintNFT(minter);
5738 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5739 env(token::acceptSellOffer(buyer, offerID));
5742 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5743 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5744 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5745 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5751 reinitializeTrustLineBalances();
5752 env(pay(gw, buyer, gwXPB(100)));
5755 auto const nftID = mintNFT(minter);
5756 auto const offerID =
5757 createBuyOffer(buyer, minter, nftID, gwXPB(10));
5758 env(token::acceptBuyOffer(minter, offerID));
5761 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5762 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5763 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5764 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5769 reinitializeTrustLineBalances();
5773 auto const nftID = mintNFT(minter, 3000);
5774 auto const primaryOfferID =
5775 createSellOffer(minter, nftID, XRP(0));
5776 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5780 auto const offerID =
5781 createSellOffer(secondarySeller, nftID, gwXAU(1000));
5782 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5785 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5788 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5789 expectInitialState();
5792 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5794 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5795 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5796 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5798 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5799 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5805 reinitializeTrustLineBalances();
5809 auto const nftID = mintNFT(minter, 3000);
5810 auto const primaryOfferID =
5811 createSellOffer(minter, nftID, XRP(0));
5812 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5816 auto const offerID =
5817 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000));
5818 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5821 env(token::acceptBuyOffer(secondarySeller, offerID),
5825 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5826 expectInitialState();
5829 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5831 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5832 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5833 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5835 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5836 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5842 reinitializeTrustLineBalances();
5846 auto const nftID = mintNFT(minter, 3000);
5847 auto const primaryOfferID =
5848 createSellOffer(minter, nftID, XRP(0));
5849 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5853 auto const offerID =
5854 createSellOffer(secondarySeller, nftID, gwXAU(900));
5855 env(token::acceptSellOffer(buyer, offerID));
5858 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5859 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5860 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5861 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5863 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5864 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5869 reinitializeTrustLineBalances();
5873 auto const nftID = mintNFT(minter, 3000);
5874 auto const primaryOfferID =
5875 createSellOffer(minter, nftID, XRP(0));
5876 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5880 auto const offerID =
5881 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900));
5882 env(token::acceptBuyOffer(secondarySeller, offerID));
5886 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5888 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5890 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5891 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5893 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5894 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5912 reinitializeTrustLineBalances();
5914 auto const nftID = mintNFT(minter);
5915 auto const sellOffer =
5916 createSellOffer(minter, nftID, gwXAU(300));
5917 auto const buyOffer =
5918 createBuyOffer(buyer, minter, nftID, gwXAU(500));
5919 env(token::brokerOffers(broker, buyOffer, sellOffer),
5920 token::brokerFee(gwXAU(100)));
5923 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400));
5924 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5925 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5926 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-400));
5927 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5928 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5946 reinitializeTrustLineBalances();
5950 auto const nftID = mintNFT(minter, 3000);
5951 auto const primaryOfferID =
5952 createSellOffer(minter, nftID, XRP(0));
5953 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5957 auto const sellOffer =
5958 createSellOffer(secondarySeller, nftID, gwXAU(300));
5959 auto const buyOffer =
5960 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500));
5961 env(token::brokerOffers(broker, buyOffer, sellOffer),
5962 token::brokerFee(gwXAU(100)));
5965 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12));
5966 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5967 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(388));
5968 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5969 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-12));
5970 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5972 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-388));
5973 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5995 using namespace test::jtx;
5997 Account
const alice{
"alice"};
5998 Account
const bob{
"bob"};
5999 Account
const broker{
"broker"};
6001 Env env{*
this, features};
6002 auto const baseFee = env.current()->fees().base;
6003 env.fund(XRP(10000), alice, bob, broker);
6029 uint256 const bobBuyOfferIndex =
6031 env(token::createOffer(bob, nftId, XRP(5)), token::owner(alice));
6033 uint256 const aliceSellOfferIndex =
6035 env(token::createOffer(alice, nftId, XRP(0)),
6036 token::destination(bob),
6041 env(token::acceptSellOffer(bob, aliceSellOfferIndex));
6048 uint256 const bobSellOfferIndex =
6050 env(token::createOffer(bob, nftId, XRP(4)), txflags(
tfSellNFToken));
6055 BEAST_EXPECT(
nftCount(env, bob) == 1);
6056 auto const bobsPriorBalance = env.balance(bob);
6057 auto const brokersPriorBalance = env.balance(broker);
6058 TER expectTer = features[fixNonFungibleTokensV1_2]
6061 env(token::brokerOffers(broker, bobBuyOfferIndex, bobSellOfferIndex),
6062 token::brokerFee(XRP(1)),
6071 BEAST_EXPECT(
nftCount(env, bob) == 1);
6072 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance - XRP(1));
6074 env.balance(broker) == brokersPriorBalance + XRP(1) - baseFee);
6080 BEAST_EXPECT(
nftCount(env, bob) == 1);
6081 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance);
6082 BEAST_EXPECT(env.balance(broker) == brokersPriorBalance - baseFee);
6089 using namespace test::jtx;
6094 auto openLedgerSeq = [](Env& env) {
return env.current()->seq(); };
6099 auto incLgrSeqForAcctDel = [&](Env& env, Account
const& acct) {
6100 int const delta = [&]() ->
int {
6101 if (env.seq(acct) + 255 > openLedgerSeq(env))
6102 return env.seq(acct) - openLedgerSeq(env) + 255;
6105 BEAST_EXPECT(delta >= 0);
6106 for (
int i = 0; i < delta; ++i)
6108 BEAST_EXPECT(openLedgerSeq(env) == env.seq(acct) + 255);
6114 auto incLgrSeqForFixNftRemint = [&](Env& env, Account
const& acct) {
6116 auto const deletableLgrSeq =
6117 (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) +
6118 (*env.le(acct))[sfMintedNFTokens] + 255;
6120 if (deletableLgrSeq > openLedgerSeq(env))
6121 delta = deletableLgrSeq - openLedgerSeq(env);
6123 BEAST_EXPECT(delta >= 0);
6124 for (
int i = 0; i < delta; ++i)
6126 BEAST_EXPECT(openLedgerSeq(env) == deletableLgrSeq);
6132 Env env{*
this, features};
6133 Account
const alice(
"alice");
6134 Account
const becky(
"becky");
6136 env.fund(XRP(10000), alice, becky);
6140 uint256 const prevNFTokenID = token::getNextID(env, alice, 0u);
6141 env(token::mint(alice));
6143 env(token::burn(alice, prevNFTokenID));
6147 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 1);
6150 incLgrSeqForAcctDel(env, alice);
6154 auto const acctDelFee{drops(env.current()->fees().increment)};
6155 env(acctdelete(alice, becky), fee(acctDelFee));
6160 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6161 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6164 env.fund(XRP(10000), alice);
6168 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6169 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6170 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6173 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6174 env(token::mint(alice));
6178 env(token::burn(alice, remintNFTokenID));
6181 if (features[fixNFTokenRemint])
6183 BEAST_EXPECT(remintNFTokenID != prevNFTokenID);
6186 BEAST_EXPECT(remintNFTokenID == prevNFTokenID);
6192 Env env{*
this, features};
6193 Account
const alice(
"alice");
6194 Account
const becky(
"becky");
6195 Account
const minter{
"minter"};
6197 env.fund(XRP(10000), alice, becky, minter);
6201 env(token::setMinter(alice, minter));
6207 for (
int i = 0; i < 500; i++)
6209 uint256 const nftokenID = token::getNextID(env, alice, 0u);
6211 env(token::mint(minter), token::issuer(alice));
6216 for (
auto const nftokenID : nftIDs)
6218 env(token::burn(minter, nftokenID));
6224 incLgrSeqForAcctDel(env, alice);
6228 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6229 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6231 auto const acctDelFee{drops(env.current()->fees().increment)};
6233 if (!features[fixNFTokenRemint])
6236 env(acctdelete(alice, becky), fee(acctDelFee));
6238 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6241 env.fund(XRP(10000), alice);
6245 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6246 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6247 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6251 uint256 const remintNFTokenID =
6252 token::getNextID(env, alice, 0u);
6253 env(token::mint(alice));
6257 env(token::burn(alice, remintNFTokenID));
6266 else if (features[fixNFTokenRemint])
6275 env(acctdelete(alice, becky),
6281 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6286 incLgrSeqForFixNftRemint(env, alice);
6289 env(acctdelete(alice, becky), fee(acctDelFee));
6294 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6295 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6298 env.fund(XRP(10000), alice);
6302 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6303 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6304 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6308 uint256 const remintNFTokenID =
6309 token::getNextID(env, alice, 0u);
6310 env(token::mint(alice));
6314 env(token::burn(alice, remintNFTokenID));
6328 Env env{*
this, features};
6330 Account
const alice{
"alice"};
6331 Account
const becky{
"becky"};
6332 env.fund(XRP(10000), alice, becky);
6339 env(ticket::create(alice, 100));
6343 BEAST_EXPECT(ownerCount(env, alice) == 100);
6348 for (
int i = 0; i < 50; i++)
6350 nftIDs.
push_back(token::getNextID(env, alice, 0u));
6351 env(token::mint(alice, 0u), ticket::use(aliceTicketSeq++));
6356 for (
auto const nftokenID : nftIDs)
6358 env(token::burn(alice, nftokenID),
6359 ticket::use(aliceTicketSeq++));
6367 incLgrSeqForAcctDel(env, alice);
6371 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6372 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6374 auto const acctDelFee{drops(env.current()->fees().increment)};
6376 if (!features[fixNFTokenRemint])
6379 env(acctdelete(alice, becky), fee(acctDelFee));
6384 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6385 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6388 env.fund(XRP(10000), alice);
6392 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6393 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6394 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6398 uint256 const remintNFTokenID =
6399 token::getNextID(env, alice, 0u);
6400 env(token::mint(alice));
6404 env(token::burn(alice, remintNFTokenID));
6413 else if (features[fixNFTokenRemint])
6422 env(acctdelete(alice, becky),
6428 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6433 incLgrSeqForFixNftRemint(env, alice);
6436 env(acctdelete(alice, becky), fee(acctDelFee));
6441 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6442 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6445 env.fund(XRP(10000), alice);
6449 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6450 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6451 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6455 uint256 const remintNFTokenID =
6456 token::getNextID(env, alice, 0u);
6457 env(token::mint(alice));
6461 env(token::burn(alice, remintNFTokenID));
6477 if (features[fixNFTokenRemint])
6479 Env env{*
this, features};
6480 Account
const alice(
"alice");
6481 Account
const becky(
"becky");
6482 Account
const minter{
"minter"};
6484 env.fund(XRP(10000), alice, becky, minter);
6488 env(token::setMinter(alice, minter));
6493 env(ticket::create(minter, 100));
6497 BEAST_EXPECT(ownerCount(env, minter) == 100);
6502 for (
int i = 0; i < 50; i++)
6504 uint256 const nftokenID = token::getNextID(env, alice, 0u);
6506 env(token::mint(minter),
6507 token::issuer(alice),
6508 ticket::use(minterTicketSeq++));
6513 for (
auto const nftokenID : nftIDs)
6515 env(token::burn(minter, nftokenID),
6516 ticket::use(minterTicketSeq++));
6524 incLgrSeqForAcctDel(env, alice);
6528 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6529 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6538 auto const acctDelFee{drops(env.current()->fees().increment)};
6539 env(acctdelete(alice, becky), fee(acctDelFee), ter(
tecTOO_SOON));
6543 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6548 incLgrSeqForFixNftRemint(env, alice);
6551 env(acctdelete(alice, becky), fee(acctDelFee));
6556 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6557 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6560 env.fund(XRP(10000), alice);
6564 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6565 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6566 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6570 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6571 env(token::mint(alice));
6575 env(token::burn(alice, remintNFTokenID));
6589 testcase(
"NFTokenMint with Create NFTokenOffer");
6591 using namespace test::jtx;
6593 if (!features[featureNFTokenMintOffer])
6595 Env env{*
this, features};
6596 Account
const alice(
"alice");
6597 Account
const buyer(
"buyer");
6599 env.fund(XRP(10000), alice, buyer);
6602 env(token::mint(alice),
6603 token::amount(XRP(10000)),
6607 env(token::mint(alice),
6608 token::destination(
"buyer"),
6612 env(token::mint(alice),
6622 Env env{*
this, features};
6623 auto const baseFee = env.current()->fees().base;
6624 Account
const alice(
"alice");
6625 Account
const buyer{
"buyer"};
6626 Account
const gw(
"gw");
6627 Account
const issuer(
"issuer");
6628 Account
const minter(
"minter");
6629 Account
const bob(
"bob");
6630 IOU
const gwAUD(gw[
"AUD"]);
6632 env.fund(XRP(10000), alice, buyer, gw, issuer, minter);
6637 env(token::mint(alice),
6638 token::destination(buyer),
6641 BEAST_EXPECT(ownerCount(env, alice) == 0);
6644 env(token::mint(alice),
6648 BEAST_EXPECT(ownerCount(env, buyer) == 0);
6654 env(token::mint(alice),
6655 token::amount(XRP(1000)),
6656 token::destination(alice),
6659 BEAST_EXPECT(ownerCount(env, alice) == 0);
6663 env(token::mint(alice),
6664 token::amount(XRP(1000)),
6665 token::destination(Account(
"demon")),
6668 BEAST_EXPECT(ownerCount(env, alice) == 0);
6673 env(token::mint(alice),
6674 token::amount(XRP(1000)),
6675 token::expiration(0),
6678 BEAST_EXPECT(ownerCount(env, alice) == 0);
6681 env(token::mint(alice),
6682 token::amount(XRP(1000)),
6686 BEAST_EXPECT(ownerCount(env, alice) == 0);
6691 env(token::mint(alice),
6692 token::amount(buyer[
"USD"](1)),
6695 env(token::mint(alice),
6696 token::amount(buyer[
"USD"](0)),
6699 BEAST_EXPECT(ownerCount(env, alice) == 0);
6702 env(token::mint(alice),
6703 token::amount(gwAUD(1000)),
6708 BEAST_EXPECT(ownerCount(env, alice) == 0);
6713 env(token::mint(gw),
6714 token::amount(gwAUD(1000)),
6716 token::xferFee(10));
6725 env(token::mint(alice),
6726 token::amount(gwAUD(1000)),
6731 BEAST_EXPECT(ownerCount(env, alice) == 0);
6734 env(token::mint(alice),
6735 token::amount(gwAUD(1000)),
6738 BEAST_EXPECT(ownerCount(env, alice) == 0);
6747 auto const acctReserve =
6748 env.current()->fees().accountReserve(0);
6749 auto const incReserve = env.current()->fees().increment;
6751 env.fund(acctReserve + incReserve, bob);
6755 env(token::mint(bob),
6756 token::amount(XRP(0)),
6761 env(pay(env.master, bob, incReserve + drops(baseFee)));
6763 env(token::mint(bob), token::amount(XRP(0)));
6767 env(pay(env.master, bob, drops(baseFee)));
6769 env(token::mint(bob),
6770 token::amount(XRP(0)),
6775 env(pay(env.master, bob, incReserve + drops(baseFee)));
6777 env(token::mint(bob), token::amount(XRP(0)));
6782 BEAST_EXPECT(ownerCount(env, alice) == 0);
6783 env(token::mint(alice), token::amount(XRP(10)));
6784 BEAST_EXPECT(ownerCount(env, alice) == 2);
6788 env(token::mint(alice),
6789 token::amount(XRP(10)),
6790 token::destination(buyer),
6791 token::expiration(
lastClose(env) + 25));
6795 env(trust(alice, gwAUD(1000)));
6797 env(token::mint(alice),
6798 token::amount(gwAUD(1)),
6799 token::destination(buyer),
6802 token::xferFee(10));
6806 env(token::mint(alice),
6807 token::amount(XRP(10)),
6808 token::destination(buyer),
6809 token::expiration(
lastClose(env) + 25));
6810 uint256 const offerAliceSellsToBuyer =
6812 env(token::cancelOffer(alice, {offerAliceSellsToBuyer}));
6816 env(token::mint(buyer),
6817 token::amount(XRP(10)),
6818 token::destination(alice),
6819 token::expiration(
lastClose(env) + 25));
6820 uint256 const offerBuyerSellsToAlice =
6822 env(token::cancelOffer(alice, {offerBuyerSellsToAlice}));
6825 env(token::setMinter(issuer, minter));
6829 BEAST_EXPECT(ownerCount(env, minter) == 0);
6830 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6831 env(token::mint(minter),
6832 token::issuer(issuer),
6833 token::amount(drops(1)));
6835 BEAST_EXPECT(ownerCount(env, minter) == 2);
6836 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6841 for (
auto const& tweakedFeatures :
6842 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
6843 features | fixNFTokenNegOffer})
6845 Env env{*
this, tweakedFeatures};
6846 Account
const alice(
"alice");
6848 env.fund(XRP(1000000), alice);
6850 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
6855 env(token::mint(alice),
6856 token::amount(XRP(-2)),
6857 ter(offerCreateTER));
6876 testcase(
"Test synthetic fields from JSON response");
6878 using namespace test::jtx;
6880 Account
const alice{
"alice"};
6881 Account
const bob{
"bob"};
6882 Account
const broker{
"broker"};
6884 Env env{*
this, features};
6885 env.fund(XRP(10000), alice, bob, broker);
6891 auto verifyNFTokenID = [&](
uint256 const& actualNftID) {
6898 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6901 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_id)))
6908 BEAST_EXPECT(nftID == actualNftID);
6913 auto verifyNFTokenIDsInCancelOffer =
6921 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6924 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_ids)))
6930 meta[jss::nftoken_ids].begin(),
6931 meta[jss::nftoken_ids].end(),
6935 BEAST_EXPECT(nftID.
parseHex(
id.asString()));
6941 std::sort(actualNftIDs.begin(), actualNftIDs.end());
6944 BEAST_EXPECT(metaIDs.
size() == actualNftIDs.size());
6948 for (
size_t i = 0; i < metaIDs.
size(); ++i)
6949 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
6954 auto verifyNFTokenOfferID = [&](
uint256 const& offerID) {
6961 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6964 if (!BEAST_EXPECT(meta.
isMember(jss::offer_id)))
6969 BEAST_EXPECT(metaOfferID == offerID);
6980 verifyNFTokenID(nftId1);
6986 verifyNFTokenID(nftId2);
6991 uint256 const aliceOfferIndex1 =
6993 env(token::createOffer(alice, nftId1, drops(1)),
6996 verifyNFTokenOfferID(aliceOfferIndex1);
6998 uint256 const aliceOfferIndex2 =
7000 env(token::createOffer(alice, nftId2, drops(1)),
7003 verifyNFTokenOfferID(aliceOfferIndex2);
7008 env(token::cancelOffer(
7009 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7011 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
7015 auto const bobBuyOfferIndex =
7017 env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice));
7019 verifyNFTokenOfferID(bobBuyOfferIndex);
7023 env(token::acceptBuyOffer(alice, bobBuyOfferIndex));
7025 verifyNFTokenID(nftId1);
7035 verifyNFTokenID(nftId);
7038 uint256 const offerAliceToBroker =
7040 env(token::createOffer(alice, nftId, drops(1)),
7041 token::destination(broker),
7044 verifyNFTokenOfferID(offerAliceToBroker);
7047 uint256 const offerBobToBroker =
7049 env(token::createOffer(bob, nftId, drops(1)), token::owner(alice));
7051 verifyNFTokenOfferID(offerBobToBroker);
7054 env(token::brokerOffers(
7055 broker, offerBobToBroker, offerAliceToBroker));
7057 verifyNFTokenID(nftId);
7068 verifyNFTokenID(nftId);
7071 uint256 const aliceOfferIndex1 =
7073 env(token::createOffer(alice, nftId, drops(1)),
7076 verifyNFTokenOfferID(aliceOfferIndex1);
7078 uint256 const aliceOfferIndex2 =
7080 env(token::createOffer(alice, nftId, drops(1)),
7083 verifyNFTokenOfferID(aliceOfferIndex2);
7087 env(token::cancelOffer(
7088 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7090 verifyNFTokenIDsInCancelOffer({nftId});
7093 if (features[featureNFTokenMintOffer])
7095 uint256 const aliceMintWithOfferIndex1 =
7097 env(token::mint(alice), token::amount(XRP(0)));
7099 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
7106 testcase(
"Test buyer reserve when accepting an offer");
7108 using namespace test::jtx;
7121 uint256 const sellOfferIndex =
7123 env(token::createOffer(acct, nftId, amt), txflags(
tfSellNFToken));
7126 return sellOfferIndex;
7133 Account
const alice{
"alice"};
7134 Account
const bob{
"bob"};
7136 Env env{*
this, features};
7137 auto const acctReserve = env.
current()->fees().accountReserve(0);
7138 auto const incReserve = env.
current()->fees().increment;
7139 auto const baseFee = env.
current()->fees().base;
7141 env.
fund(XRP(10000), alice);
7145 env.
fund(acctReserve, bob);
7149 auto const sellOfferIndex =
7150 mintAndCreateSellOffer(env, alice, XRP(0));
7153 BEAST_EXPECT(ownerCount(env, bob) == 0);
7157 if (!features[fixNFTokenReserve])
7160 env(token::acceptSellOffer(bob, sellOfferIndex));
7164 BEAST_EXPECT(ownerCount(env, bob) == 1);
7179 env(token::acceptSellOffer(bob, sellOfferIndex),
7186 BEAST_EXPECT(ownerCount(env, bob) == 0);
7191 env(pay(env.
master, bob, incReserve + drops(baseFee)));
7196 env(token::acceptSellOffer(bob, sellOfferIndex),
7202 env(pay(env.
master, bob, drops(baseFee * 2)));
7206 env(token::acceptSellOffer(bob, sellOfferIndex));
7209 BEAST_EXPECT(ownerCount(env, bob) == 1);
7216 Account
const alice{
"alice"};
7217 Account
const bob{
"bob"};
7219 Env env{*
this, features};
7220 auto const acctReserve = env.
current()->fees().accountReserve(0);
7221 auto const incReserve = env.
current()->fees().increment;
7223 env.
fund(XRP(10000), alice);
7226 env.
fund(acctReserve + XRP(1), bob);
7229 if (!features[fixNFTokenReserve])
7232 for (
size_t i = 0; i < 200; i++)
7235 auto const sellOfferIndex =
7236 mintAndCreateSellOffer(env, alice, XRP(0));
7239 env(token::acceptSellOffer(bob, sellOfferIndex));
7246 auto const sellOfferIndex1 =
7247 mintAndCreateSellOffer(env, alice, XRP(0));
7251 env(token::acceptSellOffer(bob, sellOfferIndex1),
7256 env(pay(env.
master, bob, drops(incReserve)));
7259 BEAST_EXPECT(ownerCount(env, bob) == 0);
7262 env(token::acceptSellOffer(bob, sellOfferIndex1));
7265 BEAST_EXPECT(ownerCount(env, bob) == 1);
7269 for (
size_t i = 0; i < 31; i++)
7272 auto const sellOfferIndex =
7273 mintAndCreateSellOffer(env, alice, XRP(0));
7277 env(token::acceptSellOffer(bob, sellOfferIndex));
7281 BEAST_EXPECT(ownerCount(env, bob) == 1);
7285 auto const sellOfferIndex33 =
7286 mintAndCreateSellOffer(env, alice, XRP(0));
7290 env(token::acceptSellOffer(bob, sellOfferIndex33),
7295 env(pay(env.
master, bob, drops(incReserve)));
7300 env(token::acceptSellOffer(bob, sellOfferIndex33));
7303 BEAST_EXPECT(ownerCount(env, bob) == 2);
7313 Account
const alice{
"alice"};
7314 Account
const bob{
"bob"};
7316 Env env{*
this, features};
7317 auto const acctReserve = env.
current()->fees().accountReserve(0);
7318 auto const incReserve = env.
current()->fees().increment;
7319 auto const baseFee = env.
current()->fees().base;
7321 env.
fund(XRP(10000), alice);
7327 env.
fund(acctReserve + incReserve + XRP(1), bob);
7338 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
7344 env(token::acceptBuyOffer(alice, buyOfferIndex),
7349 env(pay(env.
master, bob, drops(baseFee)));
7353 env(token::acceptBuyOffer(alice, buyOfferIndex));
7363 Account
const alice{
"alice"};
7364 Account
const bob{
"bob"};
7365 Account
const broker{
"broker"};
7367 Env env{*
this, features};
7368 auto const acctReserve = env.
current()->fees().accountReserve(0);
7369 auto const incReserve = env.
current()->fees().increment;
7370 auto const baseFee = env.
current()->fees().base;
7372 env.
fund(XRP(10000), alice, broker);
7377 env.
fund(acctReserve + incReserve + XRP(1), bob);
7387 uint256 const offerAliceToBroker =
7389 env(token::createOffer(alice, nftId, XRP(1)),
7390 token::destination(broker),
7395 uint256 const offerBobToBroker =
7397 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
7404 env(token::brokerOffers(
7405 broker, offerBobToBroker, offerAliceToBroker),
7410 env(pay(env.
master, bob, drops(baseFee)));
7414 env(token::brokerOffers(
7415 broker, offerBobToBroker, offerAliceToBroker));
7423 testcase(
"Test fix unasked for auto-trustline.");
7425 using namespace test::jtx;
7427 Account
const issuer{
"issuer"};
7428 Account
const becky{
"becky"};
7429 Account
const cheri{
"cheri"};
7430 Account
const gw(
"gw");
7431 IOU
const gwAUD(gw[
"AUD"]);
7461 features - fixRemoveNFTokenAutoTrustLine;
7463 {localFeatures - fixEnforceNFTokenTrustline,
7464 localFeatures | fixEnforceNFTokenTrustline})
7466 Env env{*
this, feats};
7467 env.fund(XRP(1000), issuer, becky, cheri, gw);
7471 env(trust(becky, gwAUD(1000)));
7472 env(trust(cheri, gwAUD(1000)));
7474 env(pay(gw, cheri, gwAUD(500)));
7479 uint256 const nftAutoTrustID{token::getNextID(
7481 env(token::mint(issuer, 0u),
7482 token::xferFee(xferFee),
7486 uint256 const nftNoAutoTrustID{
7488 env(token::mint(issuer, 0u),
7489 token::xferFee(xferFee),
7495 uint256 const beckyBuyOfferIndex1 =
7497 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
7498 token::owner(issuer));
7500 uint256 const beckyBuyOfferIndex2 =
7502 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
7503 token::owner(issuer));
7506 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1));
7507 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2));
7512 uint256 const beckyAutoTrustOfferIndex =
7514 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
7520 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
7527 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7528 env(trust(issuer, gwAUD(1000)));
7530 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7532 uint256 const beckyNoAutoTrustOfferIndex =
7534 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
7539 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7540 env(trust(issuer, gwAUD(0)));
7542 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7546 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7550 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7551 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7554 env(pay(issuer, gw, gwAUD(5)));
7556 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7560 if (feats[fixEnforceNFTokenTrustline])
7565 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex),
7571 env(trust(issuer, gwAUD(1000)));
7573 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7575 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7582 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7585 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7586 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7593 testcase(
"Test fix NFT issuer is IOU issuer");
7595 using namespace test::jtx;
7597 Account
const issuer{
"issuer"};
7598 Account
const becky{
"becky"};
7599 Account
const cheri{
"cheri"};
7600 IOU
const isISU(issuer[
"ISU"]);
7632 features - fixRemoveNFTokenAutoTrustLine;
7634 Env env{*
this, localFeatures};
7635 env.fund(XRP(1000), issuer, becky, cheri);
7639 env(trust(becky, isISU(1000)));
7640 env(trust(cheri, isISU(1000)));
7642 env(pay(issuer, cheri, isISU(500)));
7647 uint256 const nftAutoTrustID{token::getNextID(
7649 env(token::mint(issuer, 0u),
7650 token::xferFee(xferFee),
7654 uint256 const nftNoAutoTrustID{
7656 env(token::mint(issuer, 0u),
7657 token::xferFee(xferFee),
7663 uint256 const beckyBuyOfferIndex1 =
7665 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
7666 token::owner(issuer));
7668 uint256 const beckyBuyOfferIndex2 =
7670 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
7671 token::owner(issuer));
7674 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1));
7675 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2));
7681 if (!localFeatures[featureNFTokenMintOffer])
7686 env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)),
7697 uint256 const beckyAutoTrustOfferIndex =
7699 env(token::createOffer(becky, nftAutoTrustID, isISU(100)),
7704 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7709 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7710 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7716 uint256 const beckyNoAutoTrustOfferIndex =
7718 env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)),
7721 uint256 const beckyAutoTrustOfferIndex =
7723 env(token::createOffer(becky, nftAutoTrustID, isISU(100)),
7729 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7734 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7735 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7737 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7743 BEAST_EXPECT(env.balance(becky, isISU) == isISU(190));
7744 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(300));
7753 using namespace test::jtx;
7755 Account
const issuer{
"issuer"};
7756 Account
const alice(
"alice");
7757 Account
const bob(
"bob");
7759 bool const modifyEnabled = features[featureDynamicNFT];
7763 Env env{*
this, features};
7764 env.fund(XRP(10000), issuer);
7767 auto const expectedTer =
7769 env(token::mint(issuer, 0u), txflags(
tfMutable), ter(expectedTer));
7773 Env env{*
this, features};
7774 env.fund(XRP(10000), issuer);
7781 env(token::mint(issuer, 0u), txflags(
tfMutable));
7783 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7784 env(token::modify(issuer, nftId));
7785 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7789 env(token::mint(issuer, 0u));
7791 env(token::modify(issuer, nftId), ter(
temDISABLED));
7799 Env env{*
this, features};
7800 env.fund(XRP(10000), issuer);
7804 env(token::mint(issuer, 0u), txflags(
tfMutable));
7808 env(token::modify(issuer, nftId),
7814 env(token::modify(issuer, nftId),
7815 txflags(0x00000001),
7819 env(token::modify(issuer, nftId),
7820 token::owner(issuer),
7825 env(token::modify(issuer, nftId),
7831 env(token::modify(issuer, nftId),
7837 Env env{*
this, features};
7838 env.fund(XRP(10000), issuer, alice, bob);
7844 token::getNextID(env, issuer, 0u,
tfMutable)};
7847 env(token::modify(issuer, nftIDNotExists), ter(
tecNO_ENTRY));
7852 uint256 const nftIDNotModifiable{
7853 token::getNextID(env, issuer, 0u)};
7854 env(token::mint(issuer, 0u));
7857 env(token::modify(issuer, nftIDNotModifiable),
7864 token::getNextID(env, issuer, 0u,
tfMutable)};
7865 env(token::mint(issuer, 0u), txflags(
tfMutable));
7868 env(token::modify(bob, nftId),
7869 token::owner(issuer),
7873 env(token::setMinter(issuer, alice));
7876 env(token::modify(bob, nftId),
7877 token::owner(issuer),
7883 Env env{*
this, features};
7884 env.fund(XRP(10000), issuer, alice, bob);
7889 env(token::mint(issuer, 0u), txflags(
tfMutable), token::uri(
"uri"));
7896 Env env{*
this, features};
7897 env.fund(XRP(10000), issuer, alice, bob);
7901 auto accountNFTs = [&env](Account
const& acct) {
7903 params[jss::account] = acct.human();
7904 params[jss::type] =
"state";
7906 env.rpc(
"json",
"account_nfts",
to_string(params));
7907 return response[jss::result][jss::account_nfts];
7911 auto checkURI = [&accountNFTs,
this](
7912 Account
const& acct,
7915 auto const nfts = accountNFTs(acct);
7916 if (nfts.size() == 1)
7921 text <<
"checkURI: unexpected NFT count on line " << line;
7922 fail(text.
str(), __FILE__, line);
7928 if (!nfts[0u].isMember(sfURI.jsonName))
7933 text <<
"checkURI: unexpected URI present on line "
7935 fail(text.
str(), __FILE__, line);
7945 text <<
"checkURI: unexpected URI contents on line "
7947 fail(text.
str(), __FILE__, line);
7954 env(token::mint(issuer, 0u), txflags(
tfMutable), token::uri(
"uri"));
7956 checkURI(issuer,
"uri", __LINE__);
7959 env(token::modify(issuer, nftId), token::uri(
"new_uri"));
7961 checkURI(issuer,
"new_uri", __LINE__);
7964 env(token::modify(issuer, nftId));
7966 checkURI(issuer,
nullptr, __LINE__);
7969 env(token::modify(issuer, nftId), token::uri(
"uri"));
7971 checkURI(issuer,
"uri", __LINE__);
7976 env(token::createOffer(issuer, nftId, XRP(0)),
7979 env(token::acceptSellOffer(alice, offerID));
7981 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7982 BEAST_EXPECT(ownerCount(env, alice) == 1);
7983 checkURI(alice,
"uri", __LINE__);
7986 env(token::modify(alice, nftId),
7987 token::uri(
"new_uri"),
7990 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7991 BEAST_EXPECT(ownerCount(env, alice) == 1);
7992 checkURI(alice,
"uri", __LINE__);
7994 env(token::modify(issuer, nftId),
7995 token::owner(alice),
7996 token::uri(
"new_uri"));
7998 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7999 BEAST_EXPECT(ownerCount(env, alice) == 1);
8000 checkURI(alice,
"new_uri", __LINE__);
8002 env(token::modify(issuer, nftId), token::owner(alice));
8004 checkURI(alice,
nullptr, __LINE__);
8006 env(token::modify(issuer, nftId),
8007 token::owner(alice),
8010 checkURI(alice,
"uri", __LINE__);
8013 env(token::setMinter(issuer, bob));
8015 env(token::modify(bob, nftId),
8016 token::owner(alice),
8017 token::uri(
"new_uri"));
8019 checkURI(alice,
"new_uri", __LINE__);
8021 env(token::modify(bob, nftId), token::owner(alice));
8023 checkURI(alice,
nullptr, __LINE__);
8025 env(token::modify(bob, nftId),
8026 token::owner(alice),
8029 checkURI(alice,
"uri", __LINE__);
8077 using namespace test::jtx;
8082 all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8083 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8085 fixNFTokenRemint - fixNFTokenReserve - featureNFTokenMintOffer -
8087 all - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8088 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8089 all - fixNFTokenRemint - fixNFTokenReserve -
8090 featureNFTokenMintOffer - featureDynamicNFT,
8091 all - fixNFTokenReserve - featureNFTokenMintOffer -
8093 all - featureNFTokenMintOffer - featureDynamicNFT,
8094 all - featureDynamicNFT,
8097 if (BEAST_EXPECT(instance < feats.size()))
8101 BEAST_EXPECT(!last || instance == feats.size() - 1);
8174BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, tx,
ripple, 2);
8175BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx,
ripple, 2);
8176BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx,
ripple, 2);
8177BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx,
ripple, 2);
8178BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx,
ripple, 2);
8179BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx,
ripple, 2);
8180BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx,
ripple, 2);
8181BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx,
ripple, 2);
T back_inserter(T... args)
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
Value removeMember(char const *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *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=JsonOptions::none) const override
static int const cMinOffset
static std::uint64_t const cMinValue
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.