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); !isTesSuccess(err))
242 return err;
243
244 return preflight2(ctx);
245}
246
247TER
249{
250 auto const delegate = tx[~sfDelegate];
251 if (!delegate)
252 return tesSUCCESS;
253
254 auto const delegateKey = keylet::delegate(tx[sfAccount], *delegate);
255 auto const sle = view.read(delegateKey);
256
257 if (!sle)
258 return tecNO_PERMISSION;
259
260 if (checkTxPermission(sle, tx) == tesSUCCESS)
261 return tesSUCCESS;
262
264 loadGranularPermission(sle, ttPAYMENT, granularPermissions);
265
266 auto const& dstAmount = tx.getFieldAmount(sfAmount);
267 auto const& amountIssue = dstAmount.issue();
268
269 if (granularPermissions.contains(PaymentMint) && !isXRP(amountIssue) &&
270 amountIssue.account == tx[sfAccount])
271 return tesSUCCESS;
272
273 if (granularPermissions.contains(PaymentBurn) && !isXRP(amountIssue) &&
274 amountIssue.account == tx[sfDestination])
275 return tesSUCCESS;
276
277 return tecNO_PERMISSION;
278}
279
280TER
282{
283 // Ripple if source or destination is non-native or if there are paths.
284 std::uint32_t const txFlags = ctx.tx.getFlags();
285 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
286 auto const hasPaths = ctx.tx.isFieldPresent(sfPaths);
287 auto const sendMax = ctx.tx[~sfSendMax];
288
289 AccountID const dstAccountID(ctx.tx[sfDestination]);
290 STAmount const dstAmount(ctx.tx[sfAmount]);
291
292 auto const k = keylet::account(dstAccountID);
293 auto const sleDst = ctx.view.read(k);
294
295 if (!sleDst)
296 {
297 // Destination account does not exist.
298 if (!dstAmount.native())
299 {
300 JLOG(ctx.j.trace())
301 << "Delay transaction: Destination account does not exist.";
302
303 // Another transaction could create the account and then this
304 // transaction would succeed.
305 return tecNO_DST;
306 }
307 else if (ctx.view.open() && partialPaymentAllowed)
308 {
309 // You cannot fund an account with a partial payment.
310 // Make retry work smaller, by rejecting this.
311 JLOG(ctx.j.trace()) << "Delay transaction: Partial payment not "
312 "allowed to create account.";
313
314 // Another transaction could create the account and then this
315 // transaction would succeed.
316 return telNO_DST_PARTIAL;
317 }
318 else if (dstAmount < STAmount(ctx.view.fees().accountReserve(0)))
319 {
320 // accountReserve is the minimum amount that an account can have.
321 // Reserve is not scaled by load.
322 JLOG(ctx.j.trace())
323 << "Delay transaction: Destination account does not exist. "
324 << "Insufficent payment to create account.";
325
326 // TODO: dedupe
327 // Another transaction could create the account and then this
328 // transaction would succeed.
329 return tecNO_DST_INSUF_XRP;
330 }
331 }
332 else if (
333 (sleDst->getFlags() & lsfRequireDestTag) &&
334 !ctx.tx.isFieldPresent(sfDestinationTag))
335 {
336 // The tag is basically account-specific information we don't
337 // understand, but we can require someone to fill it in.
338
339 // We didn't make this test for a newly-formed account because there's
340 // no way for this field to be set.
341 JLOG(ctx.j.trace())
342 << "Malformed transaction: DestinationTag required.";
343
344 return tecDST_TAG_NEEDED;
345 }
346
347 // Payment with at least one intermediate step and uses transitive balances.
348 if ((hasPaths || sendMax || !dstAmount.native()) && ctx.view.open())
349 {
350 STPathSet const& paths = ctx.tx.getFieldPathSet(sfPaths);
351
352 if (paths.size() > MaxPathSize ||
353 std::any_of(paths.begin(), paths.end(), [](STPath const& path) {
354 return path.size() > MaxPathLength;
355 }))
356 {
357 return telBAD_PATH_COUNT;
358 }
359 }
360
361 if (auto const err = credentials::valid(ctx, ctx.tx[sfAccount]);
362 !isTesSuccess(err))
363 return err;
364
365 if (ctx.tx.isFieldPresent(sfDomainID))
366 {
368 ctx.view, ctx.tx[sfAccount], ctx.tx[sfDomainID]))
369 return tecNO_PERMISSION;
370
372 ctx.view, ctx.tx[sfDestination], ctx.tx[sfDomainID]))
373 return tecNO_PERMISSION;
374 }
375
376 return tesSUCCESS;
377}
378
379TER
381{
382 auto const deliverMin = ctx_.tx[~sfDeliverMin];
383
384 // Ripple if source or destination is non-native or if there are paths.
385 std::uint32_t const txFlags = ctx_.tx.getFlags();
386 bool const partialPaymentAllowed = txFlags & tfPartialPayment;
387 bool const limitQuality = txFlags & tfLimitQuality;
388 bool const defaultPathsAllowed = !(txFlags & tfNoRippleDirect);
389 auto const hasPaths = ctx_.tx.isFieldPresent(sfPaths);
390 auto const sendMax = ctx_.tx[~sfSendMax];
391
392 AccountID const dstAccountID(ctx_.tx.getAccountID(sfDestination));
393 STAmount const dstAmount(ctx_.tx.getFieldAmount(sfAmount));
394 bool const mptDirect = dstAmount.holds<MPTIssue>();
395 STAmount const maxSourceAmount =
396 getMaxSourceAmount(account_, dstAmount, sendMax);
397
398 JLOG(j_.trace()) << "maxSourceAmount=" << maxSourceAmount.getFullText()
399 << " dstAmount=" << dstAmount.getFullText();
400
401 // Open a ledger for editing.
402 auto const k = keylet::account(dstAccountID);
403 SLE::pointer sleDst = view().peek(k);
404
405 if (!sleDst)
406 {
407 std::uint32_t const seqno{
408 view().rules().enabled(featureDeletableAccounts) ? view().seq()
409 : 1};
410
411 // Create the account.
412 sleDst = std::make_shared<SLE>(k);
413 sleDst->setAccountID(sfAccount, dstAccountID);
414 sleDst->setFieldU32(sfSequence, seqno);
415
416 view().insert(sleDst);
417 }
418 else
419 {
420 // Tell the engine that we are intending to change the destination
421 // account. The source account gets always charged a fee so it's always
422 // marked as modified.
423 view().update(sleDst);
424 }
425
426 // Determine whether the destination requires deposit authorization.
427 bool const depositAuth = view().rules().enabled(featureDepositAuth);
428 bool const reqDepositAuth =
429 sleDst->getFlags() & lsfDepositAuth && depositAuth;
430
431 bool const depositPreauth = view().rules().enabled(featureDepositPreauth);
432
433 bool const ripple =
434 (hasPaths || sendMax || !dstAmount.native()) && !mptDirect;
435
436 // If the destination has lsfDepositAuth set, then only direct XRP
437 // payments (no intermediate steps) are allowed to the destination.
438 if (!depositPreauth && ripple && reqDepositAuth)
439 return tecNO_PERMISSION;
440
441 if (ripple)
442 {
443 // Ripple payment with at least one intermediate step and uses
444 // transitive balances.
445
446 if (depositPreauth && depositAuth)
447 {
448 // If depositPreauth is enabled, then an account that requires
449 // authorization has two ways to get an IOU Payment in:
450 // 1. If Account == Destination, or
451 // 2. If Account is deposit preauthorized by destination.
452
453 if (auto err =
454 verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst);
455 !isTesSuccess(err))
456 return err;
457 }
458
460 rcInput.partialPaymentAllowed = partialPaymentAllowed;
461 rcInput.defaultPathsAllowed = defaultPathsAllowed;
462 rcInput.limitQuality = limitQuality;
463 rcInput.isLedgerOpen = view().open();
464
466 {
467 PaymentSandbox pv(&view());
468 JLOG(j_.debug()) << "Entering RippleCalc in payment: "
471 pv,
472 maxSourceAmount,
473 dstAmount,
474 dstAccountID,
475 account_,
476 ctx_.tx.getFieldPathSet(sfPaths),
477 ctx_.tx[~sfDomainID],
478 ctx_.app.logs(),
479 &rcInput);
480 // VFALCO NOTE We might not need to apply, depending
481 // on the TER. But always applying *should*
482 // be safe.
483 pv.apply(ctx_.rawView());
484 }
485
486 // TODO: is this right? If the amount is the correct amount, was
487 // the delivered amount previously set?
488 if (rc.result() == tesSUCCESS && rc.actualAmountOut != dstAmount)
489 {
490 if (deliverMin && rc.actualAmountOut < *deliverMin)
492 else
494 }
495
496 auto terResult = rc.result();
497
498 // Because of its overhead, if RippleCalc
499 // fails with a retry code, claim a fee
500 // instead. Maybe the user will be more
501 // careful with their path spec next time.
502 if (isTerRetry(terResult))
503 terResult = tecPATH_DRY;
504 return terResult;
505 }
506 else if (mptDirect)
507 {
508 JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText();
509 auto const& mptIssue = dstAmount.get<MPTIssue>();
510
511 if (auto const ter = requireAuth(view(), mptIssue, account_);
512 ter != tesSUCCESS)
513 return ter;
514
515 if (auto const ter = requireAuth(view(), mptIssue, dstAccountID);
516 ter != tesSUCCESS)
517 return ter;
518
519 if (auto const ter =
520 canTransfer(view(), mptIssue, account_, dstAccountID);
521 ter != tesSUCCESS)
522 return ter;
523
524 if (auto err =
525 verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst);
526 !isTesSuccess(err))
527 return err;
528
529 auto const& issuer = mptIssue.getIssuer();
530
531 // Transfer rate
532 Rate rate{QUALITY_ONE};
533 // Payment between the holders
534 if (account_ != issuer && dstAccountID != issuer)
535 {
536 // If globally/individually locked then
537 // - can't send between holders
538 // - holder can send back to issuer
539 // - issuer can send to holder
540 if (isAnyFrozen(view(), {account_, dstAccountID}, mptIssue))
541 return tecLOCKED;
542
543 // Get the rate for a payment between the holders.
544 rate = transferRate(view(), mptIssue.getMptID());
545 }
546
547 // Amount to deliver.
548 STAmount amountDeliver = dstAmount;
549 // Factor in the transfer rate.
550 // No rounding. It'll change once MPT integrated into DEX.
551 STAmount requiredMaxSourceAmount = multiply(dstAmount, rate);
552
553 // Send more than the account wants to pay or less than
554 // the account wants to deliver (if no SendMax).
555 // Adjust the amount to deliver.
556 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
557 {
558 requiredMaxSourceAmount = maxSourceAmount;
559 // No rounding. It'll change once MPT integrated into DEX.
560 amountDeliver = divide(maxSourceAmount, rate);
561 }
562
563 if (requiredMaxSourceAmount > maxSourceAmount ||
564 (deliverMin && amountDeliver < *deliverMin))
565 return tecPATH_PARTIAL;
566
567 PaymentSandbox pv(&view());
568 auto res = accountSend(
569 pv, account_, dstAccountID, amountDeliver, ctx_.journal);
570 if (res == tesSUCCESS)
571 pv.apply(ctx_.rawView());
572 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
573 res = tecPATH_PARTIAL;
574
575 return res;
576 }
577
578 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
579
580 // Direct XRP payment.
581
582 auto const sleSrc = view().peek(keylet::account(account_));
583 if (!sleSrc)
584 return tefINTERNAL;
585
586 // ownerCount is the number of entries in this ledger for this
587 // account that require a reserve.
588 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
589
590 // This is the total reserve in drops.
591 auto const reserve = view().fees().accountReserve(ownerCount);
592
593 // mPriorBalance is the balance on the sending account BEFORE the
594 // fees were charged. We want to make sure we have enough reserve
595 // to send. Allow final spend to use reserve for fee.
596 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
597
598 if (mPriorBalance < dstAmount.xrp() + mmm)
599 {
600 // Vote no. However the transaction might succeed, if applied in
601 // a different order.
602 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
603 << to_string(mPriorBalance) << " / "
604 << to_string(dstAmount.xrp() + mmm) << " ("
605 << to_string(reserve) << ")";
606
607 return tecUNFUNDED_PAYMENT;
608 }
609
610 // Pseudo-accounts cannot receive payments, other than these native to
611 // their underlying ledger object - implemented in their respective
612 // transaction types. Note, this is not amendment-gated because all writes
613 // to pseudo-account discriminator fields **are** amendment gated, hence the
614 // behaviour of this check will always match the active amendments.
615 if (isPseudoAccount(sleDst))
616 return tecNO_PERMISSION;
617
618 // The source account does have enough money. Make sure the
619 // source account has authority to deposit to the destination.
620 if (depositAuth)
621 {
622 // If depositPreauth is enabled, then an account that requires
623 // authorization has three ways to get an XRP Payment in:
624 // 1. If Account == Destination, or
625 // 2. If Account is deposit preauthorized by destination, or
626 // 3. If the destination's XRP balance is
627 // a. less than or equal to the base reserve and
628 // b. the deposit amount is less than or equal to the base reserve,
629 // then we allow the deposit.
630 //
631 // Rule 3 is designed to keep an account from getting wedged
632 // in an unusable state if it sets the lsfDepositAuth flag and
633 // then consumes all of its XRP. Without the rule if an
634 // account with lsfDepositAuth set spent all of its XRP, it
635 // would be unable to acquire more XRP required to pay fees.
636 //
637 // We choose the base reserve as our bound because it is
638 // a small number that seldom changes but is always sufficient
639 // to get the account un-wedged.
640
641 // Get the base reserve.
642 XRPAmount const dstReserve{view().fees().accountReserve(0)};
643
644 if (dstAmount > dstReserve ||
645 sleDst->getFieldAmount(sfBalance) > dstReserve)
646 {
647 if (auto err =
648 verifyDepositPreauth(ctx_, account_, dstAccountID, sleDst);
649 !isTesSuccess(err))
650 return err;
651 }
652 }
653
654 // Do the arithmetic for the transfer and make the ledger change.
655 sleSrc->setFieldAmount(sfBalance, mSourceBalance - dstAmount);
656 sleDst->setFieldAmount(
657 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
658
659 // Re-arm the password change fee if we can and need to.
660 if ((sleDst->getFlags() & lsfPasswordSpent))
661 sleDst->clearFlag(lsfPasswordSpent);
662
663 return tesSUCCESS;
664}
665
666} // 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
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:36
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:248
TER doApply() override
Definition: Payment.cpp:380
static TER preclaim(PreclaimContext const &ctx)
Definition: Payment.cpp:281
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:540
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(PreflightContext const &ctx)
TER valid(PreclaimContext const &ctx, AccountID const &src)
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:26
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
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
@ telBAD_PATH_COUNT
Definition: TER.h:54
@ telNO_DST_PARTIAL
Definition: TER.h:58
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
Definition: View.cpp:2288
bool isLegalNet(STAmount const &value)
Definition: STAmount.h:600
constexpr std::uint32_t tfMPTPaymentMask
Definition: TxFlags.h:111
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 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:2496
@ tefINTERNAL
Definition: TER.h:173
constexpr std::uint32_t tfPartialPayment
Definition: TxFlags.h:107
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_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:666
constexpr std::uint32_t tfNoRippleDirect
Definition: TxFlags.h:106
@ tesSUCCESS
Definition: TER.h:244
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
bool isTesSuccess(TER x) noexcept
Definition: TER.h:672
constexpr std::uint32_t tfPaymentMask
Definition: TxFlags.h:109
constexpr std::uint32_t tfLimitQuality
Definition: TxFlags.h:108
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:1127
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:1998
TERSubset< CanCvtToNotTEC > NotTEC
Definition: TER.h:603
@ 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