diff --git a/x/interchainstaking/keeper/ibc_packet_handlers_test.go b/x/interchainstaking/keeper/ibc_packet_handlers_test.go index dae54b28b..dcc277202 100644 --- a/x/interchainstaking/keeper/ibc_packet_handlers_test.go +++ b/x/interchainstaking/keeper/ibc_packet_handlers_test.go @@ -2787,6 +2787,81 @@ func (suite *KeeperTestSuite) TestTriggerRedemptionRate() { }) } +func (suite *KeeperTestSuite) TestGetValidatorForToken() { + tests := []struct { + name string + err bool + setupConnection bool + amount func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) sdk.Coin + expectVal func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) string + }{ + { + name: "Found validator", + err: false, + setupConnection: true, + amount: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) sdk.Coin { + vals := qs.InterchainstakingKeeper.GetValidatorAddresses(ctx, zone.ChainId) + return sdk.NewCoin(vals[0]+"0x", sdk.NewInt(100)) + }, + expectVal: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) string { + vals := qs.InterchainstakingKeeper.GetValidatorAddresses(ctx, zone.ChainId) + return vals[0] + }, + }, + { + name: "Not found validator", + err: true, + setupConnection: true, + amount: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) sdk.Coin { + return sdk.NewCoin("hello", sdk.NewInt(100)) + }, + expectVal: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) string { + return "" + }, + }, + { + name: "Not setup connection", + err: true, + setupConnection: false, + amount: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) sdk.Coin { + return sdk.NewCoin("hello", sdk.NewInt(100)) + }, + expectVal: func(ctx sdk.Context, qs *app.Quicksilver, zone icstypes.Zone) string { + return "" + }, + }, + } + + for _, test := range tests { + suite.Run(test.name, func() { + suite.SetupTest() + suite.setupTestZones() + + quicksilver := suite.GetQuicksilverApp(suite.chainA) + ctx := suite.chainA.GetContext() + if test.setupConnection { + ctx = ctx.WithContext(context.WithValue(ctx.Context(), utils.ContextKey("connectionID"), suite.path.EndpointA.ConnectionID)) + } + + zone, found := quicksilver.InterchainstakingKeeper.GetZone(ctx, suite.chainB.ChainID) + + if !found { + suite.Fail("unable to retrieve zone for test") + } + amount := test.amount(ctx, quicksilver, zone) + resVal, err := quicksilver.InterchainstakingKeeper.GetValidatorForToken(ctx, amount) + + if test.err { + suite.Error(err) + } else { + suite.NoError(err) + expVal := test.expectVal(ctx, quicksilver, zone) + suite.Equal(expVal, resVal) + } + }) + } +} + func (suite *KeeperTestSuite) TestHandleFailedBankSend() { v1 := addressutils.GenerateValAddressForTest().String() v2 := addressutils.GenerateValAddressForTest().String() diff --git a/x/interchainstaking/keeper/msg_server_test.go b/x/interchainstaking/keeper/msg_server_test.go index 7e3d8c8a0..5a9fe29f7 100644 --- a/x/interchainstaking/keeper/msg_server_test.go +++ b/x/interchainstaking/keeper/msg_server_test.go @@ -7,6 +7,11 @@ import ( "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" + capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + connectiontypes "github.com/cosmos/ibc-go/v5/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v5/modules/core/04-channel/types" "github.com/quicksilver-zone/quicksilver/utils/addressutils" icskeeper "github.com/quicksilver-zone/quicksilver/x/interchainstaking/keeper" @@ -493,3 +498,89 @@ func (suite *KeeperTestSuite) TestSignalIntent() { }) } } + +func (suite *KeeperTestSuite) TestGovCloseChannel() { + testCase := []struct { + name string + malleate func(suite *KeeperTestSuite) *icstypes.MsgGovCloseChannel + expectErr error + }{ + { + name: "invalid authority", + malleate: func(suite *KeeperTestSuite) *icstypes.MsgGovCloseChannel { + return &icstypes.MsgGovCloseChannel{ + ChannelId: "", + PortId: "", + Authority: testAddress, + } + }, + expectErr: govtypes.ErrInvalidSigner, + }, + { + name: "capability not found", + malleate: func(suite *KeeperTestSuite) *icstypes.MsgGovCloseChannel { + k := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper + + return &icstypes.MsgGovCloseChannel{ + ChannelId: "", + PortId: "", + Authority: sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), k.AccountKeeper.GetModuleAddress(govtypes.ModuleName)), + } + }, + expectErr: capabilitytypes.ErrCapabilityNotFound, + }, + { + name: "invalid connection state", + malleate: func(suite *KeeperTestSuite) *icstypes.MsgGovCloseChannel { + ctx := suite.chainA.GetContext() + k := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper + channels := suite.GetQuicksilverApp(suite.chainA).IBCKeeper.ChannelKeeper.GetAllChannels(ctx) + + return &icstypes.MsgGovCloseChannel{ + ChannelId: channels[0].ChannelId, + PortId: channels[0].PortId, + Authority: sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), k.AccountKeeper.GetModuleAddress(govtypes.ModuleName)), + } + }, + expectErr: connectiontypes.ErrInvalidConnectionState, + }, + { + name: "closes an ICA channel success", + malleate: func(suite *KeeperTestSuite) *icstypes.MsgGovCloseChannel { + ctx := suite.chainA.GetContext() + suite.GetQuicksilverApp(suite.chainA).IBCKeeper.ConnectionKeeper.SetConnection(ctx, suite.path.EndpointA.ConnectionID, connectiontypes.ConnectionEnd{ClientId: "07-tendermint-0", State: connectiontypes.OPEN}) + k := suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper + channels := suite.GetQuicksilverApp(suite.chainA).IBCKeeper.ChannelKeeper.GetAllChannels(ctx) + + return &icstypes.MsgGovCloseChannel{ + ChannelId: channels[0].ChannelId, + PortId: channels[0].PortId, + Authority: sdk.MustBech32ifyAddressBytes(sdk.GetConfig().GetBech32AccountAddrPrefix(), k.AccountKeeper.GetModuleAddress(govtypes.ModuleName)), + } + }, + expectErr: nil, + }, + } + for _, tc := range testCase { + suite.Run(tc.name, func() { + suite.SetupTest() + suite.setupTestZones() + + msg := tc.malleate(suite) + msgSrv := icskeeper.NewMsgServerImpl(*suite.GetQuicksilverApp(suite.chainA).InterchainstakingKeeper) + ctx := suite.chainA.GetContext() + + _, err := msgSrv.GovCloseChannel(ctx, msg) + if tc.expectErr != nil { + suite.ErrorIs(tc.expectErr, err) + return + } + suite.NoError(err) + + // check state channel is CLOSED + channel, found := suite.GetQuicksilverApp(suite.chainA).IBCKeeper.ChannelKeeper.GetChannel(ctx, msg.PortId, msg.ChannelId) + suite.True(found) + suite.True(channel.State == channeltypes.CLOSED) + }) + } +} diff --git a/x/interchainstaking/types/accounts.go b/x/interchainstaking/types/accounts.go index effdadb21..74c65d4c0 100644 --- a/x/interchainstaking/types/accounts.go +++ b/x/interchainstaking/types/accounts.go @@ -36,7 +36,7 @@ func (a *ICAAccount) IncrementBalanceWaitgroup() { } func (a *ICAAccount) DecrementBalanceWaitgroup() error { - if a.BalanceWaitgroup <= 0 { + if a.BalanceWaitgroup == 0 { return errors.New("unable to decrement the balance waitgroup below 0") } a.BalanceWaitgroup--