diff --git a/ignite/cmd/scaffold_chain.go b/ignite/cmd/scaffold_chain.go index a51689f035..298e395c3b 100644 --- a/ignite/cmd/scaffold_chain.go +++ b/ignite/cmd/scaffold_chain.go @@ -17,6 +17,7 @@ const ( flagNoDefaultModule = "no-module" flagSkipGit = "skip-git" flagIsConsumer = "consumer" + flagFeeabsModule = "fee-abstraction" tplScaffoldChainSuccess = ` ⭐️ Successfully created a new blockchain '%[1]v'. @@ -90,9 +91,10 @@ about Cosmos SDK on https://docs.cosmos.network c.Flags().Bool(flagMinimal, false, "create a minimal blockchain (with the minimum required Cosmos SDK modules)") c.Flags().Bool(flagIsConsumer, false, "scafffold an ICS consumer chain") c.Flags().String(flagProtoDir, defaults.ProtoDir, "chain proto directory") + c.Flags().Bool(flagFeeabsModule, false, "create a project that includes the fee abstraction module") - // Cannot have both minimal and consumer flag - c.MarkFlagsMutuallyExclusive(flagIsConsumer, flagMinimal) + // Cannot have minimal, consumer, and fee-abstraction flags at the same time + c.MarkFlagsMutuallyExclusive(flagIsConsumer, flagMinimal, flagFeeabsModule) return c } @@ -114,6 +116,7 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error { moduleConfigs, _ = cmd.Flags().GetStringSlice(flagModuleConfigs) skipProto, _ = cmd.Flags().GetBool(flagSkipProto) protoDir, _ = cmd.Flags().GetString(flagProtoDir) + feeabsModule, _ = cmd.Flags().GetBool(flagFeeabsModule) ) if noDefaultModule { @@ -138,6 +141,7 @@ func scaffoldChainHandler(cmd *cobra.Command, args []string) error { addressPrefix, protoDir, noDefaultModule, + feeabsModule, minimal, isConsumer, params, diff --git a/ignite/pkg/cosmosgen/generate_openapi.go b/ignite/pkg/cosmosgen/generate_openapi.go index 7e40704d60..8a7f30d678 100644 --- a/ignite/pkg/cosmosgen/generate_openapi.go +++ b/ignite/pkg/cosmosgen/generate_openapi.go @@ -86,6 +86,7 @@ func (g *generator) generateOpenAPISpec(ctx context.Context) error { "*/cosmos/app/v1alpha1/*", "*/cosmos/tx/config/v1/config.proto", "*/cosmos/msg/textual/v1/textual.proto", + "*/osmosis-labs/fee-abstraction/*", ), cosmosbuf.FileByFile(), ); err != nil { diff --git a/ignite/services/scaffolder/init.go b/ignite/services/scaffolder/init.go index 66aca0aae9..3547b973fa 100644 --- a/ignite/services/scaffolder/init.go +++ b/ignite/services/scaffolder/init.go @@ -21,7 +21,7 @@ func Init( ctx context.Context, runner *xgenny.Runner, root, name, addressPrefix, protoDir string, - noDefaultModule, minimal, isConsumerChain bool, + noDefaultModule, feeabsModule, minimal, isConsumerChain bool, params, moduleConfigs []string, ) (string, string, error) { pathInfo, err := gomodulepath.Parse(name) @@ -59,6 +59,7 @@ func Init( protoDir, path, noDefaultModule, + feeabsModule, minimal, isConsumerChain, params, @@ -75,7 +76,7 @@ func generate( addressPrefix, protoDir, absRoot string, - noDefaultModule, minimal, isConsumerChain bool, + noDefaultModule, feeabsModule, minimal, isConsumerChain bool, params, moduleConfigs []string, ) (xgenny.SourceModification, error) { // Parse params with the associated type @@ -98,15 +99,16 @@ func generate( g, err := app.NewGenerator(&app.Options{ // generate application template - ModulePath: pathInfo.RawPath, - AppName: pathInfo.Package, - AppPath: absRoot, - ProtoDir: protoDir, - GitHubPath: githubPath, - BinaryNamePrefix: pathInfo.Root, - AddressPrefix: addressPrefix, - IsChainMinimal: minimal, - IsConsumerChain: isConsumerChain, + ModulePath: pathInfo.RawPath, + AppName: pathInfo.Package, + AppPath: absRoot, + ProtoDir: protoDir, + GitHubPath: githubPath, + BinaryNamePrefix: pathInfo.Root, + AddressPrefix: addressPrefix, + IsChainMinimal: minimal, + IsConsumerChain: isConsumerChain, + IncludeFeeabsModule: feeabsModule, }) if err != nil { return xgenny.SourceModification{}, err diff --git a/ignite/templates/app/app.go b/ignite/templates/app/app.go index b73bc73799..1edbe9e5d5 100644 --- a/ignite/templates/app/app.go +++ b/ignite/templates/app/app.go @@ -22,6 +22,9 @@ var ( //go:embed files-consumer/* files-consumer/**/* filesConsumer embed.FS + + //go:embed files-feeabs/* files-feeabs/**/* + filesFeeabs embed.FS ) const ( @@ -49,6 +52,9 @@ func NewGenerator(opts *Options) (*genny.Generator, error) { if opts.IsConsumerChain { overridesFS["files-consumer"] = filesConsumer } + if opts.IncludeFeeabsModule { + overridesFS["files-feeabs"] = filesFeeabs + } g := genny.New() if err := g.SelectiveFS(subfs, includePrefix, nil, excludePrefix, nil); err != nil { @@ -77,6 +83,7 @@ func NewGenerator(opts *Options) (*genny.Generator, error) { ctx.Set("IsConsumerChain", opts.IsConsumerChain) ctx.Set("DepTools", cosmosgen.DepTools()) ctx.Set("IsChainMinimal", opts.IsChainMinimal) + ctx.Set("IncludeFeeabsModule", opts.IncludeFeeabsModule) plushhelpers.ExtendPlushContext(ctx) g.Transformer(xgenny.Transformer(ctx)) diff --git a/ignite/templates/app/files-feeabs/app/app.go.plush b/ignite/templates/app/files-feeabs/app/app.go.plush new file mode 100644 index 0000000000..627e376a7a --- /dev/null +++ b/ignite/templates/app/files-feeabs/app/app.go.plush @@ -0,0 +1,408 @@ +package app + +import ( + "io" + + clienthelpers "cosmossdk.io/client/v2/helpers" + "cosmossdk.io/depinject" + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + circuitkeeper "cosmossdk.io/x/circuit/keeper" + evidencekeeper "cosmossdk.io/x/evidence/keeper" + feegrantkeeper "cosmossdk.io/x/feegrant/keeper" + upgradekeeper "cosmossdk.io/x/upgrade/keeper" + _ "cosmossdk.io/api/cosmos/tx/config/v1" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/auth/tx/config" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/bank" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/consensus" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/distribution" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/mint" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/staking" // import for side-effects + _ "cosmossdk.io/x/circuit" // import for side-effects + _ "cosmossdk.io/x/evidence" // import for side-effects + _ "cosmossdk.io/x/feegrant/module" // import for side-effects + _ "cosmossdk.io/x/nft/module" // import for side-effects + nftkeeper "cosmossdk.io/x/nft/keeper" + _ "cosmossdk.io/x/upgrade" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/auth/vesting" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/authz/module" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/crisis" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/group/module" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/params" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/slashing" // import for side-effects + _ "github.com/cosmos/ibc-go/modules/capability" // import for side-effects + _ "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" // import for side-effects + _ "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" // import for side-effects + dbm "github.com/cosmos/cosmos-db" + abci "github.com/cometbft/cometbft/abci/types" + "github.com/cosmos/cosmos-sdk/baseapp" + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/runtime" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/api" + "github.com/cosmos/cosmos-sdk/server/config" + sdk "github.com/cosmos/cosmos-sdk/types" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + authsims "github.com/cosmos/cosmos-sdk/x/auth/simulation" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + authzkeeper "github.com/cosmos/cosmos-sdk/x/authz/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/keeper" + crisiskeeper "github.com/cosmos/cosmos-sdk/x/crisis/keeper" + distrkeeper "github.com/cosmos/cosmos-sdk/x/distribution/keeper" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + "github.com/cosmos/cosmos-sdk/x/gov" + govclient "github.com/cosmos/cosmos-sdk/x/gov/client" + govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" + paramskeeper "github.com/cosmos/cosmos-sdk/x/params/keeper" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" + icacontrollerkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" + icahostkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" + ibcfeekeeper "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" + ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" + ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" + feeabskeeper "github.com/osmosis-labs/fee-abstraction/v8/x/feeabs/keeper" + + "<%= ModulePath %>/docs" +) + +const ( + AccountAddressPrefix = "<%= AddressPrefix %>" + Name = "<%= BinaryNamePrefix %>" +) + +var ( + // DefaultNodeHome default home directories for the application daemon + DefaultNodeHome string +) + +var ( + _ runtime.AppI = (*App)(nil) + _ servertypes.Application = (*App)(nil) +) + +// App extends an ABCI application, but with most of its parameters exported. +// They are exported for convenience in creating helper functions, as object +// capabilities aren't needed for testing. +type App struct { + *runtime.App + legacyAmino *codec.LegacyAmino + appCodec codec.Codec + txConfig client.TxConfig + interfaceRegistry codectypes.InterfaceRegistry + + // keepers + AccountKeeper authkeeper.AccountKeeper + BankKeeper bankkeeper.Keeper + StakingKeeper *stakingkeeper.Keeper + DistrKeeper distrkeeper.Keeper + ConsensusParamsKeeper consensuskeeper.Keeper + + SlashingKeeper slashingkeeper.Keeper + MintKeeper mintkeeper.Keeper + GovKeeper *govkeeper.Keeper + CrisisKeeper *crisiskeeper.Keeper + UpgradeKeeper *upgradekeeper.Keeper + ParamsKeeper paramskeeper.Keeper + AuthzKeeper authzkeeper.Keeper + EvidenceKeeper evidencekeeper.Keeper + FeeGrantKeeper feegrantkeeper.Keeper + GroupKeeper groupkeeper.Keeper + NFTKeeper nftkeeper.Keeper + CircuitBreakerKeeper circuitkeeper.Keeper + + // IBC + IBCKeeper *ibckeeper.Keeper // IBC Keeper must be a pointer in the app, so we can SetRouter on it correctly + CapabilityKeeper *capabilitykeeper.Keeper + IBCFeeKeeper ibcfeekeeper.Keeper + ICAControllerKeeper icacontrollerkeeper.Keeper + ICAHostKeeper icahostkeeper.Keeper + TransferKeeper ibctransferkeeper.Keeper + FeeabsKeeper feeabskeeper.Keeper + + // Scoped IBC + ScopedIBCKeeper capabilitykeeper.ScopedKeeper + ScopedIBCTransferKeeper capabilitykeeper.ScopedKeeper + ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper + ScopedICAHostKeeper capabilitykeeper.ScopedKeeper + ScopedFeeabsKeeper capabilitykeeper.ScopedKeeper + ScopedKeepers map[string]capabilitykeeper.ScopedKeeper + + // this line is used by starport scaffolding # stargate/app/keeperDeclaration + + // simulation manager + sm *module.SimulationManager +} + +func init() { + var err error + clienthelpers.EnvPrefix = Name + DefaultNodeHome, err = clienthelpers.GetNodeHomeDirectory("."+Name) + if err != nil { + panic(err) + } +} + +// getGovProposalHandlers return the chain proposal handlers. +func getGovProposalHandlers() []govclient.ProposalHandler { + var govProposalHandlers []govclient.ProposalHandler + // this line is used by starport scaffolding # stargate/app/govProposalHandlers + + govProposalHandlers = append(govProposalHandlers, + paramsclient.ProposalHandler, + // this line is used by starport scaffolding # stargate/app/govProposalHandler + ) + + return govProposalHandlers +} + +// AppConfig returns the default app config. +func AppConfig() depinject.Config { + return depinject.Configs( + appConfig, + // Alternatively, load the app config from a YAML file. + // appconfig.LoadYAML(AppConfigYAML), + depinject.Supply( + // supply custom module basics + map[string]module.AppModuleBasic{ + genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), + govtypes.ModuleName: gov.NewAppModuleBasic(getGovProposalHandlers()), + // this line is used by starport scaffolding # stargate/appConfig/moduleBasic + }, + ), + ) +} + +// New returns a reference to an initialized App. +func New( + logger log.Logger, + db dbm.DB, + traceStore io.Writer, + loadLatest bool, + appOpts servertypes.AppOptions, + baseAppOptions ...func(*baseapp.BaseApp), +) (*App, error) { + var ( + app = &App{ScopedKeepers: make(map[string]capabilitykeeper.ScopedKeeper)} + appBuilder *runtime.AppBuilder + + // merge the AppConfig and other configuration in one config + appConfig = depinject.Configs( + AppConfig(), + depinject.Supply( + appOpts, // supply app options + logger, // supply logger + // Supply with IBC keeper getter for the IBC modules with App Wiring. + // The IBC Keeper cannot be passed because it has not been initiated yet. + // Passing the getter, the app IBC Keeper will always be accessible. + // This needs to be removed after IBC supports App Wiring. + app.GetIBCKeeper, + app.GetCapabilityScopedKeeper, + + // here alternative options can be supplied to the DI container. + // those options can be used f.e to override the default behavior of some modules. + // for instance supplying a custom address codec for not using bech32 addresses. + // read the depinject documentation and depinject module wiring for more information + // on available options and how to use them. + ), + ) + ) + + if err := depinject.Inject(appConfig, + &appBuilder, + &app.appCodec, + &app.legacyAmino, + &app.txConfig, + &app.interfaceRegistry, + &app.AccountKeeper, + &app.BankKeeper, + &app.StakingKeeper, + &app.DistrKeeper, + &app.ConsensusParamsKeeper, + &app.SlashingKeeper, + &app.MintKeeper, + &app.GovKeeper, + &app.CrisisKeeper, + &app.UpgradeKeeper, + &app.ParamsKeeper, + &app.AuthzKeeper, + &app.EvidenceKeeper, + &app.FeeGrantKeeper, + &app.NFTKeeper, + &app.GroupKeeper, + &app.CircuitBreakerKeeper, + + ); err != nil { + panic(err) + } + + // add to default baseapp options + // enable optimistic execution + baseAppOptions = append(baseAppOptions, baseapp.SetOptimisticExecution()) + + // build app + app.App = appBuilder.Build(db, traceStore, baseAppOptions...) + + // register legacy modules + if err := app.registerIBCModules(appOpts); err != nil { + return nil, err + } + + // register streaming services + if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil { + return nil, err + } + + /**** Module Options ****/ + + app.ModuleManager.RegisterInvariants(app.CrisisKeeper) + + // create the simulation manager and define the order of the modules for deterministic simulations + overrideModules := map[string]module.AppModuleSimulation{ + authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), + } + app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) + app.sm.RegisterStoreDecoders() + + // A custom InitChainer sets if extra pre-init-genesis logic is required. + // This is necessary for manually registered modules that do not support app wiring. + // Manually set the module version map as shown below. + // The upgrade module will automatically handle de-duplication of the module version map. + app.SetInitChainer(func(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { + if err := app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()); err != nil { + return nil, err + } + return app.App.InitChainer(ctx, req) + }) + + if err := app.Load(loadLatest); err != nil { + return nil, err + } + + return app, nil +} + +// LegacyAmino returns App's amino codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *App) LegacyAmino() *codec.LegacyAmino { + return app.legacyAmino +} + +// AppCodec returns App's app codec. +// +// NOTE: This is solely to be used for testing purposes as it may be desirable +// for modules to register their own custom testing types. +func (app *App) AppCodec() codec.Codec { + return app.appCodec +} + +// GetKey returns the KVStoreKey for the provided store key. +func (app *App) GetKey(storeKey string) *storetypes.KVStoreKey { + kvStoreKey, ok := app.UnsafeFindStoreKey(storeKey).(*storetypes.KVStoreKey) + if !ok { + return nil + } + return kvStoreKey +} + +// GetMemKey returns the MemoryStoreKey for the provided store key. +func (app *App) GetMemKey(storeKey string) *storetypes.MemoryStoreKey { + key, ok := app.UnsafeFindStoreKey(storeKey).(*storetypes.MemoryStoreKey) + if !ok { + return nil + } + + return key +} + +// kvStoreKeys returns all the kv store keys registered inside App. +func (app *App) kvStoreKeys() map[string]*storetypes.KVStoreKey { + keys := make(map[string]*storetypes.KVStoreKey) + for _, k := range app.GetStoreKeys() { + if kv, ok := k.(*storetypes.KVStoreKey); ok { + keys[kv.Name()] = kv + } + } + + return keys +} + +// GetSubspace returns a param subspace for a given module name. +func (app *App) GetSubspace(moduleName string) paramstypes.Subspace { + subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) + return subspace +} + +// GetIBCKeeper returns the IBC keeper. +func (app *App) GetIBCKeeper() *ibckeeper.Keeper { + return app.IBCKeeper +} + +// GetCapabilityScopedKeeper returns the capability scoped keeper. +func (app *App) GetCapabilityScopedKeeper(moduleName string) capabilitykeeper.ScopedKeeper { + sk, ok := app.ScopedKeepers[moduleName] + if !ok { + sk = app.CapabilityKeeper.ScopeToModule(moduleName) + app.ScopedKeepers[moduleName] = sk + } + return sk +} + +// SimulationManager implements the SimulationApp interface. +func (app *App) SimulationManager() *module.SimulationManager { + return app.sm +} + +// RegisterAPIRoutes registers all application module routes with the provided +// API server. +func (app *App) RegisterAPIRoutes(apiSvr *api.Server, apiConfig config.APIConfig) { + app.App.RegisterAPIRoutes(apiSvr, apiConfig) + // register swagger API in app.go so that other applications can override easily + if err := server.RegisterSwaggerAPI(apiSvr.ClientCtx, apiSvr.Router, apiConfig.Swagger); err != nil { + panic(err) + } + + // register app's OpenAPI routes. + docs.RegisterOpenAPIService(Name, apiSvr.Router) +} + +// GetMaccPerms returns a copy of the module account permissions +// +// NOTE: This is solely to be used for testing purposes. +func GetMaccPerms() map[string][]string { + dup := make(map[string][]string) + for _, perms := range moduleAccPerms { + dup[perms.Account] = perms.Permissions + } + return dup +} + +// BlockedAddresses returns all the app's blocked account addresses. +func BlockedAddresses() map[string]bool { + result := make(map[string]bool) + if len(blockAccAddrs) > 0 { + for _, addr := range blockAccAddrs { + result[addr] = true + } + } else { + for addr := range GetMaccPerms() { + result[addr] = true + } + } + return result +} diff --git a/ignite/templates/app/files-feeabs/app/app_config.go.plush b/ignite/templates/app/files-feeabs/app/app_config.go.plush new file mode 100644 index 0000000000..fcb45ecadc --- /dev/null +++ b/ignite/templates/app/files-feeabs/app/app_config.go.plush @@ -0,0 +1,296 @@ +package app + +import ( + "time" + + runtimev1alpha1 "cosmossdk.io/api/cosmos/app/runtime/v1alpha1" + appv1alpha1 "cosmossdk.io/api/cosmos/app/v1alpha1" + authmodulev1 "cosmossdk.io/api/cosmos/auth/module/v1" + authzmodulev1 "cosmossdk.io/api/cosmos/authz/module/v1" + bankmodulev1 "cosmossdk.io/api/cosmos/bank/module/v1" + circuitmodulev1 "cosmossdk.io/api/cosmos/circuit/module/v1" + consensusmodulev1 "cosmossdk.io/api/cosmos/consensus/module/v1" + crisismodulev1 "cosmossdk.io/api/cosmos/crisis/module/v1" + distrmodulev1 "cosmossdk.io/api/cosmos/distribution/module/v1" + evidencemodulev1 "cosmossdk.io/api/cosmos/evidence/module/v1" + feegrantmodulev1 "cosmossdk.io/api/cosmos/feegrant/module/v1" + genutilmodulev1 "cosmossdk.io/api/cosmos/genutil/module/v1" + govmodulev1 "cosmossdk.io/api/cosmos/gov/module/v1" + groupmodulev1 "cosmossdk.io/api/cosmos/group/module/v1" + mintmodulev1 "cosmossdk.io/api/cosmos/mint/module/v1" + nftmodulev1 "cosmossdk.io/api/cosmos/nft/module/v1" + paramsmodulev1 "cosmossdk.io/api/cosmos/params/module/v1" + slashingmodulev1 "cosmossdk.io/api/cosmos/slashing/module/v1" + stakingmodulev1 "cosmossdk.io/api/cosmos/staking/module/v1" + txconfigv1 "cosmossdk.io/api/cosmos/tx/config/v1" + upgrademodulev1 "cosmossdk.io/api/cosmos/upgrade/module/v1" + vestingmodulev1 "cosmossdk.io/api/cosmos/vesting/module/v1" + "cosmossdk.io/core/appconfig" + circuittypes "cosmossdk.io/x/circuit/types" + evidencetypes "cosmossdk.io/x/evidence/types" + "cosmossdk.io/x/feegrant" + "cosmossdk.io/x/nft" + upgradetypes "cosmossdk.io/x/upgrade/types" + "github.com/cosmos/cosmos-sdk/runtime" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + vestingtypes "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + "github.com/cosmos/cosmos-sdk/x/authz" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types" + crisistypes "github.com/cosmos/cosmos-sdk/x/crisis/types" + distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/group" + minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + ibcfeetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + feeabstypes "github.com/osmosis-labs/fee-abstraction/v8/x/feeabs/types" + "google.golang.org/protobuf/types/known/durationpb" +) + +var ( + // NOTE: The genutils module must occur after staking so that pools are + // properly initialized with tokens from genesis accounts. + // NOTE: The genutils module must also occur after auth so that it can access the params from auth. + // NOTE: Capability module must occur first so that it can initialize any capabilities + // so that other modules that want to create or claim capabilities afterwards in InitChain + // can do so safely. + genesisModuleOrder = []string{ + // cosmos-sdk/ibc modules + capabilitytypes.ModuleName, + authtypes.ModuleName, + banktypes.ModuleName, + distrtypes.ModuleName, + stakingtypes.ModuleName, + slashingtypes.ModuleName, + govtypes.ModuleName, + minttypes.ModuleName, + crisistypes.ModuleName, + ibcexported.ModuleName, + genutiltypes.ModuleName, + evidencetypes.ModuleName, + authz.ModuleName, + ibctransfertypes.ModuleName, + icatypes.ModuleName, + ibcfeetypes.ModuleName, + feegrant.ModuleName, + paramstypes.ModuleName, + upgradetypes.ModuleName, + vestingtypes.ModuleName, + nft.ModuleName, + group.ModuleName, + consensustypes.ModuleName, + circuittypes.ModuleName, + feeabstypes.ModuleName, + // chain modules + // this line is used by starport scaffolding # stargate/app/initGenesis + } + + // During begin block slashing happens after distr.BeginBlocker so that + // there is nothing left over in the validator fee pool, so as to keep the + // CanWithdrawInvariant invariant. + // NOTE: staking module is required if HistoricalEntries param > 0 + // NOTE: capability module's beginblocker must come before any modules using capabilities (e.g. IBC) + beginBlockers = []string{ + // cosmos sdk modules + minttypes.ModuleName, + distrtypes.ModuleName, + slashingtypes.ModuleName, + evidencetypes.ModuleName, + stakingtypes.ModuleName, + authz.ModuleName, + genutiltypes.ModuleName, + // ibc modules + capabilitytypes.ModuleName, + ibcexported.ModuleName, + ibctransfertypes.ModuleName, + icatypes.ModuleName, + ibcfeetypes.ModuleName, + feeabstypes.ModuleName, + // chain modules + // this line is used by starport scaffolding # stargate/app/beginBlockers + } + + endBlockers = []string{ + // cosmos sdk modules + crisistypes.ModuleName, + govtypes.ModuleName, + stakingtypes.ModuleName, + feegrant.ModuleName, + group.ModuleName, + genutiltypes.ModuleName, + // ibc modules + ibcexported.ModuleName, + ibctransfertypes.ModuleName, + capabilitytypes.ModuleName, + icatypes.ModuleName, + ibcfeetypes.ModuleName, + feeabstypes.ModuleName, + // chain modules + // this line is used by starport scaffolding # stargate/app/endBlockers + } + + preBlockers = []string{ + upgradetypes.ModuleName, + // this line is used by starport scaffolding # stargate/app/preBlockers + } + + // module account permissions + moduleAccPerms = []*authmodulev1.ModuleAccountPermission{ + {Account: authtypes.FeeCollectorName}, + {Account: distrtypes.ModuleName}, + {Account: minttypes.ModuleName, Permissions: []string{authtypes.Minter}}, + {Account: stakingtypes.BondedPoolName, Permissions: []string{authtypes.Burner, stakingtypes.ModuleName}}, + {Account: stakingtypes.NotBondedPoolName, Permissions: []string{authtypes.Burner, stakingtypes.ModuleName}}, + {Account: govtypes.ModuleName, Permissions: []string{authtypes.Burner}}, + {Account: nft.ModuleName}, + {Account: ibctransfertypes.ModuleName, Permissions: []string{authtypes.Minter, authtypes.Burner}}, + {Account: ibcfeetypes.ModuleName}, + {Account: icatypes.ModuleName}, + {Account: feeabstypes.ModuleName}, + // this line is used by starport scaffolding # stargate/app/maccPerms + } + + // blocked account addresses + blockAccAddrs = []string{ + authtypes.FeeCollectorName, + distrtypes.ModuleName, + minttypes.ModuleName, + stakingtypes.BondedPoolName, + stakingtypes.NotBondedPoolName, + nft.ModuleName, + // We allow the following module accounts to receive funds: + // govtypes.ModuleName + } + + // appConfig application configuration (used by depinject) + appConfig = appconfig.Compose(&appv1alpha1.Config{ + Modules: []*appv1alpha1.ModuleConfig{ + { + Name: runtime.ModuleName, + Config: appconfig.WrapAny(&runtimev1alpha1.Module{ + AppName: Name, + PreBlockers: preBlockers, + BeginBlockers: beginBlockers, + EndBlockers: endBlockers, + InitGenesis: genesisModuleOrder, + OverrideStoreKeys: []*runtimev1alpha1.StoreKeyConfig{ + { + ModuleName: authtypes.ModuleName, + KvStoreKey: "acc", + }, + }, + // When ExportGenesis is not specified, the export genesis module order + // is equal to the init genesis order + // ExportGenesis: genesisModuleOrder, + // Uncomment if you want to set a custom migration order here. + // OrderMigrations: nil, + }), + }, + { + Name: authtypes.ModuleName, + Config: appconfig.WrapAny(&authmodulev1.Module{ + Bech32Prefix: AccountAddressPrefix, + ModuleAccountPermissions: moduleAccPerms, + // By default modules authority is the governance module. This is configurable with the following: + // Authority: "group", // A custom module authority can be set using a module name + // Authority: "cosmos1cwwv22j5ca08ggdv9c2uky355k908694z577tv", // or a specific address + }), + }, + { + Name: nft.ModuleName, + Config: appconfig.WrapAny(&nftmodulev1.Module{}), + }, + { + Name: vestingtypes.ModuleName, + Config: appconfig.WrapAny(&vestingmodulev1.Module{}), + }, + { + Name: banktypes.ModuleName, + Config: appconfig.WrapAny(&bankmodulev1.Module{ + BlockedModuleAccountsOverride: blockAccAddrs, + }), + }, + { + Name: stakingtypes.ModuleName, + Config: appconfig.WrapAny(&stakingmodulev1.Module{ + // NOTE: specifying a prefix is only necessary when using bech32 addresses + // If not specfied, the auth Bech32Prefix appended with "valoper" and "valcons" is used by default + Bech32PrefixValidator: AccountAddressPrefix + "valoper", + Bech32PrefixConsensus: AccountAddressPrefix + "valcons", + }), + }, + { + Name: slashingtypes.ModuleName, + Config: appconfig.WrapAny(&slashingmodulev1.Module{}), + }, + { + Name: paramstypes.ModuleName, + Config: appconfig.WrapAny(¶msmodulev1.Module{}), + }, + { + Name: "tx", + Config: appconfig.WrapAny(&txconfigv1.Config{}), + }, + { + Name: genutiltypes.ModuleName, + Config: appconfig.WrapAny(&genutilmodulev1.Module{}), + }, + { + Name: authz.ModuleName, + Config: appconfig.WrapAny(&authzmodulev1.Module{}), + }, + { + Name: upgradetypes.ModuleName, + Config: appconfig.WrapAny(&upgrademodulev1.Module{}), + }, + { + Name: distrtypes.ModuleName, + Config: appconfig.WrapAny(&distrmodulev1.Module{}), + }, + { + Name: evidencetypes.ModuleName, + Config: appconfig.WrapAny(&evidencemodulev1.Module{}), + }, + { + Name: minttypes.ModuleName, + Config: appconfig.WrapAny(&mintmodulev1.Module{}), + }, + { + Name: group.ModuleName, + Config: appconfig.WrapAny(&groupmodulev1.Module{ + MaxExecutionPeriod: durationpb.New(time.Second * 1209600), + MaxMetadataLen: 255, + }), + }, + { + Name: feegrant.ModuleName, + Config: appconfig.WrapAny(&feegrantmodulev1.Module{}), + }, + { + Name: govtypes.ModuleName, + Config: appconfig.WrapAny(&govmodulev1.Module{}), + }, + { + Name: crisistypes.ModuleName, + Config: appconfig.WrapAny(&crisismodulev1.Module{}), + }, + { + Name: consensustypes.ModuleName, + Config: appconfig.WrapAny(&consensusmodulev1.Module{}), + }, + { + Name: circuittypes.ModuleName, + Config: appconfig.WrapAny(&circuitmodulev1.Module{}), + }, + // this line is used by starport scaffolding # stargate/app/moduleConfig + }, + }) +) diff --git a/ignite/templates/app/files-feeabs/app/ibc.go.plush b/ignite/templates/app/files-feeabs/app/ibc.go.plush new file mode 100644 index 0000000000..9ae8bcd8f9 --- /dev/null +++ b/ignite/templates/app/files-feeabs/app/ibc.go.plush @@ -0,0 +1,232 @@ +package app + +import ( + "cosmossdk.io/core/appmodule" + storetypes "cosmossdk.io/store/types" + cdctypes "github.com/cosmos/cosmos-sdk/codec/types" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + "github.com/cosmos/cosmos-sdk/types/module" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + govv1beta1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + paramstypes "github.com/cosmos/cosmos-sdk/x/params/types" + "github.com/cosmos/ibc-go/modules/capability" + capabilitykeeper "github.com/cosmos/ibc-go/modules/capability/keeper" + capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + icamodule "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts" + icacontroller "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller" + icacontrollerkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/keeper" + icacontrollertypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/controller/types" + icahost "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host" + icahostkeeper "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/keeper" + icahosttypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types" + icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types" + ibcfee "github.com/cosmos/ibc-go/v8/modules/apps/29-fee" + ibcfeekeeper "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/keeper" + ibcfeetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" + ibctransfer "github.com/cosmos/ibc-go/v8/modules/apps/transfer" + ibctransferkeeper "github.com/cosmos/ibc-go/v8/modules/apps/transfer/keeper" + ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" + ibc "github.com/cosmos/ibc-go/v8/modules/core" + ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" // nolint:staticcheck // Deprecated: params key table is needed for params migration + ibcconnectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + porttypes "github.com/cosmos/ibc-go/v8/modules/core/05-port/types" + ibcexported "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibckeeper "github.com/cosmos/ibc-go/v8/modules/core/keeper" + solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + feeabsmodule "github.com/osmosis-labs/fee-abstraction/v8/x/feeabs" + feeabskeeper "github.com/osmosis-labs/fee-abstraction/v8/x/feeabs/keeper" + feeabstypes "github.com/osmosis-labs/fee-abstraction/v8/x/feeabs/types" +) + +// registerIBCModules register IBC keepers and non dependency inject modules. +func (app *App) registerIBCModules(appOpts servertypes.AppOptions) error { + // set up non depinject support modules store keys + if err := app.RegisterStores( + storetypes.NewKVStoreKey(capabilitytypes.StoreKey), + storetypes.NewKVStoreKey(ibcexported.StoreKey), + storetypes.NewKVStoreKey(ibctransfertypes.StoreKey), + storetypes.NewKVStoreKey(ibcfeetypes.StoreKey), + storetypes.NewKVStoreKey(icahosttypes.StoreKey), + storetypes.NewKVStoreKey(icacontrollertypes.StoreKey), + storetypes.NewKVStoreKey(feeabstypes.StoreKey), + storetypes.NewMemoryStoreKey(capabilitytypes.MemStoreKey), + storetypes.NewTransientStoreKey(paramstypes.TStoreKey), + ); err != nil { + return err + } + + // register the key tables for legacy param subspaces + keyTable := ibcclienttypes.ParamKeyTable() + keyTable.RegisterParamSet(&ibcconnectiontypes.Params{}) + app.ParamsKeeper.Subspace(ibcexported.ModuleName).WithKeyTable(keyTable) + app.ParamsKeeper.Subspace(ibctransfertypes.ModuleName).WithKeyTable(ibctransfertypes.ParamKeyTable()) + app.ParamsKeeper.Subspace(icacontrollertypes.SubModuleName).WithKeyTable(icacontrollertypes.ParamKeyTable()) + app.ParamsKeeper.Subspace(icahosttypes.SubModuleName).WithKeyTable(icahosttypes.ParamKeyTable()) + app.ParamsKeeper.Subspace(feeabstypes.ModuleName) + + // add capability keeper and ScopeToModule for ibc module + app.CapabilityKeeper = capabilitykeeper.NewKeeper( + app.AppCodec(), + app.GetKey(capabilitytypes.StoreKey), + app.GetMemKey(capabilitytypes.MemStoreKey), + ) + + // add capability keeper and ScopeToModule for ibc module + scopedIBCKeeper := app.CapabilityKeeper.ScopeToModule(ibcexported.ModuleName) + scopedIBCTransferKeeper := app.CapabilityKeeper.ScopeToModule(ibctransfertypes.ModuleName) + scopedICAControllerKeeper := app.CapabilityKeeper.ScopeToModule(icacontrollertypes.SubModuleName) + scopedICAHostKeeper := app.CapabilityKeeper.ScopeToModule(icahosttypes.SubModuleName) + scopedFeeabsKeeper := app.CapabilityKeeper.ScopeToModule(feeabstypes.ModuleName) + + // Create IBC keeper + app.IBCKeeper = ibckeeper.NewKeeper( + app.appCodec, + app.GetKey(ibcexported.StoreKey), + app.GetSubspace(ibcexported.ModuleName), + app.StakingKeeper, + app.UpgradeKeeper, + scopedIBCKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + // Register the proposal types + // Deprecated: Avoid adding new handlers, instead use the new proposal flow + // by granting the governance module the right to execute the message. + // See: https://docs.cosmos.network/main/modules/gov#proposal-messages + govRouter := govv1beta1.NewRouter() + govRouter.AddRoute(govtypes.RouterKey, govv1beta1.ProposalHandler) + + app.IBCFeeKeeper = ibcfeekeeper.NewKeeper( + app.appCodec, app.GetKey(ibcfeetypes.StoreKey), + app.IBCKeeper.ChannelKeeper, // may be replaced with IBC middleware + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.PortKeeper, app.AccountKeeper, app.BankKeeper, + ) + + // Create IBC transfer keeper + app.TransferKeeper = ibctransferkeeper.NewKeeper( + app.appCodec, + app.GetKey(ibctransfertypes.StoreKey), + app.GetSubspace(ibctransfertypes.ModuleName), + app.IBCFeeKeeper, + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.PortKeeper, + app.AccountKeeper, + app.BankKeeper, + scopedIBCTransferKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + // Create interchain account keepers + app.ICAHostKeeper = icahostkeeper.NewKeeper( + app.appCodec, + app.GetKey(icahosttypes.StoreKey), + app.GetSubspace(icahosttypes.SubModuleName), + app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.PortKeeper, + app.AccountKeeper, + scopedICAHostKeeper, + app.MsgServiceRouter(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + app.ICAHostKeeper.WithQueryRouter(app.GRPCQueryRouter()) + + app.ICAControllerKeeper = icacontrollerkeeper.NewKeeper( + app.appCodec, + app.GetKey(icacontrollertypes.StoreKey), + app.GetSubspace(icacontrollertypes.SubModuleName), + app.IBCFeeKeeper, // use ics29 fee as ics4Wrapper in middleware stack + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.PortKeeper, + scopedICAControllerKeeper, + app.MsgServiceRouter(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + // Create Feeabs keeper + app.FeeabsKeeper = feeabskeeper.NewKeeper( + app.appCodec, + app.GetKey(feeabstypes.StoreKey), + app.GetSubspace(feeabstypes.ModuleName), + app.StakingKeeper, + app.AccountKeeper, + app.BankKeeper, + app.TransferKeeper, + app.IBCKeeper.ChannelKeeper, + app.IBCKeeper.PortKeeper, + scopedFeeabsKeeper, + authtypes.NewModuleAddress(govtypes.ModuleName).String(), + ) + + app.GovKeeper.SetLegacyRouter(govRouter) + + // Create IBC modules with ibcfee middleware + transferIBCModule := ibcfee.NewIBCMiddleware(ibctransfer.NewIBCModule(app.TransferKeeper), app.IBCFeeKeeper) + + // integration point for custom authentication modules + var noAuthzModule porttypes.IBCModule + icaControllerIBCModule := ibcfee.NewIBCMiddleware( + icacontroller.NewIBCMiddleware(noAuthzModule, app.ICAControllerKeeper), + app.IBCFeeKeeper, + ) + + icaHostIBCModule := ibcfee.NewIBCMiddleware(icahost.NewIBCModule(app.ICAHostKeeper), app.IBCFeeKeeper) + + // Create static IBC router, add transfer route, then set and seal it + ibcRouter := porttypes.NewRouter(). + AddRoute(ibctransfertypes.ModuleName, transferIBCModule). + AddRoute(icacontrollertypes.SubModuleName, icaControllerIBCModule). + AddRoute(icahosttypes.SubModuleName, icaHostIBCModule). + AddRoute(feeabstypes.ModuleName, feeabsmodule.NewIBCModule(app.appCodec, app.FeeabsKeeper)) + + // this line is used by starport scaffolding # ibc/app/module + + app.IBCKeeper.SetRouter(ibcRouter) + + app.ScopedIBCKeeper = scopedIBCKeeper + app.ScopedIBCTransferKeeper = scopedIBCTransferKeeper + app.ScopedICAHostKeeper = scopedICAHostKeeper + app.ScopedICAControllerKeeper = scopedICAControllerKeeper + app.ScopedFeeabsKeeper = scopedFeeabsKeeper + + // register IBC modules + if err := app.RegisterModules( + ibc.NewAppModule(app.IBCKeeper), + ibctransfer.NewAppModule(app.TransferKeeper), + ibcfee.NewAppModule(app.IBCFeeKeeper), + icamodule.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), + capability.NewAppModule(app.appCodec, *app.CapabilityKeeper, false), + ibctm.NewAppModule(), + solomachine.NewAppModule(), + feeabsmodule.NewAppModule(app.appCodec, app.FeeabsKeeper), + ); err != nil { + return err + } + + return nil +} + +// RegisterIBC Since the IBC modules don't support dependency injection, +// we need to manually register the modules on the client side. +// This needs to be removed after IBC supports App Wiring. +func RegisterIBC(registry cdctypes.InterfaceRegistry) map[string]appmodule.AppModule { + modules := map[string]appmodule.AppModule{ + ibcexported.ModuleName: ibc.AppModule{}, + ibctransfertypes.ModuleName: ibctransfer.AppModule{}, + ibcfeetypes.ModuleName: ibcfee.AppModule{}, + icatypes.ModuleName: icamodule.AppModule{}, + capabilitytypes.ModuleName: capability.AppModule{}, + ibctm.ModuleName: ibctm.AppModule{}, + solomachine.ModuleName: solomachine.AppModule{}, + feeabstypes.ModuleName: feeabsmodule.AppModule{}, + } + + for name, m := range modules { + module.CoreAppModuleBasicAdaptor(name, m).RegisterInterfaces(registry) + } + + return modules +} \ No newline at end of file diff --git a/ignite/templates/app/files/go.mod.plush b/ignite/templates/app/files/go.mod.plush index bfa98c6e80..4670caedd2 100644 --- a/ignite/templates/app/files/go.mod.plush +++ b/ignite/templates/app/files/go.mod.plush @@ -39,6 +39,9 @@ require ( github.com/gorilla/mux v1.8.1 github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.1 + <%= if (IncludeFeeabsModule) { %> + github.com/osmosis-labs/fee-abstraction/v8 v8.0.2 + <% } %> github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.18.2 diff --git a/ignite/templates/app/options.go b/ignite/templates/app/options.go index 113e241f63..cdba67bb22 100644 --- a/ignite/templates/app/options.go +++ b/ignite/templates/app/options.go @@ -10,7 +10,8 @@ type Options struct { ModulePath string AddressPrefix string // IncludePrefixes is used to filter the files to include from the generator - IncludePrefixes []string - IsChainMinimal bool - IsConsumerChain bool + IncludePrefixes []string + IsChainMinimal bool + IsConsumerChain bool + IncludeFeeabsModule bool }