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