1#include <xrpld/app/ledger/Ledger.h>
2#include <xrpld/app/paths/Flow.h>
3#include <xrpld/app/tx/detail/CashCheck.h>
5#include <xrpl/basics/Log.h>
6#include <xrpl/basics/scope.h>
7#include <xrpl/protocol/Feature.h>
8#include <xrpl/protocol/Indexes.h>
9#include <xrpl/protocol/TER.h>
10#include <xrpl/protocol/TxFlags.h>
20 auto const optAmount = ctx.
tx[~sfAmount];
21 auto const optDeliverMin = ctx.
tx[~sfDeliverMin];
23 if (
static_cast<bool>(optAmount) ==
static_cast<bool>(optDeliverMin))
26 <<
"Malformed transaction: "
27 "does not specify exactly one of Amount and DeliverMin.";
32 STAmount const value{optAmount ? *optAmount : *optDeliverMin};
35 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: bad amount: "
36 << value.getFullText();
42 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Bad currency.";
55 JLOG(ctx.
j.
warn()) <<
"Check does not exist.";
60 AccountID const dstId = sleCheck->at(sfDestination);
61 if (ctx.
tx[sfAccount] != dstId)
63 JLOG(ctx.
j.
warn()) <<
"Cashing a check with wrong Destination.";
66 AccountID const srcId = sleCheck->at(sfAccount);
72 JLOG(ctx.
j.
error()) <<
"Malformed transaction: Cashing check to self.";
79 if (!sleSrc || !sleDst)
83 <<
"Malformed transaction: source or destination not in ledger";
88 !sleCheck->isFieldPresent(sfDestinationTag))
93 <<
"Malformed transaction: DestinationTag required in check.";
100 JLOG(ctx.
j.
warn()) <<
"Cashing a check that has already expired.";
108 auto const optAmount = tx[~sfAmount];
109 return optAmount ? *optAmount : tx[sfDeliverMin];
112 STAmount const sendMax = sleCheck->at(sfSendMax);
113 Currency const currency{value.getCurrency()};
116 JLOG(ctx.
j.
warn()) <<
"Check cash does not match check currency.";
119 AccountID const issuerId{value.getIssuer()};
122 JLOG(ctx.
j.
warn()) <<
"Check cash does not match check issuer.";
127 JLOG(ctx.
j.
warn()) <<
"Check cashed for more than check sendMax.";
136 sleCheck->at(sfAccount),
148 if (value > availableFunds)
151 <<
"Check cashed for more than owner's balance.";
157 if (!value.native() && (value.getIssuer() != dstId))
163 <<
"Can't receive IOUs from non-existent issuer: "
170 auto const sleTrustLine =
183 bool const canonical_gt(dstId > issuerId);
185 bool const is_authorized(
186 sleTrustLine->at(sfFlags) &
192 <<
"Can't receive IOUs from issuer without auth.";
205 JLOG(ctx.
j.
warn()) <<
"Cashing a check to a frozen trustline.";
224 JLOG(
j_.
fatal()) <<
"Precheck did not verify check's existence.";
229 AccountID const srcId{sleCheck->getAccountID(sfAccount)};
235 <<
"Precheck did not verify source or destination's existence.";
251 auto const optDeliverMin =
ctx_.
tx[~sfDeliverMin];
255 STAmount const sendMax = sleCheck->at(sfSendMax);
276 if (srcLiquid < xrpDeliver)
280 JLOG(
j_.
trace()) <<
"Cash Check: Insufficient XRP: "
281 << srcLiquid.getFullText() <<
" < "
282 << xrpDeliver.getFullText();
308 optDeliverMin->issue(),
314 Issue const& trustLineIssue = flowDeliver.issue();
315 AccountID const issuer = flowDeliver.getIssuer();
318 bool const destLow = issuer >
account_;
320 if (!psb.
exists(trustLineKey))
332 if (
std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
335 JLOG(
j_.
trace()) <<
"Trust line does not exist. "
336 "Insufficent reserve to create line.";
341 Currency const currency = flowDeliver.getCurrency();
342 STAmount initialBalance(flowDeliver.issue());
379 auto const sleTrustLine = psb.
peek(trustLineKey);
383 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
384 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
388 [&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
389 if (
auto const sleTrustLine = psb.
peek(trustLineKey))
390 sleTrustLine->at(tweakedLimit) = savedLimit;
397 sleTrustLine->at(tweakedLimit) = bigAmount;
400 auto const result =
flow(
407 static_cast<bool>(optDeliverMin),
411 sleCheck->getFieldAmount(sfSendMax),
418 return result.result();
424 if (result.actualAmountOut < *optDeliverMin)
427 <<
"flow did not produce DeliverMin.";
445 sleCheck->at(sfDestinationNode),
450 JLOG(
j_.
fatal()) <<
"Unable to delete check from destination.";
458 sleCheck->at(sfOwnerNode),
463 JLOG(
j_.
fatal()) <<
"Unable to delete check from owner.";
Stream trace() const
Severity stream access functions.
virtual beast::Journal journal(std::string const &name)=0
beast::Journal const journal
void deliver(STAmount const &amount)
Sets the DeliveredAmount field in the metadata.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
A currency issued by an account.
A wrapper which makes credits unavailable to balances.
void apply(RawView &to)
Apply changes to base view.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
void setIssuer(AccountID const &uIssuer)
static int const cMaxOffset
Currency const & getCurrency() const
static std::uint64_t const cMaxValue
AccountID const & getIssuer() const
bool native() const noexcept
STAmount const & getFieldAmount(SField const &field) const
Fees const & fees() const override
Returns the fees for the base ledger.
void erase(std::shared_ptr< SLE > const &sle) override
Remove a peeked SLE.
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
bool exists(Keylet const &k) const override
Determine if a state item exists.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Keylet check(AccountID const &id, std::uint32_t seq) noexcept
A Check.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
AccountID const & noAccount()
A placeholder for empty accounts.
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
bool isLegalNet(STAmount const &value)
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &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)
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.
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
@ tecNO_LINE_INSUF_RESERVE
bool isTesSuccess(TER x) noexcept
std::string to_string(base_uint< Bits, Tag > const &a)
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 uSrcQualityIn, std::uint32_t uSrcQualityOut, beast::Journal j)
Create a trust line.
TERSubset< CanCvtToNotTEC > NotTEC
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
A pair of SHAMap key and LedgerEntryType.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.
A field with a type known at compile time.