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 LocalValue<bool> stAmountCanonicalizeSwitchover(true);
38 
39 static const std::uint64_t tenTo14 = 100000000000000ull;
40 static const std::uint64_t tenTo14m1 = tenTo14 - 1;
41 static const std::uint64_t tenTo17 = tenTo14 * 1000;
42 
43 //------------------------------------------------------------------------------
44 static std::int64_t
45 getSNValue(STAmount const& amount)
46 {
47  if (!amount.native())
48  Throw<std::runtime_error>("amount is not native!");
49 
50  auto ret = static_cast<std::int64_t>(amount.mantissa());
51 
52  assert(static_cast<std::uint64_t>(ret) == amount.mantissa());
53 
54  if (amount.negative())
55  ret = -ret;
56 
57  return ret;
58 }
59 
60 static bool
61 areComparable(STAmount const& v1, STAmount const& v2)
62 {
63  return v1.native() == v2.native() &&
64  v1.issue().currency == v2.issue().currency;
65 }
66 
67 STAmount::STAmount(SerialIter& sit, SField const& name) : STBase(name)
68 {
69  std::uint64_t value = sit.get64();
70 
71  // native
72  if ((value & cNotNative) == 0)
73  {
74  // positive
75  if ((value & cPosNative) != 0)
76  {
77  mValue = value & ~cPosNative;
78  mOffset = 0;
79  mIsNative = true;
80  mIsNegative = false;
81  return;
82  }
83 
84  // negative
85  if (value == 0)
86  Throw<std::runtime_error>("negative zero is not canonical");
87 
88  mValue = value;
89  mOffset = 0;
90  mIsNative = true;
91  mIsNegative = true;
92  return;
93  }
94 
95  Issue issue;
96  issue.currency = sit.get160();
97 
98  if (isXRP(issue.currency))
99  Throw<std::runtime_error>("invalid native currency");
100 
101  issue.account = sit.get160();
102 
103  if (isXRP(issue.account))
104  Throw<std::runtime_error>("invalid native account");
105 
106  // 10 bits for the offset, sign and "not native" flag
107  int offset = static_cast<int>(value >> (64 - 10));
108 
109  value &= ~(1023ull << (64 - 10));
110 
111  if (value)
112  {
113  bool isNegative = (offset & 256) == 0;
114  offset = (offset & 255) - 97; // center the range
115 
116  if (value < cMinValue || value > cMaxValue || offset < cMinOffset ||
117  offset > cMaxOffset)
118  {
119  Throw<std::runtime_error>("invalid currency value");
120  }
121 
122  mIssue = issue;
123  mValue = value;
124  mOffset = offset;
125  mIsNegative = isNegative;
126  canonicalize();
127  return;
128  }
129 
130  if (offset != 512)
131  Throw<std::runtime_error>("invalid currency value");
132 
133  mIssue = issue;
134  mValue = 0;
135  mOffset = 0;
136  mIsNegative = false;
137  canonicalize();
138 }
139 
141  SField const& name,
142  Issue const& issue,
143  mantissa_type mantissa,
144  exponent_type exponent,
145  bool native,
146  bool negative,
147  unchecked)
148  : STBase(name)
149  , mIssue(issue)
150  , mValue(mantissa)
151  , mOffset(exponent)
152  , mIsNative(native)
153  , mIsNegative(negative)
154 {
155 }
156 
158  Issue const& issue,
159  mantissa_type mantissa,
160  exponent_type exponent,
161  bool native,
162  bool negative,
163  unchecked)
164  : mIssue(issue)
165  , mValue(mantissa)
166  , mOffset(exponent)
167  , mIsNative(native)
168  , mIsNegative(negative)
169 {
170 }
171 
173  SField const& name,
174  Issue const& issue,
175  mantissa_type mantissa,
176  exponent_type exponent,
177  bool native,
178  bool negative)
179  : STBase(name)
180  , mIssue(issue)
181  , mValue(mantissa)
182  , mOffset(exponent)
183  , mIsNative(native)
184  , mIsNegative(negative)
185 {
186  canonicalize();
187 }
188 
189 STAmount::STAmount(SField const& name, std::int64_t mantissa)
190  : STBase(name), mOffset(0), mIsNative(true)
191 {
192  set(mantissa);
193 }
194 
195 STAmount::STAmount(SField const& name, std::uint64_t mantissa, bool negative)
196  : STBase(name)
197  , mValue(mantissa)
198  , mOffset(0)
199  , mIsNative(true)
200  , mIsNegative(negative)
201 {
203 }
204 
206  SField const& name,
207  Issue const& issue,
208  std::uint64_t mantissa,
209  int exponent,
210  bool negative)
211  : STBase(name)
212  , mIssue(issue)
213  , mValue(mantissa)
214  , mOffset(exponent)
215  , mIsNegative(negative)
216 {
218  canonicalize();
219 }
220 
221 //------------------------------------------------------------------------------
222 
223 STAmount::STAmount(std::uint64_t mantissa, bool negative)
224  : mValue(mantissa)
225  , mOffset(0)
226  , mIsNative(true)
227  , mIsNegative(mantissa != 0 && negative)
228 {
230 }
231 
233  Issue const& issue,
234  std::uint64_t mantissa,
235  int exponent,
236  bool negative)
237  : mIssue(issue), mValue(mantissa), mOffset(exponent), mIsNegative(negative)
238 {
239  canonicalize();
240 }
241 
242 STAmount::STAmount(Issue const& issue, std::int64_t mantissa, int exponent)
243  : mIssue(issue), mOffset(exponent)
244 {
245  set(mantissa);
246  canonicalize();
247 }
248 
250  Issue const& issue,
251  std::uint32_t mantissa,
252  int exponent,
253  bool negative)
254  : STAmount(issue, safe_cast<std::uint64_t>(mantissa), exponent, negative)
255 {
256 }
257 
258 STAmount::STAmount(Issue const& issue, int mantissa, int exponent)
259  : STAmount(issue, safe_cast<std::int64_t>(mantissa), exponent)
260 {
261 }
262 
263 // Legacy support for new-style amounts
264 STAmount::STAmount(IOUAmount const& amount, Issue const& issue)
265  : mIssue(issue)
266  , mOffset(amount.exponent())
267  , mIsNative(false)
268  , mIsNegative(amount < beast::zero)
269 {
270  if (mIsNegative)
271  mValue = static_cast<std::uint64_t>(-amount.mantissa());
272  else
273  mValue = static_cast<std::uint64_t>(amount.mantissa());
274 
275  canonicalize();
276 }
277 
279  : mOffset(0), mIsNative(true), mIsNegative(amount < beast::zero)
280 {
281  if (mIsNegative)
282  mValue = unsafe_cast<std::uint64_t>(-amount.drops());
283  else
284  mValue = unsafe_cast<std::uint64_t>(amount.drops());
285 
286  canonicalize();
287 }
288 
291 {
292  return std::make_unique<STAmount>(sit, name);
293 }
294 
295 //------------------------------------------------------------------------------
296 //
297 // Conversion
298 //
299 //------------------------------------------------------------------------------
300 XRPAmount
302 {
303  if (!mIsNative)
304  Throw<std::logic_error>(
305  "Cannot return non-native STAmount as XRPAmount");
306 
307  auto drops = static_cast<XRPAmount::value_type>(mValue);
308 
309  if (mIsNegative)
310  drops = -drops;
311 
312  return XRPAmount{drops};
313 }
314 
315 IOUAmount
317 {
318  if (mIsNative)
319  Throw<std::logic_error>("Cannot return native STAmount as IOUAmount");
320 
321  auto mantissa = static_cast<std::int64_t>(mValue);
322  auto exponent = mOffset;
323 
324  if (mIsNegative)
325  mantissa = -mantissa;
326 
327  return {mantissa, exponent};
328 }
329 
330 //------------------------------------------------------------------------------
331 //
332 // Operators
333 //
334 //------------------------------------------------------------------------------
335 
336 STAmount&
338 {
339  *this = *this + a;
340  return *this;
341 }
342 
343 STAmount&
345 {
346  *this = *this - a;
347  return *this;
348 }
349 
350 STAmount
351 operator+(STAmount const& v1, STAmount const& v2)
352 {
353  if (!areComparable(v1, v2))
354  Throw<std::runtime_error>("Can't add amounts that are't comparable!");
355 
356  if (v2 == beast::zero)
357  return v1;
358 
359  if (v1 == beast::zero)
360  {
361  // Result must be in terms of v1 currency and issuer.
362  return {
363  v1.getFName(),
364  v1.issue(),
365  v2.mantissa(),
366  v2.exponent(),
367  v2.negative()};
368  }
369 
370  if (v1.native())
371  return {v1.getFName(), getSNValue(v1) + getSNValue(v2)};
372 
373  int ov1 = v1.exponent(), ov2 = v2.exponent();
374  std::int64_t vv1 = static_cast<std::int64_t>(v1.mantissa());
375  std::int64_t vv2 = static_cast<std::int64_t>(v2.mantissa());
376 
377  if (v1.negative())
378  vv1 = -vv1;
379 
380  if (v2.negative())
381  vv2 = -vv2;
382 
383  while (ov1 < ov2)
384  {
385  vv1 /= 10;
386  ++ov1;
387  }
388 
389  while (ov2 < ov1)
390  {
391  vv2 /= 10;
392  ++ov2;
393  }
394 
395  // This addition cannot overflow an std::int64_t. It can overflow an
396  // STAmount and the constructor will throw.
397 
398  std::int64_t fv = vv1 + vv2;
399 
400  if ((fv >= -10) && (fv <= 10))
401  return {v1.getFName(), v1.issue()};
402 
403  if (fv >= 0)
404  return STAmount{
405  v1.getFName(),
406  v1.issue(),
407  static_cast<std::uint64_t>(fv),
408  ov1,
409  false};
410 
411  return STAmount{
412  v1.getFName(), v1.issue(), static_cast<std::uint64_t>(-fv), ov1, true};
413 }
414 
415 STAmount
416 operator-(STAmount const& v1, STAmount const& v2)
417 {
418  return v1 + (-v2);
419 }
420 
421 //------------------------------------------------------------------------------
422 
423 std::uint64_t const STAmount::uRateOne = getRate(STAmount(1), STAmount(1));
424 
425 void
427 {
428  mIssue = issue;
429  mIsNative = isXRP(*this);
430 }
431 
432 // Convert an offer into an index amount so they sort by rate.
433 // A taker will take the best, lowest, rate first.
434 // (e.g. a taker will prefer pay 1 get 3 over pay 1 get 2.
435 // --> offerOut: takerGets: How much the offerer is selling to the taker.
436 // --> offerIn: takerPays: How much the offerer is receiving from the taker.
437 // <-- uRate: normalize(offerIn/offerOut)
438 // A lower rate is better for the person taking the order.
439 // The taker gets more for less with a lower rate.
440 // Zero is returned if the offer is worthless.
442 getRate(STAmount const& offerOut, STAmount const& offerIn)
443 {
444  if (offerOut == beast::zero)
445  return 0;
446  try
447  {
448  STAmount r = divide(offerIn, offerOut, noIssue());
449  if (r == beast::zero) // offer is too good
450  return 0;
451  assert((r.exponent() >= -100) && (r.exponent() <= 155));
452  std::uint64_t ret = r.exponent() + 100;
453  return (ret << (64 - 8)) | r.mantissa();
454  }
455  catch (std::exception const&)
456  {
457  }
458 
459  // overflow -- very bad offer
460  return 0;
461 }
462 
463 void
465 {
466  elem = Json::objectValue;
467 
468  if (!mIsNative)
469  {
470  // It is an error for currency or issuer not to be specified for valid
471  // json.
472  elem[jss::value] = getText();
473  elem[jss::currency] = to_string(mIssue.currency);
474  elem[jss::issuer] = to_string(mIssue.account);
475  }
476  else
477  {
478  elem = getText();
479  }
480 }
481 
482 //------------------------------------------------------------------------------
483 //
484 // STBase
485 //
486 //------------------------------------------------------------------------------
487 
490 {
491  std::string ret;
492 
493  ret.reserve(64);
494  ret = getText() + "/" + to_string(mIssue.currency);
495 
496  if (!mIsNative)
497  {
498  ret += "/";
499 
500  if (isXRP(*this))
501  ret += "0";
502  else if (mIssue.account == noAccount())
503  ret += "1";
504  else
505  ret += to_string(mIssue.account);
506  }
507 
508  return ret;
509 }
510 
513 {
514  // keep full internal accuracy, but make more human friendly if posible
515  if (*this == beast::zero)
516  return "0";
517 
518  std::string const raw_value(std::to_string(mValue));
519  std::string ret;
520 
521  if (mIsNegative)
522  ret.append(1, '-');
523 
524  bool const scientific(
525  (mOffset != 0) && ((mOffset < -25) || (mOffset > -5)));
526 
527  if (mIsNative || scientific)
528  {
529  ret.append(raw_value);
530 
531  if (scientific)
532  {
533  ret.append(1, 'e');
535  }
536 
537  return ret;
538  }
539 
540  assert(mOffset + 43 > 0);
541 
542  size_t const pad_prefix = 27;
543  size_t const pad_suffix = 23;
544 
545  std::string val;
546  val.reserve(raw_value.length() + pad_prefix + pad_suffix);
547  val.append(pad_prefix, '0');
548  val.append(raw_value);
549  val.append(pad_suffix, '0');
550 
551  size_t const offset(mOffset + 43);
552 
553  auto pre_from(val.begin());
554  auto const pre_to(val.begin() + offset);
555 
556  auto const post_from(val.begin() + offset);
557  auto post_to(val.end());
558 
559  // Crop leading zeroes. Take advantage of the fact that there's always a
560  // fixed amount of leading zeroes and skip them.
561  if (std::distance(pre_from, pre_to) > pad_prefix)
562  pre_from += pad_prefix;
563 
564  assert(post_to >= post_from);
565 
566  pre_from = std::find_if(pre_from, pre_to, [](char c) { return c != '0'; });
567 
568  // Crop trailing zeroes. Take advantage of the fact that there's always a
569  // fixed amount of trailing zeroes and skip them.
570  if (std::distance(post_from, post_to) > pad_suffix)
571  post_to -= pad_suffix;
572 
573  assert(post_to >= post_from);
574 
575  post_to = std::find_if(
577  std::make_reverse_iterator(post_from),
578  [](char c) { return c != '0'; })
579  .base();
580 
581  // Assemble the output:
582  if (pre_from == pre_to)
583  ret.append(1, '0');
584  else
585  ret.append(pre_from, pre_to);
586 
587  if (post_to != post_from)
588  {
589  ret.append(1, '.');
590  ret.append(post_from, post_to);
591  }
592 
593  return ret;
594 }
595 
597 {
598  Json::Value elem;
599  setJson(elem);
600  return elem;
601 }
602 
603 void
605 {
606  if (mIsNative)
607  {
608  assert(mOffset == 0);
609 
610  if (!mIsNegative)
611  s.add64(mValue | cPosNative);
612  else
613  s.add64(mValue);
614  }
615  else
616  {
617  if (*this == beast::zero)
618  s.add64(cNotNative);
619  else if (mIsNegative) // 512 = not native
620  s.add64(
621  mValue |
622  (static_cast<std::uint64_t>(mOffset + 512 + 97) << (64 - 10)));
623  else // 256 = positive
624  s.add64(
625  mValue |
626  (static_cast<std::uint64_t>(mOffset + 512 + 256 + 97)
627  << (64 - 10)));
628 
631  }
632 }
633 
634 bool
636 {
637  const STAmount* v = dynamic_cast<const STAmount*>(&t);
638  return v && (*v == *this);
639 }
640 
641 //------------------------------------------------------------------------------
642 
643 // amount = mValue * [10 ^ mOffset]
644 // Representation range is 10^80 - 10^(-80).
645 //
646 // On the wire:
647 // - high bit is 0 for XRP, 1 for issued currency
648 // - next bit is 1 for positive, 0 for negative (except 0 issued currency, which
649 // is a special case of 0x8000000000000000
650 // - for issued currencies, the next 8 bits are (mOffset+97).
651 // The +97 is so that this value is always positive.
652 // - The remaining bits are significant digits (mantissa)
653 // That's 54 bits for issued currency and 62 bits for native
654 // (but XRP only needs 57 bits for the max value of 10^17 drops)
655 //
656 // mValue is zero if the amount is zero, otherwise it's within the range
657 // 10^15 to (10^16 - 1) inclusive.
658 // mOffset is in the range -96 to +80.
659 void
661 {
662  if (isXRP(*this))
663  {
664  // native currency amounts should always have an offset of zero
665  mIsNative = true;
666 
667  // log(2^64,10) ~ 19.2
668  if (mValue == 0 || mOffset <= -20)
669  {
670  mValue = 0;
671  mOffset = 0;
672  mIsNegative = false;
673  return;
674  }
675 
677  {
678  // log(cMaxNativeN, 10) == 17
679  if (mOffset > 17)
680  Throw<std::runtime_error>(
681  "Native currency amount out of range");
682  }
683 
684  while (mOffset < 0)
685  {
686  mValue /= 10;
687  ++mOffset;
688  }
689 
690  while (mOffset > 0)
691  {
693  {
694  // N.B. do not move the overflow check to after the
695  // multiplication
696  if (mValue > cMaxNativeN)
697  Throw<std::runtime_error>(
698  "Native currency amount out of range");
699  }
700  mValue *= 10;
701  --mOffset;
702  }
703 
704  if (mValue > cMaxNativeN)
705  Throw<std::runtime_error>("Native currency amount out of range");
706 
707  return;
708  }
709 
710  mIsNative = false;
711 
712  if (mValue == 0)
713  {
714  mOffset = -100;
715  mIsNegative = false;
716  return;
717  }
718 
719  while ((mValue < cMinValue) && (mOffset > cMinOffset))
720  {
721  mValue *= 10;
722  --mOffset;
723  }
724 
725  while (mValue > cMaxValue)
726  {
727  if (mOffset >= cMaxOffset)
728  Throw<std::runtime_error>("value overflow");
729 
730  mValue /= 10;
731  ++mOffset;
732  }
733 
734  if ((mOffset < cMinOffset) || (mValue < cMinValue))
735  {
736  mValue = 0;
737  mIsNegative = false;
738  mOffset = -100;
739  return;
740  }
741 
742  if (mOffset > cMaxOffset)
743  Throw<std::runtime_error>("value overflow");
744 
745  assert((mValue == 0) || ((mValue >= cMinValue) && (mValue <= cMaxValue)));
746  assert(
747  (mValue == 0) || ((mOffset >= cMinOffset) && (mOffset <= cMaxOffset)));
748  assert((mValue != 0) || (mOffset != -100));
749 }
750 
751 void
753 {
754  if (v < 0)
755  {
756  mIsNegative = true;
757  mValue = static_cast<std::uint64_t>(-v);
758  }
759  else
760  {
761  mIsNegative = false;
762  mValue = static_cast<std::uint64_t>(v);
763  }
764 }
765 
766 //------------------------------------------------------------------------------
767 
768 STAmount
770 {
771  if (rate == 0)
772  return STAmount(noIssue());
773 
774  std::uint64_t mantissa = rate & ~(255ull << (64 - 8));
775  int exponent = static_cast<int>(rate >> (64 - 8)) - 100;
776 
777  return STAmount(noIssue(), mantissa, exponent);
778 }
779 
780 STAmount
781 amountFromString(Issue const& issue, std::string const& amount)
782 {
783  static boost::regex const reNumber(
784  "^" // the beginning of the string
785  "([-+]?)" // (optional) + or - character
786  "(0|[1-9][0-9]*)" // a number (no leading zeroes, unless 0)
787  "(\\.([0-9]+))?" // (optional) period followed by any number
788  "([eE]([+-]?)([0-9]+))?" // (optional) E, optional + or -, any number
789  "$",
790  boost::regex_constants::optimize);
791 
792  boost::smatch match;
793 
794  if (!boost::regex_match(amount, match, reNumber))
795  Throw<std::runtime_error>("Number '" + amount + "' is not valid");
796 
797  // Match fields:
798  // 0 = whole input
799  // 1 = sign
800  // 2 = integer portion
801  // 3 = whole fraction (with '.')
802  // 4 = fraction (without '.')
803  // 5 = whole exponent (with 'e')
804  // 6 = exponent sign
805  // 7 = exponent number
806 
807  // CHECKME: Why 32? Shouldn't this be 16?
808  if ((match[2].length() + match[4].length()) > 32)
809  Throw<std::runtime_error>("Number '" + amount + "' is overlong");
810 
811  bool negative = (match[1].matched && (match[1] == "-"));
812 
813  // Can't specify XRP using fractional representation
814  if (isXRP(issue) && match[3].matched)
815  Throw<std::runtime_error>("XRP must be specified in integral drops.");
816 
817  std::uint64_t mantissa;
818  int exponent;
819 
820  if (!match[4].matched) // integer only
821  {
822  mantissa =
823  beast::lexicalCastThrow<std::uint64_t>(std::string(match[2]));
824  exponent = 0;
825  }
826  else
827  {
828  // integer and fraction
829  mantissa = beast::lexicalCastThrow<std::uint64_t>(match[2] + match[4]);
830  exponent = -(match[4].length());
831  }
832 
833  if (match[5].matched)
834  {
835  // we have an exponent
836  if (match[6].matched && (match[6] == "-"))
837  exponent -= beast::lexicalCastThrow<int>(std::string(match[7]));
838  else
839  exponent += beast::lexicalCastThrow<int>(std::string(match[7]));
840  }
841 
842  return {issue, mantissa, exponent, negative};
843 }
844 
845 STAmount
846 amountFromJson(SField const& name, Json::Value const& v)
847 {
848  STAmount::mantissa_type mantissa = 0;
849  STAmount::exponent_type exponent = 0;
850  bool negative = false;
851  Issue issue;
852 
853  Json::Value value;
854  Json::Value currency;
855  Json::Value issuer;
856 
857  if (v.isNull())
858  {
859  Throw<std::runtime_error>(
860  "XRP may not be specified with a null Json value");
861  }
862  else if (v.isObject())
863  {
864  value = v[jss::value];
865  currency = v[jss::currency];
866  issuer = v[jss::issuer];
867  }
868  else if (v.isArray())
869  {
870  value = v.get(Json::UInt(0), 0);
871  currency = v.get(Json::UInt(1), Json::nullValue);
872  issuer = v.get(Json::UInt(2), Json::nullValue);
873  }
874  else if (v.isString())
875  {
876  std::string val = v.asString();
877  std::vector<std::string> elements;
878  boost::split(elements, val, boost::is_any_of("\t\n\r ,/"));
879 
880  if (elements.size() > 3)
881  Throw<std::runtime_error>("invalid amount string");
882 
883  value = elements[0];
884 
885  if (elements.size() > 1)
886  currency = elements[1];
887 
888  if (elements.size() > 2)
889  issuer = elements[2];
890  }
891  else
892  {
893  value = v;
894  }
895 
896  bool const native = !currency.isString() || currency.asString().empty() ||
897  (currency.asString() == systemCurrencyCode());
898 
899  if (native)
900  {
901  if (v.isObjectOrNull())
902  Throw<std::runtime_error>("XRP may not be specified as an object");
903  issue = xrpIssue();
904  }
905  else
906  {
907  // non-XRP
908  if (!to_currency(issue.currency, currency.asString()))
909  Throw<std::runtime_error>("invalid currency");
910 
911  if (!issuer.isString() || !to_issuer(issue.account, issuer.asString()))
912  Throw<std::runtime_error>("invalid issuer");
913 
914  if (isXRP(issue.currency))
915  Throw<std::runtime_error>("invalid issuer");
916  }
917 
918  if (value.isInt())
919  {
920  if (value.asInt() >= 0)
921  {
922  mantissa = value.asInt();
923  }
924  else
925  {
926  mantissa = -value.asInt();
927  negative = true;
928  }
929  }
930  else if (value.isUInt())
931  {
932  mantissa = v.asUInt();
933  }
934  else if (value.isString())
935  {
936  auto const ret = amountFromString(issue, value.asString());
937 
938  mantissa = ret.mantissa();
939  exponent = ret.exponent();
940  negative = ret.negative();
941  }
942  else
943  {
944  Throw<std::runtime_error>("invalid amount type");
945  }
946 
947  return {name, issue, mantissa, exponent, native, negative};
948 }
949 
950 bool
951 amountFromJsonNoThrow(STAmount& result, Json::Value const& jvSource)
952 {
953  try
954  {
955  result = amountFromJson(sfGeneric, jvSource);
956  return true;
957  }
958  catch (const std::exception& e)
959  {
960  JLOG(debugLog().warn())
961  << "amountFromJsonNoThrow: caught: " << e.what();
962  }
963  return false;
964 }
965 
966 //------------------------------------------------------------------------------
967 //
968 // Operators
969 //
970 //------------------------------------------------------------------------------
971 
972 bool
973 operator==(STAmount const& lhs, STAmount const& rhs)
974 {
975  return areComparable(lhs, rhs) && lhs.negative() == rhs.negative() &&
976  lhs.exponent() == rhs.exponent() && lhs.mantissa() == rhs.mantissa();
977 }
978 
979 bool
980 operator<(STAmount const& lhs, STAmount const& rhs)
981 {
982  if (!areComparable(lhs, rhs))
983  Throw<std::runtime_error>(
984  "Can't compare amounts that are't comparable!");
985 
986  if (lhs.negative() != rhs.negative())
987  return lhs.negative();
988 
989  if (lhs.mantissa() == 0)
990  {
991  if (rhs.negative())
992  return false;
993  return rhs.mantissa() != 0;
994  }
995 
996  // We know that lhs is non-zero and both sides have the same sign. Since
997  // rhs is zero (and thus not negative), lhs must, therefore, be strictly
998  // greater than zero. So if rhs is zero, the comparison must be false.
999  if (rhs.mantissa() == 0)
1000  return false;
1001 
1002  if (lhs.exponent() > rhs.exponent())
1003  return lhs.negative();
1004  if (lhs.exponent() < rhs.exponent())
1005  return !lhs.negative();
1006  if (lhs.mantissa() > rhs.mantissa())
1007  return lhs.negative();
1008  if (lhs.mantissa() < rhs.mantissa())
1009  return !lhs.negative();
1010 
1011  return false;
1012 }
1013 
1014 STAmount
1015 operator-(STAmount const& value)
1016 {
1017  if (value.mantissa() == 0)
1018  return value;
1019  return STAmount(
1020  value.getFName(),
1021  value.issue(),
1022  value.mantissa(),
1023  value.exponent(),
1024  value.native(),
1025  !value.negative(),
1027 }
1028 
1029 //------------------------------------------------------------------------------
1030 //
1031 // Arithmetic
1032 //
1033 //------------------------------------------------------------------------------
1034 
1035 // Calculate (a * b) / c when all three values are 64-bit
1036 // without loss of precision:
1037 static std::uint64_t
1039  std::uint64_t multiplier,
1040  std::uint64_t multiplicand,
1041  std::uint64_t divisor)
1042 {
1043  boost::multiprecision::uint128_t ret;
1044 
1045  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1046  ret /= divisor;
1047 
1049  {
1050  Throw<std::overflow_error>(
1051  "overflow: (" + std::to_string(multiplier) + " * " +
1052  std::to_string(multiplicand) + ") / " + std::to_string(divisor));
1053  }
1054 
1055  return static_cast<uint64_t>(ret);
1056 }
1057 
1058 static std::uint64_t
1060  std::uint64_t multiplier,
1061  std::uint64_t multiplicand,
1062  std::uint64_t divisor,
1063  std::uint64_t rounding)
1064 {
1065  boost::multiprecision::uint128_t ret;
1066 
1067  boost::multiprecision::multiply(ret, multiplier, multiplicand);
1068  ret += rounding;
1069  ret /= divisor;
1070 
1072  {
1073  Throw<std::overflow_error>(
1074  "overflow: ((" + std::to_string(multiplier) + " * " +
1075  std::to_string(multiplicand) + ") + " + std::to_string(rounding) +
1076  ") / " + std::to_string(divisor));
1077  }
1078 
1079  return static_cast<uint64_t>(ret);
1080 }
1081 
1082 STAmount
1083 divide(STAmount const& num, STAmount const& den, Issue const& issue)
1084 {
1085  if (den == beast::zero)
1086  Throw<std::runtime_error>("division by zero");
1087 
1088  if (num == beast::zero)
1089  return {issue};
1090 
1091  std::uint64_t numVal = num.mantissa();
1092  std::uint64_t denVal = den.mantissa();
1093  int numOffset = num.exponent();
1094  int denOffset = den.exponent();
1095 
1096  if (num.native())
1097  {
1098  while (numVal < STAmount::cMinValue)
1099  {
1100  // Need to bring into range
1101  numVal *= 10;
1102  --numOffset;
1103  }
1104  }
1105 
1106  if (den.native())
1107  {
1108  while (denVal < STAmount::cMinValue)
1109  {
1110  denVal *= 10;
1111  --denOffset;
1112  }
1113  }
1114 
1115  // We divide the two mantissas (each is between 10^15
1116  // and 10^16). To maintain precision, we multiply the
1117  // numerator by 10^17 (the product is in the range of
1118  // 10^32 to 10^33) followed by a division, so the result
1119  // is in the range of 10^16 to 10^15.
1120  return STAmount(
1121  issue,
1122  muldiv(numVal, tenTo17, denVal) + 5,
1123  numOffset - denOffset - 17,
1124  num.negative() != den.negative());
1125 }
1126 
1127 STAmount
1128 multiply(STAmount const& v1, STAmount const& v2, Issue const& issue)
1129 {
1130  if (v1 == beast::zero || v2 == beast::zero)
1131  return STAmount(issue);
1132 
1133  if (v1.native() && v2.native() && isXRP(issue))
1134  {
1135  std::uint64_t const minV =
1136  getSNValue(v1) < getSNValue(v2) ? getSNValue(v1) : getSNValue(v2);
1137  std::uint64_t const maxV =
1138  getSNValue(v1) < getSNValue(v2) ? getSNValue(v2) : getSNValue(v1);
1139 
1140  if (minV > 3000000000ull) // sqrt(cMaxNative)
1141  Throw<std::runtime_error>("Native value overflow");
1142 
1143  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1144  Throw<std::runtime_error>("Native value overflow");
1145 
1146  return STAmount(v1.getFName(), minV * maxV);
1147  }
1148 
1149  std::uint64_t value1 = v1.mantissa();
1150  std::uint64_t value2 = v2.mantissa();
1151  int offset1 = v1.exponent();
1152  int offset2 = v2.exponent();
1153 
1154  if (v1.native())
1155  {
1156  while (value1 < STAmount::cMinValue)
1157  {
1158  value1 *= 10;
1159  --offset1;
1160  }
1161  }
1162 
1163  if (v2.native())
1164  {
1165  while (value2 < STAmount::cMinValue)
1166  {
1167  value2 *= 10;
1168  --offset2;
1169  }
1170  }
1171 
1172  // We multiply the two mantissas (each is between 10^15
1173  // and 10^16), so their product is in the 10^30 to 10^32
1174  // range. Dividing their product by 10^14 maintains the
1175  // precision, by scaling the result to 10^16 to 10^18.
1176  return STAmount(
1177  issue,
1178  muldiv(value1, value2, tenTo14) + 7,
1179  offset1 + offset2 + 14,
1180  v1.negative() != v2.negative());
1181 }
1182 
1183 static void
1184 canonicalizeRound(bool native, std::uint64_t& value, int& offset)
1185 {
1186  if (native)
1187  {
1188  if (offset < 0)
1189  {
1190  int loops = 0;
1191 
1192  while (offset < -1)
1193  {
1194  value /= 10;
1195  ++offset;
1196  ++loops;
1197  }
1198 
1199  value += (loops >= 2) ? 9 : 10; // add before last divide
1200  value /= 10;
1201  ++offset;
1202  }
1203  }
1204  else if (value > STAmount::cMaxValue)
1205  {
1206  while (value > (10 * STAmount::cMaxValue))
1207  {
1208  value /= 10;
1209  ++offset;
1210  }
1211 
1212  value += 9; // add before last divide
1213  value /= 10;
1214  ++offset;
1215  }
1216 }
1217 
1218 STAmount
1220  STAmount const& v1,
1221  STAmount const& v2,
1222  Issue const& issue,
1223  bool roundUp)
1224 {
1225  if (v1 == beast::zero || v2 == beast::zero)
1226  return {issue};
1227 
1228  bool const xrp = isXRP(issue);
1229 
1230  if (v1.native() && v2.native() && xrp)
1231  {
1232  std::uint64_t minV =
1233  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v1) : getSNValue(v2);
1234  std::uint64_t maxV =
1235  (getSNValue(v1) < getSNValue(v2)) ? getSNValue(v2) : getSNValue(v1);
1236 
1237  if (minV > 3000000000ull) // sqrt(cMaxNative)
1238  Throw<std::runtime_error>("Native value overflow");
1239 
1240  if (((maxV >> 32) * minV) > 2095475792ull) // cMaxNative / 2^32
1241  Throw<std::runtime_error>("Native value overflow");
1242 
1243  return STAmount(v1.getFName(), minV * maxV);
1244  }
1245 
1246  std::uint64_t value1 = v1.mantissa(), value2 = v2.mantissa();
1247  int offset1 = v1.exponent(), offset2 = v2.exponent();
1248 
1249  if (v1.native())
1250  {
1251  while (value1 < STAmount::cMinValue)
1252  {
1253  value1 *= 10;
1254  --offset1;
1255  }
1256  }
1257 
1258  if (v2.native())
1259  {
1260  while (value2 < STAmount::cMinValue)
1261  {
1262  value2 *= 10;
1263  --offset2;
1264  }
1265  }
1266 
1267  bool const resultNegative = v1.negative() != v2.negative();
1268 
1269  // We multiply the two mantissas (each is between 10^15
1270  // and 10^16), so their product is in the 10^30 to 10^32
1271  // range. Dividing their product by 10^14 maintains the
1272  // precision, by scaling the result to 10^16 to 10^18.
1273  //
1274  // If the we're rounding up, we want to round up away
1275  // from zero, and if we're rounding down, truncation
1276  // is implicit.
1277  std::uint64_t amount = muldiv_round(
1278  value1, value2, tenTo14, (resultNegative != roundUp) ? tenTo14m1 : 0);
1279 
1280  int offset = offset1 + offset2 + 14;
1281  if (resultNegative != roundUp)
1282  canonicalizeRound(xrp, amount, offset);
1283  STAmount result(issue, amount, offset, resultNegative);
1284 
1285  if (roundUp && !resultNegative && !result)
1286  {
1287  if (xrp)
1288  {
1289  // return the smallest value above zero
1290  amount = 1;
1291  offset = 0;
1292  }
1293  else
1294  {
1295  // return the smallest value above zero
1296  amount = STAmount::cMinValue;
1297  offset = STAmount::cMinOffset;
1298  }
1299  return STAmount(issue, amount, offset, resultNegative);
1300  }
1301  return result;
1302 }
1303 
1304 STAmount
1306  STAmount const& num,
1307  STAmount const& den,
1308  Issue const& issue,
1309  bool roundUp)
1310 {
1311  if (den == beast::zero)
1312  Throw<std::runtime_error>("division by zero");
1313 
1314  if (num == beast::zero)
1315  return {issue};
1316 
1317  std::uint64_t numVal = num.mantissa(), denVal = den.mantissa();
1318  int numOffset = num.exponent(), denOffset = den.exponent();
1319 
1320  if (num.native())
1321  {
1322  while (numVal < STAmount::cMinValue)
1323  {
1324  numVal *= 10;
1325  --numOffset;
1326  }
1327  }
1328 
1329  if (den.native())
1330  {
1331  while (denVal < STAmount::cMinValue)
1332  {
1333  denVal *= 10;
1334  --denOffset;
1335  }
1336  }
1337 
1338  bool const resultNegative = (num.negative() != den.negative());
1339 
1340  // We divide the two mantissas (each is between 10^15
1341  // and 10^16). To maintain precision, we multiply the
1342  // numerator by 10^17 (the product is in the range of
1343  // 10^32 to 10^33) followed by a division, so the result
1344  // is in the range of 10^16 to 10^15.
1345  //
1346  // We round away from zero if we're rounding up or
1347  // truncate if we're rounding down.
1348  std::uint64_t amount = muldiv_round(
1349  numVal, tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1350 
1351  int offset = numOffset - denOffset - 17;
1352 
1353  if (resultNegative != roundUp)
1354  canonicalizeRound(isXRP(issue), amount, offset);
1355 
1356  STAmount result(issue, amount, offset, resultNegative);
1357  if (roundUp && !resultNegative && !result)
1358  {
1359  if (isXRP(issue))
1360  {
1361  // return the smallest value above zero
1362  amount = 1;
1363  offset = 0;
1364  }
1365  else
1366  {
1367  // return the smallest value above zero
1368  amount = STAmount::cMinValue;
1369  offset = STAmount::cMinOffset;
1370  }
1371  return STAmount(issue, amount, offset, resultNegative);
1372  }
1373  return result;
1374 }
1375 
1376 } // namespace ripple
Json::Value::isInt
bool isInt() const
Definition: json_value.cpp:979
ripple::STAmount::mIsNative
bool mIsNative
Definition: STAmount.h:54
ripple::systemCurrencyCode
static std::string const & systemCurrencyCode()
Definition: SystemParameters.h:54
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:1059
ripple::amountFromJsonNoThrow
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
Definition: STAmount.cpp:951
ripple::Issue
A currency issued by an account.
Definition: Issue.h:34
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:64
std::exception
STL class.
ripple::STAmount::set
void set(std::int64_t v)
Definition: STAmount.cpp:752
ripple::JsonOptions
JsonOptions
Definition: STBase.h:34
ripple::sfGeneric
const SField sfGeneric(access, 0)
Definition: SField.h:332
ripple::STAmount::mantissa
std::uint64_t mantissa() const noexcept
Definition: STAmount.h:193
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::STAmount::getText
std::string getText() const override
Definition: STAmount.cpp:512
ripple::STAmount::getJson
Json::Value getJson(JsonOptions) const override
Definition: STAmount.cpp:596
ripple::STAmount::mValue
mantissa_type mValue
Definition: STAmount.h:52
iterator
ripple::Issue::currency
Currency currency
Definition: Issue.h:37
ripple::tenTo14
static const std::uint64_t tenTo14
Definition: STAmount.cpp:39
std::distance
T distance(T... args)
ripple::STAmount::cMinOffset
static const int cMinOffset
Definition: STAmount.h:60
ripple::noIssue
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
Definition: Issue.h:105
ripple::operator-
STAmount operator-(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:416
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:70
ripple::IOUAmount
Floating point representation of amounts with high dynamic range.
Definition: IOUAmount.h:41
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:45
iostream
ripple::STAmount::iou
IOUAmount iou() const
Definition: STAmount.cpp:316
ripple::STAmount::operator-=
STAmount & operator-=(STAmount const &)
Definition: STAmount.cpp:344
ripple::debugLog
beast::Journal debugLog()
Returns a debug journal.
Definition: Log.cpp:452
ripple::STAmount::xrp
XRPAmount xrp() const
Definition: STAmount.cpp:301
ripple::operator==
bool operator==(Manifest const &lhs, Manifest const &rhs)
Definition: Manifest.h:159
ripple::mulRound
STAmount mulRound(STAmount const &v1, STAmount const &v2, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1219
ripple::getRate
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
Definition: STAmount.cpp:442
ripple::divide
STAmount divide(STAmount const &amount, Rate const &rate)
Definition: Rate2.cpp:77
ripple::STAmount::getFullText
std::string getFullText() const override
Definition: STAmount.cpp:489
ripple::STAmount::exponent
int exponent() const noexcept
Definition: STAmount.h:178
ripple::STAmount::mIssue
Issue mIssue
Definition: STAmount.h:51
ripple::STAmount::setJson
void setJson(Json::Value &) const
Definition: STAmount.cpp:464
ripple::operator+
const base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
Definition: base_uint.h:626
ripple::STAmount::STAmount
STAmount(SerialIter &sit, SField const &name)
Definition: STAmount.cpp:67
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
ripple::SerialIter::get64
std::uint64_t get64()
Definition: Serializer.cpp:399
ripple::operator<
bool operator<(CanonicalTXSet::Key const &lhs, CanonicalTXSet::Key const &rhs)
Definition: CanonicalTXSet.cpp:25
ripple::divRound
STAmount divRound(STAmount const &num, STAmount const &den, Issue const &issue, bool roundUp)
Definition: STAmount.cpp:1305
ripple::SerialIter::get160
uint160 get160()
Definition: Serializer.h:370
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:537
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:1038
ripple::STAmount
Definition: STAmount.h:43
ripple::amountFromJson
STAmount amountFromJson(SField const &name, Json::Value const &v)
Definition: STAmount.cpp:846
ripple::isXRP
bool isXRP(AccountID const &c)
Definition: AccountID.h:89
ripple::SerialIter
Definition: Serializer.h:310
std::uint64_t
ripple::STAmount::setIssue
void setIssue(Issue const &issue)
Set the Issue for this amount and update mIsNative.
Definition: STAmount.cpp:426
ripple::canonicalizeRound
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset)
Definition: STAmount.cpp:1184
ripple::STAmount::construct
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
Definition: STAmount.cpp:290
ripple::amountFromQuality
STAmount amountFromQuality(std::uint64_t rate)
Definition: STAmount.cpp:769
ripple::areComparable
static bool areComparable(STAmount const &v1, STAmount const &v2)
Definition: STAmount.cpp:61
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:38
ripple::STBase::getFName
SField const & getFName() const
Definition: STBase.cpp:120
ripple::Serializer
Definition: Serializer.h:39
ripple::STAmount::isEquivalent
bool isEquivalent(const STBase &t) const override
Definition: STAmount.cpp:635
ripple::STAmount::native
bool native() const noexcept
Definition: STAmount.h:183
ripple::STAmount::operator+=
STAmount & operator+=(STAmount const &)
Definition: STAmount.cpp:337
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:55
ripple::IOUAmount::mantissa
std::int64_t mantissa() const noexcept
Definition: IOUAmount.h:128
ripple::Serializer::addBitString
int addBitString(base_uint< Bits, Tag > const &v)
Definition: Serializer.h:97
ripple::amountFromString
STAmount amountFromString(Issue const &issue, std::string const &amount)
Definition: STAmount.cpp:781
ripple::STAmount::unchecked
Definition: STAmount.h:78
ripple::SField
Identifies fields.
Definition: SField.h:109
ripple::STBase
A type which can be exported to a well known binary format.
Definition: STBase.h:62
std::string::begin
T begin(T... args)
ripple::STAmount::issue
Issue const & issue() const
Definition: STAmount.h:198
std
STL namespace.
ripple::STAmount::canonicalize
void canonicalize()
Definition: STAmount.cpp:660
ripple::STAmount::add
void add(Serializer &s) const override
Definition: STAmount.cpp:604
Json::Value::asUInt
UInt asUInt() const
Definition: json_value.cpp:545
Json::Value::isUInt
bool isUInt() const
Definition: json_value.cpp:985
ripple::STAmount::value
STAmount const & value() const noexcept
Definition: STAmount.h:232
Json::nullValue
@ nullValue
'null' value
Definition: json_value.h:36
ripple::STAmount::negative
bool negative() const noexcept
Definition: STAmount.h:188
std::string::empty
T empty(T... args)
ripple::xrpIssue
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
Definition: Issue.h:97
ripple::STAmount::exponent_type
int exponent_type
Definition: STAmount.h:47
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:39
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:69
ripple::STAmount::cMaxOffset
static const int cMaxOffset
Definition: STAmount.h:61
ripple::stAmountCanonicalizeSwitchover
LocalValue< bool > stAmountCanonicalizeSwitchover(true)
Definition: STAmount.h:479
std::make_reverse_iterator
T make_reverse_iterator(T... args)
std::unique_ptr
STL class.
ripple::tenTo14m1
static const std::uint64_t tenTo14m1
Definition: STAmount.cpp:40
std::numeric_limits
ripple::STAmount::mOffset
exponent_type mOffset
Definition: STAmount.h:53
Json::Value::isObjectOrNull
bool isObjectOrNull() const
Definition: json_value.cpp:1033
ripple::noAccount
AccountID const & noAccount()
A placeholder for empty accounts.
Definition: AccountID.cpp:97
ripple::STAmount::cPosNative
static const std::uint64_t cPosNative
Definition: STAmount.h:71
ripple::STAmount::uRateOne
static const std::uint64_t uRateOne
Definition: STAmount.h:73
ripple::Issue::account
AccountID account
Definition: Issue.h:38
ripple::STAmount::cMaxValue
static const std::uint64_t cMaxValue
Definition: STAmount.h:65
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
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:104
ripple::tenTo17
static const std::uint64_t tenTo17
Definition: STAmount.cpp:41
Json::Value::asString
std::string asString() const
Returns the unquoted string value.
Definition: json_value.cpp:469
beast
Definition: base_uint.h:654