From 836c4d060da752d979d8238447dbd9b9fd2e0666 Mon Sep 17 00:00:00 2001 From: Anthony Fieroni Date: Wed, 10 Mar 2021 16:49:38 +0200 Subject: [PATCH] Do not redistribute rewards per block Signed-off-by: Anthony Fieroni --- src/masternodes/poolpairs.h | 102 +++++++---------------------------- src/test/liquidity_tests.cpp | 23 ++------ src/validation.cpp | 40 ++------------ 3 files changed, 29 insertions(+), 136 deletions(-) diff --git a/src/masternodes/poolpairs.h b/src/masternodes/poolpairs.h index c8aa796289f..cf9fd0a3caf 100644 --- a/src/masternodes/poolpairs.h +++ b/src/masternodes/poolpairs.h @@ -302,112 +302,50 @@ class CPoolPairView : public virtual CStorageView return Res::Ok(); } - CAmount DistributeRewards(CAmount yieldFarming, std::function onGetBalance, std::function onTransfer, int nHeight = 0) { + void UpdatePoolCommissions(std::function onGetBalance, int nHeight = 0) { bool newRewardCalc = nHeight >= Params().GetConsensus().BayfrontGardensHeight; - uint32_t const PRECISION = 10000; // (== 100%) just searching the way to avoid arith256 inflating - CAmount totalDistributed = 0; + constexpr uint32_t const PRECISION = 10000; // (== 100%) just searching the way to avoid arith256 inflating ForEachPoolPair([&] (DCT_ID const & poolId, CPoolPair pool) { - // yield farming counters - CAmount const poolReward = yieldFarming * pool.rewardPct / COIN; // 'rewardPct' should be defined by 'setgov "LP_SPLITS"', also, it is assumed that it was totally validated and normalized to 100% - CAmount distributedFeeA = 0; - CAmount distributedFeeB = 0; - - auto rewards = GetPoolCustomReward(poolId); - bool payCustomRewards{false}; - - if (nHeight >= Params().GetConsensus().ClarkeQuayHeight && rewards && !rewards->balances.empty()) { - for (auto it = rewards->balances.cbegin(), next_it = it; it != rewards->balances.cend(); it = next_it) { - ++next_it; - - // Get token balance - const auto balance = onGetBalance(pool.ownerAddress, it->first).nValue; - - // Make there's enough to pay reward otherwise remove it - if (balance < it->second) { - rewards->balances.erase(it); - } - } - - if (!rewards->balances.empty()) { - payCustomRewards = true; - } - } - - if (pool.totalLiquidity == 0 || (!pool.swapEvent && poolReward == 0 && !payCustomRewards)) { + if (!pool.swapEvent) { return true; // no events, skip to the next pool } + CAmount distributedFeeA = 0; + CAmount distributedFeeB = 0; + ForEachPoolShare([&] (DCT_ID const & currentId, CScript const & provider, uint32_t height) { if (currentId != poolId) { return false; // stop } CAmount const liquidity = onGetBalance(provider, poolId).nValue; - uint32_t const liqWeight = liquidity * PRECISION / pool.totalLiquidity; - assert (liqWeight < PRECISION); - // distribute trading fees - if (pool.swapEvent) { - CAmount feeA, feeB; - if (newRewardCalc) { - feeA = static_cast((arith_uint256(pool.blockCommissionA) * arith_uint256(liquidity) / arith_uint256(pool.totalLiquidity)).GetLow64()); - feeB = static_cast((arith_uint256(pool.blockCommissionB) * arith_uint256(liquidity) / arith_uint256(pool.totalLiquidity)).GetLow64()); - } else { - feeA = pool.blockCommissionA * liqWeight / PRECISION; - feeB = pool.blockCommissionB * liqWeight / PRECISION; - } - if (onTransfer(provider, CScript(), poolId, uint8_t(RewardType::Commission), {pool.idTokenA, feeA})) { - distributedFeeA += feeA; - } - if (onTransfer(provider, CScript(), poolId, uint8_t(RewardType::Commission), {pool.idTokenB, feeB})) { - distributedFeeB += feeB; - } - } - - // distribute yield farming - if (poolReward) { - CAmount providerReward = static_cast((arith_uint256(poolReward) * arith_uint256(liquidity) / arith_uint256(pool.totalLiquidity)).GetLow64()); - if (!newRewardCalc) { - providerReward = poolReward * liqWeight / PRECISION; - } - if (providerReward) { - if (onTransfer(provider, CScript(), poolId, uint8_t(RewardType::Rewards), {DCT_ID{0}, providerReward})) { - totalDistributed += providerReward; - } - } + if (newRewardCalc) { + distributedFeeA += static_cast((arith_uint256(pool.blockCommissionA) * arith_uint256(liquidity) / arith_uint256(pool.totalLiquidity)).GetLow64()); + distributedFeeB += static_cast((arith_uint256(pool.blockCommissionB) * arith_uint256(liquidity) / arith_uint256(pool.totalLiquidity)).GetLow64()); + } else { + uint32_t const liqWeight = liquidity * PRECISION / pool.totalLiquidity; + assert (liqWeight < PRECISION); + distributedFeeA += pool.blockCommissionA * liqWeight / PRECISION; + distributedFeeB += pool.blockCommissionB * liqWeight / PRECISION; } - - // Distribute custom rewards - if (payCustomRewards) { - for (const auto& reward : rewards->balances) { - CAmount providerReward = static_cast((arith_uint256(reward.second) * arith_uint256(liquidity) / arith_uint256(pool.totalLiquidity)).GetLow64()); - - if (providerReward) { - onTransfer(provider, pool.ownerAddress, poolId, uint8_t(RewardType::Rewards), {reward.first, providerReward}); - } - } - } - return true; }, PoolShareKey{poolId, CScript{}}); - if (pool.swapEvent) { - pool.blockCommissionA -= distributedFeeA; - pool.blockCommissionB -= distributedFeeB; - pool.swapEvent = false; + pool.blockCommissionA -= distributedFeeA; + pool.blockCommissionB -= distributedFeeB; + pool.swapEvent = false; - auto res = SetPoolPair(poolId, UINT_MAX, pool); - if (!res.ok) { - LogPrintf("Pool rewards: can't update pool (id=%s) state: %s\n", poolId.ToString(), res.msg); - } + auto res = SetPoolPair(poolId, UINT_MAX, pool); + if (!res.ok) { + LogPrintf("Pool rewards: can't update pool (id=%s) state: %s\n", poolId.ToString(), res.msg); } return true; }); - return totalDistributed; } // tags diff --git a/src/test/liquidity_tests.cpp b/src/test/liquidity_tests.cpp index 61706f28578..b30a646eb61 100644 --- a/src/test/liquidity_tests.cpp +++ b/src/test/liquidity_tests.cpp @@ -309,30 +309,17 @@ BOOST_AUTO_TEST_CASE(math_rewards) }); // distribute 100 coins - CAmount totalRwd = 100*COIN; - - int64_t nTimeBegin = GetTimeMicros(); - CAmount distributed = cache.DistributeRewards(totalRwd, - [&cache] (CScript const & owner, DCT_ID tokenID) { - return cache.GetBalance(owner, tokenID); - }, - [&cache] (CScript const & to, CScript const & from, DCT_ID poolID, uint8_t type, CTokenAmount amount) { - return cache.AddBalance(to, amount); - } - ); - int64_t nTimeEnd = GetTimeMicros(); auto nTimeRwd = nTimeEnd - nTimeBegin; -// printf("Rewarded %d pools with %d shares each: %.2fms \n", PoolCount, ProvidersCount, 0.001 * (nTimeRwd)); - -// printf("Distributed: = %ld\n", distributed); - BOOST_CHECK(distributed == 9999000000); // always slightly less due to MINIMUM_LIQUIDITY & rounding + CAmount totalRwd = 100*COIN*2880; + cache.SetDailyReward(1, totalRwd); + // fund community + cache.AddCommunityBalance(CommunityAccountType::IncentiveFunding, totalRwd); // check it auto rwd25 = 25 * COIN / ProvidersCount; auto rwd50 = 50 * COIN / ProvidersCount; cache.ForEachPoolShare([&] (DCT_ID const & id, CScript const & owner, uint32_t) { -// if (id == RWD25/* || id == RWD50*/) -// printf("owner = %s: %s,\n", owner.GetHex().c_str(), cache.GetBalance(owner, DCT_ID{0}).ToString().c_str()); + cache.CalculateOwnerRewards(owner, 2); // one block // check only first couple of pools and the last (zero) if (id == RWD25 && owner != CScript(id.v * ProvidersCount)) { // first got slightly less due to MINIMUM_LIQUIDITY CAmount rwd = cache.GetBalance(owner, DCT_ID{0}).nValue; diff --git a/src/validation.cpp b/src/validation.cpp index 5f1496a79c6..c0bad44643f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2344,42 +2344,10 @@ bool CChainState::ConnectBlock(const CBlock& block, CValidationState& state, CBl // make all changes to the new cache/snapshot to make it possible to take a diff later: CCustomCSView cache(mnview); -// cache.CallYourInterblockProcessingsHere(); - - // distribute pool incentive rewards and trading fees: - { - std::shared_ptr var = std::dynamic_pointer_cast(cache.GetVariable(LP_DAILY_DFI_REWARD::TypeName())); - CAmount poolsBlockReward = std::min( - cache.GetCommunityBalance(CommunityAccountType::IncentiveFunding), - var->dailyReward / (60*60*24/chainparams.GetConsensus().pos.nTargetSpacing) // 2880 - ); - - CAmount distributed = cache.DistributeRewards(poolsBlockReward, - [&cache] (CScript const & owner, DCT_ID tokenID) { - return cache.GetBalance(owner, tokenID); - }, - [&cache, &block] (CScript const & to, CScript const & from, DCT_ID poolID, uint8_t type, CTokenAmount amount) { - if (from != CScript()) { - auto res = cache.SubBalance(from, amount); - if (!res.ok) { - LogPrintf("Custom pool rewards: can't update balance of %s: %s, Block %ld (%s)\n", to.GetHex(), res.msg, block.height, block.GetHash().ToString()); - return res; // no funds, no rewards - } - } - auto res = cache.AddBalance(to, amount); - if (!res.ok) { - LogPrintf("Pool rewards: can't update balance of %s: %s, Block %ld (%s)\n", to.GetHex(), res.msg, block.height, block.GetHash().ToString()); - } - return res; - }, - pindex->nHeight - ); - - auto res = cache.SubCommunityBalance(CommunityAccountType::IncentiveFunding, distributed); - if (!res.ok) { - LogPrintf("Pool rewards: can't update community balance: %s. Block %ld (%s)\n", res.msg, block.height, block.GetHash().ToString()); - } - } + // hardfork commissions update + cache.UpdatePoolCommissions([&cache](CScript const & owner, DCT_ID tokenID) { + return cache.GetBalance(owner, tokenID); + }, pindex->nHeight); // Remove `Finalized` and/or `LPS` flags _possibly_set_ by bytecoded (cheated) txs before bayfront fork if (pindex->nHeight == chainparams.GetConsensus().BayfrontHeight - 1) { // call at block _before_ fork cache.BayfrontFlagsCleanup();