21#include <xrpld/app/tx/detail/NFTokenUtils.h>
22#include <xrpl/basics/random.h>
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/jss.h>
39 if (
auto const sleIssuer = env.
le(issuer))
40 ret = sleIssuer->at(~sfMintedNFTokens).value_or(0);
49 if (
auto const sleIssuer = env.
le(issuer))
50 ret = sleIssuer->at(~sfBurnedNFTokens).value_or(0);
59 params[jss::account] = acct.
human();
60 params[jss::type] =
"state";
62 return nfts[jss::result][jss::account_nfts].
size();
70 if (
auto const sleAcct = env.
le(acct))
71 ret = sleAcct->at(~sfTicketCount).value_or(0);
79 return env.
current()->info().parentCloseTime.time_since_epoch().count();
87 using namespace test::jtx;
93 features - featureNonFungibleTokensV1 -
94 featureNonFungibleTokensV1_1};
95 Account
const& master = env.master;
97 BEAST_EXPECT(ownerCount(env, master) == 0);
101 uint256 const nftId{token::getNextID(env, master, 0u)};
104 BEAST_EXPECT(ownerCount(env, master) == 0);
110 BEAST_EXPECT(ownerCount(env, master) == 0);
116 env(token::createOffer(master, nftId, XRP(10)), ter(
temDISABLED));
118 BEAST_EXPECT(ownerCount(env, master) == 0);
122 env(token::cancelOffer(master, {offerIndex}), ter(
temDISABLED));
124 BEAST_EXPECT(ownerCount(env, master) == 0);
128 env(token::acceptBuyOffer(master, offerIndex), ter(
temDISABLED));
130 BEAST_EXPECT(ownerCount(env, master) == 0);
137 Env env{*
this, features};
138 Account
const& master = env.master;
140 BEAST_EXPECT(ownerCount(env, master) == 0);
144 uint256 const nftId0{token::getNextID(env, env.master, 0u)};
145 env(token::mint(env.master, 0u));
147 BEAST_EXPECT(ownerCount(env, master) == 1);
151 env(token::burn(env.master, nftId0));
153 BEAST_EXPECT(ownerCount(env, master) == 0);
161 BEAST_EXPECT(ownerCount(env, master) == 1);
165 Account
const alice{
"alice"};
166 env.fund(XRP(10000), alice);
168 uint256 const aliceOfferIndex =
170 env(token::createOffer(alice, nftId1, XRP(1000)),
171 token::owner(master));
174 BEAST_EXPECT(ownerCount(env, master) == 1);
178 BEAST_EXPECT(ownerCount(env, alice) == 1);
182 env(token::acceptBuyOffer(master, aliceOfferIndex));
185 BEAST_EXPECT(ownerCount(env, master) == 0);
189 BEAST_EXPECT(ownerCount(env, alice) == 1);
201 using namespace test::jtx;
203 Env env{*
this, features};
204 Account
const alice{
"alice"};
205 Account
const minter{
"minter"};
209 auto const acctReserve = env.current()->fees().accountReserve(0);
210 auto const incReserve = env.current()->fees().increment;
211 env.fund(acctReserve, alice, minter);
213 BEAST_EXPECT(env.balance(alice) == acctReserve);
214 BEAST_EXPECT(env.balance(minter) == acctReserve);
215 BEAST_EXPECT(ownerCount(env, alice) == 0);
216 BEAST_EXPECT(ownerCount(env, minter) == 0);
222 BEAST_EXPECT(ownerCount(env, alice) == 0);
227 env(pay(env.master, alice, incReserve + drops(9)));
232 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
245 ss <<
"Wrong " << type <<
" count. Found: " << found
246 <<
"; Expected: " << exp;
247 fail(ss.
str(), __FILE__, line);
250 oneCheck(
"owner", ownerCount(env, alice), owners);
251 oneCheck(
"minted",
mintedCount(env, alice), minted);
252 oneCheck(
"burned",
burnedCount(env, alice), burned);
259 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
262 env(pay(env.master, alice, drops(11)));
266 env(token::mint(alice));
268 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
272 for (
int i = 1; i < 32; ++i)
274 env(token::mint(alice));
275 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
282 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
285 env(pay(env.master, alice, XRP(50) + drops(329)));
292 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
295 env(pay(env.master, alice, drops(11)));
299 env(token::mint(alice));
301 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
308 env(token::burn(alice, token::getID(env, alice, 0, seq++)));
310 checkAliceOwnerMintedBurned((33 - seq) ? 1 : 0, 33, seq, __LINE__);
314 env(token::burn(alice, token::getID(env, alice, 197, 5)),
317 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
322 env(token::setMinter(alice, minter));
325 env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
329 auto checkMintersOwnerMintedBurned = [&env,
this, &alice, &minter](
337 auto oneCheck = [
this](
347 ss <<
"Wrong " << type <<
" count. Found: " << found
348 <<
"; Expected: " << exp;
349 fail(ss.
str(), __FILE__, line);
352 oneCheck(
"alice owner", ownerCount(env, alice), aliceOwners, line);
354 "alice minted",
mintedCount(env, alice), aliceMinted, line);
356 "alice burned",
burnedCount(env, alice), aliceBurned, line);
358 "minter owner", ownerCount(env, minter), minterOwners, line);
360 "minter minted",
mintedCount(env, minter), minterMinted, line);
362 "minter burned",
burnedCount(env, minter), minterBurned, line);
368 env(pay(env.master, minter, XRP(50) - drops(1)));
370 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
375 env(token::mint(minter),
376 token::issuer(alice),
380 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
383 env(pay(env.master, minter, drops(11)));
387 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
389 checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
393 for (
int i = 1; i < 32; ++i)
395 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
396 checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
401 env(pay(env.master, minter, XRP(50) + drops(319)));
406 env(token::mint(minter),
407 token::issuer(alice),
411 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
414 env(pay(env.master, minter, drops(11)));
418 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
420 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
425 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
427 checkMintersOwnerMintedBurned(
428 0, 66, nftSeq, (65 - seq) ? 1 : 0, 0, 0, __LINE__);
433 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
435 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
438 env(token::burn(minter, token::getID(env, alice, 2009, 3)),
441 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
451 using namespace test::jtx;
453 Account
const alice{
"alice"};
454 Env env{*
this, features};
455 env.fund(XRP(1000), alice);
464 uint256 const nftId0{token::getNextID(env, alice, 0u)};
465 env(token::mint(alice, 0u));
468 env(token::burn(alice, nftId0));
475 env.app().openLedger().modify(
484 auto replacement = std::make_shared<SLE>(*sle, sle->key());
485 if (replacement->getFieldU32(sfMintedNFTokens) != 1)
488 if (env.current()->rules().enabled(fixNFTokenRemint))
496 (*replacement)[sfFirstNFTokenSequence] = 0xFFFF'FFFE;
497 (*replacement)[sfMintedNFTokens] = 0x0000'0000;
503 (*replacement)[sfMintedNFTokens] = 0xFFFF'FFFE;
520 using namespace test::jtx;
522 Env env{*
this, features};
523 Account
const alice{
"alice"};
524 Account
const minter{
"minter"};
529 env.fund(XRP(200), alice, minter);
536 env(pay(env.master, alice, XRP(1000)));
543 env(token::mint(alice, 0u),
548 env(token::mint(alice, 0u), txflags(0x00008000), ter(
temINVALID_FLAG));
552 env(token::mint(alice, 0u),
557 env(token::mint(alice, 0u),
563 env(token::mint(alice, 0u), token::issuer(alice), ter(
temMALFORMED));
566 env(token::mint(alice, 0u), token::uri(
""), ter(
temMALFORMED));
569 env(token::mint(alice, 0u),
577 env(token::mint(alice, 0u),
578 token::issuer(Account(
"demon")),
585 env(token::mint(minter, 0u),
586 token::issuer(alice),
596 using namespace test::jtx;
598 Env env{*
this, features};
599 Account
const alice{
"alice"};
600 Account
const buyer{
"buyer"};
601 Account
const minter{
"minter"};
602 Account
const gw(
"gw");
603 IOU
const gwAUD(gw[
"AUD"]);
608 env.fund(XRP(250), alice, buyer, minter, gw);
610 BEAST_EXPECT(ownerCount(env, alice) == 0);
616 BEAST_EXPECT(ownerCount(env, alice) == 1);
622 env(token::burn(alice, nftAlice0ID),
626 BEAST_EXPECT(ownerCount(env, alice) == 1);
629 env(token::burn(alice, nftAlice0ID),
633 BEAST_EXPECT(ownerCount(env, buyer) == 0);
639 env(token::burn(alice, token::getID(env, alice, 0, 1)),
642 BEAST_EXPECT(ownerCount(env, buyer) == 0);
654 testcase(
"Invalid NFT offer create");
656 using namespace test::jtx;
658 Env env{*
this, features};
659 Account
const alice{
"alice"};
660 Account
const buyer{
"buyer"};
661 Account
const gw(
"gw");
662 IOU
const gwAUD(gw[
"AUD"]);
667 env.fund(XRP(250), alice, buyer, gw);
669 BEAST_EXPECT(ownerCount(env, alice) == 0);
673 env(token::mint(alice, 0u),
677 BEAST_EXPECT(ownerCount(env, alice) == 1);
683 BEAST_EXPECT(ownerCount(env, alice) == 1);
685 uint256 nftNoXferID = token::getNextID(env, alice, 0);
686 env(token::mint(alice, 0));
688 BEAST_EXPECT(ownerCount(env, alice) == 1);
699 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
703 BEAST_EXPECT(ownerCount(env, buyer) == 0);
706 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
710 BEAST_EXPECT(ownerCount(env, buyer) == 0);
713 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
717 BEAST_EXPECT(ownerCount(env, buyer) == 0);
720 env(token::createOffer(buyer, nftXrpOnlyID, buyer[
"USD"](1)),
722 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](0)),
724 env(token::createOffer(buyer, nftXrpOnlyID, drops(0)),
727 BEAST_EXPECT(ownerCount(env, buyer) == 0);
730 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](1)),
731 token::expiration(0),
734 BEAST_EXPECT(ownerCount(env, buyer) == 0);
738 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
741 BEAST_EXPECT(ownerCount(env, buyer) == 0);
744 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
749 BEAST_EXPECT(ownerCount(env, alice) == 1);
752 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
756 BEAST_EXPECT(ownerCount(env, alice) == 1);
759 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
760 token::destination(alice),
764 BEAST_EXPECT(ownerCount(env, alice) == 1);
767 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
768 token::destination(Account(
"demon")),
772 BEAST_EXPECT(ownerCount(env, alice) == 1);
778 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
783 BEAST_EXPECT(ownerCount(env, buyer) == 0);
786 env(token::createOffer(
787 buyer, token::getID(env, alice, 0, 1), XRP(1000)),
791 BEAST_EXPECT(ownerCount(env, buyer) == 0);
794 env(token::createOffer(
795 alice, token::getID(env, alice, 0, 1), XRP(1000)),
799 BEAST_EXPECT(ownerCount(env, buyer) == 0);
802 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
806 BEAST_EXPECT(ownerCount(env, buyer) == 0);
808 env(trust(buyer, gwAUD(1000)));
810 BEAST_EXPECT(ownerCount(env, buyer) == 1);
814 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
818 BEAST_EXPECT(ownerCount(env, buyer) == 1);
826 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
830 BEAST_EXPECT(ownerCount(env, buyer) == 1);
837 env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
841 BEAST_EXPECT(ownerCount(env, buyer) == 1);
847 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
851 BEAST_EXPECT(ownerCount(env, buyer) == 1);
856 env(trust(buyer, gwAUD(1000)));
859 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
863 BEAST_EXPECT(ownerCount(env, buyer) == 1);
869 env(pay(gw, buyer, gwAUD(999)));
874 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
878 BEAST_EXPECT(ownerCount(env, buyer) == 1);
881 env(pay(env.master, buyer, XRP(50) + drops(119)));
884 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
888 BEAST_EXPECT(ownerCount(env, buyer) == 1);
891 env(pay(env.master, buyer, drops(11)));
896 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
900 BEAST_EXPECT(ownerCount(env, buyer) == 2);
906 testcase(
"Invalid NFT offer cancel");
908 using namespace test::jtx;
910 Env env{*
this, features};
911 Account
const alice{
"alice"};
912 Account
const buyer{
"buyer"};
913 Account
const gw(
"gw");
914 IOU
const gwAUD(gw[
"AUD"]);
916 env.fund(XRP(1000), alice, buyer, gw);
918 BEAST_EXPECT(ownerCount(env, alice) == 0);
924 BEAST_EXPECT(ownerCount(env, alice) == 1);
927 uint256 const buyerOfferIndex =
929 env(token::createOffer(buyer, nftAlice0ID, XRP(1)),
933 BEAST_EXPECT(ownerCount(env, buyer) == 1);
939 env(token::cancelOffer(buyer, {buyerOfferIndex}),
943 BEAST_EXPECT(ownerCount(env, buyer) == 1);
946 env(token::cancelOffer(buyer, {buyerOfferIndex}),
950 BEAST_EXPECT(ownerCount(env, buyer) == 1);
958 BEAST_EXPECT(ownerCount(env, buyer) == 1);
966 env(token::cancelOffer(buyer, offers), ter(
temMALFORMED));
968 BEAST_EXPECT(ownerCount(env, buyer) == 1);
972 env(token::cancelOffer(buyer, {buyerOfferIndex, buyerOfferIndex}),
975 BEAST_EXPECT(ownerCount(env, buyer) == 1);
980 BEAST_EXPECT(ownerCount(env, buyer) == 1);
986 env(pay(env.master, gw, XRP(5000)));
990 env(offer(gw, XRP(i), gwAUD(1)));
997 env(check::create(gw, env.master, XRP(300)));
1004 env(check::cancel(gw, gwCheckId));
1011 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1018 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1020 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1026 testcase(
"Invalid NFT offer accept");
1028 using namespace test::jtx;
1030 Env env{*
this, features};
1031 Account
const alice{
"alice"};
1032 Account
const buyer{
"buyer"};
1033 Account
const gw(
"gw");
1034 IOU
const gwAUD(gw[
"AUD"]);
1036 env.fund(XRP(1000), alice, buyer, gw);
1038 BEAST_EXPECT(ownerCount(env, alice) == 0);
1044 BEAST_EXPECT(ownerCount(env, alice) == 1);
1050 BEAST_EXPECT(ownerCount(env, alice) == 1);
1052 uint256 nftNoXferID = token::getNextID(env, alice, 0);
1053 env(token::mint(alice, 0));
1055 BEAST_EXPECT(ownerCount(env, alice) == 1);
1058 uint256 const plainOfferIndex =
1060 env(token::createOffer(alice, nftAlice0ID, XRP(10)),
1063 BEAST_EXPECT(ownerCount(env, alice) == 2);
1067 env(token::createOffer(alice, nftAlice0ID, gwAUD(30)),
1070 BEAST_EXPECT(ownerCount(env, alice) == 3);
1072 uint256 const xrpOnlyOfferIndex =
1074 env(token::createOffer(alice, nftXrpOnlyID, XRP(20)),
1077 BEAST_EXPECT(ownerCount(env, alice) == 4);
1079 uint256 const noXferOfferIndex =
1081 env(token::createOffer(alice, nftNoXferID, XRP(30)),
1084 BEAST_EXPECT(ownerCount(env, alice) == 5);
1087 uint256 const aliceExpOfferIndex =
1089 env(token::createOffer(alice, nftNoXferID, XRP(40)),
1093 BEAST_EXPECT(ownerCount(env, alice) == 6);
1099 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1103 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1106 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1107 txflags(0x00008000),
1110 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1114 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1118 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1123 Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1124 jv[sfNFTokenBrokerFee.jsonName] =
1128 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1133 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1134 jv[sfNFTokenBrokerFee.jsonName] =
1138 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1142 env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1143 token::brokerFee(gwAUD(0)),
1146 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1152 env(token::acceptBuyOffer(buyer, beast::zero),
1155 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1159 env(token::acceptBuyOffer(buyer, missingOfferIndex),
1162 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1165 env(token::acceptBuyOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1167 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1170 env(token::acceptSellOffer(buyer, beast::zero),
1173 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1176 env(token::acceptSellOffer(buyer, missingOfferIndex),
1179 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1182 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1184 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1191 env(trust(alice, gwAUD(1000)));
1192 env(trust(buyer, gwAUD(1000)));
1194 env(pay(gw, buyer, gwAUD(30)));
1196 BEAST_EXPECT(ownerCount(env, alice) == 7);
1197 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1203 uint256 const buyerOfferIndex =
1205 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)),
1206 token::owner(alice));
1208 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1211 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1214 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1217 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1220 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1224 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1227 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1230 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1232 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1236 uint256 const buyerOfferIndex =
1238 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)),
1239 token::owner(alice));
1241 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1245 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1246 token::brokerFee(XRP(40)),
1249 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1252 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1253 token::brokerFee(gwAUD(31)),
1256 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1260 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1261 token::brokerFee(gwAUD(1.5)),
1264 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1267 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1269 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1275 uint256 const buyerOfferIndex =
1277 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)),
1278 token::owner(alice));
1280 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1283 env(token::acceptBuyOffer(buyer, plainOfferIndex),
1286 BEAST_EXPECT(ownerCount(env, alice) == 7);
1289 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1292 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1295 env(pay(buyer, gw, gwAUD(30)));
1297 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1298 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1301 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1307 env(token::createOffer(alice, nftAlice0ID, XRP(0)),
1310 env(token::acceptSellOffer(gw, offerIndex));
1312 BEAST_EXPECT(ownerCount(env, alice) == 7);
1314 env(pay(gw, buyer, gwAUD(30)));
1318 env(token::acceptBuyOffer(alice, buyerOfferIndex),
1321 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1324 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1326 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1332 uint256 const buyerOfferIndex =
1334 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)),
1335 token::owner(alice));
1337 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1340 env(token::acceptSellOffer(alice, buyerOfferIndex),
1343 BEAST_EXPECT(ownerCount(env, alice) == 7);
1346 env(token::acceptSellOffer(alice, plainOfferIndex),
1349 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1353 env(token::acceptSellOffer(buyer, plainOfferIndex),
1356 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1364 env(token::createOffer(gw, nftAlice0ID, XRP(0)),
1367 env(token::acceptSellOffer(alice, offerIndex));
1369 BEAST_EXPECT(ownerCount(env, alice) == 7);
1371 env(pay(buyer, gw, gwAUD(30)));
1373 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1374 env(token::acceptSellOffer(buyer, audOfferIndex),
1377 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1393 using namespace test::jtx;
1395 Env env{*
this, features};
1396 Account
const alice{
"alice"};
1397 Account
const buyer{
"buyer"};
1398 Account
const minter1{
"minter1"};
1399 Account
const minter2{
"minter2"};
1401 env.fund(XRP(1000), alice, buyer, minter1, minter2);
1403 BEAST_EXPECT(ownerCount(env, alice) == 0);
1406 env(token::setMinter(alice, minter1));
1413 auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1415 uint256 const nftID{token::getNextID(env, alice, 0u, flags)};
1416 env(token::mint(minter1, 0u), token::issuer(alice), txflags(flags));
1421 env(token::createOffer(minter1, nftID, XRP(0)),
1425 env(token::acceptSellOffer(buyer, offerIndex));
1433 uint256 const noBurnID = nftToBuyer(0);
1434 env(token::burn(alice, noBurnID),
1435 token::owner(buyer),
1438 env(token::burn(minter1, noBurnID),
1439 token::owner(buyer),
1442 env(token::burn(minter2, noBurnID),
1443 token::owner(buyer),
1447 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1448 env(token::burn(buyer, noBurnID), token::owner(buyer));
1450 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1455 env(token::burn(minter2, burnableID),
1456 token::owner(buyer),
1460 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1461 env(token::burn(alice, burnableID), token::owner(buyer));
1463 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1468 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1469 env(token::burn(buyer, burnableID));
1471 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1476 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1477 env(token::burn(buyer, burnableID), token::owner(buyer));
1479 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1485 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1487 env(token::setMinter(alice, minter2));
1492 env(token::burn(minter1, burnableID),
1493 token::owner(buyer),
1496 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1499 env(token::burn(minter2, burnableID), token::owner(buyer));
1501 BEAST_EXPECT(ownerCount(env, buyer) == 0);
1511 using namespace test::jtx;
1513 Env env{*
this, features};
1514 Account
const alice{
"alice"};
1515 Account
const buyer{
"buyer"};
1516 Account
const gw(
"gw");
1517 IOU
const gwAUD(gw[
"AUD"]);
1520 env.fund(XRP(1000), alice, buyer, gw);
1522 env(trust(alice, gwAUD(1000)));
1523 env(trust(buyer, gwAUD(1000)));
1525 env(pay(gw, buyer, gwAUD(100)));
1534 BEAST_EXPECT(ownerCount(env, alice) == 2);
1535 uint256 const aliceOfferIndex =
1537 env(token::createOffer(alice, nftIOUsOkayID, gwAUD(50)),
1540 BEAST_EXPECT(ownerCount(env, alice) == 3);
1542 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1543 uint256 const buyerOfferIndex =
1545 env(token::createOffer(buyer, nftIOUsOkayID, gwAUD(50)),
1546 token::owner(alice));
1548 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1551 env(token::cancelOffer(alice, {aliceOfferIndex}));
1552 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1554 BEAST_EXPECT(ownerCount(env, alice) == 2);
1555 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1558 env(token::burn(alice, nftIOUsOkayID));
1560 BEAST_EXPECT(ownerCount(env, alice) == 1);
1570 BEAST_EXPECT(ownerCount(env, alice) == 2);
1571 env(token::createOffer(alice, nftOnlyXRPID, gwAUD(50)),
1575 BEAST_EXPECT(ownerCount(env, alice) == 2);
1577 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1578 env(token::createOffer(buyer, nftOnlyXRPID, gwAUD(50)),
1579 token::owner(alice),
1582 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1585 BEAST_EXPECT(ownerCount(env, alice) == 2);
1586 env(token::createOffer(alice, nftOnlyXRPID, XRP(60)),
1589 BEAST_EXPECT(ownerCount(env, alice) == 3);
1591 BEAST_EXPECT(ownerCount(env, buyer) == 1);
1592 env(token::createOffer(buyer, nftOnlyXRPID, XRP(60)),
1593 token::owner(alice));
1595 BEAST_EXPECT(ownerCount(env, buyer) == 2);
1603 testcase(
"Mint flagCreateTrustLines");
1605 using namespace test::jtx;
1607 Account
const alice{
"alice"};
1608 Account
const becky{
"becky"};
1609 Account
const cheri{
"cheri"};
1610 Account
const gw(
"gw");
1611 IOU
const gwAUD(gw[
"AUD"]);
1612 IOU
const gwCAD(gw[
"CAD"]);
1613 IOU
const gwEUR(gw[
"EUR"]);
1618 for (
auto const& tweakedFeatures :
1619 {features - fixRemoveNFTokenAutoTrustLine,
1620 features | fixRemoveNFTokenAutoTrustLine})
1622 Env env{*
this, tweakedFeatures};
1623 env.fund(XRP(1000), alice, becky, cheri, gw);
1627 env(trust(becky, gwAUD(1000)));
1628 env(trust(cheri, gwAUD(1000)));
1629 env(trust(becky, gwCAD(1000)));
1630 env(trust(cheri, gwCAD(1000)));
1631 env(trust(becky, gwEUR(1000)));
1632 env(trust(cheri, gwEUR(1000)));
1634 env(pay(gw, becky, gwAUD(500)));
1635 env(pay(gw, becky, gwCAD(500)));
1636 env(pay(gw, becky, gwEUR(500)));
1637 env(pay(gw, cheri, gwAUD(500)));
1638 env(pay(gw, cheri, gwCAD(500)));
1645 uint256 const nftNoAutoTrustID{
1647 env(token::mint(alice, 0u),
1648 token::xferFee(xferFee),
1653 uint256 const beckyBuyOfferIndex =
1655 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
1656 token::owner(alice));
1658 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1662 TER const createOfferTER =
1664 uint256 const beckyOfferIndex =
1666 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1668 ter(createOfferTER));
1672 uint256 const cheriOfferIndex =
1674 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1675 token::owner(becky),
1676 ter(createOfferTER));
1680 env(token::cancelOffer(becky, {beckyOfferIndex}));
1681 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1689 uint256 const nftAutoTrustID{token::getNextID(
1696 tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
1700 env(token::mint(alice, 0u),
1701 token::xferFee(transferFee),
1708 if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
1712 uint256 const beckyBuyOfferIndex =
1714 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
1715 token::owner(alice));
1717 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1721 uint256 const beckySellOfferIndex =
1723 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
1726 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1730 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1733 uint256 const beckyBuyBackOfferIndex =
1735 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)),
1736 token::owner(cheri));
1738 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1742 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1743 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1749 uint256 const nftNoAutoTrustID{token::getNextID(
1751 env(token::mint(alice, 0u),
1752 token::xferFee(transferFee),
1757 uint256 const aliceSellOfferIndex =
1759 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1762 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1768 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1771 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1775 uint256 const cheriSellOfferIndex =
1777 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1780 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1786 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1797 using namespace test::jtx;
1799 Env env{*
this, features};
1801 Account
const alice{
"alice"};
1802 Account
const becky{
"becky"};
1803 Account
const minter{
"minter"};
1805 env.fund(XRP(1000), alice, becky, minter);
1810 BEAST_EXPECT(ownerCount(env, alice) == 0);
1811 uint256 const nftAliceNoTransferID{
1812 token::getNextID(env, alice, 0u)};
1813 env(token::mint(alice, 0u), token::xferFee(0));
1815 BEAST_EXPECT(ownerCount(env, alice) == 1);
1818 BEAST_EXPECT(ownerCount(env, becky) == 0);
1819 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1820 token::owner(alice),
1824 uint256 const aliceSellOfferIndex =
1826 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)),
1829 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1831 BEAST_EXPECT(ownerCount(env, alice) == 0);
1832 BEAST_EXPECT(ownerCount(env, becky) == 1);
1835 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1839 BEAST_EXPECT(ownerCount(env, alice) == 0);
1840 BEAST_EXPECT(ownerCount(env, becky) == 1);
1844 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1846 token::destination(alice),
1849 BEAST_EXPECT(ownerCount(env, alice) == 0);
1850 BEAST_EXPECT(ownerCount(env, becky) == 1);
1854 uint256 const aliceBuyOfferIndex =
1856 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)),
1857 token::owner(becky));
1859 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1861 BEAST_EXPECT(ownerCount(env, alice) == 1);
1862 BEAST_EXPECT(ownerCount(env, becky) == 0);
1865 env(token::burn(alice, nftAliceNoTransferID));
1867 BEAST_EXPECT(ownerCount(env, alice) == 0);
1868 BEAST_EXPECT(ownerCount(env, becky) == 0);
1872 env(token::setMinter(alice, minter));
1875 BEAST_EXPECT(ownerCount(env, minter) == 0);
1876 uint256 const nftMinterNoTransferID{
1877 token::getNextID(env, alice, 0u)};
1878 env(token::mint(minter), token::issuer(alice));
1880 BEAST_EXPECT(ownerCount(env, minter) == 1);
1883 BEAST_EXPECT(ownerCount(env, becky) == 0);
1884 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1885 token::owner(minter),
1888 BEAST_EXPECT(ownerCount(env, becky) == 0);
1891 env(token::clearMinter(alice));
1895 BEAST_EXPECT(ownerCount(env, minter) == 1);
1896 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1900 BEAST_EXPECT(ownerCount(env, minter) == 1);
1904 for (
int i = 0; i < 10; ++i)
1907 env(token::setMinter(alice, minter));
1909 BEAST_EXPECT(ownerCount(env, minter) == 1);
1912 BEAST_EXPECT(ownerCount(env, minter) == 1);
1913 uint256 const minterSellOfferIndex =
1915 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)),
1918 BEAST_EXPECT(ownerCount(env, minter) == 2);
1922 env(token::clearMinter(alice));
1927 BEAST_EXPECT(ownerCount(env, becky) == 0);
1928 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1930 BEAST_EXPECT(ownerCount(env, becky) == 1);
1931 BEAST_EXPECT(ownerCount(env, minter) == 0);
1934 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1941 BEAST_EXPECT(ownerCount(env, minter) == 0);
1942 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1943 token::owner(becky),
1946 BEAST_EXPECT(ownerCount(env, minter) == 0);
1949 BEAST_EXPECT(ownerCount(env, alice) == 0);
1950 uint256 const aliceBuyOfferIndex =
1952 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)),
1953 token::owner(becky));
1955 BEAST_EXPECT(ownerCount(env, alice) == 1);
1959 for (
int i = 0; i < 10; ++i)
1962 env(token::setMinter(alice, minter));
1966 BEAST_EXPECT(ownerCount(env, minter) == 0);
1967 uint256 const minterBuyOfferIndex =
1969 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)),
1970 token::owner(becky));
1972 BEAST_EXPECT(ownerCount(env, minter) == 1);
1976 env(token::clearMinter(alice));
1980 BEAST_EXPECT(ownerCount(env, minter) == 1);
1981 BEAST_EXPECT(ownerCount(env, becky) == 1);
1982 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1984 BEAST_EXPECT(ownerCount(env, minter) == 1);
1985 BEAST_EXPECT(ownerCount(env, becky) == 0);
1986 BEAST_EXPECT(ownerCount(env, alice) == 1);
1990 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
1992 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1994 BEAST_EXPECT(ownerCount(env, alice) == 0);
1995 BEAST_EXPECT(ownerCount(env, becky) == 0);
1996 BEAST_EXPECT(ownerCount(env, minter) == 0);
2001 BEAST_EXPECT(ownerCount(env, alice) == 0);
2006 BEAST_EXPECT(ownerCount(env, alice) == 1);
2009 uint256 const aliceSellOfferIndex =
2011 env(token::createOffer(alice, nftAliceID, XRP(20)),
2014 BEAST_EXPECT(ownerCount(env, alice) == 2);
2016 uint256 const beckyBuyOfferIndex =
2018 env(token::createOffer(becky, nftAliceID, XRP(21)),
2019 token::owner(alice));
2021 BEAST_EXPECT(ownerCount(env, alice) == 2);
2024 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
2026 BEAST_EXPECT(ownerCount(env, alice) == 0);
2027 BEAST_EXPECT(ownerCount(env, becky) == 2);
2030 uint256 const beckySellOfferIndex =
2032 env(token::createOffer(becky, nftAliceID, XRP(22)),
2035 BEAST_EXPECT(ownerCount(env, alice) == 0);
2036 BEAST_EXPECT(ownerCount(env, becky) == 3);
2040 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2042 BEAST_EXPECT(ownerCount(env, alice) == 0);
2043 BEAST_EXPECT(ownerCount(env, becky) == 1);
2044 BEAST_EXPECT(ownerCount(env, minter) == 1);
2047 uint256 const minterSellOfferIndex =
2049 env(token::createOffer(minter, nftAliceID, XRP(23)),
2052 BEAST_EXPECT(ownerCount(env, alice) == 0);
2053 BEAST_EXPECT(ownerCount(env, becky) == 1);
2054 BEAST_EXPECT(ownerCount(env, minter) == 2);
2057 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2059 BEAST_EXPECT(ownerCount(env, alice) == 1);
2060 BEAST_EXPECT(ownerCount(env, becky) == 1);
2061 BEAST_EXPECT(ownerCount(env, minter) == 0);
2065 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2067 BEAST_EXPECT(ownerCount(env, alice) == 0);
2068 BEAST_EXPECT(ownerCount(env, becky) == 1);
2069 BEAST_EXPECT(ownerCount(env, minter) == 0);
2073 env(token::burn(becky, nftAliceID));
2075 BEAST_EXPECT(ownerCount(env, alice) == 0);
2076 BEAST_EXPECT(ownerCount(env, becky) == 0);
2077 BEAST_EXPECT(ownerCount(env, minter) == 0);
2087 using namespace test::jtx;
2089 Env env{*
this, features};
2091 Account
const alice{
"alice"};
2092 Account
const becky{
"becky"};
2093 Account
const carol{
"carol"};
2094 Account
const minter{
"minter"};
2095 Account
const gw{
"gw"};
2096 IOU
const gwXAU(gw[
"XAU"]);
2098 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2101 env(trust(alice, gwXAU(2000)));
2102 env(trust(becky, gwXAU(2000)));
2103 env(trust(carol, gwXAU(2000)));
2104 env(trust(minter, gwXAU(2000)));
2106 env(pay(gw, alice, gwXAU(1000)));
2107 env(pay(gw, becky, gwXAU(1000)));
2108 env(pay(gw, carol, gwXAU(1000)));
2109 env(pay(gw, minter, gwXAU(1000)));
2114 env(token::setMinter(alice, minter));
2120 BEAST_EXPECT(ownerCount(env, alice) == 1);
2121 BEAST_EXPECT(ownerCount(env, becky) == 1);
2122 BEAST_EXPECT(ownerCount(env, carol) == 1);
2123 BEAST_EXPECT(ownerCount(env, minter) == 1);
2131 uint256 const beckyBuyOfferIndex =
2133 env(token::createOffer(becky, nftID, gwXAU(10)),
2134 token::owner(alice));
2136 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2137 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2139 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2141 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2142 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2145 uint256 const beckySellOfferIndex =
2147 env(token::createOffer(becky, nftID, gwXAU(10)),
2150 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2152 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2153 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2154 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2157 uint256 const minterBuyOfferIndex =
2159 env(token::createOffer(minter, nftID, gwXAU(10)),
2160 token::owner(carol));
2162 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2164 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2165 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2166 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2167 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2171 uint256 const minterSellOfferIndex =
2173 env(token::createOffer(minter, nftID, gwXAU(10)),
2176 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2178 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2179 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2180 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2181 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2184 env(token::burn(alice, nftID));
2186 BEAST_EXPECT(ownerCount(env, alice) == 1);
2187 BEAST_EXPECT(ownerCount(env, becky) == 1);
2188 BEAST_EXPECT(ownerCount(env, carol) == 1);
2189 BEAST_EXPECT(ownerCount(env, minter) == 1);
2197 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2201 uint256 const beckyBuyOfferIndex =
2203 env(token::createOffer(becky, nftID, gwXAU(10)),
2204 token::owner(alice));
2206 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2207 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2209 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2211 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2212 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2215 uint256 const beckySellOfferIndex =
2217 env(token::createOffer(becky, nftID, gwXAU(10)),
2220 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2223 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2224 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2225 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2228 uint256 const minterBuyOfferIndex =
2230 env(token::createOffer(minter, nftID, gwXAU(10)),
2231 token::owner(carol));
2233 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2236 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2237 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2238 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2239 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2243 uint256 const minterSellOfferIndex =
2245 env(token::createOffer(minter, nftID, gwXAU(10)),
2248 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2250 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2251 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2252 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2253 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2257 env(pay(alice, becky, gwXAU(0.0001)));
2258 env(pay(alice, carol, gwXAU(0.0001)));
2261 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2262 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2263 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2264 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2267 env(token::burn(alice, nftID));
2269 BEAST_EXPECT(ownerCount(env, alice) == 1);
2270 BEAST_EXPECT(ownerCount(env, becky) == 1);
2271 BEAST_EXPECT(ownerCount(env, carol) == 1);
2272 BEAST_EXPECT(ownerCount(env, minter) == 1);
2278 env(token::mint(alice),
2285 uint256 const nftID = token::getNextID(
2287 env(token::mint(alice),
2293 uint256 const beckyBuyOfferIndex =
2295 env(token::createOffer(becky, nftID, gwXAU(10)),
2296 token::owner(alice));
2298 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2299 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2301 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2303 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2304 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2307 uint256 const beckySellOfferIndex =
2309 env(token::createOffer(becky, nftID, gwXAU(100)),
2312 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2315 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2316 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2317 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2320 uint256 const carolBuyOfferIndex =
2322 env(token::createOffer(carol, nftID, gwXAU(10)),
2323 token::owner(minter));
2325 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2328 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2329 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2330 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2331 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2335 uint256 const carolSellOfferIndex =
2337 env(token::createOffer(carol, nftID, gwXAU(10)),
2340 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2343 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2344 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2345 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2346 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2349 env(pay(alice, minter, gwXAU(55)));
2350 env(pay(becky, minter, gwXAU(40)));
2352 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2353 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2354 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2355 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2358 env(token::burn(alice, nftID));
2360 BEAST_EXPECT(ownerCount(env, alice) == 1);
2361 BEAST_EXPECT(ownerCount(env, becky) == 1);
2362 BEAST_EXPECT(ownerCount(env, carol) == 1);
2363 BEAST_EXPECT(ownerCount(env, minter) == 1);
2368 for (
auto NumberSwitchOver : {
true})
2370 if (NumberSwitchOver)
2371 env.enableFeature(fixUniversalNumber);
2373 env.disableFeature(fixUniversalNumber);
2378 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2384 STAmount aliceBalance = env.balance(alice);
2385 STAmount minterBalance = env.balance(minter);
2386 uint256 const minterBuyOfferIndex =
2388 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2390 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2392 aliceBalance += XRP(1) - fee;
2393 minterBalance -= XRP(1) + fee;
2394 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2395 BEAST_EXPECT(env.balance(minter) == minterBalance);
2399 auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
2400 STAmount carolBalance = env.balance(carol);
2401 uint256 const minterSellOfferIndex =
2403 env(token::createOffer(minter, nftID, pmt), txflags(
tfSellNFToken));
2405 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2407 minterBalance += pmt - fee;
2408 carolBalance -= pmt + fee;
2409 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2410 BEAST_EXPECT(env.balance(minter) == minterBalance);
2411 BEAST_EXPECT(env.balance(carol) == carolBalance);
2415 STAmount beckyBalance = env.balance(becky);
2416 uint256 const beckyBuyOfferIndex =
2418 pmt = NumberSwitchOver ? drops(50001) : drops(100000);
2419 env(token::createOffer(becky, nftID, pmt), token::owner(carol));
2421 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2423 carolBalance += pmt - drops(1) - fee;
2424 beckyBalance -= pmt + fee;
2425 aliceBalance += drops(1);
2427 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2428 BEAST_EXPECT(env.balance(minter) == minterBalance);
2429 BEAST_EXPECT(env.balance(carol) == carolBalance);
2430 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2439 env(token::mint(alice), txflags(
tfTransferable), token::xferFee(1));
2445 env(pay(alice, gw, env.balance(alice, gwXAU)));
2446 env(pay(minter, gw, env.balance(minter, gwXAU)));
2447 env(pay(becky, gw, env.balance(becky, gwXAU)));
2452 env(pay(gw, alice, startXAUBalance));
2453 env(pay(gw, minter, startXAUBalance));
2454 env(pay(gw, becky, startXAUBalance));
2463 STAmount aliceBalance = env.balance(alice, gwXAU);
2464 STAmount minterBalance = env.balance(minter, gwXAU);
2465 uint256 const minterBuyOfferIndex =
2467 env(token::createOffer(minter, nftID, tinyXAU),
2468 token::owner(alice));
2470 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2472 aliceBalance += tinyXAU;
2473 minterBalance -= tinyXAU;
2474 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2475 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2478 STAmount carolBalance = env.balance(carol, gwXAU);
2479 uint256 const minterSellOfferIndex =
2481 env(token::createOffer(minter, nftID, tinyXAU),
2484 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2487 minterBalance += tinyXAU;
2488 carolBalance -= tinyXAU;
2490 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2491 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2492 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2499 STAmount beckyBalance = env.balance(becky, gwXAU);
2500 uint256 const beckyBuyOfferIndex =
2502 env(token::createOffer(becky, nftID, cheapNFT),
2503 token::owner(carol));
2505 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2508 aliceBalance += tinyXAU;
2509 beckyBalance -= cheapNFT;
2510 carolBalance += cheapNFT - tinyXAU;
2511 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2512 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2513 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2514 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2524 using namespace test::jtx;
2526 Env env{*
this, features};
2528 Account
const alice{
"alice"};
2529 Account
const becky{
"becky"};
2531 env.fund(XRP(1000), alice, becky);
2540 uint256 const nftID = token::getNextID(env, alice, 0u);
2547 uint256 const nftID = token::getNextID(env, alice, 0xFFFFFFFFu);
2555 for (
int i = 0; i < 10; ++i)
2565 ss <<
"Taxon recovery failed from nftID "
2566 <<
to_string(nftID) <<
". Expected: " << taxon
2567 <<
"; got: " << gotTaxon;
2572 uint256 const nftAliceID = token::getID(
2576 rand_int<std::uint32_t>(),
2577 rand_int<std::uint16_t>(),
2578 rand_int<std::uint16_t>());
2579 check(taxon, nftAliceID);
2581 uint256 const nftBeckyID = token::getID(
2585 rand_int<std::uint32_t>(),
2586 rand_int<std::uint16_t>(),
2587 rand_int<std::uint16_t>());
2588 check(taxon, nftBeckyID);
2602 using namespace test::jtx;
2604 Env env{*
this, features};
2606 Account
const alice{
"alice"};
2607 Account
const becky{
"becky"};
2609 env.fund(XRP(10000), alice, becky);
2615 auto randURI = []() {
2637 : uri(std::move(uri_)), taxon(taxon_)
2645 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2648 for (Entry
const& entry : entries)
2650 if (entry.uri.empty())
2652 env(token::mint(alice, entry.taxon));
2656 env(token::mint(alice, entry.taxon), token::uri(entry.uri));
2664 params[jss::account] = alice.human();
2665 params[jss::type] =
"state";
2666 return env.rpc(
"json",
"account_nfts",
to_string(params));
2670 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2671 if (!BEAST_EXPECT(nfts.
size() == entries.
size()))
2684 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2689 Entry
const& entry = entries[i];
2691 BEAST_EXPECT(entry.taxon == ret[sfNFTokenTaxon.jsonName]);
2692 if (entry.uri.empty())
2694 BEAST_EXPECT(!ret.
isMember(sfURI.jsonName));
2698 BEAST_EXPECT(
strHex(entry.uri) == ret[sfURI.jsonName]);
2707 testcase(
"Create offer destination");
2709 using namespace test::jtx;
2711 Env env{*
this, features};
2713 Account
const issuer{
"issuer"};
2714 Account
const minter{
"minter"};
2715 Account
const buyer{
"buyer"};
2716 Account
const broker{
"broker"};
2718 env.fund(XRP(1000), issuer, minter, buyer, broker);
2722 env(token::setMinter(issuer, minter));
2727 env(token::mint(minter, 0),
2728 token::issuer(issuer),
2735 uint256 const offerMinterToIssuer =
2737 env(token::createOffer(minter, nftokenID, drops(1)),
2738 token::destination(issuer),
2741 uint256 const offerMinterToBuyer =
2743 env(token::createOffer(minter, nftokenID, drops(1)),
2744 token::destination(buyer),
2747 uint256 const offerIssuerToMinter =
2749 env(token::createOffer(issuer, nftokenID, drops(1)),
2750 token::owner(minter),
2751 token::destination(minter));
2753 uint256 const offerIssuerToBuyer =
2755 env(token::createOffer(issuer, nftokenID, drops(1)),
2756 token::owner(minter),
2757 token::destination(buyer));
2760 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2761 BEAST_EXPECT(ownerCount(env, minter) == 3);
2762 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2771 env(token::cancelOffer(issuer, {offerMinterToBuyer}),
2773 env(token::cancelOffer(buyer, {offerMinterToIssuer}),
2775 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
2777 env(token::cancelOffer(minter, {offerIssuerToBuyer}),
2780 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2781 BEAST_EXPECT(ownerCount(env, minter) == 3);
2782 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2786 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2787 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2788 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2789 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2791 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2792 BEAST_EXPECT(ownerCount(env, minter) == 1);
2793 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2799 uint256 const offerMinterSellsToBuyer =
2801 env(token::createOffer(minter, nftokenID, drops(1)),
2802 token::destination(buyer),
2805 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2806 BEAST_EXPECT(ownerCount(env, minter) == 2);
2807 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2811 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer),
2814 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2815 BEAST_EXPECT(ownerCount(env, minter) == 2);
2816 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2819 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2821 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2822 BEAST_EXPECT(ownerCount(env, minter) == 0);
2823 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2829 uint256 const offerMinterBuysFromBuyer =
2831 env(token::createOffer(minter, nftokenID, drops(1)),
2832 token::owner(buyer),
2833 token::destination(buyer));
2835 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2836 BEAST_EXPECT(ownerCount(env, minter) == 1);
2837 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2841 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer),
2844 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2845 BEAST_EXPECT(ownerCount(env, minter) == 1);
2846 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2849 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2851 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2852 BEAST_EXPECT(ownerCount(env, minter) == 1);
2853 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2858 uint256 const offerBuyerBuysFromMinter =
2860 env(token::createOffer(buyer, nftokenID, drops(1)),
2861 token::owner(minter),
2862 token::destination(broker));
2864 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2865 BEAST_EXPECT(ownerCount(env, minter) == 1);
2866 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2868 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter),
2873 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2875 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2876 BEAST_EXPECT(ownerCount(env, minter) == 1);
2877 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2883 uint256 const offerMinterToBroker =
2885 env(token::createOffer(minter, nftokenID, drops(1)),
2886 token::destination(broker),
2889 uint256 const offerBuyerToMinter =
2891 env(token::createOffer(buyer, nftokenID, drops(1)),
2892 token::owner(minter));
2895 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2896 BEAST_EXPECT(ownerCount(env, minter) == 2);
2897 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2902 TER const expectTer = features[fixNonFungibleTokensV1_2]
2905 env(token::brokerOffers(
2906 issuer, offerBuyerToMinter, offerMinterToBroker),
2909 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2910 BEAST_EXPECT(ownerCount(env, minter) == 2);
2911 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2916 env(token::brokerOffers(
2917 broker, offerBuyerToMinter, offerMinterToBroker));
2919 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2920 BEAST_EXPECT(ownerCount(env, minter) == 0);
2921 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2928 uint256 const offerBuyerToMinter =
2930 env(token::createOffer(buyer, nftokenID, drops(1)),
2931 token::destination(minter),
2934 uint256 const offerMinterToBuyer =
2936 env(token::createOffer(minter, nftokenID, drops(1)),
2937 token::owner(buyer));
2939 uint256 const offerIssuerToBuyer =
2941 env(token::createOffer(issuer, nftokenID, drops(1)),
2942 token::owner(buyer));
2945 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2946 BEAST_EXPECT(ownerCount(env, minter) == 1);
2947 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2952 TER const expectTer = features[fixNonFungibleTokensV1_2]
2955 env(token::brokerOffers(
2956 broker, offerIssuerToBuyer, offerBuyerToMinter),
2960 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2961 BEAST_EXPECT(ownerCount(env, minter) == 1);
2962 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2966 TER const eexpectTer = features[fixNonFungibleTokensV1_2]
2969 env(token::brokerOffers(
2970 broker, offerMinterToBuyer, offerBuyerToMinter),
2974 if (features[fixNonFungibleTokensV1_2])
2976 env(token::acceptBuyOffer(buyer, offerMinterToBuyer));
2980 env(token::cancelOffer(buyer, {offerBuyerToMinter}));
2983 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2984 BEAST_EXPECT(ownerCount(env, minter) == 1);
2985 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2988 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2990 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2991 BEAST_EXPECT(ownerCount(env, minter) == 1);
2992 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3000 uint256 const offerMinterToBroker =
3002 env(token::createOffer(minter, nftokenID, drops(1)),
3003 token::destination(broker),
3006 uint256 const offerBuyerToBroker =
3008 env(token::createOffer(buyer, nftokenID, drops(1)),
3009 token::owner(minter),
3010 token::destination(broker));
3015 TER const expectTer = features[fixNonFungibleTokensV1_2]
3018 env(token::brokerOffers(
3019 issuer, offerBuyerToBroker, offerMinterToBroker),
3022 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3023 BEAST_EXPECT(ownerCount(env, minter) == 2);
3024 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3028 env(token::brokerOffers(
3029 broker, offerBuyerToBroker, offerMinterToBroker));
3031 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3032 BEAST_EXPECT(ownerCount(env, minter) == 0);
3033 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3040 testcase(
"Create offer destination disallow incoming");
3042 using namespace test::jtx;
3047 Account
const alice{
"alice"};
3048 env.fund(XRP(10000), alice);
3051 auto const sle = env.le(alice);
3052 uint32_t flags = sle->getFlags();
3058 Account
const issuer{
"issuer"};
3059 Account
const minter{
"minter"};
3060 Account
const buyer{
"buyer"};
3061 Account
const alice{
"alice"};
3063 env.fund(XRP(1000), issuer, minter, buyer, alice);
3065 env(token::setMinter(issuer, minter));
3070 env(token::mint(minter, 0),
3071 token::issuer(issuer),
3081 env(token::createOffer(minter, nftokenID, drops(1)),
3082 token::destination(buyer),
3086 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3087 BEAST_EXPECT(ownerCount(env, minter) == 1);
3088 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3100 env(token::createOffer(minter, nftokenID, drops(1)),
3101 token::destination(buyer),
3105 env(token::cancelOffer(minter, {offerIndex}));
3114 env(token::createOffer(minter, nftokenID, drops(1)),
3115 token::destination(buyer),
3122 env(token::cancelOffer(minter, {offerIndex}));
3134 env(token::createOffer(minter, nftokenID, drops(1)),
3135 token::destination(buyer),
3139 env(token::acceptSellOffer(buyer, offerIndex));
3151 env(token::createOffer(alice, nftokenID, drops(1)),
3152 token::owner(buyer),
3159 env(token::createOffer(minter, nftokenID, drops(1)),
3160 token::owner(buyer),
3166 if (features[featureNFTokenMintOffer])
3171 env(token::mint(minter),
3172 token::amount(drops(1)),
3173 token::destination(buyer),
3179 env(token::mint(minter),
3180 token::amount(drops(1)),
3181 token::destination(buyer));
3190 testcase(
"Create offer expiration");
3192 using namespace test::jtx;
3194 Env env{*
this, features};
3196 Account
const issuer{
"issuer"};
3197 Account
const minter{
"minter"};
3198 Account
const buyer{
"buyer"};
3200 env.fund(XRP(1000), issuer, minter, buyer);
3204 env(token::setMinter(issuer, minter));
3209 env(token::mint(minter, 0),
3210 token::issuer(issuer),
3216 env(token::mint(minter, 0),
3217 token::issuer(issuer),
3226 uint256 const offerMinterToIssuer =
3228 env(token::createOffer(minter, nftokenID0, drops(1)),
3229 token::destination(issuer),
3230 token::expiration(expiration),
3233 uint256 const offerMinterToAnyone =
3235 env(token::createOffer(minter, nftokenID0, drops(1)),
3236 token::expiration(expiration),
3239 uint256 const offerIssuerToMinter =
3241 env(token::createOffer(issuer, nftokenID0, drops(1)),
3242 token::owner(minter),
3243 token::expiration(expiration));
3245 uint256 const offerBuyerToMinter =
3247 env(token::createOffer(buyer, nftokenID0, drops(1)),
3248 token::owner(minter),
3249 token::expiration(expiration));
3251 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3252 BEAST_EXPECT(ownerCount(env, minter) == 3);
3253 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3261 env(token::cancelOffer(issuer, {offerMinterToAnyone}),
3263 env(token::cancelOffer(buyer, {offerIssuerToMinter}),
3266 BEAST_EXPECT(
lastClose(env) < expiration);
3267 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3268 BEAST_EXPECT(ownerCount(env, minter) == 3);
3269 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3272 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3276 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3282 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3283 BEAST_EXPECT(ownerCount(env, minter) == 1);
3284 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3287 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3288 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3290 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3291 BEAST_EXPECT(ownerCount(env, minter) == 1);
3292 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3303 env(token::createOffer(minter, nftokenID0, drops(1)),
3304 token::expiration(expiration),
3309 env(token::createOffer(minter, nftokenID1, drops(1)),
3310 token::expiration(expiration),
3313 BEAST_EXPECT(
lastClose(env) < expiration);
3314 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3315 BEAST_EXPECT(ownerCount(env, minter) == 3);
3316 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3319 env(token::acceptSellOffer(buyer, offer0));
3325 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3326 BEAST_EXPECT(ownerCount(env, minter) == 2);
3327 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3330 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3331 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3335 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3336 BEAST_EXPECT(ownerCount(env, minter) == 2);
3337 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3340 env(token::cancelOffer(issuer, {offer1}));
3342 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3343 BEAST_EXPECT(ownerCount(env, minter) == 1);
3344 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3350 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3352 token::destination(minter));
3354 env(token::acceptSellOffer(minter, offerSellBack));
3356 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3357 BEAST_EXPECT(ownerCount(env, minter) == 1);
3358 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3368 env(token::createOffer(buyer, nftokenID0, drops(1)),
3369 token::owner(minter),
3370 token::expiration(expiration));
3373 env(token::createOffer(buyer, nftokenID1, drops(1)),
3374 token::owner(minter),
3375 token::expiration(expiration));
3377 BEAST_EXPECT(
lastClose(env) < expiration);
3378 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3379 BEAST_EXPECT(ownerCount(env, minter) == 1);
3380 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3383 env(token::acceptBuyOffer(minter, offer0));
3389 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3390 BEAST_EXPECT(ownerCount(env, minter) == 1);
3391 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3394 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3395 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3399 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3400 BEAST_EXPECT(ownerCount(env, minter) == 1);
3401 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3404 env(token::cancelOffer(issuer, {offer1}));
3406 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3407 BEAST_EXPECT(ownerCount(env, minter) == 1);
3408 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3414 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3416 token::destination(minter));
3418 env(token::acceptSellOffer(minter, offerSellBack));
3420 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3421 BEAST_EXPECT(ownerCount(env, minter) == 1);
3422 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3433 env(token::createOffer(minter, nftokenID0, drops(1)),
3434 token::expiration(expiration),
3439 env(token::createOffer(minter, nftokenID1, drops(1)),
3440 token::expiration(expiration),
3445 env(token::createOffer(buyer, nftokenID0, drops(1)),
3446 token::owner(minter));
3450 env(token::createOffer(buyer, nftokenID1, drops(1)),
3451 token::owner(minter));
3454 BEAST_EXPECT(
lastClose(env) < expiration);
3455 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3456 BEAST_EXPECT(ownerCount(env, minter) == 3);
3457 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3460 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3466 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3467 BEAST_EXPECT(ownerCount(env, minter) == 2);
3468 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3471 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3476 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3477 BEAST_EXPECT(ownerCount(env, minter) == 2);
3478 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3481 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3483 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3484 BEAST_EXPECT(ownerCount(env, minter) == 1);
3485 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3491 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3493 token::destination(minter));
3495 env(token::acceptSellOffer(minter, offerSellBack));
3497 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3498 BEAST_EXPECT(ownerCount(env, minter) == 1);
3499 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3510 env(token::createOffer(minter, nftokenID0, drops(1)),
3515 env(token::createOffer(minter, nftokenID1, drops(1)),
3520 env(token::createOffer(buyer, nftokenID0, drops(1)),
3521 token::expiration(expiration),
3522 token::owner(minter));
3526 env(token::createOffer(buyer, nftokenID1, drops(1)),
3527 token::expiration(expiration),
3528 token::owner(minter));
3531 BEAST_EXPECT(
lastClose(env) < expiration);
3532 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3533 BEAST_EXPECT(ownerCount(env, minter) == 3);
3534 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3537 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3543 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3544 BEAST_EXPECT(ownerCount(env, minter) == 2);
3545 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3548 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3553 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3554 BEAST_EXPECT(ownerCount(env, minter) == 2);
3555 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3558 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3560 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3561 BEAST_EXPECT(ownerCount(env, minter) == 1);
3562 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3568 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3570 token::destination(minter));
3572 env(token::acceptSellOffer(minter, offerSellBack));
3574 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3575 BEAST_EXPECT(ownerCount(env, minter) == 1);
3576 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3588 env(token::createOffer(minter, nftokenID0, drops(1)),
3589 token::expiration(expiration),
3594 env(token::createOffer(minter, nftokenID1, drops(1)),
3595 token::expiration(expiration),
3600 env(token::createOffer(buyer, nftokenID0, drops(1)),
3601 token::expiration(expiration),
3602 token::owner(minter));
3606 env(token::createOffer(buyer, nftokenID1, drops(1)),
3607 token::expiration(expiration),
3608 token::owner(minter));
3611 BEAST_EXPECT(
lastClose(env) < expiration);
3612 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3613 BEAST_EXPECT(ownerCount(env, minter) == 3);
3614 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3617 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3623 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3624 BEAST_EXPECT(ownerCount(env, minter) == 2);
3625 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3628 env(token::brokerOffers(issuer, buyOffer1, sellOffer1),
3633 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3634 BEAST_EXPECT(ownerCount(env, minter) == 2);
3635 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3638 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3640 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3641 BEAST_EXPECT(ownerCount(env, minter) == 1);
3642 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3648 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3650 token::destination(minter));
3652 env(token::acceptSellOffer(minter, offerSellBack));
3654 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3655 BEAST_EXPECT(ownerCount(env, minter) == 1);
3656 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3666 using namespace test::jtx;
3668 Env env{*
this, features};
3670 Account
const alice(
"alice");
3671 Account
const becky(
"becky");
3672 Account
const minter(
"minter");
3673 env.fund(XRP(50000), alice, becky, minter);
3677 env(token::setMinter(alice, minter));
3686 uint256 const expiredOfferIndex =
3689 env(token::createOffer(alice, nftokenID, XRP(1000)),
3691 token::expiration(
lastClose(env) + 13));
3695 BEAST_EXPECT(ownerCount(env, alice) == 2);
3696 env(token::cancelOffer(becky, {expiredOfferIndex}),
3704 env(token::cancelOffer(becky, {expiredOfferIndex}));
3706 BEAST_EXPECT(ownerCount(env, alice) == 1);
3710 uint256 const dest1OfferIndex =
3713 env(token::createOffer(alice, nftokenID, XRP(1000)),
3714 token::destination(becky),
3717 BEAST_EXPECT(ownerCount(env, alice) == 2);
3720 env(token::cancelOffer(minter, {dest1OfferIndex}),
3723 BEAST_EXPECT(ownerCount(env, alice) == 2);
3725 env(token::cancelOffer(becky, {dest1OfferIndex}));
3727 BEAST_EXPECT(ownerCount(env, alice) == 1);
3730 uint256 const dest2OfferIndex =
3733 env(token::createOffer(alice, nftokenID, XRP(1000)),
3734 token::destination(becky),
3737 BEAST_EXPECT(ownerCount(env, alice) == 2);
3739 env(token::cancelOffer(alice, {dest2OfferIndex}));
3741 BEAST_EXPECT(ownerCount(env, alice) == 1);
3746 uint256 const mintersNFTokenID =
3748 env(token::mint(minter, 0),
3749 token::issuer(alice),
3753 uint256 const minterOfferIndex =
3756 env(token::createOffer(minter, mintersNFTokenID, XRP(1000)),
3759 BEAST_EXPECT(ownerCount(env, minter) == 2);
3762 env(token::cancelOffer(alice, {minterOfferIndex}),
3764 env(token::cancelOffer(becky, {minterOfferIndex}),
3767 BEAST_EXPECT(ownerCount(env, minter) == 2);
3769 env(token::cancelOffer(minter, {minterOfferIndex}));
3771 BEAST_EXPECT(ownerCount(env, minter) == 1);
3778 testcase(
"Cancel too many offers");
3780 using namespace test::jtx;
3782 Env env{*
this, features};
3797 Account
const alice(
"alice");
3798 env.fund(XRP(1000), alice);
3807 Account
const offerAcct(
3809 env.fund(XRP(1000), nftAcct, offerAcct);
3814 env(token::mint(nftAcct, 0),
3821 env(token::createOffer(offerAcct, nftokenID, drops(1)),
3822 token::owner(nftAcct),
3831 for (
uint256 const& offerIndex : offerIndexes)
3838 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3842 env(token::cancelOffer(alice, {offerIndexes.
back()}));
3853 env(token::mint(alice, 0),
3859 env(token::createOffer(alice, nftokenID, drops(1)),
3864 BEAST_EXPECT(ownerCount(env, alice) == 2);
3868 env(token::cancelOffer(alice, offerIndexes), ter(
temMALFORMED));
3872 env(token::burn(alice, nftokenID));
3877 BEAST_EXPECT(ownerCount(env, alice) == 0);
3883 env(token::cancelOffer(alice, offerIndexes));
3887 for (
uint256 const& offerIndex : offerIndexes)
3897 testcase(
"Brokered NFT offer accept");
3899 using namespace test::jtx;
3901 for (
auto const& tweakedFeatures :
3902 {features - fixNonFungibleTokensV1_2,
3903 features | fixNonFungibleTokensV1_2})
3905 Env env{*
this, tweakedFeatures};
3913 Account
const issuer{
"issuer"};
3914 Account
const minter{
"minter"};
3915 Account
const buyer{
"buyer"};
3916 Account
const broker{
"broker"};
3917 Account
const gw{
"gw"};
3918 IOU
const gwXAU(gw[
"XAU"]);
3920 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3923 env(trust(issuer, gwXAU(2000)));
3924 env(trust(minter, gwXAU(2000)));
3925 env(trust(buyer, gwXAU(2000)));
3926 env(trust(broker, gwXAU(2000)));
3929 env(token::setMinter(issuer, minter));
3933 auto checkOwnerCountIsOne =
3938 for (Account
const& acct : accounts)
3945 ss <<
"Account " << acct.human()
3946 <<
" expected ownerCount == 1. Got "
3948 fail(ss.
str(), __FILE__, line);
3954 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3957 env(token::mint(minter, 0),
3958 token::issuer(issuer),
3959 token::xferFee(xferFee),
3971 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3973 uint256 const nftID = mintNFT();
3976 uint256 const minterOfferIndex =
3978 env(token::createOffer(minter, nftID, XRP(0)),
3986 env(token::createOffer(buyer, nftID, XRP(1)),
3987 token::owner(minter));
3990 auto const minterBalance = env.balance(minter);
3991 auto const buyerBalance = env.balance(buyer);
3992 auto const brokerBalance = env.balance(broker);
3993 auto const issuerBalance = env.balance(issuer);
3996 env(token::brokerOffers(
3997 broker, buyOfferIndex, minterOfferIndex));
4002 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
4003 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4004 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
4005 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4008 env(token::burn(buyer, nftID));
4018 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4020 uint256 const nftID = mintNFT();
4023 uint256 const minterOfferIndex =
4025 env(token::createOffer(minter, nftID, XRP(0)),
4033 env(token::createOffer(buyer, nftID, XRP(1)),
4034 token::owner(minter));
4038 env(token::brokerOffers(
4039 broker, buyOfferIndex, minterOfferIndex),
4040 token::brokerFee(XRP(1.1)),
4044 auto const minterBalance = env.balance(minter);
4045 auto const buyerBalance = env.balance(buyer);
4046 auto const brokerBalance = env.balance(broker);
4047 auto const issuerBalance = env.balance(issuer);
4050 env(token::brokerOffers(
4051 broker, buyOfferIndex, minterOfferIndex),
4052 token::brokerFee(XRP(0.5)));
4057 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4058 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4060 env.balance(broker) ==
4061 brokerBalance + XRP(0.5) - drops(10));
4062 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4065 env(token::burn(buyer, nftID));
4075 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4080 uint256 const minterOfferIndex =
4082 env(token::createOffer(minter, nftID, XRP(0)),
4090 env(token::createOffer(buyer, nftID, XRP(1)),
4091 token::owner(minter));
4094 auto const minterBalance = env.balance(minter);
4095 auto const buyerBalance = env.balance(buyer);
4096 auto const brokerBalance = env.balance(broker);
4097 auto const issuerBalance = env.balance(issuer);
4100 env(token::brokerOffers(
4101 broker, buyOfferIndex, minterOfferIndex));
4106 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4107 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4108 BEAST_EXPECT(env.balance(broker) == brokerBalance - drops(10));
4109 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
4112 env(token::burn(buyer, nftID));
4122 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4127 uint256 const minterOfferIndex =
4129 env(token::createOffer(minter, nftID, XRP(0)),
4137 env(token::createOffer(buyer, nftID, XRP(1)),
4138 token::owner(minter));
4141 auto const minterBalance = env.balance(minter);
4142 auto const buyerBalance = env.balance(buyer);
4143 auto const brokerBalance = env.balance(broker);
4144 auto const issuerBalance = env.balance(issuer);
4147 env(token::brokerOffers(
4148 broker, buyOfferIndex, minterOfferIndex),
4149 token::brokerFee(XRP(0.75)));
4155 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
4156 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4158 env.balance(broker) ==
4159 brokerBalance + XRP(0.75) - drops(10));
4160 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
4163 env(token::burn(buyer, nftID));
4169 auto setXAUBalance =
4170 [
this, &gw, &gwXAU, &env](
4175 for (Account
const& acct : accounts)
4177 auto const xauAmt = gwXAU(amount);
4178 auto const balance = env.balance(acct, gwXAU);
4179 if (balance < xauAmt)
4181 env(pay(gw, acct, xauAmt - balance));
4184 else if (balance > xauAmt)
4186 env(pay(acct, gw, balance - xauAmt));
4189 if (env.balance(acct, gwXAU) != xauAmt)
4192 ss <<
"Unable to set " << acct.human()
4193 <<
" account balance to gwXAU(" << amount <<
")";
4194 this->
fail(ss.
str(), __FILE__, line);
4202 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4203 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4205 uint256 const nftID = mintNFT();
4208 uint256 const minterOfferIndex =
4210 env(token::createOffer(minter, nftID, gwXAU(1000)),
4219 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4220 token::owner(minter));
4224 env(token::brokerOffers(
4225 broker, buyOfferIndex, minterOfferIndex),
4231 env(token::cancelOffer(buyer, {buyOfferIndex}));
4239 env(token::createOffer(buyer, nftID, gwXAU(999)),
4240 token::owner(minter));
4244 env(token::brokerOffers(
4245 broker, buyOfferIndex, minterOfferIndex),
4251 env(token::cancelOffer(buyer, {buyOfferIndex}));
4258 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4259 token::owner(minter));
4263 env(token::brokerOffers(
4264 broker, buyOfferIndex, minterOfferIndex),
4265 token::brokerFee(gwXAU(0.1)),
4270 env(token::brokerOffers(
4271 broker, buyOfferIndex, minterOfferIndex));
4274 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4275 BEAST_EXPECT(ownerCount(env, minter) == 1);
4276 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4277 BEAST_EXPECT(ownerCount(env, broker) == 1);
4278 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4279 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4280 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4281 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4284 env(token::burn(buyer, nftID));
4291 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4292 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4297 uint256 const minterOfferIndex =
4299 env(token::createOffer(minter, nftID, gwXAU(900)),
4307 env(token::createOffer(buyer, nftID, gwXAU(1001)),
4308 token::owner(minter));
4312 env(token::brokerOffers(
4313 broker, buyOfferIndex, minterOfferIndex),
4319 env(token::cancelOffer(buyer, {buyOfferIndex}));
4327 env(token::createOffer(buyer, nftID, gwXAU(899)),
4328 token::owner(minter));
4332 env(token::brokerOffers(
4333 broker, buyOfferIndex, minterOfferIndex),
4339 env(token::cancelOffer(buyer, {buyOfferIndex}));
4345 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4346 token::owner(minter));
4351 env(token::brokerOffers(
4352 broker, buyOfferIndex, minterOfferIndex),
4353 token::brokerFee(gwXAU(101)),
4359 env(token::brokerOffers(
4360 broker, buyOfferIndex, minterOfferIndex),
4361 token::brokerFee(gwXAU(100)));
4364 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4365 BEAST_EXPECT(ownerCount(env, minter) == 1);
4366 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4367 BEAST_EXPECT(ownerCount(env, broker) == 1);
4368 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4369 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4370 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4371 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4374 env(token::burn(buyer, nftID));
4381 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4382 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4387 uint256 const minterOfferIndex =
4389 env(token::createOffer(minter, nftID, gwXAU(900)),
4396 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4397 token::owner(minter));
4403 env(token::brokerOffers(
4404 broker, buyOfferIndex, minterOfferIndex),
4405 token::brokerFee(gwXAU(50)));
4408 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4409 BEAST_EXPECT(ownerCount(env, minter) == 1);
4410 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4411 BEAST_EXPECT(ownerCount(env, broker) == 1);
4412 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4413 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4414 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4415 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4418 env(token::burn(buyer, nftID));
4423 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4424 setXAUBalance({issuer, minter, buyer}, 1000, __LINE__);
4425 setXAUBalance({broker}, 500, __LINE__);
4429 uint256 const minterOfferIndex =
4431 env(token::createOffer(minter, nftID, gwXAU(900)),
4438 env(token::createOffer(buyer, nftID, gwXAU(1000)),
4439 token::owner(minter));
4442 if (tweakedFeatures[fixNonFungibleTokensV1_2])
4444 env(token::brokerOffers(
4445 broker, buyOfferIndex, minterOfferIndex),
4446 token::brokerFee(gwXAU(50)));
4448 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4449 BEAST_EXPECT(ownerCount(env, minter) == 1);
4450 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4451 BEAST_EXPECT(ownerCount(env, broker) == 1);
4452 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4453 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4454 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4455 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(550));
4458 env(token::burn(buyer, nftID));
4463 env(token::brokerOffers(
4464 broker, buyOfferIndex, minterOfferIndex),
4465 token::brokerFee(gwXAU(50)),
4468 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4469 BEAST_EXPECT(ownerCount(env, minter) == 3);
4470 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4471 BEAST_EXPECT(ownerCount(env, broker) == 1);
4472 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4473 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4474 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
4475 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(500));
4478 env(token::burn(minter, nftID));
4491 using namespace test::jtx;
4493 Env env{*
this, features};
4495 Account
const issuer{
"issuer"};
4496 Account
const buyer1{
"buyer1"};
4497 Account
const buyer2{
"buyer2"};
4498 env.fund(XRP(10000), issuer, buyer1, buyer2);
4507 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4508 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4509 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4512 uint256 const buyer1OfferIndex =
4514 env(token::createOffer(buyer1, nftId, XRP(100)), token::owner(issuer));
4515 uint256 const buyer2OfferIndex =
4517 env(token::createOffer(buyer2, nftId, XRP(100)), token::owner(issuer));
4527 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4529 if (buyOffers.
isMember(jss::result) &&
4530 buyOffers[jss::result].
isMember(jss::offers))
4531 return buyOffers[jss::result][jss::offers].
size();
4537 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4540 env(token::acceptBuyOffer(issuer, buyer1OfferIndex));
4544 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4545 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4546 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4550 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4554 env(token::acceptBuyOffer(buyer1, buyer2OfferIndex));
4558 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4559 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4560 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4563 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4570 testcase(
"NFToken transactions with tickets");
4572 using namespace test::jtx;
4574 Env env{*
this, features};
4576 Account
const issuer{
"issuer"};
4577 Account
const buyer{
"buyer"};
4578 env.fund(XRP(10000), issuer, buyer);
4585 env(ticket::create(issuer, 10));
4591 env(ticket::create(buyer, 10));
4597 BEAST_EXPECT(ownerCount(env, issuer) == 10);
4599 env(token::mint(issuer, 0u),
4601 ticket::use(issuerTicketSeq++));
4603 BEAST_EXPECT(ownerCount(env, issuer) == 10);
4607 BEAST_EXPECT(ownerCount(env, buyer) == 10);
4609 env(token::createOffer(buyer, nftId, XRP(1)),
4610 token::owner(issuer),
4611 ticket::use(buyerTicketSeq++));
4613 BEAST_EXPECT(ownerCount(env, buyer) == 10);
4617 env(token::cancelOffer(buyer, {offerIndex0}),
4618 ticket::use(buyerTicketSeq++));
4620 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4625 env(token::createOffer(buyer, nftId, XRP(2)),
4626 token::owner(issuer),
4627 ticket::use(buyerTicketSeq++));
4629 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4633 env(token::acceptBuyOffer(issuer, offerIndex1),
4634 ticket::use(issuerTicketSeq++));
4636 BEAST_EXPECT(ownerCount(env, issuer) == 8);
4637 BEAST_EXPECT(ownerCount(env, buyer) == 8);
4641 env(token::burn(buyer, nftId), ticket::use(buyerTicketSeq++));
4643 BEAST_EXPECT(ownerCount(env, issuer) == 8);
4644 BEAST_EXPECT(ownerCount(env, buyer) == 6);
4648 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4649 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4660 testcase(
"NFToken delete account");
4662 using namespace test::jtx;
4664 Env env{*
this, features};
4666 Account
const issuer{
"issuer"};
4667 Account
const minter{
"minter"};
4668 Account
const becky{
"becky"};
4669 Account
const carla{
"carla"};
4670 Account
const daria{
"daria"};
4672 env.fund(XRP(10000), issuer, minter, becky, carla, daria);
4676 for (
int i = 0; i < 300; ++i)
4679 env(token::setMinter(issuer, minter));
4683 env(token::mint(minter, 0u),
4684 token::issuer(issuer),
4697 for (
int i = 0; i < 15; ++i)
4701 env(token::createOffer(becky, nftId, XRP(2)), token::owner(minter));
4704 uint256 const carlaOfferIndex =
4706 env(token::createOffer(carla, nftId, XRP(3)), token::owner(minter));
4711 env(acctdelete(becky, daria), fee(XRP(50)));
4715 env(token::acceptBuyOffer(minter, carlaOfferIndex));
4720 env(acctdelete(minter, daria), fee(XRP(50)));
4732 for (
int i = 0; i < 15; ++i)
4737 env(token::burn(carla, nftId));
4740 env(acctdelete(issuer, daria), fee(XRP(50)));
4741 env(acctdelete(carla, daria), fee(XRP(50)));
4748 testcase(
"nft_buy_offers and nft_sell_offers");
4757 using namespace test::jtx;
4759 Env env{*
this, features};
4761 Account
const issuer{
"issuer"};
4762 Account
const buyer{
"buyer"};
4765 env.fund(XRP(1000000), issuer, buyer);
4774 auto checkOffers = [
this, &env, &nftID](
4775 char const* request,
4777 int expectMarkerCount,
4779 int markerCount = 0;
4786 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4790 if (!marker.
empty())
4791 params[jss::marker] = marker;
4792 return env.rpc(
"json", request,
to_string(params));
4796 if (expectCount == 0)
4800 "expected \"result\"",
4805 nftOffers[jss::result].isMember(jss::error),
4806 "expected \"error\"",
4811 nftOffers[jss::result][jss::error].asString() ==
4813 "expected \"objectNotFound\"",
4824 "expected \"result\"",
4833 marker = result[jss::marker].
asString();
4838 "expected \"offers\"",
4844 allOffers.
append(someOffers[i]);
4847 }
while (!marker.
empty());
4851 allOffers.
size() == expectCount,
4852 "Unexpected returned offer count",
4856 markerCount == expectMarkerCount,
4857 "Unexpected marker count",
4867 globalFlags = offer[jss::flags].asInt();
4870 *globalFlags == offer[jss::flags].asInt(),
4871 "Inconsistent flags returned",
4877 offerIndexes.
insert(offer[jss::nft_offer_index].asString());
4878 amounts.
insert(offer[jss::amount].asString());
4882 offerIndexes.
size() == expectCount,
4883 "Duplicate indexes returned?",
4887 amounts.
size() == expectCount,
4888 "Duplicate amounts returned?",
4894 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4898 auto makeSellOffers =
4899 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4902 while (sellPrice < limit)
4904 sellPrice += XRP(1);
4905 env(token::createOffer(issuer, nftID, sellPrice),
4907 if (++offerCount % 10 == 0)
4914 makeSellOffers(XRP(1));
4915 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4918 makeSellOffers(XRP(250));
4919 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4922 makeSellOffers(XRP(251));
4923 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4926 makeSellOffers(XRP(500));
4927 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4930 makeSellOffers(XRP(501));
4931 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4934 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4938 auto makeBuyOffers =
4939 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4942 while (buyPrice < limit)
4945 env(token::createOffer(buyer, nftID, buyPrice),
4946 token::owner(issuer));
4947 if (++offerCount % 10 == 0)
4954 makeBuyOffers(XRP(1));
4955 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4958 makeBuyOffers(XRP(250));
4959 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4962 makeBuyOffers(XRP(251));
4963 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4966 makeBuyOffers(XRP(500));
4967 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4970 makeBuyOffers(XRP(501));
4971 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4978 using namespace test::jtx;
4982 Account
const issuer{
"issuer"};
4983 Account
const buyer{
"buyer"};
4984 Account
const gw{
"gw"};
4985 IOU
const gwXAU(gw[
"XAU"]);
4991 for (
auto const& tweakedFeatures :
4992 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1 -
4993 fixNonFungibleTokensV1_2,
4994 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
4995 features | fixNFTokenNegOffer})
5000 Env env{*
this, tweakedFeatures};
5002 env.fund(XRP(1000000), issuer, buyer, gw);
5005 env(trust(issuer, gwXAU(2000)));
5006 env(trust(buyer, gwXAU(2000)));
5009 env(pay(gw, issuer, gwXAU(1000)));
5010 env(pay(gw, buyer, gwXAU(1000)));
5025 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5030 uint256 const sellNegXrpOfferIndex =
5032 env(token::createOffer(issuer, nftID0, XRP(-2)),
5034 ter(offerCreateTER));
5037 uint256 const sellNegIouOfferIndex =
5039 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
5041 ter(offerCreateTER));
5044 uint256 const buyNegXrpOfferIndex =
5046 env(token::createOffer(buyer, nftID0, XRP(-1)),
5047 token::owner(issuer),
5048 ter(offerCreateTER));
5051 uint256 const buyNegIouOfferIndex =
5053 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
5054 token::owner(issuer),
5055 ter(offerCreateTER));
5062 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5067 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
5068 ter(offerAcceptTER));
5070 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
5071 ter(offerAcceptTER));
5075 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
5076 ter(offerAcceptTER));
5078 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
5079 ter(offerAcceptTER));
5087 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5092 env(token::brokerOffers(
5093 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5094 ter(offerAcceptTER));
5096 env(token::brokerOffers(
5097 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5098 ter(offerAcceptTER));
5108 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1};
5110 env.fund(XRP(1000000), issuer, buyer, gw);
5113 env(trust(issuer, gwXAU(2000)));
5114 env(trust(buyer, gwXAU(2000)));
5117 env(pay(gw, issuer, gwXAU(1000)));
5118 env(pay(gw, buyer, gwXAU(1000)));
5134 uint256 const sellNegXrpOfferIndex =
5136 env(token::createOffer(issuer, nftID0, XRP(-2)),
5140 uint256 const sellNegIouOfferIndex =
5142 env(token::createOffer(issuer, nftID1, gwXAU(-2)),
5146 uint256 const buyNegXrpOfferIndex =
5148 env(token::createOffer(buyer, nftID0, XRP(-1)),
5149 token::owner(issuer));
5152 uint256 const buyNegIouOfferIndex =
5154 env(token::createOffer(buyer, nftID1, gwXAU(-1)),
5155 token::owner(issuer));
5159 env.enableFeature(fixNFTokenNegOffer);
5164 env(token::acceptSellOffer(buyer, sellNegXrpOfferIndex),
5167 env(token::acceptSellOffer(buyer, sellNegIouOfferIndex),
5172 env(token::acceptBuyOffer(issuer, buyNegXrpOfferIndex),
5175 env(token::acceptBuyOffer(issuer, buyNegIouOfferIndex),
5180 env(token::brokerOffers(
5181 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5184 env(token::brokerOffers(
5185 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5192 for (
auto const& tweakedFeatures :
5193 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
5194 features | fixNFTokenNegOffer})
5196 Env env{*
this, tweakedFeatures};
5198 env.fund(XRP(1000000), issuer, buyer);
5206 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5210 env(token::createOffer(buyer, nftID, drops(1)),
5211 token::owner(issuer),
5212 token::destination(issuer),
5213 ter(offerCreateTER));
5221 using namespace test::jtx;
5223 testcase(
"Payments with IOU transfer fees");
5225 for (
auto const& tweakedFeatures :
5226 {features - fixNonFungibleTokensV1_2,
5227 features | fixNonFungibleTokensV1_2})
5229 Env env{*
this, tweakedFeatures};
5231 Account
const minter{
"minter"};
5232 Account
const secondarySeller{
"seller"};
5233 Account
const buyer{
"buyer"};
5234 Account
const gw{
"gateway"};
5235 Account
const broker{
"broker"};
5236 IOU
const gwXAU(gw[
"XAU"]);
5237 IOU
const gwXPB(gw[
"XPB"]);
5239 env.fund(XRP(1000), gw, minter, secondarySeller, buyer, broker);
5242 env(trust(minter, gwXAU(2000)));
5243 env(trust(secondarySeller, gwXAU(2000)));
5244 env(trust(broker, gwXAU(10000)));
5245 env(trust(buyer, gwXAU(2000)));
5246 env(trust(buyer, gwXPB(2000)));
5250 env(rate(gw, 1.02));
5253 auto expectInitialState = [
this,
5266 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
5267 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(0));
5268 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(0));
5269 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(0));
5270 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(0));
5271 BEAST_EXPECT(env.balance(secondarySeller, gwXPB) == gwXPB(0));
5272 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5000));
5273 BEAST_EXPECT(env.balance(broker, gwXPB) == gwXPB(0));
5274 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-1000));
5275 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(0));
5276 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(0));
5277 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(0));
5279 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(0));
5281 env.balance(gw, secondarySeller[
"XPB"]) == gwXPB(0));
5282 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5000));
5283 BEAST_EXPECT(env.balance(gw, broker[
"XPB"]) == gwXPB(0));
5286 auto reinitializeTrustLineBalances = [&expectInitialState,
5295 if (
auto const difference =
5296 gwXAU(1000) - env.balance(buyer, gwXAU);
5297 difference > gwXAU(0))
5298 env(pay(gw, buyer, difference));
5299 if (env.balance(buyer, gwXPB) > gwXPB(0))
5300 env(pay(buyer, gw, env.balance(buyer, gwXPB)));
5301 if (env.balance(minter, gwXAU) > gwXAU(0))
5302 env(pay(minter, gw, env.balance(minter, gwXAU)));
5303 if (env.balance(minter, gwXPB) > gwXPB(0))
5304 env(pay(minter, gw, env.balance(minter, gwXPB)));
5305 if (env.balance(secondarySeller, gwXAU) > gwXAU(0))
5307 pay(secondarySeller,
5309 env.balance(secondarySeller, gwXAU)));
5310 if (env.balance(secondarySeller, gwXPB) > gwXPB(0))
5312 pay(secondarySeller,
5314 env.balance(secondarySeller, gwXPB)));
5315 auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU);
5316 if (brokerDiff > gwXAU(0))
5317 env(pay(gw, broker, brokerDiff));
5318 else if (brokerDiff < gwXAU(0))
5320 brokerDiff.negate();
5321 env(pay(broker, gw, brokerDiff));
5323 if (env.balance(broker, gwXPB) > gwXPB(0))
5324 env(pay(broker, gw, env.balance(broker, gwXPB)));
5326 expectInitialState();
5329 auto mintNFT = [&env](Account
const& minter,
int transferFee = 0) {
5330 uint256 const nftID = token::getNextID(
5332 env(token::mint(minter),
5333 token::xferFee(transferFee),
5339 auto createBuyOffer =
5341 Account
const& offerer,
5342 Account
const& owner,
5348 env(token::createOffer(offerer, nftID, amount),
5349 token::owner(owner),
5350 terCode ? ter(*terCode)
5356 auto createSellOffer =
5358 Account
const& offerer,
5364 env(token::createOffer(offerer, nftID, amount),
5366 terCode ? ter(*terCode)
5375 reinitializeTrustLineBalances();
5376 auto const nftID = mintNFT(minter);
5377 auto const offerID =
5378 createSellOffer(minter, nftID, gwXAU(1000));
5379 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5382 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5385 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5386 expectInitialState();
5389 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5390 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5392 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5393 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5399 reinitializeTrustLineBalances();
5400 auto const nftID = mintNFT(minter);
5401 auto const offerID =
5402 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5403 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5406 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5409 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5410 expectInitialState();
5413 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5414 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5416 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5417 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5424 reinitializeTrustLineBalances();
5425 auto const nftID = mintNFT(minter);
5426 auto const offerID = createSellOffer(minter, nftID, gwXAU(995));
5427 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5430 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5433 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5434 expectInitialState();
5437 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5438 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5439 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5440 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5447 reinitializeTrustLineBalances();
5448 auto const nftID = mintNFT(minter);
5449 auto const offerID =
5450 createBuyOffer(buyer, minter, nftID, gwXAU(995));
5451 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5454 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5457 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5458 expectInitialState();
5461 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5462 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5463 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5464 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5472 reinitializeTrustLineBalances();
5473 auto const nftID = mintNFT(minter);
5474 auto const offerID = createSellOffer(minter, nftID, gwXAU(900));
5475 env(token::acceptSellOffer(buyer, offerID));
5478 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5479 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5480 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5481 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5488 reinitializeTrustLineBalances();
5489 auto const nftID = mintNFT(minter);
5490 auto const offerID =
5491 createBuyOffer(buyer, minter, nftID, gwXAU(900));
5492 env(token::acceptBuyOffer(minter, offerID));
5495 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5496 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5497 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5498 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5505 reinitializeTrustLineBalances();
5508 env(pay(gw, buyer, gwXAU(20)));
5511 auto const nftID = mintNFT(minter);
5512 auto const offerID =
5513 createSellOffer(minter, nftID, gwXAU(1000));
5514 env(token::acceptSellOffer(buyer, offerID));
5517 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5518 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5519 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5520 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5527 reinitializeTrustLineBalances();
5530 env(pay(gw, buyer, gwXAU(20)));
5533 auto const nftID = mintNFT(minter);
5534 auto const offerID =
5535 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5536 env(token::acceptBuyOffer(minter, offerID));
5539 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5540 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5541 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5542 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5547 reinitializeTrustLineBalances();
5549 auto const nftID = mintNFT(minter);
5550 auto const offerID =
5551 createSellOffer(minter, nftID, gwXAU(1000));
5552 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5555 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5558 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5560 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5562 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5565 expectInitialState();
5570 reinitializeTrustLineBalances();
5572 auto const nftID = mintNFT(minter);
5573 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5576 auto const offerID =
5577 createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER});
5578 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5581 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5584 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5586 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5588 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5591 expectInitialState();
5596 reinitializeTrustLineBalances();
5597 auto const nftID = mintNFT(minter);
5598 auto const offerID =
5599 createSellOffer(minter, nftID, gwXAU(5000));
5600 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5603 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5606 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5608 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5610 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5613 expectInitialState();
5618 reinitializeTrustLineBalances();
5620 auto const nftID = mintNFT(minter);
5621 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5624 auto const offerID =
5625 createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER});
5626 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5629 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5632 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5634 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5636 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5639 expectInitialState();
5645 reinitializeTrustLineBalances();
5646 auto const nftID = mintNFT(gw);
5647 auto const offerID = createSellOffer(gw, nftID, gwXAU(1000));
5648 env(token::acceptSellOffer(buyer, offerID));
5651 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5652 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5658 reinitializeTrustLineBalances();
5660 auto const nftID = mintNFT(gw);
5661 auto const offerID =
5662 createBuyOffer(buyer, gw, nftID, gwXAU(1000));
5663 env(token::acceptBuyOffer(gw, offerID));
5666 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5667 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5673 reinitializeTrustLineBalances();
5674 auto const nftID = mintNFT(gw);
5675 auto const offerID = createSellOffer(gw, nftID, gwXAU(2000));
5676 env(token::acceptSellOffer(buyer, offerID),
5679 expectInitialState();
5685 reinitializeTrustLineBalances();
5686 auto const nftID = mintNFT(gw);
5687 auto const offerID =
5688 createBuyOffer(buyer, gw, nftID, gwXAU(2000));
5689 env(token::acceptBuyOffer(gw, offerID),
5692 expectInitialState();
5697 reinitializeTrustLineBalances();
5698 auto const nftID = mintNFT(minter);
5699 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5700 env(token::acceptSellOffer(buyer, offerID),
5703 expectInitialState();
5708 reinitializeTrustLineBalances();
5709 auto const nftID = mintNFT(minter);
5710 auto const offerID = createBuyOffer(
5716 env(token::acceptBuyOffer(minter, offerID),
5719 expectInitialState();
5725 reinitializeTrustLineBalances();
5726 env(pay(gw, buyer, gwXPB(100)));
5729 auto const nftID = mintNFT(minter);
5730 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5731 env(token::acceptSellOffer(buyer, offerID));
5734 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5735 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5736 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5737 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5743 reinitializeTrustLineBalances();
5744 env(pay(gw, buyer, gwXPB(100)));
5747 auto const nftID = mintNFT(minter);
5748 auto const offerID =
5749 createBuyOffer(buyer, minter, nftID, gwXPB(10));
5750 env(token::acceptBuyOffer(minter, offerID));
5753 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5754 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5755 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5756 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5761 reinitializeTrustLineBalances();
5765 auto const nftID = mintNFT(minter, 3000);
5766 auto const primaryOfferID =
5767 createSellOffer(minter, nftID, XRP(0));
5768 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5772 auto const offerID =
5773 createSellOffer(secondarySeller, nftID, gwXAU(1000));
5774 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5777 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5780 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5781 expectInitialState();
5784 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5786 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5787 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5788 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5790 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5791 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5797 reinitializeTrustLineBalances();
5801 auto const nftID = mintNFT(minter, 3000);
5802 auto const primaryOfferID =
5803 createSellOffer(minter, nftID, XRP(0));
5804 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5808 auto const offerID =
5809 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000));
5810 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5813 env(token::acceptBuyOffer(secondarySeller, offerID),
5817 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5818 expectInitialState();
5821 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5823 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5824 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5825 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5827 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5828 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5834 reinitializeTrustLineBalances();
5838 auto const nftID = mintNFT(minter, 3000);
5839 auto const primaryOfferID =
5840 createSellOffer(minter, nftID, XRP(0));
5841 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5845 auto const offerID =
5846 createSellOffer(secondarySeller, nftID, gwXAU(900));
5847 env(token::acceptSellOffer(buyer, offerID));
5850 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5851 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5852 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5853 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5855 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5856 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5861 reinitializeTrustLineBalances();
5865 auto const nftID = mintNFT(minter, 3000);
5866 auto const primaryOfferID =
5867 createSellOffer(minter, nftID, XRP(0));
5868 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5872 auto const offerID =
5873 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900));
5874 env(token::acceptBuyOffer(secondarySeller, offerID));
5878 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5880 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5882 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5883 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5885 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5886 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5904 reinitializeTrustLineBalances();
5906 auto const nftID = mintNFT(minter);
5907 auto const sellOffer =
5908 createSellOffer(minter, nftID, gwXAU(300));
5909 auto const buyOffer =
5910 createBuyOffer(buyer, minter, nftID, gwXAU(500));
5911 env(token::brokerOffers(broker, buyOffer, sellOffer),
5912 token::brokerFee(gwXAU(100)));
5915 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400));
5916 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5917 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5918 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-400));
5919 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5920 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5938 reinitializeTrustLineBalances();
5942 auto const nftID = mintNFT(minter, 3000);
5943 auto const primaryOfferID =
5944 createSellOffer(minter, nftID, XRP(0));
5945 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5949 auto const sellOffer =
5950 createSellOffer(secondarySeller, nftID, gwXAU(300));
5951 auto const buyOffer =
5952 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500));
5953 env(token::brokerOffers(broker, buyOffer, sellOffer),
5954 token::brokerFee(gwXAU(100)));
5957 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12));
5958 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5959 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(388));
5960 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5961 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-12));
5962 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5964 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-388));
5965 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5987 using namespace test::jtx;
5989 Account
const alice{
"alice"};
5990 Account
const bob{
"bob"};
5991 Account
const broker{
"broker"};
5993 Env env{*
this, features};
5994 env.fund(XRP(10000), alice, bob, broker);
6020 uint256 const bobBuyOfferIndex =
6022 env(token::createOffer(bob, nftId, XRP(5)), token::owner(alice));
6024 uint256 const aliceSellOfferIndex =
6026 env(token::createOffer(alice, nftId, XRP(0)),
6027 token::destination(bob),
6032 env(token::acceptSellOffer(bob, aliceSellOfferIndex));
6039 uint256 const bobSellOfferIndex =
6041 env(token::createOffer(bob, nftId, XRP(4)), txflags(
tfSellNFToken));
6046 BEAST_EXPECT(
nftCount(env, bob) == 1);
6047 auto const bobsPriorBalance = env.balance(bob);
6048 auto const brokersPriorBalance = env.balance(broker);
6049 TER expectTer = features[fixNonFungibleTokensV1_2]
6052 env(token::brokerOffers(broker, bobBuyOfferIndex, bobSellOfferIndex),
6053 token::brokerFee(XRP(1)),
6062 BEAST_EXPECT(
nftCount(env, bob) == 1);
6063 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance - XRP(1));
6065 env.balance(broker) ==
6066 brokersPriorBalance + XRP(1) - drops(10));
6072 BEAST_EXPECT(
nftCount(env, bob) == 1);
6073 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance);
6075 env.balance(broker) == brokersPriorBalance - drops(10));
6082 using namespace test::jtx;
6087 auto openLedgerSeq = [](Env& env) {
return env.current()->seq(); };
6092 auto incLgrSeqForAcctDel = [&](Env& env, Account
const& acct) {
6093 int const delta = [&]() ->
int {
6094 if (env.seq(acct) + 255 > openLedgerSeq(env))
6095 return env.seq(acct) - openLedgerSeq(env) + 255;
6098 BEAST_EXPECT(delta >= 0);
6099 for (
int i = 0; i < delta; ++i)
6101 BEAST_EXPECT(openLedgerSeq(env) == env.seq(acct) + 255);
6107 auto incLgrSeqForFixNftRemint = [&](Env& env, Account
const& acct) {
6109 auto const deletableLgrSeq =
6110 (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) +
6111 (*env.le(acct))[sfMintedNFTokens] + 255;
6113 if (deletableLgrSeq > openLedgerSeq(env))
6114 delta = deletableLgrSeq - openLedgerSeq(env);
6116 BEAST_EXPECT(delta >= 0);
6117 for (
int i = 0; i < delta; ++i)
6119 BEAST_EXPECT(openLedgerSeq(env) == deletableLgrSeq);
6125 Env env{*
this, features};
6126 Account
const alice(
"alice");
6127 Account
const becky(
"becky");
6129 env.fund(XRP(10000), alice, becky);
6133 uint256 const prevNFTokenID = token::getNextID(env, alice, 0u);
6134 env(token::mint(alice));
6136 env(token::burn(alice, prevNFTokenID));
6140 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 1);
6143 incLgrSeqForAcctDel(env, alice);
6147 auto const acctDelFee{drops(env.current()->fees().increment)};
6148 env(acctdelete(alice, becky), fee(acctDelFee));
6153 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6154 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6157 env.fund(XRP(10000), alice);
6161 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6162 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6163 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6166 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6167 env(token::mint(alice));
6171 env(token::burn(alice, remintNFTokenID));
6174 if (features[fixNFTokenRemint])
6176 BEAST_EXPECT(remintNFTokenID != prevNFTokenID);
6179 BEAST_EXPECT(remintNFTokenID == prevNFTokenID);
6185 Env env{*
this, features};
6186 Account
const alice(
"alice");
6187 Account
const becky(
"becky");
6188 Account
const minter{
"minter"};
6190 env.fund(XRP(10000), alice, becky, minter);
6194 env(token::setMinter(alice, minter));
6200 for (
int i = 0; i < 500; i++)
6202 uint256 const nftokenID = token::getNextID(env, alice, 0u);
6204 env(token::mint(minter), token::issuer(alice));
6209 for (
auto const nftokenID : nftIDs)
6211 env(token::burn(minter, nftokenID));
6217 incLgrSeqForAcctDel(env, alice);
6221 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6222 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6224 auto const acctDelFee{drops(env.current()->fees().increment)};
6226 if (!features[fixNFTokenRemint])
6229 env(acctdelete(alice, becky), fee(acctDelFee));
6231 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6234 env.fund(XRP(10000), alice);
6238 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6239 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6240 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6244 uint256 const remintNFTokenID =
6245 token::getNextID(env, alice, 0u);
6246 env(token::mint(alice));
6250 env(token::burn(alice, remintNFTokenID));
6259 else if (features[fixNFTokenRemint])
6268 env(acctdelete(alice, becky),
6274 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6279 incLgrSeqForFixNftRemint(env, alice);
6282 env(acctdelete(alice, becky), fee(acctDelFee));
6287 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6288 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6291 env.fund(XRP(10000), alice);
6295 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6296 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6297 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6301 uint256 const remintNFTokenID =
6302 token::getNextID(env, alice, 0u);
6303 env(token::mint(alice));
6307 env(token::burn(alice, remintNFTokenID));
6321 Env env{*
this, features};
6323 Account
const alice{
"alice"};
6324 Account
const becky{
"becky"};
6325 env.fund(XRP(10000), alice, becky);
6332 env(ticket::create(alice, 100));
6336 BEAST_EXPECT(ownerCount(env, alice) == 100);
6341 for (
int i = 0; i < 50; i++)
6343 nftIDs.
push_back(token::getNextID(env, alice, 0u));
6344 env(token::mint(alice, 0u), ticket::use(aliceTicketSeq++));
6349 for (
auto const nftokenID : nftIDs)
6351 env(token::burn(alice, nftokenID),
6352 ticket::use(aliceTicketSeq++));
6360 incLgrSeqForAcctDel(env, alice);
6364 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6365 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6367 auto const acctDelFee{drops(env.current()->fees().increment)};
6369 if (!features[fixNFTokenRemint])
6372 env(acctdelete(alice, becky), fee(acctDelFee));
6377 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6378 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6381 env.fund(XRP(10000), alice);
6385 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6386 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6387 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6391 uint256 const remintNFTokenID =
6392 token::getNextID(env, alice, 0u);
6393 env(token::mint(alice));
6397 env(token::burn(alice, remintNFTokenID));
6406 else if (features[fixNFTokenRemint])
6415 env(acctdelete(alice, becky),
6421 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6426 incLgrSeqForFixNftRemint(env, alice);
6429 env(acctdelete(alice, becky), fee(acctDelFee));
6434 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6435 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6438 env.fund(XRP(10000), alice);
6442 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6443 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6444 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6448 uint256 const remintNFTokenID =
6449 token::getNextID(env, alice, 0u);
6450 env(token::mint(alice));
6454 env(token::burn(alice, remintNFTokenID));
6470 if (features[fixNFTokenRemint])
6472 Env env{*
this, features};
6473 Account
const alice(
"alice");
6474 Account
const becky(
"becky");
6475 Account
const minter{
"minter"};
6477 env.fund(XRP(10000), alice, becky, minter);
6481 env(token::setMinter(alice, minter));
6486 env(ticket::create(minter, 100));
6490 BEAST_EXPECT(ownerCount(env, minter) == 100);
6495 for (
int i = 0; i < 50; i++)
6497 uint256 const nftokenID = token::getNextID(env, alice, 0u);
6499 env(token::mint(minter),
6500 token::issuer(alice),
6501 ticket::use(minterTicketSeq++));
6506 for (
auto const nftokenID : nftIDs)
6508 env(token::burn(minter, nftokenID),
6509 ticket::use(minterTicketSeq++));
6517 incLgrSeqForAcctDel(env, alice);
6521 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6522 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6531 auto const acctDelFee{drops(env.current()->fees().increment)};
6532 env(acctdelete(alice, becky), fee(acctDelFee), ter(
tecTOO_SOON));
6536 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6541 incLgrSeqForFixNftRemint(env, alice);
6544 env(acctdelete(alice, becky), fee(acctDelFee));
6549 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6550 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6553 env.fund(XRP(10000), alice);
6557 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6558 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6559 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6563 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6564 env(token::mint(alice));
6568 env(token::burn(alice, remintNFTokenID));
6582 testcase(
"NFTokenMint with Create NFTokenOffer");
6584 using namespace test::jtx;
6586 if (!features[featureNFTokenMintOffer])
6588 Env env{*
this, features};
6589 Account
const alice(
"alice");
6590 Account
const buyer(
"buyer");
6592 env.fund(XRP(10000), alice, buyer);
6595 env(token::mint(alice),
6596 token::amount(XRP(10000)),
6600 env(token::mint(alice),
6601 token::destination(
"buyer"),
6605 env(token::mint(alice),
6615 Env env{*
this, features};
6616 Account
const alice(
"alice");
6617 Account
const buyer{
"buyer"};
6618 Account
const gw(
"gw");
6619 Account
const issuer(
"issuer");
6620 Account
const minter(
"minter");
6621 Account
const bob(
"bob");
6622 IOU
const gwAUD(gw[
"AUD"]);
6624 env.fund(XRP(10000), alice, buyer, gw, issuer, minter);
6629 env(token::mint(alice),
6630 token::destination(buyer),
6633 BEAST_EXPECT(ownerCount(env, alice) == 0);
6636 env(token::mint(alice),
6640 BEAST_EXPECT(ownerCount(env, buyer) == 0);
6646 env(token::mint(alice),
6647 token::amount(XRP(1000)),
6648 token::destination(alice),
6651 BEAST_EXPECT(ownerCount(env, alice) == 0);
6655 env(token::mint(alice),
6656 token::amount(XRP(1000)),
6657 token::destination(Account(
"demon")),
6660 BEAST_EXPECT(ownerCount(env, alice) == 0);
6665 env(token::mint(alice),
6666 token::amount(XRP(1000)),
6667 token::expiration(0),
6670 BEAST_EXPECT(ownerCount(env, alice) == 0);
6673 env(token::mint(alice),
6674 token::amount(XRP(1000)),
6678 BEAST_EXPECT(ownerCount(env, alice) == 0);
6683 env(token::mint(alice),
6684 token::amount(buyer[
"USD"](1)),
6687 env(token::mint(alice),
6688 token::amount(buyer[
"USD"](0)),
6691 BEAST_EXPECT(ownerCount(env, alice) == 0);
6694 env(token::mint(alice),
6695 token::amount(gwAUD(1000)),
6700 BEAST_EXPECT(ownerCount(env, alice) == 0);
6705 env(token::mint(gw),
6706 token::amount(gwAUD(1000)),
6708 token::xferFee(10));
6717 env(token::mint(alice),
6718 token::amount(gwAUD(1000)),
6723 BEAST_EXPECT(ownerCount(env, alice) == 0);
6726 env(token::mint(alice),
6727 token::amount(gwAUD(1000)),
6730 BEAST_EXPECT(ownerCount(env, alice) == 0);
6739 auto const acctReserve =
6740 env.current()->fees().accountReserve(0);
6741 auto const incReserve = env.current()->fees().increment;
6743 env.fund(acctReserve + incReserve, bob);
6747 env(token::mint(bob),
6748 token::amount(XRP(0)),
6753 env(pay(env.master, bob, incReserve + drops(10)));
6755 env(token::mint(bob), token::amount(XRP(0)));
6759 env(pay(env.master, bob, drops(10)));
6761 env(token::mint(bob),
6762 token::amount(XRP(0)),
6767 env(pay(env.master, bob, incReserve + drops(10)));
6769 env(token::mint(bob), token::amount(XRP(0)));
6774 BEAST_EXPECT(ownerCount(env, alice) == 0);
6775 env(token::mint(alice), token::amount(XRP(10)));
6776 BEAST_EXPECT(ownerCount(env, alice) == 2);
6780 env(token::mint(alice),
6781 token::amount(XRP(10)),
6782 token::destination(buyer),
6783 token::expiration(
lastClose(env) + 25));
6787 env(trust(alice, gwAUD(1000)));
6789 env(token::mint(alice),
6790 token::amount(gwAUD(1)),
6791 token::destination(buyer),
6794 token::xferFee(10));
6798 env(token::mint(alice),
6799 token::amount(XRP(10)),
6800 token::destination(buyer),
6801 token::expiration(
lastClose(env) + 25));
6802 uint256 const offerAliceSellsToBuyer =
6804 env(token::cancelOffer(alice, {offerAliceSellsToBuyer}));
6808 env(token::mint(buyer),
6809 token::amount(XRP(10)),
6810 token::destination(alice),
6811 token::expiration(
lastClose(env) + 25));
6812 uint256 const offerBuyerSellsToAlice =
6814 env(token::cancelOffer(alice, {offerBuyerSellsToAlice}));
6817 env(token::setMinter(issuer, minter));
6821 BEAST_EXPECT(ownerCount(env, minter) == 0);
6822 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6823 env(token::mint(minter),
6824 token::issuer(issuer),
6825 token::amount(drops(1)));
6827 BEAST_EXPECT(ownerCount(env, minter) == 2);
6828 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6833 for (
auto const& tweakedFeatures :
6834 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
6835 features | fixNFTokenNegOffer})
6837 Env env{*
this, tweakedFeatures};
6838 Account
const alice(
"alice");
6840 env.fund(XRP(1000000), alice);
6842 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
6847 env(token::mint(alice),
6848 token::amount(XRP(-2)),
6849 ter(offerCreateTER));
6868 testcase(
"Test synthetic fields from JSON response");
6870 using namespace test::jtx;
6872 Account
const alice{
"alice"};
6873 Account
const bob{
"bob"};
6874 Account
const broker{
"broker"};
6876 Env env{*
this, features};
6877 env.fund(XRP(10000), alice, bob, broker);
6883 auto verifyNFTokenID = [&](
uint256 const& actualNftID) {
6890 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6893 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_id)))
6900 BEAST_EXPECT(nftID == actualNftID);
6905 auto verifyNFTokenIDsInCancelOffer =
6913 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6916 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_ids)))
6922 meta[jss::nftoken_ids].begin(),
6923 meta[jss::nftoken_ids].end(),
6927 BEAST_EXPECT(nftID.
parseHex(
id.asString()));
6933 std::sort(actualNftIDs.begin(), actualNftIDs.end());
6936 BEAST_EXPECT(metaIDs.
size() == actualNftIDs.size());
6940 for (
size_t i = 0; i < metaIDs.
size(); ++i)
6941 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
6946 auto verifyNFTokenOfferID = [&](
uint256 const& offerID) {
6953 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6956 if (!BEAST_EXPECT(meta.
isMember(jss::offer_id)))
6961 BEAST_EXPECT(metaOfferID == offerID);
6972 verifyNFTokenID(nftId1);
6978 verifyNFTokenID(nftId2);
6983 uint256 const aliceOfferIndex1 =
6985 env(token::createOffer(alice, nftId1, drops(1)),
6988 verifyNFTokenOfferID(aliceOfferIndex1);
6990 uint256 const aliceOfferIndex2 =
6992 env(token::createOffer(alice, nftId2, drops(1)),
6995 verifyNFTokenOfferID(aliceOfferIndex2);
7000 env(token::cancelOffer(
7001 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7003 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
7007 auto const bobBuyOfferIndex =
7009 env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice));
7011 verifyNFTokenOfferID(bobBuyOfferIndex);
7015 env(token::acceptBuyOffer(alice, bobBuyOfferIndex));
7017 verifyNFTokenID(nftId1);
7027 verifyNFTokenID(nftId);
7030 uint256 const offerAliceToBroker =
7032 env(token::createOffer(alice, nftId, drops(1)),
7033 token::destination(broker),
7036 verifyNFTokenOfferID(offerAliceToBroker);
7039 uint256 const offerBobToBroker =
7041 env(token::createOffer(bob, nftId, drops(1)), token::owner(alice));
7043 verifyNFTokenOfferID(offerBobToBroker);
7046 env(token::brokerOffers(
7047 broker, offerBobToBroker, offerAliceToBroker));
7049 verifyNFTokenID(nftId);
7060 verifyNFTokenID(nftId);
7063 uint256 const aliceOfferIndex1 =
7065 env(token::createOffer(alice, nftId, drops(1)),
7068 verifyNFTokenOfferID(aliceOfferIndex1);
7070 uint256 const aliceOfferIndex2 =
7072 env(token::createOffer(alice, nftId, drops(1)),
7075 verifyNFTokenOfferID(aliceOfferIndex2);
7079 env(token::cancelOffer(
7080 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7082 verifyNFTokenIDsInCancelOffer({nftId});
7085 if (features[featureNFTokenMintOffer])
7087 uint256 const aliceMintWithOfferIndex1 =
7089 env(token::mint(alice), token::amount(XRP(0)));
7091 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
7098 testcase(
"Test buyer reserve when accepting an offer");
7100 using namespace test::jtx;
7113 uint256 const sellOfferIndex =
7115 env(token::createOffer(acct, nftId, amt), txflags(
tfSellNFToken));
7118 return sellOfferIndex;
7125 Account
const alice{
"alice"};
7126 Account
const bob{
"bob"};
7128 Env env{*
this, features};
7129 auto const acctReserve = env.
current()->fees().accountReserve(0);
7130 auto const incReserve = env.
current()->fees().increment;
7132 env.
fund(XRP(10000), alice);
7136 env.
fund(acctReserve, bob);
7140 auto const sellOfferIndex =
7141 mintAndCreateSellOffer(env, alice, XRP(0));
7144 BEAST_EXPECT(ownerCount(env, bob) == 0);
7148 if (!features[fixNFTokenReserve])
7151 env(token::acceptSellOffer(bob, sellOfferIndex));
7155 BEAST_EXPECT(ownerCount(env, bob) == 1);
7170 env(token::acceptSellOffer(bob, sellOfferIndex),
7177 BEAST_EXPECT(ownerCount(env, bob) == 0);
7182 env(pay(env.
master, bob, incReserve + drops(10)));
7187 env(token::acceptSellOffer(bob, sellOfferIndex),
7193 env(pay(env.
master, bob, drops(20)));
7197 env(token::acceptSellOffer(bob, sellOfferIndex));
7200 BEAST_EXPECT(ownerCount(env, bob) == 1);
7207 Account
const alice{
"alice"};
7208 Account
const bob{
"bob"};
7210 Env env{*
this, features};
7211 auto const acctReserve = env.
current()->fees().accountReserve(0);
7212 auto const incReserve = env.
current()->fees().increment;
7214 env.
fund(XRP(10000), alice);
7217 env.
fund(acctReserve + XRP(1), bob);
7220 if (!features[fixNFTokenReserve])
7223 for (
size_t i = 0; i < 200; i++)
7226 auto const sellOfferIndex =
7227 mintAndCreateSellOffer(env, alice, XRP(0));
7230 env(token::acceptSellOffer(bob, sellOfferIndex));
7237 auto const sellOfferIndex1 =
7238 mintAndCreateSellOffer(env, alice, XRP(0));
7242 env(token::acceptSellOffer(bob, sellOfferIndex1),
7247 env(pay(env.
master, bob, drops(incReserve)));
7250 BEAST_EXPECT(ownerCount(env, bob) == 0);
7253 env(token::acceptSellOffer(bob, sellOfferIndex1));
7256 BEAST_EXPECT(ownerCount(env, bob) == 1);
7260 for (
size_t i = 0; i < 31; i++)
7263 auto const sellOfferIndex =
7264 mintAndCreateSellOffer(env, alice, XRP(0));
7268 env(token::acceptSellOffer(bob, sellOfferIndex));
7272 BEAST_EXPECT(ownerCount(env, bob) == 1);
7276 auto const sellOfferIndex33 =
7277 mintAndCreateSellOffer(env, alice, XRP(0));
7281 env(token::acceptSellOffer(bob, sellOfferIndex33),
7286 env(pay(env.
master, bob, drops(incReserve)));
7291 env(token::acceptSellOffer(bob, sellOfferIndex33));
7294 BEAST_EXPECT(ownerCount(env, bob) == 2);
7304 Account
const alice{
"alice"};
7305 Account
const bob{
"bob"};
7307 Env env{*
this, features};
7308 auto const acctReserve = env.
current()->fees().accountReserve(0);
7309 auto const incReserve = env.
current()->fees().increment;
7311 env.
fund(XRP(10000), alice);
7317 env.
fund(acctReserve + incReserve + XRP(1), bob);
7328 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
7334 env(token::acceptBuyOffer(alice, buyOfferIndex),
7339 env(pay(env.
master, bob, drops(10)));
7343 env(token::acceptBuyOffer(alice, buyOfferIndex));
7353 Account
const alice{
"alice"};
7354 Account
const bob{
"bob"};
7355 Account
const broker{
"broker"};
7357 Env env{*
this, features};
7358 auto const acctReserve = env.
current()->fees().accountReserve(0);
7359 auto const incReserve = env.
current()->fees().increment;
7361 env.
fund(XRP(10000), alice, broker);
7366 env.
fund(acctReserve + incReserve + XRP(1), bob);
7376 uint256 const offerAliceToBroker =
7378 env(token::createOffer(alice, nftId, XRP(1)),
7379 token::destination(broker),
7384 uint256 const offerBobToBroker =
7386 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
7393 env(token::brokerOffers(
7394 broker, offerBobToBroker, offerAliceToBroker),
7399 env(pay(env.
master, bob, drops(10)));
7403 env(token::brokerOffers(
7404 broker, offerBobToBroker, offerAliceToBroker));
7412 testcase(
"Test fix unasked for auto-trustline.");
7414 using namespace test::jtx;
7416 Account
const issuer{
"issuer"};
7417 Account
const becky{
"becky"};
7418 Account
const cheri{
"cheri"};
7419 Account
const gw(
"gw");
7420 IOU
const gwAUD(gw[
"AUD"]);
7450 features - fixRemoveNFTokenAutoTrustLine;
7452 {localFeatures - fixEnforceNFTokenTrustline,
7453 localFeatures | fixEnforceNFTokenTrustline})
7455 Env env{*
this, feats};
7456 env.fund(XRP(1000), issuer, becky, cheri, gw);
7460 env(trust(becky, gwAUD(1000)));
7461 env(trust(cheri, gwAUD(1000)));
7463 env(pay(gw, cheri, gwAUD(500)));
7468 uint256 const nftAutoTrustID{token::getNextID(
7470 env(token::mint(issuer, 0u),
7471 token::xferFee(xferFee),
7475 uint256 const nftNoAutoTrustID{
7477 env(token::mint(issuer, 0u),
7478 token::xferFee(xferFee),
7484 uint256 const beckyBuyOfferIndex1 =
7486 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
7487 token::owner(issuer));
7489 uint256 const beckyBuyOfferIndex2 =
7491 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
7492 token::owner(issuer));
7495 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1));
7496 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2));
7501 uint256 const beckyAutoTrustOfferIndex =
7503 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)),
7509 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
7516 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7517 env(trust(issuer, gwAUD(1000)));
7519 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7521 uint256 const beckyNoAutoTrustOfferIndex =
7523 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
7528 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7529 env(trust(issuer, gwAUD(0)));
7531 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7535 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7539 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7540 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7543 env(pay(issuer, gw, gwAUD(5)));
7545 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7549 if (feats[fixEnforceNFTokenTrustline])
7554 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex),
7560 env(trust(issuer, gwAUD(1000)));
7562 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7564 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7571 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7574 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7575 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7582 testcase(
"Test fix NFT issuer is IOU issuer");
7584 using namespace test::jtx;
7586 Account
const issuer{
"issuer"};
7587 Account
const becky{
"becky"};
7588 Account
const cheri{
"cheri"};
7589 IOU
const isISU(issuer[
"ISU"]);
7621 features - fixRemoveNFTokenAutoTrustLine;
7623 Env env{*
this, localFeatures};
7624 env.fund(XRP(1000), issuer, becky, cheri);
7628 env(trust(becky, isISU(1000)));
7629 env(trust(cheri, isISU(1000)));
7631 env(pay(issuer, cheri, isISU(500)));
7636 uint256 const nftAutoTrustID{token::getNextID(
7638 env(token::mint(issuer, 0u),
7639 token::xferFee(xferFee),
7643 uint256 const nftNoAutoTrustID{
7645 env(token::mint(issuer, 0u),
7646 token::xferFee(xferFee),
7652 uint256 const beckyBuyOfferIndex1 =
7654 env(token::createOffer(becky, nftAutoTrustID, drops(1)),
7655 token::owner(issuer));
7657 uint256 const beckyBuyOfferIndex2 =
7659 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)),
7660 token::owner(issuer));
7663 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex1));
7664 env(token::acceptBuyOffer(issuer, beckyBuyOfferIndex2));
7670 if (!localFeatures[featureNFTokenMintOffer])
7675 env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)),
7686 uint256 const beckyAutoTrustOfferIndex =
7688 env(token::createOffer(becky, nftAutoTrustID, isISU(100)),
7693 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7698 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7699 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7705 uint256 const beckyNoAutoTrustOfferIndex =
7707 env(token::createOffer(becky, nftNoAutoTrustID, isISU(100)),
7710 uint256 const beckyAutoTrustOfferIndex =
7712 env(token::createOffer(becky, nftAutoTrustID, isISU(100)),
7718 env(token::acceptSellOffer(cheri, beckyAutoTrustOfferIndex));
7723 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7724 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7726 env(token::acceptSellOffer(cheri, beckyNoAutoTrustOfferIndex));
7732 BEAST_EXPECT(env.balance(becky, isISU) == isISU(190));
7733 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(300));
7742 using namespace test::jtx;
7744 Account
const issuer{
"issuer"};
7745 Account
const alice(
"alice");
7746 Account
const bob(
"bob");
7748 bool const modifyEnabled = features[featureDynamicNFT];
7752 Env env{*
this, features};
7753 env.fund(XRP(10000), issuer);
7756 auto const expectedTer =
7758 env(token::mint(issuer, 0u), txflags(
tfMutable), ter(expectedTer));
7762 Env env{*
this, features};
7763 env.fund(XRP(10000), issuer);
7770 env(token::mint(issuer, 0u), txflags(
tfMutable));
7772 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7773 env(token::modify(issuer, nftId));
7774 BEAST_EXPECT(ownerCount(env, issuer) == 1);
7778 env(token::mint(issuer, 0u));
7780 env(token::modify(issuer, nftId), ter(
temDISABLED));
7788 Env env{*
this, features};
7789 env.fund(XRP(10000), issuer);
7793 env(token::mint(issuer, 0u), txflags(
tfMutable));
7797 env(token::modify(issuer, nftId),
7803 env(token::modify(issuer, nftId),
7804 txflags(0x00000001),
7808 env(token::modify(issuer, nftId),
7809 token::owner(issuer),
7814 env(token::modify(issuer, nftId),
7820 env(token::modify(issuer, nftId),
7826 Env env{*
this, features};
7827 env.fund(XRP(10000), issuer, alice, bob);
7833 token::getNextID(env, issuer, 0u,
tfMutable)};
7836 env(token::modify(issuer, nftIDNotExists), ter(
tecNO_ENTRY));
7841 uint256 const nftIDNotModifiable{
7842 token::getNextID(env, issuer, 0u)};
7843 env(token::mint(issuer, 0u));
7846 env(token::modify(issuer, nftIDNotModifiable),
7853 token::getNextID(env, issuer, 0u,
tfMutable)};
7854 env(token::mint(issuer, 0u), txflags(
tfMutable));
7857 env(token::modify(bob, nftId),
7858 token::owner(issuer),
7862 env(token::setMinter(issuer, alice));
7865 env(token::modify(bob, nftId),
7866 token::owner(issuer),
7872 Env env{*
this, features};
7873 env.fund(XRP(10000), issuer, alice, bob);
7878 env(token::mint(issuer, 0u), txflags(
tfMutable), token::uri(
"uri"));
7885 Env env{*
this, features};
7886 env.fund(XRP(10000), issuer, alice, bob);
7890 auto accountNFTs = [&env](Account
const& acct) {
7892 params[jss::account] = acct.human();
7893 params[jss::type] =
"state";
7895 env.rpc(
"json",
"account_nfts",
to_string(params));
7896 return response[jss::result][jss::account_nfts];
7900 auto checkURI = [&accountNFTs,
this](
7901 Account
const& acct,
7904 auto const nfts = accountNFTs(acct);
7905 if (nfts.size() == 1)
7910 text <<
"checkURI: unexpected NFT count on line " << line;
7911 fail(text.
str(), __FILE__, line);
7917 if (!nfts[0u].isMember(sfURI.jsonName))
7922 text <<
"checkURI: unexpected URI present on line "
7924 fail(text.
str(), __FILE__, line);
7934 text <<
"checkURI: unexpected URI contents on line "
7936 fail(text.
str(), __FILE__, line);
7943 env(token::mint(issuer, 0u), txflags(
tfMutable), token::uri(
"uri"));
7945 checkURI(issuer,
"uri", __LINE__);
7948 env(token::modify(issuer, nftId), token::uri(
"new_uri"));
7950 checkURI(issuer,
"new_uri", __LINE__);
7953 env(token::modify(issuer, nftId));
7955 checkURI(issuer,
nullptr, __LINE__);
7958 env(token::modify(issuer, nftId), token::uri(
"uri"));
7960 checkURI(issuer,
"uri", __LINE__);
7965 env(token::createOffer(issuer, nftId, XRP(0)),
7968 env(token::acceptSellOffer(alice, offerID));
7970 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7971 BEAST_EXPECT(ownerCount(env, alice) == 1);
7972 checkURI(alice,
"uri", __LINE__);
7975 env(token::modify(alice, nftId),
7976 token::uri(
"new_uri"),
7979 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7980 BEAST_EXPECT(ownerCount(env, alice) == 1);
7981 checkURI(alice,
"uri", __LINE__);
7983 env(token::modify(issuer, nftId),
7984 token::owner(alice),
7985 token::uri(
"new_uri"));
7987 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7988 BEAST_EXPECT(ownerCount(env, alice) == 1);
7989 checkURI(alice,
"new_uri", __LINE__);
7991 env(token::modify(issuer, nftId), token::owner(alice));
7993 checkURI(alice,
nullptr, __LINE__);
7995 env(token::modify(issuer, nftId),
7996 token::owner(alice),
7999 checkURI(alice,
"uri", __LINE__);
8002 env(token::setMinter(issuer, bob));
8004 env(token::modify(bob, nftId),
8005 token::owner(alice),
8006 token::uri(
"new_uri"));
8008 checkURI(alice,
"new_uri", __LINE__);
8010 env(token::modify(bob, nftId), token::owner(alice));
8012 checkURI(alice,
nullptr, __LINE__);
8014 env(token::modify(bob, nftId),
8015 token::owner(alice),
8018 checkURI(alice,
"uri", __LINE__);
8066 using namespace test::jtx;
8071 all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8072 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8074 fixNFTokenRemint - fixNFTokenReserve - featureNFTokenMintOffer -
8076 all - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8077 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8078 all - fixNFTokenRemint - fixNFTokenReserve -
8079 featureNFTokenMintOffer - featureDynamicNFT,
8080 all - fixNFTokenReserve - featureNFTokenMintOffer -
8082 all - featureNFTokenMintOffer - featureDynamicNFT,
8083 all - featureDynamicNFT,
8086 if (BEAST_EXPECT(instance < feats.size()))
8090 BEAST_EXPECT(!last || instance == feats.size() - 1);
8163BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, tx,
ripple, 2);
8164BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx,
ripple, 2);
8165BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx,
ripple, 2);
8166BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx,
ripple, 2);
8167BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx,
ripple, 2);
8168BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx,
ripple, 2);
8169BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx,
ripple, 2);
8170BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx,
ripple, 2);
T back_inserter(T... args)
UInt size() const
Number of values in array or object.
Value & append(const Value &value)
Append value to array at the end.
Value removeMember(const char *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
bool isMember(const char *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
void pass()
Record a successful test condition.
testcase_t testcase
Memberspace for declaring test cases.
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
void fail(String const &reason, char const *file, int line)
Record a failure.
void run() override
Runs the suite.
void testCreateOfferDestination(FeatureBitset features)
void testFixNFTokenRemint(FeatureBitset features)
std::uint32_t lastClose(test::jtx::Env &env)
void testMintInvalid(FeatureBitset features)
void testAcceptOfferInvalid(FeatureBitset features)
void testMintFlagTransferable(FeatureBitset features)
void testCancelOffers(FeatureBitset features)
void testNFTIssuerIsIOUIssuer(FeatureBitset features)
void testMintTaxon(FeatureBitset features)
void testNFTokenModify(FeatureBitset features)
void testNFTokenDeleteAccount(FeatureBitset features)
void testUnaskedForAutoTrustline(FeatureBitset features)
FeatureBitset const disallowIncoming
void testFixNFTokenBuyerReserve(FeatureBitset features)
void testFixNFTokenNegOffer(FeatureBitset features)
void run(std::uint32_t instance, bool last=false)
void testWithFeats(FeatureBitset features)
void testNFTokenOfferOwner(FeatureBitset features)
void testNFTokenWithTickets(FeatureBitset features)
void testCreateOfferDestinationDisallowIncoming(FeatureBitset features)
void testCreateOfferExpiration(FeatureBitset features)
void testMintMaxTokens(FeatureBitset features)
void testMintFlagCreateTrustLine(FeatureBitset features)
void testMintTransferFee(FeatureBitset features)
void testTxJsonMetaFields(FeatureBitset features)
void testNftXxxOffers(FeatureBitset features)
void testEnabled(FeatureBitset features)
void testMintURI(FeatureBitset features)
void testCancelTooManyOffers(FeatureBitset features)
void testMintFlagBurnable(FeatureBitset features)
void testMintFlagOnlyXRP(FeatureBitset features)
void testMintReserve(FeatureBitset features)
static std::uint32_t nftCount(test::jtx::Env &env, test::jtx::Account const &acct)
static std::uint32_t ticketCount(test::jtx::Env const &env, test::jtx::Account const &acct)
void testBrokeredSaleToSelf(FeatureBitset features)
void testIOUWithTransferFee(FeatureBitset features)
static std::uint32_t burnedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
void testCreateOfferInvalid(FeatureBitset features)
static std::uint32_t mintedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
void testCancelOfferInvalid(FeatureBitset features)
void testBrokeredAccept(FeatureBitset features)
void testFeatMintWithOffer(FeatureBitset features)
void run() override
Runs the suite.
void testBurnInvalid(FeatureBitset features)
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
Writable ledger view that accumulates state and tx changes.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Json::Value getJson(JsonOptions) const override
static const std::uint64_t cMinValue
static const int cMinOffset
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
A type-safe wrap around standard integral types.
Immutable cryptographic account descriptor.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
T emplace_back(T... args)
@ arrayValue
array value (ordered list)
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Taxon getTaxon(uint256 const &id)
Taxon toTaxon(std::uint32_t i)
std::uint32_t ownerCount(Env const &env, Account const &account)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::enable_if_t<(std::is_same< Byte, unsigned char >::value||std::is_same< Byte, std::uint8_t >::value), Byte > rand_byte()
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
constexpr std::uint32_t const tfOnlyXRP
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer
constexpr std::uint32_t const tfSellNFToken
std::size_t constexpr maxTokenOfferCancelCount
The maximum number of token offers that can be canceled at once.
@ lsfDisallowIncomingNFTokenOffer
std::uint16_t constexpr maxTransferFee
The maximum token transfer fee allowed.
constexpr std::uint32_t const tfBurnable
@ tefNFTOKEN_IS_NOT_TRANSFERABLE
constexpr std::uint32_t const tfTrustLine
std::string strHex(FwdIt begin, FwdIt end)
std::size_t constexpr maxTokenURILength
The maximum length of a URI inside an NFT.
constexpr std::uint32_t tfClearFreeze
@ tecNFTOKEN_OFFER_TYPE_MISMATCH
@ tecNFTOKEN_BUY_SELL_MISMATCH
@ tecMAX_SEQUENCE_REACHED
@ tecINSUFFICIENT_PAYMENT
@ tecINSUFFICIENT_RESERVE
@ tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t const tfMutable
constexpr std::uint32_t const tfTransferable
@ temBAD_NFTOKEN_TRANSFER_FEE
A pair of SHAMap key and LedgerEntryType.