diff --git a/src/ripple/basics/IOUAmount.h b/src/ripple/basics/IOUAmount.h index c3ef1340a7..764aa38aae 100644 --- a/src/ripple/basics/IOUAmount.h +++ b/src/ripple/basics/IOUAmount.h @@ -186,10 +186,6 @@ mulRatio( std::uint32_t den, bool roundUp); -// Since IOUAmount and STAmount do not have access to a ledger, this -// is needed to put low-level routines on an amendment switch. Only -// transactions need to use this switchover. Outside of a transaction -// it's safe to unconditionally use the new behavior. extern LocalValue stNumberSwitchover; /** RAII class to set and restore the Number switchover. diff --git a/src/ripple/basics/Number.h b/src/ripple/basics/Number.h index ef45b3f779..58d903579b 100644 --- a/src/ripple/basics/Number.h +++ b/src/ripple/basics/Number.h @@ -337,6 +337,24 @@ squelch(Number const& x, Number const& limit) noexcept return x; } +class saveNumberRoundMode +{ + Number::rounding_mode mode_; + +public: + ~saveNumberRoundMode() + { + Number::setround(mode_); + } + explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept + : mode_{mode} + { + } + saveNumberRoundMode(saveNumberRoundMode const&) = delete; + saveNumberRoundMode& + operator=(saveNumberRoundMode const&) = delete; +}; + } // namespace ripple #endif // RIPPLE_BASICS_NUMBER_H_INCLUDED diff --git a/src/ripple/protocol/impl/STAmount.cpp b/src/ripple/protocol/impl/STAmount.cpp index 51e8adb568..d1a878c8b4 100644 --- a/src/ripple/protocol/impl/STAmount.cpp +++ b/src/ripple/protocol/impl/STAmount.cpp @@ -725,24 +725,36 @@ STAmount::canonicalize() "Native currency amount out of range"); } - while (mOffset < 0) + if (*stNumberSwitchover && *stAmountCanonicalizeSwitchover) { - mValue /= 10; - ++mOffset; + Number num( + mIsNegative ? -mValue : mValue, mOffset, Number::unchecked{}); + XRPAmount xrp{num}; + mIsNegative = xrp.drops() < 0; + mValue = mIsNegative ? -xrp.drops() : xrp.drops(); + mOffset = 0; } - - while (mOffset > 0) + else { - if (*stAmountCanonicalizeSwitchover) + while (mOffset < 0) { - // N.B. do not move the overflow check to after the - // multiplication - if (mValue > cMaxNativeN) - Throw( - "Native currency amount out of range"); + mValue /= 10; + ++mOffset; + } + + while (mOffset > 0) + { + if (*stAmountCanonicalizeSwitchover) + { + // N.B. do not move the overflow check to after the + // multiplication + if (mValue > cMaxNativeN) + Throw( + "Native currency amount out of range"); + } + mValue *= 10; + --mOffset; } - mValue *= 10; - --mOffset; } if (mValue > cMaxNativeN) diff --git a/src/test/app/NFToken_test.cpp b/src/test/app/NFToken_test.cpp index 42a6eb4d3c..842f3f76cc 100644 --- a/src/test/app/NFToken_test.cpp +++ b/src/test/app/NFToken_test.cpp @@ -2349,7 +2349,13 @@ class NFToken_test : public beast::unit_test::suite // See the impact of rounding when the nft is sold for small amounts // of drops. + for (auto NumberSwitchOver : {true}) { + if (NumberSwitchOver) + env.enableFeature(fixUniversalNumber); + else + env.disableFeature(fixUniversalNumber); + // An nft with a transfer fee of 1 basis point. uint256 const nftID = token::getNextID(env, alice, 0u, tfTransferable, 1); @@ -2374,16 +2380,16 @@ class NFToken_test : public beast::unit_test::suite // minter sells to carol. The payment is just small enough that // alice does not get any transfer fee. + auto pmt = NumberSwitchOver ? drops(50000) : drops(99999); STAmount carolBalance = env.balance(carol); uint256 const minterSellOfferIndex = keylet::nftoffer(minter, env.seq(minter)).key; - env(token::createOffer(minter, nftID, drops(99999)), - txflags(tfSellNFToken)); + env(token::createOffer(minter, nftID, pmt), txflags(tfSellNFToken)); env.close(); env(token::acceptSellOffer(carol, minterSellOfferIndex)); env.close(); - minterBalance += drops(99999) - fee; - carolBalance -= drops(99999) + fee; + minterBalance += pmt - fee; + carolBalance -= pmt + fee; BEAST_EXPECT(env.balance(alice) == aliceBalance); BEAST_EXPECT(env.balance(minter) == minterBalance); BEAST_EXPECT(env.balance(carol) == carolBalance); @@ -2393,13 +2399,13 @@ class NFToken_test : public beast::unit_test::suite STAmount beckyBalance = env.balance(becky); uint256 const beckyBuyOfferIndex = keylet::nftoffer(becky, env.seq(becky)).key; - env(token::createOffer(becky, nftID, drops(100000)), - token::owner(carol)); + pmt = NumberSwitchOver ? drops(50001) : drops(100000); + env(token::createOffer(becky, nftID, pmt), token::owner(carol)); env.close(); env(token::acceptBuyOffer(carol, beckyBuyOfferIndex)); env.close(); - carolBalance += drops(99999) - fee; - beckyBalance -= drops(100000) + fee; + carolBalance += pmt - drops(1) - fee; + beckyBalance -= pmt + fee; aliceBalance += drops(1); BEAST_EXPECT(env.balance(alice) == aliceBalance); diff --git a/src/test/app/Taker_test.cpp b/src/test/app/Taker_test.cpp index 38735d8cfc..0b69b25f24 100644 --- a/src/test/app/Taker_test.cpp +++ b/src/test/app/Taker_test.cpp @@ -273,314 +273,521 @@ public: Quality q1 = get_quality("1", "1"); - // TAKER OWNER - // QUAL OFFER FUNDS QUAL OFFER FUNDS - // EXPECTED - // XRP USD - attempt( - Sell, - "N:N", - q1, - {"2", "2"}, - "2", - q1, - {"2", "2"}, - "2", - {"2", "2"}, - xrp(), - usd()); - attempt( - Sell, - "N:B", - q1, - {"2", "2"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "N:T", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "N:BT", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "N:TB", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); + for (auto NumberSwitchOver : {false, true}) + { + NumberSO stNumberSO{NumberSwitchOver}; + // TAKER OWNER + // QUAL OFFER FUNDS QUAL OFFER FUNDS + // EXPECTED + // XRP USD + attempt( + Sell, + "N:N", + q1, + {"2", "2"}, + "2", + q1, + {"2", "2"}, + "2", + {"2", "2"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Sell, + "N:B", + q1, + {"2", "2"}, + "2", + q1, + {"2", "2"}, + "1.8", + {"2", "1.8"}, + xrp(), + usd()); + } + else + { + attempt( + Sell, + "N:B", + q1, + {"2", "2"}, + "2", + q1, + {"2", "2"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + } + attempt( + Buy, + "N:T", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + xrp(), + usd()); + attempt( + Buy, + "N:BT", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Buy, + "N:TB", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "0.8", + {"1", "0.8"}, + xrp(), + usd()); + } + else + { + attempt( + Buy, + "N:TB", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "0.8", + {"0", "0.8"}, + xrp(), + usd()); + } + attempt( + Sell, + "T:N", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Sell, + "T:B", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + } + else + { + attempt( + Sell, + "T:B", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + } + attempt( + Buy, + "T:T", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + xrp(), + usd()); + attempt( + Buy, + "T:BT", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Buy, + "T:TB", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "0.8", + {"1", "0.8"}, + xrp(), + usd()); + } + else + { + attempt( + Buy, + "T:TB", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "0.8", + {"0", "0.8"}, + xrp(), + usd()); + } - attempt( - Sell, - "T:N", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Sell, - "T:B", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "T:T", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "T:BT", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "1.8", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "T:TB", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); + attempt( + Sell, + "A:N", + q1, + {"2", "2"}, + "1", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Sell, + "A:B", + q1, + {"2", "2"}, + "1", + q1, + {"2", "2"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + } + else + { + attempt( + Sell, + "A:B", + q1, + {"2", "2"}, + "1", + q1, + {"2", "2"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + } + attempt( + Buy, + "A:T", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "3", + {"1", "1"}, + xrp(), + usd()); + attempt( + Buy, + "A:BT", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "2.4", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Buy, + "A:TB", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "0.8", + {"1", "0.8"}, + xrp(), + usd()); + } + else + { + attempt( + Buy, + "A:TB", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "0.8", + {"0", "0.8"}, + xrp(), + usd()); + } - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Sell, - "A:B", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "A:T", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "A:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "2.4", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "A:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); + attempt( + Sell, + "TA:N", + q1, + {"2", "2"}, + "1", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Sell, + "TA:B", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + } + else + { + attempt( + Sell, + "TA:B", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + } + attempt( + Buy, + "TA:T", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "3", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Buy, + "TA:BT", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + attempt( + Buy, + "TA:TB", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + } + else + { + attempt( + Buy, + "TA:BT", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + attempt( + Buy, + "TA:TB", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + } - attempt( - Sell, - "TA:N", - q1, - {"2", "2"}, - "1", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - xrp(), - usd()); - attempt( - Sell, - "TA:B", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "TA:T", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "TA:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "TA:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - - attempt( - Sell, - "AT:N", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - attempt( - Sell, - "AT:B", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "AT:T", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "3", - {"1", "1"}, - xrp(), - usd()); - attempt( - Buy, - "AT:BT", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "1.8", - {"1", "1.8"}, - xrp(), - usd()); - attempt( - Buy, - "AT:TB", - q1, - {"2", "2"}, - "1", - q1, - {"3", "3"}, - "0.8", - {"0", "0.8"}, - xrp(), - usd()); + attempt( + Sell, + "AT:N", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "3", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Sell, + "AT:B", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + } + else + { + attempt( + Sell, + "AT:B", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + } + attempt( + Buy, + "AT:T", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "3", + {"1", "1"}, + xrp(), + usd()); + if (NumberSwitchOver) + { + attempt( + Buy, + "AT:BT", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1"}, + xrp(), + usd()); + attempt( + Buy, + "AT:TB", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "0.8", + {"1", "0.8"}, + xrp(), + usd()); + } + else + { + attempt( + Buy, + "AT:BT", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "1.8", + {"1", "1.8"}, + xrp(), + usd()); + attempt( + Buy, + "AT:TB", + q1, + {"2", "2"}, + "1", + q1, + {"3", "3"}, + "0.8", + {"0", "0.8"}, + xrp(), + usd()); + } + } } void @@ -588,316 +795,446 @@ public: { testcase("XRP Quantization: output"); - Quality q1 = get_quality("1", "1"); + for (auto NumberSwitchOver : {false, true}) + { + NumberSO stNumberSO{NumberSwitchOver}; + Quality q1 = get_quality("1", "1"); - // TAKER OWNER - // QUAL OFFER FUNDS QUAL OFFER FUNDS - // EXPECTED - // USD XRP - attempt( - Sell, - "N:N", - q1, - {"3", "3"}, - "3", - q1, - {"3", "3"}, - "3", - {"3", "3"}, - usd(), - xrp()); - attempt( - Sell, - "N:B", - q1, - {"3", "3"}, - "3", - q1, - {"3", "3"}, - "2", - {"2", "2"}, - usd(), - xrp()); - attempt( - Buy, - "N:T", - q1, - {"3", "3"}, - "2.5", - q1, - {"5", "5"}, - "5", - {"2.5", "2"}, - usd(), - xrp()); - attempt( - Buy, - "N:BT", - q1, - {"3", "3"}, - "1.5", - q1, - {"5", "5"}, - "4", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Buy, - "N:TB", - q1, - {"3", "3"}, - "2.2", - q1, - {"5", "5"}, - "1", - {"1", "1"}, - usd(), - xrp()); + // TAKER OWNER + // QUAL OFFER FUNDS QUAL OFFER FUNDS + // EXPECTED + // USD XRP + attempt( + Sell, + "N:N", + q1, + {"3", "3"}, + "3", + q1, + {"3", "3"}, + "3", + {"3", "3"}, + usd(), + xrp()); + attempt( + Sell, + "N:B", + q1, + {"3", "3"}, + "3", + q1, + {"3", "3"}, + "2", + {"2", "2"}, + usd(), + xrp()); + if (NumberSwitchOver) + { + attempt( + Buy, + "N:T", + q1, + {"3", "3"}, + "2.5", + q1, + {"5", "5"}, + "5", + {"2.5", "3"}, + usd(), + xrp()); + attempt( + Buy, + "N:BT", + q1, + {"3", "3"}, + "1.5", + q1, + {"5", "5"}, + "4", + {"1.5", "2"}, + usd(), + xrp()); + } + else + { + attempt( + Buy, + "N:T", + q1, + {"3", "3"}, + "2.5", + q1, + {"5", "5"}, + "5", + {"2.5", "2"}, + usd(), + xrp()); + attempt( + Buy, + "N:BT", + q1, + {"3", "3"}, + "1.5", + q1, + {"5", "5"}, + "4", + {"1.5", "1"}, + usd(), + xrp()); + } + attempt( + Buy, + "N:TB", + q1, + {"3", "3"}, + "2.2", + q1, + {"5", "5"}, + "1", + {"1", "1"}, + usd(), + xrp()); - attempt( - Sell, - "T:N", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - usd(), - xrp()); - attempt( - Sell, - "T:B", - q1, - {"2", "2"}, - "2", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "T:T", - q1, - {"1", "1"}, - "2", - q1, - {"2", "2"}, - "2", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "T:BT", - q1, - {"1", "1"}, - "2", - q1, - {"3", "3"}, - "2", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "T:TB", - q1, - {"2", "2"}, - "2", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); + attempt( + Sell, + "T:N", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + usd(), + xrp()); + attempt( + Sell, + "T:B", + q1, + {"2", "2"}, + "2", + q1, + {"3", "3"}, + "1", + {"1", "1"}, + usd(), + xrp()); + attempt( + Buy, + "T:T", + q1, + {"1", "1"}, + "2", + q1, + {"2", "2"}, + "2", + {"1", "1"}, + usd(), + xrp()); + attempt( + Buy, + "T:BT", + q1, + {"1", "1"}, + "2", + q1, + {"3", "3"}, + "2", + {"1", "1"}, + usd(), + xrp()); + attempt( + Buy, + "T:TB", + q1, + {"2", "2"}, + "2", + q1, + {"3", "3"}, + "1", + {"1", "1"}, + usd(), + xrp()); - attempt( - Sell, - "A:N", - q1, - {"2", "2"}, - "1.5", - q1, - {"2", "2"}, - "2", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Sell, - "A:B", - q1, - {"2", "2"}, - "1.8", - q1, - {"3", "3"}, - "2", - {"1.8", "1"}, - usd(), - xrp()); - attempt( - Buy, - "A:T", - q1, - {"2", "2"}, - "1.2", - q1, - {"3", "3"}, - "3", - {"1.2", "1"}, - usd(), - xrp()); - attempt( - Buy, - "A:BT", - q1, - {"2", "2"}, - "1.5", - q1, - {"4", "4"}, - "3", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Buy, - "A:TB", - q1, - {"2", "2"}, - "1.5", - q1, - {"4", "4"}, - "1", - {"1", "1"}, - usd(), - xrp()); + if (NumberSwitchOver) + { + attempt( + Sell, + "A:N", + q1, + {"2", "2"}, + "1.5", + q1, + {"2", "2"}, + "2", + {"1.5", "2"}, + usd(), + xrp()); + attempt( + Sell, + "A:B", + q1, + {"2", "2"}, + "1.8", + q1, + {"3", "3"}, + "2", + {"1.8", "2"}, + usd(), + xrp()); + } + else + { + attempt( + Sell, + "A:N", + q1, + {"2", "2"}, + "1.5", + q1, + {"2", "2"}, + "2", + {"1.5", "1"}, + usd(), + xrp()); + attempt( + Sell, + "A:B", + q1, + {"2", "2"}, + "1.8", + q1, + {"3", "3"}, + "2", + {"1.8", "1"}, + usd(), + xrp()); + } + attempt( + Buy, + "A:T", + q1, + {"2", "2"}, + "1.2", + q1, + {"3", "3"}, + "3", + {"1.2", "1"}, + usd(), + xrp()); + if (NumberSwitchOver) + { + attempt( + Buy, + "A:BT", + q1, + {"2", "2"}, + "1.5", + q1, + {"4", "4"}, + "3", + {"1.5", "2"}, + usd(), + xrp()); + } + else + { + attempt( + Buy, + "A:BT", + q1, + {"2", "2"}, + "1.5", + q1, + {"4", "4"}, + "3", + {"1.5", "1"}, + usd(), + xrp()); + } + attempt( + Buy, + "A:TB", + q1, + {"2", "2"}, + "1.5", + q1, + {"4", "4"}, + "1", + {"1", "1"}, + usd(), + xrp()); - attempt( - Sell, - "TA:N", - q1, - {"2", "2"}, - "1.5", - q1, - {"2", "2"}, - "2", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Sell, - "TA:B", - q1, - {"2", "2"}, - "1.5", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "TA:T", - q1, - {"2", "2"}, - "1.5", - q1, - {"3", "3"}, - "3", - {"1.5", "1"}, - usd(), - xrp()); - attempt( - Buy, - "TA:BT", - q1, - {"2", "2"}, - "1.8", - q1, - {"4", "4"}, - "3", - {"1.8", "1"}, - usd(), - xrp()); - attempt( - Buy, - "TA:TB", - q1, - {"2", "2"}, - "1.2", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); + if (NumberSwitchOver) + { + attempt( + Sell, + "TA:N", + q1, + {"2", "2"}, + "1.5", + q1, + {"2", "2"}, + "2", + {"1.5", "2"}, + usd(), + xrp()); + } + else + { + attempt( + Sell, + "TA:N", + q1, + {"2", "2"}, + "1.5", + q1, + {"2", "2"}, + "2", + {"1.5", "1"}, + usd(), + xrp()); + } + attempt( + Sell, + "TA:B", + q1, + {"2", "2"}, + "1.5", + q1, + {"3", "3"}, + "1", + {"1", "1"}, + usd(), + xrp()); + if (NumberSwitchOver) + { + attempt( + Buy, + "TA:T", + q1, + {"2", "2"}, + "1.5", + q1, + {"3", "3"}, + "3", + {"1.5", "2"}, + usd(), + xrp()); + attempt( + Buy, + "TA:BT", + q1, + {"2", "2"}, + "1.8", + q1, + {"4", "4"}, + "3", + {"1.8", "2"}, + usd(), + xrp()); + } + else + { + attempt( + Buy, + "TA:T", + q1, + {"2", "2"}, + "1.5", + q1, + {"3", "3"}, + "3", + {"1.5", "1"}, + usd(), + xrp()); + attempt( + Buy, + "TA:BT", + q1, + {"2", "2"}, + "1.8", + q1, + {"4", "4"}, + "3", + {"1.8", "1"}, + usd(), + xrp()); + } + attempt( + Buy, + "TA:TB", + q1, + {"2", "2"}, + "1.2", + q1, + {"3", "3"}, + "1", + {"1", "1"}, + usd(), + xrp()); - attempt( - Sell, - "AT:N", - q1, - {"2", "2"}, - "2.5", - q1, - {"4", "4"}, - "4", - {"2", "2"}, - usd(), - xrp()); - attempt( - Sell, - "AT:B", - q1, - {"2", "2"}, - "2.5", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); - attempt( - Buy, - "AT:T", - q1, - {"2", "2"}, - "2.5", - q1, - {"3", "3"}, - "3", - {"2", "2"}, - usd(), - xrp()); - attempt( - Buy, - "AT:BT", - q1, - {"2", "2"}, - "2.5", - q1, - {"4", "4"}, - "3", - {"2", "2"}, - usd(), - xrp()); - attempt( - Buy, - "AT:TB", - q1, - {"2", "2"}, - "2.5", - q1, - {"3", "3"}, - "1", - {"1", "1"}, - usd(), - xrp()); + attempt( + Sell, + "AT:N", + q1, + {"2", "2"}, + "2.5", + q1, + {"4", "4"}, + "4", + {"2", "2"}, + usd(), + xrp()); + attempt( + Sell, + "AT:B", + q1, + {"2", "2"}, + "2.5", + q1, + {"3", "3"}, + "1", + {"1", "1"}, + usd(), + xrp()); + attempt( + Buy, + "AT:T", + q1, + {"2", "2"}, + "2.5", + q1, + {"3", "3"}, + "3", + {"2", "2"}, + usd(), + xrp()); + attempt( + Buy, + "AT:BT", + q1, + {"2", "2"}, + "2.5", + q1, + {"4", "4"}, + "3", + {"2", "2"}, + usd(), + xrp()); + attempt( + Buy, + "AT:TB", + q1, + {"2", "2"}, + "2.5", + q1, + {"3", "3"}, + "1", + {"1", "1"}, + usd(), + xrp()); + } } void diff --git a/src/test/basics/Number_test.cpp b/src/test/basics/Number_test.cpp index d7bd826487..d3ece630e3 100644 --- a/src/test/basics/Number_test.cpp +++ b/src/test/basics/Number_test.cpp @@ -26,24 +26,6 @@ namespace ripple { -class saveNumberRoundMode -{ - Number::rounding_mode mode_; - -public: - ~saveNumberRoundMode() - { - Number::setround(mode_); - } - explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept - : mode_{mode} - { - } - saveNumberRoundMode(saveNumberRoundMode const&) = delete; - saveNumberRoundMode& - operator=(saveNumberRoundMode const&) = delete; -}; - class Number_test : public beast::unit_test::suite { public: @@ -580,6 +562,29 @@ public: BEAST_EXPECT(x == y); } + void + test_toSTAmount() + { + NumberSO stNumberSO{true}; + Issue const issue; + Number const n{7'518'783'80596, -5}; + saveNumberRoundMode const save{Number::setround(Number::to_nearest)}; + auto res2 = STAmount{issue, n.mantissa(), n.exponent()}; + BEAST_EXPECT(res2 == STAmount{7518784}); + + Number::setround(Number::towards_zero); + res2 = STAmount{issue, n.mantissa(), n.exponent()}; + BEAST_EXPECT(res2 == STAmount{7518783}); + + Number::setround(Number::downward); + res2 = STAmount{issue, n.mantissa(), n.exponent()}; + BEAST_EXPECT(res2 == STAmount{7518783}); + + Number::setround(Number::upward); + res2 = STAmount{issue, n.mantissa(), n.exponent()}; + BEAST_EXPECT(res2 == STAmount{7518784}); + } + void run() override { @@ -599,6 +604,7 @@ public: test_relationals(); test_stream(); test_inc_dec(); + test_toSTAmount(); } };