xrpld
Loading...
Searching...
No Matches
ConfidentialMPTSend.cpp
1#include <xrpl/tx/transactors/token/ConfidentialMPTSend.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Slice.h>
5#include <xrpl/beast/utility/instrumentation.h>
6#include <xrpl/core/ServiceRegistry.h>
7#include <xrpl/ledger/ReadView.h>
8#include <xrpl/ledger/helpers/CredentialHelpers.h>
9#include <xrpl/ledger/helpers/TokenHelpers.h>
10#include <xrpl/protocol/ConfidentialTransfer.h>
11#include <xrpl/protocol/Feature.h>
12#include <xrpl/protocol/Indexes.h>
13#include <xrpl/protocol/LedgerFormats.h>
14#include <xrpl/protocol/Protocol.h>
15#include <xrpl/protocol/SField.h>
16#include <xrpl/protocol/TER.h>
17#include <xrpl/protocol/XRPAmount.h>
18#include <xrpl/tx/Transactor.h>
19
20#include <memory>
21#include <optional>
22#include <utility>
23
24namespace xrpl {
25
26bool
28{
29 return !ctx.tx.isFieldPresent(sfCredentialIDs) || ctx.rules.enabled(featureCredentials);
30}
31
34{
35 auto const account = ctx.tx[sfAccount];
36 auto const issuer = MPTIssue(ctx.tx[sfMPTokenIssuanceID]).getIssuer();
37
38 // ConfidentialMPTSend only allows holder to holder, holder to second account,
39 // and second account to holder transfers. So issuer cannot be the sender.
40 if (account == issuer)
41 return temMALFORMED;
42
43 // Can not send to self
44 if (account == ctx.tx[sfDestination])
45 return temMALFORMED;
46
47 // Issuer cannot be the destination
48 if (ctx.tx[sfDestination] == issuer)
49 return temMALFORMED;
50
51 // Check the length of the encrypted amounts
52 if (ctx.tx[sfSenderEncryptedAmount].length() != kEcGamalEncryptedTotalLength ||
53 ctx.tx[sfDestinationEncryptedAmount].length() != kEcGamalEncryptedTotalLength ||
54 ctx.tx[sfIssuerEncryptedAmount].length() != kEcGamalEncryptedTotalLength)
55 {
56 return temBAD_CIPHERTEXT;
57 }
58
59 bool const hasAuditor = ctx.tx.isFieldPresent(sfAuditorEncryptedAmount);
60 if (hasAuditor && ctx.tx[sfAuditorEncryptedAmount].length() != kEcGamalEncryptedTotalLength)
61 return temBAD_CIPHERTEXT;
62
63 // Check the length of the ZKProof (fixed size regardless of recipient count)
64 if (ctx.tx[sfZKProof].length() != kEcSendProofLength)
65 return temMALFORMED;
66
67 // Check the Pedersen commitments are valid
68 if (!isValidCompressedECPoint(ctx.tx[sfBalanceCommitment]) ||
69 !isValidCompressedECPoint(ctx.tx[sfAmountCommitment]))
70 {
71 return temMALFORMED;
72 }
73
74 // Check the encrypted amount formats, this is more expensive so put it at
75 // the end
76 if (!isValidCiphertext(ctx.tx[sfSenderEncryptedAmount]) ||
77 !isValidCiphertext(ctx.tx[sfDestinationEncryptedAmount]) ||
78 !isValidCiphertext(ctx.tx[sfIssuerEncryptedAmount]))
79 {
80 return temBAD_CIPHERTEXT;
81 }
82
83 if (hasAuditor && !isValidCiphertext(ctx.tx[sfAuditorEncryptedAmount]))
84 return temBAD_CIPHERTEXT;
85
86 if (auto const err = credentials::checkFields(ctx.tx, ctx.rules, ctx.j); !isTesSuccess(err))
87 return err;
88
89 return tesSUCCESS;
90}
91
97
98namespace detail {
99
100static TER
102 PreclaimContext const& ctx,
103 std::shared_ptr<SLE const> const& sleSenderMPToken,
104 std::shared_ptr<SLE const> const& sleDestinationMPToken,
105 std::shared_ptr<SLE const> const& sleIssuance)
106{
107 // Sanity check
108 if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance)
109 {
110 // LCOV_EXCL_START
111 UNREACHABLE(
112 "xrpl::detail::verifySendProofs : caller must pre-validate sender/destination/"
113 "issuance existence");
114 return tecINTERNAL;
115 // LCOV_EXCL_STOP
116 }
117
118 auto const hasAuditor = ctx.tx.isFieldPresent(sfAuditorEncryptedAmount);
119
121 if (hasAuditor)
122 {
123 auditor.emplace(
125 .publicKey = (*sleIssuance)[sfAuditorEncryptionKey],
126 .encryptedAmount = ctx.tx[sfAuditorEncryptedAmount],
127 });
128 }
129
130 auto const contextHash = getSendContextHash(
131 ctx.tx[sfAccount],
132 ctx.tx[sfMPTokenIssuanceID],
133 ctx.tx.getSeqProxy().value(),
134 ctx.tx[sfDestination],
135 (*sleSenderMPToken)[~sfConfidentialBalanceVersion].value_or(0));
136
137 return verifySendProof(
138 ctx.tx[sfZKProof],
139 {
140 .publicKey = (*sleSenderMPToken)[sfHolderEncryptionKey],
141 .encryptedAmount = ctx.tx[sfSenderEncryptedAmount],
142 },
143 {
144 .publicKey = (*sleDestinationMPToken)[sfHolderEncryptionKey],
145 .encryptedAmount = ctx.tx[sfDestinationEncryptedAmount],
146 },
147 {
148 .publicKey = (*sleIssuance)[sfIssuerEncryptionKey],
149 .encryptedAmount = ctx.tx[sfIssuerEncryptedAmount],
150 },
151 auditor,
152 (*sleSenderMPToken)[sfConfidentialBalanceSpending],
153 ctx.tx[sfAmountCommitment],
154 ctx.tx[sfBalanceCommitment],
155 contextHash);
156}
157
158} // namespace detail
159
160TER
162{
163 // Check if sender account exists
164 auto const account = ctx.tx[sfAccount];
165 if (!ctx.view.exists(keylet::account(account)))
166 return terNO_ACCOUNT;
167
168 // Check if destination account exists
169 auto const destination = ctx.tx[sfDestination];
170 auto const sleDst = ctx.view.read(keylet::account(destination));
171 if (!sleDst)
172 return tecNO_TARGET;
173
174 // Check destination tag
175 if (((sleDst->getFlags() & lsfRequireDestTag) != 0u) &&
176 !ctx.tx.isFieldPresent(sfDestinationTag))
177 {
178 return tecDST_TAG_NEEDED;
179 }
180
181 // Check if MPT issuance exists
182 auto const mptIssuanceID = ctx.tx[sfMPTokenIssuanceID];
183 auto const sleIssuance = ctx.view.read(keylet::mptokenIssuance(mptIssuanceID));
184 if (!sleIssuance)
185 return tecOBJECT_NOT_FOUND;
186
187 // Check if the issuance allows transfer
188 if (!sleIssuance->isFlag(lsfMPTCanTransfer))
189 return tecNO_AUTH;
190
191 // Check if issuance allows confidential transfer
192 if (!sleIssuance->isFlag(lsfMPTCanHoldConfidentialBalance))
193 return tecNO_PERMISSION;
194
195 // Sanity check: transfer fee must be 0 for confidential MPTs. This should
196 // be unreachable in valid ledger state because MPTokenIssuanceCreate and
197 // MPTokenIssuanceSet enforce it.
198 if ((*sleIssuance)[~sfTransferFee].value_or(0) > 0)
199 return tecNO_PERMISSION;
200
201 // Check if issuance has issuer ElGamal public key
202 if (!sleIssuance->isFieldPresent(sfIssuerEncryptionKey))
203 return tecNO_PERMISSION;
204
205 bool const hasAuditor = ctx.tx.isFieldPresent(sfAuditorEncryptedAmount);
206 bool const requiresAuditor = sleIssuance->isFieldPresent(sfAuditorEncryptionKey);
207
208 // Tx must include auditor ciphertext if the issuance has enabled
209 // auditing, and must not include it if auditing is not enabled
210 if (requiresAuditor != hasAuditor)
211 return tecNO_PERMISSION;
212
213 // Sanity check: issuer isn't the sender
214 if (sleIssuance->getAccountID(sfIssuer) == ctx.tx[sfAccount])
215 {
216 // LCOV_EXCL_START
217 UNREACHABLE(
218 "xrpl::ConfidentialMPTSend::preclaim : issuer derived from the MPT ID must match "
219 "the ledger's stored issuer");
220 return tefINTERNAL;
221 // LCOV_EXCL_STOP
222 }
223
224 // Check sender's MPToken existence
225 auto const sleSenderMPToken = ctx.view.read(keylet::mptoken(mptIssuanceID, account));
226 if (!sleSenderMPToken)
227 return tecOBJECT_NOT_FOUND;
228
229 // Check sender's MPToken has necessary fields for confidential send
230 if (!sleSenderMPToken->isFieldPresent(sfHolderEncryptionKey) ||
231 !sleSenderMPToken->isFieldPresent(sfConfidentialBalanceSpending) ||
232 !sleSenderMPToken->isFieldPresent(sfIssuerEncryptedBalance))
233 {
234 return tecNO_PERMISSION;
235 }
236
237 // Check destination's MPToken existence
238 auto const sleDestinationMPToken = ctx.view.read(keylet::mptoken(mptIssuanceID, destination));
239 if (!sleDestinationMPToken)
240 return tecOBJECT_NOT_FOUND;
241
242 // Check destination's MPToken has necessary fields for confidential send
243 if (!sleDestinationMPToken->isFieldPresent(sfHolderEncryptionKey) ||
244 !sleDestinationMPToken->isFieldPresent(sfConfidentialBalanceInbox) ||
245 !sleDestinationMPToken->isFieldPresent(sfIssuerEncryptedBalance))
246 {
247 return tecNO_PERMISSION;
248 }
249
250 // A send homomorphically updates the mirrors of both parties, so both must
251 // be current.
252 if (ctx.view.rules().enabled(featureConfidentialMPTKeyRotation) &&
253 (!areMirrorsCurrent(*sleIssuance, *sleSenderMPToken) ||
254 !areMirrorsCurrent(*sleIssuance, *sleDestinationMPToken)))
255 {
256 return tecNO_PERMISSION;
257 }
258
259 // Sanity check: Both MPTokens' auditor fields must be present if auditing
260 // is enabled
261 if (requiresAuditor &&
262 (!sleSenderMPToken->isFieldPresent(sfAuditorEncryptedBalance) ||
263 !sleDestinationMPToken->isFieldPresent(sfAuditorEncryptedBalance)))
264 {
265 // LCOV_EXCL_START
266 UNREACHABLE(
267 "xrpl::ConfidentialMPTSend::preclaim : issuance-level auditing implies both "
268 "MPTokens already carry an auditor balance");
269 return tefINTERNAL;
270 // LCOV_EXCL_STOP
271 }
272
273 // Check lock
274 MPTIssue const mptIssue(mptIssuanceID);
275 if (auto const ter = checkFrozen(ctx.view, account, mptIssue); !isTesSuccess(ter))
276 return ter;
277
278 if (auto const ter = checkFrozen(ctx.view, destination, mptIssue); !isTesSuccess(ter))
279 return ter;
280
281 // Check auth
282 if (auto const ter = requireAuth(ctx.view, mptIssue, account); !isTesSuccess(ter))
283 return ter;
284
285 if (auto const ter = requireAuth(ctx.view, mptIssue, destination); !isTesSuccess(ter))
286 return ter;
287
288 if (auto const err = credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
289 !isTesSuccess(err))
290 return err;
291
292 // Check deposit preauth before the expensive ZK proof verification.
293 // Uses read-only view.
294 auto const preauthErr =
295 checkDepositPreauth(ctx.tx, ctx.view, account, destination, sleDst, ctx.j);
296 if (!isTesSuccess(preauthErr))
297 return preauthErr;
298
299 return detail::verifySendProofs(ctx, sleSenderMPToken, sleDestinationMPToken, sleIssuance);
300}
301
302TER
304{
305 auto const mptIssuanceID = ctx_.tx[sfMPTokenIssuanceID];
306 auto const destination = ctx_.tx[sfDestination];
307
308 auto sleSenderMPToken = view().peek(keylet::mptoken(mptIssuanceID, accountID_));
309 auto sleDestinationMPToken = view().peek(keylet::mptoken(mptIssuanceID, destination));
310 auto const sleIssuance = view().read(keylet::mptokenIssuance(mptIssuanceID));
311
312 auto const sleDestAcct = view().read(keylet::account(destination));
313
314 if (!sleSenderMPToken || !sleDestinationMPToken || !sleIssuance || !sleDestAcct)
315 {
316 // LCOV_EXCL_START
317 UNREACHABLE(
318 "xrpl::ConfidentialMPTSend::doApply : preclaim already validated these objects "
319 "exist");
320 return tecINTERNAL;
321 // LCOV_EXCL_STOP
322 }
323
324 // Deposit preauth authorization was already verified in preclaim.
325 // Remove any expired credentials.
326 if (auto err = cleanupExpiredCredentials(ctx_.tx, ctx_.view(), ctx_.journal);
327 !isTesSuccess(err))
328 return err;
329
330 auto const senderEc = ctx_.tx[sfSenderEncryptedAmount];
331 auto const destEc = ctx_.tx[sfDestinationEncryptedAmount];
332 auto const issuerEc = ctx_.tx[sfIssuerEncryptedAmount];
333 auto const proof = ctx_.tx[sfZKProof];
334 Slice const sendChallenge{proof.data(), kEcBlindingFactorLength};
335
336 auto const auditorEc = ctx_.tx[~sfAuditorEncryptedAmount];
337
338 // Subtract from sender's spending balance
339 {
340 auto const curSpending = (*sleSenderMPToken)[sfConfidentialBalanceSpending];
341 auto newSpending = homomorphicSubtract(curSpending, senderEc);
342 if (!newSpending)
343 {
344 // LCOV_EXCL_START
345 JLOG(ctx_.journal.error())
346 << "ConfidentialMPTSend failed homomorphic subtract for sender spending balance.";
347 return tecINTERNAL;
348 // LCOV_EXCL_STOP
349 }
350
351 (*sleSenderMPToken)[sfConfidentialBalanceSpending] = std::move(*newSpending);
352 }
353
354 // Subtract from issuer's balance
355 {
356 auto const curIssuerEnc = (*sleSenderMPToken)[sfIssuerEncryptedBalance];
357 auto newIssuerEnc = homomorphicSubtract(curIssuerEnc, issuerEc);
358 if (!newIssuerEnc)
359 {
360 // LCOV_EXCL_START
361 JLOG(ctx_.journal.error())
362 << "ConfidentialMPTSend failed homomorphic subtract for sender issuer balance.";
363 return tecINTERNAL;
364 // LCOV_EXCL_STOP
365 }
366
367 (*sleSenderMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc);
368 }
369
370 // Subtract from auditor's balance if present
371 if (auditorEc)
372 {
373 auto const curAuditorEnc = (*sleSenderMPToken)[sfAuditorEncryptedBalance];
374 auto newAuditorEnc = homomorphicSubtract(curAuditorEnc, *auditorEc);
375 if (!newAuditorEnc)
376 {
377 // LCOV_EXCL_START
378 JLOG(ctx_.journal.error())
379 << "ConfidentialMPTSend failed homomorphic subtract for sender auditor balance.";
380 return tecINTERNAL;
381 // LCOV_EXCL_STOP
382 }
383
384 (*sleSenderMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc);
385 }
386
387 // Add to destination's inbox balance
388 {
389 auto rerandomizedDestEc = rerandomizeCiphertext(
390 destEc, (*sleDestinationMPToken)[sfHolderEncryptionKey], sendChallenge);
391 if (!rerandomizedDestEc)
392 {
393 // LCOV_EXCL_START
394 JLOG(ctx_.journal.error())
395 << "ConfidentialMPTSend failed to rerandomize destination inbox ciphertext.";
396 return tecINTERNAL;
397 // LCOV_EXCL_STOP
398 }
399
400 auto const curInbox = (*sleDestinationMPToken)[sfConfidentialBalanceInbox];
401 auto newInbox = homomorphicAdd(curInbox, *rerandomizedDestEc);
402 if (!newInbox)
403 {
404 // LCOV_EXCL_START
405 JLOG(ctx_.journal.error())
406 << "ConfidentialMPTSend failed homomorphic add for destination inbox.";
407 return tecINTERNAL;
408 // LCOV_EXCL_STOP
409 }
410
411 (*sleDestinationMPToken)[sfConfidentialBalanceInbox] = std::move(*newInbox);
412 }
413
414 // Add to issuer's balance
415 {
416 auto rerandomizedIssuerEc =
417 rerandomizeCiphertext(issuerEc, (*sleIssuance)[sfIssuerEncryptionKey], sendChallenge);
418 if (!rerandomizedIssuerEc)
419 {
420 // LCOV_EXCL_START
421 JLOG(ctx_.journal.error())
422 << "ConfidentialMPTSend failed to rerandomize destination issuer ciphertext.";
423 return tecINTERNAL;
424 // LCOV_EXCL_STOP
425 }
426
427 auto const curIssuerEnc = (*sleDestinationMPToken)[sfIssuerEncryptedBalance];
428 auto newIssuerEnc = homomorphicAdd(curIssuerEnc, *rerandomizedIssuerEc);
429 if (!newIssuerEnc)
430 {
431 // LCOV_EXCL_START
432 JLOG(ctx_.journal.error())
433 << "ConfidentialMPTSend failed homomorphic add for destination issuer balance.";
434 return tecINTERNAL;
435 // LCOV_EXCL_STOP
436 }
437
438 (*sleDestinationMPToken)[sfIssuerEncryptedBalance] = std::move(*newIssuerEnc);
439 }
440
441 // Add to auditor's balance if present
442 if (auditorEc)
443 {
444 auto rerandomizedAuditorEc = rerandomizeCiphertext(
445 *auditorEc, (*sleIssuance)[sfAuditorEncryptionKey], sendChallenge);
446 if (!rerandomizedAuditorEc)
447 {
448 // LCOV_EXCL_START
449 JLOG(ctx_.journal.error())
450 << "ConfidentialMPTSend failed to rerandomize destination auditor ciphertext.";
451 return tecINTERNAL;
452 // LCOV_EXCL_STOP
453 }
454
455 auto const curAuditorEnc = (*sleDestinationMPToken)[sfAuditorEncryptedBalance];
456 auto newAuditorEnc = homomorphicAdd(curAuditorEnc, *rerandomizedAuditorEc);
457 if (!newAuditorEnc)
458 {
459 // LCOV_EXCL_START
460 JLOG(ctx_.journal.error())
461 << "ConfidentialMPTSend failed homomorphic add for destination auditor balance.";
462 return tecINTERNAL;
463 // LCOV_EXCL_STOP
464 }
465
466 (*sleDestinationMPToken)[sfAuditorEncryptedBalance] = std::move(*newAuditorEnc);
467 }
468
469 // increment sender version only; receiver version is not modified by incoming sends
470 incrementConfidentialVersion(*sleSenderMPToken);
471
472 view().update(sleSenderMPToken);
473 view().update(sleDestinationMPToken);
474 return tesSUCCESS;
475}
476
477void
484
485bool
487 STTx const&,
488 TER,
489 XRPAmount,
490 ReadView const&,
491 beast::Journal const&)
492{
493 return true;
494}
495
496} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
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.
void visitInvariantEntry(bool isDelete, std::shared_ptr< SLE const > const &before, std::shared_ptr< SLE const > const &after) override
static TER preclaim(PreclaimContext const &ctx)
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
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 NotTEC preflight(PreflightContext const &ctx)
AccountID const & getIssuer() const
Definition MPTIssue.cpp:29
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
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:464
SeqProxy getSeqProxy() const
Definition STTx.cpp:198
constexpr std::uint32_t value() const
Definition SeqProxy.h:80
An immutable linear range of bytes.
Definition Slice.h:28
ApplyView & view()
Definition Transactor.h:184
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
AccountID const accountID_
Definition Transactor.h:166
ApplyContext & ctx_
Definition Transactor.h:162
T emplace(T... args)
NotTEC checkFields(STTx const &tx, Rules const &rules, beast::Journal j)
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
static TER 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)
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
bool areMirrorsCurrent(SLE const &issuance, SLE const &mptoken)
Checks whether each mirror a holder is required to have is encrypted under the issuance's currently r...
@ terNO_ACCOUNT
Definition TER.h:218
std::optional< Buffer > rerandomizeCiphertext(Slice const &ciphertext, Slice const &pubKeySlice, Slice const &randomness)
Re-randomizes an ElGamal ciphertext without changing its plaintext.
constexpr std::size_t kEcBlindingFactorLength
Length of the EC blinding factor in bytes.
Definition Protocol.h:495
UInt256 getSendContextHash(AccountID const &account, UInt192 const &issuanceID, std::uint32_t sequence, AccountID const &destination, std::uint32_t version)
Generates the context hash for ConfidentialMPTSend transactions.
constexpr std::uint32_t kConfidentialFeeMultiplier
Extra base fee multiplier charged to confidential MPT transactions.
Definition Protocol.h:551
TER checkFrozen(ReadView const &view, AccountID const &account, Issue const &issue)
@ tefINTERNAL
Definition TER.h:168
bool isValidCompressedECPoint(Slice const &buffer)
Verifies that a buffer contains a valid, parsable compressed EC point.
TER verifySendProof(Slice const &proof, ConfidentialRecipient const &sender, ConfidentialRecipient const &destination, ConfidentialRecipient const &issuer, std::optional< ConfidentialRecipient > const &auditor, Slice const &spendingBalance, Slice const &amountCommitment, Slice const &balanceCommitment, UInt256 const &contextHash)
Verifies all zero-knowledge proofs for a ConfidentialMPTSend transaction.
constexpr std::size_t kEcGamalEncryptedTotalLength
EC ElGamal ciphertext length: two compressed EC points concatenated.
Definition Protocol.h:480
bool isValidCiphertext(Slice const &buffer)
Verifies that a buffer contains two valid, parsable EC public keys.
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:614
std::optional< Buffer > homomorphicSubtract(Slice const &a, Slice const &b)
Homomorphically subtracts two ElGamal ciphertexts.
TER cleanupExpiredCredentials(STTx const &tx, ApplyView &view, beast::Journal j)
Remove expired credentials referenced by the transaction.
constexpr std::size_t kEcSendProofLength
192 bytes compact sigma proof + 754 bytes double bulletproof.
Definition Protocol.h:525
@ temBAD_CIPHERTEXT
Definition TER.h:134
@ temMALFORMED
Definition TER.h:75
bool isTesSuccess(TER x) noexcept
Definition TER.h:683
TERSubset< CanCvtToTER > TER
Definition TER.h:654
TER requireAuth(ReadView const &view, MPTIssue const &mptIssue, AccountID const &account, AuthType authType=AuthType::Legacy, std::uint8_t depth=0)
Check if the account lacks required authorization for MPT.
@ tecNO_TARGET
Definition TER.h:312
@ tecOBJECT_NOT_FOUND
Definition TER.h:334
@ tecNO_AUTH
Definition TER.h:308
@ tecINTERNAL
Definition TER.h:318
@ tecNO_PERMISSION
Definition TER.h:313
@ tecDST_TAG_NEEDED
Definition TER.h:317
void incrementConfidentialVersion(STObject &mptoken)
Increments the confidential balance version counter on an MPToken.
std::optional< Buffer > homomorphicAdd(Slice const &a, Slice const &b)
Homomorphically adds two ElGamal ciphertexts.
@ tesSUCCESS
Definition TER.h:250
TER checkDepositPreauth(STTx const &tx, ReadView const &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE const > const &sleDst, beast::Journal j)
Check whether src is authorized to deposit to dst.
Bundles an ElGamal public key with its associated encrypted amount.
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:92
ReadView const & view
Definition Transactor.h:95
beast::Journal const j
Definition Transactor.h:100
State information when preflighting a tx.
Definition Transactor.h:39
beast::Journal const j
Definition Transactor.h:46