20#include <xrpld/app/misc/CredentialHelpers.h>
21#include <xrpld/app/paths/RippleCalc.h>
22#include <xrpld/app/tx/detail/Payment.h>
23#include <xrpld/ledger/View.h>
24#include <xrpl/basics/Log.h>
25#include <xrpl/protocol/Feature.h>
26#include <xrpl/protocol/Quality.h>
27#include <xrpl/protocol/TxFlags.h>
28#include <xrpl/protocol/jss.h>
29#include <xrpl/protocol/st.h>
38 tx.isFieldPresent(sfSendMax) ? tx[sfSendMax] : tx[sfAmount];
42 return maxAmount.
native() ? maxAmount.
xrp() : beast::zero;
63 dstAmount < beast::zero);
79 STAmount const dstAmount(tx.getFieldAmount(sfAmount));
89 if (txFlags & paymentMask)
91 JLOG(j.trace()) <<
"Malformed transaction: Invalid flags set.";
101 bool const hasPaths = tx.isFieldPresent(sfPaths);
102 bool const hasMax = tx.isFieldPresent(sfSendMax);
104 auto const deliverMin = tx[~sfDeliverMin];
106 auto const account = tx.getAccountID(sfAccount);
110 if ((mptDirect && dstAmount.
asset() != maxSourceAmount.
asset()) ||
113 JLOG(j.trace()) <<
"Malformed transaction: inconsistent issues: "
116 << deliverMin.value_or(
STAmount{}).getFullText();
120 auto const& srcAsset = maxSourceAmount.
asset();
121 auto const& dstAsset = dstAmount.
asset();
123 bool const xrpDirect = srcAsset.
native() && dstAsset.native();
128 auto const dstAccountID = tx.getAccountID(sfDestination);
132 JLOG(j.trace()) <<
"Malformed transaction: "
133 <<
"Payment destination account not specified.";
136 if (hasMax && maxSourceAmount <= beast::zero)
138 JLOG(j.trace()) <<
"Malformed transaction: bad max amount: "
142 if (dstAmount <= beast::zero)
144 JLOG(j.trace()) <<
"Malformed transaction: bad dst amount: "
150 JLOG(j.trace()) <<
"Malformed transaction: Bad currency.";
153 if (account == dstAccountID &&
equalTokens(srcAsset, dstAsset) && !hasPaths)
157 JLOG(j.trace()) <<
"Malformed transaction: "
158 <<
"Redundant payment from " <<
to_string(account)
159 <<
" to self without path for " <<
to_string(dstAsset);
162 if (xrpDirect && hasMax)
165 JLOG(j.trace()) <<
"Malformed transaction: "
166 <<
"SendMax specified for XRP to XRP.";
169 if ((xrpDirect || mptDirect) && hasPaths)
172 JLOG(j.trace()) <<
"Malformed transaction: "
173 <<
"Paths specified for XRP to XRP or MPT to MPT.";
176 if (xrpDirect && partialPaymentAllowed)
179 JLOG(j.trace()) <<
"Malformed transaction: "
180 <<
"Partial payment specified for XRP to XRP.";
183 if ((xrpDirect || mptDirect) && limitQuality)
187 <<
"Malformed transaction: "
188 <<
"Limit quality specified for XRP to XRP or MPT to MPT.";
191 if ((xrpDirect || mptDirect) && !defaultPathsAllowed)
195 <<
"Malformed transaction: "
196 <<
"No ripple direct specified for XRP to XRP or MPT to MPT.";
202 if (!partialPaymentAllowed)
204 JLOG(j.trace()) <<
"Malformed transaction: Partial payment not "
206 << jss::DeliverMin.c_str() <<
".";
210 auto const dMin = *deliverMin;
214 <<
"Malformed transaction: Invalid " << jss::DeliverMin.c_str()
215 <<
" amount. " << dMin.getFullText();
218 if (dMin.asset() != dstAmount.
asset())
221 <<
"Malformed transaction: Dst issue differs "
223 << jss::DeliverMin.c_str() <<
". " << dMin.getFullText();
226 if (dMin > dstAmount)
229 <<
"Malformed transaction: Dst amount less than "
230 << jss::DeliverMin.c_str() <<
". " << dMin.getFullText();
248 auto const sendMax = ctx.
tx[~sfSendMax];
250 AccountID const dstAccountID(ctx.
tx[sfDestination]);
254 auto const sleDst = ctx.
view.
read(k);
262 <<
"Delay transaction: Destination account does not exist.";
268 else if (ctx.
view.
open() && partialPaymentAllowed)
272 JLOG(ctx.
j.
trace()) <<
"Delay transaction: Partial payment not "
273 "allowed to create account.";
284 <<
"Delay transaction: Destination account does not exist. "
285 <<
"Insufficent payment to create account.";
303 <<
"Malformed transaction: DestinationTag required.";
309 if ((hasPaths || sendMax || !dstAmount.
native()) && ctx.
view.
open())
315 return path.size() > MaxPathLength;
332 auto const deliverMin =
ctx_.
tx[~sfDeliverMin];
340 auto const sendMax =
ctx_.
tx[~sfSendMax];
348 JLOG(
j_.
trace()) <<
"maxSourceAmount=" << maxSourceAmount.getFullText()
362 sleDst = std::make_shared<SLE>(k);
363 sleDst->setAccountID(sfAccount, dstAccountID);
364 sleDst->setFieldU32(sfSequence, seqno);
378 bool const reqDepositAuth =
384 (hasPaths || sendMax || !dstAmount.
native()) && !mptDirect;
388 if (!depositPreauth &&
ripple && reqDepositAuth)
396 if (depositPreauth && depositAuth)
418 JLOG(
j_.
debug()) <<
"Entering RippleCalc in payment: "
445 auto terResult = rc.
result();
478 auto const& issuer = mptIssue.
getIssuer();
481 Rate rate{QUALITY_ONE};
483 if (
account_ != issuer && dstAccountID != issuer)
506 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
508 requiredMaxSourceAmount = maxSourceAmount;
510 amountDeliver =
divide(maxSourceAmount, rate);
513 if (requiredMaxSourceAmount > maxSourceAmount ||
514 (deliverMin && amountDeliver < *deliverMin))
528 XRPL_ASSERT(dstAmount.
native(),
"ripple::Payment::doApply : amount is XRP");
538 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
552 JLOG(
j_.
trace()) <<
"Delay transaction: Insufficient funds: "
562 if (sleDst->isFieldPresent(sfAMMID))
591 if (dstAmount > dstReserve ||
592 sleDst->getFieldAmount(sfBalance) > dstReserve)
603 sleDst->setFieldAmount(
604 sfBalance, sleDst->getFieldAmount(sfBalance) + dstAmount);
Stream trace() const
Severity stream access functions.
beast::Journal const journal
void deliver(STAmount const &amount)
Sets the DeliveredAmount field in the metadata.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
A currency issued by an account.
AccountID const & getIssuer() const
A wrapper which makes credits unavailable to balances.
void apply(RawView &to)
Apply changes to base view.
static std::size_t const MaxPathSize
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
virtual bool open() const =0
Returns true if this reflects an open ledger.
virtual Fees const & fees() const =0
Returns the fees for the base ledger.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
constexpr bool holds() const noexcept
int exponent() const noexcept
Asset const & asset() const
constexpr TIss const & get() const
std::uint64_t mantissa() const noexcept
std::string getFullText() const override
bool native() const noexcept
STPathSet const & getFieldPathSet(SField const &field) const
AccountID getAccountID(SField const &field) const
STAmount const & getFieldAmount(SField const &field) const
bool isFieldPresent(SField const &field) const
std::uint32_t getFlags() const
std::vector< STPath >::const_iterator end() const
std::vector< STPath >::const_iterator begin() const
std::vector< STPath >::size_type size() const
uint256 getTransactionID() const
Class describing the consequences to the account of applying a transaction if the transaction consume...
static Output rippleCalculate(PaymentSandbox &view, STAmount const &saMaxAmountReq, STAmount const &saDstAmountReq, AccountID const &uDstAccountID, AccountID const &uSrcAccountID, STPathSet const &spsPaths, Logs &l, Input const *const pInputs=nullptr)
NotTEC checkFields(PreflightContext const &ctx)
TER valid(PreclaimContext const &ctx, AccountID const &src)
Keylet account(AccountID const &id) noexcept
AccountID root.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount divide(STAmount const &amount, Rate const &rate)
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
constexpr bool equalTokens(Asset const &lhs, Asset const &rhs)
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
bool isLegalNet(STAmount const &value)
constexpr std::uint32_t tfMPTPaymentMask
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
STAmount getMaxSourceAmount(AccountID const &account, STAmount const &dstAmount, std::optional< STAmount > const &sendMax)
STAmount multiply(STAmount const &amount, Rate const &rate)
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
bool isFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
TER canTransfer(ReadView const &view, MPTIssue const &mptIssue, AccountID const &from, AccountID const &to)
Check if the destination account is allowed to receive MPT.
constexpr std::uint32_t tfPartialPayment
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
constexpr std::uint32_t tfNoRippleDirect
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
constexpr std::uint32_t tfPaymentMask
constexpr std::uint32_t tfLimitQuality
std::string to_string(base_uint< Bits, Tag > const &a)
TER accountSend(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, beast::Journal j, WaiveTransferFee waiveFee)
Calls static accountSendIOU if saAmount represents Issue.
TERSubset< CanCvtToNotTEC > NotTEC
@ temBAD_SEND_XRP_PARTIAL
@ temBAD_SEND_XRP_NO_DIRECT
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
State information when determining if a tx is likely to claim a fee.
State information when preflighting a tx.
Represents a transfer rate.
void setResult(TER const value)