diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp index 9de281f4a6..0a8123e110 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerDelete.cpp @@ -184,6 +184,10 @@ LoanBrokerDelete::doApply() return tecHAS_OBLIGATIONS; // LCOV_EXCL_LINE } + view().erase(brokerPseudoSLE); + + view().erase(broker); + { auto owner = view().peek(keylet::account(accountID_)); if (!owner) @@ -192,14 +196,9 @@ LoanBrokerDelete::doApply() // Decreases the owner count by two: one for the LoanBroker object, and // one for the pseudo-account. // LoanBroker object can be sponsored - adjustOwnerCountObj(view(), owner, broker, -1, j_); - - // pseudo-account cannot be sponsored - adjustOwnerCount(view(), owner, {}, -1, j_); + adjustOwnerCount(view(), owner, {}, -2, j_); } - view().erase(brokerPseudoSLE); - view().erase(broker); associateAsset(*broker, vaultAsset); return tesSUCCESS; diff --git a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp index 826ff7f6fa..6509eb0ec0 100644 --- a/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanBrokerSet.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -237,29 +236,11 @@ LoanBrokerSet::doApply() if (auto const ter = dirLink(view, vaultPseudoID, broker, sfVaultNode)) return ter; // LCOV_EXCL_LINE - auto const sponsorSle = getTxReserveSponsor(view, tx); - if (!sponsorSle) - return sponsorSle.error(); // LCOV_EXCL_LINE - - if (auto const ret = checkInsufficientReserve( - view, tx, owner, preFeeBalance_, {}, *sponsorSle ? 1 : 2, 0, j_); - !isTesSuccess(ret)) - return ret; - - if (*sponsorSle) - { - if (auto const ret = checkInsufficientReserve( - view, tx, owner, preFeeBalance_, *sponsorSle, 1, 0, j_); - !isTesSuccess(ret)) - return ret; - } - // Increases the owner count by two: one for the LoanBroker object, and // one for the pseudo-account. - // Pseudo-account cannot be sponsored - adjustOwnerCount(view, owner, {}, 1, j_); - // LoanBroker object can be sponsored - adjustOwnerCount(view, owner, *sponsorSle, 1, j_); + adjustOwnerCount(view, owner, {}, 2, j_); + if (preFeeBalance_ < accountReserve(view, owner, j_)) + return tecINSUFFICIENT_RESERVE; auto maybePseudo = createPseudoAccount(view, broker->key(), sfLoanBrokerID); if (!maybePseudo) @@ -289,8 +270,6 @@ LoanBrokerSet::doApply() if (auto const coverLiq = tx[~sfCoverRateLiquidation]) broker->at(sfCoverRateLiquidation) = *coverLiq; - addSponsorToLedgerEntry(broker, *sponsorSle); - view.insert(broker); associateAsset(*broker, vaultAsset); diff --git a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp index bc2842fbb3..37ecc04b09 100644 --- a/src/libxrpl/tx/transactors/lending/LoanDelete.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanDelete.cpp @@ -103,6 +103,9 @@ LoanDelete::doApply() if (!view.dirRemove(keylet::ownerDir(borrower), loanSle->at(sfOwnerNode), loanID, false)) return tefBAD_LEDGER; // LCOV_EXCL_LINE + // Delete the Loan object + view.erase(loanSle); + // Decrement the LoanBroker's owner count. // The broker's owner count is solely for the number of outstanding loans, // and is distinct from the broker's pseudo-account's owner count @@ -127,10 +130,7 @@ LoanDelete::doApply() } } // Decrement the borrower's owner count - adjustOwnerCountObj(view, borrowerSle, loanSle, -1, j_); - - // Delete the Loan object - view.erase(loanSle); + adjustOwnerCount(view, borrowerSle, {}, -1, j_); // These associations shouldn't do anything, but do them just to be safe associateAsset(*loanSle, vaultAsset); diff --git a/src/libxrpl/tx/transactors/lending/LoanSet.cpp b/src/libxrpl/tx/transactors/lending/LoanSet.cpp index 59a762206b..6899f2b650 100644 --- a/src/libxrpl/tx/transactors/lending/LoanSet.cpp +++ b/src/libxrpl/tx/transactors/lending/LoanSet.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -513,18 +512,14 @@ LoanSet::doApply() } } - auto const sponsorSle = getTxReserveSponsor(view, tx); - if (!sponsorSle) - return sponsorSle.error(); // LCOV_EXCL_LINE + adjustOwnerCount(view, borrowerSle, {}, 1, j_); + { auto const balance = accountID_ == borrower ? preFeeBalance_ : borrowerSle->at(sfBalance).value().xrp(); - if (auto const ret = - checkInsufficientReserve(view, tx, borrowerSle, balance, *sponsorSle, 1, 0, j_); - !isTesSuccess(ret)) - return ret; + if (balance < accountReserve(view, borrowerSle, j_)) + return tecINSUFFICIENT_RESERVE; } - adjustOwnerCount(view, borrowerSle, *sponsorSle, 1, j_); // Account for the origination fee using two payments // @@ -624,7 +619,6 @@ LoanSet::doApply() loan->at(sfPreviousPaymentDueDate) = 0; loan->at(sfNextPaymentDueDate) = startDate + paymentInterval; loan->at(sfPaymentRemaining) = paymentTotal; - addSponsorToLedgerEntry(loan, *sponsorSle); view.insert(loan); // Update the balances in the vault diff --git a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp index 7e4a8a8156..711bf275d7 100644 --- a/src/libxrpl/tx/transactors/vault/VaultCreate.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultCreate.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -157,28 +156,9 @@ VaultCreate::doApply() if (auto ter = dirLink(view(), accountID_, vault)) return ter; // We will create Vault and PseudoAccount, hence increase OwnerCount by 2 - auto const sponsorSle = getTxReserveSponsor(view(), tx); - if (!sponsorSle) - return sponsorSle.error(); // LCOV_EXCL_LINE - if (!ctx_.view().rules().enabled(featureSponsor)) - { - adjustOwnerCount(view(), owner, *sponsorSle, 2, j_); - addSponsorToLedgerEntry(vault, *sponsorSle); - if (auto const ret = - checkInsufficientReserve(view(), tx, owner, preFeeBalance_, *sponsorSle, 0, 0, j_); - !isTesSuccess(ret)) - return ret; - } - else - { - // after Sponsor Amendment, check insufficient reserve first - if (auto const ret = - checkInsufficientReserve(view(), tx, owner, preFeeBalance_, *sponsorSle, 2, 0, j_); - !isTesSuccess(ret)) - return ret; - adjustOwnerCount(view(), owner, *sponsorSle, 2, j_); - addSponsorToLedgerEntry(vault, *sponsorSle); - } + adjustOwnerCount(view(), owner, {}, 2, j_); + if (preFeeBalance_ < accountReserve(view(), owner, j_)) + return tecINSUFFICIENT_RESERVE; auto maybePseudo = createPseudoAccount(view(), vault->key(), sfVaultID); if (!maybePseudo) diff --git a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp index 3ccb9498c7..8df8e73f12 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDelete.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDelete.cpp @@ -204,7 +204,7 @@ VaultDelete::doApply() } // We are destroying Vault and PseudoAccount, hence decrease by 2 - adjustOwnerCountObj(view(), owner, vault, -2, j_); + adjustOwnerCount(view(), owner, {}, -2, j_); // Destroy the vault. view().erase(vault); diff --git a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp index 9707a923fc..89205266c2 100644 --- a/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultDeposit.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -343,19 +342,9 @@ VaultDeposit::doApply() } } - auto const sponsorSle = getTxReserveSponsor(view(), ctx_.tx); - if (!sponsorSle) - return sponsorSle.error(); // LCOV_EXCL_LINE - // Transfer shares from vault to depositor. if (auto const ter = accountSend( - view(), - vaultAccount, - accountID_, - sharesCreated, - j_, - *sponsorSle, - WaiveTransferFee::Yes); + view(), vaultAccount, accountID_, sharesCreated, j_, {}, WaiveTransferFee::Yes); !isTesSuccess(ter)) return ter; diff --git a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp index 59f0ce0a2c..4ac7e57a6d 100644 --- a/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp +++ b/src/libxrpl/tx/transactors/vault/VaultWithdraw.cpp @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -326,19 +325,10 @@ VaultWithdraw::doApply() view().update(vault); auto const& vaultAccount = vault->at(sfAccount); - auto const sponsorSle = getTxReserveSponsor(view(), ctx_.tx); - if (!sponsorSle) - return sponsorSle.error(); // LCOV_EXCL_LINE // Transfer shares from depositor to vault. if (auto const ter = accountSend( - view(), - accountID_, - vaultAccount, - sharesRedeemed, - j_, - *sponsorSle, - WaiveTransferFee::Yes); + view(), accountID_, vaultAccount, sharesRedeemed, j_, {}, WaiveTransferFee::Yes); !isTesSuccess(ter)) return ter; diff --git a/src/test/app/Sponsor_test.cpp b/src/test/app/Sponsor_test.cpp index ae11ec8caf..eac249209f 100644 --- a/src/test/app/Sponsor_test.cpp +++ b/src/test/app/Sponsor_test.cpp @@ -3848,584 +3848,6 @@ public: } } - void - testVault(bool cosigning) - { - testcase("Vault"); - using namespace test::jtx; - Account const alice("alice"); - Account const bob("bob"); - Account const gw("gw"); - Account const sponsor("sponsor"); - Account const sponsor2("sponsor2"); - - Asset asset = gw["IOU"].asset(); - - // VaultCreate - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, gw, sponsor); - env.close(); - - Vault const vault{env}; - auto [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - - env(ticket::create(sponsor, 2)); - env.close(); - - testEachSponsorship( - env, - cosigning, - sponsor, - alice, - 3, // Vault, PseudoAccount, MPToken(Share Token) - 3, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { - auto result = vault.create({.owner = alice, .asset = asset}); - submit(std::get<0>(result)); - keylet = std::get<1>(result); - }); - BEAST_EXPECT(env.le(keylet)->getAccountID(sfSponsor) == sponsor.id()); - } - // VaultDeposit - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, gw, sponsor); - env.close(); - - Vault const vault{env}; - auto [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - env(tx); - env.close(); - - env(trust(bob, asset(1000))); - env.close(); - env(pay(gw, bob, asset(1000))); - env.close(); - - BEAST_EXPECT(ownerCount(env, bob) == 1); // RippleState - - auto const depositTx = - vault.deposit({.depositor = bob, .id = keylet.key, .amount = asset(100)}); - - env(ticket::create(sponsor, 2)); // for free MPToken - env.close(); - - testEachSponsorship( - env, - cosigning, - sponsor, - bob, - 1, - 1, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { submit(depositTx); }); - } - // VaultWithdraw - { - // RippleState Vault - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, gw, sponsor); - env.close(); - - Vault const vault{env}; - auto [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - env(tx); - env.close(); - - env(trust(bob, asset(100))); - env.close(); - env(pay(gw, bob, asset(100))); - env.close(); - - auto const depositTx = - vault.deposit({.depositor = bob, .id = keylet.key, .amount = asset(100)}); - - env(ticket::create(sponsor, 2)); // for free MPToken - env.close(); - - testEachSponsorship( - env, - cosigning, - sponsor, - bob, - 1, - 1, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { submit(depositTx); }); - - env(trust(bob, asset(0))); // remove trustline - env.close(); - - BEAST_EXPECT(ownerCount(env, bob) == 1); // MPToken(share) - BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1); // MPToken(share) - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); // MPToken(share) - - // create Trustline with vault withdraw - testEachSponsorship( - env, - cosigning, - sponsor, - bob, - 1, - 1, - tecNO_LINE_INSUF_RESERVE, - [&](Env& env, auto const& submit) { - submit(vault.withdraw( - {.depositor = bob, .id = keylet.key, .amount = asset(50)})); - }); - - BEAST_EXPECT(ownerCount(env, bob) == 2); // RippleState, MPToken(share) - BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 2); // RippleState, MPToken(share) - BEAST_EXPECT( - sponsoringOwnerCount(env, sponsor) == 2); // RippleState, MPToken(share) - - // remove sponsored MPToken(share) - env(vault.withdraw({.depositor = bob, .id = keylet.key, .amount = asset(50)})); - env.close(); - - BEAST_EXPECT(ownerCount(env, bob) == 1); // RippleState - BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1); // RippleState - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); // RippleState - } - // MPToken Vault - { - // VaultWithdraw doesn't create MPToken for depositor - } - } - // VaultClawback - { - // remove sponsored shares MPToken - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, gw, sponsor); - env.close(); - - env(fset(gw, asfAllowTrustLineClawback)); - env.close(); - - Vault const vault{env}; - auto [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - env(tx); - env.close(); - - env(trust(bob, asset(100))); - env.close(); - env(pay(gw, bob, asset(100))); - env.close(); - - auto const depositTx = - vault.deposit({.depositor = bob, .id = keylet.key, .amount = asset(100)}); - - env(ticket::create(sponsor, 2)); // for free MPToken - env.close(); - - testEachSponsorship( - env, - cosigning, - sponsor, - bob, - 1, - 1, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { submit(depositTx); }); - - BEAST_EXPECT(ownerCount(env, bob) == 2); // RippleState, MPToken(share) - BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 1); // MPToken(share) - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); // MPToken(share) - - env(vault.clawback({.issuer = gw, .id = keylet.key, .holder = bob, .amount = asset(0)}), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - - BEAST_EXPECT(ownerCount(env, bob) == 1); // RippleState - BEAST_EXPECT(sponsoredOwnerCount(env, bob) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - } - // VaultDelete - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, gw, sponsor); - env.close(); - - env(fset(gw, asfAllowTrustLineClawback)); - env.close(); - - Vault const vault{env}; - auto [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - env(tx, sponsor::As(sponsor, spfSponsorReserve), Sig(sfSponsorSignature, sponsor)); - env.close(); - - BEAST_EXPECT(ownerCount(env, alice) == 3); // Vault, PseudoAccount, MPToken(share) - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 3); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 3); - - env(vault.del({.owner = alice, .id = keylet.key})); - env.close(); - - BEAST_EXPECT(ownerCount(env, alice) == 0); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - } - // SponsorshipTransfer - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, gw, sponsor); - env.close(); - - Vault const vault{env}; - auto const [tx, vaultKeylet] = vault.create({.owner = alice, .asset = asset}); - env(tx); - env.close(); - - // Alice owns the vault, pseudo account and MPToken - BEAST_EXPECT(ownerCount(env, alice) == 3); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - - if (cosigning) - { - // Alice lets sponsor to sponsor her Vault - env(sponsor::transfer(alice, tfSponsorshipCreate, vaultKeylet.key), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - } - else - { - // Create sponsorship with reserve count being 2 (for vault and pseudo account) - env(sponsor::set_reserve(sponsor, 0, 2), sponsor::SponseeAcc(alice)); - env.close(); - env(sponsor::transfer(alice, tfSponsorshipCreate, vaultKeylet.key), - sponsor::As(sponsor, spfSponsorReserve)); - env.close(); - - auto const sponsorshipSle = env.le(keylet::sponsorship(sponsor, alice)); - if (!BEAST_EXPECT(sponsorshipSle)) - return; - BEAST_EXPECT(sponsorshipSle->getFieldU32(sfRemainingOwnerCount) == 0); - } - - BEAST_EXPECT(env.le(vaultKeylet)->getAccountID(sfSponsor) == sponsor.id()); - BEAST_EXPECT(ownerCount(env, alice) == 3); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 2); - // Vault counts for 2 reserves, vault and the pseudo account - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 2); - - // End sponsorship - env(sponsor::transfer(alice, tfSponsorshipEnd, vaultKeylet.key)); - env.close(); - - BEAST_EXPECT(!env.le(vaultKeylet)->isFieldPresent(sfSponsor)); - BEAST_EXPECT(ownerCount(env, alice) == 3); - // Sponsorship ended and the sponsored owner count should be 0. - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - } - } - - void - testLending(bool cosigning) - { - testcase("Lending"); - using namespace test::jtx; - Account const alice("alice"); - Account const bob("bob"); - Account const issuer("issuer"); - Account const sponsor("sponsor"); - Account const sponsor2("sponsor2"); - - // LoanBrokerSet / LoanBrokerDelete - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, sponsor, sponsor2); - env.close(); - - PrettyAsset const asset{xrpIssue(), 1'000'000}; - - Vault const vault{env}; - auto const [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - env(tx); - env.close(); - - BEAST_EXPECT( - ownerCount(env, alice) == 3); // Vault, PseudoAccount(Vault), MPToken(Vault) - - // LoanBrokerSet - testEachSponsorship( - // Both the Pseudo-account and LoanBroker objects are created, but only the - // LoanBroker is sponsored. - env, - cosigning, - sponsor, - alice, - 2, - 1, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { - submit(loanBroker::set(alice, keylet.key, 0)); - }); - - BEAST_EXPECT( - ownerCount(env, alice) == - 5); // LoanBroker, PseudoAccount(LB), (Vault, PseudoAccount(Vault), MPToken(Vault)) - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); - - auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice) - 1); - - if (cosigning) - { - // transfer sponsor - env(sponsor::transfer(alice, tfSponsorshipReassign, brokerKeylet.key), - sponsor::As(sponsor2, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor2)); - env.close(); - } - else - { - env(sponsor::set_reserve(sponsor2, 0, 1), sponsor::SponseeAcc(alice)); - env.close(); - - // transfer sponsor - env(sponsor::transfer(alice, tfSponsorshipReassign, brokerKeylet.key), - sponsor::As(sponsor2, spfSponsorReserve)); - env.close(); - } - - BEAST_EXPECT( - ownerCount(env, alice) == - 5); // LoanBroker, PseudoAccount(LB), (Vault, PseudoAccount(Vault), MPToken(Vault)) - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1); - - // LoanBrokerDelete - env(loanBroker::del(alice, brokerKeylet.key, 0)); - env.close(); - - BEAST_EXPECT(ownerCount(env, alice) == 3); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 0); - } - - // LoanBrokerConverDeposit/Withdraw/Clawback - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000), alice, bob, issuer, sponsor); - env.close(); - - MPTTester mptt{env, issuer, kMptInitNoFund}; - mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); - env.close(); - PrettyAsset const asset = mptt["MPT"]; - mptt.authorize({.account = alice}); - env.close(); - - env(pay(issuer, alice, asset(100))); - env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 1); - - Vault const vault{env}; - auto const [tx, keylet] = vault.create({.owner = alice, .asset = asset}); - env(tx); - env.close(); - - env(loanBroker::set(alice, keylet.key, 0)); - env.close(); - BEAST_EXPECT( - ownerCount(env, alice) == - 6); // LoanBroker, PseudoAccount(LB), (Vault, PseudoAccount(Vault), - // MPToken(Vault), MPToken(issuer)) - - auto const brokerKeylet = keylet::loanbroker(alice.id(), env.seq(alice) - 1); - // LoanBrokerCoverDeposit - // doesn't sponsor anything - env(loanBroker::coverDeposit(alice, brokerKeylet.key, asset(100)), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 6); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - - // remove MPToken(issuer) - mptt.authorize({.account = alice, .flags = tfMPTUnauthorize}); - env.close(); - BEAST_EXPECT(ownerCount(env, alice) == 5); - - env(ticket::create(sponsor, 2)); // for avoid free MPToken - env.close(); - - // LoanBrokerCoverWithdraw - testEachSponsorship( - env, - cosigning, - sponsor, - alice, - 1, - 1, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { - submit(loanBroker::coverWithdraw(alice, brokerKeylet.key, asset(10))); - }); - - BEAST_EXPECT(ownerCount(env, alice) == 6); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); - - // LoanBrokerCoverClawback - // doesn't sponsor anything - env(loanBroker::coverClawback(issuer), - loanBroker::kLoanBrokerId(brokerKeylet.key), - kAmount(asset(1)), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - - BEAST_EXPECT(ownerCount(env, alice) == 6); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); - } - // LoanSet - { - Env env{*this, testableAmendments()}; - env.fund(XRP(1000000), alice, bob, issuer, sponsor, sponsor2); - env.close(); - - MPTTester mptt{env, issuer, kMptInitNoFund}; - mptt.create({.flags = tfMPTCanClawback | tfMPTCanTransfer | tfMPTCanLock}); - env.close(); - PrettyAsset const asset = mptt["MPT"]; - mptt.authorize({.account = alice}); - mptt.authorize({.account = bob}); - env.close(); - - env(pay(issuer, alice, asset(1000))); - env(pay(issuer, bob, asset(1000))); - env.close(); - - Vault const vault{env}; - auto const [tx, keylet] = vault.create({.owner = bob, .asset = asset}); - env(tx); - env.close(); - env(vault.deposit({.depositor = bob, .id = keylet.key, .amount = asset(100)})); - env.close(); - - auto const brokerKeylet = keylet::loanbroker(bob.id(), env.seq(bob)); - env(loanBroker::set(bob, keylet.key, 0)); - env.close(); - env(loanBroker::coverDeposit(bob, brokerKeylet.key, asset(100))); - env.close(); - - auto broker = env.le(brokerKeylet); - BEAST_EXPECT(broker->getFieldU32(sfOwnerCount) == 0); - BEAST_EXPECT(!broker->isFieldPresent(sfSponsoredOwnerCount)); - BEAST_EXPECT(!broker->isFieldPresent(sfSponsoringOwnerCount)); - - auto const loanSeq = broker->getFieldU32(sfLoanSequence); - testEachSponsorship( - env, - cosigning, - sponsor, - alice, - 1, - 1, - tecINSUFFICIENT_RESERVE, - [&](Env& env, auto const& submit) { - submit( - loan::set(alice, brokerKeylet.key, 10), - Sig(sfCounterpartySignature, bob), - Fee(XRP(1))); - }); - broker = env.le(brokerKeylet); - // broker'object doesn't sponsored - BEAST_EXPECT(broker->getFieldU32(sfOwnerCount) == 1); - BEAST_EXPECT(!broker->isFieldPresent(sfSponsoredOwnerCount)); - BEAST_EXPECT(!broker->isFieldPresent(sfSponsoringOwnerCount)); - - auto const loanKeylet = keylet::loan(brokerKeylet.key, loanSeq); - - auto sponsorSle = env.le(keylet::account(sponsor)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfOwnerCount) == 0); - BEAST_EXPECT(!sponsorSle->isFieldPresent(sfSponsoredOwnerCount)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfSponsoringOwnerCount) == 1); - - // LoanManage - env(loan::manage(bob, loanKeylet.key, lsfLoanImpaired), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - - // doesn't sponsor anything - sponsorSle = env.le(keylet::account(sponsor)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfOwnerCount) == 0); - BEAST_EXPECT(!sponsorSle->isFieldPresent(sfSponsoredOwnerCount)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfSponsoringOwnerCount) == 1); - - // LoanPay - env(loan::pay(alice, loanKeylet.key, asset(10)), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - - // doesn't sponsor anything - sponsorSle = env.le(keylet::account(sponsor)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfOwnerCount) == 0); - BEAST_EXPECT(!sponsorSle->isFieldPresent(sfSponsoredOwnerCount)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfSponsoringOwnerCount) == 1); - - BEAST_EXPECT(ownerCount(env, alice) == 2); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - - // before transfer - BEAST_EXPECT(ownerCount(env, alice) == 2); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 1); - - if (cosigning) - { - // transfer sponsor - env(sponsor::transfer(alice, tfSponsorshipReassign, loanKeylet.key), - sponsor::As(sponsor2, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor2)); - env.close(); - } - else - { - env(sponsor::set_reserve(sponsor2, 0, 1), sponsor::SponseeAcc(alice)); - env.close(); - - // transfer sponsor - env(sponsor::transfer(alice, tfSponsorshipReassign, loanKeylet.key), - sponsor::As(sponsor2, spfSponsorReserve)); - env.close(); - } - - // after transfer - BEAST_EXPECT(ownerCount(env, alice) == 2); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 1); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor) == 0); - BEAST_EXPECT(sponsoringOwnerCount(env, sponsor2) == 1); - - // LoanDelete - env(loan::del(alice, loanKeylet.key), - sponsor::As(sponsor, spfSponsorReserve), - Sig(sfSponsorSignature, sponsor)); - env.close(); - - // Sponsored ltLoan is deleted - BEAST_EXPECT(ownerCount(env, alice) == 1); - BEAST_EXPECT(sponsoredOwnerCount(env, alice) == 0); - // Sponsor for ltLoan object is deleted - sponsorSle = env.le(keylet::account(sponsor)); - BEAST_EXPECT(sponsorSle->getFieldU32(sfOwnerCount) == 0); - BEAST_EXPECT(!sponsorSle->isFieldPresent(sfSponsoredOwnerCount)); - } - } - void testAccountDelete() { @@ -4963,8 +4385,6 @@ public: testPayChan(cosigning); testSignerList(cosigning); testTrustSet(cosigning); - testVault(cosigning); - testLending(cosigning); } protected: