From b27e7127ebec575bcad1d6ba24972456e1a09d66 Mon Sep 17 00:00:00 2001 From: sampocs Date: Mon, 15 Apr 2024 13:47:10 -0500 Subject: [PATCH] added ibc-hooks (#1173) --- app/app.go | 106 +++++++++++++++++++------------ app/upgrades.go | 5 ++ go.mod | 7 +- go.sum | 10 +-- x/autopilot/types/autopilot.go | 9 +-- x/autopilot/types/parser.go | 19 ++++-- x/autopilot/types/parser_test.go | 17 ++++- 7 files changed, 117 insertions(+), 56 deletions(-) diff --git a/app/app.go b/app/app.go index bae1ae10a6..1bf916b691 100644 --- a/app/app.go +++ b/app/app.go @@ -85,6 +85,9 @@ import ( "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7/packetforward" packetforwardkeeper "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7/packetforward/keeper" packetforwardtypes "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7/packetforward/types" + ibchooks "github.com/cosmos/ibc-apps/modules/ibc-hooks/v7" + ibchookskeeper "github.com/cosmos/ibc-apps/modules/ibc-hooks/v7/keeper" + ibchookstypes "github.com/cosmos/ibc-apps/modules/ibc-hooks/v7/types" ica "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts" icacontroller "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller" icacontrollerkeeper "github.com/cosmos/ibc-go/v7/modules/apps/27-interchain-accounts/controller/keeper" @@ -223,6 +226,7 @@ var ( staketia.AppModuleBasic{}, stakedym.AppModuleBasic{}, wasm.AppModuleBasic{}, + ibchooks.AppModuleBasic{}, ) // module account permissions @@ -306,6 +310,11 @@ type StrideApp struct { PacketForwardKeeper *packetforwardkeeper.Keeper WasmKeeper wasmkeeper.Keeper ContractKeeper *wasmkeeper.PermissionedKeeper + IBCHooksKeeper ibchookskeeper.Keeper + + // Middleware for IBCHooks + Ics20WasmHooks *ibchooks.WasmHooks + HooksICS4Wrapper ibchooks.ICS4Middleware // make scoped keepers public for test purposes ScopedIBCKeeper capabilitykeeper.ScopedKeeper @@ -381,6 +390,7 @@ func NewStrideApp( staketiatypes.StoreKey, stakedymtypes.StoreKey, wasmtypes.StoreKey, + ibchookstypes.StoreKey, ) tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey) memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey) @@ -458,13 +468,13 @@ func NewStrideApp( stakingtypes.NewMultiStakingHooks(app.DistrKeeper.Hooks(), app.ClaimKeeper.Hooks()), ) - // ... other modules keepers - + // Add ICS Consumer Keeper app.ConsumerKeeper = ccvconsumerkeeper.NewNonZeroKeeper( appCodec, keys[ccvconsumertypes.StoreKey], app.GetSubspace(ccvconsumertypes.ModuleName), ) + // Create IBC Keeper app.IBCKeeper = ibckeeper.NewKeeper( appCodec, @@ -475,6 +485,14 @@ func NewStrideApp( scopedIBCKeeper, ) + // Create IBC Hooks Keeper (must be defined after the wasmKeeper is created) + app.IBCHooksKeeper = ibchookskeeper.NewKeeper( + keys[ibchookstypes.StoreKey], + ) + wasmHooks := ibchooks.NewWasmHooks(&app.IBCHooksKeeper, nil, AccountAddressPrefix) // the contract keeper is set later + app.Ics20WasmHooks = &wasmHooks + app.Ics20WasmHooks.ContractKeeper = &app.WasmKeeper // wasm keeper initialized below + // Create Ratelimit Keeper scopedratelimitKeeper := app.CapabilityKeeper.ScopeToModule(ratelimittypes.ModuleName) app.ScopedratelimitKeeper = scopedratelimitKeeper @@ -489,6 +507,13 @@ func NewStrideApp( ) ratelimitModule := ratelimit.NewAppModule(appCodec, app.RatelimitKeeper) + // Create the ICS4 wrapper which routes up the stack from ibchooks -> ratelimit + // (see full stack definition below) + app.HooksICS4Wrapper = ibchooks.NewICS4Middleware( + app.RatelimitKeeper, // ICS4Wrapper + app.Ics20WasmHooks, + ) + // Initialize the packet forward middleware Keeper // It's important to note that the PFM Keeper must be initialized before the Transfer Keeper app.PacketForwardKeeper = packetforwardkeeper.NewKeeper( @@ -498,7 +523,7 @@ func NewStrideApp( app.IBCKeeper.ChannelKeeper, app.DistrKeeper, app.BankKeeper, - app.RatelimitKeeper, // ICS4Wrapper + app.HooksICS4Wrapper, // ICS4Wrapper authtypes.NewModuleAddress(govtypes.ModuleName).String(), ) @@ -517,8 +542,36 @@ func NewStrideApp( // Set the TransferKeeper reference in the PacketForwardKeeper app.PacketForwardKeeper.SetTransferKeeper(app.TransferKeeper) - transferModule := transfer.NewAppModule(app.TransferKeeper) - transferIBCModule := transfer.NewIBCModule(app.TransferKeeper) + // Add wasm keeper (must be after IBCKeeper and TransferKeeper) + wasmCapabilities := "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4" + wasmDir := filepath.Join(homePath, "wasm") + wasmConfig, err := wasm.ReadWasmConfig(appOpts) + if err != nil { + panic(fmt.Sprintf("error while reading wasm config: %s", err)) + } + + scopedWasmKeeper := app.CapabilityKeeper.ScopeToModule(wasmtypes.ModuleName) + app.WasmKeeper = wasmkeeper.NewKeeper( + appCodec, + keys[wasmtypes.StoreKey], + app.AccountKeeper, + app.BankKeeper, + app.StakingKeeper, + distrkeeper.NewQuerier(app.DistrKeeper), + app.IBCKeeper.ChannelKeeper, // ICS4Wrapper + app.IBCKeeper.ChannelKeeper, + &app.IBCKeeper.PortKeeper, + scopedWasmKeeper, + app.TransferKeeper, + app.MsgServiceRouter(), + app.GRPCQueryRouter(), + wasmDir, + wasmConfig, + wasmCapabilities, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + wasmOpts..., + ) + app.ContractKeeper = wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper) // Create evidence Keeper for to register the IBC light client misbehaviour evidence route evidenceKeeper := evidencekeeper.NewKeeper( @@ -660,39 +713,6 @@ func NewStrideApp( app.AccountKeeper, app.BankKeeper, app.DistrKeeper, app.StakingKeeper, ) - // Add wasm keeper - wasmCapabilities := "iterator,staking,stargate,cosmwasm_1_1,cosmwasm_1_2,cosmwasm_1_3,cosmwasm_1_4" - wasmDir := filepath.Join(homePath, "wasm") - wasmConfig, err := wasm.ReadWasmConfig(appOpts) - if err != nil { - panic(fmt.Sprintf("error while reading wasm config: %s", err)) - } - - scopedWasmKeeper := app.CapabilityKeeper.ScopeToModule(wasmtypes.ModuleName) - - app.WasmKeeper = wasmkeeper.NewKeeper( - appCodec, - keys[wasmtypes.StoreKey], - app.AccountKeeper, - app.BankKeeper, - app.StakingKeeper, - distrkeeper.NewQuerier(app.DistrKeeper), - app.IBCKeeper.ChannelKeeper, // ICS4Wrapper - app.IBCKeeper.ChannelKeeper, - &app.IBCKeeper.PortKeeper, - scopedWasmKeeper, - app.TransferKeeper, - app.MsgServiceRouter(), - app.GRPCQueryRouter(), - wasmDir, - wasmConfig, - wasmCapabilities, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), - wasmOpts..., - ) - - app.ContractKeeper = wasmkeeper.NewDefaultPermissionKeeper(app.WasmKeeper) - // Register Gov (must be registered after stakeibc) govRouter := govtypesv1beta1.NewRouter() govRouter.AddRoute(govtypes.RouterKey, govtypesv1beta1.ProposalHandler). @@ -781,12 +801,13 @@ func NewStrideApp( // - staketia // - stakedym // - ratelimit + // - ibchooks // - pfm // - transfer // - base app // Note: Traffic up the stack does not pass through records or autopilot, // as defined via the ICS4Wrappers of each keeper - var transferStack porttypes.IBCModule = transferIBCModule + var transferStack porttypes.IBCModule = transfer.NewIBCModule(app.TransferKeeper) transferStack = packetforward.NewIBCMiddleware( transferStack, app.PacketForwardKeeper, @@ -794,6 +815,7 @@ func NewStrideApp( packetforwardkeeper.DefaultForwardTransferPacketTimeoutTimestamp, // forward timeout packetforwardkeeper.DefaultRefundTransferPacketTimeoutTimestamp, // refund timeout ) + transferStack = ibchooks.NewIBCMiddleware(transferStack, &app.HooksICS4Wrapper) transferStack = ratelimit.NewIBCMiddleware(app.RatelimitKeeper, transferStack) transferStack = staketia.NewIBCMiddleware(app.StaketiaKeeper, transferStack) transferStack = stakedym.NewIBCMiddleware(app.StakedymKeeper, transferStack) @@ -850,7 +872,8 @@ func NewStrideApp( // technically, app.GetSubspace(packetforwardtypes.ModuleName) will never be run https://github.com/cosmos/ibc-apps/issues/146#issuecomment-1839242144 packetforward.NewAppModule(app.PacketForwardKeeper, app.GetSubspace(packetforwardtypes.ModuleName)), wasm.NewAppModule(appCodec, &app.WasmKeeper, app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.BaseApp.MsgServiceRouter(), app.GetSubspace(wasmtypes.ModuleName)), - transferModule, + ibchooks.NewAppModule(app.AccountKeeper), + transfer.NewAppModule(app.TransferKeeper), // monitoringModule, stakeibcModule, epochsModule, @@ -906,6 +929,7 @@ func NewStrideApp( staketiatypes.ModuleName, stakedymtypes.ModuleName, wasmtypes.ModuleName, + ibchookstypes.ModuleName, ) app.mm.SetOrderEndBlockers( @@ -944,6 +968,7 @@ func NewStrideApp( staketiatypes.ModuleName, stakedymtypes.ModuleName, wasmtypes.ModuleName, + ibchookstypes.ModuleName, ) // NOTE: The genutils module must occur after staking so that pools are @@ -987,6 +1012,7 @@ func NewStrideApp( staketiatypes.ModuleName, stakedymtypes.ModuleName, wasmtypes.ModuleName, + ibchookstypes.ModuleName, ) app.mm.RegisterInvariants(app.CrisisKeeper) diff --git a/app/upgrades.go b/app/upgrades.go index 5fcdf47cc1..90e28a0d33 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -13,6 +13,7 @@ import ( crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" packetforwardtypes "github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7/packetforward/types" + ibchookstypes "github.com/cosmos/ibc-apps/modules/ibc-hooks/v7/types" consumertypes "github.com/cosmos/interchain-security/v4/x/ccv/consumer/types" evmosvestingtypes "github.com/evmos/vesting/x/vesting/types" @@ -347,6 +348,10 @@ func (app *StrideApp) setupUpgradeHandlers(appOpts servertypes.AppOptions) { storeUpgrades = &storetypes.StoreUpgrades{ Added: []string{wasmtypes.ModuleName, stakedymtypes.ModuleName}, } + case "v22": + storeUpgrades = &storetypes.StoreUpgrades{ + Added: []string{ibchookstypes.ModuleName}, + } } if storeUpgrades != nil { diff --git a/go.mod b/go.mod index 4fb4a64cf2..8ca1491ae0 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,8 @@ require ( github.com/cosmos/cosmos-sdk v0.47.10 github.com/cosmos/gogoproto v1.4.10 github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3-0.20240228213828-cce7f56d000b - github.com/cosmos/ibc-go/v7 v7.3.1 + github.com/cosmos/ibc-apps/modules/ibc-hooks/v7 v7.0.0-20240403143657-8e64543c87e0 + github.com/cosmos/ibc-go/v7 v7.4.0 github.com/cosmos/ics23/go v0.10.0 github.com/cosmos/interchain-security/v4 v4.0.0 github.com/evmos/vesting v0.0.0-20230818101748-9ea561e4529c @@ -40,13 +41,13 @@ require ( cloud.google.com/go/iam v1.1.5 // indirect cloud.google.com/go/storage v1.30.1 // indirect cosmossdk.io/api v0.3.1 // indirect - cosmossdk.io/core v0.5.1 // indirect + cosmossdk.io/core v0.6.1 // indirect cosmossdk.io/depinject v1.0.0-alpha.4 // indirect cosmossdk.io/log v1.3.1 // indirect cosmossdk.io/tools/rosetta v0.2.1 // indirect filippo.io/edwards25519 v1.0.0 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect - github.com/99designs/keyring v1.2.1 // indirect + github.com/99designs/keyring v1.2.2 // indirect github.com/ChainSafe/go-schnorrkel v1.0.0 // indirect github.com/CosmWasm/wasmvm v1.5.2 // indirect github.com/armon/go-metrics v0.4.1 // indirect diff --git a/go.sum b/go.sum index c5be1e84b1..97d82f6330 100644 --- a/go.sum +++ b/go.sum @@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.3.1 h1:NNiOclKRR0AOlO4KIqeaG6PS6kswOMhHD0ir0SscNXE= cosmossdk.io/api v0.3.1/go.mod h1:DfHfMkiNA2Uhy8fj0JJlOCYOBp4eWUUJ1te5zBGNyIw= -cosmossdk.io/core v0.5.1 h1:vQVtFrIYOQJDV3f7rw4pjjVqc1id4+mE0L9hHP66pyI= -cosmossdk.io/core v0.5.1/go.mod h1:KZtwHCLjcFuo0nmDc24Xy6CRNEL9Vl/MeimQ2aC7NLE= +cosmossdk.io/core v0.6.1 h1:OBy7TI2W+/gyn2z40vVvruK3di+cAluinA6cybFbE7s= +cosmossdk.io/core v0.6.1/go.mod h1:g3MMBCBXtxbDWBURDVnJE7XML4BG5qENhs0gzkcpuFA= cosmossdk.io/depinject v1.0.0-alpha.4 h1:PLNp8ZYAMPTUKyG9IK2hsbciDWqna2z1Wsl98okJopc= cosmossdk.io/depinject v1.0.0-alpha.4/go.mod h1:HeDk7IkR5ckZ3lMGs/o91AVUc7E596vMaOmslGFM3yU= cosmossdk.io/errors v1.0.1 h1:bzu+Kcr0kS/1DuPBtUFdWjzLqyUuCiyHjyJB6srBV/0= @@ -354,8 +354,10 @@ github.com/cosmos/iavl v0.20.1 h1:rM1kqeG3/HBT85vsZdoSNsehciqUQPWrR4BYmqE2+zg= github.com/cosmos/iavl v0.20.1/go.mod h1:WO7FyvaZJoH65+HFOsDir7xU9FWk2w9cHXNW1XHcl7A= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3-0.20240228213828-cce7f56d000b h1:VwhHRRIPdMshBMb2TP7xrkY4Ee8CJWsHZvucYeJ56no= github.com/cosmos/ibc-apps/middleware/packet-forward-middleware/v7 v7.1.3-0.20240228213828-cce7f56d000b/go.mod h1:UvDmcGIWJPIytq+Q78/ff5NTOsuX/7IrNgEugTW5i0s= -github.com/cosmos/ibc-go/v7 v7.3.1 h1:bil1IjnHdyWDASFYKfwdRiNtFP6WK3osW7QFEAgU4I8= -github.com/cosmos/ibc-go/v7 v7.3.1/go.mod h1:wvx4pPBofe5ZdMNV3OFRxSI4auEP5Qfqf8JXLLNV04g= +github.com/cosmos/ibc-apps/modules/ibc-hooks/v7 v7.0.0-20240403143657-8e64543c87e0 h1:obD+CSx+aXpMEUWHLyMkWEcxLuYAcxvQaIXTwjjh3qI= +github.com/cosmos/ibc-apps/modules/ibc-hooks/v7 v7.0.0-20240403143657-8e64543c87e0/go.mod h1:JwHFbo1oX/ht4fPpnPvmhZr+dCkYK1Vihw+vZE9umR4= +github.com/cosmos/ibc-go/v7 v7.4.0 h1:8FqYMptvksgMvlbN4UW9jFxTXzsPyfAzEZurujXac8M= +github.com/cosmos/ibc-go/v7 v7.4.0/go.mod h1:L/KaEhzV5TGUCTfGysVgMBQtl5Dm7hHitfpk+GIeoAo= github.com/cosmos/ics23/go v0.10.0 h1:iXqLLgp2Lp+EdpIuwXTYIQU+AiHj9mOC2X9ab++bZDM= github.com/cosmos/ics23/go v0.10.0/go.mod h1:ZfJSmng/TBNTBkFemHHHj5YY7VAU/MBU980F4VU1NG0= github.com/cosmos/interchain-security/v4 v4.0.0 h1:6olP/UIrvckLgDpzJLAqPjmzo3+AoHjMM1TRrcrpME0= diff --git a/x/autopilot/types/autopilot.go b/x/autopilot/types/autopilot.go index 44e8eaf67b..e599e84ace 100644 --- a/x/autopilot/types/autopilot.go +++ b/x/autopilot/types/autopilot.go @@ -8,10 +8,10 @@ import ( ) // RawPacketMetadata defines the raw JSON memo that's used in an autopilot transfer -// The PFM forward key is also used here to validate that the packet is not trying -// to use autopilot and PFM at the same time -// As a result, only the forward key is needed, cause the actual parsing of the PFM -// packet will occur in the PFM module +// The PFM forward key and wasm keys are also used here to validate that the packet +// was not trying to use more than one of autopilot PFM, and wasm at the same time +// As a result, only the key is needed, cause the actual parsing of the PFM/wasm +// packet will occur in the respective module type RawPacketMetadata struct { Autopilot *struct { Receiver string `json:"receiver"` @@ -19,6 +19,7 @@ type RawPacketMetadata struct { Claim *ClaimPacketMetadata `json:"claim,omitempty"` } `json:"autopilot"` Forward *interface{} `json:"forward"` + Wasm *interface{} `json:"wasm"` } // AutopilotActionMetadata stores the metadata that's specific to the autopilot action diff --git a/x/autopilot/types/parser.go b/x/autopilot/types/parser.go index c7770c5efb..838eda5a33 100644 --- a/x/autopilot/types/parser.go +++ b/x/autopilot/types/parser.go @@ -66,10 +66,21 @@ func ParseAutopilotMetadata(metadata string) (*AutopilotMetadata, error) { return nil, nil } - // Packets cannot be used for both autopilot and PFM at the same time - // If both fields were provided, reject the packet - if raw.Autopilot != nil && raw.Forward != nil { - return nil, errorsmod.Wrapf(ErrInvalidPacketMetadata, "autopilot and pfm cannot both be used in the same packet") + // Packets cannot be used for more than one of autopilot, pfm, or wasmhooks at the same time + // If more than one module key was provided, reject the packet + middlewareModulesEnabled := 0 + if raw.Autopilot != nil { + middlewareModulesEnabled++ + } + if raw.Forward != nil { + middlewareModulesEnabled++ + } + if raw.Wasm != nil { + middlewareModulesEnabled++ + } + if middlewareModulesEnabled > 1 { + return nil, errorsmod.Wrapf(ErrInvalidPacketMetadata, + "only one of autopilot, pfm, and wasm can both be used in the same packet") } // If no forwarding logic was used for autopilot, return nil to indicate that diff --git a/x/autopilot/types/parser_test.go b/x/autopilot/types/parser_test.go index b93945efa3..40d51a095e 100644 --- a/x/autopilot/types/parser_test.go +++ b/x/autopilot/types/parser_test.go @@ -148,7 +148,22 @@ func TestParsePacketMetadata(t *testing.T) { { name: "both autopilot and pfm in the memo", metadata: `{"autopilot": {}, "forward": {}}`, - expectedErr: "autopilot and pfm cannot both be used in the same packet", + expectedErr: "only one of autopilot, pfm, and wasm can both be used in the same packet", + }, + { + name: "both autopilot and wasm in the memo", + metadata: `{"autopilot": {}, "wasm": {}}`, + expectedErr: "only one of autopilot, pfm, and wasm can both be used in the same packet", + }, + { + name: "both pfm and wasm in the memo", + metadata: `{"forward": {}, "wasm": {}}`, + expectedErr: "only one of autopilot, pfm, and wasm can both be used in the same packet", + }, + { + name: "autopilot, pfm, and wasm in the memo", + metadata: `{"autopilot": {}, "pfm": {}, "wasm": {}}`, + expectedErr: "only one of autopilot, pfm, and wasm can both be used in the same packet", }, { name: "empty receiver address",