20#include <xrpl/basics/LocalValue.h>
21#include <xrpl/basics/Log.h>
22#include <xrpl/basics/Number.h>
23#include <xrpl/basics/base_uint.h>
24#include <xrpl/basics/contract.h>
25#include <xrpl/basics/safe_cast.h>
26#include <xrpl/beast/core/LexicalCast.h>
27#include <xrpl/beast/utility/Zero.h>
28#include <xrpl/beast/utility/instrumentation.h>
29#include <xrpl/json/json_forwards.h>
30#include <xrpl/json/json_value.h>
31#include <xrpl/protocol/AccountID.h>
32#include <xrpl/protocol/Asset.h>
33#include <xrpl/protocol/IOUAmount.h>
34#include <xrpl/protocol/Issue.h>
35#include <xrpl/protocol/MPTAmount.h>
36#include <xrpl/protocol/MPTIssue.h>
37#include <xrpl/protocol/Protocol.h>
38#include <xrpl/protocol/SField.h>
39#include <xrpl/protocol/STAmount.h>
40#include <xrpl/protocol/STBase.h>
41#include <xrpl/protocol/STNumber.h>
42#include <xrpl/protocol/Serializer.h>
43#include <xrpl/protocol/SystemParameters.h>
44#include <xrpl/protocol/UintTypes.h>
45#include <xrpl/protocol/XRPAmount.h>
46#include <xrpl/protocol/jss.h>
48#include <boost/algorithm/string/classification.hpp>
49#include <boost/algorithm/string/split.hpp>
50#include <boost/multiprecision/detail/default_ops.hpp>
51#include <boost/multiprecision/fwd.hpp>
52#include <boost/regex/v5/regbase.hpp>
53#include <boost/regex/v5/regex.hpp>
54#include <boost/regex/v5/regex_fwd.hpp>
55#include <boost/regex/v5/regex_match.hpp>
75getStaticSTAmountCanonicalizeSwitchover()
77 static LocalValue<bool> r{
true};
85 return *getStaticSTAmountCanonicalizeSwitchover();
91 *getStaticSTAmountCanonicalizeSwitchover() = v;
103 Throw<std::runtime_error>(error);
105 amount.
exponent() == 0,
"ripple::getInt64Value : exponent is zero");
111 "ripple::getInt64Value : mantissa must roundtrip");
172 Throw<std::runtime_error>(
"negative zero is not canonical");
184 Throw<std::runtime_error>(
"invalid native currency");
189 Throw<std::runtime_error>(
"invalid native account");
192 int offset =
static_cast<int>(
value >> (64 - 10));
194 value &= ~(1023ull << (64 - 10));
198 bool isNegative = (offset & 256) == 0;
199 offset = (offset & 255) - 97;
204 Throw<std::runtime_error>(
"invalid currency value");
216 Throw<std::runtime_error>(
"invalid currency value");
236 , mIsNegative(negative)
240 "ripple::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
246 , mAsset(from.mAsset)
247 , mValue(from.mValue)
248 , mOffset(from.mOffset)
249 , mIsNegative(from.mIsNegative)
253 "ripple::STAmount::STAmount(SField, STAmount) : maximum input");
263 , mIsNegative(mantissa != 0 && negative)
267 "ripple::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
272 : mAsset(
xrpIssue()), mOffset(0), mIsNegative(amount <
beast::zero)
275 mValue = unsafe_cast<std::uint64_t>(-amount.
drops());
277 mValue = unsafe_cast<std::uint64_t>(amount.
drops());
297 return emplace(n, buf, std::move(*
this));
309 Throw<std::logic_error>(
310 "Cannot return non-native STAmount as XRPAmount");
313 XRPL_ASSERT(
mOffset == 0,
"ripple::STAmount::xrp : amount is canonical");
324 if (
native() || !holds<Issue>())
325 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
339 if (!holds<MPTIssue>())
340 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
343 XRPL_ASSERT(
mOffset == 0,
"ripple::STAmount::mpt : amount is canonical");
356 "ripple::STAmount::operator=(IOUAmount) : is not XRP");
390 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
392 if (v2 == beast::zero)
395 if (v1 == beast::zero)
445 if ((fv >= -10) && (fv <= 10))
488 if (offerOut == beast::zero)
493 if (r == beast::zero)
497 "ripple::getRate : exponent inside range");
499 return (ret << (64 - 8)) | r.
mantissa();
535 if (a == beast::zero || b == beast::zero)
563 return ((rhs.
negative() ? -rhs : rhs) +
564 (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
585 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
615 if (b == beast::zero)
660 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
709 if (*
this == beast::zero)
718 bool const scientific(
734 XRPL_ASSERT(
mOffset + 43 > 0,
"ripple::STAmount::getText : minimum offset");
736 size_t const pad_prefix = 27;
737 size_t const pad_suffix = 23;
741 val.
append(pad_prefix,
'0');
743 val.
append(pad_suffix,
'0');
745 size_t const offset(
mOffset + 43);
747 auto pre_from(val.
begin());
748 auto const pre_to(val.
begin() + offset);
750 auto const post_from(val.
begin() + offset);
751 auto post_to(val.
end());
756 pre_from += pad_prefix;
759 post_to >= post_from,
760 "ripple::STAmount::getText : first distance check");
762 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
767 post_to -= pad_suffix;
770 post_to >= post_from,
771 "ripple::STAmount::getText : second distance check");
776 [](
char c) {
return c !=
'0'; })
780 if (pre_from == pre_to)
783 ret.
append(pre_from, pre_to);
785 if (post_to != post_from)
788 ret.
append(post_from, post_to);
807 XRPL_ASSERT(
mOffset == 0,
"ripple::STAmount::add : zero offset");
816 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
818 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
825 if (*
this == beast::zero)
845 return v && (*v == *
this);
891 Throw<std::runtime_error>(
892 "Native currency amount out of range");
895 Throw<std::runtime_error>(
"MPT amount out of range");
902 auto set = [&](
auto const& val) {
927 Throw<std::runtime_error>(
928 "Native currency amount out of range");
930 Throw<std::runtime_error>(
"MPT amount out of range");
938 Throw<std::runtime_error>(
"Native currency amount out of range");
940 Throw<std::runtime_error>(
"MPT amount out of range");
967 Throw<std::runtime_error>(
"value overflow");
982 Throw<std::runtime_error>(
"value overflow");
986 "ripple::STAmount::canonicalize : value inside range");
989 "ripple::STAmount::canonicalize : offset inside range");
992 "ripple::STAmount::canonicalize : value or offset set");
1019 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
1029 Throw<std::runtime_error>(
1030 "XRP and MPT must be specified as integral amount.");
1031 return {asset, parts.mantissa, parts.exponent, parts.negative};
1046 Throw<std::runtime_error>(
1047 "XRP may not be specified with a null Json value");
1052 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
1054 value = v[jss::value];
1055 if (v.
isMember(jss::mpt_issuance_id))
1058 currencyOrMPTID = v[jss::mpt_issuance_id];
1062 currencyOrMPTID = v[jss::currency];
1063 issuer = v[jss::issuer];
1076 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
1078 if (elements.
size() > 3)
1079 Throw<std::runtime_error>(
"invalid amount string");
1081 value = elements[0];
1083 if (elements.
size() > 1)
1084 currencyOrMPTID = elements[1];
1086 if (elements.
size() > 2)
1087 issuer = elements[2];
1094 bool const native = !currencyOrMPTID.
isString() ||
1101 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1111 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1118 Throw<std::runtime_error>(
"invalid currency");
1121 Throw<std::runtime_error>(
"invalid issuer");
1123 Throw<std::runtime_error>(
"invalid issuer");
1132 if (value.
asInt() >= 0)
1151 Throw<std::runtime_error>(
1152 "XRP and MPT must be specified as integral amount.");
1156 Throw<std::runtime_error>(
"invalid amount type");
1173 <<
"amountFromJsonNoThrow: caught: " << e.
what();
1195 Throw<std::runtime_error>(
1196 "Can't compare amounts that are't comparable!");
1254 boost::multiprecision::uint128_t ret;
1256 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1261 Throw<std::overflow_error>(
1266 return static_cast<uint64_t
>(ret);
1276 boost::multiprecision::uint128_t ret;
1278 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1284 Throw<std::overflow_error>(
1290 return static_cast<uint64_t
>(ret);
1296 if (den == beast::zero)
1297 Throw<std::runtime_error>(
"division by zero");
1299 if (num == beast::zero)
1334 numOffset - denOffset - 17,
1341 if (v1 == beast::zero || v2 == beast::zero)
1349 if (minV > 3000000000ull)
1350 Throw<std::runtime_error>(
"Native value overflow");
1352 if (((maxV >> 32) * minV) > 2095475792ull)
1353 Throw<std::runtime_error>(
"Native value overflow");
1362 if (minV > 3037000499ull)
1363 Throw<std::runtime_error>(
"MPT value overflow");
1365 if (((maxV >> 32) * minV) > 2147483648ull)
1366 Throw<std::runtime_error>(
"MPT value overflow");
1368 return STAmount(asset, minV * maxV);
1374 return STAmount{asset, r.mantissa(), r.exponent()};
1407 offset1 + offset2 + 14,
1447 value += (loops >= 2) ? 9 : 10;
1481 bool hadRemainder =
false;
1489 hadRemainder |= (value != (newValue * 10));
1494 (hadRemainder && roundUp) ? 10 : 9;
1516class DontAffectNumberRoundMode
1523 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1525 DontAffectNumberRoundMode&
1526 operator=(DontAffectNumberRoundMode
const&) =
delete;
1537 typename MightSaveRound>
1545 if (v1 == beast::zero || v2 == beast::zero)
1548 bool const xrp = asset.
native();
1555 if (minV > 3000000000ull)
1556 Throw<std::runtime_error>(
"Native value overflow");
1558 if (((maxV >> 32) * minV) > 2095475792ull)
1559 Throw<std::runtime_error>(
"Native value overflow");
1569 if (minV > 3037000499ull)
1570 Throw<std::runtime_error>(
"MPT value overflow");
1572 if (((maxV >> 32) * minV) > 2147483648ull)
1573 Throw<std::runtime_error>(
"MPT value overflow");
1575 return STAmount(asset, minV * maxV);
1612 int offset = offset1 + offset2 + 14;
1613 if (resultNegative != roundUp)
1615 CanonicalizeFunc(xrp, amount, offset, roundUp);
1621 return STAmount(asset, amount, offset, resultNegative);
1624 if (roundUp && !resultNegative && !result)
1638 return STAmount(asset, amount, offset, resultNegative);
1650 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1651 v1, v2, asset, roundUp);
1661 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1662 v1, v2, asset, roundUp);
1667template <
typename MightSaveRound>
1675 if (den == beast::zero)
1676 Throw<std::runtime_error>(
"division by zero");
1678 if (num == beast::zero)
1713 numVal,
tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1715 int offset = numOffset - denOffset - 17;
1717 if (resultNegative != roundUp)
1726 MightSaveRound
const savedRound(
1727 roundUp ^ resultNegative ? upward : downward);
1728 return STAmount(asset, amount, offset, resultNegative);
1731 if (roundUp && !resultNegative && !result)
1745 return STAmount(asset, amount, offset, resultNegative);
1757 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1767 return divRoundImpl<NumberRoundModeGuard>(num, den, asset, roundUp);
bool isObjectOrNull() const
std::string asString() const
Returns the unquoted string value.
bool isNull() const
isNull() tests to see if this field is null.
bool isMember(char const *key) const
Return true if the object has a member named key.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
void setJson(Json::Value &jv) const
constexpr TIss const & get() const
constexpr bool holds() const
std::string getText() const
Floating point representation of amounts with high dynamic range.
int exponent() const noexcept
std::int64_t mantissa() const noexcept
A currency issued by an account.
constexpr value_type value() const
Returns the underlying value.
constexpr MPTID const & getMptID() const
constexpr bool holds() const noexcept
Json::Value getJson(JsonOptions=JsonOptions::none) const override
static std::uint64_t const cMaxNativeN
STAmount & operator=(beast::Zero)
int exponent() const noexcept
STBase * move(std::size_t n, void *buf) override
Asset const & asset() const
static std::uint64_t const cPositive
constexpr TIss const & get() const
static int const cMaxOffset
static int const cMinOffset
STAmount & operator+=(STAmount const &)
static std::uint64_t const cMinValue
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
void setIssue(Asset const &asset)
Set the Issue for this amount.
void setJson(Json::Value &) const
bool isDefault() const override
STAmount & operator-=(STAmount const &)
void add(Serializer &s) const override
static std::uint64_t const cIssuedCurrency
static std::uint64_t const cMPToken
SerializedTypeID getSType() const override
static std::uint64_t const cMaxValue
STAmount const & value() const noexcept
std::string getText() const override
bool negative() const noexcept
bool isEquivalent(STBase const &t) const override
STBase * copy(std::size_t n, void *buf) const override
static std::uint64_t const cValueMask
Issue const & issue() const
std::uint64_t mantissa() const noexcept
std::string getFullText() const override
STAmount(SerialIter &sit, SField const &name)
bool native() const noexcept
static std::uint64_t const uRateOne
A type which can be exported to a well known binary format.
SField const & getFName() const
static STBase * emplace(std::size_t n, void *buf, T &&val)
int addBitString(base_uint< Bits, Tag > const &v)
int add8(unsigned char i)
constexpr value_type drops() const
Returns the number of drops.
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
T make_reverse_iterator(T... args)
@ objectValue
object value (collection of name/value pairs).
TER valid(STTx const &tx, ReadView const &view, AccountID const &src, beast::Journal j)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
static void canonicalizeRoundStrict(bool native, std::uint64_t &value, int &offset, bool roundUp)
STAmount divide(STAmount const &amount, Rate const &rate)
NumberParts partsFromString(std::string const &number)
bool isXRP(AccountID const &c)
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
static bool areComparable(STAmount const &v1, STAmount const &v2)
STAmount divRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
STAmount amountFromJson(SField const &name, Json::Value const &v)
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
static std::uint64_t const tenTo17
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
STAmount amountFromQuality(std::uint64_t rate)
bool getSTAmountCanonicalizeSwitchover()
static std::string const & systemCurrencyCode()
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
static std::uint64_t const tenTo14m1
STAmount multiply(STAmount const &amount, Rate const &rate)
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
static std::int64_t getSNValue(STAmount const &amount)
bool validJSONAsset(Json::Value const &jv)
beast::Journal debugLog()
Returns a debug journal.
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
static std::int64_t getInt64Value(STAmount const &amount, bool valid, char const *error)
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
static std::int64_t getMPTValue(STAmount const &amount)
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
void setSTAmountCanonicalizeSwitchover(bool v)
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
Number operator-(Number const &x, Number const &y)
STAmount amountFromString(Asset const &asset, std::string const &amount)
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Asset const &asset, bool roundUp)
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
static std::uint64_t muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
static std::uint64_t const tenTo14
bool getSTNumberSwitchover()
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset, bool)
Note, should be treated as flags that can be | and &.