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