20 #include <ripple/app/tx/impl/CashCheck.h>
21 #include <ripple/app/ledger/Ledger.h>
22 #include <ripple/app/paths/Flow.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))
57 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: "
58 "does not specify exactly one of Amount and DeliverMin.";
63 STAmount const value {optAmount ? *optAmount : *optDeliverMin};
64 if (!
isLegalNet (value) || value.signum() <= 0)
66 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: bad amount: "
67 << value.getFullText();
73 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Bad currency.";
86 JLOG(ctx.
j.
warn()) <<
"Check does not exist.";
94 JLOG(ctx.
j.
warn()) <<
"Cashing a check with wrong Destination.";
102 JLOG(ctx.
j.
error()) <<
"Malformed transaction: Cashing check to self.";
108 if (!sleSrc || !sleDst)
112 <<
"Malformed transaction: source or destination not in ledger";
122 <<
"Malformed transaction: DestinationTag required in check.";
138 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.";
181 availableFunds += XRPAmount{ctx.view.fees().increment};
183 if (value > availableFunds)
186 <<
"Check cashed for more than owner's balance.";
192 if (! value.native() && (value.getIssuer() != dstId))
194 auto const sleTrustLine = ctx.view.read (
199 <<
"Cannot cash check for IOU without trustline.";
207 <<
"Can't receive IOUs from non-existent issuer: "
217 bool const canonical_gt (dstId > issuerId);
219 bool const is_authorized ((*sleTrustLine)[
sfFlags] &
225 <<
"Can't receive IOUs from issuer without auth.";
236 if (
isFrozen (ctx.view, dstId, currency, issuerId))
239 <<
"Cashing a check to a frozen trustline.";
248 CashCheck::doApply ()
255 auto const sleCheck = psb.
peek (keylet::check (checkKey));
259 <<
"Precheck did not verify check's existence.";
264 auto const sleSrc = psb.
peek (keylet::account (srcId));
265 auto const sleDst = psb.
peek (keylet::account (account_));
267 if (!sleSrc || !sleDst)
269 JLOG(ctx_.journal.fatal())
270 <<
"Precheck did not verify source or destination's existence.";
284 auto viewJ = ctx_.app.journal (
"View");
286 bool const doFix1623 {ctx_.view().rules().enabled (
fix1623)};
287 if (srcId != account_)
292 if (sendMax.native())
305 STAmount const xrpDeliver {optDeliverMin ?
309 if (srcLiquid < xrpDeliver)
313 JLOG(j_.
trace()) <<
"Cash Check: Insufficient XRP: "
314 << srcLiquid.getFullText()
315 <<
" < " << xrpDeliver.getFullText();
319 if (optDeliverMin && doFix1623)
321 ctx_.deliver (xrpDeliver);
325 psb, srcId, account_, xrpDeliver, viewJ)}; ter !=
tesSUCCESS)
340 STAmount const flowDeliver {optDeliverMin ?
342 STAmount::cMaxValue / 2, STAmount::cMaxOffset } :
346 auto const result =
flow (psb, flowDeliver, srcId, account_,
349 static_cast<bool>(optDeliverMin),
358 JLOG(ctx_.journal.warn())
359 <<
"flow failed when cashing check.";
360 return result.result();
366 if (result.actualAmountOut < *optDeliverMin)
368 JLOG(ctx_.journal.warn()) <<
"flow did not produce DeliverMin.";
373 ctx_.deliver (result.actualAmountOut);
380 if (srcId != account_)
383 if (! ctx_.view().dirRemove(
384 keylet::ownerDir(account_), page, checkKey,
true))
386 JLOG(j_.
warn()) <<
"Unable to delete check from destination.";
393 if (! ctx_.view().dirRemove(
394 keylet::ownerDir(srcId), page, checkKey,
true))
396 JLOG(j_.
warn()) <<
"Unable to delete check from owner.";
404 psb.
erase (sleCheck);
406 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.
Stream trace() const
Severity stream access functions.
A wrapper which makes credits unavailable to balances.
static NotTEC preflight(PreflightContext const &ctx)
const SF_Account sfAccount(access, STI_ACCOUNT, 1, "Account")
const SF_U32 sfFlags(access, STI_UINT32, 2, "Flags")
base_uint< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
bool isLegalNet(STAmount const &value)
static const check_t check
std::string to_string(ListDisposition disposition)
const SF_U64 sfOwnerNode(access, STI_UINT64, 4, "OwnerNode")
const SF_Amount sfAmount(access, STI_AMOUNT, 1, "Amount")
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_U32 sfDestinationTag(access, STI_UINT32, 14, "DestinationTag")
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
static TER preclaim(PreclaimContext const &ctx)
static const account_t account
const SF_Amount sfSendMax(access, STI_AMOUNT, 9, "SendMax")
const SF_U64 sfDestinationNode(access, STI_UINT64, 9, "DestinationNode")
TERSubset< CanCvtToTER > TER
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.
const uint256 featureChecks
const SF_U32 sfExpiration(access, STI_UINT32, 10, "Expiration")
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)
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.
const SF_Amount sfDeliverMin(access, STI_AMOUNT, 10, "DeliverMin")
void apply(RawView &to)
Apply changes to base view.
Issue const & issue() const
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 sfDestination(access, STI_ACCOUNT, 3, "Destination")
const SF_U256 sfCheckID(access, STI_HASH256, 24, "CheckID")
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.
std::chrono::time_point< NetClock > time_point
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
TERSubset< CanCvtToNotTEC > NotTEC