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