183 Env env{*
this, features};
185 Account const minter{
"minter"};
189 auto const acctReserve = env.current()->fees().reserve;
190 auto const incReserve = env.current()->fees().increment;
191 auto const baseFee = env.current()->fees().base;
193 env.fund(acctReserve, alice, minter);
196 BEAST_EXPECT(env.balance(alice) == acctReserve);
197 BEAST_EXPECT(env.balance(minter) == acctReserve);
211 env(pay(env.master, alice, incReserve + drops(baseFee - 1)));
216 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
229 ss <<
"Wrong " << type <<
" count. Found: " << found <<
"; Expected: " << exp;
230 fail(ss.
str(), __FILE__, line);
233 oneCheck(
"owner",
ownerCount(env, alice), owners);
234 oneCheck(
"minted",
mintedCount(env, alice), minted);
235 oneCheck(
"burned",
burnedCount(env, alice), burned);
243 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
246 env(pay(env.master, alice, drops(baseFee + 1)));
250 env(token::mint(alice));
253 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
257 for (
int i = 1; i < 32; ++i)
259 env(token::mint(alice));
260 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
267 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
270 env(pay(env.master, alice, incReserve + drops(baseFee * 33 - 1)));
277 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
280 env(pay(env.master, alice, drops(baseFee + 1)));
284 env(token::mint(alice));
286 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
293 env(token::burn(alice, token::getID(env, alice, 0, seq++)));
295 checkAliceOwnerMintedBurned(((33 - seq) != 0u) ? 1 : 0, 33, seq, __LINE__);
299 env(token::burn(alice, token::getID(env, alice, 197, 5)), Ter(
tecNO_ENTRY));
301 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
306 env(token::setMinter(alice, minter));
308 BEAST_EXPECT(env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
312 auto checkMintersOwnerMintedBurned = [&env,
this, &alice, &minter](
329 ss <<
"Wrong " << type <<
" count. Found: " << found
330 <<
"; Expected: " << exp;
331 fail(ss.
str(), __FILE__, line);
334 oneCheck(
"alice owner",
ownerCount(env, alice), aliceOwners, line);
335 oneCheck(
"alice minted",
mintedCount(env, alice), aliceMinted, line);
336 oneCheck(
"alice burned",
burnedCount(env, alice), aliceBurned, line);
337 oneCheck(
"minter owner",
ownerCount(env, minter), minterOwners, line);
338 oneCheck(
"minter minted",
mintedCount(env, minter), minterMinted, line);
339 oneCheck(
"minter burned",
burnedCount(env, minter), minterBurned, line);
345 env(pay(env.master, minter, incReserve - drops(1)));
347 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
352 env(token::mint(minter),
353 token::Issuer(alice),
357 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
360 env(pay(env.master, minter, drops(baseFee + 1)));
364 env(token::mint(minter), token::Issuer(alice), token::Uri(
"uri"));
366 checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
370 for (
int i = 1; i < 32; ++i)
372 env(token::mint(minter), token::Issuer(alice), token::Uri(
"uri"));
373 checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
378 env(pay(env.master, minter, incReserve + drops(baseFee * 32 - 1)));
383 env(token::mint(minter),
384 token::Issuer(alice),
388 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
391 env(pay(env.master, minter, drops(baseFee + 1)));
395 env(token::mint(minter), token::Issuer(alice), token::Uri(
"uri"));
397 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
402 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
404 checkMintersOwnerMintedBurned(
405 0, 66, nftSeq, ((65 - seq) != 0u) ? 1 : 0, 0, 0, __LINE__);
410 env(token::burn(minter, token::getID(env, alice, 0, nftSeq++)));
412 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
415 env(token::burn(minter, token::getID(env, alice, 2009, 3)), Ter(
tecNO_ENTRY));
417 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
605 testcase(
"Invalid NFT offer create");
609 Env env{*
this, features};
613 IOU
const gwAUD(gw[
"AUD"]);
618 env.fund(XRP(250), alice, buyer, gw);
622 UInt256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable, 10);
623 env(token::mint(alice, 0u), Txflags(tfTransferable), token::XferFee(10));
627 UInt256 const nftXrpOnlyID = token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable);
628 env(token::mint(alice, 0), Txflags(tfOnlyXRP | tfTransferable));
632 UInt256 const nftNoXferID = token::getNextID(env, alice, 0);
633 env(token::mint(alice, 0));
646 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
653 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
660 env(token::createOffer(buyer, nftAlice0ID, XRP(1000)),
667 env(token::createOffer(buyer, nftXrpOnlyID, buyer[
"USD"](1)), Ter(
temBAD_AMOUNT));
668 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](0)), Ter(
temBAD_AMOUNT));
669 env(token::createOffer(buyer, nftXrpOnlyID, drops(0)), Ter(
temBAD_AMOUNT));
674 env(token::createOffer(buyer, nftAlice0ID, buyer[
"USD"](1)),
675 token::Expiration(0),
682 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)), Ter(
temMALFORMED));
687 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
689 Txflags(tfSellNFToken),
695 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
702 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
703 token::Destination(alice),
704 Txflags(tfSellNFToken),
710 env(token::createOffer(alice, nftXrpOnlyID, XRP(1000)),
711 token::Destination(
Account(
"demon")),
712 Txflags(tfSellNFToken),
721 env(token::createOffer(buyer, nftXrpOnlyID, XRP(1000)),
729 env(token::createOffer(buyer, token::getID(env, alice, 0, 1), XRP(1000)),
736 env(token::createOffer(alice, token::getID(env, alice, 0, 1), XRP(1000)),
737 Txflags(tfSellNFToken),
743 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
749 env(trust(buyer, gwAUD(1000)));
755 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
762 env(trust(gw, alice[
"AUD"](999), tfSetFreeze));
767 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
774 env(trust(gw, alice[
"AUD"](999), tfClearFreeze));
778 env(token::createOffer(buyer, nftNoXferID, gwAUD(1000)),
785 env(trust(gw, buyer[
"AUD"](999), tfSetFreeze));
788 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
796 env(trust(gw, buyer[
"AUD"](999), tfClearFreeze));
797 env(trust(buyer, gwAUD(1000)));
800 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
810 env(pay(gw, buyer, gwAUD(999)));
815 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
822 auto const baseFee = env.current()->fees().base;
823 env(pay(env.master, buyer, XRP(50) + drops(baseFee * 12 - 1)));
826 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
833 env(pay(env.master, buyer, drops(baseFee + 1)));
838 env(token::createOffer(buyer, nftAlice0ID, gwAUD(1000)),
983 testcase(
"Invalid NFT offer accept");
987 Env env{*
this, features};
991 IOU
const gwAUD(gw[
"AUD"]);
993 env.fund(XRP(1000), alice, buyer, gw);
998 UInt256 const nftAlice0ID = token::getNextID(env, alice, 0, tfTransferable);
999 env(token::mint(alice, 0u), Txflags(tfTransferable));
1001 uint8_t aliceCount = 1;
1002 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1004 UInt256 const nftXrpOnlyID = token::getNextID(env, alice, 0, tfOnlyXRP | tfTransferable);
1005 env(token::mint(alice, 0), Txflags(tfOnlyXRP | tfTransferable));
1007 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1009 UInt256 const nftNoXferID = token::getNextID(env, alice, 0);
1010 env(token::mint(alice, 0));
1012 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1015 UInt256 const plainOfferIndex =
1017 env(token::createOffer(alice, nftAlice0ID, XRP(10)), Txflags(tfSellNFToken));
1020 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1024 env(token::createOffer(alice, nftAlice0ID, gwAUD(30)), Txflags(tfSellNFToken));
1027 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1029 UInt256 const xrpOnlyOfferIndex =
1031 env(token::createOffer(alice, nftXrpOnlyID, XRP(20)), Txflags(tfSellNFToken));
1034 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1036 UInt256 const noXferOfferIndex =
1038 env(token::createOffer(alice, nftNoXferID, XRP(30)), Txflags(tfSellNFToken));
1041 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1044 UInt256 const aliceExpOfferIndex =
1046 env(token::createOffer(alice, nftNoXferID, XRP(40)),
1047 Txflags(tfSellNFToken),
1051 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1054 UInt256 const buyerExpOfferIndex =
1056 env(token::createOffer(buyer, nftAlice0ID, XRP(40)),
1057 token::Owner(alice),
1060 uint8_t buyerCount = 1;
1061 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1067 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1071 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1074 env(token::acceptSellOffer(buyer, noXferOfferIndex),
1075 Txflags(0x00008000),
1078 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1082 json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1086 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1091 json::Value jv = token::acceptBuyOffer(buyer, noXferOfferIndex);
1095 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1100 json::Value jv = token::acceptSellOffer(buyer, noXferOfferIndex);
1104 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1108 env(token::brokerOffers(buyer, noXferOfferIndex, xrpOnlyOfferIndex),
1109 token::BrokerFee(gwAUD(0)),
1112 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1120 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1126 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1130 env(token::acceptBuyOffer(alice, buyerExpOfferIndex), Ter(
tecEXPIRED));
1132 if (features[fixCleanup3_1_3])
1137 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1142 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1147 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1151 env(token::acceptSellOffer(buyer, aliceExpOfferIndex), Ter(
tecEXPIRED));
1156 if (features[fixCleanup3_1_3])
1161 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1162 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1169 env(trust(alice, gwAUD(1000)));
1170 env(trust(buyer, gwAUD(1000)));
1172 env(pay(gw, buyer, gwAUD(30)));
1176 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1177 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1179 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1180 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1186 UInt256 const buyerOfferIndex =
1188 env(token::createOffer(buyer, nftAlice0ID, gwAUD(29)), token::Owner(alice));
1191 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1194 env(token::brokerOffers(gw, buyerOfferIndex, xrpOnlyOfferIndex),
1197 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1200 env(token::brokerOffers(gw, buyerOfferIndex, plainOfferIndex),
1203 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1207 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1210 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1213 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1216 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1220 UInt256 const buyerOfferIndex =
1222 env(token::createOffer(buyer, nftAlice0ID, gwAUD(31)), token::Owner(alice));
1225 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1229 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1230 token::BrokerFee(XRP(40)),
1233 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1236 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1237 token::BrokerFee(gwAUD(31)),
1240 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1244 env(token::brokerOffers(gw, buyerOfferIndex, audOfferIndex),
1245 token::BrokerFee(gwAUD(1.5)),
1248 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1251 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1254 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1260 UInt256 const buyerOfferIndex =
1262 env(token::createOffer(buyer, nftAlice0ID, gwAUD(30)), token::Owner(alice));
1265 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1270 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1273 env(token::acceptBuyOffer(buyer, buyerOfferIndex),
1276 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1279 env(pay(buyer, gw, gwAUD(30)));
1281 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1284 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1290 env(token::createOffer(alice, nftAlice0ID, XRP(0)), Txflags(tfSellNFToken));
1292 env(token::acceptSellOffer(gw, offerIndex));
1294 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1296 env(pay(gw, buyer, gwAUD(30)));
1302 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1305 env(token::cancelOffer(buyer, {buyerOfferIndex}));
1308 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1314 UInt256 const buyerOfferIndex =
1316 env(token::createOffer(buyer, nftXrpOnlyID, XRP(30)), token::Owner(alice));
1319 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1322 env(token::acceptSellOffer(alice, buyerOfferIndex),
1325 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1328 env(token::acceptSellOffer(alice, plainOfferIndex),
1331 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1335 env(token::acceptSellOffer(buyer, plainOfferIndex), Ter(
tecNO_PERMISSION));
1337 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1345 env(token::createOffer(gw, nftAlice0ID, XRP(0)), Txflags(tfSellNFToken));
1347 env(token::acceptSellOffer(alice, offerIndex));
1349 BEAST_EXPECT(
ownerCount(env, alice) == aliceCount);
1351 env(pay(buyer, gw, gwAUD(30)));
1353 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1356 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
1565 testcase(
"Mint flagCreateTrustLines");
1573 IOU
const gwAUD(gw[
"AUD"]);
1574 IOU
const gwCAD(gw[
"CAD"]);
1575 IOU
const gwEUR(gw[
"EUR"]);
1580 for (
auto const& tweakedFeatures :
1581 {features - fixRemoveNFTokenAutoTrustLine, features | fixRemoveNFTokenAutoTrustLine})
1583 Env env{*
this, tweakedFeatures};
1584 env.fund(XRP(1000), alice, becky, cheri, gw);
1588 env(trust(becky, gwAUD(1000)));
1589 env(trust(cheri, gwAUD(1000)));
1590 env(trust(becky, gwCAD(1000)));
1591 env(trust(cheri, gwCAD(1000)));
1592 env(trust(becky, gwEUR(1000)));
1593 env(trust(cheri, gwEUR(1000)));
1595 env(pay(gw, becky, gwAUD(500)));
1596 env(pay(gw, becky, gwCAD(500)));
1597 env(pay(gw, becky, gwEUR(500)));
1598 env(pay(gw, cheri, gwAUD(500)));
1599 env(pay(gw, cheri, gwCAD(500)));
1606 UInt256 const nftNoAutoTrustID{
1607 token::getNextID(env, alice, 0u, tfTransferable, xferFee)};
1608 env(token::mint(alice, 0u), token::XferFee(xferFee), Txflags(tfTransferable));
1612 UInt256 const beckyBuyOfferIndex =
1614 env(token::createOffer(becky, nftNoAutoTrustID, drops(1)), token::Owner(alice));
1616 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1621 UInt256 const beckyOfferIndex =
1623 env(token::createOffer(becky, nftNoAutoTrustID, gwAUD(100)),
1624 Txflags(tfSellNFToken),
1625 Ter(createOfferTER));
1629 UInt256 const cheriOfferIndex =
1631 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1632 token::Owner(becky),
1633 Ter(createOfferTER));
1637 env(token::cancelOffer(becky, {beckyOfferIndex}));
1638 env(token::cancelOffer(cheri, {cheriOfferIndex}));
1647 token::getNextID(env, alice, 0u, tfTransferable |
tfTrustLine, transferFee)};
1652 TER const mintTER = tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
1656 env(token::mint(alice, 0u),
1657 token::XferFee(transferFee),
1664 if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
1668 UInt256 const beckyBuyOfferIndex =
1670 env(token::createOffer(becky, nftAutoTrustID, drops(1)), token::Owner(alice));
1672 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
1676 UInt256 const beckySellOfferIndex =
1678 env(token::createOffer(becky, nftAutoTrustID, gwAUD(100)), Txflags(tfSellNFToken));
1680 env(token::acceptSellOffer(cheri, beckySellOfferIndex));
1684 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1687 UInt256 const beckyBuyBackOfferIndex =
1689 env(token::createOffer(becky, nftAutoTrustID, gwCAD(50)), token::Owner(cheri));
1691 env(token::acceptBuyOffer(cheri, beckyBuyBackOfferIndex));
1695 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1696 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1702 UInt256 const nftNoAutoTrustID{
1703 token::getNextID(env, alice, 0u, tfTransferable, transferFee)};
1704 env(token::mint(alice, 0u), token::XferFee(transferFee), Txflags(tfTransferable));
1708 UInt256 const aliceSellOfferIndex =
1710 env(token::createOffer(alice, nftNoAutoTrustID, gwAUD(200)),
1711 Txflags(tfSellNFToken));
1713 env(token::acceptSellOffer(cheri, aliceSellOfferIndex));
1719 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1722 env(token::createOffer(cheri, nftNoAutoTrustID, gwEUR(50)),
1723 Txflags(tfSellNFToken),
1726 UInt256 const cheriSellOfferIndex =
1728 env(token::createOffer(cheri, nftNoAutoTrustID, gwCAD(100)),
1729 Txflags(tfSellNFToken));
1731 env(token::acceptSellOffer(becky, cheriSellOfferIndex));
1737 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1750 Env env{*
this, features};
1754 Account const minter{
"minter"};
1756 env.fund(XRP(1000), alice, becky, minter);
1762 UInt256 const nftAliceNoTransferID{token::getNextID(env, alice, 0u)};
1763 env(token::mint(alice, 0u), token::XferFee(0));
1769 env(token::createOffer(becky, nftAliceNoTransferID, XRP(20)),
1770 token::Owner(alice),
1774 UInt256 const aliceSellOfferIndex =
1776 env(token::createOffer(alice, nftAliceNoTransferID, XRP(20)), Txflags(tfSellNFToken));
1778 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1784 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1785 Txflags(tfSellNFToken),
1793 env(token::createOffer(becky, nftAliceNoTransferID, XRP(21)),
1794 Txflags(tfSellNFToken),
1795 token::Destination(alice),
1803 UInt256 const aliceBuyOfferIndex =
1805 env(token::createOffer(alice, nftAliceNoTransferID, XRP(22)), token::Owner(becky));
1807 env(token::acceptBuyOffer(becky, aliceBuyOfferIndex));
1813 env(token::burn(alice, nftAliceNoTransferID));
1820 env(token::setMinter(alice, minter));
1824 UInt256 const nftMinterNoTransferID{token::getNextID(env, alice, 0u)};
1825 env(token::mint(minter), token::Issuer(alice));
1831 env(token::createOffer(becky, nftMinterNoTransferID, XRP(20)),
1832 token::Owner(minter),
1838 env(token::clearMinter(alice));
1843 env(token::createOffer(minter, nftMinterNoTransferID, XRP(21)),
1844 Txflags(tfSellNFToken),
1851 for (
int i = 0; i < 10; ++i)
1854 env(token::setMinter(alice, minter));
1860 UInt256 const minterSellOfferIndex =
1862 env(token::createOffer(minter, nftMinterNoTransferID, XRP(22)), Txflags(tfSellNFToken));
1868 env(token::clearMinter(alice));
1874 env(token::acceptSellOffer(becky, minterSellOfferIndex));
1880 env(token::createOffer(becky, nftMinterNoTransferID, XRP(23)),
1881 Txflags(tfSellNFToken),
1888 env(token::createOffer(minter, nftMinterNoTransferID, XRP(24)),
1889 token::Owner(becky),
1896 UInt256 const aliceBuyOfferIndex =
1898 env(token::createOffer(alice, nftMinterNoTransferID, XRP(25)), token::Owner(becky));
1904 for (
int i = 0; i < 10; ++i)
1907 env(token::setMinter(alice, minter));
1912 UInt256 const minterBuyOfferIndex =
1914 env(token::createOffer(minter, nftMinterNoTransferID, XRP(26)), token::Owner(becky));
1920 env(token::clearMinter(alice));
1926 env(token::acceptBuyOffer(becky, minterBuyOfferIndex));
1934 env(token::burn(minter, nftMinterNoTransferID), Ter(
tesSUCCESS));
1936 env(token::cancelOffer(alice, {aliceBuyOfferIndex}));
1946 UInt256 const nftAliceID{token::getNextID(env, alice, 0u, tfTransferable)};
1947 env(token::mint(alice, 0u), Txflags(tfTransferable));
1952 UInt256 const aliceSellOfferIndex =
1954 env(token::createOffer(alice, nftAliceID, XRP(20)), Txflags(tfSellNFToken));
1958 UInt256 const beckyBuyOfferIndex =
1960 env(token::createOffer(becky, nftAliceID, XRP(21)), token::Owner(alice));
1965 env(token::acceptSellOffer(becky, aliceSellOfferIndex));
1971 UInt256 const beckySellOfferIndex =
1973 env(token::createOffer(becky, nftAliceID, XRP(22)), Txflags(tfSellNFToken));
1980 env(token::acceptSellOffer(minter, beckySellOfferIndex));
1987 UInt256 const minterSellOfferIndex =
1989 env(token::createOffer(minter, nftAliceID, XRP(23)), Txflags(tfSellNFToken));
1996 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2004 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2012 env(token::burn(becky, nftAliceID));
2028 Env env{*
this, features};
2029 auto const baseFee = env.current()->fees().base;
2034 Account const minter{
"minter"};
2036 IOU
const gwXAU(gw[
"XAU"]);
2038 env.fund(XRP(1000), alice, becky, carol, minter, gw);
2041 env(trust(alice, gwXAU(2000)));
2042 env(trust(becky, gwXAU(2000)));
2043 env(trust(carol, gwXAU(2000)));
2044 env(trust(minter, gwXAU(2000)));
2046 env(pay(gw, alice, gwXAU(1000)));
2047 env(pay(gw, becky, gwXAU(1000)));
2048 env(pay(gw, carol, gwXAU(1000)));
2049 env(pay(gw, minter, gwXAU(1000)));
2054 env(token::setMinter(alice, minter));
2065 UInt256 const nftID = token::getNextID(env, alice, 0u, tfTransferable);
2066 env(token::mint(alice), Txflags(tfTransferable));
2070 UInt256 const beckyBuyOfferIndex =
2072 env(token::createOffer(becky, nftID, gwXAU(10)), token::Owner(alice));
2074 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2075 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2077 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2079 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2080 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2083 UInt256 const beckySellOfferIndex =
2085 env(token::createOffer(becky, nftID, gwXAU(10)), Txflags(tfSellNFToken));
2087 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2089 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2090 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2091 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2094 UInt256 const minterBuyOfferIndex =
2096 env(token::createOffer(minter, nftID, gwXAU(10)), token::Owner(carol));
2098 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2100 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2101 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2102 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2103 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2107 UInt256 const minterSellOfferIndex =
2109 env(token::createOffer(minter, nftID, gwXAU(10)), Txflags(tfSellNFToken));
2111 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2113 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2114 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2115 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2116 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2119 env(token::burn(alice, nftID));
2130 UInt256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1);
2131 env(token::mint(alice), Txflags(tfTransferable), token::XferFee(1));
2135 UInt256 const beckyBuyOfferIndex =
2137 env(token::createOffer(becky, nftID, gwXAU(10)), token::Owner(alice));
2139 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2140 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2142 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2144 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2145 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2148 UInt256 const beckySellOfferIndex =
2150 env(token::createOffer(becky, nftID, gwXAU(10)), Txflags(tfSellNFToken));
2152 env(token::acceptSellOffer(carol, beckySellOfferIndex));
2155 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2156 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2157 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2160 UInt256 const minterBuyOfferIndex =
2162 env(token::createOffer(minter, nftID, gwXAU(10)), token::Owner(carol));
2164 env(token::acceptBuyOffer(carol, minterBuyOfferIndex));
2167 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2168 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2169 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2170 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2174 UInt256 const minterSellOfferIndex =
2176 env(token::createOffer(minter, nftID, gwXAU(10)), Txflags(tfSellNFToken));
2178 env(token::acceptSellOffer(alice, minterSellOfferIndex));
2180 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2181 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2182 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2183 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2187 env(pay(alice, becky, gwXAU(0.0001)));
2188 env(pay(alice, carol, gwXAU(0.0001)));
2191 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2192 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2193 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2194 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2197 env(token::burn(alice, nftID));
2208 env(token::mint(alice),
2209 Txflags(tfTransferable),
2216 env(token::mint(alice), Txflags(tfTransferable), token::XferFee(
kMaxTransferFee));
2220 UInt256 const beckyBuyOfferIndex =
2222 env(token::createOffer(becky, nftID, gwXAU(10)), token::Owner(alice));
2224 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2225 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2227 env(token::acceptBuyOffer(alice, beckyBuyOfferIndex));
2229 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2230 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2233 UInt256 const beckySellOfferIndex =
2235 env(token::createOffer(becky, nftID, gwXAU(100)), Txflags(tfSellNFToken));
2237 env(token::acceptSellOffer(minter, beckySellOfferIndex));
2240 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2241 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2242 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2245 UInt256 const carolBuyOfferIndex =
2247 env(token::createOffer(carol, nftID, gwXAU(10)), token::Owner(minter));
2249 env(token::acceptBuyOffer(minter, carolBuyOfferIndex));
2252 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2253 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2254 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2255 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2259 UInt256 const carolSellOfferIndex =
2261 env(token::createOffer(carol, nftID, gwXAU(10)), Txflags(tfSellNFToken));
2263 env(token::acceptSellOffer(alice, carolSellOfferIndex));
2266 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2267 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2268 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2269 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2272 env(pay(alice, minter, gwXAU(55)));
2273 env(pay(becky, minter, gwXAU(40)));
2275 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2276 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2277 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2278 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2281 env(token::burn(alice, nftID));
2293 UInt256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1);
2294 env(token::mint(alice), Txflags(tfTransferable), token::XferFee(1));
2299 STAmount aliceBalance = env.balance(alice);
2300 STAmount minterBalance = env.balance(minter);
2301 UInt256 const minterBuyOfferIndex =
2303 env(token::createOffer(minter, nftID, XRP(1)), token::Owner(alice));
2305 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2307 aliceBalance += XRP(1) - baseFee;
2308 minterBalance -= XRP(1) + baseFee;
2309 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2310 BEAST_EXPECT(env.balance(minter) == minterBalance);
2314 auto pmt = drops(50000);
2315 STAmount carolBalance = env.balance(carol);
2316 UInt256 const minterSellOfferIndex =
2318 env(token::createOffer(minter, nftID, pmt), Txflags(tfSellNFToken));
2320 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2322 minterBalance += pmt - baseFee;
2323 carolBalance -= pmt + baseFee;
2324 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2325 BEAST_EXPECT(env.balance(minter) == minterBalance);
2326 BEAST_EXPECT(env.balance(carol) == carolBalance);
2330 STAmount beckyBalance = env.balance(becky);
2331 UInt256 const beckyBuyOfferIndex =
2334 env(token::createOffer(becky, nftID, pmt), token::Owner(carol));
2336 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2338 carolBalance += pmt - drops(1) - baseFee;
2339 beckyBalance -= pmt + baseFee;
2340 aliceBalance += drops(1);
2342 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2343 BEAST_EXPECT(env.balance(minter) == minterBalance);
2344 BEAST_EXPECT(env.balance(carol) == carolBalance);
2345 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2352 UInt256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1);
2353 env(token::mint(alice), Txflags(tfTransferable), token::XferFee(1));
2359 env(pay(alice, gw, env.balance(alice, gwXAU)));
2360 env(pay(minter, gw, env.balance(minter, gwXAU)));
2361 env(pay(becky, gw, env.balance(becky, gwXAU)));
2365 env(pay(gw, alice, startXAUBalance));
2366 env(pay(gw, minter, startXAUBalance));
2367 env(pay(gw, becky, startXAUBalance));
2375 STAmount aliceBalance = env.balance(alice, gwXAU);
2376 STAmount minterBalance = env.balance(minter, gwXAU);
2377 UInt256 const minterBuyOfferIndex =
2379 env(token::createOffer(minter, nftID, tinyXAU), token::Owner(alice));
2381 env(token::acceptBuyOffer(alice, minterBuyOfferIndex));
2383 aliceBalance += tinyXAU;
2384 minterBalance -= tinyXAU;
2385 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2386 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2389 STAmount carolBalance = env.balance(carol, gwXAU);
2390 UInt256 const minterSellOfferIndex =
2392 env(token::createOffer(minter, nftID, tinyXAU), Txflags(tfSellNFToken));
2394 env(token::acceptSellOffer(carol, minterSellOfferIndex));
2397 minterBalance += tinyXAU;
2398 carolBalance -= tinyXAU;
2400 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2401 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2402 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2408 STAmount beckyBalance = env.balance(becky, gwXAU);
2409 UInt256 const beckyBuyOfferIndex =
2411 env(token::createOffer(becky, nftID, cheapNFT), token::Owner(carol));
2413 env(token::acceptBuyOffer(carol, beckyBuyOfferIndex));
2416 aliceBalance += tinyXAU;
2417 beckyBalance -= cheapNFT;
2418 carolBalance += cheapNFT - tinyXAU;
2419 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2420 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2421 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2422 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2615 testcase(
"Create offer destination");
2619 Env env{*
this, features};
2621 Account const issuer{
"issuer"};
2622 Account const minter{
"minter"};
2624 Account const broker{
"broker"};
2626 env.fund(XRP(1000), issuer, minter, buyer, broker);
2630 env(token::setMinter(issuer, minter));
2633 UInt256 const nftokenID = token::getNextID(env, issuer, 0, tfTransferable);
2634 env(token::mint(minter, 0), token::Issuer(issuer), Txflags(tfTransferable));
2640 UInt256 const offerMinterToIssuer =
2642 env(token::createOffer(minter, nftokenID, drops(1)),
2643 token::Destination(issuer),
2644 Txflags(tfSellNFToken));
2646 UInt256 const offerMinterToBuyer =
2648 env(token::createOffer(minter, nftokenID, drops(1)),
2649 token::Destination(buyer),
2650 Txflags(tfSellNFToken));
2652 UInt256 const offerIssuerToMinter =
2654 env(token::createOffer(issuer, nftokenID, drops(1)),
2655 token::Owner(minter),
2656 token::Destination(minter));
2658 UInt256 const offerIssuerToBuyer =
2660 env(token::createOffer(issuer, nftokenID, drops(1)),
2661 token::Owner(minter),
2662 token::Destination(buyer));
2676 env(token::cancelOffer(issuer, {offerMinterToBuyer}), Ter(
tecNO_PERMISSION));
2677 env(token::cancelOffer(buyer, {offerMinterToIssuer}), Ter(
tecNO_PERMISSION));
2678 env(token::cancelOffer(buyer, {offerIssuerToMinter}), Ter(
tecNO_PERMISSION));
2679 env(token::cancelOffer(minter, {offerIssuerToBuyer}), Ter(
tecNO_PERMISSION));
2687 env(token::cancelOffer(buyer, {offerMinterToBuyer}));
2688 env(token::cancelOffer(minter, {offerMinterToIssuer}));
2689 env(token::cancelOffer(buyer, {offerIssuerToBuyer}));
2690 env(token::cancelOffer(issuer, {offerIssuerToMinter}));
2700 UInt256 const offerMinterSellsToBuyer =
2702 env(token::createOffer(minter, nftokenID, drops(1)),
2703 token::Destination(buyer),
2704 Txflags(tfSellNFToken));
2712 env(token::acceptSellOffer(issuer, offerMinterSellsToBuyer), Ter(
tecNO_PERMISSION));
2719 env(token::acceptSellOffer(buyer, offerMinterSellsToBuyer));
2729 UInt256 const offerMinterBuysFromBuyer =
2731 env(token::createOffer(minter, nftokenID, drops(1)),
2732 token::Owner(buyer),
2733 token::Destination(buyer));
2741 env(token::acceptBuyOffer(issuer, offerMinterBuysFromBuyer), Ter(
tecNO_PERMISSION));
2748 env(token::acceptBuyOffer(buyer, offerMinterBuysFromBuyer));
2757 UInt256 const offerBuyerBuysFromMinter =
2759 env(token::createOffer(buyer, nftokenID, drops(1)),
2760 token::Owner(minter),
2761 token::Destination(broker));
2767 env(token::acceptBuyOffer(minter, offerBuyerBuysFromMinter), Ter(
tecNO_PERMISSION));
2771 env(token::cancelOffer(buyer, {offerBuyerBuysFromMinter}));
2781 UInt256 const offerMinterToBroker =
2783 env(token::createOffer(minter, nftokenID, drops(1)),
2784 token::Destination(broker),
2785 Txflags(tfSellNFToken));
2787 UInt256 const offerBuyerToMinter =
2789 env(token::createOffer(buyer, nftokenID, drops(1)), token::Owner(minter));
2799 env(token::brokerOffers(issuer, offerBuyerToMinter, offerMinterToBroker),
2809 env(token::brokerOffers(broker, offerBuyerToMinter, offerMinterToBroker));
2820 UInt256 const offerBuyerToMinter =
2822 env(token::createOffer(buyer, nftokenID, drops(1)),
2823 token::Destination(minter),
2824 Txflags(tfSellNFToken));
2826 UInt256 const offerMinterToBuyer =
2828 env(token::createOffer(minter, nftokenID, drops(1)), token::Owner(buyer));
2830 UInt256 const offerIssuerToBuyer =
2832 env(token::createOffer(issuer, nftokenID, drops(1)), token::Owner(buyer));
2842 env(token::brokerOffers(broker, offerIssuerToBuyer, offerBuyerToMinter),
2850 env(token::brokerOffers(broker, offerMinterToBuyer, offerBuyerToMinter),
2855 env(token::acceptBuyOffer(buyer, offerMinterToBuyer));
2859 env(token::cancelOffer(buyer, {offerBuyerToMinter}));
2867 env(token::cancelOffer(issuer, {offerIssuerToBuyer}));
2879 UInt256 const offerMinterToBroker =
2881 env(token::createOffer(minter, nftokenID, drops(1)),
2882 token::Destination(broker),
2883 Txflags(tfSellNFToken));
2885 UInt256 const offerBuyerToBroker =
2887 env(token::createOffer(buyer, nftokenID, drops(1)),
2888 token::Owner(minter),
2889 token::Destination(broker));
2894 env(token::brokerOffers(issuer, offerBuyerToBroker, offerMinterToBroker),
2903 env(token::brokerOffers(broker, offerBuyerToBroker, offerMinterToBroker));
3047 testcase(
"Create offer expiration");
3051 Env env{*
this, features};
3053 Account const issuer{
"issuer"};
3054 Account const minter{
"minter"};
3057 env.fund(XRP(1000), issuer, minter, buyer);
3061 env(token::setMinter(issuer, minter));
3064 UInt256 const nftokenID0 = token::getNextID(env, issuer, 0, tfTransferable);
3065 env(token::mint(minter, 0), token::Issuer(issuer), Txflags(tfTransferable));
3068 UInt256 const nftokenID1 = token::getNextID(env, issuer, 0, tfTransferable);
3069 env(token::mint(minter, 0), token::Issuer(issuer), Txflags(tfTransferable));
3071 uint8_t issuerCount = 0, minterCount = 0, buyerCount = 0;
3078 UInt256 const offerMinterToIssuer =
3080 env(token::createOffer(minter, nftokenID0, drops(1)),
3081 token::Destination(issuer),
3082 token::Expiration(expiration),
3083 Txflags(tfSellNFToken));
3085 UInt256 const offerMinterToAnyone =
3087 env(token::createOffer(minter, nftokenID0, drops(1)),
3088 token::Expiration(expiration),
3089 Txflags(tfSellNFToken));
3091 UInt256 const offerIssuerToMinter =
3093 env(token::createOffer(issuer, nftokenID0, drops(1)),
3094 token::Owner(minter),
3095 token::Expiration(expiration));
3097 UInt256 const offerBuyerToMinter =
3099 env(token::createOffer(buyer, nftokenID0, drops(1)),
3100 token::Owner(minter),
3101 token::Expiration(expiration));
3106 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3107 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3108 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3116 env(token::cancelOffer(issuer, {offerMinterToAnyone}), Ter(
tecNO_PERMISSION));
3117 env(token::cancelOffer(buyer, {offerIssuerToMinter}), Ter(
tecNO_PERMISSION));
3119 BEAST_EXPECT(
lastClose(env) < expiration);
3120 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3121 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3122 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3125 env(token::cancelOffer(minter, {offerMinterToAnyone}));
3130 env(token::cancelOffer(issuer, {offerMinterToIssuer}));
3137 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3138 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3139 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3142 env(token::cancelOffer(issuer, {offerBuyerToMinter}));
3144 env(token::cancelOffer(buyer, {offerIssuerToMinter}));
3147 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3148 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3149 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3160 env(token::createOffer(minter, nftokenID0, drops(1)),
3161 token::Expiration(expiration),
3162 Txflags(tfSellNFToken));
3167 env(token::createOffer(minter, nftokenID1, drops(1)),
3168 token::Expiration(expiration),
3169 Txflags(tfSellNFToken));
3172 BEAST_EXPECT(
lastClose(env) < expiration);
3173 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3174 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3175 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3178 env(token::acceptSellOffer(buyer, offer0));
3186 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3187 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3188 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3191 env(token::acceptSellOffer(buyer, offer1), Ter(
tecEXPIRED));
3196 if (features[fixCleanup3_1_3])
3206 env(token::acceptSellOffer(issuer, offer1), Ter(
tecEXPIRED));
3211 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3212 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3213 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3215 if (!features[fixCleanup3_1_3])
3219 env(token::cancelOffer(issuer, {offer1}));
3225 BEAST_EXPECT(
ownerCount(env, issuer) == 0 && issuerCount == 0);
3226 BEAST_EXPECT(
ownerCount(env, minter) == 1 && minterCount == 1);
3227 BEAST_EXPECT(
ownerCount(env, buyer) == 1 && buyerCount == 1);
3233 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3234 Txflags(tfSellNFToken),
3235 token::Destination(minter));
3237 env(token::acceptSellOffer(minter, offerSellBack));
3240 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3241 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3242 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3253 env(token::createOffer(buyer, nftokenID0, drops(1)),
3254 token::Owner(minter),
3255 token::Expiration(expiration));
3260 env(token::createOffer(buyer, nftokenID1, drops(1)),
3261 token::Owner(minter),
3262 token::Expiration(expiration));
3265 BEAST_EXPECT(
lastClose(env) < expiration);
3266 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3267 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3268 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3271 env(token::acceptBuyOffer(minter, offer0));
3277 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3278 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3279 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3282 env(token::acceptBuyOffer(minter, offer1), Ter(
tecEXPIRED));
3287 if (features[fixCleanup3_1_3])
3297 env(token::acceptBuyOffer(issuer, offer1), Ter(
tecEXPIRED));
3302 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3303 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3304 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3306 if (!features[fixCleanup3_1_3])
3310 env(token::cancelOffer(issuer, {offer1}));
3316 BEAST_EXPECT(
ownerCount(env, issuer) == 0 && issuerCount == 0);
3317 BEAST_EXPECT(
ownerCount(env, minter) == 1 && minterCount == 1);
3318 BEAST_EXPECT(
ownerCount(env, buyer) == 1 && buyerCount == 1);
3324 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3325 Txflags(tfSellNFToken),
3326 token::Destination(minter));
3328 env(token::acceptSellOffer(minter, offerSellBack));
3331 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3332 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3333 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3344 env(token::createOffer(minter, nftokenID0, drops(1)),
3345 token::Expiration(expiration),
3346 Txflags(tfSellNFToken));
3351 env(token::createOffer(minter, nftokenID1, drops(1)),
3352 token::Expiration(expiration),
3353 Txflags(tfSellNFToken));
3358 env(token::createOffer(buyer, nftokenID0, drops(1)), token::Owner(minter));
3363 env(token::createOffer(buyer, nftokenID1, drops(1)), token::Owner(minter));
3367 BEAST_EXPECT(
lastClose(env) < expiration);
3368 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3369 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3370 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3373 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3380 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3381 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3382 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3385 env(token::brokerOffers(issuer, buyOffer1, sellOffer1), Ter(
tecEXPIRED));
3388 if (features[fixCleanup3_1_3])
3394 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3395 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3396 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3398 if (features[fixCleanup3_1_3])
3402 env(token::cancelOffer(buyer, {buyOffer1}));
3408 env(token::cancelOffer(buyer, {buyOffer1, sellOffer1}));
3415 BEAST_EXPECT(
ownerCount(env, issuer) == 0 && issuerCount == 0);
3416 BEAST_EXPECT(
ownerCount(env, minter) == 1 && minterCount == 1);
3417 BEAST_EXPECT(
ownerCount(env, buyer) == 1 && buyerCount == 1);
3423 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3424 Txflags(tfSellNFToken),
3425 token::Destination(minter));
3427 env(token::acceptSellOffer(minter, offerSellBack));
3430 BEAST_EXPECT(
ownerCount(env, issuer) == issuerCount);
3431 BEAST_EXPECT(
ownerCount(env, minter) == minterCount);
3432 BEAST_EXPECT(
ownerCount(env, buyer) == buyerCount);
3443 env(token::createOffer(minter, nftokenID0, drops(1)), Txflags(tfSellNFToken));
3447 env(token::createOffer(minter, nftokenID1, drops(1)), Txflags(tfSellNFToken));
3451 env(token::createOffer(buyer, nftokenID0, drops(1)),
3452 token::Expiration(expiration),
3453 token::Owner(minter));
3457 env(token::createOffer(buyer, nftokenID1, drops(1)),
3458 token::Expiration(expiration),
3459 token::Owner(minter));
3462 BEAST_EXPECT(
lastClose(env) < expiration);
3468 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3478 env(token::brokerOffers(issuer, buyOffer1, sellOffer1), Ter(
tecEXPIRED));
3482 if (features[fixCleanup3_1_3])
3490 env(token::cancelOffer(minter, {sellOffer1}));
3498 env(token::cancelOffer(minter, {buyOffer1, sellOffer1}));
3509 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3510 Txflags(tfSellNFToken),
3511 token::Destination(minter));
3513 env(token::acceptSellOffer(minter, offerSellBack));
3529 env(token::createOffer(minter, nftokenID0, drops(1)),
3530 token::Expiration(expiration),
3531 Txflags(tfSellNFToken));
3535 env(token::createOffer(minter, nftokenID1, drops(1)),
3536 token::Expiration(expiration),
3537 Txflags(tfSellNFToken));
3541 env(token::createOffer(buyer, nftokenID0, drops(1)),
3542 token::Expiration(expiration),
3543 token::Owner(minter));
3547 env(token::createOffer(buyer, nftokenID1, drops(1)),
3548 token::Expiration(expiration),
3549 token::Owner(minter));
3552 BEAST_EXPECT(
lastClose(env) < expiration);
3558 env(token::brokerOffers(issuer, buyOffer0, sellOffer0));
3568 env(token::brokerOffers(issuer, buyOffer1, sellOffer1), Ter(
tecEXPIRED));
3573 if (!features[fixCleanup3_1_3])
3579 env(token::cancelOffer(issuer, {buyOffer1, sellOffer1}));
3590 env(token::createOffer(buyer, nftokenID0, XRP(0)),
3591 Txflags(tfSellNFToken),
3592 token::Destination(minter));
3594 env(token::acceptSellOffer(minter, offerSellBack));
3823 testcase(
"Brokered NFT offer accept");
3828 Env env{*
this, features};
3829 auto const baseFee = env.current()->fees().base;
3837 Account const issuer{
"issuer"};
3838 Account const minter{
"minter"};
3840 Account const broker{
"broker"};
3842 IOU
const gwXAU(gw[
"XAU"]);
3844 env.fund(XRP(1000), issuer, minter, buyer, broker, gw);
3847 env(trust(issuer, gwXAU(2000)));
3848 env(trust(minter, gwXAU(2000)));
3849 env(trust(buyer, gwXAU(2000)));
3850 env(trust(broker, gwXAU(2000)));
3853 env(token::setMinter(issuer, minter));
3857 auto checkOwnerCountIsOne =
3861 for (
Account const& acct : accounts)
3867 ss <<
"Account " << acct.human() <<
" expected ownerCount == 1. Got "
3869 fail(ss.
str(), __FILE__, line);
3875 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3876 UInt256 const nftID = token::getNextID(env, issuer, 0, tfTransferable, xferFee);
3877 env(token::mint(minter, 0),
3878 token::Issuer(issuer),
3879 token::XferFee(xferFee),
3880 Txflags(tfTransferable));
3891 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3893 UInt256 const nftID = mintNFT();
3896 UInt256 const minterOfferIndex =
3898 env(token::createOffer(minter, nftID, XRP(0)), Txflags(tfSellNFToken));
3905 env(token::createOffer(buyer, nftID, XRP(1)), token::Owner(minter));
3908 auto const minterBalance = env.balance(minter);
3909 auto const buyerBalance = env.balance(buyer);
3910 auto const brokerBalance = env.balance(broker);
3911 auto const issuerBalance = env.balance(issuer);
3914 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
3919 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(1));
3920 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3921 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
3922 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3925 env(token::burn(buyer, nftID));
3935 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3937 UInt256 const nftID = mintNFT();
3940 UInt256 const minterOfferIndex =
3942 env(token::createOffer(minter, nftID, XRP(0)), Txflags(tfSellNFToken));
3949 env(token::createOffer(buyer, nftID, XRP(1)), token::Owner(minter));
3953 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3954 token::BrokerFee(XRP(1.1)),
3958 auto const minterBalance = env.balance(minter);
3959 auto const buyerBalance = env.balance(buyer);
3960 auto const brokerBalance = env.balance(broker);
3961 auto const issuerBalance = env.balance(issuer);
3964 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
3965 token::BrokerFee(XRP(0.5)));
3970 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
3971 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
3972 BEAST_EXPECT(env.balance(broker) == brokerBalance + XRP(0.5) - baseFee);
3973 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
3976 env(token::burn(buyer, nftID));
3986 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3991 UInt256 const minterOfferIndex =
3993 env(token::createOffer(minter, nftID, XRP(0)), Txflags(tfSellNFToken));
4000 env(token::createOffer(buyer, nftID, XRP(1)), token::Owner(minter));
4003 auto const minterBalance = env.balance(minter);
4004 auto const buyerBalance = env.balance(buyer);
4005 auto const brokerBalance = env.balance(broker);
4006 auto const issuerBalance = env.balance(issuer);
4009 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
4014 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.5));
4015 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4016 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
4017 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.5));
4020 env(token::burn(buyer, nftID));
4030 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4035 UInt256 const minterOfferIndex =
4037 env(token::createOffer(minter, nftID, XRP(0)), Txflags(tfSellNFToken));
4044 env(token::createOffer(buyer, nftID, XRP(1)), token::Owner(minter));
4047 auto const minterBalance = env.balance(minter);
4048 auto const buyerBalance = env.balance(buyer);
4049 auto const brokerBalance = env.balance(broker);
4050 auto const issuerBalance = env.balance(issuer);
4053 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4054 token::BrokerFee(XRP(0.75)));
4060 BEAST_EXPECT(env.balance(minter) == minterBalance + XRP(0.125));
4061 BEAST_EXPECT(env.balance(buyer) == buyerBalance - XRP(1));
4062 BEAST_EXPECT(env.balance(broker) == brokerBalance + XRP(0.75) - baseFee);
4063 BEAST_EXPECT(env.balance(issuer) == issuerBalance + XRP(0.125));
4066 env(token::burn(buyer, nftID));
4072 auto setXAUBalance =
4073 [
this, &gw, &gwXAU, &env](
4077 for (
Account const& acct : accounts)
4079 auto const xauAmt = gwXAU(amount);
4080 auto const balance = env.balance(acct, gwXAU);
4081 if (balance < xauAmt)
4083 env(pay(gw, acct, xauAmt - balance));
4086 else if (balance > xauAmt)
4088 env(pay(acct, gw, balance - xauAmt));
4091 if (env.balance(acct, gwXAU) != xauAmt)
4094 ss <<
"Unable to set " << acct.human() <<
" account balance to gwXAU("
4096 this->
fail(ss.
str(), __FILE__, line);
4104 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4105 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4107 UInt256 const nftID = mintNFT();
4110 UInt256 const minterOfferIndex =
4112 env(token::createOffer(minter, nftID, gwXAU(1000)), Txflags(tfSellNFToken));
4120 env(token::createOffer(buyer, nftID, gwXAU(1001)), token::Owner(minter));
4124 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4130 env(token::cancelOffer(buyer, {buyOfferIndex}));
4138 env(token::createOffer(buyer, nftID, gwXAU(999)), token::Owner(minter));
4142 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4148 env(token::cancelOffer(buyer, {buyOfferIndex}));
4155 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::Owner(minter));
4159 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4160 token::BrokerFee(gwXAU(0.1)),
4165 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex));
4172 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4173 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4174 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4175 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4178 env(token::burn(buyer, nftID));
4185 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4186 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4191 UInt256 const minterOfferIndex =
4193 env(token::createOffer(minter, nftID, gwXAU(900)), Txflags(tfSellNFToken));
4200 env(token::createOffer(buyer, nftID, gwXAU(1001)), token::Owner(minter));
4204 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4210 env(token::cancelOffer(buyer, {buyOfferIndex}));
4218 env(token::createOffer(buyer, nftID, gwXAU(899)), token::Owner(minter));
4222 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4228 env(token::cancelOffer(buyer, {buyOfferIndex}));
4234 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::Owner(minter));
4239 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4240 token::BrokerFee(gwXAU(101)),
4246 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4247 token::BrokerFee(gwXAU(100)));
4254 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4255 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4256 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4257 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4260 env(token::burn(buyer, nftID));
4267 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4268 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4273 UInt256 const minterOfferIndex =
4275 env(token::createOffer(minter, nftID, gwXAU(900)), Txflags(tfSellNFToken));
4281 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::Owner(minter));
4287 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4288 token::BrokerFee(gwXAU(50)));
4295 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4296 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4297 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4298 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4301 env(token::burn(buyer, nftID));
4306 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4307 setXAUBalance({issuer, minter, buyer}, 1000, __LINE__);
4308 setXAUBalance({broker}, 500, __LINE__);
4312 UInt256 const minterOfferIndex =
4314 env(token::createOffer(minter, nftID, gwXAU(900)), Txflags(tfSellNFToken));
4320 env(token::createOffer(buyer, nftID, gwXAU(1000)), token::Owner(minter));
4323 env(token::brokerOffers(broker, buyOfferIndex, minterOfferIndex),
4324 token::BrokerFee(gwXAU(50)));
4330 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4331 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4332 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4333 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(550));
4336 env(token::burn(buyer, nftID));
4998 testcase(
"Payments with IOU transfer fees");
5001 Env env{*
this, features};
5003 Account const minter{
"minter"};
5004 Account const secondarySeller{
"seller"};
5007 Account const broker{
"broker"};
5008 IOU
const gwXAU(gw[
"XAU"]);
5009 IOU
const gwXPB(gw[
"XPB"]);
5011 env.fund(XRP(1000), gw, minter, secondarySeller, buyer, broker);
5014 env(trust(minter, gwXAU(2000)));
5015 env(trust(secondarySeller, gwXAU(2000)));
5016 env(trust(broker, gwXAU(10000)));
5017 env(trust(buyer, gwXAU(2000)));
5018 env(trust(buyer, gwXPB(2000)));
5022 env(rate(gw, 1.02));
5025 auto expectInitialState =
5026 [
this, &env, &buyer, &minter, &secondarySeller, &broker, &gw, &gwXAU, &gwXPB]() {
5031 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
5032 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(0));
5033 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(0));
5034 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(0));
5035 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(0));
5036 BEAST_EXPECT(env.balance(secondarySeller, gwXPB) == gwXPB(0));
5037 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5000));
5038 BEAST_EXPECT(env.balance(broker, gwXPB) == gwXPB(0));
5039 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-1000));
5040 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(0));
5041 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(0));
5042 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(0));
5043 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(0));
5044 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XPB"]) == gwXPB(0));
5045 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5000));
5046 BEAST_EXPECT(env.balance(gw, broker[
"XPB"]) == gwXPB(0));
5049 auto reinitializeTrustLineBalances = [&expectInitialState,
5058 if (
auto const difference = gwXAU(1000) - env.balance(buyer, gwXAU);
5059 difference > gwXAU(0))
5060 env(pay(gw, buyer, difference));
5061 if (env.balance(buyer, gwXPB) > gwXPB(0))
5062 env(pay(buyer, gw, env.balance(buyer, gwXPB)));
5063 if (env.balance(minter, gwXAU) > gwXAU(0))
5064 env(pay(minter, gw, env.balance(minter, gwXAU)));
5065 if (env.balance(minter, gwXPB) > gwXPB(0))
5066 env(pay(minter, gw, env.balance(minter, gwXPB)));
5067 if (env.balance(secondarySeller, gwXAU) > gwXAU(0))
5068 env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXAU)));
5069 if (env.balance(secondarySeller, gwXPB) > gwXPB(0))
5070 env(pay(secondarySeller, gw, env.balance(secondarySeller, gwXPB)));
5071 auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU);
5072 if (brokerDiff > gwXAU(0))
5074 env(pay(gw, broker, brokerDiff));
5076 else if (brokerDiff < gwXAU(0))
5078 brokerDiff.negate();
5079 env(pay(broker, gw, brokerDiff));
5081 if (env.balance(broker, gwXPB) > gwXPB(0))
5082 env(pay(broker, gw, env.balance(broker, gwXPB)));
5084 expectInitialState();
5087 auto mintNFT = [&env](
Account const& minter,
int transferFee = 0) {
5088 UInt256 const nftID = token::getNextID(env, minter, 0, tfTransferable, transferFee);
5089 env(token::mint(minter), token::XferFee(transferFee), Txflags(tfTransferable));
5094 auto createBuyOffer = [&env](
5102 env(token::createOffer(offerer, nftID, amount),
5103 token::Owner(owner),
5104 terCode ? Ter(*terCode) : Ter(
static_cast<TER>(
tesSUCCESS)));
5109 auto createSellOffer = [&env](
5116 env(token::createOffer(offerer, nftID, amount),
5117 Txflags(tfSellNFToken),
5118 terCode ? Ter(*terCode) : Ter(
static_cast<TER>(
tesSUCCESS)));
5126 reinitializeTrustLineBalances();
5127 auto const nftID = mintNFT(minter);
5128 auto const offerID = createSellOffer(minter, nftID, gwXAU(1000));
5130 env(token::acceptSellOffer(buyer, offerID), Ter(sellTER));
5133 expectInitialState();
5138 reinitializeTrustLineBalances();
5139 auto const nftID = mintNFT(minter);
5140 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5142 env(token::acceptBuyOffer(minter, offerID), Ter(sellTER));
5145 expectInitialState();
5151 reinitializeTrustLineBalances();
5152 auto const nftID = mintNFT(minter);
5153 auto const offerID = createSellOffer(minter, nftID, gwXAU(995));
5155 env(token::acceptSellOffer(buyer, offerID), Ter(sellTER));
5158 expectInitialState();
5164 reinitializeTrustLineBalances();
5165 auto const nftID = mintNFT(minter);
5166 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(995));
5168 env(token::acceptBuyOffer(minter, offerID), Ter(sellTER));
5171 expectInitialState();
5178 reinitializeTrustLineBalances();
5179 auto const nftID = mintNFT(minter);
5180 auto const offerID = createSellOffer(minter, nftID, gwXAU(900));
5181 env(token::acceptSellOffer(buyer, offerID));
5184 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5185 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5186 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5187 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5194 reinitializeTrustLineBalances();
5195 auto const nftID = mintNFT(minter);
5196 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(900));
5197 env(token::acceptBuyOffer(minter, offerID));
5200 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5201 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5202 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5203 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5210 reinitializeTrustLineBalances();
5213 env(pay(gw, buyer, gwXAU(20)));
5216 auto const nftID = mintNFT(minter);
5217 auto const offerID = createSellOffer(minter, nftID, gwXAU(1000));
5218 env(token::acceptSellOffer(buyer, offerID));
5221 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5222 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5223 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5224 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5231 reinitializeTrustLineBalances();
5234 env(pay(gw, buyer, gwXAU(20)));
5237 auto const nftID = mintNFT(minter);
5238 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5239 env(token::acceptBuyOffer(minter, offerID));
5242 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5243 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5244 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5245 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5250 reinitializeTrustLineBalances();
5252 auto const nftID = mintNFT(minter);
5253 auto const offerID = createSellOffer(minter, nftID, gwXAU(1000));
5255 env(token::acceptSellOffer(gw, offerID), Ter(sellTER));
5258 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5259 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5264 reinitializeTrustLineBalances();
5266 auto const nftID = mintNFT(minter);
5268 auto const offerID = createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER});
5270 env(token::acceptBuyOffer(minter, offerID), Ter(sellTER));
5273 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5274 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5279 reinitializeTrustLineBalances();
5280 auto const nftID = mintNFT(minter);
5281 auto const offerID = createSellOffer(minter, nftID, gwXAU(5000));
5283 env(token::acceptSellOffer(gw, offerID), Ter(sellTER));
5286 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5287 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5292 reinitializeTrustLineBalances();
5294 auto const nftID = mintNFT(minter);
5296 auto const offerID = createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER});
5298 env(token::acceptBuyOffer(minter, offerID), Ter(sellTER));
5301 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5302 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5308 reinitializeTrustLineBalances();
5309 auto const nftID = mintNFT(gw);
5310 auto const offerID = createSellOffer(gw, nftID, gwXAU(1000));
5311 env(token::acceptSellOffer(buyer, offerID));
5314 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5315 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5321 reinitializeTrustLineBalances();
5323 auto const nftID = mintNFT(gw);
5324 auto const offerID = createBuyOffer(buyer, gw, nftID, gwXAU(1000));
5325 env(token::acceptBuyOffer(gw, offerID));
5328 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5329 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5335 reinitializeTrustLineBalances();
5336 auto const nftID = mintNFT(gw);
5337 auto const offerID = createSellOffer(gw, nftID, gwXAU(2000));
5338 env(token::acceptSellOffer(buyer, offerID),
5341 expectInitialState();
5347 reinitializeTrustLineBalances();
5348 auto const nftID = mintNFT(gw);
5349 auto const offerID = createBuyOffer(buyer, gw, nftID, gwXAU(2000));
5350 env(token::acceptBuyOffer(gw, offerID),
5353 expectInitialState();
5358 reinitializeTrustLineBalances();
5359 auto const nftID = mintNFT(minter);
5360 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5361 env(token::acceptSellOffer(buyer, offerID),
5364 expectInitialState();
5369 reinitializeTrustLineBalances();
5370 auto const nftID = mintNFT(minter);
5371 auto const offerID = createBuyOffer(
5373 env(token::acceptBuyOffer(minter, offerID),
5376 expectInitialState();
5382 reinitializeTrustLineBalances();
5383 env(pay(gw, buyer, gwXPB(100)));
5386 auto const nftID = mintNFT(minter);
5387 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5388 env(token::acceptSellOffer(buyer, offerID));
5391 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5392 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5393 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5394 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5400 reinitializeTrustLineBalances();
5401 env(pay(gw, buyer, gwXPB(100)));
5404 auto const nftID = mintNFT(minter);
5405 auto const offerID = createBuyOffer(buyer, minter, nftID, gwXPB(10));
5406 env(token::acceptBuyOffer(minter, offerID));
5409 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5410 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5411 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5412 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5417 reinitializeTrustLineBalances();
5421 auto const nftID = mintNFT(minter, 3000);
5422 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5423 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5427 auto const offerID = createSellOffer(secondarySeller, nftID, gwXAU(1000));
5429 env(token::acceptSellOffer(buyer, offerID), Ter(sellTER));
5432 expectInitialState();
5437 reinitializeTrustLineBalances();
5441 auto const nftID = mintNFT(minter, 3000);
5442 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5443 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5447 auto const offerID = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000));
5449 env(token::acceptBuyOffer(secondarySeller, offerID), Ter(sellTER));
5452 expectInitialState();
5457 reinitializeTrustLineBalances();
5461 auto const nftID = mintNFT(minter, 3000);
5462 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5463 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5467 auto const offerID = createSellOffer(secondarySeller, nftID, gwXAU(900));
5468 env(token::acceptSellOffer(buyer, offerID));
5471 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5472 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5473 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5474 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5475 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5476 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5481 reinitializeTrustLineBalances();
5485 auto const nftID = mintNFT(minter, 3000);
5486 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5487 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5491 auto const offerID = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900));
5492 env(token::acceptBuyOffer(secondarySeller, offerID));
5496 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5498 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5500 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5501 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5502 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5503 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5521 reinitializeTrustLineBalances();
5523 auto const nftID = mintNFT(minter);
5524 auto const sellOffer = createSellOffer(minter, nftID, gwXAU(300));
5525 auto const buyOffer = createBuyOffer(buyer, minter, nftID, gwXAU(500));
5526 env(token::brokerOffers(broker, buyOffer, sellOffer), token::BrokerFee(gwXAU(100)));
5529 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400));
5530 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5531 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5532 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-400));
5533 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5534 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5552 reinitializeTrustLineBalances();
5556 auto const nftID = mintNFT(minter, 3000);
5557 auto const primaryOfferID = createSellOffer(minter, nftID, XRP(0));
5558 env(token::acceptSellOffer(secondarySeller, primaryOfferID));
5562 auto const sellOffer = createSellOffer(secondarySeller, nftID, gwXAU(300));
5563 auto const buyOffer = createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500));
5564 env(token::brokerOffers(broker, buyOffer, sellOffer), token::BrokerFee(gwXAU(100)));
5567 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12));
5568 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5569 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(388));
5570 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5571 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-12));
5572 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5573 BEAST_EXPECT(env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-388));
5574 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5677 auto openLedgerSeq = [](Env& env) {
return env.current()->seq(); };
5681 auto incLgrSeqForAcctDel = [&](Env& env,
Account const& acct) {
5682 int const delta = [&]() ->
int {
5683 if (env.seq(acct) + 255 > openLedgerSeq(env))
5684 return env.seq(acct) - openLedgerSeq(env) + 255;
5687 BEAST_EXPECT(delta >= 0);
5688 for (
int i = 0; i < delta; ++i)
5690 BEAST_EXPECT(openLedgerSeq(env) == env.seq(acct) + 255);
5695 auto incLgrSeqForFixNftRemint = [&](Env& env,
Account const& acct) {
5697 auto const deletableLgrSeq = (*env.le(acct))[~sfFirstNFTokenSequence].value_or(0) +
5698 (*env.le(acct))[sfMintedNFTokens] + 255;
5700 if (deletableLgrSeq > openLedgerSeq(env))
5701 delta = deletableLgrSeq - openLedgerSeq(env);
5703 BEAST_EXPECT(delta >= 0);
5704 for (
int i = 0; i < delta; ++i)
5706 BEAST_EXPECT(openLedgerSeq(env) == deletableLgrSeq);
5712 Env env{*
this, features};
5716 env.fund(XRP(10000), alice, becky);
5720 UInt256 const prevNFTokenID = token::getNextID(env, alice, 0u);
5721 env(token::mint(alice));
5723 env(token::burn(alice, prevNFTokenID));
5727 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 1);
5730 incLgrSeqForAcctDel(env, alice);
5734 auto const acctDelFee{drops(env.current()->fees().increment)};
5735 env(acctdelete(alice, becky), Fee(acctDelFee));
5740 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5741 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5744 env.fund(XRP(10000), alice);
5748 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5749 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5750 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5753 UInt256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5754 env(token::mint(alice));
5758 env(token::burn(alice, remintNFTokenID));
5762 BEAST_EXPECT(remintNFTokenID != prevNFTokenID);
5768 Env env{*
this, features};
5771 Account const minter{
"minter"};
5773 env.fund(XRP(10000), alice, becky, minter);
5777 env(token::setMinter(alice, minter));
5783 for (
int i = 0; i < 500; i++)
5785 UInt256 const nftokenID = token::getNextID(env, alice, 0u);
5787 env(token::mint(minter), token::Issuer(alice));
5792 for (
auto const nftokenID : nftIDs)
5794 env(token::burn(minter, nftokenID));
5798 incLgrSeqForAcctDel(env, alice);
5802 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5803 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5805 auto const acctDelFee{drops(env.current()->fees().increment)};
5814 env(acctdelete(alice, becky), Fee(acctDelFee), Ter(
tecTOO_SOON));
5818 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5823 incLgrSeqForFixNftRemint(env, alice);
5826 env(acctdelete(alice, becky), Fee(acctDelFee));
5831 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5832 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5835 env.fund(XRP(10000), alice);
5839 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5840 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5841 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5845 UInt256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5846 env(token::mint(alice));
5850 env(token::burn(alice, remintNFTokenID));
5861 Env env{*
this, features};
5865 env.fund(XRP(10000), alice, becky);
5872 env(ticket::create(alice, 100));
5881 for (
int i = 0; i < 50; i++)
5883 nftIDs.
push_back(token::getNextID(env, alice, 0u));
5884 env(token::mint(alice, 0u), ticket::Use(aliceTicketSeq++));
5889 for (
auto const nftokenID : nftIDs)
5891 env(token::burn(alice, nftokenID), ticket::Use(aliceTicketSeq++));
5897 incLgrSeqForAcctDel(env, alice);
5901 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5902 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5904 auto const acctDelFee{drops(env.current()->fees().increment)};
5913 env(acctdelete(alice, becky), Fee(acctDelFee), Ter(
tecTOO_SOON));
5917 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5922 incLgrSeqForFixNftRemint(env, alice);
5925 env(acctdelete(alice, becky), Fee(acctDelFee));
5930 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
5931 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
5934 env.fund(XRP(10000), alice);
5938 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
5939 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
5940 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
5944 UInt256 const remintNFTokenID = token::getNextID(env, alice, 0u);
5945 env(token::mint(alice));
5949 env(token::burn(alice, remintNFTokenID));
5961 Env env{*
this, features};
5964 Account const minter{
"minter"};
5966 env.fund(XRP(10000), alice, becky, minter);
5970 env(token::setMinter(alice, minter));
5975 env(ticket::create(minter, 100));
5979 BEAST_EXPECT(
ownerCount(env, minter) == 100);
5984 for (
int i = 0; i < 50; i++)
5986 UInt256 const nftokenID = token::getNextID(env, alice, 0u);
5988 env(token::mint(minter), token::Issuer(alice), ticket::Use(minterTicketSeq++));
5993 for (
auto const nftokenID : nftIDs)
5995 env(token::burn(minter, nftokenID), ticket::Use(minterTicketSeq++));
6001 incLgrSeqForAcctDel(env, alice);
6005 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6006 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6015 auto const acctDelFee{drops(env.current()->fees().increment)};
6016 env(acctdelete(alice, becky), Fee(acctDelFee), Ter(
tecTOO_SOON));
6020 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6025 incLgrSeqForFixNftRemint(env, alice);
6028 env(acctdelete(alice, becky), Fee(acctDelFee));
6033 BEAST_EXPECT(!env.closed()->exists(aliceAcctKey));
6034 BEAST_EXPECT(!env.current()->exists(aliceAcctKey));
6037 env.fund(XRP(10000), alice);
6041 BEAST_EXPECT(env.closed()->exists(aliceAcctKey));
6042 BEAST_EXPECT(env.current()->exists(aliceAcctKey));
6043 BEAST_EXPECT((*env.le(alice))[sfMintedNFTokens] == 0);
6047 UInt256 const remintNFTokenID = token::getNextID(env, alice, 0u);
6048 env(token::mint(alice));
6052 env(token::burn(alice, remintNFTokenID));
6318 testcase(
"Test synthetic fields from JSON response");
6324 Account const broker{
"broker"};
6326 Env env{*
this, features};
6327 env.fund(XRP(10000), alice, bob, broker);
6333 if (tx.isMember(jss::meta))
6334 return &tx[jss::meta];
6335 if (tx.isMember(jss::metaData))
6336 return &tx[jss::metaData];
6345 return entry[jss::tx][jss::hash].
asString();
6346 if (entry.
isMember(jss::tx_json) && entry[jss::tx_json].
isMember(jss::hash))
6347 return entry[jss::tx_json][jss::hash].
asString();
6348 return entry[jss::hash].
asString();
6357 auto verifyMetaInAllResponses = [&](
auto verifyMeta) {
6364 for (
unsigned const apiVersion :
6369 json::Value const txResult = env.rpc(apiVersion,
"tx", txHash)[jss::result];
6370 verifyMeta(txResult[jss::meta]);
6375 ledgerParams[jss::ledger_index] = txResult[jss::ledger_index].
asUInt();
6376 ledgerParams[jss::transactions] =
true;
6377 ledgerParams[jss::expand] =
true;
6379 auto const ledgerResult =
6380 env.rpc(apiVersion,
"json",
"ledger",
to_string(ledgerParams));
6381 auto const& ledgerTx =
6382 ledgerResult[jss::result][jss::ledger][jss::transactions][0u];
6385 BEAST_EXPECT(getHash(ledgerTx) == txHash);
6387 if (
auto const* meta = getMeta(ledgerTx); BEAST_EXPECT(meta !=
nullptr))
6394 accountTxParams[jss::account] = txResult.
isMember(jss::tx_json)
6395 ? txResult[jss::tx_json][jss::Account].
asString()
6396 : txResult[jss::Account].
asString();
6398 auto const accountTxResult =
6399 env.rpc(apiVersion,
"json",
"account_tx",
to_string(accountTxParams));
6405 for (
auto const& entry : accountTxResult[jss::result][jss::transactions])
6407 if (getHash(entry) == txHash)
6414 if (!BEAST_EXPECT(accountTx !=
nullptr))
6417 if (
auto const* meta = getMeta(*accountTx); BEAST_EXPECT(meta !=
nullptr))
6425 auto verifyNFTokenID = [&](
UInt256 const& actualNftID) {
6426 verifyMetaInAllResponses([&](
json::Value const& meta) {
6428 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_id)))
6434 BEAST_EXPECT(nftID == actualNftID);
6444 verifyMetaInAllResponses([&](
json::Value const& meta) {
6446 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_ids)))
6452 meta[jss::nftoken_ids].begin(),
6453 meta[jss::nftoken_ids].end(),
6457 BEAST_EXPECT(nftID.
parseHex(
id.asString()));
6464 if (!BEAST_EXPECT(metaIDs.
size() == actualNftIDs.size()))
6469 for (
size_t i = 0; i < metaIDs.
size(); ++i)
6470 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
6476 auto verifyNFTokenOfferID = [&](
UInt256 const& offerID) {
6477 verifyMetaInAllResponses([&](
json::Value const& meta) {
6479 if (!BEAST_EXPECT(meta.
isMember(jss::offer_id)))
6484 BEAST_EXPECT(metaOfferID == offerID);
6492 UInt256 const nftId1{token::getNextID(env, alice, 0u, tfTransferable)};
6493 env(token::mint(alice, 0u), Txflags(tfTransferable));
6495 verifyNFTokenID(nftId1);
6497 UInt256 const nftId2{token::getNextID(env, alice, 0u, tfTransferable)};
6498 env(token::mint(alice, 0u), Txflags(tfTransferable));
6500 verifyNFTokenID(nftId2);
6505 UInt256 const aliceOfferIndex1 =
6507 env(token::createOffer(alice, nftId1, drops(1)), Txflags(tfSellNFToken));
6509 verifyNFTokenOfferID(aliceOfferIndex1);
6511 UInt256 const aliceOfferIndex2 =
6513 env(token::createOffer(alice, nftId2, drops(1)), Txflags(tfSellNFToken));
6515 verifyNFTokenOfferID(aliceOfferIndex2);
6520 env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2}));
6522 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
6526 auto const bobBuyOfferIndex =
6528 env(token::createOffer(bob, nftId1, drops(1)), token::Owner(alice));
6530 verifyNFTokenOfferID(bobBuyOfferIndex);
6534 env(token::acceptBuyOffer(alice, bobBuyOfferIndex));
6536 verifyNFTokenID(nftId1);
6542 UInt256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6543 env(token::mint(alice, 0u), Txflags(tfTransferable));
6545 verifyNFTokenID(nftId);
6548 UInt256 const offerAliceToBroker =
6550 env(token::createOffer(alice, nftId, drops(1)),
6551 token::Destination(broker),
6552 Txflags(tfSellNFToken));
6554 verifyNFTokenOfferID(offerAliceToBroker);
6557 UInt256 const offerBobToBroker =
6559 env(token::createOffer(bob, nftId, drops(1)), token::Owner(alice));
6561 verifyNFTokenOfferID(offerBobToBroker);
6564 env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker));
6566 verifyNFTokenID(nftId);
6573 UInt256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6574 env(token::mint(alice, 0u), Txflags(tfTransferable));
6576 verifyNFTokenID(nftId);
6579 UInt256 const aliceOfferIndex1 =
6581 env(token::createOffer(alice, nftId, drops(1)), Txflags(tfSellNFToken));
6583 verifyNFTokenOfferID(aliceOfferIndex1);
6585 UInt256 const aliceOfferIndex2 =
6587 env(token::createOffer(alice, nftId, drops(1)), Txflags(tfSellNFToken));
6589 verifyNFTokenOfferID(aliceOfferIndex2);
6593 env(token::cancelOffer(alice, {aliceOfferIndex1, aliceOfferIndex2}));
6595 verifyNFTokenIDsInCancelOffer({nftId});
6598 if (features[featureNFTokenMintOffer])
6600 UInt256 const aliceMintWithOfferIndex1 =
6602 env(token::mint(alice), token::Amount(XRP(0)));
6604 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
6611 testcase(
"Test buyer reserve when accepting an offer");
6616 auto mintAndCreateSellOffer =
6619 UInt256 const nftId{token::getNextID(env, acct, 0u, tfTransferable)};
6620 env(token::mint(acct, 0u), Txflags(tfTransferable));
6624 UInt256 const sellOfferIndex =
6626 env(token::createOffer(acct, nftId, amt), Txflags(tfSellNFToken));
6629 return sellOfferIndex;
6639 Env env{*
this, features};
6640 auto const acctReserve = env.
current()->fees().reserve;
6641 auto const incReserve = env.current()->fees().increment;
6642 auto const baseFee = env.current()->fees().base;
6644 env.fund(XRP(10000), alice);
6648 env.fund(acctReserve, bob);
6652 auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0));
6677 env(pay(env.master, bob, incReserve + drops(baseFee)));
6687 env(pay(env.master, bob, drops(baseFee * 2)));
6691 env(token::acceptSellOffer(bob, sellOfferIndex));
6703 Env env{*
this, features};
6704 auto const acctReserve = env.
current()->fees().reserve;
6705 auto const incReserve = env.current()->fees().increment;
6707 env.fund(XRP(10000), alice);
6710 env.fund(acctReserve + XRP(1), bob);
6714 auto const sellOfferIndex1 = mintAndCreateSellOffer(env, alice, XRP(0));
6722 env(pay(env.master, bob, drops(incReserve)));
6728 env(token::acceptSellOffer(bob, sellOfferIndex1));
6735 for (
size_t i = 0; i < 31; i++)
6738 auto const sellOfferIndex = mintAndCreateSellOffer(env, alice, XRP(0));
6742 env(token::acceptSellOffer(bob, sellOfferIndex));
6750 auto const sellOfferIndex33 = mintAndCreateSellOffer(env, alice, XRP(0));
6758 env(pay(env.master, bob, drops(incReserve)));
6763 env(token::acceptSellOffer(bob, sellOfferIndex33));
6774 Env env{*
this, features};
6775 auto const acctReserve = env.
current()->fees().reserve;
6776 auto const incReserve = env.current()->fees().increment;
6777 auto const baseFee = env.current()->fees().base;
6779 env.fund(XRP(10000), alice);
6785 env.fund(acctReserve + incReserve + XRP(1), bob);
6789 UInt256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6790 env(token::mint(alice, 0u), Txflags(tfTransferable));
6794 auto const buyOfferIndex =
6796 env(token::createOffer(bob, nftId, XRP(1)), token::Owner(alice));
6806 env(pay(env.master, bob, drops(baseFee)));
6810 env(token::acceptBuyOffer(alice, buyOfferIndex));
6818 Account const broker{
"broker"};
6820 Env env{*
this, features};
6821 auto const acctReserve = env.
current()->fees().reserve;
6822 auto const incReserve = env.current()->fees().increment;
6823 auto const baseFee = env.current()->fees().base;
6825 env.fund(XRP(10000), alice, broker);
6830 env.fund(acctReserve + incReserve + XRP(1), bob);
6834 UInt256 const nftId{token::getNextID(env, alice, 0u, tfTransferable)};
6835 env(token::mint(alice, 0u), Txflags(tfTransferable));
6839 UInt256 const offerAliceToBroker =
6841 env(token::createOffer(alice, nftId, XRP(1)),
6842 token::Destination(broker),
6843 Txflags(tfSellNFToken));
6847 UInt256 const offerBobToBroker =
6849 env(token::createOffer(bob, nftId, XRP(1)), token::Owner(alice));
6856 env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker),
6861 env(pay(env.master, bob, drops(baseFee)));
6865 env(token::brokerOffers(broker, offerBobToBroker, offerAliceToBroker));
7188 Account const issuer{
"issuer"};
7192 bool const modifyEnabled = features[featureDynamicNFT];
7196 Env env{*
this, features};
7197 env.fund(XRP(10000), issuer);
7201 env(token::mint(issuer, 0u), Txflags(tfMutable), Ter(expectedTer));
7205 Env env{*
this, features};
7206 env.fund(XRP(10000), issuer);
7210 UInt256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
7213 env(token::mint(issuer, 0u), Txflags(tfMutable));
7216 env(token::modify(issuer, nftId));
7221 env(token::mint(issuer, 0u));
7223 env(token::modify(issuer, nftId), Ter(
temDISABLED));
7231 Env env{*
this, features};
7232 env.fund(XRP(10000), issuer);
7235 UInt256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
7236 env(token::mint(issuer, 0u), Txflags(tfMutable));
7244 env(token::modify(issuer, nftId), Txflags(0x00000001), Ter(
temINVALID_FLAG));
7247 env(token::modify(issuer, nftId), token::Owner(issuer), Ter(
temMALFORMED));
7251 env(token::modify(issuer, nftId), token::Uri(
""), Ter(
temMALFORMED));
7255 env(token::modify(issuer, nftId),
7261 Env env{*
this, features};
7262 env.fund(XRP(10000), issuer, alice, bob);
7267 UInt256 const nftIDNotExists{token::getNextID(env, issuer, 0u, tfMutable)};
7270 env(token::modify(issuer, nftIDNotExists), Ter(
tecNO_ENTRY));
7275 UInt256 const nftIDNotModifiable{token::getNextID(env, issuer, 0u)};
7276 env(token::mint(issuer, 0u));
7284 UInt256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
7285 env(token::mint(issuer, 0u), Txflags(tfMutable));
7288 env(token::modify(bob, nftId), token::Owner(issuer), Ter(
tecNO_PERMISSION));
7291 env(token::setMinter(issuer, alice));
7294 env(token::modify(bob, nftId), token::Owner(issuer), Ter(
tecNO_PERMISSION));
7299 Env env{*
this, features};
7300 env.fund(XRP(10000), issuer, alice, bob);
7304 UInt256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
7305 env(token::mint(issuer, 0u), Txflags(tfMutable), token::Uri(
"uri"));
7312 Env env{*
this, features};
7313 env.fund(XRP(10000), issuer, alice, bob);
7317 auto accountNFTs = [&env](
Account const& acct) {
7319 params[jss::account] = acct.human();
7320 params[jss::type] =
"state";
7321 auto response = env.rpc(
"json",
"account_nfts",
to_string(params));
7322 return response[jss::result][jss::account_nfts];
7326 auto checkURI = [&accountNFTs,
this](
Account const& acct,
char const* uri,
int line) {
7327 auto const nfts = accountNFTs(acct);
7328 if (nfts.size() == 1)
7335 text <<
"checkURI: unexpected NFT count on line " << line;
7336 fail(text.
str(), __FILE__, line);
7342 if (!nfts[0u].isMember(sfURI.jsonName))
7349 text <<
"checkURI: unexpected URI present on line " << line;
7350 fail(text.
str(), __FILE__, line);
7362 text <<
"checkURI: unexpected URI contents on line " << line;
7363 fail(text.
str(), __FILE__, line);
7367 UInt256 const nftId{token::getNextID(env, issuer, 0u, tfMutable)};
7370 env(token::mint(issuer, 0u), Txflags(tfMutable), token::Uri(
"uri"));
7372 checkURI(issuer,
"uri", __LINE__);
7375 env(token::modify(issuer, nftId), token::Uri(
"new_uri"));
7377 checkURI(issuer,
"new_uri", __LINE__);
7380 env(token::modify(issuer, nftId));
7382 checkURI(issuer,
nullptr, __LINE__);
7385 env(token::modify(issuer, nftId), token::Uri(
"uri"));
7387 checkURI(issuer,
"uri", __LINE__);
7392 env(token::createOffer(issuer, nftId, XRP(0)), Txflags(tfSellNFToken));
7394 env(token::acceptSellOffer(alice, offerID));
7398 checkURI(alice,
"uri", __LINE__);
7401 env(token::modify(alice, nftId), token::Uri(
"new_uri"), Ter(
tecNO_PERMISSION));
7405 checkURI(alice,
"uri", __LINE__);
7407 env(token::modify(issuer, nftId), token::Owner(alice), token::Uri(
"new_uri"));
7411 checkURI(alice,
"new_uri", __LINE__);
7413 env(token::modify(issuer, nftId), token::Owner(alice));
7415 checkURI(alice,
nullptr, __LINE__);
7417 env(token::modify(issuer, nftId), token::Owner(alice), token::Uri(
"uri"));
7419 checkURI(alice,
"uri", __LINE__);
7422 env(token::setMinter(issuer, bob));
7424 env(token::modify(bob, nftId), token::Owner(alice), token::Uri(
"new_uri"));
7426 checkURI(alice,
"new_uri", __LINE__);
7428 env(token::modify(bob, nftId), token::Owner(alice));
7430 checkURI(alice,
nullptr, __LINE__);
7432 env(token::modify(bob, nftId), token::Owner(alice), token::Uri(
"uri"));
7434 checkURI(alice,
"uri", __LINE__);