20#include <xrpld/app/misc/CredentialHelpers.h>
21#include <xrpld/app/misc/HashRouter.h>
22#include <xrpld/app/tx/detail/Escrow.h>
23#include <xrpld/app/tx/detail/MPTokenAuthorize.h>
24#include <xrpld/conditions/Condition.h>
25#include <xrpld/conditions/Fulfillment.h>
26#include <xrpld/ledger/ApplyView.h>
27#include <xrpld/ledger/View.h>
29#include <xrpl/basics/Log.h>
30#include <xrpl/basics/chrono.h>
31#include <xrpl/protocol/Feature.h>
32#include <xrpl/protocol/Indexes.h>
33#include <xrpl/protocol/MPTAmount.h>
34#include <xrpl/protocol/TxFlags.h>
35#include <xrpl/protocol/XRPAmount.h>
40#define SF_CF_INVALID SF_PRIVATE5
41#define SF_CF_VALID SF_PRIVATE6
85 ctx.
tx,
isXRP(ctx.
tx[sfAmount]) ? ctx.
tx[sfAmount].xrp() : beast::zero};
88template <Val
idIssueType T>
97 if (amount.
native() || amount <= beast::zero)
113 auto const amount = ctx.
tx[sfAmount];
114 if (amount.native() || amount.mpt() >
MPTAmount{maxMPTokenAmount} ||
115 amount <= beast::zero)
137 [&]<
typename T>(T
const&) {
138 return escrowCreatePreflightHelper<T>(ctx);
140 amount.asset().value());
146 if (amount <= beast::zero)
151 if (!ctx.
tx[~sfCancelAfter] && !ctx.
tx[~sfFinishAfter])
156 if (ctx.
tx[~sfCancelAfter] && ctx.
tx[~sfFinishAfter] &&
157 ctx.
tx[sfCancelAfter] <= ctx.
tx[sfFinishAfter])
166 if (!ctx.
tx[~sfFinishAfter] && !ctx.
tx[~sfCondition])
170 if (
auto const cb = ctx.
tx[~sfCondition])
176 auto condition = Condition::deserialize(*cb, ec);
180 <<
"Malformed condition during escrow creation: "
187 if (condition->type != Type::preimageSha256 &&
195template <Val
idIssueType T>
213 if (issuer == account)
224 auto const sleRippleState =
229 STAmount const balance = (*sleRippleState)[sfBalance];
232 if (balance > beast::zero && issuer < account)
236 if (balance < beast::zero && issuer > account)
266 if (spendableAmount <= beast::zero)
271 if (spendableAmount < amount)
275 if (!
canAdd(spendableAmount, amount))
291 if (issuer == account)
295 auto const issuanceKey =
297 auto const sleIssuance = ctx.
view.
read(issuanceKey);
307 if (sleIssuance->getAccountID(sfIssuer) != issuer)
351 if (spendableAmount <= beast::zero)
356 if (spendableAmount < amount)
386 [&]<
typename T>(T
const&) {
387 return escrowCreatePreclaimHelper<T>(
388 ctx, account, dest, amount);
390 amount.asset().value());
397template <Val
idIssueType T>
417 if (issuer == sender)
444 if (issuer == sender)
474 if (
ctx_.
tx[~sfCancelAfter])
476 auto const cancelAfter =
ctx_.
tx[sfCancelAfter];
478 if (closeTime.time_since_epoch().count() >= cancelAfter)
482 if (
ctx_.
tx[~sfFinishAfter])
484 auto const finishAfter =
ctx_.
tx[sfFinishAfter];
486 if (closeTime.time_since_epoch().count() >= finishAfter)
518 !
ctx_.
tx[~sfDestinationTag])
531 auto const slep = std::make_shared<SLE>(escrowKeylet);
532 (*slep)[sfAmount] = amount;
534 (*slep)[~sfCondition] =
ctx_.
tx[~sfCondition];
535 (*slep)[~sfSourceTag] =
ctx_.
tx[~sfSourceTag];
536 (*slep)[sfDestination] =
ctx_.
tx[sfDestination];
537 (*slep)[~sfCancelAfter] =
ctx_.
tx[~sfCancelAfter];
538 (*slep)[~sfFinishAfter] =
ctx_.
tx[~sfFinishAfter];
539 (*slep)[~sfDestinationTag] =
ctx_.
tx[~sfDestinationTag];
545 (*slep)[sfTransferRate] = xferRate.value;
558 (*slep)[sfOwnerNode] = *page;
569 (*slep)[sfDestinationNode] = *page;
575 AccountID const issuer = amount.getIssuer();
576 if (!
isXRP(amount) && issuer !=
account_ && issuer != dest &&
583 (*slep)[sfIssuerNode] = *page;
588 (*sle)[sfBalance] = (*sle)[sfBalance] - amount;
592 [&]<
typename T>(T
const&) {
593 return escrowLockApplyHelper<T>(
596 amount.asset().value());
616 auto condition = Condition::deserialize(c, ec);
620 auto fulfillment = Fulfillment::deserialize(f, ec);
624 return validate(*fulfillment, *condition);
640 auto const cb = ctx.
tx[~sfCondition];
641 auto const fb = ctx.
tx[~sfFulfillment];
645 if (
static_cast<bool>(cb) !=
static_cast<bool>(fb))
661 auto const flags = router.getFlags(
id);
666 if (!(flags & (SF_CF_INVALID | SF_CF_VALID)))
669 router.setFlags(
id, SF_CF_VALID);
671 router.setFlags(
id, SF_CF_INVALID);
686 if (
auto const fb = tx[~sfFulfillment])
688 extraFee +=
view.
fees().
base * (32 + (fb->size() / 16));
694template <Val
idIssueType T>
738 auto const issuanceKey =
740 auto const sleIssuance = ctx.
view.
read(issuanceKey);
776 AccountID const dest = (*slep)[sfDestination];
777 STAmount const amount = (*slep)[sfAmount];
782 [&]<
typename T>(T
const&) {
783 return escrowFinishPreclaimHelper<T>(ctx, dest, amount);
793template <Val
idIssueType T>
822 bool const recvLow = issuer > receiver;
823 bool const senderIssuer = issuer == sender;
824 bool const receiverIssuer = issuer == receiver;
825 bool const issuerHigh = issuer > receiver;
835 if (!view.
exists(trustLineKey) && createAsset && !receiverIssuer)
838 if (
std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
839 xrpBalance < view.
fees().accountReserve(ownerCount + 1))
841 JLOG(journal.
trace()) <<
"Trust line does not exist. "
842 "Insufficent reserve to create line.";
864 Issue(currency, receiver),
877 if (!view.
exists(trustLineKey) && !receiverIssuer)
882 if (xferRate < lockedRate)
883 lockedRate = xferRate;
894 auto finalAmt = amount;
895 if ((!senderIssuer && !receiverIssuer) && lockedRate !=
parityRate)
898 auto const xferFee = amount.
value() -
901 finalAmt = amount.
value() - xferFee;
908 auto const sleRippleState = view.
peek(trustLineKey);
914 STAmount const lineLimit = sleRippleState->getFieldAmount(
915 issuerHigh ? sfLowLimit : sfHighLimit);
917 STAmount lineBalance = sleRippleState->getFieldAmount(sfBalance);
924 lineBalance += finalAmt;
927 if (lineLimit < lineBalance)
935 rippleCredit(view, issuer, receiver, finalAmt,
true, journal);
956 bool const senderIssuer = issuer == sender;
957 bool const receiverIssuer = issuer == receiver;
959 auto const mptID = amount.
get<
MPTIssue>().getMptID();
962 createAsset && !receiverIssuer)
964 if (
std::uint32_t const ownerCount = {sleDest->at(sfOwnerCount)};
965 xrpBalance < view.
fees().accountReserve(ownerCount + 1))
987 if (xferRate < lockedRate)
988 lockedRate = xferRate;
999 auto finalAmt = amount;
1000 if ((!senderIssuer && !receiverIssuer) && lockedRate !=
parityRate)
1003 auto const xferFee = amount.
value() -
1006 finalAmt = amount.
value() - xferFee;
1033 if ((*slep)[~sfFinishAfter] && !
after(now, (*slep)[sfFinishAfter]))
1037 if ((*slep)[~sfCancelAfter] &&
after(now, (*slep)[sfCancelAfter]))
1043 if ((*slep)[~sfFinishAfter] &&
1045 (*slep)[sfFinishAfter])
1049 if ((*slep)[~sfCancelAfter] &&
1051 (*slep)[sfCancelAfter])
1060 auto const cb =
ctx_.
tx[~sfCondition];
1065 if (cb && !(flags & (SF_CF_INVALID | SF_CF_VALID)))
1067 auto const fb =
ctx_.
tx[~sfFulfillment];
1073 flags = SF_CF_VALID;
1075 flags = SF_CF_INVALID;
1082 if (flags & SF_CF_INVALID)
1086 auto const cond = (*slep)[~sfCondition];
1098 if (cond && (cond != cb))
1103 AccountID const destID = (*slep)[sfDestination];
1115 AccountID const account = (*slep)[sfAccount];
1119 auto const page = (*slep)[sfOwnerNode];
1123 JLOG(
j_.
fatal()) <<
"Unable to delete Escrow from owner.";
1129 if (
auto const optPage = (*slep)[~sfDestinationNode])
1134 JLOG(
j_.
fatal()) <<
"Unable to delete Escrow from recipient.";
1139 STAmount const amount = slep->getFieldAmount(sfAmount);
1142 (*sled)[sfBalance] = (*sled)[sfBalance] + amount;
1148 Rate lockedRate = slep->isFieldPresent(sfTransferRate)
1152 bool const createAsset = destID ==
account_;
1154 [&]<
typename T>(T
const&) {
1155 return escrowUnlockApplyHelper<T>(
1172 if (
auto const optPage = (*slep)[~sfIssuerNode]; optPage)
1177 JLOG(
j_.
fatal()) <<
"Unable to delete Escrow from recipient.";
1209template <Val
idIssueType T>
1225 if (issuer == account)
1245 if (issuer == account)
1249 auto const issuanceKey =
1251 auto const sleIssuance = ctx.
view.
read(issuanceKey);
1258 if (
auto const ter =
1272 auto const slep = ctx.
view.
read(k);
1276 AccountID const account = (*slep)[sfAccount];
1277 STAmount const amount = (*slep)[sfAmount];
1282 [&]<
typename T>(T
const&) {
1283 return escrowCancelPreclaimHelper<T>(
1284 ctx, account, amount);
1312 if (!(*slep)[~sfCancelAfter])
1316 if (!
after(now, (*slep)[sfCancelAfter]))
1322 if (!(*slep)[~sfCancelAfter] ||
1324 (*slep)[sfCancelAfter])
1328 AccountID const account = (*slep)[sfAccount];
1332 auto const page = (*slep)[sfOwnerNode];
1336 JLOG(
j_.
fatal()) <<
"Unable to delete Escrow from owner.";
1342 if (
auto const optPage = (*slep)[~sfDestinationNode]; optPage)
1350 JLOG(
j_.
fatal()) <<
"Unable to delete Escrow from recipient.";
1356 STAmount const amount = slep->getFieldAmount(sfAmount);
1360 (*sle)[sfBalance] = (*sle)[sfBalance] + amount;
1367 bool const createAsset = account ==
account_;
1369 [&]<
typename T>(T
const&) {
1370 return escrowUnlockApplyHelper<T>(
1387 if (
auto const optPage = (*slep)[~sfIssuerNode]; optPage)
1392 JLOG(
j_.
fatal()) <<
"Unable to delete Escrow from recipient.";
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
virtual HashRouter & getHashRouter()=0
beast::Journal const journal
Writeable view to a ledger, for applying a transaction.
virtual void update(std::shared_ptr< SLE > const &sle)=0
Indicate changes to a peeked SLE.
bool dirRemove(Keylet const &directory, std::uint64_t page, uint256 const &key, bool keepRoot)
Remove an entry from a directory.
virtual void insert(std::shared_ptr< SLE > const &sle)=0
Insert a new state SLE.
std::optional< std::uint64_t > dirInsert(Keylet const &directory, uint256 const &key, std::function< void(std::shared_ptr< SLE > const &)> const &describe)
Insert an entry to a directory.
virtual std::shared_ptr< SLE > peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void erase(std::shared_ptr< SLE > const &sle)=0
Remove a peeked SLE.
constexpr value_type const & value() const
static NotTEC preflight(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static TxConsequences makeTxConsequences(PreflightContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
static TER preclaim(PreclaimContext const &ctx)
static NotTEC preflight(PreflightContext const &ctx)
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
int getFlags(uint256 const &key)
bool setFlags(uint256 const &key, int flags)
Set the flags on a hash.
A currency issued by an account.
constexpr MPTID const & getMptID() const
static TER createMPToken(ApplyView &view, MPTID const &mptIssuanceID, AccountID const &account, std::uint32_t const flags)
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.
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
virtual LedgerInfo const & info() const =0
Returns information about the 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
Asset const & asset() const
constexpr TIss const & get() const
void setIssuer(AccountID const &uIssuer)
Currency const & getCurrency() const
STAmount const & value() const noexcept
AccountID const & getIssuer() const
Issue const & issue() const
bool native() const noexcept
bool isFieldPresent(SField const &field) const
std::uint32_t getFlags() const
std::uint32_t getSeqValue() const
Returns the first non-zero value of (Sequence, TicketSequence).
uint256 getTransactionID() const
An immutable linear range of bytes.
static XRPAmount calculateBaseFee(ReadView const &view, STTx const &tx)
Class describing the consequences to the account of applying a transaction if the transaction consume...
NotTEC checkFields(PreflightContext const &ctx)
TER valid(PreclaimContext const &ctx, AccountID const &src)
Keylet mptoken(MPTID const &issuanceID, AccountID const &holder) noexcept
Keylet line(AccountID const &id0, AccountID const &id1, Currency const ¤cy) noexcept
The index of a trust line for a given currency.
Keylet mptIssuance(std::uint32_t seq, AccountID const &issuer) noexcept
Keylet account(AccountID const &id) noexcept
AccountID root.
Keylet escrow(AccountID const &src, std::uint32_t seq) noexcept
An escrow entry.
Keylet ownerDir(AccountID const &id) noexcept
The root page of an account's directory.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
TER rippleLockEscrowMPT(ApplyView &view, AccountID const &sender, STAmount const &amount, beast::Journal j)
AccountID const & noAccount()
A placeholder for empty accounts.
TER escrowFinishPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
Currency const & badCurrency()
We deliberately disallow the currency that looks like "XRP" because too many people were using it ins...
TER escrowCreatePreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
bool isXRP(AccountID const &c)
static TER escrowFinishPreclaimHelper(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
TER requireAuth(ReadView const &view, Issue const &issue, AccountID const &account)
Check if the account lacks required authorization.
TER escrowLockApplyHelper< Issue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
@ lsfAllowTrustLineLocking
TER escrowCancelPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
static TER escrowLockApplyHelper(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
std::function< void(SLE::ref)> describeOwnerDir(AccountID const &account)
NotTEC preflight1(PreflightContext const &ctx)
Performs early sanity checks on the account and fee fields.
STAmount divideRound(STAmount const &amount, Rate const &rate, bool roundUp)
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.
TER escrowCreatePreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
TER rippleUnlockEscrowMPT(ApplyView &view, AccountID const &sender, AccountID const &receiver, STAmount const &amount, beast::Journal j)
static bool adjustOwnerCount(ApplyContext &ctx, int count)
NotTEC preflight2(PreflightContext const &ctx)
Checks whether the signature appears valid.
static bool checkCondition(Slice f, Slice c)
TER escrowUnlockApplyHelper< MPTIssue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
static NotTEC escrowCreatePreflightHelper(PreflightContext const &ctx)
static TER escrowCancelPreclaimHelper(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
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.
@ tecCRYPTOCONDITION_ERROR
@ tecNO_LINE_INSUF_RESERVE
@ tecINSUFFICIENT_RESERVE
TER verifyDepositPreauth(ApplyContext &ctx, AccountID const &src, AccountID const &dst, std::shared_ptr< SLE > const &sleDst)
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j)
NotTEC escrowCreatePreflightHelper< MPTIssue >(PreflightContext const &ctx)
bool isTesSuccess(TER x) noexcept
TER escrowFinishPreclaimHelper< MPTIssue >(PreclaimContext const &ctx, AccountID const &dest, STAmount const &amount)
NotTEC escrowCreatePreflightHelper< Issue >(PreflightContext const &ctx)
bool after(NetClock::time_point now, std::uint32_t mark)
Has the specified time passed?
constexpr std::uint32_t tfUniversalMask
TER rippleCredit(ApplyView &view, AccountID const &uSenderID, AccountID const &uReceiverID, STAmount const &saAmount, bool bCheckIssuer, beast::Journal j)
Calls static rippleCreditIOU if saAmount represents Issue.
TER escrowCancelPreclaimHelper< Issue >(PreclaimContext const &ctx, AccountID const &account, STAmount const &amount)
TER escrowLockApplyHelper< MPTIssue >(ApplyView &view, AccountID const &issuer, AccountID const &sender, STAmount const &amount, beast::Journal journal)
static TER escrowUnlockApplyHelper(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
bool isPseudoAccount(std::shared_ptr< SLE const > sleAcct)
TERSubset< CanCvtToNotTEC > NotTEC
TER escrowUnlockApplyHelper< Issue >(ApplyView &view, Rate lockedRate, std::shared_ptr< SLE > const &sleDest, STAmount const &xrpBalance, STAmount const &amount, AccountID const &issuer, AccountID const &sender, AccountID const &receiver, bool createAsset, beast::Journal journal)
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
static TER escrowCreatePreclaimHelper(PreclaimContext const &ctx, AccountID const &account, AccountID const &dest, STAmount const &amount)
XRPAmount accountReserve(std::size_t ownerCount) const
Returns the account reserve given the owner count, in drops.
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.
Represents a transfer rate.
T time_since_epoch(T... args)