xrpld
Loading...
Searching...
No Matches
LoanSecurity_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/fee.h>
7#include <test/jtx/noop.h>
8#include <test/jtx/txflags.h>
9#include <test/jtx/vault.h>
10
11#include <xrpl/basics/Number.h>
12#include <xrpl/basics/chrono.h>
13#include <xrpl/beast/unit_test/suite.h>
14#include <xrpl/beast/utility/Zero.h>
15#include <xrpl/json/to_string.h>
16#include <xrpl/ledger/helpers/LendingHelpers.h>
17#include <xrpl/protocol/Feature.h>
18#include <xrpl/protocol/Indexes.h>
19#include <xrpl/protocol/Issue.h>
20#include <xrpl/protocol/Protocol.h>
21#include <xrpl/protocol/SField.h>
22#include <xrpl/protocol/STAmount.h>
23#include <xrpl/protocol/SeqProxy.h>
24#include <xrpl/protocol/TxFlags.h>
25#include <xrpl/protocol/jss.h>
26
27#include <algorithm>
28#include <cstdint>
29#include <ostream>
30
31namespace xrpl::test {
32
34{
35private:
36 void
38 {
39 // --- PoC Summary ----------------------------------------------------
40 // Scenario: Borrower makes one periodic payment early (before next due)
41 // so doPayment sets sfPreviousPaymentDueDate to the (future)
42 // sfNextPaymentDueDate and advances sfNextPaymentDueDate by one
43 // interval. Borrower then immediately performs a full-payment
44 // (tfLoanFullPayment). Why it matters: Full-payment interest accrual
45 // uses
46 // delta = now - max(prevPaymentDate, startDate)
47 // with an unsigned clock representation (uint32). If prevPaymentDate is
48 // in the future, the subtraction underflows to a very large positive
49 // number. This inflates roundedFullInterest and total full-close due,
50 // and LoanPay applies the inflated valueChange to the vault
51 // (sfAssetsTotal), increasing NAV.
52 // --------------------------------------------------------------------
53 testcase("PoC: Unsigned-underflow full-pay accrual after early periodic");
54
55 using namespace jtx;
56 using namespace loan;
57 using namespace std::chrono_literals;
58
59 Env env{*this, features};
60
61 Account const lender{"poc_lender4"};
62 Account const borrower{"poc_borrower4"};
63 env.fund(XRP(3'000'000), lender, borrower);
64 env.close();
65
66 PrettyAsset const asset{xrpIssue(), 1'000'000};
67 BrokerParameters const brokerParams{};
68 auto const broker = createVaultAndBroker(env, asset, lender, brokerParams);
69
70 // Create a 3-payment loan so full-payment path is enabled after 1
71 // periodic payment.
72 auto const loanSetFee = Fee(env.current()->fees().base * 2);
73 Number const principalRequest = asset(1000).value();
74 auto const originationFee = asset(0).value();
75 auto const serviceFee = asset(1).value();
76 auto const serviceFeePA = asset(1);
77 auto const lateFee = asset(0).value();
78 auto const closeFee = asset(0).value();
79 auto const interest = percentageToTenthBips(12);
80 auto const lateInterest = percentageToTenthBips(12) / 10;
81 auto const closeInterest = percentageToTenthBips(12) / 10;
82 auto const overpaymentInterest = percentageToTenthBips(12) / 10;
83 auto const total = 3u;
84 auto const interval = 600u;
85 auto const grace = 60u;
86
87 auto createJtx = env.jt(
88 set(borrower, broker.brokerID, principalRequest, 0),
89 Sig(sfCounterpartySignature, lender),
90 kLoanOriginationFee(originationFee),
91 kLoanServiceFee(serviceFee),
92 kLatePaymentFee(lateFee),
93 kClosePaymentFee(closeFee),
94 kOverpaymentFee(percentageToTenthBips(5) / 10),
95 kInterestRate(interest),
96 kLateInterestRate(lateInterest),
97 kCloseInterestRate(closeInterest),
98 kOverpaymentInterestRate(overpaymentInterest),
99 kPaymentTotal(total),
100 kPaymentInterval(interval),
101 kGracePeriod(grace),
102 Fee(loanSetFee));
103
104 auto const brokerSle = env.le(keylet::loanBroker(broker.brokerID));
105 BEAST_EXPECT(brokerSle);
106 auto const loanSequence = brokerSle ? brokerSle->at(sfLoanSequence) : 0;
107 auto const loanKeylet = keylet::loan(broker.brokerID, SeqProxy::rawSequence(loanSequence));
108
109 env(createJtx);
110 env.close();
111
112 // Compute a regular periodic due and pay it early (before next due).
113 auto state = getCurrentState(env, broker, loanKeylet);
114 Number const periodicRate = loanPeriodicRate(state.interestRate, state.paymentInterval);
115 auto const components = xrpl::detail::computePaymentComponents(
116 env.current()->rules(),
117 asset.raw(),
118 state.loanScale,
119 state.totalValue,
120 state.principalOutstanding,
121 state.managementFeeOutstanding,
122 state.periodicPayment,
123 periodicRate,
124 state.paymentRemaining,
125 brokerParams.managementFeeRate);
126 STAmount const regularDue{asset, components.trackedValueDelta + serviceFeePA.number()};
127 // now < nextDue immediately after creation, so this is an early pay.
128 env(pay(borrower, loanKeylet.key, regularDue));
129 env.close();
130
131 // Immediately attempt a full payoff. Compute the exact full-payment
132 // due to ensure the tx applies.
133 auto after = getCurrentState(env, broker, loanKeylet);
134 auto const loanSle = env.le(loanKeylet);
135 BEAST_EXPECT(loanSle);
136 auto const brokerSle2 = env.le(keylet::loanBroker(broker.brokerID));
137 BEAST_EXPECT(brokerSle2);
138
139 auto const closePaymentFee = loanSle ? loanSle->at(sfClosePaymentFee) : Number{};
140 auto const closeInterestRate =
141 loanSle ? TenthBips32{loanSle->at(sfCloseInterestRate)} : TenthBips32{};
142 auto const managementFeeRate =
143 brokerSle2 ? TenthBips16{brokerSle2->at(sfManagementFeeRate)} : TenthBips16{};
144
145 Number const periodicRate2 = loanPeriodicRate(after.interestRate, after.paymentInterval);
146 // Accrued + prepayment-penalty interest based on current periodic
147 // schedule
148 auto const fullPaymentInterest = computeFullPaymentInterest(
150 env.current()->rules(),
151 after.periodicPayment,
152 periodicRate2,
153 after.paymentRemaining),
154 periodicRate2,
155 env.current()->parentCloseTime(),
156 after.paymentInterval,
157 after.previousPaymentDate,
158 static_cast<std::uint32_t>(after.startDate.time_since_epoch().count()),
159 closeInterestRate);
160
161 // Round to asset scale and split interest/fee parts
162 auto const roundedInterest =
163 roundToAsset(asset.raw(), fullPaymentInterest, after.loanScale);
164 Number const roundedFullMgmtFee =
165 computeManagementFee(asset.raw(), roundedInterest, managementFeeRate, after.loanScale);
166 Number const roundedFullInterest = roundedInterest - roundedFullMgmtFee;
167
168 // Show both signed and unsigned deltas to highlight the underflow.
169 auto const nowSecs =
170 static_cast<std::uint32_t>(env.current()->parentCloseTime().time_since_epoch().count());
171 auto const startSecs =
172 static_cast<std::uint32_t>(after.startDate.time_since_epoch().count());
173 auto const lastPaymentDate = std::max(after.previousPaymentDate, startSecs);
174 auto const signedDelta =
175 static_cast<std::int64_t>(nowSecs) - static_cast<std::int64_t>(lastPaymentDate);
176 auto const unsignedDelta = static_cast<std::uint32_t>(nowSecs - lastPaymentDate);
177 log << "PoC window: prev=" << after.previousPaymentDate << " start=" << startSecs
178 << " now=" << nowSecs << " signedDelta=" << signedDelta
179 << " unsignedDelta=" << unsignedDelta << std::endl;
180
181 // Reference (clamped) computation: emulate a non-negative accrual
182 // window by clamping prevPaymentDate to 'now' for the full-pay path.
183 auto const prevClamped = std::min(after.previousPaymentDate, nowSecs);
184 auto const fullPaymentInterestClamped = computeFullPaymentInterest(
186 env.current()->rules(),
187 after.periodicPayment,
188 periodicRate2,
189 after.paymentRemaining),
190 periodicRate2,
191 env.current()->parentCloseTime(),
192 after.paymentInterval,
193 prevClamped,
194 startSecs,
195 closeInterestRate);
196 auto const roundedInterestClamped =
197 roundToAsset(asset.raw(), fullPaymentInterestClamped, after.loanScale);
198 Number const roundedFullMgmtFeeClamped = computeManagementFee(
199 asset.raw(), roundedInterestClamped, managementFeeRate, after.loanScale);
200 Number const roundedFullInterestClamped =
201 roundedInterestClamped - roundedFullMgmtFeeClamped;
202 STAmount const fullDueClamped{
203 asset,
204 after.principalOutstanding + roundedFullInterestClamped + roundedFullMgmtFeeClamped +
205 closePaymentFee};
206
207 // Collect vault NAV before closing payment
208 auto const vaultId2 = brokerSle2 ? brokerSle2->at(sfVaultID) : uint256{};
209 auto const vaultKey2 = keylet::vault(vaultId2);
210 auto const vaultBefore = env.le(vaultKey2);
211 BEAST_EXPECT(vaultBefore);
212 Number const assetsTotalBefore = vaultBefore ? vaultBefore->at(sfAssetsTotal) : Number{};
213
214 STAmount const fullDue{
215 asset,
216 after.principalOutstanding + roundedFullInterest + roundedFullMgmtFee +
217 closePaymentFee};
218
219 log << "PoC payoff: principalOutstanding=" << after.principalOutstanding
220 << " roundedFullInterest=" << roundedFullInterest
221 << " roundedFullMgmtFee=" << roundedFullMgmtFee << " closeFee=" << closePaymentFee
222 << " fullDue=" << to_string(fullDue.getJson()) << std::endl;
223 log << "PoC reference (clamped): roundedFullInterestClamped=" << roundedFullInterestClamped
224 << " roundedFullMgmtFeeClamped=" << roundedFullMgmtFeeClamped
225 << " fullDueClamped=" << to_string(fullDueClamped.getJson()) << std::endl;
226
227 env(pay(borrower, loanKeylet.key, fullDue), Txflags(tfLoanFullPayment));
228 env.close();
229
230 // Sanity: underflow present (unsigned delta very large relative to
231 // interval)
232 BEAST_EXPECT(unsignedDelta > after.paymentInterval);
233
234 // Compare vault NAV before/after the full close
235 auto const vaultAfter = env.le(vaultKey2);
236 BEAST_EXPECT(vaultAfter);
237 if (vaultAfter)
238 {
239 auto const assetsTotalAfter = vaultAfter->at(sfAssetsTotal);
240 log << "PoC NAV: assetsTotalBefore=" << assetsTotalBefore
241 << " assetsTotalAfter=" << assetsTotalAfter
242 << " delta=" << (assetsTotalAfter - assetsTotalBefore) << std::endl;
243
244 // Regression check: the underflowed window must be clamped so the
245 // payoff matches the non-underflow reference, i.e. no overcharge.
246 BEAST_EXPECT(fullDue == fullDueClamped);
247 if (fullDue != fullDueClamped)
248 log << "PoC delta: overcharge (fullDue > clamped)" << std::endl;
249 }
250
251 // Loan should be paid off
252 auto const finalLoan = env.le(loanKeylet);
253 BEAST_EXPECT(finalLoan);
254 if (finalLoan)
255 {
256 BEAST_EXPECT(finalLoan->at(sfPaymentRemaining) == 0);
257 BEAST_EXPECT(finalLoan->at(sfPrincipalOutstanding) == 0);
258 }
259 }
260
261 void
263 {
264 using namespace jtx;
265
266 testcase("RIPD-3831");
267
268 Account const issuer("issuer");
269 Account const lender("lender");
270 Account const borrower("borrower");
271
272 BrokerParameters const brokerParams{
273 .vaultDeposit = 100000,
274 .debtMax = 0,
275 .coverRateMin = TenthBips32{0},
276 // .managementFeeRate = TenthBips16{5919},
277 .coverRateLiquidation = TenthBips32{0}};
278 LoanParameters const loanParams{
279 .account = lender,
280 .counter = borrower,
281 .principalRequest = Number{200'000, -6},
282 .lateFee = Number{200, -6},
283 .interest = TenthBips32{50'000},
284 .payTotal = 10,
285 .payInterval = 150};
286
287 auto const assetType = AssetType::XRP;
288
289 Env env{*this, features};
290
291 auto loanResult =
292 createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower);
293
294 if (BEAST_EXPECT(loanResult); !loanResult.has_value())
295 return;
296
297 auto broker = std::get<BrokerInfo>(*loanResult);
298 auto loanKeylet = std::get<Keylet>(*loanResult);
299
300 using tp = NetClock::time_point;
301 using d = NetClock::duration;
302
303 auto state = getCurrentState(env, broker, loanKeylet);
304 if (auto loan = env.le(loanKeylet); BEAST_EXPECT(loan))
305 {
306 env.close(tp{d{loan->at(sfNextPaymentDueDate) + loan->at(sfGracePeriod) + 1}});
307 }
308
309 topUpBorrower(env, broker, issuer, borrower, state, loanParams.serviceFee);
310
311 using namespace jtx::loan;
312
313 auto jv = pay(borrower, loanKeylet.key, drops(XRPAmount(state.totalValue)));
314
315 {
316 auto const submitParam = to_string(jv);
317 auto const jr = env.rpc("submit", borrower.name(), submitParam);
318
319 BEAST_EXPECT(jr.isMember(jss::result));
320 }
321
322 env.close();
323
324 // Make sure the system keeps responding
325 env(noop(borrower));
326 env.close();
327 env(noop(issuer));
328 env.close();
329 env(noop(lender));
330 env.close();
331 }
332
333 void
335 {
336 testcase("RIPD-3459 - LoanBroker incorrect debt total");
337
338 using namespace jtx;
339
340 Account const issuer("issuer");
341 Account const lender("lender");
342 Account const borrower("borrower");
343
344 BrokerParameters const brokerParams{
345 .vaultDeposit = 200'000,
346 .debtMax = 0,
347 .coverRateMin = TenthBips32{0},
348 .managementFeeRate = TenthBips16{500},
349 .coverRateLiquidation = TenthBips32{0}};
350 LoanParameters const loanParams{
351 .account = lender,
352 .counter = borrower,
353 .principalRequest = Number{100'000, -4},
354 .interest = TenthBips32{100'000},
355 .payTotal = 10};
356
357 auto const assetType = AssetType::MPT;
358
359 Env env{*this, features};
360
361 auto loanResult =
362 createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower);
363
364 if (BEAST_EXPECT(loanResult); !loanResult.has_value())
365 return;
366
367 auto broker = std::get<BrokerInfo>(*loanResult);
368 auto loanKeylet = std::get<Keylet>(*loanResult);
369 auto pseudoAcct = std::get<Account>(*loanResult);
370
371 VerifyLoanStatus const verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
372
373 if (auto const brokerSle = env.le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
374 {
375 if (auto const loanSle = env.le(loanKeylet); BEAST_EXPECT(loanSle))
376 {
377 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == loanSle->at(sfTotalValueOutstanding));
378 }
379 }
380
382 env,
383 broker,
384 loanParams,
385 loanKeylet,
386 verifyLoanStatus,
387 issuer,
388 lender,
389 borrower,
390 PaymentParameters{.showStepBalances = true});
391
392 if (auto const brokerSle = env.le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
393 {
394 if (auto const loanSle = env.le(loanKeylet); BEAST_EXPECT(loanSle))
395 {
396 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == loanSle->at(sfTotalValueOutstanding));
397 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == beast::kZero);
398 }
399 }
400 }
401
402 void
404 {
405 testcase("Crash with tfLoanOverpayment");
406 using namespace jtx;
407 using namespace loan;
408 Account const lender{"lender"};
409 Account const issuer{"issuer"};
410 Account const borrower{"borrower"};
411 Account const depositor{"depositor"};
412 auto const txFee = Fee(XRP(100));
413
414 Env env(*this);
415 Vault const vault(env);
416
417 env.fund(XRP(10'000), lender, issuer, borrower, depositor);
418 env.close();
419
420 auto [tx, vaultKeyLet] = vault.create({.owner = lender, .asset = xrpIssue()});
421 env(tx, txFee);
422 env.close();
423
424 env(vault.deposit({.depositor = depositor, .id = vaultKeyLet.key, .amount = XRP(1'000)}),
425 txFee);
426 env.close();
427
428 auto const brokerKeyLet =
429 keylet::loanBroker(lender.id(), SeqProxy::rawSequence(env.seq(lender)));
430
431 env(loan_broker::set(lender, vaultKeyLet.key), txFee);
432 env.close();
433
434 STAmount const debtMaximumRequest = XRPAmount(200'000);
435
436 env(set(borrower, brokerKeyLet.key, debtMaximumRequest),
437 Sig(sfCounterpartySignature, lender),
438 kInterestRate(TenthBips32(50'000)),
439 kPaymentTotal(2),
440 kPaymentInterval(150),
441 Txflags(tfLoanOverpayment),
442 txFee);
443 env.close();
444
445 std::uint32_t const loanSequence = 1;
446 auto const loanKeylet = keylet::loan(brokerKeyLet.key, SeqProxy::rawSequence(loanSequence));
447
448 if (auto loan = env.le(loanKeylet); env.test.BEAST_EXPECT(loan))
449 {
450 env(loan::pay(borrower, loanKeylet.key, XRPAmount(150'001)),
451 Txflags(tfLoanOverpayment),
452 txFee);
453 env.close();
454 }
455 }
456
457 void
459 {
460 testcase("RIPD-3902 - 1 IOU loan payments");
461
462 using namespace jtx;
463
464 Account const issuer("issuer");
465 Account const lender("lender");
466 Account const borrower("borrower");
467
468 BrokerParameters const brokerParams{
469 .vaultDeposit = 10,
470 .debtMax = 0,
471 .coverRateMin = TenthBips32{0},
472 .managementFeeRate = TenthBips16{0},
473 .coverRateLiquidation = TenthBips32{0}};
474 LoanParameters const loanParams{
475 .account = lender,
476 .counter = borrower,
477 .principalRequest = Number{1, 0},
478 .interest = TenthBips32{100'000},
479 .payTotal = 5,
480 .payInterval = 150,
481 .gracePd = 60};
482
483 auto const assetType = AssetType::IOU;
484
485 Env env{*this, features};
486
487 auto loanResult =
488 createLoan(env, assetType, brokerParams, loanParams, issuer, lender, borrower);
489
490 if (BEAST_EXPECT(loanResult); !loanResult.has_value())
491 return;
492
493 auto broker = std::get<BrokerInfo>(*loanResult);
494 auto loanKeylet = std::get<Keylet>(*loanResult);
495 auto pseudoAcct = std::get<Account>(*loanResult);
496
497 VerifyLoanStatus const verifyLoanStatus(env, broker, pseudoAcct, loanKeylet);
498
500 env,
501 broker,
502 loanParams,
503 loanKeylet,
504 verifyLoanStatus,
505 issuer,
506 lender,
507 borrower,
508 PaymentParameters{.showStepBalances = true});
509 }
510
511 void
516
517 // Tests run under each entry in amendmentCombinations().
518 void
520 {
522 testRIPD3831(features);
523 testRIPD3459(features);
524 testRIPD3902(features);
525 }
526
527public:
528 void
529 run() override
530 {
532 for (auto const& features : jtx::amendmentCombinations(
533 {fixCleanup3_1_3, fixCleanup3_2_0, featureMPTokensV2}, all_))
534 runAmendmentSensitive(features);
535 }
536};
537
538BEAST_DEFINE_TESTSUITE(LoanSecurity, tx, xrpl);
539
540} // namespace xrpl::test
LogOs< char > log
Logging output stream.
Definition suite.h:150
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
std::chrono::time_point< NetClock > time_point
Definition chrono.h:48
std::chrono::duration< rep, period > duration
Definition chrono.h:47
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
Definition STAmount.cpp:734
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:62
void testRIPD3902(FeatureBitset features)
void runAmendmentSensitive(FeatureBitset features)
void testRIPD3459(FeatureBitset features)
void run() override
Runs the suite.
void testPoCUnsignedUnderflowOnFullPayAfterEarlyPeriodic(FeatureBitset features)
void testRIPD3831(FeatureBitset features)
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)
static void topUpBorrower(jtx::Env &env, BrokerInfo const &broker, jtx::Account const &issuer, jtx::Account const &borrower, LoanState const &state, std::optional< Number > const &servFee)
Immutable cryptographic account descriptor.
Definition jtx/Account.h:21
std::string const & name() const
Return the name.
Definition jtx/Account.h:75
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
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:1056
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
Definition Env.h:721
beast::unit_test::Suite & test
Definition Env.h:163
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
Set the regular signature on a JTx.
Definition sig.h:19
Set the flags on a JTx.
Definition txflags.h:14
T endl(T... args)
T max(T... args)
T min(T... args)
constexpr Zero kZero
Definition Zero.h:30
Number loanPrincipalFromPeriodicPayment(Rules const &rules, Number const &periodicPayment, Number const &periodicRate, std::uint32_t paymentsRemaining)
PaymentComponents computePaymentComponents(Rules const &rules, Asset const &asset, std::int32_t scale, Number const &totalValueOutstanding, Number const &principalOutstanding, Number const &managementFeeOutstanding, Number const &periodicPayment, Number const &periodicRate, std::uint32_t paymentRemaining, TenthBips16 managementFeeRate)
Keylet loan(uint256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
Definition Indexes.cpp:573
Keylet vault(AccountID const &owner, SeqProxy const &seq) noexcept
Definition Indexes.cpp:561
Keylet loanBroker(AccountID const &owner, SeqProxy const &seq) noexcept
Definition Indexes.cpp:567
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)
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
json::Value noop(Account const &account)
The null transaction.
Definition noop.h:14
XRPAmount txFee(Env const &env, std::uint16_t n)
PrettyAmount drops(Integer i)
Returns an XRP PrettyAmount, which is trivially convertible to STAmount.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
constexpr XRPAmount
Convert XRP to drops (integral types).
Definition TxTest.h:54
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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
Number loanPeriodicRate(TenthBips32 interestRate, std::uint32_t paymentInterval)
constexpr TenthBips32 percentageToTenthBips(std::uint32_t percentage)
Definition Protocol.h:126
TenthBips< std::uint32_t > TenthBips32
Definition Units.h:454
TenthBips< std::uint16_t > TenthBips16
Definition Units.h:453
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
Definition View.cpp:572
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
Definition STAmount.h:735
Number computeManagementFee(Asset const &asset, Number const &interest, TenthBips32 managementFeeRate, std::int32_t scale)
BaseUInt< 256 > uint256
Definition base_uint.h:580
Number computeFullPaymentInterest(Number const &theoreticalPrincipalOutstanding, Number const &periodicRate, NetClock::time_point parentCloseTime, std::uint32_t paymentInterval, std::uint32_t prevPaymentDate, std::uint32_t startDate, TenthBips32 closeInterestRate)
Helper class to compare the expected state of a loan and loan broker against the data in the ledger.