diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md index b9b83f6e65..25abddde5e 100644 --- a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md +++ b/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md @@ -7,3 +7,6 @@ Please make sure to check the following for your PR: Ignite CLI team only: - [ ] I have updated the _Unreleased_ section in the changelog.md for my changes. +- [ ] If the templates in `ignite/templates/files` have been changed, make + sure that the change doesn't need to be reflected in the + `ignite/templates/files-*` folders. diff --git a/changelog.md b/changelog.md index 6892399f13..4a8038d7bf 100644 --- a/changelog.md +++ b/changelog.md @@ -19,6 +19,7 @@ - [#3885](https://github.com/ignite/cli/pull/3885) Scaffold chain with Cosmos SDK `v0.50.3` - [#3877](https://github.com/ignite/cli/pull/3877) Change Ignite App extension to "ign" +- [#3897](https://github.com/ignite/cli/pull/3897) Introduce alternative folder in templates ## [`v28.1.0`](https://github.com/ignite/cli/releases/tag/v28.1.0) diff --git a/ignite/templates/app/app.go b/ignite/templates/app/app.go index fb89241163..573a05d896 100644 --- a/ignite/templates/app/app.go +++ b/ignite/templates/app/app.go @@ -2,7 +2,6 @@ package app import ( "embed" - "fmt" "io/fs" "github.com/gobuffalo/genny/v2" @@ -14,13 +13,16 @@ import ( "github.com/ignite/cli/v28/ignite/templates/field/plushhelpers" ) -//go:embed files/* files/**/* -var files embed.FS - var ( - ibcConfig = "app/ibc.go" - minimalAppConfig = "app/app_config_minimal.go" - appConfig = "app/app_config.go" + //go:embed files/* files/**/* + files embed.FS + + //go:embed files-minimal/* files-minimal/**/* + filesMinimal embed.FS +) + +const ( + ibcConfig = "app/ibc.go" ) // NewGenerator returns the generator to scaffold a new Cosmos SDK app. @@ -32,12 +34,10 @@ func NewGenerator(opts *Options) (*genny.Generator, error) { } g := genny.New() - // always exclude minimal app config it will be created later - // app_config_minimal is only used for the minimal app template - excludePrefix := []string{minimalAppConfig} + var excludePrefix []string if opts.IsChainMinimal { - // minimal chain does not have ibc or classic app config - excludePrefix = append(excludePrefix, ibcConfig, appConfig) + // minimal chain does not have ibc + excludePrefix = append(excludePrefix, ibcConfig) } if err := g.SelectiveFS(subfs, opts.IncludePrefixes, nil, excludePrefix, nil); err != nil { @@ -45,12 +45,15 @@ func NewGenerator(opts *Options) (*genny.Generator, error) { } if opts.IsChainMinimal { - file, err := subfs.Open(fmt.Sprintf("%s.plush", minimalAppConfig)) + // Remove "files-minimal/" prefix + subfs, err := fs.Sub(filesMinimal, "files-minimal") if err != nil { - return g, errors.Errorf("open minimal app config: %w", err) + return nil, errors.Errorf("generator sub minimal: %w", err) + } + // Override files from "files" with the ones from "files-minimal" + if err := g.FS(subfs); err != nil { + return g, errors.Errorf("generator fs minimal: %w", err) } - - g.File(genny.NewFile(appConfig, file)) } ctx := plush.NewContext() diff --git a/ignite/templates/app/files-minimal/app/app.go.plush b/ignite/templates/app/files-minimal/app/app.go.plush new file mode 100644 index 0000000000..e5ea32dc46 --- /dev/null +++ b/ignite/templates/app/files-minimal/app/app.go.plush @@ -0,0 +1,340 @@ +package app + +import ( + "io" + "os" + "path/filepath" + + "cosmossdk.io/depinject" + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + _ "cosmossdk.io/api/cosmos/tx/config/v1" // import for side-effects + _ "github.com/cosmos/cosmos-sdk/x/auth" // 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 + dbm "github.com/cosmos/cosmos-db" + "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" + servertypes "github.com/cosmos/cosmos-sdk/server/types" + testdata_pulsar "github.com/cosmos/cosmos-sdk/testutil/testdata/testpb" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" + consensuskeeper "github.com/cosmos/cosmos-sdk/x/consensus/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" + mintkeeper "github.com/cosmos/cosmos-sdk/x/mint/keeper" + stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" + + // this line is used by starport scaffolding # stargate/app/moduleImport + + "<%= 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 + + // this line is used by starport scaffolding # stargate/app/keeperDeclaration + + // simulation manager + sm *module.SimulationManager +} + +func init() { + userHomeDir, err := os.UserHomeDir() + if err != nil { + panic(err) + } + + DefaultNodeHome = filepath.Join(userHomeDir, "."+Name) +} + +// AppConfig returns the default app config. +func AppConfig() depinject.Config { + return depinject.Configs( + appConfig, + // Loads 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), + // 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{} + appBuilder *runtime.AppBuilder + + // merge the AppConfig and other configuration in one config + appConfig = depinject.Configs( + AppConfig(), + depinject.Supply( + // Supply the application options + appOpts, + // Supply the logger + logger, + + // ADVANCED CONFIGURATION + // + // AUTH + // + // For providing a custom function required in auth to generate custom account types + // add it below. By default the auth module uses simulation.RandomGenesisAccounts. + // + // authtypes.RandomGenesisAccountsFn(simulation.RandomGenesisAccounts), + // + // For providing a custom a base account type add it below. + // By default the auth module uses authtypes.ProtoBaseAccount(). + // + // func() sdk.AccountI { return authtypes.ProtoBaseAccount() }, + // + // For providing a different address codec, add it below. + // By default the auth module uses a Bech32 address codec, + // with the prefix defined in the auth module configuration. + // + // func() address.Codec { return <- custom address codec type -> } + + // + // STAKING + // + // For provinding a different validator and consensus address codec, add it below. + // By default the staking module uses the bech32 prefix provided in the auth config, + // and appends "valoper" and "valcons" for validator and consensus addresses respectively. + // When providing a custom address codec in auth, custom address codecs must be provided here as well. + // + // func() runtime.ValidatorAddressCodec { return <- custom validator address codec type -> } + // func() runtime.ConsensusAddressCodec { return <- custom consensus address codec type -> } + + // + // MINT + // + + // For providing a custom inflation function for x/mint add here your + // custom function that implements the minttypes.InflationCalculationFn + // interface. + ), + ) + ) + + if err := depinject.Inject(appConfig, + &appBuilder, + &app.appCodec, + &app.legacyAmino, + &app.txConfig, + &app.interfaceRegistry, + &app.AccountKeeper, + &app.BankKeeper, + &app.StakingKeeper, + &app.DistrKeeper, + &app.ConsensusParamsKeeper, + // this line is used by starport scaffolding # stargate/app/keeperDefinition + ); err != nil { + panic(err) + } + + // Below we could construct and set an application specific mempool and + // ABCI 1.0 PrepareProposal and ProcessProposal handlers. These defaults are + // already set in the SDK's BaseApp, this shows an example of how to override + // them. + // + // Example: + // + // app.App = appBuilder.Build(...) + // nonceMempool := mempool.NewSenderNonceMempool() + // abciPropHandler := NewDefaultProposalHandler(nonceMempool, app.App.BaseApp) + // + // app.App.BaseApp.SetMempool(nonceMempool) + // app.App.BaseApp.SetPrepareProposal(abciPropHandler.PrepareProposalHandler()) + // app.App.BaseApp.SetProcessProposal(abciPropHandler.ProcessProposalHandler()) + // + // Alternatively, you can construct BaseApp options, append those to + // baseAppOptions and pass them to the appBuilder. + // + // Example: + // + // prepareOpt = func(app *baseapp.BaseApp) { + // abciPropHandler := baseapp.NewDefaultProposalHandler(nonceMempool, app) + // app.SetPrepareProposal(abciPropHandler.PrepareProposalHandler()) + // } + // baseAppOptions = append(baseAppOptions, prepareOpt) + // + // create and set vote extension handler + // voteExtOp := func(bApp *baseapp.BaseApp) { + // voteExtHandler := NewVoteExtensionHandler() + // voteExtHandler.SetHandlers(bApp) + // } + + app.App = appBuilder.Build(db, traceStore, baseAppOptions...) + + // register streaming services + if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil { + return nil, err + } + + /**** Module Options ****/ + overrideModules := make(map[string]module.AppModuleSimulation) + app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) + app.sm.RegisterStoreDecoders() + + // A custom InitChainer can be set if extra pre-init-genesis logic is required. + // By default, when using app wiring enabled module, this is not required. + // For instance, the upgrade module will set automatically the module version map in its init genesis thanks to app wiring. + // However, when registering a module manually (i.e. that does not support app wiring), the module version map + // must be set manually as follow. The upgrade module will de-duplicate the module version map. + // + // app.SetInitChainer(func(ctx sdk.Context, req *abci.RequestInitChain) (*abci.ResponseInitChain, error) { + // app.UpgradeKeeper.SetModuleVersionMap(ctx, app.ModuleManager.GetVersionMap()) + // 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 +} + +// 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/app/app_config_minimal.go.plush b/ignite/templates/app/files-minimal/app/app_config.go.plush similarity index 100% rename from ignite/templates/app/files/app/app_config_minimal.go.plush rename to ignite/templates/app/files-minimal/app/app_config.go.plush diff --git a/ignite/templates/app/files/app/app.go.plush b/ignite/templates/app/files/app/app.go.plush index 6516f5e5c9..99280aeeeb 100644 --- a/ignite/templates/app/files/app/app.go.plush +++ b/ignite/templates/app/files/app/app.go.plush @@ -20,7 +20,6 @@ import ( _ "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 -<%= if (!IsChainMinimal) { %> _ "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 @@ -34,7 +33,6 @@ import ( _ "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" "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/client" @@ -113,7 +111,6 @@ type App struct { DistrKeeper distrkeeper.Keeper ConsensusParamsKeeper consensuskeeper.Keeper -<%= if (!IsChainMinimal) { %> SlashingKeeper slashingkeeper.Keeper MintKeeper mintkeeper.Keeper GovKeeper *govkeeper.Keeper @@ -139,7 +136,6 @@ type App struct { ScopedIBCTransferKeeper capabilitykeeper.ScopedKeeper ScopedICAControllerKeeper capabilitykeeper.ScopedKeeper ScopedICAHostKeeper capabilitykeeper.ScopedKeeper -<% } %> // this line is used by starport scaffolding # stargate/app/keeperDeclaration @@ -156,7 +152,6 @@ func init() { DefaultNodeHome = filepath.Join(userHomeDir, "."+Name) } -<%= if (!IsChainMinimal) { %> // getGovProposalHandlers return the chain proposal handlers. func getGovProposalHandlers() []govclient.ProposalHandler { var govProposalHandlers []govclient.ProposalHandler @@ -169,7 +164,6 @@ func getGovProposalHandlers() []govclient.ProposalHandler { return govProposalHandlers } -<% } %> // AppConfig returns the default app config. func AppConfig() depinject.Config { @@ -181,9 +175,7 @@ func AppConfig() depinject.Config { // supply custom module basics map[string]module.AppModuleBasic{ genutiltypes.ModuleName: genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), - <%= if (!IsChainMinimal) { %> govtypes.ModuleName: gov.NewAppModuleBasic(getGovProposalHandlers()), - <% } %> // this line is used by starport scaffolding # stargate/appConfig/moduleBasic }, ), @@ -209,14 +201,12 @@ func New( depinject.Supply( // Supply the application options appOpts, - <%= if (!IsChainMinimal) { %> - // 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, - <% } %> + // 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, // Supply the logger logger, @@ -228,11 +218,11 @@ func New( // add it below. By default the auth module uses simulation.RandomGenesisAccounts. // // authtypes.RandomGenesisAccountsFn(simulation.RandomGenesisAccounts), - // + // // For providing a custom a base account type add it below. // By default the auth module uses authtypes.ProtoBaseAccount(). // - // func() sdk.AccountI { return authtypes.ProtoBaseAccount() }, + // func() sdk.AccountI { return authtypes.ProtoBaseAccount() }, // // For providing a different address codec, add it below. // By default the auth module uses a Bech32 address codec, @@ -273,7 +263,6 @@ func New( &app.StakingKeeper, &app.DistrKeeper, &app.ConsensusParamsKeeper, -<%= if (!IsChainMinimal) { %> &app.SlashingKeeper, &app.MintKeeper, &app.GovKeeper, @@ -285,7 +274,6 @@ func New( &app.FeeGrantKeeper, &app.GroupKeeper, &app.CircuitBreakerKeeper, -<% } %> // this line is used by starport scaffolding # stargate/app/keeperDefinition ); err != nil { panic(err) @@ -325,32 +313,24 @@ func New( app.App = appBuilder.Build(db, traceStore, baseAppOptions...) -<%= if (!IsChainMinimal) { %> // Register legacy modules app.registerIBCModules() -<% } %> // register streaming services - if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil { + if err := app.RegisterStreamingServices(appOpts, app.kvStoreKeys()); err != nil { return nil, err } /**** Module Options ****/ -<%= if (!IsChainMinimal) { %> app.ModuleManager.RegisterInvariants(app.CrisisKeeper) -<% } %> -<%= if (!IsChainMinimal) { %> // create the simulation manager and define the order of the modules for deterministic simulations // // NOTE: this is not required apps that don't use the simulator for fuzz testing transactions overrideModules := map[string]module.AppModuleSimulation{ authtypes.ModuleName: auth.NewAppModule(app.appCodec, app.AccountKeeper, authsims.RandomGenesisAccounts, app.GetSubspace(authtypes.ModuleName)), } -<% } else { %> - overrideModules := make(map[string]module.AppModuleSimulation) -<% } %> app.sm = module.NewSimulationManagerFromAppModules(app.ModuleManager.Modules, overrideModules) app.sm.RegisterStoreDecoders() @@ -419,7 +399,6 @@ func (app *App) kvStoreKeys() map[string]*storetypes.KVStoreKey { return keys } -<%= if (!IsChainMinimal) { %> // GetSubspace returns a param subspace for a given module name. func (app *App) GetSubspace(moduleName string) paramstypes.Subspace { subspace, _ := app.ParamsKeeper.GetSubspace(moduleName) @@ -435,7 +414,6 @@ func (app *App) GetIBCKeeper() *ibckeeper.Keeper { func (app *App) GetCapabilityScopedKeeper(moduleName string) capabilitykeeper.ScopedKeeper { return app.CapabilityKeeper.ScopeToModule(moduleName) } -<% } %> // SimulationManager implements the SimulationApp interface. func (app *App) SimulationManager() *module.SimulationManager {