xrpld
Loading...
Searching...
No Matches
CheckCash.cpp
1#include <xrpl/tx/transactors/check/CheckCash.h>
2
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/scope.h>
5#include <xrpl/beast/utility/Zero.h>
6#include <xrpl/core/ServiceRegistry.h>
7#include <xrpl/ledger/ApplyView.h>
8#include <xrpl/ledger/PaymentSandbox.h>
9#include <xrpl/ledger/View.h>
10#include <xrpl/ledger/helpers/AccountRootHelpers.h>
11#include <xrpl/ledger/helpers/MPTokenHelpers.h>
12#include <xrpl/ledger/helpers/RippleStateHelpers.h>
13#include <xrpl/ledger/helpers/SponsorHelpers.h>
14#include <xrpl/ledger/helpers/TokenHelpers.h>
15#include <xrpl/protocol/AccountID.h>
16#include <xrpl/protocol/Asset.h>
17#include <xrpl/protocol/Feature.h>
18#include <xrpl/protocol/Indexes.h>
19#include <xrpl/protocol/Issue.h>
20#include <xrpl/protocol/Keylet.h>
21#include <xrpl/protocol/LedgerFormats.h>
22#include <xrpl/protocol/MPTAmount.h>
23#include <xrpl/protocol/MPTIssue.h>
24#include <xrpl/protocol/Quality.h>
25#include <xrpl/protocol/SField.h>
26#include <xrpl/protocol/STAmount.h>
27#include <xrpl/protocol/STLedgerEntry.h>
28#include <xrpl/protocol/STTx.h>
29#include <xrpl/protocol/TER.h>
30#include <xrpl/protocol/UintTypes.h>
31#include <xrpl/protocol/XRPAmount.h>
32#include <xrpl/tx/Transactor.h>
33#include <xrpl/tx/paths/Flow.h>
34#include <xrpl/tx/paths/detail/Steps.h>
35
36#include <algorithm>
37#include <memory>
38#include <optional>
39
40namespace xrpl {
41
42bool
44{
45 auto const optAmount = ctx.tx[~sfAmount];
46 auto const optDeliverMin = ctx.tx[~sfDeliverMin];
47
48 return ctx.rules.enabled(featureMPTokensV2) ||
49 (!(optAmount && optAmount->holds<MPTIssue>()) &&
50 !(optDeliverMin && optDeliverMin->holds<MPTIssue>()));
51}
52
55{
56 if (ctx.rules.enabled(fixCleanup3_3_0) && ctx.tx[sfCheckID] == beast::kZero)
57 return temMALFORMED;
58
59 // Exactly one of Amount or DeliverMin must be present.
60 auto const optAmount = ctx.tx[~sfAmount];
61 auto const optDeliverMin = ctx.tx[~sfDeliverMin];
62
63 if (static_cast<bool>(optAmount) == static_cast<bool>(optDeliverMin))
64 {
65 JLOG(ctx.j.warn()) << "Malformed transaction: "
66 "does not specify exactly one of Amount and DeliverMin.";
67 return temMALFORMED;
68 }
69
70 // Make sure the amount is valid.
71 STAmount const value{optAmount ? *optAmount : *optDeliverMin};
72 if (!isLegalNet(value) || value.signum() <= 0)
73 {
74 JLOG(ctx.j.warn()) << "Malformed transaction: bad amount: " << value.getFullText();
75 return temBAD_AMOUNT;
76 }
77
78 if (badAsset() == value.asset())
79 {
80 JLOG(ctx.j.warn()) << "Malformed transaction: Bad currency.";
81 return temBAD_CURRENCY;
82 }
83
84 return tesSUCCESS;
85}
86
87TER
89{
90 auto const sleCheck = ctx.view.read(keylet::check(ctx.tx[sfCheckID]));
91 if (!sleCheck)
92 {
93 JLOG(ctx.j.warn()) << "Check does not exist.";
94 return tecNO_ENTRY;
95 }
96
97 // Only cash a check with this account as the destination.
98 AccountID const dstId = sleCheck->at(sfDestination);
99 if (ctx.tx[sfAccount] != dstId)
100 {
101 JLOG(ctx.j.warn()) << "Cashing a check with wrong Destination.";
102 return tecNO_PERMISSION;
103 }
104 AccountID const srcId = sleCheck->at(sfAccount);
105 if (srcId == dstId)
106 {
107 // They wrote a check to themselves. This should be caught when
108 // the check is created, but better late than never.
109 // LCOV_EXCL_START
110 JLOG(ctx.j.error()) << "Malformed transaction: Cashing check to self.";
111 return tecINTERNAL;
112 // LCOV_EXCL_STOP
113 }
114 {
115 auto const sleSrc = ctx.view.read(keylet::account(srcId));
116 auto const sleDst = ctx.view.read(keylet::account(dstId));
117 if (!sleSrc || !sleDst)
118 {
119 // If the check exists this should never occur.
120 JLOG(ctx.j.warn()) << "Malformed transaction: source or destination not in ledger";
121 return tecNO_ENTRY;
122 }
123
124 if (sleDst->isFlag(lsfRequireDestTag) && !sleCheck->isFieldPresent(sfDestinationTag))
125 {
126 // The tag is basically account-specific information we don't
127 // understand, but we can require someone to fill it in.
128 JLOG(ctx.j.warn()) << "Malformed transaction: DestinationTag required in check.";
129 return tecDST_TAG_NEEDED;
130 }
131 }
132
133 if (hasExpired(ctx.view, sleCheck->at(~sfExpiration)))
134 {
135 JLOG(ctx.j.warn()) << "Cashing a check that has already expired.";
136 return tecEXPIRED;
137 }
138
139 {
140 // Preflight verified exactly one of Amount or DeliverMin is present.
141 // Make sure the requested amount is reasonable.
142 STAmount const value{[](STTx const& tx) {
143 auto const optAmount = tx[~sfAmount];
144 return optAmount ? *optAmount : tx[sfDeliverMin];
145 }(ctx.tx)};
146
147 STAmount const sendMax = sleCheck->at(sfSendMax);
148 // A legacy Check may contain a non-canonical MPT sfSendMax. Universal
149 // preflight only validates the CheckCash transaction, not the stored Check.
150 if (ctx.view.rules().enabled(fixCleanup3_2_0) && !isLegalMPT(sendMax))
151 return tefBAD_LEDGER;
152
153 if (!equalTokens(value.asset(), sendMax.asset()))
154 {
155 JLOG(ctx.j.warn()) << "Check cash does not match check currency.";
156 return temMALFORMED;
157 }
158 AccountID const issuerId{value.getIssuer()};
159 if (issuerId != sendMax.getIssuer())
160 {
161 JLOG(ctx.j.warn()) << "Check cash does not match check issuer.";
162 return temMALFORMED;
163 }
164 if (value > sendMax)
165 {
166 JLOG(ctx.j.warn()) << "Check cashed for more than check sendMax.";
167 return tecPATH_PARTIAL;
168 }
169
170 // Make sure the check owner holds at least value. If they have
171 // less than value the check cannot be cashed.
172 {
173 STAmount availableFunds{accountFunds(
174 ctx.view,
175 sleCheck->at(sfAccount),
176 value,
179 ctx.j)};
180
181 // Note that src will have one reserve's worth of additional XRP
182 // once the check is cashed, since the check's reserve will no
183 // longer be required. So, if we're dealing in XRP, we add one
184 // reserve's worth to the available funds.
185 if (value.native() && !sleCheck->isFieldPresent(sfSponsor))
186 availableFunds += XRPAmount{ctx.view.fees().increment};
187
188 if (value > availableFunds)
189 {
190 JLOG(ctx.j.warn()) << "Check cashed for more than owner's balance.";
191 return tecPATH_PARTIAL;
192 }
193 }
194
195 // An issuer can always accept their own currency.
196 if (!value.native() && (value.getIssuer() != dstId))
197 {
198 return value.asset().visit(
199 [&](Issue const& issue) -> TER {
200 Currency const currency{issue.currency};
201 auto const sleTrustLine =
202 ctx.view.read(keylet::trustLine(dstId, issuerId, currency));
203
204 auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
205 if (!sleIssuer)
206 {
207 JLOG(ctx.j.warn()) << "Can't receive IOUs from "
208 "non-existent issuer: "
209 << to_string(issuerId);
210 return tecNO_ISSUER;
211 }
212
213 if (sleIssuer->isFlag(lsfRequireAuth))
214 {
215 if (!sleTrustLine)
216 {
217 // We can only create a trust line if the issuer
218 // does not have lsfRequireAuth set.
219 return tecNO_AUTH;
220 }
221
222 // Entries have a canonical representation,
223 // determined by a lexicographical "greater than"
224 // comparison employing strict weak ordering.
225 // Determine which entry we need to access.
226 bool const canonicalGt(dstId > issuerId);
227
228 bool const isAuthorized(
229 (sleTrustLine->at(sfFlags) &
230 (canonicalGt ? lsfLowAuth : lsfHighAuth)) != 0u);
231
232 if (!isAuthorized)
233 {
234 JLOG(ctx.j.warn()) << "Can't receive IOUs from "
235 "issuer without auth.";
236 return tecNO_AUTH;
237 }
238 }
239
240 // The trustline from source to issuer does not need to
241 // be checked for freezing, since we already verified
242 // that the source has sufficient non-frozen funds
243 // available.
244
245 // However, the trustline from destination to issuer may
246 // not be frozen.
247 if (isFrozen(ctx.view, dstId, currency, issuerId))
248 {
249 JLOG(ctx.j.warn()) << "Cashing a check to a frozen trustline.";
250 return tecFROZEN;
251 }
252
253 return tesSUCCESS;
254 },
255 [&](MPTIssue const& issue) -> TER {
256 auto const sleIssuer = ctx.view.read(keylet::account(issuerId));
257 if (!sleIssuer)
258 {
259 JLOG(ctx.j.warn()) << "Can't receive MPTs from "
260 "non-existent issuer: "
261 << to_string(issuerId);
262 return tecNO_ISSUER;
263 }
264
265 if (auto const err = requireAuth(ctx.view, issue, dstId, AuthType::WeakAuth);
266 !isTesSuccess(err))
267 {
268 JLOG(ctx.j.warn()) << "Cashing a check to a MPT requiring auth.";
269 return err;
270 }
271
272 if (isFrozen(ctx.view, dstId, issue))
273 {
274 JLOG(ctx.j.warn()) << "Cashing a check to a frozen MPT.";
275 return tecLOCKED;
276 }
277
278 if (auto const err = canTransfer(ctx.view, issue, srcId, dstId);
279 !isTesSuccess(err))
280 {
281 JLOG(ctx.j.warn()) << "MPT transfer is disabled.";
282 return err;
283 }
284
285 return tesSUCCESS;
286 });
287 }
288 }
289 return tesSUCCESS;
290}
291
292TER
294{
295 // Flow requires that we operate on a PaymentSandbox, rather than
296 // directly on a View.
297 PaymentSandbox psb(&ctx_.view());
298
299 auto sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
300 if (!sleCheck)
301 {
302 // LCOV_EXCL_START
303 JLOG(j_.fatal()) << "Precheck did not verify check's existence.";
305 // LCOV_EXCL_STOP
306 }
307
308 AccountID const srcId{sleCheck->getAccountID(sfAccount)};
309 if (!psb.exists(keylet::account(srcId)) || !psb.exists(keylet::account(accountID_)))
310 {
311 // LCOV_EXCL_START
312 JLOG(ctx_.journal.fatal()) << "Precheck did not verify source or destination's existence.";
314 // LCOV_EXCL_STOP
315 }
316
317 auto const sponsorCheckSle = getLedgerEntryReserveSponsor(psb, sleCheck);
318
319 // Preclaim already checked that source has at least the requested
320 // funds.
321 //
322 // Therefore, if this is a check written to self, (and it shouldn't be)
323 // we know they have sufficient funds to pay the check. Since they are
324 // taking the funds from their own pocket and putting it back in their
325 // pocket no balance will change.
326 //
327 // If it is not a check to self (as should be the case), then there's
328 // work to do...
329 auto viewJ = ctx_.registry.get().getJournal("View");
330 auto const optDeliverMin = ctx_.tx[~sfDeliverMin];
331
332 if (srcId != accountID_)
333 {
334 STAmount const sendMax = sleCheck->at(sfSendMax);
335
336 // Flow() doesn't do XRP to XRP transfers.
337 if (sendMax.native())
338 {
339 // Here we need to calculate the amount of XRP src can send.
340 // The amount they have available is their balance minus their
341 // reserve.
342 //
343 // Since (if we're successful) we're about to remove an entry
344 // from src's directory, we allow them to send that additional
345 // incremental reserve amount in the transfer. Hence the -1
346 // argument.
347 STAmount const srcLiquid{xrpLiquid(psb, srcId, sponsorCheckSle ? 0 : -1, viewJ)};
348
349 // Now, how much do they need in order to be successful?
350 STAmount const xrpDeliver{
351 optDeliverMin ? std::max(*optDeliverMin, std::min(sendMax, srcLiquid))
352 : ctx_.tx.getFieldAmount(sfAmount)};
353
354 if (srcLiquid < xrpDeliver)
355 {
356 // Vote no. However the transaction might succeed if applied
357 // in a different order.
358 JLOG(j_.trace()) << "Cash Check: Insufficient XRP: " << srcLiquid.getFullText()
359 << " < " << xrpDeliver.getFullText();
360 return tecUNFUNDED_PAYMENT;
361 }
362
363 if (optDeliverMin)
364 {
365 // Set the DeliveredAmount metadata.
366 ctx_.deliver(xrpDeliver);
367 }
368
369 // The source account has enough XRP so make the ledger change.
370 if (TER const ter{transferXRP(psb, srcId, accountID_, xrpDeliver, viewJ)};
371 !isTesSuccess(ter))
372 {
373 // The transfer failed. Return the error code.
374 return ter;
375 }
376 }
377 else
378 {
379 // Note that for DeliverMin we don't know exactly how much
380 // currency we want flow to deliver. For IOUs, use a value
381 // higher than any real delivery as the request. MPTs are
382 // bounded integral amounts, so use the maximum output the check
383 // can actually deliver without exceeding SendMax.
384 auto const maxDeliverMin = [&]() {
385 return optDeliverMin->asset().visit(
386 [&](Issue const&) {
387 return STAmount(
388 optDeliverMin->asset(), STAmount::kMaxValue / 2, STAmount::kMaxOffset);
389 },
390 [&](MPTIssue const& issue) {
391 MPTAmount maxDeliver = sendMax.mpt();
392 auto const& issuer = issue.getIssuer();
393 if (srcId != issuer && accountID_ != issuer)
394 {
395 auto const rate = transferRate(psb, issue.getMptID());
396 // Request at most floor(SendMax / rate). The endpoint reverse pass
397 // will quote ceil(output * rate), so this keeps the input
398 // representable and within SendMax.
399 maxDeliver =
400 mulRatio(maxDeliver, QUALITY_ONE, rate.value, /*roundUp*/ false);
401 }
402 return STAmount(maxDeliver, issue);
403 });
404 };
405 STAmount const flowDeliver{
406 optDeliverMin ? maxDeliverMin() : ctx_.tx.getFieldAmount(sfAmount)};
407
408 auto applyViewContext = ApplyViewContext({.view = psb, .tx = ctx_.tx});
409 auto const sponsorSle = getTxReserveSponsor(applyViewContext);
410 if (!sponsorSle)
411 return sponsorSle.error(); // LCOV_EXCL_LINE
412
413 // Check reserve. Return destination account SLE if enough reserve,
414 // otherwise return nullptr.
415 auto checkDstReserve = [&]() -> SLE::pointer {
416 auto sleDst = psb.peek(keylet::account(accountID_));
417
418 // Can the account cover the trust line's or MPT reserve?
419 if (auto const ret = checkReserve(
420 applyViewContext,
421 sleDst,
423 *sponsorSle,
424 {.ownerCountDelta = 1},
425 j_);
426 !isTesSuccess(ret))
427 {
428 JLOG(j_.trace()) << "Trust line does not exist. "
429 "Insufficient reserve to create line.";
430
431 return nullptr;
432 }
433 return sleDst;
434 };
435
436 std::optional<Keylet> trustLineKey;
437 STAmount savedLimit;
438 bool destLow = false;
439 AccountID const& deliverIssuer = flowDeliver.getIssuer();
440 auto const err = flowDeliver.asset().visit(
441 [&](Issue const& issue) -> std::optional<TER> {
442 // An issuer needs no holder-limit waiver to receive its own currency.
443 if (deliverIssuer == accountID_ && ctx_.view().rules().enabled(fixCleanup3_4_0))
444 {
445 return std::nullopt;
446 }
447
448 // If a trust line does not exist yet create one.
449 Issue const& trustLineIssue = issue;
450 AccountID const truster = deliverIssuer == accountID_ ? srcId : accountID_;
451 trustLineKey = keylet::trustLine(truster, trustLineIssue);
452 destLow = deliverIssuer > accountID_;
453
454 if (!psb.exists(*trustLineKey))
455 {
456 // 1. Can the check casher meet the reserve for the
457 // trust line?
458 // 2. Create trust line between destination (this)
459 // account
460 // and the issuer.
461 // 3. Apply correct noRipple settings on trust line.
462 // Use...
463 // a. this (destination) account and
464 // b. issuing account (not sending account).
465
466 auto const sleDst = checkDstReserve();
467 if (sleDst == nullptr)
469
470 Currency const& currency = issue.currency;
471 STAmount initialBalance(flowDeliver.asset());
472 initialBalance.get<Issue>().account = noAccount();
473
474 if (TER const ter = trustCreate(
475 psb, // payment sandbox
476 destLow, // is dest low?
477 deliverIssuer, // source
478 accountID_, // destination
479 trustLineKey->key, // ledger index
480 sleDst, // Account to add to
481 false, // authorize account
482 !sleDst->isFlag(lsfDefaultRipple), //
483 false, // freeze trust line
484 false, // deep freeze trust line
485 initialBalance, // zero initial balance
486 Issue(currency, accountID_), // limit of zero
487 0, // quality in
488 0, // quality out
489 *sponsorSle, // sponsor
490 viewJ); // journal
491 !isTesSuccess(ter))
492 {
493 return ter;
494 }
495
496 psb.update(sleDst);
497
498 // Note that we _don't_ need to be careful about
499 // destroying the trust line if the check cashing
500 // fails. The transaction machinery will
501 // automatically clean it up.
502 }
503
504 // Since the destination is signing the check, they
505 // clearly want the funds even if their new total funds
506 // would exceed the limit on their trust line. So we
507 // tweak the trust line limits before calling flow and
508 // then restore the trust line limits afterwards.
509 auto const sleTrustLine = psb.peek(*trustLineKey);
510 if (!sleTrustLine)
511 return tecNO_LINE;
512
513 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
514 savedLimit = sleTrustLine->at(tweakedLimit);
515
516 // Set the trust line limit to the highest possible
517 // value while flow runs.
518 STAmount const bigAmount(
520 sleTrustLine->at(tweakedLimit) = bigAmount;
521
522 return std::nullopt;
523 },
524 [&](MPTIssue const& issue) -> std::optional<TER> {
525 if (accountID_ != deliverIssuer)
526 {
527 auto const& mptID = issue.getMptID();
528 // Create MPT if it doesn't exist
529 auto const mptokenKey = keylet::mptoken(mptID, accountID_);
530 if (!psb.exists(mptokenKey))
531 {
532 auto sleDst = checkDstReserve();
533 if (sleDst == nullptr)
535
536 if (auto const err =
537 checkCreateMPT(psb, mptID, accountID_, *sponsorSle, 0, j_);
538 !isTesSuccess(err))
539 {
540 return err;
541 }
542 }
543 }
544
545 return std::nullopt;
546 });
547 if (err)
548 return *err;
549 // Make sure the tweaked limits are restored when we leave
550 // scope.
551 ScopeExit const fixup([&psb, &trustLineKey, destLow, &savedLimit]() {
552 if (trustLineKey)
553 {
554 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
555 if (auto const sleTrustLine = psb.peek(*trustLineKey))
556 sleTrustLine->at(tweakedLimit) = savedLimit;
557 }
558 });
559
560 // Let flow() do the heavy lifting on a check for an IOU.
561 auto const result = flow(
562 psb,
563 flowDeliver,
564 srcId,
566 STPathSet{},
567 true, // default path
568 static_cast<bool>(optDeliverMin), // partial payment
569 true, // owner pays transfer fee
571 std::nullopt,
572 sleCheck->getFieldAmount(sfSendMax),
573 std::nullopt, // check does not support domain
574 viewJ);
575
576 if (!isTesSuccess(result.result()))
577 {
578 JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
579 return result.result();
580 }
581
582 // Make sure that deliverMin was satisfied.
583 if (optDeliverMin)
584 {
585 if (result.actualAmountOut < *optDeliverMin)
586 {
587 JLOG(ctx_.journal.warn()) << "flow did not produce DeliverMin.";
588 return tecPATH_PARTIAL;
589 }
590 ctx_.deliver(result.actualAmountOut);
591 }
592
593 // Set the delivered amount metadata in all cases, not just
594 // for DeliverMin.
595 ctx_.deliver(result.actualAmountOut);
596
597 sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
598 }
599 }
600
601 // Check was cashed. If not a self send (and it shouldn't be), remove
602 // check link from destination directory.
603 if (srcId != accountID_ &&
604 !psb.dirRemove(
605 keylet::ownerDir(accountID_), sleCheck->at(sfDestinationNode), sleCheck->key(), true))
606 {
607 // LCOV_EXCL_START
608 JLOG(j_.fatal()) << "Unable to delete check from destination.";
609 return tefBAD_LEDGER;
610 // LCOV_EXCL_STOP
611 }
612
613 // Remove check from check owner's directory.
614 if (!psb.dirRemove(keylet::ownerDir(srcId), sleCheck->at(sfOwnerNode), sleCheck->key(), true))
615 {
616 // LCOV_EXCL_START
617 JLOG(j_.fatal()) << "Unable to delete check from owner.";
618 return tefBAD_LEDGER;
619 // LCOV_EXCL_STOP
620 }
621
622 // If we succeeded, update the check owner's reserve.
623 decreaseOwnerCountForObject(psb, srcId, sleCheck, 1, viewJ);
624
625 // Remove check from ledger.
626 psb.erase(sleCheck);
627
628 psb.apply(ctx_.rawView());
629 return tesSUCCESS;
630}
631
632void
634{
635 // No transaction-specific invariants yet (future work).
636}
637
638bool
640{
641 // No transaction-specific invariants yet (future work).
642 return true;
643}
644
645} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:44
Stream error() const
Definition Journal.h:362
Stream warn() const
Definition Journal.h:356
bool dirRemove(Keylet const &directory, std::uint64_t page, UInt256 const &key, bool keepRoot)
Remove an entry from a directory.
constexpr auto visit(Visitors &&... visitors) const -> decltype(auto)
Definition Asset.h:117
TER doApply() override
static TER preclaim(PreclaimContext const &ctx)
Definition CheckCash.cpp:88
void visitInvariantEntry(bool isDelete, SLE::ConstRef before, SLE::ConstRef after) override
Inspect a single ledger entry modified by this transaction.
static NotTEC preflight(PreflightContext const &ctx)
Definition CheckCash.cpp:54
static bool checkExtraFeatures(PreflightContext const &ctx)
Definition CheckCash.cpp:43
bool finalizeInvariants(STTx const &tx, TER result, XRPAmount fee, ReadView const &view, beast::Journal const &j) override
Check transaction-specific post-conditions after all entries have been visited.
A currency issued by an account.
Definition Issue.h:18
Currency currency
Definition Issue.h:20
A wrapper which makes credits unavailable to balances.
void apply(RawView &to)
Apply changes to base view.
A view into a ledger.
Definition ReadView.h:41
virtual Rules const & rules() const =0
Returns the tx processing rules.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
virtual SLE::const_pointer 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:182
constexpr TIss const & get() const
std::string getFullText() const override
Definition STAmount.cpp:637
bool native() const noexcept
Definition STAmount.h:471
Asset const & asset() const
Definition STAmount.h:496
MPTAmount mpt() const
Definition STAmount.cpp:302
AccountID const & getIssuer() const
Definition STAmount.h:516
static constexpr std::uint64_t kMaxValue
Definition STAmount.h:67
static constexpr int kMaxOffset
Definition STAmount.h:62
std::shared_ptr< STLedgerEntry > pointer
std::shared_ptr< STLedgerEntry const > const & ConstRef
beast::Journal const j_
Definition Transactor.h:164
AccountID const accountID_
Definition Transactor.h:166
XRPAmount preFeeBalance_
Definition Transactor.h:167
ApplyContext & ctx_
Definition Transactor.h:162
SLE::pointer peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
void erase(SLE::Ref sle) override
Remove a peeked SLE.
void update(SLE::Ref sle) override
Indicate changes to a peeked SLE.
bool exists(Keylet const &k) const override
Determine if a state item exists.
T max(T... args)
T min(T... args)
constexpr Zero kZero
Definition Zero.h:30
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Definition Indexes.cpp:403
Keylet check(AccountID const &id, SeqProxy const &seq) noexcept
A Check.
Definition Indexes.cpp:360
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:573
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:220
Keylet trustLine(AccountID const &id0, AccountID const &id1, Currency const &currency) noexcept
The index of a trust line for a given currency.
Definition Indexes.cpp:275
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
Calculate liquid XRP balance for an account.
bool isLegalMPT(STAmount const &value)
Definition STAmount.h:622
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp, ExpiryComparison comparison=ExpiryComparison::Inclusive)
Determines whether the given expiration time has passed.
Definition View.cpp:51
TER checkCreateMPT(xrpl::ApplyView &view, xrpl::MPTIssue const &mptIssue, xrpl::AccountID const &holder, SLE::Ref sponsorSle, std::uint32_t flags, beast::Journal j)
@ tefBAD_LEDGER
Definition TER.h:165
bool isLegalNet(STAmount const &value)
Definition STAmount.h:616
BaseUInt< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Definition UintTypes.h:42
TER checkReserve(ApplyViewContext ctx, SLE::ConstRef accSle, XRPAmount accBalance, SLE::ConstRef sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
TER trustCreate(ApplyView &view, bool const bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, UInt256 const &uIndex, SLE::Ref sleAccount, bool const bAuth, bool const bNoRipple, bool const bFreeze, bool bDeepFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, SLE::Ref sponsorSle, beast::Journal j)
Create a trust line.
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to, WaiveMPTCanTransfer waive=WaiveMPTCanTransfer::No, std::uint8_t depth=0)
Check whether to may receive the given MPT from from.
TypedField< STAmount > SF_AMOUNT
Definition SField.h:358
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:657
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
std::expected< SLE::pointer, TER > getTxReserveSponsor(ApplyViewContext ctx)
Return a mutable SLE for the transaction's reserve sponsor account.
TERSubset< CanCvtToNotTEC > NotTEC
Definition TER.h:614
void decreaseOwnerCountForObject(ApplyView &view, SLE::Ref accountSle, SLE::Ref objectSle, std::uint32_t count, beast::Journal j)
Decrease owner-count fields for an existing ledger object.
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
Definition StrandFlow.h:103
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, std::uint8_t depth=0)
Returns true if account cannot send or receive tokens of mptIssue because a freeze applies.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
Definition AccountID.h:34
AccountID const & noAccount()
A placeholder for empty accounts.
@ temBAD_CURRENCY
Definition TER.h:78
@ temMALFORMED
Definition TER.h:75
@ temBAD_AMOUNT
Definition TER.h:77
bool isTesSuccess(TER x) noexcept
Definition TER.h:683
SLE::pointer getLedgerEntryReserveSponsor(ApplyView &view, SLE::ConstRef sle, SF_ACCOUNT const &field=sfSponsor)
Return a mutable SLE for the reserve sponsor recorded on a ledger entry.
TERSubset< CanCvtToTER > TER
Definition TER.h:654
TER requireAuth(ReadView const &view, MPTIssue const &mptIssue, AccountID const &account, AuthType authType=AuthType::Legacy, std::uint8_t depth=0)
Check if the account lacks required authorization for MPT.
@ tecLOCKED
Definition TER.h:366
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:300
@ tecPATH_PARTIAL
Definition TER.h:290
@ tecUNFUNDED_PAYMENT
Definition TER.h:293
@ tecNO_ENTRY
Definition TER.h:314
@ tecNO_AUTH
Definition TER.h:308
@ tecINTERNAL
Definition TER.h:318
@ tecFAILED_PROCESSING
Definition TER.h:294
@ tecFROZEN
Definition TER.h:311
@ tecEXPIRED
Definition TER.h:322
@ tecNO_LINE
Definition TER.h:309
@ tecINSUFFICIENT_RESERVE
Definition TER.h:315
@ tecNO_PERMISSION
Definition TER.h:313
@ tecDST_TAG_NEEDED
Definition TER.h:317
@ tecNO_ISSUER
Definition TER.h:307
BadAsset const & badAsset()
Definition Asset.h:40
@ tesSUCCESS
Definition TER.h:250
constexpr bool equalTokens(Asset const &lhs, Asset const &rhs)
Definition Asset.h:286
Bundles the mutable ledger view and the transaction being applied.
Definition ApplyView.h:451
XRPAmount increment
Additional XRP reserve required per owned ledger object.
State information when determining if a tx is likely to claim a fee.
Definition Transactor.h:92
ReadView const & view
Definition Transactor.h:95
beast::Journal const j
Definition Transactor.h:100
State information when preflighting a tx.
Definition Transactor.h:39
beast::Journal const j
Definition Transactor.h:46
std::uint32_t value
Definition Rate.h:22