rippled
Loading...
Searching...
No Matches
Payment.cpp
1#include <xrpld/app/misc/DelegateUtils.h>
2#include <xrpld/app/misc/PermissionedDEXHelpers.h>
3#include <xrpld/app/paths/RippleCalc.h>
4#include <xrpld/app/tx/detail/Payment.h>
5
6#include <xrpl/basics/Log.h>
7#include <xrpl/ledger/CredentialHelpers.h>
8#include <xrpl/ledger/View.h>
9#include <xrpl/protocol/Feature.h>
10#include <xrpl/protocol/Quality.h>
11#include <xrpl/protocol/TxFlags.h>
12#include <xrpl/protocol/jss.h>
13
14namespace ripple {
15
16TxConsequences
18{
19 auto calculateMaxXRPSpend = [](STTx const& tx) -> XRPAmount {
20 STAmount const maxAmount =
21 tx.isFieldPresent(sfSendMax) ? tx[sfSendMax] : tx[sfAmount];
22
23 // If there's no sfSendMax in XRP, and the sfAmount isn't
24 // in XRP, then the transaction does not spend XRP.
25 return maxAmount.native() ? maxAmount.xrp() : beast::zero;
26 };
27
28 return TxConsequences{ctx.tx, calculateMaxXRPSpend(ctx.tx)};
29}
30
33 AccountID const& account,
34 STAmount const& dstAmount,
35 std::optional<STAmount> const& sendMax)
36{
37 if (sendMax)
38 return *sendMax;
39 else if (dstAmount.native() || dstAmount.holds<MPTIssue>())
40 return dstAmount;
41 else
42 return STAmount(
43 Issue{dstAmount.get<Issue>().currency, account},
44 dstAmount.mantissa(),
45 dstAmount.exponent(),
46 dstAmount < beast::zero);
47}
48
49bool
51{
52 if (ctx.tx.isFieldPresent(sfCredentialIDs) &&
53 !ctx.rules.enabled(featureCredentials))
54 return false;
55 if (ctx.tx.isFieldPresent(sfDomainID) &&
56 !ctx.rules.enabled(featurePermissionedDEX))
57 return false;
58
59 return true;
60}
61
64{
65 auto& tx = ctx.tx;
66
67 STAmount const dstAmount(tx.getFieldAmount(sfAmount));
68 bool const mptDirect = dstAmount.holds<MPTIssue>();
69
70 return mptDirect ? tfMPTPaymentMask : tfPaymentMask;
71}
72
75{
76 auto& tx = ctx.tx;
77 auto& j = ctx.j;
78
79 STAmount const dstAmount(tx.getFieldAmount(sfAmount));
80 bool const mptDirect = dstAmount.holds<MPTIssue>();
81
82 if (mptDirect && !ctx.rules.enabled(featureMPTokensV1))
83 return temDISABLED;
84
85 std::uint32_t const txFlags = tx.getFlags();
86
87 if (mptDirect && ctx.tx.isFieldPresent(sfPaths))
88 return temMALFORMED;
89
90 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
91 bool const limitQuality = txFlags & tfLimitQuality;
92 bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect);
93 bool const hasPaths = tx.isFieldPresent(sfPaths);
94 bool const hasMax = tx.isFieldPresent(sfSendMax);
95
96 auto const deliverMin = tx[~sfDeliverMin];
97
98 auto const account = tx.getAccountID(sfAccount);
99 STAmount const maxSourceAmount =
100 getMaxSourceAmount(account, dstAmount, tx[~sfSendMax]);
101
102 if ((mptDirect && dstAmount.asset() != maxSourceAmount.asset()) ||
103 (!mptDirect && maxSourceAmount.holds<MPTIssue>()))
104 {
105 JLOG(j.trace()) << "Malformed transaction: inconsistent issues: "
106 << dstAmount.getFullText() << " "
107 << maxSourceAmount.getFullText() << " "
108 << deliverMin.value_or(STAmount{}).getFullText();
109 return temMALFORMED;
110 }
111
112 auto const& srcAsset = maxSourceAmount.asset();
113 auto const& dstAsset = dstAmount.asset();
114
115 bool const xrpDirect = srcAsset.native() && dstAsset.native();
116
117 if (!isLegalNet(dstAmount) || !isLegalNet(maxSourceAmount))
118 return temBAD_AMOUNT;
119
120 auto const dstAccountID = tx.getAccountID(sfDestination);
121
122 if (!dstAccountID)
123 {
124 JLOG(j.trace()) << "Malformed transaction: "
125 << "Payment destination account not specified.";
126 return temDST_NEEDED;
127 }
128 if (hasMax && maxSourceAmount <= beast::zero)
129 {
130 JLOG(j.trace()) << "Malformed transaction: bad max amount: "
131 << maxSourceAmount.getFullText();
132 return temBAD_AMOUNT;
133 }
134 if (dstAmount <= beast::zero)
135 {
136 JLOG(j.trace()) << "Malformed transaction: bad dst amount: "
137 << dstAmount.getFullText();
138 return temBAD_AMOUNT;
139 }
140 if (badCurrency() == srcAsset || badCurrency() == dstAsset)
141 {
142 JLOG(j.trace()) << "Malformed transaction: Bad currency.";
143 return temBAD_CURRENCY;
144 }
145 if (account == dstAccountID && equalTokens(srcAsset, dstAsset) && !hasPaths)
146 {
147 // You're signing yourself a payment.
148 // If hasPaths is true, you might be trying some arbitrage.
149 JLOG(j.trace()) << "Malformed transaction: "
150 << "Redundant payment from " << to_string(account)
151 << " to self without path for " << to_string(dstAsset);
152 return temREDUNDANT;
153 }
154 if (xrpDirect && hasMax)
155 {
156 // Consistent but redundant transaction.
157 JLOG(j.trace()) << "Malformed transaction: "
158 << "SendMax specified for XRP to XRP.";
159 return temBAD_SEND_XRP_MAX;
160 }
161 if ((xrpDirect || mptDirect) && hasPaths)
162 {
163 // XRP is sent without paths.
164 JLOG(j.trace()) << "Malformed transaction: "
165 << "Paths specified for XRP to XRP or MPT to MPT.";
167 }
168 if (xrpDirect && partialPaymentAllowed)
169 {
170 // Consistent but redundant transaction.
171 JLOG(j.trace()) << "Malformed transaction: "
172 << "Partial payment specified for XRP to XRP.";
174 }
175 if ((xrpDirect || mptDirect) && limitQuality)
176 {
177 // Consistent but redundant transaction.
178 JLOG(j.trace())
179 << "Malformed transaction: "
180 << "Limit quality specified for XRP to XRP or MPT to MPT.";
182 }
183 if ((xrpDirect || mptDirect) && !defaultPathsAllowed)
184 {
185 // Consistent but redundant transaction.
186 JLOG(j.trace())
187 << "Malformed transaction: "
188 << "No ripple direct specified for XRP to XRP or MPT to MPT.";
190 }
191
192 if (deliverMin)
193 {
194 if (!partialPaymentAllowed)
195 {
196 JLOG(j.trace()) << "Malformed transaction: Partial payment not "
197 "specified for "
198 << jss::DeliverMin.c_str() << ".";
199 return temBAD_AMOUNT;
200 }
201
202 auto const dMin = *deliverMin;
203 if (!isLegalNet(dMin) || dMin <= beast::zero)
204 {
205 JLOG(j.trace())
206 << "Malformed transaction: Invalid " << jss::DeliverMin.c_str()
207 << " amount. " << dMin.getFullText();
208 return temBAD_AMOUNT;
209 }
210 if (dMin.asset() != dstAmount.asset())
211 {
212 JLOG(j.trace())
213 << "Malformed transaction: Dst issue differs "
214 "from "
215 << jss::DeliverMin.c_str() << ". " << dMin.getFullText();
216 return temBAD_AMOUNT;
217 }
218 if (dMin > dstAmount)
219 {
220 JLOG(j.trace())
221 << "Malformed transaction: Dst amount less than "
222 << jss::DeliverMin.c_str() << ". " << dMin.getFullText();
223 return temBAD_AMOUNT;
224 }
225 }
226
227 if (auto const err = credentials::checkFields(ctx.tx, ctx.j);
228 !isTesSuccess(err))
229 return err;
230
231 return tesSUCCESS;
232}
233
234NotTEC
236{
237 auto const delegate = tx[~sfDelegate];
238 if (!delegate)
239 return tesSUCCESS;
240
241 auto const delegateKey = keylet::delegate(tx[sfAccount], *delegate);
242 auto const sle = view.read(delegateKey);
243
244 if (!sle)
246
247 if (checkTxPermission(sle, tx) == tesSUCCESS)
248 return tesSUCCESS;
249
251 loadGranularPermission(sle, ttPAYMENT, granularPermissions);
252
253 auto const& dstAmount = tx.getFieldAmount(sfAmount);
254 auto const& amountAsset = dstAmount.asset();
255
256 // Granular permissions are only valid for direct payments.
257 if ((tx.isFieldPresent(sfSendMax) &&
258 tx[sfSendMax].asset() != amountAsset) ||
259 tx.isFieldPresent(sfPaths))
261
262 if (granularPermissions.contains(PaymentMint) && !isXRP(amountAsset) &&
263 amountAsset.getIssuer() == tx[sfAccount])
264 return tesSUCCESS;
265
266 if (granularPermissions.contains(PaymentBurn) && !isXRP(amountAsset) &&
267 amountAsset.getIssuer() == tx[sfDestination])
268 return tesSUCCESS;
269
271}
272
273TER
275{
276 // Ripple if source or destination is non-native or if there are paths.
277 std::uint32_t const txFlags = ctx.tx.getFlags();
278 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
279 auto const hasPaths = ctx.tx.isFieldPresent(sfPaths);
280 auto const sendMax = ctx.tx[~sfSendMax];
281
282 AccountID const dstAccountID(ctx.tx[sfDestination]);
283 STAmount const dstAmount(ctx.tx[sfAmount]);
284
285 auto const k = keylet::account(dstAccountID);
286 auto const sleDst = ctx.view.read(k);
287
288 if (!sleDst)
289 {
290 // Destination account does not exist.
291 if (!dstAmount.native())
292 {
293 JLOG(ctx.j.trace())
294 << "Delay transaction: Destination account does not exist.";
295
296 // Another transaction could create the account and then this
297 // transaction would succeed.
298 return tecNO_DST;
299 }
300 else if (ctx.view.open() && partialPaymentAllowed)
301 {
302 // You cannot fund an account with a partial payment.
303 // Make retry work smaller, by rejecting this.
304 JLOG(ctx.j.trace()) << "Delay transaction: Partial payment not "
305 "allowed to create account.";
306
307 // Another transaction could create the account and then this
308 // transaction would succeed.
309 return telNO_DST_PARTIAL;
310 }
311 else if (dstAmount < STAmount(ctx.view.fees().reserve))
312 {
313 // accountReserve is the minimum amount that an account can have.
314 // Reserve is not scaled by load.
315 JLOG(ctx.j.trace())
316 << "Delay transaction: Destination account does not exist. "
317 << "Insufficent payment to create account.";
318
319 // TODO: dedupe
320 // Another transaction could create the account and then this
321 // transaction would succeed.
322 return tecNO_DST_INSUF_XRP;
323 }
324 }
325 else if (
326 (sleDst->getFlags() & lsfRequireDestTag) &&
327 !ctx.tx.isFieldPresent(sfDestinationTag))
328 {
329 // The tag is basically account-specific information we don't
330 // understand, but we can require someone to fill it in.
331
332 // We didn't make this test for a newly-formed account because there's
333 // no way for this field to be set.
334 JLOG(ctx.j.trace())
335 << "Malformed transaction: DestinationTag required.";
336
337 return tecDST_TAG_NEEDED;
338 }
339
340 // Payment with at least one intermediate step and uses transitive balances.
341 if ((hasPaths || sendMax || !dstAmount.native()) && ctx.view.open())
342 {
343 STPathSet const& paths = ctx.tx.getFieldPathSet(sfPaths);
344
345 if (paths.size() > MaxPathSize ||
346 std::any_of(paths.begin(), paths.end(), [](STPath const& path) {
347 return path.size() > MaxPathLength;
348 }))
349 {
350 return telBAD_PATH_COUNT;
351 }
352 }
353
354 if (auto const err =
355 credentials::valid(ctx.tx, ctx.view, ctx.tx[sfAccount], ctx.j);
356 !isTesSuccess(err))
357 return err;
358
359 if (ctx.tx.isFieldPresent(sfDomainID))
360 {
362 ctx.view, ctx.tx[sfAccount], ctx.tx[sfDomainID]))
363 return tecNO_PERMISSION;
364
366 ctx.view, ctx.tx[sfDestination], ctx.tx[sfDomainID]))
367 return tecNO_PERMISSION;
368 }
369
370 return tesSUCCESS;
371}
372
373TER
375{
376 auto const deliverMin = ctx_.tx[~sfDeliverMin];
377
378 // Ripple if source or destination is non-native or if there are paths.
379 std::uint32_t const txFlags = ctx_.tx.getFlags();
380 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
381 bool const limitQuality = txFlags & tfLimitQuality;
382 bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect);
383 auto const hasPaths = ctx_.tx.isFieldPresent(sfPaths);
384 auto const sendMax = ctx_.tx[~sfSendMax];
385
386 AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination));
387 STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount));
388 bool const mptDirect = dstAmount.holds<MPTIssue>();
389 STAmount const maxSourceAmount =
390 getMaxSourceAmount(account_, dstAmount, sendMax);
391
392 JLOG(j_.trace()) << "maxSourceAmount=" << maxSourceAmount.getFullText()
393 << " dstAmount=" << dstAmount.getFullText();
394
395 // Open a ledger for editing.
396 auto const k = keylet::account(dstAccountID);
397 SLE::pointer sleDst = view().peek(k);
398
399 if (!sleDst)
400 {
401 std::uint32_t const seqno{
402 view().rules().enabled(featureDeletableAccounts) ? view().seq()
403 : 1};
404
405 // Create the account.
406 sleDst = std::make_shared<SLE>(k);
407 sleDst->setAccountID(sfAccount, dstAccountID);
408 sleDst->setFieldU32(sfSequence, seqno);
409
410 view().insert(sleDst);
411 }
412 else
413 {
414 // Tell the engine that we are intending to change the destination
415 // account. The source account gets always charged a fee so it's always
416 // marked as modified.
417 view().update(sleDst);
418 }
419
420 // Determine whether the destination requires deposit authorization.
421 bool const depositAuth = view().rules().enabled(featureDepositAuth);
422 bool const reqDepositAuth =
423 sleDst->getFlags() & lsfDepositAuth && depositAuth;
424
425 bool const depositPreauth = view().rules().enabled(featureDepositPreauth);
426
427 bool const ripple =
428 (hasPaths || sendMax || !dstAmount.native()) && !mptDirect;
429
430 // If the destination has lsfDepositAuth set, then only direct XRP
431 // payments (no intermediate steps) are allowed to the destination.
432 if (!depositPreauth && ripple && reqDepositAuth)
433 return tecNO_PERMISSION;
434
435 if (ripple)
436 {
437 // Ripple payment with at least one intermediate step and uses
438 // transitive balances.
439
440 if (depositPreauth && depositAuth)
441 {
442 // If depositPreauth is enabled, then an account that requires
443 // authorization has two ways to get an IOU Payment in:
444 // 1. If Account == Destination, or
445 // 2. If Account is deposit preauthorized by destination.
446
447 if (auto err = verifyDepositPreauth(
448 ctx_.tx,
449 ctx_.view(),
450 account_,
451 dstAccountID,
452 sleDst,
453 ctx_.journal);
454 !isTesSuccess(err))
455 return err;
456 }
457
459 rcInput.partialPaymentAllowed = partialPaymentAllowed;
460 rcInput.defaultPathsAllowed = defaultPathsAllowed;
461 rcInput.limitQuality = limitQuality;
462 rcInput.isLedgerOpen = view().open();
463
465 {
466 PaymentSandbox pv(&view());
467 JLOG(j_.debug()) << "Entering RippleCalc in payment: "
470 pv,
471 maxSourceAmount,
472 dstAmount,
473 dstAccountID,
474 account_,
475 ctx_.tx.getFieldPathSet(sfPaths),
476 ctx_.tx[~sfDomainID],
477 ctx_.app.logs(),
478 &rcInput);
479 // VFALCO NOTE We might not need to apply, depending
480 // on the TER. But always applying *should*
481 // be safe.
482 pv.apply(ctx_.rawView());
483 }
484
485 // TODO: is this right? If the amount is the correct amount, was
486 // the delivered amount previously set?
487 if (rc.result() == tesSUCCESS && rc.actualAmountOut != dstAmount)
488 {
489 if (deliverMin && rc.actualAmountOut < *deliverMin)
491 else
493 }
494
495 auto terResult = rc.result();
496
497 // Because of its overhead, if RippleCalc
498 // fails with a retry code, claim a fee
499 // instead. Maybe the user will be more
500 // careful with their path spec next time.
501 if (isTerRetry(terResult))
502 terResult = tecPATH_DRY;
503 return terResult;
504 }
505 else if (mptDirect)
506 {
507 JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText();
508 auto const& mptIssue = dstAmount.get<MPTIssue>();
509
510 if (auto const ter = requireAuth(view(), mptIssue, account_);
511 ter != tesSUCCESS)
512 return ter;
513
514 if (auto const ter = requireAuth(view(), mptIssue, dstAccountID);
515 ter != tesSUCCESS)
516 return ter;
517
518 if (auto const ter =
519 canTransfer(view(), mptIssue, account_, dstAccountID);
520 ter != tesSUCCESS)
521 return ter;
522
523 if (auto err = verifyDepositPreauth(
524 ctx_.tx,
525 ctx_.view(),
526 account_,
527 dstAccountID,
528 sleDst,
529 ctx_.journal);
530 !isTesSuccess(err))
531 return err;
532
533 auto const& issuer = mptIssue.getIssuer();
534
535 // Transfer rate
536 Rate rate{QUALITY_ONE};
537 // Payment between the holders
538 if (account_ != issuer && dstAccountID != issuer)
539 {
540 // If globally/individually locked then
541 // - can't send between holders
542 // - holder can send back to issuer
543 // - issuer can send to holder
544 if (isAnyFrozen(view(), {account_, dstAccountID}, mptIssue))
545 return tecLOCKED;
546
547 // Get the rate for a payment between the holders.
548 rate = transferRate(view(), mptIssue.getMptID());
549 }
550
551 // Amount to deliver.
552 STAmount amountDeliver = dstAmount;
553 // Factor in the transfer rate.
554 // No rounding. It'll change once MPT integrated into DEX.
555 STAmount requiredMaxSourceAmount = multiply(dstAmount, rate);
556
557 // Send more than the account wants to pay or less than
558 // the account wants to deliver (if no SendMax).
559 // Adjust the amount to deliver.
560 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
561 {
562 requiredMaxSourceAmount = maxSourceAmount;
563 // No rounding. It'll change once MPT integrated into DEX.
564 amountDeliver = divide(maxSourceAmount, rate);
565 }
566
567 if (requiredMaxSourceAmount > maxSourceAmount ||
568 (deliverMin && amountDeliver < *deliverMin))
569 return tecPATH_PARTIAL;
570
571 PaymentSandbox pv(&view());
572 auto res = accountSend(
573 pv, account_, dstAccountID, amountDeliver, ctx_.journal);
574 if (res == tesSUCCESS)
575 {
576 pv.apply(ctx_.rawView());
577
578 // If the actual amount delivered is different from the original
579 // amount due to partial payment or transfer fee, we need to update
580 // DelieveredAmount using the actual delivered amount
581 if (view().rules().enabled(fixMPTDeliveredAmount) &&
582 amountDeliver != dstAmount)
583 ctx_.deliver(amountDeliver);
584 }
585 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
586 res = tecPATH_PARTIAL;
587
588 return res;
589 }
590
591 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
592
593 // Direct XRP payment.
594
595 auto const sleSrc = view().peek(keylet::account(account_));
596 if (!sleSrc)
597 return tefINTERNAL; // LCOV_EXCL_LINE
598
599 // ownerCount is the number of entries in this ledger for this
600 // account that require a reserve.
601 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
602
603 // This is the total reserve in drops.
604 auto const reserve = view().fees().accountReserve(ownerCount);
605
606 // mPriorBalance is the balance on the sending account BEFORE the
607 // fees were charged. We want to make sure we have enough reserve
608 // to send. Allow final spend to use reserve for fee.
609 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
610
611 if (mPriorBalance < dstAmount.xrp() + mmm)
612 {
613 // Vote no. However the transaction might succeed, if applied in
614 // a different order.
615 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
616 << to_string(mPriorBalance) << " / "
617 << to_string(dstAmount.xrp() + mmm) << " ("
618 << to_string(reserve) << ")";
619
620 return tecUNFUNDED_PAYMENT;
621 }
622
623 // Pseudo-accounts cannot receive payments, other than these native to
624 // their underlying ledger object - implemented in their respective
625 // transaction types. Note, this is not amendment-gated because all writes
626 // to pseudo-account discriminator fields **are** amendment gated, hence the
627 // behaviour of this check will always match the active amendments.
628 if (isPseudoAccount(sleDst))
629 return tecNO_PERMISSION;
630
631 // The source account does have enough money. Make sure the
632 // source account has authority to deposit to the destination.
633 if (depositAuth)
634 {
635 // If depositPreauth is enabled, then an account that requires
636 // authorization has three ways to get an XRP Payment in:
637 // 1. If Account == Destination, or
638 // 2. If Account is deposit preauthorized by destination, or
639 // 3. If the destination's XRP balance is
640 // a. less than or equal to the base reserve and
641 // b. the deposit amount is less than or equal to the base reserve,
642 // then we allow the deposit.
643 //
644 // Rule 3 is designed to keep an account from getting wedged
645 // in an unusable state if it sets the lsfDepositAuth flag and
646 // then consumes all of its XRP. Without the rule if an
647 // account with lsfDepositAuth set spent all of its XRP, it
648 // would be unable to acquire more XRP required to pay fees.
649 //
650 // We choose the base reserve as our bound because it is
651 // a small number that seldom changes but is always sufficient
652 // to get the account un-wedged.
653
654 // Get the base reserve.
655 XRPAmount const dstReserve{view().fees().reserve};
656
657 if (dstAmount > dstReserve ||
658 sleDst->getFieldAmount(sfBalance) > dstReserve)
659 {
660 if (auto err = verifyDepositPreauth(
661 ctx_.tx,
662 ctx_.view(),
663 account_,
664 dstAccountID,
665 sleDst,
666 ctx_.journal);
667 !isTesSuccess(err))
668 return err;
669 }
670 }
671
672 // Do the arithmetic for the transfer and make the ledger change.
673 sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount);
674 sleDst->setFieldAmount(
675 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
676
677 // Re-arm the password change fee if we can and need to.
678 if ((sleDst->getFlags() & lsfPasswordSpent))
679 sleDst->clearFlag(lsfPasswordSpent);
680
681 return tesSUCCESS;
682}
683
684} // namespace ripple
T any_of(T... args)
Stream debug() const
Definition Journal.h:309
Stream trace() const
Severity stream access functions.
Definition Journal.h:303
virtual Logs & logs()=0
ApplyView & view()
Application & app
beast::Journal const journal
void deliver(STAmount const &amount)
Sets the DeliveredAmount field in the metadata.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
bool native() const
Definition Asset.h:82
A currency issued by an account.
Definition Issue.h:14
AccountID const & getIssuer() const
Definition MPTIssue.cpp:21
A wrapper which makes credits unavailable to balances.
void apply(RawView &to)
Apply changes to base view.
static NotTEC checkPermission(ReadView const &view, STTx const &tx)
Definition Payment.cpp:235
static std::size_t const MaxPathSize
Definition Payment.h:11
static bool checkExtraFeatures(PreflightContext const &ctx)
Definition Payment.cpp:50
TER doApply() override
Definition Payment.cpp:374
static std::uint32_t getFlagsMask(PreflightContext const &ctx)
Definition Payment.cpp:63
static TER preclaim(PreclaimContext const &ctx)
Definition Payment.cpp:274
static NotTEC preflight(PreflightContext const &ctx)
Definition Payment.cpp:74
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
Definition Payment.cpp:17
A view into a ledger.
Definition ReadView.h:32
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual bool open() const =0
Returns true if this reflects an open ledger.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition ReadView.h:99
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 bool holds() const noexcept
Definition STAmount.h:446
int exponent() const noexcept
Definition STAmount.h:433
Asset const & asset() const
Definition STAmount.h:464
constexpr TIss const & get() const
XRPAmount xrp() const
Definition STAmount.cpp:264
std::uint64_t mantissa() const noexcept
Definition STAmount.h:458
std::string getFullText() const override
Definition STAmount.cpp:654
bool native() const noexcept
Definition STAmount.h:439
STPathSet const & getFieldPathSet(SField const &field) const
Definition STObject.cpp:659
AccountID getAccountID(SField const &field) const
Definition STObject.cpp:638
STAmount const & getFieldAmount(SField const &field) const
Definition STObject.cpp:652
bool isFieldPresent(SField const &field) const
Definition STObject.cpp:465
std::uint32_t getFlags() const
Definition STObject.cpp:518
std::vector< STPath >::const_iterator end() const
Definition STPathSet.h:477
std::vector< STPath >::const_iterator begin() const
Definition STPathSet.h:471
std::vector< STPath >::size_type size() const
Definition STPathSet.h:483
uint256 getTransactionID() const
Definition STTx.h:230
AccountID const account_
Definition Transactor.h:128
ApplyView & view()
Definition Transactor.h:144
beast::Journal const j_
Definition Transactor.h:126
XRPAmount mPriorBalance
Definition Transactor.h:129
XRPAmount mSourceBalance
Definition Transactor.h:130
ApplyContext & ctx_
Definition Transactor.h:124
Class describing the consequences to the account of applying a transaction if the transaction consume...
Definition applySteps.h:39
static Output rippleCalculate(PaymentSandbox &view, STAmount const &saMaxAmountReq, STAmount const &saDstAmountReq, AccountID const &uDstAccountID, AccountID const &uSrcAccountID, STPathSet const &spsPaths, std::optional< uint256 > const &domainID, Logs &l, Input const *const pInputs=nullptr)
T contains(T... args)
T is_same_v
T max(T... args)
NotTEC checkFields(STTx const &tx, beast::Journal j)
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Keylet delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
Definition Indexes.cpp:446
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:165
bool accountInDomain(ReadView const &view, AccountID const &account, Domain const &domainID)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
STAmount divide(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:74
NotTEC checkTxPermission(std::shared_ptr< SLE const > const &delegate, STTx const &tx)
Check if the delegate account has permission to execute the transaction.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr bool equalTokens(Asset const &lhs, Asset const &rhs)
Definition Asset.h:182
bool isXRP(AccountID const &c)
Definition AccountID.h:71
@ telBAD_PATH_COUNT
Definition TER.h:35
@ telNO_DST_PARTIAL
Definition TER.h:39
bool isLegalNet(STAmount const &value)
Definition STAmount.h:581
constexpr std::uint32_t tfMPTPaymentMask
Definition TxFlags.h:93
STAmount getMaxSourceAmount(AccountID const &account, STAmount const &dstAmount, std::optional< STAmount > const &sendMax)
Definition Payment.cpp:32
@ lsfRequireDestTag
@ lsfPasswordSpent
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition Rate2.cpp:34
TER accountSend(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee=WaiveTransferFee::No)
Calls static accountSendIOU if saAmount represents Issue.
Definition View.cpp:2172
TER verifyDepositPreauth(STTx const &tx, ApplyView &view, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst, beast::Journal j)
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account, AuthType authType=AuthType::Legacy)
Check if the account lacks required authorization.
Definition View.cpp:2466
@ tefINTERNAL
Definition TER.h:154
constexpr std::uint32_t tfPartialPayment
Definition TxFlags.h:89
void loadGranularPermission(std::shared_ptr< SLE const > const &delegate, TxType const &type, std::unordered_set< GranularPermissionType > &granularPermissions)
Load the granular permissions granted to the delegate account for the specified transaction type.
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
Definition View.cpp:2685
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
Definition View.cpp:743
@ tecNO_DST
Definition TER.h:272
@ tecINSUFFICIENT_FUNDS
Definition TER.h:307
@ tecNO_PERMISSION
Definition TER.h:287
@ tecDST_TAG_NEEDED
Definition TER.h:291
@ tecPATH_PARTIAL
Definition TER.h:264
@ tecUNFUNDED_PAYMENT
Definition TER.h:267
@ tecPATH_DRY
Definition TER.h:276
@ tecNO_DST_INSUF_XRP
Definition TER.h:273
@ tecLOCKED
Definition TER.h:340
bool isTerRetry(TER x) noexcept
Definition TER.h:653
constexpr std::uint32_t tfNoRippleDirect
Definition TxFlags.h:88
@ tesSUCCESS
Definition TER.h:226
bool isTesSuccess(TER x) noexcept
Definition TER.h:659
constexpr std::uint32_t tfPaymentMask
Definition TxFlags.h:91
constexpr std::uint32_t tfLimitQuality
Definition TxFlags.h:90
std::string to_string(base_uint< Bits, Tag > const &a)
Definition base_uint.h:611
bool isAnyFrozen(ReadView const &view, std::initializer_list< AccountID > const &accounts, MPTIssue const &mptIssue, int depth=0)
Definition View.cpp:263
@ terNO_DELEGATE_PERMISSION
Definition TER.h:211
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
Definition View.cpp:1099
@ temBAD_SEND_XRP_PARTIAL
Definition TER.h:83
@ temBAD_AMOUNT
Definition TER.h:70
@ temREDUNDANT
Definition TER.h:93
@ temDST_NEEDED
Definition TER.h:90
@ temBAD_CURRENCY
Definition TER.h:71
@ temBAD_SEND_XRP_LIMIT
Definition TER.h:80
@ temMALFORMED
Definition TER.h:68
@ temBAD_SEND_XRP_PATHS
Definition TER.h:84
@ temBAD_SEND_XRP_NO_DIRECT
Definition TER.h:82
@ temDISABLED
Definition TER.h:95
@ temBAD_SEND_XRP_MAX
Definition TER.h:81
XRPAmount reserve
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
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
beast::Journal const j
Definition Transactor.h:23
Represents a transfer rate.
Definition Rate.h:21
void setResult(TER const value)
Definition RippleCalc.h:63