rippled
STAmount.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 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/basics/Log.h>
21 #include <ripple/basics/contract.h>
22 #include <ripple/basics/safe_cast.h>
23 #include <ripple/beast/core/LexicalCast.h>
24 #include <ripple/protocol/STAmount.h>
25 #include <ripple/protocol/SystemParameters.h>
26 #include <ripple/protocol/UintTypes.h>
27 #include <ripple/protocol/jss.h>
28 #include <boost/algorithm/string.hpp>
29 #include <boost/multiprecision/cpp_int.hpp>
30 #include <boost/regex.hpp>
31 #include <iostream>
32 #include <iterator>
33 #include <memory>
34 
35 namespace ripple {
36 
37 namespace {
38 
39 // Use a static inside a function to help prevent order-of-initialzation issues
40 LocalValue<bool>&
41 getStaticSTAmountCanonicalizeSwitchover()
42 {
43  static LocalValue<bool> r{true};
44  return r;
45 }
46 } // namespace
47 
48 bool
50 {
51  return *getStaticSTAmountCanonicalizeSwitchover();
52 }
53 
54 void
56 {
57  *getStaticSTAmountCanonicalizeSwitchover() = v;
58 }
59 
60 static const std::uint64_t tenTo14 = 100000000000000ull;
61 static const std::uint64_t tenTo14m1 = tenTo14 - 1;
62 static const std::uint64_t tenTo17 = tenTo14 * 1000;
63 
64 //------------------------------------------------------------------------------
65 static std::int64_t
66 getSNValue(STAmount const& amount)
67 {
68  if (!amount.native())
69  Throw<std::runtime_error>("amount is not native!");
70 
71  auto ret = static_cast<std::int64_t>(amount.mantissa());
72 
73  assert(static_cast<std::uint64_t>(ret) == amount.mantissa());
74 
75  if (amount.negative())
76  ret = -ret;
77 
78  return ret;
79 }
80 
81 static bool
82 areComparable(STAmount const& v1, STAmount const& v2)
83 {
84  return v1.native() == v2.native() &&
85  v1.issue().currency == v2.issue().currency;
86 }
87 
88 STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name)
89 {
90  std::uint64_t value = sit.get64();
91 
92  // native
93  if ((value & cNotNative) == 0)
94  {
95  // positive
96  if ((value & cPosNative) != 0)
97  {
98  mValue = value & ~cPosNative;
99  mOffset = 0;
100  mIsNative = true;
101  mIsNegative = false;
102  return;
103  }
104 
105  // negative
106  if (value == 0)
107  Throw<std::runtime_error>("negative zero is not canonical");
108 
109  mValue = value;
110  mOffset = 0;
111  mIsNative = true;
112  mIsNegative = true;
113  return;
114  }
115 
116  Issue issue;
117  issue.currency = sit.get160();
118 
119  if (isXRP(issue.currency))
120  Throw<std::runtime_error>("invalid native currency");
121 
122  issue.account = sit.get160();
123 
124  if (isXRP(issue.account))
125  Throw<std::runtime_error>("invalid native account");
126 
127  // 10 bits for the offset, sign and "not native" flag
128  int offset = static_cast<int>(value >> (64 - 10));
129 
130  value &= ~(1023ull << (64 - 10));
131 
132  if (value)
133  {
134  bool isNegative = (offset & 256) == 0;
135  offset = (offset & 255) - 97; // center the range
136 
137  if (value < cMinValue || value > cMaxValue || offset < cMinOffset ||
138  offset > cMaxOffset)
139  {
140  Throw<std::runtime_error>("invalid currency value");
141  }
142 
143  mIssue = issue;
144  mValue = value;
145  mOffset = offset;
146  mIsNegative = isNegative;
147  canonicalize();
148  return;
149  }
150 
151  if (offset != 512)
152  Throw<std::runtime_error>("invalid currency value");
153 
154  mIssue = issue;
155  mValue = 0;
156  mOffset = 0;
157  mIsNegative = false;
158  canonicalize();
159 }
160 
162  SField const& name,
163  Issue const& issue,
164  mantissa_type mantissa,
165  exponent_type exponent,
166  bool native,
167  bool negative,
168  unchecked)
169  : STBase(name)
170  , mIssue(issue)
171  , mValue(mantissa)
172  , mOffset(exponent)
173  , mIsNative(native)
174  , mIsNegative(negative)
175 {
176 }
177 
179  Issue const& issue,
180  mantissa_type mantissa,
181  exponent_type exponent,
182  bool native,
183  bool negative,
184  unchecked)
185  : mIssue(issue)
186  , mValue(mantissa)
187  , mOffset(exponent)
188  , mIsNative(native)
189  , mIsNegative(negative)
190 {
191 }
192 
194  SField const& name,
195  Issue const& issue,
196  mantissa_type mantissa,
197  exponent_type exponent,
198  bool native,
199  bool negative)
200  : STBase(name)
201  , mIssue(issue)
202  , mValue(mantissa)
203  , mOffset(exponent)
204  , mIsNative(native)
205  , mIsNegative(negative)
206 {
207  canonicalize();
208 }
209 
210 STAmount::STAmount(SField const& name, std::int64_t mantissa)
211  : STBase(name), mOffset(0), mIsNative(true)
212 {
213  set(mantissa);
214 }
215 
216 STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative)
217  : STBase(name)
218  , mValue(mantissa)
219  , mOffset(0)
220  , mIsNative(true)
221  , mIsNegative(negative)
222 {
224 }
225 
227  SField const& name,
228  Issue const& issue,
229  std::uint64_t mantissa,
230  int exponent,
231  bool negative)
232  : STBase(name)
233  , mIssue(issue)
234  , mValue(mantissa)
235  , mOffset(exponent)
236  , mIsNegative(negative)
237 {
239  canonicalize();
240 }
241 
242 STAmount::STAmount(SField const& name, STAmount const& from)
243  : STBase(name)
244  , mIssue(from.mIssue)
245  , mValue(from.mValue)
246  , mOffset(from.mOffset)
247  , mIsNegative(from.mIsNegative)
248 {
250  canonicalize();
251 }
252 
253 //------------------------------------------------------------------------------
254 
255 STAmount::STAmount(std::uint64_t mantissa, bool negative)
256  : mValue(mantissa)
257  , mOffset(0)
258  , mIsNative(true)
259  , mIsNegative(mantissa != 0 && negative)
260 {
262 }
263 
265  Issue const& issue,
266  std::uint64_t mantissa,
267  int exponent,
268  bool negative)
269  : mIssue(issue), mValue(mantissa), mOffset(exponent), mIsNegative(negative)
270 {
271  canonicalize();
272 }
273 
274 STAmount::STAmount(Issue const& issue, std::int64_t mantissa, int exponent)
275  : mIssue(issue), mOffset(exponent)
276 {
277  set(mantissa);
278  canonicalize();
279 }
280 
282  Issue const& issue,
283  std::uint32_t mantissa,
284  int exponent,
285  bool negative)
286  : STAmount(issue, safe_cast<std::uint64_t>(mantissa), exponent, negative)
287 {
288 }
289 
290 STAmount::STAmount(Issue const& issue, int mantissa, int exponent)
291  : STAmount(issue, safe_cast<std::int64_t>(mantissa), exponent)
292 {
293 }
294 
295 // Legacy support for new-style amounts
296 STAmount::STAmount(IOUAmount const& amount, Issue const& issue)
297  : mIssue(issue)
298  , mOffset(amount.exponent())
299  , mIsNative(false)
300  , mIsNegative(amount < beast::zero)
301 {
302  if (mIsNegative)
303  mValue = static_cast<std::uint64_t>(-amount.mantissa());
304  else
305  mValue = static_cast<std::uint64_t>(amount.mantissa());
306 
307  canonicalize();
308 }
309 
311  : mOffset(0), mIsNative(true), mIsNegative(amount < beast::zero)
312 {
313  if (mIsNegative)
314  mValue = unsafe_cast<std::uint64_t>(-amount.drops());
315  else
316  mValue = unsafe_cast<std::uint64_t>(amount.drops());
317 
318  canonicalize();
319 }
320 
323 {
324  return std::make_unique<STAmount>(sit, name);
325 }
326 
327 STBase*
328 STAmount::copy(std::size_t n, void* buf) const
329 {
330  return emplace(n, buf, *this);
331 }
332 
333 STBase*
335 {
336  return emplace(n, buf, std::move(*this));
337 }
338 
339 //------------------------------------------------------------------------------
340 //
341 // Conversion
342 //
343 //------------------------------------------------------------------------------
344 XRPAmount
346 {
347  if (!mIsNative)
348  Throw<std::logic_error>(
349  "Cannot return non-native STAmount as XRPAmount");
350 
351  auto drops = static_cast<XRPAmount::value_type>(mValue);
352 
353  if (mIsNegative)
354  drops = -drops;
355 
356  return XRPAmount{drops};
357 }
358 
359 IOUAmount
361 {
362  if (mIsNative)
363  Throw<std::logic_error>("Cannot return native STAmount as IOUAmount");
364 
365  auto mantissa = static_cast<std::int64_t>(mValue);
366  auto exponent = mOffset;
367 
368  if (mIsNegative)
369  mantissa = -mantissa;
370 
371  return {mantissa, exponent};
372 }
373 
374 STAmount&
376 {
377  assert(mIsNative == false);
378  mOffset = iou.exponent();
379  mIsNegative = iou < beast::zero;
380  if (mIsNegative)
381  mValue = static_cast<std::uint64_t>(-iou.mantissa());
382  else
383  mValue = static_cast<std::uint64_t>(iou.mantissa());
384  return *this;
385 }
386 
387 //------------------------------------------------------------------------------
388 //
389 // Operators
390 //
391 //------------------------------------------------------------------------------
392 
393 STAmount&
395 {
396  *this = *this + a;
397  return *this;
398 }
399 
400 STAmount&
402 {
403  *this = *this - a;
404  return *this;
405 }
406 
407 STAmount
408 operator+(STAmount const& v1, STAmount const& v2)
409 {
410  if (!areComparable(v1, v2))
411  Throw<std::runtime_error>("Can't add amounts that are't comparable!");
412 
413  if (v2 == beast::zero)
414  return v1;
415 
416  if (v1 == beast::zero)
417  {
418  // Result must be in terms of v1 currency and issuer.
419  return {
420  v1.getFName(),
421  v1.issue(),
422  v2.mantissa(),
423  v2.exponent(),
424  v2.negative()};
425  }
426 
427  if (v1.native())
428  return {v1.getFName(), getSNValue(v1) + getSNValue(v2)};
429 
430  if (getSTNumberSwitchover())
431  {
432  auto x = v1;
433  x = v1.iou() + v2.iou();
434  return x;
435  }
436 
437  int ov1 = v1.exponent(), ov2 = v2.exponent();
438  std::int64_t vv1 = static_cast<std::int64_t>(v1.mantissa());
439  std::int64_t vv2 = static_cast<std::int64_t>(v2.mantissa());
440 
441  if (v1.negative())
442  vv1 = -vv1;
443 
444  if (v2.negative())
445  vv2 = -vv2;
446 
447  while (ov1 < ov2)
448  {
449  vv1 /= 10;
450  ++ov1;
451  }
452 
453  while (ov2 < ov1)
454  {
455  vv2 /= 10;
456  ++ov2;
457  }
458 
459  // This addition cannot overflow an std::int64_t. It can overflow an
460  // STAmount and the constructor will throw.
461 
462  std::int64_t fv = vv1 + vv2;
463 
464  if ((fv >= -10) && (fv <= 10))
465  return {v1.getFName(), v1.issue()};
466 
467  if (fv >= 0)
468  return STAmount{
469  v1.getFName(),
470  v1.issue(),
471  static_cast<std::uint64_t>(fv),
472  ov1,
473  false};
474 
475  return STAmount{
476  v1.getFName(), v1.issue(), static_cast<std::uint64_t>(-fv), ov1, true};
477 }
478 
479 STAmount
480 operator-(STAmount const& v1, STAmount const& v2)
481 {
482  return v1 + (-v2);
483 }
484 
485 //------------------------------------------------------------------------------
486 
487 std::uint64_t const STAmount::uRateOne = getRate(STAmount(1), STAmount(1));
488 
489 void
491 {
492  mIssue = issue;
493  mIsNative = isXRP(*this);
494 }
495 
496 // Convert an offer into an index amount so they sort by rate.
497 // A taker will take the best, lowest, rate first.
498 // (e.g. a taker will prefer pay 1 get 3 over pay 1 get 2.
499 // --> offerOut: takerGets: How much the offerer is selling to the taker.
500 // --> offerIn: takerPays: How much the offerer is receiving from the taker.
501 // <-- uRate: normalize(offerIn/offerOut)
502 // A lower rate is better for the person taking the order.
503 // The taker gets more for less with a lower rate.
504 // Zero is returned if the offer is worthless.
506 getRate(STAmount const& offerOut, STAmount const& offerIn)
507 {
508  if (offerOut == beast::zero)
509  return 0;
510  try
511  {
512  STAmount r = divide(offerIn, offerOut, noIssue());
513  if (r == beast::zero) // offer is too good
514  return 0;
515  assert((r.exponent() >= -100) && (r.exponent() <= 155));
516  std::uint64_t ret = r.exponent() + 100;
517  return (ret << (64 - 8)) | r.mantissa();
518  }
519  catch (std::exception const&)
520  {
521  }
522 
523  // overflow -- very bad offer
524  return 0;
525 }
526 
527 void
529 {
530  elem = Json::objectValue;
531 
532  if (!mIsNative)
533  {
534  // It is an error for currency or issuer not to be specified for valid
535  // json.
536  elem[jss::value] = getText();
537  elem[jss::currency] = to_string(mIssue.currency);
538  elem[jss::issuer] = to_string(mIssue.account);
539  }
540  else
541  {
542  elem = getText();
543  }
544 }
545 
546 //------------------------------------------------------------------------------
547 //
548 // STBase
549 //
550 //------------------------------------------------------------------------------
551 
554 {
555  return STI_AMOUNT;
556 }
557 
560 {
561  std::string ret;
562 
563  ret.reserve(64);
564  ret = getText() + "/" + mIssue.getText();
565  return ret;
566 }
567 
570 {
571  // keep full internal accuracy, but make more human friendly if posible
572  if (*this == beast::zero)
573  return "0";
574 
575  std::string const raw_value(std::to_string(mValue));
576  std::string ret;
577 
578  if (mIsNegative)
579  ret.append(1, '-');
580 
581  bool const scientific(
582  (mOffset != 0) && ((mOffset < -25) || (mOffset > -5)));
583 
584  if (mIsNative || scientific)
585  {
586  ret.append(raw_value);
587 
588  if (scientific)
589  {
590  ret.append(1, 'e');
592  }
593 
594  return ret;
595  }
596 
597  assert(mOffset + 43 > 0);
598 
599  size_t const pad_prefix = 27;
600  size_t const pad_suffix = 23;
601 
602  std::string val;
603  val.reserve(raw_value.length() + pad_prefix + pad_suffix);
604  val.append(pad_prefix, '0');
605  val.append(raw_value);
606  val.append(pad_suffix, '0');
607 
608  size_t const offset(mOffset + 43);
609 
610  auto pre_from(val.begin());
611  auto const pre_to(val.begin() + offset);
612 
613  auto const post_from(val.begin() + offset);
614  auto post_to(val.end());
615 
616  // Crop leading zeroes. Take advantage of the fact that there's always a
617  // fixed amount of leading zeroes and skip them.
618  if (std::distance(pre_from, pre_to) > pad_prefix)
619  pre_from += pad_prefix;
620 
621  assert(post_to >= post_from);
622 
623  pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
624 
625  // Crop trailing zeroes. Take advantage of the fact that there's always a
626  // fixed amount of trailing zeroes and skip them.
627  if (std::distance(post_from, post_to) > pad_suffix)
628  post_to -= pad_suffix;
629 
630  assert(post_to >= post_from);
631 
632  post_to = std::find_if(
634  std::make_reverse_iterator(post_from),
635  [](char c) { return c != '0'; })
636  .base();
637 
638  // Assemble the output:
639  if (pre_from == pre_to)
640  ret.append(1, '0');
641  else
642  ret.append(pre_from, pre_to);
643 
644  if (post_to != post_from)
645  {
646  ret.append(1, '.');
647  ret.append(post_from, post_to);
648  }
649 
650  return ret;
651 }
652 
654 {
655  Json::Value elem;
656  setJson(elem);
657  return elem;
658 }
659 
660 void
662 {
663  if (mIsNative)
664  {
665  assert(mOffset == 0);
666 
667  if (!mIsNegative)
668  s.add64(mValue | cPosNative);
669  else
670  s.add64(mValue);
671  }
672  else
673  {
674  if (*this == beast::zero)
675  s.add64(cNotNative);
676  else if (mIsNegative) // 512 = not native
677  s.add64(
678  mValue |
679  (static_cast<std::uint64_t>(mOffset + 512 + 97) << (64 - 10)));
680  else // 256 = positive
681  s.add64(
682  mValue |
683  (static_cast<std::uint64_t>(mOffset + 512 + 256 + 97)
684  << (64 - 10)));
685 
688  }
689 }
690 
691 bool
693 {
694  const STAmount* v = dynamic_cast<const STAmount*>(&t);
695  return v && (*v == *this);
696 }
697 
698 bool
700 {
701  return (mValue == 0) && mIsNative;
702 }
703 
704 //------------------------------------------------------------------------------
705 
706 // amount = mValue * [10 ^ mOffset]
707 // Representation range is 10^80 - 10^(-80).
708 //
709 // On the wire:
710 // - high bit is 0 for XRP, 1 for issued currency
711 // - next bit is 1 for positive, 0 for negative (except 0 issued currency, which
712 // is a special case of 0x8000000000000000
713 // - for issued currencies, the next 8 bits are (mOffset+97).
714 // The +97 is so that this value is always positive.
715 // - The remaining bits are significant digits (mantissa)
716 // That's 54 bits for issued currency and 62 bits for native
717 // (but XRP only needs 57 bits for the max value of 10^17 drops)
718 //
719 // mValue is zero if the amount is zero, otherwise it's within the range
720 // 10^15 to (10^16 - 1) inclusive.
721 // mOffset is in the range -96 to +80.
722 void
724 {
725  if (isXRP(*this))
726  {
727  // native currency amounts should always have an offset of zero
728  mIsNative = true;
729 
730  // log(2^64,10) ~ 19.2
731  if (mValue == 0 || mOffset <= -20)
732  {
733  mValue = 0;
734  mOffset = 0;
735  mIsNegative = false;
736  return;
737  }
738 
740  {
741  // log(cMaxNativeN, 10) == 17
742  if (mOffset > 17)
743  Throw<std::runtime_error>(
744  "Native currency amount out of range");
745  }
746 
748  {
749  Number num(
751  XRPAmount xrp{num};
752  mIsNegative = xrp.drops() < 0;
753  mValue = mIsNegative ? -xrp.drops() : xrp.drops();
754  mOffset = 0;
755  }
756  else
757  {
758  while (mOffset < 0)
759  {
760  mValue /= 10;
761  ++mOffset;
762  }
763 
764  while (mOffset > 0)
765  {
767  {
768  // N.B. do not move the overflow check to after the
769  // multiplication
770  if (mValue > cMaxNativeN)
771  Throw<std::runtime_error>(
772  "Native currency amount out of range");
773  }
774  mValue *= 10;
775  --mOffset;
776  }
777  }
778 
779  if (mValue > cMaxNativeN)
780  Throw<std::runtime_error>("Native currency amount out of range");
781 
782  return;
783  }
784 
785  mIsNative = false;
786 
787  if (getSTNumberSwitchover())
788  {
789  *this = iou();
790  return;
791  }
792 
793  if (mValue == 0)
794  {
795  mOffset = -100;
796  mIsNegative = false;
797  return;
798  }
799 
800  while ((mValue < cMinValue) && (mOffset > cMinOffset))
801  {
802  mValue *= 10;
803  --mOffset;
804  }
805 
806  while (mValue > cMaxValue)
807  {
808  if (mOffset >= cMaxOffset)
809  Throw<std::runtime_error>("value overflow");
810 
811  mValue /= 10;
812  ++mOffset;
813  }
814 
815  if ((mOffset < cMinOffset) || (mValue < cMinValue))
816  {
817  mValue = 0;
818  mIsNegative = false;
819  mOffset = -100;
820  return;
821  }
822 
823  if (mOffset > cMaxOffset)
824  Throw<std::runtime_error>("value overflow");
825 
826  assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)));
827  assert(
828  (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)));
829  assert((mValue != 0) || (mOffset != -100));
830 }
831 
832 void
834 {
835  if (v < 0)
836  {
837  mIsNegative = true;
838  mValue = static_cast<std::uint64_t>(-v);
839  }
840  else
841  {
842  mIsNegative = false;
843  mValue = static_cast<std::uint64_t>(v);
844  }
845 }
846 
847 //------------------------------------------------------------------------------
848 
849 STAmount
851 {
852  if (rate == 0)
853  return STAmount(noIssue());
854 
855  std::uint64_t mantissa = rate & ~(255ull << (64 - 8));
856  int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
857 
858  return STAmount(noIssue(), mantissa, exponent);
859 }
860 
861 STAmount
862 amountFromString(Issue const& issue, std::string const& amount)
863 {
864  static boost::regex const reNumber(
865  "^" // the beginning of the string
866  "([-+]?)" // (optional) + or - character
867  "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
868  "(\\.([0-9]+))?" // (optional) period followed by any number
869  "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
870  "$",
871  boost::regex_constants::optimize);
872 
873  boost::smatch match;
874 
875  if (!boost::regex_match(amount, match, reNumber))
876  Throw<std::runtime_error>("Number '" + amount + "' is not valid");
877 
878  // Match fields:
879  // 0 = whole input
880  // 1 = sign
881  // 2 = integer portion
882  // 3 = whole fraction (with '.')
883  // 4 = fraction (without '.')
884  // 5 = whole exponent (with 'e')
885  // 6 = exponent sign
886  // 7 = exponent number
887 
888  // CHECKME: Why 32? Shouldn't this be 16?
889  if ((match[2].length() + match[4].length()) > 32)
890  Throw<std::runtime_error>("Number '" + amount + "' is overlong");
891 
892  bool negative = (match[1].matched && (match[1] == "-"));
893 
894  // Can't specify XRP using fractional representation
895  if (isXRP(issue) && match[3].matched)
896  Throw<std::runtime_error>("XRP must be specified in integral drops.");
897 
898  std::uint64_t mantissa;
899  int exponent;
900 
901  if (!match[4].matched) // integer only
902  {
903  mantissa =
904  beast::lexicalCastThrow<std::uint64_t>(std::string(match[2]));
905  exponent = 0;
906  }
907  else
908  {
909  // integer and fraction
910  mantissa = beast::lexicalCastThrow<std::uint64_t>(match[2] + match[4]);
911  exponent = -(match[4].length());
912  }
913 
914  if (match[5].matched)
915  {
916  // we have an exponent
917  if (match[6].matched && (match[6] == "-"))
918  exponent -= beast::lexicalCastThrow<int>(std::string(match[7]));
919  else
920  exponent += beast::lexicalCastThrow<int>(std::string(match[7]));
921  }
922 
923  return {issue, mantissa, exponent, negative};
924 }
925 
926 STAmount
927 amountFromJson(SField const& name, Json::Value const& v)
928 {
929  STAmount::mantissa_type mantissa = 0;
930  STAmount::exponent_type exponent = 0;
931  bool negative = false;
932  Issue issue;
933 
934  Json::Value value;
935  Json::Value currency;
936  Json::Value issuer;
937 
938  if (v.isNull())
939  {
940  Throw<std::runtime_error>(
941  "XRP may not be specified with a null Json value");
942  }
943  else if (v.isObject())
944  {
945  value = v[jss::value];
946  currency = v[jss::currency];
947  issuer = v[jss::issuer];
948  }
949  else if (v.isArray())
950  {
951  value = v.get(Json::UInt(0), 0);
952  currency = v.get(Json::UInt(1), Json::nullValue);
953  issuer = v.get(Json::UInt(2), Json::nullValue);
954  }
955  else if (v.isString())
956  {
957  std::string val = v.asString();
958  std::vector<std::string> elements;
959  boost::split(elements, val, boost::is_any_of("\t\n\r ,/"));
960 
961  if (elements.size() > 3)
962  Throw<std::runtime_error>("invalid amount string");
963 
964  value = elements[0];
965 
966  if (elements.size() > 1)
967  currency = elements[1];
968 
969  if (elements.size() > 2)
970  issuer = elements[2];
971  }
972  else
973  {
974  value = v;
975  }
976 
977  bool const native = !currency.isString() || currency.asString().empty() ||
978  (currency.asString() == systemCurrencyCode());
979 
980  if (native)
981  {
982  if (v.isObjectOrNull())
983  Throw<std::runtime_error>("XRP may not be specified as an object");
984  issue = xrpIssue();
985  }
986  else
987  {
988  // non-XRP
989  if (!to_currency(issue.currency, currency.asString()))
990  Throw<std::runtime_error>("invalid currency");
991 
992  if (!issuer.isString() || !to_issuer(issue.account, issuer.asString()))
993  Throw<std::runtime_error>("invalid issuer");
994 
995  if (isXRP(issue.currency))
996  Throw<std::runtime_error>("invalid issuer");
997  }
998 
999  if (value.isInt())
1000  {
1001  if (value.asInt() >= 0)
1002  {
1003  mantissa = value.asInt();
1004  }
1005  else
1006  {
1007  mantissa = -value.asInt();
1008  negative = true;
1009  }
1010  }
1011  else if (value.isUInt())
1012  {
1013  mantissa = v.asUInt();
1014  }
1015  else if (value.isString())
1016  {
1017  auto const ret = amountFromString(issue, value.asString());
1018 
1019  mantissa = ret.mantissa();
1020  exponent = ret.exponent();
1021  negative = ret.negative();
1022  }
1023  else
1024  {
1025  Throw<std::runtime_error>("invalid amount type");
1026  }
1027 
1028  return {name, issue, mantissa, exponent, native, negative};
1029 }
1030 
1031 bool
1032 amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource)
1033 {
1034  try
1035  {
1036  result = amountFromJson(sfGeneric, jvSource);
1037  return true;
1038  }
1039  catch (const std::exception& e)
1040  {
1041  JLOG(debugLog().warn())
1042  << "amountFromJsonNoThrow: caught: " << e.what();
1043  }
1044  return false;
1045 }
1046 
1047 //------------------------------------------------------------------------------
1048 //
1049 // Operators
1050 //
1051 //------------------------------------------------------------------------------
1052 
1053 bool
1054 operator==(STAmount const& lhs, STAmount const& rhs)
1055 {
1056  return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() &&
1057  lhs.exponent() == rhs.exponent() && lhs.mantissa() == rhs.mantissa();
1058 }
1059 
1060 bool
1061 operator<(STAmount const& lhs, STAmount const& rhs)
1062 {
1063  if (!areComparable(lhs, rhs))
1064  Throw<std::runtime_error>(
1065  "Can't compare amounts that are't comparable!");
1066 
1067  if (lhs.negative() != rhs.negative())
1068  return lhs.negative();
1069 
1070  if (lhs.mantissa() == 0)
1071  {
1072  if (rhs.negative())
1073  return false;
1074  return rhs.mantissa() != 0;
1075  }
1076 
1077  // We know that lhs is non-zero and both sides have the same sign. Since
1078  // rhs is zero (and thus not negative), lhs must, therefore, be strictly
1079  // greater than zero. So if rhs is zero, the comparison must be false.
1080  if (rhs.mantissa() == 0)
1081  return false;
1082 
1083  if (lhs.exponent() > rhs.exponent())
1084  return lhs.negative();
1085  if (lhs.exponent() < rhs.exponent())
1086  return !lhs.negative();
1087  if (lhs.mantissa() > rhs.mantissa())
1088  return lhs.negative();
1089  if (lhs.mantissa() < rhs.mantissa())
1090  return !lhs.negative();
1091 
1092  return false;
1093 }
1094 
1095 STAmount
1096 operator-(STAmount const& value)
1097 {
1098  if (value.mantissa() == 0)
1099  return value;
1100  return STAmount(
1101  value.getFName(),
1102  value.issue(),
1103  value.mantissa(),
1104  value.exponent(),
1105  value.native(),
1106  !value.negative(),
1108 }
1109 
1110 //------------------------------------------------------------------------------
1111 //
1112 // Arithmetic
1113 //
1114 //------------------------------------------------------------------------------
1115 
1116 // Calculate (a * b) / c when all three values are 64-bit
1117 // without loss of precision:
1118 static std::uint64_t
1120  std::uint64_t multiplier,
1121  std::uint64_t multiplicand,
1122  std::uint64_t divisor)
1123 {
1124  boost::multiprecision::uint128_t ret;
1125 
1126  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1127  ret /= divisor;
1128 
1130  {
1131  Throw<std::overflow_error>(
1132  "overflow: (" + std::to_string(multiplier) + " * " +
1133  std::to_string(multiplicand) + ") / " + std::to_string(divisor));
1134  }
1135 
1136  return static_cast<uint64_t>(ret);
1137 }
1138 
1139 static std::uint64_t
1141  std::uint64_t multiplier,
1142  std::uint64_t multiplicand,
1143  std::uint64_t divisor,
1144  std::uint64_t rounding)
1145 {
1146  boost::multiprecision::uint128_t ret;
1147 
1148  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1149  ret += rounding;
1150  ret /= divisor;
1151 
1153  {
1154  Throw<std::overflow_error>(
1155  "overflow: ((" + std::to_string(multiplier) + " * " +
1156  std::to_string(multiplicand) + ") + " + std::to_string(rounding) +
1157  ") / " + std::to_string(divisor));
1158  }
1159 
1160  return static_cast<uint64_t>(ret);
1161 }
1162 
1163 STAmount
1164 divide(STAmount const& num, STAmount const& den, Issue const& issue)
1165 {
1166  if (den == beast::zero)
1167  Throw<std::runtime_error>("division by zero");
1168 
1169  if (num == beast::zero)
1170  return {issue};
1171 
1172  std::uint64_t numVal = num.mantissa();
1173  std::uint64_t denVal = den.mantissa();
1174  int numOffset = num.exponent();
1175  int denOffset = den.exponent();
1176 
1177  if (num.native())
1178  {
1179  while (numVal < STAmount::cMinValue)
1180  {
1181  // Need to bring into range
1182  numVal *= 10;
1183  --numOffset;
1184  }
1185  }
1186 
1187  if (den.native())
1188  {
1189  while (denVal < STAmount::cMinValue)
1190  {
1191  denVal *= 10;
1192  --denOffset;
1193  }
1194  }
1195 
1196  // We divide the two mantissas (each is between 10^15
1197  // and 10^16). To maintain precision, we multiply the
1198  // numerator by 10^17 (the product is in the range of
1199  // 10^32 to 10^33) followed by a division, so the result
1200  // is in the range of 10^16 to 10^15.
1201  return STAmount(
1202  issue,
1203  muldiv(numVal, tenTo17, denVal) + 5,
1204  numOffset - denOffset - 17,
1205  num.negative() != den.negative());
1206 }
1207 
1208 STAmount
1209 multiply(STAmount const& v1, STAmount const& v2, Issue const& issue)
1210 {
1211  if (v1 == beast::zero || v2 == beast::zero)
1212  return STAmount(issue);
1213 
1214  if (v1.native() && v2.native() && isXRP(issue))
1215  {
1216  std::uint64_t const minV =
1217  getSNValue(v1) < getSNValue(v2) ? getSNValue(v1) : getSNValue(v2);
1218  std::uint64_t const maxV =
1219  getSNValue(v1) < getSNValue(v2) ? getSNValue(v2) : getSNValue(v1);
1220 
1221  if (minV > 3000000000ull) // sqrt(cMaxNative)
1222  Throw<std::runtime_error>("Native value overflow");
1223 
1224  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1225  Throw<std::runtime_error>("Native value overflow");
1226 
1227  return STAmount(v1.getFName(), minV * maxV);
1228  }
1229 
1230  if (getSTNumberSwitchover())
1231  return {IOUAmount{Number{v1} * Number{v2}}, issue};
1232 
1233  std::uint64_t value1 = v1.mantissa();
1234  std::uint64_t value2 = v2.mantissa();
1235  int offset1 = v1.exponent();
1236  int offset2 = v2.exponent();
1237 
1238  if (v1.native())
1239  {
1240  while (value1 < STAmount::cMinValue)
1241  {
1242  value1 *= 10;
1243  --offset1;
1244  }
1245  }
1246 
1247  if (v2.native())
1248  {
1249  while (value2 < STAmount::cMinValue)
1250  {
1251  value2 *= 10;
1252  --offset2;
1253  }
1254  }
1255 
1256  // We multiply the two mantissas (each is between 10^15
1257  // and 10^16), so their product is in the 10^30 to 10^32
1258  // range. Dividing their product by 10^14 maintains the
1259  // precision, by scaling the result to 10^16 to 10^18.
1260  return STAmount(
1261  issue,
1262  muldiv(value1, value2, tenTo14) + 7,
1263  offset1 + offset2 + 14,
1264  v1.negative() != v2.negative());
1265 }
1266 
1267 // This is the legacy version of canonicalizeRound. It's been in use
1268 // for years, so it is deeply embedded in the behavior of cross-currency
1269 // transactions.
1270 //
1271 // However in 2022 it was noticed that the rounding characteristics were
1272 // surprising. When the code converts from IOU-like to XRP-like there may
1273 // be a fraction of the IOU-like representation that is too small to be
1274 // represented in drops. `canonicalizeRound()` currently does some unusual
1275 // rounding.
1276 //
1277 // 1. If the fractional part is greater than or equal to 0.1, then the
1278 // number of drops is rounded up.
1279 //
1280 // 2. However, if the fractional part is less than 0.1 (for example,
1281 // 0.099999), then the number of drops is rounded down.
1282 //
1283 // The XRP Ledger has this rounding behavior baked in. But there are
1284 // situations where this rounding behavior led to undesirable outcomes.
1285 // So an alternative rounding approach was introduced. You'll see that
1286 // alternative below.
1287 static void
1288 canonicalizeRound(bool native, std::uint64_t& value, int& offset, bool)
1289 {
1290  if (native)
1291  {
1292  if (offset < 0)
1293  {
1294  int loops = 0;
1295 
1296  while (offset < -1)
1297  {
1298  value /= 10;
1299  ++offset;
1300  ++loops;
1301  }
1302 
1303  value += (loops >= 2) ? 9 : 10; // add before last divide
1304  value /= 10;
1305  ++offset;
1306  }
1307  }
1308  else if (value > STAmount::cMaxValue)
1309  {
1310  while (value > (10 * STAmount::cMaxValue))
1311  {
1312  value /= 10;
1313  ++offset;
1314  }
1315 
1316  value += 9; // add before last divide
1317  value /= 10;
1318  ++offset;
1319  }
1320 }
1321 
1322 // The original canonicalizeRound did not allow the rounding direction to
1323 // be specified. It also ignored some of the bits that could contribute to
1324 // rounding decisions. canonicalizeRoundStrict() tracks all of the bits in
1325 // the value being rounded.
1326 static void
1328  bool native,
1329  std::uint64_t& value,
1330  int& offset,
1331  bool roundUp)
1332 {
1333  if (native)
1334  {
1335  if (offset < 0)
1336  {
1337  bool hadRemainder = false;
1338 
1339  while (offset < -1)
1340  {
1341  // It would be better to use std::lldiv than to separately
1342  // compute the remainder. But std::lldiv does not support
1343  // unsigned arguments.
1344  std::uint64_t const newValue = value / 10;
1345  hadRemainder |= (value != (newValue * 10));
1346  value = newValue;
1347  ++offset;
1348  }
1349  value +=
1350  (hadRemainder && roundUp) ? 10 : 9; // Add before last divide
1351  value /= 10;
1352  ++offset;
1353  }
1354  }
1355  else if (value > STAmount::cMaxValue)
1356  {
1357  while (value > (10 * STAmount::cMaxValue))
1358  {
1359  value /= 10;
1360  ++offset;
1361  }
1362  value += 9; // add before last divide
1363  value /= 10;
1364  ++offset;
1365  }
1366 }
1367 
1368 namespace {
1369 
1370 // saveNumberRoundMode doesn't do quite enough for us. What we want is a
1371 // Number::RoundModeGuard that sets the new mode and restores the old mode
1372 // when it leaves scope. Since Number doesn't have that facility, we'll
1373 // build it here.
1374 class NumberRoundModeGuard
1375 {
1376  saveNumberRoundMode saved_;
1377 
1378 public:
1379  explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept
1380  : saved_{Number::setround(mode)}
1381  {
1382  }
1383 
1384  NumberRoundModeGuard(NumberRoundModeGuard const&) = delete;
1385 
1386  NumberRoundModeGuard&
1387  operator=(NumberRoundModeGuard const&) = delete;
1388 };
1389 
1390 // We need a class that has an interface similar to NumberRoundModeGuard
1391 // but does nothing.
1392 class DontAffectNumberRoundMode
1393 {
1394 public:
1395  explicit DontAffectNumberRoundMode(Number::rounding_mode mode) noexcept
1396  {
1397  }
1398 
1399  DontAffectNumberRoundMode(DontAffectNumberRoundMode const&) = delete;
1400 
1401  DontAffectNumberRoundMode&
1402  operator=(DontAffectNumberRoundMode const&) = delete;
1403 };
1404 
1405 } // anonymous namespace
1406 
1407 // Pass the canonicalizeRound function pointer as a template parameter.
1408 //
1409 // We might need to use NumberRoundModeGuard. Allow the caller
1410 // to pass either that or a replacement as a template parameter.
1411 template <
1412  void (*CanonicalizeFunc)(bool, std::uint64_t&, int&, bool),
1413  typename MightSaveRound>
1414 static STAmount
1416  STAmount const& v1,
1417  STAmount const& v2,
1418  Issue const& issue,
1419  bool roundUp)
1420 {
1421  if (v1 == beast::zero || v2 == beast::zero)
1422  return {issue};
1423 
1424  bool const xrp = isXRP(issue);
1425 
1426  if (v1.native() && v2.native() && xrp)
1427  {
1428  std::uint64_t minV =
1429  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v1) : getSNValue(v2);
1430  std::uint64_t maxV =
1431  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v2) : getSNValue(v1);
1432 
1433  if (minV > 3000000000ull) // sqrt(cMaxNative)
1434  Throw<std::runtime_error>("Native value overflow");
1435 
1436  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1437  Throw<std::runtime_error>("Native value overflow");
1438 
1439  return STAmount(v1.getFName(), minV * maxV);
1440  }
1441 
1442  std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa();
1443  int offset1 = v1.exponent(), offset2 = v2.exponent();
1444 
1445  if (v1.native())
1446  {
1447  while (value1 < STAmount::cMinValue)
1448  {
1449  value1 *= 10;
1450  --offset1;
1451  }
1452  }
1453 
1454  if (v2.native())
1455  {
1456  while (value2 < STAmount::cMinValue)
1457  {
1458  value2 *= 10;
1459  --offset2;
1460  }
1461  }
1462 
1463  bool const resultNegative = v1.negative() != v2.negative();
1464 
1465  // We multiply the two mantissas (each is between 10^15
1466  // and 10^16), so their product is in the 10^30 to 10^32
1467  // range. Dividing their product by 10^14 maintains the
1468  // precision, by scaling the result to 10^16 to 10^18.
1469  //
1470  // If the we're rounding up, we want to round up away
1471  // from zero, and if we're rounding down, truncation
1472  // is implicit.
1473  std::uint64_t amount = muldiv_round(
1474  value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0);
1475 
1476  int offset = offset1 + offset2 + 14;
1477  if (resultNegative != roundUp)
1478  {
1479  CanonicalizeFunc(xrp, amount, offset, roundUp);
1480  }
1481  STAmount result = [&]() {
1482  // If appropriate, tell Number to round down. This gives the desired
1483  // result from STAmount::canonicalize.
1484  MightSaveRound const savedRound(Number::towards_zero);
1485  return STAmount(issue, amount, offset, resultNegative);
1486  }();
1487 
1488  if (roundUp && !resultNegative && !result)
1489  {
1490  if (xrp)
1491  {
1492  // return the smallest value above zero
1493  amount = 1;
1494  offset = 0;
1495  }
1496  else
1497  {
1498  // return the smallest value above zero
1499  amount = STAmount::cMinValue;
1500  offset = STAmount::cMinOffset;
1501  }
1502  return STAmount(issue, amount, offset, resultNegative);
1503  }
1504  return result;
1505 }
1506 
1507 STAmount
1509  STAmount const& v1,
1510  STAmount const& v2,
1511  Issue const& issue,
1512  bool roundUp)
1513 {
1514  return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1515  v1, v2, issue, roundUp);
1516 }
1517 
1518 STAmount
1520  STAmount const& v1,
1521  STAmount const& v2,
1522  Issue const& issue,
1523  bool roundUp)
1524 {
1525  return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1526  v1, v2, issue, roundUp);
1527 }
1528 
1529 // We might need to use NumberRoundModeGuard. Allow the caller
1530 // to pass either that or a replacement as a template parameter.
1531 template <typename MightSaveRound>
1532 static STAmount
1534  STAmount const& num,
1535  STAmount const& den,
1536  Issue const& issue,
1537  bool roundUp)
1538 {
1539  if (den == beast::zero)
1540  Throw<std::runtime_error>("division by zero");
1541 
1542  if (num == beast::zero)
1543  return {issue};
1544 
1545  std::uint64_t numVal = num.mantissa(), denVal = den.mantissa();
1546  int numOffset = num.exponent(), denOffset = den.exponent();
1547 
1548  if (num.native())
1549  {
1550  while (numVal < STAmount::cMinValue)
1551  {
1552  numVal *= 10;
1553  --numOffset;
1554  }
1555  }
1556 
1557  if (den.native())
1558  {
1559  while (denVal < STAmount::cMinValue)
1560  {
1561  denVal *= 10;
1562  --denOffset;
1563  }
1564  }
1565 
1566  bool const resultNegative = (num.negative() != den.negative());
1567 
1568  // We divide the two mantissas (each is between 10^15
1569  // and 10^16). To maintain precision, we multiply the
1570  // numerator by 10^17 (the product is in the range of
1571  // 10^32 to 10^33) followed by a division, so the result
1572  // is in the range of 10^16 to 10^15.
1573  //
1574  // We round away from zero if we're rounding up or
1575  // truncate if we're rounding down.
1576  std::uint64_t amount = muldiv_round(
1577  numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1578 
1579  int offset = numOffset - denOffset - 17;
1580 
1581  if (resultNegative != roundUp)
1582  canonicalizeRound(isXRP(issue), amount, offset, roundUp);
1583 
1584  STAmount result = [&]() {
1585  // If appropriate, tell Number the rounding mode we are using.
1586  // Note that "roundUp == true" actually means "round away from zero".
1587  // Otherwise round toward zero.
1588  using enum Number::rounding_mode;
1589  MightSaveRound const savedRound(
1590  roundUp ^ resultNegative ? upward : downward);
1591  return STAmount(issue, amount, offset, resultNegative);
1592  }();
1593 
1594  if (roundUp && !resultNegative && !result)
1595  {
1596  if (isXRP(issue))
1597  {
1598  // return the smallest value above zero
1599  amount = 1;
1600  offset = 0;
1601  }
1602  else
1603  {
1604  // return the smallest value above zero
1605  amount = STAmount::cMinValue;
1606  offset = STAmount::cMinOffset;
1607  }
1608  return STAmount(issue, amount, offset, resultNegative);
1609  }
1610  return result;
1611 }
1612 
1613 STAmount
1615  STAmount const& num,
1616  STAmount const& den,
1617  Issue const& issue,
1618  bool roundUp)
1619 {
1620  return divRoundImpl<DontAffectNumberRoundMode>(num, den, issue, roundUp);
1621 }
1622 
1623 STAmount
1625  STAmount const& num,
1626  STAmount const& den,
1627  Issue const& issue,
1628  bool roundUp)
1629 {
1630  return divRoundImpl<NumberRoundModeGuard>(num, den, issue, roundUp);
1631 }
1632 
1633 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::STAmount::mIsNative
bool mIsNative
Definition: STAmount.h:57
ripple::STAmount::move
STBase * move(std::size_t n, void *buf) override
Definition: STAmount.cpp:334
ripple::systemCurrencyCode
static std::string const & systemCurrencyCode()
Definition: SystemParameters.h:62
ripple::STAmount::copy
STBase * copy(std::size_t n, void *buf) const override
Definition: STAmount.cpp:328
ripple::to_currency
bool to_currency(Currency &currency, std::string const &code)
Tries to convert a string to a Currency, returns true on success.
Definition: UintTypes.cpp:80
ripple::muldiv_round
static std::uint64_t muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
Definition: STAmount.cpp:1140
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:1032
ripple::IOUAmount::exponent
int exponent() const noexcept
Definition: IOUAmount.h:163
ripple::Issue
A currency issued by an account.
Definition: Issue.h:35
Json::Value::isObject
bool isObject() const
Definition: json_value.cpp:1027
std::string
STL class.
Json::Value::isString
bool isString() const
Definition: json_value.cpp:1009
ripple::STAmount::cMinValue
static const std::uint64_t cMinValue
Definition: STAmount.h:67
std::exception
STL class.
ripple::STAmount::set
void set(std::int64_t v)
Definition: STAmount.cpp:833
ripple::JsonOptions
JsonOptions
Definition: STBase.h:34
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:328
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:350
ripple::STAmount::mantissa
std::uint64_t mantissa() const noexcept
Definition: STAmount.h:344
std::string::reserve
T reserve(T... args)
ripple::XRPAmount::drops
constexpr value_type drops() const
Returns the number of drops.
Definition: XRPAmount.h:172
Json::UInt
unsigned int UInt
Definition: json_forwards.h:27
Json::Value::get
Value get(UInt index, const Value &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
Definition: json_value.cpp:834
std::vector< std::string >
std::find_if
T find_if(T... args)
std::string::length
T length(T... args)
ripple::STI_AMOUNT
@ STI_AMOUNT
Definition: SField.h:66
ripple::mulRoundStrict
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1519
ripple::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:569
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:653
ripple::SerializedTypeID
SerializedTypeID
Definition: SField.h:55
ripple::operator-
Number operator-(Number const &x, Number const &y)
Definition: Number.h:277
ripple::STAmount::mValue
mantissa_type mValue
Definition: STAmount.h:55
ripple::canonicalizeRound
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset, bool)
Definition: STAmount.cpp:1288
iterator
ripple::Issue::currency
Currency currency
Definition: Issue.h:38
ripple::tenTo14
static const std::uint64_t tenTo14
Definition: STAmount.cpp:60
std::distance
T distance(T... args)
ripple::STAmount::cMinOffset
static const int cMinOffset
Definition: STAmount.h:63
ripple::noIssue
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:113
Json::Value::isNull
bool isNull() const
isNull() tests to see if this field is null.
Definition: json_value.cpp:967
ripple::STAmount::cNotNative
static const std::uint64_t cNotNative
Definition: STAmount.h:73
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:43
ripple::STAmount::operator=
STAmount & operator=(beast::Zero)
Definition: STAmount.h:391
ripple::Serializer::add64
int add64(std::uint64_t i)
Definition: Serializer.cpp:60
ripple::getSNValue
static std::int64_t getSNValue(STAmount const &amount)
Definition: STAmount.cpp:66
iostream
ripple::STAmount::iou
IOUAmount iou() const
Definition: STAmount.cpp:360
ripple::STAmount::operator-=
STAmount & operator-=(STAmount const &)
Definition: STAmount.cpp:401
ripple::Number::rounding_mode
rounding_mode
Definition: Number.h:161
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:452
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:345
ripple::canonicalizeRoundStrict
static void canonicalizeRoundStrict(bool native, std::uint64_t &value, int &offset, bool roundUp)
Definition: STAmount.cpp:1327
ripple::operator==
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:165
ripple::mulRound
STAmount mulRound(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1508
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:506
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:86
ripple::STAmount::getFullText
std::string getFullText() const override
Definition: STAmount.cpp:559
ripple::STAmount::exponent
int exponent() const noexcept
Definition: STAmount.h:326
ripple::STAmount::mIssue
Issue mIssue
Definition: STAmount.h:54
ripple::STAmount::setJson
void setJson(Json::Value &) const
Definition: STAmount.cpp:528
ripple::Number
Definition: Number.h:36
ripple::STAmount::STAmount
STAmount(SerialIter &sit, SField const &name)
Definition: STAmount.cpp:88
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::operator+
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:613
ripple::STBase::emplace
static STBase * emplace(std::size_t n, void *buf, T &&val)
Definition: STBase.h:165
ripple::SerialIter::get64
std::uint64_t get64()
Definition: Serializer.cpp:399
ripple::setSTAmountCanonicalizeSwitchover
void setSTAmountCanonicalizeSwitchover(bool v)
Definition: STAmount.cpp:55
ripple::operator<
bool operator<(CanonicalTXSet::Key const &lhs, CanonicalTXSet::Key const &rhs)
Definition: CanonicalTXSet.cpp:25
ripple::Number::setround
static rounding_mode setround(rounding_mode mode)
Definition: Number.cpp:47
ripple::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1614
ripple::SerialIter::get160
uint160 get160()
Definition: Serializer.h:371
ripple::divRoundStrict
STAmount divRoundStrict(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1624
ripple::Number::towards_zero
@ towards_zero
Definition: Number.h:161
ripple::safe_cast
constexpr std::enable_if_t< std::is_same_v< typename Dest::unit_type, typename Src::unit_type > &&std::is_integral_v< typename Dest::value_type > &&std::is_integral_v< typename Src::value_type >, Dest > safe_cast(Src s) noexcept
Definition: FeeUnits.h:536
ripple::Issue::getText
std::string getText() const
Definition: Issue.cpp:30
ripple::STAmount::value
STAmount const & value() const noexcept
Definition: STAmount.h:443
std::to_string
T to_string(T... args)
ripple::muldiv
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
Definition: STAmount.cpp:1119
ripple::STAmount
Definition: STAmount.h:46
ripple::divRoundImpl
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1533
ripple::getSTAmountCanonicalizeSwitchover
bool getSTAmountCanonicalizeSwitchover()
Definition: STAmount.cpp:49
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:927
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:91
ripple::SerialIter
Definition: Serializer.h:311
std::uint64_t
ripple::STAmount::setIssue
void setIssue(Issue const &issue)
Set the Issue for this amount and update mIsNative.
Definition: STAmount.cpp:490
ripple::STAmount::construct
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
Definition: STAmount.cpp:322
ripple::amountFromQuality
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:850
ripple::areComparable
static bool areComparable(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:82
memory
std::string::append
T append(T... args)
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
ripple::multiply
STAmount multiply(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:47
ripple::STBase::getFName
SField const & getFName() const
Definition: STBase.cpp:132
ripple::Serializer
Definition: Serializer.h:40
ripple::STAmount::isEquivalent
bool isEquivalent(const STBase &t) const override
Definition: STAmount.cpp:692
ripple::STAmount::native
bool native() const noexcept
Definition: STAmount.h:332
ripple::STAmount::operator+=
STAmount & operator+=(STAmount const &)
Definition: STAmount.cpp:394
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::STAmount::mIsNegative
bool mIsNegative
Definition: STAmount.h:58
ripple::IOUAmount::mantissa
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:169
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:98
ripple::amountFromString
STAmount amountFromString(Issue const &issue, std::string const &amount)
Definition: STAmount.cpp:862
ripple::STAmount::isDefault
bool isDefault() const override
Definition: STAmount.cpp:699
ripple::STAmount::unchecked
Definition: STAmount.h:81
ripple::getSTNumberSwitchover
bool getSTNumberSwitchover()
Definition: IOUAmount.cpp:42
ripple::SField
Identifies fields.
Definition: SField.h:117
ripple::STBase
A type which can be exported to a well known binary format.
Definition: STBase.h:66
std::string::begin
T begin(T... args)
std
STL namespace.
ripple::STAmount::canonicalize
void canonicalize()
Definition: STAmount.cpp:723
ripple::STAmount::add
void add(Serializer &s) const override
Definition: STAmount.cpp:661
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:985
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::STAmount::negative
bool negative() const noexcept
Definition: STAmount.h:338
std::string::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:105
ripple::STAmount::exponent_type
int exponent_type
Definition: STAmount.h:50
std::size_t
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
Json::Value::asInt
Int asInt() const
Definition: json_value.cpp:503
std::string::end
T end(T... args)
ripple::STAmount::cMaxNativeN
static const std::uint64_t cMaxNativeN
Definition: STAmount.h:72
ripple::STAmount::cMaxOffset
static const int cMaxOffset
Definition: STAmount.h:64
std::make_reverse_iterator
T make_reverse_iterator(T... args)
std::unique_ptr
STL class.
ripple::Number::unchecked
Definition: Number.h:43
ripple::tenTo14m1
static const std::uint64_t tenTo14m1
Definition: STAmount.cpp:61
std::numeric_limits
ripple::STAmount::mOffset
exponent_type mOffset
Definition: STAmount.h:56
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1033
ripple::STAmount::cPosNative
static const std::uint64_t cPosNative
Definition: STAmount.h:74
ripple::STAmount::uRateOne
static const std::uint64_t uRateOne
Definition: STAmount.h:76
ripple::STAmount::getSType
SerializedTypeID getSType() const override
Definition: STAmount.cpp:553
ripple::Issue::account
AccountID account
Definition: Issue.h:39
ripple::STAmount::cMaxValue
static const std::uint64_t cMaxValue
Definition: STAmount.h:68
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::mulRoundImpl
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1415
ripple::XRPAmount
Definition: XRPAmount.h:46
ripple::to_issuer
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
Definition: AccountID.cpp:182
ripple::tenTo17
static const std::uint64_t tenTo17
Definition: STAmount.cpp:62
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
beast
Definition: base_uint.h:641