20#include <xrpld/app/misc/CredentialHelpers.h>
21#include <xrpld/app/misc/DelegateUtils.h>
22#include <xrpld/app/paths/RippleCalc.h>
23#include <xrpld/app/tx/detail/Payment.h>
24#include <xrpld/ledger/View.h>
26#include <xrpl/basics/Log.h>
27#include <xrpl/protocol/Feature.h>
28#include <xrpl/protocol/Quality.h>
29#include <xrpl/protocol/TxFlags.h>
30#include <xrpl/protocol/jss.h>
39 tx.isFieldPresent(sfSendMax) ? tx[sfSendMax] : tx[sfAmount];
43 return maxAmount.
native() ? maxAmount.
xrp() : beast::zero;
64 dstAmount < beast::zero);
80 STAmount const dstAmount(tx.getFieldAmount(sfAmount));
90 if (txFlags & paymentMask)
92 JLOG(j.trace()) <<
"Malformed transaction: Invalid flags set.";
102 bool const hasPaths = tx.isFieldPresent(sfPaths);
103 bool const hasMax = tx.isFieldPresent(sfSendMax);
105 auto const deliverMin = tx[~sfDeliverMin];
107 auto const account = tx.getAccountID(sfAccount);
111 if ((mptDirect && dstAmount.
asset() != maxSourceAmount.
asset()) ||
114 JLOG(j.trace()) <<
"Malformed transaction: inconsistent issues: "
117 << deliverMin.value_or(
STAmount{}).getFullText();
121 auto const& srcAsset = maxSourceAmount.
asset();
122 auto const& dstAsset = dstAmount.
asset();
124 bool const xrpDirect = srcAsset.
native() && dstAsset.native();
129 auto const dstAccountID = tx.getAccountID(sfDestination);
133 JLOG(j.trace()) <<
"Malformed transaction: "
134 <<
"Payment destination account not specified.";
137 if (hasMax && maxSourceAmount <= beast::zero)
139 JLOG(j.trace()) <<
"Malformed transaction: bad max amount: "
143 if (dstAmount <= beast::zero)
145 JLOG(j.trace()) <<
"Malformed transaction: bad dst amount: "
151 JLOG(j.trace()) <<
"Malformed transaction: Bad currency.";
154 if (account == dstAccountID &&
equalTokens(srcAsset, dstAsset) && !hasPaths)
158 JLOG(j.trace()) <<
"Malformed transaction: "
159 <<
"Redundant payment from " <<
to_string(account)
160 <<
" to self without path for " <<
to_string(dstAsset);
163 if (xrpDirect && hasMax)
166 JLOG(j.trace()) <<
"Malformed transaction: "
167 <<
"SendMax specified for XRP to XRP.";
170 if ((xrpDirect || mptDirect) && hasPaths)
173 JLOG(j.trace()) <<
"Malformed transaction: "
174 <<
"Paths specified for XRP to XRP or MPT to MPT.";
177 if (xrpDirect && partialPaymentAllowed)
180 JLOG(j.trace()) <<
"Malformed transaction: "
181 <<
"Partial payment specified for XRP to XRP.";
184 if ((xrpDirect || mptDirect) && limitQuality)
188 <<
"Malformed transaction: "
189 <<
"Limit quality specified for XRP to XRP or MPT to MPT.";
192 if ((xrpDirect || mptDirect) && !defaultPathsAllowed)
196 <<
"Malformed transaction: "
197 <<
"No ripple direct specified for XRP to XRP or MPT to MPT.";
203 if (!partialPaymentAllowed)
205 JLOG(j.trace()) <<
"Malformed transaction: Partial payment not "
207 << jss::DeliverMin.c_str() <<
".";
211 auto const dMin = *deliverMin;
215 <<
"Malformed transaction: Invalid " << jss::DeliverMin.c_str()
216 <<
" amount. " << dMin.getFullText();
219 if (dMin.asset() != dstAmount.
asset())
222 <<
"Malformed transaction: Dst issue differs "
224 << jss::DeliverMin.c_str() <<
". " << dMin.getFullText();
227 if (dMin > dstAmount)
230 <<
"Malformed transaction: Dst amount less than "
231 << jss::DeliverMin.c_str() <<
". " << dMin.getFullText();
245 auto const delegate = tx[~sfDelegate];
250 auto const sle =
view.
read(delegateKey);
262 auto const& amountIssue = dstAmount.
issue();
264 if (granularPermissions.
contains(PaymentMint) && !
isXRP(amountIssue) &&
265 amountIssue.account == tx[sfAccount])
268 if (granularPermissions.
contains(PaymentBurn) && !
isXRP(amountIssue) &&
269 amountIssue.account == tx[sfDestination])
282 auto const sendMax = ctx.
tx[~sfSendMax];
284 AccountID const dstAccountID(ctx.
tx[sfDestination]);
288 auto const sleDst = ctx.
view.
read(k);
296 <<
"Delay transaction: Destination account does not exist.";
302 else if (ctx.
view.
open() && partialPaymentAllowed)
306 JLOG(ctx.
j.
trace()) <<
"Delay transaction: Partial payment not "
307 "allowed to create account.";
318 <<
"Delay transaction: Destination account does not exist. "
319 <<
"Insufficent payment to create account.";
337 <<
"Malformed transaction: DestinationTag required.";
343 if ((hasPaths || sendMax || !dstAmount.
native()) && ctx.
view.
open())
349 return path.size() > MaxPathLength;
366 auto const deliverMin =
ctx_.
tx[~sfDeliverMin];
374 auto const sendMax =
ctx_.
tx[~sfSendMax];
382 JLOG(
j_.
trace()) <<
"maxSourceAmount=" << maxSourceAmount.getFullText()
396 sleDst = std::make_shared<SLE>(k);
397 sleDst->setAccountID(sfAccount, dstAccountID);
398 sleDst->setFieldU32(sfSequence, seqno);
412 bool const reqDepositAuth =
418 (hasPaths || sendMax || !dstAmount.
native()) && !mptDirect;
422 if (!depositPreauth &&
ripple && reqDepositAuth)
430 if (depositPreauth && depositAuth)
452 JLOG(
j_.
debug()) <<
"Entering RippleCalc in payment: "
479 auto terResult = rc.
result();
512 auto const& issuer = mptIssue.
getIssuer();
515 Rate rate{QUALITY_ONE};
517 if (
account_ != issuer && dstAccountID != issuer)
540 if (partialPaymentAllowed && requiredMaxSourceAmount > maxSourceAmount)
542 requiredMaxSourceAmount = maxSourceAmount;
544 amountDeliver =
divide(maxSourceAmount, rate);
547 if (requiredMaxSourceAmount > maxSourceAmount ||
548 (deliverMin && amountDeliver < *deliverMin))
562 XRPL_ASSERT(dstAmount.
native(),
"ripple::Payment::doApply : amount is XRP");
572 auto const ownerCount = sleSrc->getFieldU32(sfOwnerCount);
586 JLOG(
j_.
trace()) <<
"Delay transaction: Insufficient funds: "
596 if (sleDst->isFieldPresent(sfAMMID))
625 if (dstAmount > dstReserve ||
626 sleDst->getFieldAmount(sfBalance) > dstReserve)
637 sleDst->setFieldAmount(
638 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 checkPermission(ReadView const &view, STTx const &tx)
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
Issue const & issue() 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 delegate(AccountID const &account, AccountID const &authorizedAccount) noexcept
A keylet for Delegate object.
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)
bool isXRP(AccountID const &c)
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
void loadGranularPermission(std::shared_ptr< SLE const > const &delegate, TxType const &type, std::unordered_set< GranularPermissionType > &granularPermissions)
Load the granular permissions granted to the delegate account for the specified transaction type.
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
TER checkTxPermission(std::shared_ptr< SLE const > const &delegate, STTx const &tx)
Check if the delegate account has permission to execute the transaction.
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)