20#include <xrpld/app/tx/detail/Taker.h>
22#include <xrpl/basics/Log.h>
23#include <xrpl/basics/contract.h>
39 Amounts
const& amount,
40 Quality
const& quality,
47 , threshold_(quality_)
51 , issue_in_(remaining_.
in.issue())
52 , issue_out_(remaining_.
out.issue())
54 , m_rate_out(rate_out)
55 , cross_type_(cross_type)
60 "ripple::BasicTaker::BasicTaker : positive remaining in");
63 "ripple::BasicTaker::BasicTaker : positive remaining out");
66 m_rate_in.
value,
"ripple::BasicTaker::BasicTaker : nonzero rate in");
75 "ripple::BasicTaker::BasicTaker : valid cross to IOU");
80 "ripple::BasicTaker::BasicTaker : valid cross to XRP");
85 "ripple::BasicTaker::BasicTaker : not crossing XRP for XRP");
118 JLOG(
journal_.
debug()) <<
"Unfunded: taker is out of funds.";
129 <<
"Done: all the input currency has been consumed.";
137 JLOG(
journal_.
debug()) <<
"Done: the desired amount has been received.";
166 "ripple::BasicTaker::remaining_offer : positive remaining in");
176 "ripple::BasicTaker::remaining_offer : positive remaining out");
195 auto result =
divide(amount, quality.rate(), output.
issue());
202 auto result =
multiply(amount, quality.rate(), output.
issue());
213 stream << description;
230 Amounts
const& order,
234 Rate const& rate_out)
243 if (owner_funds < f.
issuers.out)
248 log_flow(
"(clamped on owner balance)", f);
257 log_flow(
"(clamped on taker output)", f);
261 if (taker_funds < f.
order.in)
263 f.
order.in = taker_funds;
266 log_flow(
"(clamped on taker funds)", f);
276 log_flow(
"(clamped on taker input)", f);
284 Amounts
const& order,
297 if (owner_funds < f.
order.out)
299 f.
order.out = owner_funds;
302 log_flow(
"(clamped on owner funds)", f);
314 log_flow(
"(clamped on taker output)", f);
324 log_flow(
"(clamped on taker input)", f);
328 if (taker_funds < f.
issuers.in)
333 log_flow(
"(clamped on taker funds)", f);
341 Amounts
const& order,
346 Rate const& rate_out)
356 if (owner_funds < f.
issuers.out)
362 log_flow(
"(clamped on owner funds)", f);
372 log_flow(
"(clamped on taker output)", f);
382 log_flow(
"(clamped on taker input)", f);
386 if (taker_funds < f.
issuers.in)
392 log_flow(
"(clamped on taker funds)", f);
402 auto const owner_funds =
get_funds(owner, offer.out);
437 Throw<std::logic_error>(
"Computed flow fails sanity check.");
444 "ripple::BasicTaker::do_cross : minimum remaining in");
461 "ripple::BasicTaker::do_cross : offer1 in is not XRP");
464 "ripple::BasicTaker::do_cross : offer1 out is XRP");
466 offer2.in.native(),
"ripple::BasicTaker::do_cross : offer2 in is XRP");
468 !offer2.out.native(),
469 "ripple::BasicTaker::do_cross : offer2 out is not XRP");
477 JLOG(
journal_.
trace()) <<
"The taker owns the first leg of a bridge.";
478 leg1_in_funds =
std::max(leg1_in_funds, offer1.in);
483 auto leg2_out_funds =
get_funds(owner2, offer2.out);
487 JLOG(
journal_.
trace()) <<
"The taker owns the second leg of a bridge.";
488 leg2_out_funds =
std::max(leg2_out_funds, offer2.out);
499 auto xrp_funds =
get_funds(owner1, offer1.out);
501 if (owner1 == owner2)
504 <<
"The bridge endpoints are owned by the same account.";
505 xrp_funds =
std::max(offer1.out, offer2.in);
510 stream <<
"Available bridge funds:";
522 flow_iou_to_xrp(offer1, quality1, xrp_funds, leg1_in_funds, leg1_rate);
524 if (!flow1.sanity_check())
525 Throw<std::logic_error>(
"Computed flow1 fails sanity check.");
528 flow_xrp_to_iou(offer2, quality2, leg2_out_funds, xrp_funds, leg2_rate);
530 if (!flow2.sanity_check())
531 Throw<std::logic_error>(
"Computed flow2 fails sanity check.");
537 if (flow1.order.out < flow2.order.in)
540 flow2.order.in = flow1.order.out;
541 flow2.order.out =
qual_div(flow2.order.in, quality2, flow2.order.out);
542 flow2.issuers.out =
multiply(flow2.order.out, leg2_rate);
543 log_flow(
"Balancing: adjusted second leg down", flow2);
545 else if (flow1.order.out > flow2.order.in)
548 flow1.order.out = flow2.order.in;
549 flow1.order.in =
qual_mul(flow1.order.out, quality1, flow1.order.in);
550 flow1.issuers.in =
multiply(flow1.order.in, leg1_rate);
551 log_flow(
"Balancing: adjusted first leg down", flow2);
554 if (flow1.order.out != flow2.order.in)
555 Throw<std::logic_error>(
"Bridged flow is out of balance.");
569 Amounts
const& offer,
578 calculateRate(view, offer.
in.getIssuer(), account),
579 calculateRate(view, offer.
out.getIssuer(), account),
583 , direct_crossings_(0)
584 , bridge_crossings_(0)
588 "ripple::Taker::Taker : issue in is a match");
591 "ripple::Taker::Taker : issue out is a match");
609 stream <<
" Balance: "
617 if (order.in < beast::zero)
618 Throw<std::logic_error>(
"flow with negative input.");
620 if (order.out < beast::zero)
621 Throw<std::logic_error>(
"flow with negative output.");
633 offer.consume(
view_, order);
649 Throw<std::logic_error>(
"Using transferXRP with IOU");
655 if (amount == beast::zero)
668 Throw<std::logic_error>(
"Using redeemIOU with XRP");
674 if (amount == beast::zero)
680 Throw<std::logic_error>(
"redeemIOU has no funds to redeem");
685 Throw<std::logic_error>(
"redeemIOU redeemed more funds than available");
697 Throw<std::logic_error>(
"Using issueIOU with XRP");
703 if (amount == beast::zero)
721 !
isXRP(
flow.order.in),
"ripple::Taker::fill : order in is not XRP");
734 isXRP(
flow.order.in),
"ripple::Taker::fill : order in is XRP");
745 "ripple::Taker::fill : order out is not XRP");
749 offer.owner(),
flow.issuers.out,
flow.issuers.out.issue());
758 isXRP(
flow.order.out),
"ripple::Taker::fill : order out is XRP");
825 if (
isXRP(offer.amount().in) &&
isXRP(offer.amount().out))
829 do_cross(offer.amount(), offer.quality(), offer.owner());
831 return fill(amount, offer);
850 return fill(ret.first, leg1, ret.second, leg2);
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
Writeable view to a ledger, for applying a transaction.
State for the active party during order book or payment operations.
Flow flow_iou_to_iou(Amounts const &offer, Quality quality, STAmount const &owner_funds, STAmount const &taker_funds, Rate const &rate_in, Rate const &rate_out)
bool done() const
Returns true if order crossing should not continue.
Rate in_rate(AccountID const &from, AccountID const &to) const
Flow flow_iou_to_xrp(Amounts const &offer, Quality quality, STAmount const &owner_funds, STAmount const &taker_funds, Rate const &rate_in)
Flow flow_xrp_to_iou(Amounts const &offer, Quality quality, STAmount const &owner_funds, STAmount const &taker_funds, Rate const &rate_out)
beast::Journal const journal_
CrossType cross_type() const
Returns the type of crossing that is being performed.
AccountID const & account() const noexcept
Returns the account identifier of the taker.
void log_flow(char const *description, Flow const &flow)
Issue const & issue_in() const
Returns the Issue associated with the input of the offer.
Amounts remaining_offer() const
Returns the amount remaining on the offer.
Rate out_rate(AccountID const &from, AccountID const &to) const
Amounts const & original_offer() const
Returns the amount that the offer was originally placed at.
Issue const & issue_out() const
Returns the Issue associated with the output of the offer.
virtual STAmount get_funds(AccountID const &account, STAmount const &funds) const =0
static Rate effective_rate(Rate const &rate, Issue const &issue, AccountID const &from, AccountID const &to)
BasicTaker::Flow do_cross(Amounts offer, Quality quality, AccountID const &owner)
Perform direct crossing through given offer.
bool unfunded() const
Returns true if the taker has run out of funds.
A currency issued by an account.
std::string getText() const override
Issue const & issue() const
Quality quality() const noexcept
Returns the quality of the offer.
AccountID const & owner() const
Returns the account id of the offer's owner.
TAmounts< TIn, TOut > const & amount() const
Returns the in and out amounts.
STAmount get_funds(AccountID const &account, STAmount const &funds) const override
TER issueIOU(AccountID const &account, STAmount const &amount, Issue const &issue)
static Rate calculateRate(ApplyView const &view, AccountID const &issuer, AccountID const &account)
std::uint32_t direct_crossings_
TER redeemIOU(AccountID const &account, STAmount const &amount, Issue const &issue)
std::uint32_t bridge_crossings_
TER fill(BasicTaker::Flow const &flow, Offer &offer)
TER transferXRP(AccountID const &from, AccountID const &to, STAmount const &amount)
void consume_offer(Offer &offer, Amounts const &order)
TER cross(Offer &offer)
Perform a direct or bridged offer crossing as appropriate.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
STAmount divide(STAmount const &amount, Rate const &rate)
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
bool isXRP(AccountID const &c)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
STAmount multiply(STAmount const &amount, Rate const &rate)
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
StrandResult< TInAmt, TOutAmt > flow(PaymentSandbox const &baseView, Strand const &strand, std::optional< TInAmt > const &maxIn, TOutAmt const &out, beast::Journal j)
Request out amount from a strand.
constexpr std::uint32_t tfPassive
static STAmount qual_mul(STAmount const &amount, Quality const &quality, STAmount const &output)
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
static std::string format_amount(STAmount const &amount)
static STAmount qual_div(STAmount const &amount, Quality const &quality, STAmount const &output)
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
std::string to_string(base_uint< Bits, Tag > const &a)
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr std::uint32_t tfSell
CrossType
The flavor of an offer crossing.
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
bool sanity_check() const
Represents a transfer rate.