22#include <xrpld/app/tx/detail/NFTokenUtils.h>
24#include <xrpl/basics/random.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/jss.h>
41 if (
auto const sleIssuer = env.
le(issuer))
42 ret = sleIssuer->at(~sfMintedNFTokens).value_or(0);
51 if (
auto const sleIssuer = env.
le(issuer))
52 ret = sleIssuer->at(~sfBurnedNFTokens).value_or(0);
61 params[jss::account] = acct.
human();
62 params[jss::type] =
"state";
64 return nfts[jss::result][jss::account_nfts].
size();
72 if (
auto const sleAcct = env.
le(acct))
73 ret = sleAcct->at(~sfTicketCount).value_or(0);
81 return env.
current()->info().parentCloseTime.time_since_epoch().count();
89 using namespace test::jtx;
95 features - featureNonFungibleTokensV1 -
96 featureNonFungibleTokensV1_1};
139 Env env{*
this, features};
168 env.fund(
XRP(10000), alice);
170 uint256 const aliceOfferIndex =
203 using namespace test::jtx;
205 Env env{*
this, features};
207 Account const minter{
"minter"};
211 auto const acctReserve = env.current()->fees().accountReserve(0);
212 auto const incReserve = env.current()->fees().increment;
213 auto const baseFee = env.current()->fees().base;
215 env.fund(acctReserve, alice, minter);
218 BEAST_EXPECT(env.balance(alice) == acctReserve);
219 BEAST_EXPECT(env.balance(minter) == acctReserve);
233 env(
pay(env.master, alice, incReserve +
drops(baseFee - 1)));
238 auto checkAliceOwnerMintedBurned = [&env,
this, &alice](
251 ss <<
"Wrong " << type <<
" count. Found: " << found
252 <<
"; Expected: " << exp;
253 fail(ss.
str(), __FILE__, line);
257 oneCheck(
"minted",
mintedCount(env, alice), minted);
258 oneCheck(
"burned",
burnedCount(env, alice), burned);
266 checkAliceOwnerMintedBurned(0, 0, 0, __LINE__);
269 env(
pay(env.master, alice,
drops(baseFee + 1)));
276 checkAliceOwnerMintedBurned(1, 1, 0, __LINE__);
280 for (
int i = 1; i < 32; ++i)
283 checkAliceOwnerMintedBurned(1, i + 1, 0, __LINE__);
290 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
293 env(
pay(env.master, alice, incReserve +
drops(baseFee * 33 - 1)));
300 checkAliceOwnerMintedBurned(1, 32, 0, __LINE__);
303 env(
pay(env.master, alice,
drops(baseFee + 1)));
309 checkAliceOwnerMintedBurned(2, 33, 0, __LINE__);
318 checkAliceOwnerMintedBurned((33 -
seq) ? 1 : 0, 33,
seq, __LINE__);
325 checkAliceOwnerMintedBurned(0, 33, 33, __LINE__);
333 env.le(alice)->getAccountID(sfNFTokenMinter) == minter.id());
337 auto checkMintersOwnerMintedBurned = [&env,
this, &alice, &minter](
345 auto oneCheck = [
this](
355 ss <<
"Wrong " << type <<
" count. Found: " << found
356 <<
"; Expected: " << exp;
357 fail(ss.
str(), __FILE__, line);
360 oneCheck(
"alice owner",
ownerCount(env, alice), aliceOwners, line);
362 "alice minted",
mintedCount(env, alice), aliceMinted, line);
364 "alice burned",
burnedCount(env, alice), aliceBurned, line);
366 "minter owner",
ownerCount(env, minter), minterOwners, line);
368 "minter minted",
mintedCount(env, minter), minterMinted, line);
370 "minter burned",
burnedCount(env, minter), minterBurned, line);
376 env(
pay(env.master, minter, incReserve -
drops(1)));
378 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
388 checkMintersOwnerMintedBurned(0, 33, nftSeq, 0, 0, 0, __LINE__);
391 env(
pay(env.master, minter,
drops(baseFee + 1)));
397 checkMintersOwnerMintedBurned(0, 34, nftSeq, 1, 0, 0, __LINE__);
401 for (
int i = 1; i < 32; ++i)
404 checkMintersOwnerMintedBurned(0, i + 34, nftSeq, 1, 0, 0, __LINE__);
409 env(
pay(env.master, minter, incReserve +
drops(baseFee * 32 - 1)));
419 checkMintersOwnerMintedBurned(0, 65, nftSeq, 1, 0, 0, __LINE__);
422 env(
pay(env.master, minter,
drops(baseFee + 1)));
428 checkMintersOwnerMintedBurned(0, 66, nftSeq, 2, 0, 0, __LINE__);
435 checkMintersOwnerMintedBurned(
436 0, 66, nftSeq, (65 -
seq) ? 1 : 0, 0, 0, __LINE__);
443 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
449 checkMintersOwnerMintedBurned(0, 66, nftSeq, 0, 0, 0, __LINE__);
459 using namespace test::jtx;
462 Env env{*
this, features};
463 env.fund(
XRP(1000), alice);
483 env.app().openLedger().modify(
492 auto replacement = std::make_shared<SLE>(*sle, sle->key());
493 if (replacement->getFieldU32(sfMintedNFTokens) != 1)
496 if (env.current()->rules().enabled(fixNFTokenRemint))
504 (*replacement)[sfFirstNFTokenSequence] = 0xFFFF'FFFE;
505 (*replacement)[sfMintedNFTokens] = 0x0000'0000;
511 (*replacement)[sfMintedNFTokens] = 0xFFFF'FFFE;
528 using namespace test::jtx;
530 Env env{*
this, features};
532 Account const minter{
"minter"};
537 env.fund(
XRP(200), alice, minter);
544 env(
pay(env.master, alice,
XRP(1000)));
604 using namespace test::jtx;
606 Env env{*
this, features};
609 Account const minter{
"minter"};
611 IOU const gwAUD(gw[
"AUD"]);
616 env.fund(
XRP(250), alice, buyer, minter, gw);
662 testcase(
"Invalid NFT offer create");
664 using namespace test::jtx;
666 Env env{*
this, features};
670 IOU const gwAUD(gw[
"AUD"]);
675 env.fund(
XRP(250), alice, buyer, gw);
816 env(
trust(buyer, gwAUD(1000)));
864 env(
trust(buyer, gwAUD(1000)));
877 env(
pay(gw, buyer, gwAUD(999)));
889 auto const baseFee = env.current()->fees().base;
890 env(
pay(env.master, buyer,
XRP(50) +
drops(baseFee * 12 - 1)));
900 env(
pay(env.master, buyer,
drops(baseFee + 1)));
915 testcase(
"Invalid NFT offer cancel");
917 using namespace test::jtx;
919 Env env{*
this, features};
923 IOU const gwAUD(gw[
"AUD"]);
925 env.fund(
XRP(1000), alice, buyer, gw);
936 uint256 const buyerOfferIndex =
995 env(
pay(env.master, gw,
XRP(5000)));
1035 testcase(
"Invalid NFT offer accept");
1037 using namespace test::jtx;
1039 Env env{*
this, features};
1043 IOU const gwAUD(gw[
"AUD"]);
1045 env.fund(
XRP(1000), alice, buyer, gw);
1067 uint256 const plainOfferIndex =
1081 uint256 const xrpOnlyOfferIndex =
1088 uint256 const noXferOfferIndex =
1096 uint256 const aliceExpOfferIndex =
1133 jv[sfNFTokenBrokerFee.jsonName] =
1143 jv[sfNFTokenBrokerFee.jsonName] =
1200 env(
trust(alice, gwAUD(1000)));
1201 env(
trust(buyer, gwAUD(1000)));
1203 env(
pay(gw, buyer, gwAUD(30)));
1212 uint256 const buyerOfferIndex =
1245 uint256 const buyerOfferIndex =
1284 uint256 const buyerOfferIndex =
1304 env(
pay(buyer, gw, gwAUD(30)));
1306 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1323 env(
pay(gw, buyer, gwAUD(30)));
1341 uint256 const buyerOfferIndex =
1380 env(
pay(buyer, gw, gwAUD(30)));
1382 BEAST_EXPECT(env.balance(buyer, gwAUD) == gwAUD(0));
1402 using namespace test::jtx;
1404 Env env{*
this, features};
1407 Account const minter1{
"minter1"};
1408 Account const minter2{
"minter2"};
1410 env.fund(
XRP(1000), alice, buyer, minter1, minter2);
1422 auto nftToBuyer = [&env, &alice, &minter1, &buyer](
1442 uint256 const noBurnID = nftToBuyer(0);
1520 using namespace test::jtx;
1522 Env env{*
this, features};
1526 IOU const gwAUD(gw[
"AUD"]);
1529 env.fund(
XRP(1000), alice, buyer, gw);
1531 env(
trust(alice, gwAUD(1000)));
1532 env(
trust(buyer, gwAUD(1000)));
1534 env(
pay(gw, buyer, gwAUD(100)));
1544 uint256 const aliceOfferIndex =
1552 uint256 const buyerOfferIndex =
1612 testcase(
"Mint flagCreateTrustLines");
1614 using namespace test::jtx;
1620 IOU const gwAUD(gw[
"AUD"]);
1621 IOU const gwCAD(gw[
"CAD"]);
1622 IOU const gwEUR(gw[
"EUR"]);
1627 for (
auto const& tweakedFeatures :
1628 {features - fixRemoveNFTokenAutoTrustLine,
1629 features | fixRemoveNFTokenAutoTrustLine})
1631 Env env{*
this, tweakedFeatures};
1632 env.
fund(
XRP(1000), alice, becky, cheri, gw);
1636 env(
trust(becky, gwAUD(1000)));
1637 env(
trust(cheri, gwAUD(1000)));
1638 env(
trust(becky, gwCAD(1000)));
1639 env(
trust(cheri, gwCAD(1000)));
1640 env(
trust(becky, gwEUR(1000)));
1641 env(
trust(cheri, gwEUR(1000)));
1643 env(
pay(gw, becky, gwAUD(500)));
1644 env(
pay(gw, becky, gwCAD(500)));
1645 env(
pay(gw, becky, gwEUR(500)));
1646 env(
pay(gw, cheri, gwAUD(500)));
1647 env(
pay(gw, cheri, gwCAD(500)));
1654 uint256 const nftNoAutoTrustID{
1662 uint256 const beckyBuyOfferIndex =
1671 TER const createOfferTER =
1673 uint256 const beckyOfferIndex =
1677 ter(createOfferTER));
1681 uint256 const cheriOfferIndex =
1685 ter(createOfferTER));
1705 tweakedFeatures[fixRemoveNFTokenAutoTrustLine]
1717 if (tweakedFeatures[fixRemoveNFTokenAutoTrustLine])
1721 uint256 const beckyBuyOfferIndex =
1730 uint256 const beckySellOfferIndex =
1739 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1742 uint256 const beckyBuyBackOfferIndex =
1751 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(10));
1752 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(5));
1766 uint256 const aliceSellOfferIndex =
1777 BEAST_EXPECT(env.balance(alice, gwAUD) == gwAUD(210));
1784 uint256 const cheriSellOfferIndex =
1795 BEAST_EXPECT(env.balance(alice, gwCAD) == gwCAD(10));
1806 using namespace test::jtx;
1808 Env env{*
this, features};
1812 Account const minter{
"minter"};
1814 env.fund(
XRP(1000), alice, becky, minter);
1820 uint256 const nftAliceNoTransferID{
1833 uint256 const aliceSellOfferIndex =
1863 uint256 const aliceBuyOfferIndex =
1885 uint256 const nftMinterNoTransferID{
1913 for (
int i = 0; i < 10; ++i)
1922 uint256 const minterSellOfferIndex =
1959 uint256 const aliceBuyOfferIndex =
1968 for (
int i = 0; i < 10; ++i)
1976 uint256 const minterBuyOfferIndex =
2018 uint256 const aliceSellOfferIndex =
2025 uint256 const beckyBuyOfferIndex =
2039 uint256 const beckySellOfferIndex =
2056 uint256 const minterSellOfferIndex =
2096 using namespace test::jtx;
2098 Env env{*
this, features};
2099 auto const baseFee = env.current()->fees().base;
2104 Account const minter{
"minter"};
2106 IOU const gwXAU(gw[
"XAU"]);
2108 env.fund(
XRP(1000), alice, becky, carol, minter, gw);
2111 env(
trust(alice, gwXAU(2000)));
2112 env(
trust(becky, gwXAU(2000)));
2113 env(
trust(carol, gwXAU(2000)));
2114 env(
trust(minter, gwXAU(2000)));
2116 env(
pay(gw, alice, gwXAU(1000)));
2117 env(
pay(gw, becky, gwXAU(1000)));
2118 env(
pay(gw, carol, gwXAU(1000)));
2119 env(
pay(gw, minter, gwXAU(1000)));
2141 uint256 const beckyBuyOfferIndex =
2146 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2147 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2151 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2152 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2155 uint256 const beckySellOfferIndex =
2162 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2163 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2164 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2167 uint256 const minterBuyOfferIndex =
2174 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2175 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2176 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2177 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2181 uint256 const minterSellOfferIndex =
2188 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2189 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2190 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2191 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2211 uint256 const beckyBuyOfferIndex =
2216 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2217 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2221 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2222 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2225 uint256 const beckySellOfferIndex =
2233 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0001));
2234 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2235 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2238 uint256 const minterBuyOfferIndex =
2246 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010.0002));
2247 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2248 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2249 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(990));
2253 uint256 const minterSellOfferIndex =
2260 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000.0002));
2261 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(999.9999));
2262 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(999.9999));
2263 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2267 env(
pay(alice, becky, gwXAU(0.0001)));
2268 env(
pay(alice, carol, gwXAU(0.0001)));
2271 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2272 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2273 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2274 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2303 uint256 const beckyBuyOfferIndex =
2308 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2309 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2313 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1010));
2314 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(990));
2317 uint256 const beckySellOfferIndex =
2325 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1060));
2326 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2327 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
2330 uint256 const carolBuyOfferIndex =
2338 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1065));
2339 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2340 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2341 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(990));
2345 uint256 const carolSellOfferIndex =
2353 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1055));
2354 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1040));
2355 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(905));
2356 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2359 env(
pay(alice, minter, gwXAU(55)));
2360 env(
pay(becky, minter, gwXAU(40)));
2362 BEAST_EXPECT(env.balance(alice, gwXAU) == gwXAU(1000));
2363 BEAST_EXPECT(env.balance(becky, gwXAU) == gwXAU(1000));
2364 BEAST_EXPECT(env.balance(carol, gwXAU) == gwXAU(1000));
2365 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
2378 for (
auto NumberSwitchOver : {
true})
2380 if (NumberSwitchOver)
2381 env.enableFeature(fixUniversalNumber);
2383 env.disableFeature(fixUniversalNumber);
2393 STAmount aliceBalance = env.balance(alice);
2394 STAmount minterBalance = env.balance(minter);
2395 uint256 const minterBuyOfferIndex =
2401 aliceBalance +=
XRP(1) - baseFee;
2402 minterBalance -=
XRP(1) + baseFee;
2403 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2404 BEAST_EXPECT(env.balance(minter) == minterBalance);
2408 auto pmt = NumberSwitchOver ?
drops(50000) :
drops(99999);
2409 STAmount carolBalance = env.balance(carol);
2410 uint256 const minterSellOfferIndex =
2416 minterBalance += pmt - baseFee;
2417 carolBalance -= pmt + baseFee;
2418 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2419 BEAST_EXPECT(env.balance(minter) == minterBalance);
2420 BEAST_EXPECT(env.balance(carol) == carolBalance);
2424 STAmount beckyBalance = env.balance(becky);
2425 uint256 const beckyBuyOfferIndex =
2427 pmt = NumberSwitchOver ?
drops(50001) :
drops(100000);
2432 carolBalance += pmt -
drops(1) - baseFee;
2433 beckyBalance -= pmt + baseFee;
2434 aliceBalance +=
drops(1);
2436 BEAST_EXPECT(env.balance(alice) == aliceBalance);
2437 BEAST_EXPECT(env.balance(minter) == minterBalance);
2438 BEAST_EXPECT(env.balance(carol) == carolBalance);
2439 BEAST_EXPECT(env.balance(becky) == beckyBalance);
2454 env(
pay(alice, gw, env.balance(alice, gwXAU)));
2455 env(
pay(minter, gw, env.balance(minter, gwXAU)));
2456 env(
pay(becky, gw, env.balance(becky, gwXAU)));
2461 env(
pay(gw, alice, startXAUBalance));
2462 env(
pay(gw, minter, startXAUBalance));
2463 env(
pay(gw, becky, startXAUBalance));
2472 STAmount aliceBalance = env.balance(alice, gwXAU);
2473 STAmount minterBalance = env.balance(minter, gwXAU);
2474 uint256 const minterBuyOfferIndex =
2481 aliceBalance += tinyXAU;
2482 minterBalance -= tinyXAU;
2483 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2484 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2487 STAmount carolBalance = env.balance(carol, gwXAU);
2488 uint256 const minterSellOfferIndex =
2496 minterBalance += tinyXAU;
2497 carolBalance -= tinyXAU;
2499 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2500 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2501 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2508 STAmount beckyBalance = env.balance(becky, gwXAU);
2509 uint256 const beckyBuyOfferIndex =
2517 aliceBalance += tinyXAU;
2518 beckyBalance -= cheapNFT;
2519 carolBalance += cheapNFT - tinyXAU;
2520 BEAST_EXPECT(env.balance(alice, gwXAU) == aliceBalance);
2521 BEAST_EXPECT(env.balance(minter, gwXAU) == minterBalance);
2522 BEAST_EXPECT(env.balance(carol, gwXAU) == carolBalance);
2523 BEAST_EXPECT(env.balance(becky, gwXAU) == beckyBalance);
2533 using namespace test::jtx;
2535 Env env{*
this, features};
2540 env.fund(
XRP(1000), alice, becky);
2564 for (
int i = 0; i < 10; ++i)
2574 ss <<
"Taxon recovery failed from nftID "
2575 <<
to_string(nftID) <<
". Expected: " << taxon
2576 <<
"; got: " << gotTaxon;
2585 rand_int<std::uint32_t>(),
2586 rand_int<std::uint16_t>(),
2587 rand_int<std::uint16_t>());
2588 check(taxon, nftAliceID);
2594 rand_int<std::uint32_t>(),
2595 rand_int<std::uint16_t>(),
2596 rand_int<std::uint16_t>());
2597 check(taxon, nftBeckyID);
2611 using namespace test::jtx;
2613 Env env{*
this, features};
2618 env.fund(
XRP(10000), alice, becky);
2624 auto randURI = []() {
2646 : uri(std::move(uri_)), taxon(taxon_)
2654 entries.
emplace_back(randURI(), rand_int<std::uint32_t>());
2657 for (Entry
const& entry : entries)
2659 if (entry.uri.empty())
2673 params[jss::account] = alice.human();
2674 params[jss::type] =
"state";
2675 return env.rpc(
"json",
"account_nfts",
to_string(params));
2679 Json::Value& nfts = aliceNFTs[jss::result][jss::account_nfts];
2680 if (!BEAST_EXPECT(nfts.
size() == entries.
size()))
2693 return lhs[jss::nft_serial] < rhs[jss::nft_serial];
2698 Entry
const& entry = entries[i];
2700 BEAST_EXPECT(entry.taxon == ret[sfNFTokenTaxon.jsonName]);
2701 if (entry.uri.empty())
2703 BEAST_EXPECT(!ret.
isMember(sfURI.jsonName));
2707 BEAST_EXPECT(
strHex(entry.uri) == ret[sfURI.jsonName]);
2716 testcase(
"Create offer destination");
2718 using namespace test::jtx;
2720 Env env{*
this, features};
2722 Account const issuer{
"issuer"};
2723 Account const minter{
"minter"};
2725 Account const broker{
"broker"};
2727 env.fund(
XRP(1000), issuer, minter, buyer, broker);
2744 uint256 const offerMinterToIssuer =
2750 uint256 const offerMinterToBuyer =
2756 uint256 const offerIssuerToMinter =
2762 uint256 const offerIssuerToBuyer =
2808 uint256 const offerMinterSellsToBuyer =
2838 uint256 const offerMinterBuysFromBuyer =
2867 uint256 const offerBuyerBuysFromMinter =
2892 uint256 const offerMinterToBroker =
2898 uint256 const offerBuyerToMinter =
2911 TER const expectTer = features[fixNonFungibleTokensV1_2]
2915 issuer, offerBuyerToMinter, offerMinterToBroker),
2926 broker, offerBuyerToMinter, offerMinterToBroker));
2937 uint256 const offerBuyerToMinter =
2943 uint256 const offerMinterToBuyer =
2948 uint256 const offerIssuerToBuyer =
2961 TER const expectTer = features[fixNonFungibleTokensV1_2]
2965 broker, offerIssuerToBuyer, offerBuyerToMinter),
2975 TER const eexpectTer = features[fixNonFungibleTokensV1_2]
2979 broker, offerMinterToBuyer, offerBuyerToMinter),
2983 if (features[fixNonFungibleTokensV1_2])
3009 uint256 const offerMinterToBroker =
3015 uint256 const offerBuyerToBroker =
3024 TER const expectTer = features[fixNonFungibleTokensV1_2]
3028 issuer, offerBuyerToBroker, offerMinterToBroker),
3038 broker, offerBuyerToBroker, offerMinterToBroker));
3049 testcase(
"Create offer destination disallow incoming");
3051 using namespace test::jtx;
3057 env.fund(
XRP(10000), alice);
3060 auto const sle = env.le(alice);
3061 uint32_t
flags = sle->getFlags();
3067 Account const issuer{
"issuer"};
3068 Account const minter{
"minter"};
3072 env.fund(
XRP(1000), issuer, minter, buyer, alice);
3175 if (features[featureNFTokenMintOffer])
3199 testcase(
"Create offer expiration");
3201 using namespace test::jtx;
3203 Env env{*
this, features};
3205 Account const issuer{
"issuer"};
3206 Account const minter{
"minter"};
3209 env.fund(
XRP(1000), issuer, minter, buyer);
3235 uint256 const offerMinterToIssuer =
3242 uint256 const offerMinterToAnyone =
3248 uint256 const offerIssuerToMinter =
3254 uint256 const offerBuyerToMinter =
3675 using namespace test::jtx;
3677 Env env{*
this, features};
3681 Account const minter(
"minter");
3682 env.fund(
XRP(50000), alice, becky, minter);
3695 uint256 const expiredOfferIndex =
3719 uint256 const dest1OfferIndex =
3739 uint256 const dest2OfferIndex =
3755 uint256 const mintersNFTokenID =
3762 uint256 const minterOfferIndex =
3787 testcase(
"Cancel too many offers");
3789 using namespace test::jtx;
3791 Env env{*
this, features};
3807 env.fund(
XRP(1000), alice);
3818 env.fund(
XRP(1000), nftAcct, offerAcct);
3840 for (
uint256 const& offerIndex : offerIndexes)
3896 for (
uint256 const& offerIndex : offerIndexes)
3906 testcase(
"Brokered NFT offer accept");
3908 using namespace test::jtx;
3910 for (
auto const& tweakedFeatures :
3911 {features - fixNonFungibleTokensV1_2,
3912 features | fixNonFungibleTokensV1_2})
3914 Env env{*
this, tweakedFeatures};
3915 auto const baseFee = env.
current()->fees().base;
3923 Account const issuer{
"issuer"};
3924 Account const minter{
"minter"};
3926 Account const broker{
"broker"};
3928 IOU const gwXAU(gw[
"XAU"]);
3930 env.fund(
XRP(1000), issuer, minter, buyer, broker, gw);
3933 env(
trust(issuer, gwXAU(2000)));
3934 env(
trust(minter, gwXAU(2000)));
3935 env(
trust(buyer, gwXAU(2000)));
3936 env(
trust(broker, gwXAU(2000)));
3943 auto checkOwnerCountIsOne =
3948 for (
Account const& acct : accounts)
3955 ss <<
"Account " << acct.human()
3956 <<
" expected ownerCount == 1. Got "
3958 fail(ss.
str(), __FILE__, line);
3964 auto mintNFT = [&env, &issuer, &minter](
std::uint16_t xferFee = 0) {
3981 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
3983 uint256 const nftID = mintNFT();
3986 uint256 const minterOfferIndex =
4000 auto const minterBalance = env.balance(minter);
4001 auto const buyerBalance = env.balance(buyer);
4002 auto const brokerBalance = env.balance(broker);
4003 auto const issuerBalance = env.balance(issuer);
4007 broker, buyOfferIndex, minterOfferIndex));
4012 BEAST_EXPECT(env.balance(minter) == minterBalance +
XRP(1));
4013 BEAST_EXPECT(env.balance(buyer) == buyerBalance -
XRP(1));
4014 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
4015 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4028 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4030 uint256 const nftID = mintNFT();
4033 uint256 const minterOfferIndex =
4049 broker, buyOfferIndex, minterOfferIndex),
4054 auto const minterBalance = env.balance(minter);
4055 auto const buyerBalance = env.balance(buyer);
4056 auto const brokerBalance = env.balance(broker);
4057 auto const issuerBalance = env.balance(issuer);
4061 broker, buyOfferIndex, minterOfferIndex),
4067 BEAST_EXPECT(env.balance(minter) == minterBalance +
XRP(0.5));
4068 BEAST_EXPECT(env.balance(buyer) == buyerBalance -
XRP(1));
4070 env.balance(broker) == brokerBalance +
XRP(0.5) - baseFee);
4071 BEAST_EXPECT(env.balance(issuer) == issuerBalance);
4084 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4089 uint256 const minterOfferIndex =
4103 auto const minterBalance = env.balance(minter);
4104 auto const buyerBalance = env.balance(buyer);
4105 auto const brokerBalance = env.balance(broker);
4106 auto const issuerBalance = env.balance(issuer);
4110 broker, buyOfferIndex, minterOfferIndex));
4115 BEAST_EXPECT(env.balance(minter) == minterBalance +
XRP(0.5));
4116 BEAST_EXPECT(env.balance(buyer) == buyerBalance -
XRP(1));
4117 BEAST_EXPECT(env.balance(broker) == brokerBalance - baseFee);
4118 BEAST_EXPECT(env.balance(issuer) == issuerBalance +
XRP(0.5));
4131 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4136 uint256 const minterOfferIndex =
4150 auto const minterBalance = env.balance(minter);
4151 auto const buyerBalance = env.balance(buyer);
4152 auto const brokerBalance = env.balance(broker);
4153 auto const issuerBalance = env.balance(issuer);
4157 broker, buyOfferIndex, minterOfferIndex),
4164 BEAST_EXPECT(env.balance(minter) == minterBalance +
XRP(0.125));
4165 BEAST_EXPECT(env.balance(buyer) == buyerBalance -
XRP(1));
4167 env.balance(broker) == brokerBalance +
XRP(0.75) - baseFee);
4168 BEAST_EXPECT(env.balance(issuer) == issuerBalance +
XRP(0.125));
4177 auto setXAUBalance =
4178 [
this, &gw, &gwXAU, &env](
4183 for (
Account const& acct : accounts)
4185 auto const xauAmt = gwXAU(amount);
4197 if (env.balance(acct, gwXAU) != xauAmt)
4200 ss <<
"Unable to set " << acct.human()
4201 <<
" account balance to gwXAU(" << amount <<
")";
4202 this->
fail(ss.
str(), __FILE__, line);
4210 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4211 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4213 uint256 const nftID = mintNFT();
4216 uint256 const minterOfferIndex =
4233 broker, buyOfferIndex, minterOfferIndex),
4253 broker, buyOfferIndex, minterOfferIndex),
4272 broker, buyOfferIndex, minterOfferIndex),
4279 broker, buyOfferIndex, minterOfferIndex));
4286 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4287 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(2000));
4288 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4289 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1000));
4299 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4300 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4305 uint256 const minterOfferIndex =
4321 broker, buyOfferIndex, minterOfferIndex),
4341 broker, buyOfferIndex, minterOfferIndex),
4360 broker, buyOfferIndex, minterOfferIndex),
4368 broker, buyOfferIndex, minterOfferIndex),
4376 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1450));
4377 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1450));
4378 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4379 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1100));
4389 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4390 setXAUBalance({issuer, minter, buyer, broker}, 1000, __LINE__);
4395 uint256 const minterOfferIndex =
4412 broker, buyOfferIndex, minterOfferIndex),
4420 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4421 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4422 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4423 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(1050));
4431 checkOwnerCountIsOne({issuer, minter, buyer, broker}, __LINE__);
4432 setXAUBalance({issuer, minter, buyer}, 1000, __LINE__);
4433 setXAUBalance({broker}, 500, __LINE__);
4437 uint256 const minterOfferIndex =
4450 if (tweakedFeatures[fixNonFungibleTokensV1_2])
4453 broker, buyOfferIndex, minterOfferIndex),
4460 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1237.5));
4461 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1712.5));
4462 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
4463 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(550));
4472 broker, buyOfferIndex, minterOfferIndex),
4480 BEAST_EXPECT(env.balance(issuer, gwXAU) == gwXAU(1000));
4481 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
4482 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
4483 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(500));
4499 using namespace test::jtx;
4501 Env env{*
this, features};
4503 Account const issuer{
"issuer"};
4504 Account const buyer1{
"buyer1"};
4505 Account const buyer2{
"buyer2"};
4506 env.fund(
XRP(10000), issuer, buyer1, buyer2);
4515 BEAST_EXPECT(
nftCount(env, issuer) == 1);
4516 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4517 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4520 uint256 const buyer1OfferIndex =
4523 uint256 const buyer2OfferIndex =
4535 env.rpc(
"json",
"nft_buy_offers",
to_string(params));
4537 if (buyOffers.
isMember(jss::result) &&
4538 buyOffers[jss::result].
isMember(jss::offers))
4539 return buyOffers[jss::result][jss::offers].
size();
4545 BEAST_EXPECT(nftBuyOfferCount(nftId) == 2);
4552 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4553 BEAST_EXPECT(
nftCount(env, buyer1) == 1);
4554 BEAST_EXPECT(
nftCount(env, buyer2) == 0);
4558 BEAST_EXPECT(nftBuyOfferCount(nftId) == 1);
4566 BEAST_EXPECT(
nftCount(env, issuer) == 0);
4567 BEAST_EXPECT(
nftCount(env, buyer1) == 0);
4568 BEAST_EXPECT(
nftCount(env, buyer2) == 1);
4571 BEAST_EXPECT(nftBuyOfferCount(nftId) == 0);
4578 testcase(
"NFToken transactions with tickets");
4580 using namespace test::jtx;
4582 Env env{*
this, features};
4584 Account const issuer{
"issuer"};
4586 env.fund(
XRP(10000), issuer, buyer);
4656 BEAST_EXPECT(env.seq(issuer) == issuerSeq);
4657 BEAST_EXPECT(env.seq(buyer) == buyerSeq);
4668 testcase(
"NFToken delete account");
4670 using namespace test::jtx;
4672 Env env{*
this, features};
4674 Account const issuer{
"issuer"};
4675 Account const minter{
"minter"};
4680 env.fund(
XRP(10000), issuer, minter, becky, carla, daria);
4684 for (
int i = 0; i < 300; ++i)
4705 for (
int i = 0; i < 15; ++i)
4712 uint256 const carlaOfferIndex =
4740 for (
int i = 0; i < 15; ++i)
4756 testcase(
"nft_buy_offers and nft_sell_offers");
4765 using namespace test::jtx;
4767 Env env{*
this, features};
4769 Account const issuer{
"issuer"};
4773 env.fund(
XRP(1000000), issuer, buyer);
4782 auto checkOffers = [
this, &env, &nftID](
4783 char const* request,
4785 int expectMarkerCount,
4787 int markerCount = 0;
4794 Json::Value nftOffers = [&env, &nftID, &request, &marker]() {
4798 if (!marker.
empty())
4799 params[jss::marker] = marker;
4800 return env.rpc(
"json", request,
to_string(params));
4804 if (expectCount == 0)
4808 "expected \"result\"",
4813 nftOffers[jss::result].isMember(jss::error),
4814 "expected \"error\"",
4819 nftOffers[jss::result][jss::error].asString() ==
4821 "expected \"objectNotFound\"",
4832 "expected \"result\"",
4841 marker = result[jss::marker].
asString();
4846 "expected \"offers\"",
4852 allOffers.
append(someOffers[i]);
4855 }
while (!marker.
empty());
4859 allOffers.
size() == expectCount,
4860 "Unexpected returned offer count",
4864 markerCount == expectMarkerCount,
4865 "Unexpected marker count",
4878 *globalFlags ==
offer[jss::flags].asInt(),
4879 "Inconsistent flags returned",
4885 offerIndexes.
insert(
offer[jss::nft_offer_index].asString());
4890 offerIndexes.
size() == expectCount,
4891 "Duplicate indexes returned?",
4895 amounts.
size() == expectCount,
4896 "Duplicate amounts returned?",
4902 checkOffers(
"nft_sell_offers", 0,
false, __LINE__);
4906 auto makeSellOffers =
4907 [&env, &issuer, &nftID, &sellPrice](
STAmount const& limit) {
4910 while (sellPrice < limit)
4912 sellPrice +=
XRP(1);
4915 if (++offerCount % 10 == 0)
4922 makeSellOffers(
XRP(1));
4923 checkOffers(
"nft_sell_offers", 1, 0, __LINE__);
4926 makeSellOffers(
XRP(250));
4927 checkOffers(
"nft_sell_offers", 250, 0, __LINE__);
4930 makeSellOffers(
XRP(251));
4931 checkOffers(
"nft_sell_offers", 251, 1, __LINE__);
4934 makeSellOffers(
XRP(500));
4935 checkOffers(
"nft_sell_offers", 500, 1, __LINE__);
4938 makeSellOffers(
XRP(501));
4939 checkOffers(
"nft_sell_offers", 501, 2, __LINE__);
4942 checkOffers(
"nft_buy_offers", 0, 0, __LINE__);
4946 auto makeBuyOffers =
4947 [&env, &buyer, &issuer, &nftID, &buyPrice](
STAmount const& limit) {
4950 while (buyPrice < limit)
4955 if (++offerCount % 10 == 0)
4962 makeBuyOffers(
XRP(1));
4963 checkOffers(
"nft_buy_offers", 1, 0, __LINE__);
4966 makeBuyOffers(
XRP(250));
4967 checkOffers(
"nft_buy_offers", 250, 0, __LINE__);
4970 makeBuyOffers(
XRP(251));
4971 checkOffers(
"nft_buy_offers", 251, 1, __LINE__);
4974 makeBuyOffers(
XRP(500));
4975 checkOffers(
"nft_buy_offers", 500, 1, __LINE__);
4978 makeBuyOffers(
XRP(501));
4979 checkOffers(
"nft_buy_offers", 501, 2, __LINE__);
4986 using namespace test::jtx;
4990 Account const issuer{
"issuer"};
4993 IOU const gwXAU(gw[
"XAU"]);
4999 for (
auto const& tweakedFeatures :
5000 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1 -
5001 fixNonFungibleTokensV1_2,
5002 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
5003 features | fixNFTokenNegOffer})
5008 Env env{*
this, tweakedFeatures};
5010 env.
fund(
XRP(1000000), issuer, buyer, gw);
5013 env(
trust(issuer, gwXAU(2000)));
5014 env(
trust(buyer, gwXAU(2000)));
5017 env(
pay(gw, issuer, gwXAU(1000)));
5018 env(
pay(gw, buyer, gwXAU(1000)));
5033 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5038 uint256 const sellNegXrpOfferIndex =
5042 ter(offerCreateTER));
5045 uint256 const sellNegIouOfferIndex =
5049 ter(offerCreateTER));
5052 uint256 const buyNegXrpOfferIndex =
5056 ter(offerCreateTER));
5059 uint256 const buyNegIouOfferIndex =
5063 ter(offerCreateTER));
5070 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5076 ter(offerAcceptTER));
5079 ter(offerAcceptTER));
5084 ter(offerAcceptTER));
5087 ter(offerAcceptTER));
5095 TER const offerAcceptTER = tweakedFeatures[fixNFTokenNegOffer]
5101 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5102 ter(offerAcceptTER));
5105 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5106 ter(offerAcceptTER));
5116 features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1};
5118 env.fund(
XRP(1000000), issuer, buyer, gw);
5121 env(
trust(issuer, gwXAU(2000)));
5122 env(
trust(buyer, gwXAU(2000)));
5125 env(
pay(gw, issuer, gwXAU(1000)));
5126 env(
pay(gw, buyer, gwXAU(1000)));
5142 uint256 const sellNegXrpOfferIndex =
5148 uint256 const sellNegIouOfferIndex =
5154 uint256 const buyNegXrpOfferIndex =
5160 uint256 const buyNegIouOfferIndex =
5167 env.enableFeature(fixNFTokenNegOffer);
5189 gw, buyNegXrpOfferIndex, sellNegXrpOfferIndex),
5193 gw, buyNegIouOfferIndex, sellNegIouOfferIndex),
5200 for (
auto const& tweakedFeatures :
5201 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
5202 features | fixNFTokenNegOffer})
5204 Env env{*
this, tweakedFeatures};
5206 env.
fund(
XRP(1000000), issuer, buyer);
5214 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
5221 ter(offerCreateTER));
5229 using namespace test::jtx;
5231 testcase(
"Payments with IOU transfer fees");
5233 for (
auto const& tweakedFeatures :
5234 {features - fixNonFungibleTokensV1_2,
5235 features | fixNonFungibleTokensV1_2})
5237 Env env{*
this, tweakedFeatures};
5239 Account const minter{
"minter"};
5240 Account const secondarySeller{
"seller"};
5243 Account const broker{
"broker"};
5244 IOU const gwXAU(gw[
"XAU"]);
5245 IOU const gwXPB(gw[
"XPB"]);
5247 env.fund(
XRP(1000), gw, minter, secondarySeller, buyer, broker);
5250 env(
trust(minter, gwXAU(2000)));
5251 env(
trust(secondarySeller, gwXAU(2000)));
5252 env(
trust(broker, gwXAU(10000)));
5253 env(
trust(buyer, gwXAU(2000)));
5254 env(
trust(buyer, gwXPB(2000)));
5258 env(
rate(gw, 1.02));
5261 auto expectInitialState = [
this,
5274 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(1000));
5275 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(0));
5276 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(0));
5277 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(0));
5278 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(0));
5279 BEAST_EXPECT(env.balance(secondarySeller, gwXPB) == gwXPB(0));
5280 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5000));
5281 BEAST_EXPECT(env.balance(broker, gwXPB) == gwXPB(0));
5282 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-1000));
5283 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(0));
5284 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(0));
5285 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(0));
5287 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(0));
5289 env.balance(gw, secondarySeller[
"XPB"]) == gwXPB(0));
5290 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5000));
5291 BEAST_EXPECT(env.balance(gw, broker[
"XPB"]) == gwXPB(0));
5294 auto reinitializeTrustLineBalances = [&expectInitialState,
5303 if (
auto const difference =
5304 gwXAU(1000) - env.balance(buyer, gwXAU);
5305 difference > gwXAU(0))
5306 env(
pay(gw, buyer, difference));
5307 if (env.balance(buyer, gwXPB) > gwXPB(0))
5308 env(
pay(buyer, gw, env.balance(buyer, gwXPB)));
5309 if (env.balance(minter, gwXAU) > gwXAU(0))
5310 env(
pay(minter, gw, env.balance(minter, gwXAU)));
5311 if (env.balance(minter, gwXPB) > gwXPB(0))
5312 env(
pay(minter, gw, env.balance(minter, gwXPB)));
5313 if (env.balance(secondarySeller, gwXAU) > gwXAU(0))
5315 pay(secondarySeller,
5317 env.balance(secondarySeller, gwXAU)));
5318 if (env.balance(secondarySeller, gwXPB) > gwXPB(0))
5320 pay(secondarySeller,
5322 env.balance(secondarySeller, gwXPB)));
5323 auto brokerDiff = gwXAU(5000) - env.balance(broker, gwXAU);
5324 if (brokerDiff > gwXAU(0))
5325 env(
pay(gw, broker, brokerDiff));
5326 else if (brokerDiff < gwXAU(0))
5328 brokerDiff.negate();
5329 env(
pay(broker, gw, brokerDiff));
5331 if (env.balance(broker, gwXPB) > gwXPB(0))
5332 env(
pay(broker, gw, env.balance(broker, gwXPB)));
5334 expectInitialState();
5337 auto mintNFT = [&env](
Account const& minter,
int transferFee = 0) {
5347 auto createBuyOffer =
5358 terCode ?
ter(*terCode)
5364 auto createSellOffer =
5374 terCode ?
ter(*terCode)
5383 reinitializeTrustLineBalances();
5384 auto const nftID = mintNFT(minter);
5385 auto const offerID =
5386 createSellOffer(minter, nftID, gwXAU(1000));
5387 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5393 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5394 expectInitialState();
5397 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5398 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5400 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5401 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5407 reinitializeTrustLineBalances();
5408 auto const nftID = mintNFT(minter);
5409 auto const offerID =
5410 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5411 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5417 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5418 expectInitialState();
5421 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5422 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5424 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5425 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5432 reinitializeTrustLineBalances();
5433 auto const nftID = mintNFT(minter);
5434 auto const offerID = createSellOffer(minter, nftID, gwXAU(995));
5435 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5441 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5442 expectInitialState();
5445 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5446 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5447 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5448 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5455 reinitializeTrustLineBalances();
5456 auto const nftID = mintNFT(minter);
5457 auto const offerID =
5458 createBuyOffer(buyer, minter, nftID, gwXAU(995));
5459 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5465 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5466 expectInitialState();
5469 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(995));
5470 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-14.9));
5471 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-995));
5472 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(14.9));
5480 reinitializeTrustLineBalances();
5481 auto const nftID = mintNFT(minter);
5482 auto const offerID = createSellOffer(minter, nftID, gwXAU(900));
5486 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5487 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5488 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5489 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5496 reinitializeTrustLineBalances();
5497 auto const nftID = mintNFT(minter);
5498 auto const offerID =
5499 createBuyOffer(buyer, minter, nftID, gwXAU(900));
5503 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(900));
5504 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5505 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-900));
5506 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5513 reinitializeTrustLineBalances();
5516 env(
pay(gw, buyer, gwXAU(20)));
5519 auto const nftID = mintNFT(minter);
5520 auto const offerID =
5521 createSellOffer(minter, nftID, gwXAU(1000));
5525 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5526 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5527 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5528 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5535 reinitializeTrustLineBalances();
5538 env(
pay(gw, buyer, gwXAU(20)));
5541 auto const nftID = mintNFT(minter);
5542 auto const offerID =
5543 createBuyOffer(buyer, minter, nftID, gwXAU(1000));
5547 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5548 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5549 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5550 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5555 reinitializeTrustLineBalances();
5557 auto const nftID = mintNFT(minter);
5558 auto const offerID =
5559 createSellOffer(minter, nftID, gwXAU(1000));
5560 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5566 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5568 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5570 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5573 expectInitialState();
5578 reinitializeTrustLineBalances();
5580 auto const nftID = mintNFT(minter);
5581 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5584 auto const offerID =
5585 createBuyOffer(gw, minter, nftID, gwXAU(1000), {offerTER});
5586 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5592 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5594 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(1000));
5596 env.balance(gw, minter[
"XAU"]) == gwXAU(-1000));
5599 expectInitialState();
5604 reinitializeTrustLineBalances();
5605 auto const nftID = mintNFT(minter);
5606 auto const offerID =
5607 createSellOffer(minter, nftID, gwXAU(5000));
5608 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5614 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5616 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5618 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5621 expectInitialState();
5626 reinitializeTrustLineBalances();
5628 auto const nftID = mintNFT(minter);
5629 auto const offerTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5632 auto const offerID =
5633 createBuyOffer(gw, minter, nftID, gwXAU(5000), {offerTER});
5634 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5640 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5642 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(5000));
5644 env.balance(gw, minter[
"XAU"]) == gwXAU(-5000));
5647 expectInitialState();
5653 reinitializeTrustLineBalances();
5654 auto const nftID = mintNFT(gw);
5655 auto const offerID = createSellOffer(gw, nftID, gwXAU(1000));
5659 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5660 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5666 reinitializeTrustLineBalances();
5668 auto const nftID = mintNFT(gw);
5669 auto const offerID =
5670 createBuyOffer(buyer, gw, nftID, gwXAU(1000));
5674 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(0));
5675 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(0));
5681 reinitializeTrustLineBalances();
5682 auto const nftID = mintNFT(gw);
5683 auto const offerID = createSellOffer(gw, nftID, gwXAU(2000));
5687 expectInitialState();
5693 reinitializeTrustLineBalances();
5694 auto const nftID = mintNFT(gw);
5695 auto const offerID =
5696 createBuyOffer(buyer, gw, nftID, gwXAU(2000));
5700 expectInitialState();
5705 reinitializeTrustLineBalances();
5706 auto const nftID = mintNFT(minter);
5707 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5711 expectInitialState();
5716 reinitializeTrustLineBalances();
5717 auto const nftID = mintNFT(minter);
5718 auto const offerID = createBuyOffer(
5727 expectInitialState();
5733 reinitializeTrustLineBalances();
5734 env(
pay(gw, buyer, gwXPB(100)));
5737 auto const nftID = mintNFT(minter);
5738 auto const offerID = createSellOffer(minter, nftID, gwXPB(10));
5742 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5743 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5744 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5745 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5751 reinitializeTrustLineBalances();
5752 env(
pay(gw, buyer, gwXPB(100)));
5755 auto const nftID = mintNFT(minter);
5756 auto const offerID =
5757 createBuyOffer(buyer, minter, nftID, gwXPB(10));
5761 BEAST_EXPECT(env.balance(minter, gwXPB) == gwXPB(10));
5762 BEAST_EXPECT(env.balance(buyer, gwXPB) == gwXPB(89.8));
5763 BEAST_EXPECT(env.balance(gw, minter[
"XPB"]) == gwXPB(-10));
5764 BEAST_EXPECT(env.balance(gw, buyer[
"XPB"]) == gwXPB(-89.8));
5769 reinitializeTrustLineBalances();
5773 auto const nftID = mintNFT(minter, 3000);
5774 auto const primaryOfferID =
5775 createSellOffer(minter, nftID,
XRP(0));
5780 auto const offerID =
5781 createSellOffer(secondarySeller, nftID, gwXAU(1000));
5782 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5788 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5789 expectInitialState();
5792 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5794 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5795 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5796 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5798 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5799 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5805 reinitializeTrustLineBalances();
5809 auto const nftID = mintNFT(minter, 3000);
5810 auto const primaryOfferID =
5811 createSellOffer(minter, nftID,
XRP(0));
5816 auto const offerID =
5817 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(1000));
5818 auto const sellTER = tweakedFeatures[fixNonFungibleTokensV1_2]
5825 if (tweakedFeatures[fixNonFungibleTokensV1_2])
5826 expectInitialState();
5829 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(30));
5831 env.balance(secondarySeller, gwXAU) == gwXAU(970));
5832 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(-20));
5833 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-30));
5835 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-970));
5836 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(20));
5842 reinitializeTrustLineBalances();
5846 auto const nftID = mintNFT(minter, 3000);
5847 auto const primaryOfferID =
5848 createSellOffer(minter, nftID,
XRP(0));
5853 auto const offerID =
5854 createSellOffer(secondarySeller, nftID, gwXAU(900));
5858 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5859 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5860 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5861 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5863 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5864 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5869 reinitializeTrustLineBalances();
5873 auto const nftID = mintNFT(minter, 3000);
5874 auto const primaryOfferID =
5875 createSellOffer(minter, nftID,
XRP(0));
5880 auto const offerID =
5881 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(900));
5886 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(27));
5888 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(873));
5890 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(82));
5891 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-27));
5893 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-873));
5894 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-82));
5912 reinitializeTrustLineBalances();
5914 auto const nftID = mintNFT(minter);
5915 auto const sellOffer =
5916 createSellOffer(minter, nftID, gwXAU(300));
5917 auto const buyOffer =
5918 createBuyOffer(buyer, minter, nftID, gwXAU(500));
5923 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(400));
5924 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5925 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5926 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-400));
5927 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5928 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5946 reinitializeTrustLineBalances();
5950 auto const nftID = mintNFT(minter, 3000);
5951 auto const primaryOfferID =
5952 createSellOffer(minter, nftID,
XRP(0));
5957 auto const sellOffer =
5958 createSellOffer(secondarySeller, nftID, gwXAU(300));
5959 auto const buyOffer =
5960 createBuyOffer(buyer, secondarySeller, nftID, gwXAU(500));
5965 BEAST_EXPECT(env.balance(minter, gwXAU) == gwXAU(12));
5966 BEAST_EXPECT(env.balance(buyer, gwXAU) == gwXAU(490));
5967 BEAST_EXPECT(env.balance(secondarySeller, gwXAU) == gwXAU(388));
5968 BEAST_EXPECT(env.balance(broker, gwXAU) == gwXAU(5100));
5969 BEAST_EXPECT(env.balance(gw, minter[
"XAU"]) == gwXAU(-12));
5970 BEAST_EXPECT(env.balance(gw, buyer[
"XAU"]) == gwXAU(-490));
5972 env.balance(gw, secondarySeller[
"XAU"]) == gwXAU(-388));
5973 BEAST_EXPECT(env.balance(gw, broker[
"XAU"]) == gwXAU(-5100));
5995 using namespace test::jtx;
5999 Account const broker{
"broker"};
6001 Env env{*
this, features};
6002 auto const baseFee = env.current()->fees().base;
6003 env.fund(
XRP(10000), alice, bob, broker);
6029 uint256 const bobBuyOfferIndex =
6033 uint256 const aliceSellOfferIndex =
6048 uint256 const bobSellOfferIndex =
6055 BEAST_EXPECT(
nftCount(env, bob) == 1);
6056 auto const bobsPriorBalance = env.balance(bob);
6057 auto const brokersPriorBalance = env.balance(broker);
6058 TER expectTer = features[fixNonFungibleTokensV1_2]
6071 BEAST_EXPECT(
nftCount(env, bob) == 1);
6072 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance -
XRP(1));
6074 env.balance(broker) == brokersPriorBalance +
XRP(1) - baseFee);
6080 BEAST_EXPECT(
nftCount(env, bob) == 1);
6081 BEAST_EXPECT(env.balance(bob) == bobsPriorBalance);
6082 BEAST_EXPECT(env.balance(broker) == brokersPriorBalance - baseFee);
6089 using namespace test::jtx;
6094 auto openLedgerSeq = [](
Env& env) {
return env.current()->seq(); };
6099 auto incLgrSeqForAcctDel = [&](
Env& env,
Account const& acct) {
6100 int const delta = [&]() ->
int {
6101 if (env.
seq(acct) + 255 > openLedgerSeq(env))
6102 return env.
seq(acct) - openLedgerSeq(env) + 255;
6105 BEAST_EXPECT(delta >= 0);
6106 for (
int i = 0; i < delta; ++i)
6108 BEAST_EXPECT(openLedgerSeq(env) == env.
seq(acct) + 255);
6114 auto incLgrSeqForFixNftRemint = [&](
Env& env,
Account const& acct) {
6116 auto const deletableLgrSeq =
6117 (*env.
le(acct))[~sfFirstNFTokenSequence].value_or(0) +
6118 (*env.
le(acct))[sfMintedNFTokens] + 255;
6120 if (deletableLgrSeq > openLedgerSeq(env))
6121 delta = deletableLgrSeq - openLedgerSeq(env);
6123 BEAST_EXPECT(delta >= 0);
6124 for (
int i = 0; i < delta; ++i)
6126 BEAST_EXPECT(openLedgerSeq(env) == deletableLgrSeq);
6132 Env env{*
this, features};
6136 env.
fund(
XRP(10000), alice, becky);
6147 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 1);
6150 incLgrSeqForAcctDel(env, alice);
6154 auto const acctDelFee{
drops(env.
current()->fees().increment)};
6160 BEAST_EXPECT(!env.
closed()->exists(aliceAcctKey));
6161 BEAST_EXPECT(!env.
current()->exists(aliceAcctKey));
6168 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6169 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6170 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 0);
6181 if (features[fixNFTokenRemint])
6183 BEAST_EXPECT(remintNFTokenID != prevNFTokenID);
6186 BEAST_EXPECT(remintNFTokenID == prevNFTokenID);
6192 Env env{*
this, features};
6195 Account const minter{
"minter"};
6197 env.
fund(
XRP(10000), alice, becky, minter);
6207 for (
int i = 0; i < 500; i++)
6216 for (
auto const nftokenID : nftIDs)
6224 incLgrSeqForAcctDel(env, alice);
6228 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6229 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6231 auto const acctDelFee{
drops(env.
current()->fees().increment)};
6233 if (!features[fixNFTokenRemint])
6238 BEAST_EXPECT(!env.
current()->exists(aliceAcctKey));
6245 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6246 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6247 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 0);
6251 uint256 const remintNFTokenID =
6266 else if (features[fixNFTokenRemint])
6281 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6286 incLgrSeqForFixNftRemint(env, alice);
6294 BEAST_EXPECT(!env.
closed()->exists(aliceAcctKey));
6295 BEAST_EXPECT(!env.
current()->exists(aliceAcctKey));
6302 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6303 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6304 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 0);
6308 uint256 const remintNFTokenID =
6328 Env env{*
this, features};
6332 env.
fund(
XRP(10000), alice, becky);
6348 for (
int i = 0; i < 50; i++)
6356 for (
auto const nftokenID : nftIDs)
6367 incLgrSeqForAcctDel(env, alice);
6371 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6372 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6374 auto const acctDelFee{
drops(env.
current()->fees().increment)};
6376 if (!features[fixNFTokenRemint])
6384 BEAST_EXPECT(!env.
closed()->exists(aliceAcctKey));
6385 BEAST_EXPECT(!env.
current()->exists(aliceAcctKey));
6392 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6393 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6394 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 0);
6398 uint256 const remintNFTokenID =
6413 else if (features[fixNFTokenRemint])
6428 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6433 incLgrSeqForFixNftRemint(env, alice);
6441 BEAST_EXPECT(!env.
closed()->exists(aliceAcctKey));
6442 BEAST_EXPECT(!env.
current()->exists(aliceAcctKey));
6449 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6450 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6451 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 0);
6455 uint256 const remintNFTokenID =
6477 if (features[fixNFTokenRemint])
6479 Env env{*
this, features};
6482 Account const minter{
"minter"};
6484 env.
fund(
XRP(10000), alice, becky, minter);
6497 BEAST_EXPECT(
ownerCount(env, minter) == 100);
6502 for (
int i = 0; i < 50; i++)
6513 for (
auto const nftokenID : nftIDs)
6524 incLgrSeqForAcctDel(env, alice);
6528 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6529 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6538 auto const acctDelFee{
drops(env.
current()->fees().increment)};
6543 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6548 incLgrSeqForFixNftRemint(env, alice);
6556 BEAST_EXPECT(!env.
closed()->exists(aliceAcctKey));
6557 BEAST_EXPECT(!env.
current()->exists(aliceAcctKey));
6564 BEAST_EXPECT(env.
closed()->exists(aliceAcctKey));
6565 BEAST_EXPECT(env.
current()->exists(aliceAcctKey));
6566 BEAST_EXPECT((*env.
le(alice))[sfMintedNFTokens] == 0);
6589 testcase(
"NFTokenMint with Create NFTokenOffer");
6591 using namespace test::jtx;
6593 if (!features[featureNFTokenMintOffer])
6595 Env env{*
this, features};
6599 env.fund(
XRP(10000), alice, buyer);
6622 Env env{*
this, features};
6623 auto const baseFee = env.current()->fees().base;
6627 Account const issuer(
"issuer");
6628 Account const minter(
"minter");
6630 IOU const gwAUD(gw[
"AUD"]);
6632 env.fund(
XRP(10000), alice, buyer, gw, issuer, minter);
6747 auto const acctReserve =
6748 env.current()->fees().accountReserve(0);
6749 auto const incReserve = env.current()->fees().increment;
6751 env.fund(acctReserve + incReserve, bob);
6761 env(
pay(env.master, bob, incReserve +
drops(baseFee)));
6767 env(
pay(env.master, bob,
drops(baseFee)));
6775 env(
pay(env.master, bob, incReserve +
drops(baseFee)));
6795 env(
trust(alice, gwAUD(1000)));
6810 uint256 const offerAliceSellsToBuyer =
6820 uint256 const offerBuyerSellsToAlice =
6841 for (
auto const& tweakedFeatures :
6842 {features - fixNFTokenNegOffer - featureNonFungibleTokensV1_1,
6843 features | fixNFTokenNegOffer})
6845 Env env{*
this, tweakedFeatures};
6848 env.fund(
XRP(1000000), alice);
6850 TER const offerCreateTER = tweakedFeatures[fixNFTokenNegOffer]
6857 ter(offerCreateTER));
6876 testcase(
"Test synthetic fields from JSON response");
6878 using namespace test::jtx;
6882 Account const broker{
"broker"};
6884 Env env{*
this, features};
6885 env.fund(
XRP(10000), alice, bob, broker);
6891 auto verifyNFTokenID = [&](
uint256 const& actualNftID) {
6898 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6901 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_id)))
6908 BEAST_EXPECT(nftID == actualNftID);
6913 auto verifyNFTokenIDsInCancelOffer =
6921 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6924 if (!BEAST_EXPECT(meta.
isMember(jss::nftoken_ids)))
6930 meta[jss::nftoken_ids].begin(),
6931 meta[jss::nftoken_ids].end(),
6935 BEAST_EXPECT(nftID.
parseHex(
id.asString()));
6941 std::sort(actualNftIDs.begin(), actualNftIDs.end());
6944 BEAST_EXPECT(metaIDs.
size() == actualNftIDs.size());
6948 for (
size_t i = 0; i < metaIDs.
size(); ++i)
6949 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
6954 auto verifyNFTokenOfferID = [&](
uint256 const& offerID) {
6961 env.rpc(
"tx", txHash)[jss::result][jss::meta];
6964 if (!BEAST_EXPECT(meta.
isMember(jss::offer_id)))
6969 BEAST_EXPECT(metaOfferID == offerID);
6980 verifyNFTokenID(nftId1);
6986 verifyNFTokenID(nftId2);
6991 uint256 const aliceOfferIndex1 =
6996 verifyNFTokenOfferID(aliceOfferIndex1);
6998 uint256 const aliceOfferIndex2 =
7003 verifyNFTokenOfferID(aliceOfferIndex2);
7009 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7011 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
7015 auto const bobBuyOfferIndex =
7019 verifyNFTokenOfferID(bobBuyOfferIndex);
7025 verifyNFTokenID(nftId1);
7035 verifyNFTokenID(nftId);
7038 uint256 const offerAliceToBroker =
7044 verifyNFTokenOfferID(offerAliceToBroker);
7047 uint256 const offerBobToBroker =
7051 verifyNFTokenOfferID(offerBobToBroker);
7055 broker, offerBobToBroker, offerAliceToBroker));
7057 verifyNFTokenID(nftId);
7068 verifyNFTokenID(nftId);
7071 uint256 const aliceOfferIndex1 =
7076 verifyNFTokenOfferID(aliceOfferIndex1);
7078 uint256 const aliceOfferIndex2 =
7083 verifyNFTokenOfferID(aliceOfferIndex2);
7088 alice, {aliceOfferIndex1, aliceOfferIndex2}));
7090 verifyNFTokenIDsInCancelOffer({nftId});
7093 if (features[featureNFTokenMintOffer])
7095 uint256 const aliceMintWithOfferIndex1 =
7099 verifyNFTokenOfferID(aliceMintWithOfferIndex1);
7106 testcase(
"Test buyer reserve when accepting an offer");
7108 using namespace test::jtx;
7121 uint256 const sellOfferIndex =
7126 return sellOfferIndex;
7136 Env env{*
this, features};
7137 auto const acctReserve = env.
current()->fees().accountReserve(0);
7138 auto const incReserve = env.
current()->fees().increment;
7139 auto const baseFee = env.
current()->fees().base;
7145 env.
fund(acctReserve, bob);
7149 auto const sellOfferIndex =
7150 mintAndCreateSellOffer(env, alice,
XRP(0));
7157 if (!features[fixNFTokenReserve])
7219 Env env{*
this, features};
7220 auto const acctReserve = env.
current()->fees().accountReserve(0);
7221 auto const incReserve = env.
current()->fees().increment;
7226 env.
fund(acctReserve +
XRP(1), bob);
7229 if (!features[fixNFTokenReserve])
7232 for (
size_t i = 0; i < 200; i++)
7235 auto const sellOfferIndex =
7236 mintAndCreateSellOffer(env, alice,
XRP(0));
7246 auto const sellOfferIndex1 =
7247 mintAndCreateSellOffer(env, alice,
XRP(0));
7269 for (
size_t i = 0; i < 31; i++)
7272 auto const sellOfferIndex =
7273 mintAndCreateSellOffer(env, alice,
XRP(0));
7285 auto const sellOfferIndex33 =
7286 mintAndCreateSellOffer(env, alice,
XRP(0));
7316 Env env{*
this, features};
7317 auto const acctReserve = env.
current()->fees().accountReserve(0);
7318 auto const incReserve = env.
current()->fees().increment;
7319 auto const baseFee = env.
current()->fees().base;
7327 env.
fund(acctReserve + incReserve +
XRP(1), bob);
7365 Account const broker{
"broker"};
7367 Env env{*
this, features};
7368 auto const acctReserve = env.
current()->fees().accountReserve(0);
7369 auto const incReserve = env.
current()->fees().increment;
7370 auto const baseFee = env.
current()->fees().base;
7372 env.
fund(
XRP(10000), alice, broker);
7377 env.
fund(acctReserve + incReserve +
XRP(1), bob);
7387 uint256 const offerAliceToBroker =
7395 uint256 const offerBobToBroker =
7405 broker, offerBobToBroker, offerAliceToBroker),
7415 broker, offerBobToBroker, offerAliceToBroker));
7423 testcase(
"Test fix unasked for auto-trustline.");
7425 using namespace test::jtx;
7427 Account const issuer{
"issuer"};
7431 IOU const gwAUD(gw[
"AUD"]);
7461 features - fixRemoveNFTokenAutoTrustLine;
7463 {localFeatures - fixEnforceNFTokenTrustline,
7464 localFeatures | fixEnforceNFTokenTrustline})
7466 Env env{*
this, feats};
7467 env.
fund(
XRP(1000), issuer, becky, cheri, gw);
7471 env(
trust(becky, gwAUD(1000)));
7472 env(
trust(cheri, gwAUD(1000)));
7474 env(
pay(gw, cheri, gwAUD(500)));
7486 uint256 const nftNoAutoTrustID{
7495 uint256 const beckyBuyOfferIndex1 =
7500 uint256 const beckyBuyOfferIndex2 =
7512 uint256 const beckyAutoTrustOfferIndex =
7528 env(
trust(issuer, gwAUD(1000)));
7532 uint256 const beckyNoAutoTrustOfferIndex =
7540 env(
trust(issuer, gwAUD(0)));
7551 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7554 env(
pay(issuer, gw, gwAUD(5)));
7560 if (feats[fixEnforceNFTokenTrustline])
7571 env(
trust(issuer, gwAUD(1000)));
7586 BEAST_EXPECT(env.balance(issuer, gwAUD) == gwAUD(5));
7593 testcase(
"Test fix NFT issuer is IOU issuer");
7595 using namespace test::jtx;
7597 Account const issuer{
"issuer"};
7600 IOU const isISU(issuer[
"ISU"]);
7632 features - fixRemoveNFTokenAutoTrustLine;
7634 Env env{*
this, localFeatures};
7635 env.fund(
XRP(1000), issuer, becky, cheri);
7639 env(
trust(becky, isISU(1000)));
7640 env(
trust(cheri, isISU(1000)));
7642 env(
pay(issuer, cheri, isISU(500)));
7654 uint256 const nftNoAutoTrustID{
7663 uint256 const beckyBuyOfferIndex1 =
7668 uint256 const beckyBuyOfferIndex2 =
7681 if (!localFeatures[featureNFTokenMintOffer])
7697 uint256 const beckyAutoTrustOfferIndex =
7709 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7710 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7716 uint256 const beckyNoAutoTrustOfferIndex =
7721 uint256 const beckyAutoTrustOfferIndex =
7734 BEAST_EXPECT(env.balance(becky, isISU) == isISU(95));
7735 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(400));
7743 BEAST_EXPECT(env.balance(becky, isISU) == isISU(190));
7744 BEAST_EXPECT(env.balance(cheri, isISU) == isISU(300));
7753 using namespace test::jtx;
7755 Account const issuer{
"issuer"};
7759 bool const modifyEnabled = features[featureDynamicNFT];
7763 Env env{*
this, features};
7764 env.fund(
XRP(10000), issuer);
7767 auto const expectedTer =
7773 Env env{*
this, features};
7774 env.fund(
XRP(10000), issuer);
7799 Env env{*
this, features};
7800 env.fund(
XRP(10000), issuer);
7837 Env env{*
this, features};
7838 env.fund(
XRP(10000), issuer, alice, bob);
7852 uint256 const nftIDNotModifiable{
7883 Env env{*
this, features};
7884 env.fund(
XRP(10000), issuer, alice, bob);
7896 Env env{*
this, features};
7897 env.fund(
XRP(10000), issuer, alice, bob);
7901 auto accountNFTs = [&env](
Account const& acct) {
7903 params[jss::account] = acct.human();
7904 params[jss::type] =
"state";
7906 env.rpc(
"json",
"account_nfts",
to_string(params));
7907 return response[jss::result][jss::account_nfts];
7911 auto checkURI = [&accountNFTs,
this](
7915 auto const nfts = accountNFTs(acct);
7916 if (nfts.size() == 1)
7921 text <<
"checkURI: unexpected NFT count on line " << line;
7922 fail(text.
str(), __FILE__, line);
7928 if (!nfts[0u].isMember(sfURI.jsonName))
7933 text <<
"checkURI: unexpected URI present on line "
7935 fail(text.
str(), __FILE__, line);
7945 text <<
"checkURI: unexpected URI contents on line "
7947 fail(text.
str(), __FILE__, line);
7956 checkURI(issuer,
"uri", __LINE__);
7961 checkURI(issuer,
"new_uri", __LINE__);
7966 checkURI(issuer,
nullptr, __LINE__);
7971 checkURI(issuer,
"uri", __LINE__);
7983 checkURI(alice,
"uri", __LINE__);
7992 checkURI(alice,
"uri", __LINE__);
8000 checkURI(alice,
"new_uri", __LINE__);
8004 checkURI(alice,
nullptr, __LINE__);
8010 checkURI(alice,
"uri", __LINE__);
8019 checkURI(alice,
"new_uri", __LINE__);
8023 checkURI(alice,
nullptr, __LINE__);
8029 checkURI(alice,
"uri", __LINE__);
8077 using namespace test::jtx;
8082 all - fixNFTDir - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8083 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8085 fixNFTokenRemint - fixNFTokenReserve - featureNFTokenMintOffer -
8087 all - fixNonFungibleTokensV1_2 - fixNFTokenRemint -
8088 fixNFTokenReserve - featureNFTokenMintOffer - featureDynamicNFT,
8089 all - fixNFTokenRemint - fixNFTokenReserve -
8090 featureNFTokenMintOffer - featureDynamicNFT,
8091 all - fixNFTokenReserve - featureNFTokenMintOffer -
8093 all - featureNFTokenMintOffer - featureDynamicNFT,
8094 all - featureDynamicNFT,
8097 if (BEAST_EXPECT(instance < feats.size()))
8101 BEAST_EXPECT(!last || instance == feats.size() - 1);
8174BEAST_DEFINE_TESTSUITE_PRIO(NFTokenBaseUtil, tx,
ripple, 2);
8175BEAST_DEFINE_TESTSUITE_PRIO(NFTokenDisallowIncoming, tx,
ripple, 2);
8176BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOfixV1, tx,
ripple, 2);
8177BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenRemint, tx,
ripple, 2);
8178BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOTokenReserve, tx,
ripple, 2);
8179BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOMintOffer, tx,
ripple, 2);
8180BEAST_DEFINE_TESTSUITE_PRIO(NFTokenWOModify, tx,
ripple, 2);
8181BEAST_DEFINE_TESTSUITE_PRIO(NFTokenAllFeatures, tx,
ripple, 2);
T back_inserter(T... args)
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
Value removeMember(char const *key)
Remove and return the named member.
std::string asString() const
Returns the unquoted string value.
bool isMember(char const *key) const
Return true if the object has a member named key.
A generic endpoint for log messages.
void pass()
Record a successful test condition.
testcase_t testcase
Memberspace for declaring test cases.
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
void fail(String const &reason, char const *file, int line)
Record a failure.
void run() override
Runs the suite.
void testCreateOfferDestination(FeatureBitset features)
void testFixNFTokenRemint(FeatureBitset features)
std::uint32_t lastClose(test::jtx::Env &env)
void testMintInvalid(FeatureBitset features)
void testAcceptOfferInvalid(FeatureBitset features)
void testMintFlagTransferable(FeatureBitset features)
void testCancelOffers(FeatureBitset features)
void testNFTIssuerIsIOUIssuer(FeatureBitset features)
void testMintTaxon(FeatureBitset features)
void testNFTokenModify(FeatureBitset features)
void testNFTokenDeleteAccount(FeatureBitset features)
void testUnaskedForAutoTrustline(FeatureBitset features)
FeatureBitset const disallowIncoming
void testFixNFTokenBuyerReserve(FeatureBitset features)
void testFixNFTokenNegOffer(FeatureBitset features)
void run(std::uint32_t instance, bool last=false)
void testWithFeats(FeatureBitset features)
void testNFTokenOfferOwner(FeatureBitset features)
void testNFTokenWithTickets(FeatureBitset features)
void testCreateOfferDestinationDisallowIncoming(FeatureBitset features)
void testCreateOfferExpiration(FeatureBitset features)
void testMintMaxTokens(FeatureBitset features)
void testMintFlagCreateTrustLine(FeatureBitset features)
void testMintTransferFee(FeatureBitset features)
void testTxJsonMetaFields(FeatureBitset features)
void testNftXxxOffers(FeatureBitset features)
void testEnabled(FeatureBitset features)
void testMintURI(FeatureBitset features)
void testCancelTooManyOffers(FeatureBitset features)
void testMintFlagBurnable(FeatureBitset features)
void testMintFlagOnlyXRP(FeatureBitset features)
void testMintReserve(FeatureBitset features)
static std::uint32_t nftCount(test::jtx::Env &env, test::jtx::Account const &acct)
static std::uint32_t ticketCount(test::jtx::Env const &env, test::jtx::Account const &acct)
void testBrokeredSaleToSelf(FeatureBitset features)
void testIOUWithTransferFee(FeatureBitset features)
static std::uint32_t burnedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
void testCreateOfferInvalid(FeatureBitset features)
static std::uint32_t mintedCount(test::jtx::Env const &env, test::jtx::Account const &issuer)
void testCancelOfferInvalid(FeatureBitset features)
void testBrokeredAccept(FeatureBitset features)
void testFeatMintWithOffer(FeatureBitset features)
void run() override
Runs the suite.
void testBurnInvalid(FeatureBitset features)
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
void run() override
Runs the suite.
Writable ledger view that accumulates state and tx changes.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Json::Value getJson(JsonOptions=JsonOptions::none) const override
static int const cMinOffset
static std::uint64_t const cMinValue
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
A type-safe wrap around standard integral types.
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
static Account const master
The master account.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::shared_ptr< SLE const > le(Account const &account) const
Return an account root.
Converts to IOU Issue or STAmount.
balance(Account const &account, none_t)
Match the number of items in the account's owner directory.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Set a ticket sequence on a JTx.
Sets the optional amount field on an NFTokenMint.
Sets the optional NFTokenBrokerFee field in a brokerOffer transaction.
Sets the optional Destination field on an NFTokenOffer.
Sets the optional Expiration field on an NFTokenOffer.
Sets the optional Issuer on an NFTokenMint.
Sets the optional Owner on an NFTokenOffer.
Sets the optional URI on an NFTokenMint.
Sets the optional TransferFee on an NFTokenMint.
T emplace_back(T... args)
@ arrayValue
array value (ordered list)
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet nftoffer(AccountID const &owner, std::uint32_t seq)
An offer from an account to buy or sell an NFT.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Taxon getTaxon(uint256 const &id)
Taxon toTaxon(std::uint32_t i)
Json::Value create(A const &account, A const &dest, STAmount const &sendMax)
Create a check.
Json::Value cancel(jtx::Account const &dest, uint256 const &checkId)
Cancel a check.
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
Json::Value clearMinter(jtx::Account const &account)
Clear any authorized minter from an account root.
uint256 getNextID(jtx::Env const &env, jtx::Account const &issuer, std::uint32_t nfTokenTaxon, std::uint16_t flags, std::uint16_t xferFee)
Get the next NFTokenID that will be issued.
uint256 getID(jtx::Env const &env, jtx::Account const &issuer, std::uint32_t nfTokenTaxon, std::uint32_t nftSeq, std::uint16_t flags, std::uint16_t xferFee)
Get the NFTokenID for a particular nftSequence.
Json::Value setMinter(jtx::Account const &account, jtx::Account const &minter)
Set the authorized minter on an account root.
Json::Value createOffer(jtx::Account const &account, uint256 const &nftokenID, STAmount const &amount)
Create an NFTokenOffer.
Json::Value acceptSellOffer(jtx::Account const &account, uint256 const &offerIndex)
Accept an NFToken sell offer.
Json::Value modify(jtx::Account const &account, uint256 const &nftokenID)
Modify an NFToken.
Json::Value acceptBuyOffer(jtx::Account const &account, uint256 const &offerIndex)
Accept an NFToken buy offer.
Json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
Json::Value burn(jtx::Account const &account, uint256 const &nftokenID)
Burn an NFToken.
Json::Value cancelOffer(jtx::Account const &account, std::initializer_list< uint256 > const &nftokenOffers)
Cancel NFTokenOffers.
Json::Value brokerOffers(jtx::Account const &account, uint256 const &buyOfferIndex, uint256 const &sellOfferIndex)
Broker two NFToken offers.
std::uint32_t ownerCount(Env const &env, Account const &account)
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
owner_count< ltOFFER > offers
Match the number of offers in the account's owner directory.
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Json::Value acctdelete(Account const &account, Account const &dest)
Delete account.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
std::enable_if_t<(std::is_same< Byte, unsigned char >::value||std::is_same< Byte, std::uint8_t >::value), Byte > rand_byte()
std::enable_if_t< std::is_integral< Integral >::value, Integral > rand_int()
constexpr std::uint32_t const tfOnlyXRP
constexpr std::uint32_t asfDisallowIncomingNFTokenOffer
constexpr std::uint32_t const tfSellNFToken
std::size_t constexpr maxTokenOfferCancelCount
The maximum number of token offers that can be canceled at once.
@ lsfDisallowIncomingNFTokenOffer
std::uint16_t constexpr maxTransferFee
The maximum token transfer fee allowed.
constexpr std::uint32_t const tfBurnable
@ tefNFTOKEN_IS_NOT_TRANSFERABLE
constexpr std::uint32_t const tfTrustLine
std::string strHex(FwdIt begin, FwdIt end)
std::size_t constexpr maxTokenURILength
The maximum length of a URI inside an NFT.
constexpr std::uint32_t tfClearFreeze
@ tecNFTOKEN_OFFER_TYPE_MISMATCH
@ tecNFTOKEN_BUY_SELL_MISMATCH
@ tecMAX_SEQUENCE_REACHED
@ tecINSUFFICIENT_PAYMENT
@ tecINSUFFICIENT_RESERVE
@ tecCANT_ACCEPT_OWN_NFTOKEN_OFFER
std::string to_string(base_uint< Bits, Tag > const &a)
constexpr std::uint32_t tfFullyCanonicalSig
Transaction flags.
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t tfSetFreeze
constexpr std::uint32_t const tfMutable
constexpr std::uint32_t const tfTransferable
@ temBAD_NFTOKEN_TRANSFER_FEE
A pair of SHAMap key and LedgerEntryType.
Set the sequence number on a JTx.