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>
80 Throw<std::runtime_error>(error);
82 amount.
exponent() == 0,
"ripple::getInt64Value : exponent is zero");
88 "ripple::getInt64Value : mantissa must roundtrip");
149 Throw<std::runtime_error>(
"negative zero is not canonical");
161 Throw<std::runtime_error>(
"invalid native currency");
166 Throw<std::runtime_error>(
"invalid native account");
169 int offset =
static_cast<int>(
value >> (64 - 10));
171 value &= ~(1023ull << (64 - 10));
175 bool isNegative = (offset & 256) == 0;
176 offset = (offset & 255) - 97;
181 Throw<std::runtime_error>(
"invalid currency value");
193 Throw<std::runtime_error>(
"invalid currency value");
213 , mIsNegative(negative)
217 "ripple::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
223 , mAsset(from.mAsset)
224 , mValue(from.mValue)
225 , mOffset(from.mOffset)
226 , mIsNegative(from.mIsNegative)
230 "ripple::STAmount::STAmount(SField, STAmount) : maximum input");
240 , mIsNegative(mantissa != 0 && negative)
244 "ripple::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
249 : mAsset(
xrpIssue()), mOffset(0), mIsNegative(amount <
beast::zero)
252 mValue = unsafe_cast<std::uint64_t>(-amount.
drops());
254 mValue = unsafe_cast<std::uint64_t>(amount.
drops());
274 return emplace(n, buf, std::move(*
this));
286 Throw<std::logic_error>(
287 "Cannot return non-native STAmount as XRPAmount");
290 XRPL_ASSERT(
mOffset == 0,
"ripple::STAmount::xrp : amount is canonical");
301 if (
native() || !holds<Issue>())
302 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
316 if (!holds<MPTIssue>())
317 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
320 XRPL_ASSERT(
mOffset == 0,
"ripple::STAmount::mpt : amount is canonical");
333 "ripple::STAmount::operator=(IOUAmount) : is not XRP");
367 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
369 if (v2 == beast::zero)
372 if (v1 == beast::zero)
422 if ((fv >= -10) && (fv <= 10))
465 if (offerOut == beast::zero)
470 if (r == beast::zero)
474 "ripple::getRate : exponent inside range");
476 return (ret << (64 - 8)) | r.
mantissa();
512 if (a == beast::zero || b == beast::zero)
540 return ((rhs.
negative() ? -rhs : rhs) +
541 (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
562 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
592 if (b == beast::zero)
637 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
686 if (*
this == beast::zero)
695 bool const scientific(
711 XRPL_ASSERT(
mOffset + 43 > 0,
"ripple::STAmount::getText : minimum offset");
713 size_t const pad_prefix = 27;
714 size_t const pad_suffix = 23;
718 val.
append(pad_prefix,
'0');
720 val.
append(pad_suffix,
'0');
722 size_t const offset(
mOffset + 43);
724 auto pre_from(val.
begin());
725 auto const pre_to(val.
begin() + offset);
727 auto const post_from(val.
begin() + offset);
728 auto post_to(val.
end());
733 pre_from += pad_prefix;
736 post_to >= post_from,
737 "ripple::STAmount::getText : first distance check");
739 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
744 post_to -= pad_suffix;
747 post_to >= post_from,
748 "ripple::STAmount::getText : second distance check");
753 [](
char c) {
return c !=
'0'; })
757 if (pre_from == pre_to)
760 ret.
append(pre_from, pre_to);
762 if (post_to != post_from)
765 ret.
append(post_from, post_to);
784 XRPL_ASSERT(
mOffset == 0,
"ripple::STAmount::add : zero offset");
793 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
795 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
802 if (*
this == beast::zero)
822 return v && (*v == *
this);
866 Throw<std::runtime_error>(
"Native currency amount out of range");
869 Throw<std::runtime_error>(
"MPT amount out of range");
875 auto set = [&](
auto const& val) {
898 Throw<std::runtime_error>(
899 "Native currency amount out of range");
901 Throw<std::runtime_error>(
"MPT amount out of range");
909 Throw<std::runtime_error>(
"Native currency amount out of range");
911 Throw<std::runtime_error>(
"MPT amount out of range");
938 Throw<std::runtime_error>(
"value overflow");
953 Throw<std::runtime_error>(
"value overflow");
957 "ripple::STAmount::canonicalize : value inside range");
960 "ripple::STAmount::canonicalize : offset inside range");
963 "ripple::STAmount::canonicalize : value or offset set");
990 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
1000 Throw<std::runtime_error>(
1001 "XRP and MPT must be specified as integral amount.");
1002 return {asset, parts.mantissa, parts.exponent, parts.negative};
1017 Throw<std::runtime_error>(
1018 "XRP may not be specified with a null Json value");
1023 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
1025 value = v[jss::value];
1026 if (v.
isMember(jss::mpt_issuance_id))
1029 currencyOrMPTID = v[jss::mpt_issuance_id];
1033 currencyOrMPTID = v[jss::currency];
1034 issuer = v[jss::issuer];
1047 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
1049 if (elements.
size() > 3)
1050 Throw<std::runtime_error>(
"invalid amount string");
1052 value = elements[0];
1054 if (elements.
size() > 1)
1055 currencyOrMPTID = elements[1];
1057 if (elements.
size() > 2)
1058 issuer = elements[2];
1065 bool const native = !currencyOrMPTID.
isString() ||
1072 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1082 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1089 Throw<std::runtime_error>(
"invalid currency");
1092 Throw<std::runtime_error>(
"invalid issuer");
1094 Throw<std::runtime_error>(
"invalid issuer");
1103 if (value.
asInt() >= 0)
1122 Throw<std::runtime_error>(
1123 "XRP and MPT must be specified as integral amount.");
1127 Throw<std::runtime_error>(
"invalid amount type");
1144 <<
"amountFromJsonNoThrow: caught: " << e.
what();
1166 Throw<std::runtime_error>(
1167 "Can't compare amounts that are't comparable!");
1225 boost::multiprecision::uint128_t ret;
1227 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1232 Throw<std::overflow_error>(
1237 return static_cast<uint64_t
>(ret);
1247 boost::multiprecision::uint128_t ret;
1249 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1255 Throw<std::overflow_error>(
1261 return static_cast<uint64_t
>(ret);
1267 if (den == beast::zero)
1268 Throw<std::runtime_error>(
"division by zero");
1270 if (num == beast::zero)
1305 numOffset - denOffset - 17,
1312 if (v1 == beast::zero || v2 == beast::zero)
1320 if (minV > 3000000000ull)
1321 Throw<std::runtime_error>(
"Native value overflow");
1323 if (((maxV >> 32) * minV) > 2095475792ull)
1324 Throw<std::runtime_error>(
"Native value overflow");
1333 if (minV > 3037000499ull)
1334 Throw<std::runtime_error>(
"MPT value overflow");
1336 if (((maxV >> 32) * minV) > 2147483648ull)
1337 Throw<std::runtime_error>(
"MPT value overflow");
1339 return STAmount(asset, minV * maxV);
1345 return STAmount{asset, r.mantissa(), r.exponent()};
1378 offset1 + offset2 + 14,
1418 value += (loops >= 2) ? 9 : 10;
1452 bool hadRemainder =
false;
1460 hadRemainder |= (value != (newValue * 10));
1465 (hadRemainder && roundUp) ? 10 : 9;
1487class DontAffectNumberRoundMode
1494 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1496 DontAffectNumberRoundMode&
1497 operator=(DontAffectNumberRoundMode
const&) =
delete;
1508 typename MightSaveRound>
1516 if (v1 == beast::zero || v2 == beast::zero)
1519 bool const xrp = asset.
native();
1526 if (minV > 3000000000ull)
1527 Throw<std::runtime_error>(
"Native value overflow");
1529 if (((maxV >> 32) * minV) > 2095475792ull)
1530 Throw<std::runtime_error>(
"Native value overflow");
1540 if (minV > 3037000499ull)
1541 Throw<std::runtime_error>(
"MPT value overflow");
1543 if (((maxV >> 32) * minV) > 2147483648ull)
1544 Throw<std::runtime_error>(
"MPT value overflow");
1546 return STAmount(asset, minV * maxV);
1583 int offset = offset1 + offset2 + 14;
1584 if (resultNegative != roundUp)
1586 CanonicalizeFunc(xrp, amount, offset, roundUp);
1592 return STAmount(asset, amount, offset, resultNegative);
1595 if (roundUp && !resultNegative && !result)
1609 return STAmount(asset, amount, offset, resultNegative);
1621 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1622 v1, v2, asset, roundUp);
1632 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1633 v1, v2, asset, roundUp);
1638template <
typename MightSaveRound>
1646 if (den == beast::zero)
1647 Throw<std::runtime_error>(
"division by zero");
1649 if (num == beast::zero)
1684 numVal,
tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1686 int offset = numOffset - denOffset - 17;
1688 if (resultNegative != roundUp)
1697 MightSaveRound
const savedRound(
1698 roundUp ^ resultNegative ? upward : downward);
1699 return STAmount(asset, amount, offset, resultNegative);
1702 if (roundUp && !resultNegative && !result)
1716 return STAmount(asset, amount, offset, resultNegative);
1728 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1738 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)
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
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 &.