fix(x/protocolpool): Stop allocating funds to expired funds (#20768)
This commit is contained in:
@@ -270,6 +270,17 @@ func (k Keeper) iterateAndUpdateFundsDistribution(ctx context.Context, toDistrib
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
cf, err := k.ContinuousFund.Get(ctx, key)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
|
||||
// Check if the continuous fund has expired
|
||||
if cf.Expiry != nil && cf.Expiry.Before(k.HeaderService.HeaderInfo(ctx).Time) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
totalPercentageToBeDistributed = totalPercentageToBeDistributed.Add(value)
|
||||
recipientFundList = append(recipientFundList, recipientFund{
|
||||
RecipientAddr: addr,
|
||||
|
||||
@@ -95,11 +95,11 @@ func (s *KeeperTestSuite) mockSendCoinsFromModuleToAccount(accAddr sdk.AccAddres
|
||||
}
|
||||
|
||||
func (s *KeeperTestSuite) mockWithdrawContinuousFund() {
|
||||
s.authKeeper.EXPECT().GetModuleAccount(s.ctx, types.ModuleName).Return(poolAcc).AnyTimes()
|
||||
s.authKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.ModuleName).Return(poolAcc).AnyTimes()
|
||||
distrBal := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000)))
|
||||
s.bankKeeper.EXPECT().GetAllBalances(s.ctx, gomock.Any()).Return(distrBal).AnyTimes()
|
||||
s.bankKeeper.EXPECT().SendCoinsFromModuleToAccount(s.ctx, gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
s.stakingKeeper.EXPECT().BondDenom(s.ctx).AnyTimes()
|
||||
s.bankKeeper.EXPECT().GetAllBalances(gomock.Any(), gomock.Any()).Return(distrBal).AnyTimes()
|
||||
s.bankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
|
||||
s.stakingKeeper.EXPECT().BondDenom(gomock.Any()).Return("stake", nil).AnyTimes()
|
||||
}
|
||||
|
||||
func (s *KeeperTestSuite) mockStreamFunds() {
|
||||
|
||||
@@ -968,3 +968,62 @@ func (suite *KeeperTestSuite) TestCancelContinuousFund() {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestWithdrawExpiredFunds checks that a continuous fund cannot be withdrawn if it has expired.
|
||||
// There was a case in which an expired continuous fund would keep getting funds allocated when
|
||||
// other funds were withdrawn. These funds would then get withdrawn if CancelContinuousFund was called.
|
||||
func (suite *KeeperTestSuite) TestWithdrawExpiredFunds() {
|
||||
suite.SetupTest()
|
||||
recipientStrAddr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(recipientAddr)
|
||||
suite.Require().NoError(err)
|
||||
recipient2 := sdk.AccAddress([]byte("recipientAddr2___________________"))
|
||||
recipient2StrAddr, err := codectestutil.CodecOptions{}.GetAddressCodec().BytesToString(recipient2)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
expiration := suite.environment.HeaderService.HeaderInfo(suite.ctx).Time.Add(24 * time.Hour)
|
||||
_, err = suite.msgServer.CreateContinuousFund(suite.ctx, &types.MsgCreateContinuousFund{
|
||||
Authority: suite.poolKeeper.GetAuthority(),
|
||||
Recipient: recipientStrAddr,
|
||||
Percentage: math.LegacyMustNewDecFromStr("0.5"),
|
||||
Expiry: &expiration,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
_, err = suite.msgServer.CreateContinuousFund(suite.ctx, &types.MsgCreateContinuousFund{
|
||||
Authority: suite.poolKeeper.GetAuthority(),
|
||||
Recipient: recipient2StrAddr,
|
||||
Percentage: math.LegacyMustNewDecFromStr("0.5"),
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
toDistribute := sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(100000)))
|
||||
suite.mockStreamFunds()
|
||||
err = suite.poolKeeper.SetToDistribute(suite.ctx, toDistribute, suite.poolKeeper.GetAuthority())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.mockWithdrawContinuousFund()
|
||||
_, err = suite.msgServer.WithdrawContinuousFund(suite.ctx, &types.MsgWithdrawContinuousFund{RecipientAddress: recipientStrAddr})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
header := suite.ctx.HeaderInfo()
|
||||
header.Time = expiration.Add(1 * time.Second)
|
||||
suite.ctx = suite.ctx.WithHeaderInfo(header)
|
||||
|
||||
_, err = suite.msgServer.WithdrawContinuousFund(suite.ctx, &types.MsgWithdrawContinuousFund{RecipientAddress: recipientStrAddr})
|
||||
suite.Require().ErrorContains(err, "continuous fund expired for recipient")
|
||||
|
||||
suite.mockStreamFunds()
|
||||
err = suite.poolKeeper.SetToDistribute(suite.ctx, toDistribute, suite.poolKeeper.GetAuthority())
|
||||
suite.Require().NoError(err)
|
||||
|
||||
suite.mockWithdrawContinuousFund()
|
||||
_, err = suite.msgServer.WithdrawContinuousFund(suite.ctx, &types.MsgWithdrawContinuousFund{RecipientAddress: recipient2StrAddr})
|
||||
suite.Require().NoError(err)
|
||||
|
||||
res, err := suite.msgServer.CancelContinuousFund(suite.ctx, &types.MsgCancelContinuousFund{
|
||||
Authority: suite.poolKeeper.GetAuthority(),
|
||||
RecipientAddress: recipientStrAddr,
|
||||
})
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(sdk.NewCoin(sdk.DefaultBondDenom, math.NewInt(0)), res.WithdrawnAllocatedFund)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user