1#include <xrpl/tx/transactors/token/MPTokenIssuanceSet.h>
3#include <xrpl/beast/utility/Journal.h>
4#include <xrpl/beast/utility/Zero.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/core/ServiceRegistry.h>
7#include <xrpl/ledger/ReadView.h>
8#include <xrpl/protocol/ConfidentialTransfer.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Indexes.h>
11#include <xrpl/protocol/LedgerFormats.h>
12#include <xrpl/protocol/Permissions.h>
13#include <xrpl/protocol/Protocol.h>
14#include <xrpl/protocol/SField.h>
15#include <xrpl/protocol/STLedgerEntry.h>
16#include <xrpl/protocol/STTx.h>
17#include <xrpl/protocol/TER.h>
18#include <xrpl/protocol/TxFlags.h>
19#include <xrpl/protocol/XRPAmount.h>
20#include <xrpl/tx/Transactor.h>
38 return tfMPTokenIssuanceSetMask;
46 auto const metadata = ctx.
tx[~sfMPTokenMetadata];
47 auto const transferFee = ctx.
tx[~sfTransferFee];
48 auto const immutableFlags = ctx.
tx[~sfImmutableFlags];
49 auto const isMutate = (enableFlags != 0u) || metadata || transferFee || immutableFlags;
50 auto const hasIssuerElGamalKey = ctx.
tx.
isFieldPresent(sfIssuerEncryptionKey);
51 auto const hasAuditorElGamalKey = ctx.
tx.
isFieldPresent(sfAuditorEncryptionKey);
53 bool const enablePrivacy = (enableFlags & tfMPTSetCanHoldConfidentialBalance) != 0u;
60 bool const setConfidentialBalanceImmutable =
62 if ((hasIssuerElGamalKey || hasAuditorElGamalKey || enablePrivacy ||
63 setConfidentialBalanceImmutable) &&
67 if (hasDomain && hasHolder)
70 if (enablePrivacy && hasHolder)
77 auto const accountID = ctx.
tx[sfAccount];
78 auto const holderID = ctx.
tx[~sfHolder];
79 if (holderID && accountID == holderID)
86 if (txFlags == 0 && !hasDomain && !hasIssuerElGamalKey && !hasAuditorElGamalKey &&
94 if (isMutate && holderID)
105 if (transferFee && *transferFee > 0u && enablePrivacy)
113 if (immutableFlags &&
114 ((*immutableFlags == 0u) ||
119 if (hasHolder && (hasIssuerElGamalKey || hasAuditorElGamalKey))
129 if (hasAuditorElGamalKey && !hasIssuerElGamalKey &&
150 if (!sleMptIssuance->isFlag(lsfMPTCanLock))
165 if ((*sleMptIssuance)[sfIssuer] != ctx.
tx[sfAccount])
168 if (
auto const holderID = ctx.
tx[~sfHolder])
179 if (
auto const domain = ctx.
tx[~sfDomainID])
181 if (not sleMptIssuance->isFlag(lsfMPTRequireAuth))
194 auto const currentImmutableFlags = sleMptIssuance->getFieldU32(sfImmutableFlags);
196 auto isImmutable = [&](
std::uint32_t flag) ->
bool {
return currentImmutableFlags & flag; };
199 if (enableFlags != 0u)
203 return isImmutable(f.immutableFlag) && ctx.
tx.
isFlag(f.setFlag);
211 if (
auto const fee = ctx.
tx[~sfTransferFee])
216 if (fee > 0u && !sleMptIssuance->isFlag(lsfMPTCanTransfer) &&
217 (enableFlags & tfMPTSetCanTransfer) == 0u)
222 if (fee > 0u && sleMptIssuance->isFlag(lsfMPTCanHoldConfidentialBalance))
232 bool const canRotateKey = ctx.
view.
rules().
enabled(featureConfidentialMPTKeyRotation);
236 bool const sleHasIssuerKey = sleMptIssuance->isFieldPresent(sfIssuerEncryptionKey);
237 bool const sleHasAuditorKey = sleMptIssuance->isFieldPresent(sfAuditorEncryptionKey);
244 bool const registersAuditorKey = txHasAuditorKey && !sleHasAuditorKey;
245 bool const issuerKeyExists = sleHasIssuerKey || txHasIssuerKey;
246 if (registersAuditorKey && !issuerKeyExists)
251 if (txHasIssuerKey && sleHasIssuerKey &&
252 ctx.
tx[sfIssuerEncryptionKey] == (*sleMptIssuance)[sfIssuerEncryptionKey])
255 if (txHasAuditorKey && sleHasAuditorKey &&
256 ctx.
tx[sfAuditorEncryptionKey] == (*sleMptIssuance)[sfAuditorEncryptionKey])
263 if (txHasIssuerKey && sleHasIssuerKey &&
264 (*sleMptIssuance)[~sfIssuerKeyEpoch].value_or(0) ==
kMaxKeyEpoch)
267 if (txHasAuditorKey && sleHasAuditorKey &&
268 (*sleMptIssuance)[~sfAuditorKeyEpoch].value_or(0) ==
kMaxKeyEpoch)
275 if (txHasIssuerKey && sleHasIssuerKey)
279 if (txHasAuditorKey && sleHasAuditorKey)
283 auto const enablesConfidentialBalance =
284 (enableFlags & tfMPTSetCanHoldConfidentialBalance) != 0u;
285 if (enablesConfidentialBalance && sleMptIssuance->isFieldPresent(sfTransferFee) &&
286 (*sleMptIssuance)[sfTransferFee] > 0u)
291 if (txHasIssuerKey && !sleMptIssuance->isFlag(lsfMPTCanHoldConfidentialBalance) &&
292 !enablesConfidentialBalance)
297 if (txHasAuditorKey && !sleMptIssuance->isFlag(lsfMPTCanHoldConfidentialBalance) &&
298 !enablesConfidentialBalance)
303 bool const hasConfidentialOA =
304 (*sleMptIssuance)[~sfConfidentialOutstandingAmount].value_or(0) > 0;
308 if (!canRotateKey && (txHasIssuerKey || txHasAuditorKey) && hasConfidentialOA)
313 if (enablesConfidentialBalance && hasConfidentialOA)
322 auto const mptIssuanceID =
ctx_.tx[sfMPTokenIssuanceID];
323 auto const holderID =
ctx_.tx[~sfHolder];
324 auto const domainID =
ctx_.tx[~sfDomainID];
342 if (
ctx_.tx.isFlag(tfMPTLock))
344 flagsOut |= lsfMPTLocked;
346 else if (
ctx_.tx.isFlag(tfMPTUnlock))
348 flagsOut &= ~lsfMPTLocked;
356 if (
ctx_.tx.isFlag(f.setFlag))
358 flagsOut |= f.ledgerFlag;
363 if (flagsIn != flagsOut)
364 sle->setFieldU32(sfFlags, flagsOut);
366 if (
auto const immutableFlags =
ctx_.tx[~sfImmutableFlags])
377 sle->getType() == ltMPTOKEN_ISSUANCE,
378 "MPTokenIssuanceSet::doApply : modifying MPTokenIssuance");
380 if (sle->getType() != ltMPTOKEN_ISSUANCE)
383 (*sle)[sfImmutableFlags] = (*sle)[sfImmutableFlags] | *immutableFlags;
386 if (
auto const transferFee =
ctx_.tx[~sfTransferFee])
392 if (transferFee == 0)
394 sle->makeFieldAbsent(sfTransferFee);
398 sle->setFieldU16(sfTransferFee, *transferFee);
402 if (
auto const metadata =
ctx_.tx[~sfMPTokenMetadata])
404 if (metadata->empty())
406 sle->makeFieldAbsent(sfMPTokenMetadata);
410 sle->setFieldVL(sfMPTokenMetadata, *metadata);
418 sle->getType() == ltMPTOKEN_ISSUANCE,
419 "MPTokenIssuanceSet::doApply : modifying MPTokenIssuance");
423 sle->setFieldH256(sfDomainID, *domainID);
427 if (sle->isFieldPresent(sfDomainID))
428 sle->makeFieldAbsent(sfDomainID);
437 bool const canRotateKey =
view().
rules().
enabled(featureConfidentialMPTKeyRotation);
438 auto const setEncryptionKey = [&](
SF_VL const& keyField,
SF_UINT32 const& epochField) ->
TER {
439 auto const pubKey =
ctx_.tx[~keyField];
446 sle->getType() == ltMPTOKEN_ISSUANCE,
447 "MPTokenIssuanceSet::doApply : modifying MPTokenIssuance");
452 if (canRotateKey && sle->getType() != ltMPTOKEN_ISSUANCE)
456 bool const isRotation = sle->isFieldPresent(keyField);
457 sle->setFieldVL(keyField, *pubKey);
466 UNREACHABLE(
"xrpl::MPTokenIssuanceSet::doApply : rotation without amendment");
471 auto const epoch = (*sle)[~epochField].valueOr(0);
477 UNREACHABLE(
"xrpl::MPTokenIssuanceSet::doApply : key epoch overflow");
482 (*sle)[epochField] = epoch + 1;
488 if (
auto const ter = setEncryptionKey(sfIssuerEncryptionKey, sfIssuerKeyEpoch);
492 if (
auto const ter = setEncryptionKey(sfAuditorEncryptionKey, sfAuditorKeyEpoch);
A generic endpoint for log messages.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::Ref sle)=0
Indicate changes to a peeked SLE.
static NotTEC preflight(PreflightContext const &ctx)
void visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override
Inspect a single ledger entry modified by this transaction.
static bool checkExtraFeatures(PreflightContext const &ctx)
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
static TER preclaim(PreclaimContext const &ctx)
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
static constexpr std::array< FlagMapping, 7 > flagMapping
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual SLE::const_pointer read(Keylet const &k) const =0
Return the state item associated with a key.
bool enabled(UInt256 const &feature) const
Returns true if a feature is enabled.
std::shared_ptr< STLedgerEntry > pointer
std::shared_ptr< STLedgerEntry const > const & ConstRef
bool isFlag(std::uint32_t) const
bool isFieldPresent(SField const &field) const
std::uint32_t getFlags() const
Keylet permissionedDomain(AccountID const &account, SeqProxy const &seq) noexcept
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool isValidCompressedECPoint(Slice const &buffer)
Verifies that a buffer contains a valid, parsable compressed EC point.
TypedField< STInteger< std::uint32_t > > SF_UINT32
TERSubset< CanCvtToNotTEC > NotTEC
constexpr FlagValue tfMPTokenIssuanceSetEnableFlagMask
constexpr std::size_t kMaxMpTokenMetadataLength
The maximum length of MPTokenMetadata.
TypedField< STBlob > SF_VL
constexpr FlagValue tifMPTokenIssuanceImmutableMask
constexpr std::uint32_t kMaxKeyEpoch
Maximum value a confidential MPT key epoch may reach.
constexpr std::uint16_t kMaxTransferFee
The maximum token transfer fee allowed.
constexpr FlagValue tifMPTCanHoldConfidentialBalance
constexpr std::uint32_t lsifMPTMetadata
bool isTesSuccess(TER x) noexcept
TERSubset< CanCvtToTER > TER
constexpr std::uint32_t lsifMPTTransferFee
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.