xrpld
Loading...
Searching...
No Matches
LoanValidation_test.cpp
1#include <test/app/lending/LoanTestBase.h>
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/TestHelpers.h>
5#include <test/jtx/amount.h>
6#include <test/jtx/envconfig.h>
7#include <test/jtx/fee.h>
8#include <test/jtx/flags.h>
9#include <test/jtx/mpt.h>
10#include <test/jtx/pay.h>
11#include <test/jtx/sponsor.h>
12#include <test/jtx/ter.h>
13#include <test/jtx/trust.h>
14#include <test/jtx/txflags.h>
15#include <test/jtx/vault.h>
16
17#include <xrpl/basics/Number.h>
18#include <xrpl/basics/base_uint.h>
19#include <xrpl/basics/strHex.h>
20#include <xrpl/beast/unit_test/suite.h>
21#include <xrpl/beast/utility/Journal.h>
22#include <xrpl/beast/utility/Zero.h>
23#include <xrpl/json/json_value.h>
24#include <xrpl/json/to_string.h>
25#include <xrpl/ledger/helpers/AccountRootHelpers.h>
26#include <xrpl/protocol/Feature.h>
27#include <xrpl/protocol/Indexes.h>
28#include <xrpl/protocol/Issue.h>
29#include <xrpl/protocol/Protocol.h>
30#include <xrpl/protocol/SField.h>
31#include <xrpl/protocol/STTx.h>
32#include <xrpl/protocol/SeqProxy.h>
33#include <xrpl/protocol/TER.h>
34#include <xrpl/protocol/TxFlags.h>
35#include <xrpl/protocol/jss.h>
36#include <xrpl/tx/transactors/lending/LoanSet.h>
37
38#include <cstdint>
39#include <optional>
40
41namespace xrpl::test {
42
44{
45private:
46 void
48 {
49 testcase("Disabled");
50 // Lending Protocol depends on Single Asset Vault (SAV). Test
51 // combinations of the two amendments.
52 // Single Asset Vault depends on MPTokensV1, but don't test every combo
53 // of that.
54 using namespace jtx;
55 auto failAll = [this](FeatureBitset features) {
56 Env env(*this, features);
57
58 Account const alice{"alice"};
59 Account const bob{"bob"};
60 env.fund(XRP(10000), alice, bob);
61
62 auto const keylet = keylet::loanBroker(alice, SeqProxy::rawSequence(env.seq(alice)));
63
64 using namespace std::chrono_literals;
65 using namespace loan;
66
67 // counter party signature is optional on LoanSet. Confirm that by
68 // sending transaction without one.
69 auto setTx = env.jt(set(alice, keylet.key, Number(10000)), Ter(temDISABLED));
70 env(setTx);
71
72 // All loan transactions are disabled.
73 // 1. LoanSet
74 setTx = env.jt(setTx, Sig(sfCounterpartySignature, bob), Ter(temDISABLED));
75 env(setTx);
76 // Actual sequence will be based off the loan broker, but we
77 // obviously don't have one of those if the amendment is disabled
78 auto const loanKeylet = keylet::loan(keylet.key, SeqProxy::rawSequence(env.seq(alice)));
79 // Other Loan transactions are disabled, too.
80 // 2. LoanDelete
81 env(del(alice, loanKeylet.key), Ter(temDISABLED));
82 // 3. LoanManage
83 env(manage(alice, loanKeylet.key, tfLoanImpair), Ter(temDISABLED));
84 // 4. LoanPay
85 env(pay(alice, loanKeylet.key, XRP(500)), Ter(temDISABLED));
86 };
87 failAll(all_ - featureMPTokensV1);
88 failAll(all_ - featureSingleAssetVault - featureLendingProtocol);
89 failAll(all_ - featureSingleAssetVault);
90 failAll(all_ - featureLendingProtocol);
91 }
92
93 void
95 {
97 std::string("Invalid LoanSet (") +
98 (vaultKind == VaultKind::OpenEnded ? "open-ended" : "closed-ended") + " vault)");
99 using namespace jtx;
100 using namespace loan;
101 Account const lender{"lender"};
102 Account const issuer{"issuer"};
103 Account const borrower{"borrower"};
104 Account const sponsor{"sponsor"};
105 auto const iou = issuer["IOU"];
106
107 auto testWrapper = [&](auto&& test) {
108 Env env(*this);
109 env.fund(XRP(1'000), lender, issuer, borrower, sponsor);
110 env(trust(lender, iou(10'000'000)));
111 env(pay(issuer, lender, iou(5'000'000)));
112 BrokerInfo const brokerInfo{
113 createVaultAndBroker(env, issuer["IOU"], lender, {.vaultKind = vaultKind})};
114
115 auto const loanSetFee = Fee(env.current()->fees().base * 2);
116 Number const debtMaximumRequest = brokerInfo.asset(1'000).value();
117 test(env, brokerInfo, loanSetFee, debtMaximumRequest);
118 };
119
120 // preflight:
121 testWrapper([&](Env& env,
122 BrokerInfo const& brokerInfo,
123 jtx::Fee const& loanSetFee,
124 Number const& debtMaximumRequest) {
125 for (auto const sponsorFlags : {spfSponsorReserve, spfSponsorReserve | spfSponsorFee})
126 {
127 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
128 sponsor::As(sponsor, sponsorFlags),
129 Sig(sfCounterpartySignature, lender),
130 loanSetFee,
132 }
133
134 // first temBAD_SIGNER: TODO
135 // invalid grace period
136 {
137 // zero grace period
138 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
139 Sig(sfCounterpartySignature, lender),
140 kGracePeriod(0),
141 loanSetFee,
142 Ter(temINVALID));
143
144 // grace period less than default minimum
145 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
146 Sig(sfCounterpartySignature, lender),
147 kGracePeriod(LoanSet::kDefaultGracePeriod - 1),
148 loanSetFee,
149 Ter(temINVALID));
150
151 // grace period greater than payment interval
152 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
153 Sig(sfCounterpartySignature, lender),
154 kPaymentInterval(120),
155 kGracePeriod(121),
156 loanSetFee,
157 Ter(temINVALID));
158 }
159 // empty/zero broker ID
160 {
161 auto jv = set(borrower, UInt256{}, debtMaximumRequest);
162
163 auto testZeroBrokerID = [&](std::string const& id, std::uint32_t flags = 0) {
164 // empty broker ID
165 jv[sfLoanBrokerID] = id;
166 env(jv,
167 Sig(sfCounterpartySignature, lender),
168 loanSetFee,
169 Txflags(flags),
170 Ter(temINVALID));
171 };
172 // empty broker ID
173 testZeroBrokerID(std::string(""));
174 // zero broker ID
175 // needs a flag to distinguish the parsed STTx from the prior
176 // test
177 testZeroBrokerID(to_string(UInt256{}), tfFullyCanonicalSig);
178 }
179
180 // preflightCheckSigningKey() failure:
181 // can it happen? the signature is checked before transactor
182 // executes
183
184 JTx const tx = env.jt(
185 set(borrower, brokerInfo.brokerID, debtMaximumRequest),
186 Sig(sfCounterpartySignature, lender),
187 loanSetFee);
188 STTx local = *(tx.stx);
189 auto counterpartySig = local.getFieldObject(sfCounterpartySignature);
190 auto badPubKey = counterpartySig.getFieldVL(sfSigningPubKey);
191 badPubKey[20] ^= 0xAA;
192 counterpartySig.setFieldVL(sfSigningPubKey, badPubKey);
193 local.setFieldObject(sfCounterpartySignature, counterpartySig);
194 json::Value jvResult;
195 jvResult[jss::tx_blob] = strHex(local.getSerializer().slice());
196 auto res = env.rpc("json", "submit", to_string(jvResult))["result"];
197 BEAST_EXPECT(
198 res[jss::error] == "invalidTransaction" &&
199 res[jss::error_exception] ==
200 "fails local checks: Counterparty: Invalid signature.");
201 });
202
203 // preclaim:
204 testWrapper([&](Env& env,
205 BrokerInfo const& brokerInfo,
206 jtx::Fee const& loanSetFee,
207 Number const& debtMaximumRequest) {
208 // canAddHoldingFailure (IOU only, if MPT doesn't have
209 // MPTCanTransfer set, then can't create Vault/LoanBroker,
210 // and LoanSet will fail with different error
211 env(fclear(issuer, asfDefaultRipple));
212 env.close();
213 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
214 Sig(sfCounterpartySignature, lender),
215 loanSetFee,
217 });
218
219 // doApply:
220 testWrapper([&](Env& env,
221 BrokerInfo const& brokerInfo,
222 jtx::Fee const& loanSetFee,
223 Number const& debtMaximumRequest) {
224 auto const amt =
225 env.balance(borrower) - accountReserve(*env.current(), borrower.id(), env.journal);
226 env(pay(borrower, issuer, amt));
227
228 // tecINSUFFICIENT_RESERVE
229 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
230 Sig(sfCounterpartySignature, lender),
231 loanSetFee,
233
234 // addEmptyHolding failure
235 env(pay(issuer, borrower, amt));
236 env(fset(issuer, asfGlobalFreeze));
237 env.close();
238
239 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
240 Sig(sfCounterpartySignature, lender),
241 loanSetFee,
242 Ter(tecFROZEN));
243 });
244 }
245
246 void
248 {
249 testcase("Invalid LoanDelete");
250 using namespace jtx;
251 using namespace loan;
252
253 // preflight: temINVALID, LoanID == zero
254 {
255 Account const alice{"alice"};
256 Env env(*this);
257 env.fund(XRP(1'000), alice);
258 env.close();
259 env(del(alice, beast::kZero), Ter(temINVALID));
260 }
261 }
262
263 void
265 {
266 testcase("Invalid LoanManage");
267 using namespace jtx;
268 using namespace loan;
269
270 // preflight: temINVALID, LoanID == zero
271 {
272 Account const alice{"alice"};
273 Env env(*this);
274 env.fund(XRP(1'000), alice);
275 env.close();
276 env(manage(alice, beast::kZero, tfLoanDefault), Ter(temINVALID));
277 }
278 }
279
280 void
282 {
283 testcase("Invalid LoanPay");
284 using namespace jtx;
285 using namespace loan;
286 Account const lender{"lender"};
287 Account const issuer{"issuer"};
288 Account const borrower{"borrower"};
289 auto const iou = issuer["IOU"];
290
291 // preclaim
292 Env env(*this);
293 env.fund(XRP(1'000), lender, issuer, borrower);
294 env(trust(lender, iou(10'000'000)));
295 env(pay(issuer, lender, iou(5'000'000)));
296 BrokerInfo brokerInfo{createVaultAndBroker(env, issuer["IOU"], lender)};
297
298 auto const loanSetFee = Fee(env.current()->fees().base * 2);
299 STAmount const debtMaximumRequest = brokerInfo.asset(1'000).value();
300
301 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
302 Sig(sfCounterpartySignature, lender),
303 loanSetFee);
304
305 env.close();
306
307 std::uint32_t const loanSequence = 1;
308 auto const loanKeylet =
309 keylet::loan(brokerInfo.brokerID, SeqProxy::rawSequence(loanSequence));
310
311 env(fset(issuer, asfGlobalFreeze));
312 env.close();
313
314 // preclaim: tecFROZEN
315 env(pay(borrower, loanKeylet.key, debtMaximumRequest), Ter(tecFROZEN));
316 env.close();
317
318 env(fclear(issuer, asfGlobalFreeze));
319 env.close();
320
321 auto const pseudoBroker = [&]() -> std::optional<Account> {
322 if (auto brokerSle = env.le(keylet::loanBroker(brokerInfo.brokerID));
323 BEAST_EXPECT(brokerSle))
324 {
325 return Account{"pseudo", brokerSle->at(sfAccount)};
326 }
327
328 return std::nullopt;
329 }();
330 if (!pseudoBroker)
331 return;
332
333 // Lender and pseudoaccount must both be frozen
334 env(trust(issuer, lender["IOU"](1'000), lender, tfSetFreeze | tfSetDeepFreeze));
335 env(trust(
336 issuer, (*pseudoBroker)["IOU"](1'000), *pseudoBroker, tfSetFreeze | tfSetDeepFreeze));
337 env.close();
338
339 // preclaim: tecFROZEN due to deep frozen
340 env(pay(borrower, loanKeylet.key, debtMaximumRequest), Ter(tecFROZEN));
341 env.close();
342
343 // Only one needs to be unfrozen
344 env(trust(issuer, lender["IOU"](1'000), tfClearFreeze | tfClearDeepFreeze));
345 env.close();
346
347 // The payment is late by this point. With fixCleanup3_4_0,
348 // isPaymentLate() uses a strict (Exclusive) comparison, so advance
349 // one more ledger close to be sure the due date instant itself has
350 // passed, not merely reached.
351 env.close();
352
353 env(pay(borrower, loanKeylet.key, debtMaximumRequest), Ter(tecEXPIRED));
354 env.close();
355 env(pay(borrower, loanKeylet.key, debtMaximumRequest, tfLoanLatePayment));
356 env.close();
357
358 // preclaim: tecKILLED
359 // note that tecKILLED in loanMakePayment()
360 // doesn't happen because of the preclaim check.
361 env(pay(borrower, loanKeylet.key, debtMaximumRequest), Ter(tecKILLED));
362 }
363
364 void
366 {
367 testcase("Require Auth - Implicit Pseudo-account authorization");
368 using namespace jtx;
369 using namespace loan;
370 Account const lender{"lender"};
371 Account const issuer{"issuer"};
372 Account const borrower{"borrower"};
373 Env env(*this);
374
375 env.fund(XRP(100'000), issuer, lender, borrower);
376 env.close();
377
378 auto asset = MPTTester({
379 .env = env,
380 .issuer = issuer,
381 .holders = {lender, borrower},
382 .flags = kMptDexFlags | tfMPTRequireAuth | tfMPTCanClawback | tfMPTCanLock,
383 .authHolder = true,
384 });
385
386 env(pay(issuer, lender, asset(5'000'000)));
387 BrokerInfo brokerInfo{createVaultAndBroker(env, asset, lender)};
388
389 auto const loanSetFee = Fee(env.current()->fees().base * 2);
390 STAmount const debtMaximumRequest = brokerInfo.asset(1'000).value();
391
392 auto forUnauthAuth = [&](auto&& doTx) {
393 for (auto const flag : {tfMPTUnauthorize, 0u})
394 {
395 asset.authorize({.account = issuer, .holder = borrower, .flags = flag});
396 env.close();
397 doTx(flag == 0);
398 env.close();
399 }
400 };
401
402 // Can't create a loan if the borrower is not authorized
403 forUnauthAuth([&](bool authorized) {
404 auto const err = !authorized ? Ter(tecNO_AUTH) : Ter(tesSUCCESS);
405 env(set(borrower, brokerInfo.brokerID, debtMaximumRequest),
406 Sig(sfCounterpartySignature, lender),
407 loanSetFee,
408 err);
409 });
410
411 static constexpr std::uint32_t kLoanSequence = 1;
412 auto const loanKeylet =
413 keylet::loan(brokerInfo.brokerID, SeqProxy::rawSequence(kLoanSequence));
414
415 // Can't loan pay if the borrower is not authorized
416 forUnauthAuth([&](bool authorized) {
417 auto const err = !authorized ? Ter(tecNO_AUTH) : Ter(tesSUCCESS);
418 env(pay(borrower, loanKeylet.key, debtMaximumRequest), err);
419 });
420 }
421
422 void
424 {
425 testcase("RIPD-4125 - overpayment");
426
427 using namespace jtx;
428
429 Account const issuer("issuer");
430 Account const lender("lender");
431 Account const borrower("borrower");
432
433 BrokerParameters const brokerParams{
434 .vaultDeposit = 100'000,
435 .debtMax = 0,
436 .coverRateMin = TenthBips32{0},
437 .managementFeeRate = TenthBips16{0},
438 .coverRateLiquidation = TenthBips32{0}};
439 LoanParameters const loanParams{
440 .account = lender,
441 .counter = borrower,
442 .principalRequest = Number{200000, -6},
443 .interest = TenthBips32{50000},
444 .payTotal = 3,
445 .payInterval = 200,
446 .gracePd = 60,
447 .flags = tfLoanOverpayment,
448 };
449
450 auto const assetType = AssetType::XRP;
451
452 Env env(*this, makeConfig(), all_, nullptr, beast::Severity::Warning);
453
454 auto loanResult =
455 createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower);
456
457 if (BEAST_EXPECT(loanResult); !loanResult.has_value())
458 return;
459
460 auto broker = std::get<BrokerInfo>(*loanResult);
461 auto loanKeylet = std::get<Keylet>(*loanResult);
462 auto pseudoAcct = std::get<Account>(*loanResult);
463
464 VerifyLoanStatus const verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
465
466 auto const state = getCurrentState(env, broker, loanKeylet);
467
468 env(loan::pay(
469 borrower,
470 loanKeylet.key,
471 STAmount{broker.asset, state.periodicPayment * 3 / 2 + 1},
472 tfLoanOverpayment));
473 env.close();
474
475 PaymentParameters const paymentParams{
476 .showStepBalances = false,
477 .validateBalances = true,
478 };
479
481 env,
482 broker,
483 loanParams,
484 loanKeylet,
485 verifyLoanStatus,
486 issuer,
487 lender,
488 borrower,
489 paymentParams);
490 }
491
492 void
494 {
495 // From FIND-003
496 testcase << "Wrong Max Debt Behavior";
497
498 using namespace jtx;
499 using namespace std::chrono_literals;
500 Env env(*this, features);
501
502 Account const issuer{"issuer"};
503 Account const lender{"lender"};
504
505 BrokerParameters const brokerParams{.debtMax = 0};
506 env.fund(XRP(brokerParams.vaultDeposit * 100), issuer, noripple(lender));
507 env.close();
508
509 PrettyAsset const xrpAsset{xrpIssue(), 1'000'000};
510
511 BrokerInfo const broker{createVaultAndBroker(env, xrpAsset, lender, brokerParams)};
512
513 if (auto const brokerSle = env.le(keylet::loanBroker(broker.brokerID));
514 BEAST_EXPECT(brokerSle))
515 {
516 BEAST_EXPECT(brokerSle->at(sfDebtMaximum) == 0);
517 }
518
519 using namespace loan;
520
521 auto const loanSetFee = Fee(env.current()->fees().base * 2);
522 Number const principalRequest{1, 3};
523
524 // The lender is both the borrower and the counterparty here, but the
525 // two roles sign different bytes, so each signature must be made for
526 // the field it goes into.
527 auto const createJson = env.json(
528 set(lender, broker.brokerID, principalRequest),
529 Sig(sfCounterpartySignature, lender),
530 Fee(loanSetFee));
531 env(createJson);
532
533 env.close();
534 }
535
536 // Under featureLendingProtocolV1_1 LoanBrokerSet::preclaim rejects
537 // attaching a broker to an open-ended vault. VaultCreate itself is
538 // not gated by the amendment, so the same open-ended vault can be
539 // built under either feature set; only the broker create is
540 // amendment-sensitive. Cover both branches: LP V1.1 disabled lets
541 // the broker create succeed, LP V1.1 enabled rejects it. The gate
542 // only fires on the create path; existing brokers keep working.
543 void
545 {
546 testcase("LoanBrokerSet requires closed-ended vault under LP V1.1");
547 using namespace jtx;
548
549 Account const owner{"lp11_owner"};
550
551 auto const build = [&](FeatureBitset features,
552 TER expected,
553 std::optional<TER> updateExpected = std::nullopt) {
554 Env env(*this, features);
555 env.fund(XRP(1'000), owner);
556 env.close();
557
558 Vault const vault{env};
559 auto [tx, vaultKeylet] = vault.create({.owner = owner, .asset = xrpIssue()});
560 env(tx);
561 env.close();
562 env(vault.deposit({.depositor = owner, .id = vaultKeylet.key, .amount = XRP(100)}));
563 env.close();
564
565 auto const brokerKeylet =
566 keylet::loanBroker(owner.id(), SeqProxy::rawSequence(env.seq(owner)));
567 env(loan_broker::set(owner, vaultKeylet.key), Ter(expected));
568 env.close();
569
570 // The create-path gate is the only new check; updates to an
571 // existing broker on the same open-ended vault are not
572 // affected. Only exercise the update path when the create
573 // succeeded (so there is a broker to update).
574 if (updateExpected && expected == tesSUCCESS)
575 {
576 env(loan_broker::set(owner, vaultKeylet.key),
577 loan_broker::kLoanBrokerId(brokerKeylet.key),
578 loan_broker::kDebtMaximum(XRP(1'000).value()),
579 Ter(*updateExpected));
580 env.close();
581 }
582 };
583
584 // Baseline: LP V1.1 disabled -> open-ended vault + broker succeeds.
585 build(all_, tesSUCCESS, tesSUCCESS);
586
587 // LP V1.1 enabled -> open-ended vault + broker rejected on create.
588 build(all_ | featureLendingProtocolV1_1, tecNO_PERMISSION);
589 }
590
591 void
604
605 // Tests run under each entry in amendmentCombinations().
606 void
611
612public:
613 void
614 run() override
615 {
617 for (auto const& features : jtx::amendmentCombinations(
618 {fixCleanup3_1_3, fixCleanup3_2_0, featureMPTokensV2}, all_))
619 runAmendmentSensitive(features);
620 }
621};
622
623BEAST_DEFINE_TESTSUITE(LoanValidation, tx, xrpl);
624
625} // namespace xrpl::test
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
Represents a JSON value.
Definition json_value.h:117
static constexpr std::uint32_t kDefaultGracePeriod
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
Blob getFieldVL(SField const &field) const
Definition STObject.cpp:649
Serializer getSerializer() const
Definition STObject.h:1003
void setFieldObject(SField const &field, STObject const &v)
Definition STObject.cpp:839
STObject getFieldObject(SField const &field) const
Definition STObject.cpp:678
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:62
Slice slice() const noexcept
Definition Serializer.h:141
Shared base for the Loan*_test family under src/test/app/lending/.
FeatureBitset const all_
BrokerInfo createVaultAndBroker(jtx::Env &env, jtx::PrettyAsset const &asset, jtx::Account const &lender, BrokerParameters const &params=BrokerParameters::defaults())
LoanState getCurrentState(jtx::Env const &env, BrokerInfo const &broker, Keylet const &loanKeylet)
Get the state without checking anything.
void makeLoanPayments(jtx::Env &env, BrokerInfo const &broker, LoanParameters const &loanParams, Keylet const &loanKeylet, VerifyLoanStatus const &verifyLoanStatus, jtx::Account const &issuer, jtx::Account const &lender, jtx::Account const &borrower, PaymentParameters const &paymentParams=PaymentParameters::defaults())
std::optional< std::tuple< BrokerInfo, Keylet, jtx::Account > > createLoan(jtx::Env &env, AssetType assetType, BrokerParameters const &brokerParams, LoanParameters const &loanParams, jtx::Account const &issuer, jtx::Account const &lender, jtx::Account const &borrower)
void runAmendmentSensitive(FeatureBitset features)
void run() override
Runs the suite.
void testWrongMaxDebtBehavior(FeatureBitset features)
void testInvalidLoanSet(VaultKind vaultKind)
Immutable cryptographic account descriptor.
Definition jtx/Account.h:21
AccountID id() const
Returns the Account ID.
A transaction testing environment.
Definition Env.h:161
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:133
json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
Definition Env.h:752
SLE::const_pointer le(Account const &account) const
Return an account root.
Definition Env.cpp:311
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:323
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
Definition Env.cpp:302
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:1058
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition Env.h:723
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
Definition Env.cpp:201
beast::Journal const journal
Definition Env.h:204
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:377
Set the fee on a JTx.
Definition fee.h:20
Test helper for creating, mutating, and asserting MPT and confidential MPT ledger state.
Definition mpt.h:512
Set the regular signature on a JTx.
Definition sig.h:19
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:18
Set the flags on a JTx.
Definition txflags.h:14
constexpr Zero kZero
Definition Zero.h:30
Keylet computation functions.
Definition Indexes.h:40
Keylet loanBroker(AccountID const &owner, SeqProxy const &seq) noexcept
Definition Indexes.cpp:597
Keylet loan(UInt256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
Definition Indexes.cpp:603
json::Value set(AccountID const &account, UInt256 const &vaultId, uint32_t flags)
json::Value pay(AccountID const &account, UInt256 const &loanID, STAmount const &amount, std::uint32_t flags)
auto const kMptDexFlags
Definition mpt.h:47
json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:14
std::vector< FeatureBitset > amendmentCombinations(std::initializer_list< UInt256 > features, FeatureBitset seed)
Returns all 2^N permutations of a seed FeatureBitset with each subset of the given features excluded.
Definition Env.h:123
XrpT const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:92
std::unique_ptr< Config > makeConfig(std::map< std::string, std::string > extraTxQ={}, std::map< std::string, std::string > extraVoting={})
json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:110
std::array< Account, 1+sizeof...(Args)> noripple(Account const &account, Args const &... args)
Designate accounts as no-ripple in Env::fund.
Definition Env.h:86
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:18
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:15
static STAmount accountReserve(jtx::Env &env, std::uint32_t count=1)
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr FlagValue spfSponsorFee
Definition TxFlags.h:465
@ terNO_RIPPLE
Definition TER.h:225
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition Issue.h:108
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:13
static bool authorized(Port const &port, std::map< std::string, std::string > const &h)
TenthBips< std::uint32_t > TenthBips32
Definition Units.h:454
TenthBips< std::uint16_t > TenthBips16
Definition Units.h:453
VaultKind
Vault kind.
Definition Protocol.h:336
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
BaseUInt< 256 > UInt256
Definition base_uint.h:580
@ temINVALID
Definition TER.h:98
@ temINVALID_FLAG
Definition TER.h:99
@ temDISABLED
Definition TER.h:102
TERSubset< CanCvtToTER > TER
Definition TER.h:654
@ tecNO_AUTH
Definition TER.h:308
@ tecFROZEN
Definition TER.h:311
@ tecEXPIRED
Definition TER.h:322
@ tecINSUFFICIENT_RESERVE
Definition TER.h:315
@ tecKILLED
Definition TER.h:324
@ tecNO_PERMISSION
Definition TER.h:313
constexpr FlagValue spfSponsorReserve
Definition TxFlags.h:466
@ tesSUCCESS
Definition TER.h:250
constexpr FlagValue tfFullyCanonicalSig
Definition TxFlags.h:43
Helper class to compare the expected state of a loan and loan broker against the data in the ledger.
Execution context for applying a JSON transaction.
Definition JTx.h:27
std::shared_ptr< STTx const > stx
Definition JTx.h:37