rippled
Loading...
Searching...
No Matches
Clawback.cpp
1#include <xrpld/app/tx/detail/Clawback.h>
2
3#include <xrpl/ledger/View.h>
4#include <xrpl/protocol/Feature.h>
5#include <xrpl/protocol/Indexes.h>
6#include <xrpl/protocol/MPTAmount.h>
7#include <xrpl/protocol/Protocol.h>
8#include <xrpl/protocol/TxFlags.h>
9
10namespace ripple {
11
12template <ValidIssueType T>
13static NotTEC
15
16template <>
19{
20 if (ctx.tx.isFieldPresent(sfHolder))
21 return temMALFORMED;
22
23 AccountID const issuer = ctx.tx[sfAccount];
24 STAmount const clawAmount = ctx.tx[sfAmount];
25
26 // The issuer field is used for the token holder instead
27 AccountID const& holder = clawAmount.getIssuer();
28
29 if (issuer == holder || isXRP(clawAmount) || clawAmount <= beast::zero)
30 return temBAD_AMOUNT;
31
32 return tesSUCCESS;
33}
34
35template <>
38{
39 if (!ctx.rules.enabled(featureMPTokensV1))
40 return temDISABLED;
41
42 auto const mptHolder = ctx.tx[~sfHolder];
43 auto const clawAmount = ctx.tx[sfAmount];
44
45 if (!mptHolder)
46 return temMALFORMED;
47
48 // issuer is the same as holder
49 if (ctx.tx[sfAccount] == *mptHolder)
50 return temMALFORMED;
51
52 if (clawAmount.mpt() > MPTAmount{maxMPTokenAmount} ||
53 clawAmount <= beast::zero)
54 return temBAD_AMOUNT;
55
56 return tesSUCCESS;
57}
58
64
67{
68 if (auto const ret = std::visit(
69 [&]<typename T>(T const&) { return preflightHelper<T>(ctx); },
70 ctx.tx[sfAmount].asset().value());
71 !isTesSuccess(ret))
72 return ret;
73
74 return tesSUCCESS;
75}
76
77template <ValidIssueType T>
78static TER
80 PreclaimContext const& ctx,
81 SLE const& sleIssuer,
82 AccountID const& issuer,
83 AccountID const& holder,
84 STAmount const& clawAmount);
85
86template <>
89 PreclaimContext const& ctx,
90 SLE const& sleIssuer,
91 AccountID const& issuer,
92 AccountID const& holder,
93 STAmount const& clawAmount)
94{
95 std::uint32_t const issuerFlagsIn = sleIssuer.getFieldU32(sfFlags);
96
97 // If AllowTrustLineClawback is not set or NoFreeze is set, return no
98 // permission
99 if (!(issuerFlagsIn & lsfAllowTrustLineClawback) ||
100 (issuerFlagsIn & lsfNoFreeze))
101 return tecNO_PERMISSION;
102
103 auto const sleRippleState =
104 ctx.view.read(keylet::line(holder, issuer, clawAmount.getCurrency()));
105 if (!sleRippleState)
106 return tecNO_LINE;
107
108 STAmount const balance = (*sleRippleState)[sfBalance];
109
110 // If balance is positive, issuer must have higher address than holder
111 if (balance > beast::zero && issuer < holder)
112 return tecNO_PERMISSION;
113
114 // If balance is negative, issuer must have lower address than holder
115 if (balance < beast::zero && issuer > holder)
116 return tecNO_PERMISSION;
117
118 // At this point, we know that issuer and holder accounts
119 // are correct and a trustline exists between them.
120 //
121 // Must now explicitly check the balance to make sure
122 // available balance is non-zero.
123 //
124 // We can't directly check the balance of trustline because
125 // the available balance of a trustline is prone to new changes (eg.
126 // XLS-34). So we must use `accountHolds`.
127 if (accountHolds(
128 ctx.view,
129 holder,
130 clawAmount.getCurrency(),
131 issuer,
133 ctx.j) <= beast::zero)
135
136 return tesSUCCESS;
137}
138
139template <>
142 PreclaimContext const& ctx,
143 SLE const& sleIssuer,
144 AccountID const& issuer,
145 AccountID const& holder,
146 STAmount const& clawAmount)
147{
148 auto const issuanceKey =
149 keylet::mptIssuance(clawAmount.get<MPTIssue>().getMptID());
150 auto const sleIssuance = ctx.view.read(issuanceKey);
151 if (!sleIssuance)
152 return tecOBJECT_NOT_FOUND;
153
154 if (!((*sleIssuance)[sfFlags] & lsfMPTCanClawback))
155 return tecNO_PERMISSION;
156
157 if (sleIssuance->getAccountID(sfIssuer) != issuer)
158 return tecNO_PERMISSION;
159
160 if (!ctx.view.exists(keylet::mptoken(issuanceKey.key, holder)))
161 return tecOBJECT_NOT_FOUND;
162
163 if (accountHolds(
164 ctx.view,
165 holder,
166 clawAmount.get<MPTIssue>(),
169 ctx.j) <= beast::zero)
171
172 return tesSUCCESS;
173}
174
175TER
177{
178 AccountID const issuer = ctx.tx[sfAccount];
179 auto const clawAmount = ctx.tx[sfAmount];
180 AccountID const holder =
181 clawAmount.holds<Issue>() ? clawAmount.getIssuer() : ctx.tx[sfHolder];
182
183 auto const sleIssuer = ctx.view.read(keylet::account(issuer));
184 auto const sleHolder = ctx.view.read(keylet::account(holder));
185 if (!sleIssuer || !sleHolder)
186 return terNO_ACCOUNT;
187
188 // Note the order of checks - when SAV is active, this check here will make
189 // the one which follows `sleHolder->isFieldPresent(sfAMMID)` redundant.
190 if (ctx.view.rules().enabled(featureSingleAssetVault) &&
191 isPseudoAccount(sleHolder))
192 return tecPSEUDO_ACCOUNT;
193 else if (sleHolder->isFieldPresent(sfAMMID))
194 return tecAMM_ACCOUNT;
195
196 return std::visit(
197 [&]<typename T>(T const&) {
198 return preclaimHelper<T>(
199 ctx, *sleIssuer, issuer, holder, clawAmount);
200 },
201 ctx.tx[sfAmount].asset().value());
202}
203
204template <ValidIssueType T>
205static TER
207
208template <>
211{
212 AccountID const issuer = ctx.tx[sfAccount];
213 STAmount clawAmount = ctx.tx[sfAmount];
214 AccountID const holder = clawAmount.getIssuer(); // cannot be reference
215
216 // Replace the `issuer` field with issuer's account
217 clawAmount.setIssuer(issuer);
218 if (holder == issuer)
219 return tecINTERNAL; // LCOV_EXCL_LINE
220
221 // Get the spendable balance. Must use `accountHolds`.
222 STAmount const spendableAmount = accountHolds(
223 ctx.view(),
224 holder,
225 clawAmount.getCurrency(),
226 clawAmount.getIssuer(),
228 ctx.journal);
229
230 return rippleCredit(
231 ctx.view(),
232 holder,
233 issuer,
234 std::min(spendableAmount, clawAmount),
235 true,
236 ctx.journal);
237}
238
239template <>
242{
243 AccountID const issuer = ctx.tx[sfAccount];
244 auto clawAmount = ctx.tx[sfAmount];
245 AccountID const holder = ctx.tx[sfHolder];
246
247 // Get the spendable balance. Must use `accountHolds`.
248 STAmount const spendableAmount = accountHolds(
249 ctx.view(),
250 holder,
251 clawAmount.get<MPTIssue>(),
254 ctx.journal);
255
256 return rippleCredit(
257 ctx.view(),
258 holder,
259 issuer,
260 std::min(spendableAmount, clawAmount),
261 /*checkIssuer*/ false,
262 ctx.journal);
263}
264
265TER
267{
268 return std::visit(
269 [&]<typename T>(T const&) { return applyHelper<T>(ctx_); },
270 ctx_.tx[sfAmount].asset().value());
271}
272
273} // namespace ripple
State information when applying a tx.
ApplyView & view()
beast::Journal const journal
static NotTEC preflight(PreflightContext const &ctx)
Definition Clawback.cpp:66
static TER preclaim(PreclaimContext const &ctx)
Definition Clawback.cpp:176
TER doApply() override
Definition Clawback.cpp:266
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
Definition Clawback.cpp:60
A currency issued by an account.
Definition Issue.h:14
AccountID const & getIssuer() const
Definition Issue.h:26
constexpr MPTID const & getMptID() const
Definition MPTIssue.h:27
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:111
constexpr TIss const & get() const
void setIssuer(AccountID const &uIssuer)
Definition STAmount.h:569
Currency const & getCurrency() const
Definition STAmount.h:483
AccountID const & getIssuer() const
Definition STAmount.h:489
std::uint32_t getFieldU32(SField const &field) const
Definition STObject.cpp:596
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:465
ApplyContext & ctx_
Definition Transactor.h:124
T min(T... args)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:521
Keylet line(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:225
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Definition Indexes.cpp:507
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
@ fhIGNORE_FREEZE
Definition View.h:58
bool isXRP(AccountID const &c)
Definition AccountID.h:71
static NotTEC preflightHelper(PreflightContext const &ctx)
constexpr std::uint32_t const tfClawbackMask
Definition TxFlags.h:222
@ lsfAllowTrustLineClawback
@ lsfMPTCanClawback
TER preclaimHelper< MPTIssue >(PreclaimContext const &ctx, SLE const &sleIssuer, AccountID const &issuer, AccountID const &holder, STAmount const &clawAmount)
Definition Clawback.cpp:141
@ ahIGNORE_AUTH
Definition View.h:61
NotTEC preflightHelper< Issue >(PreflightContext const &ctx)
Definition Clawback.cpp:18
TER applyHelper< Issue >(ApplyContext &ctx)
Definition Clawback.cpp:210
TER preclaimHelper< Issue >(PreclaimContext const &ctx, SLE const &sleIssuer, AccountID const &issuer, AccountID const &holder, STAmount const &clawAmount)
Definition Clawback.cpp:88
NotTEC preflightHelper< MPTIssue >(PreflightContext const &ctx)
Definition Clawback.cpp:37
@ tecPSEUDO_ACCOUNT
Definition TER.h:344
@ tecOBJECT_NOT_FOUND
Definition TER.h:308
@ tecINSUFFICIENT_FUNDS
Definition TER.h:307
@ tecINTERNAL
Definition TER.h:292
@ tecNO_PERMISSION
Definition TER.h:287
@ tecAMM_ACCOUNT
Definition TER.h:316
@ tecNO_LINE
Definition TER.h:283
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
Definition View.cpp:2837
@ tesSUCCESS
Definition TER.h:226
static TER applyHelper(ApplyContext &ctx)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
Definition View.cpp:368
bool isTesSuccess(TER x) noexcept
Definition TER.h:659
static TER preclaimHelper(PreclaimContext const &ctx, SLE const &sleIssuer, AccountID const &issuer, AccountID const &holder, STAmount const &clawAmount)
TER applyHelper< MPTIssue >(ApplyContext &ctx)
Definition Clawback.cpp:241
@ terNO_ACCOUNT
Definition TER.h:198
TERSubset< CanCvtToTER > TER
Definition TER.h:630
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
Definition View.cpp:1099
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:590
@ temBAD_AMOUNT
Definition TER.h:70
@ temMALFORMED
Definition TER.h:68
@ temDISABLED
Definition TER.h:95
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:61
ReadView const & view
Definition Transactor.h:64
beast::Journal const j
Definition Transactor.h:69
State information when preflighting a tx.
Definition Transactor.h:16
T visit(T... args)