rippled
Taker.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/tx/impl/Taker.h>
21 #include <ripple/basics/contract.h>
22 #include <ripple/basics/Log.h>
23 
24 namespace ripple {
25 
26 static
28 format_amount (STAmount const& amount)
29 {
30  std::string txt = amount.getText ();
31  txt += "/";
32  txt += to_string (amount.issue().currency);
33  return txt;
34 }
35 
37  CrossType cross_type, AccountID const& account, Amounts const& amount,
38  Quality const& quality, std::uint32_t flags, Rate const& rate_in,
39  Rate const& rate_out, beast::Journal journal)
40  : account_ (account)
41  , quality_ (quality)
42  , threshold_ (quality_)
43  , sell_ (flags & tfSell)
44  , original_ (amount)
45  , remaining_ (amount)
46  , issue_in_ (remaining_.in.issue ())
47  , issue_out_ (remaining_.out.issue ())
48  , m_rate_in (rate_in)
49  , m_rate_out (rate_out)
50  , cross_type_ (cross_type)
51  , journal_ (journal)
52 {
53  assert (remaining_.in > beast::zero);
54  assert (remaining_.out > beast::zero);
55 
56  assert (m_rate_in.value != 0);
57  assert (m_rate_out.value != 0);
58 
59  // If we are dealing with a particular flavor, make sure that it's the
60  // flavor we expect:
61  assert (cross_type != CrossType::XrpToIou ||
62  (isXRP (issue_in ()) && !isXRP (issue_out ())));
63 
64  assert (cross_type != CrossType::IouToXrp ||
65  (!isXRP (issue_in ()) && isXRP (issue_out ())));
66 
67  // And make sure we're not crossing XRP for XRP
68  assert (!isXRP (issue_in ()) || !isXRP (issue_out ()));
69 
70  // If this is a passive order, we adjust the quality so as to prevent offers
71  // at the same quality level from being consumed.
72  if (flags & tfPassive)
73  ++threshold_;
74 }
75 
76 Rate
78  Rate const& rate, Issue const &issue,
79  AccountID const& from, AccountID const& to)
80 {
81  // If there's a transfer rate, the issuer is not involved
82  // and the sender isn't the same as the recipient, return
83  // the actual transfer rate.
84  if (rate != parityRate &&
85  from != to &&
86  from != issue.account &&
87  to != issue.account)
88  {
89  return rate;
90  }
91 
92  return parityRate;
93 }
94 
95 bool
97 {
98  if (get_funds (account(), remaining_.in) > beast::zero)
99  return false;
100 
101  JLOG(journal_.debug()) << "Unfunded: taker is out of funds.";
102  return true;
103 }
104 
105 bool
107 {
108  // We are done if we have consumed all the input currency
109  if (remaining_.in <= beast::zero)
110  {
111  JLOG(journal_.debug()) << "Done: all the input currency has been consumed.";
112  return true;
113  }
114 
115  // We are done if using buy semantics and we received the
116  // desired amount of output currency
117  if (!sell_ && (remaining_.out <= beast::zero))
118  {
119  JLOG(journal_.debug()) << "Done: the desired amount has been received.";
120  return true;
121  }
122 
123  // We are done if the taker is out of funds
124  if (unfunded ())
125  {
126  JLOG(journal_.debug()) << "Done: taker out of funds.";
127  return true;
128  }
129 
130  return false;
131 }
132 
133 Amounts
135 {
136  // If the taker is done, then there's no offer to place.
137  if (done ())
138  return Amounts (remaining_.in.zeroed(), remaining_.out.zeroed());
139 
140  // Avoid math altogether if we didn't cross.
141  if (original_ == remaining_)
142  return original_;
143 
144  if (sell_)
145  {
146  assert (remaining_.in > beast::zero);
147 
148  // We scale the output based on the remaining input:
149  return Amounts (remaining_.in, divRound (
150  remaining_.in, quality_.rate (), issue_out_, true));
151  }
152 
153  assert (remaining_.out > beast::zero);
154 
155  // We scale the input based on the remaining output:
156  return Amounts (mulRound (
157  remaining_.out, quality_.rate (), issue_in_, true),
158  remaining_.out);
159 }
160 
161 Amounts const&
163 {
164  return original_;
165 }
166 
167 // TODO: the presence of 'output' is an artifact caused by the fact that
168 // Amounts carry issue information which should be decoupled.
169 static
170 STAmount
171 qual_div (STAmount const& amount, Quality const& quality, STAmount const& output)
172 {
173  auto result = divide (amount, quality.rate (), output.issue ());
174  return std::min (result, output);
175 }
176 
177 static
178 STAmount
179 qual_mul (STAmount const& amount, Quality const& quality, STAmount const& output)
180 {
181  auto result = multiply (amount, quality.rate (), output.issue ());
182  return std::min (result, output);
183 }
184 
185 void
186 BasicTaker::log_flow (char const* description, Flow const& flow)
187 {
188  auto stream = journal_.debug();
189  if (!stream)
190  return;
191 
192  stream << description;
193 
194  if (isXRP (issue_in ()))
195  stream << " order in: " << format_amount (flow.order.in);
196  else
197  stream << " order in: " << format_amount (flow.order.in) <<
198  " (issuer: " << format_amount (flow.issuers.in) << ")";
199 
200  if (isXRP (issue_out ()))
201  stream << " order out: " << format_amount (flow.order.out);
202  else
203  stream << " order out: " << format_amount (flow.order.out) <<
204  " (issuer: " << format_amount (flow.issuers.out) << ")";
205 }
206 
209  Amounts const& order, Quality quality,
210  STAmount const& owner_funds, STAmount const& taker_funds,
211  Rate const& rate_out)
212 {
213  Flow f;
214  f.order = order;
215  f.issuers.out = multiply (f.order.out, rate_out);
216 
217  log_flow ("flow_xrp_to_iou", f);
218 
219  // Clamp on owner balance
220  if (owner_funds < f.issuers.out)
221  {
222  f.issuers.out = owner_funds;
223  f.order.out = divide (f.issuers.out, rate_out);
224  f.order.in = qual_mul (f.order.out, quality, f.order.in);
225  log_flow ("(clamped on owner balance)", f);
226  }
227 
228  // Clamp if taker wants to limit the output
229  if (!sell_ && remaining_.out < f.order.out)
230  {
231  f.order.out = remaining_.out;
232  f.order.in = qual_mul (f.order.out, quality, f.order.in);
233  f.issuers.out = multiply (f.order.out, rate_out);
234  log_flow ("(clamped on taker output)", f);
235  }
236 
237  // Clamp on the taker's funds
238  if (taker_funds < f.order.in)
239  {
240  f.order.in = taker_funds;
241  f.order.out = qual_div (f.order.in, quality, f.order.out);
242  f.issuers.out = multiply (f.order.out, rate_out);
243  log_flow ("(clamped on taker funds)", f);
244  }
245 
246  // Clamp on remaining offer if we are not handling the second leg
247  // of an autobridge.
248  if (cross_type_ == CrossType::XrpToIou && (remaining_.in < f.order.in))
249  {
250  f.order.in = remaining_.in;
251  f.order.out = qual_div (f.order.in, quality, f.order.out);
252  f.issuers.out = multiply (f.order.out, rate_out);
253  log_flow ("(clamped on taker input)", f);
254  }
255 
256  return f;
257 }
258 
261  Amounts const& order, Quality quality,
262  STAmount const& owner_funds, STAmount const& taker_funds,
263  Rate const& rate_in)
264 {
265  Flow f;
266  f.order = order;
267  f.issuers.in = multiply (f.order.in, rate_in);
268 
269  log_flow ("flow_iou_to_xrp", f);
270 
271  // Clamp on owner's funds
272  if (owner_funds < f.order.out)
273  {
274  f.order.out = owner_funds;
275  f.order.in = qual_mul (f.order.out, quality, f.order.in);
276  f.issuers.in = multiply (f.order.in, rate_in);
277  log_flow ("(clamped on owner funds)", f);
278  }
279 
280  // Clamp if taker wants to limit the output and we are not the
281  // first leg of an autobridge.
283  {
284  if (remaining_.out < f.order.out)
285  {
286  f.order.out = remaining_.out;
287  f.order.in = qual_mul (f.order.out, quality, f.order.in);
288  f.issuers.in = multiply (f.order.in, rate_in);
289  log_flow ("(clamped on taker output)", f);
290  }
291  }
292 
293  // Clamp on the taker's input offer
294  if (remaining_.in < f.order.in)
295  {
296  f.order.in = remaining_.in;
297  f.issuers.in = multiply (f.order.in, rate_in);
298  f.order.out = qual_div (f.order.in, quality, f.order.out);
299  log_flow ("(clamped on taker input)", f);
300  }
301 
302  // Clamp on the taker's input balance
303  if (taker_funds < f.issuers.in)
304  {
305  f.issuers.in = taker_funds;
306  f.order.in = divide (f.issuers.in, rate_in);
307  f.order.out = qual_div (f.order.in, quality, f.order.out);
308  log_flow ("(clamped on taker funds)", f);
309  }
310 
311  return f;
312 }
313 
316  Amounts const& order, Quality quality,
317  STAmount const& owner_funds, STAmount const& taker_funds,
318  Rate const& rate_in, Rate const& rate_out)
319 {
320  Flow f;
321  f.order = order;
322  f.issuers.in = multiply (f.order.in, rate_in);
323  f.issuers.out = multiply (f.order.out, rate_out);
324 
325  log_flow ("flow_iou_to_iou", f);
326 
327  // Clamp on owner balance
328  if (owner_funds < f.issuers.out)
329  {
330  f.issuers.out = owner_funds;
331  f.order.out = divide (f.issuers.out, rate_out);
332  f.order.in = qual_mul (f.order.out, quality, f.order.in);
333  f.issuers.in = multiply (f.order.in, rate_in);
334  log_flow ("(clamped on owner funds)", f);
335  }
336 
337  // Clamp on taker's offer
338  if (!sell_ && remaining_.out < f.order.out)
339  {
340  f.order.out = remaining_.out;
341  f.order.in = qual_mul (f.order.out, quality, f.order.in);
342  f.issuers.out = multiply (f.order.out, rate_out);
343  f.issuers.in = multiply (f.order.in, rate_in);
344  log_flow ("(clamped on taker output)", f);
345  }
346 
347  // Clamp on the taker's input offer
348  if (remaining_.in < f.order.in)
349  {
350  f.order.in = remaining_.in;
351  f.issuers.in = multiply (f.order.in, rate_in);
352  f.order.out = qual_div (f.order.in, quality, f.order.out);
353  f.issuers.out = multiply (f.order.out, rate_out);
354  log_flow ("(clamped on taker input)", f);
355  }
356 
357  // Clamp on the taker's input balance
358  if (taker_funds < f.issuers.in)
359  {
360  f.issuers.in = taker_funds;
361  f.order.in = divide (f.issuers.in, rate_in);
362  f.order.out = qual_div (f.order.in, quality, f.order.out);
363  f.issuers.out = multiply (f.order.out, rate_out);
364  log_flow ("(clamped on taker funds)", f);
365  }
366 
367  return f;
368 }
369 
370 // Calculates the direct flow through the specified offer
372 BasicTaker::do_cross (Amounts offer, Quality quality, AccountID const& owner)
373 {
374  auto const owner_funds = get_funds (owner, offer.out);
375  auto const taker_funds = get_funds (account (), offer.in);
376 
377  Flow result;
378 
380  {
381  result = flow_xrp_to_iou (offer, quality, owner_funds, taker_funds,
382  out_rate (owner, account ()));
383  }
384  else if (cross_type_ == CrossType::IouToXrp)
385  {
386  result = flow_iou_to_xrp (offer, quality, owner_funds, taker_funds,
387  in_rate (owner, account ()));
388  }
389  else
390  {
391  result = flow_iou_to_iou (offer, quality, owner_funds, taker_funds,
392  in_rate (owner, account ()), out_rate (owner, account ()));
393  }
394 
395  if (!result.sanity_check ())
396  Throw<std::logic_error> ("Computed flow fails sanity check.");
397 
398  remaining_.out -= result.order.out;
399  remaining_.in -= result.order.in;
400 
401  assert (remaining_.in >= beast::zero);
402 
403  return result;
404 }
405 
406 // Calculates the bridged flow through the specified offers
409  Amounts offer1, Quality quality1, AccountID const& owner1,
410  Amounts offer2, Quality quality2, AccountID const& owner2)
411 {
412  assert (!offer1.in.native ());
413  assert (offer1.out.native ());
414  assert (offer2.in.native ());
415  assert (!offer2.out.native ());
416 
417  // If the taker owns the first leg of the offer, then the taker's available
418  // funds aren't the limiting factor for the input - the offer itself is.
419  auto leg1_in_funds = get_funds (account (), offer1.in);
420 
421  if (account () == owner1)
422  {
423  JLOG(journal_.trace()) << "The taker owns the first leg of a bridge.";
424  leg1_in_funds = std::max (leg1_in_funds, offer1.in);
425  }
426 
427  // If the taker owns the second leg of the offer, then the taker's available
428  // funds are not the limiting factor for the output - the offer itself is.
429  auto leg2_out_funds = get_funds (owner2, offer2.out);
430 
431  if (account () == owner2)
432  {
433  JLOG(journal_.trace()) << "The taker owns the second leg of a bridge.";
434  leg2_out_funds = std::max (leg2_out_funds, offer2.out);
435  }
436 
437  // The amount available to flow via XRP is the amount that the owner of the
438  // first leg of the bridge has, up to the first leg's output.
439  //
440  // But, when both legs of a bridge are owned by the same person, the amount
441  // of XRP that can flow between the two legs is, essentially, infinite
442  // since all the owner is doing is taking out XRP of his left pocket
443  // and putting it in his right pocket. In that case, we set the available
444  // XRP to the largest of the two offers.
445  auto xrp_funds = get_funds (owner1, offer1.out);
446 
447  if (owner1 == owner2)
448  {
449  JLOG(journal_.trace()) <<
450  "The bridge endpoints are owned by the same account.";
451  xrp_funds = std::max (offer1.out, offer2.in);
452  }
453 
454  if (auto stream = journal_.debug())
455  {
456  stream << "Available bridge funds:";
457  stream << " leg1 in: " << format_amount (leg1_in_funds);
458  stream << " leg2 out: " << format_amount (leg2_out_funds);
459  stream << " xrp: " << format_amount (xrp_funds);
460  }
461 
462  auto const leg1_rate = in_rate (owner1, account ());
463  auto const leg2_rate = out_rate (owner2, account ());
464 
465  // Attempt to determine the maximal flow that can be achieved across each
466  // leg independent of the other.
467  auto flow1 = flow_iou_to_xrp (offer1, quality1, xrp_funds, leg1_in_funds, leg1_rate);
468 
469  if (!flow1.sanity_check ())
470  Throw<std::logic_error> ("Computed flow1 fails sanity check.");
471 
472  auto flow2 = flow_xrp_to_iou (offer2, quality2, leg2_out_funds, xrp_funds, leg2_rate);
473 
474  if (!flow2.sanity_check ())
475  Throw<std::logic_error> ("Computed flow2 fails sanity check.");
476 
477  // We now have the maximal flows across each leg individually. We need to
478  // equalize them, so that the amount of XRP that flows out of the first leg
479  // is the same as the amount of XRP that flows into the second leg. We take
480  // the side which is the limiting factor (if any) and adjust the other.
481  if (flow1.order.out < flow2.order.in)
482  {
483  // Adjust the second leg of the offer down:
484  flow2.order.in = flow1.order.out;
485  flow2.order.out = qual_div (flow2.order.in, quality2, flow2.order.out);
486  flow2.issuers.out = multiply (flow2.order.out, leg2_rate);
487  log_flow ("Balancing: adjusted second leg down", flow2);
488  }
489  else if (flow1.order.out > flow2.order.in)
490  {
491  // Adjust the first leg of the offer down:
492  flow1.order.out = flow2.order.in;
493  flow1.order.in = qual_mul (flow1.order.out, quality1, flow1.order.in);
494  flow1.issuers.in = multiply (flow1.order.in, leg1_rate);
495  log_flow ("Balancing: adjusted first leg down", flow2);
496  }
497 
498  if (flow1.order.out != flow2.order.in)
499  Throw<std::logic_error> ("Bridged flow is out of balance.");
500 
501  remaining_.out -= flow2.order.out;
502  remaining_.in -= flow1.order.in;
503 
504  return std::make_pair (flow1, flow2);
505 }
506 
507 //==============================================================================
508 
509 Taker::Taker (CrossType cross_type, ApplyView& view,
510  AccountID const& account, Amounts const& offer,
511  std::uint32_t flags,
512  beast::Journal journal)
513  : BasicTaker (cross_type, account, offer, Quality(offer), flags,
514  calculateRate(view, offer.in.getIssuer(), account),
515  calculateRate(view, offer.out.getIssuer(), account), journal)
516  , view_ (view)
517  , xrp_flow_ (0)
518  , direct_crossings_ (0)
519  , bridge_crossings_ (0)
520 {
521  assert (issue_in () == offer.in.issue ());
522  assert (issue_out () == offer.out.issue ());
523 
524  if (auto stream = journal_.debug())
525  {
526  stream << "Crossing as: " << to_string (account);
527 
528  if (isXRP (issue_in ()))
529  stream << " Offer in: " << format_amount (offer.in);
530  else
531  stream << " Offer in: " << format_amount (offer.in) <<
532  " (issuer: " << issue_in ().account << ")";
533 
534  if (isXRP (issue_out ()))
535  stream << " Offer out: " << format_amount (offer.out);
536  else
537  stream << " Offer out: " << format_amount (offer.out) <<
538  " (issuer: " << issue_out ().account << ")";
539 
540  stream <<
541  " Balance: " << format_amount (get_funds (account, offer.in));
542  }
543 }
544 
545 void
546 Taker::consume_offer (Offer& offer, Amounts const& order)
547 {
548  if (order.in < beast::zero)
549  Throw<std::logic_error> ("flow with negative input.");
550 
551  if (order.out < beast::zero)
552  Throw<std::logic_error> ("flow with negative output.");
553 
554  JLOG(journal_.debug()) << "Consuming from offer " << offer;
555 
556  if (auto stream = journal_.trace())
557  {
558  auto const& available = offer.amount ();
559 
560  stream << " in:" << format_amount (available.in);
561  stream << " out:" << format_amount(available.out);
562  }
563 
564  offer.consume (view_, order);
565 }
566 
567 STAmount
568 Taker::get_funds (AccountID const& account, STAmount const& amount) const
569 {
571 }
572 
574  AccountID const& from,
575  AccountID const& to,
576  STAmount const& amount)
577 {
578  if (!isXRP (amount))
579  Throw<std::logic_error> ("Using transferXRP with IOU");
580 
581  if (from == to)
582  return tesSUCCESS;
583 
584  // Transferring zero is equivalent to not doing a transfer
585  if (amount == beast::zero)
586  return tesSUCCESS;
587 
588  return ripple::transferXRP (view_, from, to, amount, journal_);
589 }
590 
592  AccountID const& account,
593  STAmount const& amount,
594  Issue const& issue)
595 {
596  if (isXRP (amount))
597  Throw<std::logic_error> ("Using redeemIOU with XRP");
598 
599  if (account == issue.account)
600  return tesSUCCESS;
601 
602  // Transferring zero is equivalent to not doing a transfer
603  if (amount == beast::zero)
604  return tesSUCCESS;
605 
606  // If we are trying to redeem some amount, then the account
607  // must have a credit balance.
608  if (get_funds (account, amount) <= beast::zero)
609  Throw<std::logic_error> ("redeemIOU has no funds to redeem");
610 
611  auto ret = ripple::redeemIOU (view_, account, amount, issue, journal_);
612 
613  if (get_funds (account, amount) < beast::zero)
614  Throw<std::logic_error> ("redeemIOU redeemed more funds than available");
615 
616  return ret;
617 }
618 
620  AccountID const& account,
621  STAmount const& amount,
622  Issue const& issue)
623 {
624  if (isXRP (amount))
625  Throw<std::logic_error> ("Using issueIOU with XRP");
626 
627  if (account == issue.account)
628  return tesSUCCESS;
629 
630  // Transferring zero is equivalent to not doing a transfer
631  if (amount == beast::zero)
632  return tesSUCCESS;
633 
634  return ripple::issueIOU (view_, account, amount, issue, journal_);
635 }
636 
637 // Performs funds transfers to fill the given offer and adjusts offer.
638 TER
640 {
641  // adjust offer
642  consume_offer (offer, flow.order);
643 
644  TER result = tesSUCCESS;
645 
647  {
648  assert (!isXRP (flow.order.in));
649 
650  if(result == tesSUCCESS)
651  result = redeemIOU (account (), flow.issuers.in, flow.issuers.in.issue ());
652 
653  if (result == tesSUCCESS)
654  result = issueIOU (offer.owner (), flow.order.in, flow.order.in.issue ());
655  }
656  else
657  {
658  assert (isXRP (flow.order.in));
659 
660  if (result == tesSUCCESS)
661  result = transferXRP (account (), offer.owner (), flow.order.in);
662  }
663 
664  // Now send funds from the account whose offer we're taking
666  {
667  assert (!isXRP (flow.order.out));
668 
669  if(result == tesSUCCESS)
670  result = redeemIOU (offer.owner (), flow.issuers.out, flow.issuers.out.issue ());
671 
672  if (result == tesSUCCESS)
673  result = issueIOU (account (), flow.order.out, flow.order.out.issue ());
674  }
675  else
676  {
677  assert (isXRP (flow.order.out));
678 
679  if (result == tesSUCCESS)
680  result = transferXRP (offer.owner (), account (), flow.order.out);
681  }
682 
683  if (result == tesSUCCESS)
685 
686  return result;
687 }
688 
689 // Performs bridged funds transfers to fill the given offers and adjusts offers.
690 TER
692  BasicTaker::Flow const& flow1, Offer& leg1,
693  BasicTaker::Flow const& flow2, Offer& leg2)
694 {
695  // Adjust offers accordingly
696  consume_offer (leg1, flow1.order);
697  consume_offer (leg2, flow2.order);
698 
699  TER result = tesSUCCESS;
700 
701  // Taker to leg1: IOU
702  if (leg1.owner () != account ())
703  {
704  if (result == tesSUCCESS)
705  result = redeemIOU (account (), flow1.issuers.in, flow1.issuers.in.issue ());
706 
707  if (result == tesSUCCESS)
708  result = issueIOU (leg1.owner (), flow1.order.in, flow1.order.in.issue ());
709  }
710 
711  // leg1 to leg2: bridging over XRP
712  if (result == tesSUCCESS)
713  result = transferXRP (leg1.owner (), leg2.owner (), flow1.order.out);
714 
715  // leg2 to Taker: IOU
716  if (leg2.owner () != account ())
717  {
718  if (result == tesSUCCESS)
719  result = redeemIOU (leg2.owner (), flow2.issuers.out, flow2.issuers.out.issue ());
720 
721  if (result == tesSUCCESS)
722  result = issueIOU (account (), flow2.order.out, flow2.order.out.issue ());
723  }
724 
725  if (result == tesSUCCESS)
726  {
728  xrp_flow_ += flow1.order.out;
729  }
730 
731  return result;
732 }
733 
734 TER
736 {
737  // In direct crossings, at least one leg must not be XRP.
738  if (isXRP (offer.amount ().in) && isXRP (offer.amount ().out))
739  return tefINTERNAL;
740 
741  auto const amount = do_cross (
742  offer.amount (), offer.quality (), offer.owner ());
743 
744  return fill (amount, offer);
745 }
746 
747 TER
748 Taker::cross (Offer& leg1, Offer& leg2)
749 {
750  // In bridged crossings, XRP must can't be the input to the first leg
751  // or the output of the second leg.
752  if (isXRP (leg1.amount ().in) || isXRP (leg2.amount ().out))
753  return tefINTERNAL;
754 
755  auto ret = do_cross (
756  leg1.amount (), leg1.quality (), leg1.owner (),
757  leg2.amount (), leg2.quality (), leg2.owner ());
758 
759  return fill (ret.first, leg1, ret.second, leg2);
760 }
761 
762 Rate
764  ApplyView const& view,
765  AccountID const& issuer,
766  AccountID const& account)
767 {
768  return isXRP (issuer) || (account == issuer)
769  ? parityRate
770  : transferRate (view, issuer);
771 }
772 
773 } // ripple
774 
ripple::Taker::get_funds
STAmount get_funds(AccountID const &account, STAmount const &funds) const override
Definition: Taker.cpp:568
ripple::transferRate
Rate transferRate(ReadView const &view, AccountID const &issuer)
Definition: View.cpp:338
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
ripple::tefINTERNAL
@ tefINTERNAL
Definition: TER.h:153
std::string
STL class.
ripple::fhZERO_IF_FROZEN
@ fhZERO_IF_FROZEN
Definition: View.h:56
ripple::Rate
Represents a transfer rate.
Definition: Rate.h:37
ripple::Taker::fill
TER fill(BasicTaker::Flow const &flow, Offer &offer)
Definition: Taker.cpp:639
beast::Journal::trace
Stream trace() const
Severity stream access functions.
Definition: Journal.h:287
ripple::Taker::view_
ApplyView & view_
Definition: Taker.h:302
ripple::BasicTaker::unfunded
bool unfunded() const
Returns true if the taker has run out of funds.
Definition: Taker.cpp:96
ripple::BasicTaker::flow_iou_to_iou
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)
Definition: Taker.cpp:315
std::pair
ripple::qual_div
static STAmount qual_div(STAmount const &amount, Quality const &quality, STAmount const &output)
Definition: Taker.cpp:171
ripple::BasicTaker::do_cross
BasicTaker::Flow do_cross(Amounts offer, Quality quality, AccountID const &owner)
Perform direct crossing through given offer.
Definition: Taker.cpp:372
ripple::qual_mul
static STAmount qual_mul(STAmount const &amount, Quality const &quality, STAmount const &output)
Definition: Taker.cpp:179
ripple::BasicTaker::remaining_offer
Amounts remaining_offer() const
Returns the amount remaining on the offer.
Definition: Taker.cpp:134
ripple::tfPassive
const std::uint32_t tfPassive
Definition: TxFlags.h:76
ripple::BasicTaker::in_rate
Rate in_rate(AccountID const &from, AccountID const &to) const
Definition: Taker.h:123
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:492
ripple::CrossType::XrpToIou
@ XrpToIou
ripple::BasicTaker::m_rate_in
const Rate m_rate_in
Definition: Taker.h:65
ripple::Taker::direct_crossings_
std::uint32_t direct_crossings_
Definition: Taker.h:308
ripple::BasicTaker::log_flow
void log_flow(char const *description, Flow const &flow)
Definition: Taker.cpp:186
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::CrossType::IouToXrp
@ IouToXrp
ripple::format_amount
static std::string format_amount(STAmount const &amount)
Definition: Taker.cpp:28
ripple::BasicTaker::issue_in
Issue const & issue_in() const
Returns the Issue associated with the input of the offer.
Definition: Taker.h:183
ripple::BasicTaker::flow_xrp_to_iou
Flow flow_xrp_to_iou(Amounts const &offer, Quality quality, STAmount const &owner_funds, STAmount const &taker_funds, Rate const &rate_out)
Definition: Taker.cpp:208
ripple::BasicTaker::remaining_
Amounts remaining_
Definition: Taker.h:57
ripple::QualityDirection::in
@ in
ripple::BasicTaker
State for the active party during order book or payment operations.
Definition: Taker.h:44
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::BasicTaker::BasicTaker
BasicTaker()=delete
ripple::BasicTaker::cross_type
CrossType cross_type() const
Returns the type of crossing that is being performed.
Definition: Taker.h:176
ripple::BasicTaker::journal_
const beast::Journal journal_
Definition: Taker.h:72
ripple::parityRate
const Rate parityRate(QUALITY_ONE)
A transfer rate signifying a 1:1 exchange.
Definition: Rate.h:110
ripple::ApplyView
Writeable view to a ledger, for applying a transaction.
Definition: ApplyView.h:150
ripple::Taker::redeemIOU
TER redeemIOU(AccountID const &account, STAmount const &amount, Issue const &issue)
Definition: Taker.cpp:591
ripple::mulRound
STAmount mulRound(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1173
ripple::TOffer::quality
const Quality quality() const noexcept
Returns the quality of the offer.
Definition: Offer.h:75
ripple::TOffer::amount
TAmounts< TIn, TOut > const & amount() const
Returns the in and out amounts.
Definition: Offer.h:91
ripple::BasicTaker::flow_iou_to_xrp
Flow flow_iou_to_xrp(Amounts const &offer, Quality quality, STAmount const &owner_funds, STAmount const &taker_funds, Rate const &rate_in)
Definition: Taker.cpp:260
ripple::Taker::calculateRate
static Rate calculateRate(ApplyView const &view, AccountID const &issuer, AccountID const &account)
Definition: Taker.cpp:763
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:92
ripple::BasicTaker::sell_
bool sell_
Definition: Taker.h:51
ripple::base_uint< 160, detail::AccountIDTag >
ripple::BasicTaker::original_
const Amounts original_
Definition: Taker.h:54
ripple::BasicTaker::issue_out
Issue const & issue_out() const
Returns the Issue associated with the output of the offer.
Definition: Taker.h:190
ripple::BasicTaker::Flow::order
Amounts order
Definition: Taker.h:78
ripple::CrossType
CrossType
The flavor of an offer crossing.
Definition: Taker.h:36
ripple::QualityDirection::out
@ out
ripple::Taker::Taker
Taker()=delete
ripple::BasicTaker::Flow
Definition: Taker.h:74
ripple::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1257
ripple::Taker::xrp_flow_
STAmount xrp_flow_
Definition: Taker.h:305
ripple::Taker::issueIOU
TER issueIOU(AccountID const &account, STAmount const &amount, Issue const &issue)
Definition: Taker.cpp:619
ripple::TERSubset< CanCvtToTER >
ripple::TOffer::owner
AccountID const & owner() const
Returns the account id of the offer's owner.
Definition: Offer.h:82
ripple::BasicTaker::threshold_
Quality threshold_
Definition: Taker.h:49
ripple::STAmount
Definition: STAmount.h:42
ripple::BasicTaker::original_offer
Amounts const & original_offer() const
Returns the amount that the offer was originally placed at.
Definition: Taker.cpp:162
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:121
ripple::Taker::consume_offer
void consume_offer(Offer &offer, Amounts const &order)
Definition: Taker.cpp:546
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
ripple::Taker::bridge_crossings_
std::uint32_t bridge_crossings_
Definition: Taker.h:311
std::uint32_t
ripple::BasicTaker::cross_type_
CrossType cross_type_
Definition: Taker.h:69
ripple::BasicTaker::Flow::sanity_check
bool sanity_check() const
Definition: Taker.h:81
ripple::BasicTaker::Flow::issuers
Amounts issuers
Definition: Taker.h:79
ripple::BasicTaker::effective_rate
static Rate effective_rate(Rate const &rate, Issue const &issue, AccountID const &from, AccountID const &to)
Definition: Taker.cpp:77
ripple::accountFunds
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Definition: View.cpp:133
ripple::transferXRP
TER transferXRP(ApplyView &view, AccountID const &from, AccountID const &to, STAmount const &amount, beast::Journal j)
Definition: View.cpp:1405
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:37
std::min
T min(T... args)
ripple::BasicTaker::get_funds
virtual STAmount get_funds(AccountID const &account, STAmount const &funds) const =0
ripple::issueIOU
TER issueIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1262
ripple::BasicTaker::done
bool done() const
Returns true if order crossing should not continue.
Definition: Taker.cpp:106
ripple::Rate::value
std::uint32_t value
Definition: Rate.h:40
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::BasicTaker::issue_in_
Issue const & issue_in_
Definition: Taker.h:60
ripple::tfSell
const std::uint32_t tfSell
Definition: TxFlags.h:79
ripple::redeemIOU
TER redeemIOU(ApplyView &view, AccountID const &account, STAmount const &amount, Issue const &issue, beast::Journal j)
Definition: View.cpp:1335
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:156
ripple::Taker::transferXRP
TER transferXRP(AccountID const &from, AccountID const &to, STAmount const &amount)
Definition: Taker.cpp:573
ripple::flow
path::RippleCalc::Output flow(PaymentSandbox &view, STAmount const &deliver, AccountID const &src, AccountID const &dst, STPathSet const &paths, bool defaultPaths, bool partialPayment, bool ownerPaysTransferFee, bool offerCrossing, boost::optional< Quality > const &limitQuality, boost::optional< STAmount > const &sendMax, beast::Journal j, path::detail::FlowDebugInfo *flowDebugInfo=nullptr)
Make a payment from the src account to the dst account.
beast::Journal::debug
Stream debug() const
Definition: Journal.h:292
std::make_pair
T make_pair(T... args)
ripple::BasicTaker::quality_
Quality quality_
Definition: Taker.h:48
std::max
T max(T... args)
ripple::BasicTaker::m_rate_out
const Rate m_rate_out
Definition: Taker.h:66
ripple::BasicTaker::account
AccountID const & account() const noexcept
Returns the account identifier of the taker.
Definition: Taker.h:162
ripple::tesSUCCESS
@ tesSUCCESS
Definition: TER.h:219
ripple::TOffer
Definition: Offer.h:50
ripple::BasicTaker::issue_out_
Issue const & issue_out_
Definition: Taker.h:61
ripple::Taker::cross
TER cross(Offer &offer)
Perform a direct or bridged offer crossing as appropriate.
Definition: Taker.cpp:735
ripple::BasicTaker::out_rate
Rate out_rate(AccountID const &from, AccountID const &to) const
Definition: Taker.h:130
ripple::Issue::account
AccountID account
Definition: Issue.h:38