xrpld
Loading...
Searching...
No Matches
TestHelpers.cpp
1#include <test/jtx/TestHelpers.h>
2
3#include <test/jtx/Account.h>
4#include <test/jtx/Env.h>
5#include <test/jtx/amount.h>
6#include <test/jtx/balance.h> // IWYU pragma: keep
7#include <test/jtx/envconfig.h>
8#include <test/jtx/mpt.h>
9#include <test/jtx/offer.h>
10#include <test/jtx/owners.h>
11#include <test/jtx/rate.h>
12#include <test/jtx/trust.h>
13
14#include <xrpld/core/Config.h>
15#include <xrpld/rpc/RPCHandler.h>
16#include <xrpld/rpc/Role.h>
17
18#include <xrpl/basics/Number.h>
19#include <xrpl/basics/Slice.h>
20#include <xrpl/basics/base_uint.h>
21#include <xrpl/basics/chrono.h>
22#include <xrpl/basics/contract.h>
23#include <xrpl/basics/strHex.h>
24#include <xrpl/beast/unit_test/suite.h>
25#include <xrpl/beast/utility/instrumentation.h>
26#include <xrpl/core/Job.h>
27#include <xrpl/core/ServiceRegistry.h>
28#include <xrpl/json/json_value.h>
29#include <xrpl/json/to_string.h>
30#include <xrpl/ledger/ReadView.h>
31#include <xrpl/ledger/helpers/DirectoryHelpers.h>
32#include <xrpl/protocol/AccountID.h>
33#include <xrpl/protocol/ApiVersion.h>
34#include <xrpl/protocol/Book.h>
35#include <xrpl/protocol/Indexes.h>
36#include <xrpl/protocol/Issue.h>
37#include <xrpl/protocol/LedgerFormats.h>
38#include <xrpl/protocol/MPTIssue.h>
39#include <xrpl/protocol/PathAsset.h>
40#include <xrpl/protocol/PublicKey.h>
41#include <xrpl/protocol/Quality.h>
42#include <xrpl/protocol/SField.h>
43#include <xrpl/protocol/STAmount.h>
44#include <xrpl/protocol/STParsedJSON.h>
45#include <xrpl/protocol/STPathSet.h>
46#include <xrpl/protocol/UintTypes.h>
47#include <xrpl/protocol/XRPAmount.h>
48#include <xrpl/protocol/jss.h>
49#include <xrpl/resource/Charge.h>
50#include <xrpl/resource/Consumer.h>
51#include <xrpl/resource/Fees.h>
52#include <xrpl/tx/paths/detail/Steps.h>
53
54#include <algorithm>
55#include <chrono>
56#include <cstddef>
57#include <cstdint>
58#include <memory>
59#include <optional>
60#include <stdexcept>
61#include <tuple>
62#include <utility>
63#include <variant>
64#include <vector>
65
66namespace xrpl::test::jtx {
67
68// Functions used in debugging
69json::Value
70getAccountOffers(Env& env, AccountID const& acct, bool current)
71{
72 json::Value jv;
73 jv[jss::account] = to_string(acct);
74 return env.rpc("json", "account_offers", to_string(jv))[jss::result];
75}
76
78getAccountLines(Env& env, AccountID const& acctId)
79{
80 json::Value jv;
81 jv[jss::account] = to_string(acctId);
82 return env.rpc("json", "account_lines", to_string(jv))[jss::result];
83}
84
85bool
86checkArraySize(json::Value const& val, unsigned int size)
87{
88 return val.isArray() && val.size() == size;
89}
90
92ownerCount(Env const& env, Account const& account)
93{
94 return env.ownerCount(account);
95}
96
97/* Path finding */
98/******************************************************************************/
99void
100stpathAppendOne(STPath& st, Account const& account)
101{
102 st.pushBack(STPathElement({account.id(), std::nullopt, std::nullopt}));
103}
104
105void
107{
108 st.pushBack(pe);
109}
110
111bool
112equal(STAmount const& sa1, STAmount const& sa2)
113{
114 return sa1 == sa2 && sa1.getIssuer() == sa2.getIssuer();
115}
116
117static void
119 json::Value& jv,
120 PathAsset const& srcAsset,
121 std::optional<AccountID> const& srcIssuer)
122{
124 [&]<typename TAsset>(TAsset const& asset) {
126 {
127 jv[jss::currency] = to_string(asset);
128 if (srcIssuer)
129 jv[jss::issuer] = to_string(*srcIssuer);
130 }
131 else
132 {
133 if (srcIssuer)
134 Throw<std::runtime_error>("MPT source_currencies can't have issuer");
135 jv[jss::mpt_issuance_id] = to_string(asset);
136 }
137 },
138 srcAsset.value());
139}
140
142rpf(jtx::Account const& src,
143 jtx::Account const& dst,
144 STAmount const& dstAmount,
145 std::optional<STAmount> const& sendMax,
146 std::optional<PathAsset> const& srcAsset,
147 std::optional<AccountID> const& srcIssuer)
148{
150 jv[jss::command] = "ripple_path_find";
151 jv[jss::source_account] = toBase58(src);
152 jv[jss::destination_account] = toBase58(dst);
153 jv[jss::destination_amount] = dstAmount.getJson(JsonOptions::Values::None);
154 if (sendMax)
155 jv[jss::send_max] = sendMax->getJson(JsonOptions::Values::None);
156 if (srcAsset)
157 {
158 auto& sc = jv[jss::source_currencies] = json::ValueType::Array;
160 addSourceAsset(j, *srcAsset, srcIssuer);
161 sc.append(j);
162 }
163
164 return jv;
165}
166
169{
170 // These tests were originally written with search parameters that are
171 // different from the current defaults. This function creates an env
172 // with the search parameters that the tests were written for.
173 using namespace jtx;
174 return Env(suite, envconfig([](std::unique_ptr<Config> cfg) {
175 cfg->pathSearchOld = 7;
176 cfg->pathSearch = 7;
177 cfg->pathSearchMax = 10;
178 return cfg;
179 }));
180}
181
184 jtx::Env& env,
185 jtx::Account const& src,
186 jtx::Account const& dst,
187 STAmount const& saDstAmount,
188 std::optional<STAmount> const& saSendMax,
189 std::optional<PathAsset> const& srcAsset,
190 std::optional<AccountID> const& srcIssuer,
191 std::optional<uint256> const& domain)
192{
193 using namespace jtx;
194
195 auto& app = env.app();
198
199 RPC::JsonContext context{
200 {.j = env.journal,
201 .app = app,
202 .loadType = loadType,
203 .netOps = app.getOPs(),
204 .ledgerMaster = app.getLedgerMaster(),
205 .consumer = c,
206 .role = Role::USER,
207 .coro = {},
208 .infoSub = {},
209 .apiVersion = RPC::kApiVersionIfUnspecified},
210 {},
211 {}};
212
214 params[jss::command] = "ripple_path_find";
215 params[jss::source_account] = toBase58(src);
216 params[jss::destination_account] = toBase58(dst);
217 params[jss::destination_amount] = saDstAmount.getJson(JsonOptions::Values::None);
218 if (saSendMax)
219 params[jss::send_max] = saSendMax->getJson(JsonOptions::Values::None);
220
221 if (srcAsset)
222 {
223 auto& sc = params[jss::source_currencies] = json::ValueType::Array;
225 addSourceAsset(j, *srcAsset, srcIssuer);
226 sc.append(j);
227 }
228
229 if (domain)
230 params[jss::domain] = to_string(*domain);
231
232 json::Value result;
233 Gate g;
234 app.getJobQueue().postCoro(JtClient, "RPC-Client", [&](auto const& coro) {
235 context.params = std::move(params);
236 context.coro = coro;
237 RPC::doCommand(context, result);
238 g.signal();
239 });
240
241 using namespace std::chrono_literals;
242 using namespace beast::unit_test;
243 g.waitFor(5s);
244 return result;
245}
246
249 jtx::Env& env,
250 jtx::Account const& src,
251 jtx::Account const& dst,
252 STAmount const& saDstAmount,
253 std::optional<STAmount> const& saSendMax,
254 std::optional<PathAsset> const& srcAsset,
255 std::optional<AccountID> const& srcIssuer,
256 std::optional<uint256> const& domain)
257{
258 json::Value result =
259 findPathsRequest(env, src, dst, saDstAmount, saSendMax, srcAsset, srcIssuer, domain);
260 if (result.isMember(jss::error))
262
263 STAmount da;
264 if (result.isMember(jss::destination_amount))
265 da = amountFromJson(sfGeneric, result[jss::destination_amount]);
266
267 STAmount sa;
268 STPathSet paths;
269 if (result.isMember(jss::alternatives))
270 {
271 auto const& alts = result[jss::alternatives];
272 if (alts.size() > 0)
273 {
274 auto const& path = alts[0u];
275
276 if (path.isMember(jss::source_amount))
277 sa = amountFromJson(sfGeneric, path[jss::source_amount]);
278
279 if (path.isMember(jss::destination_amount))
280 da = amountFromJson(sfGeneric, path[jss::destination_amount]);
281
282 if (path.isMember(jss::paths_computed))
283 {
284 json::Value p;
285 p["Paths"] = path[jss::paths_computed];
286 STParsedJSONObject po("generic", p);
287 if (po.object)
288 paths = po.object->getFieldPathSet(sfPaths);
289 }
290 }
291 }
292
293 return std::make_tuple(std::move(paths), std::move(sa), std::move(da));
294}
295
298 jtx::Env& env,
299 jtx::Account const& src,
300 jtx::Account const& dst,
301 STAmount const& saDstAmount,
302 std::optional<STAmount> const& saSendMax,
303 std::optional<STPathElement> const& srcElement,
304 std::optional<AccountID> const& srcIssuer,
305 std::optional<uint256> const& domain)
306{
307 // srcElement is optional but is expected to always be present
308 XRPL_ASSERT(
309 srcElement.has_value(), "xrpl::test::jtx::findPathsByElement::srcElement : nullptr");
310
311 return findPaths(
312 env,
313 src,
314 dst,
315 saDstAmount,
316 saSendMax,
317 // NOLINTNEXTLINE(bugprone-unchecked-optional-access)
318 srcElement->getPathAsset(),
319 srcIssuer,
320 domain);
321}
322
323/******************************************************************************/
324
326txFee(Env const& env, std::uint16_t n)
327{
328 return env.current()->fees().base * n;
329}
330
332xrpMinusFee(Env const& env, std::int64_t xrpAmount)
333{
334 auto feeDrops = env.current()->fees().base;
335 return drops(kJtxDropsPerXrp * xrpAmount - feeDrops);
336};
337
338[[nodiscard]] bool
339expectHolding(Env& env, AccountID const& account, STAmount const& value, bool defaultLimits)
340{
341 if (auto const sle = env.le(keylet::trustLine(account, value.get<Issue>())))
342 {
343 Issue const issue = value.get<Issue>();
344 bool const accountLow = account < issue.account;
345
346 bool expectDefaultTrustLine = true;
347 if (defaultLimits)
348 {
349 STAmount low{issue};
350 STAmount high{issue};
351
352 low.get<Issue>().account = accountLow ? account : issue.account;
353 high.get<Issue>().account = accountLow ? issue.account : account;
354
355 expectDefaultTrustLine =
356 sle->getFieldAmount(sfLowLimit) == low && sle->getFieldAmount(sfHighLimit) == high;
357 }
358
359 auto amount = sle->getFieldAmount(sfBalance);
360 amount.get<Issue>().account = value.getIssuer();
361 if (!accountLow)
362 amount.negate();
363 return amount == value && expectDefaultTrustLine;
364 }
365 return false;
366}
367
368[[nodiscard]] bool
369expectHolding(Env& env, AccountID const& account, None const&, Issue const& issue)
370{
371 return !env.le(keylet::trustLine(account, issue));
372}
373
374[[nodiscard]] bool
375expectHolding(Env& env, AccountID const& account, None const&, MPTIssue const& mptIssue)
376{
377 return !env.le(keylet::mptoken(mptIssue.getMptID(), account));
378}
379
380[[nodiscard]] bool
381expectHolding(Env& env, AccountID const& account, None const& value)
382{
383 return std::visit(
384 [&](auto const& issue) { return expectHolding(env, account, value, issue); },
385 value.asset.value());
386}
387
388[[nodiscard]] bool
389expectMPT(Env& env, AccountID const& account, STAmount const& value)
390{
391 auto const mptIssuanceID = keylet::mptokenIssuance(value.asset().get<MPTIssue>());
392 auto const mptToken = env.le(keylet::mptoken(mptIssuanceID.key, account));
393 return mptToken && (*mptToken)[sfMPTAmount] == value.mpt().value();
394}
395
396[[nodiscard]] bool
398 Env& env,
399 AccountID const& account,
400 std::uint16_t size,
401 std::vector<Amounts> const& toMatch)
402{
403 std::uint16_t cnt = 0;
404 std::uint16_t matched = 0;
405 forEachItem(*env.current(), account, [&](SLE::const_ref sle) {
406 if (!sle)
407 return false;
408 if (sle->getType() == ltOFFER)
409 {
410 ++cnt;
411 if (std::ranges::find_if(toMatch, [&](auto const& a) {
412 return a.in == sle->getFieldAmount(sfTakerPays) &&
413 a.out == sle->getFieldAmount(sfTakerGets);
414 }) != toMatch.end())
415 ++matched;
416 }
417 return true;
418 });
419 return size == cnt && ((toMatch.empty() && size != 0) || (matched == toMatch.size()));
420}
421
423ledgerEntryRoot(Env& env, Account const& acct)
424{
425 json::Value jvParams;
426 jvParams[jss::ledger_index] = "current";
427 jvParams[jss::account_root] = acct.human();
428 return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
429}
430
432ledgerEntryState(Env& env, Account const& acctA, Account const& acctB, std::string const& currency)
433{
434 json::Value jvParams;
435 jvParams[jss::ledger_index] = "current";
436 jvParams[jss::ripple_state][jss::currency] = currency;
437 jvParams[jss::ripple_state][jss::accounts] = json::ValueType::Array;
438 jvParams[jss::ripple_state][jss::accounts].append(acctA.human());
439 jvParams[jss::ripple_state][jss::accounts].append(acctB.human());
440 return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
441}
442
445{
446 json::Value jvParams;
447 jvParams[jss::offer][jss::account] = acct.human();
448 jvParams[jss::offer][jss::seq] = offerSeq;
449 return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
450}
451
453ledgerEntryMPT(jtx::Env& env, jtx::Account const& acct, MPTID const& mptID)
454{
455 json::Value jvParams;
456 jvParams[jss::mptoken][jss::account] = acct.human();
457 jvParams[jss::mptoken][jss::mpt_issuance_id] = to_string(mptID);
458 return env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
459}
460
462getBookOffers(jtx::Env& env, Asset const& takerPays, Asset const& takerGets)
463{
464 json::Value jvbp;
465 jvbp[jss::ledger_index] = "current";
466 takerPays.setJson(jvbp[jss::taker_pays]);
467 takerGets.setJson(jvbp[jss::taker_gets]);
468 return env.rpc("json", "book_offers", to_string(jvbp))[jss::result];
469}
470
472accountBalance(Env& env, Account const& acct)
473{
474 auto const jrr = ledgerEntryRoot(env, acct);
475 return jrr[jss::node][sfBalance.fieldName];
476}
477
478[[nodiscard]] bool
479expectLedgerEntryRoot(Env& env, Account const& acct, STAmount const& expectedValue)
480{
481 return accountBalance(env, acct) == to_string(expectedValue.xrp());
482}
483
484/* Payment Channel */
485/******************************************************************************/
486namespace paychan {
487
490 AccountID const& account,
491 AccountID const& to,
492 STAmount const& amount,
493 NetClock::duration const& settleDelay,
494 PublicKey const& pk,
495 std::optional<NetClock::time_point> const& cancelAfter,
496 std::optional<std::uint32_t> const& dstTag)
497{
498 json::Value jv;
499 jv[jss::TransactionType] = jss::PaymentChannelCreate;
500 jv[jss::Account] = to_string(account);
501 jv[jss::Destination] = to_string(to);
502 jv[jss::Amount] = amount.getJson(JsonOptions::Values::None);
503 jv[jss::SettleDelay] = settleDelay.count();
504 jv[sfPublicKey.fieldName] = strHex(pk.slice());
505 if (cancelAfter)
506 jv[sfCancelAfter.fieldName] = cancelAfter->time_since_epoch().count();
507 if (dstTag)
508 jv[sfDestinationTag.fieldName] = *dstTag;
509 return jv;
510}
511
514 AccountID const& account,
515 uint256 const& channel,
516 STAmount const& amount,
517 std::optional<NetClock::time_point> const& expiration)
518{
519 json::Value jv;
520 jv[jss::TransactionType] = jss::PaymentChannelFund;
521 jv[jss::Account] = to_string(account);
522 jv[sfChannel.fieldName] = to_string(channel);
523 jv[jss::Amount] = amount.getJson(JsonOptions::Values::None);
524 if (expiration)
525 jv[sfExpiration.fieldName] = expiration->time_since_epoch().count();
526 return jv;
527}
528
531 AccountID const& account,
532 uint256 const& channel,
533 std::optional<STAmount> const& balance,
534 std::optional<STAmount> const& amount,
535 std::optional<Slice> const& signature,
536 std::optional<PublicKey> const& pk)
537{
538 json::Value jv;
539 jv[jss::TransactionType] = jss::PaymentChannelClaim;
540 jv[jss::Account] = to_string(account);
541 jv["Channel"] = to_string(channel);
542 if (amount)
543 jv[jss::Amount] = amount->getJson(JsonOptions::Values::None);
544 if (balance)
545 jv["Balance"] = balance->getJson(JsonOptions::Values::None);
546 if (signature)
547 jv["Signature"] = strHex(*signature);
548 if (pk)
549 jv["PublicKey"] = strHex(pk->slice());
550 return jv;
551}
552
554channel(AccountID const& account, AccountID const& dst, std::uint32_t seqProxyValue)
555{
556 auto const k = keylet::payChannel(account, dst, seqProxyValue);
557 return k.key;
558}
559
561channelBalance(ReadView const& view, uint256 const& chan)
562{
563 auto const slep = view.read({ltPAYCHAN, chan});
564 if (!slep)
565 return XRPAmount{-1};
566 return (*slep)[sfBalance];
567}
568
569bool
570channelExists(ReadView const& view, uint256 const& chan)
571{
572 auto const slep = view.read({ltPAYCHAN, chan});
573 return bool(slep);
574}
575
576} // namespace paychan
577
578/* Crossing Limits */
579/******************************************************************************/
580
581void
582nOffers(Env& env, std::size_t n, Account const& account, STAmount const& in, STAmount const& out)
583{
584 auto const ownerCount = env.le(account)->getFieldU32(sfOwnerCount);
585 for (std::size_t i = 0; i < n; i++)
586 {
587 env(offer(account, in, out));
588 env.close();
589 }
590 env.require(Owners(account, ownerCount + n));
591}
592
593/* Pay Strand */
594/***************************************************************/
595
596// Currency path element
598cpe(PathAsset const& pa)
599{
600 return pa.visit(
601 [](Currency const& currency) {
603 },
604 [](MPTID const& mpt) {
606 });
607};
608
609// All path element
611allPathElements(AccountID const& a, Asset const& asset)
612{
613 return STPathElement(a, asset, asset.getIssuer());
614};
615
617ipe(Asset const& asset)
618{
619 return asset.visit(
620 [](Issue const& issue) {
621 return STPathElement(
623 xrpAccount(),
624 issue.currency,
625 issue.account);
626 },
627 [](MPTIssue const& issue) {
628 return STPathElement(
630 xrpAccount(),
631 issue.getMptID(),
632 issue.getIssuer());
633 });
634};
635
636// Issuer path element
638iape(AccountID const& account)
639{
641};
642
643// Account path element
649
650bool
652{
653 if (!s1)
654 return false;
655 return test::directStepEqual(*s1, dsi.src, dsi.dst, dsi.currency);
656}
657
658bool
660{
661 if (!s1)
662 return false;
663 return test::mptEndpointStepEqual(*s1, dsi.src, dsi.dst, dsi.mptid);
664}
665
666bool
668{
669 if (!s1)
670 return false;
671 return test::xrpEndpointStepEqual(*s1, xrpStepInfo.acc);
672}
673
674bool
676{
677 if (!s1)
678 return false;
679 return bookStepEqual(*s1, bsi);
680}
681
682namespace detail {
683
684IOU
686{
687 auto const iou = args.issuer[args.token];
688 if (args.transferFee != 0)
689 {
690 auto const tfee = 1. + (static_cast<double>(args.transferFee) / 100'000);
691 args.env(rate(args.issuer, tfee));
692 }
693 for (auto const& account : args.holders)
694 {
695 args.env(trust(account, iou(args.limit.value_or(1'000))));
696 }
697 return iou;
698}
699
700MPT
702{
703 using namespace jtx;
704 if (args.limit)
705 {
706 MPT const mpt = MPTTester(
707 {.env = args.env,
708 .issuer = args.issuer,
709 .holders = args.holders,
710 .transferFee = args.transferFee,
711 .maxAmt = args.limit});
712 return mpt;
713 }
714
715 MPT const mpt = MPTTester(
716 {.env = args.env,
717 .issuer = args.issuer,
718 .holders = args.holders,
719 .transferFee = args.transferFee});
720 return mpt;
721}
722
723} // namespace detail
724
725/* LoanBroker */
726/******************************************************************************/
727
728namespace loanBroker {
729
731set(AccountID const& account, uint256 const& vaultId, uint32_t flags)
732{
733 json::Value jv;
734 jv[sfTransactionType] = jss::LoanBrokerSet;
735 jv[sfAccount] = to_string(account);
736 jv[sfVaultID] = to_string(vaultId);
737 jv[sfFlags] = flags;
738 return jv;
739}
740
742del(AccountID const& account, uint256 const& brokerID, uint32_t flags)
743{
744 json::Value jv;
745 jv[sfTransactionType] = jss::LoanBrokerDelete;
746 jv[sfAccount] = to_string(account);
747 jv[sfLoanBrokerID] = to_string(brokerID);
748 jv[sfFlags] = flags;
749 return jv;
750}
751
754 AccountID const& account,
755 uint256 const& brokerID,
756 STAmount const& amount,
757 uint32_t flags)
758{
759 json::Value jv;
760 jv[sfTransactionType] = jss::LoanBrokerCoverDeposit;
761 jv[sfAccount] = to_string(account);
762 jv[sfLoanBrokerID] = to_string(brokerID);
763 jv[sfAmount] = amount.getJson(JsonOptions::Values::None);
764 jv[sfFlags] = flags;
765 return jv;
766}
767
770 AccountID const& account,
771 uint256 const& brokerID,
772 STAmount const& amount,
773 uint32_t flags)
774{
775 json::Value jv;
776 jv[sfTransactionType] = jss::LoanBrokerCoverWithdraw;
777 jv[sfAccount] = to_string(account);
778 jv[sfLoanBrokerID] = to_string(brokerID);
779 jv[sfAmount] = amount.getJson(JsonOptions::Values::None);
780 jv[sfFlags] = flags;
781 return jv;
782}
783
786{
787 json::Value jv;
788 jv[sfTransactionType] = jss::LoanBrokerCoverClawback;
789 jv[sfAccount] = to_string(account);
790 jv[sfFlags] = flags;
791 return jv;
792}
793
794} // namespace loanBroker
795
796/* Loan */
797/******************************************************************************/
798namespace loan {
799
801set(AccountID const& account,
802 uint256 const& loanBrokerID,
803 Number principalRequested,
804 std::uint32_t flags)
805{
806 json::Value jv;
807 jv[sfTransactionType] = jss::LoanSet;
808 jv[sfAccount] = to_string(account);
809 jv[sfLoanBrokerID] = to_string(loanBrokerID);
810 jv[sfPrincipalRequested] = to_string(principalRequested);
811 jv[sfFlags] = flags;
812 return jv;
813}
814
816manage(AccountID const& account, uint256 const& loanID, std::uint32_t flags)
817{
818 json::Value jv;
819 jv[sfTransactionType] = jss::LoanManage;
820 jv[sfAccount] = to_string(account);
821 jv[sfLoanID] = to_string(loanID);
822 jv[sfFlags] = flags;
823 return jv;
824}
825
827del(AccountID const& account, uint256 const& loanID, std::uint32_t flags)
828{
829 json::Value jv;
830 jv[sfTransactionType] = jss::LoanDelete;
831 jv[sfAccount] = to_string(account);
832 jv[sfLoanID] = to_string(loanID);
833 jv[sfFlags] = flags;
834 return jv;
835}
836
838pay(AccountID const& account, uint256 const& loanID, STAmount const& amount, std::uint32_t flags)
839{
840 json::Value jv;
841 jv[sfTransactionType] = jss::LoanPay;
842 jv[sfAccount] = to_string(account);
843 jv[sfLoanID] = to_string(loanID);
844 jv[sfAmount] = amount.getJson();
845 jv[sfFlags] = flags;
846 return jv;
847}
848
849} // namespace loan
850} // namespace xrpl::test::jtx
A testsuite class.
Definition suite.h:50
Represents a JSON value.
Definition json_value.h:130
bool isArray() const
Value & append(Value const &value)
Append value to array at the end.
UInt size() const
Number of values in array or object.
bool isMember(char const *key) const
Return true if the object has a member named key.
void setJson(json::Value &jv) const
Definition Asset.cpp:33
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
Definition Asset.h:107
AccountID const & getIssuer() const
Definition Asset.cpp:21
Specifies an order book.
Definition Book.h:16
A currency issued by an account.
Definition Issue.h:13
Currency currency
Definition Issue.h:15
AccountID account
Definition Issue.h:16
AccountID const & getIssuer() const
Definition Issue.h:25
constexpr MPTID const & getMptID() const
Definition MPTIssue.h:33
std::chrono::duration< rep, period > duration
Definition chrono.h:45
Number is a floating point type that can represent a wide range of values.
Definition Number.h:306
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
Definition PathAsset.h:43
constexpr std::variant< Currency, MPTID > const & value() const
Definition PathAsset.h:84
A public key.
Definition PublicKey.h:42
Slice slice() const noexcept
Definition PublicKey.h:103
A view into a ledger.
Definition ReadView.h:31
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
A consumption charge.
Definition Charge.h:9
An endpoint that consumes resources.
Definition Consumer.h:15
constexpr TIss const & get() const
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
Definition STAmount.cpp:734
AccountID const & getIssuer() const
Definition STAmount.h:498
XRPAmount xrp() const
Definition STAmount.cpp:271
std::shared_ptr< STLedgerEntry const > const & const_ref
Holds the serialized result of parsing an input JSON object.
std::optional< STObject > object
The STObject if the parse was successful.
void pushBack(STPathElement const &e)
Definition STPathSet.h:436
Immutable cryptographic account descriptor.
Definition jtx/Account.h:17
std::string const & human() const
Returns the human readable public key.
Definition jtx/Account.h:92
A transaction testing environment.
Definition Env.h:143
Application & app()
Definition Env.h:280
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
SLE::const_pointer le(Account const &account) const
Return an account root.
Definition Env.cpp:284
std::uint32_t ownerCount(Account const &account) const
Return the number of objects owned by an account.
Definition Env.cpp:266
json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
Definition Env.h:864
beast::Journal const journal
Definition Env.h:184
void require(Args const &... args)
Check a set of requirements.
Definition Env.h:605
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:353
bool waitFor(std::chrono::duration< Rep, Period > const &relTime)
Converts to IOU Issue or STAmount.
Test helper for creating, mutating, and asserting MPT and confidential MPT ledger state.
Definition mpt.h:385
Converts to MPT Issue or STAmount.
Match the number of items in the account's owner directory.
Definition owners.h:52
T is_same_v
T make_tuple(T... args)
@ Array
array value (ordered list)
Definition json_value.h:25
@ Object
object value (collection of name/value pairs).
Definition json_value.h:26
static constexpr auto kApiVersionIfUnspecified
Definition ApiVersion.h:43
Status doCommand(RPC::JsonContext &context, json::Value &result)
Execute an RPC command and store the results in a json::Value.
Charge const kFeeReferenceRpc
Keylet mptokenIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:521
Keylet payChannel(AccountID const &src, AccountID const &dst, std::uint32_t seq) noexcept
A PaymentChannel.
Definition Indexes.cpp:378
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:533
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:241
MPT issueHelperMPT(IssuerArgs const &args)
IOU issueHelperIOU(IssuerArgs const &args)
json::Value set(AccountID const &account, uint256 const &vaultId, uint32_t flags)
json::Value coverWithdraw(AccountID const &account, uint256 const &brokerID, STAmount const &amount, uint32_t flags)
json::Value coverDeposit(AccountID const &account, uint256 const &brokerID, STAmount const &amount, uint32_t flags)
json::Value coverClawback(AccountID const &account, std::uint32_t flags)
json::Value del(AccountID const &account, uint256 const &brokerID, uint32_t flags)
json::Value set(AccountID const &account, uint256 const &loanBrokerID, Number principalRequested, std::uint32_t flags)
json::Value manage(AccountID const &account, uint256 const &loanID, std::uint32_t flags)
json::Value del(AccountID const &account, uint256 const &loanID, std::uint32_t flags)
json::Value pay(AccountID const &account, uint256 const &loanID, STAmount const &amount, std::uint32_t flags)
json::Value fund(AccountID const &account, uint256 const &channel, STAmount const &amount, std::optional< NetClock::time_point > const &expiration)
STAmount channelBalance(ReadView const &view, uint256 const &chan)
json::Value create(AccountID const &account, AccountID const &to, STAmount const &amount, NetClock::duration const &settleDelay, PublicKey const &pk, std::optional< NetClock::time_point > const &cancelAfter, std::optional< std::uint32_t > const &dstTag)
uint256 channel(AccountID const &account, AccountID const &dst, std::uint32_t seqProxyValue)
json::Value claim(AccountID const &account, uint256 const &channel, std::optional< STAmount > const &balance, std::optional< STAmount > const &amount, std::optional< Slice > const &signature, std::optional< PublicKey > const &pk)
bool channelExists(ReadView const &view, uint256 const &chan)
void nOffers(Env &env, std::size_t n, Account const &account, STAmount const &in, STAmount const &out)
json::Value findPathsRequest(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax, std::optional< PathAsset > const &srcAsset, std::optional< AccountID > const &srcIssuer, std::optional< uint256 > const &domain)
jtx::Env pathTestEnv(beast::unit_test::Suite &suite)
json::Value ledgerEntryMPT(jtx::Env &env, jtx::Account const &acct, MPTID const &mptID)
bool expectLedgerEntryRoot(Env &env, Account const &acct, STAmount const &expectedValue)
bool expectMPT(Env &env, AccountID const &account, STAmount const &value)
PrettyAmount xrpMinusFee(Env const &env, std::int64_t xrpAmount)
bool expectOffers(Env &env, AccountID const &account, std::uint16_t size, std::vector< Amounts > const &toMatch)
STPathElement allPathElements(AccountID const &a, Asset const &asset)
bool expectHolding(Env &env, AccountID const &account, STAmount const &value, bool defaultLimits)
static void addSourceAsset(json::Value &jv, PathAsset const &srcAsset, std::optional< AccountID > const &srcIssuer)
constexpr XRPAmount kJtxDropsPerXrp
json::Value getBookOffers(jtx::Env &env, Asset const &takerPays, Asset const &takerGets)
std::uint32_t ownerCount(Env const &env, Account const &account)
XRPAmount txFee(Env const &env, std::uint16_t n)
std::tuple< STPathSet, STAmount, STAmount > findPaths(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax, std::optional< PathAsset > const &srcAsset, std::optional< AccountID > const &srcIssuer, std::optional< uint256 > const &domain)
json::Value rpf(jtx::Account const &src, jtx::Account const &dst, STAmount const &dstAmount, std::optional< STAmount > const &sendMax, std::optional< PathAsset > const &srcAsset, std::optional< AccountID > const &srcIssuer)
STPathElement cpe(PathAsset const &pa)
std::tuple< STPathSet, STAmount, STAmount > findPathsByElement(jtx::Env &env, jtx::Account const &src, jtx::Account const &dst, STAmount const &saDstAmount, std::optional< STAmount > const &saSendMax, std::optional< STPathElement > const &srcElement, std::optional< AccountID > const &srcIssuer, std::optional< uint256 > const &domain)
STPathElement ipe(Asset const &asset)
json::Value ledgerEntryState(Env &env, Account const &acctA, Account const &acctB, std::string const &currency)
bool equal(STAmount const &sa1, STAmount const &sa2)
STPathElement iape(AccountID const &account)
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition offer.cpp:14
json::Value ledgerEntryRoot(Env &env, Account const &acct)
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:28
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:18
void stpathAppendOne(STPath &st, Account const &account)
json::Value accountBalance(Env &env, Account const &acct)
json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition rate.cpp:15
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
json::Value getAccountLines(Env &env, AccountID const &acctId)
bool checkArraySize(json::Value const &val, unsigned int size)
json::Value ledgerEntryOffer(jtx::Env &env, jtx::Account const &acct, std::uint32_t offerSeq)
STPathElement ape(AccountID const &a)
json::Value getAccountOffers(Env &env, AccountID const &acct, bool current)
bool bookStepEqual(Step const &step, xrpl::Book const &book)
bool xrpEndpointStepEqual(Step const &step, AccountID const &acc)
bool mptEndpointStepEqual(Step const &step, AccountID const &src, AccountID const &dst, MPTID const &mptid)
bool directStepEqual(Step const &step, AccountID const &src, AccountID const &dst, Currency const &currency)
constexpr XRPAmount
Convert XRP to drops (integral types).
Definition TxTest.h:48
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:10
SField const sfGeneric
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition AccountID.cpp:93
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition UintTypes.h:36
Currency const & xrpCurrency()
XRP currency.
Definition UintTypes.cpp:99
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
@ USER
Definition Role.h:24
@ JtClient
Definition Job.h:26
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
Definition UintTypes.h:44
STAmount amountFromJson(SField const &name, json::Value const &v)
Definition STAmount.cpp:916
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:28
void forEachItem(ReadView const &view, Keylet const &root, std::function< void(SLE::const_ref)> const &f)
Iterate all items in the given directory.
AccountID const & xrpAccount()
Compute AccountID from public key.
BaseUInt< 256 > uint256
Definition base_uint.h:562
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
T has_value(T... args)
std::shared_ptr< JobQueue::Coro > coro
Definition Context.h:27
json::Value params
Definition Context.h:43
std::optional< std::uint64_t > limit
std::vector< jtx::Account > holders
Represents an XRP, IOU, or MPT quantity This customizes the string conversion and supports XRP conver...
T value_or(T... args)
T visit(T... args)