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