xrpld
Loading...
Searching...
No Matches
LoanMisc_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/mpt.h>
8#include <test/jtx/noop.h>
9#include <test/jtx/offer.h>
10#include <test/jtx/pay.h>
11#include <test/jtx/seq.h>
12#include <test/jtx/sig.h>
13#include <test/jtx/tags.h>
14#include <test/jtx/ter.h>
15
16#include <xrpl/basics/Number.h>
17#include <xrpl/beast/unit_test/suite.h>
18#include <xrpl/beast/xor_shift_engine.h>
19#include <xrpl/json/json_value.h>
20#include <xrpl/json/to_string.h>
21#include <xrpl/protocol/Feature.h>
22#include <xrpl/protocol/Indexes.h>
23#include <xrpl/protocol/KeyType.h>
24#include <xrpl/protocol/SField.h>
25#include <xrpl/protocol/SeqProxy.h>
26#include <xrpl/protocol/TER.h>
27#include <xrpl/protocol/TxFlags.h>
28#include <xrpl/protocol/Units.h>
29#include <xrpl/protocol/jss.h>
30
31#include <algorithm>
32#include <cstddef>
33#include <cstdint>
34#include <random>
35#include <string>
36
37namespace xrpl::test {
38
40{
41private:
42 void
44 {
45 // This will expand as more test cases are added. Some functionality
46 // is tested in other test functions.
47 testcase("RPC");
48
49 using namespace jtx;
50
51 Env env(*this, features);
52
53 auto lowerFee = [&]() {
54 // Run the local fee back down.
55 while (env.app().getFeeTrack().lowerLocalFee())
56 ;
57 };
58
59 auto const baseFee = env.current()->fees().base;
60
61 Account const alice{"alice"};
62 std::string const borrowerPass = "borrower";
63 Account const borrower{borrowerPass, KeyType::Ed25519};
64 auto const lenderPass = "lender";
65 Account const lender{lenderPass, KeyType::Ed25519};
66
67 env.fund(XRP(1'000'000), alice, lender, borrower);
68 env.close();
69 env(noop(lender));
70 env(noop(lender));
71 env(noop(lender));
72 env(noop(lender));
73 env(noop(lender));
74 env.close();
75
76 {
77 testcase("RPC AccountSet");
79 txJson[sfTransactionType] = "AccountSet";
80 txJson[sfAccount] = borrower.human();
81
82 auto const signParams = [&]() {
84 signParams[jss::passphrase] = borrowerPass;
85 signParams[jss::key_type] = "ed25519";
86 signParams[jss::tx_json] = txJson;
87 return signParams;
88 }();
89 auto const jSign = env.rpc("json", "sign", to_string(signParams));
90 BEAST_EXPECT(jSign.isMember(jss::result) && jSign[jss::result].isMember(jss::tx_json));
91 auto txSignResult = jSign[jss::result][jss::tx_json];
92 auto txSignBlob = jSign[jss::result][jss::tx_blob].asString();
93 txSignResult.removeMember(jss::hash);
94
95 auto const jtx = env.jt(txJson, Sig(borrower));
96 BEAST_EXPECT(txSignResult == jtx.jv);
97
98 lowerFee();
99 auto const jSubmit = env.rpc("submit", txSignBlob);
100 BEAST_EXPECT(
101 jSubmit.isMember(jss::result) &&
102 jSubmit[jss::result].isMember(jss::engine_result) &&
103 jSubmit[jss::result][jss::engine_result].asString() == "tesSUCCESS");
104
105 lowerFee();
106 env(jtx.jv, Sig(kNone), Seq(kNone), Fee(kNone), Ter(tefPAST_SEQ));
107 }
108
109 {
110 testcase("RPC LoanSet - illegal signature_target");
111
113 txJson[sfTransactionType] = "AccountSet";
114 txJson[sfAccount] = borrower.human();
115
116 // "Destination" is not an inner object at all. "Book" is one, but
117 // it holds no transaction signature, so it is not a target either.
118 for (char const* target : {"Destination", "Book", "Signer"})
119 {
120 auto const borrowerSignParams = [&]() {
122 params[jss::passphrase] = borrowerPass;
123 params[jss::key_type] = "ed25519";
124 params[jss::signature_target] = target;
125 params[jss::tx_json] = txJson;
126 return params;
127 }();
128 auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams));
129 BEAST_EXPECT(
130 jSignBorrower.isMember(jss::result) &&
131 jSignBorrower[jss::result].isMember(jss::error) &&
132 jSignBorrower[jss::result][jss::error] == "invalidParams" &&
133 jSignBorrower[jss::result].isMember(jss::error_message) &&
134 jSignBorrower[jss::result][jss::error_message] == target);
135 }
136 }
137 {
138 testcase("RPC LoanSet - sign and submit borrower initiated");
139 // 1. Borrower creates the transaction
141 txJson[sfTransactionType] = "LoanSet";
142 txJson[sfAccount] = borrower.human();
143 txJson[sfCounterparty] = lender.human();
144 txJson[sfLoanBrokerID] =
145 "FF924CD18A236C2B49CF8E80A351CEAC6A10171DC9F110025646894FEC"
146 "F83F"
147 "5C";
148 txJson[sfPrincipalRequested] = "100000000";
149 txJson[sfPaymentTotal] = 10000;
150 txJson[sfPaymentInterval] = 3600;
151 txJson[sfGracePeriod] = 300;
152 txJson[sfFlags] = 65536; // tfLoanOverpayment
153 txJson[sfFee] = to_string(24 * baseFee / 10);
154
155 // 2. Borrower signs the transaction
156 auto const borrowerSignParams = [&]() {
158 params[jss::passphrase] = borrowerPass;
159 params[jss::key_type] = "ed25519";
160 params[jss::tx_json] = txJson;
161 return params;
162 }();
163 auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams));
164 BEAST_EXPECTS(
165 jSignBorrower.isMember(jss::result) &&
166 jSignBorrower[jss::result].isMember(jss::tx_json),
167 to_string(jSignBorrower));
168 auto const txBorrowerSignResult = jSignBorrower[jss::result][jss::tx_json];
169 auto const txBorrowerSignBlob = jSignBorrower[jss::result][jss::tx_blob].asString();
170
171 // 2a. Borrower attempts to submit the transaction. It doesn't
172 // work
173 {
174 lowerFee();
175 auto const jSubmitBlob = env.rpc("submit", txBorrowerSignBlob);
176 BEAST_EXPECT(jSubmitBlob.isMember(jss::result));
177 auto const jSubmitBlobResult = jSubmitBlob[jss::result];
178 BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json));
179 // Transaction fails because the CounterpartySignature is
180 // missing
181 BEAST_EXPECT(
182 jSubmitBlobResult.isMember(jss::engine_result) &&
183 jSubmitBlobResult[jss::engine_result].asString() == "temBAD_SIGNER");
184 }
185
186 // 3. Borrower sends the signed transaction to the lender
187 // 4. Lender signs the transaction
188 auto const lenderSignParams = [&]() {
190 params[jss::passphrase] = lenderPass;
191 params[jss::key_type] = "ed25519";
192 params[jss::signature_target] = "CounterpartySignature";
193 params[jss::tx_json] = txBorrowerSignResult;
194 return params;
195 }();
196 auto const jSignLender = env.rpc("json", "sign", to_string(lenderSignParams));
197 BEAST_EXPECT(
198 jSignLender.isMember(jss::result) &&
199 jSignLender[jss::result].isMember(jss::tx_json));
200 auto const txLenderSignResult = jSignLender[jss::result][jss::tx_json];
201 auto const txLenderSignBlob = jSignLender[jss::result][jss::tx_blob].asString();
202
203 // 5. Lender submits the signed transaction blob
204 lowerFee();
205 auto const jSubmitBlob = env.rpc("submit", txLenderSignBlob);
206 BEAST_EXPECT(jSubmitBlob.isMember(jss::result));
207 auto const jSubmitBlobResult = jSubmitBlob[jss::result];
208 BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json));
209 auto const jSubmitBlobTx = jSubmitBlobResult[jss::tx_json];
210 // To get far enough to return tecNO_ENTRY means that the
211 // signatures all validated. Of course the transaction won't
212 // succeed because no Vault or Broker were created.
213 BEAST_EXPECTS(
214 jSubmitBlobResult.isMember(jss::engine_result) &&
215 jSubmitBlobResult[jss::engine_result].asString() == "tecNO_ENTRY",
216 to_string(jSubmitBlobResult));
217
218 BEAST_EXPECT(
219 !jSubmitBlob.isMember(jss::error) && !jSubmitBlobResult.isMember(jss::error));
220
221 // 4-alt. Lender submits the transaction json originally
222 // received from the Borrower. It gets signed, but is now a
223 // duplicate, so fails. Borrower could done this instead of
224 // steps 4 and 5.
225 lowerFee();
226 auto const jSubmitJson = env.rpc("json", "submit", to_string(lenderSignParams));
227 BEAST_EXPECT(jSubmitJson.isMember(jss::result));
228 auto const jSubmitJsonResult = jSubmitJson[jss::result];
229 BEAST_EXPECT(jSubmitJsonResult.isMember(jss::tx_json));
230 auto const jSubmitJsonTx = jSubmitJsonResult[jss::tx_json];
231 // Since the previous tx claimed a fee, this duplicate is not
232 // going anywhere
233 BEAST_EXPECTS(
234 jSubmitJsonResult.isMember(jss::engine_result) &&
235 jSubmitJsonResult[jss::engine_result].asString() == "tefPAST_SEQ",
236 to_string(jSubmitJsonResult));
237
238 BEAST_EXPECT(
239 !jSubmitJson.isMember(jss::error) && !jSubmitJsonResult.isMember(jss::error));
240
241 BEAST_EXPECT(jSubmitBlobTx == jSubmitJsonTx);
242 }
243
244 {
245 testcase("RPC LoanSet - sign and submit lender initiated");
246 // 1. Lender creates the transaction
248 txJson[sfTransactionType] = "LoanSet";
249 txJson[sfAccount] = lender.human();
250 txJson[sfCounterparty] = borrower.human();
251 txJson[sfLoanBrokerID] =
252 "FF924CD18A236C2B49CF8E80A351CEAC6A10171DC9F110025646894FEC"
253 "F83F"
254 "5C";
255 txJson[sfPrincipalRequested] = "100000000";
256 txJson[sfPaymentTotal] = 10000;
257 txJson[sfPaymentInterval] = 3600;
258 txJson[sfGracePeriod] = 300;
259 txJson[sfFlags] = 65536; // tfLoanOverpayment
260 txJson[sfFee] = to_string(24 * baseFee / 10);
261
262 // 2. Lender signs the transaction
263 auto const lenderSignParams = [&]() {
265 params[jss::passphrase] = lenderPass;
266 params[jss::key_type] = "ed25519";
267 params[jss::tx_json] = txJson;
268 return params;
269 }();
270 auto const jSignLender = env.rpc("json", "sign", to_string(lenderSignParams));
271 BEAST_EXPECT(
272 jSignLender.isMember(jss::result) &&
273 jSignLender[jss::result].isMember(jss::tx_json));
274 auto const txLenderSignResult = jSignLender[jss::result][jss::tx_json];
275 auto const txLenderSignBlob = jSignLender[jss::result][jss::tx_blob].asString();
276
277 // 2a. Lender attempts to submit the transaction. It doesn't
278 // work
279 {
280 lowerFee();
281 auto const jSubmitBlob = env.rpc("submit", txLenderSignBlob);
282 BEAST_EXPECT(jSubmitBlob.isMember(jss::result));
283 auto const jSubmitBlobResult = jSubmitBlob[jss::result];
284 BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json));
285 // Transaction fails because the CounterpartySignature is
286 // missing
287 BEAST_EXPECT(
288 jSubmitBlobResult.isMember(jss::engine_result) &&
289 jSubmitBlobResult[jss::engine_result].asString() == "temBAD_SIGNER");
290 }
291
292 // 3. Lender sends the signed transaction to the Borrower
293 // 4. Borrower signs the transaction
294 auto const borrowerSignParams = [&]() {
296 params[jss::passphrase] = borrowerPass;
297 params[jss::key_type] = "ed25519";
298 params[jss::signature_target] = "CounterpartySignature";
299 params[jss::tx_json] = txLenderSignResult;
300 return params;
301 }();
302 auto const jSignBorrower = env.rpc("json", "sign", to_string(borrowerSignParams));
303 BEAST_EXPECT(
304 jSignBorrower.isMember(jss::result) &&
305 jSignBorrower[jss::result].isMember(jss::tx_json));
306 auto const txBorrowerSignResult = jSignBorrower[jss::result][jss::tx_json];
307 auto const txBorrowerSignBlob = jSignBorrower[jss::result][jss::tx_blob].asString();
308
309 // 5. Borrower submits the signed transaction blob
310 lowerFee();
311 auto const jSubmitBlob = env.rpc("submit", txBorrowerSignBlob);
312 BEAST_EXPECT(jSubmitBlob.isMember(jss::result));
313 auto const jSubmitBlobResult = jSubmitBlob[jss::result];
314 BEAST_EXPECT(jSubmitBlobResult.isMember(jss::tx_json));
315 auto const jSubmitBlobTx = jSubmitBlobResult[jss::tx_json];
316 // To get far enough to return tecNO_ENTRY means that the
317 // signatures all validated. Of course the transaction won't
318 // succeed because no Vault or Broker were created.
319 BEAST_EXPECTS(
320 jSubmitBlobResult.isMember(jss::engine_result) &&
321 jSubmitBlobResult[jss::engine_result].asString() == "tecNO_ENTRY",
322 to_string(jSubmitBlobResult));
323
324 BEAST_EXPECT(
325 !jSubmitBlob.isMember(jss::error) && !jSubmitBlobResult.isMember(jss::error));
326
327 // 4-alt. Borrower submits the transaction json originally
328 // received from the Lender. It gets signed, but is now a
329 // duplicate, so fails. Lender could done this instead of steps
330 // 4 and 5.
331 lowerFee();
332 auto const jSubmitJson = env.rpc("json", "submit", to_string(borrowerSignParams));
333 BEAST_EXPECT(jSubmitJson.isMember(jss::result));
334 auto const jSubmitJsonResult = jSubmitJson[jss::result];
335 BEAST_EXPECT(jSubmitJsonResult.isMember(jss::tx_json));
336 auto const jSubmitJsonTx = jSubmitJsonResult[jss::tx_json];
337 // Since the previous tx claimed a fee, this duplicate is not
338 // going anywhere
339 BEAST_EXPECTS(
340 jSubmitJsonResult.isMember(jss::engine_result) &&
341 jSubmitJsonResult[jss::engine_result].asString() == "tefPAST_SEQ",
342 to_string(jSubmitJsonResult));
343
344 BEAST_EXPECT(
345 !jSubmitJson.isMember(jss::error) && !jSubmitJsonResult.isMember(jss::error));
346
347 BEAST_EXPECT(jSubmitBlobTx == jSubmitJsonTx);
348 }
349 }
350
351 void
353 {
354 testcase("Lending: CanTrade disabled has no impact");
355 using namespace jtx;
356 using namespace loan;
357 using namespace loan_broker;
358
359 Env env(*this, all_);
360
361 Account const issuer{"issuer"};
362 Account const lender{"lender"};
363 Account const borrower{"borrower"};
364
365 env.fund(XRP(1'000'000), issuer, lender, borrower);
366 env.close();
367
368 MPTTester mpt(
369 {.env = env,
370 .issuer = issuer,
371 .holders = {lender, borrower},
372 .flags = tfMPTCanTransfer | tfMPTCanLock});
373 PrettyAsset const asset = mpt.issuanceID();
374 env(pay(issuer, lender, asset(10'000'000)));
375 env(pay(issuer, borrower, asset(100'000)));
376 env.close();
377
378 auto const broker = createVaultAndBroker(env, asset, lender);
379
380 // CanTrade is not set
381 env(offer(lender, XRP(1), asset(10)), Ter{tecNO_PERMISSION});
382 env.close();
383
384 auto const loanSetFee = Fee(env.current()->fees().base * 2);
385
386 // New cover deposits still work.
387 env(coverDeposit(lender, broker.brokerID, asset(100)));
388 env.close();
389
390 // New loan issuance still works.
391 env(loan::set(borrower, broker.brokerID, 1'000),
392 Sig(sfCounterpartySignature, lender),
393 loanSetFee);
394 env.close();
395 auto const loanKeylet = keylet::loan(broker.brokerID, SeqProxy::rawSequence(1));
396 BEAST_EXPECT(env.le(loanKeylet));
397
398 // Repayment still works.
399 env(pay(borrower, loanKeylet.key, asset(1'000)));
400 env.close();
401
402 // Cover withdrawal still works.
403 env(coverWithdraw(lender, broker.brokerID, asset(100)));
404 env.close();
405
406 // Enable CanTrade and verify the DEX path is restored.
407 mpt.set({.flags = tfMPTSetCanTrade});
408 env.close();
409
410 env(offer(lender, XRP(1), asset(10)));
411 env.close();
412 }
413
414 void
419
420 // Tests run under each entry in amendmentCombinations().
421 void
423 {
424 testRPC(features);
425 }
426
427public:
428 void
429 run() override
430 {
432 for (auto const& features : jtx::amendmentCombinations(
433 {fixCleanup3_1_3, fixCleanup3_2_0, featureMPTokensV2}, all_))
434 runAmendmentSensitive(features);
435 }
436};
437
439{
440protected:
442
450 /*
451 # Generate parameters that are more likely to be valid
452 principal = Decimal(str(rand.randint(100000,
453 100'000'000))).quantize(ROUND_TARGET)
454
455 interest_rate = Decimal(rand.randint(1, 10000)) /
456 Decimal(100000)
457
458 payment_total = rand.randint(12, 10000)
459
460 payment_interval = Decimal(str(rand.randint(60, 2629746)))
461
462 interest_fee = Decimal(rand.randint(0, 100000)) /
463 Decimal(100000)
464*/
465
466 void
468 {
469 using namespace jtx;
470
471 Account const issuer("issuer");
472 Account const lender("lender");
473 Account const borrower("borrower");
474
475 // Determine all the random parameters at once
476 auto const assetType = static_cast<AssetType>(assetDist_(engine_));
477 auto const principalRequest = principalDist_(engine_);
478 TenthBips16 const managementFeeRate{managementFeeRateDist_(engine_)};
479 auto const serviceFee = serviceFeeDist_(engine_);
481 auto payTotal = paymentTotalDist_(engine_);
482 auto const payInterval = paymentIntervalDist_(engine_);
483 // The end of the last payment's grace period must fit in a 32-bit
484 // ripple-epoch timestamp, or LoanSet fails with tecKILLED. Cap the
485 // schedule well below that horizon (2e9 seconds is roughly 63 years,
486 // leaving ample headroom over the ledger start date).
487 constexpr std::uint32_t kMaxScheduleSeconds = 2'000'000'000;
488 payTotal = std::min(payTotal, static_cast<int>(kMaxScheduleSeconds / payInterval));
489
490 BrokerParameters const brokerParams{
491 .vaultDeposit = principalRequest * 10,
492 .debtMax = 0,
493 .coverRateMin = TenthBips32{0},
494 .managementFeeRate = managementFeeRate,
495 .coverRateLiquidation = TenthBips32{0}};
496 LoanParameters const loanParams{
497 .account = lender,
498 .counter = borrower,
499 .principalRequest = principalRequest,
500 .serviceFee = serviceFee,
501 .interest = interest,
502 .payTotal = payTotal,
503 .payInterval = payInterval,
504 };
505
506 runLoan(assetType, brokerParams, loanParams, all_);
507 }
508
509public:
510 void
511 run() override
512 {
513 auto const numIterations = [s = arg()]() -> int {
514 int const defaultNum = 5;
515 if (s.empty())
516 return defaultNum;
517 try
518 {
519 std::size_t pos = 0;
520 auto const r = stoi(s, &pos);
521 if (pos != s.size())
522 return defaultNum;
523 return r;
524 }
525 catch (...)
526 {
527 return defaultNum;
528 }
529 }();
530
531 using namespace jtx;
532
533 auto const updateInterval = std::max(std::min(numIterations / 5, 100), 1);
534
535 for (int i = 0; i < numIterations; ++i)
536 {
537 if (i % updateInterval == 0)
538 testcase << "Random Loan Test iteration " << (i + 1) << "/" << numIterations;
540 }
541 }
542};
545{
546 void
547 run() override
548 {
549 using namespace jtx;
550
551 BrokerParameters const brokerParams{
552 .vaultDeposit = 10000,
553 .debtMax = 0,
554 .coverRateMin = TenthBips32{0},
555 .managementFeeRate = TenthBips16{0},
556 .coverRateLiquidation = TenthBips32{0}};
557 LoanParameters const loanParams{
558 .account = Account("lender"),
559 .counter = Account("borrower"),
560 .principalRequest = Number{200000, -6},
561 .interest = TenthBips32{50000},
562 .payTotal = 2,
563 .payInterval = 200};
564
565 runLoan(AssetType::XRP, brokerParams, loanParams, all_);
566 }
567};
571BEAST_DEFINE_TESTSUITE_MANUAL(LoanArbitrary, tx, xrpl);
572
573} // namespace xrpl::test
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
std::string const & arg() const
Return the argument associated with the runner.
Definition suite.h:292
Represents a JSON value.
Definition json_value.h:117
Number is a floating point type that can represent a wide range of values.
Definition Number.h:351
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
Definition SeqProxy.h:62
virtual LoadFeeTrack & getFeeTrack()=0
void run() override
Runs the suite.
std::uniform_int_distribution paymentIntervalDist_
std::uniform_int_distribution paymentTotalDist_
std::uniform_int_distribution< std::int64_t > principalDist_
void run() override
Runs the suite.
std::uniform_int_distribution< std::uint16_t > managementFeeRateDist_
beast::XorShiftEngine engine_
std::uniform_int_distribution serviceFeeDist_
std::uniform_int_distribution< std::uint32_t > interestRateDist_
std::uniform_int_distribution assetDist_
void runAmendmentSensitive(FeatureBitset features)
void run() override
Runs the suite.
void testRPC(FeatureBitset features)
Shared base for the Loan*_test family under src/test/app/lending/.
FeatureBitset const all_
void runLoan(AssetType assetType, BrokerParameters const &brokerParams, LoanParameters const &loanParams, FeatureBitset features)
BrokerInfo createVaultAndBroker(jtx::Env &env, jtx::PrettyAsset const &asset, jtx::Account const &lender, BrokerParameters const &params=BrokerParameters::defaults())
Immutable cryptographic account descriptor.
Definition jtx/Account.h:21
std::string const & human() const
Returns the human readable public key.
A transaction testing environment.
Definition Env.h:161
Application & app()
Definition Env.h:300
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
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
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
T max(T... args)
T min(T... args)
detail::XorShiftEngine<> XorShiftEngine
XOR-shift Generator.
@ Object
object value (collection of name/value pairs).
Definition json_value.h:29
Keylet loan(UInt256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
Definition Indexes.cpp:603
json::Value set(AccountID const &account, UInt256 const &loanBrokerID, Number principalRequested, std::uint32_t flags)
static NoneT const kNone
Definition tags.h:9
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
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition offer.cpp:14
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
BEAST_DEFINE_TESTSUITE_MANUAL(AMMCalc, app, xrpl)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ tefPAST_SEQ
Definition TER.h:170
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:657
@ tecNO_PERMISSION
Definition TER.h:313
Set the sequence number on a JTx.
Definition seq.h:16