Compare commits

...

6 Commits

Author SHA1 Message Date
Mayukha Vadari
345a870b0d Include Keylet.h in the SLEBase test
(cherry picked from commit 3cca9d3266)
2026-10-05 14:38:52 +01:00
Mayukha Vadari
03438164d8 test: Drop extern template declarations from SLEBase test
An explicit instantiation declaration stops clang from emitting the
inline constructors of the header-only entries at -O0, so the debug
builds fail to link xrpl_tests (undefined AccountRootEntry constructors).
Naming each class in a static_assert already instantiates its definition,
which is all the exhaustiveness check needs.

(cherry picked from commit 611415e1f9)
2026-10-05 14:38:52 +01:00
Mayukha Vadari
a382d1a70f Drop unused include from LoanTestBase.h 2026-10-05 13:45:16 +01:00
Mayukha Vadari
71058accef refactor: Move getVaultVersion onto VaultEntry
Replace the free getVaultVersion(VaultEntryR const&) helper with the
const member VaultEntry::version(). The body moves to the new
src/libxrpl/ledger/entries/VaultEntry.cpp, which explicitly
instantiates VaultEntry for ReadView and ApplyView. Callers now call
vault.version().
2026-10-05 13:45:16 +01:00
Mayukha Vadari
8a1bfc322a test: Declare, not define, entry instantiations in SLEBase test
The exhaustive per-entry-type check in the SLEBase gtest used explicit
instantiation definitions. Once an entry class gets out-of-line member
bodies in its own .cpp (with the explicit instantiation definition
there), the test would instantiate the class a second time, and MSVC
rejects it with C4661 because those member bodies are not visible in
the test translation unit. Explicit instantiation declarations still
instantiate the class definition, which is all the check needs.

(cherry picked from commit 8b07abc3cd)
2026-10-05 13:45:16 +01:00
Mayukha Vadari
f66808c64a refactor: Use VaultEntry everywhere
Replace raw Vault SLE pointers with VaultEntryR/VaultEntryW in the
ledger helpers, the Vault transactors, and the lending transactors.
Helpers that take a Vault SLE (getVaultVersion, getVaultKind,
getVaultPhase, clampToAssetsTotalScale, the share/asset conversions,
getAssetsTotalScale, minimumBrokerCover, the lending accounting
dispatchers, and the transactor-local helpers) now take
VaultEntryR const& or VaultEntryW& and stay free functions.

The compiler now enforces the entry type and read/write access at
every Vault call site. Invariants and tests get only the minimal
edits the new signatures force: they wrap their SLE in VaultEntryR.

Pure refactor with no behavior change.
2026-10-05 13:33:07 +01:00
35 changed files with 234 additions and 153 deletions

View File

@@ -8,6 +8,7 @@
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SeqProxy.h>
namespace xrpl {
@@ -38,6 +39,19 @@ public:
: Base(keylet::vault(vaultID), view, j)
{
}
/**
* Resolves the Vault's LEVersion, the single point every accounting touch
* point should call to determine which recognition model (instant
* interest recognition vs. cash-basis) the Vault uses. Vaults created
* before featureLendingProtocolV1_1 activated never have sfLEVersion set,
* which resolves here to VaultVersion::Legacy.
*
* @return The Vault's LEVersion, or VaultVersion::Legacy if the field is
* absent.
*/
[[nodiscard]] VaultVersion
version() const;
};
using VaultEntryR = VaultEntry<ReadView>;

View File

@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/LedgerFormats.h> // IWYU pragma: keep
@@ -255,7 +256,7 @@ adjustImpreciseNumber(
}
inline int
getAssetsTotalScale(SLE::ConstRef vaultSle)
getAssetsTotalScale(VaultEntryR const& vaultSle)
{
if (!vaultSle)
return Number::kMinExponent - 1; // LCOV_EXCL_LINE
@@ -266,7 +267,10 @@ getAssetsTotalScale(SLE::ConstRef vaultSle)
// DebtTotal is a broker-level aggregate maintained at vault scale, so the
// rounding must also use vault scale — never an individual loan's scale.
inline Number
minimumBrokerCover(Number const& debtTotal, TenthBips32 coverRateMinimum, SLE::ConstRef vaultSle)
minimumBrokerCover(
Number const& debtTotal,
TenthBips32 coverRateMinimum,
VaultEntryR const& vaultSle)
{
XRPL_ASSERT(
vaultSle && vaultSle->getType() == ltVAULT, "xrpl::minimumBrokerCover : valid Vault sle");
@@ -380,26 +384,26 @@ loanPaymentDeltas(LoanPaymentParts const& parts);
} // namespace cash_basis
// Public dispatchers: pick cash_basis:: if featureLendingProtocolV1_1 is
// enabled AND the Vault's LEVersion (VaultHelpers::getVaultVersion) is
// enabled AND the Vault's LEVersion (VaultEntry::version) is
// VaultVersion::CashBasis, else instant_recognition::. These are the only entry points
// transactors call.
AccountingDeltas
loanOriginationDeltas(
SLE::ConstRef vaultSle,
VaultEntryR const& vaultSle,
Number const& principalRequested,
Number const& interestDue);
bool
loanOriginationExceedsVaultMaximum(
SLE::ConstRef vaultSle,
VaultEntryR const& vaultSle,
Number const& vaultTotal,
Number const& interestDue);
Number
loanVaultExposure(SLE::ConstRef vaultSle, SLE::ConstRef loanSle);
loanVaultExposure(VaultEntryR const& vaultSle, SLE::ConstRef loanSle);
AccountingDeltas
loanPaymentDeltas(SLE::ConstRef vaultSle, LoanPaymentParts const& parts);
loanPaymentDeltas(VaultEntryR const& vaultSle, LoanPaymentParts const& parts);
namespace detail {
// These classes and functions should only be accessed by LendingHelper

View File

@@ -2,6 +2,7 @@
#include <xrpl/basics/Number.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Protocol.h>
@@ -29,7 +30,7 @@ class STTx;
* @return The number of shares, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& assets);
assetsToSharesDeposit(VaultEntryR const& vault, SLE::ConstRef issuance, STAmount const& assets);
/**
* From the perspective of a vault, return the number of assets to take from
@@ -43,7 +44,7 @@ assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount cons
* @return The number of assets, or nullopt on error.
*/
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& shares);
sharesToAssetsDeposit(VaultEntryR const& vault, SLE::ConstRef issuance, STAmount const& shares);
/**
* Adjusts a requested asset change (`delta`) to match the decimal scale of the
@@ -69,7 +70,7 @@ sharesToAssetsDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount cons
* change is below representable precision.
*/
[[nodiscard]] std::expected<STAmount, TER>
clampToAssetsTotalScale(SLE::ConstRef vault, STAmount const& delta);
clampToAssetsTotalScale(VaultEntryR const& vault, STAmount const& delta);
/**
* Controls whether to truncate shares instead of rounding.
@@ -95,7 +96,7 @@ enum class WaiveUnrealizedLoss : bool { No = false, Yes = true };
* @param waive Whether to skip subtracting the unrealized loss.
*/
[[nodiscard]] Number
assetsTotalForWithdrawal(SLE::ConstRef vault, WaiveUnrealizedLoss waive);
assetsTotalForWithdrawal(VaultEntryR const& vault, WaiveUnrealizedLoss waive);
/**
* Returns true if debiting `amount` from `total` (the current value of a
@@ -131,7 +132,7 @@ debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount
*/
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
SLE::ConstRef vault,
VaultEntryR const& vault,
SLE::ConstRef issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::No,
@@ -152,7 +153,7 @@ assetsToSharesWithdraw(
*/
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
SLE::ConstRef vault,
VaultEntryR const& vault,
SLE::ConstRef issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
@@ -170,21 +171,6 @@ sharesToAssetsWithdraw(
[[nodiscard]] bool
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::ConstRef issuance);
/**
* Resolves a Vault's LEVersion, the single point every accounting touch
* point should call to determine which recognition model (instant interest
* recognition vs. cash-basis) a Vault uses. Vaults created before featureLendingProtocolV1_1
* activated never have sfLEVersion set, which resolves here to
* VaultVersion::Legacy.
*
* @param vault The vault SLE.
*
* @return The Vault's LEVersion, or VaultVersion::Legacy if the field is
* absent.
*/
[[nodiscard]] VaultVersion
getVaultVersion(SLE::ConstRef vault);
/**
* Resolves the VaultKind of a vault SLE. Returns VaultKind::ClosedEnded when
* sfVaultKind is present and equal to that value; anything else (including an
@@ -193,7 +179,7 @@ getVaultVersion(SLE::ConstRef vault);
* @param vault The vault SLE.
*/
[[nodiscard]] VaultKind
getVaultKind(SLE::ConstRef vault);
getVaultKind(VaultEntryR const& vault);
/**
* Reads sfVaultKind from a transaction. An absent field resolves to
@@ -240,7 +226,7 @@ isValidClosedEndedGap(std::uint32_t sub, std::uint32_t red);
* @param vault The vault SLE.
*/
[[nodiscard]] VaultPhase
getVaultPhase(ReadView const& view, SLE::ConstRef vault);
getVaultPhase(ReadView const& view, VaultEntryR const& vault);
/**
* Raw-fields overload of getVaultPhase. Derives the phase from an already

View File

@@ -4,6 +4,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/STTx.h>
#include <xrpl/protocol/TER.h>
@@ -44,7 +45,7 @@ public:
ApplyView& view,
SLE::Ref loanSle,
SLE::Ref brokerSle,
SLE::Ref vaultSle,
VaultEntryW& vaultSle,
Asset const& vaultAsset,
beast::Journal j);
@@ -55,7 +56,7 @@ public:
impairLoan(
ApplyView& view,
SLE::Ref loanSle,
SLE::Ref vaultSle,
VaultEntryW& vaultSle,
Asset const& vaultAsset,
beast::Journal j);
@@ -66,7 +67,7 @@ public:
unimpairLoan(
ApplyView& view,
SLE::Ref loanSle,
SLE::Ref vaultSle,
VaultEntryW& vaultSle,
Asset const& vaultAsset,
beast::Journal j);

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STTx.h>
@@ -48,7 +49,7 @@ public:
private:
std::expected<std::pair<STAmount, STAmount>, TER>
assetsToClawback(
SLE::Ref vault,
VaultEntryW& vault,
SLE::ConstRef sleShareIssuance,
AccountID const& holder,
STAmount const& clawbackAmount);

View File

@@ -9,6 +9,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -127,8 +128,8 @@ isVaultPseudoAccountFrozenForIssuance(
if (!mptIssuer->isFieldPresent(sfVaultID))
return false; // not a Vault pseudo-account, common case
auto const vault = view.read(keylet::vault(mptIssuer->getFieldH256(sfVaultID)));
if (vault == nullptr)
VaultEntryR const vault(mptIssuer->getFieldH256(sfVaultID), view);
if (!vault)
{ // LCOV_EXCL_START
UNREACHABLE("xrpl::isVaultPseudoAccountFrozen : null vault");
return false;

View File

@@ -0,0 +1,37 @@
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/Protocol.h>
#include <xrpl/protocol/SField.h>
#include <utility>
namespace xrpl {
template <typename ViewT>
VaultVersion
VaultEntry<ViewT>::version() const
{
XRPL_ASSERT(
*this && (*this)->getType() == ltVAULT, "xrpl::VaultEntry::version : valid Vault sle");
if (!(*this)->isFieldPresent(sfLEVersion))
return VaultVersion::Legacy;
auto const version = (*this)->at(sfLEVersion);
if (version > std::to_underlying(VaultVersion::CashBasis))
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::VaultEntry::version : invalid vault version");
return VaultVersion::Legacy;
// LCOV_EXCL_STOP
}
return static_cast<VaultVersion>(version);
}
template class VaultEntry<ReadView>;
template class VaultEntry<ApplyView>;
} // namespace xrpl

View File

@@ -9,6 +9,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -103,7 +104,7 @@ getLoanDefaultFreezeExemptAccounts(ReadView const& view, STTx const& tx)
if (!brokerSle)
return std::nullopt; // LCOV_EXCL_LINE
auto const vaultSle = view.read(keylet::vault(brokerSle->at(sfVaultID)));
VaultEntryR const vaultSle(brokerSle->at(sfVaultID), view);
if (!vaultSle)
return std::nullopt; // LCOV_EXCL_LINE
@@ -253,16 +254,16 @@ namespace {
// VaultVersion::CashBasis). Vaults created before activation keep instant
// interest recognition forever, even after the amendment later turns on.
bool
cashBasisEnabled(SLE::ConstRef vaultSle)
cashBasisEnabled(VaultEntryR const& vaultSle)
{
return getVaultVersion(vaultSle) == VaultVersion::CashBasis;
return vaultSle.version() == VaultVersion::CashBasis;
}
} // namespace
AccountingDeltas
loanOriginationDeltas(
SLE::ConstRef vaultSle,
VaultEntryR const& vaultSle,
Number const& principalRequested,
Number const& interestDue)
{
@@ -273,7 +274,7 @@ loanOriginationDeltas(
bool
loanOriginationExceedsVaultMaximum(
SLE::ConstRef vaultSle,
VaultEntryR const& vaultSle,
Number const& vaultTotal,
Number const& interestDue)
{
@@ -288,14 +289,14 @@ loanOriginationExceedsVaultMaximum(
}
Number
loanVaultExposure(SLE::ConstRef vaultSle, SLE::ConstRef loanSle)
loanVaultExposure(VaultEntryR const& vaultSle, SLE::ConstRef loanSle)
{
return cashBasisEnabled(vaultSle) ? cash_basis::loanVaultExposure(loanSle)
: instant_recognition::loanVaultExposure(loanSle);
}
AccountingDeltas
loanPaymentDeltas(SLE::ConstRef vaultSle, LoanPaymentParts const& parts)
loanPaymentDeltas(VaultEntryR const& vaultSle, LoanPaymentParts const& parts)
{
return cashBasisEnabled(vaultSle) ? cash_basis::loanPaymentDeltas(parts)
: instant_recognition::loanPaymentDeltas(parts);

View File

@@ -7,6 +7,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -421,7 +422,7 @@ requireAuth(
if (sleIssuer->isFieldPresent(sfVaultID))
{
auto const sleVault = view.read(keylet::vault(sleIssuer->getFieldH256(sfVaultID)));
VaultEntryR const sleVault(sleIssuer->getFieldH256(sfVaultID), view);
if (!sleVault)
return tefINTERNAL; // LCOV_EXCL_LINE

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
@@ -25,7 +26,7 @@
namespace xrpl {
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& assets)
assetsToSharesDeposit(VaultEntryR const& vault, SLE::ConstRef issuance, STAmount const& assets)
{
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
XRPL_ASSERT(
@@ -49,7 +50,7 @@ assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount cons
}
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& shares)
sharesToAssetsDeposit(VaultEntryR const& vault, SLE::ConstRef issuance, STAmount const& shares)
{
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(
@@ -72,7 +73,7 @@ sharesToAssetsDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount cons
}
[[nodiscard]] std::expected<STAmount, TER>
clampToAssetsTotalScale(SLE::ConstRef vault, STAmount const& delta)
clampToAssetsTotalScale(VaultEntryR const& vault, STAmount const& delta)
{
XRPL_ASSERT(
delta.asset() == vault->at(sfAsset),
@@ -131,7 +132,7 @@ clampToAssetsTotalScale(SLE::ConstRef vault, STAmount const& delta)
}
[[nodiscard]] Number
assetsTotalForWithdrawal(SLE::ConstRef vault, WaiveUnrealizedLoss waive)
assetsTotalForWithdrawal(VaultEntryR const& vault, WaiveUnrealizedLoss waive)
{
Number assetTotal = vault->at(sfAssetsTotal);
if (waive == WaiveUnrealizedLoss::No)
@@ -149,7 +150,7 @@ debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
SLE::ConstRef vault,
VaultEntryR const& vault,
SLE::ConstRef issuance,
STAmount const& assets,
TruncateShares truncate,
@@ -176,7 +177,7 @@ assetsToSharesWithdraw(
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
SLE::ConstRef vault,
VaultEntryR const& vault,
SLE::ConstRef issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive)
@@ -217,24 +218,6 @@ isSoleShareholder(ReadView const& view, AccountID const& account, SLE::ConstRef
return sleToken->getFieldU64(sfMPTAmount) == outstanding;
}
[[nodiscard]] VaultVersion
getVaultVersion(SLE::ConstRef vault)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultVersion : valid Vault sle");
if (!vault->isFieldPresent(sfLEVersion))
return VaultVersion::Legacy;
auto const version = vault->at(sfLEVersion);
if (version > std::to_underlying(VaultVersion::CashBasis))
{
// LCOV_EXCL_START
UNREACHABLE("xrpl::getVaultVersion : invalid vault version");
return VaultVersion::Legacy;
// LCOV_EXCL_STOP
}
return static_cast<VaultVersion>(version);
}
namespace {
[[nodiscard]] VaultKind
@@ -248,7 +231,7 @@ decodeVaultKind(std::optional<std::uint8_t> vaultKind)
} // namespace
[[nodiscard]] VaultKind
getVaultKind(SLE::ConstRef vault)
getVaultKind(VaultEntryR const& vault)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultKind : valid Vault sle");
return decodeVaultKind(vault->at(~sfVaultKind));
@@ -279,7 +262,7 @@ isValidClosedEndedGap(std::uint32_t sub, std::uint32_t red)
}
[[nodiscard]] VaultPhase
getVaultPhase(ReadView const& view, SLE::ConstRef vault)
getVaultPhase(ReadView const& view, VaultEntryR const& vault)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::getVaultPhase : valid Vault sle");
return getVaultPhase(

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Asset.h>
@@ -160,7 +161,7 @@ ValidLoanBroker::finalize(
roundToAsset(
Asset{vault->at(sfAsset)},
debtTotal,
getAssetsTotalScale(vault),
getAssetsTotalScale(VaultEntryR(vault, view)),
Number::RoundingMode::TowardsZero) != beast::kZero)
{
JLOG(j.fatal())

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -75,7 +76,7 @@ ValidLoan::finalize(
auto const vault = view.read(keylet::vault(broker->at(sfVaultID)));
// We don't check for LendingProtocolV1_1 amendment because a ClosedEnded Vault will
// not exist without the amendment enabled
if (vault && getVaultKind(vault) == VaultKind::ClosedEnded)
if (vault && getVaultKind(VaultEntryR(vault, view)) == VaultKind::ClosedEnded)
{
std::uint32_t const startDate = after->at(sfStartDate);
std::uint32_t const interval = after->at(sfPaymentInterval);

View File

@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -161,7 +162,7 @@ determineClawAmount(
SLE const& sleBroker,
Asset const& vaultAsset,
std::optional<STAmount> const& amount,
SLE::ConstRef vaultSle,
VaultEntryR const& vaultSle,
Rules const& rules)
{
auto const maxClawAmount = [&]() {
@@ -254,7 +255,7 @@ LoanBrokerCoverClawback::preclaim(PreclaimContext const& ctx)
auto const brokerPseudoAccountID = sleBroker->at(sfAccount);
auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
VaultEntryR const vault(sleBroker->at(sfVaultID), ctx.view);
if (!vault)
{
// LCOV_EXCL_START
@@ -350,7 +351,7 @@ LoanBrokerCoverClawback::doApply()
auto const brokerPseudoID = *sleBroker->at(sfAccount);
auto const vault = view().read(keylet::vault(sleBroker->at(sfVaultID)));
VaultEntryR const vault(sleBroker->at(sfVaultID), view());
if (!vault)
return tecINTERNAL; // LCOV_EXCL_LINE

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Feature.h>
@@ -62,7 +63,7 @@ LoanBrokerCoverDeposit::preclaim(PreclaimContext const& ctx)
JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker.";
return tecNO_PERMISSION;
}
auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
VaultEntryR const vault(sleBroker->at(sfVaultID), ctx.view);
if (!vault)
{
// LCOV_EXCL_START
@@ -143,7 +144,7 @@ LoanBrokerCoverDeposit::doApply()
if (!broker)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const vault = view().read(keylet::vault(broker->at(sfVaultID)));
VaultEntryR const vault(broker->at(sfVaultID), view());
if (!vault)
return tecINTERNAL; // LCOV_EXCL_LINE

View File

@@ -4,6 +4,7 @@
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
@@ -90,7 +91,7 @@ LoanBrokerCoverWithdraw::preclaim(PreclaimContext const& ctx)
JLOG(ctx.j.warn()) << "Account is not the owner of the LoanBroker.";
return tecNO_PERMISSION;
}
auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
VaultEntryR const vault(sleBroker->at(sfVaultID), ctx.view);
if (!vault)
{
// LCOV_EXCL_START
@@ -218,7 +219,7 @@ LoanBrokerCoverWithdraw::doApply()
if (!broker)
return tecINTERNAL; // LCOV_EXCL_LINE
auto const vault = view().read(keylet::vault(broker->at(sfVaultID)));
VaultEntryR const vault(broker->at(sfVaultID), view());
if (!vault)
return tecINTERNAL; // LCOV_EXCL_LINE

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/Number.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -62,7 +63,7 @@ LoanBrokerDelete::preclaim(PreclaimContext const& ctx)
return tecHAS_OBLIGATIONS;
}
auto const vault = ctx.view.read(keylet::vault(sleBroker->at(sfVaultID)));
VaultEntryR const vault(sleBroker->at(sfVaultID), ctx.view);
if (!vault)
{
// LCOV_EXCL_START
@@ -132,7 +133,7 @@ LoanBrokerDelete::doApply()
if (!broker)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultID = broker->at(sfVaultID);
auto const sleVault = view().read(keylet::vault(vaultID));
VaultEntryR const sleVault(vaultID, view());
if (!sleVault)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultPseudoID = sleVault->at(sfAccount);

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -98,7 +99,7 @@ LoanBrokerSet::preclaim(PreclaimContext const& ctx)
auto const account = tx[sfAccount];
auto const vaultID = tx[sfVaultID];
auto const sleVault = ctx.view.read(keylet::vault(vaultID));
VaultEntryR const sleVault(vaultID, ctx.view);
if (!sleVault)
{
JLOG(ctx.j.warn()) << "Vault does not exist.";
@@ -204,7 +205,7 @@ LoanBrokerSet::doApply()
// LCOV_EXCL_STOP
}
auto const vault = view.read(keylet::vault(broker->at(sfVaultID)));
VaultEntryR const vault(broker->at(sfVaultID), view);
if (!vault)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -223,7 +224,7 @@ LoanBrokerSet::doApply()
{
// Create a new LoanBroker pointing back to the given Vault
auto const vaultID = tx[sfVaultID];
auto const sleVault = view.read(keylet::vault(vaultID));
VaultEntryR const sleVault(vaultID, view);
if (!sleVault)
{
// This should be impossible

View File

@@ -4,6 +4,7 @@
#include <xrpl/basics/Number.h> // IWYU pragma: keep
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/protocol/Indexes.h>
@@ -90,7 +91,7 @@ LoanDelete::doApply()
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const brokerPseudoAccount = brokerSle->at(sfAccount);
auto const vaultSle = view.peek(keylet::vault(brokerSle->at(sfVaultID)));
VaultEntryW vaultSle(brokerSle->at(sfVaultID), view);
if (!vaultSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultAsset = vaultSle->at(sfAsset);

View File

@@ -6,6 +6,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/Asset.h>
@@ -136,7 +137,7 @@ LoanManage::defaultLoan(
ApplyView& view,
SLE::Ref loanSle,
SLE::Ref brokerSle,
SLE::Ref vaultSle,
VaultEntryW& vaultSle,
Asset const& vaultAsset,
beast::Journal j)
{
@@ -238,7 +239,7 @@ LoanManage::defaultLoan(
adjustImpreciseNumber(
vaultLossUnrealizedProxy, -totalDefaultAmount, vaultAsset, vaultScale);
}
view.update(vaultSle);
vaultSle.update();
}
// Update the LoanBroker object:
@@ -287,7 +288,7 @@ TER
LoanManage::impairLoan(
ApplyView& view,
SLE::Ref loanSle,
SLE::Ref vaultSle,
VaultEntryW& vaultSle,
Asset const& vaultAsset,
beast::Journal j)
{
@@ -316,7 +317,7 @@ LoanManage::impairLoan(
JLOG(j.warn()) << "Vault unrealized loss is too large, and will corrupt the vault.";
return tecLIMIT_EXCEEDED;
}
view.update(vaultSle);
vaultSle.update();
// Update the Loan object
loanSle->setFlag(lsfLoanImpaired);
@@ -339,7 +340,7 @@ LoanManage::impairLoan(
LoanManage::unimpairLoan(
ApplyView& view,
SLE::Ref loanSle,
SLE::Ref vaultSle,
VaultEntryW& vaultSle,
Asset const& vaultAsset,
beast::Journal j)
{
@@ -361,7 +362,7 @@ LoanManage::unimpairLoan(
// Reverse the "paper loss"
adjustImpreciseNumber(vaultLossUnrealizedProxy, -lossReversed, vaultAsset, vaultScale);
view.update(vaultSle);
vaultSle.update();
// Update the Loan object
loanSle->clearFlag(lsfLoanImpaired);
@@ -405,7 +406,7 @@ LoanManage::doApply()
if (!brokerSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultSle = view.peek(keylet::vault(brokerSle->at(sfVaultID)));
VaultEntryW vaultSle(brokerSle->at(sfVaultID), view);
if (!vaultSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultAsset = vaultSle->at(sfAsset);

View File

@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/json/to_string.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -167,7 +168,7 @@ LoanPay::calculateBaseFee(ReadView const& view, STTx const& tx)
// Let preclaim worry about the error for this
return normalCost;
}
auto const vaultSle = view.read(keylet::vault(brokerSle->at(sfVaultID)));
VaultEntryR const vaultSle(brokerSle->at(sfVaultID), view);
if (!vaultSle)
{
// Let preclaim worry about the error for this
@@ -273,7 +274,7 @@ LoanPay::preclaim(PreclaimContext const& ctx)
// LCOV_EXCL_STOP
}
auto const vaultID = loanBrokerSle->at(sfVaultID);
auto const vaultSle = ctx.view.read(keylet::vault(vaultID));
VaultEntryR const vaultSle(vaultID, ctx.view);
if (!vaultSle)
{
// This should be impossible
@@ -349,7 +350,7 @@ LoanPay::doApply()
auto const brokerOwner = brokerSle->at(sfOwner);
auto const brokerPseudoAccount = brokerSle->at(sfAccount);
auto const vaultID = brokerSle->at(sfVaultID);
auto const vaultSle = view.peek(keylet::vault(vaultID));
VaultEntryW vaultSle(vaultID, view);
if (!vaultSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultPseudoAccount = vaultSle->at(sfAccount);
@@ -514,7 +515,7 @@ LoanPay::doApply()
//------------------------------------------------------
// Vault object state changes
view.update(vaultSle);
vaultSle.update();
Number const assetsAvailableBefore = *assetsAvailableProxy;
Number const assetsTotalBefore = *assetsTotalProxy;

View File

@@ -7,6 +7,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -313,7 +314,7 @@ LoanSet::preclaim(PreclaimContext const& ctx)
return terNO_ACCOUNT;
}
auto const vault = ctx.view.read(keylet::vault(brokerSle->at(sfVaultID)));
VaultEntryR const vault(brokerSle->at(sfVaultID), ctx.view);
if (!vault)
{
// Should be impossible
@@ -351,7 +352,7 @@ LoanSet::preclaim(PreclaimContext const& ctx)
// already at AssetsMaximum cannot take another loan. Cash-basis origination
// does not change AssetsTotal (see cash_basis::loanOriginationDeltas), so
// this leftover instant-recognition gate must not apply there.
if (getVaultVersion(vault) != VaultVersion::CashBasis && vault->at(sfAssetsMaximum) != 0 &&
if (vault.version() != VaultVersion::CashBasis && vault->at(sfAssetsMaximum) != 0 &&
vault->at(sfAssetsTotal) >= vault->at(sfAssetsMaximum))
{
JLOG(ctx.j.warn()) << "Vault at maximum assets limit. Can't add another loan.";
@@ -447,7 +448,7 @@ LoanSet::doApply()
if (!brokerOwnerSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultSle = view.peek(keylet::vault(brokerSle->at(sfVaultID)));
VaultEntryW vaultSle(brokerSle->at(sfVaultID), view);
if (!vaultSle)
return tefBAD_LEDGER; // LCOV_EXCL_LINE
auto const vaultPseudo = vaultSle->at(sfAccount);
@@ -499,8 +500,7 @@ LoanSet::doApply()
properties.loanState.managementFeeDue);
XRPL_ASSERT_PARTS(
*vaultSle->at(sfAssetsMaximum) == 0 ||
getVaultVersion(vaultSle) == VaultVersion::CashBasis ||
*vaultSle->at(sfAssetsMaximum) == 0 || vaultSle.version() == VaultVersion::CashBasis ||
*vaultSle->at(sfAssetsMaximum) > *vaultTotalProxy,
"xrpl::LoanSet::doApply",
"instant-recognition vault is below maximum limit");
@@ -702,7 +702,7 @@ LoanSet::doApply()
*vaultAvailableProxy <= *vaultTotalProxy,
"xrpl::LoanSet::doApply",
"assets available must not be greater than assets outstanding");
view.update(vaultSle);
vaultSle.update();
// Update the balances in the loan broker
adjustImpreciseNumber(brokerSle->at(sfDebtTotal), debtTotalDelta, vaultAsset, vaultScale);

View File

@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
@@ -61,7 +62,7 @@ VaultClawback::preflight(PreflightContext const& ctx)
[[nodiscard]] STAmount
clawbackAmount(
SLE::ConstRef vault,
VaultEntryR const& vault,
std::optional<STAmount> const& maybeAmount,
AccountID const& account)
{
@@ -78,7 +79,7 @@ clawbackAmount(
TER
VaultClawback::preclaim(PreclaimContext const& ctx)
{
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
VaultEntryR const vault(ctx.tx[sfVaultID], ctx.view);
if (!vault)
return tecNO_ENTRY;
@@ -232,7 +233,7 @@ VaultClawback::preclaim(PreclaimContext const& ctx)
std::expected<std::pair<STAmount, STAmount>, TER>
VaultClawback::assetsToClawback(
SLE::Ref vault,
VaultEntryW& vault,
SLE::ConstRef sleShareIssuance,
AccountID const& holder,
STAmount const& clawbackAmount)
@@ -390,7 +391,7 @@ TER
VaultClawback::doApply()
{
auto const& tx = ctx_.tx;
auto const vault = view().peek(keylet::vault(tx[sfVaultID]));
VaultEntryW vault(tx[sfVaultID], view());
if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -475,7 +476,7 @@ VaultClawback::doApply()
assetsTotal -= assetsRecovered;
assetsAvailable -= assetsRecovered;
view().update(vault);
vault.update();
auto const& vaultAccount = vault->at(sfAccount);
// Transfer shares from holder to vault.

View File

@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -185,9 +186,12 @@ VaultCreate::doApply()
if (owner == nullptr)
return tefINTERNAL; // LCOV_EXCL_LINE
auto vault = std::make_shared<SLE>(keylet::vault(accountID_, sequence));
VaultEntryW vault(accountID_, sequence, view());
vault.newSLE();
if (auto ter = dirLink(view(), accountID_, vault))
// dirLink takes a non-const SLE::pointer&, so pass it a copy of the handle.
SLE::pointer vaultSle = vault.mutableRawSle();
if (auto ter = dirLink(view(), accountID_, vaultSle))
return ter;
// We will create Vault and PseudoAccount, hence increase OwnerCount by 2
increaseOwnerCount(view(), owner, {}, 2, j_);
@@ -285,7 +289,7 @@ VaultCreate::doApply()
vault->at(sfRedemptionDate) = tx[sfRedemptionDate];
}
}
view().insert(vault);
vault.insert();
// Explicitly create MPToken for the vault owner
if (auto const err = authorizeMPToken(

View File

@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -43,7 +44,7 @@ VaultDelete::preflight(PreflightContext const& ctx)
TER
VaultDelete::preclaim(PreclaimContext const& ctx)
{
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
VaultEntryR const vault(ctx.tx[sfVaultID], ctx.view);
if (!vault)
return tecNO_ENTRY;
@@ -96,7 +97,7 @@ VaultDelete::preclaim(PreclaimContext const& ctx)
TER
VaultDelete::doApply()
{
auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
VaultEntryW vault(ctx_.tx[sfVaultID], view());
auto applyViewContext = ctx_.getApplyViewContext();
if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -214,10 +215,10 @@ VaultDelete::doApply()
}
// We are destroying Vault and PseudoAccount, hence decrease by 2
decreaseOwnerCountForObject(view(), owner, vault, 2, j_);
decreaseOwnerCountForObject(view(), owner, vault.mutableRawSle(), 2, j_);
// Destroy the vault.
view().erase(vault);
vault.erase();
return tesSUCCESS;
}

View File

@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
@@ -33,7 +34,7 @@ namespace xrpl {
[[nodiscard]]
static STAmount
roundToVaultScale(STAmount const& amount, SLE::ConstRef vault)
roundToVaultScale(STAmount const& amount, VaultEntryR const& vault)
{
XRPL_ASSERT(vault && vault->getType() == ltVAULT, "xrpl::roundToVaultScale : valid vault sle");
XRPL_ASSERT(
@@ -103,7 +104,7 @@ VaultDeposit::preclaim(PreclaimContext const& ctx)
auto const fix320Enabled = ctx.view.rules().enabled(fixCleanup3_2_0);
auto const fix330Enabled = ctx.view.rules().enabled(fixCleanup3_3_0);
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
VaultEntryR const vault(ctx.tx[sfVaultID], ctx.view);
if (!vault)
return tecNO_ENTRY;
@@ -231,7 +232,7 @@ VaultDeposit::doApply()
{
bool const fix320Enabled = view().rules().enabled(fixCleanup3_2_0);
bool const fix340Enabled = view().rules().enabled(fixCleanup3_4_0);
auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
VaultEntryW vault(ctx_.tx[sfVaultID], view());
auto applyViewContext = ctx_.getApplyViewContext();
if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -380,7 +381,7 @@ VaultDeposit::doApply()
vault->at(sfAssetsTotal) += assetsDeposited;
vault->at(sfAssetsAvailable) += assetsDeposited;
view().update(vault);
vault.update();
// A deposit must not push the vault over its limit.
auto const maximum = *vault->at(sfAssetsMaximum);

View File

@@ -2,6 +2,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -63,7 +64,7 @@ VaultSet::preflight(PreflightContext const& ctx)
TER
VaultSet::preclaim(PreclaimContext const& ctx)
{
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
VaultEntryR const vault(ctx.tx[sfVaultID], ctx.view);
if (!vault)
return tecNO_ENTRY;
@@ -123,7 +124,7 @@ VaultSet::doApply()
auto const& tx = ctx_.tx;
// Update existing object.
auto vault = view().peek(keylet::vault(tx[sfVaultID]));
VaultEntryW vault(tx[sfVaultID], view());
if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -170,7 +171,7 @@ VaultSet::doApply()
// Note, we must update Vault object even if only DomainID is being updated
// in Issuance object. Otherwise it's really difficult for Vault invariants
// to verify the operation.
view().update(vault);
vault.update();
associateAsset(*vault, vaultAsset);

View File

@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -83,7 +84,7 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
auto const fix330Enabled = ctx.view.rules().enabled(fixCleanup3_3_0);
auto const fix340Enabled = ctx.view.rules().enabled(fixCleanup3_4_0);
auto const vault = ctx.view.read(keylet::vault(ctx.tx[sfVaultID]));
VaultEntryR const vault(ctx.tx[sfVaultID], ctx.view);
if (!vault)
return tecNO_ENTRY;
@@ -278,7 +279,7 @@ TER
VaultWithdraw::doApply()
{
bool const fix340Enabled = view().rules().enabled(fixCleanup3_4_0);
auto const vault = view().peek(keylet::vault(ctx_.tx[sfVaultID]));
VaultEntryW vault(ctx_.tx[sfVaultID], view());
auto applyViewContext = ctx_.getApplyViewContext();
if (!vault)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -543,7 +544,7 @@ VaultWithdraw::doApply()
assetsTotal -= assetsWithdrawn;
assetsAvailable -= assetsWithdrawn;
}
view().update(vault);
vault.update();
auto const& vaultAccount = vault->at(sfAccount);

View File

@@ -11,6 +11,7 @@
#include <xrpl/basics/Number.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -1682,7 +1683,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
"loanOriginationDeltas dispatcher: amendment enabled, legacy vault picks "
"InstantRecognition");
Env const env{*this};
auto const deltas = loanOriginationDeltas(legacyVault, principalRequested, interestDue);
auto const deltas = loanOriginationDeltas(
VaultEntryR(legacyVault, *env.current()), principalRequested, interestDue);
auto const expected =
xrpl::instant_recognition::loanOriginationDeltas(principalRequested, interestDue);
BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta);
@@ -1694,8 +1696,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
"loanOriginationDeltas dispatcher: amendment enabled, LEVersion == "
"VaultVersion::CashBasis picks CashBasis");
Env const env{*this};
auto const deltas =
loanOriginationDeltas(cashBasisVault, principalRequested, interestDue);
auto const deltas = loanOriginationDeltas(
VaultEntryR(cashBasisVault, *env.current()), principalRequested, interestDue);
auto const expected = xrpl::cash_basis::loanOriginationDeltas(principalRequested);
BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta);
BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta);
@@ -1721,7 +1723,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
"picks InstantRecognition");
Env const env{*this};
BEAST_EXPECT(
loanOriginationExceedsVaultMaximum(legacyVault, vaultTotal, interestDue) ==
loanOriginationExceedsVaultMaximum(
VaultEntryR(legacyVault, *env.current()), vaultTotal, interestDue) ==
xrpl::instant_recognition::loanOriginationExceedsVaultMaximum(
vaultMaximum, vaultTotal, interestDue));
}
@@ -1732,8 +1735,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
"VaultVersion::CashBasis picks CashBasis");
Env const env{*this};
BEAST_EXPECT(
loanOriginationExceedsVaultMaximum(cashBasisVault, vaultTotal, interestDue) ==
false);
loanOriginationExceedsVaultMaximum(
VaultEntryR(cashBasisVault, *env.current()), vaultTotal, interestDue) == false);
}
}
@@ -1752,7 +1755,7 @@ class LendingHelpers_test : public beast::unit_test::Suite
Env const env{*this};
auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50});
BEAST_EXPECT(
loanVaultExposure(legacyVault, sle) ==
loanVaultExposure(VaultEntryR(legacyVault, *env.current()), sle) ==
xrpl::instant_recognition::loanVaultExposure(sle));
}
@@ -1764,7 +1767,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
Env const env{*this};
auto sle = makeLoanSle(Number{1'000}, Number{800}, Number{50});
BEAST_EXPECT(
loanVaultExposure(cashBasisVault, sle) == xrpl::cash_basis::loanVaultExposure(sle));
loanVaultExposure(VaultEntryR(cashBasisVault, *env.current()), sle) ==
xrpl::cash_basis::loanVaultExposure(sle));
}
}
@@ -1787,7 +1791,7 @@ class LendingHelpers_test : public beast::unit_test::Suite
"loanPaymentDeltas dispatcher: amendment enabled, legacy vault picks "
"InstantRecognition");
Env const env{*this};
auto const deltas = loanPaymentDeltas(legacyVault, parts);
auto const deltas = loanPaymentDeltas(VaultEntryR(legacyVault, *env.current()), parts);
auto const expected = xrpl::instant_recognition::loanPaymentDeltas(parts);
BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta);
BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta);
@@ -1799,7 +1803,8 @@ class LendingHelpers_test : public beast::unit_test::Suite
"VaultVersion::CashBasis "
"picks CashBasis");
Env const env{*this};
auto const deltas = loanPaymentDeltas(cashBasisVault, parts);
auto const deltas =
loanPaymentDeltas(VaultEntryR(cashBasisVault, *env.current()), parts);
auto const expected = xrpl::cash_basis::loanPaymentDeltas(parts);
BEAST_EXPECT(deltas.assetsTotalDelta == expected.assetsTotalDelta);
BEAST_EXPECT(deltas.debtTotalDelta == expected.debtTotalDelta);

View File

@@ -13,8 +13,8 @@
#include <xrpl/basics/chrono.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Issue.h>
@@ -1126,7 +1126,7 @@ private:
auto const vaultSle = env.le(broker.vaultKeylet());
BEAST_EXPECT(vaultSle);
BEAST_EXPECT(!vaultSle->isFieldPresent(sfLEVersion));
BEAST_EXPECT(getVaultVersion(vaultSle) == VaultVersion::Legacy);
BEAST_EXPECT(VaultEntryR(vaultSle, *env.current()).version() == VaultVersion::Legacy);
}
}

View File

@@ -14,6 +14,7 @@
#include <xrpl/basics/Number.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_value.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -665,7 +666,8 @@ private:
return std::nullopt;
if (!BEAST_EXPECT(tinyLoanSle->at(sfLoanScale) == -12) ||
!BEAST_EXPECT(bigLoanSle->at(sfLoanScale) == -11) ||
!BEAST_EXPECT(getAssetsTotalScale(vaultSle) == -11))
!BEAST_EXPECT(
getAssetsTotalScale(VaultEntryR(vaultSle, *env.current())) == -11))
return std::nullopt;
// Use issuer clawback to reduce cover to the minimum the
@@ -792,7 +794,7 @@ private:
auto const coverAvail = brokerSle->at(sfCoverAvailable);
auto const debtTotal = brokerSle->at(sfDebtTotal);
auto const vaultScale = getAssetsTotalScale(vaultSle);
auto const vaultScale = getAssetsTotalScale(VaultEntryR(vaultSle, *env.current()));
auto const debtScale = scale(debtTotal, asset);
// Sanity: debt scale differs from vault scale for this setup.
@@ -806,7 +808,9 @@ private:
debtScale);
}();
auto const newMin = minimumBrokerCover(
debtTotal, TenthBips32{c.brokerParams.coverRateMin}, vaultSle);
debtTotal,
TenthBips32{c.brokerParams.coverRateMin},
VaultEntryR(vaultSle, *env.current()));
// The new (vaultScale) minimum must be strictly larger than
// the old (debtScale) minimum — that is the gap the amendment
@@ -890,7 +894,7 @@ private:
auto const vaultSle = env.le(keylet::vault(c.broker.vaultID));
if (!BEAST_EXPECT(vaultSle))
return;
auto const vaultScale = getAssetsTotalScale(vaultSle);
auto const vaultScale = getAssetsTotalScale(VaultEntryR(vaultSle, *env.current()));
BEAST_EXPECT(vaultScale == -11);
// Now try to create a tiny additional loan. Principal is

View File

@@ -26,9 +26,9 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/json/json_value.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -190,7 +190,7 @@ protected:
using namespace jtx;
auto const vaultSle = env.le(keylet::vault(vaultID));
return getAssetsTotalScale(vaultSle);
return getAssetsTotalScale(VaultEntryR(vaultSle, *env.current()));
}
};
@@ -346,7 +346,8 @@ protected:
{
auto const expectedDebt =
env.current()->rules().enabled(featureLendingProtocolV1_1) &&
getVaultVersion(vaultSle) == VaultVersion::CashBasis
VaultEntryR(vaultSle, *env.current()).version() ==
VaultVersion::CashBasis
? principalOutstanding
: principalOutstanding + interestOwed;
env.test.BEAST_EXPECT(brokerDebt == expectedDebt);
@@ -451,7 +452,8 @@ protected:
env.test.BEAST_EXPECT(
vaultSle->at(sfLossUnrealized) ==
(env.current()->rules().enabled(featureLendingProtocolV1_1) &&
getVaultVersion(vaultSle) == VaultVersion::CashBasis
VaultEntryR(vaultSle, *env.current()).version() ==
VaultVersion::CashBasis
? principalOutstanding
: totalValue - managementFeeOutstanding));
}
@@ -666,7 +668,8 @@ protected:
vaultSle->at(sfAssetsTotal) - vaultSle->at(sfAssetsAvailable);
auto const unrealizedLoss = vaultSle->at(sfLossUnrealized) +
(env.current()->rules().enabled(featureLendingProtocolV1_1) &&
getVaultVersion(vaultSle) == VaultVersion::CashBasis
VaultEntryR(vaultSle, *env.current()).version() ==
VaultVersion::CashBasis
? state.principalOutstanding
: state.totalValue - state.managementFeeOutstanding);

View File

@@ -22,6 +22,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_forwards.h>
#include <xrpl/json/json_value.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -1521,7 +1522,7 @@ private:
// same conversion helper VaultClawback itself uses, rather than
// assuming an exact 90/10 split holds under truncation.
auto const maybeSharesDestroyed = assetsToSharesWithdraw(
vaultBefore,
VaultEntryR(vaultBefore, *env.current()),
issuanceBefore,
setup.usd(9'000).value(),
TruncateShares::Yes,

View File

@@ -15,6 +15,7 @@
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/json/json_forwards.h>
#include <xrpl/json/json_value.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -473,7 +474,9 @@ private:
auto const sle = env.le(keylet);
if (!BEAST_EXPECT(sle))
return;
BEAST_EXPECT(getVaultPhase(*env.current(), sle) == VaultPhase::NoPhase);
BEAST_EXPECT(
getVaultPhase(*env.current(), VaultEntryR(sle, *env.current())) ==
VaultPhase::NoPhase);
};
// Advance the clock through a wide range of ledger times: an open-ended vault's phase

View File

@@ -1,8 +1,10 @@
#include <test/jtx/Account.h>
#include <test/jtx/Env.h>
#include <xrpl/basics/Number.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/ledger/entries/VaultEntry.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Indexes.h>
@@ -29,8 +31,9 @@ namespace xrpl {
// True unit test of `clampToAssetsTotalScale`. The function under test only
// reads sfAsset and sfAssetsTotal from the vault SLE and never touches a
// ledger view or Rules, so a bare in-memory ltVAULT SLE is enough; there is
// no jtx::Env and no transaction submitted anywhere in this file.
// ledger view or Rules, so a bare in-memory ltVAULT SLE is enough. The only
// jtx::Env is the one runCases() needs so VaultEntryR can wrap that SLE; no
// transaction is submitted anywhere in this file.
//
// Number regime: this suite relies on the default thread_local Number
// mantissa range, which src/libxrpl/basics/Number.cpp initializes to
@@ -86,6 +89,9 @@ private:
Number::RoundingMode::Upward,
Number::RoundingMode::TowardsZero};
test::jtx::Env const env{*this};
auto const view = env.current();
for (auto const& c : cases)
{
testcase(c.name);
@@ -106,7 +112,7 @@ private:
for (auto const mode : modes)
{
NumberRoundModeGuard const rg(mode);
auto const result = clampToAssetsTotalScale(vault, delta);
auto const result = clampToAssetsTotalScale(VaultEntryR(vault, *view), delta);
// The function must be insensitive to the caller's ambient
// rounding mode: every mode must agree with the first one

View File

@@ -38,6 +38,7 @@
#include <xrpl/ledger/entries/XChainOwnedClaimIDEntry.h> // IWYU pragma: keep
#include <xrpl/ledger/entries/XChainOwnedCreateAccountClaimIDEntry.h> // IWYU pragma: keep
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/Keylet.h>
#include <xrpl/protocol/LedgerFormats.h>
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STLedgerEntry.h>
@@ -76,12 +77,22 @@ template class SLEBase<ApplyView>;
#pragma push_macro("LEDGER_ENTRY")
#undef LEDGER_ENTRY
// No explicit instantiation here, neither a definition nor a declaration.
// A definition would instantiate an entry a second time once its member
// bodies live in its own .cpp (MSVC rejects that with C4661 under /WX), and a
// declaration (`extern template`) stops clang from emitting the inline
// constructors of the header-only entries at -O0, which leaves them undefined
// at link time in the debug builds. Naming the class in a static_assert is
// enough to instantiate its definition, which is all this exhaustiveness
// check needs; the per-type suites exercise the members.
#define LEDGER_ENTRY(tag, value, name, ...) \
template class name##Entry<ReadView>; \
template class name##Entry<ApplyView>; \
static_assert( \
name##Entry<ReadView>::kEntryType == tag && name##Entry<ApplyView>::kEntryType == tag, \
#name "Entry must be bound to " #tag);
#name "Entry must be bound to " #tag); \
static_assert( \
std::is_constructible_v<name##Entry<ReadView>, Keylet const&, ReadView const&> && \
std::is_constructible_v<name##Entry<ApplyView>, Keylet const&, ApplyView&>, \
#name "Entry must be constructible from a Keylet and a view");
#include <xrpl/protocol/detail/ledger_entries.macro>