1#include <xrpl/tx/paths/OfferStream.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/basics/base_uint.h>
6#include <xrpl/basics/chrono.h>
7#include <xrpl/basics/contract.h>
8#include <xrpl/beast/utility/Journal.h>
9#include <xrpl/beast/utility/Zero.h>
10#include <xrpl/beast/utility/instrumentation.h>
11#include <xrpl/ledger/ApplyView.h>
12#include <xrpl/ledger/ReadView.h>
13#include <xrpl/ledger/helpers/MPTokenHelpers.h>
14#include <xrpl/ledger/helpers/PermissionedDEXHelpers.h>
15#include <xrpl/ledger/helpers/RippleStateHelpers.h>
16#include <xrpl/ledger/helpers/TokenHelpers.h>
17#include <xrpl/protocol/AccountID.h>
18#include <xrpl/protocol/Asset.h>
19#include <xrpl/protocol/Book.h>
20#include <xrpl/protocol/Concepts.h>
21#include <xrpl/protocol/Feature.h>
22#include <xrpl/protocol/IOUAmount.h>
23#include <xrpl/protocol/Indexes.h>
24#include <xrpl/protocol/MPTAmount.h>
25#include <xrpl/protocol/MPTIssue.h>
26#include <xrpl/protocol/Quality.h>
27#include <xrpl/protocol/SField.h>
28#include <xrpl/protocol/STLedgerEntry.h>
29#include <xrpl/protocol/TER.h>
30#include <xrpl/protocol/XRPAmount.h>
31#include <xrpl/tx/paths/detail/Steps.h>
44 auto issuerExists = [](
ReadView const& view,
Asset const& asset) ->
bool {
45 auto const& issuer = asset.getIssuer();
48 return issuerExists(view,
book.in) && issuerExists(view,
book.out);
52template <StepAmount TIn, StepAmount TOut>
69 XRPL_ASSERT(
validBook_,
"xrpl::TOfferStreamBase::TOfferStreamBase : valid book");
74template <StepAmount TIn, StepAmount TOut>
86 JLOG(
j_.error()) <<
"Missing directory " <<
tip_.dir() <<
" for offer " <<
tip_.index();
90 auto v(p->getFieldV256(sfIndexes));
95 JLOG(
j_.error()) <<
"Missing offer " <<
tip_.index() <<
" for directory " <<
tip_.dir();
100 p->setFieldV256(sfIndexes, v);
103 JLOG(
j_.trace()) <<
"Missing offer " <<
tip_.index() <<
" removed from directory "
107template <StepAmount T>
137template <StepAmount TIn, StepAmount TOut>
138template <
class TTakerPays,
class TTakerGets>
139 requires ValidTaker<TTakerPays, TTakerGets>
149 if constexpr (!kInIsIntegral && kOutIsIntegral)
164 if constexpr (!kInIsIntegral && !kOutIsIntegral)
172 auto const effectiveAmounts = [&] {
176 bool const issuerHasUnlimitedFunds =
offer_.owner() ==
offer_.assetOut().getIssuer() &&
177 offer_.assetOut().template holds<Issue>();
190 if (effectiveAmounts.in.signum() <= 0 || effectiveAmounts.out.signum() <= 0)
193 if (effectiveAmounts.in > TTakerPays::minPositiveAmount())
196 Quality const effectiveQuality{effectiveAmounts};
197 return effectiveQuality <
offer_.quality();
200template <StepAmount TIn, StepAmount TOut>
235 if (entry->isFieldPresent(sfExpiration) && Tp{D{(*entry)[sfExpiration]}} <=
expire_)
237 JLOG(
j_.trace()) <<
"Removing expired offer " << entry->key();
244 auto const amount(
offer_.amount());
249 JLOG(
j_.warn()) <<
"Removing bad offer " << entry->key();
257 JLOG(
j_.trace()) <<
"Removing deep frozen unfunded offer " << entry->key();
270 if (
view_.rules().enabled(fixCleanup3_4_0) &&
book_.domain.has_value() &&
271 (!entry->isFieldPresent(sfDomainID) ||
272 entry->getFieldH256(sfDomainID) != *
book_.domain))
274 JLOG(
j_.error()) <<
"Offer " << entry->key()
275 <<
" domain missing or does not match book domain";
277 tecINTERNAL,
"Offer domain missing or does not match book domain.");
285 if ((!
view_.rules().enabled(fixCleanup3_3_0) ||
book_.domain.has_value()) &&
286 entry->isFieldPresent(sfDomainID) &&
288 view_, entry->key(), entry->getFieldH256(sfDomainID),
j_))
290 JLOG(
j_.trace()) <<
"Removing offer no longer in domain " << entry->key();
324 JLOG(
j_.trace()) <<
"Removing unfunded offer " << entry->key();
328 JLOG(
j_.trace()) <<
"Removing became unfunded offer " << entry->key();
338 bool shouldRemoveSmallIncreasedQOffer =
false;
345 if (
view_.rules().enabled(featureMPTokensV2))
349 "OfferStream::step removed MPT offer with overflowing "
352 JLOG(
j_.warn()) <<
"Removing offer with overflowing reduced quality "
363 view_.rules().enabled(featureMPTokensV2),
364 "xrpl::TOfferStreamBase::step : overflow implies MPTokensV2");
369 if (shouldRemoveSmallIncreasedQOffer)
383 JLOG(
j_.trace()) <<
"Removing tiny offer due to reduced quality " << entry->key();
387 JLOG(
j_.trace()) <<
"Removing tiny offer that became tiny due "
388 "to reduced quality "
402template <StepAmount TIn, StepAmount TOut>
A generic endpoint for log messages.
Writeable view to a ledger, for applying a transaction.
virtual SLE::pointer peek(Keylet const &k)=0
Prepare to modify the SLE associated with key.
virtual void update(SLE::Ref sle)=0
Indicate changes to a peeked SLE.
constexpr TIss const & get() const
AccountID const & getIssuer() const
Presents and consumes the offers in an order book.
void permRmOffer(UInt256 const &offerIndex) override
boost::container::flat_set< UInt256 > permToRemove_
std::chrono::time_point< NetClock > time_point
std::chrono::duration< rep, period > duration
Number is a floating point type that can represent a wide range of values.
Represents the logical ratio of output currency to input currency.
std::shared_ptr< STLedgerEntry > pointer
std::optional< TOut > ownerFunds_
virtual void permRmOffer(UInt256 const &offerIndex)=0
TOfferStreamBase(ApplyView &view, ApplyView &cancelView, Book const &book, NetClock::time_point when, StepCounter &counter, beast::Journal journal)
bool shouldRmSmallIncreasedQOffer() const
NetClock::time_point const expire_
TOffer< TIn, TOut > offer_
bool step()
Advance to the next valid offer.
void erase(ApplyView &view)
Keylet book(Book const &b)
The beginning of an order book.
Keylet page(UInt256 const &root, std::uint64_t const index=0) noexcept
A page in a directory.
Keylet account(AccountID const &id) noexcept
AccountID root.
bool offerInDomain(ReadView const &view, UInt256 const &offerID, Domain const &domainID, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
static T accountFundsHelper(ReadView const &view, AccountID const &id, T const &amtDefault, Asset const &asset, FreezeHandling freezeHandling, AuthHandling authHandling, beast::Journal j)
FreezeHandling
Controls the treatment of frozen account balances.
bool isXRP(AccountID const &c)
bool isDeepFrozen(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer)
T toAmount(STAmount const &amt)=delete
AuthHandling
Controls the treatment of unauthorized MPT balances.
BaseUInt< 160, detail::AccountIDTag > AccountID
A 160-bit unsigned that uniquely identifies an account.
void erase(STObject &st, TypedField< U > const &f)
Remove a field in an STObject.
STAmount issuerFundsToSelfIssue(ReadView const &view, MPTIssue const &issue)
Determine funds available for an issuer to sell in an issuer owned offer.
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const ¤cy, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=SpendableHandling::SimpleBalance)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Represents a pair of input and output currencies.