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