21#include <test/jtx/AMM.h>
22#include <test/jtx/xchain_bridge.h>
23#include <xrpld/app/tx/detail/NFTokenMint.h>
24#include <xrpl/json/json_reader.h>
25#include <xrpl/json/json_value.h>
26#include <xrpl/json/to_string.h>
27#include <xrpl/protocol/jss.h>
28#include <xrpl/protocol/nft.h>
30#include <boost/utility/string_ref.hpp>
39 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
40 "BookDirectory" : "50AD0A9E54D2B381288D535EB724E4275FFBF41580D28A925D038D7EA4C68000",
43 "LedgerEntryType" : "Offer",
48 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
51 "TakerPays" : "100000000",
52 "index" : "29665262716C19830E26AEEC0916E476FC7D8EF195FF3B4F06829E64F82A3B3E"
57 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
63 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
67 "LedgerEntryType" : "RippleState",
70 "issuer" : "r9cZvwKU3zzuZK9JFovGg1JC5n7QiqNL8L",
74 "index" : "D13183BCFFC9AAC9F96AEBB5F66E4A652AD1F5D10273AEB615478302BEBFD4A4"
79 "issuer" : "rrrrrrrrrrrrrrrrrrrrBZbvji",
85 "issuer" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
89 "LedgerEntryType" : "RippleState",
92 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
96 "index" : "D89BC239086183EB9458C396E643795C1134963E6550E682A190A5F021766D43"
99 "Account" : "rPMh7Pi9ct699iZUTWaytJUoHcJ7cgyziK",
100 "BookDirectory" : "B025997A323F5C3E03DDF1334471F5984ABDE31C59D463525D038D7EA4C68000",
103 "LedgerEntryType" : "Offer",
108 "issuer" : "r32rQHyesiTtdWFU7UJVtff4nCR5SHCbJW",
111 "TakerPays" : "100000000",
112 "index" : "F03ABE26CB8C5F4AFB31A86590BD25C64C5756FCE5CE9704C27AFE291A4A29A1"
129 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
131 resp[jss::result][jss::error_message] ==
132 "Missing field 'account'.");
136 auto testInvalidAccountParam = [&](
auto const& param) {
138 params[jss::account] = param;
140 "json",
"account_objects",
to_string(params))[jss::result];
141 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
143 jrr[jss::error_message] ==
"Invalid field 'account'.");
146 testInvalidAccountParam(1);
147 testInvalidAccountParam(1.1);
148 testInvalidAccountParam(
true);
156 params[jss::account] =
157 "n94JNrQYkDrpt62bbSR7nVEhdyAvcJXRAsjEkFYyqRkh9SUTYEqV";
158 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
160 resp[jss::result][jss::error_message] ==
"Account malformed.");
166 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
168 resp[jss::result][jss::error_message] ==
"Account not found.");
174 params[jss::account] = bob.human();
175 params[jss::ledger_index] = 10;
176 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
178 resp[jss::result][jss::error_message] ==
"ledgerNotFound");
185 params[jss::account] = bob.human();
186 params[jss::type] = 10;
187 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
189 resp[jss::result][jss::error_message] ==
190 "Invalid field 'type', not string.");
195 params[jss::account] = bob.human();
196 params[jss::type] =
"expedited";
197 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
199 resp[jss::result][jss::error_message] ==
200 "Invalid field 'type'.");
205 params[jss::account] = bob.human();
206 params[jss::limit] = -1;
207 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
209 resp[jss::result][jss::error_message] ==
210 "Invalid field 'limit', not unsigned integer.");
216 auto const USD = gw[
"USD"];
217 env.
trust(USD(1000), bob);
218 env(
pay(gw, bob,
XRP(1)));
222 params[jss::account] = bob.human();
223 params[jss::limit] = 1;
224 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
226 auto resume_marker = resp[jss::result][jss::marker];
228 params[jss::marker] = 10;
229 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
231 resp[jss::result][jss::error_message] ==
232 "Invalid field 'marker', not string.");
234 params[jss::marker] =
"This is a string with no comma";
235 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
237 resp[jss::result][jss::error_message] ==
238 "Invalid field 'marker'.");
240 params[jss::marker] =
"This string has a comma, but is not hex";
241 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
243 resp[jss::result][jss::error_message] ==
244 "Invalid field 'marker'.");
247 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
249 resp[jss::result][jss::error_message] ==
250 "Invalid field 'marker'.");
253 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
255 resp[jss::result][jss::error_message] ==
256 "Invalid field 'marker'.");
258 params[jss::marker] =
std::string(&mark[1U], 65) +
"not hex";
259 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
261 resp[jss::result][jss::error_message] ==
262 "Invalid field 'marker'.");
268 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
269 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
285 auto const USD1 = gw1[
"USD"];
286 auto const USD2 = gw2[
"USD"];
288 env.
fund(
XRP(1000), gw1, gw2, bob);
289 env.
trust(USD1(1000), bob);
290 env.
trust(USD2(1000), bob);
292 env(
pay(gw1, bob, USD1(1000)));
293 env(
pay(gw2, bob, USD2(1000)));
299 for (
int i = 0; i < 4; ++i)
306 params[jss::account] = bob.human();
307 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
308 BEAST_EXPECT(!resp.isMember(jss::marker));
310 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 4);
311 for (
int i = 0; i < 4; ++i)
313 auto& aobj = resp[jss::result][jss::account_objects][i];
314 aobj.removeMember(
"PreviousTxnID");
315 aobj.removeMember(
"PreviousTxnLgrSeq");
316 BEAST_EXPECT(aobj == bobj[i]);
322 params[jss::account] = bob.human();
323 params[jss::type] = jss::state;
324 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
325 BEAST_EXPECT(!resp.isMember(jss::marker));
327 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 2);
328 for (
int i = 0; i < 2; ++i)
330 auto& aobj = resp[jss::result][jss::account_objects][i];
331 aobj.removeMember(
"PreviousTxnID");
332 aobj.removeMember(
"PreviousTxnLgrSeq");
333 BEAST_EXPECT(aobj == bobj[i + 1]);
339 params[jss::account] = bob.human();
340 params[jss::limit] = 1;
341 for (
int i = 0; i < 4; ++i)
345 auto& aobjs = resp[jss::result][jss::account_objects];
346 BEAST_EXPECT(aobjs.size() == 1);
347 auto& aobj = aobjs[0U];
349 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
351 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
353 aobj.removeMember(
"PreviousTxnID");
354 aobj.removeMember(
"PreviousTxnLgrSeq");
356 BEAST_EXPECT(aobj == bobj[i]);
358 params[jss::marker] = resp[jss::result][jss::marker];
369 testcase(
"unsteppedThenSteppedWithNFTs");
378 auto const USD1 = gw1[
"USD"];
379 auto const USD2 = gw2[
"USD"];
381 env.
fund(
XRP(1000), gw1, gw2, bob);
388 params[jss::account] = bob.human();
389 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
390 BEAST_EXPECT(!resp.isMember(jss::marker));
391 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
394 params[jss::limit] = 1;
395 resp = env.
rpc(
"json",
"account_objects",
to_string(params));
396 BEAST_EXPECT(!resp.isMember(jss::marker));
397 BEAST_EXPECT(resp[jss::result][jss::account_objects].size() == 0);
409 params[jss::account] = bob.human();
410 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
411 BEAST_EXPECT(!resp.isMember(jss::marker));
413 unpaged = resp[jss::result][jss::account_objects];
414 BEAST_EXPECT(unpaged.
size() == 1);
419 params[jss::account] = bob.human();
420 params[jss::type] = jss::nft_page;
421 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
422 BEAST_EXPECT(!resp.isMember(jss::marker));
423 Json::Value& aobjs = resp[jss::result][jss::account_objects];
424 BEAST_EXPECT(aobjs.
size() == 1);
426 aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
427 BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].
size() == 1);
432 params[jss::account] = bob.human();
433 params[jss::limit] = 1;
437 Json::Value& aobjs = resp[jss::result][jss::account_objects];
438 BEAST_EXPECT(aobjs.
size() == 1);
439 auto& aobj = aobjs[0U];
440 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
441 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
443 BEAST_EXPECT(aobj == unpaged[0u]);
447 env.
trust(USD1(1000), bob);
448 env.
trust(USD2(1000), bob);
450 env(
pay(gw1, bob, USD1(1000)));
451 env(
pay(gw2, bob, USD2(1000)));
460 params[jss::account] = bob.human();
461 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
462 BEAST_EXPECT(!resp.isMember(jss::marker));
464 unpaged = resp[jss::result][jss::account_objects];
465 BEAST_EXPECT(unpaged.
size() == 5);
470 params[jss::account] = bob.human();
471 params[jss::type] = jss::nft_page;
472 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
473 BEAST_EXPECT(!resp.isMember(jss::marker));
474 Json::Value& aobjs = resp[jss::result][jss::account_objects];
475 BEAST_EXPECT(aobjs.
size() == 1);
477 aobjs[0u][sfLedgerEntryType.jsonName] == jss::NFTokenPage);
478 BEAST_EXPECT(aobjs[0u][sfNFTokens.jsonName].
size() == 1);
483 params[jss::account] = bob.human();
484 params[jss::limit] = 1;
485 for (
int i = 0; i < 5; ++i)
489 Json::Value& aobjs = resp[jss::result][jss::account_objects];
490 BEAST_EXPECT(aobjs.
size() == 1);
491 auto& aobj = aobjs[0U];
494 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
495 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
499 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
500 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
503 BEAST_EXPECT(aobj == unpaged[i]);
505 params[jss::marker] = resp[jss::result][jss::marker];
510 for (
int i = 0; i < 32; ++i)
518 params[jss::account] = bob.human();
519 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
520 BEAST_EXPECT(!resp.isMember(jss::marker));
522 unpaged = resp[jss::result][jss::account_objects];
523 BEAST_EXPECT(unpaged.
size() == 6);
528 params[jss::account] = bob.human();
529 params[jss::type] = jss::nft_page;
530 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
531 BEAST_EXPECT(!resp.isMember(jss::marker));
532 Json::Value& aobjs = resp[jss::result][jss::account_objects];
533 BEAST_EXPECT(aobjs.
size() == 2);
538 params[jss::account] = bob.human();
539 params[jss::limit] = 1;
540 for (
int i = 0; i < 6; ++i)
544 Json::Value& aobjs = resp[jss::result][jss::account_objects];
545 BEAST_EXPECT(aobjs.
size() == 1);
546 auto& aobj = aobjs[0U];
549 BEAST_EXPECT(resp[jss::result][jss::limit] == 1);
550 BEAST_EXPECT(resp[jss::result].isMember(jss::marker));
554 BEAST_EXPECT(!resp[jss::result].isMember(jss::limit));
555 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
558 BEAST_EXPECT(aobj == unpaged[i]);
560 params[jss::marker] = resp[jss::result][jss::marker];
576 auto const USD = gw[
"USD"];
579 featurePermissionedDomains;
580 Env env(*
this, features);
583 auto acctObjs = [&env](
591 params[jss::type] = *type;
593 params[jss::limit] = *limit;
595 params[jss::marker] = *marker;
596 params[jss::ledger_index] =
"validated";
597 return env.
rpc(
"json",
"account_objects",
to_string(params));
601 auto acctObjsIsSize = [](
Json::Value const& resp,
unsigned size) {
602 return resp[jss::result][jss::account_objects].
isArray() &&
603 (resp[jss::result][jss::account_objects].
size() == size);
607 auto acctObjsTypeIsInvalid = [](
Json::Value const& resp) {
608 return resp[jss::result].
isMember(jss::error) &&
609 resp[jss::result][jss::error_message] ==
610 "Invalid field \'type\'.";
613 env.
fund(
XRP(10000), gw, alice);
618 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::account), 0));
619 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::check), 0));
620 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::deposit_preauth), 0));
621 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::escrow), 0));
622 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::nft_page), 0));
623 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::offer), 0));
624 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::payment_channel), 0));
625 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::signer_list), 0));
626 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::state), 0));
627 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::ticket), 0));
628 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0));
629 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::did), 0));
630 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::permissioned_domain), 0));
633 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments)));
634 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::directory)));
635 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::fee)));
636 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::hashes)));
637 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::NegativeUNL)));
645 Json::Value const resp = acctObjs(gw, jss::nft_page);
646 BEAST_EXPECT(acctObjsIsSize(resp, 1));
648 auto const& nftPage = resp[jss::result][jss::account_objects][0u];
649 BEAST_EXPECT(nftPage[sfNFTokens.jsonName].size() == 1);
651 nftPage[sfNFTokens.jsonName][0u][sfNFToken.jsonName]
652 [sfNFTokenID.jsonName] ==
to_string(nftID));
656 env.
trust(USD(1000), alice);
658 env(
pay(gw, alice, USD(5)));
663 BEAST_EXPECT(acctObjsIsSize(resp, 1));
665 auto const& state = resp[jss::result][jss::account_objects][0u];
666 BEAST_EXPECT(state[sfBalance.jsonName][jss::value].asInt() == -5);
668 state[sfHighLimit.jsonName][jss::value].asUInt() == 1000);
676 BEAST_EXPECT(acctObjsIsSize(resp, 1));
678 auto const& check = resp[jss::result][jss::account_objects][0u];
679 BEAST_EXPECT(check[sfAccount.jsonName] == gw.human());
680 BEAST_EXPECT(check[sfDestination.jsonName] == alice.human());
681 BEAST_EXPECT(check[sfSendMax.jsonName][jss::value].asUInt() == 10);
688 Json::Value const resp = acctObjs(gw, jss::deposit_preauth);
689 BEAST_EXPECT(acctObjsIsSize(resp, 1));
691 auto const& preauth = resp[jss::result][jss::account_objects][0u];
692 BEAST_EXPECT(preauth[sfAccount.jsonName] == gw.human());
693 BEAST_EXPECT(preauth[sfAuthorize.jsonName] == alice.human());
698 jvEscrow[jss::TransactionType] = jss::EscrowCreate;
700 jvEscrow[jss::Account] = gw.human();
701 jvEscrow[jss::Destination] = gw.human();
703 jvEscrow[sfFinishAfter.jsonName] =
710 Json::Value const resp = acctObjs(gw, jss::escrow);
711 BEAST_EXPECT(acctObjsIsSize(resp, 1));
713 auto const&
escrow = resp[jss::result][jss::account_objects][0u];
714 BEAST_EXPECT(
escrow[sfAccount.jsonName] == gw.human());
715 BEAST_EXPECT(
escrow[sfDestination.jsonName] == gw.human());
716 BEAST_EXPECT(
escrow[sfAmount.jsonName].
asUInt() == 100'000'000);
729 Json::Value const resp = acctObjs(gw, jss::permissioned_domain);
730 BEAST_EXPECT(acctObjsIsSize(resp, 1));
732 auto const& permissionedDomain =
733 resp[jss::result][jss::account_objects][0u];
735 permissionedDomain.isMember(jss::Owner) &&
736 (permissionedDomain[jss::Owner] == gw.human()));
737 bool const check1 = BEAST_EXPECT(
738 permissionedDomain.isMember(jss::AcceptedCredentials) &&
739 permissionedDomain[jss::AcceptedCredentials].isArray() &&
740 (permissionedDomain[jss::AcceptedCredentials].size() == 1) &&
741 (permissionedDomain[jss::AcceptedCredentials][0u].isMember(
747 permissionedDomain[jss::AcceptedCredentials][0u]
753 credential.isMember(sfCredentialType.jsonName) &&
755 strHex(credentialType1)));
765 auto scEnvAcctObjs = [&](
Account const& acct,
char const* type) {
767 params[jss::account] = acct.
human();
768 params[jss::type] = type;
769 params[jss::ledger_index] =
"validated";
770 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
776 BEAST_EXPECT(acctObjsIsSize(resp, 1));
777 auto const& acct_bridge =
778 resp[jss::result][jss::account_objects][0u];
782 acct_bridge[sfLedgerEntryType.getJsonName()] ==
"Bridge");
784 acct_bridge[sfXChainClaimID.getJsonName()].asUInt() == 0);
786 acct_bridge[sfXChainAccountClaimCount.getJsonName()].asUInt() ==
789 acct_bridge[sfXChainAccountCreateCount.getJsonName()]
792 acct_bridge[sfMinAccountCreateAmount.getJsonName()].asUInt() ==
795 acct_bridge[sfSignatureReward.getJsonName()].asUInt() ==
797 BEAST_EXPECT(acct_bridge[sfXChainBridge.getJsonName()] == x.
jvb);
812 auto scEnvAcctObjs = [&](
Account const& acct,
char const* type) {
814 params[jss::account] = acct.
human();
815 params[jss::type] = type;
816 params[jss::ledger_index] =
"validated";
817 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
823 scEnvAcctObjs(x.
scAlice, jss::xchain_owned_claim_id);
824 BEAST_EXPECT(acctObjsIsSize(resp, 1));
826 auto const& xchain_seq =
827 resp[jss::result][jss::account_objects][0u];
831 xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 1);
836 scEnvAcctObjs(x.
scBob, jss::xchain_owned_claim_id);
837 BEAST_EXPECT(acctObjsIsSize(resp, 1));
839 auto const& xchain_seq =
840 resp[jss::result][jss::account_objects][0u];
841 BEAST_EXPECT(xchain_seq[sfAccount.jsonName] == x.
scBob.
human());
843 xchain_seq[sfXChainClaimID.getJsonName()].asUInt() == 2);
850 auto const amt =
XRP(1000);
869 auto scEnvAcctObjs = [&](
Account const& acct,
char const* type) {
871 params[jss::account] = acct.
human();
872 params[jss::type] = type;
873 params[jss::ledger_index] =
"validated";
874 return scEnv.
rpc(
"json",
"account_objects",
to_string(params));
881 BEAST_EXPECT(acctObjsIsSize(resp, 1));
883 auto const& xchain_create_account_claim_id =
884 resp[jss::result][jss::account_objects][0u];
886 xchain_create_account_claim_id[sfAccount.jsonName] ==
889 xchain_create_account_claim_id[sfXChainAccountCreateCount
901 BEAST_EXPECT(acctObjsIsSize(resp, 1));
903 auto const&
offer = resp[jss::result][jss::account_objects][0u];
904 BEAST_EXPECT(
offer[sfAccount.jsonName] == gw.human());
905 BEAST_EXPECT(
offer[sfTakerGets.jsonName].
asUInt() == 14'000'000);
906 BEAST_EXPECT(
offer[sfTakerPays.jsonName][jss::value].
asUInt() == 7);
912 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;
940 jvDID[jss::Account] = gw.human();
948 BEAST_EXPECT(acctObjsIsSize(resp, 1));
950 auto const& did = resp[jss::result][jss::account_objects][0u];
951 BEAST_EXPECT(did[sfAccount.jsonName] == gw.human());
959 Json::Value const resp = acctObjs(gw, jss::signer_list);
960 BEAST_EXPECT(acctObjsIsSize(resp, 1));
962 auto const& signerList =
963 resp[jss::result][jss::account_objects][0u];
964 BEAST_EXPECT(signerList[sfSignerQuorum.jsonName] == 6);
965 auto const& entry = signerList[sfSignerEntries.jsonName][0u]
966 [sfSignerEntry.jsonName];
967 BEAST_EXPECT(entry[sfAccount.jsonName] == alice.human());
968 BEAST_EXPECT(entry[sfSignerWeight.jsonName].asUInt() == 7);
972 auto const seq = env.
seq(gw);
978 Json::Value const resp = acctObjs(gw, jss::ticket);
979 BEAST_EXPECT(acctObjsIsSize(resp, 1));
981 auto const& ticket = resp[jss::result][jss::account_objects][0u];
982 BEAST_EXPECT(ticket[sfAccount.jsonName] == gw.human());
983 BEAST_EXPECT(ticket[sfLedgerEntryType.jsonName] == jss::Ticket);
984 BEAST_EXPECT(ticket[sfTicketSequence.jsonName].asUInt() ==
seq + 1);
990 params[jss::account] = gw.human();
991 params[jss::deletion_blockers_only] =
true;
992 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
998 jss::NFTokenPage.c_str(),
999 jss::RippleState.c_str(),
1000 jss::PayChannel.c_str(),
1001 jss::PermissionedDomain.c_str()};
1009 if (BEAST_EXPECT(acctObjsIsSize(resp, expectedAccountObjects)))
1011 auto const& aobjs = resp[jss::result][jss::account_objects];
1013 gotLedgerTypes.
reserve(expectedAccountObjects);
1017 aobjs[i][
"LedgerEntryType"].asString());
1020 BEAST_EXPECT(gotLedgerTypes == expectedLedgerTypes);
1027 params[jss::account] = gw.human();
1028 params[jss::deletion_blockers_only] =
true;
1029 params[jss::type] = jss::escrow;
1030 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1032 if (BEAST_EXPECT(acctObjsIsSize(resp, 1u)))
1034 auto const& aobjs = resp[jss::result][jss::account_objects];
1035 BEAST_EXPECT(aobjs[0u][
"LedgerEntryType"] == jss::Escrow);
1042 auto const objs = resp[jss::result][jss::account_objects];
1043 for (
auto const& obj : resp[jss::result][jss::account_objects])
1045 obj[sfLedgerEntryType.fieldName].asString());
1046 std::sort(typesOut.begin(), typesOut.end());
1050 auto expectObjects =
1053 if (!acctObjsIsSize(resp, types.
size()))
1056 getTypes(resp, typesOut);
1057 return types == typesOut;
1060 AMM amm(env, gw,
XRP(1'000), USD(1'000));
1061 amm.deposit(alice, USD(1));
1064 BEAST_EXPECT(
lines[jss::lines].size() == 3);
1067 acctObjsIsSize(acctObjs(amm.ammAccount(), jss::amm), 1));
1069 auto resp = acctObjs(amm.ammAccount(), std::nullopt, 2);
1071 getTypes(resp, typesOut);
1077 resp[jss::result][jss::marker].
asString());
1078 getTypes(resp, typesOut);
1083 jss::RippleState.c_str(),
1084 jss::RippleState.c_str(),
1085 jss::RippleState.c_str()}));
1087 resp = acctObjs(amm.ammAccount(), jss::state, 10);
1088 BEAST_EXPECT(expectObjects(
1090 {jss::RippleState.c_str(),
1091 jss::RippleState.c_str(),
1092 jss::RippleState.c_str()}));
1095 acctObjsIsSize(acctObjs(amm.ammAccount(), jss::offer), 0));
1097 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::amm), 0));
1101 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::amendments)));
1102 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::directory)));
1103 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::fee)));
1104 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::hashes)));
1105 BEAST_EXPECT(acctObjsTypeIsInvalid(acctObjs(gw, jss::NegativeUNL)));
1109 for (
int d = 1'000'032; d >= 1'000'000; --d)
1116 BEAST_EXPECT(acctObjsIsSize(acctObjs(gw, jss::account), 0));
1128 using namespace jtx;
1134 static constexpr unsigned nftsSize = 10;
1135 for (
unsigned i = 0; i < nftsSize; i++)
1146 params[jss::account] = bob.human();
1147 params[jss::ledger_index] =
"validated";
1150 Json::Value const& nfts = resp[jss::result][jss::account_nfts];
1158 auto compareNFTs = [&tokenIDs, &env, &bob](
1159 unsigned const limit,
unsigned const lastIndex) {
1161 params[jss::account] = bob.human();
1162 params[jss::limit] = limit;
1163 params[jss::marker] = tokenIDs[lastIndex];
1164 params[jss::ledger_index] =
"validated";
1168 if (resp[jss::result].isMember(jss::error))
1171 Json::Value const& nfts = resp[jss::result][jss::account_nfts];
1172 unsigned const nftsCount = tokenIDs.
size() - lastIndex - 1 < limit
1173 ? tokenIDs.
size() - lastIndex - 1
1176 if (nfts.
size() != nftsCount)
1179 for (
unsigned i = 0; i < nftsCount; i++)
1181 if (nfts[i][
"NFTokenID"] != tokenIDs[lastIndex + 1 + i])
1189 BEAST_EXPECT(compareNFTs(4, 2));
1192 BEAST_EXPECT(compareNFTs(4, 7));
1195 auto testInvalidMarker = [&env, &bob](
1196 auto marker,
char const* errorMessage) {
1198 params[jss::account] = bob.human();
1199 params[jss::limit] = 4;
1200 params[jss::ledger_index] = jss::validated;
1201 params[jss::marker] = marker;
1204 return resp[jss::result][jss::error_message] == errorMessage;
1209 testInvalidMarker(17,
"Invalid field \'marker\', not string."));
1212 BEAST_EXPECT(testInvalidMarker(
1213 "00000000F51DFC2A09D62CBBA1DFBDD4691DAC96AD98B900000000000000000G",
1214 "Invalid field \'marker\'."));
1219 auto createFakeNFTMarker = [](
AccountID const& issuer,
1230 BEAST_EXPECT(testInvalidMarker(
1231 createFakeNFTMarker(bob.id(), 0x000000000, 0x00000000),
1232 "Invalid field \'marker\'."));
1236 BEAST_EXPECT(testInvalidMarker(
1237 createFakeNFTMarker(bob.id(), 0xFFFFFFFF, 0xFFFFFFFF),
1238 "Invalid field \'marker\'."));
1246 using namespace jtx;
1251 auto testInvalidAccountParam = [&](
auto const& param) {
1253 params[jss::account] = param;
1255 "json",
"account_nfts",
to_string(params))[jss::result];
1256 BEAST_EXPECT(jrr[jss::error] ==
"invalidParams");
1258 jrr[jss::error_message] ==
"Invalid field 'account'.");
1261 testInvalidAccountParam(1);
1262 testInvalidAccountParam(1.1);
1263 testInvalidAccountParam(
true);
1275 using namespace jtx;
1281 env.
fund(
XRP(10000), alice, bob, carol);
1283 unsigned const accountObjectSize = 30;
1284 for (
unsigned i = 0; i < accountObjectSize; i++)
1287 for (
unsigned i = 0; i < 10; i++)
1292 unsigned const limit = 11;
1298 params[jss::account] = bob.human();
1299 params[jss::limit] = limit;
1300 params[jss::ledger_index] =
"validated";
1301 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1302 auto& accountObjects = resp[jss::result][jss::account_objects];
1303 marker = resp[jss::result][jss::marker];
1304 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1305 BEAST_EXPECT(accountObjects.size() == limit);
1311 params[jss::account] = bob.human();
1312 params[jss::limit] = limit;
1313 params[jss::marker] = marker;
1314 params[jss::ledger_index] =
"validated";
1315 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1316 auto& accountObjects = resp[jss::result][jss::account_objects];
1317 marker = resp[jss::result][jss::marker];
1318 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1319 BEAST_EXPECT(accountObjects.size() == limit);
1323 auto testInvalidMarker = [&](
std::string& marker) {
1325 params[jss::account] = bob.human();
1326 params[jss::limit] = limit;
1327 params[jss::ledger_index] = jss::validated;
1328 params[jss::marker] = marker;
1331 return resp[jss::result][jss::error_message] ==
1332 "Invalid field \'marker\'.";
1335 auto const markerStr = marker.
asString();
1336 auto const& idx = markerStr.
find(
',');
1337 auto const dirIndex = markerStr.substr(0, idx);
1338 auto const entryIndex = markerStr.substr(idx + 1);
1343 BEAST_EXPECT(testInvalidMarker(s));
1350 BEAST_EXPECT(testInvalidMarker(s));
1358 BEAST_EXPECT(testInvalidMarker(s));
1366 s = dirIndex +
',' + s;
1367 BEAST_EXPECT(testInvalidMarker(s));
1374 BEAST_EXPECT(testInvalidMarker(s));
1383 params[jss::account] = bob.human();
1384 params[jss::limit] = limit;
1385 params[jss::marker] = s;
1386 params[jss::ledger_index] =
"validated";
1387 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1388 auto& accountObjects = resp[jss::result][jss::account_objects];
1389 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1390 BEAST_EXPECT(accountObjects.size() == limit);
1397 BEAST_EXPECT(testInvalidMarker(s));
1404 BEAST_EXPECT(testInvalidMarker(s));
1411 params[jss::account] = bob.human();
1412 params[jss::limit] = limit;
1413 params[jss::marker] = marker;
1414 params[jss::ledger_index] =
"validated";
1415 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1416 auto& accountObjects = resp[jss::result][jss::account_objects];
1417 BEAST_EXPECT(!resp[jss::result].isMember(jss::error));
1419 accountObjects.size() == accountObjectSize - limit * 2);
1420 BEAST_EXPECT(!resp[jss::result].isMember(jss::marker));
1427 params[jss::account] = carol.human();
1428 params[jss::limit] = 10;
1429 params[jss::marker] =
"0," + entryIndex;
1430 params[jss::ledger_index] =
"validated";
1431 auto resp = env.
rpc(
"json",
"account_objects",
to_string(params));
1432 auto& accountObjects = resp[jss::result][jss::account_objects];
1433 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(const char *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)
constexpr std::uint32_t tfUniversal
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)