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