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/IOUAmount.h>
15#include <xrpl/protocol/Issue.h>
16#include <xrpl/protocol/MPTAmount.h>
17#include <xrpl/protocol/MPTIssue.h>
18#include <xrpl/protocol/Protocol.h>
19#include <xrpl/protocol/SField.h>
20#include <xrpl/protocol/STAmount.h>
21#include <xrpl/protocol/STBase.h>
22#include <xrpl/protocol/STNumber.h>
23#include <xrpl/protocol/Serializer.h>
24#include <xrpl/protocol/SystemParameters.h>
25#include <xrpl/protocol/UintTypes.h>
26#include <xrpl/protocol/XRPAmount.h>
27#include <xrpl/protocol/jss.h>
29#include <boost/algorithm/string/classification.hpp>
30#include <boost/algorithm/string/split.hpp>
31#include <boost/multiprecision/detail/default_ops.hpp>
32#include <boost/multiprecision/fwd.hpp>
33#include <boost/regex/v5/regbase.hpp>
34#include <boost/regex/v5/regex.hpp>
35#include <boost/regex/v5/regex_fwd.hpp>
36#include <boost/regex/v5/regex_match.hpp>
61 Throw<std::runtime_error>(error);
63 amount.exponent() == 0,
"xrpl::getInt64Value : exponent is zero");
69 "xrpl::getInt64Value : mantissa must roundtrip");
71 if (amount.negative())
80 return getInt64Value(amount, amount.native(),
"amount is not native!");
87 amount, amount.holds<
MPTIssue>(),
"amount is not MPT!");
130 Throw<std::runtime_error>(
"negative zero is not canonical");
142 Throw<std::runtime_error>(
"invalid native currency");
147 Throw<std::runtime_error>(
"invalid native account");
150 int offset =
static_cast<int>(
value >> (64 - 10));
152 value &= ~(1023ull << (64 - 10));
156 bool isNegative = (offset & 256) == 0;
157 offset = (offset & 255) - 97;
162 Throw<std::runtime_error>(
"invalid currency value");
174 Throw<std::runtime_error>(
"invalid currency value");
194 , mIsNegative(negative)
198 "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
204 , mAsset(from.mAsset)
205 , mValue(from.mValue)
206 , mOffset(from.mOffset)
207 , mIsNegative(from.mIsNegative)
211 "xrpl::STAmount::STAmount(SField, STAmount) : maximum input");
221 , mIsNegative(mantissa != 0 && negative)
225 "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
230 : mAsset(
xrpIssue()), mOffset(0), mIsNegative(amount <
beast::zero)
233 mValue = unsafe_cast<std::uint64_t>(-amount.drops());
235 mValue = unsafe_cast<std::uint64_t>(amount.drops());
255 return emplace(n, buf, std::move(*
this));
267 Throw<std::logic_error>(
268 "Cannot return non-native STAmount as XRPAmount");
271 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::xrp : amount is canonical");
283 Throw<std::logic_error>(
"Cannot return non-IOU STAmount as IOUAmount");
297 if (!holds<MPTIssue>())
298 Throw<std::logic_error>(
"Cannot return STAmount as MPTAmount");
301 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::mpt : amount is canonical");
313 native() ==
false,
"xrpl::STAmount::operator=(IOUAmount) : is not XRP");
347 Throw<std::runtime_error>(
"Can't add amounts that are't comparable!");
349 if (v2 == beast::zero)
352 if (v1 == beast::zero)
402 if ((fv >= -10) && (fv <= 10))
445 if (offerOut == beast::zero)
450 if (r == beast::zero)
454 "xrpl::getRate : exponent inside range");
456 return (ret << (64 - 8)) | r.
mantissa();
492 if (a == beast::zero || b == beast::zero)
520 return ((rhs.
negative() ? -rhs : rhs) +
521 (lhs.
negative() ? -lhs : lhs)) <= maxLoss;
542 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
572 if (b == beast::zero)
617 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
666 if (*
this == beast::zero)
675 bool const scientific(
691 XRPL_ASSERT(
mOffset + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
693 size_t const pad_prefix = 27;
694 size_t const pad_suffix = 23;
698 val.
append(pad_prefix,
'0');
700 val.
append(pad_suffix,
'0');
702 size_t const offset(
mOffset + 43);
704 auto pre_from(val.
begin());
705 auto const pre_to(val.
begin() + offset);
707 auto const post_from(val.
begin() + offset);
708 auto post_to(val.
end());
713 pre_from += pad_prefix;
716 post_to >= post_from,
"xrpl::STAmount::getText : first distance check");
718 pre_from =
std::find_if(pre_from, pre_to, [](
char c) {
return c !=
'0'; });
723 post_to -= pad_suffix;
726 post_to >= post_from,
727 "xrpl::STAmount::getText : second distance check");
732 [](
char c) {
return c !=
'0'; })
736 if (pre_from == pre_to)
739 ret.
append(pre_from, pre_to);
741 if (post_to != post_from)
744 ret.
append(post_from, post_to);
763 XRPL_ASSERT(
mOffset == 0,
"xrpl::STAmount::add : zero offset");
772 auto u8 =
static_cast<unsigned char>(
cMPToken >> 56);
774 u8 |=
static_cast<unsigned char>(
cPositive >> 56);
781 if (*
this == beast::zero)
801 return v && (*v == *
this);
845 Throw<std::runtime_error>(
"Native currency amount out of range");
848 Throw<std::runtime_error>(
"MPT amount out of range");
854 auto set = [&](
auto const& val) {
863 Throw<std::runtime_error>(
"Unknown integral asset type");
879 Throw<std::runtime_error>(
880 "Native currency amount out of range");
882 Throw<std::runtime_error>(
"MPT amount out of range");
890 Throw<std::runtime_error>(
"Native currency amount out of range");
892 Throw<std::runtime_error>(
"MPT amount out of range");
919 Throw<std::runtime_error>(
"value overflow");
934 Throw<std::runtime_error>(
"value overflow");
938 "xrpl::STAmount::canonicalize : value inside range");
941 "xrpl::STAmount::canonicalize : offset inside range");
944 "xrpl::STAmount::canonicalize : value or offset set");
971 int exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
981 Throw<std::runtime_error>(
982 "XRP and MPT must be specified as integral amount.");
983 return {asset, parts.mantissa, parts.exponent, parts.negative};
998 Throw<std::runtime_error>(
999 "XRP may not be specified with a null Json value");
1004 Throw<std::runtime_error>(
"Invalid Asset's Json specification");
1006 value = v[jss::value];
1007 if (v.
isMember(jss::mpt_issuance_id))
1010 currencyOrMPTID = v[jss::mpt_issuance_id];
1014 currencyOrMPTID = v[jss::currency];
1015 issuer = v[jss::issuer];
1028 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
1030 if (elements.
size() > 3)
1031 Throw<std::runtime_error>(
"invalid amount string");
1033 value = elements[0];
1035 if (elements.
size() > 1)
1036 currencyOrMPTID = elements[1];
1038 if (elements.
size() > 2)
1039 issuer = elements[2];
1046 bool const native = !currencyOrMPTID.
isString() ||
1053 Throw<std::runtime_error>(
"XRP may not be specified as an object");
1063 Throw<std::runtime_error>(
"invalid MPTokenIssuanceID");
1070 Throw<std::runtime_error>(
"invalid currency");
1073 Throw<std::runtime_error>(
"invalid issuer");
1075 Throw<std::runtime_error>(
"invalid issuer");
1084 if (value.
asInt() >= 0)
1103 Throw<std::runtime_error>(
1104 "XRP and MPT must be specified as integral amount.");
1108 Throw<std::runtime_error>(
"invalid amount type");
1125 <<
"amountFromJsonNoThrow: caught: " << e.
what();
1147 Throw<std::runtime_error>(
1148 "Can't compare amounts that are't comparable!");
1206 boost::multiprecision::uint128_t ret;
1208 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1213 Throw<std::overflow_error>(
1218 return static_cast<uint64_t
>(ret);
1228 boost::multiprecision::uint128_t ret;
1230 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1236 Throw<std::overflow_error>(
1242 return static_cast<uint64_t
>(ret);
1248 if (den == beast::zero)
1249 Throw<std::runtime_error>(
"division by zero");
1251 if (num == beast::zero)
1286 numOffset - denOffset - 17,
1293 if (v1 == beast::zero || v2 == beast::zero)
1301 if (minV > 3000000000ull)
1302 Throw<std::runtime_error>(
"Native value overflow");
1304 if (((maxV >> 32) * minV) > 2095475792ull)
1305 Throw<std::runtime_error>(
"Native value overflow");
1314 if (minV > 3037000499ull)
1315 Throw<std::runtime_error>(
"MPT value overflow");
1317 if (((maxV >> 32) * minV) > 2147483648ull)
1318 Throw<std::runtime_error>(
"MPT value overflow");
1320 return STAmount(asset, minV * maxV);
1326 return STAmount{asset, r.mantissa(), r.exponent()};
1359 offset1 + offset2 + 14,
1399 value += (loops >= 2) ? 9 : 10;
1433 bool hadRemainder =
false;
1441 hadRemainder |= (value != (newValue * 10));
1446 (hadRemainder && roundUp) ? 10 : 9;
1488 return (value + referenceValue) - referenceValue;
1495class DontAffectNumberRoundMode
1502 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1504 DontAffectNumberRoundMode&
1505 operator=(DontAffectNumberRoundMode
const&) =
delete;
1516 typename MightSaveRound>
1524 if (v1 == beast::zero || v2 == beast::zero)
1527 bool const xrp = asset.
native();
1534 if (minV > 3000000000ull)
1535 Throw<std::runtime_error>(
"Native value overflow");
1537 if (((maxV >> 32) * minV) > 2095475792ull)
1538 Throw<std::runtime_error>(
"Native value overflow");
1548 if (minV > 3037000499ull)
1549 Throw<std::runtime_error>(
"MPT value overflow");
1551 if (((maxV >> 32) * minV) > 2147483648ull)
1552 Throw<std::runtime_error>(
"MPT value overflow");
1554 return STAmount(asset, minV * maxV);
1591 int offset = offset1 + offset2 + 14;
1592 if (resultNegative != roundUp)
1594 CanonicalizeFunc(xrp, amount, offset, roundUp);
1600 return STAmount(asset, amount, offset, resultNegative);
1603 if (roundUp && !resultNegative && !result)
1617 return STAmount(asset, amount, offset, resultNegative);
1629 return mulRoundImpl<canonicalizeRound, DontAffectNumberRoundMode>(
1630 v1, v2, asset, roundUp);
1640 return mulRoundImpl<canonicalizeRoundStrict, NumberRoundModeGuard>(
1641 v1, v2, asset, roundUp);
1646template <
typename MightSaveRound>
1654 if (den == beast::zero)
1655 Throw<std::runtime_error>(
"division by zero");
1657 if (num == beast::zero)
1692 numVal,
tenTo17, denVal, (resultNegative != roundUp) ? denVal - 1 : 0);
1694 int offset = numOffset - denOffset - 17;
1696 if (resultNegative != roundUp)
1705 MightSaveRound
const savedRound(
1706 roundUp ^ resultNegative ? upward : downward);
1707 return STAmount(asset, amount, offset, resultNegative);
1710 if (roundUp && !resultNegative && !result)
1724 return STAmount(asset, amount, offset, resultNegative);
1736 return divRoundImpl<DontAffectNumberRoundMode>(num, den, asset, roundUp);
1746 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.
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
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
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 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)
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)
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 getSTNumberSwitchover()
Note, should be treated as flags that can be | and &.