Skip to content

Middleware Wiring Improvements #8528

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jun 26, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions e2e/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ module github.com/cosmos/ibc-go/e2e

go 1.24.3

// TODO: Remove when v11 release of interchaintest is available (that is where this one is coming from)
replace github.com/cosmos/interchain-security/v7 => github.com/cosmos/interchain-security/v7 v7.0.0-20250622154438-73c73cf686e5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to add this, because interchaintest pulls in this, and the changes here break it :/
The PR that has the commit referenced in the replace: cosmos/interchain-security#2622


replace (
github.com/cosmos/ibc-go/modules/light-clients/08-wasm/v10 => ../modules/light-clients/08-wasm
// uncomment to use the local version of ibc-go, you will need to run `go mod tidy` in e2e directory.
Expand Down
4 changes: 2 additions & 2 deletions e2e/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -856,8 +856,8 @@ github.com/cosmos/iavl v1.2.4 h1:IHUrG8dkyueKEY72y92jajrizbkZKPZbMmG14QzsEkw=
github.com/cosmos/iavl v1.2.4/go.mod h1:GiM43q0pB+uG53mLxLDzimxM9l/5N9UuSY3/D0huuVw=
github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU=
github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0=
github.com/cosmos/interchain-security/v7 v7.0.0-20250408210344-06e0dc6bf6d6 h1:SzJ/+uqrTsJmI+f/GqPdC4lGxgDQKYvtRCMXFdJljNM=
github.com/cosmos/interchain-security/v7 v7.0.0-20250408210344-06e0dc6bf6d6/go.mod h1:W7JHsNaZ5XoH88cKT+wuCRsXkx/Fcn2kEwzpeGdJBxI=
github.com/cosmos/interchain-security/v7 v7.0.0-20250622154438-73c73cf686e5 h1:6LnlaeVk/wHPicQG8NqElL1F1FDVGEl7xF0JXGGhgEs=
github.com/cosmos/interchain-security/v7 v7.0.0-20250622154438-73c73cf686e5/go.mod h1:9EIcx4CzKt/5/2KHtniyzt7Kz8Wgk6fdvyr+AFIUGHc=
github.com/cosmos/interchaintest/v10 v10.0.0 h1:DEsXOS10x191Q3EU4RkOnyqahGCTnLaBGEN//C2MvUQ=
github.com/cosmos/interchaintest/v10 v10.0.0/go.mod h1:caS4BRkAg8NkiZ8BsHEzjNBibt2OVdTctW5Ezz+Jqxs=
github.com/cosmos/ledger-cosmos-go v0.14.0 h1:WfCHricT3rPbkPSVKRH+L4fQGKYHuGOK9Edpel8TYpE=
Expand Down
55 changes: 37 additions & 18 deletions modules/apps/27-interchain-accounts/controller/ibc_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,34 +26,53 @@ var (
// ICA controller keeper and the underlying application.
type IBCMiddleware struct {
app porttypes.IBCModule
keeper keeper.Keeper
keeper *keeper.Keeper
}

// NewIBCMiddleware creates a new IBCMiddleware given the associated keeper.
// The underlying application is set to nil and authentication is assumed to
// be performed by a Cosmos SDK module that sends messages to controller message server.
func NewIBCMiddleware(k keeper.Keeper) IBCMiddleware {
return IBCMiddleware{
func NewIBCMiddleware(k *keeper.Keeper) *IBCMiddleware {
return &IBCMiddleware{
app: nil,
keeper: k,
}
}

// NewIBCMiddlewareWithAuth creates a new IBCMiddleware given the associated keeper and underlying application
func NewIBCMiddlewareWithAuth(app porttypes.IBCModule, k keeper.Keeper) IBCMiddleware {
return IBCMiddleware{
func NewIBCMiddlewareWithAuth(app porttypes.IBCModule, k *keeper.Keeper) *IBCMiddleware {
return &IBCMiddleware{
app: app,
keeper: k,
}
}

// SetUnderlyingApplication sets the underlying application for the middleware.
func (im *IBCMiddleware) SetUnderlyingApplication(app porttypes.IBCModule) {
if app == nil {
panic(errors.New("underlying application cannot be nil"))
}
if im.app != nil {
panic(errors.New("underlying application already set"))
}
im.app = app
}

// SetICS4Wrapper sets the ICS4Wrapper for the middleware.
func (im *IBCMiddleware) SetICS4Wrapper(ics4Wrapper porttypes.ICS4Wrapper) {
if ics4Wrapper == nil {
panic(errors.New("ICS4Wrapper cannot be nil"))
}
im.keeper.WithICS4Wrapper(ics4Wrapper)
}

// OnChanOpenInit implements the IBCMiddleware interface
//
// Interchain Accounts is implemented to act as middleware for connected authentication modules on
// the controller side. The connected modules may not change the controller side portID or
// version. They will be allowed to perform custom logic without changing
// the parameters stored within a channel struct.
func (im IBCMiddleware) OnChanOpenInit(
func (im *IBCMiddleware) OnChanOpenInit(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
Expand Down Expand Up @@ -84,7 +103,7 @@ func (im IBCMiddleware) OnChanOpenInit(
}

// OnChanOpenTry implements the IBCMiddleware interface
func (IBCMiddleware) OnChanOpenTry(
func (*IBCMiddleware) OnChanOpenTry(
ctx sdk.Context,
order channeltypes.Order,
connectionHops []string,
Expand All @@ -102,7 +121,7 @@ func (IBCMiddleware) OnChanOpenTry(
// the controller side. The connected modules may not change the portID or
// version. They will be allowed to perform custom logic without changing
// the parameters stored within a channel struct.
func (im IBCMiddleware) OnChanOpenAck(
func (im *IBCMiddleware) OnChanOpenAck(
ctx sdk.Context,
portID,
channelID string,
Expand Down Expand Up @@ -131,7 +150,7 @@ func (im IBCMiddleware) OnChanOpenAck(
}

// OnChanOpenConfirm implements the IBCMiddleware interface
func (IBCMiddleware) OnChanOpenConfirm(
func (*IBCMiddleware) OnChanOpenConfirm(
ctx sdk.Context,
portID,
channelID string,
Expand All @@ -140,7 +159,7 @@ func (IBCMiddleware) OnChanOpenConfirm(
}

// OnChanCloseInit implements the IBCMiddleware interface
func (IBCMiddleware) OnChanCloseInit(
func (*IBCMiddleware) OnChanCloseInit(
ctx sdk.Context,
portID,
channelID string,
Expand All @@ -150,7 +169,7 @@ func (IBCMiddleware) OnChanCloseInit(
}

// OnChanCloseConfirm implements the IBCMiddleware interface
func (im IBCMiddleware) OnChanCloseConfirm(
func (im *IBCMiddleware) OnChanCloseConfirm(
ctx sdk.Context,
portID,
channelID string,
Expand All @@ -172,7 +191,7 @@ func (im IBCMiddleware) OnChanCloseConfirm(
}

// OnRecvPacket implements the IBCMiddleware interface
func (IBCMiddleware) OnRecvPacket(
func (*IBCMiddleware) OnRecvPacket(
ctx sdk.Context,
_ string,
packet channeltypes.Packet,
Expand All @@ -185,7 +204,7 @@ func (IBCMiddleware) OnRecvPacket(
}

// OnAcknowledgementPacket implements the IBCMiddleware interface
func (im IBCMiddleware) OnAcknowledgementPacket(
func (im *IBCMiddleware) OnAcknowledgementPacket(
ctx sdk.Context,
channelVersion string,
packet channeltypes.Packet,
Expand All @@ -210,7 +229,7 @@ func (im IBCMiddleware) OnAcknowledgementPacket(
}

// OnTimeoutPacket implements the IBCMiddleware interface
func (im IBCMiddleware) OnTimeoutPacket(
func (im *IBCMiddleware) OnTimeoutPacket(
ctx sdk.Context,
channelVersion string,
packet channeltypes.Packet,
Expand All @@ -237,7 +256,7 @@ func (im IBCMiddleware) OnTimeoutPacket(
}

// SendPacket implements the ICS4 Wrapper interface
func (IBCMiddleware) SendPacket(
func (*IBCMiddleware) SendPacket(
ctx sdk.Context,
sourcePort string,
sourceChannel string,
Expand All @@ -249,7 +268,7 @@ func (IBCMiddleware) SendPacket(
}

// WriteAcknowledgement implements the ICS4 Wrapper interface
func (IBCMiddleware) WriteAcknowledgement(
func (*IBCMiddleware) WriteAcknowledgement(
ctx sdk.Context,
packet ibcexported.PacketI,
ack ibcexported.Acknowledgement,
Expand All @@ -258,14 +277,14 @@ func (IBCMiddleware) WriteAcknowledgement(
}

// GetAppVersion returns the interchain accounts metadata.
func (im IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) {
func (im *IBCMiddleware) GetAppVersion(ctx sdk.Context, portID, channelID string) (string, bool) {
return im.keeper.GetAppVersion(ctx, portID, channelID)
}

// UnmarshalPacketData attempts to unmarshal the provided packet data bytes
// into an InterchainAccountPacketData. This function implements the optional
// PacketDataUnmarshaler interface required for ADR 008 support.
func (im IBCMiddleware) UnmarshalPacketData(ctx sdk.Context, portID string, channelID string, bz []byte) (any, string, error) {
func (im *IBCMiddleware) UnmarshalPacketData(ctx sdk.Context, portID string, channelID string, bz []byte) (any, string, error) {
var data icatypes.InterchainAccountPacketData
err := data.UnmarshalJSON(bz)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
host "github.com/cosmos/ibc-go/v10/modules/core/24-host"
ibcerrors "github.com/cosmos/ibc-go/v10/modules/core/errors"
ibctesting "github.com/cosmos/ibc-go/v10/testing"
ibcmock "github.com/cosmos/ibc-go/v10/testing/mock"
)

const invalidVersion = "invalid|version"
Expand Down Expand Up @@ -108,6 +109,88 @@ func SetupICAPath(path *ibctesting.Path, owner string) error {
return path.EndpointB.ChanOpenConfirm()
}

func (s *InterchainAccountsTestSuite) TestSetUnderlyingApplication() {
var (
app porttypes.IBCModule
mw porttypes.Middleware
)
testCases := []struct {
name string
malleate func()
expPanic bool
}{
{
"success", func() {}, false,
},
{
"nil underlying app", func() {
app = nil
}, true,
},
{
"app already set", func() {
mw.SetUnderlyingApplication(&ibcmock.IBCModule{})
}, true,
},
}

for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest() // reset

app = &ibcmock.IBCModule{}
mw = controller.NewIBCMiddleware(s.chainA.GetSimApp().ICAControllerKeeper)

tc.malleate() // malleate mutates test data

if tc.expPanic {
s.Require().Panics(func() {
mw.SetUnderlyingApplication(app)
})
} else {
s.Require().NotPanics(func() {
mw.SetUnderlyingApplication(app)
})
}
})
}
}

func (s *InterchainAccountsTestSuite) TestSetICS4Wrapper() {
var wrapper porttypes.ICS4Wrapper
mw := controller.NewIBCMiddleware(s.chainA.GetSimApp().ICAControllerKeeper)
testCases := []struct {
name string
malleate func()
expPanic bool
}{
{
"success", func() {}, false,
},
{
"nil ICS4Wrapper", func() {
wrapper = nil
}, true,
},
}
for _, tc := range testCases {
s.Run(tc.name, func() {
s.SetupTest() // reset
wrapper = s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper
tc.malleate() // malleate mutates test data
if tc.expPanic {
s.Require().Panics(func() {
mw.SetICS4Wrapper(wrapper)
})
} else {
s.Require().NotPanics(func() {
mw.SetICS4Wrapper(wrapper)
})
}
})
}
}

func (s *InterchainAccountsTestSuite) TestOnChanOpenInit() {
var (
channel *channeltypes.Channel
Expand Down Expand Up @@ -816,7 +899,7 @@ func (s *InterchainAccountsTestSuite) TestInFlightHandshakeRespectsGoAPICaller()
s.Require().NoError(err)

// attempt to start a second handshake via the controller msg server
msgServer := controllerkeeper.NewMsgServerImpl(&s.chainA.GetSimApp().ICAControllerKeeper)
msgServer := controllerkeeper.NewMsgServerImpl(s.chainA.GetSimApp().ICAControllerKeeper)
msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, s.chainA.SenderAccount.GetAddress().String(), TestVersion, ordering)

res, err := msgServer.RegisterInterchainAccount(s.chainA.GetContext(), msgRegisterInterchainAccount)
Expand All @@ -833,7 +916,7 @@ func (s *InterchainAccountsTestSuite) TestInFlightHandshakeRespectsMsgServerCall
path.SetupConnections()

// initiate a channel handshake such that channel.State == INIT
msgServer := controllerkeeper.NewMsgServerImpl(&s.chainA.GetSimApp().ICAControllerKeeper)
msgServer := controllerkeeper.NewMsgServerImpl(s.chainA.GetSimApp().ICAControllerKeeper)
msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, s.chainA.SenderAccount.GetAddress().String(), TestVersion, ordering)

res, err := msgServer.RegisterInterchainAccount(s.chainA.GetContext(), msgRegisterInterchainAccount)
Expand Down Expand Up @@ -868,7 +951,7 @@ func (s *InterchainAccountsTestSuite) TestClosedChannelReopensWithMsgServer() {
channelSeq := s.chainA.GetSimApp().GetIBCKeeper().ChannelKeeper.GetNextChannelSequence(s.chainA.GetContext())

// route a new MsgRegisterInterchainAccount in order to reopen the
msgServer := controllerkeeper.NewMsgServerImpl(&s.chainA.GetSimApp().ICAControllerKeeper)
msgServer := controllerkeeper.NewMsgServerImpl(s.chainA.GetSimApp().ICAControllerKeeper)
msgRegisterInterchainAccount := types.NewMsgRegisterInterchainAccount(path.EndpointA.ConnectionID, s.chainA.SenderAccount.GetAddress().String(), path.EndpointA.ChannelConfig.Version, ordering)

res, err := msgServer.RegisterInterchainAccount(s.chainA.GetContext(), msgRegisterInterchainAccount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func (s *KeeperTestSuite) TestInitGenesis() {

tc.malleate()

keeper.InitGenesis(s.chainA.GetContext(), s.chainA.GetSimApp().ICAControllerKeeper, genesisState)
keeper.InitGenesis(s.chainA.GetContext(), *s.chainA.GetSimApp().ICAControllerKeeper, genesisState)

channelID, found := s.chainA.GetSimApp().ICAControllerKeeper.GetActiveChannelID(s.chainA.GetContext(), ibctesting.FirstConnectionID, TestPortID)
s.Require().True(found)
Expand Down Expand Up @@ -93,7 +93,7 @@ func (s *KeeperTestSuite) TestExportGenesis() {
interchainAccAddr, exists := s.chainB.GetSimApp().ICAHostKeeper.GetInterchainAccountAddress(s.chainB.GetContext(), path.EndpointB.ConnectionID, path.EndpointA.ChannelConfig.PortID)
s.Require().True(exists)

genesisState := keeper.ExportGenesis(s.chainA.GetContext(), s.chainA.GetSimApp().ICAControllerKeeper)
genesisState := keeper.ExportGenesis(s.chainA.GetContext(), *s.chainA.GetSimApp().ICAControllerKeeper)

s.Require().Equal(path.EndpointA.ChannelID, genesisState.ActiveChannels[0].ChannelId)
s.Require().Equal(path.EndpointA.ChannelConfig.PortID, genesisState.ActiveChannels[0].PortId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,17 @@ type Keeper struct {
// NewKeeper creates a new interchain accounts controller Keeper instance
func NewKeeper(
cdc codec.Codec, storeService corestore.KVStoreService,
ics4Wrapper porttypes.ICS4Wrapper, channelKeeper icatypes.ChannelKeeper,
channelKeeper icatypes.ChannelKeeper,
msgRouter icatypes.MessageRouter, authority string,
) Keeper {
) *Keeper {
if strings.TrimSpace(authority) == "" {
panic(errors.New("authority must be non-empty"))
}

return Keeper{
return &Keeper{
storeService: storeService,
cdc: cdc,
ics4Wrapper: ics4Wrapper,
ics4Wrapper: channelKeeper,
channelKeeper: channelKeeper,
msgRouter: msgRouter,
authority: authority,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,6 @@ func (s *KeeperTestSuite) TestNewKeeper() {
s.chainA.GetSimApp().AppCodec(),
runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(types.StoreKey)),
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
s.chainA.GetSimApp().MsgServiceRouter(),
s.chainA.GetSimApp().ICAControllerKeeper.GetAuthority(),
)
Expand All @@ -130,7 +129,6 @@ func (s *KeeperTestSuite) TestNewKeeper() {
s.chainA.GetSimApp().AppCodec(),
runtime.NewKVStoreService(s.chainA.GetSimApp().GetKey(types.StoreKey)),
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
s.chainA.GetSimApp().IBCKeeper.ChannelKeeper,
s.chainA.GetSimApp().MsgServiceRouter(),
"", // authority
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (s *KeeperTestSuite) TestRegisterInterchainAccount_MsgServer() {
tc.malleate()

ctx := s.chainA.GetContext()
msgServer := keeper.NewMsgServerImpl(&s.chainA.GetSimApp().ICAControllerKeeper)
msgServer := keeper.NewMsgServerImpl(s.chainA.GetSimApp().ICAControllerKeeper)
res, err := msgServer.RegisterInterchainAccount(ctx, msg)

if tc.expErr == nil {
Expand Down Expand Up @@ -186,7 +186,7 @@ func (s *KeeperTestSuite) TestSubmitTx() {
tc.malleate() // malleate mutates test data

ctx := s.chainA.GetContext()
msgServer := keeper.NewMsgServerImpl(&s.chainA.GetSimApp().ICAControllerKeeper)
msgServer := keeper.NewMsgServerImpl(s.chainA.GetSimApp().ICAControllerKeeper)
res, err := msgServer.SendTx(ctx, msg)

if tc.expErr == nil {
Expand Down
Loading
Loading