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))
25 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: "
26 "does not specify exactly one of Amount and DeliverMin.";
31 STAmount const value{optAmount ? *optAmount : *optDeliverMin};
34 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: bad amount: " << value.getFullText();
40 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: Bad currency.";
53 JLOG(ctx.
j.
warn()) <<
"Check does not exist.";
58 AccountID const dstId = sleCheck->at(sfDestination);
59 if (ctx.
tx[sfAccount] != dstId)
61 JLOG(ctx.
j.
warn()) <<
"Cashing a check with wrong Destination.";
64 AccountID const srcId = sleCheck->at(sfAccount);
70 JLOG(ctx.
j.
error()) <<
"Malformed transaction: Cashing check to self.";
77 if (!sleSrc || !sleDst)
80 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: source or destination not in ledger";
84 if ((sleDst->getFlags() &
lsfRequireDestTag) && !sleCheck->isFieldPresent(sfDestinationTag))
88 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: DestinationTag required in check.";
95 JLOG(ctx.
j.
warn()) <<
"Cashing a check that has already expired.";
103 auto const optAmount = tx[~sfAmount];
104 return optAmount ? *optAmount : tx[sfDeliverMin];
107 STAmount const sendMax = sleCheck->at(sfSendMax);
108 Currency const currency{value.getCurrency()};
111 JLOG(ctx.
j.
warn()) <<
"Check cash does not match check currency.";
114 AccountID const issuerId{value.getIssuer()};
117 JLOG(ctx.
j.
warn()) <<
"Check cash does not match check issuer.";
122 JLOG(ctx.
j.
warn()) <<
"Check cashed for more than check sendMax.";
138 if (value > availableFunds)
140 JLOG(ctx.
j.
warn()) <<
"Check cashed for more than owner's balance.";
146 if (!value.native() && (value.getIssuer() != dstId))
151 JLOG(ctx.
j.
warn()) <<
"Can't receive IOUs from non-existent issuer: " <<
to_string(issuerId);
169 bool const canonical_gt(dstId > issuerId);
175 JLOG(ctx.
j.
warn()) <<
"Can't receive IOUs from issuer without auth.";
188 JLOG(ctx.
j.
warn()) <<
"Cashing a check to a frozen trustline.";
207 JLOG(
j_.
fatal()) <<
"Precheck did not verify check's existence.";
212 AccountID const srcId{sleCheck->getAccountID(sfAccount)};
216 JLOG(
ctx_.
journal.
fatal()) <<
"Precheck did not verify source or destination's existence.";
232 auto const optDeliverMin =
ctx_.
tx[~sfDeliverMin];
236 STAmount const sendMax = sleCheck->at(sfSendMax);
256 if (srcLiquid < xrpDeliver)
260 JLOG(
j_.
trace()) <<
"Cash Check: Insufficient XRP: " << srcLiquid.getFullText() <<
" < "
261 << xrpDeliver.getFullText();
288 Issue const& trustLineIssue = flowDeliver.issue();
289 AccountID const issuer = flowDeliver.getIssuer();
292 bool const destLow = issuer >
account_;
294 if (!psb.
exists(trustLineKey))
306 if (
std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
309 JLOG(
j_.
trace()) <<
"Trust line does not exist. "
310 "Insufficent reserve to create line.";
315 Currency const currency = flowDeliver.getCurrency();
316 STAmount initialBalance(flowDeliver.issue());
353 auto const sleTrustLine = psb.
peek(trustLineKey);
357 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
358 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
361 scope_exit fixup([&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
362 if (
auto const sleTrustLine = psb.
peek(trustLineKey))
363 sleTrustLine->at(tweakedLimit) = savedLimit;
369 sleTrustLine->at(tweakedLimit) = bigAmount;
372 auto const result =
flow(
379 static_cast<bool>(optDeliverMin),
383 sleCheck->getFieldAmount(sfSendMax),
390 return result.result();
396 if (result.actualAmountOut < *optDeliverMin)
417 JLOG(
j_.
fatal()) <<
"Unable to delete check from destination.";
426 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
void deliver(STAmount const &amount)
Sets the DeliveredAmount field in the metadata.
beast::Journal const journal
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext 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 Fees const & fees() const =0
Returns the fees for the base ledger.
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
static constexpr std::uint64_t cMaxValue
void setIssuer(AccountID const &uIssuer)
static int const cMaxOffset
Currency const & getCurrency() const
bool native() const noexcept
AccountID const & getIssuer() const
STAmount const & getFieldAmount(SField const &field) const
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
void erase(std::shared_ptr< SLE > const &sle) override
Remove a peeked SLE.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
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.
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.
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.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
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.
XRPAmount xrpLiquid(ReadView const &view, AccountID const &id, std::int32_t ownerCountAdj, beast::Journal j)
std::string to_string(base_uint< Bits, Tag > const &a)
bool hasExpired(ReadView const &view, std::optional< std::uint32_t > const &exp)
Determines whether the given expiration time has passed.
bool isLegalNet(STAmount const &value)
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
void adjustOwnerCount(ApplyView &view, std::shared_ptr< SLE > const &sle, std::int32_t amount, beast::Journal j)
Adjust the owner count up or down.
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)
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
AccountID const & noAccount()
A placeholder for empty accounts.
bool isTesSuccess(TER x) noexcept
@ tecNO_LINE_INSUF_RESERVE
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
TERSubset< CanCvtToNotTEC > NotTEC
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.