rippled
Loading...
Searching...
No Matches
MPTokenAuthorize.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2024 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
21#include <xrpld/ledger/View.h>
22
23#include <xrpl/protocol/Feature.h>
24#include <xrpl/protocol/TxFlags.h>
25#include <xrpl/protocol/st.h>
26
27namespace ripple {
28
31{
32 if (!ctx.rules.enabled(featureMPTokensV1))
33 return temDISABLED;
34
35 if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
36 return ret;
37
39 return temINVALID_FLAG;
40
41 if (ctx.tx[sfAccount] == ctx.tx[~sfHolder])
42 return temMALFORMED;
43
44 return preflight2(ctx);
45}
46
47TER
49{
50 auto const accountID = ctx.tx[sfAccount];
51 auto const holderID = ctx.tx[~sfHolder];
52
53 // if non-issuer account submits this tx, then they are trying either:
54 // 1. Unauthorize/delete MPToken
55 // 2. Use/create MPToken
56 //
57 // Note: `accountID` is holder's account
58 // `holderID` is NOT used
59 if (!holderID)
60 {
62 keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], accountID));
63
64 // There is an edge case where all holders have zero balance, issuance
65 // is legally destroyed, then outstanding MPT(s) are deleted afterwards.
66 // Thus, there is no need to check for the existence of the issuance if
67 // the MPT is being deleted with a zero balance. Check for unauthorize
68 // before fetching the MPTIssuance object.
69
70 // if holder wants to delete/unauthorize a mpt
71 if (ctx.tx.getFlags() & tfMPTUnauthorize)
72 {
73 if (!sleMpt)
75
76 if ((*sleMpt)[sfMPTAmount] != 0)
77 {
78 auto const sleMptIssuance = ctx.view.read(
79 keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID]));
80 if (!sleMptIssuance)
81 return tefINTERNAL;
82
83 return tecHAS_OBLIGATIONS;
84 }
85
86 if ((*sleMpt)[~sfLockedAmount].value_or(0) != 0)
87 {
88 auto const sleMptIssuance = ctx.view.read(
89 keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID]));
90 if (!sleMptIssuance)
91 return tefINTERNAL; // LCOV_EXCL_LINE
92
93 return tecHAS_OBLIGATIONS;
94 }
95 if (ctx.view.rules().enabled(featureSingleAssetVault) &&
96 sleMpt->isFlag(lsfMPTLocked))
97 return tecNO_PERMISSION;
98
99 return tesSUCCESS;
100 }
101
102 // Now test when the holder wants to hold/create/authorize a new MPT
103 auto const sleMptIssuance =
104 ctx.view.read(keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID]));
105
106 if (!sleMptIssuance)
107 return tecOBJECT_NOT_FOUND;
108
109 if (accountID == (*sleMptIssuance)[sfIssuer])
110 return tecNO_PERMISSION;
111
112 // if holder wants to use and create a mpt
113 if (sleMpt)
114 return tecDUPLICATE;
115
116 return tesSUCCESS;
117 }
118
119 if (!ctx.view.exists(keylet::account(*holderID)))
120 return tecNO_DST;
121
122 auto const sleMptIssuance =
123 ctx.view.read(keylet::mptIssuance(ctx.tx[sfMPTokenIssuanceID]));
124 if (!sleMptIssuance)
125 return tecOBJECT_NOT_FOUND;
126
127 std::uint32_t const mptIssuanceFlags = sleMptIssuance->getFieldU32(sfFlags);
128
129 // If tx is submitted by issuer, they would either try to do the following
130 // for allowlisting:
131 // 1. authorize an account
132 // 2. unauthorize an account
133 //
134 // Note: `accountID` is issuer's account
135 // `holderID` is holder's account
136 if (accountID != (*sleMptIssuance)[sfIssuer])
137 return tecNO_PERMISSION;
138
139 // If tx is submitted by issuer, it only applies for MPT with
140 // lsfMPTRequireAuth set
141 if (!(mptIssuanceFlags & lsfMPTRequireAuth))
142 return tecNO_AUTH;
143
144 // The holder must create the MPT before the issuer can authorize it.
145 if (!ctx.view.exists(
146 keylet::mptoken(ctx.tx[sfMPTokenIssuanceID], *holderID)))
147 return tecOBJECT_NOT_FOUND;
148
149 return tesSUCCESS;
150}
151
152TER
154 ApplyView& view,
155 MPTID const& mptIssuanceID,
156 AccountID const& account,
157 std::uint32_t const flags)
158{
159 auto const mptokenKey = keylet::mptoken(mptIssuanceID, account);
160
161 auto const ownerNode = view.dirInsert(
162 keylet::ownerDir(account), mptokenKey, describeOwnerDir(account));
163
164 if (!ownerNode)
165 return tecDIR_FULL; // LCOV_EXCL_LINE
166
167 auto mptoken = std::make_shared<SLE>(mptokenKey);
168 (*mptoken)[sfAccount] = account;
169 (*mptoken)[sfMPTokenIssuanceID] = mptIssuanceID;
170 (*mptoken)[sfFlags] = flags;
171 (*mptoken)[sfOwnerNode] = *ownerNode;
172
173 view.insert(mptoken);
174
175 return tesSUCCESS;
176}
177
178TER
180{
181 auto const& tx = ctx_.tx;
182 return authorizeMPToken(
183 ctx_.view(),
185 tx[sfMPTokenIssuanceID],
186 account_,
188 tx.getFlags(),
189 tx[~sfHolder]);
190}
191
192} // namespace ripple
ApplyView & view()
beast::Journal const journal
Writeable view to a ledger, for applying a transaction.
Definition ApplyView.h:144
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
Definition ApplyView.h:318
static TER createMPToken(ApplyView &view, MPTID const &mptIssuanceID, AccountID const &account, std::uint32_t const flags)
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
Definition Rules.cpp:130
std::uint32_t getFlags() const
Definition STObject.cpp:537
AccountID const account_
Definition Transactor.h:143
ApplyView & view()
Definition Transactor.h:159
XRPAmount mPriorBalance
Definition Transactor.h:144
ApplyContext & ctx_
Definition Transactor.h:140
T is_same_v
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:540
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:526
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:184
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:374
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
@ lsfMPTRequireAuth
constexpr std::uint32_t const tfMPTokenAuthorizeMask
Definition TxFlags.h:156
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
Definition View.cpp:1048
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
@ tefINTERNAL
Definition TER.h:173
TER authorizeMPToken(ApplyView &view, XRPAmount const &priorBalance, MPTID const &mptIssuanceID, AccountID const &account, beast::Journal journal, std::uint32_t flags, std::optional< AccountID > holderID)
Definition View.cpp:1221
constexpr std::uint32_t const tfMPTUnauthorize
Definition TxFlags.h:155
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
@ tecNO_DST
Definition TER.h:290
@ tecOBJECT_NOT_FOUND
Definition TER.h:326
@ tecDIR_FULL
Definition TER.h:287
@ tecDUPLICATE
Definition TER.h:315
@ tecNO_PERMISSION
Definition TER.h:305
@ tecHAS_OBLIGATIONS
Definition TER.h:317
@ tecNO_AUTH
Definition TER.h:300
@ tesSUCCESS
Definition TER.h:244
bool isTesSuccess(TER x) noexcept
Definition TER.h:674
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:605
@ temMALFORMED
Definition TER.h:87
@ temINVALID_FLAG
Definition TER.h:111
@ temDISABLED
Definition TER.h:114
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:79
ReadView const & view
Definition Transactor.h:82
State information when preflighting a tx.
Definition Transactor.h:34