20 #include <ripple/app/ledger/Ledger.h>
21 #include <ripple/app/paths/Flow.h>
22 #include <ripple/app/tx/impl/CashCheck.h>
23 #include <ripple/basics/Log.h>
24 #include <ripple/basics/scope.h>
25 #include <ripple/protocol/Feature.h>
26 #include <ripple/protocol/Indexes.h>
27 #include <ripple/protocol/STAccount.h>
28 #include <ripple/protocol/TER.h>
29 #include <ripple/protocol/TxFlags.h>
48 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Invalid flags set.";
56 if (
static_cast<bool>(optAmount) ==
static_cast<bool>(optDeliverMin))
59 <<
"Malformed transaction: "
60 "does not specify exactly one of Amount and DeliverMin.";
65 STAmount const value{optAmount ? *optAmount : *optDeliverMin};
68 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: bad amount: "
69 << value.getFullText();
75 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Bad currency.";
88 JLOG(ctx.
j.
warn()) <<
"Check does not exist.";
96 JLOG(ctx.
j.
warn()) <<
"Cashing a check with wrong Destination.";
104 JLOG(ctx.
j.
error()) <<
"Malformed transaction: Cashing check to self.";
110 if (!sleSrc || !sleDst)
114 <<
"Malformed transaction: source or destination not in ledger";
124 <<
"Malformed transaction: DestinationTag required in check.";
140 JLOG(ctx.
j.
warn()) <<
"Cashing a check that has already expired.";
148 auto const optAmount = tx[~
sfAmount];
152 STAmount
const sendMax = sleCheck->at(
sfSendMax);
153 Currency const currency{value.getCurrency()};
154 if (currency != sendMax.getCurrency())
156 JLOG(ctx.j.warn()) <<
"Check cash does not match check currency.";
159 AccountID const issuerId{value.getIssuer()};
160 if (issuerId != sendMax.getIssuer())
162 JLOG(ctx.j.warn()) <<
"Check cash does not match check issuer.";
167 JLOG(ctx.j.warn()) <<
"Check cashed for more than check sendMax.";
186 availableFunds += XRPAmount{ctx.view.fees().increment};
188 if (value > availableFunds)
191 <<
"Check cashed for more than owner's balance.";
197 if (!value.native() && (value.getIssuer() != dstId))
199 auto const sleTrustLine =
206 <<
"Cannot cash check for IOU without trustline.";
214 <<
"Can't receive IOUs from non-existent issuer: "
231 bool const canonical_gt(dstId > issuerId);
233 bool const is_authorized(
240 <<
"Can't receive IOUs from issuer without auth.";
251 if (
isFrozen(ctx.view, dstId, currency, issuerId))
253 JLOG(ctx.j.warn()) <<
"Cashing a check to a frozen trustline.";
268 auto const sleCheck = psb.
peek(keylet::check(ctx_.tx[
sfCheckID]));
271 JLOG(j_.
fatal()) <<
"Precheck did not verify check's existence.";
276 auto const sleSrc = psb.
peek(keylet::account(srcId));
277 auto const sleDst = psb.
peek(keylet::account(account_));
279 if (!sleSrc || !sleDst)
281 JLOG(ctx_.journal.fatal())
282 <<
"Precheck did not verify source or destination's existence.";
296 auto viewJ = ctx_.app.journal(
"View");
298 bool const doFix1623{ctx_.view().rules().enabled(
fix1623)};
300 if (srcId != account_)
321 : ctx_.tx.getFieldAmount(
sfAmount)};
323 if (srcLiquid < xrpDeliver)
327 JLOG(j_.
trace()) <<
"Cash Check: Insufficient XRP: "
328 << srcLiquid.getFullText() <<
" < "
329 << xrpDeliver.getFullText();
333 if (optDeliverMin && doFix1623)
335 ctx_.deliver(xrpDeliver);
339 transferXRP(psb, srcId, account_, xrpDeliver, viewJ)};
355 optDeliverMin->issue(),
356 STAmount::cMaxValue / 2,
357 STAmount::cMaxOffset)
358 : ctx_.tx.getFieldAmount(
sfAmount)};
361 Issue const& trustLineIssue = flowDeliver.issue();
362 AccountID const issuer = flowDeliver.getIssuer();
363 AccountID const truster = issuer == account_ ? srcId : account_;
364 Keylet const trustLineKey = keylet::line(truster, trustLineIssue);
365 bool const destLow = issuer > account_;
367 bool const checkCashMakesTrustLine =
370 if (checkCashMakesTrustLine && !psb.
exists(trustLineKey))
381 mPriorBalance < psb.
fees().accountReserve(ownerCount + 1))
383 JLOG(j_.
trace()) <<
"Trust line does not exist. "
384 "Insufficent reserve to create line.";
389 Currency const currency = flowDeliver.getCurrency();
390 STAmount initialBalance(flowDeliver.issue());
405 Issue(currency, account_),
424 auto const sleTrustLine = psb.
peek(trustLineKey);
429 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
433 [&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
434 if (
auto const sleTrustLine = psb.
peek(trustLineKey))
435 sleTrustLine->at(tweakedLimit) = savedLimit;
438 if (checkCashMakesTrustLine)
443 trustLineIssue, STAmount::cMaxValue, STAmount::cMaxOffset);
444 sleTrustLine->at(tweakedLimit) = bigAmount;
448 auto const result =
flow(
455 static_cast<bool>(optDeliverMin),
464 JLOG(ctx_.journal.warn()) <<
"flow failed when cashing check.";
465 return result.result();
471 if (result.actualAmountOut < *optDeliverMin)
473 JLOG(ctx_.journal.warn())
474 <<
"flow did not produce DeliverMin.";
477 if (doFix1623 && !checkCashMakesTrustLine)
479 ctx_.deliver(result.actualAmountOut);
483 if (checkCashMakesTrustLine)
484 ctx_.deliver(result.actualAmountOut);
490 if (srcId != account_)
493 if (!ctx_.view().dirRemove(
494 keylet::ownerDir(account_), page, sleCheck->
key(),
true))
496 JLOG(j_.
fatal()) <<
"Unable to delete check from destination.";
503 if (!ctx_.view().dirRemove(
504 keylet::ownerDir(srcId), page, sleCheck->
key(),
true))
506 JLOG(j_.
fatal()) <<
"Unable to delete check from owner.";
516 psb.
apply(ctx_.rawView());
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
const SF_UINT32 sfOwnerCount
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
A pair of SHAMap key and LedgerEntryType.
A currency issued by an account.
const SF_AMOUNT sfSendMax
const SF_UINT64 sfOwnerNode
A field with a type known at compile time.
Stream trace() const
Severity stream access functions.
const SF_ACCOUNT sfDestination
A wrapper which makes credits unavailable to balances.
static NotTEC preflight(PreflightContext const &ctx)
bool exists(Keylet const &k) const override
Determine if a state item exists.
bool isLegalNet(STAmount const &value)
void setIssuer(AccountID const &uIssuer)
Fees const & fees() const override
Returns the fees for the base ledger.
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
const SF_UINT32 sfExpiration
const SF_AMOUNT sfDeliverMin
const SF_AMOUNT sfLowLimit
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
path::RippleCalc::Output flow(PaymentSandbox &view, STAmount const &deliver, AccountID const &src, AccountID const &dst, STPathSet const &paths, bool defaultPaths, bool partialPayment, bool ownerPaysTransferFee, bool offerCrossing, std::optional< Quality > const &limitQuality, std::optional< STAmount > const &sendMax, beast::Journal j, path::detail::FlowDebugInfo *flowDebugInfo=nullptr)
Make a payment from the src account to the dst account.
Keylet account(AccountID const &id) noexcept
AccountID root.
static TER preclaim(PreclaimContext const &ctx)
TERSubset< CanCvtToTER > TER
const SF_UINT64 sfDestinationNode
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
std::uint32_t getFlags() const
const SF_AMOUNT sfHighLimit
bool enabled(uint256 const &id) const
Returns true if a feature is enabled.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
const uint256 featureChecks
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
const SF_HASH256 sfCheckID
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
State information when determining if a tx is likely to claim a fee.
void erase(std::shared_ptr< SLE > const &sle) override
Remove a peeked SLE.
bool native() const noexcept
base_uint< 160, detail::CurrencyTag > Currency
Currency is a hash representing a specific currency.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
TER trustCreate(ApplyView &view, const bool bSrcHigh, AccountID const &uSrcAccountID, AccountID const &uDstAccountID, uint256 const &uIndex, SLE::ref sleAccount, const bool bAuth, const bool bNoRipple, const bool bFreeze, STAmount const &saBalance, STAmount const &saLimit, std::uint32_t uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
@ tecNO_LINE_INSUF_RESERVE
void apply(RawView &to)
Apply changes to base view.
const SF_UINT32 sfDestinationTag
std::string to_string(Manifest const &m)
Format the specified manifest to a string for debugging purposes.
const SF_ACCOUNT sfAccount
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
Rules const & rules() const override
Returns the tx processing rules.
std::chrono::duration< rep, period > duration
const std::uint32_t tfUniversalMask
const uint256 featureCheckCashMakesTrustLine
State information when preflighting a tx.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
std::chrono::time_point< NetClock > time_point
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
AccountID const & noAccount()
A placeholder for empty accounts.
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TERSubset< CanCvtToNotTEC > NotTEC