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/protocol/Feature.h>
25 #include <ripple/protocol/Indexes.h>
26 #include <ripple/protocol/STAccount.h>
27 #include <ripple/protocol/TER.h>
28 #include <ripple/protocol/TxFlags.h>
47 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Invalid flags set.";
55 if (
static_cast<bool>(optAmount) ==
static_cast<bool>(optDeliverMin))
58 <<
"Malformed transaction: "
59 "does not specify exactly one of Amount and DeliverMin.";
64 STAmount const value{optAmount ? *optAmount : *optDeliverMin};
67 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: bad amount: "
68 << value.getFullText();
74 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Bad currency.";
87 JLOG(ctx.
j.
warn()) <<
"Check does not exist.";
95 JLOG(ctx.
j.
warn()) <<
"Cashing a check with wrong Destination.";
103 JLOG(ctx.
j.
error()) <<
"Malformed transaction: Cashing check to self.";
109 if (!sleSrc || !sleDst)
113 <<
"Malformed transaction: source or destination not in ledger";
123 <<
"Malformed transaction: DestinationTag required in check.";
139 JLOG(ctx.
j.
warn()) <<
"Cashing a check that has already expired.";
147 auto const optAmount = tx[~
sfAmount];
151 STAmount
const sendMax{(*sleCheck)[
sfSendMax]};
152 Currency const currency{value.getCurrency()};
153 if (currency != sendMax.getCurrency())
155 JLOG(ctx.j.warn()) <<
"Check cash does not match check currency.";
158 AccountID const issuerId{value.getIssuer()};
159 if (issuerId != sendMax.getIssuer())
161 JLOG(ctx.j.warn()) <<
"Check cash does not match check issuer.";
166 JLOG(ctx.j.warn()) <<
"Check cashed for more than check sendMax.";
185 availableFunds += XRPAmount{ctx.view.fees().increment};
187 if (value > availableFunds)
190 <<
"Check cashed for more than owner's balance.";
196 if (!value.native() && (value.getIssuer() != dstId))
198 auto const sleTrustLine =
203 <<
"Cannot cash check for IOU without trustline.";
211 <<
"Can't receive IOUs from non-existent issuer: "
221 bool const canonical_gt(dstId > issuerId);
223 bool const is_authorized(
230 <<
"Can't receive IOUs from issuer without auth.";
241 if (
isFrozen(ctx.view, dstId, currency, issuerId))
243 JLOG(ctx.j.warn()) <<
"Cashing a check to a frozen trustline.";
258 auto const sleCheck = psb.
peek(keylet::check(ctx_.tx[
sfCheckID]));
261 JLOG(j_.
fatal()) <<
"Precheck did not verify check's existence.";
266 auto const sleSrc = psb.
peek(keylet::account(srcId));
267 auto const sleDst = psb.
peek(keylet::account(account_));
269 if (!sleSrc || !sleDst)
271 JLOG(ctx_.journal.fatal())
272 <<
"Precheck did not verify source or destination's existence.";
286 auto viewJ = ctx_.app.journal(
"View");
288 bool const doFix1623{ctx_.view().rules().enabled(
fix1623)};
289 if (srcId != account_)
294 if (sendMax.native())
310 : ctx_.tx.getFieldAmount(
sfAmount)};
312 if (srcLiquid < xrpDeliver)
316 JLOG(j_.
trace()) <<
"Cash Check: Insufficient XRP: "
317 << srcLiquid.getFullText() <<
" < "
318 << xrpDeliver.getFullText();
322 if (optDeliverMin && doFix1623)
324 ctx_.deliver(xrpDeliver);
328 transferXRP(psb, srcId, account_, xrpDeliver, viewJ)};
346 ?
STAmount{optDeliverMin->
issue(), STAmount::cMaxValue / 2, STAmount::cMaxOffset}
350 auto const result =
flow(
357 static_cast<bool>(optDeliverMin),
366 JLOG(ctx_.journal.warn()) <<
"flow failed when cashing check.";
367 return result.result();
373 if (result.actualAmountOut < *optDeliverMin)
375 JLOG(ctx_.journal.warn())
376 <<
"flow did not produce DeliverMin.";
381 ctx_.deliver(result.actualAmountOut);
388 if (srcId != account_)
391 if (!ctx_.view().dirRemove(
392 keylet::ownerDir(account_), page, sleCheck->
key(),
true))
394 JLOG(j_.
fatal()) <<
"Unable to delete check from destination.";
401 if (!ctx_.view().dirRemove(
402 keylet::ownerDir(srcId), page, sleCheck->
key(),
true))
404 JLOG(j_.
fatal()) <<
"Unable to delete check from owner.";
414 psb.
apply(ctx_.rawView());
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
const SF_AMOUNT sfSendMax
const SF_UINT64 sfOwnerNode
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 isLegalNet(STAmount const &value)
std::string to_string(ListDisposition disposition)
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
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
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
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.
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.
void apply(RawView &to)
Apply changes to base view.
Issue const & issue() const
const SF_UINT32 sfDestinationTag
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, boost::optional< Quality > const &limitQuality, boost::optional< STAmount > const &sendMax, beast::Journal j, path::detail::FlowDebugInfo *flowDebugInfo=nullptr)
Make a payment from the src account to the dst account.
const SF_ACCOUNT sfAccount
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
std::chrono::duration< rep, period > duration
const std::uint32_t tfUniversalMask
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)
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
TERSubset< CanCvtToNotTEC > NotTEC