1#include <xrpl/basics/LocalValue.h>
2#include <xrpl/basics/Log.h>
3#include <xrpl/basics/Number.h>
4#include <xrpl/basics/base_uint.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/basics/safe_cast.h>
7#include <xrpl/beast/core/LexicalCast.h>
8#include <xrpl/beast/utility/Zero.h>
9#include <xrpl/beast/utility/instrumentation.h>
10#include <xrpl/json/json_forwards.h>
11#include <xrpl/json/json_value.h>
12#include <xrpl/protocol/AccountID.h>
13#include <xrpl/protocol/Asset.h>
14#include <xrpl/protocol/Feature.h>
15#include <xrpl/protocol/IOUAmount.h>
16#include <xrpl/protocol/Issue.h>
17#include <xrpl/protocol/MPTAmount.h>
18#include <xrpl/protocol/MPTIssue.h>
19#include <xrpl/protocol/Protocol.h>
20#include <xrpl/protocol/Rules.h>
21#include <xrpl/protocol/SField.h>
22#include <xrpl/protocol/STAmount.h>
23#include <xrpl/protocol/STBase.h>
24#include <xrpl/protocol/STNumber.h>
25#include <xrpl/protocol/Serializer.h>
26#include <xrpl/protocol/SystemParameters.h>
27#include <xrpl/protocol/UintTypes.h>
28#include <xrpl/protocol/XRPAmount.h>
29#include <xrpl/protocol/jss.h>
31#include <boost/algorithm/string/classification.hpp>
32#include <boost/algorithm/string/split.hpp>
33#include <boost/multiprecision/detail/default_ops.hpp>
34#include <boost/multiprecision/fwd.hpp>
35#include <boost/regex/v5/regbase.hpp>
36#include <boost/regex/v5/regex.hpp>
37#include <boost/regex/v5/regex_fwd.hpp>
38#include <boost/regex/v5/regex_match.hpp>
63 Throw<std::runtime_error>(error);
64 XRPL_ASSERT(amount.exponent() == 0,
"xrpl::getInt64Value : exponent is zero");
68 XRPL_ASSERT(
static_cast<std::uint64_t>(ret) == amount.mantissa(),
"xrpl::getInt64Value : mantissa must roundtrip");
70 if (amount.negative())
79 return getInt64Value(amount, amount.native(),
"amount is not native!");
129 Throw<std::runtime_error>(
"negative zero is not canonical");
141 Throw<std::runtime_error>(
"invalid native currency");
146 Throw<std::runtime_error>(
"invalid native account");
149 int offset =
static_cast<int>(
value >> (64 - 10));
151 value &= ~(1023ull << (64 - 10));
155 bool isNegative = (offset & 256) == 0;
156 offset = (offset & 255) - 97;
160 Throw<std::runtime_error>(
"invalid currency value");
172 Throw<std::runtime_error>(
"invalid currency value");
187 :
STBase(name), mAsset(
xrpIssue()), mValue(mantissa), mOffset(0), mIsNegative(negative)
191 "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
196 :
STBase(name), mAsset(from.mAsset), mValue(from.mValue), mOffset(from.mOffset), mIsNegative(from.mIsNegative)
200 "xrpl::STAmount::STAmount(SField, STAmount) : maximum input");
207 : mAsset(
xrpIssue()), mValue(mantissa), mOffset(0), mIsNegative(mantissa != 0 && negative)
211 "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
218 mValue = unsafe_cast<std::uint64_t>(-amount.drops());
220 mValue = unsafe_cast<std::uint64_t>(amount.drops());
240 return emplace(n, buf, std::move(*
this));
252 Throw<std::logic_error>(
"Cannot return non-native STAmount as XRPAmount");
255 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::xrp : amount is canonical");
267 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
281 if (!holds<MPTIssue>())
282 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
285 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::mpt : amount is canonical");
296 XRPL_ASSERT(
integral() ==
false,
"xrpl::STAmount::operator=(IOUAmount) : is not integral");
316 auto const originalMantissa = number.
mantissa();
349 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
351 if (v2 == beast::zero)
354 if (v1 == beast::zero)
399 if ((fv >= -10) && (fv <= 10))
436 if (offerOut == beast::zero)
441 if (r == beast::zero)
443 XRPL_ASSERT((r.
exponent() >= -100) && (r.
exponent() <= 155),
"xrpl::getRate : exponent inside range");
445 return (ret << (64 - 8)) | r.
mantissa();
481 if (a == beast::zero || b == beast::zero)
505 return ((rhs.
negative() ? -rhs : rhs) + (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
522 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
552 if (b == beast::zero)
593 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
642 if (*
this == beast::zero)
666 XRPL_ASSERT(
mOffset + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
668 size_t const pad_prefix = 27;
669 size_t const pad_suffix = 23;
673 val.
append(pad_prefix,
'0');
675 val.
append(pad_suffix,
'0');
677 size_t const offset(
mOffset + 43);
679 auto pre_from(val.
begin());
680 auto const pre_to(val.
begin() + offset);
682 auto const post_from(val.
begin() + offset);
683 auto post_to(val.
end());
688 pre_from += pad_prefix;
690 XRPL_ASSERT(post_to >= post_from,
"xrpl::STAmount::getText : first distance check");
692 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
697 post_to -= pad_suffix;
699 XRPL_ASSERT(post_to >= post_from,
"xrpl::STAmount::getText : second distance check");
706 if (pre_from == pre_to)
709 ret.
append(pre_from, pre_to);
711 if (post_to != post_from)
714 ret.
append(post_from, post_to);
733 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::add : zero offset");
742 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
744 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
751 if (*
this == beast::zero)
766 return v && (*v == *
this);
810 Throw<std::runtime_error>(
"Native currency amount out of range");
813 Throw<std::runtime_error>(
"MPT amount out of range");
818 auto set = [&](
auto const& val) {
828 Throw<std::runtime_error>(
"Unknown integral asset type");
844 Throw<std::runtime_error>(
"Native currency amount out of range");
846 Throw<std::runtime_error>(
"MPT amount out of range");
854 Throw<std::runtime_error>(
"Native currency amount out of range");
856 Throw<std::runtime_error>(
"MPT amount out of range");
883 Throw<std::runtime_error>(
"value overflow");
898 Throw<std::runtime_error>(
"value overflow");
902 "xrpl::STAmount::canonicalize : value inside range");
905 "xrpl::STAmount::canonicalize : offset inside range");
906 XRPL_ASSERT((
mValue != 0) || (
mOffset != -100),
"xrpl::STAmount::canonicalize : value or offset set");
933 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
943 Throw<std::runtime_error>(
"XRP and MPT must be specified as integral amount.");
944 return {asset, parts.mantissa, parts.exponent, parts.negative};
959 Throw<std::runtime_error>(
"XRP may not be specified with a null Json value");
964 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
966 value = v[jss::value];
967 if (v.
isMember(jss::mpt_issuance_id))
970 currencyOrMPTID = v[jss::mpt_issuance_id];
974 currencyOrMPTID = v[jss::currency];
975 issuer = v[jss::issuer];
988 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
990 if (elements.
size() > 3)
991 Throw<std::runtime_error>(
"invalid amount string");
995 if (elements.
size() > 1)
996 currencyOrMPTID = elements[1];
998 if (elements.
size() > 2)
999 issuer = elements[2];
1012 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1022 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1029 Throw<std::runtime_error>(
"invalid currency");
1031 Throw<std::runtime_error>(
"invalid issuer");
1033 Throw<std::runtime_error>(
"invalid issuer");
1042 if (value.
asInt() >= 0)
1061 Throw<std::runtime_error>(
"XRP and MPT must be specified as integral amount.");
1065 Throw<std::runtime_error>(
"invalid amount type");
1081 JLOG(
debugLog().warn()) <<
"amountFromJsonNoThrow: caught: " << e.
what();
1103 Throw<std::runtime_error>(
"Can't compare amounts that are't comparable!");
1153 boost::multiprecision::uint128_t ret;
1155 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1160 Throw<std::overflow_error>(
1165 return static_cast<uint64_t
>(ret);
1171 boost::multiprecision::uint128_t ret;
1173 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1179 Throw<std::overflow_error>(
1184 return static_cast<uint64_t
>(ret);
1190 if (den == beast::zero)
1191 Throw<std::runtime_error>(
"division by zero");
1193 if (num == beast::zero)
1232 if (v1 == beast::zero || v2 == beast::zero)
1240 if (minV > 3000000000ull)
1241 Throw<std::runtime_error>(
"Native value overflow");
1243 if (((maxV >> 32) * minV) > 2095475792ull)
1244 Throw<std::runtime_error>(
"Native value overflow");
1253 if (minV > 3037000499ull)
1254 Throw<std::runtime_error>(
"MPT value overflow");
1256 if (((maxV >> 32) * minV) > 2147483648ull)
1257 Throw<std::runtime_error>(
"MPT value overflow");
1259 return STAmount(asset, minV * maxV);
1334 value += (loops >= 2) ? 9 : 10;
1364 bool hadRemainder =
false;
1372 hadRemainder |= (value != (newValue * 10));
1376 value += (hadRemainder && roundUp) ? 10 : 9;
1402 if (value == beast::zero)
1418 return (value + referenceValue) - referenceValue;
1425class DontAffectNumberRoundMode
1432 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1434 DontAffectNumberRoundMode&
1435 operator=(DontAffectNumberRoundMode
const&) =
delete;
1444template <
void (*CanonicalizeFunc)(
bool, std::u
int64_t&,
int&,
bool),
typename MightSaveRound>
1448 if (v1 == beast::zero || v2 == beast::zero)
1451 bool const xrp = asset.
native();
1458 if (minV > 3000000000ull)
1459 Throw<std::runtime_error>(
"Native value overflow");
1461 if (((maxV >> 32) * minV) > 2095475792ull)
1462 Throw<std::runtime_error>(
"Native value overflow");
1472 if (minV > 3037000499ull)
1473 Throw<std::runtime_error>(
"MPT value overflow");
1475 if (((maxV >> 32) * minV) > 2147483648ull)
1476 Throw<std::runtime_error>(
"MPT value overflow");
1478 return STAmount(asset, minV * maxV);
1514 int offset = offset1 + offset2 + 14;
1515 if (resultNegative != roundUp)
1517 CanonicalizeFunc(xrp, amount, offset, roundUp);
1523 return STAmount(asset, amount, offset, resultNegative);
1526 if (roundUp && !resultNegative && !result)
1540 return STAmount(asset, amount, offset, resultNegative);
1548 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(v1, v2, asset, roundUp);
1554 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(v1, v2, asset, roundUp);
1559template <
typename MightSaveRound>
1563 if (den == beast::zero)
1564 Throw<std::runtime_error>(
"division by zero");
1566 if (num == beast::zero)
1602 int offset = numOffset - denOffset - 17;
1604 if (resultNegative != roundUp)
1612 MightSaveRound
const savedRound(roundUp ^ resultNegative ? upward : downward);
1613 return STAmount(asset, amount, offset, resultNegative);
1616 if (roundUp && !resultNegative && !result)
1630 return STAmount(asset, amount, offset, resultNegative);
1638 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1644 return divRoundImpl<NumberRoundModeGuard>(num, den, asset, roundUp);
bool isObjectOrNull() const
UInt asAbsUInt() const
Correct absolute value from int or unsigned int.
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...
constexpr TIss const & get() const
std::string getText() const
void setJson(Json::Value &jv) const
constexpr bool holds() const
Floating point representation of amounts with high dynamic range.
mantissa_type mantissa() const noexcept
exponent_type exponent() const noexcept
A currency issued by an account.
constexpr value_type value() const
Returns the underlying value.
constexpr MPTID const & getMptID() const
Number is a floating point type that can represent a wide range of values.
constexpr rep mantissa() const noexcept
Returns the mantissa of the external view of the Number.
constexpr int exponent() const noexcept
Returns the exponent of the external view of the Number.
constexpr bool holds() const noexcept
Json::Value getJson(JsonOptions=JsonOptions::none) const override
constexpr TIss const & get() const
void setIssue(Asset const &asset)
Set the Issue for this amount.
std::string getFullText() const override
static constexpr std::uint64_t cMaxValue
Issue const & issue() const
static std::uint64_t const uRateOne
static STAmount fromNumber(A const &asset, Number const &number)
void add(Serializer &s) const override
std::uint64_t mantissa() const noexcept
bool isEquivalent(STBase const &t) const override
STBase * copy(std::size_t n, void *buf) const override
static constexpr std::uint64_t cValueMask
std::string getText() const override
void setJson(Json::Value &) const
SerializedTypeID getSType() const override
bool negative() const noexcept
static int const cMaxOffset
bool isDefault() const override
bool integral() const noexcept
STAmount & operator=(beast::Zero)
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
static constexpr std::uint64_t cIssuedCurrency
bool native() const noexcept
static constexpr std::uint64_t cMinValue
Asset const & asset() const
static int const cMinOffset
STAmount & operator+=(STAmount const &)
STAmount & operator-=(STAmount const &)
static constexpr std::uint64_t cMPToken
int exponent() const noexcept
static constexpr std::uint64_t cMaxNativeN
STBase * move(std::size_t n, void *buf) override
static constexpr std::uint64_t cPositive
STAmount const & value() const noexcept
STAmount(SerialIter &sit, SField const &name)
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.
static std::int64_t getMPTValue(STAmount const &amount)
STAmount divide(STAmount const &amount, Rate const &rate)
bool operator<(Slice const &lhs, Slice const &rhs) noexcept
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,...
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
static void canonicalizeRoundStrict(bool native, std::uint64_t &value, int &offset, bool roundUp)
static void canonicalizeRound(bool native, std::uint64_t &value, int &offset, bool)
bool isXRP(AccountID const &c)
constexpr base_uint< Bits, Tag > operator+(base_uint< Bits, Tag > const &a, base_uint< Bits, Tag > const &b)
bool validJSONAsset(Json::Value const &jv)
beast::Journal debugLog()
Returns a debug journal.
NumberParts partsFromString(std::string const &number)
static std::uint64_t muldiv_round(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
Number operator-(Number const &x, Number const &y)
STAmount amountFromJson(SField const &name, Json::Value const &v)
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
std::uint64_t constexpr maxMPTokenAmount
The maximum amount of MPTokenIssuance.
static std::uint64_t const tenTo14m1
STAmount amountFromString(Asset const &asset, std::string const &amount)
std::optional< Rules > const & getCurrentTransactionRules()
static std::uint64_t const tenTo17
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
STAmount multiply(STAmount const &amount, Rate const &rate)
STAmount roundToScale(STAmount const &value, std::int32_t scale, Number::rounding_mode rounding=Number::getround())
Round an arbitrary precision Amount to the precision of an STAmount that has a given exponent.
static std::uint64_t const tenTo14
constexpr bool operator==(base_uint< Bits, Tag > const &lhs, base_uint< Bits, Tag > const &rhs)
bool amountFromJsonNoThrow(STAmount &result, Json::Value const &jvSource)
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
STAmount amountFromQuality(std::uint64_t rate)
std::uint64_t getRate(STAmount const &offerOut, STAmount const &offerIn)
static std::int64_t getSNValue(STAmount const &amount)
static bool areComparable(STAmount const &v1, STAmount const &v2)
bool to_issuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
STAmount mulRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
static std::int64_t getInt64Value(STAmount const &amount, bool valid, char const *error)
bool canSubtract(STAmount const &amt1, STAmount const &amt2)
Determines if it is safe to subtract one STAmount from another.
STAmount divRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr XRPAmount INITIAL_XRP
Configure the native currency.
Issue const & noIssue()
Returns an asset specifier that represents no account and currency.
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
static std::string const & systemCurrencyCode()
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Asset const &asset, bool roundUp)
bool to_currency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
bool isFeatureEnabled(uint256 const &feature)
bool getSTNumberSwitchover()
Note, should be treated as flags that can be | and &.