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 // If a trust line does not exist yet create one.
443 Issue const& trustLineIssue = issue;
444 AccountID const truster = deliverIssuer == accountID_ ? srcId : accountID_;
445 trustLineKey = keylet::trustLine(truster, trustLineIssue);
446 destLow = deliverIssuer > accountID_;
447
448 if (!psb.exists(*trustLineKey))
449 {
450 // 1. Can the check casher meet the reserve for the
451 // trust line?
452 // 2. Create trust line between destination (this)
453 // account
454 // and the issuer.
455 // 3. Apply correct noRipple settings on trust line.
456 // Use...
457 // a. this (destination) account and
458 // b. issuing account (not sending account).
459
460 auto const sleDst = checkDstReserve();
461 if (sleDst == nullptr)
463
464 Currency const& currency = issue.currency;
465 STAmount initialBalance(flowDeliver.asset());
466 initialBalance.get<Issue>().account = noAccount();
467
468 if (TER const ter = trustCreate(
469 psb, // payment sandbox
470 destLow, // is dest low?
471 deliverIssuer, // source
472 accountID_, // destination
473 trustLineKey->key, // ledger index
474 sleDst, // Account to add to
475 false, // authorize account
476 !sleDst->isFlag(lsfDefaultRipple), //
477 false, // freeze trust line
478 false, // deep freeze trust line
479 initialBalance, // zero initial balance
480 Issue(currency, accountID_), // limit of zero
481 0, // quality in
482 0, // quality out
483 *sponsorSle, // sponsor
484 viewJ); // journal
485 !isTesSuccess(ter))
486 {
487 return ter;
488 }
489
490 psb.update(sleDst);
491
492 // Note that we _don't_ need to be careful about
493 // destroying the trust line if the check cashing
494 // fails. The transaction machinery will
495 // automatically clean it up.
496 }
497
498 // Since the destination is signing the check, they
499 // clearly want the funds even if their new total funds
500 // would exceed the limit on their trust line. So we
501 // tweak the trust line limits before calling flow and
502 // then restore the trust line limits afterwards.
503 auto const sleTrustLine = psb.peek(*trustLineKey);
504 if (!sleTrustLine)
505 return tecNO_LINE;
506
507 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
508 savedLimit = sleTrustLine->at(tweakedLimit);
509
510 // Set the trust line limit to the highest possible
511 // value while flow runs.
512 STAmount const bigAmount(
514 sleTrustLine->at(tweakedLimit) = bigAmount;
515
516 return std::nullopt;
517 },
518 [&](MPTIssue const& issue) -> std::optional<TER> {
519 if (accountID_ != deliverIssuer)
520 {
521 auto const& mptID = issue.getMptID();
522 // Create MPT if it doesn't exist
523 auto const mptokenKey = keylet::mptoken(mptID, accountID_);
524 if (!psb.exists(mptokenKey))
525 {
526 auto sleDst = checkDstReserve();
527 if (sleDst == nullptr)
529
530 if (auto const err =
531 checkCreateMPT(psb, mptID, accountID_, *sponsorSle, 0, j_);
532 !isTesSuccess(err))
533 {
534 return err;
535 }
536 }
537 }
538
539 return std::nullopt;
540 });
541 if (err)
542 return *err;
543 // Make sure the tweaked limits are restored when we leave
544 // scope.
545 ScopeExit const fixup([&psb, &trustLineKey, destLow, &savedLimit]() {
546 if (trustLineKey)
547 {
548 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
549 if (auto const sleTrustLine = psb.peek(*trustLineKey))
550 sleTrustLine->at(tweakedLimit) = savedLimit;
551 }
552 });
553
554 // Let flow() do the heavy lifting on a check for an IOU.
555 auto const result = flow(
556 psb,
557 flowDeliver,
558 srcId,
560 STPathSet{},
561 true, // default path
562 static_cast<bool>(optDeliverMin), // partial payment
563 true, // owner pays transfer fee
565 std::nullopt,
566 sleCheck->getFieldAmount(sfSendMax),
567 std::nullopt, // check does not support domain
568 viewJ);
569
570 if (!isTesSuccess(result.result()))
571 {
572 JLOG(ctx_.journal.warn()) << "flow failed when cashing check.";
573 return result.result();
574 }
575
576 // Make sure that deliverMin was satisfied.
577 if (optDeliverMin)
578 {
579 if (result.actualAmountOut < *optDeliverMin)
580 {
581 JLOG(ctx_.journal.warn()) << "flow did not produce DeliverMin.";
582 return tecPATH_PARTIAL;
583 }
584 ctx_.deliver(result.actualAmountOut);
585 }
586
587 // Set the delivered amount metadata in all cases, not just
588 // for DeliverMin.
589 ctx_.deliver(result.actualAmountOut);
590
591 sleCheck = psb.peek(keylet::check(ctx_.tx[sfCheckID]));
592 }
593 }
594
595 // Check was cashed. If not a self send (and it shouldn't be), remove
596 // check link from destination directory.
597 if (srcId != accountID_ &&
598 !psb.dirRemove(
599 keylet::ownerDir(accountID_), sleCheck->at(sfDestinationNode), sleCheck->key(), true))
600 {
601 // LCOV_EXCL_START
602 JLOG(j_.fatal()) << "Unable to delete check from destination.";
603 return tefBAD_LEDGER;
604 // LCOV_EXCL_STOP
605 }
606
607 // Remove check from check owner's directory.
608 if (!psb.dirRemove(keylet::ownerDir(srcId), sleCheck->at(sfOwnerNode), sleCheck->key(), true))
609 {
610 // LCOV_EXCL_START
611 JLOG(j_.fatal()) << "Unable to delete check from owner.";
612 return tefBAD_LEDGER;
613 // LCOV_EXCL_STOP
614 }
615
616 // If we succeeded, update the check owner's reserve.
617 decreaseOwnerCountForObject(psb, srcId, sleCheck, 1, viewJ);
618
619 // Remove check from ledger.
620 psb.erase(sleCheck);
621
622 psb.apply(ctx_.rawView());
623 return tesSUCCESS;
624}
625
626void
628{
629 // No transaction-specific invariants yet (future work).
630}
631
632bool
634{
635 // No transaction-specific invariants yet (future work).
636 return true;
637}
638
639} // 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
static NotTEC preflight(PreflightContext const &ctx)
Definition CheckCash.cpp:54
static bool checkExtraFeatures(PreflightContext const &ctx)
Definition CheckCash.cpp:43
void visitInvariantEntry(bool isDelete, SLE::const_ref before, SLE::const_ref after) override
Inspect a single ledger entry modified by this transaction.
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:180
constexpr TIss const & get() const
std::string getFullText() const override
Definition STAmount.cpp:636
bool native() const noexcept
Definition STAmount.h:471
Asset const & asset() const
Definition STAmount.h:496
MPTAmount mpt() const
Definition STAmount.cpp:301
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 & const_ref
beast::Journal const j_
Definition Transactor.h:155
AccountID const accountID_
Definition Transactor.h:157
XRPAmount preFeeBalance_
Definition Transactor.h:158
ApplyContext & ctx_
Definition Transactor.h:153
SLE::pointer peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
void update(SLE::ref sle) override
Indicate changes to a peeked SLE.
void erase(SLE::ref sle) override
Remove 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:373
Keylet check(AccountID const &id, SeqProxy const &seq) noexcept
A Check.
Definition Indexes.cpp:338
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Definition Indexes.cpp:543
Keylet account(AccountID const &id) noexcept
AccountID root.
Definition Indexes.cpp:198
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:253
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
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.
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:48
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:162
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 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.
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.
TypedField< STAmount > SF_AMOUNT
Definition SField.h:355
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
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:607
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)
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.
TER checkReserve(ApplyViewContext ctx, SLE::const_ref accSle, XRPAmount accBalance, SLE::const_ref sponsorSle, Adjustment adj, beast::Journal j, TER insufReserveCode=tecINSUFFICIENT_RESERVE)
Check if an account has sufficient reserve.
@ 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:676
TERSubset< CanCvtToTER > TER
Definition TER.h:647
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:361
@ tecNO_LINE_INSUF_RESERVE
Definition TER.h:295
@ tecPATH_PARTIAL
Definition TER.h:285
@ tecUNFUNDED_PAYMENT
Definition TER.h:288
@ tecNO_ENTRY
Definition TER.h:309
@ tecNO_AUTH
Definition TER.h:303
@ tecINTERNAL
Definition TER.h:313
@ tecFAILED_PROCESSING
Definition TER.h:289
@ tecFROZEN
Definition TER.h:306
@ tecEXPIRED
Definition TER.h:317
@ tecNO_LINE
Definition TER.h:304
@ tecINSUFFICIENT_RESERVE
Definition TER.h:310
@ tecNO_PERMISSION
Definition TER.h:308
@ tecDST_TAG_NEEDED
Definition TER.h:312
@ tecNO_ISSUER
Definition TER.h:302
SLE::pointer getLedgerEntryReserveSponsor(ApplyView &view, SLE::const_ref sle, SF_ACCOUNT const &field=sfSponsor)
Return a mutable SLE for the reserve sponsor recorded on a ledger entry.
BadAsset const & badAsset()
Definition Asset.h:40
@ tesSUCCESS
Definition TER.h:245
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:444
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:83
ReadView const & view
Definition Transactor.h:86
beast::Journal const j
Definition Transactor.h:91
State information when preflighting a tx.
Definition Transactor.h:38
beast::Journal const j
Definition Transactor.h:45
std::uint32_t value
Definition Rate.h:22