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