146 using namespace std::chrono_literals;
149 auto baseFee = env.
current()->fees().base.drops();
156 stream[jss::streams].append(
"transactions");
157 auto jv = wsc->invoke(
"subscribe", stream);
158 if (wsc->version() == 2)
160 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
161 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
162 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
164 BEAST_EXPECT(jv[jss::status] ==
"success");
172 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
173 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"][
"NewFields"][jss::Account]
174 == Account(
"alice").human() &&
175 jv[jss::transaction][jss::TransactionType]
177 jv[jss::transaction][jss::DeliverMax]
178 == std::to_string(10000000000 + baseFee) &&
179 jv[jss::transaction][jss::Fee]
180 == std::to_string(baseFee) &&
181 jv[jss::transaction][jss::Sequence]
186 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
187 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"][
"FinalFields"][jss::Account] ==
188 Account(
"alice").human();
195 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
196 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"][
"NewFields"][jss::Account]
197 == Account(
"bob").human() &&
198 jv[jss::transaction][jss::TransactionType]
200 jv[jss::transaction][jss::DeliverMax]
201 == std::to_string(10000000000 + baseFee) &&
202 jv[jss::transaction][jss::Fee]
203 == std::to_string(baseFee) &&
204 jv[jss::transaction][jss::Sequence]
209 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
210 return jv[jss::meta][
"AffectedNodes"][0u][
"ModifiedNode"][
"FinalFields"][jss::Account] ==
211 Account(
"bob").human();
217 auto jv = wsc->invoke(
"unsubscribe", stream);
218 if (wsc->version() == 2)
220 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
221 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
222 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
224 BEAST_EXPECT(jv[jss::status] ==
"success");
231 stream[jss::accounts].append(
Account(
"alice").human());
232 auto jv = wsc->invoke(
"subscribe", stream);
233 if (wsc->version() == 2)
235 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
236 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
237 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
239 BEAST_EXPECT(jv[jss::status] ==
"success");
246 BEAST_EXPECT(!wsc->getMsg(10ms));
253 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
254 return jv[jss::meta][
"AffectedNodes"][1u][
"ModifiedNode"][
"FinalFields"][jss::Account] ==
255 Account(
"alice").human();
258 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
259 return jv[jss::meta][
"AffectedNodes"][1u][
"CreatedNode"][
"NewFields"][
"LowLimit"][jss::issuer] ==
260 Account(
"alice").human();
265 auto jv = wsc->invoke(
"unsubscribe", stream);
266 if (wsc->version() == 2)
268 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
269 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
270 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
272 BEAST_EXPECT(jv[jss::status] ==
"success");
390 auto& cfg = env.app().config();
391 if (!BEAST_EXPECT(cfg.section(SECTION_VALIDATION_SEED).empty()))
393 auto const parsedseed = parseBase58<Seed>(cfg.section(SECTION_VALIDATION_SEED).values()[0]);
394 if (!BEAST_EXPECT(parsedseed))
407 stream[jss::streams].append(
"validations");
408 auto jv = wsc->invoke(
"subscribe", stream);
409 if (wsc->version() == 2)
411 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
412 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
413 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
415 BEAST_EXPECT(jv[jss::status] ==
"success");
420 auto validValidationFields = [&env, &valPublicKey](
Json::Value const& jv) {
421 if (jv[jss::type] !=
"validationReceived")
424 if (jv[jss::validation_public_key].asString() != valPublicKey)
427 if (jv[jss::ledger_hash] !=
to_string(env.closed()->header().hash))
430 if (jv[jss::ledger_index] !=
std::to_string(env.closed()->header().seq))
436 if (jv[jss::full] !=
true)
439 if (jv.isMember(jss::load_fee))
442 if (!jv.isMember(jss::signature))
445 if (!jv.isMember(jss::signing_time))
448 if (!jv.isMember(jss::cookie))
451 if (!jv.isMember(jss::validated_hash))
454 uint32_t netID = env.app().config().NETWORK_ID;
455 if (!jv.isMember(jss::network_id) || jv[jss::network_id] != netID)
459 bool const isFlagLedger = (env.closed()->header().seq + 1) % 256 == 0;
475 while (env.closed()->header().seq < 300)
478 using namespace std::chrono_literals;
479 BEAST_EXPECT(wsc->findMsg(5s, validValidationFields));
484 auto jv = wsc->invoke(
"unsubscribe", stream);
485 if (wsc->version() == 2)
487 BEAST_EXPECT(jv.isMember(jss::jsonrpc) && jv[jss::jsonrpc] ==
"2.0");
488 BEAST_EXPECT(jv.isMember(jss::ripplerpc) && jv[jss::ripplerpc] ==
"2.0");
489 BEAST_EXPECT(jv.isMember(jss::id) && jv[jss::id] == 5);
491 BEAST_EXPECT(jv[jss::status] ==
"success");
527 auto const method = subscribe ?
"subscribe" :
"unsubscribe";
528 testcase <<
"Error cases for " << method;
534 auto jr = env.rpc(
"json", method,
"{}")[jss::result];
535 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
536 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
541 jv[jss::url] =
"not-a-url";
542 jv[jss::username] =
"admin";
543 jv[jss::password] =
"password";
544 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
547 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
548 BEAST_EXPECT(jr[jss::error_message] ==
"Failed to parse url.");
556 jv[jss::url] =
"ftp://scheme.not.supported.tld";
557 auto jr = env.rpc(
"json", method,
to_string(jv))[jss::result];
560 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
561 BEAST_EXPECT(jr[jss::error_message] ==
"Only http and https is supported.");
568 jv[jss::url] =
"no-url";
569 auto jr = env_nonadmin.rpc(
"json", method,
to_string(jv))[jss::result];
570 BEAST_EXPECT(jr[jss::error] ==
"noPermission");
571 BEAST_EXPECT(jr[jss::error_message] ==
"You don't have permission for this command.");
583 for (
auto const& f : {jss::accounts_proposed, jss::accounts})
585 for (
auto const& nonArray : nonArrays)
589 auto jr = wsc->invoke(method, jv)[jss::result];
590 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
591 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
597 auto jr = wsc->invoke(method, jv)[jss::result];
598 BEAST_EXPECT(jr[jss::error] ==
"actMalformed");
599 BEAST_EXPECT(jr[jss::error_message] ==
"Account malformed.");
603 for (
auto const& nonArray : nonArrays)
606 jv[jss::books] = nonArray;
607 auto jr = wsc->invoke(method, jv)[jss::result];
608 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
609 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
615 jv[jss::books][0u] = 1;
616 auto jr = wsc->invoke(method, jv)[jss::result];
617 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
618 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
627 auto jr = wsc->invoke(method, jv)[jss::result];
628 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
629 BEAST_EXPECT(jr[jss::error_message] ==
"Source currency is malformed.");
638 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"ZZZZ";
639 auto jr = wsc->invoke(method, jv)[jss::result];
640 BEAST_EXPECT(jr[jss::error] ==
"srcCurMalformed");
641 BEAST_EXPECT(jr[jss::error_message] ==
"Source currency is malformed.");
650 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
651 jv[jss::books][0u][jss::taker_pays][jss::issuer] = 1;
652 auto jr = wsc->invoke(method, jv)[jss::result];
653 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
654 BEAST_EXPECT(jr[jss::error_message] ==
"Source issuer is malformed.");
663 jv[jss::books][0u][jss::taker_pays][jss::currency] =
"USD";
664 jv[jss::books][0u][jss::taker_pays][jss::issuer] =
Account{
"gateway"}.
human() +
"DEAD";
665 auto jr = wsc->invoke(method, jv)[jss::result];
666 BEAST_EXPECT(jr[jss::error] ==
"srcIsrMalformed");
667 BEAST_EXPECT(jr[jss::error_message] ==
"Source issuer is malformed.");
674 jv[jss::books][0u][jss::taker_pays] =
677 auto jr = wsc->invoke(method, jv)[jss::result];
680 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
681 BEAST_EXPECT(jr[jss::error_message] ==
"Destination amount/currency/issuer is malformed.");
688 jv[jss::books][0u][jss::taker_pays] =
690 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"ZZZZ";
691 auto jr = wsc->invoke(method, jv)[jss::result];
694 BEAST_EXPECT(jr[jss::error] ==
"dstAmtMalformed");
695 BEAST_EXPECT(jr[jss::error_message] ==
"Destination amount/currency/issuer is malformed.");
702 jv[jss::books][0u][jss::taker_pays] =
704 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
705 jv[jss::books][0u][jss::taker_gets][jss::issuer] = 1;
706 auto jr = wsc->invoke(method, jv)[jss::result];
707 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
708 BEAST_EXPECT(jr[jss::error_message] ==
"Destination issuer is malformed.");
715 jv[jss::books][0u][jss::taker_pays] =
717 jv[jss::books][0u][jss::taker_gets][jss::currency] =
"USD";
718 jv[jss::books][0u][jss::taker_gets][jss::issuer] =
Account{
"gateway"}.
human() +
"DEAD";
719 auto jr = wsc->invoke(method, jv)[jss::result];
720 BEAST_EXPECT(jr[jss::error] ==
"dstIsrMalformed");
721 BEAST_EXPECT(jr[jss::error_message] ==
"Destination issuer is malformed.");
728 jv[jss::books][0u][jss::taker_pays] =
730 jv[jss::books][0u][jss::taker_gets] =
732 auto jr = wsc->invoke(method, jv)[jss::result];
733 BEAST_EXPECT(jr[jss::error] ==
"badMarket");
734 BEAST_EXPECT(jr[jss::error_message] ==
"No such market.");
737 for (
auto const& nonArray : nonArrays)
740 jv[jss::streams] = nonArray;
741 auto jr = wsc->invoke(method, jv)[jss::result];
742 BEAST_EXPECT(jr[jss::error] ==
"invalidParams");
743 BEAST_EXPECT(jr[jss::error_message] ==
"Invalid parameters.");
749 jv[jss::streams][0u] = 1;
750 auto jr = wsc->invoke(method, jv)[jss::result];
751 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
752 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
758 jv[jss::streams][0u] =
"not_a_stream";
759 auto jr = wsc->invoke(method, jv)[jss::result];
760 BEAST_EXPECT(jr[jss::error] ==
"malformedStream");
761 BEAST_EXPECT(jr[jss::error_message] ==
"Stream malformed.");
770 using namespace std::chrono_literals;
783 auto goodSubRPC = [](
Json::Value const& subReply) ->
bool {
784 return subReply.isMember(jss::result) && subReply[jss::result].isMember(jss::status) &&
785 subReply[jss::result][jss::status] == jss::success;
794 bool first_flag =
false;
796 for (
int i = 0; i < numReplies; ++i)
799 auto reply = wsc.
getMsg(100ms);
803 if (r.isMember(jss::account_history_tx_index))
804 idx = r[jss::account_history_tx_index].asInt();
805 if (r.isMember(jss::account_history_tx_first))
807 bool boundary = r.isMember(jss::account_history_boundary);
808 int ledger_idx = r[jss::ledger_index].asInt();
809 if (r.isMember(jss::transaction) && r[jss::transaction].isMember(jss::hash))
811 auto t{r[jss::transaction]};
812 v.emplace_back(idx, t[jss::hash].asString(), boundary, ledger_idx);
816 return {
false, first_flag};
819 return {
true, first_flag};
826 auto sendPayments = [](
Env& env,
834 for (
int i = 0; i < newTxns; ++i)
836 auto& from = (i % 2 == 0) ? a : b;
837 auto& to = (i % 2 == 0) ? b : a;
843 for (
int i = 0; i < ledgersToClose; ++i)
853 auto hashCompare = [](IdxHashVec
const& accountVec, IdxHashVec
const& txHistoryVec,
bool sizeCompare) ->
bool {
854 if (accountVec.empty() || txHistoryVec.empty())
856 if (sizeCompare && accountVec.size() != (txHistoryVec.size()))
860 for (
auto const& tx : txHistoryVec)
866 if (i >= accountVec.size())
869 if (it == txHistoryMap.
end())
874 auto firstHistoryIndex = getHistoryIndex(0);
875 if (!firstHistoryIndex)
877 for (
std::size_t i = 1; i < accountVec.size(); ++i)
879 if (
auto idx = getHistoryIndex(i); !idx || *idx != *firstHistoryIndex + i)
915 auto checkBoundary = [](IdxHashVec
const& vec,
bool ) {
916 size_t num_tx = vec.size();
917 for (
size_t i = 0; i < num_tx; ++i)
919 auto [idx, hash, boundary, ledger] = vec[i];
920 if ((i + 1 == num_tx || ledger !=
std::get<3>(vec[i + 1])) != boundary)
939 request[jss::account_history_tx_stream][jss::account] = alice.
human();
940 auto jv = wscTxHistory->invoke(
"subscribe", request);
941 if (!BEAST_EXPECT(goodSubRPC(jv)))
944 jv = wscTxHistory->invoke(
"subscribe", request);
945 BEAST_EXPECT(!goodSubRPC(jv));
950 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
true;
951 jv = wscTxHistory->invoke(
"unsubscribe", request);
952 if (!BEAST_EXPECT(goodSubRPC(jv)))
955 sendPayments(env, env.
master, alice, 1, 1, 123456);
958 auto r = getTxHash(*wscTxHistory, vec, 1);
959 if (!BEAST_EXPECT(r.first && r.second))
965 request[jss::account_history_tx_stream][jss::stop_history_tx_only] =
false;
966 jv = wscTxHistory->invoke(
"unsubscribe", request);
967 BEAST_EXPECT(goodSubRPC(jv));
969 sendPayments(env, env.
master, alice, 1, 1);
970 r = getTxHash(*wscTxHistory, vec, 1);
971 BEAST_EXPECT(!r.first);
982 request[jss::account_history_tx_stream][jss::account] =
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
983 auto jv = wscTxHistory->invoke(
"subscribe", request);
984 if (!BEAST_EXPECT(goodSubRPC(jv)))
986 IdxHashVec genesisFullHistoryVec;
987 if (!BEAST_EXPECT(!getTxHash(*wscTxHistory, genesisFullHistoryVec, 1).first))
994 sendPayments(env, env.
master, bob, 1, 1, 654321);
996 auto r = getTxHash(*wscTxHistory, genesisFullHistoryVec, 1);
997 if (!BEAST_EXPECT(r.first && r.second))
1000 request[jss::account_history_tx_stream][jss::account] = bob.
human();
1001 jv = wscTxHistory->invoke(
"subscribe", request);
1002 if (!BEAST_EXPECT(goodSubRPC(jv)))
1004 IdxHashVec bobFullHistoryVec;
1005 r = getTxHash(*wscTxHistory, bobFullHistoryVec, 1);
1006 if (!BEAST_EXPECT(r.first && r.second))
1013 jv = wscTxHistory->invoke(
"unsubscribe", request);
1014 if (!BEAST_EXPECT(goodSubRPC(jv)))
1016 request[jss::account_history_tx_stream][jss::account] =
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1017 jv = wscTxHistory->invoke(
"unsubscribe", request);
1018 BEAST_EXPECT(goodSubRPC(jv));
1024 sendPayments(env, env.
master, bob, 30, 300);
1026 request[jss::account_history_tx_stream][jss::account] = bob.
human();
1027 jv = wscTxHistory->invoke(
"subscribe", request);
1029 bobFullHistoryVec.
clear();
1030 BEAST_EXPECT(getTxHash(*wscTxHistory, bobFullHistoryVec, 31).second);
1031 jv = wscTxHistory->invoke(
"unsubscribe", request);
1033 request[jss::account_history_tx_stream][jss::account] =
"rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh";
1034 jv = wscTxHistory->invoke(
"subscribe", request);
1035 genesisFullHistoryVec.
clear();
1036 BEAST_EXPECT(getTxHash(*wscTxHistory, genesisFullHistoryVec, 31).second);
1037 jv = wscTxHistory->invoke(
"unsubscribe", request);
1052 env.
fund(
XRP(222222), accounts);
1058 stream[jss::accounts].append(alice.
human());
1059 auto jv = wscAccount->invoke(
"subscribe", stream);
1061 sendPayments(env, alice, bob, 5, 1);
1062 sendPayments(env, alice, bob, 5, 1);
1063 IdxHashVec accountVec;
1064 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1070 request[jss::account_history_tx_stream][jss::account] = alice.
human();
1071 jv = wscTxHistory->invoke(
"subscribe", request);
1074 IdxHashVec txHistoryVec;
1075 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1077 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1082 if (!BEAST_EXPECT(checkBoundary(txHistoryVec,
false)))
1087 IdxHashVec initFundTxns;
1088 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, initFundTxns, 10).second) ||
1089 !BEAST_EXPECT(checkBoundary(initFundTxns,
false)))
1094 sendPayments(env, alice, bob, 10, 1);
1095 if (!BEAST_EXPECT(getTxHash(*wscAccount, accountVec, 10).first))
1097 if (!BEAST_EXPECT(getTxHash(*wscTxHistory, txHistoryVec, 10).first))
1099 if (!BEAST_EXPECT(hashCompare(accountVec, txHistoryVec,
true)))
1104 if (!BEAST_EXPECT(checkBoundary(txHistoryVec,
false)))
1107 wscTxHistory->invoke(
"unsubscribe", request);
1108 wscAccount->invoke(
"unsubscribe", stream);
1117 auto const USD_a = alice[
"USD"];
1120 env.
fund(
XRP(333333), accounts);
1121 env.
trust(USD_a(20000), carol);
1124 auto mixedPayments = [&]() ->
int {
1125 sendPayments(env, alice, carol, 1, 0);
1126 env(
pay(alice, carol, USD_a(100)));
1134 request[jss::account_history_tx_stream][jss::account] = carol.
human();
1136 auto jv = ws->invoke(
"subscribe", request);
1140 getTxHash(*ws, tempVec, 100);
1143 auto count = mixedPayments();
1145 if (!BEAST_EXPECT(getTxHash(*ws, vec1, count).first))
1147 ws->invoke(
"unsubscribe", request);
1156 env.
fund(
XRP(444444), accounts);
1160 auto oneRound = [&](
int numPayments) {
return sendPayments(env, alice, carol, numPayments, 300); };
1165 request[jss::account_history_tx_stream][jss::account] = carol.
human();
1167 auto jv = wscLong->invoke(
"subscribe", request);
1171 getTxHash(*wscLong, tempVec, 100);
1175 for (
int kk = 2; kk < 10; ++kk)
1177 auto count = oneRound(kk);
1179 if (!BEAST_EXPECT(getTxHash(*wscLong, vec1, count).first))
1184 auto jv = wscShort->invoke(
"subscribe", request);
1186 if (!BEAST_EXPECT(getTxHash(*wscShort, vec2, count).first))
1188 if (!BEAST_EXPECT(hashCompare(vec1, vec2,
true)))
1190 wscShort->invoke(
"unsubscribe", request);
1256 testcase(
"Test synthetic fields from Subscribe response");
1258 using namespace test::jtx;
1259 using namespace std::chrono_literals;
1263 Account const broker{
"broker"};
1265 Env env{*
this, features};
1266 env.fund(
XRP(10000), alice, bob, broker);
1272 stream[jss::streams].append(
"transactions");
1273 auto jv = wsc->invoke(
"subscribe", stream);
1278 auto verifyNFTokenID = [&](
uint256 const& actualNftID) {
1279 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
1281 BEAST_EXPECT(nftID.parseHex(jv[jss::meta][jss::nftoken_id].asString()));
1282 return nftID == actualNftID;
1289 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
1290 std::vector<uint256> metaIDs;
1292 jv[jss::meta][jss::nftoken_ids].begin(),
1293 jv[jss::meta][jss::nftoken_ids].end(),
1294 std::back_inserter(metaIDs),
1295 [this](Json::Value id) {
1297 BEAST_EXPECT(nftID.parseHex(id.asString()));
1301 std::sort(metaIDs.begin(), metaIDs.end());
1302 std::sort(actualNftIDs.begin(), actualNftIDs.end());
1305 BEAST_EXPECT(metaIDs.size() == actualNftIDs.size());
1309 for (
size_t i = 0; i < metaIDs.size(); ++i)
1310 BEAST_EXPECT(metaIDs[i] == actualNftIDs[i]);
1317 auto verifyNFTokenOfferID = [&](
uint256 const& offerID) {
1318 BEAST_EXPECT(wsc->findMsg(5s, [&](
auto const& jv) {
1319 uint256 metaOfferID;
1320 BEAST_EXPECT(metaOfferID.parseHex(jv[jss::meta][jss::offer_id].asString()));
1321 return metaOfferID == offerID;
1332 verifyNFTokenID(nftId1);
1337 verifyNFTokenID(nftId2);
1345 verifyNFTokenOfferID(aliceOfferIndex1);
1350 verifyNFTokenOfferID(aliceOfferIndex2);
1357 verifyNFTokenIDsInCancelOffer({nftId1, nftId2});
1364 verifyNFTokenOfferID(bobBuyOfferIndex);
1370 verifyNFTokenID(nftId1);
1379 verifyNFTokenID(nftId);
1385 verifyNFTokenOfferID(offerAliceToBroker);
1391 verifyNFTokenOfferID(offerBobToBroker);
1396 verifyNFTokenID(nftId);
1406 verifyNFTokenID(nftId);
1412 verifyNFTokenOfferID(aliceOfferIndex1);
1417 verifyNFTokenOfferID(aliceOfferIndex2);
1423 verifyNFTokenIDsInCancelOffer({nftId});
1426 if (features[featureNFTokenMintOffer])
1431 verifyNFTokenOfferID(aliceMintWithOfferIndex1);