Skip to content

Commit

Permalink
Fix pool rewards after actual share (#1070)
Browse files Browse the repository at this point in the history
Signed-off-by: Anthony Fieroni <[email protected]>

Co-authored-by: Prasanna Loganathar <[email protected]>
  • Loading branch information
bvbfan and prasannavl authored Jan 26, 2022
1 parent 39f6784 commit c383b74
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 15 deletions.
52 changes: 40 additions & 12 deletions src/masternodes/poolpairs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,27 @@ void ReadValueMoveToNext(TIterator & it, DCT_ID poolId, ValueType & value, uint3
}
}

template<typename TIterator, typename ValueType>
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<CAmount()> onLiquidity, uint32_t begin, uint32_t end, std::function<void(RewardType, CTokenAmount, uint32_t)> onReward) {
if (begin >= end) {
return;
Expand All @@ -231,27 +252,32 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function<CA
PoolHeightKey poolKey = {poolId, begin};

CAmount poolReward = 0;
CAmount poolLoanReward = 0;
auto nextPoolReward = begin;
auto nextPoolLoanReward = begin;
auto startPoolReward = begin;
auto itPoolReward = LowerBound<ByPoolReward>(poolKey);
FindSuitablePoolRewards(itPoolReward, poolKey, end, poolReward, startPoolReward);
auto nextPoolReward = startPoolReward;

CAmount poolLoanReward = 0;
auto startPoolLoanReward = begin;
auto itPoolLoanReward = LowerBound<ByPoolLoanReward>(poolKey);
FindSuitablePoolRewards(itPoolLoanReward, poolKey, end, poolLoanReward, startPoolLoanReward);
auto nextPoolLoanReward = startPoolLoanReward;

CAmount totalLiquidity = 0;
auto nextTotalLiquidity = begin;
auto itTotalLiquidity = LowerBound<ByTotalLiquidity>(poolKey);

CBalances customRewards;
auto nextCustomRewards = begin;
auto startCustomRewards = begin;
auto itCustomRewards = LowerBound<ByCustomReward>(poolKey);
FindSuitablePoolRewards(itCustomRewards, poolKey, end, customRewards, startCustomRewards);
auto nextCustomRewards = startCustomRewards;

PoolSwapValue poolSwap;
auto nextPoolSwap = UINT_MAX;
auto poolSwapHeight = UINT_MAX;
auto itPoolSwap = LowerBound<ByPoolSwap>(poolKey);
if (itPoolSwap.Valid() && itPoolSwap.Key().poolID == poolId) {
nextPoolSwap = itPoolSwap.Key().height;
}
FindSuitablePoolRewards(itPoolSwap, poolKey, end, poolSwap, nextPoolSwap);

for (auto height = begin; height < end;) {
// find suitable pool liquidity
Expand All @@ -276,7 +302,7 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function<CA
}
const auto liquidity = onLiquidity();
// daily rewards
if (poolReward != 0) {
if (height >= startPoolReward && poolReward != 0) {
CAmount providerReward = 0;
if (height < newCalcHeight) { // old calculation
uint32_t liqWeight = liquidity * PRECISION / totalLiquidity;
Expand All @@ -286,7 +312,7 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function<CA
}
onReward(RewardType::Coinbase, {DCT_ID{0}, providerReward}, height);
}
if (poolLoanReward != 0) {
if (height >= startPoolLoanReward && poolLoanReward != 0) {
CAmount providerReward = liquidityReward(poolLoanReward, liquidity, totalLiquidity);
onReward(RewardType::LoanTokenDEXReward, {DCT_ID{0}, providerReward}, height);
}
Expand All @@ -309,9 +335,11 @@ void CPoolPairView::CalculatePoolRewards(DCT_ID const & poolId, std::function<CA
}
}
// custom rewards
for (const auto& reward : customRewards.balances) {
if (auto providerReward = liquidityReward(reward.second, liquidity, totalLiquidity)) {
onReward(RewardType::Pool, {reward.first, providerReward}, height);
if (height >= startCustomRewards) {
for (const auto& reward : customRewards.balances) {
if (auto providerReward = liquidityReward(reward.second, liquidity, totalLiquidity)) {
onReward(RewardType::Pool, {reward.first, providerReward}, height);
}
}
}
++height;
Expand Down
45 changes: 42 additions & 3 deletions src/test/liquidity_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ BOOST_AUTO_TEST_CASE(owner_rewards)
return true;
});

mnview.SetDailyReward(3, COIN);
mnview.SetDailyReward(4, COIN);

auto oldRewardCalculation = [](CAmount liquidity, const CPoolPair& pool) -> CAmount {
constexpr const uint32_t PRECISION = 10000;
Expand All @@ -420,6 +420,14 @@ BOOST_AUTO_TEST_CASE(owner_rewards)
return std::make_pair(feeA, feeB);
};

// fixes the bug
const int bugFixHeight = 7; // < 10
const_cast<int&>(Params().GetConsensus().FortCanningHillHeight) = bugFixHeight;

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;
Expand All @@ -428,12 +436,15 @@ 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;
Expand All @@ -446,8 +457,12 @@ 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<int&>(Params().GetConsensus().BayfrontGardensHeight) = 6;
const_cast<int&>(Params().GetConsensus().BayfrontGardensHeight) = 8;

auto newRewardCalculation = [](CAmount liquidity, const CPoolPair& pool) -> CAmount {
return COIN / 2880 * pool.rewardPct / COIN * liquidity / pool.totalLiquidity;
Expand All @@ -461,12 +476,21 @@ 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.SetPoolPair(idPool, 8, pool);
mnview.UpdatePoolPair(idPool, 8, pool.status, pool.commission, pool.ownerAddress, pool.rewards);
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;
Expand All @@ -476,22 +500,29 @@ 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<CAmount>((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);
}
}
Expand All @@ -500,6 +531,14 @@ 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()

0 comments on commit c383b74

Please sign in to comment.