From 7f1dc0d4c5cdf88f547d77e1bea132d7bf45da52 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 12:14:45 +0530 Subject: [PATCH 01/11] Revert "Fix pool rewards after actual share (#1070)" This reverts commit c383b74b32ab365c433721cfbec7c78551c88214. --- src/masternodes/poolpairs.cpp | 52 ++++++++--------------------------- src/test/liquidity_tests.cpp | 45 ++---------------------------- 2 files changed, 15 insertions(+), 82 deletions(-) diff --git a/src/masternodes/poolpairs.cpp b/src/masternodes/poolpairs.cpp index 22bc6967c9..a11c17c155 100644 --- a/src/masternodes/poolpairs.cpp +++ b/src/masternodes/poolpairs.cpp @@ -218,27 +218,6 @@ void ReadValueMoveToNext(TIterator & it, DCT_ID poolId, ValueType & value, uint3 } } -template -void FindSuitablePoolRewards(TIterator & it, PoolHeightKey poolKey, uint32_t endHeight, ValueType & value, uint32_t & height) { - - static const auto poolStartHeight = uint32_t(Params().GetConsensus().FortCanningHillHeight); - poolKey.height = std::max(poolKey.height, poolStartHeight); - - auto maxHeight = 0u; - while ((!it.Valid() || it.Key().poolID != poolKey.poolID) && poolKey.height < endHeight) { - maxHeight = poolKey.height; - it.Seek(poolKey); - poolKey.height++; - } - - if (it.Valid() && it.Key().poolID == poolKey.poolID) { - value = it.Value(); - height = std::max(maxHeight, it.Key().height); - } else { - height = UINT_MAX; - } -} - void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function onLiquidity, uint32_t begin, uint32_t end, std::function onReward) { if (begin >= end) { return; @@ -252,32 +231,27 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function(poolKey); - FindSuitablePoolRewards(itPoolReward, poolKey, end, poolReward, startPoolReward); - auto nextPoolReward = startPoolReward; - CAmount poolLoanReward = 0; - auto startPoolLoanReward = begin; + auto nextPoolReward = begin; + auto nextPoolLoanReward = begin; + auto itPoolReward = LowerBound(poolKey); auto itPoolLoanReward = LowerBound(poolKey); - FindSuitablePoolRewards(itPoolLoanReward, poolKey, end, poolLoanReward, startPoolLoanReward); - auto nextPoolLoanReward = startPoolLoanReward; CAmount totalLiquidity = 0; auto nextTotalLiquidity = begin; auto itTotalLiquidity = LowerBound(poolKey); CBalances customRewards; - auto startCustomRewards = begin; + auto nextCustomRewards = begin; auto itCustomRewards = LowerBound(poolKey); - FindSuitablePoolRewards(itCustomRewards, poolKey, end, customRewards, startCustomRewards); - auto nextCustomRewards = startCustomRewards; PoolSwapValue poolSwap; auto nextPoolSwap = UINT_MAX; auto poolSwapHeight = UINT_MAX; auto itPoolSwap = LowerBound(poolKey); - FindSuitablePoolRewards(itPoolSwap, poolKey, end, poolSwap, nextPoolSwap); + if (itPoolSwap.Valid() && itPoolSwap.Key().poolID == poolId) { + nextPoolSwap = itPoolSwap.Key().height; + } for (auto height = begin; height < end;) { // find suitable pool liquidity @@ -302,7 +276,7 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function= startPoolReward && poolReward != 0) { + if (poolReward != 0) { CAmount providerReward = 0; if (height < newCalcHeight) { // old calculation uint32_t liqWeight = liquidity * PRECISION / totalLiquidity; @@ -312,7 +286,7 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function= startPoolLoanReward && poolLoanReward != 0) { + if (poolLoanReward != 0) { CAmount providerReward = liquidityReward(poolLoanReward, liquidity, totalLiquidity); onReward(RewardType::LoanTokenDEXReward, {DCT_ID{0}, providerReward}, height); } @@ -335,11 +309,9 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function= startCustomRewards) { - for (const auto& reward : customRewards.balances) { - if (auto providerReward = liquidityReward(reward.second, liquidity, totalLiquidity)) { - onReward(RewardType::Pool, {reward.first, providerReward}, height); - } + for (const auto& reward : customRewards.balances) { + if (auto providerReward = liquidityReward(reward.second, liquidity, totalLiquidity)) { + onReward(RewardType::Pool, {reward.first, providerReward}, height); } } ++height; diff --git a/src/test/liquidity_tests.cpp b/src/test/liquidity_tests.cpp index c3639fe8ef..5da5a4d43a 100644 --- a/src/test/liquidity_tests.cpp +++ b/src/test/liquidity_tests.cpp @@ -409,7 +409,7 @@ BOOST_AUTO_TEST_CASE(owner_rewards) return true; }); - mnview.SetDailyReward(4, COIN); + mnview.SetDailyReward(3, COIN); auto oldRewardCalculation = [](CAmount liquidity, const CPoolPair& pool) -> CAmount { constexpr const uint32_t PRECISION = 10000; @@ -425,14 +425,6 @@ BOOST_AUTO_TEST_CASE(owner_rewards) return std::make_pair(feeA, feeB); }; - // fixes the bug - const int bugFixHeight = Params().GetConsensus().FortCanningHillHeight; - BOOST_REQUIRE(bugFixHeight < 10); - - int rewardsCount = 0; - int commissionACount = 0; - int commissionBCount = 0; - mnview.ForEachPoolPair([&] (DCT_ID const & idPool, CPoolPair pool) { auto onLiquidity = [&]() -> CAmount { return mnview.GetBalance(shareAddress[0], idPool).nValue; @@ -441,15 +433,12 @@ BOOST_AUTO_TEST_CASE(owner_rewards) [&](RewardType type, CTokenAmount amount, uint32_t height) { switch(type) { case RewardType::Coinbase: - rewardsCount++; BOOST_CHECK_EQUAL(amount.nValue, oldRewardCalculation(onLiquidity(), pool)); break; case RewardType::Commission: if (amount.nTokenId == pool.idTokenA) { - commissionACount++; BOOST_CHECK_EQUAL(amount.nValue, oldCommissionCalculation(onLiquidity(), pool).first); } else { - commissionBCount++; BOOST_CHECK_EQUAL(amount.nValue, oldCommissionCalculation(onLiquidity(), pool).second); } break; @@ -462,12 +451,8 @@ BOOST_AUTO_TEST_CASE(owner_rewards) return true; }); - BOOST_CHECK_EQUAL(rewardsCount, 10 * (10 - bugFixHeight)); - BOOST_CHECK_EQUAL(commissionACount, 10); - BOOST_CHECK_EQUAL(commissionBCount, 10); - // new calculation - const_cast(Params().GetConsensus().BayfrontGardensHeight) = 8; + const_cast(Params().GetConsensus().BayfrontGardensHeight) = 6; auto newRewardCalculation = [](CAmount liquidity, const CPoolPair& pool) -> CAmount { return COIN / 2880 * pool.rewardPct / COIN * liquidity / pool.totalLiquidity; @@ -481,21 +466,12 @@ BOOST_AUTO_TEST_CASE(owner_rewards) mnview.ForEachPoolPair([&] (DCT_ID const & idPool, CPoolPair pool) { pool.swapEvent = true; - mnview.SetPoolPair(idPool, 8, pool); pool.ownerAddress = shareAddress[1]; pool.rewards = CBalances{TAmounts{{DCT_ID{idPool.v+1}, COIN}}}; - mnview.UpdatePoolPair(idPool, 8, pool.status, pool.commission, pool.ownerAddress, pool.rewards); + mnview.SetPoolPair(idPool, 8, pool); return false; }); - int oldRewardsCount = 0; - int newRewardsCount = 0; - int poolRewardsCount = 0; - int oldCommissionACount = 0; - int newCommissionACount = 0; - int oldCommissionBCount = 0; - int newCommissionBCount = 0; - mnview.ForEachPoolPair([&] (DCT_ID const & idPool, CPoolPair pool) { auto onLiquidity = [&] () -> CAmount { return mnview.GetBalance(shareAddress[1], idPool).nValue; @@ -505,29 +481,22 @@ BOOST_AUTO_TEST_CASE(owner_rewards) if (height >= Params().GetConsensus().BayfrontGardensHeight) { if (type == RewardType::Pool) { for (const auto& reward : pool.rewards.balances) { - poolRewardsCount++; auto providerReward = static_cast((arith_uint256(reward.second) * arith_uint256(onLiquidity()) / arith_uint256(pool.totalLiquidity)).GetLow64()); BOOST_CHECK_EQUAL(amount.nValue, providerReward); } } else if (type == RewardType::Coinbase) { - newRewardsCount++; BOOST_CHECK_EQUAL(amount.nValue, newRewardCalculation(onLiquidity(), pool)); } else if (amount.nTokenId == pool.idTokenA) { - newCommissionACount++; BOOST_CHECK_EQUAL(amount.nValue, newCommissionCalculation(onLiquidity(), pool).first); } else { - newCommissionBCount++; BOOST_CHECK_EQUAL(amount.nValue, newCommissionCalculation(onLiquidity(), pool).second); } } else { if (type & RewardType::Rewards) { - oldRewardsCount++; BOOST_CHECK_EQUAL(amount.nValue, oldRewardCalculation(onLiquidity(), pool)); } else if (amount.nTokenId == pool.idTokenA) { - oldCommissionACount++; BOOST_CHECK_EQUAL(amount.nValue, oldCommissionCalculation(onLiquidity(), pool).first); } else { - oldCommissionBCount++; BOOST_CHECK_EQUAL(amount.nValue, oldCommissionCalculation(onLiquidity(), pool).second); } } @@ -536,14 +505,6 @@ BOOST_AUTO_TEST_CASE(owner_rewards) ); return false; }); - - BOOST_CHECK_EQUAL(oldRewardsCount, 1); - BOOST_CHECK_EQUAL(newRewardsCount, 2); - BOOST_CHECK_EQUAL(poolRewardsCount, 2); - BOOST_CHECK_EQUAL(oldCommissionACount, 1); - BOOST_CHECK_EQUAL(newCommissionACount, 1); - BOOST_CHECK_EQUAL(oldCommissionBCount, 1); - BOOST_CHECK_EQUAL(newCommissionBCount, 1); } BOOST_AUTO_TEST_SUITE_END() From 3d59902f847f4f9b7941c70582636ea50ddf7f64 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 12:13:15 +0530 Subject: [PATCH 02/11] Change display of interest per block to high precision --- src/masternodes/rpc_loan.cpp | 64 +++++++++++++++++++++++++++++++----- 1 file changed, 55 insertions(+), 9 deletions(-) diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index 7b45c50190..97ef4dda06 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -1,4 +1,5 @@ #include +#include extern UniValue tokenToJSON(DCT_ID const& id, CTokenImplementation const& token, bool verbose); extern UniValue listauctions(const JSONRPCRequest& request); @@ -1325,6 +1326,47 @@ UniValue getloaninfo(const JSONRPCRequest& request) { return (ret); } +std::string GetInterestPerBlockHighPrecisionString(base_uint<128> value) { + struct HighPrecisionInterestValue { + typedef boost::multiprecision::int128_t int128; + typedef int64_t int64; + + int128 value; + HighPrecisionInterestValue(base_uint<128> val) { + value = int128("0x" + val.GetHex()); + } + + int64 GetInterestPerBlockSat() + { + return int64(value / HIGH_PRECISION_SCALER); + } + + int64 GetInterestPerBlockSubSat() + { + return int64(value % HIGH_PRECISION_SCALER); + } + + int64 GetInterestPerBlockMagnitude() + { + return int64(value / HIGH_PRECISION_SCALER / COIN); + } + + int128 GetInterestPerBlockDecimal() + { + auto v = GetInterestPerBlockSat(); + return v == 0 ? value : int128(value % (int128(HIGH_PRECISION_SCALER) * COIN)); + } + + std::string GetInterestPerBlockString() { + std::ostringstream result; + result << GetInterestPerBlockMagnitude() << "."; + result << std::setw(24) << std::setfill('0') << GetInterestPerBlockDecimal(); + return result.str(); + } + }; + return HighPrecisionInterestValue(value).GetInterestPerBlockString(); +} + UniValue getinterest(const JSONRPCRequest& request) { RPCHelpMan{"getinterest", "Returns the global and per block interest by loan scheme.\n", @@ -1395,19 +1437,23 @@ UniValue getinterest(const JSONRPCRequest& request) { UniValue obj(UniValue::VOBJ); for (std::map, base_uint<128> > >::iterator it=interest.begin(); it!=interest.end(); ++it) { - auto token = pcustomcsview->GetToken(it->first); - obj.pushKV("token", token->CreateSymbolKey(it->first)); - obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(it->second.first, height))); - obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(it->second.second, height))); - if (height >= Params().GetConsensus().FortCanningHillHeight) + auto tokenId = it->first; + auto interestRate = it->second; + auto totalInterest = it->second.first; + auto interestPerBlock = it->second.second; + + auto token = pcustomcsview->GetToken(tokenId); + obj.pushKV("token", token->CreateSymbolKey(tokenId)); + obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(totalInterest, height))); + if (height < Params().GetConsensus().FortCanningHillHeight) { - auto subSatoshiInterest = (it->second.second - ((it->second.second / HIGH_PRECISION_SCALER) * HIGH_PRECISION_SCALER)).GetLow64(); - obj.pushKV("immatureInterest", UniValue(UniValue::VNUM, strprintf("%de-24", subSatoshiInterest))); + obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(interestPerBlock, height))); + } else { + obj.pushKV("interestPerBlock", GetInterestPerBlockHighPrecisionString(interestPerBlock)); + obj.pushKV("interestOnRealizedBlock", ValueFromAmount(CeilInterest(interestPerBlock, height))); } - ret.push_back(obj); } - return ret; } From e7b781a43e6749708d4bf6bac77d1625bc41df39 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 12:56:22 +0530 Subject: [PATCH 03/11] Switch to realizedInterestPerBlock --- src/masternodes/rpc_loan.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index 97ef4dda06..402f572298 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -1445,12 +1445,10 @@ UniValue getinterest(const JSONRPCRequest& request) { auto token = pcustomcsview->GetToken(tokenId); obj.pushKV("token", token->CreateSymbolKey(tokenId)); obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(totalInterest, height))); + obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(interestPerBlock, height))); if (height < Params().GetConsensus().FortCanningHillHeight) { - obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(interestPerBlock, height))); - } else { - obj.pushKV("interestPerBlock", GetInterestPerBlockHighPrecisionString(interestPerBlock)); - obj.pushKV("interestOnRealizedBlock", ValueFromAmount(CeilInterest(interestPerBlock, height))); + obj.pushKV("realizedInterestPerBlock", UniValue(UniValue::VNUM, GetInterestPerBlockHighPrecisionString(interestPerBlock))); } ret.push_back(obj); } From acdf2303ebd0b6c4dbc97127e0c1ea4a51704c2e Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 12:59:07 +0530 Subject: [PATCH 04/11] Fix height --- src/masternodes/rpc_loan.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index 402f572298..909ce8386e 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -1446,7 +1446,7 @@ UniValue getinterest(const JSONRPCRequest& request) { obj.pushKV("token", token->CreateSymbolKey(tokenId)); obj.pushKV("totalInterest", ValueFromAmount(CeilInterest(totalInterest, height))); obj.pushKV("interestPerBlock", ValueFromAmount(CeilInterest(interestPerBlock, height))); - if (height < Params().GetConsensus().FortCanningHillHeight) + if (height >= Params().GetConsensus().FortCanningHillHeight) { obj.pushKV("realizedInterestPerBlock", UniValue(UniValue::VNUM, GetInterestPerBlockHighPrecisionString(interestPerBlock))); } From 8862d7ccf887a45f8ef3c077aa93756bcd9fea8c Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 13:14:36 +0530 Subject: [PATCH 05/11] Refactor and add description --- src/masternodes/rpc_loan.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/masternodes/rpc_loan.cpp b/src/masternodes/rpc_loan.cpp index 909ce8386e..cb8f1c32eb 100644 --- a/src/masternodes/rpc_loan.cpp +++ b/src/masternodes/rpc_loan.cpp @@ -1332,29 +1332,26 @@ std::string GetInterestPerBlockHighPrecisionString(base_uint<128> value) { typedef int64_t int64; int128 value; + HighPrecisionInterestValue(base_uint<128> val) { value = int128("0x" + val.GetHex()); } - int64 GetInterestPerBlockSat() - { + int64 GetInterestPerBlockSat() { return int64(value / HIGH_PRECISION_SCALER); } - int64 GetInterestPerBlockSubSat() - { + int64 GetInterestPerBlockSubSat() { return int64(value % HIGH_PRECISION_SCALER); } - int64 GetInterestPerBlockMagnitude() - { + int64 GetInterestPerBlockMagnitude() { return int64(value / HIGH_PRECISION_SCALER / COIN); } - int128 GetInterestPerBlockDecimal() - { + int128 GetInterestPerBlockDecimal() { auto v = GetInterestPerBlockSat(); - return v == 0 ? value : int128(value % (int128(HIGH_PRECISION_SCALER) * COIN)); + return v == 0 ? value : value % (int128(HIGH_PRECISION_SCALER) * COIN); } std::string GetInterestPerBlockString() { @@ -1377,6 +1374,13 @@ UniValue getinterest(const JSONRPCRequest& request) { RPCResult { "{...} (object) Json object with interest information\n" + " - `interestPerBlock`: Interest per block is always ceiled\n" + " to the min. unit of fi (8 decimals), however interest\n" + " less than this will continue to accrue until actual utilization\n" + " (eg. - payback of the loan), or until sub-fi maturity." + " - `realizedInterestPerBlock`: The actual realized interest\n" + " per block. This is continues to accumulate until\n" + " the min. unit of the blockchain (fi) can be realized. \n" }, RPCExamples{ HelpExampleCli("getinterest", "LOAN0001 TSLA") From d2622b870b6dfdb9c1e1c785fb81d6f260781256 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 13:27:04 +0530 Subject: [PATCH 06/11] Fix lint --- test/lint/lint-includes.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh index f7d609af5b..57fd588ede 100755 --- a/test/lint/lint-includes.sh +++ b/test/lint/lint-includes.sh @@ -82,6 +82,7 @@ EXPECTED_BOOST_INCLUDES=( boost/variant.hpp boost/variant/apply_visitor.hpp boost/variant/static_visitor.hpp + boost/multiprecision/cpp_int.hpp ) for BOOST_INCLUDE in $(git grep '^#include ' | sort -u); do From 3c53d3637ece71c609c0809e7c0f9fe5ca641ee1 Mon Sep 17 00:00:00 2001 From: Prasanna Loganathar Date: Fri, 28 Jan 2022 13:44:11 +0530 Subject: [PATCH 07/11] Refactor GetInterestPerBlockHighPrecisionString --- src/masternodes/loan.cpp | 39 ++++++++++++++++++++++++++++++++++++ src/masternodes/loan.h | 2 ++ src/masternodes/rpc_loan.cpp | 39 ------------------------------------ src/test/loan_tests.cpp | 7 +++++++ 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/masternodes/loan.cpp b/src/masternodes/loan.cpp index 75f6bf3b25..a4f2b9e7f2 100644 --- a/src/masternodes/loan.cpp +++ b/src/masternodes/loan.cpp @@ -1,6 +1,7 @@ #include #include +#include std::unique_ptr CLoanView::GetLoanCollateralToken(uint256 const & txid) const { @@ -478,3 +479,41 @@ CAmount CLoanView::GetLoanLiquidationPenalty() return 5 * COIN / 100; } + +std::string GetInterestPerBlockHighPrecisionString(base_uint<128> value) { + struct HighPrecisionInterestValue { + typedef boost::multiprecision::int128_t int128; + typedef int64_t int64; + + int128 value; + + HighPrecisionInterestValue(base_uint<128> val) { + value = int128("0x" + val.GetHex()); + } + + int64 GetInterestPerBlockSat() { + return int64(value / HIGH_PRECISION_SCALER); + } + + int64 GetInterestPerBlockSubSat() { + return int64(value % HIGH_PRECISION_SCALER); + } + + int64 GetInterestPerBlockMagnitude() { + return int64(value / HIGH_PRECISION_SCALER / COIN); + } + + int128 GetInterestPerBlockDecimal() { + auto v = GetInterestPerBlockSat(); + return v == 0 ? value : value % (int128(HIGH_PRECISION_SCALER) * COIN); + } + + std::string GetInterestPerBlockString() { + std::ostringstream result; + result << GetInterestPerBlockMagnitude() << "."; + result << std::setw(24) << std::setfill('0') << GetInterestPerBlockDecimal(); + return result.str(); + } + }; + return HighPrecisionInterestValue(value).GetInterestPerBlockString(); +} diff --git a/src/masternodes/loan.h b/src/masternodes/loan.h index 33cb7cfdb8..541990d20b 100644 --- a/src/masternodes/loan.h +++ b/src/masternodes/loan.h @@ -11,6 +11,7 @@ #include #include