IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.
IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.
middleware developers must use the same serialization and deserialization method as in ibc-go’s codec: transfertypes.ModuleCdc.[Must]MarshalJSON
The interfaces a middleware must implement are found here.
// Middleware implements the ICS26 Module interfacetype Middleware interface { IBCModule // middleware has access to an underlying application which may be wrapped by more middleware ICS4Wrapper // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware. // SetUnderlyingModule sets the underlying IBC module. This function may be used after // the middleware's initialization to set the ibc module which is below this middleware. SetUnderlyingApplication(IBCModule)}
An IBCMiddleware struct implementing the Middleware interface can be defined with its constructor as follows. Note that the constructor does not accept the underlying app or ics4Wrapper — those are wired up later by IBCStackBuilder via SetUnderlyingApplication and SetICS4Wrapper:
// @ x/module_name/ibc_middleware.go// IBCMiddleware implements the ICS26 callbacks and ICS4Wrapper for the middleware given its keeper.type IBCMiddleware struct { app porttypes.IBCModule ics4Wrapper porttypes.ICS4Wrapper keeper *keeper.Keeper}// NewIBCMiddleware creates a new IBCMiddleware given the keeper.// The underlying app and ICS4Wrapper are set later by IBCStackBuilder.func NewIBCMiddleware(k *keeper.Keeper) *IBCMiddleware { return &IBCMiddleware{ keeper: k, }}// SetUnderlyingApplication sets the underlying IBC module.func (im *IBCMiddleware) SetUnderlyingApplication(app porttypes.IBCModule) { if im.app != nil { panic("underlying application already set") } im.app = app}// SetICS4Wrapper sets the ICS4Wrapper.func (im *IBCMiddleware) SetICS4Wrapper(wrapper porttypes.ICS4Wrapper) { if wrapper == nil { panic("ICS4Wrapper cannot be nil") } im.ics4Wrapper = wrapper}
Note how this is analogous to implementing the same interfaces for IBC applications that act as base applications.
As will be mentioned in the integration section, this struct should be different than the struct that implements AppModule in case the middleware maintains its own internal state and processes separate SDK messages.The middleware must have access to the underlying application, and be called before it during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application’s callback.
Middleware may choose not to call the underlying application’s callback at all. Though these should generally be limited to error cases.
The IBCModule interface consists of the channel handshake callbacks and packet callbacks. Most of the custom logic will be performed in the packet callbacks, in the case of the channel handshake callbacks, introducing the middleware requires consideration to the version negotiation.
In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application.Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following:
The <middleware_version_key> key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. fee_version).During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on <middleware_version_value>, and pass the <application_version_value> to the underlying application.
NOTE: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly.
func (im IBCMiddleware)OnChanOpenInit( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID string, channelID string, counterparty channeltypes.Counterparty, version string,) (string, error) { if version != "" { // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. metadata, err := Unmarshal(version) if err != nil { // Since it is valid for fee version to not be specified, // the above middleware version may be for another middleware. // Pass the entire version string onto the underlying application. return im.app.OnChanOpenInit( ctx, order, connectionHops, portID, channelID, counterparty, version, )}else { metadata = { // set middleware version to default value MiddlewareVersion: defaultMiddlewareVersion, // allow application to return its default version AppVersion: "",}}}doCustomLogic() // if the version string is empty, OnChanOpenInit is expected to return // a default version string representing the version(s)it supports appVersion, err := im.app.OnChanOpenInit( ctx, order, connectionHops, portID, channelID, counterparty, metadata.AppVersion, // note we only pass app version here ) if err != nil { return "", err} version := constructVersion(metadata.MiddlewareVersion, appVersion)return version, nil}
See here an example implementation of this callback for the Callbacks Middleware module.
func (im IBCMiddleware)OnChanOpenTry( ctx sdk.Context, order channeltypes.Order, connectionHops []string, portID, channelID string, counterparty channeltypes.Counterparty, counterpartyVersion string,) (string, error) { // try to unmarshal JSON-encoded version string and pass // the app-specific version to app callback. // otherwise, pass version directly to app callback. cpMetadata, err := Unmarshal(counterpartyVersion) if err != nil { return app.OnChanOpenTry( ctx, order, connectionHops, portID, channelID, counterparty, counterpartyVersion, )}doCustomLogic() // Call the underlying application's OnChanOpenTry callback. // The try callback must select the final app-specific version string and return it. appVersion, err := app.OnChanOpenTry( ctx, order, connectionHops, portID, channelID, counterparty, cpMetadata.AppVersion, // note we only pass counterparty app version here ) if err != nil { return "", err} // negotiate final middleware version middlewareVersion := negotiateMiddlewareVersion(cpMetadata.MiddlewareVersion) version := constructVersion(middlewareVersion, appVersion)return version, nil}
See here an example implementation of this callback for the Callbacks Middleware module.
The packet callbacks just like the handshake callbacks wrap the application’s packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware.
Middleware must also wrap ICS-04 so that any communication from the application to the channelKeeper goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes.To ensure optimal generalisability, the ICS4Wrapper abstraction serves to abstract away whether a middleware is the topmost middleware (and thus directly calling into the ICS-04 channelKeeper) or itself being wrapped by another middleware.Remember that middleware can be stateful or stateless. When defining the stateful middleware’s keeper, the ics4Wrapper field is included. Then the appropriate keeper can be passed when instantiating the middleware’s keeper in app.go
For stateless middleware, the ics4Wrapper can be passed on directly without having to instantiate a keeper struct for the middleware.The interface looks as follows:
// This is implemented by ICS4 and all middleware that are wrapping base application.// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them// which will call the next middleware until it reaches the core IBC handler.type ICS4Wrapper interface { SendPacket( ctx sdk.Context, sourcePort string, sourceChannel string, timeoutHeight clienttypes.Height, timeoutTimestamp uint64, data []byte, ) (sequence uint64, err error)WriteAcknowledgement( ctx sdk.Context, packet exported.PacketI, ack exported.Acknowledgement, )error GetAppVersion( ctx sdk.Context, portID, channelID string, ) (string, bool)}
:warning: In the following paragraphs, the methods are presented in pseudo code which has been kept general, not stating whether the middleware is stateful or stateless. Remember that when the middleware is stateful, ics4Wrapper can be accessed through the keeper.Check out the references provided for an actual implementation to clarify, where the ics4Wrapper methods in ibc_middleware.go simply call the equivalent keeper methods where the actual logic resides.
Middleware must also implement the following functions so that they can be called in the stack builder in order to correctly wire the application stack together: SetUnderlyingApplication and SetICS4Wrapper.
// SetUnderlyingModule sets the underlying IBC module. This function may be used after// the middleware's initialization to set the ibc module which is below this middleware.SetUnderlyingApplication(IBCModule)// SetICS4Wrapper sets the ICS4Wrapper. This function may be used after// the module's initialization to set the middleware which is above this// module in the IBC application stack.// The ICS4Wrapper **must** be used for sending packets and writing acknowledgements// to ensure that the middleware can intercept and process these calls.// Do not use the channel keeper directly to send packets or write acknowledgements// as this will bypass the middleware.SetICS4Wrapper(wrapper ICS4Wrapper)
The middleware itself should have access to the underlying app (note this may be a base app or an application wrapped by layers of lower-level middleware(s)) and access to the higher layer ICS4wrapper. The underlying app gets called during the relayer initiated actions: recvPacket, acknowledgePacket, and timeoutPacket. The ics4Wrapper gets called on user-initiated actions like sendPacket and writeAcknowledgement.The functions above are used by the StackBuilder during application setup to wire the stack correctly. The stack must be wired first and have all of the wrappers and applications set correctly before transaction execution starts and packet processing begins.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"IBC Documentation","description":"Documentation for the Inter-Blockchain Communication protocol, its Go implementation, and the IBC CLI.","colors":{"primary":"#000000","light":"#cccccc","dark":"#0E0E0E"},"logo":{"light":"https://mintcdn.com/ibc-docs/_IzGrVOELf0DsHtq/mintlify/assets/brand/ibc-wordmark-dark.svg?fit=max\u0026auto=format\u0026n=_IzGrVOELf0DsHtq\u0026q=85\u0026s=dd69509f8e278637cefba78620bc6f19","dark":"https://mintcdn.com/ibc-docs/_IzGrVOELf0DsHtq/mintlify/assets/brand/ibc-wordmark.svg?fit=max\u0026auto=format\u0026n=_IzGrVOELf0DsHtq\u0026q=85\u0026s=4332fd7d24e0e9834a0ff6d9b0907db8","href":"/"},"favicon":{"light":"https://mintcdn.com/ibc-docs/_IzGrVOELf0DsHtq/mintlify/assets/brand/ibc-dark.svg?fit=max\u0026auto=format\u0026n=_IzGrVOELf0DsHtq\u0026q=85\u0026s=950310224e31e8dcbbbae521db80542e","dark":"https://mintcdn.com/ibc-docs/_IzGrVOELf0DsHtq/mintlify/assets/brand/ibc.svg?fit=max\u0026auto=format\u0026n=_IzGrVOELf0DsHtq\u0026q=85\u0026s=8846e23ba7502345c1b7016d0ec9315d"},"navbar":{"primary":{"type":"button","label":"Get started","href":"/ibc/05-ibc-cli/02-tutorial/01-deploy-ibc-and-send-a-token"}},"footer":{"socials":{"x":"https://twitter.com/cosmos","github":"https://github.com/cosmos","discord":"https://discord.gg/interchain","website":"https://cosmos.network"},"links":[{"header":"Documentation","items":[{"label":"Learn how IBC works","href":"/ibc/01-introduction/01-what-is-ibc"},{"label":"IBC CLI","href":"/ibc/05-ibc-cli/01-overview"},{"label":"IBC-Solidity","href":"/ibc/06-ibc-solidity-contracts/01-overview"},{"label":"IBC-Go","href":"/ibc-go/latest/intro"},{"label":"Specification","href":"/ibc/spec/ics-001-ics-standard/README"}]},{"header":"Repositories","items":[{"label":"cosmos/ibc","href":"https://github.com/cosmos/ibc"},{"label":"cosmos/ibc-go","href":"https://github.com/cosmos/ibc-go"},{"label":"cosmos/ibc-contracts","href":"https://github.com/cosmos/ibc-contracts"}]},{"header":"Security","items":[{"label":"Security audits","href":"/ibc/07-security/01-audits"},{"label":"Bug Bounty","href":"https://immunefi.com/bug-bounty/cosmos/information"}]}]},"icons":{"library":"lucide"},"styling":{"codeblocks":{"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}},"latex":false},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","cursor","vscode"],"display":"header"},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"ibc-docs","hasAudioNarration":false,"actualSubdomain":"ibc-docs","customDomains":[],"gitSource":{"type":"github","owner":"cosmos","repo":"ibc","deployBranch":"main","contentDirectory":"docs","isPrivate":false,"mountPath":"","label":"","_id":"6ae38e8fd265945f8832a739"},"chroma":{"latestBuiltDeploymentHistoryId":"6ae38f56d265945f8832b6ee","collectionId":"e8081330-a92e-4d86-a023-d2707473bf51","liveDeploymentHistoryId":"6ae38f56d265945f8832b6ee","schemaVersion":"v3"},"entitlements":{},"buildId":"6ae393af0b369713606c9b5e","clientVersion":"0.0.4021","searchFilterCounts":[{"language":"default","tag":"Getting Started","count":2}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"/docs","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"per-site-search-delta","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-private-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"byok-sep-25","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"vite-origin","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-updated-9-15","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"mintlify/style.css","content":"/* cyrillic-ext */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh0NSDulI.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh2dSDulI.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh0dSDulI.woff2) format('woff2');\n unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh3tSDulI.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* symbols2 */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bhZ_Wmh2uX.woff2) format('woff2');\n unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh09SDulI.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 400;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh3dSD.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n/* cyrillic-ext */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh0NSDulI.woff2) format('woff2');\n unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;\n}\n/* cyrillic */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh2dSDulI.woff2) format('woff2');\n unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;\n}\n/* greek-ext */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh0dSDulI.woff2) format('woff2');\n unicode-range: U+1F00-1FFF;\n}\n/* greek */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh3tSDulI.woff2) format('woff2');\n unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;\n}\n/* symbols2 */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bhZ_Wmh2uX.woff2) format('woff2');\n unicode-range: U+2000-2001, U+2004-2008, U+200A, U+23B8-23BD, U+2500-259F;\n}\n/* latin-ext */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh09SDulI.woff2) format('woff2');\n unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;\n}\n/* latin */\n@font-face {\n font-family: 'Fira Code';\n font-style: normal;\n font-weight: 500;\n font-display: swap;\n src: url(/docs/_mintlify/assets/fonts/google/s/firacode/v27/uU9NCBsR6Z2vfE9aq3bh3dSD.woff2) format('woff2');\n unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;\n}\n:root{--background-light:255 255 255}.bg-primary\\/10,.dark .bg-primary\\/10,.dark\\:bg-primary-light\\/10:is(.dark *){background-color:var(--nav-accent, #40b3ff)}.bg-primary\\/10 .text-primary,.bg-primary\\/10.text-primary,.dark\\:bg-primary-light\\/10:is(.dark *),.dark\\:bg-primary-light\\/10:is(.dark *) .text-primary,.dark\\:bg-primary-light\\/10:is(.dark *).dark\\:text-primary-light{color:var(--nav-accent-ink, #0e0e0e)}@font-face{font-family:'The Future';src:url(/mintlify/assets/fonts/the-future-regular.woff2) format('woff2');font-weight:400;font-style:normal;font-display:swap}@font-face{font-family:'The Future';src:url(/mintlify/assets/fonts/the-future-medium.woff2) format('woff2');font-weight:500;font-style:normal;font-display:swap}@font-face{font-family:'The Future';src:url(/mintlify/assets/fonts/the-future-bold.woff2) format('woff2');font-weight:700;font-style:normal;font-display:swap}@font-face{font-family:'The Future';src:url(/mintlify/assets/fonts/the-future-light.woff2) format('woff2');font-weight:300;font-style:normal;font-display:swap}body:has(#custom-index-content) #header,body:has(#custom-index-content) #navbar,body:has(#custom-index-content) #search-bar-entry,body:has(#custom-index-content) #search-bar-entry-mobile,body:has(#custom-index-content) .chat-assistant-floating-input,body:has(#custom-index-content) :has(>.chat-assistant-floating-input),body:has(#custom-index-content) button#search-bar-entry,body:has(#custom-index-content) button#search-bar-entry-mobile,body:has(#custom-index-content) header,body:has(#custom-index-content) nav[aria-label]{display:none!important;visibility:hidden!important;opacity:0!important;width:0!important;height:0!important;position:absolute!important;left:-99999px!important;pointer-events:none!important}body:has(#custom-index-content) #custom-index-content,body:has(#custom-index-content) #custom-index-content a,body:has(#custom-index-content) #custom-index-content h1,body:has(#custom-index-content) #custom-index-content h2,body:has(#custom-index-content) #custom-index-content h3,body:has(#custom-index-content) #custom-index-content p{font-family:'The Future',sans-serif}@media (max-width:768px){button[aria-label=\"More actions\"]{display:none!important}#custom-index-content{margin-top:-120px}}@media (min-width:769px) and (max-width:1023px){#custom-index-content{margin-top:-120px}}.prose .callout a,.prose .info a,.prose .note a,.prose .step a,.prose .steps a,.prose .tip a,.prose .warning a,.prose [role=listitem] a,.prose div[data-callout-type] a,.prose li a,.prose p a,.prose span a,.prose ul a{border-bottom-color:#0e0e0e!important;text-decoration-color:#0e0e0e!important}.dark .prose .callout a,.dark .prose .info a,.dark .prose .note a,.dark .prose .step a,.dark .prose .steps a,.dark .prose .tip a,.dark .prose .warning a,.dark .prose [role=listitem] a,.dark .prose div[data-callout-type] a,.dark .prose li a,.dark .prose p a,.dark .prose span a,.dark .prose ul a{border-bottom-color:#ccc!important;text-decoration-color:#ccc!important}.highlighted-card-bg{background-color:#ffb84d;position:relative;overflow:hidden;transition:box-shadow .3s ease-in-out}.highlighted-card-bg:hover{box-shadow:0 0 30px rgba(255,184,77,.5),0 0 60px rgba(255,184,77,.3),0 10px 40px rgba(255,184,77,.2)}.highlighted-card-bg::before{content:'';position:absolute;top:-50%;left:-50%;width:200%;height:200%;background:linear-gradient(45deg,transparent 30%,rgba(255,255,255,.4) 50%,transparent 70%);transform:translateX(-100%) translateY(-100%) rotate(45deg);transition:transform .6s ease-in-out}.highlighted-card-bg:hover::before{transform:translateX(100%) translateY(100%) rotate(45deg)}@layer utilities{body:has(#custom-index-content) #footer{display:flex!important}}code,pre,pre code{font-family:'Fira Code','Cascadia Code','JetBrains Mono',monospace!important}#navbar a>span.absolute.bg-primary-dark,header a>span.absolute.bg-primary-dark{background-color:var(--nav-accent, #40b3ff);transition:background-color 120ms ease}#navbar a:hover>span.absolute.bg-primary-dark,header a:hover>span.absolute.bg-primary-dark{background-color:color-mix(in srgb,var(--nav-accent, #40b3ff) 82%,white);opacity:1}#navbar a:has(>span.absolute.bg-primary-dark),#navbar a:has(>span.absolute.bg-primary-dark) *,header a:has(>span.absolute.bg-primary-dark),header a:has(>span.absolute.bg-primary-dark) *{color:var(--nav-accent-ink, #0e0e0e);font-weight:600}.nav-tabs-item{--tab-accent:#40b3ff;--tab-ink:#0e0e0e;transition:color 120ms ease}.nav-tabs-item::before{content:\"\";position:absolute;inset:9px -10px;border-radius:.5rem;background-color:transparent;transition:background-color 120ms ease;z-index:-1}.nav-tabs-item:hover::before{background-color:var(--tab-accent)}.nav-tabs-item:hover,.nav-tabs-item:hover *{color:var(--tab-ink)!important}.nav-tabs-item[href^=\"/ibc/05-ibc-cli/\"]{--tab-accent:#22e2a8;--tab-ink:#0e0e0e}.nav-tabs-item[href^=\"/ibc/06-ibc-solidity-contracts/\"]{--tab-accent:#7522b5;--tab-ink:#ffffff}.nav-tabs-item[href^=\"/ibc-go/\"]{--tab-accent:#4b47ca;--tab-ink:#ffffff}.nav-tabs-item[href^=\"/ibc/spec/\"]{--tab-accent:#ef5628;--tab-ink:#0e0e0e}img.nav-logo{height:3rem}"}],"page":{"pagePath":"ibc-go/latest/ibc/middleware/develop","slug":"/ibc-go/latest/ibc/middleware/develop","pageMetadata":{"title":"Create a custom IBC middleware","description":"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.","href":"/ibc-go/latest/ibc/middleware/develop"},"description":{"compiledSource":"\"use strict\";\nconst {jsx: _jsx} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n p: \"p\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsx(_components.p, {\n children: \"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.\"\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx,jsxs:_jsxs}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){const _components={a:`a`,blockquote:`blockquote`,code:`code`,p:`p`,pre:`pre`,span:`span`,strong:`strong`,..._provideComponents(),...props.components},{CodeBlock,Heading,Warning}=_components;if(!CodeBlock)_missingMdxReference(`CodeBlock`,true);if(!Heading)_missingMdxReference(`Heading`,true);if(!Warning)_missingMdxReference(`Warning`,true);return _jsxs(_Fragment,{children:[_jsx(_components.p,{children:`IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.`}),`\n`,_jsx(Warning,{children:_jsx(_components.p,{children:`middleware developers must use the same serialization and deserialization method as in ibc-go’s codec: transfertypes.ModuleCdc.[Must]MarshalJSON`})}),`\n`,_jsx(_components.p,{children:`For middleware builders this means:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`5`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`5`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`import`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` transfertypes `}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`github.com/cosmos/ibc-go/v11/modules/apps/transfer/types`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`transfertypes.ModuleCdc.[Must]MarshalJSON`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` MarshalAsIBCDoes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`ack`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Acknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) ([]`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`byte`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` transfertypes.ModuleCdc.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`MarshalJSON`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`\u0026`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`ack)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The interfaces a middleware must implement are found `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/main/modules/core/05-port/types/module.go`,children:`here`}),`.`]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`9`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// Middleware implements the ICS26 Module interface`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`type`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` Middleware`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` interface`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` IBCModule`}),_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // middleware has access to an underlying application which may be wrapped by more middleware`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ICS4Wrapper`}),_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // middleware has access to ICS4Wrapper which may be core IBC Channel Handler or a higher-level middleware that wraps this middleware.`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // SetUnderlyingModule sets the underlying IBC module. This function may be used after`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`\t// the middleware's initialization to set the ibc module which is below this middleware.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`\tSetUnderlyingApplication`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCModule`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`An `,_jsx(_components.code,{children:`IBCMiddleware`}),` struct implementing the `,_jsx(_components.code,{children:`Middleware`}),` interface can be defined with its constructor as follows. Note that the constructor `,_jsx(_components.strong,{children:`does not`}),` accept the underlying `,_jsx(_components.code,{children:`app`}),` or `,_jsx(_components.code,{children:`ics4Wrapper`}),` — those are wired up later by `,_jsx(_components.code,{children:`IBCStackBuilder`}),` via `,_jsx(_components.code,{children:`SetUnderlyingApplication`}),` and `,_jsx(_components.code,{children:`SetICS4Wrapper`}),`:`]}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`32`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`32`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// @ x/module_name/ibc_middleware.go`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// IBCMiddleware implements the ICS26 callbacks and ICS4Wrapper for the middleware given its keeper.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`type`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` IBCMiddleware`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` struct`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`porttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCModule`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ics4Wrapper `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`porttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`ICS4Wrapper`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` keeper `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`*`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`keeper`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Keeper`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// NewIBCMiddleware creates a new IBCMiddleware given the keeper.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// The underlying app and ICS4Wrapper are set later by IBCStackBuilder.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` NewIBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`k`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` *`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`keeper`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Keeper`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`*`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` \u0026`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`{`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` keeper: k,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` }`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// SetUnderlyingApplication sets the underlying IBC module.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`*`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) `}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`SetUnderlyingApplication`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`app`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` porttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCModule`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` im.app `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` panic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"underlying application already set\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` }`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` im.app `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// SetICS4Wrapper sets the ICS4Wrapper.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`*`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) `}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`SetICS4Wrapper`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`wrapper`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` porttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`ICS4Wrapper`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` wrapper `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`==`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` panic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"ICS4Wrapper cannot be nil\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` }`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` im.ics4Wrapper `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` wrapper`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(Heading,{level:`2`,id:`implement-ibcmodule-interface`,children:[`Implement `,_jsx(_components.code,{children:`IBCModule`}),` interface`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.code,{children:`IBCMiddleware`}),` is a struct that implements the `,_jsxs(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/core/05-port/types/module.go#L13-L118`,children:[`ICS-26 `,_jsx(_components.code,{children:`IBCModule`}),` interface (`,_jsx(_components.code,{children:`porttypes.IBCModule`}),`)`]}),`. It is recommended to separate these callbacks into a separate file `,_jsx(_components.code,{children:`ibc_middleware.go`}),`.`]}),`\n`,_jsxs(_components.blockquote,{children:[`\n`,_jsx(_components.p,{children:`Note how this is analogous to implementing the same interfaces for IBC applications that act as base applications.`}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`As will be mentioned in the `,_jsx(_components.a,{href:`/ibc-go/latest/ibc/middleware/integration`,children:`integration section`}),`, this struct should be different than the struct that implements `,_jsx(_components.code,{children:`AppModule`}),` in case the middleware maintains its own internal state and processes separate SDK messages.`]}),`\n`,_jsx(_components.p,{children:`The middleware must have access to the underlying application, and be called before it during all ICS-26 callbacks. It may execute custom logic during these callbacks, and then call the underlying application’s callback.`}),`\n`,_jsxs(_components.blockquote,{children:[`\n`,_jsxs(_components.p,{children:[`Middleware `,_jsx(_components.strong,{children:`may`}),` choose not to call the underlying application’s callback at all. Though these should generally be limited to error cases.`]}),`\n`]}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`IBCModule`}),` interface consists of the channel handshake callbacks and packet callbacks. Most of the custom logic will be performed in the packet callbacks, in the case of the channel handshake callbacks, introducing the middleware requires consideration to the version negotiation.`]}),`\n`,_jsx(Heading,{level:`3`,id:`channel-handshake-callbacks`,children:`Channel handshake callbacks`}),`\n`,_jsx(Heading,{level:`4`,id:`version-negotiation`,children:`Version negotiation`}),`\n`,_jsx(_components.p,{children:`In the case where the IBC middleware expects to speak to a compatible IBC middleware on the counterparty chain, they must use the channel handshake to negotiate the middleware version without interfering in the version negotiation of the underlying application.`}),`\n`,_jsx(_components.p,{children:`Middleware accomplishes this by formatting the version in a JSON-encoded string containing the middleware version and the application version. The application version may as well be a JSON-encoded string, possibly including further middleware and app versions, if the application stack consists of multiple milddlewares wrapping a base application. The format of the version is specified in ICS-30 as the following:`}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`4`,language:`json`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`json`,children:_jsxs(_components.code,{language:`json`,numberOfLines:`4`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`{`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#024C1A`,\"--shiki-dark\":`#72F088`},children:` \"\u003cmiddleware_version_key>\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`: `}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"\u003cmiddleware_version_value>\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#024C1A`,\"--shiki-dark\":`#72F088`},children:` \"app_version\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`: `}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"\u003capplication_version_value>\"`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The `,_jsx(_components.code,{children:`\u003cmiddleware_version_key>`}),` key in the JSON struct should be replaced by the actual name of the key for the corresponding middleware (e.g. `,_jsx(_components.code,{children:`fee_version`}),`).`]}),`\n`,_jsxs(_components.p,{children:[`During the handshake callbacks, the middleware can unmarshal the version string and retrieve the middleware and application versions. It can do its negotiation logic on `,_jsx(_components.code,{children:`\u003cmiddleware_version_value>`}),`, and pass the `,_jsx(_components.code,{children:`\u003capplication_version_value>`}),` to the underlying application.`]}),`\n`,_jsxs(_components.blockquote,{children:[`\n`,_jsxs(_components.p,{children:[_jsx(_components.strong,{children:`NOTE`}),`: Middleware that does not need to negotiate with a counterparty middleware on the remote stack will not implement the version unmarshalling and negotiation, and will simply perform its own custom logic on the callbacks without relying on the counterparty behaving similarly.`]}),`\n`]}),`\n`,_jsx(Heading,{level:`4`,id:`onchanopeninit`,children:_jsx(_components.code,{children:`OnChanOpenInit`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`65`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`65`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenInit`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` order`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Order`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` connectionHops`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` []`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` counterparty`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Counterparty`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` version`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) (`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:` \"\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // try to unmarshal JSON-encoded version string and pass`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // the app-specific version to app callback.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // otherwise, pass version directly to app callback.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` metadata, err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` Unmarshal`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(version)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // Since it is valid for fee version to not be specified,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // the above middleware version may be for another middleware.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // Pass the entire version string onto the underlying application.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` im.app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenInit`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ctx,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` order,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` connectionHops,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` portID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` channelID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` counterparty,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` )`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`else`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` metadata `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // set middleware version to default value`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` MiddlewareVersion: defaultMiddlewareVersion,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // allow application to return its default version`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` AppVersion: `}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`()`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // if the version string is empty, OnChanOpenInit is expected to return`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // a default version string representing the version(s)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`it supports`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` appVersion, err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` im.app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenInit`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ctx,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` order,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` connectionHops,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` portID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` channelID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` counterparty,`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` metadata.AppVersion, `}),_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// note we only pass app version here`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` )`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:` \"\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, err`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` constructVersion`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(metadata.MiddlewareVersion, appVersion)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version, `}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:`nil`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L314-L324`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`onchanopentry`,children:_jsx(_components.code,{children:`OnChanOpenTry`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`50`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`50`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenTry`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` order`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Order`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` connectionHops`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` []`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` counterparty`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Counterparty`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` counterpartyVersion`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) (`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // try to unmarshal JSON-encoded version string and pass`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // the app-specific version to app callback.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // otherwise, pass version directly to app callback.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` cpMetadata, err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` Unmarshal`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(counterpartyVersion)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenTry`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ctx,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` order,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` connectionHops,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` portID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` channelID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` counterparty,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` counterpartyVersion,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` )`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`()`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // Call the underlying application's OnChanOpenTry callback.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // The try callback must select the final app-specific version string and return it.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` appVersion, err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenTry`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ctx,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` order,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` connectionHops,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` portID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` channelID,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` counterparty,`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` cpMetadata.AppVersion, `}),_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// note we only pass counterparty app version here`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` )`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:` \"\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, err`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // negotiate final middleware version`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` middlewareVersion `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` negotiateMiddlewareVersion`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(cpMetadata.MiddlewareVersion)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` constructVersion`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(middlewareVersion, appVersion)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version, `}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:`nil`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L327-L336`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`onchanopenack`,children:_jsx(_components.code,{children:`OnChanOpenAck`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`27`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`27`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenAck`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` counterpartyChannelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` counterpartyVersion`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // try to unmarshal JSON-encoded version string and pass`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // the app-specific version to app callback.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // otherwise, pass version directly to app callback.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` cpMetadata, err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` UnmarshalJSON`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(counterpartyVersion)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenAck`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, portID, channelID, counterpartyChannelID, counterpartyVersion)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` !`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`isCompatible`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(cpMetadata.MiddlewareVersion) {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` error`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`()`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // call the underlying application's OnChanOpenTry callback`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenAck`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, portID, channelID, counterpartyChannelID, cpMetadata.AppVersion)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L339-L347`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`onchanopenconfirm`,children:_jsx(_components.code,{children:`OnChanOpenConfirm`})}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`11`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`11`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` OnChanOpenConfirm`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`()`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanOpenConfirm`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, portID, channelID)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L350-L352`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`onchancloseinit`,children:_jsx(_components.code,{children:`OnChanCloseInit`})}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`11`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`11`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` OnChanCloseInit`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`()`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanCloseInit`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, portID, channelID)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L355-L357`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`onchancloseconfirm`,children:_jsx(_components.code,{children:`OnChanCloseConfirm`})}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`11`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`11`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` OnChanCloseConfirm`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`()`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnChanCloseConfirm`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, portID, channelID)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L360-L362`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`3`,id:`packet-callbacks`,children:`Packet callbacks`}),`\n`,_jsx(_components.p,{children:`The packet callbacks just like the handshake callbacks wrap the application’s packet callbacks. The packet callbacks are where the middleware performs most of its custom logic. The middleware may read the packet flow data and perform some additional packet handling, or it may modify the incoming data before it reaches the underlying application. This enables a wide degree of usecases, as a simple base application like token-transfer can be transformed for a variety of usecases by combining it with custom middleware.`}),`\n`,_jsx(Heading,{level:`4`,id:`onrecvpacket`,children:_jsx(_components.code,{children:`OnRecvPacket`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`17`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`17`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnRecvPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelVersion`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` packet`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Packet`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` relayer`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`AccAddress`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`ibcexported.Acknowledgement {`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(packet)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ack `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnRecvPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, channelVersion, packet, relayer)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ack) `}),_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// middleware may modify outgoing ack`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` `})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ack`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L225-L265`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`onacknowledgementpacket`,children:_jsx(_components.code,{children:`OnAcknowledgementPacket`})}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`15`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`15`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnAcknowledgementPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelVersion`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` packet`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Packet`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` acknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` []`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`byte`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` relayer`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`AccAddress`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(packet, ack)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnAcknowledgementPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, channelVersion, packet, ack, relayer)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L139-L180`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`4`,id:`ontimeoutpacket`,children:_jsx(_components.code,{children:`OnTimeoutPacket`})}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`14`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`14`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`im IBCMiddleware`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnTimeoutPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelVersion`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` packet`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channeltypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Packet`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` relayer`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`AccAddress`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(packet)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` app.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`OnTimeoutPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, channelVersion, packet, relayer)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L186-L218`,children:`here`}),` an example implementation of this callback for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`2`,id:`ics-04-wrappers`,children:`ICS-04 wrappers`}),`\n`,_jsxs(_components.p,{children:[`Middleware must also wrap ICS-04 so that any communication from the application to the `,_jsx(_components.code,{children:`channelKeeper`}),` goes through the middleware first. Similar to the packet callbacks, the middleware may modify outgoing acknowledgements and packets in any way it wishes.`]}),`\n`,_jsxs(_components.p,{children:[`To ensure optimal generalisability, the `,_jsx(_components.code,{children:`ICS4Wrapper`}),` abstraction serves to abstract away whether a middleware is the topmost middleware (and thus directly calling into the ICS-04 `,_jsx(_components.code,{children:`channelKeeper`}),`) or itself being wrapped by another middleware.`]}),`\n`,_jsxs(_components.p,{children:[`Remember that middleware can be stateful or stateless. When defining the stateful middleware’s keeper, the `,_jsx(_components.code,{children:`ics4Wrapper`}),` field is included. Then the appropriate keeper can be passed when instantiating the middleware’s keeper in `,_jsx(_components.code,{children:`app.go`})]}),`\n`,_jsx(CodeBlock,{filename:``,numberOfLines:`9`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`9`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`type`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` Keeper`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` struct`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` storeKey `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`storetypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`StoreKey`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` cdc `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`codec`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`BinaryCodec`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ics4Wrapper `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`porttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`ICS4Wrapper`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` channelKeeper `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`types`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`ChannelKeeper`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` portKeeper `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`types`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`PortKeeper`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` ...`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`For stateless middleware, the `,_jsx(_components.code,{children:`ics4Wrapper`}),` can be passed on directly without having to instantiate a keeper struct for the middleware.`]}),`\n`,_jsxs(_components.p,{children:[_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/core/05-port/types/module.go#L119-L143`,children:`The interface`}),` looks as follows:`]}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`27`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`27`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// This is implemented by ICS4 and all middleware that are wrapping base application.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:\"// The base application will call `sendPacket` or `writeAcknowledgement` of the middleware directly above them\"})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// which will call the next middleware until it reaches the core IBC handler.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`type`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ICS4Wrapper`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` interface`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` SendPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sourcePort`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sourceChannel`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` timeoutHeight`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` clienttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Height`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` timeoutTimestamp`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` uint64`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` data`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` []`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`byte`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ) (`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`sequence`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` uint64`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`err`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`WriteAcknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` packet`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` exported`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`PacketI`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ack`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` exported`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Acknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` )`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` GetAppVersion`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ) (`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`bool`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`:warning: In the following paragraphs, the methods are presented in pseudo code which has been kept general, not stating whether the middleware is stateful or stateless. Remember that when the middleware is stateful, `,_jsx(_components.code,{children:`ics4Wrapper`}),` can be accessed through the keeper.`]}),`\n`,_jsxs(_components.p,{children:[`Check out the references provided for an actual implementation to clarify, where the `,_jsx(_components.code,{children:`ics4Wrapper`}),` methods in `,_jsx(_components.code,{children:`ibc_middleware.go`}),` simply call the equivalent keeper methods where the actual logic resides.`]}),`\n`,_jsx(Heading,{level:`3`,id:`sendpacket`,children:_jsx(_components.code,{children:`SendPacket`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`20`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`20`,children:[_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` SendPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sourcePort`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sourceChannel`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` timeoutHeight`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` clienttypes`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Height`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` timeoutTimestamp`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` uint64`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` appData`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` []`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`byte`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) (`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`uint64`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // middleware may modify data`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` data `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(appData)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ics4Wrapper.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`SendPacket`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ctx, `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` sourcePort, `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` sourceChannel, `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` timeoutHeight, `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` timeoutTimestamp, `})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` data,`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` )`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L92-L133`,children:`here`}),` an example implementation of this function for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`3`,id:`writeacknowledgement`,children:_jsx(_components.code,{children:`WriteAcknowledgement`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`13`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`13`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// only called for async acks`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` WriteAcknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` packet`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` exported`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`PacketI`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ack`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` exported`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Acknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`)`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`error`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // middleware may modify acknowledgement`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ack_bytes `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` doCustomLogic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ack)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ics4Wrapper.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`WriteAcknowledgement`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(packet, ack_bytes)`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L272-L311`,children:`here`}),` an example implementation of this function for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`3`,id:`getappversion`,children:_jsx(_components.code,{children:`GetAppVersion`})}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`22`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`22`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// middleware must return the underlying application version`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`func`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` GetAppVersion`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` ctx`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` sdk`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`.`}),_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:`Context`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` portID`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#702C00`,\"--shiki-dark\":`#FFB757`},children:` channelID`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`,`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) (`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`string`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`bool`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`) {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version, found `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` ics4Wrapper.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`GetAppVersion`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(ctx, portID, channelID)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` !`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`found {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:` \"\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, `}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:`false`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` !`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`MiddlewareEnabled {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` version, `}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:`true`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:` // unwrap channel version`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` metadata, err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`:=`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` Unmarshal`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(version)`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:` if`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` err `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`!=`}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:` nil`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` {`})]}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:` panic`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(fmt.`}),_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`Errorf`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"unable to unmarshal version: `}),_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`%w`}),_jsx(_components.span,{style:{color:`#032563`,\"--shiki-dark\":`#ADDCFF`},children:`\"`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`, err))`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#A0111F`,\"--shiki-dark\":`#FF9492`},children:`return`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:` metadata.AppVersion, `}),_jsx(_components.span,{style:{color:`#023B95`,\"--shiki-dark\":`#91CBFF`},children:`true`})]}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`}`})}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`See `,_jsx(_components.a,{href:`https://github.com/cosmos/ibc-go/blob/4dc625ae138c52bfe5b8585c24de9b16ddcf6186/modules/apps/callbacks/ibc_middleware.go#L366-L368`,children:`here`}),` an example implementation of this function for the Callbacks Middleware module.`]}),`\n`,_jsx(Heading,{level:`2`,id:`wiring-interface-requirements`,children:`Wiring Interface Requirements`}),`\n`,_jsxs(_components.p,{children:[`Middleware must also implement the following functions so that they can be called in the stack builder in order to correctly wire the application stack together: `,_jsx(_components.code,{children:`SetUnderlyingApplication`}),` and `,_jsx(_components.code,{children:`SetICS4Wrapper`}),`.`]}),`\n`,_jsx(CodeBlock,{filename:``,expandable:`true`,numberOfLines:`12`,language:`go`,children:_jsx(_components.pre,{className:`shiki shiki-themes github-light-high-contrast github-dark-high-contrast`,style:{backgroundColor:`#ffffff`,\"--shiki-dark-bg\":`#0a0c10`,color:`#0e1116`,\"--shiki-dark\":`#f0f3f6`},language:`go`,children:_jsxs(_components.code,{language:`go`,numberOfLines:`12`,children:[_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// SetUnderlyingModule sets the underlying IBC module. This function may be used after`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// the middleware's initialization to set the ibc module which is below this middleware.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`SetUnderlyingApplication`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(IBCModule)`})]}),`\n`,_jsx(_components.span,{className:`line`}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// SetICS4Wrapper sets the ICS4Wrapper. This function may be used after`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// the module's initialization to set the middleware which is above this`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// module in the IBC application stack.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// The ICS4Wrapper **must** be used for sending packets and writing acknowledgements`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// to ensure that the middleware can intercept and process these calls.`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// Do not use the channel keeper directly to send packets or write acknowledgements`})}),`\n`,_jsx(_components.span,{className:`line`,children:_jsx(_components.span,{style:{color:`#66707B`,\"--shiki-dark\":`#BDC4CC`},children:`// as this will bypass the middleware.`})}),`\n`,_jsxs(_components.span,{className:`line`,children:[_jsx(_components.span,{style:{color:`#622CBC`,\"--shiki-dark\":`#DBB7FF`},children:`SetICS4Wrapper`}),_jsx(_components.span,{style:{color:`#0E1116`,\"--shiki-dark\":`#F0F3F6`},children:`(wrapper ICS4Wrapper)`})]}),`\n`]})})}),`\n`,_jsxs(_components.p,{children:[`The middleware itself should have access to the `,_jsx(_components.code,{children:`underlying app`}),` (note this may be a base app or an application wrapped by layers of lower-level middleware(s)) and access to the higher layer `,_jsx(_components.code,{children:`ICS4wrapper`}),`. The `,_jsx(_components.code,{children:`underlying app`}),` gets called during the relayer initiated actions: `,_jsx(_components.code,{children:`recvPacket`}),`, `,_jsx(_components.code,{children:`acknowledgePacket`}),`, and `,_jsx(_components.code,{children:`timeoutPacket`}),`. The `,_jsx(_components.code,{children:`ics4Wrapper`}),` gets called on user-initiated actions like `,_jsx(_components.code,{children:`sendPacket`}),` and `,_jsx(_components.code,{children:`writeAcknowledgement`}),`.`]}),`\n`,_jsxs(_components.p,{children:[`The functions above are used by the `,_jsx(_components.code,{children:`StackBuilder`}),` during application setup to wire the stack correctly. The stack must be wired first and have all of the wrappers and applications set correctly before transaction execution starts and packet processing begins.`]})]})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent};function _missingMdxReference(id,component){throw new Error(`Expected `+(component?`component`:`object`)+\" `\"+id+\"` to be defined: you likely forgot to import, pass, or provide it.\")}","frontmatter":{},"scope":{"codeStyling":{"theme":{"light":"github-light-high-contrast","dark":"github-dark-high-contrast"}},"config":{},"pageMetadata":{"title":"Create a custom IBC middleware","description":"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.","href":"/ibc-go/latest/ibc/middleware/develop"}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[{"title":"Implement IBCModule interface","slug":"implement-ibcmodule-interface","depth":2,"children":[{"title":"Channel handshake callbacks","slug":"channel-handshake-callbacks","depth":3,"children":[]},{"title":"Version negotiation","slug":"version-negotiation","depth":4,"children":[]},{"title":"OnChanOpenInit","slug":"onchanopeninit","depth":4,"children":[]},{"title":"OnChanOpenTry","slug":"onchanopentry","depth":4,"children":[]},{"title":"OnChanOpenAck","slug":"onchanopenack","depth":4,"children":[]},{"title":"OnChanOpenConfirm","slug":"onchanopenconfirm","depth":4,"children":[]},{"title":"OnChanCloseInit","slug":"onchancloseinit","depth":4,"children":[]},{"title":"OnChanCloseConfirm","slug":"onchancloseconfirm","depth":4,"children":[]},{"title":"Packet callbacks","slug":"packet-callbacks","depth":3,"children":[]},{"title":"OnRecvPacket","slug":"onrecvpacket","depth":4,"children":[]},{"title":"OnAcknowledgementPacket","slug":"onacknowledgementpacket","depth":4,"children":[]},{"title":"OnTimeoutPacket","slug":"ontimeoutpacket","depth":4,"children":[]}]},{"title":"ICS-04 wrappers","slug":"ics-04-wrappers","depth":2,"children":[{"title":"SendPacket","slug":"sendpacket","depth":3,"children":[]},{"title":"WriteAcknowledgement","slug":"writeacknowledgement","depth":3,"children":[]},{"title":"GetAppVersion","slug":"getappversion","depth":3,"children":[]}]},{"title":"Wiring Interface Requirements","slug":"wiring-interface-requirements","depth":2,"children":[]}],"codeExamples":{}},"jsLinks":["/docs/_mintlify/custom/ibc-docs/1efa1b9f25769b22/custom.js"],"subdomain":"ibc-docs","siteName":"IBC Documentation","title":"Create a custom IBC middleware - IBC Documentation","navMaps":{"firstHrefInVersion":{"latest":{"href":"/ibc-go/latest/ibc/middleware/develop","matchLevel":0},"v10.1.x":{"href":"/ibc-go/v10.1.x/ibc/middleware/develop","matchLevel":1,"noindex":true,"canonicalOverride":true}},"firstHrefInLanguage":{}},"lastModified":"2026-10-29T18:43:19.174Z","originalFileLocation":"ibc-go/latest/ibc/middleware/develop.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.\">\u003cmeta data-mint-head name=\"application-name\" content=\"IBC Documentation\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Create a custom IBC middleware - IBC Documentation\">\u003cmeta data-mint-head property=\"og:description\" content=\"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"IBC Documentation\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://ibc-docs.mintlify.app/_mintlify/api/og/v2?division=Middleware\u0026amp;title=Create+a+custom+IBC+middleware\u0026amp;description=IBC+middleware+will+wrap+over+an+underlying+IBC+application+%28a+base+application+or+downstream+middleware%29+and+sits+between+core+IBC+and+the+base+application.\u0026amp;theme=83cf7571a86e66a217192c59\u0026amp;signature=b91b52a5dd844039c2567228e62e9aca86f8d8b391c91df4fc1c344e2c9e1dd1\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Create a custom IBC middleware - IBC Documentation\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://ibc-docs.mintlify.app/_mintlify/api/og/v2?division=Middleware\u0026amp;title=Create+a+custom+IBC+middleware\u0026amp;description=IBC+middleware+will+wrap+over+an+underlying+IBC+application+%28a+base+application+or+downstream+middleware%29+and+sits+between+core+IBC+and+the+base+application.\u0026amp;theme=83cf7571a86e66a217192c59\u0026amp;signature=b91b52a5dd844039c2567228e62e9aca86f8d8b391c91df4fc1c344e2c9e1dd1\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/ibc-docs/M8QbcV1CzT5u-Qmv/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"IBC Documentation\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#000000\">\u003clink data-mint-head rel=\"canonical\" href=\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/ibc-go/latest/ibc/middleware/develop.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://ibc-docs.mintlify.dev/#organization\",\"name\":\"IBC Documentation\",\"url\":\"https://ibc-docs.mintlify.dev\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/ibc-docs/_IzGrVOELf0DsHtq/mintlify/assets/brand/ibc-wordmark-dark.svg?fit=max\u0026auto=format\u0026n=_IzGrVOELf0DsHtq\u0026q=85\u0026s=dd69509f8e278637cefba78620bc6f19\"}},{\"@type\":\"WebSite\",\"@id\":\"https://ibc-docs.mintlify.dev/docs#website\",\"name\":\"IBC Documentation\",\"url\":\"https://ibc-docs.mintlify.dev/docs\",\"publisher\":{\"@id\":\"https://ibc-docs.mintlify.dev/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop#webpage\",\"url\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop\",\"name\":\"Create a custom IBC middleware\",\"description\":\"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.\",\"dateModified\":\"2026-10-29T18:43:19.174Z\",\"isPartOf\":{\"@id\":\"https://ibc-docs.mintlify.dev/docs#website\"},\"breadcrumb\":{\"@id\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"IBC Core\",\"item\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/overview\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Middleware\",\"item\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/overview\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Create a custom IBC middleware\",\"item\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop\"}]},{\"@type\":[\"Article\",\"TechArticle\"],\"@id\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop#article\",\"headline\":\"Create a custom IBC middleware\",\"name\":\"Create a custom IBC middleware\",\"description\":\"IBC middleware will wrap over an underlying IBC application (a base application or downstream middleware) and sits between core IBC and the base application.\",\"url\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop\",\"mainEntityOfPage\":{\"@id\":\"https://ibc-docs.mintlify.dev/docs/ibc-go/latest/ibc/middleware/develop#webpage\"},\"dateModified\":\"2026-10-29T18:43:19.174Z\",\"publisher\":{\"@id\":\"https://ibc-docs.mintlify.dev/#organization\"},\"isPartOf\":{\"@id\":\"https://ibc-docs.mintlify.dev/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"IBC Documentation\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"IBC Documentation","nav":{"global":null,"tabs":[{"tab":"Learn","pages":[{"title":"Learn","href":""}]},{"tab":"IBC CLI","pages":[{"title":"IBC CLI","href":"/ibc/05-ibc-cli/01-overview"}]},{"tab":"IBC-Solidity","pages":[{"title":"IBC-Solidity","href":"/ibc/06-ibc-solidity-contracts/01-overview"}]},{"tab":"IBC-Go","versions":[{"version":"latest","groups":[{"group":"Introduction","icon":"book-open","pages":[{"title":"IBC Documentation","href":"/ibc-go/latest/intro"}]},{"group":"IBC Core","icon":"box","pages":[{"title":"Overview","href":"/ibc-go/latest/ibc/overview"},{"group":"Core Concepts","icon":"lightbulb","pages":[{"title":"Best Practices","href":"/ibc-go/latest/ibc/best-practices"},{"title":"Integration","href":"/ibc-go/latest/ibc/integration"},{"title":"Permissioning","href":"/ibc-go/latest/ibc/permissioning"},{"title":"Relayer","href":"/ibc-go/latest/ibc/relayer"}]},{"group":"Apps","icon":"app-window","pages":[{"title":"IBC v2 Applications","href":"/ibc-go/latest/ibc/apps/ibcv2apps"},{"title":"IBC Applications","href":"/ibc-go/latest/ibc/apps/apps"},{"title":"Implement IBCModule interface and callbacks","href":"/ibc-go/latest/ibc/apps/ibcmodule"},{"title":"Bind ports","href":"/ibc-go/latest/ibc/apps/bindports"},{"title":"Keeper","href":"/ibc-go/latest/ibc/apps/keeper"},{"title":"Define packets and acks","href":"/ibc-go/latest/ibc/apps/packets_acks"},{"title":"Routing","href":"/ibc-go/latest/ibc/apps/routing"},{"title":"Custom Address Codec","href":"/ibc-go/latest/ibc/apps/address-codec"}]},{"group":"Middleware","icon":"layers","pages":[{"title":"IBC middleware","description":null,"href":"/ibc-go/latest/ibc/middleware/overview"},{"title":"Create a custom IBC middleware","href":"/ibc-go/latest/ibc/middleware/develop"},{"title":"Create and integrate IBC v2 middleware","description":"1. Create a custom IBC v2 middleware 2. Implement IBCModule interface 3. WriteAckWrapper 4. Integrate IBC v2 Middleware 5. Security Model 6. Design Principles","href":"/ibc-go/latest/ibc/middleware/developIBCv2"},{"title":"Integrating IBC middleware into a chain","href":"/ibc-go/latest/ibc/middleware/integration"}]},{"group":"Upgrades","icon":"arrow-up","pages":[{"title":"Upgrading IBC Chains Overview","href":"/ibc-go/latest/ibc/upgrades/intro"},{"title":"How to Upgrade IBC Chains and their Clients","href":"/ibc-go/latest/ibc/upgrades/quick-guide"},{"title":"IBC Client Developer Guide to Upgrades","href":"/ibc-go/latest/ibc/upgrades/developer-guide"},{"title":"Genesis Restart Upgrades","href":"/ibc-go/latest/ibc/upgrades/genesis-restart"}]}]},{"group":"IBC Migrations","icon":"arrow-right-left","pages":[{"group":"Version Upgrades","icon":"git-branch","pages":[{"title":"IBC-Go v11.0 to v11.1","href":"/ibc-go/latest/migrations/v11-to-v11-1"},{"title":"IBC-Go v10 to v11.1","href":"/ibc-go/latest/migrations/v10-to-v11-1"},{"title":"IBC-Go v10 to v11","href":"/ibc-go/latest/migrations/v10-to-v11"},{"title":"IBC-Go v8.1 to v10","href":"/ibc-go/latest/migrations/v8_1-to-v10"},{"title":"IBC-Go v8 to v8.1","href":"/ibc-go/latest/migrations/v8-to-v8_1"},{"title":"IBC-Go v7 to v8","href":"/ibc-go/latest/migrations/v7-to-v8"},{"title":"IBC-Go v7.2 to v7.3","href":"/ibc-go/latest/migrations/v7_2-to-v7_3"},{"title":"IBC-Go v7 to v7.1","href":"/ibc-go/latest/migrations/v7-to-v7_1"},{"title":"IBC-Go v6 to v7","href":"/ibc-go/latest/migrations/v6-to-v7"},{"title":"IBC-Go v5 to v6","href":"/ibc-go/latest/migrations/v5-to-v6"},{"title":"IBC-Go v4 to v5","href":"/ibc-go/latest/migrations/v4-to-v5"},{"title":"IBC-Go v3 to v4","href":"/ibc-go/latest/migrations/v3-to-v4"},{"title":"IBC-Go v2 to v3","href":"/ibc-go/latest/migrations/v2-to-v3"},{"title":"IBC-Go v1 to v2","href":"/ibc-go/latest/migrations/v1-to-v2"}]},{"group":"Additional Migration Guides","icon":"map","pages":[{"title":"SDK v0.43 to IBC-Go v1","href":"/ibc-go/latest/migrations/sdk-to-v1"},{"title":"Support transfer of coins whose base denom contains slashes","href":"/ibc-go/latest/migrations/support-denoms-with-slashes"},{"title":"Support the new StackBuilder primitive for Wiring Middlewares in the chain application","href":"/ibc-go/latest/migrations/support-stackbuilder"}]}]},{"group":"IBC Light Clients","icon":"shield-check","pages":[{"group":"Developer Guide","icon":"code","pages":[{"title":"Overview","href":"/ibc-go/latest/light-clients/developer-guide/overview"},{"title":"Light Client Module interface","href":"/ibc-go/latest/light-clients/developer-guide/light-client-module"},{"title":"Client State interface","href":"/ibc-go/latest/light-clients/developer-guide/client-state"},{"title":"Consensus State interface","href":"/ibc-go/latest/light-clients/developer-guide/consensus-state"},{"title":"Handling Updates and Misbehaviour","href":"/ibc-go/latest/light-clients/developer-guide/updates-and-misbehaviour"},{"title":"Handling Upgrades","href":"/ibc-go/latest/light-clients/developer-guide/upgrades"},{"title":"Existence/Non-Existence Proofs","href":"/ibc-go/latest/light-clients/developer-guide/proofs"},{"title":"Handling Proposals","href":"/ibc-go/latest/light-clients/developer-guide/proposals"},{"title":"Setup","href":"/ibc-go/latest/light-clients/developer-guide/setup"},{"title":"Governance Proposals","href":"/ibc-go/latest/light-clients/proposals"}]},{"group":"Attestation","icon":"badge-check","pages":[{"title":"The attestation light client","href":"/ibc-go/latest/light-clients/attestation/attestation-light-client"}]},{"group":"Localhost","icon":"monitor","pages":[{"title":"Overview","href":"/ibc-go/latest/light-clients/localhost/overview"},{"title":"Integration","href":"/ibc-go/latest/light-clients/localhost/integration"},{"title":"ClientState","href":"/ibc-go/latest/light-clients/localhost/client-state"},{"title":"Connection","href":"/ibc-go/latest/light-clients/localhost/connection"},{"title":"State Verification","href":"/ibc-go/latest/light-clients/localhost/state-verification"}]},{"group":"Solo Machine","icon":"cpu","pages":[{"title":"Solomachine","href":"/ibc-go/latest/light-clients/solomachine/solomachine"},{"title":"Concepts","href":"/ibc-go/latest/light-clients/solomachine/concepts"},{"title":"State","href":"/ibc-go/latest/light-clients/solomachine/state"},{"title":"State Transitions","href":"/ibc-go/latest/light-clients/solomachine/state_transitions"}]},{"group":"Tendermint","icon":"boxes","pages":[{"title":"Overview","href":"/ibc-go/latest/light-clients/tendermint/overview"}]},{"group":"WASM","icon":"binary","pages":[{"title":"Overview","href":"/ibc-go/latest/light-clients/wasm/overview"},{"title":"Concepts","href":"/ibc-go/latest/light-clients/wasm/concepts"},{"title":"Integration","href":"/ibc-go/latest/light-clients/wasm/integration"},{"title":"Messages","href":"/ibc-go/latest/light-clients/wasm/messages"},{"title":"Governance","href":"/ibc-go/latest/light-clients/wasm/governance"},{"title":"Events","href":"/ibc-go/latest/light-clients/wasm/events"},{"title":"Contracts","href":"/ibc-go/latest/light-clients/wasm/contracts"},{"title":"Client","href":"/ibc-go/latest/light-clients/wasm/client"},{"title":"Migrations","href":"/ibc-go/latest/light-clients/wasm/migrations"}]}]},{"group":"IBC Apps","icon":"blocks","pages":[{"title":"General Message Passing (GMP)","href":"/ibc-go/latest/apps/gmp"},{"group":"Interchain Accounts","icon":"users","pages":[{"title":"Overview","href":"/ibc-go/latest/apps/interchain-accounts/overview"},{"title":"Development Use Cases","href":"/ibc-go/latest/apps/interchain-accounts/development"},{"title":"Authentication Modules","href":"/ibc-go/latest/apps/interchain-accounts/auth-modules"},{"title":"Integration","href":"/ibc-go/latest/apps/interchain-accounts/integration"},{"title":"Messages","href":"/ibc-go/latest/apps/interchain-accounts/messages"},{"title":"Parameters","href":"/ibc-go/latest/apps/interchain-accounts/parameters"},{"title":"Transaction Encoding","href":"/ibc-go/latest/apps/interchain-accounts/tx-encoding"},{"title":"Client","href":"/ibc-go/latest/apps/interchain-accounts/client"},{"title":"Active Channels","href":"/ibc-go/latest/apps/interchain-accounts/active-channels"},{"group":"Legacy","icon":"archive","pages":[{"title":"Authentication Modules","href":"/ibc-go/latest/apps/interchain-accounts/legacy/auth-modules"},{"title":"Integration","href":"/ibc-go/latest/apps/interchain-accounts/legacy/integration"},{"title":"Keeper API","href":"/ibc-go/latest/apps/interchain-accounts/legacy/keeper-api"}]}]},{"group":"Transfer","icon":"send","pages":[{"title":"Overview","href":"/ibc-go/latest/apps/transfer/overview"},{"title":"State","href":"/ibc-go/latest/apps/transfer/state"},{"title":"State Transitions","href":"/ibc-go/latest/apps/transfer/state-transitions"},{"title":"Messages","href":"/ibc-go/latest/apps/transfer/messages"},{"title":"Events","href":"/ibc-go/latest/apps/transfer/events"},{"title":"Metrics","href":"/ibc-go/latest/apps/transfer/metrics"},{"title":"Params","href":"/ibc-go/latest/apps/transfer/params"},{"title":"Authorizations","href":"/ibc-go/latest/apps/transfer/authorizations"},{"title":"Client","href":"/ibc-go/latest/apps/transfer/client"},{"title":"IBC v2 Transfer","href":"/ibc-go/latest/apps/transfer/IBCv2-transfer"}]}]},{"group":"IBC Middleware","icon":"layers","pages":[{"group":"Callbacks","icon":"repeat","pages":[{"title":"Overview","href":"/ibc-go/latest/middleware/callbacks/overview"},{"title":"Integration","href":"/ibc-go/latest/middleware/callbacks/integration"},{"title":"Interfaces","href":"/ibc-go/latest/middleware/callbacks/interfaces"},{"title":"Events","href":"/ibc-go/latest/middleware/callbacks/events"},{"title":"End Users","href":"/ibc-go/latest/middleware/callbacks/end-users"},{"title":"Gas Management","href":"/ibc-go/latest/middleware/callbacks/gas"},{"title":"Callbacks with IBC v2","href":"/ibc-go/latest/middleware/callbacks/callbacks-IBCv2"}]},{"group":"Packet Forward Middleware","icon":"forward","pages":[{"title":"Overview","href":"/ibc-go/latest/middleware/packet-forward-middleware/overview"},{"title":"Integration","href":"/ibc-go/latest/middleware/packet-forward-middleware/integration"},{"title":"Example Flows","href":"/ibc-go/latest/middleware/packet-forward-middleware/example-usage"}]},{"group":"Rate Limit Middleware","icon":"gauge","pages":[{"title":"Overview","href":"/ibc-go/latest/middleware/rate-limit-middleware/overview"},{"title":"Integration","href":"/ibc-go/latest/middleware/rate-limit-middleware/integration"},{"title":"Setting Rate Limits","href":"/ibc-go/latest/middleware/rate-limit-middleware/setting-limits"},{"title":"Migration","href":"/ibc-go/latest/middleware/rate-limit-middleware/migration"}]}]},{"group":"Security","icon":"lock","pages":[{"title":"Security Audits","href":"/ibc-go/latest/security-audits"}]},{"group":"Architecture Decision Records","icon":"scroll-text","pages":[{"title":"Architecture Decision Records (ADR)","href":"/ibc-go/latest/architecture/README"},{"title":"ADR 001: Coin Source Tracing","href":"/ibc-go/latest/architecture/adr-001-coin-source-tracing"},{"title":"ADR 002: Go Module Versioning","href":"/ibc-go/latest/architecture/adr-002-go-module-versioning"},{"title":"ADR 003: ICS-27 Acknowledgement Format","href":"/ibc-go/latest/architecture/adr-003-ics27-acknowledgement"},{"title":"ADR 004: Lock Fee Module Upon Escrow Out Of Balance","href":"/ibc-go/latest/architecture/adr-004-ics29-lock-fee-module"},{"title":"ADR 005: UpdateClient Events ClientState Consensus Heights","href":"/ibc-go/latest/architecture/adr-005-consensus-height-events"},{"title":"ADR 006: 02-Client Refactor","href":"/ibc-go/latest/architecture/adr-006-02-client-refactor"},{"title":"ADR 007: Solo Machine Sign Bytes","href":"/ibc-go/latest/architecture/adr-007-solomachine-signbytes"},{"title":"ADR 008: Callback to IBC Actors","href":"/ibc-go/latest/architecture/adr-008-app-caller-cbs"},{"title":"ADR 009: ICS27 Message Server Addition","href":"/ibc-go/latest/architecture/adr-009-v6-ics27-msgserver"},{"title":"ADR 010: IBC Light Clients As SDK Modules","href":"/ibc-go/latest/architecture/adr-010-light-clients-as-sdk-modules"},{"title":"ADR 011: ICS-20 Transfer State Entry For Total Amount Of Tokens In Escrow","href":"/ibc-go/latest/architecture/adr-011-transfer-total-escrow-state-entry"},{"title":"ADR 015: IBC Packet Receiver","href":"/ibc-go/latest/architecture/adr-015-ibc-packet-receiver"},{"title":"ADR 025: IBC Passive Channels","href":"/ibc-go/latest/architecture/adr-025-ibc-passive-channels"},{"title":"ADR 026: IBC Client Recovery Mechanisms","href":"/ibc-go/latest/architecture/adr-026-ibc-client-recovery-mechanisms"},{"title":"ADR 27: Add Support For Wasm Based Light Client","href":"/ibc-go/latest/architecture/adr-027-ibc-wasm"}]},{"group":"Changelog","icon":"rotate-ccw","pages":[{"title":"Changelog","mode":"wide","href":"/ibc-go/latest/changelog/release-notes"}]},{"group":"Repositories","icon":"folder-git-2","pages":[{"title":"cosmos/ibc-go","url":"https://github.com/cosmos/ibc-go","icon":"github","href":"/ibc-go/latest/repos/go-ibc-go"}]}]},{"version":"v10.1.x","pages":[{"title":"v10.1.x","href":"/ibc-go/v10.1.x/ibc/middleware/develop"}]}]},{"tab":"Specification","pages":[{"title":"Specification","href":"/ibc/spec/ics-001-ics-standard/README"}]}]},"title":"Create a custom IBC middleware - IBC Documentation","buildId":"dpl_DGmhKsAzJdVqypJzon18vViniWRY","deploymentId":"dpl_DGmhKsAzJdVqypJzon18vViniWRY","dynamics":[],"chunks":[]}