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 bool const ripple =
421 (hasPaths || sendMax || !dstAmount.native()) && !mptDirect;
422
423 if (ripple)
424 {
425 // Ripple payment with at least one intermediate step and uses
426 // transitive balances.
427
428 // An account that requires authorization has two ways to get an
429 // IOU Payment in:
430 // 1. If Account == Destination, or
431 // 2. If Account is deposit preauthorized by destination.
432
433 if (auto err = verifyDepositPreauth(
434 ctx_.tx,
435 ctx_.view(),
436 account_,
437 dstAccountID,
438 sleDst,
439 ctx_.journal);
440 !isTesSuccess(err))
441 return err;
442
444 rcInput.partialPaymentAllowed = partialPaymentAllowed;
445 rcInput.defaultPathsAllowed = defaultPathsAllowed;
446 rcInput.limitQuality = limitQuality;
447 rcInput.isLedgerOpen = view().open();
448
450 {
451 PaymentSandbox pv(&view());
452 JLOG(j_.debug()) << "Entering RippleCalc in payment: "
455 pv,
456 maxSourceAmount,
457 dstAmount,
458 dstAccountID,
459 account_,
460 ctx_.tx.getFieldPathSet(sfPaths),
461 ctx_.tx[~sfDomainID],
462 ctx_.app.logs(),
463 &rcInput);
464 // VFALCO NOTE We might not need to apply, depending
465 // on the TER. But always applying *should*
466 // be safe.
467 pv.apply(ctx_.rawView());
468 }
469
470 // TODO: is this right? If the amount is the correct amount, was
471 // the delivered amount previously set?
472 if (rc.result() == tesSUCCESS && rc.actualAmountOut != dstAmount)
473 {
474 if (deliverMin && rc.actualAmountOut < *deliverMin)
476 else
478 }
479
480 auto terResult = rc.result();
481
482 // Because of its overhead, if RippleCalc
483 // fails with a retry code, claim a fee
484 // instead. Maybe the user will be more
485 // careful with their path spec next time.
486 if (isTerRetry(terResult))
487 terResult = tecPATH_DRY;
488 return terResult;
489 }
490 else if (mptDirect)
491 {
492 JLOG(j_.trace()) << " dstAmount=" << dstAmount.getFullText();
493 auto const& mptIssue = dstAmount.get<MPTIssue>();
494
495 if (auto const ter = requireAuth(view(), mptIssue, account_);
496 ter != tesSUCCESS)
497 return ter;
498
499 if (auto const ter = requireAuth(view(), mptIssue, dstAccountID);
500 ter != tesSUCCESS)
501 return ter;
502
503 if (auto const ter =
504 canTransfer(view(), mptIssue, account_, dstAccountID);
505 ter != tesSUCCESS)
506 return ter;
507
508 if (auto err = verifyDepositPreauth(
509 ctx_.tx,
510 ctx_.view(),
511 account_,
512 dstAccountID,
513 sleDst,
514 ctx_.journal);
515 !isTesSuccess(err))
516 return err;
517
518 auto const& issuer = mptIssue.getIssuer();
519
520 // Transfer rate
521 Rate rate{QUALITY_ONE};
522 // Payment between the holders
523 if (account_ != issuer && dstAccountID != issuer)
524 {
525 // If globally/individually locked then
526 // - can't send between holders
527 // - holder can send back to issuer
528 // - issuer can send to holder
529 if (isAnyFrozen(view(), {account_, dstAccountID}, mptIssue))
530 return tecLOCKED;
531
532 // Get the rate for a payment between the holders.
533 rate = transferRate(view(), mptIssue.getMptID());
534 }
535
536 // Amount to deliver.
537 STAmount amountDeliver = dstAmount;
538 // Factor in the transfer rate.
539 // No rounding. It'll change once MPT integrated into DEX.
540 STAmount requiredMaxSourceAmount = multiply(dstAmount, rate);
541
542 // Send more than the account wants to pay or less than
543 // the account wants to deliver (if no SendMax).
544 // Adjust the amount to deliver.
545 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
546 {
547 requiredMaxSourceAmount = maxSourceAmount;
548 // No rounding. It'll change once MPT integrated into DEX.
549 amountDeliver = divide(maxSourceAmount, rate);
550 }
551
552 if (requiredMaxSourceAmount > maxSourceAmount ||
553 (deliverMin && amountDeliver < *deliverMin))
554 return tecPATH_PARTIAL;
555
556 PaymentSandbox pv(&view());
557 auto res = accountSend(
558 pv, account_, dstAccountID, amountDeliver, ctx_.journal);
559 if (res == tesSUCCESS)
560 {
561 pv.apply(ctx_.rawView());
562
563 // If the actual amount delivered is different from the original
564 // amount due to partial payment or transfer fee, we need to update
565 // DelieveredAmount using the actual delivered amount
566 if (view().rules().enabled(fixMPTDeliveredAmount) &&
567 amountDeliver != dstAmount)
568 ctx_.deliver(amountDeliver);
569 }
570 else if (res == tecINSUFFICIENT_FUNDS || res == tecPATH_DRY)
571 res = tecPATH_PARTIAL;
572
573 return res;
574 }
575
576 XRPL_ASSERT(dstAmount.native(), "ripple::Payment::doApply : amount is XRP");
577
578 // Direct XRP payment.
579
580 auto const sleSrc = view().peek(keylet::account(account_));
581 if (!sleSrc)
582 return tefINTERNAL; // LCOV_EXCL_LINE
583
584 // ownerCount is the number of entries in this ledger for this
585 // account that require a reserve.
586 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
587
588 // This is the total reserve in drops.
589 auto const reserve = view().fees().accountReserve(ownerCount);
590
591 // mPriorBalance is the balance on the sending account BEFORE the
592 // fees were charged. We want to make sure we have enough reserve
593 // to send. Allow final spend to use reserve for fee.
594 auto const mmm = std::max(reserve, ctx_.tx.getFieldAmount(sfFee).xrp());
595
596 if (mPriorBalance < dstAmount.xrp() + mmm)
597 {
598 // Vote no. However the transaction might succeed, if applied in
599 // a different order.
600 JLOG(j_.trace()) << "Delay transaction: Insufficient funds: "
601 << to_string(mPriorBalance) << " / "
602 << to_string(dstAmount.xrp() + mmm) << " ("
603 << to_string(reserve) << ")";
604
605 return tecUNFUNDED_PAYMENT;
606 }
607
608 // Pseudo-accounts cannot receive payments, other than these native to
609 // their underlying ledger object - implemented in their respective
610 // transaction types. Note, this is not amendment-gated because all writes
611 // to pseudo-account discriminator fields **are** amendment gated, hence the
612 // behaviour of this check will always match the active amendments.
613 if (isPseudoAccount(sleDst))
614 return tecNO_PERMISSION;
615
616 // The source account does have enough money. Make sure the
617 // source account has authority to deposit to the destination.
618 // An account that requires authorization has three ways to get an XRP
619 // Payment in:
620 // 1. If Account == Destination, or
621 // 2. If Account is deposit preauthorized by destination, or
622 // 3. If the destination's XRP balance is
623 // a. less than or equal to the base reserve and
624 // b. the deposit amount is less than or equal to the base reserve,
625 // then we allow the deposit.
626 //
627 // Rule 3 is designed to keep an account from getting wedged
628 // in an unusable state if it sets the lsfDepositAuth flag and
629 // then consumes all of its XRP. Without the rule if an
630 // account with lsfDepositAuth set spent all of its XRP, it
631 // would be unable to acquire more XRP required to pay fees.
632 //
633 // We choose the base reserve as our bound because it is
634 // a small number that seldom changes but is always sufficient
635 // to get the account un-wedged.
636
637 // Get the base reserve.
638 XRPAmount const dstReserve{view().fees().reserve};
639
640 if (dstAmount > dstReserve ||
641 sleDst->getFieldAmount(sfBalance) > dstReserve)
642 {
643 if (auto err = verifyDepositPreauth(
644 ctx_.tx,
645 ctx_.view(),
646 account_,
647 dstAccountID,
648 sleDst,
649 ctx_.journal);
650 !isTesSuccess(err))
651 return err;
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: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:221
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