1#include <xrpl/basics/scope.h>
2#include <xrpl/ledger/View.h>
3#include <xrpl/ledger/helpers/AccountRootHelpers.h>
4#include <xrpl/ledger/helpers/RippleStateHelpers.h>
5#include <xrpl/protocol/Feature.h>
6#include <xrpl/protocol/Indexes.h>
7#include <xrpl/protocol/TER.h>
8#include <xrpl/protocol/TxFlags.h>
9#include <xrpl/tx/paths/Flow.h>
10#include <xrpl/tx/transactors/check/CheckCash.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) != 0u) &&
85 !sleCheck->isFieldPresent(sfDestinationTag))
89 JLOG(ctx.
j.
warn()) <<
"Malformed transaction: DestinationTag required in check.";
96 JLOG(ctx.
j.
warn()) <<
"Cashing a check that has already expired.";
104 auto const optAmount = tx[~sfAmount];
105 return optAmount ? *optAmount : tx[sfDeliverMin];
108 STAmount const sendMax = sleCheck->at(sfSendMax);
109 Currency const currency{value.getCurrency()};
112 JLOG(ctx.
j.
warn()) <<
"Check cash does not match check currency.";
115 AccountID const issuerId{value.getIssuer()};
118 JLOG(ctx.
j.
warn()) <<
"Check cash does not match check issuer.";
123 JLOG(ctx.
j.
warn()) <<
"Check cashed for more than check sendMax.";
140 if (value > availableFunds)
142 JLOG(ctx.
j.
warn()) <<
"Check cashed for more than owner's balance.";
148 if (!value.native() && (value.getIssuer() != dstId))
154 <<
"Can't receive IOUs from non-existent issuer: " <<
to_string(issuerId);
158 if ((sleIssuer->at(sfFlags) & lsfRequireAuth) != 0u)
172 bool const canonical_gt(dstId > issuerId);
174 bool const is_authorized(
175 (sleTrustLine->at(sfFlags) & (canonical_gt ? lsfLowAuth : lsfHighAuth)) != 0u);
179 JLOG(ctx.
j.
warn()) <<
"Can't receive IOUs from issuer without auth.";
192 JLOG(ctx.
j.
warn()) <<
"Cashing a check to a frozen trustline.";
211 JLOG(
j_.
fatal()) <<
"Precheck did not verify check's existence.";
216 AccountID const srcId{sleCheck->getAccountID(sfAccount)};
220 JLOG(
ctx_.
journal.
fatal()) <<
"Precheck did not verify source or destination's existence.";
236 auto const optDeliverMin =
ctx_.
tx[~sfDeliverMin];
240 STAmount const sendMax = sleCheck->at(sfSendMax);
260 if (srcLiquid < xrpDeliver)
264 JLOG(
j_.
trace()) <<
"Cash Check: Insufficient XRP: " << srcLiquid.getFullText()
265 <<
" < " << xrpDeliver.getFullText();
297 Issue const& trustLineIssue = flowDeliver.issue();
298 AccountID const issuer = flowDeliver.getIssuer();
301 bool const destLow = issuer >
account_;
303 if (!psb.
exists(trustLineKey))
315 if (
std::uint32_t const ownerCount = {sleDst->at(sfOwnerCount)};
318 JLOG(
j_.
trace()) <<
"Trust line does not exist. "
319 "Insufficent reserve to create line.";
324 Currency const currency = flowDeliver.getCurrency();
325 STAmount initialBalance(flowDeliver.issue());
336 (sleDst->getFlags() & lsfDefaultRipple) == 0,
360 auto const sleTrustLine = psb.
peek(trustLineKey);
364 SF_AMOUNT const& tweakedLimit = destLow ? sfLowLimit : sfHighLimit;
365 STAmount const savedLimit = sleTrustLine->at(tweakedLimit);
368 scope_exit const fixup([&psb, &trustLineKey, &tweakedLimit, &savedLimit]() {
369 if (
auto const sleTrustLine = psb.
peek(trustLineKey))
370 sleTrustLine->at(tweakedLimit) = savedLimit;
376 sleTrustLine->at(tweakedLimit) = bigAmount;
379 auto const result =
flow(
386 static_cast<bool>(optDeliverMin),
390 sleCheck->getFieldAmount(sfSendMax),
397 return result.result();
403 if (result.actualAmountOut < *optDeliverMin)
425 JLOG(
j_.
fatal()) <<
"Unable to delete check from destination.";
434 JLOG(
j_.
fatal()) <<
"Unable to delete check from owner.";
Stream trace() const
Severity stream access functions.
std::reference_wrapper< ServiceRegistry > registry
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 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 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.
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)
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 uQualityIn, std::uint32_t uQualityOut, beast::Journal j)
Create a trust line.
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)
bool isFrozen(ReadView const &view, AccountID const &account, MPTIssue const &mptIssue, int depth=0)
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.
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
XRPAmount increment
Additional XRP reserve required per owned ledger object.
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.