From 853c42fb9e53ce1b92efaad3aac82db5fe4f5ea1 Mon Sep 17 00:00:00 2001 From: Ed Hennis Date: Thu, 10 Apr 2025 19:25:29 -0400 Subject: [PATCH] Initial implementation of LoanBrokerDelete - Completely untested --- src/xrpld/app/tx/detail/InvariantCheck.cpp | 14 +- src/xrpld/app/tx/detail/LoanBrokerDelete.cpp | 150 +++++++++++++++++++ src/xrpld/app/tx/detail/LoanBrokerDelete.h | 56 +++++++ src/xrpld/app/tx/detail/LoanBrokerSet.cpp | 1 - src/xrpld/app/tx/detail/LoanBrokerSet.h | 4 +- src/xrpld/app/tx/detail/applySteps.cpp | 1 + src/xrpld/ledger/detail/View.cpp | 4 +- 7 files changed, 221 insertions(+), 9 deletions(-) create mode 100644 src/xrpld/app/tx/detail/LoanBrokerDelete.cpp create mode 100644 src/xrpld/app/tx/detail/LoanBrokerDelete.h diff --git a/src/xrpld/app/tx/detail/InvariantCheck.cpp b/src/xrpld/app/tx/detail/InvariantCheck.cpp index 1dbac33b5a..4fca45fab5 100644 --- a/src/xrpld/app/tx/detail/InvariantCheck.cpp +++ b/src/xrpld/app/tx/detail/InvariantCheck.cpp @@ -434,7 +434,9 @@ AccountRootsDeletedClean::finalize( // feature is enabled. Enabled, or not, though, a fatal-level message will // be logged [[maybe_unused]] bool const enforce = - view.rules().enabled(featureInvariantsV1_1); + view.rules().enabled(featureInvariantsV1_1) || + view.rules().enabled(featureSingleAssetVault) || + view.rules().enabled(featureLendingProtocol); auto const objectExists = [&view, enforce, &j](auto const& keylet) { if (auto const sle = view.read(keylet)) @@ -487,10 +489,14 @@ AccountRootsDeletedClean::finalize( } // Keys directly stored in the AccountRoot object - if (auto const ammKey = accountSLE->at(~sfAMMID)) + for (auto const& field : getPseudoAccountFields()) { - if (objectExists(keylet::amm(*ammKey)) && enforce) - return false; + if (accountSLE->isFieldPresent(*field)) + { + auto const key = accountSLE->getFieldH256(*field); + if (objectExists(keylet::unchecked(key)) && enforce) + return false; + } } } diff --git a/src/xrpld/app/tx/detail/LoanBrokerDelete.cpp b/src/xrpld/app/tx/detail/LoanBrokerDelete.cpp new file mode 100644 index 0000000000..a9dbecfb7e --- /dev/null +++ b/src/xrpld/app/tx/detail/LoanBrokerDelete.cpp @@ -0,0 +1,150 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2025 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace ripple { + +bool +LoanBrokerDelete::isEnabled(PreflightContext const& ctx) +{ + return lendingProtocolEnabled(ctx); +} + +std::uint32_t +LoanBrokerDelete::getFlagsMask(PreflightContext const& ctx) +{ + return tfUniversalMask; +} + +NotTEC +LoanBrokerDelete::doPreflight(PreflightContext const& ctx) +{ + return tesSUCCESS; +} + +TER +LoanBrokerDelete::preclaim(PreclaimContext const& ctx) +{ + auto const& tx = ctx.tx; + + auto const account = tx[sfAccount]; + auto const brokerID = tx[sfLoanBrokerID]; + + auto const sleBroker = ctx.view.read(keylet::loanbroker(brokerID)); + if (!sleBroker) + { + JLOG(ctx.j.warn()) << "LoanBroker does not exist."; + return tecNO_ENTRY; + } + if (account != sleBroker->at(sfOwner)) + { + JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker."; + return tecNO_PERMISSION; + } + if (sleBroker->at(sfOwnerCount) != 0) + { + JLOG(ctx.j.warn()) << "LoanBrokerSet: Owner count is not zero"; + return tecHAS_OBLIGATIONS; + } + + return tesSUCCESS; +} + +TER +LoanBrokerDelete::doApply() +{ + auto const& tx = ctx_.tx; + auto& view = ctx_.view(); + + auto const brokerID = tx[sfLoanBrokerID]; + + // Delete the loan broker + auto broker = view.peek(keylet::loanbroker(brokerID)); + auto const vaultID = broker->at(sfVaultID); + auto const sleVault = view.read(keylet::vault(vaultID)); + auto const vaultPseudoID = sleVault->at(sfAccount); + auto const vaultAsset = sleVault->at(sfAsset); + + auto const brokerPseudoID = broker->at(sfAccount); + + if (!view.dirRemove( + keylet::ownerDir(account_), + broker->at(sfOwnerNode), + broker->key(), + false)) + { + return tefBAD_LEDGER; + } + if (!view.dirRemove( + keylet::ownerDir(vaultPseudoID), + broker->at(sfVaultNode), + broker->key(), + false)) + { + return tefBAD_LEDGER; + } + + { + auto const coverAvailable = + STAmount{vaultAsset, broker->at(sfCoverAvailable)}; + if (auto const ter = accountSend( + view, + brokerPseudoID, + account_, + coverAvailable, + j_, + WaiveTransferFee::Yes)) + return ter; + } + + auto brokerPseudoSLE = view.peek(keylet::account(brokerPseudoID)); + if (!brokerPseudoSLE) + return tefBAD_LEDGER; + + view.erase(brokerPseudoSLE); + + view.erase(broker); + + return tesSUCCESS; +} + +//------------------------------------------------------------------------------ + +} // namespace ripple diff --git a/src/xrpld/app/tx/detail/LoanBrokerDelete.h b/src/xrpld/app/tx/detail/LoanBrokerDelete.h new file mode 100644 index 0000000000..550a56fc58 --- /dev/null +++ b/src/xrpld/app/tx/detail/LoanBrokerDelete.h @@ -0,0 +1,56 @@ +//------------------------------------------------------------------------------ +/* + This file is part of rippled: https://github.com/ripple/rippled + Copyright (c) 2025 Ripple Labs Inc. + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ +//============================================================================== + +#ifndef RIPPLE_TX_LOANBROKERDELETE_H_INCLUDED +#define RIPPLE_TX_LOANBROKERDELETE_H_INCLUDED + +#include + +namespace ripple { + +class LoanBrokerDelete : public Transactor +{ +public: + static constexpr ConsequencesFactoryType ConsequencesFactory{Normal}; + + explicit LoanBrokerDelete(ApplyContext& ctx) : Transactor(ctx) + { + } + + static bool + isEnabled(PreflightContext const& ctx); + + static std::uint32_t + getFlagsMask(PreflightContext const& ctx); + + static NotTEC + doPreflight(PreflightContext const& ctx); + + static TER + preclaim(PreclaimContext const& ctx); + + TER + doApply() override; +}; + +//------------------------------------------------------------------------------ + +} // namespace ripple + +#endif diff --git a/src/xrpld/app/tx/detail/LoanBrokerSet.cpp b/src/xrpld/app/tx/detail/LoanBrokerSet.cpp index 7a043e205b..30db23e005 100644 --- a/src/xrpld/app/tx/detail/LoanBrokerSet.cpp +++ b/src/xrpld/app/tx/detail/LoanBrokerSet.cpp @@ -19,7 +19,6 @@ #include #include -#include #include #include #include diff --git a/src/xrpld/app/tx/detail/LoanBrokerSet.h b/src/xrpld/app/tx/detail/LoanBrokerSet.h index 23248d1c9d..6eef736e28 100644 --- a/src/xrpld/app/tx/detail/LoanBrokerSet.h +++ b/src/xrpld/app/tx/detail/LoanBrokerSet.h @@ -17,8 +17,8 @@ */ //============================================================================== -#ifndef RIPPLE_TX_LOANBROKER_H_INCLUDED -#define RIPPLE_TX_LOANBROKER_H_INCLUDED +#ifndef RIPPLE_TX_LOANBROKERSET_H_INCLUDED +#define RIPPLE_TX_LOANBROKERSET_H_INCLUDED #include diff --git a/src/xrpld/app/tx/detail/applySteps.cpp b/src/xrpld/app/tx/detail/applySteps.cpp index cc0e6ef6c1..e0079a2d1c 100644 --- a/src/xrpld/app/tx/detail/applySteps.cpp +++ b/src/xrpld/app/tx/detail/applySteps.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include diff --git a/src/xrpld/ledger/detail/View.cpp b/src/xrpld/ledger/detail/View.cpp index 47096d8113..11b144d8aa 100644 --- a/src/xrpld/ledger/detail/View.cpp +++ b/src/xrpld/ledger/detail/View.cpp @@ -1092,7 +1092,7 @@ getPseudoAccountFields() [[nodiscard]] bool isPseudoAccount(std::shared_ptr sleAcct) { - std::vector const& fields = getPseudoAccountFields(); + auto const& fields = getPseudoAccountFields(); // Intentionally use defensive coding here because it's cheap and makes the // semantics of true return value clean. @@ -1112,7 +1112,7 @@ createPseudoAccount( uint256 const& pseudoOwnerKey, SField const& ownerField) { - std::vector const& fields = getPseudoAccountFields(); + auto const& fields = getPseudoAccountFields(); XRPL_ASSERT( std::count_if( fields.begin(),