132 using namespace test::jtx;
134 Env env{*
this, features};
135 Account
const alice{
"alice"};
136 Account
const minter{
"minter"};
140 auto const acctReserve = env.current()->fees().reserve;
141 auto const incReserve = env.current()->fees().increment;
142 auto const baseFee = env.current()->fees().base;
144 env.fund(acctReserve, alice, minter);
147 BEAST_EXPECT(env.balance(alice) == acctReserve);
148 BEAST_EXPECT(env.balance(minter) == acctReserve);
149 BEAST_EXPECT(ownerCount(env, alice) == 0);
150 BEAST_EXPECT(ownerCount(env, minter) == 0);
157 BEAST_EXPECT(ownerCount(env, alice) == 0);
162 env(pay(env.master, alice, incReserve + drops(baseFee - 1)));
167 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
180 ss <<
"Wrong " << type <<
" count. Found: " << found <<
"; Expected: " << exp;
181 fail(ss.
str(), __FILE__, line);
184 oneCheck(
"owner", ownerCount(env, alice), owners);
185 oneCheck(
"minted",
mintedCount(env, alice), minted);
186 oneCheck(
"burned",
burnedCount(env, alice), burned);
194 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
197 env(pay(env.master, alice, drops(baseFee + 1)));
201 env(token::mint(alice));
204 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
208 for (
int i = 1; i < 32; ++i)
210 env(token::mint(alice));
211 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
218 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
221 env(pay(env.master, alice, incReserve + drops(baseFee * 33 - 1)));
228 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
231 env(pay(env.master, alice, drops(baseFee + 1)));
235 env(token::mint(alice));
237 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
244 env(token::burn(alice, token::getID(env, alice, 0, seq++)));
246 checkAliceOwnerMintedBurned(((33 - seq) != 0u) ? 1 : 0, 33, seq, __LINE__);
250 env(token::burn(alice, token::getID(env, alice, 197, 5)), ter(
tecNO_ENTRY));
252 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
257 env(token::setMinter(alice, minter));
259 BEAST_EXPECT(env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
263 auto checkMintersOwnerMintedBurned = [&env,
this, &alice, &minter](
280 ss <<
"Wrong " << type <<
" count. Found: " << found
281 <<
"; Expected: " << exp;
282 fail(ss.
str(), __FILE__, line);
285 oneCheck(
"alice owner", ownerCount(env, alice), aliceOwners, line);
286 oneCheck(
"alice minted",
mintedCount(env, alice), aliceMinted, line);
287 oneCheck(
"alice burned",
burnedCount(env, alice), aliceBurned, line);
288 oneCheck(
"minter owner", ownerCount(env, minter), minterOwners, line);
289 oneCheck(
"minter minted",
mintedCount(env, minter), minterMinted, line);
290 oneCheck(
"minter burned",
burnedCount(env, minter), minterBurned, line);
296 env(pay(env.master, minter, incReserve - drops(1)));
298 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
303 env(token::mint(minter),
304 token::issuer(alice),
308 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
311 env(pay(env.master, minter, drops(baseFee + 1)));
315 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
317 checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
321 for (
int i = 1; i < 32; ++i)
323 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
324 checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
329 env(pay(env.master, minter, incReserve + drops(baseFee * 32 - 1)));
334 env(token::mint(minter),
335 token::issuer(alice),
339 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
342 env(pay(env.master, minter, drops(baseFee + 1)));
346 env(token::mint(minter), token::issuer(alice), token::uri(
"uri"));
348 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
353 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
355 checkMintersOwnerMintedBurned(
356 0, 66, nftSeq, ((65 - seq) != 0u) ? 1 : 0, 0, 0, __LINE__);
361 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
363 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
366 env(token::burn(minter, token::getID(env, alice, 2009, 3)), ter(
tecNO_ENTRY));
368 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
556 testcase(
"Invalid NFT offer create");
558 using namespace test::jtx;
560 Env env{*
this, features};
561 Account
const alice{
"alice"};
562 Account
const buyer{
"buyer"};
563 Account
const gw(
"gw");
564 IOU
const gwAUD(gw[
"AUD"]);
569 env.fund(XRP(250), alice, buyer, gw);
571 BEAST_EXPECT(ownerCount(env, alice) == 0);
573 uint256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable, 10);
574 env(token::mint(alice, 0u), txflags(tfTransferable), token::xferFee(10));
576 BEAST_EXPECT(ownerCount(env, alice) == 1);
578 uint256 const nftXrpOnlyID = token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable);
579 env(token::mint(alice, 0), txflags(tfOnlyXRP | tfTransferable));
581 BEAST_EXPECT(ownerCount(env, alice) == 1);
583 uint256 const nftNoXferID = token::getNextID(env, alice, 0);
584 env(token::mint(alice, 0));
586 BEAST_EXPECT(ownerCount(env, alice) == 1);
597 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
601 BEAST_EXPECT(ownerCount(env, buyer) == 0);
604 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
608 BEAST_EXPECT(ownerCount(env, buyer) == 0);
611 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
615 BEAST_EXPECT(ownerCount(env, buyer) == 0);
618 env(token::createOffer(buyer, nftXrpOnlyID, buyer[
"USD"](1)), ter(
temBAD_AMOUNT));
619 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](0)), ter(
temBAD_AMOUNT));
620 env(token::createOffer(buyer, nftXrpOnlyID, drops(0)), ter(
temBAD_AMOUNT));
622 BEAST_EXPECT(ownerCount(env, buyer) == 0);
625 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](1)),
626 token::expiration(0),
629 BEAST_EXPECT(ownerCount(env, buyer) == 0);
633 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)), ter(
temMALFORMED));
635 BEAST_EXPECT(ownerCount(env, buyer) == 0);
638 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
640 txflags(tfSellNFToken),
643 BEAST_EXPECT(ownerCount(env, alice) == 1);
646 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
650 BEAST_EXPECT(ownerCount(env, alice) == 1);
653 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
654 token::destination(alice),
655 txflags(tfSellNFToken),
658 BEAST_EXPECT(ownerCount(env, alice) == 1);
661 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
662 token::destination(Account(
"demon")),
663 txflags(tfSellNFToken),
666 BEAST_EXPECT(ownerCount(env, alice) == 1);
672 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
677 BEAST_EXPECT(ownerCount(env, buyer) == 0);
680 env(token::createOffer(buyer, token::getID(env, alice, 0, 1), XRP(1000)),
684 BEAST_EXPECT(ownerCount(env, buyer) == 0);
687 env(token::createOffer(alice, token::getID(env, alice, 0, 1), XRP(1000)),
688 txflags(tfSellNFToken),
691 BEAST_EXPECT(ownerCount(env, buyer) == 0);
694 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
698 BEAST_EXPECT(ownerCount(env, buyer) == 0);
700 env(trust(buyer, gwAUD(1000)));
702 BEAST_EXPECT(ownerCount(env, buyer) == 1);
706 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
710 BEAST_EXPECT(ownerCount(env, buyer) == 1);
713 env(trust(gw, alice[
"AUD"](999), tfSetFreeze));
718 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
722 BEAST_EXPECT(ownerCount(env, buyer) == 1);
725 env(trust(gw, alice[
"AUD"](999), tfClearFreeze));
729 env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
733 BEAST_EXPECT(ownerCount(env, buyer) == 1);
736 env(trust(gw, buyer[
"AUD"](999), tfSetFreeze));
739 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
743 BEAST_EXPECT(ownerCount(env, buyer) == 1);
747 env(trust(gw, buyer[
"AUD"](999), tfClearFreeze));
748 env(trust(buyer, gwAUD(1000)));
751 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
755 BEAST_EXPECT(ownerCount(env, buyer) == 1);
761 env(pay(gw, buyer, gwAUD(999)));
766 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
770 BEAST_EXPECT(ownerCount(env, buyer) == 1);
773 auto const baseFee = env.current()->fees().base;
774 env(pay(env.master, buyer, XRP(50) + drops(baseFee * 12 - 1)));
777 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
781 BEAST_EXPECT(ownerCount(env, buyer) == 1);
784 env(pay(env.master, buyer, drops(baseFee + 1)));
789 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
793 BEAST_EXPECT(ownerCount(env, buyer) == 2);
913 testcase(
"Invalid NFT offer accept");
915 using namespace test::jtx;
917 Env env{*
this, features};
918 Account
const alice{
"alice"};
919 Account
const buyer{
"buyer"};
920 Account
const gw(
"gw");
921 IOU
const gwAUD(gw[
"AUD"]);
923 env.fund(XRP(1000), alice, buyer, gw);
925 BEAST_EXPECT(ownerCount(env, alice) == 0);
926 BEAST_EXPECT(ownerCount(env, buyer) == 0);
928 uint256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable);
929 env(token::mint(alice, 0u), txflags(tfTransferable));
931 uint8_t aliceCount = 1;
932 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
934 uint256 const nftXrpOnlyID = token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable);
935 env(token::mint(alice, 0), txflags(tfOnlyXRP | tfTransferable));
937 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
939 uint256 const nftNoXferID = token::getNextID(env, alice, 0);
940 env(token::mint(alice, 0));
942 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
946 env(token::createOffer(alice, nftAlice0ID, XRP(10)), txflags(tfSellNFToken));
949 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
952 env(token::createOffer(alice, nftAlice0ID, gwAUD(30)), txflags(tfSellNFToken));
955 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
958 env(token::createOffer(alice, nftXrpOnlyID, XRP(20)), txflags(tfSellNFToken));
961 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
964 env(token::createOffer(alice, nftNoXferID, XRP(30)), txflags(tfSellNFToken));
967 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
971 env(token::createOffer(alice, nftNoXferID, XRP(40)),
972 txflags(tfSellNFToken),
976 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
980 env(token::createOffer(buyer, nftAlice0ID, XRP(40)),
984 uint8_t buyerCount = 1;
985 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
991 env(token::acceptSellOffer(buyer, noXferOfferIndex),
995 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
998 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1002 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1006 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1010 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1015 Json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1019 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1024 Json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1028 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1032 env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1033 token::brokerFee(gwAUD(0)),
1036 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1044 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1050 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1055 env(token::acceptBuyOffer(alice, buyerExpOfferIndex), ter(
tecEXPIRED));
1057 if (features[fixExpiredNFTokenOfferRemoval])
1061 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1066 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1071 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1076 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), ter(
tecEXPIRED));
1080 if (features[fixExpiredNFTokenOfferRemoval])
1084 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1085 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1092 env(trust(alice, gwAUD(1000)));
1093 env(trust(buyer, gwAUD(1000)));
1095 env(pay(gw, buyer, gwAUD(30)));
1099 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1100 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1102 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1103 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1110 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)), token::owner(alice));
1113 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1116 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1119 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1122 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1125 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1129 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1132 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1135 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1138 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1143 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)), token::owner(alice));
1146 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1150 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1151 token::brokerFee(XRP(40)),
1154 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1157 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1158 token::brokerFee(gwAUD(31)),
1161 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1165 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1166 token::brokerFee(gwAUD(1.5)),
1169 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1172 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1175 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1182 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)), token::owner(alice));
1185 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1190 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1193 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1196 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1199 env(pay(buyer, gw, gwAUD(30)));
1201 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1204 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1209 env(token::createOffer(alice, nftAlice0ID, XRP(0)), txflags(tfSellNFToken));
1211 env(token::acceptSellOffer(gw, offerIndex));
1213 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1215 env(pay(gw, buyer, gwAUD(30)));
1221 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1224 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1227 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1234 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)), token::owner(alice));
1237 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1240 env(token::acceptSellOffer(alice, buyerOfferIndex),
1243 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1246 env(token::acceptSellOffer(alice, plainOfferIndex),
1249 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1253 env(token::acceptSellOffer(buyer, plainOfferIndex), ter(
tecNO_PERMISSION));
1255 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1262 env(token::createOffer(gw, nftAlice0ID, XRP(0)), txflags(tfSellNFToken));
1264 env(token::acceptSellOffer(alice, offerIndex));
1266 BEAST_EXPECT(ownerCount(env, alice) == aliceCount);
1268 env(pay(buyer, gw, gwAUD(30)));
1270 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1273 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
1479 testcase(
"Mint flagCreateTrustLines");
1481 using namespace test::jtx;
1483 Account
const alice{
"alice"};
1484 Account
const becky{
"becky"};
1485 Account
const cheri{
"cheri"};
1486 Account
const gw(
"gw");
1487 IOU
const gwAUD(gw[
"AUD"]);
1488 IOU
const gwCAD(gw[
"CAD"]);
1489 IOU
const gwEUR(gw[
"EUR"]);
1494 for (
auto const& tweakedFeatures :
1495 {features - fixRemoveNFTokenAutoTrustLine, features | fixRemoveNFTokenAutoTrustLine})
1497 Env env{*
this, tweakedFeatures};
1498 env.fund(XRP(1000), alice, becky, cheri, gw);
1502 env(trust(becky, gwAUD(1000)));
1503 env(trust(cheri, gwAUD(1000)));
1504 env(trust(becky, gwCAD(1000)));
1505 env(trust(cheri, gwCAD(1000)));
1506 env(trust(becky, gwEUR(1000)));
1507 env(trust(cheri, gwEUR(1000)));
1509 env(pay(gw, becky, gwAUD(500)));
1510 env(pay(gw, becky, gwCAD(500)));
1511 env(pay(gw, becky, gwEUR(500)));
1512 env(pay(gw, cheri, gwAUD(500)));
1513 env(pay(gw, cheri, gwCAD(500)));
1520 uint256 const nftNoAutoTrustID{
1521 token::getNextID(env, alice, 0u, tfTransferable, xferFee)};
1522 env(token::mint(alice, 0u), token::xferFee(xferFee), txflags(tfTransferable));
1527 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), token::owner(alice));
1529 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1535 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1536 txflags(tfSellNFToken),
1537 ter(createOfferTER));
1542 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1543 token::owner(becky),
1544 ter(createOfferTER));
1548 env(token::cancelOffer(becky, {beckyOfferIndex}));
1549 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1558 token::getNextID(env, alice, 0u, tfTransferable |
tfTrustLine, transferFee)};
1563 TER const mintTER = tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
1567 env(token::mint(alice, 0u),
1568 token::xferFee(transferFee),
1575 if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
1580 env(token::createOffer(becky, nftAutoTrustID, drops(1)), token::owner(alice));
1582 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1587 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), txflags(tfSellNFToken));
1589 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1593 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1597 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)), token::owner(cheri));
1599 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1603 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1604 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1610 uint256 const nftNoAutoTrustID{
1611 token::getNextID(env, alice, 0u, tfTransferable, transferFee)};
1612 env(token::mint(alice, 0u), token::xferFee(transferFee), txflags(tfTransferable));
1617 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1618 txflags(tfSellNFToken));
1620 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1626 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1629 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1630 txflags(tfSellNFToken),
1634 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1635 txflags(tfSellNFToken));
1637 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1643 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1654 using namespace test::jtx;
1656 Env env{*
this, features};
1658 Account
const alice{
"alice"};
1659 Account
const becky{
"becky"};
1660 Account
const minter{
"minter"};
1662 env.fund(XRP(1000), alice, becky, minter);
1667 BEAST_EXPECT(ownerCount(env, alice) == 0);
1668 uint256 const nftAliceNoTransferID{token::getNextID(env, alice, 0u)};
1669 env(token::mint(alice, 0u), token::xferFee(0));
1671 BEAST_EXPECT(ownerCount(env, alice) == 1);
1674 BEAST_EXPECT(ownerCount(env, becky) == 0);
1675 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1676 token::owner(alice),
1681 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)), txflags(tfSellNFToken));
1683 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1685 BEAST_EXPECT(ownerCount(env, alice) == 0);
1686 BEAST_EXPECT(ownerCount(env, becky) == 1);
1689 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1690 txflags(tfSellNFToken),
1693 BEAST_EXPECT(ownerCount(env, alice) == 0);
1694 BEAST_EXPECT(ownerCount(env, becky) == 1);
1698 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1699 txflags(tfSellNFToken),
1700 token::destination(alice),
1703 BEAST_EXPECT(ownerCount(env, alice) == 0);
1704 BEAST_EXPECT(ownerCount(env, becky) == 1);
1709 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)), token::owner(becky));
1711 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1713 BEAST_EXPECT(ownerCount(env, alice) == 1);
1714 BEAST_EXPECT(ownerCount(env, becky) == 0);
1717 env(token::burn(alice, nftAliceNoTransferID));
1719 BEAST_EXPECT(ownerCount(env, alice) == 0);
1720 BEAST_EXPECT(ownerCount(env, becky) == 0);
1724 env(token::setMinter(alice, minter));
1727 BEAST_EXPECT(ownerCount(env, minter) == 0);
1728 uint256 const nftMinterNoTransferID{token::getNextID(env, alice, 0u)};
1729 env(token::mint(minter), token::issuer(alice));
1731 BEAST_EXPECT(ownerCount(env, minter) == 1);
1734 BEAST_EXPECT(ownerCount(env, becky) == 0);
1735 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1736 token::owner(minter),
1739 BEAST_EXPECT(ownerCount(env, becky) == 0);
1742 env(token::clearMinter(alice));
1746 BEAST_EXPECT(ownerCount(env, minter) == 1);
1747 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1748 txflags(tfSellNFToken),
1751 BEAST_EXPECT(ownerCount(env, minter) == 1);
1755 for (
int i = 0; i < 10; ++i)
1758 env(token::setMinter(alice, minter));
1760 BEAST_EXPECT(ownerCount(env, minter) == 1);
1763 BEAST_EXPECT(ownerCount(env, minter) == 1);
1765 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)), txflags(tfSellNFToken));
1767 BEAST_EXPECT(ownerCount(env, minter) == 2);
1771 env(token::clearMinter(alice));
1776 BEAST_EXPECT(ownerCount(env, becky) == 0);
1777 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1779 BEAST_EXPECT(ownerCount(env, becky) == 1);
1780 BEAST_EXPECT(ownerCount(env, minter) == 0);
1783 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1784 txflags(tfSellNFToken),
1790 BEAST_EXPECT(ownerCount(env, minter) == 0);
1791 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1792 token::owner(becky),
1795 BEAST_EXPECT(ownerCount(env, minter) == 0);
1798 BEAST_EXPECT(ownerCount(env, alice) == 0);
1800 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)), token::owner(becky));
1802 BEAST_EXPECT(ownerCount(env, alice) == 1);
1806 for (
int i = 0; i < 10; ++i)
1809 env(token::setMinter(alice, minter));
1813 BEAST_EXPECT(ownerCount(env, minter) == 0);
1815 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)), token::owner(becky));
1817 BEAST_EXPECT(ownerCount(env, minter) == 1);
1821 env(token::clearMinter(alice));
1825 BEAST_EXPECT(ownerCount(env, minter) == 1);
1826 BEAST_EXPECT(ownerCount(env, becky) == 1);
1827 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1829 BEAST_EXPECT(ownerCount(env, minter) == 1);
1830 BEAST_EXPECT(ownerCount(env, becky) == 0);
1831 BEAST_EXPECT(ownerCount(env, alice) == 1);
1835 env(token::burn(minter, nftMinterNoTransferID), ter(
tesSUCCESS));
1837 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1839 BEAST_EXPECT(ownerCount(env, alice) == 0);
1840 BEAST_EXPECT(ownerCount(env, becky) == 0);
1841 BEAST_EXPECT(ownerCount(env, minter) == 0);
1846 BEAST_EXPECT(ownerCount(env, alice) == 0);
1847 uint256 const nftAliceID{token::getNextID(env, alice, 0u, tfTransferable)};
1848 env(token::mint(alice, 0u), txflags(tfTransferable));
1850 BEAST_EXPECT(ownerCount(env, alice) == 1);
1854 env(token::createOffer(alice, nftAliceID, XRP(20)), txflags(tfSellNFToken));
1856 BEAST_EXPECT(ownerCount(env, alice) == 2);
1859 env(token::createOffer(becky, nftAliceID, XRP(21)), token::owner(alice));
1861 BEAST_EXPECT(ownerCount(env, alice) == 2);
1864 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1866 BEAST_EXPECT(ownerCount(env, alice) == 0);
1867 BEAST_EXPECT(ownerCount(env, becky) == 2);
1871 env(token::createOffer(becky, nftAliceID, XRP(22)), txflags(tfSellNFToken));
1873 BEAST_EXPECT(ownerCount(env, alice) == 0);
1874 BEAST_EXPECT(ownerCount(env, becky) == 3);
1878 env(token::acceptSellOffer(minter, beckySellOfferIndex));
1880 BEAST_EXPECT(ownerCount(env, alice) == 0);
1881 BEAST_EXPECT(ownerCount(env, becky) == 1);
1882 BEAST_EXPECT(ownerCount(env, minter) == 1);
1886 env(token::createOffer(minter, nftAliceID, XRP(23)), txflags(tfSellNFToken));
1888 BEAST_EXPECT(ownerCount(env, alice) == 0);
1889 BEAST_EXPECT(ownerCount(env, becky) == 1);
1890 BEAST_EXPECT(ownerCount(env, minter) == 2);
1893 env(token::acceptSellOffer(alice, minterSellOfferIndex));
1895 BEAST_EXPECT(ownerCount(env, alice) == 1);
1896 BEAST_EXPECT(ownerCount(env, becky) == 1);
1897 BEAST_EXPECT(ownerCount(env, minter) == 0);
1901 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1903 BEAST_EXPECT(ownerCount(env, alice) == 0);
1904 BEAST_EXPECT(ownerCount(env, becky) == 1);
1905 BEAST_EXPECT(ownerCount(env, minter) == 0);
1909 env(token::burn(becky, nftAliceID));
1911 BEAST_EXPECT(ownerCount(env, alice) == 0);
1912 BEAST_EXPECT(ownerCount(env, becky) == 0);
1913 BEAST_EXPECT(ownerCount(env, minter) == 0);
1923 using namespace test::jtx;
1925 Env env{*
this, features};
1926 auto const baseFee = env.current()->fees().base;
1928 Account
const alice{
"alice"};
1929 Account
const becky{
"becky"};
1930 Account
const carol{
"carol"};
1931 Account
const minter{
"minter"};
1932 Account
const gw{
"gw"};
1933 IOU
const gwXAU(gw[
"XAU"]);
1935 env.fund(XRP(1000), alice, becky, carol, minter, gw);
1938 env(trust(alice, gwXAU(2000)));
1939 env(trust(becky, gwXAU(2000)));
1940 env(trust(carol, gwXAU(2000)));
1941 env(trust(minter, gwXAU(2000)));
1943 env(pay(gw, alice, gwXAU(1000)));
1944 env(pay(gw, becky, gwXAU(1000)));
1945 env(pay(gw, carol, gwXAU(1000)));
1946 env(pay(gw, minter, gwXAU(1000)));
1951 env(token::setMinter(alice, minter));
1957 BEAST_EXPECT(ownerCount(env, alice) == 1);
1958 BEAST_EXPECT(ownerCount(env, becky) == 1);
1959 BEAST_EXPECT(ownerCount(env, carol) == 1);
1960 BEAST_EXPECT(ownerCount(env, minter) == 1);
1962 uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable);
1963 env(token::mint(alice), txflags(tfTransferable));
1968 env(token::createOffer(becky, nftID, gwXAU(10)), token::owner(alice));
1970 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
1971 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
1973 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1975 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
1976 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
1980 env(token::createOffer(becky, nftID, gwXAU(10)), txflags(tfSellNFToken));
1982 env(token::acceptSellOffer(carol, beckySellOfferIndex));
1984 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
1985 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
1986 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
1990 env(token::createOffer(minter, nftID, gwXAU(10)), token::owner(carol));
1992 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
1994 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
1995 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
1996 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
1997 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2002 env(token::createOffer(minter, nftID, gwXAU(10)), txflags(tfSellNFToken));
2004 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2006 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2007 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2008 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2009 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2012 env(token::burn(alice, nftID));
2014 BEAST_EXPECT(ownerCount(env, alice) == 1);
2015 BEAST_EXPECT(ownerCount(env, becky) == 1);
2016 BEAST_EXPECT(ownerCount(env, carol) == 1);
2017 BEAST_EXPECT(ownerCount(env, minter) == 1);
2023 uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1);
2024 env(token::mint(alice), txflags(tfTransferable), token::xferFee(1));
2029 env(token::createOffer(becky, nftID, gwXAU(10)), token::owner(alice));
2031 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2032 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2034 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2036 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2037 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2041 env(token::createOffer(becky, nftID, gwXAU(10)), txflags(tfSellNFToken));
2043 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2046 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2047 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2048 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2052 env(token::createOffer(minter, nftID, gwXAU(10)), token::owner(carol));
2054 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2057 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2058 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2059 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2060 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2065 env(token::createOffer(minter, nftID, gwXAU(10)), txflags(tfSellNFToken));
2067 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2069 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2070 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2071 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2072 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2076 env(pay(alice, becky, gwXAU(0.0001)));
2077 env(pay(alice, carol, gwXAU(0.0001)));
2080 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2081 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2082 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2083 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2086 env(token::burn(alice, nftID));
2088 BEAST_EXPECT(ownerCount(env, alice) == 1);
2089 BEAST_EXPECT(ownerCount(env, becky) == 1);
2090 BEAST_EXPECT(ownerCount(env, carol) == 1);
2091 BEAST_EXPECT(ownerCount(env, minter) == 1);
2097 env(token::mint(alice),
2098 txflags(tfTransferable),
2105 env(token::mint(alice), txflags(tfTransferable), token::xferFee(
maxTransferFee));
2110 env(token::createOffer(becky, nftID, gwXAU(10)), token::owner(alice));
2112 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2113 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2115 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2117 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2118 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2122 env(token::createOffer(becky, nftID, gwXAU(100)), txflags(tfSellNFToken));
2124 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2127 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2128 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2129 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2133 env(token::createOffer(carol, nftID, gwXAU(10)), token::owner(minter));
2135 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2138 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2139 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2140 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2141 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2146 env(token::createOffer(carol, nftID, gwXAU(10)), txflags(tfSellNFToken));
2148 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2151 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2152 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2153 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2154 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2157 env(pay(alice, minter, gwXAU(55)));
2158 env(pay(becky, minter, gwXAU(40)));
2160 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2161 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2162 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2163 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2166 env(token::burn(alice, nftID));
2168 BEAST_EXPECT(ownerCount(env, alice) == 1);
2169 BEAST_EXPECT(ownerCount(env, becky) == 1);
2170 BEAST_EXPECT(ownerCount(env, carol) == 1);
2171 BEAST_EXPECT(ownerCount(env, minter) == 1);
2176 for (
auto NumberSwitchOver : {
true})
2178 if (NumberSwitchOver)
2180 env.enableFeature(fixUniversalNumber);
2184 env.disableFeature(fixUniversalNumber);
2188 uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1);
2189 env(token::mint(alice), txflags(tfTransferable), token::xferFee(1));
2194 STAmount aliceBalance = env.balance(alice);
2195 STAmount minterBalance = env.balance(minter);
2197 env(token::createOffer(minter, nftID, XRP(1)), token::owner(alice));
2199 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2201 aliceBalance += XRP(1) - baseFee;
2202 minterBalance -= XRP(1) + baseFee;
2203 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2204 BEAST_EXPECT(env.balance(minter) == minterBalance);
2208 auto pmt = NumberSwitchOver ? drops(50000) : drops(99999);
2209 STAmount carolBalance = env.balance(carol);
2211 env(token::createOffer(minter, nftID, pmt), txflags(tfSellNFToken));
2213 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2215 minterBalance += pmt - baseFee;
2216 carolBalance -= pmt + baseFee;
2217 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2218 BEAST_EXPECT(env.balance(minter) == minterBalance);
2219 BEAST_EXPECT(env.balance(carol) == carolBalance);
2223 STAmount beckyBalance = env.balance(becky);
2225 pmt = NumberSwitchOver ? drops(50001) : drops(100000);
2226 env(token::createOffer(becky, nftID, pmt), token::owner(carol));
2228 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2230 carolBalance += pmt - drops(1) - baseFee;
2231 beckyBalance -= pmt + baseFee;
2232 aliceBalance += drops(1);
2234 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2235 BEAST_EXPECT(env.balance(minter) == minterBalance);
2236 BEAST_EXPECT(env.balance(carol) == carolBalance);
2237 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2244 uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1);
2245 env(token::mint(alice), txflags(tfTransferable), token::xferFee(1));
2251 env(pay(alice, gw, env.balance(alice, gwXAU)));
2252 env(pay(minter, gw, env.balance(minter, gwXAU)));
2253 env(pay(becky, gw, env.balance(becky, gwXAU)));
2258 env(pay(gw, alice, startXAUBalance));
2259 env(pay(gw, minter, startXAUBalance));
2260 env(pay(gw, becky, startXAUBalance));
2268 STAmount aliceBalance = env.balance(alice, gwXAU);
2269 STAmount minterBalance = env.balance(minter, gwXAU);
2271 env(token::createOffer(minter, nftID, tinyXAU), token::owner(alice));
2273 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2275 aliceBalance += tinyXAU;
2276 minterBalance -= tinyXAU;
2277 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2278 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2281 STAmount carolBalance = env.balance(carol, gwXAU);
2283 env(token::createOffer(minter, nftID, tinyXAU), txflags(tfSellNFToken));
2285 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2288 minterBalance += tinyXAU;
2289 carolBalance -= tinyXAU;
2291 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2292 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2293 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2299 STAmount beckyBalance = env.balance(becky, gwXAU);
2301 env(token::createOffer(becky, nftID, cheapNFT), token::owner(carol));
2303 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2306 aliceBalance += tinyXAU;
2307 beckyBalance -= cheapNFT;
2308 carolBalance += cheapNFT - tinyXAU;
2309 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2310 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2311 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2312 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2505 testcase(
"Create offer destination");
2507 using namespace test::jtx;
2509 Env env{*
this, features};
2511 Account
const issuer{
"issuer"};
2512 Account
const minter{
"minter"};
2513 Account
const buyer{
"buyer"};
2514 Account
const broker{
"broker"};
2516 env.fund(XRP(1000), issuer, minter, buyer, broker);
2520 env(token::setMinter(issuer, minter));
2523 uint256 const nftokenID = token::getNextID(env, issuer, 0, tfTransferable);
2524 env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable));
2531 env(token::createOffer(minter, nftokenID, drops(1)),
2532 token::destination(issuer),
2533 txflags(tfSellNFToken));
2536 env(token::createOffer(minter, nftokenID, drops(1)),
2537 token::destination(buyer),
2538 txflags(tfSellNFToken));
2541 env(token::createOffer(issuer, nftokenID, drops(1)),
2542 token::owner(minter),
2543 token::destination(minter));
2546 env(token::createOffer(issuer, nftokenID, drops(1)),
2547 token::owner(minter),
2548 token::destination(buyer));
2551 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2552 BEAST_EXPECT(ownerCount(env, minter) == 3);
2553 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2562 env(token::cancelOffer(issuer, {offerMinterToBuyer}), ter(
tecNO_PERMISSION));
2563 env(token::cancelOffer(buyer, {offerMinterToIssuer}), ter(
tecNO_PERMISSION));
2564 env(token::cancelOffer(buyer, {offerIssuerToMinter}), ter(
tecNO_PERMISSION));
2565 env(token::cancelOffer(minter, {offerIssuerToBuyer}), ter(
tecNO_PERMISSION));
2567 BEAST_EXPECT(ownerCount(env, issuer) == 2);
2568 BEAST_EXPECT(ownerCount(env, minter) == 3);
2569 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2573 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2574 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2575 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2576 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2578 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2579 BEAST_EXPECT(ownerCount(env, minter) == 1);
2580 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2587 env(token::createOffer(minter, nftokenID, drops(1)),
2588 token::destination(buyer),
2589 txflags(tfSellNFToken));
2591 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2592 BEAST_EXPECT(ownerCount(env, minter) == 2);
2593 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2597 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer), ter(
tecNO_PERMISSION));
2599 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2600 BEAST_EXPECT(ownerCount(env, minter) == 2);
2601 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2604 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2606 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2607 BEAST_EXPECT(ownerCount(env, minter) == 0);
2608 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2615 env(token::createOffer(minter, nftokenID, drops(1)),
2616 token::owner(buyer),
2617 token::destination(buyer));
2619 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2620 BEAST_EXPECT(ownerCount(env, minter) == 1);
2621 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2625 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer), ter(
tecNO_PERMISSION));
2627 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2628 BEAST_EXPECT(ownerCount(env, minter) == 1);
2629 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2632 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2634 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2635 BEAST_EXPECT(ownerCount(env, minter) == 1);
2636 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2642 env(token::createOffer(buyer, nftokenID, drops(1)),
2643 token::owner(minter),
2644 token::destination(broker));
2646 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2647 BEAST_EXPECT(ownerCount(env, minter) == 1);
2648 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2650 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter), ter(
tecNO_PERMISSION));
2654 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2656 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2657 BEAST_EXPECT(ownerCount(env, minter) == 1);
2658 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2665 env(token::createOffer(minter, nftokenID, drops(1)),
2666 token::destination(broker),
2667 txflags(tfSellNFToken));
2670 env(token::createOffer(buyer, nftokenID, drops(1)), token::owner(minter));
2673 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2674 BEAST_EXPECT(ownerCount(env, minter) == 2);
2675 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2680 env(token::brokerOffers(issuer, offerBuyerToMinter, offerMinterToBroker),
2683 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2684 BEAST_EXPECT(ownerCount(env, minter) == 2);
2685 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2690 env(token::brokerOffers(broker, offerBuyerToMinter, offerMinterToBroker));
2692 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2693 BEAST_EXPECT(ownerCount(env, minter) == 0);
2694 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2702 env(token::createOffer(buyer, nftokenID, drops(1)),
2703 token::destination(minter),
2704 txflags(tfSellNFToken));
2707 env(token::createOffer(minter, nftokenID, drops(1)), token::owner(buyer));
2710 env(token::createOffer(issuer, nftokenID, drops(1)), token::owner(buyer));
2713 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2714 BEAST_EXPECT(ownerCount(env, minter) == 1);
2715 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2720 env(token::brokerOffers(broker, offerIssuerToBuyer, offerBuyerToMinter),
2724 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2725 BEAST_EXPECT(ownerCount(env, minter) == 1);
2726 BEAST_EXPECT(ownerCount(env, buyer) == 2);
2728 env(token::brokerOffers(broker, offerMinterToBuyer, offerBuyerToMinter),
2733 env(token::acceptBuyOffer(buyer, offerMinterToBuyer));
2737 env(token::cancelOffer(buyer, {offerBuyerToMinter}));
2740 BEAST_EXPECT(ownerCount(env, issuer) == 1);
2741 BEAST_EXPECT(ownerCount(env, minter) == 1);
2742 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2745 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2747 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2748 BEAST_EXPECT(ownerCount(env, minter) == 1);
2749 BEAST_EXPECT(ownerCount(env, buyer) == 0);
2758 env(token::createOffer(minter, nftokenID, drops(1)),
2759 token::destination(broker),
2760 txflags(tfSellNFToken));
2763 env(token::createOffer(buyer, nftokenID, drops(1)),
2764 token::owner(minter),
2765 token::destination(broker));
2770 env(token::brokerOffers(issuer, offerBuyerToBroker, offerMinterToBroker),
2773 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2774 BEAST_EXPECT(ownerCount(env, minter) == 2);
2775 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2779 env(token::brokerOffers(broker, offerBuyerToBroker, offerMinterToBroker));
2781 BEAST_EXPECT(ownerCount(env, issuer) == 0);
2782 BEAST_EXPECT(ownerCount(env, minter) == 0);
2783 BEAST_EXPECT(ownerCount(env, buyer) == 1);
2920 testcase(
"Create offer expiration");
2922 using namespace test::jtx;
2924 Env env{*
this, features};
2926 Account
const issuer{
"issuer"};
2927 Account
const minter{
"minter"};
2928 Account
const buyer{
"buyer"};
2930 env.fund(XRP(1000), issuer, minter, buyer);
2934 env(token::setMinter(issuer, minter));
2937 uint256 const nftokenID0 = token::getNextID(env, issuer, 0, tfTransferable);
2938 env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable));
2941 uint256 const nftokenID1 = token::getNextID(env, issuer, 0, tfTransferable);
2942 env(token::mint(minter, 0), token::issuer(issuer), txflags(tfTransferable));
2944 uint8_t issuerCount = 0, minterCount = 0, buyerCount = 0;
2952 env(token::createOffer(minter, nftokenID0, drops(1)),
2953 token::destination(issuer),
2954 token::expiration(expiration),
2955 txflags(tfSellNFToken));
2958 env(token::createOffer(minter, nftokenID0, drops(1)),
2959 token::expiration(expiration),
2960 txflags(tfSellNFToken));
2963 env(token::createOffer(issuer, nftokenID0, drops(1)),
2964 token::owner(minter),
2965 token::expiration(expiration));
2968 env(token::createOffer(buyer, nftokenID0, drops(1)),
2969 token::owner(minter),
2970 token::expiration(expiration));
2975 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
2976 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
2977 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
2985 env(token::cancelOffer(issuer, {offerMinterToAnyone}), ter(
tecNO_PERMISSION));
2986 env(token::cancelOffer(buyer, {offerIssuerToMinter}), ter(
tecNO_PERMISSION));
2988 BEAST_EXPECT(
lastClose(env) < expiration);
2989 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
2990 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
2991 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
2994 env(token::cancelOffer(minter, {offerMinterToAnyone}));
2999 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3006 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3007 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3008 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3011 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3013 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3016 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3017 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3018 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3028 env(token::createOffer(minter, nftokenID0, drops(1)),
3029 token::expiration(expiration),
3030 txflags(tfSellNFToken));
3034 env(token::createOffer(minter, nftokenID1, drops(1)),
3035 token::expiration(expiration),
3036 txflags(tfSellNFToken));
3039 BEAST_EXPECT(
lastClose(env) < expiration);
3040 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3041 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3042 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3045 env(token::acceptSellOffer(buyer, offer0));
3053 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3054 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3055 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3058 env(token::acceptSellOffer(buyer, offer1), ter(
tecEXPIRED));
3063 if (features[fixExpiredNFTokenOfferRemoval])
3073 env(token::acceptSellOffer(issuer, offer1), ter(
tecEXPIRED));
3078 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3079 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3080 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3082 if (!features[fixExpiredNFTokenOfferRemoval])
3086 env(token::cancelOffer(issuer, {offer1}));
3092 BEAST_EXPECT(ownerCount(env, issuer) == 0 && issuerCount == 0);
3093 BEAST_EXPECT(ownerCount(env, minter) == 1 && minterCount == 1);
3094 BEAST_EXPECT(ownerCount(env, buyer) == 1 && buyerCount == 1);
3099 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3100 txflags(tfSellNFToken),
3101 token::destination(minter));
3103 env(token::acceptSellOffer(minter, offerSellBack));
3106 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3107 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3108 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3118 env(token::createOffer(buyer, nftokenID0, drops(1)),
3119 token::owner(minter),
3120 token::expiration(expiration));
3124 env(token::createOffer(buyer, nftokenID1, drops(1)),
3125 token::owner(minter),
3126 token::expiration(expiration));
3129 BEAST_EXPECT(
lastClose(env) < expiration);
3130 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3131 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3132 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3135 env(token::acceptBuyOffer(minter, offer0));
3141 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3142 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3143 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3146 env(token::acceptBuyOffer(minter, offer1), ter(
tecEXPIRED));
3151 if (features[fixExpiredNFTokenOfferRemoval])
3161 env(token::acceptBuyOffer(issuer, offer1), ter(
tecEXPIRED));
3166 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3167 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3168 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3170 if (!features[fixExpiredNFTokenOfferRemoval])
3174 env(token::cancelOffer(issuer, {offer1}));
3180 BEAST_EXPECT(ownerCount(env, issuer) == 0 && issuerCount == 0);
3181 BEAST_EXPECT(ownerCount(env, minter) == 1 && minterCount == 1);
3182 BEAST_EXPECT(ownerCount(env, buyer) == 1 && buyerCount == 1);
3187 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3188 txflags(tfSellNFToken),
3189 token::destination(minter));
3191 env(token::acceptSellOffer(minter, offerSellBack));
3194 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3195 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3196 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3206 env(token::createOffer(minter, nftokenID0, drops(1)),
3207 token::expiration(expiration),
3208 txflags(tfSellNFToken));
3212 env(token::createOffer(minter, nftokenID1, drops(1)),
3213 token::expiration(expiration),
3214 txflags(tfSellNFToken));
3218 env(token::createOffer(buyer, nftokenID0, drops(1)), token::owner(minter));
3222 env(token::createOffer(buyer, nftokenID1, drops(1)), token::owner(minter));
3226 BEAST_EXPECT(
lastClose(env) < expiration);
3227 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3228 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3229 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3232 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3239 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3240 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3241 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3244 env(token::brokerOffers(issuer, buyOffer1, sellOffer1), ter(
tecEXPIRED));
3247 if (features[fixExpiredNFTokenOfferRemoval])
3253 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3254 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3255 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3257 if (features[fixExpiredNFTokenOfferRemoval])
3261 env(token::cancelOffer(buyer, {buyOffer1}));
3267 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3274 BEAST_EXPECT(ownerCount(env, issuer) == 0 && issuerCount == 0);
3275 BEAST_EXPECT(ownerCount(env, minter) == 1 && minterCount == 1);
3276 BEAST_EXPECT(ownerCount(env, buyer) == 1 && buyerCount == 1);
3281 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3282 txflags(tfSellNFToken),
3283 token::destination(minter));
3285 env(token::acceptSellOffer(minter, offerSellBack));
3288 BEAST_EXPECT(ownerCount(env, issuer) == issuerCount);
3289 BEAST_EXPECT(ownerCount(env, minter) == minterCount);
3290 BEAST_EXPECT(ownerCount(env, buyer) == buyerCount);
3300 env(token::createOffer(minter, nftokenID0, drops(1)), txflags(tfSellNFToken));
3303 env(token::createOffer(minter, nftokenID1, drops(1)), txflags(tfSellNFToken));
3306 env(token::createOffer(buyer, nftokenID0, drops(1)),
3307 token::expiration(expiration),
3308 token::owner(minter));
3311 env(token::createOffer(buyer, nftokenID1, drops(1)),
3312 token::expiration(expiration),
3313 token::owner(minter));
3316 BEAST_EXPECT(
lastClose(env) < expiration);
3317 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3318 BEAST_EXPECT(ownerCount(env, minter) == 3);
3319 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3322 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3328 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3329 BEAST_EXPECT(ownerCount(env, minter) == 2);
3330 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3332 env(token::brokerOffers(issuer, buyOffer1, sellOffer1), ter(
tecEXPIRED));
3335 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3336 if (features[fixExpiredNFTokenOfferRemoval])
3340 BEAST_EXPECT(ownerCount(env, minter) == 2);
3341 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3344 env(token::cancelOffer(minter, {sellOffer1}));
3349 BEAST_EXPECT(ownerCount(env, minter) == 2);
3350 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3352 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3355 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3356 BEAST_EXPECT(ownerCount(env, minter) == 1);
3357 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3362 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3363 txflags(tfSellNFToken),
3364 token::destination(minter));
3366 env(token::acceptSellOffer(minter, offerSellBack));
3368 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3369 BEAST_EXPECT(ownerCount(env, minter) == 1);
3370 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3381 env(token::createOffer(minter, nftokenID0, drops(1)),
3382 token::expiration(expiration),
3383 txflags(tfSellNFToken));
3386 env(token::createOffer(minter, nftokenID1, drops(1)),
3387 token::expiration(expiration),
3388 txflags(tfSellNFToken));
3391 env(token::createOffer(buyer, nftokenID0, drops(1)),
3392 token::expiration(expiration),
3393 token::owner(minter));
3396 env(token::createOffer(buyer, nftokenID1, drops(1)),
3397 token::expiration(expiration),
3398 token::owner(minter));
3401 BEAST_EXPECT(
lastClose(env) < expiration);
3402 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3403 BEAST_EXPECT(ownerCount(env, minter) == 3);
3404 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3407 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3413 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3414 BEAST_EXPECT(ownerCount(env, minter) == 2);
3415 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3417 env(token::brokerOffers(issuer, buyOffer1, sellOffer1), ter(
tecEXPIRED));
3421 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3422 if (!features[fixExpiredNFTokenOfferRemoval])
3425 BEAST_EXPECT(ownerCount(env, minter) == 2);
3426 BEAST_EXPECT(ownerCount(env, buyer) == 2);
3428 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3431 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3432 BEAST_EXPECT(ownerCount(env, minter) == 1);
3433 BEAST_EXPECT(ownerCount(env, buyer) == 1);
3438 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3439 txflags(tfSellNFToken),
3440 token::destination(minter));
3442 env(token::acceptSellOffer(minter, offerSellBack));
3444 BEAST_EXPECT(ownerCount(env, issuer) == 0);
3445 BEAST_EXPECT(ownerCount(env, minter) == 1);
3446 BEAST_EXPECT(ownerCount(env, buyer) == 0);
3665 testcase(
"Brokered NFT offer accept");
3667 using namespace test::jtx;
3670 Env env{*
this, features};
3671 auto const baseFee = env.current()->fees().base;
3679 Account
const issuer{
"issuer"};
3680 Account
const minter{
"minter"};
3681 Account
const buyer{
"buyer"};
3682 Account
const broker{
"broker"};
3683 Account
const gw{
"gw"};
3684 IOU
const gwXAU(gw[
"XAU"]);
3686 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3689 env(trust(issuer, gwXAU(2000)));
3690 env(trust(minter, gwXAU(2000)));
3691 env(trust(buyer, gwXAU(2000)));
3692 env(trust(broker, gwXAU(2000)));
3695 env(token::setMinter(issuer, minter));
3699 auto checkOwnerCountIsOne =
3703 for (Account
const& acct : accounts)
3709 ss <<
"Account " << acct.human() <<
" expected ownerCount == 1. Got "
3711 fail(ss.
str(), __FILE__, line);
3717 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3718 uint256 const nftID = token::getNextID(env, issuer, 0, tfTransferable, xferFee);
3719 env(token::mint(minter, 0),
3720 token::issuer(issuer),
3721 token::xferFee(xferFee),
3722 txflags(tfTransferable));
3733 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3735 uint256 const nftID = mintNFT();
3739 env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken));
3745 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3748 auto const minterBalance = env.balance(minter);
3749 auto const buyerBalance = env.balance(buyer);
3750 auto const brokerBalance = env.balance(broker);
3751 auto const issuerBalance = env.balance(issuer);
3754 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3759 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
3760 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3761 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
3762 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3765 env(token::burn(buyer, nftID));
3775 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3777 uint256 const nftID = mintNFT();
3781 env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken));
3787 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3791 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3792 token::brokerFee(XRP(1.1)),
3796 auto const minterBalance = env.balance(minter);
3797 auto const buyerBalance = env.balance(buyer);
3798 auto const brokerBalance = env.balance(broker);
3799 auto const issuerBalance = env.balance(issuer);
3802 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3803 token::brokerFee(XRP(0.5)));
3808 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3809 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3810 BEAST_EXPECT(env.balance(broker) == brokerBalance + XRP(0.5) - baseFee);
3811 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3814 env(token::burn(buyer, nftID));
3824 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3830 env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken));
3836 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3839 auto const minterBalance = env.balance(minter);
3840 auto const buyerBalance = env.balance(buyer);
3841 auto const brokerBalance = env.balance(broker);
3842 auto const issuerBalance = env.balance(issuer);
3845 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3850 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3851 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3852 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
3853 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
3856 env(token::burn(buyer, nftID));
3866 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3872 env(token::createOffer(minter, nftID, XRP(0)), txflags(tfSellNFToken));
3878 env(token::createOffer(buyer, nftID, XRP(1)), token::owner(minter));
3881 auto const minterBalance = env.balance(minter);
3882 auto const buyerBalance = env.balance(buyer);
3883 auto const brokerBalance = env.balance(broker);
3884 auto const issuerBalance = env.balance(issuer);
3887 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3888 token::brokerFee(XRP(0.75)));
3894 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
3895 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3896 BEAST_EXPECT(env.balance(broker) == brokerBalance + XRP(0.75) - baseFee);
3897 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
3900 env(token::burn(buyer, nftID));
3906 auto setXAUBalance =
3907 [
this, &gw, &gwXAU, &env](
3911 for (Account
const& acct : accounts)
3913 auto const xauAmt = gwXAU(amount);
3914 auto const balance = env.balance(acct, gwXAU);
3915 if (balance < xauAmt)
3917 env(pay(gw, acct, xauAmt - balance));
3920 else if (balance > xauAmt)
3922 env(pay(acct, gw, balance - xauAmt));
3925 if (env.balance(acct, gwXAU) != xauAmt)
3928 ss <<
"Unable to set " << acct.human() <<
" account balance to gwXAU("
3930 this->
fail(ss.
str(), __FILE__, line);
3938 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3939 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
3941 uint256 const nftID = mintNFT();
3945 env(token::createOffer(minter, nftID, gwXAU(1000)), txflags(tfSellNFToken));
3952 env(token::createOffer(buyer, nftID, gwXAU(1001)), token::owner(minter));
3956 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3962 env(token::cancelOffer(buyer, {buyOfferIndex}));
3969 env(token::createOffer(buyer, nftID, gwXAU(999)), token::owner(minter));
3973 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3979 env(token::cancelOffer(buyer, {buyOfferIndex}));
3985 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter));
3989 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3990 token::brokerFee(gwXAU(0.1)),
3995 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3998 BEAST_EXPECT(ownerCount(env, issuer) == 1);
3999 BEAST_EXPECT(ownerCount(env, minter) == 1);
4000 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4001 BEAST_EXPECT(ownerCount(env, broker) == 1);
4002 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4003 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4004 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4005 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4008 env(token::burn(buyer, nftID));
4015 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4016 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4022 env(token::createOffer(minter, nftID, gwXAU(900)), txflags(tfSellNFToken));
4028 env(token::createOffer(buyer, nftID, gwXAU(1001)), token::owner(minter));
4032 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4038 env(token::cancelOffer(buyer, {buyOfferIndex}));
4045 env(token::createOffer(buyer, nftID, gwXAU(899)), token::owner(minter));
4049 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4055 env(token::cancelOffer(buyer, {buyOfferIndex}));
4060 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter));
4065 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4066 token::brokerFee(gwXAU(101)),
4072 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4073 token::brokerFee(gwXAU(100)));
4076 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4077 BEAST_EXPECT(ownerCount(env, minter) == 1);
4078 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4079 BEAST_EXPECT(ownerCount(env, broker) == 1);
4080 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4081 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4082 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4083 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4086 env(token::burn(buyer, nftID));
4093 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4094 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4100 env(token::createOffer(minter, nftID, gwXAU(900)), txflags(tfSellNFToken));
4105 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter));
4111 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4112 token::brokerFee(gwXAU(50)));
4115 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4116 BEAST_EXPECT(ownerCount(env, minter) == 1);
4117 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4118 BEAST_EXPECT(ownerCount(env, broker) == 1);
4119 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4120 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4121 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4122 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4125 env(token::burn(buyer, nftID));
4130 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4131 setXAUBalance({issuer, minter, buyer}, 1000, __LINE__);
4132 setXAUBalance({broker}, 500, __LINE__);
4137 env(token::createOffer(minter, nftID, gwXAU(900)), txflags(tfSellNFToken));
4142 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::owner(minter));
4145 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4146 token::brokerFee(gwXAU(50)));
4148 BEAST_EXPECT(ownerCount(env, issuer) == 1);
4149 BEAST_EXPECT(ownerCount(env, minter) == 1);
4150 BEAST_EXPECT(ownerCount(env, buyer) == 2);
4151 BEAST_EXPECT(ownerCount(env, broker) == 1);
4152 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4153 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4154 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4155 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(550));
4158 env(token::burn(buyer, nftID));
4728 using namespace test::jtx;
4730 testcase(
"Payments with IOU transfer fees");
4733 Env env{*
this, features};
4735 Account
const minter{
"minter"};
4736 Account
const secondarySeller{
"seller"};
4737 Account
const buyer{
"buyer"};
4738 Account
const gw{
"gateway"};
4739 Account
const broker{
"broker"};
4740 IOU
const gwXAU(gw[
"XAU"]);
4741 IOU
const gwXPB(gw[
"XPB"]);
4743 env.fund(XRP(1000), gw, minter, secondarySeller, buyer, broker);
4746 env(trust(minter, gwXAU(2000)));
4747 env(trust(secondarySeller, gwXAU(2000)));
4748 env(trust(broker, gwXAU(10000)));
4749 env(trust(buyer, gwXAU(2000)));
4750 env(trust(buyer, gwXPB(2000)));
4754 env(rate(gw, 1.02));
4757 auto expectInitialState =
4758 [
this, &env, &buyer, &minter, &secondarySeller, &broker, &gw, &gwXAU, &gwXPB]() {
4763 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
4764 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(0));
4765 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(0));
4766 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(0));
4767 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(0));
4768 BEAST_EXPECT(env.balance(secondarySeller, gwXPB) == gwXPB(0));
4769 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5000));
4770 BEAST_EXPECT(env.balance(broker, gwXPB) == gwXPB(0));
4771 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-1000));
4772 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(0));
4773 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(0));
4774 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(0));
4775 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(0));
4776 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XPB"]) == gwXPB(0));
4777 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5000));
4778 BEAST_EXPECT(env.balance(gw, broker[
"XPB"]) == gwXPB(0));
4781 auto reinitializeTrustLineBalances = [&expectInitialState,
4790 if (
auto const difference = gwXAU(1000) - env.balance(buyer, gwXAU);
4791 difference > gwXAU(0))
4792 env(pay(gw, buyer, difference));
4793 if (env.balance(buyer, gwXPB) > gwXPB(0))
4794 env(pay(buyer, gw, env.balance(buyer, gwXPB)));
4795 if (env.balance(minter, gwXAU) > gwXAU(0))
4796 env(pay(minter, gw, env.balance(minter, gwXAU)));
4797 if (env.balance(minter, gwXPB) > gwXPB(0))
4798 env(pay(minter, gw, env.balance(minter, gwXPB)));
4799 if (env.balance(secondarySeller, gwXAU) > gwXAU(0))
4800 env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXAU)));
4801 if (env.balance(secondarySeller, gwXPB) > gwXPB(0))
4802 env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXPB)));
4803 auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU);
4804 if (brokerDiff > gwXAU(0))
4806 env(pay(gw, broker, brokerDiff));
4808 else if (brokerDiff < gwXAU(0))
4810 brokerDiff.negate();
4811 env(pay(broker, gw, brokerDiff));
4813 if (env.balance(broker, gwXPB) > gwXPB(0))
4814 env(pay(broker, gw, env.balance(broker, gwXPB)));
4816 expectInitialState();
4819 auto mintNFT = [&env](Account
const& minter,
int transferFee = 0) {
4820 uint256 const nftID = token::getNextID(env, minter, 0, tfTransferable, transferFee);
4821 env(token::mint(minter), token::xferFee(transferFee), txflags(tfTransferable));
4826 auto createBuyOffer = [&env](
4827 Account
const& offerer,
4828 Account
const& owner,
4833 env(token::createOffer(offerer, nftID, amount),
4834 token::owner(owner),
4835 terCode ? ter(*terCode) : ter(
static_cast<TER>(
tesSUCCESS)));
4840 auto createSellOffer = [&env](
4841 Account
const& offerer,
4846 env(token::createOffer(offerer, nftID, amount),
4847 txflags(tfSellNFToken),
4848 terCode ? ter(*terCode) : ter(
static_cast<TER>(
tesSUCCESS)));
4856 reinitializeTrustLineBalances();
4857 auto const nftID = mintNFT(minter);
4858 auto const offerID = createSellOffer(minter, nftID, gwXAU(1000));
4860 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
4863 expectInitialState();
4868 reinitializeTrustLineBalances();
4869 auto const nftID = mintNFT(minter);
4870 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(1000));
4872 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
4875 expectInitialState();
4881 reinitializeTrustLineBalances();
4882 auto const nftID = mintNFT(minter);
4883 auto const offerID = createSellOffer(minter, nftID, gwXAU(995));
4885 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
4888 expectInitialState();
4894 reinitializeTrustLineBalances();
4895 auto const nftID = mintNFT(minter);
4896 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(995));
4898 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
4901 expectInitialState();
4908 reinitializeTrustLineBalances();
4909 auto const nftID = mintNFT(minter);
4910 auto const offerID = createSellOffer(minter, nftID, gwXAU(900));
4911 env(token::acceptSellOffer(buyer, offerID));
4914 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
4915 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
4916 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
4917 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
4924 reinitializeTrustLineBalances();
4925 auto const nftID = mintNFT(minter);
4926 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(900));
4927 env(token::acceptBuyOffer(minter, offerID));
4930 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
4931 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
4932 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
4933 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
4940 reinitializeTrustLineBalances();
4943 env(pay(gw, buyer, gwXAU(20)));
4946 auto const nftID = mintNFT(minter);
4947 auto const offerID = createSellOffer(minter, nftID, gwXAU(1000));
4948 env(token::acceptSellOffer(buyer, offerID));
4951 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4952 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4953 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
4954 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
4961 reinitializeTrustLineBalances();
4964 env(pay(gw, buyer, gwXAU(20)));
4967 auto const nftID = mintNFT(minter);
4968 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(1000));
4969 env(token::acceptBuyOffer(minter, offerID));
4972 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4973 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4974 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
4975 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
4980 reinitializeTrustLineBalances();
4982 auto const nftID = mintNFT(minter);
4983 auto const offerID = createSellOffer(minter, nftID, gwXAU(1000));
4985 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
4988 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4989 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
4994 reinitializeTrustLineBalances();
4996 auto const nftID = mintNFT(minter);
4998 auto const offerID = createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER});
5000 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5003 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5004 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5009 reinitializeTrustLineBalances();
5010 auto const nftID = mintNFT(minter);
5011 auto const offerID = createSellOffer(minter, nftID, gwXAU(5000));
5013 env(token::acceptSellOffer(gw, offerID), ter(sellTER));
5016 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5017 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5022 reinitializeTrustLineBalances();
5024 auto const nftID = mintNFT(minter);
5026 auto const offerID = createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER});
5028 env(token::acceptBuyOffer(minter, offerID), ter(sellTER));
5031 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5032 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5038 reinitializeTrustLineBalances();
5039 auto const nftID = mintNFT(gw);
5040 auto const offerID = createSellOffer(gw, nftID, gwXAU(1000));
5041 env(token::acceptSellOffer(buyer, offerID));
5044 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5045 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5051 reinitializeTrustLineBalances();
5053 auto const nftID = mintNFT(gw);
5054 auto const offerID = createBuyOffer(buyer, gw, nftID, gwXAU(1000));
5055 env(token::acceptBuyOffer(gw, offerID));
5058 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5059 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5065 reinitializeTrustLineBalances();
5066 auto const nftID = mintNFT(gw);
5067 auto const offerID = createSellOffer(gw, nftID, gwXAU(2000));
5068 env(token::acceptSellOffer(buyer, offerID),
5071 expectInitialState();
5077 reinitializeTrustLineBalances();
5078 auto const nftID = mintNFT(gw);
5079 auto const offerID = createBuyOffer(buyer, gw, nftID, gwXAU(2000));
5080 env(token::acceptBuyOffer(gw, offerID),
5083 expectInitialState();
5088 reinitializeTrustLineBalances();
5089 auto const nftID = mintNFT(minter);
5090 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5091 env(token::acceptSellOffer(buyer, offerID),
5094 expectInitialState();
5099 reinitializeTrustLineBalances();
5100 auto const nftID = mintNFT(minter);
5101 auto const offerID = createBuyOffer(
5103 env(token::acceptBuyOffer(minter, offerID),
5106 expectInitialState();
5112 reinitializeTrustLineBalances();
5113 env(pay(gw, buyer, gwXPB(100)));
5116 auto const nftID = mintNFT(minter);
5117 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5118 env(token::acceptSellOffer(buyer, offerID));
5121 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5122 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5123 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5124 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5130 reinitializeTrustLineBalances();
5131 env(pay(gw, buyer, gwXPB(100)));
5134 auto const nftID = mintNFT(minter);
5135 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXPB(10));
5136 env(token::acceptBuyOffer(minter, offerID));
5139 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5140 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5141 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5142 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5147 reinitializeTrustLineBalances();
5151 auto const nftID = mintNFT(minter, 3000);
5152 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5153 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5157 auto const offerID = createSellOffer(secondarySeller, nftID, gwXAU(1000));
5159 env(token::acceptSellOffer(buyer, offerID), ter(sellTER));
5162 expectInitialState();
5167 reinitializeTrustLineBalances();
5171 auto const nftID = mintNFT(minter, 3000);
5172 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5173 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5177 auto const offerID = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000));
5179 env(token::acceptBuyOffer(secondarySeller, offerID), ter(sellTER));
5182 expectInitialState();
5187 reinitializeTrustLineBalances();
5191 auto const nftID = mintNFT(minter, 3000);
5192 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5193 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5197 auto const offerID = createSellOffer(secondarySeller, nftID, gwXAU(900));
5198 env(token::acceptSellOffer(buyer, offerID));
5201 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5202 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5203 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5204 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5205 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5206 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5211 reinitializeTrustLineBalances();
5215 auto const nftID = mintNFT(minter, 3000);
5216 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5217 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5221 auto const offerID = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900));
5222 env(token::acceptBuyOffer(secondarySeller, offerID));
5226 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5228 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5230 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5231 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5232 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5233 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5251 reinitializeTrustLineBalances();
5253 auto const nftID = mintNFT(minter);
5254 auto const sellOffer = createSellOffer(minter, nftID, gwXAU(300));
5255 auto const buyOffer = createBuyOffer(buyer, minter, nftID, gwXAU(500));
5256 env(token::brokerOffers(broker, buyOffer, sellOffer), token::brokerFee(gwXAU(100)));
5259 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400));
5260 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5261 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5262 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-400));
5263 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5264 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5282 reinitializeTrustLineBalances();
5286 auto const nftID = mintNFT(minter, 3000);
5287 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5288 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5292 auto const sellOffer = createSellOffer(secondarySeller, nftID, gwXAU(300));
5293 auto const buyOffer = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500));
5294 env(token::brokerOffers(broker, buyOffer, sellOffer), token::brokerFee(gwXAU(100)));
5297 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12));
5298 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5299 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(388));
5300 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5301 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-12));
5302 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5303 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-388));
5304 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5399 using namespace test::jtx;
5404 auto openLedgerSeq = [](Env& env) {
return env.current()->seq(); };
5408 auto incLgrSeqForAcctDel = [&](Env& env, Account
const& acct) {
5409 int const delta = [&]() ->
int {
5410 if (env.seq(acct) + 255 > openLedgerSeq(env))
5411 return env.seq(acct) - openLedgerSeq(env) + 255;
5414 BEAST_EXPECT(delta >= 0);
5415 for (
int i = 0; i < delta; ++i)
5417 BEAST_EXPECT(openLedgerSeq(env) == env.seq(acct) + 255);
5422 auto incLgrSeqForFixNftRemint = [&](Env& env, Account
const& acct) {
5424 auto const deletableLgrSeq = (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) +
5425 (*env.le(acct))[sfMintedNFTokens] + 255;
5427 if (deletableLgrSeq > openLedgerSeq(env))
5428 delta = deletableLgrSeq - openLedgerSeq(env);
5430 BEAST_EXPECT(delta >= 0);
5431 for (
int i = 0; i < delta; ++i)
5433 BEAST_EXPECT(openLedgerSeq(env) == deletableLgrSeq);
5439 Env env{*
this, features};
5440 Account
const alice(
"alice");
5441 Account
const becky(
"becky");
5443 env.fund(XRP(10000), alice, becky);
5447 uint256 const prevNFTokenID = token::getNextID(env, alice, 0u);
5448 env(token::mint(alice));
5450 env(token::burn(alice, prevNFTokenID));
5454 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 1);
5457 incLgrSeqForAcctDel(env, alice);
5461 auto const acctDelFee{drops(env.current()->fees().increment)};
5462 env(acctdelete(alice, becky), fee(acctDelFee));
5467 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5468 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5471 env.fund(XRP(10000), alice);
5475 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5476 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5477 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5480 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5481 env(token::mint(alice));
5485 env(token::burn(alice, remintNFTokenID));
5489 BEAST_EXPECT(remintNFTokenID != prevNFTokenID);
5495 Env env{*
this, features};
5496 Account
const alice(
"alice");
5497 Account
const becky(
"becky");
5498 Account
const minter{
"minter"};
5500 env.fund(XRP(10000), alice, becky, minter);
5504 env(token::setMinter(alice, minter));
5510 for (
int i = 0; i < 500; i++)
5512 uint256 const nftokenID = token::getNextID(env, alice, 0u);
5514 env(token::mint(minter), token::issuer(alice));
5519 for (
auto const nftokenID : nftIDs)
5521 env(token::burn(minter, nftokenID));
5525 incLgrSeqForAcctDel(env, alice);
5529 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5530 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5532 auto const acctDelFee{drops(env.current()->fees().increment)};
5541 env(acctdelete(alice, becky), fee(acctDelFee), ter(
tecTOO_SOON));
5545 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5550 incLgrSeqForFixNftRemint(env, alice);
5553 env(acctdelete(alice, becky), fee(acctDelFee));
5558 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5559 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5562 env.fund(XRP(10000), alice);
5566 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5567 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5568 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5572 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5573 env(token::mint(alice));
5577 env(token::burn(alice, remintNFTokenID));
5588 Env env{*
this, features};
5590 Account
const alice{
"alice"};
5591 Account
const becky{
"becky"};
5592 env.fund(XRP(10000), alice, becky);
5599 env(ticket::create(alice, 100));
5603 BEAST_EXPECT(ownerCount(env, alice) == 100);
5608 for (
int i = 0; i < 50; i++)
5610 nftIDs.
push_back(token::getNextID(env, alice, 0u));
5611 env(token::mint(alice, 0u), ticket::use(aliceTicketSeq++));
5616 for (
auto const nftokenID : nftIDs)
5618 env(token::burn(alice, nftokenID), ticket::use(aliceTicketSeq++));
5624 incLgrSeqForAcctDel(env, alice);
5628 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5629 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5631 auto const acctDelFee{drops(env.current()->fees().increment)};
5640 env(acctdelete(alice, becky), fee(acctDelFee), ter(
tecTOO_SOON));
5644 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5649 incLgrSeqForFixNftRemint(env, alice);
5652 env(acctdelete(alice, becky), fee(acctDelFee));
5657 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5658 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5661 env.fund(XRP(10000), alice);
5665 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5666 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5667 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5671 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5672 env(token::mint(alice));
5676 env(token::burn(alice, remintNFTokenID));
5688 Env env{*
this, features};
5689 Account
const alice(
"alice");
5690 Account
const becky(
"becky");
5691 Account
const minter{
"minter"};
5693 env.fund(XRP(10000), alice, becky, minter);
5697 env(token::setMinter(alice, minter));
5702 env(ticket::create(minter, 100));
5706 BEAST_EXPECT(ownerCount(env, minter) == 100);
5711 for (
int i = 0; i < 50; i++)
5713 uint256 const nftokenID = token::getNextID(env, alice, 0u);
5715 env(token::mint(minter), token::issuer(alice), ticket::use(minterTicketSeq++));
5720 for (
auto const nftokenID : nftIDs)
5722 env(token::burn(minter, nftokenID), ticket::use(minterTicketSeq++));
5728 incLgrSeqForAcctDel(env, alice);
5732 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5733 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5742 auto const acctDelFee{drops(env.current()->fees().increment)};
5743 env(acctdelete(alice, becky), fee(acctDelFee), ter(
tecTOO_SOON));
5747 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5752 incLgrSeqForFixNftRemint(env, alice);
5755 env(acctdelete(alice, becky), fee(acctDelFee));
5760 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5761 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5764 env.fund(XRP(10000), alice);
5768 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5769 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5770 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5774 uint256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5775 env(token::mint(alice));
5779 env(token::burn(alice, remintNFTokenID));
5790 testcase(
"NFTokenMint with Create NFTokenOffer");
5792 using namespace test::jtx;
5794 if (!features[featureNFTokenMintOffer])
5796 Env env{*
this, features};
5797 Account
const alice(
"alice");
5798 Account
const buyer(
"buyer");
5800 env.fund(XRP(10000), alice, buyer);
5803 env(token::mint(alice), token::amount(XRP(10000)), ter(
temDISABLED));
5806 env(token::mint(alice), token::destination(
"buyer"), ter(
temDISABLED));
5817 Env env{*
this, features};
5818 auto const baseFee = env.current()->fees().base;
5819 Account
const alice(
"alice");
5820 Account
const buyer{
"buyer"};
5821 Account
const gw(
"gw");
5822 Account
const issuer(
"issuer");
5823 Account
const minter(
"minter");
5824 Account
const bob(
"bob");
5825 IOU
const gwAUD(gw[
"AUD"]);
5827 env.fund(XRP(10000), alice, buyer, gw, issuer, minter);
5832 env(token::mint(alice), token::destination(buyer), ter(
temMALFORMED));
5834 BEAST_EXPECT(ownerCount(env, alice) == 0);
5839 BEAST_EXPECT(ownerCount(env, buyer) == 0);
5845 env(token::mint(alice),
5846 token::amount(XRP(1000)),
5847 token::destination(alice),
5850 BEAST_EXPECT(ownerCount(env, alice) == 0);
5854 env(token::mint(alice),
5855 token::amount(XRP(1000)),
5856 token::destination(Account(
"demon")),
5859 BEAST_EXPECT(ownerCount(env, alice) == 0);
5864 env(token::mint(alice),
5865 token::amount(XRP(1000)),
5866 token::expiration(0),
5869 BEAST_EXPECT(ownerCount(env, alice) == 0);
5872 env(token::mint(alice),
5873 token::amount(XRP(1000)),
5877 BEAST_EXPECT(ownerCount(env, alice) == 0);
5882 env(token::mint(alice),
5883 token::amount(buyer[
"USD"](1)),
5886 env(token::mint(alice), token::amount(buyer[
"USD"](0)), ter(
temBAD_AMOUNT));
5888 BEAST_EXPECT(ownerCount(env, alice) == 0);
5891 env(token::mint(alice),
5892 token::amount(gwAUD(1000)),
5893 txflags(tfTransferable),
5897 BEAST_EXPECT(ownerCount(env, alice) == 0);
5902 env(token::mint(gw),
5903 token::amount(gwAUD(1000)),
5904 txflags(tfTransferable),
5905 token::xferFee(10));
5909 env(trust(gw, alice[
"AUD"](999), tfSetFreeze));
5914 env(token::mint(alice),
5915 token::amount(gwAUD(1000)),
5916 txflags(tfTransferable),
5920 BEAST_EXPECT(ownerCount(env, alice) == 0);
5923 env(token::mint(alice), token::amount(gwAUD(1000)), ter(
tecFROZEN));
5925 BEAST_EXPECT(ownerCount(env, alice) == 0);
5928 env(trust(gw, alice[
"AUD"](999), tfClearFreeze));
5934 auto const acctReserve = env.current()->fees().reserve;
5935 auto const incReserve = env.current()->fees().increment;
5937 env.fund(acctReserve + incReserve, bob);
5945 env(pay(env.master, bob, incReserve + drops(baseFee)));
5947 env(token::mint(bob), token::amount(XRP(0)));
5951 env(pay(env.master, bob, drops(baseFee)));
5957 env(pay(env.master, bob, incReserve + drops(baseFee)));
5959 env(token::mint(bob), token::amount(XRP(0)));
5964 BEAST_EXPECT(ownerCount(env, alice) == 0);
5965 env(token::mint(alice), token::amount(XRP(10)));
5966 BEAST_EXPECT(ownerCount(env, alice) == 2);
5970 env(token::mint(alice),
5971 token::amount(XRP(10)),
5972 token::destination(buyer),
5973 token::expiration(
lastClose(env) + 25));
5977 env(trust(alice, gwAUD(1000)));
5979 env(token::mint(alice),
5980 token::amount(gwAUD(1)),
5981 token::destination(buyer),
5983 txflags(tfTransferable),
5984 token::xferFee(10));
5988 env(token::mint(alice),
5989 token::amount(XRP(10)),
5990 token::destination(buyer),
5991 token::expiration(
lastClose(env) + 25));
5993 env(token::cancelOffer(alice, {offerAliceSellsToBuyer}));
5997 env(token::mint(buyer),
5998 token::amount(XRP(10)),
5999 token::destination(alice),
6000 token::expiration(
lastClose(env) + 25));
6002 env(token::cancelOffer(alice, {offerBuyerSellsToAlice}));
6005 env(token::setMinter(issuer, minter));
6009 BEAST_EXPECT(ownerCount(env, minter) == 0);
6010 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6011 env(token::mint(minter), token::issuer(issuer), token::amount(drops(1)));
6013 BEAST_EXPECT(ownerCount(env, minter) == 2);
6014 BEAST_EXPECT(ownerCount(env, issuer) == 0);
6017 Env env{*
this, features};
6018 Account
const alice(
"alice");
6020 env.fund(XRP(1000000), alice);
6025 env(token::mint(alice), token::amount(XRP(-2)), ter(offerCreateTER));
6043 testcase(
"Test synthetic fields from JSON response");
6045 using namespace test::jtx;
6047 Account
const alice{
"alice"};
6048 Account
const bob{
"bob"};
6049 Account
const broker{
"broker"};
6051 Env env{*
this, features};
6052 env.fund(XRP(10000), alice, bob, broker);
6058 auto verifyNFTokenID = [&](
uint256 const& actualNftID) {
6063 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
6066 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_id)))
6073 BEAST_EXPECT(nftID == actualNftID);
6083 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
6086 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_ids)))
6092 meta[jss::nftoken_ids].begin(),
6093 meta[jss::nftoken_ids].end(),
6097 BEAST_EXPECT(nftID.
parseHex(
id.asString()));
6103 std::sort(actualNftIDs.begin(), actualNftIDs.end());
6106 BEAST_EXPECT(metaIDs.
size() == actualNftIDs.size());
6110 for (
size_t i = 0; i < metaIDs.
size(); ++i)
6111 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
6116 auto verifyNFTokenOfferID = [&](
uint256 const& offerID) {
6121 Json::Value const meta = env.rpc(
"tx", txHash)[jss::result][jss::meta];
6124 if (!BEAST_EXPECT(meta.
isMember(jss::offer_id)))
6129 BEAST_EXPECT(metaOfferID == offerID);
6136 uint256 const nftId1{token::getNextID(env, alice, 0u, tfTransferable)};
6137 env(token::mint(alice, 0u), txflags(tfTransferable));
6139 verifyNFTokenID(nftId1);
6141 uint256 const nftId2{token::getNextID(env, alice, 0u, tfTransferable)};
6142 env(token::mint(alice, 0u), txflags(tfTransferable));
6144 verifyNFTokenID(nftId2);
6150 env(token::createOffer(alice, nftId1, drops(1)), txflags(tfSellNFToken));
6152 verifyNFTokenOfferID(aliceOfferIndex1);
6155 env(token::createOffer(alice, nftId2, drops(1)), txflags(tfSellNFToken));
6157 verifyNFTokenOfferID(aliceOfferIndex2);
6162 env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2}));
6164 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
6169 env(token::createOffer(bob, nftId1, drops(1)), token::owner(alice));
6171 verifyNFTokenOfferID(bobBuyOfferIndex);
6175 env(token::acceptBuyOffer(alice, bobBuyOfferIndex));
6177 verifyNFTokenID(nftId1);
6183 uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6184 env(token::mint(alice, 0u), txflags(tfTransferable));
6186 verifyNFTokenID(nftId);
6190 env(token::createOffer(alice, nftId, drops(1)),
6191 token::destination(broker),
6192 txflags(tfSellNFToken));
6194 verifyNFTokenOfferID(offerAliceToBroker);
6198 env(token::createOffer(bob, nftId, drops(1)), token::owner(alice));
6200 verifyNFTokenOfferID(offerBobToBroker);
6203 env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker));
6205 verifyNFTokenID(nftId);
6212 uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6213 env(token::mint(alice, 0u), txflags(tfTransferable));
6215 verifyNFTokenID(nftId);
6219 env(token::createOffer(alice, nftId, drops(1)), txflags(tfSellNFToken));
6221 verifyNFTokenOfferID(aliceOfferIndex1);
6224 env(token::createOffer(alice, nftId, drops(1)), txflags(tfSellNFToken));
6226 verifyNFTokenOfferID(aliceOfferIndex2);
6230 env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2}));
6232 verifyNFTokenIDsInCancelOffer({nftId});
6235 if (features[featureNFTokenMintOffer])
6238 env(token::mint(alice), token::amount(XRP(0)));
6240 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
6247 testcase(
"Test buyer reserve when accepting an offer");
6249 using namespace test::jtx;
6252 auto mintAndCreateSellOffer =
6255 uint256 const nftId{token::getNextID(env, acct, 0u, tfTransferable)};
6256 env(token::mint(acct, 0u), txflags(tfTransferable));
6261 env(token::createOffer(acct, nftId, amt), txflags(tfSellNFToken));
6264 return sellOfferIndex;
6271 Account
const alice{
"alice"};
6272 Account
const bob{
"bob"};
6274 Env env{*
this, features};
6275 auto const acctReserve = env.
current()->fees().reserve;
6276 auto const incReserve = env.
current()->fees().increment;
6277 auto const baseFee = env.
current()->fees().base;
6279 env.
fund(XRP(10000), alice);
6283 env.
fund(acctReserve, bob);
6287 auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0));
6290 BEAST_EXPECT(ownerCount(env, bob) == 0);
6294 if (!features[fixNFTokenReserve])
6297 env(token::acceptSellOffer(bob, sellOfferIndex));
6301 BEAST_EXPECT(ownerCount(env, bob) == 1);
6322 BEAST_EXPECT(ownerCount(env, bob) == 0);
6327 env(pay(env.
master, bob, incReserve + drops(baseFee)));
6337 env(pay(env.
master, bob, drops(baseFee * 2)));
6341 env(token::acceptSellOffer(bob, sellOfferIndex));
6344 BEAST_EXPECT(ownerCount(env, bob) == 1);
6351 Account
const alice{
"alice"};
6352 Account
const bob{
"bob"};
6354 Env env{*
this, features};
6355 auto const acctReserve = env.
current()->fees().reserve;
6356 auto const incReserve = env.
current()->fees().increment;
6358 env.
fund(XRP(10000), alice);
6361 env.
fund(acctReserve + XRP(1), bob);
6364 if (!features[fixNFTokenReserve])
6367 for (
size_t i = 0; i < 200; i++)
6370 auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0));
6373 env(token::acceptSellOffer(bob, sellOfferIndex));
6380 auto const sellOfferIndex1 = mintAndCreateSellOffer(env, alice, XRP(0));
6388 env(pay(env.
master, bob, drops(incReserve)));
6391 BEAST_EXPECT(ownerCount(env, bob) == 0);
6394 env(token::acceptSellOffer(bob, sellOfferIndex1));
6397 BEAST_EXPECT(ownerCount(env, bob) == 1);
6401 for (
size_t i = 0; i < 31; i++)
6404 auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0));
6408 env(token::acceptSellOffer(bob, sellOfferIndex));
6412 BEAST_EXPECT(ownerCount(env, bob) == 1);
6416 auto const sellOfferIndex33 = mintAndCreateSellOffer(env, alice, XRP(0));
6424 env(pay(env.
master, bob, drops(incReserve)));
6429 env(token::acceptSellOffer(bob, sellOfferIndex33));
6432 BEAST_EXPECT(ownerCount(env, bob) == 2);
6442 Account
const alice{
"alice"};
6443 Account
const bob{
"bob"};
6445 Env env{*
this, features};
6446 auto const acctReserve = env.
current()->fees().reserve;
6447 auto const incReserve = env.
current()->fees().increment;
6448 auto const baseFee = env.
current()->fees().base;
6450 env.
fund(XRP(10000), alice);
6456 env.
fund(acctReserve + incReserve + XRP(1), bob);
6460 uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6461 env(token::mint(alice, 0u), txflags(tfTransferable));
6466 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
6476 env(pay(env.
master, bob, drops(baseFee)));
6480 env(token::acceptBuyOffer(alice, buyOfferIndex));
6490 Account
const alice{
"alice"};
6491 Account
const bob{
"bob"};
6492 Account
const broker{
"broker"};
6494 Env env{*
this, features};
6495 auto const acctReserve = env.
current()->fees().reserve;
6496 auto const incReserve = env.
current()->fees().increment;
6497 auto const baseFee = env.
current()->fees().base;
6499 env.
fund(XRP(10000), alice, broker);
6504 env.
fund(acctReserve + incReserve + XRP(1), bob);
6508 uint256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6509 env(token::mint(alice, 0u), txflags(tfTransferable));
6514 env(token::createOffer(alice, nftId, XRP(1)),
6515 token::destination(broker),
6516 txflags(tfSellNFToken));
6521 env(token::createOffer(bob, nftId, XRP(1)), token::owner(alice));
6528 env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker),
6533 env(pay(env.
master, bob, drops(baseFee)));
6537 env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker));
6849 using namespace test::jtx;
6851 Account
const issuer{
"issuer"};
6852 Account
const alice(
"alice");
6853 Account
const bob(
"bob");
6855 bool const modifyEnabled = features[featureDynamicNFT];
6859 Env env{*
this, features};
6860 env.fund(XRP(10000), issuer);
6864 env(token::mint(issuer, 0u), txflags(tfMutable), ter(expectedTer));
6868 Env env{*
this, features};
6869 env.fund(XRP(10000), issuer);
6873 uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
6876 env(token::mint(issuer, 0u), txflags(tfMutable));
6878 BEAST_EXPECT(ownerCount(env, issuer) == 1);
6879 env(token::modify(issuer, nftId));
6880 BEAST_EXPECT(ownerCount(env, issuer) == 1);
6884 env(token::mint(issuer, 0u));
6886 env(token::modify(issuer, nftId), ter(
temDISABLED));
6894 Env env{*
this, features};
6895 env.fund(XRP(10000), issuer);
6898 uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
6899 env(token::mint(issuer, 0u), txflags(tfMutable));
6907 env(token::modify(issuer, nftId), txflags(0x00000001), ter(
temINVALID_FLAG));
6910 env(token::modify(issuer, nftId), token::owner(issuer), ter(
temMALFORMED));
6914 env(token::modify(issuer, nftId), token::uri(
""), ter(
temMALFORMED));
6918 env(token::modify(issuer, nftId),
6924 Env env{*
this, features};
6925 env.fund(XRP(10000), issuer, alice, bob);
6930 uint256 const nftIDNotExists{token::getNextID(env, issuer, 0u, tfMutable)};
6933 env(token::modify(issuer, nftIDNotExists), ter(
tecNO_ENTRY));
6938 uint256 const nftIDNotModifiable{token::getNextID(env, issuer, 0u)};
6939 env(token::mint(issuer, 0u));
6947 uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
6948 env(token::mint(issuer, 0u), txflags(tfMutable));
6951 env(token::modify(bob, nftId), token::owner(issuer), ter(
tecNO_PERMISSION));
6954 env(token::setMinter(issuer, alice));
6957 env(token::modify(bob, nftId), token::owner(issuer), ter(
tecNO_PERMISSION));
6962 Env env{*
this, features};
6963 env.fund(XRP(10000), issuer, alice, bob);
6967 uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
6968 env(token::mint(issuer, 0u), txflags(tfMutable), token::uri(
"uri"));
6975 Env env{*
this, features};
6976 env.fund(XRP(10000), issuer, alice, bob);
6980 auto accountNFTs = [&env](Account
const& acct) {
6982 params[jss::account] = acct.human();
6983 params[jss::type] =
"state";
6984 auto response = env.rpc(
"json",
"account_nfts",
to_string(params));
6985 return response[jss::result][jss::account_nfts];
6989 auto checkURI = [&accountNFTs,
this](Account
const& acct,
char const* uri,
int line) {
6990 auto const nfts = accountNFTs(acct);
6991 if (nfts.size() == 1)
6998 text <<
"checkURI: unexpected NFT count on line " << line;
6999 fail(text.
str(), __FILE__, line);
7005 if (!nfts[0u].isMember(sfURI.jsonName))
7012 text <<
"checkURI: unexpected URI present on line " << line;
7013 fail(text.
str(), __FILE__, line);
7025 text <<
"checkURI: unexpected URI contents on line " << line;
7026 fail(text.
str(), __FILE__, line);
7030 uint256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
7033 env(token::mint(issuer, 0u), txflags(tfMutable), token::uri(
"uri"));
7035 checkURI(issuer,
"uri", __LINE__);
7038 env(token::modify(issuer, nftId), token::uri(
"new_uri"));
7040 checkURI(issuer,
"new_uri", __LINE__);
7043 env(token::modify(issuer, nftId));
7045 checkURI(issuer,
nullptr, __LINE__);
7048 env(token::modify(issuer, nftId), token::uri(
"uri"));
7050 checkURI(issuer,
"uri", __LINE__);
7054 env(token::createOffer(issuer, nftId, XRP(0)), txflags(tfSellNFToken));
7056 env(token::acceptSellOffer(alice, offerID));
7058 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7059 BEAST_EXPECT(ownerCount(env, alice) == 1);
7060 checkURI(alice,
"uri", __LINE__);
7063 env(token::modify(alice, nftId), token::uri(
"new_uri"), ter(
tecNO_PERMISSION));
7065 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7066 BEAST_EXPECT(ownerCount(env, alice) == 1);
7067 checkURI(alice,
"uri", __LINE__);
7069 env(token::modify(issuer, nftId), token::owner(alice), token::uri(
"new_uri"));
7071 BEAST_EXPECT(ownerCount(env, issuer) == 0);
7072 BEAST_EXPECT(ownerCount(env, alice) == 1);
7073 checkURI(alice,
"new_uri", __LINE__);
7075 env(token::modify(issuer, nftId), token::owner(alice));
7077 checkURI(alice,
nullptr, __LINE__);
7079 env(token::modify(issuer, nftId), token::owner(alice), token::uri(
"uri"));
7081 checkURI(alice,
"uri", __LINE__);
7084 env(token::setMinter(issuer, bob));
7086 env(token::modify(bob, nftId), token::owner(alice), token::uri(
"new_uri"));
7088 checkURI(alice,
"new_uri", __LINE__);
7090 env(token::modify(bob, nftId), token::owner(alice));
7092 checkURI(alice,
nullptr, __LINE__);
7094 env(token::modify(bob, nftId), token::owner(alice), token::uri(
"uri"));
7096 checkURI(alice,
"uri", __LINE__);