github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/distribution/distribution_suit_test.go (about)

     1  package distribution
     2  
     3  import (
     4  	"testing"
     5  	"time"
     6  
     7  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
     8  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
     9  	abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types"
    10  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    11  	"github.com/fibonacci-chain/fbc/x/distribution/keeper"
    12  	"github.com/fibonacci-chain/fbc/x/distribution/types"
    13  	"github.com/fibonacci-chain/fbc/x/staking"
    14  	"github.com/stretchr/testify/require"
    15  	"github.com/stretchr/testify/suite"
    16  )
    17  
    18  var (
    19  	ctx                    sdk.Context
    20  	ak                     auth.AccountKeeper
    21  	dk                     Keeper
    22  	sk                     staking.Keeper
    23  	supplyKeeper           types.SupplyKeeper
    24  	blockRewardValueTokens = sdk.SysCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.NewDec(int64(100))}}
    25  	votes                  []abci.VoteInfo
    26  	depositCoin            = sdk.NewCoin(sk.BondDenom(ctx), sdk.NewInt(100))
    27  )
    28  
    29  type testAllocationParam struct {
    30  	totalPower int64
    31  	isVote     []bool
    32  	isJailed   []bool
    33  	fee        sdk.SysCoins
    34  }
    35  
    36  func allocateTokens(t *testing.T) {
    37  	feePoolBefore, _ := dk.GetFeePool(ctx).CommunityPool.TruncateDecimal()
    38  	setTestFees(t, ctx, ak, blockRewardValueTokens)
    39  	dk.AllocateTokens(ctx, 1, keeper.TestConsAddrs[0], votes)
    40  	feePoolAfter, _ := dk.GetFeePool(ctx).CommunityPool.TruncateDecimal()
    41  	require.Equal(t, feePoolBefore.Add2(getDecCoins("2")), feePoolAfter)
    42  	staking.EndBlocker(ctx, sk)
    43  	ctx.SetBlockHeight(ctx.BlockHeight() + 1)
    44  }
    45  
    46  func initEnv(t *testing.T, validatorCount int64, newVersion bool) {
    47  	communityTax := sdk.NewDecWithPrec(2, 2)
    48  	ctx, ak, _, dk, sk, _, supplyKeeper = keeper.CreateTestInputAdvanced(t, false, 1000, communityTax)
    49  	if newVersion {
    50  		tmtypes.UnittestOnlySetMilestoneVenus2Height(-1)
    51  		dk.SetInitExistedValidatorFlag(ctx, true)
    52  	}
    53  
    54  	h := staking.NewHandler(sk)
    55  	valOpAddrs, valConsPks, _ := keeper.GetTestAddrs()
    56  
    57  	// create four validators
    58  	for i := int64(0); i < validatorCount; i++ {
    59  		msg := staking.NewMsgCreateValidator(valOpAddrs[i], valConsPks[i],
    60  			staking.Description{}, keeper.NewTestSysCoin(i+1, 0))
    61  		_, e := h(ctx, msg)
    62  		require.Nil(t, e)
    63  		if newVersion {
    64  			require.True(t, dk.GetValidatorAccumulatedCommission(ctx, valOpAddrs[i]).IsZero())
    65  		} else {
    66  			require.Panics(t, func() {
    67  				dk.GetValidatorOutstandingRewards(ctx, valOpAddrs[i])
    68  			})
    69  		}
    70  	}
    71  	staking.EndBlocker(ctx, sk)
    72  	ctx.SetBlockHeight(ctx.BlockHeight() + 1)
    73  
    74  	testAllocationParam := testAllocationParam{
    75  		10,
    76  		[]bool{true, true, true, true}, []bool{false, false, false, false},
    77  		nil,
    78  	}
    79  	votes = createTestVotes(ctx, sk, testAllocationParam)
    80  }
    81  
    82  func createTestVotes(ctx sdk.Context, sk staking.Keeper, test testAllocationParam) []abci.VoteInfo {
    83  	var votes []abci.VoteInfo
    84  	for i := int64(0); i < int64(len(test.isVote)); i++ {
    85  		if test.isJailed[i] {
    86  			sk.Jail(ctx, keeper.TestConsAddrs[i])
    87  		}
    88  		abciVal := abci.Validator{Address: keeper.TestConsAddrs[i], Power: i + 1}
    89  		if test.isVote[i] {
    90  			votes = append(votes, abci.VoteInfo{Validator: abciVal, SignedLastBlock: true})
    91  		}
    92  	}
    93  	return votes
    94  }
    95  
    96  type DistributionSuite struct {
    97  	suite.Suite
    98  }
    99  
   100  func TestDistributionSuit(t *testing.T) {
   101  	suite.Run(t, new(DistributionSuite))
   102  }
   103  
   104  func getDecCoins(value string) sdk.SysCoins {
   105  	if value == "0" {
   106  		var decCoins sdk.SysCoins
   107  		return decCoins
   108  	}
   109  
   110  	dec, _ := sdk.NewDecFromStr(value)
   111  	return sdk.SysCoins{{Denom: sdk.DefaultBondDenom, Amount: dec}}
   112  }
   113  
   114  func (suite *DistributionSuite) TestNormal() {
   115  	testCases := []struct {
   116  		title                string
   117  		valCount             int64
   118  		beforeCommissionDec  [4]string
   119  		beforeOutstandingDec [4]string
   120  		afterCommissionDec   [4]string
   121  		afterOutstandingDec  [4]string
   122  		decCommunity         string
   123  		distrType            uint32
   124  		remainReferenceCount uint64
   125  	}{
   126  		{
   127  			"1 validator onchain",
   128  			int64(1),
   129  			[4]string{"98"},
   130  			[4]string{"98"},
   131  			[4]string{"0"},
   132  			[4]string{"0"},
   133  			"2",
   134  			1,
   135  			1,
   136  		},
   137  		{
   138  			"2 validator onchain",
   139  			int64(2),
   140  			[4]string{"49", "49"},
   141  			[4]string{"49", "49"},
   142  			[4]string{"0", "0"},
   143  			[4]string{"0", "0"},
   144  			"2",
   145  			1,
   146  			2,
   147  		},
   148  		{
   149  			"3 validator onchain",
   150  			int64(3),
   151  			[4]string{"32.666666666666666633", "32.666666666666666633", "32.666666666666666633"},
   152  			[4]string{"32.666666666666666633", "32.666666666666666633", "32.666666666666666633"},
   153  			[4]string{"0.666666666666666633", "0.666666666666666633", "0.666666666666666633"},
   154  			[4]string{"0.666666666666666633", "0.666666666666666633", "0.666666666666666633"},
   155  			"2.000000000000000101",
   156  			1,
   157  			3,
   158  		},
   159  		{
   160  			"4 validator onchain",
   161  			int64(4),
   162  			[4]string{"24.5", "24.5", "24.5", "24.5"},
   163  			[4]string{"24.5", "24.5", "24.5", "24.5"},
   164  			[4]string{"0.5", "0.5", "0.5", "0.5"},
   165  			[4]string{"0.5", "0.5", "0.5", "0.5"},
   166  			"2",
   167  			1,
   168  			4,
   169  		},
   170  		{
   171  			"1 validator offchain",
   172  			int64(1),
   173  			[4]string{"98"},
   174  			[4]string{"98"},
   175  			[4]string{"0"},
   176  			[4]string{"0"},
   177  			"2",
   178  			0,
   179  			1,
   180  		},
   181  		{
   182  			"2 validator offchain",
   183  			int64(2),
   184  			[4]string{"49", "49"},
   185  			[4]string{"49", "49"},
   186  			[4]string{"0", "0"},
   187  			[4]string{"0", "0"},
   188  			"2",
   189  			0,
   190  			2,
   191  		},
   192  		{
   193  			"3 validator offchain",
   194  			int64(3),
   195  			[4]string{"32.666666666666666633", "32.666666666666666633", "32.666666666666666633"},
   196  			[4]string{"32.666666666666666633", "32.666666666666666633", "32.666666666666666633"},
   197  			[4]string{"0.666666666666666633", "0.666666666666666633", "0.666666666666666633"},
   198  			[4]string{"0.666666666666666633", "0.666666666666666633", "0.666666666666666633"},
   199  			"2.000000000000000101",
   200  			0,
   201  			3,
   202  		},
   203  		{
   204  			"4 validator offchain",
   205  			int64(4),
   206  			[4]string{"24.5", "24.5", "24.5", "24.5"},
   207  			[4]string{"24.5", "24.5", "24.5", "24.5"},
   208  			[4]string{"0.5", "0.5", "0.5", "0.5"},
   209  			[4]string{"0.5", "0.5", "0.5", "0.5"},
   210  			"2",
   211  			0,
   212  			4,
   213  		},
   214  	}
   215  
   216  	for _, tc := range testCases {
   217  		suite.Run(tc.title, func() {
   218  			initEnv(suite.T(), tc.valCount, true)
   219  			dk.SetDistributionType(ctx, tc.distrType)
   220  			allocateTokens(suite.T())
   221  
   222  			for i := int64(0); i < tc.valCount; i++ {
   223  				require.Equal(suite.T(), getDecCoins(tc.beforeCommissionDec[i]), dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i]))
   224  				require.Equal(suite.T(), getDecCoins(tc.beforeOutstandingDec[i]), dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]))
   225  				require.Equal(suite.T(), getDecCoins(tc.decCommunity), dk.GetFeePoolCommunityCoins(ctx))
   226  
   227  				dk.WithdrawValidatorCommission(ctx, keeper.TestValAddrs[i])
   228  
   229  				require.Equal(suite.T(), getDecCoins(tc.afterCommissionDec[i]), dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i]))
   230  				require.Equal(suite.T(), getDecCoins(tc.afterOutstandingDec[i]), dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]))
   231  				require.Equal(suite.T(), getDecCoins(tc.decCommunity), dk.GetFeePoolCommunityCoins(ctx))
   232  
   233  				truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
   234  				truncatedCommission, _ := dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
   235  				require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
   236  			}
   237  
   238  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
   239  		})
   240  	}
   241  }
   242  
   243  func (suite *DistributionSuite) TestDelegator() {
   244  	testCases := []struct {
   245  		title                string
   246  		valCount             int64
   247  		delCount             int64
   248  		decRewards           [4][4]string
   249  		rate                 string
   250  		distrType            uint32
   251  		remainReferenceCount uint64
   252  	}{
   253  		{
   254  			"1 delegator,1 validator, onchain",
   255  			1,
   256  			1,
   257  			[4][4]string{{"48"}},
   258  			"0.5",
   259  			1,
   260  			1,
   261  		},
   262  		{
   263  			"1 delegator,1 validator, offchain",
   264  			1,
   265  			1,
   266  			[4][4]string{{"0"}},
   267  			"0.5",
   268  			0,
   269  			1,
   270  		},
   271  		{
   272  			"1 delegator,2 validator, onchain",
   273  			2,
   274  			1,
   275  			[4][4]string{{"24", "24"}},
   276  			"0.5",
   277  			1,
   278  			2,
   279  		},
   280  		{
   281  			"1 delegator,2 validator, offchain",
   282  			2,
   283  			1,
   284  			[4][4]string{{"0", "0"}},
   285  			"0.5",
   286  			0,
   287  			2,
   288  		},
   289  		{
   290  			"1 delegator,4 validator, onchain",
   291  			4,
   292  			1,
   293  			[4][4]string{{"12", "12", "12", "12"}},
   294  			"0.5",
   295  			1,
   296  			4,
   297  		},
   298  		{
   299  			"1 delegator,4 validator, offchain",
   300  			4,
   301  			1,
   302  			[4][4]string{{"0", "0", "0", "0"}},
   303  			"0.5",
   304  			0,
   305  			4,
   306  		},
   307  		{
   308  			"2 delegator,1 validator, onchain",
   309  			1,
   310  			2,
   311  			[4][4]string{{"24"}, {"24"}},
   312  			"0.5",
   313  			1,
   314  			1,
   315  		},
   316  		{
   317  			"2 delegator,1 validator, offchain",
   318  			1,
   319  			2,
   320  			[4][4]string{{"0"}, {"0"}},
   321  			"0.5",
   322  			0,
   323  			1,
   324  		},
   325  		{
   326  			"2 delegator,2 validator, onchain",
   327  			2,
   328  			2,
   329  			[4][4]string{{"12", "12"}, {"12", "12"}},
   330  			"0.5",
   331  			1,
   332  			2,
   333  		},
   334  		{
   335  			"2 delegator,2 validator, offchain",
   336  			2,
   337  			2,
   338  			[4][4]string{{"0", "0"}, {"0", "0"}},
   339  			"0.5",
   340  			0,
   341  			2,
   342  		},
   343  		{
   344  			"2 delegator,4 validator, onchain",
   345  			4,
   346  			2,
   347  			[4][4]string{{"6", "6", "6", "6"}, {"6", "6", "6", "6"}},
   348  			"0.5",
   349  			1,
   350  			4,
   351  		},
   352  		{
   353  			"2 delegator,4 validator, offchain",
   354  			4,
   355  			2,
   356  			[4][4]string{{"0", "0", "0", "0"}, {"0", "0", "0", "0"}},
   357  			"0.5",
   358  			0,
   359  			4,
   360  		},
   361  		{
   362  			"1 delegator,4 validator, onchain, rate 0",
   363  			4,
   364  			1,
   365  			[4][4]string{{"24", "24", "24", "24"}},
   366  			"0",
   367  			1,
   368  			4,
   369  		},
   370  		{
   371  			"1 delegator,4 validator, onchain, rate 1",
   372  			4,
   373  			1,
   374  			[4][4]string{{"0", "0", "0", "0"}},
   375  			"1",
   376  			1,
   377  			4,
   378  		},
   379  	}
   380  
   381  	for _, tc := range testCases {
   382  		suite.Run(tc.title, func() {
   383  			initEnv(suite.T(), tc.valCount, true)
   384  			dk.SetDistributionType(ctx, tc.distrType)
   385  
   386  			newRate, _ := sdk.NewDecFromStr(tc.rate)
   387  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
   388  			for i := int64(0); i < tc.valCount; i++ {
   389  				keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[i], newRate)
   390  			}
   391  
   392  			for i := int64(0); i < tc.delCount; i++ {
   393  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
   394  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:tc.valCount])
   395  				delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
   396  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
   397  			}
   398  
   399  			allocateTokens(suite.T())
   400  
   401  			beforeValCommission := [4]types.ValidatorAccumulatedCommission{}
   402  			for i := int64(0); i < tc.valCount; i++ {
   403  				beforeValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
   404  			}
   405  
   406  			for i := int64(0); i < tc.delCount; i++ {
   407  				for j := int64(0); j < tc.valCount; j++ {
   408  					queryRewards := keeper.GetQueriedDelegationRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   409  					queryRewards, _ = queryRewards.TruncateWithPrec(int64(0))
   410  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   411  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   412  					require.Nil(suite.T(), err)
   413  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   414  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decRewards[i][j]))
   415  					require.Equal(suite.T(), queryRewards, getDecCoins(tc.decRewards[i][j]))
   416  				}
   417  			}
   418  
   419  			afterValCommission := [4]types.ValidatorAccumulatedCommission{}
   420  			for i := int64(0); i < tc.valCount; i++ {
   421  				afterValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
   422  			}
   423  
   424  			//withdraw again
   425  			staking.EndBlocker(ctx, sk)
   426  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
   427  			for i := int64(0); i < tc.delCount; i++ {
   428  				for j := int64(0); j < tc.valCount; j++ {
   429  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   430  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   431  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   432  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
   433  
   434  					truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[j]).TruncateDecimal()
   435  					truncatedCommission, _ := dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[j]).TruncateDecimal()
   436  					require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
   437  				}
   438  			}
   439  			require.Equal(suite.T(), beforeValCommission, afterValCommission)
   440  
   441  			//allocate and withdraw agagin
   442  			allocateTokens(suite.T())
   443  			for i := int64(0); i < tc.delCount; i++ {
   444  				for j := int64(0); j < tc.valCount; j++ {
   445  					queryRewards := keeper.GetQueriedDelegationRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   446  					queryRewards, _ = queryRewards.TruncateWithPrec(int64(0))
   447  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   448  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   449  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   450  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decRewards[i][j]))
   451  					require.Equal(suite.T(), queryRewards, getDecCoins(tc.decRewards[i][j]))
   452  				}
   453  			}
   454  
   455  			//withdraw token
   456  			allocateTokens(suite.T())
   457  			for i := int64(0); i < tc.delCount; i++ {
   458  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   459  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
   460  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   461  				rewards := sdk.SysCoins{}
   462  				for j := int64(0); j < tc.valCount; j++ {
   463  					rewards = rewards.Add2(getDecCoins(tc.decRewards[i][j]))
   464  				}
   465  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), rewards)
   466  				for j := int64(0); j < tc.valCount; j++ {
   467  					require.False(suite.T(), dk.HasDelegatorStartingInfo(ctx, keeper.TestValAddrs[j], keeper.TestDelAddrs[i]))
   468  				}
   469  			}
   470  
   471  			//withdraw again
   472  			for i := int64(0); i < tc.delCount; i++ {
   473  				for j := int64(0); j < tc.valCount; j++ {
   474  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   475  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationDistInfo(), err)
   476  				}
   477  			}
   478  
   479  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
   480  		})
   481  	}
   482  }
   483  
   484  func (suite *DistributionSuite) TestProxy() {
   485  	testCases := []struct {
   486  		title                string
   487  		valCount             int64
   488  		proxyCount           int64
   489  		proxyRewards         [4][4]string
   490  		rate                 string
   491  		distrType            uint32
   492  		remainReferenceCount uint64
   493  	}{
   494  		{
   495  			"1 proxy,1 validator, onchain",
   496  			1,
   497  			1,
   498  			[4][4]string{{"48"}},
   499  			"0.5",
   500  			1,
   501  			1,
   502  		},
   503  		{
   504  			"1 proxy,1 validator, offchain",
   505  			1,
   506  			1,
   507  			[4][4]string{{"0"}},
   508  			"0.5",
   509  			0,
   510  			1,
   511  		},
   512  		{
   513  			"1 proxy,2 validator, onchain",
   514  			2,
   515  			1,
   516  			[4][4]string{{"24", "24"}},
   517  			"0.5",
   518  			1,
   519  			2,
   520  		},
   521  		{
   522  			"1 proxy,2 validator, offchain",
   523  			2,
   524  			1,
   525  			[4][4]string{{"0", "0"}},
   526  			"0.5",
   527  			0,
   528  			2,
   529  		},
   530  		{
   531  			"1 proxy,4 validator, onchain",
   532  			4,
   533  			1,
   534  			[4][4]string{{"12", "12", "12", "12"}},
   535  			"0.5",
   536  			1,
   537  			4,
   538  		},
   539  		{
   540  			"1 proxy,4 validator, offchain",
   541  			4,
   542  			1,
   543  			[4][4]string{{"0", "0", "0", "0"}},
   544  			"0.5",
   545  			0,
   546  			4,
   547  		},
   548  		{
   549  			"2 proxy,1 validator, onchain",
   550  			1,
   551  			2,
   552  			[4][4]string{{"24"}, {"24"}},
   553  			"0.5",
   554  			1,
   555  			1,
   556  		},
   557  		{
   558  			"2 proxy,1 validator, offchain",
   559  			1,
   560  			2,
   561  			[4][4]string{{"0"}, {"0"}},
   562  			"0.5",
   563  			0,
   564  			1,
   565  		},
   566  		{
   567  			"2 proxy,2 validator, onchain",
   568  			2,
   569  			2,
   570  			[4][4]string{{"12", "12"}, {"12", "12"}},
   571  			"0.5",
   572  			1,
   573  			2,
   574  		},
   575  		{
   576  			"2 proxy,2 validator, offchain",
   577  			2,
   578  			2,
   579  			[4][4]string{{"0", "0"}, {"0", "0"}},
   580  			"0.5",
   581  			0,
   582  			2,
   583  		},
   584  		{
   585  			"2 proxy,4 validator, onchain",
   586  			4,
   587  			2,
   588  			[4][4]string{{"6", "6", "6", "6"}, {"6", "6", "6", "6"}},
   589  			"0.5",
   590  			1,
   591  			4,
   592  		},
   593  		{
   594  			"2 proxy,4 validator, offchain",
   595  			4,
   596  			2,
   597  			[4][4]string{{"0", "0", "0", "0"}, {"0", "0", "0", "0"}},
   598  			"0.5",
   599  			0,
   600  			4,
   601  		},
   602  	}
   603  
   604  	for _, tc := range testCases {
   605  		suite.Run(tc.title, func() {
   606  			initEnv(suite.T(), tc.valCount, true)
   607  			dk.SetDistributionType(ctx, tc.distrType)
   608  
   609  			newRate, _ := sdk.NewDecFromStr(tc.rate)
   610  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
   611  			for i := int64(0); i < tc.valCount; i++ {
   612  				keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[i], newRate)
   613  			}
   614  
   615  			staking.EndBlocker(ctx, sk)
   616  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
   617  			for i := int64(0); i < tc.proxyCount; i++ {
   618  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestProxyAddrs[i], depositCoin)
   619  				keeper.DoRegProxy(suite.T(), ctx, sk, keeper.TestProxyAddrs[i], true)
   620  
   621  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
   622  				keeper.DoBindProxy(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestProxyAddrs[i])
   623  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestProxyAddrs[i], keeper.TestValAddrs[0:tc.valCount])
   624  				delegator := sk.Delegator(ctx, keeper.TestProxyAddrs[i])
   625  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
   626  			}
   627  
   628  			//test withdraw rewards
   629  			testProxyWithdrawRewards(suite, tc.valCount, tc.proxyCount, tc.proxyRewards)
   630  
   631  			//proxy withdraw rewards again, delegator withdraw reards again
   632  			testProxyWithdrawRewardsAgain(suite, tc.valCount, tc.proxyCount)
   633  
   634  			// UnBindProxy
   635  			for i := int64(0); i < tc.proxyCount; i++ {
   636  				keeper.DoUnBindProxy(suite.T(), ctx, sk, keeper.TestDelAddrs[i])
   637  			}
   638  
   639  			allocateTokens(suite.T())
   640  
   641  			for i := int64(0); i < tc.proxyCount; i++ {
   642  				for j := int64(0); j < tc.valCount; j++ {
   643  					queryRewards := keeper.GetQueriedDelegationRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestProxyAddrs[i], keeper.TestValAddrs[j])
   644  					queryRewards, _ = queryRewards.TruncateWithPrec(int64(0))
   645  					beforeAccount := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   646  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestProxyAddrs[i], keeper.TestValAddrs[j])
   647  					require.Nil(suite.T(), err)
   648  					afterAccount := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   649  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.proxyRewards[i][j]))
   650  					require.Equal(suite.T(), queryRewards, getDecCoins(tc.proxyRewards[i][j]))
   651  				}
   652  			}
   653  
   654  			//proxy withdraw rewards again, delegator withdraw rewards again
   655  			testProxyWithdrawRewardsAgain(suite, tc.valCount, tc.proxyCount)
   656  
   657  			//bind proxy again
   658  			testProxyBindAgain(suite, tc.valCount, tc.proxyCount, tc.proxyRewards)
   659  
   660  			//delegator deposit to proxy
   661  			testProxyDelDepositAgain(suite, tc.valCount, tc.proxyCount, tc.proxyRewards)
   662  
   663  			//proxy deposit again
   664  			testProxyProxyDepositAgain(suite, tc.valCount, tc.proxyCount, tc.proxyRewards)
   665  
   666  			//withdraw token
   667  			allocateTokens(suite.T())
   668  			for i := int64(0); i < tc.proxyCount; i++ {
   669  				beforeAccountCoins := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   670  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin.Add(depositCoin))
   671  				keeper.DoRegProxy(suite.T(), ctx, sk, keeper.TestProxyAddrs[i], false)
   672  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestProxyAddrs[i], depositCoin.Add(depositCoin))
   673  				afterAccountCoins := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   674  				rewards := sdk.SysCoins{}
   675  				for j := int64(0); j < tc.valCount; j++ {
   676  					rewards = rewards.Add2(getDecCoins(tc.proxyRewards[i][j]))
   677  				}
   678  				require.Equal(suite.T(), afterAccountCoins.Sub(beforeAccountCoins), rewards)
   679  				for j := int64(0); j < tc.valCount; j++ {
   680  					require.False(suite.T(), dk.HasDelegatorStartingInfo(ctx, keeper.TestValAddrs[j], keeper.TestProxyAddrs[i]))
   681  				}
   682  			}
   683  
   684  			//proxy withdraw rewards again
   685  			for i := int64(0); i < tc.proxyCount; i++ {
   686  				for j := int64(0); j < tc.valCount; j++ {
   687  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestProxyAddrs[i], keeper.TestValAddrs[j])
   688  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationDistInfo(), err)
   689  				}
   690  			}
   691  
   692  			//delegator withdraw rewards again
   693  			for i := int64(0); i < tc.proxyCount; i++ {
   694  				for j := int64(0); j < tc.valCount; j++ {
   695  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   696  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationDistInfo(), err)
   697  				}
   698  			}
   699  
   700  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
   701  		})
   702  	}
   703  }
   704  
   705  func testProxyWithdrawRewards(suite *DistributionSuite, valCount int64, proxyCount int64, proxyRewards [4][4]string) {
   706  	allocateTokens(suite.T())
   707  	beforeValCommission := [4]types.ValidatorAccumulatedCommission{}
   708  	for i := int64(0); i < valCount; i++ {
   709  		beforeValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
   710  	}
   711  
   712  	for i := int64(0); i < proxyCount; i++ {
   713  		for j := int64(0); j < valCount; j++ {
   714  			queryRewards := keeper.GetQueriedDelegationRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestProxyAddrs[i], keeper.TestValAddrs[j])
   715  			queryRewards, _ = queryRewards.TruncateWithPrec(int64(0))
   716  			beforeAccount := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   717  			dk.WithdrawDelegationRewards(ctx, keeper.TestProxyAddrs[i], keeper.TestValAddrs[j])
   718  			afterAccount := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   719  			require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(proxyRewards[i][j]))
   720  			require.Equal(suite.T(), queryRewards, getDecCoins(proxyRewards[i][j]))
   721  		}
   722  	}
   723  
   724  	afterValCommission := [4]types.ValidatorAccumulatedCommission{}
   725  	for i := int64(0); i < valCount; i++ {
   726  		afterValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
   727  		truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
   728  		truncatedCommission, _ := afterValCommission[i].TruncateDecimal()
   729  		require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
   730  	}
   731  	require.Equal(suite.T(), beforeValCommission, afterValCommission)
   732  }
   733  
   734  func testProxyWithdrawRewardsAgain(suite *DistributionSuite, valCount int64, proxyCount int64) {
   735  	staking.EndBlocker(ctx, sk)
   736  	ctx.SetBlockHeight(ctx.BlockHeight() + 1)
   737  	for i := int64(0); i < proxyCount; i++ {
   738  		for j := int64(0); j < valCount; j++ {
   739  			beforeAccount := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   740  			dk.WithdrawDelegationRewards(ctx, keeper.TestProxyAddrs[i], keeper.TestValAddrs[j])
   741  			afterAccount := ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   742  			require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
   743  		}
   744  	}
   745  
   746  	//delegator withdraw
   747  	staking.EndBlocker(ctx, sk)
   748  	ctx.SetBlockHeight(ctx.BlockHeight() + 1)
   749  	for i := int64(0); i < proxyCount; i++ {
   750  		for j := int64(0); j < valCount; j++ {
   751  			beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   752  			dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   753  			afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   754  			require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
   755  		}
   756  	}
   757  }
   758  
   759  func testProxyBindAgain(suite *DistributionSuite, valCount int64, proxyCount int64, proxyRewards [4][4]string) {
   760  	allocateTokens(suite.T())
   761  	beforeProxyAccountCoins := [4]sdk.SysCoins{}
   762  	for i := int64(0); i < proxyCount; i++ {
   763  		beforeProxyAccountCoins[i] = ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   764  		for j := int64(0); j < valCount; j++ {
   765  			beforeProxyAccountCoins[i] = beforeProxyAccountCoins[i].Add2(getDecCoins(proxyRewards[i][j]))
   766  		}
   767  	}
   768  	for i := int64(0); i < proxyCount; i++ {
   769  		keeper.DoBindProxy(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestProxyAddrs[i])
   770  	}
   771  	afterProxyAccountCoins := [4]sdk.SysCoins{}
   772  	for i := int64(0); i < proxyCount; i++ {
   773  		afterProxyAccountCoins[i] = ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   774  	}
   775  	require.Equal(suite.T(), beforeProxyAccountCoins, afterProxyAccountCoins)
   776  }
   777  
   778  func testProxyDelDepositAgain(suite *DistributionSuite, valCount int64, proxyCount int64, proxyRewards [4][4]string) {
   779  	allocateTokens(suite.T())
   780  	beforeProxyAccountCoins := [4]sdk.SysCoins{}
   781  	for i := int64(0); i < proxyCount; i++ {
   782  		beforeProxyAccountCoins[i] = ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   783  		for j := int64(0); j < valCount; j++ {
   784  			beforeProxyAccountCoins[i] = beforeProxyAccountCoins[i].Add2(getDecCoins(proxyRewards[i][j]))
   785  		}
   786  	}
   787  	for i := int64(0); i < proxyCount; i++ {
   788  		keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
   789  	}
   790  	afterProxyAccountCoins := [4]sdk.SysCoins{}
   791  	for i := int64(0); i < proxyCount; i++ {
   792  		afterProxyAccountCoins[i] = ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   793  	}
   794  	require.Equal(suite.T(), beforeProxyAccountCoins, afterProxyAccountCoins)
   795  }
   796  
   797  func testProxyProxyDepositAgain(suite *DistributionSuite, valCount int64, proxyCount int64, proxyRewards [4][4]string) {
   798  	allocateTokens(suite.T())
   799  	beforeProxyAccountCoins := [4]sdk.SysCoins{}
   800  	for i := int64(0); i < proxyCount; i++ {
   801  		beforeProxyAccountCoins[i] = ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   802  		for j := int64(0); j < valCount; j++ {
   803  			beforeProxyAccountCoins[i] = beforeProxyAccountCoins[i].Add2(getDecCoins(proxyRewards[i][j]))
   804  		}
   805  	}
   806  	for i := int64(0); i < proxyCount; i++ {
   807  		beforeProxyAccountCoins[i] = beforeProxyAccountCoins[i].Sub(sdk.NewCoins(depositCoin))
   808  		keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestProxyAddrs[i], depositCoin)
   809  	}
   810  	afterProxyAccountCoins := [4]sdk.SysCoins{}
   811  	for i := int64(0); i < proxyCount; i++ {
   812  		afterProxyAccountCoins[i] = ak.GetAccount(ctx, keeper.TestProxyAddrs[i]).GetCoins()
   813  	}
   814  	require.Equal(suite.T(), beforeProxyAccountCoins, afterProxyAccountCoins)
   815  }
   816  
   817  func (suite *DistributionSuite) TestWithdraw() {
   818  	testCases := []struct {
   819  		title                string
   820  		valCount             int64
   821  		delCount             int64
   822  		decRewards           [4][4]string
   823  		rate                 string
   824  		distrType            uint32
   825  		remainReferenceCount uint64
   826  	}{
   827  		{
   828  			"1 delegator,1 validator, onchain",
   829  			1,
   830  			1,
   831  			[4][4]string{{"48"}},
   832  			"0.5",
   833  			1,
   834  			1,
   835  		},
   836  		{
   837  			"1 delegator,1 validator, offchain",
   838  			1,
   839  			1,
   840  			[4][4]string{{"0"}},
   841  			"0.5",
   842  			0,
   843  			1,
   844  		},
   845  		{
   846  			"1 delegator,2 validator, onchain",
   847  			2,
   848  			1,
   849  			[4][4]string{{"24", "24"}},
   850  			"0.5",
   851  			1,
   852  			2,
   853  		},
   854  		{
   855  			"1 delegator,2 validator, offchain",
   856  			2,
   857  			1,
   858  			[4][4]string{{"0", "0"}},
   859  			"0.5",
   860  			0,
   861  			2,
   862  		},
   863  		{
   864  			"1 delegator,4 validator, onchain",
   865  			4,
   866  			1,
   867  			[4][4]string{{"12", "12", "12", "12"}},
   868  			"0.5",
   869  			1,
   870  			4,
   871  		},
   872  		{
   873  			"1 delegator,4 validator, offchain",
   874  			4,
   875  			1,
   876  			[4][4]string{{"0", "0", "0", "0"}},
   877  			"0.5",
   878  			0,
   879  			4,
   880  		},
   881  		{
   882  			"2 delegator,1 validator, onchain",
   883  			1,
   884  			2,
   885  			[4][4]string{{"24"}, {"24"}},
   886  			"0.5",
   887  			1,
   888  			1,
   889  		},
   890  		{
   891  			"2 delegator,1 validator, offchain",
   892  			1,
   893  			2,
   894  			[4][4]string{{"0"}, {"0"}},
   895  			"0.5",
   896  			0,
   897  			1,
   898  		},
   899  		{
   900  			"2 delegator,2 validator, onchain",
   901  			2,
   902  			2,
   903  			[4][4]string{{"12", "12"}, {"12", "12"}},
   904  			"0.5",
   905  			1,
   906  			2,
   907  		},
   908  		{
   909  			"2 delegator,2 validator, offchain",
   910  			2,
   911  			2,
   912  			[4][4]string{{"0", "0"}, {"0", "0"}},
   913  			"0.5",
   914  			0,
   915  			2,
   916  		},
   917  		{
   918  			"2 delegator,4 validator, onchain",
   919  			4,
   920  			2,
   921  			[4][4]string{{"6", "6", "6", "6"}, {"6", "6", "6", "6"}},
   922  			"0.5",
   923  			1,
   924  			4,
   925  		},
   926  		{
   927  			"2 delegator,4 validator, offchain",
   928  			4,
   929  			2,
   930  			[4][4]string{{"0", "0", "0", "0"}, {"0", "0", "0", "0"}},
   931  			"0.5",
   932  			0,
   933  			4,
   934  		},
   935  	}
   936  
   937  	for _, tc := range testCases {
   938  		suite.Run(tc.title, func() {
   939  			initEnv(suite.T(), tc.valCount, true)
   940  			dk.SetDistributionType(ctx, tc.distrType)
   941  
   942  			newRate, _ := sdk.NewDecFromStr(tc.rate)
   943  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
   944  			for i := int64(0); i < tc.valCount; i++ {
   945  				keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[i], newRate)
   946  			}
   947  
   948  			for i := int64(0); i < tc.delCount; i++ {
   949  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
   950  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:tc.valCount])
   951  				delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
   952  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
   953  			}
   954  
   955  			allocateTokens(suite.T())
   956  
   957  			beforeValCommission := [4]types.ValidatorAccumulatedCommission{}
   958  			for i := int64(0); i < tc.valCount; i++ {
   959  				beforeValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
   960  			}
   961  
   962  			for i := int64(0); i < tc.delCount; i++ {
   963  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   964  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
   965  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   966  				rewards := sdk.SysCoins{}
   967  				for j := int64(0); j < tc.valCount; j++ {
   968  					rewards = rewards.Add2(getDecCoins(tc.decRewards[i][j]))
   969  
   970  				}
   971  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), rewards)
   972  			}
   973  
   974  			afterValCommission := [4]types.ValidatorAccumulatedCommission{}
   975  			for i := int64(0); i < tc.valCount; i++ {
   976  				afterValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
   977  				truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
   978  				truncatedCommission, _ := dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
   979  				require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
   980  			}
   981  			require.Equal(suite.T(), beforeValCommission, afterValCommission)
   982  
   983  			//withdraw again
   984  			staking.EndBlocker(ctx, sk)
   985  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
   986  			for i := int64(0); i < tc.delCount; i++ {
   987  				for j := int64(0); j < tc.valCount; j++ {
   988  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   989  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
   990  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
   991  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
   992  				}
   993  			}
   994  
   995  			//allocate and withdraw again, do nothing
   996  			allocateTokens(suite.T())
   997  			for i := int64(0); i < tc.delCount; i++ {
   998  				for j := int64(0); j < tc.valCount; j++ {
   999  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1000  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1001  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationDistInfo(), err)
  1002  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1003  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
  1004  				}
  1005  			}
  1006  
  1007  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
  1008  		})
  1009  	}
  1010  }
  1011  
  1012  func (suite *DistributionSuite) TestWithdrawAllRewards() {
  1013  	testCases := []struct {
  1014  		title                string
  1015  		valCount             int64
  1016  		delCount             int64
  1017  		decRewards           [4]string
  1018  		rate                 string
  1019  		distrType            uint32
  1020  		remainReferenceCount uint64
  1021  		addShares            bool
  1022  	}{
  1023  		{
  1024  			"1 delegator,1 validator, onchain",
  1025  			1,
  1026  			1,
  1027  			[4]string{"0"},
  1028  			"0.5",
  1029  			1,
  1030  			1,
  1031  			false,
  1032  		},
  1033  		{
  1034  			"1 delegator,1 validator, onchain",
  1035  			1,
  1036  			1,
  1037  			[4]string{"48"},
  1038  			"0.5",
  1039  			1,
  1040  			1,
  1041  			true,
  1042  		},
  1043  		{
  1044  			"1 delegator,1 validator, offchain",
  1045  			1,
  1046  			1,
  1047  			[4]string{"0"},
  1048  			"0.5",
  1049  			0,
  1050  			1,
  1051  			true,
  1052  		},
  1053  		{
  1054  			"1 delegator,2 validator, onchain",
  1055  			2,
  1056  			1,
  1057  			[4]string{"48"},
  1058  			"0.5",
  1059  			1,
  1060  			2,
  1061  			true,
  1062  		},
  1063  		{
  1064  			"1 delegator,2 validator, offchain",
  1065  			2,
  1066  			1,
  1067  			[4]string{"0"},
  1068  			"0.5",
  1069  			0,
  1070  			2,
  1071  			true,
  1072  		},
  1073  		{
  1074  			"1 delegator,4 validator, onchain",
  1075  			4,
  1076  			1,
  1077  			[4]string{"48"},
  1078  			"0.5",
  1079  			1,
  1080  			4,
  1081  			true,
  1082  		},
  1083  		{
  1084  			"1 delegator,4 validator, offchain",
  1085  			4,
  1086  			1,
  1087  			[4]string{"0"},
  1088  			"0.5",
  1089  			0,
  1090  			4,
  1091  			true,
  1092  		},
  1093  		{
  1094  			"2 delegator,1 validator, onchain",
  1095  			1,
  1096  			2,
  1097  			[4]string{"24", "24"},
  1098  			"0.5",
  1099  			1,
  1100  			1,
  1101  			true,
  1102  		},
  1103  		{
  1104  			"2 delegator,1 validator, offchain",
  1105  			1,
  1106  			2,
  1107  			[4]string{"0", "0"},
  1108  			"0.5",
  1109  			0,
  1110  			1,
  1111  			true,
  1112  		},
  1113  		{
  1114  			"2 delegator,2 validator, onchain",
  1115  			2,
  1116  			2,
  1117  			[4]string{"24", "24"},
  1118  			"0.5",
  1119  			1,
  1120  			2,
  1121  			true,
  1122  		},
  1123  		{
  1124  			"2 delegator,2 validator, offchain",
  1125  			2,
  1126  			2,
  1127  			[4]string{"0", "0"},
  1128  			"0.5",
  1129  			0,
  1130  			2,
  1131  			true,
  1132  		},
  1133  		{
  1134  			"2 delegator,4 validator, onchain",
  1135  			4,
  1136  			2,
  1137  			[4]string{"24", "24"},
  1138  			"0.5",
  1139  			1,
  1140  			4,
  1141  			true,
  1142  		},
  1143  		{
  1144  			"2 delegator,4 validator, offchain",
  1145  			4,
  1146  			2,
  1147  			[4]string{"0", "0"},
  1148  			"0.5",
  1149  			0,
  1150  			4,
  1151  			true,
  1152  		},
  1153  		{
  1154  			"1 delegator,4 validator, onchain, rate 0",
  1155  			4,
  1156  			1,
  1157  			[4]string{"96"},
  1158  			"0",
  1159  			1,
  1160  			4,
  1161  			true,
  1162  		},
  1163  		{
  1164  			"1 delegator,4 validator, onchain, rate 1",
  1165  			4,
  1166  			1,
  1167  			[4]string{"0"},
  1168  			"1",
  1169  			1,
  1170  			4,
  1171  			true,
  1172  		},
  1173  	}
  1174  
  1175  	for _, tc := range testCases {
  1176  		suite.Run(tc.title, func() {
  1177  			initEnv(suite.T(), tc.valCount, true)
  1178  			dk.SetDistributionType(ctx, tc.distrType)
  1179  
  1180  			newRate, _ := sdk.NewDecFromStr(tc.rate)
  1181  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
  1182  			for i := int64(0); i < tc.valCount; i++ {
  1183  				keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[i], newRate)
  1184  			}
  1185  
  1186  			for i := int64(0); i < tc.delCount; i++ {
  1187  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1188  				if tc.addShares {
  1189  					keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:tc.valCount])
  1190  					delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
  1191  					require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
  1192  				}
  1193  			}
  1194  
  1195  			allocateTokens(suite.T())
  1196  
  1197  			beforeValCommission := [4]types.ValidatorAccumulatedCommission{}
  1198  			for i := int64(0); i < tc.valCount; i++ {
  1199  				beforeValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
  1200  			}
  1201  
  1202  			for i := int64(0); i < tc.delCount; i++ {
  1203  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1204  				response := keeper.GetQueriedDelegationTotalRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestDelAddrs[i])
  1205  				var queryRewards sdk.SysCoins
  1206  				for _, v := range response.Rewards {
  1207  					coins, _ := v.Reward.TruncateWithPrec(int64(0))
  1208  					queryRewards = queryRewards.Add2(coins)
  1209  				}
  1210  				err := dk.WithdrawDelegationAllRewards(ctx, keeper.TestDelAddrs[i])
  1211  				if tc.addShares {
  1212  					require.Nil(suite.T(), err)
  1213  				} else {
  1214  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationVoteValidator(), err)
  1215  				}
  1216  
  1217  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1218  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decRewards[i]))
  1219  				require.Equal(suite.T(), queryRewards, getDecCoins(tc.decRewards[i]))
  1220  			}
  1221  
  1222  			afterValCommission := [4]types.ValidatorAccumulatedCommission{}
  1223  			for i := int64(0); i < tc.valCount; i++ {
  1224  				afterValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
  1225  			}
  1226  
  1227  			//withdraw again
  1228  			staking.EndBlocker(ctx, sk)
  1229  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1230  			for i := int64(0); i < tc.delCount; i++ {
  1231  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1232  				err := dk.WithdrawDelegationAllRewards(ctx, keeper.TestDelAddrs[i])
  1233  				if tc.addShares {
  1234  					require.Nil(suite.T(), err)
  1235  				} else {
  1236  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationVoteValidator(), err)
  1237  				}
  1238  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1239  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
  1240  				truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[0]).TruncateDecimal()
  1241  				truncatedCommission, _ := dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[0]).TruncateDecimal()
  1242  				if tc.addShares {
  1243  					require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
  1244  				} else {
  1245  					require.Equal(suite.T(), truncatedOutstanding, truncatedCommission.QuoDec(sdk.MustNewDecFromStr(tc.rate)))
  1246  				}
  1247  			}
  1248  			require.Equal(suite.T(), beforeValCommission, afterValCommission)
  1249  
  1250  			//allocate and withdraw agagin
  1251  			allocateTokens(suite.T())
  1252  			for i := int64(0); i < tc.delCount; i++ {
  1253  				response := keeper.GetQueriedDelegationTotalRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestDelAddrs[i])
  1254  				var queryRewards sdk.SysCoins
  1255  				for _, v := range response.Rewards {
  1256  					coins, _ := v.Reward.TruncateWithPrec(int64(0))
  1257  					queryRewards = queryRewards.Add2(coins)
  1258  				}
  1259  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1260  				err := dk.WithdrawDelegationAllRewards(ctx, keeper.TestDelAddrs[i])
  1261  				if tc.addShares {
  1262  					require.Nil(suite.T(), err)
  1263  				} else {
  1264  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationVoteValidator(), err)
  1265  				}
  1266  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1267  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decRewards[i]))
  1268  				require.Equal(suite.T(), queryRewards, getDecCoins(tc.decRewards[i]))
  1269  			}
  1270  
  1271  			//withdraw token
  1272  			allocateTokens(suite.T())
  1273  			for i := int64(0); i < tc.delCount; i++ {
  1274  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1275  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1276  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1277  				rewards := getDecCoins(tc.decRewards[i])
  1278  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), rewards)
  1279  				for j := int64(0); j < tc.valCount; j++ {
  1280  					require.False(suite.T(), dk.HasDelegatorStartingInfo(ctx, keeper.TestValAddrs[j], keeper.TestDelAddrs[i]))
  1281  				}
  1282  			}
  1283  
  1284  			//withdraw again
  1285  			for i := int64(0); i < tc.delCount; i++ {
  1286  				err := dk.WithdrawDelegationAllRewards(ctx, keeper.TestDelAddrs[i])
  1287  				require.Equal(suite.T(), types.ErrCodeEmptyDelegationDistInfo(), err)
  1288  			}
  1289  
  1290  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
  1291  		})
  1292  	}
  1293  }
  1294  
  1295  func (suite *DistributionSuite) TestDestroyValidator() {
  1296  	testCases := []struct {
  1297  		title                string
  1298  		valCount             int64
  1299  		delCount             int64
  1300  		decRewards           [4][4]string
  1301  		rate                 string
  1302  		distrType            uint32
  1303  		remainReferenceCount uint64
  1304  	}{
  1305  		{
  1306  			"1 delegator,1 validator, onchain",
  1307  			1,
  1308  			1,
  1309  			[4][4]string{{"24"}},
  1310  			"0.5",
  1311  			1,
  1312  			0,
  1313  		},
  1314  		{
  1315  			"1 delegator,1 validator, offchain",
  1316  			1,
  1317  			1,
  1318  			[4][4]string{{"0"}},
  1319  			"0.5",
  1320  			0,
  1321  			0,
  1322  		},
  1323  	}
  1324  
  1325  	for _, tc := range testCases {
  1326  		suite.Run(tc.title, func() {
  1327  			initEnv(suite.T(), tc.valCount, true)
  1328  			dk.SetDistributionType(ctx, tc.distrType)
  1329  
  1330  			newRate, _ := sdk.NewDecFromStr(tc.rate)
  1331  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
  1332  			for i := int64(0); i < tc.valCount; i++ {
  1333  				keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[i], newRate)
  1334  			}
  1335  
  1336  			for i := int64(0); i < tc.delCount; i++ {
  1337  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1338  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:tc.valCount])
  1339  				delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
  1340  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
  1341  			}
  1342  
  1343  			for j := int64(0); j < tc.valCount; j++ {
  1344  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestValAccAddrs[j], depositCoin)
  1345  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestValAccAddrs[j], keeper.TestValAddrs[0:tc.valCount])
  1346  				delegator := sk.Delegator(ctx, keeper.TestValAccAddrs[j])
  1347  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
  1348  			}
  1349  
  1350  			allocateTokens(suite.T())
  1351  
  1352  			beforeValCommission := [4]types.ValidatorAccumulatedCommission{}
  1353  			for i := int64(0); i < tc.valCount; i++ {
  1354  				beforeValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
  1355  			}
  1356  
  1357  			//withdraw validator
  1358  			for j := int64(0); j < tc.valCount; j++ {
  1359  				keeper.DoDestroyValidator(suite.T(), ctx, sk, keeper.TestValAccAddrs[j])
  1360  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestValAccAddrs[j], depositCoin)
  1361  			}
  1362  
  1363  			staking.EndBlocker(ctx, sk)
  1364  
  1365  			for i := int64(0); i < tc.delCount; i++ {
  1366  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1367  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1368  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1369  				rewards := sdk.SysCoins{}
  1370  				for j := int64(0); j < tc.valCount; j++ {
  1371  					rewards = rewards.Add2(getDecCoins(tc.decRewards[i][j]))
  1372  
  1373  				}
  1374  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), rewards)
  1375  			}
  1376  
  1377  			afterValCommission := [4]types.ValidatorAccumulatedCommission{}
  1378  			for i := int64(0); i < tc.valCount; i++ {
  1379  				afterValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
  1380  				truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
  1381  				truncatedCommission, _ := dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i]).TruncateDecimal()
  1382  				require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
  1383  			}
  1384  			require.Equal(suite.T(), beforeValCommission, afterValCommission)
  1385  
  1386  			//withdraw again
  1387  			staking.EndBlocker(ctx, sk)
  1388  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1389  			for i := int64(0); i < tc.delCount; i++ {
  1390  				for j := int64(0); j < tc.valCount; j++ {
  1391  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1392  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1393  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1394  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
  1395  				}
  1396  			}
  1397  
  1398  			//allocate and withdraw again, do nothing
  1399  			staking.EndBlocker(ctx, sk)
  1400  			for i := int64(0); i < tc.delCount; i++ {
  1401  				for j := int64(0); j < tc.valCount; j++ {
  1402  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1403  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1404  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1405  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
  1406  				}
  1407  			}
  1408  
  1409  			hook := dk.Hooks()
  1410  			for j := int64(0); j < tc.valCount; j++ {
  1411  				hook.AfterValidatorRemoved(ctx, nil, keeper.TestValAddrs[j])
  1412  				require.True(suite.T(), dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[j]).IsZero())
  1413  				require.Panics(suite.T(), func() {
  1414  					require.True(suite.T(), dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[j]).IsZero())
  1415  				})
  1416  			}
  1417  
  1418  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
  1419  		})
  1420  	}
  1421  }
  1422  
  1423  func setTestFees(t *testing.T, ctx sdk.Context, ak auth.AccountKeeper, fees sdk.SysCoins) {
  1424  	feeCollector := supplyKeeper.GetModuleAccount(ctx, auth.FeeCollectorName)
  1425  	require.NotNil(t, feeCollector)
  1426  	err := feeCollector.SetCoins(fees)
  1427  	require.NoError(t, err)
  1428  	ak.SetAccount(ctx, feeCollector)
  1429  }
  1430  
  1431  func (suite *DistributionSuite) TestUpgrade() {
  1432  	testCases := []struct {
  1433  		title                   string
  1434  		valCount                int64
  1435  		delCount                int64
  1436  		decBeforeUpgradeRewards [4][4]string
  1437  		decAfterUpgradeRewards  [4][4]string
  1438  		rate                    string
  1439  		remainReferenceCount    uint64
  1440  	}{
  1441  		{
  1442  			"1 delegator,1 validator",
  1443  			1,
  1444  			1,
  1445  			[4][4]string{{"0"}},
  1446  			[4][4]string{{"48"}},
  1447  			"0.5",
  1448  			2,
  1449  		},
  1450  		{
  1451  			"1 delegator,2 validator",
  1452  			2,
  1453  			1,
  1454  			[4][4]string{{"0", "0"}},
  1455  			[4][4]string{{"24", "24"}},
  1456  			"0.5",
  1457  			4,
  1458  		},
  1459  		{
  1460  			"2 delegator,1 validator",
  1461  			1,
  1462  			2,
  1463  			[4][4]string{{"0"}, {"0"}},
  1464  			[4][4]string{{"24"}, {"24"}},
  1465  			"0.5",
  1466  			2,
  1467  		},
  1468  		{
  1469  			"2 delegator,2 validator",
  1470  			2,
  1471  			2,
  1472  			[4][4]string{{"0", "0"}, {"0", "0"}},
  1473  			[4][4]string{{"12", "12"}, {"12", "12"}},
  1474  			"0.5",
  1475  			4,
  1476  		},
  1477  		{
  1478  			"2 delegator,4 validator",
  1479  			4,
  1480  			2,
  1481  			[4][4]string{{"0", "0", "0", "0"}, {"0", "0", "0", "0"}},
  1482  			[4][4]string{{"6", "6", "6", "6"}, {"6", "6", "6", "6"}},
  1483  			"0.5",
  1484  			8,
  1485  		},
  1486  		{
  1487  			"4 delegator,4 validator",
  1488  			4,
  1489  			4,
  1490  			[4][4]string{{"0", "0", "0", "0"}, {"0", "0", "0", "0"}, {"0", "0", "0", "0"}, {"0", "0", "0", "0"}},
  1491  			[4][4]string{{"3", "3", "3", "3"}, {"3", "3", "3", "3"}, {"3", "3", "3", "3"}, {"3", "3", "3", "3"}},
  1492  			"0.5",
  1493  			8,
  1494  		},
  1495  	}
  1496  
  1497  	for _, tc := range testCases {
  1498  		suite.Run(tc.title, func() {
  1499  			initEnv(suite.T(), tc.valCount, false)
  1500  			ctx.SetBlockTime(time.Now())
  1501  			for i := int64(0); i < tc.delCount; i++ {
  1502  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1503  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:tc.valCount])
  1504  				delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
  1505  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
  1506  			}
  1507  
  1508  			allocateTokens(suite.T())
  1509  
  1510  			beforeValCommission := [4]types.ValidatorAccumulatedCommission{}
  1511  			for i := int64(0); i < tc.valCount; i++ {
  1512  				beforeValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
  1513  			}
  1514  
  1515  			for i := int64(0); i < tc.delCount; i++ {
  1516  				for j := int64(0); j < tc.valCount; j++ {
  1517  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1518  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1519  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1520  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decBeforeUpgradeRewards[i][j]))
  1521  				}
  1522  			}
  1523  
  1524  			afterValCommission := [4]types.ValidatorAccumulatedCommission{}
  1525  			for i := int64(0); i < tc.valCount; i++ {
  1526  				afterValCommission[i] = dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[i])
  1527  				require.Panics(suite.T(), func() {
  1528  					require.True(suite.T(), dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[i]).IsZero())
  1529  				})
  1530  			}
  1531  
  1532  			//withdraw again
  1533  			staking.EndBlocker(ctx, sk)
  1534  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1535  			for i := int64(0); i < tc.delCount; i++ {
  1536  				for j := int64(0); j < tc.valCount; j++ {
  1537  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1538  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1539  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1540  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
  1541  				}
  1542  			}
  1543  			require.Equal(suite.T(), beforeValCommission, afterValCommission)
  1544  
  1545  			//allocate and withdraw agagin
  1546  			allocateTokens(suite.T())
  1547  			for i := int64(0); i < tc.delCount; i++ {
  1548  				for j := int64(0); j < tc.valCount; j++ {
  1549  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1550  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1551  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1552  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decBeforeUpgradeRewards[i][j]))
  1553  				}
  1554  			}
  1555  
  1556  			// upgrade
  1557  			tmtypes.UnittestOnlySetMilestoneVenus2Height(-1)
  1558  			proposal := makeChangeDistributionTypeProposal(types.DistributionTypeOnChain)
  1559  			hdlr := NewDistributionProposalHandler(dk)
  1560  			require.NoError(suite.T(), hdlr(ctx, &proposal))
  1561  			queryDistrType := dk.GetDistributionType(ctx)
  1562  			require.Equal(suite.T(), queryDistrType, types.DistributionTypeOnChain)
  1563  			staking.EndBlocker(ctx, sk)
  1564  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1565  
  1566  			//set rate
  1567  			newRate, _ := sdk.NewDecFromStr(tc.rate)
  1568  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
  1569  			for i := int64(0); i < tc.valCount; i++ {
  1570  				keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[i], newRate)
  1571  			}
  1572  
  1573  			allocateTokens(suite.T())
  1574  
  1575  			//withdraw reward
  1576  			for i := int64(0); i < tc.delCount; i++ {
  1577  				for j := int64(0); j < tc.valCount; j++ {
  1578  					queryRewards := keeper.GetQueriedDelegationRewards(suite.T(), ctx, NewQuerier(dk), keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1579  					queryRewards, _ = queryRewards.TruncateWithPrec(int64(0))
  1580  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1581  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1582  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1583  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins(tc.decAfterUpgradeRewards[i][j]))
  1584  					require.Equal(suite.T(), queryRewards, getDecCoins(tc.decAfterUpgradeRewards[i][j]))
  1585  				}
  1586  			}
  1587  
  1588  			//withdraw reward again
  1589  			staking.EndBlocker(ctx, sk)
  1590  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1591  			for i := int64(0); i < tc.delCount; i++ {
  1592  				for j := int64(0); j < tc.valCount; j++ {
  1593  					beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1594  					dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1595  					afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1596  					require.Equal(suite.T(), afterAccount.Sub(beforeAccount), getDecCoins("0"))
  1597  				}
  1598  			}
  1599  
  1600  			allocateTokens(suite.T())
  1601  
  1602  			//withdraw token
  1603  			for i := int64(0); i < tc.delCount; i++ {
  1604  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1605  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1606  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1607  				rewards := sdk.SysCoins{}
  1608  				for j := int64(0); j < tc.valCount; j++ {
  1609  					rewards = rewards.Add2(getDecCoins(tc.decAfterUpgradeRewards[i][j]))
  1610  				}
  1611  				require.Equal(suite.T(), afterAccount.Sub(beforeAccount), rewards)
  1612  				for j := int64(0); j < tc.valCount; j++ {
  1613  					require.False(suite.T(), dk.HasDelegatorStartingInfo(ctx, keeper.TestValAddrs[j], keeper.TestDelAddrs[i]))
  1614  				}
  1615  			}
  1616  
  1617  			//withdraw again
  1618  			for i := int64(0); i < tc.delCount; i++ {
  1619  				for j := int64(0); j < tc.valCount; j++ {
  1620  					_, err := dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[j])
  1621  					require.Equal(suite.T(), types.ErrCodeEmptyDelegationDistInfo(), err)
  1622  
  1623  					truncatedOutstanding, _ := dk.GetValidatorOutstandingRewards(ctx, keeper.TestValAddrs[j]).TruncateDecimal()
  1624  					truncatedCommission, _ := dk.GetValidatorAccumulatedCommission(ctx, keeper.TestValAddrs[j]).TruncateDecimal()
  1625  					require.Equal(suite.T(), truncatedOutstanding, truncatedCommission)
  1626  				}
  1627  			}
  1628  
  1629  			require.Equal(suite.T(), tc.remainReferenceCount, dk.GetValidatorHistoricalReferenceCount(ctx))
  1630  		})
  1631  	}
  1632  }
  1633  
  1634  func allocateVariateTokens(t *testing.T, blockRewards string) {
  1635  	feePoolBefore, _ := dk.GetFeePool(ctx).CommunityPool.TruncateDecimal()
  1636  	VariateBlockRewards := sdk.SysCoins{{Denom: sdk.DefaultBondDenom, Amount: sdk.MustNewDecFromStr(blockRewards)}}
  1637  	setTestFees(t, ctx, ak, VariateBlockRewards)
  1638  	dk.SetCommunityTax(ctx, sdk.MustNewDecFromStr("0"))
  1639  	dk.AllocateTokens(ctx, 1, keeper.TestConsAddrs[0], votes[0:1])
  1640  	feePoolAfter, _ := dk.GetFeePool(ctx).CommunityPool.TruncateDecimal()
  1641  	require.Equal(t, feePoolBefore, feePoolAfter)
  1642  	staking.EndBlocker(ctx, sk)
  1643  	ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1644  }
  1645  
  1646  func (suite *DistributionSuite) TestTruncateWithPrecWithdraw() {
  1647  	testCases := []struct {
  1648  		title        string
  1649  		precision    int64
  1650  		delCount     int64
  1651  		depositCoins [4]string
  1652  		blockRewards string
  1653  		decRewards   [4]string
  1654  	}{
  1655  		{
  1656  			"1 delegator, precision 18, reward 1",
  1657  			18,
  1658  			1,
  1659  			[4]string{"100"},
  1660  			"1",
  1661  			[4]string{"0.990099009900990000"},
  1662  		},
  1663  		{
  1664  			"2 delegator, precision 18, reward 1",
  1665  			18,
  1666  			2,
  1667  			[4]string{"100", "200"},
  1668  			"1",
  1669  			[4]string{"0.332225913621262400", "0.664451827242524800"},
  1670  		},
  1671  		{
  1672  			"3 delegator, precision 18, reward 1",
  1673  			18,
  1674  			3,
  1675  			[4]string{"100", "200", "300"},
  1676  			"1",
  1677  			[4]string{"0.166389351081530700", "0.332778702163061400", "0.499168053244592100"},
  1678  		},
  1679  		{
  1680  			"4 delegator, precision 18, reward 1",
  1681  			18,
  1682  			4,
  1683  			[4]string{"100", "200", "300", "400"},
  1684  			"1",
  1685  			[4]string{"0.099900099900099900", "0.199800199800199800", "0.299700299700299700", "0.399600399600399600"},
  1686  		},
  1687  		{
  1688  			"1 delegator, precision 5, reward 1",
  1689  			5,
  1690  			1,
  1691  			[4]string{"100"},
  1692  			"1",
  1693  			[4]string{"0.99009"},
  1694  		},
  1695  		{
  1696  			"2 delegator, precision 18, reward 1",
  1697  			5,
  1698  			2,
  1699  			[4]string{"100", "200"},
  1700  			"1",
  1701  			[4]string{"0.33222", "0.66445"},
  1702  		},
  1703  		{
  1704  			"3 delegator, precision 18, reward 1",
  1705  			5,
  1706  			3,
  1707  			[4]string{"100", "200", "300"},
  1708  			"1",
  1709  			[4]string{"0.16638", "0.33277", "0.49916"},
  1710  		},
  1711  		{
  1712  			"4 delegator, precision 18, reward 1",
  1713  			5,
  1714  			4,
  1715  			[4]string{"100", "200", "300", "400"},
  1716  			"1",
  1717  			[4]string{"0.09990", "0.19980", "0.29970", "0.39960"},
  1718  		},
  1719  		{
  1720  			"4 delegator, precision 0, reward 1",
  1721  			0,
  1722  			4,
  1723  			[4]string{"100", "200", "300", "400"},
  1724  			"1",
  1725  			[4]string{"0", "0", "0", "0"},
  1726  		},
  1727  		{
  1728  			"4 delegator, precision 18, reward 100",
  1729  			18,
  1730  			4,
  1731  			[4]string{"100", "200", "300", "400"},
  1732  			"100",
  1733  			[4]string{"9.990009990009990000", "19.980019980019980000", "29.970029970029970000", "39.960039960039960000"},
  1734  		},
  1735  		{
  1736  			"4 delegator, precision 10, reward 100",
  1737  			10,
  1738  			4,
  1739  			[4]string{"100", "200", "300", "400"},
  1740  			"100",
  1741  			[4]string{"9.9900099900", "19.9800199800", "29.9700299700", "39.9600399600"},
  1742  		},
  1743  		{
  1744  			"4 delegator, precision 1, reward 100",
  1745  			1,
  1746  			4,
  1747  			[4]string{"100", "200", "300", "400"},
  1748  			"100",
  1749  			[4]string{"9.9", "19.9", "29.9", "39.9"},
  1750  		},
  1751  		{
  1752  			"4 delegator, precision 1, reward 100",
  1753  			0,
  1754  			4,
  1755  			[4]string{"100", "200", "300", "400"},
  1756  			"100",
  1757  			[4]string{"9", "19", "29", "39"},
  1758  		},
  1759  	}
  1760  
  1761  	for _, tc := range testCases {
  1762  		suite.Run(tc.title, func() {
  1763  			initEnv(suite.T(), 1, true)
  1764  			dk.SetDistributionType(ctx, types.DistributionTypeOnChain)
  1765  			dk.SetRewardTruncatePrecision(ctx, tc.precision)
  1766  			ctx.SetBlockTime(time.Now().UTC().Add(48 * time.Hour))
  1767  			keeper.DoEditValidator(suite.T(), ctx, sk, keeper.TestValAddrs[0], sdk.MustNewDecFromStr("0"))
  1768  			// UTC Time: 2000/1/1 00:00:00
  1769  			blockTimestampEpoch := int64(946684800)
  1770  			ctx.SetBlockTime(time.Unix(blockTimestampEpoch, 0))
  1771  
  1772  			//deposit, add shares, withdraw msg in one block
  1773  			allocateVariateTokens(suite.T(), tc.blockRewards)
  1774  			staking.EndBlocker(ctx, sk)
  1775  			for i := int64(0); i < tc.delCount; i++ {
  1776  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], getDecCoins(tc.depositCoins[i])[0])
  1777  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:1])
  1778  				delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
  1779  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
  1780  
  1781  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1782  				dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[0])
  1783  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1784  				require.Equal(suite.T(), getDecCoins("0"), afterAccount.Sub(beforeAccount))
  1785  
  1786  				beforeAccount = ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1787  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], getDecCoins(tc.depositCoins[i])[0])
  1788  				afterAccount = ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1789  				require.Equal(suite.T(), getDecCoins("0"), afterAccount.Sub(beforeAccount))
  1790  			}
  1791  
  1792  			allocateVariateTokens(suite.T(), tc.blockRewards)
  1793  			staking.EndBlocker(ctx, sk)
  1794  			//nomal
  1795  			for i := int64(0); i < tc.delCount; i++ {
  1796  				keeper.DoDeposit(suite.T(), ctx, sk, keeper.TestDelAddrs[i], getDecCoins(tc.depositCoins[i])[0])
  1797  				keeper.DoAddShares(suite.T(), ctx, sk, keeper.TestDelAddrs[i], keeper.TestValAddrs[0:1])
  1798  				delegator := sk.Delegator(ctx, keeper.TestDelAddrs[i])
  1799  				require.False(suite.T(), delegator.GetLastAddedShares().IsZero())
  1800  			}
  1801  
  1802  			allocateVariateTokens(suite.T(), tc.blockRewards)
  1803  			staking.EndBlocker(ctx, sk)
  1804  			//withdraw reward
  1805  			ctx.SetBlockHeight(ctx.BlockHeight() + 1)
  1806  			feePoolBefore := dk.GetFeePool(ctx).CommunityPool
  1807  			for i := int64(0); i < tc.delCount; i++ {
  1808  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1809  				dk.WithdrawDelegationRewards(ctx, keeper.TestDelAddrs[i], keeper.TestValAddrs[0])
  1810  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1811  				require.Equal(suite.T(), getDecCoins(tc.decRewards[i]), afterAccount.Sub(beforeAccount))
  1812  			}
  1813  			feePoolEnd := dk.GetFeePool(ctx).CommunityPool
  1814  			diff := feePoolEnd.Sub(feePoolBefore)
  1815  			if tc.precision == sdk.Precision {
  1816  				require.True(suite.T(), diff.IsZero())
  1817  			} else {
  1818  				require.False(suite.T(), diff.IsZero())
  1819  			}
  1820  
  1821  			// withdraw
  1822  			allocateVariateTokens(suite.T(), tc.blockRewards)
  1823  			staking.EndBlocker(ctx, sk)
  1824  			for i := int64(0); i < tc.delCount; i++ {
  1825  				beforeAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1826  				keeper.DoWithdraw(suite.T(), ctx, sk, keeper.TestDelAddrs[i], depositCoin)
  1827  				afterAccount := ak.GetAccount(ctx, keeper.TestDelAddrs[i]).GetCoins()
  1828  				require.Equal(suite.T(), getDecCoins(tc.decRewards[i]), afterAccount.Sub(beforeAccount))
  1829  			}
  1830  		})
  1831  	}
  1832  }