1#include <xrpl/protocol/STAmount.h>
3#include <xrpl/basics/Log.h>
4#include <xrpl/basics/Number.h>
5#include <xrpl/basics/contract.h>
6#include <xrpl/basics/safe_cast.h>
7#include <xrpl/beast/utility/Zero.h>
8#include <xrpl/beast/utility/instrumentation.h>
9#include <xrpl/json/json_forwards.h>
10#include <xrpl/json/json_value.h>
11#include <xrpl/protocol/AccountID.h>
12#include <xrpl/protocol/Asset.h>
13#include <xrpl/protocol/Concepts.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/STArray.h>
23#include <xrpl/protocol/STBase.h>
24#include <xrpl/protocol/STNumber.h>
25#include <xrpl/protocol/STObject.h>
26#include <xrpl/protocol/Serializer.h>
27#include <xrpl/protocol/SystemParameters.h>
28#include <xrpl/protocol/UintTypes.h>
29#include <xrpl/protocol/XRPAmount.h>
30#include <xrpl/protocol/jss.h>
32#include <boost/algorithm/string/classification.hpp>
33#include <boost/algorithm/string/split.hpp>
34#include <boost/multiprecision/detail/default_ops.hpp>
62 XRPL_ASSERT(amount.
exponent() == 0,
"xrpl::getInt64Value : exponent is zero");
68 "xrpl::getInt64Value : mantissa must roundtrip");
95 return v1.
native() == v2.
native() && issue1.currency == issue2.currency;
99 return issue1 == issue2;
161 int offset =
static_cast<int>(
value >> (64 - 10));
163 value &= ~(1023ull << (64 - 10));
167 bool const isNegative = (offset & 256) == 0;
168 offset = (offset & 255) - 97;
204 "xrpl::STAmount::STAmount(SField, std::uint64_t, bool) : maximum "
217 "xrpl::STAmount::STAmount(SField, STAmount) : maximum input");
228 "xrpl::STAmount::STAmount(std::uint64_t, bool) : maximum mantissa "
262 return emplace(n, buf, std::move(*
this));
277 XRPL_ASSERT(
offset_ == 0,
"xrpl::STAmount::xrp : amount is canonical");
307 XRPL_ASSERT(
offset_ == 0,
"xrpl::STAmount::mpt : amount is canonical");
318 XRPL_ASSERT(
integral() ==
false,
"xrpl::STAmount::operator=(IOUAmount) : is not integral");
342 auto const originalMantissa = number.
mantissa();
434 "xrpl::getRate : exponent inside range");
436 return (ret << (64 - 8)) | r.
mantissa();
497 return ((rhs.
negative() ? -rhs : rhs) + (lhs.
negative() ? -lhs : lhs)) <= kMaxLoss;
518 UNREACHABLE(
"STAmount::canAdd : unexpected STAmount type");
600 UNREACHABLE(
"STAmount::canSubtract : unexpected STAmount type");
673 XRPL_ASSERT(
offset_ + 43 > 0,
"xrpl::STAmount::getText : minimum offset");
675 size_t const padPrefix = 27;
676 size_t const padSuffix = 23;
680 val.
append(padPrefix,
'0');
682 val.
append(padSuffix,
'0');
684 size_t const offset(
offset_ + 43);
686 auto preFrom(val.
begin());
687 auto const preTo(val.
begin() + offset);
689 auto const postFrom(val.
begin() + offset);
690 auto postTo(val.
end());
695 preFrom += padPrefix;
697 XRPL_ASSERT(postTo >= postFrom,
"xrpl::STAmount::getText : first distance check");
699 preFrom =
std::find_if(preFrom, preTo, [](
char c) {
return c !=
'0'; });
706 XRPL_ASSERT(postTo >= postFrom,
"xrpl::STAmount::getText : second distance check");
711 [](
char c) {
return c !=
'0'; })
715 if (preFrom == preTo)
721 ret.
append(preFrom, preTo);
724 if (postTo != postFrom)
727 ret.
append(postFrom, postTo);
746 auto u8 =
static_cast<unsigned char>(
kMpToken >> 56);
748 u8 |=
static_cast<unsigned char>(
kPositive >> 56);
753 [&](
Issue const& issue) {
756 XRPL_ASSERT(
offset_ == 0,
"xrpl::STAmount::add : zero offset");
792 auto const* v =
dynamic_cast<STAmount const*
>(&t);
793 return (v !=
nullptr) && (*v == *
this);
843 auto set = [&](
auto const& val) {
844 auto const value = val.value();
901 int const exponent =
static_cast<int>(rate >> (64 - 8)) - 100;
912 return {asset, parts.mantissa, parts.exponent, parts.negative};
934 value = v[jss::value];
935 if (v.
isMember(jss::mpt_issuance_id))
938 currencyOrMPTID = v[jss::mpt_issuance_id];
942 currencyOrMPTID = v[jss::currency];
943 issuer = v[jss::issuer];
956 boost::split(elements, val, boost::is_any_of(
"\t\n\r ,/"));
958 if (elements.
size() > 3)
963 if (elements.
size() > 1)
964 currencyOrMPTID = elements[1];
966 if (elements.
size() > 2)
967 issuer = elements[2];
1010 if (value.asInt() >= 0)
1016 parts.
mantissa = value.asAbsUInt();
1020 else if (value.isUInt())
1024 else if (value.isString())
1049 JLOG(
debugLog().warn()) <<
"amountFromJsonNoThrow: caught: " << e.
what();
1104 if (value.mantissa() == 0)
1137 JLOG(j.
error()) <<
"hasInvalidAmount: depth exceeds 10";
1155 case STI_LEDGERENTRY:
1156 case STI_TRANSACTION:
1164 dynamic_cast<STObject const*
>(&field) ==
nullptr,
1165 "xrpl::hasInvalidAmount : unhandled STObject type");
1188 boost::multiprecision::uint128_t ret;
1190 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1200 return static_cast<uint64_t
>(ret);
1210 boost::multiprecision::uint128_t ret;
1212 boost::multiprecision::multiply(ret, multiplier, multiplicand);
1223 return static_cast<uint64_t
>(ret);
1267 numOffset - denOffset - 17,
1282 if (minV > 3000000000ull)
1285 if (((maxV >> 32) * minV) > 2095475792ull)
1295 if (minV > 3037000499ull)
1298 if (((maxV >> 32) * minV) > 2147483648ull)
1301 return STAmount(asset, minV * maxV);
1344 value += (loops >= 2) ? 9 : 10;
1374 bool hadRemainder =
false;
1382 hadRemainder |= (value != (newValue * 10));
1386 value += (hadRemainder && roundUp) ? 10 : 9;
1408 if (value.integral())
1418 if (value.exponent() >=
scale)
1428 return (value + referenceValue) - referenceValue;
1435class DontAffectNumberRoundMode
1442 DontAffectNumberRoundMode(DontAffectNumberRoundMode
const&) =
delete;
1444 DontAffectNumberRoundMode&
1445 operator=(DontAffectNumberRoundMode
const&) =
delete;
1449roundMode(
bool const resultNegative,
bool const roundUp)
1460 return roundUp ^ resultNegative ? Upward : Downward;
1466 bool const resultNegative,
1473 auto result =
STAmount{asset, number};
1474 [[maybe_unused]]
bool const nonzeroPositiveRoundUp =
1478 "xrpl::roundNumberResult : positive rounded-up MPT result is representable");
1480 if (roundUp && !resultNegative && !result)
1492 if (asset.integral())
1507template <
void (*CanonicalizeFunc)(
bool, std::u
int64_t&,
int&,
bool),
typename MightSaveRound>
1519 if (minV > 3000000000ull)
1522 if (((maxV >> 32) * minV) > 2095475792ull)
1533 if (minV > 3037000499ull)
1536 if (((maxV >> 32) * minV) > 2147483648ull)
1539 return STAmount(asset, minV * maxV);
1555 return roundNumberResult(asset, resultNegative, roundUp, result);
1589 int offset = offset1 + offset2 + 14;
1590 if (resultNegative != roundUp)
1592 CanonicalizeFunc(asset.
integral(), amount, offset, roundUp);
1598 return STAmount(asset, amount, offset, resultNegative);
1601 if (roundUp && !resultNegative && !result)
1615 return STAmount(asset, amount, offset, resultNegative);
1634template <
typename MightSaveRound>
1657 return roundNumberResult(asset, resultNegative, roundUp, result);
1692 int offset = numOffset - denOffset - 17;
1694 if (resultNegative != roundUp)
1702 MightSaveRound
const savedRound(roundUp ^ resultNegative ? Upward : Downward);
1703 return STAmount(asset, amount, offset, resultNegative);
1706 if (roundUp && !resultNegative && !result)
1720 return STAmount(asset, amount, offset, resultNegative);
A generic endpoint for log messages.
bool isNull() const
isNull() tests to see if this field is null.
Value get(UInt index, Value const &defaultValue) const
If the array contains at least index+1 elements, returns the element value, otherwise returns default...
std::string asString() const
Returns the unquoted string value.
bool isObjectOrNull() const
bool isMember(char const *key) const
Return true if the object has a member named key.
constexpr bool native() const
constexpr bool holds() const
constexpr value_type const & value() const
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Floating point representation of amounts with high dynamic range.
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
void setIssue(Asset const &asset)
Set the Issue for this amount.
static constexpr std::uint64_t kIssuedCurrency
std::string getFullText() const override
static STAmount fromNumber(A const &asset, Number const &number)
void add(Serializer &s) const override
static std::uint64_t const kURateOne
std::uint64_t mantissa() const noexcept
static constexpr std::uint64_t kPositive
int signum() const noexcept
bool isEquivalent(STBase const &t) const override
STBase * copy(std::size_t n, void *buf) const override
std::string getText() const override
static constexpr int kMinOffset
SerializedTypeID getSType() const override
bool negative() const noexcept
static constexpr std::uint64_t kMaxNativeN
bool isDefault() const override
bool integral() const noexcept
static constexpr std::uint64_t kValueMask
STAmount & operator=(beast::Zero)
static std::unique_ptr< STAmount > construct(SerialIter &, SField const &name)
bool native() const noexcept
Asset const & asset() const
STAmount & operator+=(STAmount const &)
void setJson(json::Value &) const
static constexpr std::uint64_t kMpToken
json::Value getJson(JsonOptions=JsonOptions::Values::None) const override
STAmount & operator-=(STAmount const &)
int exponent() const noexcept
bool isZeroAtScale(int scale) const
Checks if this amount evaluates to zero when constrained to a specific accounting scale.
static constexpr std::uint64_t kMinValue
static constexpr std::uint64_t kMaxValue
STBase * move(std::size_t n, void *buf) override
static constexpr int kMaxOffset
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)
virtual SerializedTypeID getSType() const
int addBitString(BaseUInt< Bits, Tag > const &v)
int add8(unsigned char i)
constexpr value_type drops() const
Returns the number of drops.
T make_reverse_iterator(T... args)
@ Object
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.
constexpr BaseUInt< Bits, Tag > operator+(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
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
Issue const & xrpIssue()
Returns an asset specifier that represents XRP.
static STAmount mulRoundImpl(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
bool isFeatureEnabled(uint256 const &feature, bool resultIfNoRules)
Check whether a feature is enabled in the current ledger rules.
constexpr bool operator==(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
bool isLegalMPT(STAmount const &value)
Dest safeDowncast(Src *s) noexcept
bool isXRP(AccountID const &c)
beast::Journal debugLog()
Returns a debug journal.
NumberParts partsFromString(std::string const &number)
Number operator-(Number const &x, Number const &y)
STAmount mulRoundStrict(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
int scale(Number const &number, Asset const &asset)
Get the scale of a Number for a given asset.
bool isLegalNet(STAmount const &value)
bool validJSONAsset(json::Value const &jv)
STAmount amountFromString(Asset const &asset, std::string const &amount)
std::optional< Rules > const & getCurrentTransactionRules()
bool toCurrency(Currency &, std::string const &)
Tries to convert a string to a Currency, returns true on success.
static std::uint64_t const kTenTO14
STAmount divRound(STAmount const &v1, STAmount const &v2, Asset const &asset, bool roundUp)
constexpr Dest unsafeCast(Src s) noexcept
STAmount roundToScale(STAmount const &value, std::int32_t scale, Number::RoundingMode rounding=Number::getround())
Round an arbitrary precision Amount to the precision of an STAmount that has a given exponent.
bool canAdd(STAmount const &amt1, STAmount const &amt2)
Safely checks if two STAmount values can be added without overflow, underflow, or precision loss.
bool amountFromJsonNoThrow(STAmount &result, json::Value const &jvSource)
STAmount amountFromQuality(std::uint64_t rate)
BaseUInt< 192 > MPTID
MPTID is a 192-bit value representing MPT Issuance ID, which is a concatenation of a 32-bit sequence ...
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)
STAmount amountFromJson(SField const &name, json::Value const &v)
bool hasInvalidAmount(STBase const &field, beast::Journal j)
static std::uint64_t const kTenTO17
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.
static std::uint64_t muldivRound(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor, std::uint64_t rounding)
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.
constexpr bool kIsMptissueV
static std::uint64_t muldiv(std::uint64_t multiplier, std::uint64_t multiplicand, std::uint64_t divisor)
static std::string const & systemCurrencyCode()
STAmount multiply(STAmount const &amount, Number const &frac, Number::RoundingMode rm)
static STAmount divRoundImpl(STAmount const &num, STAmount const &den, Asset const &asset, bool roundUp)
constexpr std::uint64_t kMaxMpTokenAmount
The maximum amount of MPTokenIssuance.
constexpr XRPAmount kInitialXrp
Configure the native currency.
static void canonicalizeRoundStrict(bool integral, std::uint64_t &value, int &offset, bool roundUp)
bool toIssuer(AccountID &, std::string const &)
Convert hex or base58 string to AccountID.
static std::uint64_t const kTenTO14M1
static void canonicalizeRound(bool integral, std::uint64_t &value, int &offset, bool)
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Note, should be treated as flags that can be | and &.