1#include <test/app/lending/LoanTestBase.h>
2#include <test/jtx/Account.h>
3#include <test/jtx/Env.h>
4#include <test/jtx/JTx.h>
5#include <test/jtx/TestHelpers.h>
6#include <test/jtx/amount.h>
7#include <test/jtx/batch.h>
8#include <test/jtx/fee.h>
9#include <test/jtx/flags.h>
10#include <test/jtx/offer.h>
11#include <test/jtx/owners.h>
12#include <test/jtx/pay.h>
13#include <test/jtx/seq.h>
14#include <test/jtx/sig.h>
15#include <test/jtx/tags.h>
16#include <test/jtx/ter.h>
17#include <test/jtx/trust.h>
18#include <test/jtx/vault.h>
20#include <xrpl/basics/Number.h>
21#include <xrpl/basics/base_uint.h>
22#include <xrpl/basics/chrono.h>
23#include <xrpl/basics/strHex.h>
24#include <xrpl/beast/unit_test/suite.h>
25#include <xrpl/json/json_value.h>
26#include <xrpl/protocol/Feature.h>
27#include <xrpl/protocol/Indexes.h>
28#include <xrpl/protocol/Issue.h>
29#include <xrpl/protocol/Keylet.h>
30#include <xrpl/protocol/LedgerFormats.h>
31#include <xrpl/protocol/Protocol.h>
32#include <xrpl/protocol/SField.h>
33#include <xrpl/protocol/STAmount.h>
34#include <xrpl/protocol/SeqProxy.h>
35#include <xrpl/protocol/TER.h>
36#include <xrpl/protocol/TxFlags.h>
37#include <xrpl/protocol/Units.h>
55 Keylet const& brokerKeylet,
60 if (
auto const loanSle = env.
le(loanKeylet); BEAST_EXPECT(loanSle))
62 BEAST_EXPECT(loanSle->at(sfPrincipalOutstanding) == 0);
63 BEAST_EXPECT(loanSle->at(sfTotalValueOutstanding) == 0);
64 BEAST_EXPECT(loanSle->at(sfPaymentRemaining) == 0);
66 if (
auto const brokerSle = env.
le(brokerKeylet); BEAST_EXPECT(brokerSle))
67 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == 0);
68 if (
auto const vaultSle = env.
le(vaultKeylet); BEAST_EXPECT(vaultSle))
69 BEAST_EXPECT(vaultSle->at(sfAssetsAvailable) == depositValue);
90 set(account, brokerID, principal.
value()),
91 kCounterparty(counterparty.
id()),
92 kPaymentTotal(paymentTotal),
106 Vault const vault{env};
108 auto const seq = env.
seq(owner);
109 auto const balanceBefore = env.
balance(owner);
110 auto const ownerCountBefore = env.
ownerCount(owner);
115 auto const depositAmount =
XRP(1'000);
121 vault.deposit({.depositor = owner, .id = vaultKeylet.key, .amount = depositAmount}),
125 {.depositor = owner, .id = vaultKeylet.key, .amount = depositAmount}),
127 batch::Inner(vault.del({.owner = owner, .id = vaultKeylet.key}), seq + 4),
131 BEAST_EXPECT(!env.
le(vaultKeylet));
132 BEAST_EXPECT(env.
balance(owner) == balanceBefore - batchFee);
133 BEAST_EXPECT(env.
ownerCount(owner) == ownerCountBefore);
134 BEAST_EXPECT(env.
seq(owner) == seq + 5);
143 testcase(
"vault lifecycle in a batch");
147 Env env(*
this, features);
163 testcase(
"vault lifecycle in a batch, closed-ended vault, subscription phase");
167 Env env(*
this, features);
186 testcase(
"loan lifecycle in a batch, open-ended vault");
190 Env env(*
this, features);
192 Account const lender{
"lender"};
193 Account const borrower{
"borrower"};
194 env.
fund(
XRP(1'000'000), lender, borrower);
198 Vault const vault{env};
200 auto const lenderSeq = env.
seq(lender);
201 auto const borrowerSeq = env.
seq(borrower);
202 auto const lenderBalanceBefore = env.
balance(lender);
203 auto const borrowerBalanceBefore = env.
balance(borrower);
205 auto const depositAmount = asset(50'000);
206 auto const principal = asset(1'000);
209 auto const brokerKeylet =
213 auto const createTx = std::get<0>(vault.create({.owner = lender, .asset = xrpIssue()}));
218 auto const loanSetTx =
loanSetInner(env, lender, brokerKeylet.key, borrower, principal, 2);
219 auto const loanPayTx =
220 loan::pay(borrower, loanKeylet.key, principal.value(), tfLoanFullPayment);
223 env(
batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
227 {.depositor = lender, .id = vaultKeylet.key, .amount = depositAmount.value()}),
241 BEAST_EXPECT(env.
balance(borrower) == borrowerBalanceBefore);
242 BEAST_EXPECT(env.
balance(lender) == lenderBalanceBefore - batchFee - depositAmount.
value());
252 testcase(
"loan lifecycle in a batch, closed-ended vault");
256 Env env(*
this, features);
258 Account const lender{
"lender"};
259 Account const borrower{
"borrower"};
260 env.
fund(
XRP(1'000'000), lender, borrower);
264 Vault const vault{env};
266 auto const lenderSeq1 = env.
seq(lender);
267 auto const depositAmount = asset(50'000);
270 auto const brokerKeylet =
273 auto const created = vault.createClosedEnded(
275 auto const createTx = std::get<0>(created);
276 auto const subscriptionDate = std::get<2>(created);
282 env(
batch::outer(lender, lenderSeq1, batch1Fee, tfAllOrNothing),
286 {.depositor = lender, .id = vaultKeylet.key, .amount = depositAmount.value()}),
292 if (
auto const vaultSle = env.
le(vaultKeylet); BEAST_EXPECT(vaultSle))
293 BEAST_EXPECT(vaultSle->at(sfAssetsAvailable) == depositAmount.value());
294 BEAST_EXPECT(env.
le(brokerKeylet));
296 vault.closePastSubscription(subscriptionDate);
299 auto const principal = asset(1'000);
301 auto const lenderSeq2 = env.
seq(lender);
302 auto const borrowerSeq = env.
seq(borrower);
303 auto const lenderBalanceBefore = env.
balance(lender);
304 auto const borrowerBalanceBefore = env.
balance(borrower);
306 auto const loanSetTx =
loanSetInner(env, lender, brokerKeylet.key, borrower, principal, 2);
307 auto const loanPayTx =
308 loan::pay(borrower, loanKeylet.key, principal.value(), tfLoanFullPayment);
311 env(
batch::outer(lender, lenderSeq2, batch2Fee, tfAllOrNothing),
320 BEAST_EXPECT(env.
balance(borrower) == borrowerBalanceBefore);
323 BEAST_EXPECT(env.
balance(lender) == lenderBalanceBefore - batch2Fee);
347 Account const issuer{
"issuer"};
348 Account const lender{
"lender"};
349 Account const borrower{
"borrower"};
352 env.
fund(
XRP(1'000'000), issuer, lender, borrower, mm1, mm2);
353 env(
fset(issuer, asfDefaultRipple));
357 STAmount const iouLimit = iou(1'000'000'000);
358 env(
trust(lender, iouLimit));
359 env(
trust(borrower, iouLimit));
360 env(
trust(mm1, iouLimit));
361 env(
trust(mm2, iouLimit));
372 env(
pay(issuer, mm2, iou(20'000)));
377 env(
offer(mm1, iou(1'000),
XRP(400)));
384 .borrower = borrower,
397 testcase(
"arbitrage across a loan and two crossing offers in a batch");
401 Env env(*
this, features);
403 auto const& iou = setup.iou;
404 auto const& lender = setup.lender;
405 auto const& borrower = setup.borrower;
406 auto const& broker = setup.broker;
407 auto const& mm2 = setup.mm2;
410 auto const principal = iou(1'000);
412 BEAST_EXPECT(env.
balance(borrower, iou) == iou(0));
414 auto const borrowerSeq = env.
seq(borrower);
415 auto const mm2Seq = env.
seq(mm2);
417 auto const loanSetTx =
loanSetInner(env, borrower, broker.brokerID, lender, principal, 2);
418 auto const loanPayTx =
419 loan::pay(borrower, loanKeylet.key, principal.value(), tfLoanFullPayment);
422 env(
batch::outer(borrower, borrowerSeq, batchFee, tfAllOrNothing),
425 offer(borrower,
XRP(400), principal.value(), tfFillOrKill), borrowerSeq + 2),
428 offer(borrower, iou(1'008).value(),
XRP(400), tfFillOrKill), borrowerSeq + 3),
434 if (
auto const loanSle = env.
le(loanKeylet); BEAST_EXPECT(loanSle))
435 BEAST_EXPECT(loanSle->at(sfPrincipalOutstanding) == 0);
436 BEAST_EXPECT(env.
balance(borrower, iou) == iou(8));
439 if (
auto const brokerSle = env.
le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
440 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == 0);
441 if (
auto const vaultSle = env.
le(broker.vaultKeylet()); BEAST_EXPECT(vaultSle))
444 vaultSle->at(sfAssetsAvailable) == iou(broker.params.vaultDeposit).value());
456 testcase(
"arbitrage batch rolls back when the sell offer cannot fill");
460 Env env(*
this, features);
462 auto const& iou = setup.iou;
463 auto const& lender = setup.lender;
464 auto const& borrower = setup.borrower;
465 auto const& broker = setup.broker;
467 auto const brokerSleBefore = env.
le(broker.brokerKeylet());
468 auto const vaultSleBefore = env.
le(broker.vaultKeylet());
469 if (!BEAST_EXPECT(brokerSleBefore) || !BEAST_EXPECT(vaultSleBefore))
471 auto const loanSequenceBefore = brokerSleBefore->at(sfLoanSequence);
472 auto const assetsAvailableBefore = vaultSleBefore->at(sfAssetsAvailable);
475 auto const principal = iou(1'000);
477 auto const borrowerSeq = env.
seq(borrower);
478 auto const borrowerBalanceBefore = env.
balance(borrower);
480 auto const loanSetTx =
loanSetInner(env, borrower, broker.brokerID, lender, principal, 2);
481 auto const loanPayTx =
482 loan::pay(borrower, loanKeylet.key, principal.value(), tfLoanFullPayment);
485 env(
batch::outer(borrower, borrowerSeq, batchFee, tfAllOrNothing),
488 offer(borrower,
XRP(400), principal.value(), tfFillOrKill), borrowerSeq + 2),
490 offer(borrower, iou(1'008).value(),
XRP(400), tfFillOrKill), borrowerSeq + 3),
496 BEAST_EXPECT(!env.
le(loanKeylet));
497 if (
auto const brokerSle = env.
le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
499 BEAST_EXPECT(brokerSle->at(sfLoanSequence) == loanSequenceBefore);
500 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == 0);
502 BEAST_EXPECT(env.
balance(borrower, iou) == iou(0));
503 BEAST_EXPECT(env.
balance(borrower) == borrowerBalanceBefore - batchFee);
505 if (
auto const vaultSle = env.
le(broker.vaultKeylet()); BEAST_EXPECT(vaultSle))
506 BEAST_EXPECT(vaultSle->at(sfAssetsAvailable) == assetsAvailableBefore);
524 kCounterparty(borrower.
id()),
526 kPaymentInterval(86400),
528 Sig(sfCounterpartySignature, borrower),
541 testcase(
"loan impairment and cover deposit in a batch");
545 Env env(*
this, features);
547 Account const lender{
"lender"};
548 Account const borrower{
"borrower"};
549 env.
fund(
XRP(100'000'000), lender, borrower);
556 originateLoan(env, broker, lender, borrower, asset(1'000).value());
558 auto const loanSleBefore = env.
le(loanKeylet);
559 if (!BEAST_EXPECT(loanSleBefore))
565 env.
close(Tp{D{loanSleBefore->at(sfNextPaymentDueDate) + 1}});
567 auto const brokerSleBefore = env.
le(broker.brokerKeylet());
568 auto const vaultSleBefore = env.
le(broker.vaultKeylet());
569 if (!BEAST_EXPECT(brokerSleBefore) || !BEAST_EXPECT(vaultSleBefore))
571 auto const coverAvailableBefore = brokerSleBefore->at(sfCoverAvailable);
572 auto const lossUnrealizedBefore = vaultSleBefore->at(sfLossUnrealized);
573 auto const additionalCover = asset(500).value();
575 auto const lenderSeq = env.
seq(lender);
577 env(
batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
584 if (
auto const loanSle = env.
le(loanKeylet); BEAST_EXPECT(loanSle))
585 BEAST_EXPECT(loanSle->isFlag(lsfLoanImpaired));
588 if (
auto const vaultSle = env.
le(broker.vaultKeylet()); BEAST_EXPECT(vaultSle))
591 vaultSle->at(sfLossUnrealized) ==
592 lossUnrealizedBefore + loanSleBefore->at(sfPrincipalOutstanding));
594 if (
auto const brokerSle = env.
le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
595 BEAST_EXPECT(brokerSle->at(sfCoverAvailable) == coverAvailableBefore + additionalCover);
606 testcase(
"loan default and cover withdraw in a batch");
610 Env env(*
this, features);
612 Account const lender{
"lender"};
613 Account const borrower{
"borrower"};
614 env.
fund(
XRP(100'000'000), lender, borrower);
621 originateLoan(env, broker, lender, borrower, asset(1'000).value());
623 auto const loanSleBefore = env.
le(loanKeylet);
624 if (!BEAST_EXPECT(loanSleBefore))
629 auto const dueDate = loanSleBefore->at(sfNextPaymentDueDate);
630 auto const gracePeriod = loanSleBefore->at(sfGracePeriod);
633 env.
close(Tp{D{dueDate + gracePeriod + 1}});
635 auto const brokerSleBefore = env.
le(broker.brokerKeylet());
636 auto const vaultSleBefore = env.
le(broker.vaultKeylet());
637 if (!BEAST_EXPECT(brokerSleBefore) || !BEAST_EXPECT(vaultSleBefore))
640 auto const coverAvailableBefore = brokerSleBefore->at(sfCoverAvailable);
641 auto const assetsAvailableBefore = vaultSleBefore->at(sfAssetsAvailable);
642 auto const assetsTotalBefore = vaultSleBefore->at(sfAssetsTotal);
644 TenthBips32 const coverRateMin{brokerSleBefore->at(sfCoverRateMinimum)};
645 TenthBips32 const coverRateLiquidation{brokerSleBefore->at(sfCoverRateLiquidation)};
646 Number const totalDefaultAmount{loanSleBefore->at(sfPrincipalOutstanding)};
656 auto const minimumCover =
663 loanSleBefore->at(sfLoanScale)),
664 Number{coverAvailableBefore});
666 auto const vaultDefaultAmount = totalDefaultAmount - defaultCovered;
668 auto const lenderSeq = env.
seq(lender);
669 auto const lenderBalanceBefore = env.
balance(lender);
670 auto const withdrawAmount =
STAmount{asset.
raw(), coverAvailableBefore - defaultCovered};
673 env(
batch::outer(lender, lenderSeq, batchFee, tfAllOrNothing),
680 if (
auto const loanSle = env.
le(loanKeylet); BEAST_EXPECT(loanSle))
682 BEAST_EXPECT(loanSle->isFlag(lsfLoanDefault));
683 BEAST_EXPECT(loanSle->at(sfPrincipalOutstanding) == 0);
685 if (
auto const brokerSle = env.
le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
687 BEAST_EXPECT(brokerSle->at(sfCoverAvailable) == 0);
688 BEAST_EXPECT(brokerSle->at(sfDebtTotal) == 0);
690 BEAST_EXPECT(env.
balance(lender) == lenderBalanceBefore - batchFee + withdrawAmount);
694 if (
auto const vaultSle = env.
le(broker.vaultKeylet()); BEAST_EXPECT(vaultSle))
696 BEAST_EXPECT(vaultSle->at(sfAssetsAvailable) == assetsAvailableBefore + defaultCovered);
697 BEAST_EXPECT(vaultSle->at(sfAssetsTotal) == assetsTotalBefore - vaultDefaultAmount);
709 testcase(
"independent batch runs every inner despite failing inners");
713 Env env(*
this, features);
719 Vault const vault{env};
721 auto const seq = env.
seq(owner);
723 auto const createTx = std::get<0>(vault.create({.owner = owner, .asset = xrpIssue()}));
724 auto const amount =
XRP(1'000);
727 auto const batchTx = env.
jt(
731 vault.withdraw({.depositor = owner, .id = vaultKeylet.key, .amount = amount}),
734 vault.deposit({.depositor = owner, .id = vaultKeylet.key, .amount = amount}),
736 batch::Inner(vault.del({.owner = owner, .id = vaultKeylet.key}), seq + 4));
740 auto const batchID =
strHex(batchTx.stx->getTransactionID());
741 auto const& innerIDs = batchTx.stx->getBatchTransactionIDs();
742 if (!BEAST_EXPECT(innerIDs.size() == 4))
746 env, batchID,
strHex(innerIDs[1]),
"VaultWithdraw",
"tecPRECISION_LOSS");
749 env, batchID,
strHex(innerIDs[3]),
"VaultDelete",
"tecHAS_OBLIGATIONS");
751 if (
auto const vaultSle = env.
le(vaultKeylet); BEAST_EXPECT(vaultSle))
752 BEAST_EXPECT(vaultSle->at(sfAssetsTotal) == amount.value());
753 BEAST_EXPECT(env.
seq(owner) == seq + 5);
764 testcase(
"independent batch runs every loan inner despite a failing payment");
768 Env env(*
this, features);
770 Account const issuer{
"issuer"};
771 Account const lender{
"lender"};
772 Account const borrower{
"borrower"};
773 env.
fund(
XRP(1'000'000), issuer, lender, borrower);
774 env(
fset(issuer, asfDefaultRipple));
778 STAmount const iouLimit = iou(1'000'000'000);
779 env(
trust(lender, iouLimit));
780 env(
trust(borrower, iouLimit));
783 env(
pay(issuer, lender, iou(2'000'000)));
789 auto const principal = iou(1'000);
790 auto const brokerSleBefore = env.
le(broker.brokerKeylet());
791 if (!BEAST_EXPECT(brokerSleBefore))
793 auto const coverAvailableBefore = brokerSleBefore->at(sfCoverAvailable);
795 auto const lenderSeq = env.
seq(lender);
796 auto const borrowerSeq = env.
seq(borrower);
798 auto const loanSetTx =
loanSetInner(env, lender, broker.brokerID, borrower, principal, 2);
799 auto const loanPayTx =
800 loan::pay(borrower, loanKeylet.key, iou(2'000).value(), tfLoanFullPayment);
801 auto const additionalCover = iou(500);
804 auto const batchTx = env.
jt(
805 batch::outer(lender, lenderSeq, batchFee, tfIndependent),
814 auto const batchID =
strHex(batchTx.stx->getTransactionID());
815 auto const& innerIDs = batchTx.stx->getBatchTransactionIDs();
816 if (!BEAST_EXPECT(innerIDs.size() == 3))
820 env, batchID,
strHex(innerIDs[1]),
"LoanPay",
"tecINSUFFICIENT_FUNDS");
822 env, batchID,
strHex(innerIDs[2]),
"LoanBrokerCoverDeposit",
"tesSUCCESS");
824 if (
auto const loanSle = env.
le(loanKeylet); BEAST_EXPECT(loanSle))
825 BEAST_EXPECT(loanSle->at(sfPrincipalOutstanding) == principal.value());
826 if (
auto const brokerSle = env.
le(broker.brokerKeylet()); BEAST_EXPECT(brokerSle))
829 brokerSle->at(sfCoverAvailable) == coverAvailableBefore + additionalCover.value());
839 for (
auto const& features : {lendingBatch, lendingBatch | featureLendingProtocolV1_1})
TestcaseT testcase
Memberspace for declaring test cases.
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
Number is a floating point type that can represent a wide range of values.
STAmount const & value() const noexcept
static constexpr SeqProxy rawSequence(std::uint32_t v)
Factory function to return a sequence-based SeqProxy.
void testLoanLifecycleClosedEndedVault(FeatureBitset features)
void testVaultLifecycle(FeatureBitset features)
void assertLoanFullyRepaid(jtx::Env const &env, Keylet const &brokerKeylet, Keylet const &vaultKeylet, Keylet const &loanKeylet, STAmount const &depositValue)
void testLoanLifecycleOpenEndedVault(FeatureBitset features)
void testArbitrage(FeatureBitset features)
ArbitrageSetup setupArbitrage(jtx::Env &env)
void testIndependentLoanChain(FeatureBitset features)
void run() override
Runs the suite.
void testIndependentVaultChain(FeatureBitset features)
static void originateLoan(jtx::Env &env, BrokerInfo const &broker, jtx::Account const &lender, jtx::Account const &borrower, STAmount const &principal)
void testImpairAndCoverDeposit(FeatureBitset features)
void testClosedEndedVaultLifecycle(FeatureBitset features)
void testArbitrageRollback(FeatureBitset features)
void testDefaultAndCoverWithdraw(FeatureBitset features)
void runVaultLifecycleBatch(jtx::Env &env, jtx::Account const &owner, json::Value const &createTx)
static json::Value loanSetInner(jtx::Env &env, jtx::Account const &account, uint256 const &brokerID, jtx::Account const &counterparty, STAmount const &principal, std::uint32_t paymentTotal)
Shared base for the Loan*_test family under src/test/app/lending/.
BrokerInfo createVaultAndBroker(jtx::Env &env, jtx::PrettyAsset const &asset, jtx::Account const &lender, BrokerParameters const ¶ms=BrokerParameters::defaults())
Keylet nextLoanKeylet(jtx::Env const &env, BrokerInfo const &broker)
std::string const iouCurrency_
Immutable cryptographic account descriptor.
AccountID id() const
Returns the Account ID.
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
json::Value json(JsonValue &&jv, FN const &... fN)
Create JSON from parameters.
SLE::const_pointer le(Account const &account) const
Return an account root.
std::uint32_t ownerCount(Account const &account) const
Return the number of objects owned by an account.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
std::uint32_t seq(Account const &account) const
Returns the next sequence number on account.
JTx jt(JsonValue &&jv, FN const &... fN)
Create a JTx from parameters.
PrettyAmount balance(Account const &account) const
Returns the XRP balance on an account.
void require(Args const &... args)
Check a set of requirements.
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Set the regular signature on a JTx.
Set the expected result code for a JTx The test will fail if the code doesn't match.
Adds an inner Batch transaction to a JTx and autofills it.
Sets the Batch transaction signers on a JTx.
Keylet vault(AccountID const &owner, SeqProxy const &seq) noexcept
Keylet loanBroker(AccountID const &owner, SeqProxy const &seq) noexcept
Keylet loan(UInt256 const &loanBrokerID, SeqProxy const &loanSeq) noexcept
void validateInnerTxn(Env &env, std::string const &batchID, std::string const &txHash, std::string const &txType, std::string const &result, std::source_location const &loc=std::source_location::current())
Expect an inner Batch transaction to be recorded with the given type and result, and with ParentBatch...
json::Value outer(jtx::Account const &account, uint32_t seq, STAmount const &fee, std::uint32_t flags)
Build an outer Batch transaction JSON object.
XRPAmount calcBatchFee(jtx::Env const &env, uint32_t const &numSigners, uint32_t const &txns=0)
Calculate the expected outer Batch transaction fee.
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 manage(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 pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
XrpT const XRP
Converts to XRP Issue or STAmount.
OwnerCount< ltOFFER > Offers
Match the number of offers in the account's owner directory.
json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
BEAST_DEFINE_TESTSUITE(AMMClawback, app, xrpl)
STTx createTx(bool disabling, LedgerIndex seq, PublicKey const &txKey)
Create ttUNL_MODIFY Tx.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool set(T &target, std::string const &name, Section const §ion)
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.
std::string strHex(FwdIt begin, FwdIt end)
constexpr T tenthBipsOfValue(T value, TenthBips< TBips > bips)
TenthBips< std::uint32_t > TenthBips32
void roundToAsset(A const &asset, Number &value)
Round an arbitrary precision Number IN PLACE to the precision of a given Asset.
A pair of SHAMap key and LedgerEntryType.
TenthBips32 coverRateLiquidation
STAmount const & value() const
Asset const & raw() const
Set the sequence number on a JTx.
std::tuple< json::Value, Keylet > create(CreateArgs const &args) const
Return a VaultCreate transaction and the Vault's expected keylet.
std::tuple< json::Value, Keylet, NetClock::time_point > createClosedEnded(CreateClosedEndedArgs const &args) const
Return a VaultCreate transaction for a closed-ended vault, its expected keylet, and the vault's Subsc...