diff --git a/x/distribution/keeper/allocation.go b/x/distribution/keeper/allocation.go index 92863052a5..1acd3e7304 100644 --- a/x/distribution/keeper/allocation.go +++ b/x/distribution/keeper/allocation.go @@ -32,14 +32,12 @@ func (k Keeper) AllocateFees(ctx sdk.Context) { proposerMultiplier := sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(4, 2).Mul( sumPowerPrecommitValidators).Quo(bondedTokens)) proposerReward := feesCollectedDec.MulDec(proposerMultiplier) - fmt.Printf("debug proposerReward: %v\n", proposerReward[0].Amount.String()) // apply commission commission := proposerReward.MulDec(proposerValidator.GetCommission()) remaining := proposerReward.MulDec(sdk.OneDec().Sub(proposerValidator.GetCommission())) proposerDist.PoolCommission = proposerDist.PoolCommission.Plus(commission) proposerDist.Pool = proposerDist.Pool.Plus(remaining) - fmt.Printf("debug proposerDist.Pool: %v\n", proposerDist.Pool[0].Amount.String()) // allocate community funding communityTax := k.GetCommunityTax(ctx) @@ -50,7 +48,6 @@ func (k Keeper) AllocateFees(ctx sdk.Context) { // set the global pool within the distribution module poolReceived := feesCollectedDec.MulDec(sdk.OneDec().Sub(proposerMultiplier).Sub(communityTax)) feePool.Pool = feePool.Pool.Plus(poolReceived) - fmt.Printf("debug poolReceived: %v\n", poolReceived[0].Amount.String()) k.SetValidatorDistInfo(ctx, proposerDist) k.SetFeePool(ctx, feePool) diff --git a/x/distribution/keeper/delegation.go b/x/distribution/keeper/delegation.go index 0bcaa69e4c..b7443a0c11 100644 --- a/x/distribution/keeper/delegation.go +++ b/x/distribution/keeper/delegation.go @@ -79,6 +79,7 @@ func (k Keeper) WithdrawDelegationReward(ctx sdk.Context, delegatorAddr sdk.AccA k.SetFeePool(ctx, feePool) k.SetValidatorDistInfo(ctx, valInfo) + k.SetDelegationDistInfo(ctx, delInfo) withdrawAddr := k.GetDelegatorWithdrawAddr(ctx, delegatorAddr) _, _, err := k.bankKeeper.AddCoins(ctx, withdrawAddr, withdraw.TruncateDecimal()) if err != nil { diff --git a/x/distribution/keeper/delegation_test.go b/x/distribution/keeper/delegation_test.go index 047d5bccd1..b41245f3b3 100644 --- a/x/distribution/keeper/delegation_test.go +++ b/x/distribution/keeper/delegation_test.go @@ -42,8 +42,8 @@ func TestWithdrawDelegationRewardBasic(t *testing.T) { keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1) amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) - expRes := sdk.NewDec(90).Add(sdk.NewDec(100).Quo(sdk.NewDec(2))) // 90 + 100 tokens * 10/20 - require.True(sdk.DecEq(t, expRes, sdk.NewDecFromInt(amt))) + expRes := sdk.NewDec(90).Add(sdk.NewDec(100).Quo(sdk.NewDec(2))).TruncateInt() // 90 + 100 tokens * 10/20 + require.True(sdk.IntEq(t, expRes, amt)) } func TestWithdrawDelegationRewardWithCommission(t *testing.T) { @@ -81,12 +81,128 @@ func TestWithdrawDelegationRewardWithCommission(t *testing.T) { keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1) amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) - expRes := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(2))) // 90 + 100*90% tokens * 10/20 - require.True(sdk.DecEq(t, expRes, sdk.NewDecFromInt(amt))) + expRes := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(2))).TruncateInt() // 90 + 100*90% tokens * 10/20 + require.True(sdk.IntEq(t, expRes, amt)) } func TestWithdrawDelegationRewardTwoDelegators(t *testing.T) { + ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec()) + stakeHandler := stake.NewHandler(sk) + denom := sk.GetParams(ctx).BondDenom + //first make a validator with 10% commission + msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission( + valOpAddr1, valConsPk1, 10, sdk.NewDecWithPrec(1, 1)) + got := stakeHandler(ctx, msgCreateValidator) + require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) + + // delegate + msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10) + got = stakeHandler(ctx, msgDelegate) + require.True(t, got.IsOK()) + amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) + require.Equal(t, int64(90), amt.Int64()) + + msgDelegate = stake.NewTestMsgDelegate(delAddr2, valOpAddr1, 20) + got = stakeHandler(ctx, msgDelegate) + require.True(t, got.IsOK()) + amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom) + require.Equal(t, int64(80), amt.Int64()) + + totalPower := int64(40) + totalPowerDec := sdk.NewDec(totalPower) + + // allocate 100 denom of fees + feeInputs := sdk.NewInt(100) + fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) + require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) + keeper.SetProposerConsAddr(ctx, valConsAddr1) + keeper.SetSumPrecommitPower(ctx, totalPowerDec) + keeper.AllocateFees(ctx) + + // delegator 1 withdraw delegation + ctx = ctx.WithBlockHeight(1) + keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1) + amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) + + expRes := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(4))).TruncateInt() // 90 + 100*90% tokens * 10/40 + require.True(sdk.IntEq(t, expRes, amt)) +} + +// this test demonstrates how two delegators with the same power can end up +// with different rewards in the end +func TestWithdrawDelegationRewardTwoDelegatorsUneven(t *testing.T) { + ctx, accMapper, keeper, sk, fck := CreateTestInputAdvanced(t, false, 100, sdk.ZeroDec()) + stakeHandler := stake.NewHandler(sk) + denom := sk.GetParams(ctx).BondDenom + + //first make a validator with no commission + msgCreateValidator := stake.NewTestMsgCreateValidatorWithCommission( + valOpAddr1, valConsPk1, 10, sdk.ZeroDec()) + got := stakeHandler(ctx, msgCreateValidator) + require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) + _ = sk.ApplyAndReturnValidatorSetUpdates(ctx) + + // delegate + msgDelegate := stake.NewTestMsgDelegate(delAddr1, valOpAddr1, 10) + got = stakeHandler(ctx, msgDelegate) + require.True(t, got.IsOK()) + amt := accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) + require.Equal(t, int64(90), amt.Int64()) + + msgDelegate = stake.NewTestMsgDelegate(delAddr2, valOpAddr1, 10) + got = stakeHandler(ctx, msgDelegate) + require.True(t, got.IsOK()) + amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom) + require.Equal(t, int64(90), amt.Int64()) + + totalPower := int64(30) + totalPowerDec := sdk.NewDec(totalPower) + + // allocate 100 denom of fees + feeInputs := sdk.NewInt(90) + fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) + require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) + keeper.SetProposerConsAddr(ctx, valConsAddr1) + keeper.SetSumPrecommitPower(ctx, totalPowerDec) + keeper.AllocateFees(ctx) + ctx = ctx.WithBlockHeight(1) + + // delegator 1 withdraw delegation early, delegator 2 just keeps it's accum + keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1) + amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) + + expRes1 := sdk.NewDec(90).Add(sdk.NewDec(90).Quo(sdk.NewDec(3))).TruncateInt() // 90 + 100 * 10/30 + require.True(sdk.IntEq(t, expRes1, amt)) + + // allocate 200 denom of fees + feeInputs = sdk.NewInt(180) + fck.SetCollectedFees(sdk.Coins{sdk.NewCoin(denom, feeInputs)}) + require.Equal(t, feeInputs, fck.GetCollectedFees(ctx).AmountOf(denom)) + keeper.SetProposerConsAddr(ctx, valConsAddr1) + keeper.SetSumPrecommitPower(ctx, totalPowerDec) + keeper.AllocateFees(ctx) + ctx = ctx.WithBlockHeight(2) + + // delegator 2 now withdraws everything it's entitled to + keeper.WithdrawDelegationReward(ctx, delAddr2, valOpAddr1) + amt = accMapper.GetAccount(ctx, delAddr2).GetCoins().AmountOf(denom) + // existingTokens + (100+200 * (10/(20+30)) + withdrawnFromVal := sdk.NewDec(60 + 180).Mul(sdk.NewDec(2)).Quo(sdk.NewDec(5)) + expRes2 := sdk.NewDec(90).Add(withdrawnFromVal).TruncateInt() + require.True(sdk.IntEq(t, expRes2, amt)) + + // finally delegator 1 withdraws the remainder of its reward + keeper.WithdrawDelegationReward(ctx, delAddr1, valOpAddr1) + amt = accMapper.GetAccount(ctx, delAddr1).GetCoins().AmountOf(denom) + + remainingInVal := sdk.NewDec(60 + 180).Sub(withdrawnFromVal) + expRes3 := sdk.NewDecFromInt(expRes1).Add(remainingInVal.Mul(sdk.NewDec(1)).Quo(sdk.NewDec(3))).TruncateInt() + require.True(sdk.IntEq(t, expRes3, amt)) + + // verify the final withdraw amounts are different + require.True(t, expRes2.GT(expRes3)) } func TestWithdrawDelegationRewardsAll(t *testing.T) {