xrpld
Loading...
Searching...
No Matches
MPTokenAuthorize.cpp
1#include <xrpl/tx/transactors/token/MPTokenAuthorize.h>
2
3#include <xrpl/core/ServiceRegistry.h>
4#include <xrpl/ledger/helpers/AccountRootHelpers.h>
5#include <xrpl/ledger/helpers/MPTokenHelpers.h>
6#include <xrpl/protocol/Feature.h>
7#include <xrpl/protocol/Indexes.h>
8#include <xrpl/protocol/LedgerFormats.h>
9#include <xrpl/protocol/SField.h>
10#include <xrpl/protocol/STLedgerEntry.h>
11#include <xrpl/protocol/STTx.h>
12#include <xrpl/protocol/TER.h>
13#include <xrpl/protocol/TxFlags.h>
14#include <xrpl/protocol/XRPAmount.h>
15#include <xrpl/tx/Transactor.h>
16
17#include <cstdint>
18namespace xrpl {
19
20std::uint32_t
22{
23 return tfMPTokenAuthorizeMask;
24}
25
28{
29 if (ctx.tx[sfAccount] == ctx.tx[~sfHolder])
30 return temMALFORMED;
31
32 return tesSUCCESS;
33}
34
35TER
37{
38 auto const accountID = ctx.tx[sfAccount];
39 auto const holderID = ctx.tx[~sfHolder];
40 auto const sleMptIssuance = ctx.view.read(keylet::mptokenIssuance(ctx.tx[sfMPTokenIssuanceID]));
41
42 // if non-issuer account submits this tx, then they are trying either:
43 // 1. Unauthorize/delete MPToken
44 // 2. Use/create MPToken
45 //
46 // Note: `accountID` is holder's account
47 // `holderID` is NOT used
48 if (!holderID)
49 {
50 SLE::const_pointer const sleMpt =
51 ctx.view.read(keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], accountID));
52
53 // There is an edge case where all holders have zero balance, issuance
54 // is legally destroyed, then outstanding MPT(s) are deleted afterwards.
55 // Thus, the unauthorize/delete path below does not require the issuance
56 // to exist when the MPT is being deleted with a zero balance.
57
58 // if holder wants to delete/unauthorize a mpt
59 if (ctx.tx.isFlag(tfMPTUnauthorize))
60 {
61 if (!sleMpt)
63
64 if ((*sleMpt)[sfMPTAmount] != 0)
65 {
66 if (!sleMptIssuance)
67 return tefINTERNAL; // LCOV_EXCL_LINE
68
69 return tecHAS_OBLIGATIONS;
70 }
71
72 if ((*sleMpt)[~sfLockedAmount].value_or(0) != 0)
73 {
74 if (!sleMptIssuance)
75 return tefINTERNAL; // LCOV_EXCL_LINE
76
77 return tecHAS_OBLIGATIONS;
78 }
79 if (ctx.view.rules().enabled(fixCleanup3_4_0))
80 {
81 if (sleMptIssuance && sleMpt->isFlag(lsfMPTLocked))
82 return tecNO_PERMISSION;
83 }
84 else if (
85 ctx.view.rules().enabled(featureSingleAssetVault) && sleMpt->isFlag(lsfMPTLocked))
86 {
87 return tecNO_PERMISSION;
88 }
89
90 if (ctx.view.rules().enabled(featureConfidentialTransfer))
91 {
92 // if there still existing encrypted balances of MPT in
93 // circulation
94 if (sleMptIssuance &&
95 (*sleMptIssuance)[~sfConfidentialOutstandingAmount].value_or(0) != 0)
96 {
97 // this MPT still has encrypted balance, since we don't know
98 // if it's non-zero or not, we won't allow deletion of
99 // MPToken
100 if (sleMpt->isFieldPresent(sfConfidentialBalanceInbox) ||
101 sleMpt->isFieldPresent(sfConfidentialBalanceSpending))
102 return tecHAS_OBLIGATIONS;
103 }
104 }
105
106 return tesSUCCESS;
107 }
108
109 // Now test when the holder wants to hold/create/authorize a new MPT
110 if (!sleMptIssuance)
111 return tecOBJECT_NOT_FOUND;
112
113 if (accountID == (*sleMptIssuance)[sfIssuer])
114 return tecNO_PERMISSION;
115
116 // if holder wants to use and create a mpt
117 if (sleMpt)
118 return tecDUPLICATE;
119
120 return tesSUCCESS;
121 }
122
123 auto const sleHolder = ctx.view.read(keylet::account(*holderID));
124 if (!sleHolder)
125 return tecNO_DST;
126
127 if (!sleMptIssuance)
128 return tecOBJECT_NOT_FOUND;
129
130 // If tx is submitted by issuer, they would either try to do the following
131 // for allowlisting:
132 // 1. authorize an account
133 // 2. unauthorize an account
134 //
135 // Note: `accountID` is issuer's account
136 // `holderID` is holder's account
137 if (accountID != (*sleMptIssuance)[sfIssuer])
138 return tecNO_PERMISSION;
139
140 // If tx is submitted by issuer, it only applies for MPT with
141 // lsfMPTRequireAuth set
142 if (!sleMptIssuance->isFlag(lsfMPTRequireAuth))
143 return tecNO_AUTH;
144
145 // The holder must create the MPT before the issuer can authorize it.
146 if (!ctx.view.exists(keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], *holderID)))
147 return tecOBJECT_NOT_FOUND;
148
149 // Can't unauthorize the pseudo-accounts because they are implicitly
150 // always authorized. No need to amendment gate since Vault and LoanBroker
151 // can only be created if the Vault amendment is enabled; AMM with MPToken asset
152 // can only be created if MPTokensV2 is enabled.
153 if (isPseudoAccount(ctx.view, *holderID))
154 return tecNO_PERMISSION;
155
156 return tesSUCCESS;
157}
158
159TER
161{
162 auto const& tx = ctx_.tx;
163 return authorizeMPToken(
164 ctx_.getApplyViewContext(),
166 tx[sfMPTokenIssuanceID],
168 ctx_.journal,
169 tx.getFlags(),
170 tx[~sfHolder]);
171}
172
173void
175{
176 // No transaction-specific invariants yet (future work).
177}
178
179bool
181 STTx const&,
182 TER,
183 XRPAmount,
184 ReadView const&,
185 beast::Journal const&)
186{
187 // No transaction-specific invariants yet (future work).
188 return true;
189}
190
191} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
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.
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.
A view into a ledger.
Definition ReadView.h:41
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.
Definition Rules.cpp:182
std::shared_ptr< STLedgerEntry const > const & ConstRef
std::shared_ptr< STLedgerEntry const > const_pointer
bool isFlag(std::uint32_t) const
Definition STObject.cpp:511
AccountID const accountID_
Definition Transactor.h:166
XRPAmount preFeeBalance_
Definition Transactor.h:167
ApplyContext & ctx_
Definition Transactor.h:162
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:573
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:220
Keylet mptokenIssuance(MPTID const &issuanceID) noexcept
Definition Indexes.cpp:567
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ tefINTERNAL
Definition TER.h:168
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:614
bool isPseudoAccount(SLE::const_pointer sleAcct)
Returns true if and only if sleAcct is a pseudo-account of any kind (i.e.
@ temMALFORMED
Definition TER.h:75
TERSubset< CanCvtToTER > TER
Definition TER.h:654
TER authorizeMPToken(ApplyViewContext ctx, XRPAmount const &priorBalance, MPTID const &mptIssuanceID, AccountID const &account, beast::Journal journal, std::uint32_t flags=0, std::optional< AccountID > holderID=std::nullopt)
@ tecOBJECT_NOT_FOUND
Definition TER.h:334
@ tecNO_AUTH
Definition TER.h:308
@ tecNO_PERMISSION
Definition TER.h:313
@ tecDUPLICATE
Definition TER.h:323
@ tecHAS_OBLIGATIONS
Definition TER.h:325
@ tecNO_DST
Definition TER.h:298
@ tesSUCCESS
Definition TER.h:250
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:92
ReadView const & view
Definition Transactor.h:95
State information when preflighting a tx.
Definition Transactor.h:39