21#include <test/jtx/AMM.h>
22#include <test/jtx/xchain_bridge.h>
24#include <xrpld/app/tx/detail/NFTokenMint.h>
26#include <xrpl/json/json_reader.h>
27#include <xrpl/json/json_value.h>
28#include <xrpl/json/to_string.h>
29#include <xrpl/protocol/jss.h>
30#include <xrpl/protocol/nft.h>
32#include <boost/utility/string_ref.hpp>
41 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
42 "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
45 "LedgerEntryType" : "Offer",
50 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
53 "TakerPays" : "100000000",
54 "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
59 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
65 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
69 "LedgerEntryType" : "RippleState",
72 "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
76 "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
81 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
87 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
91 "LedgerEntryType" : "RippleState",
94 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
98 "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
101 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
102 "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
105 "LedgerEntryType" : "Offer",
110 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
113 "TakerPays" : "100000000",
114 "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
131 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
133 resp[jss::result][jss::error_message] ==
134 "Missing field 'account'.");
138 auto testInvalidAccountParam = [&](
auto const& param) {
140 params[jss::account] = param;
142 "json",
"account_objects",
to_string(params))[jss::result];
143 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
145 jrr[jss::error_message] ==
"Invalid field 'account'.");
148 testInvalidAccountParam(1);
149 testInvalidAccountParam(1.1);
150 testInvalidAccountParam(
true);
158 params[jss::account] =
159 "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
160 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
162 resp[jss::result][jss::error_message] ==
"Account malformed.");
168 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
170 resp[jss::result][jss::error_message] ==
"Account not found.");
176 params[jss::account] = bob.human();
177 params[jss::ledger_index] = 10;
178 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
180 resp[jss::result][jss::error_message] ==
"ledgerNotFound");
187 params[jss::account] = bob.human();
188 params[jss::type] = 10;
189 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
191 resp[jss::result][jss::error_message] ==
192 "Invalid field 'type', not string.");
197 params[jss::account] = bob.human();
198 params[jss::type] =
"expedited";
199 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
201 resp[jss::result][jss::error_message] ==
202 "Invalid field 'type'.");
207 params[jss::account] = bob.human();
208 params[jss::limit] = -1;
209 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
211 resp[jss::result][jss::error_message] ==
212 "Invalid field 'limit', not unsigned integer.");
218 auto const USD = gw[
"USD"];
219 env.
trust(USD(1000), bob);
220 env(
pay(gw, bob,
XRP(1)));
224 params[jss::account] = bob.human();
225 params[jss::limit] = 1;
226 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
228 auto resume_marker = resp[jss::result][jss::marker];
230 params[jss::marker] = 10;
231 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
233 resp[jss::result][jss::error_message] ==
234 "Invalid field 'marker', not string.");
236 params[jss::marker] =
"This is a string with no comma";
237 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
239 resp[jss::result][jss::error_message] ==
240 "Invalid field 'marker'.");
242 params[jss::marker] =
"This string has a comma, but is not hex";
243 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
245 resp[jss::result][jss::error_message] ==
246 "Invalid field 'marker'.");
249 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
251 resp[jss::result][jss::error_message] ==
252 "Invalid field 'marker'.");
255 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
257 resp[jss::result][jss::error_message] ==
258 "Invalid field 'marker'.");
260 params[jss::marker] =
std::string(&mark[1U], 65) +
"not hex";
261 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
263 resp[jss::result][jss::error_message] ==
264 "Invalid field 'marker'.");
270 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
271 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
287 auto const USD1 = gw1[
"USD"];
288 auto const USD2 = gw2[
"USD"];
290 env.
fund(
XRP(1000), gw1, gw2, bob);
291 env.
trust(USD1(1000), bob);
292 env.
trust(USD2(1000), bob);
294 env(
pay(gw1, bob, USD1(1000)));
295 env(
pay(gw2, bob, USD2(1000)));
301 for (
int i = 0; i < 4; ++i)
308 params[jss::account] = bob.human();
309 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
310 BEAST_EXPECT(!resp.isMember(jss::marker));
312 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 4);
313 for (
int i = 0; i < 4; ++i)
315 auto& aobj = resp[jss::result][jss::account_objects][i];
316 aobj.removeMember(
"PreviousTxnID");
317 aobj.removeMember(
"PreviousTxnLgrSeq");
318 BEAST_EXPECT(aobj == bobj[i]);
324 params[jss::account] = bob.human();
325 params[jss::type] = jss::state;
326 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
327 BEAST_EXPECT(!resp.isMember(jss::marker));
329 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
330 for (
int i = 0; i < 2; ++i)
332 auto& aobj = resp[jss::result][jss::account_objects][i];
333 aobj.removeMember(
"PreviousTxnID");
334 aobj.removeMember(
"PreviousTxnLgrSeq");
335 BEAST_EXPECT(aobj == bobj[i + 1]);
341 params[jss::account] = bob.human();
342 params[jss::limit] = 1;
343 for (
int i = 0; i < 4; ++i)
347 auto& aobjs = resp[jss::result][jss::account_objects];
348 BEAST_EXPECT(aobjs.size() == 1);
349 auto& aobj = aobjs[0U];
351 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
353 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
355 aobj.removeMember(
"PreviousTxnID");
356 aobj.removeMember(
"PreviousTxnLgrSeq");
358 BEAST_EXPECT(aobj == bobj[i]);
360 params[jss::marker] = resp[jss::result][jss::marker];
371 testcase(
"unsteppedThenSteppedWithNFTs");
380 auto const USD1 = gw1[
"USD"];
381 auto const USD2 = gw2[
"USD"];
383 env.
fund(
XRP(1000), gw1, gw2, bob);
390 params[jss::account] = bob.human();
391 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
392 BEAST_EXPECT(!resp.isMember(jss::marker));
393 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
396 params[jss::limit] = 1;
397 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
398 BEAST_EXPECT(!resp.isMember(jss::marker));
399 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
411 params[jss::account] = bob.human();
412 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
413 BEAST_EXPECT(!resp.isMember(jss::marker));
415 unpaged = resp[jss::result][jss::account_objects];
416 BEAST_EXPECT(unpaged.
size() == 1);
421 params[jss::account] = bob.human();
422 params[jss::type] = jss::nft_page;
423 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
424 BEAST_EXPECT(!resp.isMember(jss::marker));
425 Json::Value& aobjs = resp[jss::result][jss::account_objects];
426 BEAST_EXPECT(aobjs.
size() == 1);
428 aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
429 BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].
size() == 1);
434 params[jss::account] = bob.human();
435 params[jss::limit] = 1;
439 Json::Value& aobjs = resp[jss::result][jss::account_objects];
440 BEAST_EXPECT(aobjs.
size() == 1);
441 auto& aobj = aobjs[0U];
442 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
443 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
445 BEAST_EXPECT(aobj == unpaged[0u]);
449 env.
trust(USD1(1000), bob);
450 env.
trust(USD2(1000), bob);
452 env(
pay(gw1, bob, USD1(1000)));
453 env(
pay(gw2, bob, USD2(1000)));
462 params[jss::account] = bob.human();
463 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
464 BEAST_EXPECT(!resp.isMember(jss::marker));
466 unpaged = resp[jss::result][jss::account_objects];
467 BEAST_EXPECT(unpaged.
size() == 5);
472 params[jss::account] = bob.human();
473 params[jss::type] = jss::nft_page;
474 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
475 BEAST_EXPECT(!resp.isMember(jss::marker));
476 Json::Value& aobjs = resp[jss::result][jss::account_objects];
477 BEAST_EXPECT(aobjs.
size() == 1);
479 aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
480 BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].
size() == 1);
485 params[jss::account] = bob.human();
486 params[jss::limit] = 1;
487 for (
int i = 0; i < 5; ++i)
491 Json::Value& aobjs = resp[jss::result][jss::account_objects];
492 BEAST_EXPECT(aobjs.
size() == 1);
493 auto& aobj = aobjs[0U];
496 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
497 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
501 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
502 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
505 BEAST_EXPECT(aobj == unpaged[i]);
507 params[jss::marker] = resp[jss::result][jss::marker];
512 for (
int i = 0; i < 32; ++i)
520 params[jss::account] = bob.human();
521 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
522 BEAST_EXPECT(!resp.isMember(jss::marker));
524 unpaged = resp[jss::result][jss::account_objects];
525 BEAST_EXPECT(unpaged.
size() == 6);
530 params[jss::account] = bob.human();
531 params[jss::type] = jss::nft_page;
532 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
533 BEAST_EXPECT(!resp.isMember(jss::marker));
534 Json::Value& aobjs = resp[jss::result][jss::account_objects];
535 BEAST_EXPECT(aobjs.
size() == 2);
540 params[jss::account] = bob.human();
541 params[jss::limit] = 1;
542 for (
int i = 0; i < 6; ++i)
546 Json::Value& aobjs = resp[jss::result][jss::account_objects];
547 BEAST_EXPECT(aobjs.
size() == 1);
548 auto& aobj = aobjs[0U];
551 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
552 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
556 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
557 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
560 BEAST_EXPECT(aobj == unpaged[i]);
562 params[jss::marker] = resp[jss::result][jss::marker];
578 auto const USD = gw[
"USD"];
581 featurePermissionedDomains;
582 Env env(*
this, features);
585 auto acctObjs = [&env](
593 params[jss::type] = *type;
595 params[jss::limit] = *limit;
597 params[jss::marker] = *marker;
598 params[jss::ledger_index] =
"validated";
599 return env.
rpc(
"json",
"account_objects",
to_string(params));
603 auto acctObjsIsSize = [](
Json::Value const& resp,
unsigned size) {
604 return resp[jss::result][jss::account_objects].
isArray() &&
605 (resp[jss::result][jss::account_objects].
size() == size);
609 auto acctObjsTypeIsInvalid = [](
Json::Value const& resp) {
610 return resp[jss::result].
isMember(jss::error) &&
611 resp[jss::result][jss::error_message] ==
612 "Invalid field \'type\'.";
615 env.
fund(
XRP(10000), gw, alice);
620 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::account), 0));
621 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::check), 0));
622 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::deposit_preauth), 0));
623 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::escrow), 0));
624 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::nft_page), 0));
625 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::offer), 0));
626 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::payment_channel), 0));
627 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::signer_list), 0));
628 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::state), 0));
629 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::ticket), 0));
630 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0));
631 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::did), 0));
632 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::permissioned_domain), 0));
635 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments)));
636 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::directory)));
637 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::fee)));
638 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::hashes)));
639 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::NegativeUNL)));
647 Json::Value const resp = acctObjs(gw, jss::nft_page);
648 BEAST_EXPECT(acctObjsIsSize(resp, 1));
650 auto const& nftPage = resp[jss::result][jss::account_objects][0u];
651 BEAST_EXPECT(nftPage[sfNFTokens.jsonName].size() == 1);
653 nftPage[sfNFTokens.jsonName][0u][sfNFToken.jsonName]
654 [sfNFTokenID.jsonName] ==
to_string(nftID));
658 env.
trust(USD(1000), alice);
660 env(
pay(gw, alice, USD(5)));
665 BEAST_EXPECT(acctObjsIsSize(resp, 1));
667 auto const& state = resp[jss::result][jss::account_objects][0u];
668 BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5);
670 state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
678 BEAST_EXPECT(acctObjsIsSize(resp, 1));
680 auto const& check = resp[jss::result][jss::account_objects][0u];
681 BEAST_EXPECT(check[sfAccount.jsonName] == gw.human());
682 BEAST_EXPECT(check[sfDestination.jsonName] == alice.human());
683 BEAST_EXPECT(check[sfSendMax.jsonName][jss::value].asUInt() == 10);
690 Json::Value const resp = acctObjs(gw, jss::deposit_preauth);
691 BEAST_EXPECT(acctObjsIsSize(resp, 1));
693 auto const& preauth = resp[jss::result][jss::account_objects][0u];
694 BEAST_EXPECT(preauth[sfAccount.jsonName] == gw.human());
695 BEAST_EXPECT(preauth[sfAuthorize.jsonName] == alice.human());
700 jvEscrow[jss::TransactionType] = jss::EscrowCreate;
701 jvEscrow[jss::Account] = gw.human();
702 jvEscrow[jss::Destination] = gw.human();
704 jvEscrow[sfFinishAfter.jsonName] =
711 Json::Value const resp = acctObjs(gw, jss::escrow);
712 BEAST_EXPECT(acctObjsIsSize(resp, 1));
714 auto const&
escrow = resp[jss::result][jss::account_objects][0u];
715 BEAST_EXPECT(
escrow[sfAccount.jsonName] == gw.human());
716 BEAST_EXPECT(
escrow[sfDestination.jsonName] == gw.human());
717 BEAST_EXPECT(
escrow[sfAmount.jsonName].
asUInt() == 100'000'000);
730 Json::Value const resp = acctObjs(gw, jss::permissioned_domain);
731 BEAST_EXPECT(acctObjsIsSize(resp, 1));
733 auto const& permissionedDomain =
734 resp[jss::result][jss::account_objects][0u];
736 permissionedDomain.isMember(jss::Owner) &&
737 (permissionedDomain[jss::Owner] == gw.human()));
738 bool const check1 = BEAST_EXPECT(
739 permissionedDomain.isMember(jss::AcceptedCredentials) &&
740 permissionedDomain[jss::AcceptedCredentials].isArray() &&
741 (permissionedDomain[jss::AcceptedCredentials].size() == 1) &&
742 (permissionedDomain[jss::AcceptedCredentials][0u].isMember(
748 permissionedDomain[jss::AcceptedCredentials][0u]
754 credential.isMember(sfCredentialType.jsonName) &&
756 strHex(credentialType1)));
766 auto scEnvAcctObjs = [&](
Account const& acct,
char const* type) {
768 params[jss::account] = acct.
human();
769 params[jss::type] = type;
770 params[jss::ledger_index] =
"validated";
771 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
777 BEAST_EXPECT(acctObjsIsSize(resp, 1));
778 auto const& acct_bridge =
779 resp[jss::result][jss::account_objects][0u];
783 acct_bridge[sfLedgerEntryType.getJsonName()] ==
"Bridge");
785 acct_bridge[sfXChainClaimID.getJsonName()].asUInt() == 0);
787 acct_bridge[sfXChainAccountClaimCount.getJsonName()].asUInt() ==
790 acct_bridge[sfXChainAccountCreateCount.getJsonName()]
793 acct_bridge[sfMinAccountCreateAmount.getJsonName()].asUInt() ==
796 acct_bridge[sfSignatureReward.getJsonName()].asUInt() ==
798 BEAST_EXPECT(acct_bridge[sfXChainBridge.getJsonName()] == x.
jvb);
813 auto scEnvAcctObjs = [&](
Account const& acct,
char const* type) {
815 params[jss::account] = acct.
human();
816 params[jss::type] = type;
817 params[jss::ledger_index] =
"validated";
818 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
824 scEnvAcctObjs(x.
scAlice, jss::xchain_owned_claim_id);
825 BEAST_EXPECT(acctObjsIsSize(resp, 1));
827 auto const& xchain_seq =
828 resp[jss::result][jss::account_objects][0u];
832 xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 1);
837 scEnvAcctObjs(x.
scBob, jss::xchain_owned_claim_id);
838 BEAST_EXPECT(acctObjsIsSize(resp, 1));
840 auto const& xchain_seq =
841 resp[jss::result][jss::account_objects][0u];
842 BEAST_EXPECT(xchain_seq[sfAccount.jsonName] == x.
scBob.
human());
844 xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 2);
851 auto const amt =
XRP(1000);
870 auto scEnvAcctObjs = [&](
Account const& acct,
char const* type) {
872 params[jss::account] = acct.
human();
873 params[jss::type] = type;
874 params[jss::ledger_index] =
"validated";
875 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
882 BEAST_EXPECT(acctObjsIsSize(resp, 1));
884 auto const& xchain_create_account_claim_id =
885 resp[jss::result][jss::account_objects][0u];
887 xchain_create_account_claim_id[sfAccount.jsonName] ==
890 xchain_create_account_claim_id[sfXChainAccountCreateCount
902 BEAST_EXPECT(acctObjsIsSize(resp, 1));
904 auto const&
offer = resp[jss::result][jss::account_objects][0u];
905 BEAST_EXPECT(
offer[sfAccount.jsonName] == gw.human());
906 BEAST_EXPECT(
offer[sfTakerGets.jsonName].
asUInt() == 14'000'000);
907 BEAST_EXPECT(
offer[sfTakerPays.jsonName][jss::value].
asUInt() == 7);
913 jvPayChan[jss::TransactionType] = jss::PaymentChannelCreate;
914 jvPayChan[jss::Account] = gw.human();
915 jvPayChan[jss::Destination] = alice.human();
916 jvPayChan[jss::Amount] =
918 jvPayChan[sfSettleDelay.jsonName] = 24 * 60 * 60;
919 jvPayChan[sfPublicKey.jsonName] =
strHex(gw.pk().slice());
925 Json::Value const resp = acctObjs(gw, jss::payment_channel);
926 BEAST_EXPECT(acctObjsIsSize(resp, 1));
928 auto const& payChan = resp[jss::result][jss::account_objects][0u];
929 BEAST_EXPECT(payChan[sfAccount.jsonName] == gw.human());
930 BEAST_EXPECT(payChan[sfAmount.jsonName].asUInt() == 300'000'000);
932 payChan[sfSettleDelay.jsonName].asUInt() == 24 * 60 * 60);
938 jvDID[jss::TransactionType] = jss::DIDSet;
939 jvDID[jss::Account] = gw.human();
947 BEAST_EXPECT(acctObjsIsSize(resp, 1));
949 auto const& did = resp[jss::result][jss::account_objects][0u];
950 BEAST_EXPECT(did[sfAccount.jsonName] == gw.human());
958 Json::Value const resp = acctObjs(gw, jss::signer_list);
959 BEAST_EXPECT(acctObjsIsSize(resp, 1));
961 auto const& signerList =
962 resp[jss::result][jss::account_objects][0u];
963 BEAST_EXPECT(signerList[sfSignerQuorum.jsonName] == 6);
964 auto const& entry = signerList[sfSignerEntries.jsonName][0u]
965 [sfSignerEntry.jsonName];
966 BEAST_EXPECT(entry[sfAccount.jsonName] == alice.human());
967 BEAST_EXPECT(entry[sfSignerWeight.jsonName].
asUInt() == 7);
971 auto const seq = env.
seq(gw);
977 Json::Value const resp = acctObjs(gw, jss::ticket);
978 BEAST_EXPECT(acctObjsIsSize(resp, 1));
980 auto const& ticket = resp[jss::result][jss::account_objects][0u];
981 BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human());
982 BEAST_EXPECT(ticket[sfLedgerEntryType.jsonName] == jss::Ticket);
983 BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() ==
seq + 1);
989 params[jss::account] = gw.human();
990 params[jss::deletion_blockers_only] =
true;
991 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
997 jss::NFTokenPage.c_str(),
998 jss::RippleState.c_str(),
999 jss::PayChannel.c_str(),
1000 jss::PermissionedDomain.c_str()};
1008 if (BEAST_EXPECT(acctObjsIsSize(resp, expectedAccountObjects)))
1010 auto const& aobjs = resp[jss::result][jss::account_objects];
1012 gotLedgerTypes.
reserve(expectedAccountObjects);
1016 aobjs[i][
"LedgerEntryType"].asString());
1019 BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
1026 params[jss::account] = gw.human();
1027 params[jss::deletion_blockers_only] =
true;
1028 params[jss::type] = jss::escrow;
1029 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1031 if (BEAST_EXPECT(acctObjsIsSize(resp, 1u)))
1033 auto const& aobjs = resp[jss::result][jss::account_objects];
1034 BEAST_EXPECT(aobjs[0u][
"LedgerEntryType"] == jss::Escrow);
1041 auto const objs = resp[jss::result][jss::account_objects];
1042 for (
auto const& obj : resp[jss::result][jss::account_objects])
1044 obj[sfLedgerEntryType.fieldName].asString());
1045 std::sort(typesOut.begin(), typesOut.end());
1049 auto expectObjects =
1052 if (!acctObjsIsSize(resp, types.
size()))
1055 getTypes(resp, typesOut);
1056 return types == typesOut;
1059 AMM amm(env, gw,
XRP(1'000), USD(1'000));
1060 amm.deposit(alice, USD(1));
1063 BEAST_EXPECT(
lines[jss::lines].size() == 3);
1066 acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1));
1068 auto resp = acctObjs(amm.ammAccount(), std::nullopt, 2);
1070 getTypes(resp, typesOut);
1076 resp[jss::result][jss::marker].
asString());
1077 getTypes(resp, typesOut);
1082 jss::RippleState.c_str(),
1083 jss::RippleState.c_str(),
1084 jss::RippleState.c_str()}));
1086 resp = acctObjs(amm.ammAccount(), jss::state, 10);
1087 BEAST_EXPECT(expectObjects(
1089 {jss::RippleState.c_str(),
1090 jss::RippleState.c_str(),
1091 jss::RippleState.c_str()}));
1094 acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0));
1096 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0));
1100 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments)));
1101 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::directory)));
1102 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::fee)));
1103 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::hashes)));
1104 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::NegativeUNL)));
1108 for (
int d = 1'000'032; d >= 1'000'000; --d)
1115 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::account), 0));
1127 using namespace jtx;
1133 static constexpr unsigned nftsSize = 10;
1134 for (
unsigned i = 0; i < nftsSize; i++)
1145 params[jss::account] = bob.human();
1146 params[jss::ledger_index] =
"validated";
1149 Json::Value const& nfts = resp[jss::result][jss::account_nfts];
1157 auto compareNFTs = [&tokenIDs, &env, &bob](
1158 unsigned const limit,
unsigned const lastIndex) {
1160 params[jss::account] = bob.human();
1161 params[jss::limit] = limit;
1162 params[jss::marker] = tokenIDs[lastIndex];
1163 params[jss::ledger_index] =
"validated";
1167 if (resp[jss::result].isMember(jss::error))
1170 Json::Value const& nfts = resp[jss::result][jss::account_nfts];
1171 unsigned const nftsCount = tokenIDs.
size() - lastIndex - 1 < limit
1172 ? tokenIDs.
size() - lastIndex - 1
1175 if (nfts.
size() != nftsCount)
1178 for (
unsigned i = 0; i < nftsCount; i++)
1180 if (nfts[i][
"NFTokenID"] != tokenIDs[lastIndex + 1 + i])
1188 BEAST_EXPECT(compareNFTs(4, 2));
1191 BEAST_EXPECT(compareNFTs(4, 7));
1194 auto testInvalidMarker = [&env, &bob](
1195 auto marker,
char const* errorMessage) {
1197 params[jss::account] = bob.human();
1198 params[jss::limit] = 4;
1199 params[jss::ledger_index] = jss::validated;
1200 params[jss::marker] = marker;
1203 return resp[jss::result][jss::error_message] == errorMessage;
1208 testInvalidMarker(17,
"Invalid field \'marker\', not string."));
1211 BEAST_EXPECT(testInvalidMarker(
1212 "00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G",
1213 "Invalid field \'marker\'."));
1218 auto createFakeNFTMarker = [](
AccountID const& issuer,
1229 BEAST_EXPECT(testInvalidMarker(
1230 createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000),
1231 "Invalid field \'marker\'."));
1235 BEAST_EXPECT(testInvalidMarker(
1236 createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF),
1237 "Invalid field \'marker\'."));
1245 using namespace jtx;
1250 auto testInvalidAccountParam = [&](
auto const& param) {
1252 params[jss::account] = param;
1254 "json",
"account_nfts",
to_string(params))[jss::result];
1255 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1257 jrr[jss::error_message] ==
"Invalid field 'account'.");
1260 testInvalidAccountParam(1);
1261 testInvalidAccountParam(1.1);
1262 testInvalidAccountParam(
true);
1274 using namespace jtx;
1280 env.
fund(
XRP(10000), alice, bob, carol);
1282 unsigned const accountObjectSize = 30;
1283 for (
unsigned i = 0; i < accountObjectSize; i++)
1286 for (
unsigned i = 0; i < 10; i++)
1291 unsigned const limit = 11;
1297 params[jss::account] = bob.human();
1298 params[jss::limit] = limit;
1299 params[jss::ledger_index] =
"validated";
1300 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1301 auto& accountObjects = resp[jss::result][jss::account_objects];
1302 marker = resp[jss::result][jss::marker];
1303 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1304 BEAST_EXPECT(accountObjects.size() == limit);
1310 params[jss::account] = bob.human();
1311 params[jss::limit] = limit;
1312 params[jss::marker] = marker;
1313 params[jss::ledger_index] =
"validated";
1314 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1315 auto& accountObjects = resp[jss::result][jss::account_objects];
1316 marker = resp[jss::result][jss::marker];
1317 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1318 BEAST_EXPECT(accountObjects.size() == limit);
1322 auto testInvalidMarker = [&](
std::string& marker) {
1324 params[jss::account] = bob.human();
1325 params[jss::limit] = limit;
1326 params[jss::ledger_index] = jss::validated;
1327 params[jss::marker] = marker;
1330 return resp[jss::result][jss::error_message] ==
1331 "Invalid field \'marker\'.";
1334 auto const markerStr = marker.
asString();
1335 auto const& idx = markerStr.
find(
',');
1336 auto const dirIndex = markerStr.substr(0, idx);
1337 auto const entryIndex = markerStr.substr(idx + 1);
1342 BEAST_EXPECT(testInvalidMarker(s));
1349 BEAST_EXPECT(testInvalidMarker(s));
1357 BEAST_EXPECT(testInvalidMarker(s));
1365 s = dirIndex +
',' + s;
1366 BEAST_EXPECT(testInvalidMarker(s));
1373 BEAST_EXPECT(testInvalidMarker(s));
1382 params[jss::account] = bob.human();
1383 params[jss::limit] = limit;
1384 params[jss::marker] = s;
1385 params[jss::ledger_index] =
"validated";
1386 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1387 auto& accountObjects = resp[jss::result][jss::account_objects];
1388 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1389 BEAST_EXPECT(accountObjects.size() == limit);
1396 BEAST_EXPECT(testInvalidMarker(s));
1403 BEAST_EXPECT(testInvalidMarker(s));
1410 params[jss::account] = bob.human();
1411 params[jss::limit] = limit;
1412 params[jss::marker] = marker;
1413 params[jss::ledger_index] =
"validated";
1414 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1415 auto& accountObjects = resp[jss::result][jss::account_objects];
1416 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1418 accountObjects.size() == accountObjectSize - limit * 2);
1419 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
1426 params[jss::account] = carol.human();
1427 params[jss::limit] = 10;
1428 params[jss::marker] =
"0," + entryIndex;
1429 params[jss::ledger_index] =
"validated";
1430 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1431 auto& accountObjects = resp[jss::result][jss::account_objects];
1432 BEAST_EXPECT(accountObjects.size() == 0);
Unserialize a JSON document into a Value.
bool parse(std::string const &document, Value &root)
Read a Value from a JSON document.
UInt size() const
Number of values in array or object.
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.
testcase_t testcase
Memberspace for declaring test cases.
static uint256 createNFTokenID(std::uint16_t flags, std::uint16_t fee, AccountID const &issuer, nft::Taxon taxon, std::uint32_t tokenSeq)
void testUnsteppedThenSteppedWithNFTs()
void testAccountObjectMarker()
void testUnsteppedThenStepped()
void run() override
Runs the suite.
Convenience class to test AMM functionality.
Immutable cryptographic account descriptor.
static Account const master
The master account.
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
NetClock::time_point now()
Returns the current network time.
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)
Set the expected result code for a JTx The test will fail if the code doesn't match.
@ arrayValue
array value (ordered list)
@ objectValue
object value (collection of name/value pairs).
Taxon toTaxon(std::uint32_t i)
Json::Value create(A const &account, A const &dest, STAmount const &sendMax)
Create a check.
Json::Value auth(Account const &account, Account const &auth)
Preauthorize for deposit.
Json::Value setTx(AccountID const &account, Credentials const &credentials, std::optional< uint256 > domain)
Json::Value create(Account const &account, std::uint32_t count)
Create one of more tickets.
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.
Json::Value mint(jtx::Account const &account, std::uint32_t nfTokenTaxon)
Mint an NFToken.
Json::Value create_account_attestation(jtx::Account const &submittingAccount, Json::Value const &jvBridge, jtx::Account const &sendingAccount, jtx::AnyAmount const &sendingAmount, jtx::AnyAmount const &rewardAmount, jtx::Account const &rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const &dst, jtx::signer const &signer)
Json::Value escrow(AccountID const &account, AccountID const &to, STAmount const &amount)
Json::Value signers(Account const &account, std::uint32_t quorum, std::vector< signer > const &v)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
Json::Value getAccountLines(Env &env, AccountID const &acctId)
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Json::Value xchain_create_claim_id(Account const &acc, Json::Value const &bridge, STAmount const &reward, Account const &otherChainSource)
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
XRP_t const XRP
Converts to XRP Issue or STAmount.
FeatureBitset supported_amendments()
static char const * bobs_account_objects[]
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr std::uint32_t tfPassive
std::string strHex(FwdIt begin, FwdIt end)
std::string to_string(base_uint< Bits, Tag > const &a)
@ credential
Credentials signature.
constexpr std::uint32_t const tfTransferable
void createScBridgeObjects(Env &scEnv)
std::vector< Account > const payees
std::vector< signer > const signers
Set the sequence number on a JTx.
T time_since_epoch(T... args)