20#include <xrpld/app/misc/AMMUtils.h>
21#include <xrpld/app/paths/AMMLiquidity.h>
22#include <xrpld/app/paths/AMMOffer.h>
23#include <xrpld/app/paths/detail/FlatSets.h>
24#include <xrpld/app/paths/detail/Steps.h>
25#include <xrpld/app/tx/detail/OfferStream.h>
26#include <xrpld/ledger/PaymentSandbox.h>
27#include <xrpl/basics/Log.h>
28#include <xrpl/basics/contract.h>
29#include <xrpl/beast/utility/instrumentation.h>
30#include <xrpl/protocol/Book.h>
31#include <xrpl/protocol/Feature.h>
32#include <xrpl/protocol/IOUAmount.h>
33#include <xrpl/protocol/Quality.h>
34#include <xrpl/protocol/XRPAmount.h>
36#include <boost/container/flat_set.hpp>
43template <
class TIn,
class TOut,
class TDerived>
44class BookStep :
public StepImp<TIn, TOut, BookStep<TIn, TOut, TDerived>>
77 Cache(TIn
const& in_, TOut
const& out_) :
in(in_),
out(out_)
103 ammSle && ammSle->getFieldAmount(sfLPTokenBalance) != beast::zero)
106 (*ammSle)[sfAccount],
163 boost::container::flat_set<uint256>& ofrsToRm,
170 boost::container::flat_set<uint256>& ofrsToRm,
209 return !(lhs == rhs);
220 template <
class Callback>
226 Callback& callback)
const;
229 template <
template <
typename,
typename>
typename Offer>
234 TAmounts<TIn, TOut>
const& ofrAmt,
235 TAmounts<TIn, TOut>
const& stepAmt,
236 TOut
const& ownerGives)
const;
269template <
class TIn,
class TOut>
280 template <
template <
typename,
typename>
typename Offer>
367template <
class TIn,
class TOut>
369 :
public BookStep<TIn, TOut, BookOfferCrossingStep<TIn, TOut>>
385 "ripple::BookOfferCrossingStep::getQuality : nonzero quality");
387 Throw<FlowException>(
tefINTERNAL,
"Offer requires quality.");
388 return *limitQuality;
402 template <
template <
typename,
typename>
typename Offer>
410 bool const offerAttempted)
const
442 strandSrc == offer.owner() && strandDst == offer.owner())
445 if (
auto const key = offer.
key())
446 offers.permRmOffer(*key);
490 Step const* prevStep,
497 return owner == srcAcct
505 Step const* prevStep,
524 Rules const& rules)
const
536 if (!rules.
enabled(fixAMMv1_1))
539 offerType == OfferType::CLOB ||
571template <
class TIn,
class TOut,
class TDerived>
576 return book_ == bs->book_;
580template <
class TIn,
class TOut,
class TDerived>
590 return {std::nullopt, dir};
592 auto const waiveFee = (std::get<OfferType>(*res) == OfferType::AMM)
596 Quality
const q =
static_cast<TDerived const*
>(
this)->adjustQualityWithFees(
598 std::get<Quality>(*res),
601 std::get<OfferType>(*res),
606template <
class TIn,
class TOut,
class TDerived>
616 return {std::nullopt, dir};
623 static_cast<TDerived const*
>(
this)->adjustQualityWithFees(
638 Quality
const q =
static_cast<TDerived const*
>(
this)->adjustQualityWithFees(
648template <
class TIn,
class TOut,
class TDerived>
656template <
class TIn,
class TOut,
class Offer>
660 TAmounts<TIn, TOut>& ofrAmt,
661 TAmounts<TIn, TOut>& stpAmt,
667 if (limit < stpAmt.in)
671 mulRatio(stpAmt.in, QUALITY_ONE, transferRateIn,
false);
679 ofrAmt = offer.limitIn(ofrAmt, inLmt,
false);
680 stpAmt.out = ofrAmt.out;
682 ofrAmt.out, transferRateOut, QUALITY_ONE,
false);
687template <
class TIn,
class TOut,
class Offer>
691 TAmounts<TIn, TOut>& ofrAmt,
692 TAmounts<TIn, TOut>& stpAmt,
698 if (limit < stpAmt.out)
702 stpAmt.out, transferRateOut, QUALITY_ONE,
false);
703 ofrAmt = offer.limitOut(
708 mulRatio(ofrAmt.in, transferRateIn, QUALITY_ONE,
true);
712template <
class TIn,
class TOut,
class TDerived>
713template <
class Callback>
719 Callback& callback)
const
727 if (
isXRP(
id) ||
id == this->strandDst_)
733 redeems(prevStepDir) ? rate(book_.in.account) : QUALITY_ONE;
736 ownerPaysTransferFee_ ? rate(book_.out.account) : QUALITY_ONE;
739 maxOffersToConsume_, j_);
744 bool const flowCross = afView.
rules().
enabled(featureFlowCross);
745 bool offerAttempted =
false;
747 auto execOffer = [&](
auto& offer) {
751 ofrQ = offer.quality();
752 else if (*ofrQ != offer.quality())
755 if (
static_cast<TDerived const*
>(
this)->limitSelfCrossQuality(
756 strandSrc_, strandDst_, offer, ofrQ, offers, offerAttempted))
761 if (flowCross && (!
isXRP(offer.issueIn().currency)) &&
762 (offer.owner() != offer.issueIn().account))
764 auto const& issuerID = offer.issueIn().account;
769 auto const& ownerID = offer.owner();
770 auto const authFlag =
773 auto const line = afView.
read(
774 keylet::line(ownerID, issuerID, offer.issueIn().currency));
776 if (!line || (((*line)[sfFlags] & authFlag) == 0))
780 if (
auto const key = offer.
key())
781 offers.permRmOffer(*key);
791 if (!
static_cast<TDerived const*
>(
this)->checkQualityThreshold(
795 auto const [ofrInRate, ofrOutRate] = offer.adjustRates(
796 static_cast<TDerived const*
>(
this)->getOfrInRate(
797 prevStep_, offer.owner(), trIn),
798 static_cast<TDerived const*
>(
this)->getOfrOutRate(
799 prevStep_, offer.owner(), strandDst_, trOut));
801 auto ofrAmt = offer.amount();
803 mulRatio(ofrAmt.in, ofrInRate, QUALITY_ONE,
true),
808 mulRatio(ofrAmt.out, ofrOutRate, QUALITY_ONE,
false);
810 auto const funds = offer.isFunded()
812 : offers.ownerFunds();
815 if (funds < ownerGives)
820 ownerGives, QUALITY_ONE, ofrOutRate,
false);
825 ofrAmt = offer.limitOut(ofrAmt, stpAmt.out,
false);
828 mulRatio(ofrAmt.in, ofrInRate, QUALITY_ONE,
true);
831 offerAttempted =
true;
833 offer, ofrAmt, stpAmt, ownerGives, ofrInRate, ofrOutRate);
842 return static_cast<TDerived const*
>(
this)->qualityThreshold(
846 auto ammOffer = getAMMOffer(sb, qualityThreshold);
847 return !ammOffer || execOffer(*ammOffer);
852 if (tryAMM(offers.tip().quality()))
856 if (!execOffer(offers.tip()))
858 }
while (offers.step());
864 tryAMM(std::nullopt);
867 return {offers.permToRemove(), counter.
count()};
870template <
class TIn,
class TOut,
class TDerived>
871template <
template <
typename,
typename>
typename Offer>
876 TAmounts<TIn, TOut>
const& ofrAmt,
877 TAmounts<TIn, TOut>
const& stepAmt,
878 TOut
const& ownerGives)
const
880 if (!offer.checkInvariant(ofrAmt, j_))
886 Throw<FlowException>(
894 auto const dr = offer.send(
901 Throw<FlowException>(dr);
907 auto const cr = offer.send(
914 Throw<FlowException>(cr);
917 offer.consume(sb, ofrAmt);
920template <
class TIn,
class TOut,
class TDerived>
927 return ammLiquidity_->getOffer(view, clobQuality);
931template <
class TIn,
class TOut,
class TDerived>
938 auto const lobQuality =
959 return static_cast<TDerived const*
>(
this)->qualityThreshold(
964 if (
auto const ammOffer = getAMMOffer(view, qualityThreshold); ammOffer &&
965 ((lobQuality && ammOffer->quality() > lobQuality) || !lobQuality))
971template <
class TIn,
class TOut,
class TDerived>
976 if (
auto const res = tip(view); !res)
978 else if (
auto const q = std::get_if<Quality>(&(*res)))
985template <
class TIn,
class TOut,
class TDerived>
989 if (
auto const res = tip(view); !res)
991 else if (
auto const q = std::get_if<Quality>(&(*res)))
994 return std::get<AMMOffer<TIn, TOut>>(*res).getQualityFunc();
997template <
class TCollection>
999sum(TCollection
const& col)
1003 return TResult{beast::zero};
1007template <
class TIn,
class TOut,
class TDerived>
1012 boost::container::flat_set<uint256>& ofrsToRm,
1017 TAmounts<TIn, TOut> result(beast::zero, beast::zero);
1019 auto remainingOut =
out;
1021 boost::container::flat_multiset<TIn> savedIns;
1022 savedIns.reserve(64);
1023 boost::container::flat_multiset<TOut> savedOuts;
1024 savedOuts.reserve(64);
1030 auto eachOffer = [&](
auto& offer,
1031 TAmounts<TIn, TOut>
const& ofrAmt,
1032 TAmounts<TIn, TOut>
const& stpAmt,
1033 TOut
const& ownerGives,
1036 if (remainingOut <= beast::zero)
1039 if (stpAmt.out <= remainingOut)
1041 savedIns.insert(stpAmt.in);
1042 savedOuts.insert(stpAmt.out);
1043 result = TAmounts<TIn, TOut>(
sum(savedIns),
sum(savedOuts));
1044 remainingOut =
out - result.out;
1045 this->consumeOffer(sb, offer, ofrAmt, stpAmt, ownerGives);
1052 auto ofrAdjAmt = ofrAmt;
1053 auto stpAdjAmt = stpAmt;
1054 auto ownerGivesAdj = ownerGives;
1063 remainingOut = beast::zero;
1064 savedIns.insert(stpAdjAmt.in);
1065 savedOuts.insert(remainingOut);
1066 result.in =
sum(savedIns);
1068 this->consumeOffer(sb, offer, ofrAdjAmt, stpAdjAmt, ownerGivesAdj);
1075 return offer.fully_consumed();
1080 auto const prevStepDebtDir = [&] {
1085 auto const r = forEachOffer(sb, afView, prevStepDebtDir, eachOffer);
1086 boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r));
1088 offersUsed_ = offersConsumed;
1091 if (offersConsumed >= maxOffersToConsume_)
1097 cache_.emplace(beast::zero, beast::zero);
1098 return {beast::zero, beast::zero};
1107 switch (remainingOut.signum())
1112 <<
"BookStep remainingOut < 0 " <<
to_string(remainingOut);
1113 UNREACHABLE(
"ripple::BookStep::revImp : remaining less than zero");
1114 cache_.emplace(beast::zero, beast::zero);
1115 return {beast::zero, beast::zero};
1124 cache_.emplace(result.in, result.out);
1125 return {result.in, result.out};
1128template <
class TIn,
class TOut,
class TDerived>
1133 boost::container::flat_set<uint256>& ofrsToRm,
1136 XRPL_ASSERT(cache_,
"ripple::BookStep::fwdImp : cache is set");
1138 TAmounts<TIn, TOut> result(beast::zero, beast::zero);
1140 auto remainingIn =
in;
1142 boost::container::flat_multiset<TIn> savedIns;
1143 savedIns.reserve(64);
1144 boost::container::flat_multiset<TOut> savedOuts;
1145 savedOuts.reserve(64);
1149 auto eachOffer = [&](
auto& offer,
1150 TAmounts<TIn, TOut>
const& ofrAmt,
1151 TAmounts<TIn, TOut>
const& stpAmt,
1152 TOut
const& ownerGives,
1156 cache_,
"ripple::BookStep::fwdImp::eachOffer : cache is set");
1158 if (remainingIn <= beast::zero)
1161 bool processMore =
true;
1162 auto ofrAdjAmt = ofrAmt;
1163 auto stpAdjAmt = stpAmt;
1164 auto ownerGivesAdj = ownerGives;
1166 typename boost::container::flat_multiset<TOut>::const_iterator lastOut;
1167 if (stpAmt.in <= remainingIn)
1169 savedIns.insert(stpAmt.in);
1170 lastOut = savedOuts.insert(stpAmt.out);
1171 result = TAmounts<TIn, TOut>(
sum(savedIns),
sum(savedOuts));
1185 savedIns.insert(remainingIn);
1186 lastOut = savedOuts.insert(stpAdjAmt.out);
1187 result.out =
sum(savedOuts);
1190 processMore =
false;
1193 if (result.out > cache_->out && result.in <= cache_->in)
1202 auto const lastOutAmt = *lastOut;
1203 savedOuts.erase(lastOut);
1204 auto const remainingOut = cache_->out -
sum(savedOuts);
1205 auto ofrAdjAmtRev = ofrAmt;
1206 auto stpAdjAmtRev = stpAmt;
1207 auto ownerGivesAdjRev = ownerGives;
1217 if (stpAdjAmtRev.in == remainingIn)
1220 result.out = cache_->out;
1223 savedIns.insert(result.in);
1225 savedOuts.insert(result.out);
1227 ofrAdjAmt = ofrAdjAmtRev;
1228 stpAdjAmt.in = remainingIn;
1229 stpAdjAmt.out = remainingOut;
1230 ownerGivesAdj = ownerGivesAdjRev;
1236 savedOuts.insert(lastOutAmt);
1240 remainingIn =
in - result.in;
1241 this->consumeOffer(sb, offer, ofrAdjAmt, stpAdjAmt, ownerGivesAdj);
1247 return processMore || offer.fully_consumed();
1251 auto const prevStepDebtDir = [&] {
1256 auto const r = forEachOffer(sb, afView, prevStepDebtDir, eachOffer);
1257 boost::container::flat_set<uint256> toRm = std::move(std::get<0>(r));
1259 offersUsed_ = offersConsumed;
1262 if (offersConsumed >= maxOffersToConsume_)
1268 cache_.emplace(beast::zero, beast::zero);
1269 return {beast::zero, beast::zero};
1278 switch (remainingIn.signum())
1283 <<
"BookStep remainingIn < 0 " <<
to_string(remainingIn);
1284 UNREACHABLE(
"ripple::BookStep::fwdImp : remaining less than zero");
1285 cache_.emplace(beast::zero, beast::zero);
1286 return {beast::zero, beast::zero};
1295 cache_.emplace(result.in, result.out);
1296 return {result.in, result.out};
1299template <
class TIn,
class TOut,
class TDerived>
1308 JLOG(j_.
trace()) <<
"Expected valid cache in validFwd";
1312 auto const savCache = *cache_;
1316 boost::container::flat_set<uint256> dummy;
1317 fwdImp(sb, afView, dummy, get<TIn>(
in));
1319 catch (FlowException
const&)
1324 if (!(
checkNear(savCache.in, cache_->in) &&
1327 JLOG(j_.
warn()) <<
"Strand re-execute check failed."
1328 <<
" ExpectedIn: " <<
to_string(savCache.in)
1329 <<
" CachedIn: " <<
to_string(cache_->in)
1330 <<
" ExpectedOut: " <<
to_string(savCache.out)
1331 <<
" CachedOut: " <<
to_string(cache_->out);
1337template <
class TIn,
class TOut,
class TDerived>
1341 if (book_.in == book_.out)
1343 JLOG(j_.
debug()) <<
"BookStep: Book with same in and out issuer "
1349 JLOG(j_.
debug()) <<
"Book: currency is inconsistent with issuer."
1359 JLOG(j_.
debug()) <<
"BookStep: loop detected: " << *
this;
1365 JLOG(j_.
debug()) <<
"BookStep: loop detected: " << *
this;
1369 auto issuerExists = [](
ReadView const& view,
Issue const& iss) ->
bool {
1373 if (!issuerExists(ctx.
view, book_.in) || !issuerExists(ctx.
view, book_.out))
1375 JLOG(j_.
debug()) <<
"BookStep: deleted issuer detected: " << *
this;
1383 auto const& view = ctx.
view;
1384 auto const& cur = book_.in.account;
1389 if ((*sle)[sfFlags] &
1403template <
class TIn,
class TOut,
class TDerived>
1408 return book == bs->book();
1417 if (inXRP && outXRP)
1419 UNREACHABLE(
"ripple::test::bookStepEqual : no XRP to XRP book step");
1422 if (inXRP && !outXRP)
1427 if (!inXRP && outXRP)
1432 if (!inXRP && !outXRP)
1443template <
class TIn,
class TOut>
1451 auto offerCrossingStep =
1452 std::make_unique<BookOfferCrossingStep<TIn, TOut>>(ctx,
in,
out);
1453 ter = offerCrossingStep->check(ctx);
1454 r = std::move(offerCrossingStep);
1459 std::make_unique<BookPaymentStep<TIn, TOut>>(ctx,
in,
out);
1460 ter = paymentStep->check(ctx);
1461 r = std::move(paymentStep);
1464 return {ter,
nullptr};
1472 return make_BookStepHelper<IOUAmount, IOUAmount>(ctx,
in,
out);
1478 return make_BookStepHelper<IOUAmount, XRPAmount>(ctx,
in,
xrpIssue());
1484 return make_BookStepHelper<XRPAmount, IOUAmount>(ctx,
xrpIssue(),
out);
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
AccountID account() const
Represents synthetic AMM offer in BookStep.
Quality quality() const noexcept
Writeable view to a ledger, for applying a transaction.
std::uint32_t getOfrInRate(Step const *prevStep, AccountID const &owner, std::uint32_t trIn) const
static Quality getQuality(std::optional< Quality > const &limitQuality)
BookOfferCrossingStep(StrandContext const &ctx, Issue const &in, Issue const &out)
bool checkQualityThreshold(Quality const &quality) const
std::string logString() const override
std::uint32_t getOfrOutRate(Step const *prevStep, AccountID const &owner, AccountID const &strandDst, std::uint32_t trOut) const
bool limitSelfCrossQuality(AccountID const &strandSrc, AccountID const &strandDst, Offer< TIn, TOut > const &offer, std::optional< Quality > &ofrQ, FlowOfferStream< TIn, TOut > &offers, bool const offerAttempted) const
Quality const qualityThreshold_
std::optional< Quality > qualityThreshold(Quality const &lobQuality) const
Quality adjustQualityWithFees(ReadView const &v, Quality const &ofrQ, DebtDirection prevStepDir, WaiveTransferFee waiveFee, OfferType offerType, Rules const &rules) const
bool limitSelfCrossQuality(AccountID const &, AccountID const &, Offer< TIn, TOut > const &offer, std::optional< Quality > &, FlowOfferStream< TIn, TOut > &, bool) const
Quality adjustQualityWithFees(ReadView const &v, Quality const &ofrQ, DebtDirection prevStepDir, WaiveTransferFee waiveFee, OfferType, Rules const &) const
std::uint32_t getOfrOutRate(Step const *, AccountID const &, AccountID const &, std::uint32_t trOut) const
BookPaymentStep()=default
std::uint32_t getOfrInRate(Step const *, AccountID const &, std::uint32_t trIn) const
bool checkQualityThreshold(Quality const &quality) const
std::optional< Quality > qualityThreshold(Quality const &lobQuality) const
std::string logString() const override
std::optional< AMMOffer< TIn, TOut > > getAMMOffer(ReadView const &view, std::optional< Quality > const &clobQuality) const
std::optional< AMMLiquidity< TIn, TOut > > ammLiquidity_
friend bool operator==(BookStep const &lhs, BookStep const &rhs)
std::uint32_t offersUsed() const override
std::optional< Book > bookStepBook() const override
std::uint32_t offersUsed_
Number of offers consumed or partially consumed the last time the step ran, including expired and unf...
std::optional< EitherAmount > cachedOut() const override
std::optional< std::pair< Quality, OfferType > > tipOfferQuality(ReadView const &view) const
void consumeOffer(PaymentSandbox &sb, Offer< TIn, TOut > &offer, TAmounts< TIn, TOut > const &ofrAmt, TAmounts< TIn, TOut > const &stepAmt, TOut const &ownerGives) const
std::pair< std::optional< QualityFunction >, DebtDirection > getQualityFunc(ReadView const &v, DebtDirection prevStepDir) const override
TER check(StrandContext const &ctx) const
std::pair< boost::container::flat_set< uint256 >, std::uint32_t > forEachOffer(PaymentSandbox &sb, ApplyView &afView, DebtDirection prevStepDebtDir, Callback &callback) const
std::pair< bool, EitherAmount > validFwd(PaymentSandbox &sb, ApplyView &afView, EitherAmount const &in) override
Book const & book() const
std::optional< EitherAmount > cachedIn() const override
uint32_t const maxOffersToConsume_
bool equal(Step const &rhs) const override
DebtDirection debtDirection(ReadView const &sb, StrandDirection dir) const override
std::pair< TIn, TOut > revImp(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, TOut const &out)
Step const *const prevStep_
friend bool operator!=(BookStep const &lhs, BookStep const &rhs)
std::string logStringImpl(char const *name) const
BookStep(StrandContext const &ctx, Issue const &in, Issue const &out)
std::pair< TIn, TOut > fwdImp(PaymentSandbox &sb, ApplyView &afView, boost::container::flat_set< uint256 > &ofrsToRm, TIn const &in)
std::optional< QualityFunction > tipOfferQualityF(ReadView const &view) const
bool inactive() const override
static uint32_t getMaxOffersToConsume(StrandContext const &ctx)
std::optional< std::variant< Quality, AMMOffer< TIn, TOut > > > tip(ReadView const &view) const
std::pair< std::optional< Quality >, DebtDirection > qualityUpperBound(ReadView const &v, DebtDirection prevStepDir) const override
bool const ownerPaysTransferFee_
std::optional< Cache > cache_
Iterates and consumes raw offers in an order book.
bool step(beast::Journal j)
Erases the current offer and advance to the next offer.
Quality const & quality() const noexcept
Presents and consumes the offers in an order book.
Floating point representation of amounts with high dynamic range.
A currency issued by an account.
A wrapper which makes credits unavailable to balances.
Average quality of a path as a function of out: q(out) = m * out + b, where m = -1 / poolGets,...
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
virtual Rules const & rules() const =0
Returns the tx processing rules.
Rules controlling protocol behavior.
bool enabled(uint256 const &feature) const
Returns true if a feature is enabled.
static std::uint64_t const uRateOne
Discardable, editable view to a ledger.
A step in a payment path.
virtual std::optional< Book > bookStepBook() const
If this step is a BookStep, return the book.
virtual std::optional< AccountID > directStepSrcAcct() const
If this step is DirectStepI (IOU->IOU direct step), return the src account.
std::uint32_t count() const
Rules const & rules() const override
Returns the tx processing rules.
Keylet amm(Asset const &issue1, Asset const &issue2) noexcept
AMM entry.
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.
static bool equalHelper(Step const &step, ripple::Book const &book)
bool bookStepEqual(Step const &step, ripple::Book const &book)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
static auto sum(TCollection const &col)
bool isConsistent(Book const &book)
bool isXRP(AccountID const &c)
static void limitStepIn(Offer const &offer, TAmounts< TIn, TOut > &ofrAmt, TAmounts< TIn, TOut > &stpAmt, TOut &ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut, TIn const &limit)
std::uint16_t getTradingFee(ReadView const &view, SLE const &ammSle, AccountID const &account)
Get AMM trading fee for the given account.
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
STAmount toSTAmount(IOUAmount const &iou, Issue const &iss)
static bool isDefaultPath(STPath const &path)
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Quality composed_quality(Quality const &lhs, Quality const &rhs)
void SetUnion(boost::container::flat_set< T > &dst, boost::container::flat_set< T > const &src)
Given two flat sets dst and src, compute dst = dst union src.
std::pair< TER, std::unique_ptr< Step > > make_BookStepXI(StrandContext const &ctx, Issue const &out)
std::pair< TER, std::unique_ptr< Step > > make_BookStepIX(StrandContext const &ctx, Issue const &in)
bool checkNear(IOUAmount const &expected, IOUAmount const &actual)
static void limitStepOut(Offer const &offer, TAmounts< TIn, TOut > &ofrAmt, TAmounts< TIn, TOut > &stpAmt, TOut &ownerGives, std::uint32_t transferRateIn, std::uint32_t transferRateOut, TOut const &limit)
static std::pair< TER, std::unique_ptr< Step > > make_BookStepHelper(StrandContext const &ctx, Issue const &in, Issue const &out)
std::pair< TER, std::unique_ptr< Step > > make_BookStepII(StrandContext const &ctx, Issue const &in, Issue const &out)
IOUAmount mulRatio(IOUAmount const &amt, std::uint32_t num, std::uint32_t den, bool roundUp)
std::string to_string(base_uint< Bits, Tag > const &a)
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
Cache(TIn const &in_, TOut const &out_)
Context needed to build Strand Steps and for error checking.
boost::container::flat_set< Issue > & seenBookOuts
A strand may not include an offer that output the same issue more than once.
ReadView const & view
Current ReadView.
std::array< boost::container::flat_set< Issue >, 2 > & seenDirectIssues
A strand may not include the same account node more than once in the same currency.
Step const *const prevStep
The previous step in the strand.
OfferCrossing const offerCrossing
Yes/Sell if offer crossing, not payment.