Compare commits

...
Author SHA1 Message Date
Mayukha Vadari 0a40c8e642 Document maxAmount return value 2026-10-05 15:45:03 +01:00
Mayukha Vadari 4d14f5ac77 Include Keylet.h in the SLEBase test
(cherry picked from commit 3cca9d3266)
2026-10-05 15:44:19 +01:00
Mayukha Vadari 517a2f2320 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 15:44:19 +01:00
Mayukha Vadari 2a4f714370 refactor: Move maxMPTAmount onto MPTokenIssuanceEntry
Add the const member MPTokenIssuanceEntry::maxAmount() and use it at
every call site that already holds an issuance entry. The member body
lives in the new src/libxrpl/ledger/entries/MPTokenIssuanceEntry.cpp,
which explicitly instantiates the read-only and writable entries.

The free maxMPTAmount(SLE const&) stays and holds the implementation:
ValidMPTBalanceChanges::visitEntry and the RPC AssetCache call it with
a bare SLE and no view, so they cannot build an entry.
2026-10-05 15:44:19 +01:00
Mayukha Vadari 2dfc9d0d02 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 15:44:19 +01:00
Mayukha Vadari 63751ecbb0 Document isGlobalFrozen return value 2026-10-05 15:43:21 +01:00
Mayukha Vadari 6e7265e3d0 refactor: Move isGlobalFrozen onto MPTokenIssuanceEntry
Replace the free isGlobalFrozen(MPTokenIssuanceEntryR const&) with a
const member MPTokenIssuanceEntry::isGlobalFrozen(). The
(ReadView, MPTIssue) overload stays as a shim that builds the entry and
calls the member. The old type assertion is dropped: the entry type is
now bound at compile time and checked by the SLEBase constructors.
2026-10-05 14:18:25 +01:00
Mayukha Vadari aad945ffb0 refactor: Use MPTokenIssuanceEntry in ConfidentialMPTHolderKeyUpdate
Develop added the ConfidentialMPTHolderKeyUpdate transactor (#8266),
which reads the issuance with a raw view.read(). Use
MPTokenIssuanceEntryR there too, so that this PR still covers every
MPTokenIssuance read.
2026-10-05 14:18:04 +01:00
Mayukha Vadari 5252fbf8a2 refactor: Use MPTokenIssuanceEntry everywhere
Replace raw MPTokenIssuance SLE pointers with MPTokenIssuanceEntryR
(read-only) and MPTokenIssuanceEntryW (writable) in the ledger
helpers, transactors, and payment paths. view.read()/peek() become
entry constructors, and insert/update/erase go through the entry.

Helpers that take an issuance SLE now take MPTokenIssuanceEntryR:
isGlobalFrozen, assetOfHolding (issuance parameter only),
availableMPTAmount, isVaultPseudoAccountFrozen, the vault share
conversion helpers, isSoleShareholder, checkVaultDomain, and a few
file-local helpers. They stay free functions.

maxMPTAmount keeps its SLE parameter because an invariant calls it
from visitEntry(), where no view exists to build an entry. Code that
branches on MPToken vs. MPTokenIssuance keeps its generic SLE.

Pure refactor: no behavior change.
2026-10-05 13:33:20 +01:00
36 changed files with 241 additions and 146 deletions

No files matched your search

+2 -1
View File
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Keylet.h>
@@ -83,7 +84,7 @@ isVaultPseudoAccountFrozen(
isVaultPseudoAccountFrozen(
ReadView const& view,
AccountID const& account,
SLE const& issuanceSle,
MPTokenIssuanceEntryR const& issuanceSle,
std::uint8_t depth);
[[nodiscard]] bool
@@ -48,6 +48,26 @@ public:
: Base(keylet::mptokenIssuance(issuanceKey), view, j)
{
}
/**
* Returns true if the issuance is locked (lsfMPTLocked).
*
* @return true if lsfMPTLocked is set, false otherwise.
*/
[[nodiscard]] bool
isGlobalFrozen() const
{
return (*this)->isFlag(lsfMPTLocked);
}
/**
* Returns the issuance's MaximumAmount, or the protocol maximum if the
* field is absent. Never exceeds 2**63-1.
*
* @return the maximum amount that may be outstanding for this issuance.
*/
[[nodiscard]] std::int64_t
maxAmount() const;
};
using MPTokenIssuanceEntryR = MPTokenIssuanceEntry<ReadView>;
+3 -5
View File
@@ -3,6 +3,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
@@ -29,9 +30,6 @@ namespace xrpl {
[[nodiscard]] bool
isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue);
[[nodiscard]] bool
isGlobalFrozen(SLE const& issuanceSle);
/**
* Returns true if @p account's MPToken for @p mptIssue carries the
* individual-lock flag (lsfMPTLocked).
@@ -178,7 +176,7 @@ enforceMPTokenAuthorization(
* @return The underlying Asset (MPTIssue or Issue).
*/
[[nodiscard]] Asset
assetOfHolding(SLE const& sleShareIssuance, SLE const& sleHolding);
assetOfHolding(MPTokenIssuanceEntryR const& sleShareIssuance, SLE const& sleHolding);
/**
* Check whether @p to may receive the given MPT from @p from.
@@ -319,7 +317,7 @@ maxMPTAmount(SLE const& sleIssuance);
// OutstandingAmount may overflow and available amount might be negative.
// But available amount is always <= |MaximumAmount - OutstandingAmount|.
std::int64_t
availableMPTAmount(SLE const& sleIssuance);
availableMPTAmount(MPTokenIssuanceEntryR const& sleIssuance);
std::int64_t
availableMPTAmount(ReadView const& view, MPTID const& mptID);
+16 -6
View File
@@ -2,6 +2,7 @@
#include <xrpl/basics/Number.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Protocol.h>
@@ -29,7 +30,10 @@ 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(
SLE::ConstRef vault,
MPTokenIssuanceEntryR const& issuance,
STAmount const& assets);
/**
* From the perspective of a vault, return the number of assets to take from
@@ -43,7 +47,10 @@ 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(
SLE::ConstRef vault,
MPTokenIssuanceEntryR const& issuance,
STAmount const& shares);
/**
* Adjusts a requested asset change (`delta`) to match the decimal scale of the
@@ -132,7 +139,7 @@ debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
SLE::ConstRef vault,
SLE::ConstRef issuance,
MPTokenIssuanceEntryR const& issuance,
STAmount const& assets,
TruncateShares truncate = TruncateShares::No,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
@@ -153,7 +160,7 @@ assetsToSharesWithdraw(
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
SLE::ConstRef vault,
SLE::ConstRef issuance,
MPTokenIssuanceEntryR const& issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive = WaiveUnrealizedLoss::No);
@@ -168,7 +175,10 @@ sharesToAssetsWithdraw(
* both the share MPTID and the outstanding-amount total.
*/
[[nodiscard]] bool
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::ConstRef issuance);
isSoleShareholder(
ReadView const& view,
AccountID const& account,
MPTokenIssuanceEntryR const& issuance);
/**
* Resolves a Vault's LEVersion, the single point every accounting touch
@@ -295,7 +305,7 @@ enum class SuppressExpired : bool { No = false, Yes = true };
[[nodiscard]] TER
checkVaultDomain(
ReadView const& view,
SLE::ConstRef issuance,
MPTokenIssuanceEntryR const& issuance,
AccountID const& subject,
SuppressExpired suppressExpired);
@@ -3,6 +3,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/STAmount.h>
#include <xrpl/protocol/STTx.h>
@@ -49,7 +50,7 @@ private:
std::expected<std::pair<STAmount, STAmount>, TER>
assetsToClawback(
SLE::Ref vault,
SLE::ConstRef sleShareIssuance,
MPTokenIssuanceEntryR const& sleShareIssuance,
AccountID const& holder,
STAmount const& clawbackAmount);
};
+10 -9
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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -86,24 +87,24 @@ bool
isVaultPseudoAccountFrozenForIssuance(
ReadView const& view,
AccountID const& account,
SLE const& issuanceSle,
MPTokenIssuanceEntryR const& issuanceSle,
std::uint8_t depth)
{
XRPL_ASSERT(
issuanceSle.getType() == ltMPTOKEN_ISSUANCE,
issuanceSle->getType() == ltMPTOKEN_ISSUANCE,
"xrpl::isVaultPseudoAccountFrozenForIssuance : MPTokenIssuance SLE");
auto const issuer = issuanceSle.getAccountID(sfIssuer);
auto const issuer = issuanceSle->getAccountID(sfIssuer);
// Post-fixCleanup3_2_0: vault shares carry sfReferenceHolding pointing
// to the vault pseudo's MPToken or RippleState for the underlying.
// Read it to derive the underlying asset and recurse, skipping the
// issuer-account-then-vault chain. Pre-amendment shares (no field)
// fall back to the chain lookup below.
if (issuanceSle.isFieldPresent(sfReferenceHolding))
if (issuanceSle->isFieldPresent(sfReferenceHolding))
{
auto const sleHolding =
view.read(keylet::unchecked(issuanceSle.getFieldH256(sfReferenceHolding)));
view.read(keylet::unchecked(issuanceSle->getFieldH256(sfReferenceHolding)));
if (!sleHolding)
{
// LCOV_EXCL_START
@@ -144,7 +145,7 @@ bool
isVaultPseudoAccountFrozen(
ReadView const& view,
AccountID const& account,
SLE const& issuanceSle,
MPTokenIssuanceEntryR const& issuanceSle,
std::uint8_t depth)
{
if (auto const result = checkVaultPseudoAccountFrozenPreconditions(view, depth))
@@ -163,11 +164,11 @@ isVaultPseudoAccountFrozen(
if (auto const result = checkVaultPseudoAccountFrozenPreconditions(view, depth))
return *result;
auto const issuanceSle = view.read(keylet::mptokenIssuance(mptShare.getMptID()));
if (issuanceSle == nullptr)
MPTokenIssuanceEntryR const issuanceSle(mptShare.getMptID(), view);
if (!issuanceSle)
return false; // zero MPToken won't block deletion of MPTokenIssuance
return isVaultPseudoAccountFrozenForIssuance(view, account, *issuanceSle, depth);
return isVaultPseudoAccountFrozenForIssuance(view, account, issuanceSle, depth);
}
bool
@@ -0,0 +1,21 @@
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <cstdint>
namespace xrpl {
template <typename ViewT>
std::int64_t
MPTokenIssuanceEntry<ViewT>::maxAmount() const
{
return maxMPTAmount(**this);
}
template class MPTokenIssuanceEntry<ReadView>;
template class MPTokenIssuanceEntry<ApplyView>;
} // namespace xrpl
+41 -47
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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
@@ -41,20 +42,11 @@ namespace xrpl {
bool
isGlobalFrozen(ReadView const& view, MPTIssue const& mptIssue)
{
if (auto const sle = view.read(keylet::mptokenIssuance(mptIssue.getMptID())))
return isGlobalFrozen(*sle);
if (auto const sle = MPTokenIssuanceEntryR(mptIssue.getMptID(), view))
return sle.isGlobalFrozen();
return false;
}
bool
isGlobalFrozen(SLE const& issuanceSle)
{
XRPL_ASSERT(
issuanceSle.getType() == ltMPTOKEN_ISSUANCE, "xrpl::isGlobalFrozen : MPTokenIssuance SLE");
return issuanceSle.isFlag(lsfMPTLocked);
}
bool
isIndividualFrozen(ReadView const& view, AccountID const& account, MPTIssue const& mptIssue)
{
@@ -94,20 +86,23 @@ isFrozen(ReadView const& view, AccountID const& account, SLE const& sle, std::ui
XRPL_ASSERT(sle[sfAccount] == account, "xrpl::isFrozen : valid MPToken holder");
MPTID const mptID = sle[sfMPTokenIssuanceID];
auto const issuanceSle = view.read(keylet::mptokenIssuance(mptID));
MPTokenIssuanceEntryR const issuanceSle(mptID, view);
if ((issuanceSle && isGlobalFrozen(*issuanceSle)) || isIndividualFrozen(sle))
if ((issuanceSle && issuanceSle.isGlobalFrozen()) || isIndividualFrozen(sle))
return true;
if (issuanceSle)
return isVaultPseudoAccountFrozen(view, account, *issuanceSle, depth);
return isVaultPseudoAccountFrozen(view, account, issuanceSle, depth);
return isVaultPseudoAccountFrozen(view, account, MPTIssue{mptID}, depth);
}
// Non-owning pointer (aliasing constructor): the caller owns sle for the
// whole call, so this avoids copying the SLE.
MPTokenIssuanceEntryR const issuanceSle(SLE::const_pointer(SLE::const_pointer{}, &sle), view);
MPTIssue const mptIssue{sle[sfSequence], sle[sfIssuer]};
return isGlobalFrozen(sle) || isIndividualFrozen(view, account, mptIssue) ||
isVaultPseudoAccountFrozen(view, account, sle, depth);
return issuanceSle.isGlobalFrozen() || isIndividualFrozen(view, account, mptIssue) ||
isVaultPseudoAccountFrozen(view, account, issuanceSle, depth);
}
[[nodiscard]] bool
@@ -117,8 +112,8 @@ isAnyFrozen(
MPTIssue const& mptIssue,
std::uint8_t depth)
{
auto const issuanceSle = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
if (issuanceSle && isGlobalFrozen(*issuanceSle))
MPTokenIssuanceEntryR const issuanceSle(mptIssue.getMptID(), view);
if (issuanceSle && issuanceSle.isGlobalFrozen())
return true;
for (auto const& account : accounts)
@@ -135,7 +130,7 @@ isAnyFrozen(
});
};
return issuanceSle ? anyVaultFrozen(*issuanceSle) : anyVaultFrozen(mptIssue);
return issuanceSle ? anyVaultFrozen(issuanceSle) : anyVaultFrozen(mptIssue);
}
Rate
@@ -144,7 +139,7 @@ transferRate(ReadView const& view, MPTID const& issuanceID)
// fee is 0-50,000 (0-50%), rate is 1,000,000,000-2,000,000,000
// For example, if transfer fee is 50% then 10,000 * 50,000 = 500,000
// which represents 50% of 1,000,000,000
if (auto const sle = view.read(keylet::mptokenIssuance(issuanceID));
if (auto const sle = MPTokenIssuanceEntryR(issuanceID, view);
sle && sle->isFieldPresent(sfTransferFee))
{
auto const fee = sle->getFieldU16(sfTransferFee);
@@ -159,7 +154,7 @@ transferRate(ReadView const& view, MPTID const& issuanceID)
canAddHolding(ReadView const& view, MPTIssue const& mptIssue)
{
auto mptID = mptIssue.getMptID();
auto issuance = view.read(keylet::mptokenIssuance(mptID));
MPTokenIssuanceEntryR const issuance(mptID, view);
if (!issuance)
{
return tecOBJECT_NOT_FOUND;
@@ -181,7 +176,7 @@ addEmptyHolding(
beast::Journal journal)
{
auto const& mptID = mptIssue.getMptID();
auto const mpt = ctx.view.peek(keylet::mptokenIssuance(mptID));
MPTokenIssuanceEntryW mpt(mptID, ctx.view);
if (!mpt)
return tefINTERNAL; // LCOV_EXCL_LINE
// Unlike IOU addEmptyHolding (post-fixCleanup3_4_0), a locked issuance is
@@ -264,7 +259,7 @@ authorizeMPToken(
}
// Defensive check before we attempt to create MPToken for the issuer
auto const mpt = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const mpt(mptIssuanceID, ctx.view);
if (!mpt || mpt->getAccountID(sfIssuer) == account)
{
// LCOV_EXCL_START
@@ -291,7 +286,7 @@ authorizeMPToken(
return tesSUCCESS;
}
auto const sleMptIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleMptIssuance(mptIssuanceID, ctx.view);
if (!sleMptIssuance)
return tecINTERNAL; // LCOV_EXCL_LINE
@@ -390,7 +385,7 @@ requireAuth(
};
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
auto const sleIssuance = view.read(mptID);
MPTokenIssuanceEntryR const sleIssuance(mptID, view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -485,7 +480,7 @@ enforceMPTokenAuthorization(
XRPAmount const& priorBalance, // for MPToken authorization
beast::Journal j)
{
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
return tefINTERNAL; // LCOV_EXCL_LINE
@@ -578,21 +573,21 @@ enforceMPTokenAuthorization(
}
[[nodiscard]] Asset
assetOfHolding(SLE const& sleShareIssuance, SLE const& sleHolding)
assetOfHolding(MPTokenIssuanceEntryR const& sleShareIssuance, SLE const& sleHolding)
{
XRPL_ASSERT_PARTS(
sleHolding.getType() == ltRIPPLE_STATE || sleHolding.getType() == ltMPTOKEN,
"xrpl::assetOfHolding",
"unexpected holding type");
XRPL_ASSERT_PARTS(
sleShareIssuance.getType() == ltMPTOKEN_ISSUANCE,
sleShareIssuance->getType() == ltMPTOKEN_ISSUANCE,
"xrpl::assetOfHolding",
"not SLE MPTokenIssuance");
if (sleHolding.getType() == ltMPTOKEN)
return MPTIssue{sleHolding.getFieldH192(sfMPTokenIssuanceID)};
auto const vaultPseudo = sleShareIssuance.at(sfIssuer);
auto const vaultPseudo = sleShareIssuance->at(sfIssuer);
auto const lowLimit = sleHolding.getFieldAmount(sfLowLimit);
auto const highLimit = sleHolding.getFieldAmount(sfHighLimit);
auto const& iouIssuer =
@@ -609,8 +604,7 @@ canTransfer(
WaiveMPTCanTransfer waive,
std::uint8_t depth)
{
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
auto const sleIssuance = view.read(mptID);
MPTokenIssuanceEntryR const sleIssuance(mptIssue.getMptID(), view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -647,7 +641,7 @@ canTransfer(
return canTransfer(
view,
assetOfHolding(*sleIssuance, *sleHolding),
assetOfHolding(sleIssuance, *sleHolding),
from,
to,
WaiveMPTCanTransfer::No,
@@ -663,7 +657,7 @@ canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth)
return asset.visit(
[&](Issue const&) -> TER { return tesSUCCESS; },
[&](MPTIssue const& mptIssue) -> TER {
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
MPTokenIssuanceEntryR const sleIssuance(mptIssue.getMptID(), view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
if (!sleIssuance->isFlag(lsfMPTCanTrade))
@@ -690,7 +684,7 @@ canTrade(ReadView const& view, Asset const& asset, std::uint8_t depth)
if (!sleHolding)
return tefINTERNAL; // LCOV_EXCL_LINE
return canTrade(view, assetOfHolding(*sleIssuance, *sleHolding), depth + 1);
return canTrade(view, assetOfHolding(sleIssuance, *sleHolding), depth + 1);
}
return tesSUCCESS;
@@ -718,7 +712,7 @@ lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount,
{
auto const mptIssue = amount.get<MPTIssue>();
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
auto sleIssuance = view.peek(mptID);
MPTokenIssuanceEntryW sleIssuance(mptID, view);
if (!sleIssuance)
{ // LCOV_EXCL_START
JLOG(j.error()) << "lockEscrowMPT: MPT issuance not found for " << mptIssue.getMptID();
@@ -801,7 +795,7 @@ lockEscrowMPT(ApplyView& view, AccountID const& sender, STAmount const& amount,
sleIssuance->setFieldU64(sfLockedAmount, pay);
}
view.update(sleIssuance);
sleIssuance.update();
}
return tesSUCCESS;
}
@@ -823,7 +817,7 @@ unlockEscrowMPT(
auto const& issuer = netAmount.getIssuer();
auto const& mptIssue = netAmount.get<MPTIssue>();
auto const mptID = keylet::mptokenIssuance(mptIssue.getMptID());
auto sleIssuance = view.peek(mptID);
MPTokenIssuanceEntryW sleIssuance(mptID, view);
if (!sleIssuance)
{ // LCOV_EXCL_START
JLOG(j.error()) << "unlockEscrowMPT: MPT issuance not found for " << mptIssue.getMptID();
@@ -859,7 +853,7 @@ unlockEscrowMPT(
{
sleIssuance->setFieldU64(sfLockedAmount, newLocked);
}
view.update(sleIssuance);
sleIssuance.update();
}
if (issuer != receiver)
@@ -902,7 +896,7 @@ unlockEscrowMPT(
} // LCOV_EXCL_STOP
sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - redeem);
view.update(sleIssuance);
sleIssuance.update();
}
if (issuer == sender)
@@ -965,7 +959,7 @@ unlockEscrowMPT(
} // LCOV_EXCL_STOP
sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - diff);
view.update(sleIssuance);
sleIssuance.update();
}
return tesSUCCESS;
}
@@ -1048,20 +1042,20 @@ maxMPTAmount(SLE const& sleIssuance)
}
std::int64_t
availableMPTAmount(SLE const& sleIssuance)
availableMPTAmount(MPTokenIssuanceEntryR const& sleIssuance)
{
auto const max = maxMPTAmount(sleIssuance);
auto const outstanding = sleIssuance[sfOutstandingAmount];
auto const max = sleIssuance.maxAmount();
auto const outstanding = (*sleIssuance)[sfOutstandingAmount];
return max - outstanding;
}
std::int64_t
availableMPTAmount(ReadView const& view, MPTID const& mptID)
{
auto const sle = view.read(keylet::mptokenIssuance(mptID));
MPTokenIssuanceEntryR const sle(mptID, view);
if (!sle)
Throw<std::runtime_error>(transHuman(tecINTERNAL));
return availableMPTAmount(*sle);
return availableMPTAmount(sle);
}
bool
@@ -1082,10 +1076,10 @@ issuerFundsToSelfIssue(ReadView const& view, MPTIssue const& issue)
{
STAmount amount{issue};
auto const sle = view.read(keylet::mptokenIssuance(issue));
MPTokenIssuanceEntryR const sle(issue.getMptID(), view);
if (!sle)
return amount;
auto const available = availableMPTAmount(*sle);
auto const available = availableMPTAmount(sle);
return view.balanceHookSelfIssueMPT(issue, available);
}
+12 -11
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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/RippleStateHelpers.h>
@@ -424,13 +425,13 @@ accountHolds(
{
// if the account is the issuer, and the issuance exists, their limit is
// the issuance limit minus the outstanding value
auto const issuance = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
MPTokenIssuanceEntryR const issuance(mptIssue.getMptID(), view);
if (!issuance)
{
return amount;
}
auto const available = availableMPTAmount(*issuance);
auto const available = availableMPTAmount(issuance);
if (!mptokensV2)
return STAmount{mptIssue, available};
return view.balanceHookMPT(issuer, mptIssue, available);
@@ -459,7 +460,7 @@ accountHolds(
}
else if (zeroIfUnauthorized == AuthHandling::ZeroIfUnauthorized)
{
auto const sleIssuance = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
MPTokenIssuanceEntryR const sleIssuance(mptIssue.getMptID(), view);
// if auth is enabled on the issuance and mpt is not authorized,
// clear amount
@@ -1217,13 +1218,13 @@ directSendNoFeeMPT(
// Do not check MPT authorization here - it must have been checked earlier
auto const mptID = keylet::mptokenIssuance(saAmount.get<MPTIssue>().getMptID());
auto const& issuer = saAmount.getIssuer();
auto sleIssuance = view.peek(mptID);
MPTokenIssuanceEntryW sleIssuance(mptID, view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
auto const maxAmount = maxMPTAmount(*sleIssuance);
auto const maxAmount = sleIssuance.maxAmount();
auto const outstanding = sleIssuance->getFieldU64(sfOutstandingAmount);
auto const available = availableMPTAmount(*sleIssuance);
auto const available = availableMPTAmount(sleIssuance);
auto const amt = saAmount.mpt().value();
if (uSenderID == issuer)
@@ -1234,7 +1235,7 @@ directSendNoFeeMPT(
return tecPATH_DRY;
}
(*sleIssuance)[sfOutstandingAmount] += amt;
view.update(sleIssuance);
sleIssuance.update();
}
else
{
@@ -1259,7 +1260,7 @@ directSendNoFeeMPT(
if (outstanding >= amt)
{
sleIssuance->setFieldU64(sfOutstandingAmount, outstanding - amt);
view.update(sleIssuance);
sleIssuance.update();
}
else
{
@@ -1307,7 +1308,7 @@ directSendNoLimitMPT(
// Safe to get MPT since directSendNoLimitMPT is only called by accountSendMPT
auto const& issuer = saAmount.getIssuer();
auto const sle = view.read(keylet::mptokenIssuance(saAmount.get<MPTIssue>().getMptID()));
MPTokenIssuanceEntryR const sle(saAmount.get<MPTIssue>().getMptID(), view);
if (!sle)
return tecOBJECT_NOT_FOUND;
@@ -1318,7 +1319,7 @@ directSendNoLimitMPT(
if (uSenderID == issuer)
{
auto const sendAmount = saAmount.mpt().value();
auto const maxAmount = maxMPTAmount(*sle);
auto const maxAmount = sle.maxAmount();
auto const outstanding = sle->getFieldU64(sfOutstandingAmount);
auto const mptokensV2 = view.rules().enabled(featureMPTokensV2);
allowOverflow = (allowOverflow == AllowMPTOverflow::Yes && mptokensV2)
@@ -1364,7 +1365,7 @@ directSendNoLimitMultiMPT(
{
auto const& issuer = mptIssue.getIssuer();
auto const sle = view.read(keylet::mptokenIssuance(mptIssue.getMptID()));
MPTokenIssuanceEntryR const sle(mptIssue.getMptID(), view);
if (!sle)
return tecOBJECT_NOT_FOUND;
+16 -6
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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/protocol/AccountID.h>
#include <xrpl/protocol/Indexes.h>
@@ -25,7 +26,10 @@
namespace xrpl {
[[nodiscard]] std::optional<STAmount>
assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& assets)
assetsToSharesDeposit(
SLE::ConstRef vault,
MPTokenIssuanceEntryR const& issuance,
STAmount const& assets)
{
XRPL_ASSERT(!assets.negative(), "xrpl::assetsToSharesDeposit : non-negative assets");
XRPL_ASSERT(
@@ -49,7 +53,10 @@ assetsToSharesDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount cons
}
[[nodiscard]] std::optional<STAmount>
sharesToAssetsDeposit(SLE::ConstRef vault, SLE::ConstRef issuance, STAmount const& shares)
sharesToAssetsDeposit(
SLE::ConstRef vault,
MPTokenIssuanceEntryR const& issuance,
STAmount const& shares)
{
XRPL_ASSERT(!shares.negative(), "xrpl::sharesToAssetsDeposit : non-negative shares");
XRPL_ASSERT(
@@ -150,7 +157,7 @@ debitIsNonZeroDust(Asset const& asset, Number const& total, Number const& amount
[[nodiscard]] std::optional<STAmount>
assetsToSharesWithdraw(
SLE::ConstRef vault,
SLE::ConstRef issuance,
MPTokenIssuanceEntryR const& issuance,
STAmount const& assets,
TruncateShares truncate,
WaiveUnrealizedLoss waive)
@@ -177,7 +184,7 @@ assetsToSharesWithdraw(
[[nodiscard]] std::optional<STAmount>
sharesToAssetsWithdraw(
SLE::ConstRef vault,
SLE::ConstRef issuance,
MPTokenIssuanceEntryR const& issuance,
STAmount const& shares,
WaiveUnrealizedLoss waive)
{
@@ -198,7 +205,10 @@ sharesToAssetsWithdraw(
}
[[nodiscard]] bool
isSoleShareholder(ReadView const& view, AccountID const& account, SLE::ConstRef issuance)
isSoleShareholder(
ReadView const& view,
AccountID const& account,
MPTokenIssuanceEntryR const& issuance)
{
XRPL_ASSERT(
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE,
@@ -308,7 +318,7 @@ getVaultPhase(
[[nodiscard]] TER
checkVaultDomain(
ReadView const& view,
SLE::ConstRef issuance,
MPTokenIssuanceEntryR const& issuance,
AccountID const& subject,
SuppressExpired suppressExpired)
{
+3 -2
View File
@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/PaymentSandbox.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -471,7 +472,7 @@ MPTEndpointStep<TDerived>::maxPaymentFlow(ReadView const& sb) const
return {toAmount<MPTAmount>(maxFlow), DebtDirection::Redeems};
// From an issuer to a holder
if (auto const sle = sb.read(keylet::mptokenIssuance(mptIssue_)))
if (auto const sle = MPTokenIssuanceEntryR(mptIssue_.getMptID(), sb))
{
// If issuer is the source account, and it is direct payment then
// MPTEndpointStep is the only step. Provide available maxFlow.
@@ -483,7 +484,7 @@ MPTEndpointStep<TDerived>::maxPaymentFlow(ReadView const& sb) const
// the previous step may issue or redeem. Allow OutstandingAmount
// to temporarily overflow. Let the previous step figure out how
// to limit the flow.
std::int64_t const maxAmount = maxMPTAmount(*sle);
std::int64_t const maxAmount = sle.maxAmount();
return {MPTAmount{maxAmount}, DebtDirection::Issues};
}
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -136,7 +137,7 @@ AMMClawback::preclaim(PreclaimContext const& ctx)
!sleIssuer->isFlag(lsfNoFreeze);
},
[&](MPTIssue const& issue) {
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(issue.getMptID()));
MPTokenIssuanceEntryR const sleIssuance(issue.getMptID(), ctx.view);
return sleIssuance && sleIssuance->isFlag(lsfMPTCanClawback) &&
sleIssuance->getAccountID(sfIssuer) == ctx.tx[sfAccount];
+2 -1
View File
@@ -5,6 +5,7 @@
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/Sandbox.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AMMHelpers.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -227,7 +228,7 @@ AMMCreate::preclaim(PreclaimContext const& ctx)
auto clawbackDisabled = [&](Asset const& asset) -> TER {
return asset.visit(
[&](MPTIssue const& issue) -> TER {
auto const sle = ctx.view.read(keylet::mptokenIssuance(issue.getMptID()));
MPTokenIssuanceEntryR const sle(issue.getMptID(), ctx.view);
if (!sle)
return tecINTERNAL; // LCOV_EXCL_LINE
if (sle->isFlag(lsfMPTCanClawback))
@@ -3,6 +3,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/EscrowHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -73,8 +74,7 @@ escrowCancelPreclaimHelper<MPTIssue>(
return tecINTERNAL; // LCOV_EXCL_LINE
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = ctx.view.read(issuanceKey);
MPTokenIssuanceEntryR const sleIssuance(amount.get<MPTIssue>().getMptID(), ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -7,6 +7,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
@@ -278,7 +279,7 @@ escrowCreatePreclaimHelper<MPTIssue>(
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = ctx.view.read(issuanceKey);
MPTokenIssuanceEntryR const sleIssuance(issuanceKey, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -9,6 +9,7 @@
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/EscrowHelpers.h>
@@ -179,8 +180,7 @@ escrowFinishPreclaimHelper<MPTIssue>(
return tesSUCCESS;
// If the mpt does not exist, return tecOBJECT_NOT_FOUND
auto const issuanceKey = keylet::mptokenIssuance(amount.get<MPTIssue>().getMptID());
auto const sleIssuance = ctx.view.read(issuanceKey);
MPTokenIssuanceEntryR const sleIssuance(amount.get<MPTIssue>().getMptID(), ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/LendingHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -218,8 +219,7 @@ preclaimHelper<MPTIssue>(
SLE const& sleIssuer,
STAmount const& clawAmount)
{
auto const issuanceKey = keylet::mptokenIssuance(clawAmount.get<MPTIssue>().getMptID());
auto const sleIssuance = ctx.view.read(issuanceKey);
MPTokenIssuanceEntryR const sleIssuance(clawAmount.get<MPTIssue>().getMptID(), ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -2,6 +2,7 @@
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/AccountID.h>
@@ -154,7 +155,7 @@ preclaimHelper<MPTIssue>(
STAmount const& clawAmount)
{
auto const issuanceKey = keylet::mptokenIssuance(clawAmount.get<MPTIssue>().getMptID());
auto const sleIssuance = ctx.view.read(issuanceKey);
MPTokenIssuanceEntryR const sleIssuance(issuanceKey, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -4,6 +4,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -66,7 +67,7 @@ ConfidentialMPTClawback::preclaim(PreclaimContext const& ctx)
// Check if MPT issuance exists
auto const mptIssuanceID = ctx.tx[sfMPTokenIssuanceID];
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -132,7 +133,7 @@ ConfidentialMPTClawback::doApply()
auto const mptIssuanceID = ctx_.tx[sfMPTokenIssuanceID];
auto const holder = ctx_.tx[sfHolder];
auto sleIssuance = view().peek(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryW sleIssuance(mptIssuanceID, view(), j_);
auto sleHolderMPToken = view().peek(keylet::mptoken(mptIssuanceID, holder));
if (!sleIssuance || !sleHolderMPToken)
@@ -229,7 +230,7 @@ ConfidentialMPTClawback::doApply()
(*sleIssuance)[sfOutstandingAmount] = oldOA - clawAmount;
view().update(sleHolderMPToken);
view().update(sleIssuance);
sleIssuance.update();
return tesSUCCESS;
}
@@ -6,6 +6,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
@@ -78,7 +79,7 @@ ConfidentialMPTConvert::preclaim(PreclaimContext const& ctx)
auto const amount = ctx.tx[sfMPTAmount];
// ensure that issuance exists
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(issuanceID));
MPTokenIssuanceEntryR const sleIssuance(issuanceID, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -236,7 +237,7 @@ ConfidentialMPTConvert::doApply()
// LCOV_EXCL_STOP
}
auto sleIssuance = view().peek(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryW sleIssuance(mptIssuanceID, view(), j_);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -376,7 +377,7 @@ ConfidentialMPTConvert::doApply()
// LCOV_EXCL_STOP
}
view().update(sleIssuance);
sleIssuance.update();
view().update(sleMptoken);
return tesSUCCESS;
}
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
@@ -70,7 +71,7 @@ ConfidentialMPTConvertBack::calculateBaseFee(ReadView const& view, STTx const& t
static TER
verifyProofs(
STTx const& tx,
std::shared_ptr<SLE const> const& issuance,
MPTokenIssuanceEntryR const& issuance,
std::shared_ptr<SLE const> const& mptoken)
{
if (!mptoken->isFieldPresent(sfHolderEncryptionKey))
@@ -154,7 +155,7 @@ ConfidentialMPTConvertBack::preclaim(PreclaimContext const& ctx)
auto const amount = ctx.tx[sfMPTAmount];
// ensure that issuance exists
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -255,7 +256,7 @@ ConfidentialMPTConvertBack::doApply()
// LCOV_EXCL_STOP
}
auto sleIssuance = view().peek(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryW sleIssuance(mptIssuanceID, view(), j_);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -333,7 +334,7 @@ ConfidentialMPTConvertBack::doApply()
incrementConfidentialVersion(*sleMptoken);
view().update(sleIssuance);
sleIssuance.update();
view().update(sleMptoken);
return tesSUCCESS;
}
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -109,7 +110,7 @@ ConfidentialMPTHolderKeyUpdate::preclaim(PreclaimContext const& ctx)
auto const account = ctx.tx[sfAccount];
auto const mptIssuanceID = ctx.tx[sfMPTokenIssuanceID];
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
auto const sleIssuance = MPTokenIssuanceEntryR(mptIssuanceID, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Indexes.h>
@@ -40,7 +41,7 @@ ConfidentialMPTMergeInbox::calculateBaseFee(ReadView const& view, STTx const& tx
TER
ConfidentialMPTMergeInbox::preclaim(PreclaimContext const& ctx)
{
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(ctx.tx[sfMPTokenIssuanceID]));
MPTokenIssuanceEntryR const sleIssuance(ctx.tx[sfMPTokenIssuanceID], ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -99,7 +100,7 @@ ConfidentialMPTMirrorUpdate::preclaim(PreclaimContext const& ctx)
// The issuance must exist and have confidential balances enabled with a
// registered issuer encryption key; otherwise there is no mirror to update.
auto const mptIssuanceID = ctx.tx[sfMPTokenIssuanceID];
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -209,7 +210,7 @@ ConfidentialMPTMirrorUpdate::doApply()
{
auto const mptIssuanceID = ctx_.tx[sfMPTokenIssuanceID];
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, view());
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
@@ -102,7 +103,7 @@ verifySendProofs(
PreclaimContext const& ctx,
std::shared_ptr<SLE const> const& sleSenderMPToken,
std::shared_ptr<SLE const> const& sleDestinationMPToken,
std::shared_ptr<SLE const> const& sleIssuance)
MPTokenIssuanceEntryR const& sleIssuance)
{
// Sanity check
if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance)
@@ -180,7 +181,7 @@ ConfidentialMPTSend::preclaim(PreclaimContext const& ctx)
// Check if MPT issuance exists
auto const mptIssuanceID = ctx.tx[sfMPTokenIssuanceID];
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
return tecOBJECT_NOT_FOUND;
@@ -307,7 +308,7 @@ ConfidentialMPTSend::doApply()
auto sleSenderMPToken = view().peek(keylet::mptoken(mptIssuanceID, accountID_));
auto sleDestinationMPToken = view().peek(keylet::mptoken(mptIssuanceID, destination));
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, view());
auto const sleDestAcct = view().read(keylet::account(destination));
@@ -1,6 +1,7 @@
#include <xrpl/tx/transactors/token/MPTokenAuthorize.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/protocol/Feature.h>
@@ -37,7 +38,7 @@ MPTokenAuthorize::preclaim(PreclaimContext const& ctx)
{
auto const accountID = ctx.tx[sfAccount];
auto const holderID = ctx.tx[~sfHolder];
auto const sleMptIssuance = ctx.view.read(keylet::mptokenIssuance(ctx.tx[sfMPTokenIssuanceID]));
MPTokenIssuanceEntryR const sleMptIssuance(ctx.tx[sfMPTokenIssuanceID], ctx.view);
// if non-issuer account submits this tx, then they are trying either:
// 1. Unauthorize/delete MPToken
@@ -5,6 +5,7 @@
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ApplyView.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/DirectoryHelpers.h>
#include <xrpl/ledger/helpers/SponsorHelpers.h>
@@ -154,7 +155,8 @@ MPTokenIssuanceCreate::create(
if (!ownerNode)
return std::unexpected(tecDIR_FULL); // LCOV_EXCL_LINE
auto mptIssuance = std::make_shared<SLE>(mptIssuanceKeylet);
MPTokenIssuanceEntryW mptIssuance(mptIssuanceKeylet, ctx.view, journal);
mptIssuance.newSLE();
(*mptIssuance)[sfFlags] = args.flags & ~tfUniversal;
(*mptIssuance)[sfIssuer] = args.account;
(*mptIssuance)[sfOutstandingAmount] = 0;
@@ -195,9 +197,9 @@ MPTokenIssuanceCreate::create(
(*mptIssuance)[sfReferenceHolding] = *args.referenceHolding;
}
addSponsorToLedgerEntry(mptIssuance, sponsorSle);
addSponsorToLedgerEntry(mptIssuance.mutableRawSle(), sponsorSle);
ctx.view.insert(mptIssuance);
mptIssuance.insert();
}
// Update owner count.
@@ -1,5 +1,7 @@
#include <xrpl/tx/transactors/token/MPTokenIssuanceDestroy.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/SField.h>
@@ -21,7 +23,7 @@ TER
MPTokenIssuanceDestroy::preclaim(PreclaimContext const& ctx)
{
// ensure that issuance exists
auto const sleMPT = ctx.view.read(keylet::mptokenIssuance(ctx.tx[sfMPTokenIssuanceID]));
MPTokenIssuanceEntryR const sleMPT(ctx.tx[sfMPTokenIssuanceID], ctx.view);
if (!sleMPT)
return tecOBJECT_NOT_FOUND;
@@ -42,15 +44,15 @@ MPTokenIssuanceDestroy::preclaim(PreclaimContext const& ctx)
TER
MPTokenIssuanceDestroy::doApply()
{
auto const mpt = view().peek(keylet::mptokenIssuance(ctx_.tx[sfMPTokenIssuanceID]));
MPTokenIssuanceEntryW mpt(ctx_.tx[sfMPTokenIssuanceID], view(), j_);
if (accountID_ != mpt->getAccountID(sfIssuer))
return tecINTERNAL; // LCOV_EXCL_LINE
if (!view().dirRemove(keylet::ownerDir(accountID_), (*mpt)[sfOwnerNode], mpt->key(), false))
return tefBAD_LEDGER; // LCOV_EXCL_LINE
decreaseOwnerCountForObject(view(), accountID_, mpt, 1, j_);
view().erase(mpt);
decreaseOwnerCountForObject(view(), accountID_, mpt.mutableRawSle(), 1, j_);
mpt.erase();
return tesSUCCESS;
}
@@ -5,6 +5,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/core/ServiceRegistry.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/ConfidentialTransfer.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
@@ -143,7 +144,7 @@ TER
MPTokenIssuanceSet::preclaim(PreclaimContext const& ctx)
{
// ensure that issuance exists
auto const sleMptIssuance = ctx.view.read(keylet::mptokenIssuance(ctx.tx[sfMPTokenIssuanceID]));
MPTokenIssuanceEntryR const sleMptIssuance(ctx.tx[sfMPTokenIssuanceID], ctx.view);
if (!sleMptIssuance)
return tecOBJECT_NOT_FOUND;
@@ -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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
@@ -87,7 +88,7 @@ VaultClawback::preclaim(PreclaimContext const& ctx)
auto const holder = ctx.tx[sfHolder];
auto const maybeAmount = ctx.tx[~sfAmount];
auto const mptIssuanceID = vault->at(sfShareMPTID);
auto const sleShareIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleShareIssuance(mptIssuanceID, ctx.view);
if (!sleShareIssuance)
{
// LCOV_EXCL_START
@@ -192,8 +193,8 @@ VaultClawback::preclaim(PreclaimContext const& ctx)
return vaultAsset.visit(
[&](MPTIssue const& issue) -> TER {
auto const mptIssue = ctx.view.read(keylet::mptokenIssuance(issue.getMptID()));
if (mptIssue == nullptr)
MPTokenIssuanceEntryR const mptIssue(issue.getMptID(), ctx.view);
if (!mptIssue)
return tecOBJECT_NOT_FOUND;
if (!mptIssue->isFlag(lsfMPTCanClawback))
@@ -233,7 +234,7 @@ VaultClawback::preclaim(PreclaimContext const& ctx)
std::expected<std::pair<STAmount, STAmount>, TER>
VaultClawback::assetsToClawback(
SLE::Ref vault,
SLE::ConstRef sleShareIssuance,
MPTokenIssuanceEntryR const& sleShareIssuance,
AccountID const& holder,
STAmount const& clawbackAmount)
{
@@ -395,7 +396,7 @@ VaultClawback::doApply()
return tefINTERNAL; // LCOV_EXCL_LINE
auto const mptIssuanceID = *vault->at(sfShareMPTID);
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, view());
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -66,7 +67,7 @@ VaultDelete::preclaim(PreclaimContext const& ctx)
}
// Verify we can destroy MPTokenIssuance
auto const sleMPT = ctx.view.read(keylet::mptokenIssuance(vault->at(sfShareMPTID)));
MPTokenIssuanceEntryR const sleMPT(vault->at(sfShareMPTID), ctx.view);
if (!sleMPT)
{
@@ -121,7 +122,7 @@ VaultDelete::doApply()
// Destroy the share issuance. Do not use MPTokenIssuanceDestroy for this,
// no special logic needed. First run few checks, duplicated from preclaim.
auto const shareMPTID = *vault->at(sfShareMPTID);
auto const mpt = view().peek(keylet::mptokenIssuance(shareMPTID));
MPTokenIssuanceEntryW mpt(shareMPTID, view(), j_);
if (!mpt)
{
// LCOV_EXCL_START
@@ -155,9 +156,9 @@ VaultDelete::doApply()
return tefBAD_LEDGER;
// LCOV_EXCL_STOP
}
decreaseOwnerCountForObject(view(), pseudoAcct, mpt, 1, j_);
decreaseOwnerCountForObject(view(), pseudoAcct, mpt.mutableRawSle(), 1, j_);
view().erase(mpt);
mpt.erase();
// The pseudo-account's directory should have been deleted already.
if (view().peek(keylet::ownerDir(pseudoID)))
@@ -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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/MPTokenHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
@@ -141,7 +142,7 @@ VaultDeposit::preclaim(PreclaimContext const& ctx)
// LCOV_EXCL_STOP
}
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -253,7 +254,7 @@ VaultDeposit::doApply()
// Make sure the depositor can hold shares.
auto const mptIssuanceID = (*vault)[sfShareMPTID];
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, view());
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -2,6 +2,7 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/protocol/Feature.h>
#include <xrpl/protocol/Indexes.h>
#include <xrpl/protocol/LedgerFormats.h>
@@ -75,7 +76,7 @@ VaultSet::preclaim(PreclaimContext const& ctx)
}
auto const mptIssuanceID = (*vault)[sfShareMPTID];
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, ctx.view);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -130,7 +131,7 @@ VaultSet::doApply()
auto const vaultAsset = vault->at(sfAsset);
auto const mptIssuanceID = (*vault)[sfShareMPTID];
auto const sleIssuance = view().peek(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryW sleIssuance(mptIssuanceID, view(), j_);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -164,7 +165,7 @@ VaultSet::doApply()
{
sleIssuance->makeFieldAbsent(sfDomainID);
}
view().update(sleIssuance);
sleIssuance.update();
}
// Note, we must update Vault object even if only DomainID is being updated
@@ -7,6 +7,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/ledger/ReadView.h>
#include <xrpl/ledger/View.h>
#include <xrpl/ledger/entries/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/AccountRootHelpers.h>
#include <xrpl/ledger/helpers/CredentialHelpers.h>
#include <xrpl/ledger/helpers/TokenHelpers.h>
@@ -38,7 +39,10 @@ VaultWithdraw::checkExtraFeatures(PreflightContext const& ctx)
}
static WaiveUnrealizedLoss
shouldWaiveWithdrawal(ReadView const& view, AccountID const& account, SLE::ConstRef issuance)
shouldWaiveWithdrawal(
ReadView const& view,
AccountID const& account,
MPTokenIssuanceEntryR const& issuance)
{
XRPL_ASSERT(
issuance && issuance->getType() == ltMPTOKEN_ISSUANCE,
@@ -150,7 +154,7 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
// to the equivalent asset amount before checking withdrawal
// limits. Pre-amendment the limit check was skipped for
// share-denominated withdrawals.
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(vaultShare));
MPTokenIssuanceEntryR const sleIssuance(vaultShare, ctx.view);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -227,7 +231,7 @@ VaultWithdraw::preclaim(PreclaimContext const& ctx)
if (fix340Enabled && vault->isFlag(lsfVaultPrivate) && dstAcct != account &&
dstAcct != vaultAsset.getIssuer())
{
auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(vaultShare));
MPTokenIssuanceEntryR const sleIssuance(vaultShare, ctx.view);
if (!sleIssuance)
{
// LCOV_EXCL_START
@@ -284,7 +288,7 @@ VaultWithdraw::doApply()
return tefINTERNAL; // LCOV_EXCL_LINE
auto const mptIssuanceID = *((*vault)[sfShareMPTID]);
auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
MPTokenIssuanceEntryR const sleIssuance(mptIssuanceID, view());
if (!sleIssuance)
{
// LCOV_EXCL_START
+2 -1
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/MPTokenIssuanceEntry.h>
#include <xrpl/ledger/helpers/VaultHelpers.h>
#include <xrpl/protocol/Asset.h>
#include <xrpl/protocol/Feature.h>
@@ -1522,7 +1523,7 @@ private:
// assuming an exact 90/10 split holds under truncation.
auto const maybeSharesDestroyed = assetsToSharesWithdraw(
vaultBefore,
issuanceBefore,
MPTokenIssuanceEntryR(issuanceBefore, *env.current()),
setup.usd(9'000).value(),
TruncateShares::Yes,
WaiveUnrealizedLoss::Yes);
+14 -3
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>