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