diff --git a/spawn/cfg.go b/spawn/cfg.go index f0b14974..41c0cd4e 100644 --- a/spawn/cfg.go +++ b/spawn/cfg.go @@ -12,6 +12,7 @@ import ( "time" "github.com/rollchains/spawn/simapp" + "github.com/rollchains/spawn/spawn/types" localictypes "github.com/strangelove-ventures/interchaintest/local-interchain/interchain/types" "github.com/strangelove-ventures/interchaintest/v8/chain/cosmos" "github.com/strangelove-ventures/interchaintest/v8/ibc" @@ -59,7 +60,12 @@ type NewChainConfig struct { IgnoreGitInit bool DisabledModules []string Logger *slog.Logger - isUsingICS bool +} + +// NodeHome returns the full path to the node home directory +// ex: $HOME/.simapp +func (cfg NewChainConfig) NodeHome() string { + return path.Join("$HOME", cfg.HomeDir) } func (cfg NewChainConfig) ValidateAndRun(doAnnounce bool) error { @@ -84,16 +90,7 @@ func (cfg NewChainConfig) ValidateAndRun(doAnnounce bool) error { func (cfg *NewChainConfig) SetProperFeaturePairs() { d := RemoveDuplicates(cfg.DisabledModules) - isUsingICS := true - for _, name := range d { - if AliasName(name) == InterchainSecurity { - isUsingICS = false - } - } - cfg.isUsingICS = isUsingICS - - // remove POA if it is being used - if isUsingICS { + if cfg.IsFeatureEnabled(InterchainSecurity) { d = append(d, POA) } @@ -101,50 +98,41 @@ func (cfg *NewChainConfig) SetProperFeaturePairs() { cfg.Logger.Debug("SetProperFeaturePairs Disabled features", "features", cfg.DisabledModules) } -func (cfg *NewChainConfig) IsFeatureDisabled(featName string) bool { - for _, feat := range cfg.DisabledModules { - if AliasName(feat) == AliasName(featName) { - return true - } - } - return false -} - func (cfg *NewChainConfig) Validate() error { if cfg.ProjectName == "" { - return ErrCfgEmptyProject + return types.ErrCfgEmptyProject } if strings.ContainsAny(cfg.ProjectName, `~!@#$%^&*()_+{}|:"<>?/.,;'[]\=-`) { - return ErrCfgProjSpecialChars + return types.ErrCfgProjSpecialChars } if cfg.GithubOrg == "" { - return ErrCfgEmptyOrg + return types.ErrCfgEmptyOrg } minDenomLen := 3 if len(cfg.Denom) < minDenomLen { - return ErrExpectedRange(ErrCfgDenomTooShort, minDenomLen, len(cfg.Denom)) + return types.ErrExpectedRange(types.ErrCfgDenomTooShort, minDenomLen, len(cfg.Denom)) } minBinLen := 2 if len(cfg.BinDaemon) < minBinLen { - return ErrExpectedRange(ErrCfgBinTooShort, minBinLen, len(cfg.BinDaemon)) + return types.ErrExpectedRange(types.ErrCfgBinTooShort, minBinLen, len(cfg.BinDaemon)) } if cfg.Bech32Prefix == "" { - return ErrCfgEmptyBech32 + return types.ErrCfgEmptyBech32 } cfg.Bech32Prefix = strings.ToLower(cfg.Bech32Prefix) if !isAlphaFn(cfg.Bech32Prefix) { - return ErrCfgBech32Alpha + return types.ErrCfgBech32Alpha } minHomeLen := 2 if len(cfg.HomeDir) < minHomeLen { - return ErrExpectedRange(ErrCfgHomeDirTooShort, minHomeLen, len(cfg.HomeDir)) + return types.ErrExpectedRange(types.ErrCfgHomeDirTooShort, minHomeLen, len(cfg.HomeDir)) } if cfg.Logger == nil { @@ -196,6 +184,8 @@ func (cfg *NewChainConfig) CreateNewChain() error { } cfg.MetadataFile().SaveJSON(fmt.Sprintf("%s/chain_metadata.json", NewDirName)) + cfg.ChainRegistryFile().SaveJSON(fmt.Sprintf("%s/chain_registry.json", NewDirName)) + cfg.ChainRegistryAssetsFile().SaveJSON(fmt.Sprintf("%s/chain_registry_assets.json", NewDirName)) // setup local-interchain testnets // *testnet.json (chains/ directory) @@ -207,7 +197,7 @@ func (cfg *NewChainConfig) CreateNewChain() error { cfg.GitInitNewProjectRepo() } - if !cfg.IsFeatureDisabled("block-explorer") { + if cfg.IsFeatureEnabled("block-explorer") { cfg.NewPingPubExplorer() } @@ -322,7 +312,7 @@ func (cfg *NewChainConfig) SetupLocalInterchainJSON() { cosmos.NewGenesisKV("app_state.gov.params.min_deposit.0.amount", "1"), } - if cfg.isUsingICS { + if cfg.IsFeatureEnabled(InterchainSecurity) { c.SetICSConsumerLink("localcosmos-1") } else { // make this is an IBC testnet for POA/POS chains @@ -393,6 +383,16 @@ func GetFileContent(logger *slog.Logger, newFilePath string, fs embed.FS, relPat return fc, nil } +func (cfg *NewChainConfig) IsFeatureEnabled(feat string) bool { + featAlias := AliasName(feat) + for _, disabledFeat := range cfg.DisabledModules { + if AliasName(disabledFeat) == featAlias { + return false + } + } + return true +} + // debugErrorFile saves the errored file to a debug directory for easier debugging. // Returning the path to the file. func debugErrorFile(logger *slog.Logger, newDirname string) string { diff --git a/spawn/cfg_registry_schema.go b/spawn/cfg_registry_schema.go new file mode 100644 index 00000000..23ba9467 --- /dev/null +++ b/spawn/cfg_registry_schema.go @@ -0,0 +1,166 @@ +package spawn + +import ( + "fmt" + "strings" + + "golang.org/x/text/cases" + "golang.org/x/text/language" + + "github.com/rollchains/spawn/spawn/types" +) + +var caser = cases.Title(language.English) + +func (cfg NewChainConfig) ChainRegistryFile() types.ChainRegistryFormat { + // TODO: update as needed + DefaultSDKVersion := "0.50" + DefaultTendermintVersion := "0.38" + DefaultIBCGoVersion := "8" + DefaultCosmWasmVersion := "" + if cfg.IsFeatureEnabled(CosmWasm) { + DefaultCosmWasmVersion = "0.50" + } + DefaultConsensus := "tendermint" // TODO: gordian in the future on gen + + return types.ChainRegistryFormat{ + Schema: DefaultChainRegistrySchema, + ChainName: cfg.ProjectName, + ChainType: "cosmos", + Status: "live", + Website: DefaultWebsite, + NetworkType: DefaultNetworkType, + PrettyName: caser.String(cfg.ProjectName), + ChainID: DefaultChainID, + Bech32Prefix: cfg.Bech32Prefix, + DaemonName: cfg.BinDaemon, + NodeHome: cfg.NodeHome(), + KeyAlgos: []string{"secp256k1"}, + Slip44: DefaultSlip44CoinType, + Fees: types.Fees{ + FeeTokens: []types.FeeTokens{ + { + Denom: cfg.Denom, + FixedMinGasPrice: 0, + LowGasPrice: 0, + AverageGasPrice: 0.025, + HighGasPrice: 0.04, + }, + }, + }, + Codebase: types.Codebase{ + GitRepo: "https://" + cfg.GithubPath(), + RecommendedVersion: "v1.0.0", + CompatibleVersions: []string{"v0.9.0"}, + CosmosSdkVersion: DefaultSDKVersion, + Consensus: types.Consensus{ + Type: DefaultConsensus, + Version: DefaultTendermintVersion, + }, + CosmwasmVersion: DefaultCosmWasmVersion, + CosmwasmEnabled: cfg.IsFeatureEnabled(CosmWasm), + IbcGoVersion: DefaultIBCGoVersion, + IcsEnabled: []string{"ics20-1"}, + Genesis: types.Genesis{ + Name: "v1", + GenesisURL: fmt.Sprintf("https://%s/%s", cfg.GithubPath(), "networks/raw/main/genesis.json"), + }, + Versions: []types.Versions{ + { + Name: "v1.0.0", + Tag: "v1.0.0", + Height: 0, + NextVersionName: "v2", + }, + }, + }, + Staking: types.Staking{ + StakingTokens: []types.StakingTokens{ + { + Denom: cfg.Denom, + }, + }, + LockDuration: types.LockDuration{ + Time: "1814400s", // 21 days + }, + }, + Images: []types.Images{ + { + Png: DefaultLogo, + Theme: types.Theme{ + PrimaryColorHex: DefaultThemeHexColor, + }, + }, + }, + Peers: types.Peers{}, + Apis: types.Apis{ + RPC: []types.RPC{ + { + Address: "tcp://127.0.0.1:26657", + Provider: "localhost", + }, + }, + Rest: []types.Rest{ + { + Address: "tcp://127.0.0.1:1317", + Provider: "localhost", + }, + }, + }, + Explorers: []types.Explorers{ + { + Kind: "cosmos", + URL: "https://example.com", + TxPage: "https://example.com/tx", + AccountPage: "https://example.com/account", + }, + }, + Keywords: []string{"cosmos", "spawn"}, + } +} + +// The ICS MetadataFile is similar to this. +func (cfg NewChainConfig) ChainRegistryAssetsFile() types.ChainRegistryAssetsList { + display := strings.TrimPrefix(strings.ToUpper(cfg.Denom), "U") + + return types.ChainRegistryAssetsList{ + Schema: DefaultChainRegistryAssetsSchema, + ChainName: cfg.ProjectName, + Assets: []types.Assets{ + { + Description: "The native token of " + cfg.ProjectName, + DenomUnits: []types.DenomUnits{ + { + Denom: cfg.Denom, // utoken + Exponent: 0, + }, + { + Denom: display, // TOKEN + Exponent: 6, + }, + }, + Base: cfg.Denom, // utoken + Name: fmt.Sprintf("%s %s", cfg.ProjectName, display), + Display: strings.ToLower(display), // token + Symbol: display, // TOKEN + LogoURIs: types.LogoURIs{ + Png: DefaultLogo, + Svg: DefaultLogoSVG, + }, + Images: []types.ImagesAssetLists{ + { + Png: DefaultLogo, + Svg: DefaultLogoSVG, + Theme: types.Theme{ + PrimaryColorHex: DefaultThemeHexColor, + }, + }, + }, + Socials: types.Socials{ + Website: DefaultWebsite, + Twitter: "https://x.com/cosmoshub", + }, + }, + }, + } +} diff --git a/spawn/cfg_test.go b/spawn/cfg_test.go index 8a38c5f5..0d4a51d4 100644 --- a/spawn/cfg_test.go +++ b/spawn/cfg_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/rollchains/spawn/spawn" + "github.com/rollchains/spawn/spawn/types" "github.com/stretchr/testify/require" ) @@ -208,22 +209,22 @@ func goodCfg() spawn.NewChainConfig { func TestBadConfigInputs(t *testing.T) { chainCases := []cfgCase{ NewCfgCase("valid config", goodCfg(), nil), - NewCfgCase("no github org", goodCfg().WithOrg(""), spawn.ErrCfgEmptyOrg), - NewCfgCase("no project name", goodCfg().WithProjectName(""), spawn.ErrCfgEmptyProject), - NewCfgCase("project special chars -", goodCfg().WithProjectName("my-project"), spawn.ErrCfgProjSpecialChars), - NewCfgCase("project special chars /", goodCfg().WithProjectName("my/project"), spawn.ErrCfgProjSpecialChars), - NewCfgCase("binary name to short len 1", goodCfg().WithBinDaemon("a"), spawn.ErrCfgBinTooShort), + NewCfgCase("no github org", goodCfg().WithOrg(""), types.ErrCfgEmptyOrg), + NewCfgCase("no project name", goodCfg().WithProjectName(""), types.ErrCfgEmptyProject), + NewCfgCase("project special chars -", goodCfg().WithProjectName("my-project"), types.ErrCfgProjSpecialChars), + NewCfgCase("project special chars /", goodCfg().WithProjectName("my/project"), types.ErrCfgProjSpecialChars), + NewCfgCase("binary name to short len 1", goodCfg().WithBinDaemon("a"), types.ErrCfgBinTooShort), NewCfgCase("success: binary name len 2", goodCfg().WithBinDaemon("ad"), nil), - NewCfgCase("token denom too short len 1", goodCfg().WithDenom("a"), spawn.ErrCfgDenomTooShort), - NewCfgCase("token denom too short len 2", goodCfg().WithDenom("ab"), spawn.ErrCfgDenomTooShort), + NewCfgCase("token denom too short len 1", goodCfg().WithDenom("a"), types.ErrCfgDenomTooShort), + NewCfgCase("token denom too short len 2", goodCfg().WithDenom("ab"), types.ErrCfgDenomTooShort), NewCfgCase("success: token denom special chars", goodCfg().WithDenom("my-cool/token"), nil), NewCfgCase("success: token denom 3", goodCfg().WithDenom("abc"), nil), - NewCfgCase("home dir too short", goodCfg().WithHomeDir("."), spawn.ErrCfgHomeDirTooShort), + NewCfgCase("home dir too short", goodCfg().WithHomeDir("."), types.ErrCfgHomeDirTooShort), NewCfgCase("success: home dir valid", goodCfg().WithHomeDir(".a"), nil), - NewCfgCase("bech32 prefix to short", goodCfg().WithBech32Prefix(""), spawn.ErrCfgEmptyBech32), - NewCfgCase("bech32 not alpha", goodCfg().WithBech32Prefix("c919"), spawn.ErrCfgBech32Alpha), - NewCfgCase("bech32 not alpha", goodCfg().WithBech32Prefix("1"), spawn.ErrCfgBech32Alpha), - NewCfgCase("bech32 not alpha", goodCfg().WithBech32Prefix("---"), spawn.ErrCfgBech32Alpha), + NewCfgCase("bech32 prefix to short", goodCfg().WithBech32Prefix(""), types.ErrCfgEmptyBech32), + NewCfgCase("bech32 not alpha", goodCfg().WithBech32Prefix("c919"), types.ErrCfgBech32Alpha), + NewCfgCase("bech32 not alpha", goodCfg().WithBech32Prefix("1"), types.ErrCfgBech32Alpha), + NewCfgCase("bech32 not alpha", goodCfg().WithBech32Prefix("---"), types.ErrCfgBech32Alpha), NewCfgCase("success: bech32 prefix", goodCfg().WithBech32Prefix("c"), nil), } @@ -242,3 +243,12 @@ func TestBadConfigInputs(t *testing.T) { }) } } + +func TestChainRegistry(t *testing.T) { + cfg := goodCfg() + cr := cfg.ChainRegistryFile() + require.Equal(t, cfg.ProjectName, cr.ChainName) + require.Equal(t, bech, cr.Bech32Prefix) + require.Equal(t, bin, cr.DaemonName) + require.Equal(t, denom, cr.Fees.FeeTokens[0].Denom) +} diff --git a/spawn/metadata.go b/spawn/metadata.go index e8b7836f..5ed42878 100644 --- a/spawn/metadata.go +++ b/spawn/metadata.go @@ -7,6 +7,19 @@ import ( "time" ) +const ( + DefaultWebsite = "https://example.com" + DefaultLogo = "https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.png" + DefaultLogoSVG = "https://raw.githubusercontent.com/cosmos/chain-registry/master/cosmoshub/images/atom.svg" + DefaultDescription = "A short description of your project" + DefaultChainID = "newchain-1" + DefaultNetworkType = "testnet" // or mainnet + DefaultSlip44CoinType = 118 + DefaultChainRegistrySchema = "https://raw.githubusercontent.com/cosmos/chain-registry/master/chain.schema.json" + DefaultChainRegistryAssetsSchema = "https://github.com/cosmos/chain-registry/blob/master/assetlist.schema.json" + DefaultThemeHexColor = "#FF2D00" +) + func (cfg *NewChainConfig) MetadataFile() MetadataFile { now := time.Now().UTC() now = now.Round(time.Minute) @@ -23,10 +36,10 @@ func (cfg *NewChainConfig) MetadataFile() MetadataFile { Project: ProjectMeta{ Github: cfg.GithubPath(), TargetLaunchDate: now, - Logo: "https://example.com/logo.png", - Website: "https://example.com", - Description: "A short description of your project", - ShortDescription: "A short description of your project", + Logo: DefaultLogo, + Website: DefaultWebsite, + Description: DefaultDescription, + ShortDescription: DefaultDescription, Whitepaper: "https://example.com/whitepaper.pdf", Contact: ContactMeta{ Email: "", @@ -39,12 +52,12 @@ func (cfg *NewChainConfig) MetadataFile() MetadataFile { ICS: ICSMeta{}, } - if cfg.isUsingICS { + if cfg.IsFeatureEnabled(InterchainSecurity) { mf.ICS = ICSMeta{ SpawnTime: now, Title: cfg.BinDaemon, - Summary: ".md description of your chain and all other relevant information", - ChainID: "newchain-1", + Summary: DefaultDescription + " ( in .md format)", + ChainID: DefaultChainID, InitialHeight: ICSClientTypes{ RevisionHeight: 0, RevisionNumber: 1, diff --git a/spawn/proto_parser.go b/spawn/proto_parser.go index 547d4d6d..0753bdf4 100644 --- a/spawn/proto_parser.go +++ b/spawn/proto_parser.go @@ -9,6 +9,62 @@ import ( "strings" ) +/// --- types --- + +// FileType tells the application which type of proto file is it so we can sort Txs from Queries +type FileType string + +const ( + Tx FileType = "tx" + Query FileType = "query" + None FileType = "none" +) + +// get the str of FileType +func (ft FileType) String() string { + return string(ft) +} + +// ModuleMapping a map of the module name to a list of ProtoRPCs +type ModuleMapping map[string][]*ProtoRPC + +func (mm ModuleMapping) Print(logger *slog.Logger) { + for name, v := range mm { + v := v + name := name + + for _, rpc := range v { + logger.Debug("module", "module", name, "rpc", rpc.Name, "req", rpc.Req, "res", rpc.Res, "module", rpc.Module, "ftype", rpc.FType, "fileloc", rpc.FileLoc) + } + } +} + +// A Proto server RPC method. +type ProtoRPC struct { + // The name of the proto RPC service (i.e. rpc Params would be Params for the name) + Name string + // The request object, such as QueryParamsRequest (queries) or MsgUpdateParams (txs) + Req string + // The response object, such as QueryParamsResponse (queries) or MsgUpdateParamsResponse (txs) + Res string + + // The name of the cosmos extension (x/module) + Module string + // The type of file this proto service is (tx, query, none) + FType FileType + // Where there Query/Msg Server is located (querier.go, msgserver.gom, etc.) + FileLoc string +} + +func (pr *ProtoRPC) String() string { + return fmt.Sprintf( + "Name: %s, Req: %s, Res: %s, Module: %s, FType: %s, FileLoc: %s", + pr.Name, pr.Req, pr.Res, pr.Module, pr.FType, pr.FileLoc, + ) +} + +// -------------- + // BuildProtoInterfaceStub returns the string to save to the file for the msgServer or Querier. func (pr ProtoRPC) BuildProtoInterfaceStub() string { if pr.FType == Tx { @@ -350,7 +406,7 @@ func ApplyMissingRPCMethodsToGoSourceFiles(logger *slog.Logger, missingRPCMethod content = append(content, []byte("\n"+code)...) if err := os.WriteFile(fileLoc, content, 0644); err != nil { - logger.Error("Error: ", err) + logger.Error("error", "err", err) return err } } diff --git a/spawn/proto_types.go b/spawn/proto_types.go deleted file mode 100644 index 414598f1..00000000 --- a/spawn/proto_types.go +++ /dev/null @@ -1,58 +0,0 @@ -package spawn - -import ( - "fmt" - "log/slog" -) - -// FileType tells the application which type of proto file is it so we can sort Txs from Queries -type FileType string - -const ( - Tx FileType = "tx" - Query FileType = "query" - None FileType = "none" -) - -// get the str of FileType -func (ft FileType) String() string { - return string(ft) -} - -// ModuleMapping a map of the module name to a list of ProtoRPCs -type ModuleMapping map[string][]*ProtoRPC - -func (mm ModuleMapping) Print(logger *slog.Logger) { - for name, v := range mm { - v := v - name := name - - for _, rpc := range v { - logger.Debug("module", "module", name, "rpc", rpc.Name, "req", rpc.Req, "res", rpc.Res, "module", rpc.Module, "ftype", rpc.FType, "fileloc", rpc.FileLoc) - } - } -} - -// A Proto server RPC method. -type ProtoRPC struct { - // The name of the proto RPC service (i.e. rpc Params would be Params for the name) - Name string - // The request object, such as QueryParamsRequest (queries) or MsgUpdateParams (txs) - Req string - // The response object, such as QueryParamsResponse (queries) or MsgUpdateParamsResponse (txs) - Res string - - // The name of the cosmos extension (x/module) - Module string - // The type of file this proto service is (tx, query, none) - FType FileType - // Where there Query/Msg Server is located (querier.go, msgserver.gom, etc.) - FileLoc string -} - -func (pr *ProtoRPC) String() string { - return fmt.Sprintf( - "Name: %s, Req: %s, Res: %s, Module: %s, FType: %s, FileLoc: %s", - pr.Name, pr.Req, pr.Res, pr.Module, pr.FType, pr.FileLoc, - ) -} diff --git a/spawn/remove_features.go b/spawn/remove_features.go index e5f73cf6..7a22da8a 100644 --- a/spawn/remove_features.go +++ b/spawn/remove_features.go @@ -88,7 +88,7 @@ func (fc *FileContent) RemoveDisabledFeatures(cfg *NewChainConfig) { case GlobalFee: fc.RemoveGlobalFee() case CosmWasm: - fc.RemoveCosmWasm(cfg.IsFeatureDisabled(WasmLC)) + fc.RemoveCosmWasm(!cfg.IsFeatureEnabled(WasmLC)) case WasmLC: fc.RemoveWasmLightClient() case PacketForward: @@ -107,7 +107,7 @@ func (fc *FileContent) RemoveDisabledFeatures(cfg *NewChainConfig) { } } - if cfg.isUsingICS { + if cfg.IsFeatureEnabled(InterchainSecurity) { fc.RemoveStandardTestNodeScript() fc.HandleAllTagged("not-ics") // interchaintest fc.removePacketForwardTestOnly() diff --git a/spawn/types/chain_registry.go b/spawn/types/chain_registry.go new file mode 100644 index 00000000..f2ffbe77 --- /dev/null +++ b/spawn/types/chain_registry.go @@ -0,0 +1,141 @@ +package types + +import ( + "encoding/json" + "os" +) + +// TOOL: https://mholt.github.io/json-to-go/ +// Manual Modifications: +// - Consensus: add omitempty +// - Codebase.Consensus: add omitempty +// - Peers: add omitempty +// - added: ChainRegistryFormat ChainType string + +type ChainRegistryFormat struct { + Schema string `json:"$schema"` + ChainName string `json:"chain_name"` + ChainType string `json:"chain_type"` + Status string `json:"status"` + Website string `json:"website"` + NetworkType string `json:"network_type"` + PrettyName string `json:"pretty_name"` + ChainID string `json:"chain_id"` + Bech32Prefix string `json:"bech32_prefix"` + DaemonName string `json:"daemon_name"` + NodeHome string `json:"node_home"` + KeyAlgos []string `json:"key_algos"` + Slip44 int `json:"slip44"` + Fees Fees `json:"fees"` + Staking Staking `json:"staking"` + Codebase Codebase `json:"codebase"` + Images []Images `json:"images"` + Peers Peers `json:"peers"` + Apis Apis `json:"apis"` + Explorers []Explorers `json:"explorers"` + Keywords []string `json:"keywords"` +} +type FeeTokens struct { + Denom string `json:"denom"` + FixedMinGasPrice int `json:"fixed_min_gas_price"` + LowGasPrice int `json:"low_gas_price"` + AverageGasPrice float64 `json:"average_gas_price"` + HighGasPrice float64 `json:"high_gas_price"` +} +type Fees struct { + FeeTokens []FeeTokens `json:"fee_tokens"` +} +type StakingTokens struct { + Denom string `json:"denom"` +} +type LockDuration struct { + Time string `json:"time"` +} +type Staking struct { + StakingTokens []StakingTokens `json:"staking_tokens"` + LockDuration LockDuration `json:"lock_duration"` +} +type Consensus struct { + Type string `json:"type,omitempty"` + Version string `json:"version,omitempty"` +} +type Genesis struct { + Name string `json:"name"` + GenesisURL string `json:"genesis_url"` +} +type Versions struct { + Name string `json:"name"` + Tag string `json:"tag"` + Height int `json:"height"` + NextVersionName string `json:"next_version_name"` + Proposal int `json:"proposal,omitempty"` + RecommendedVersion string `json:"recommended_version,omitempty"` + CompatibleVersions []string `json:"compatible_versions,omitempty"` + CosmosSdkVersion string `json:"cosmos_sdk_version,omitempty"` + Consensus Consensus `json:"consensus,omitempty"` + CosmwasmVersion string `json:"cosmwasm_version,omitempty"` + CosmwasmEnabled bool `json:"cosmwasm_enabled,omitempty"` + IbcGoVersion string `json:"ibc_go_version,omitempty"` + IcsEnabled []string `json:"ics_enabled,omitempty"` +} +type Codebase struct { + GitRepo string `json:"git_repo"` + RecommendedVersion string `json:"recommended_version"` + CompatibleVersions []string `json:"compatible_versions"` + CosmosSdkVersion string `json:"cosmos_sdk_version"` + Consensus Consensus `json:"consensus,omitempty"` + CosmwasmVersion string `json:"cosmwasm_version"` + CosmwasmEnabled bool `json:"cosmwasm_enabled"` + IbcGoVersion string `json:"ibc_go_version"` + IcsEnabled []string `json:"ics_enabled"` + Genesis Genesis `json:"genesis"` + Versions []Versions `json:"versions"` +} +type Theme struct { + PrimaryColorHex string `json:"primary_color_hex"` +} +type Images struct { + Png string `json:"png"` + Theme Theme `json:"theme"` +} +type Seeds struct { + ID string `json:"id"` + Address string `json:"address"` + Provider string `json:"provider"` +} +type PersistentPeers struct { + ID string `json:"id"` + Address string `json:"address"` + Provider string `json:"provider"` +} +type Peers struct { + Seeds []Seeds `json:"seeds,omitempty"` + PersistentPeers []PersistentPeers `json:"persistent_peers,omitempty"` +} +type RPC struct { + Address string `json:"address"` + Provider string `json:"provider"` +} +type Rest struct { + Address string `json:"address"` + Provider string `json:"provider"` +} +type Apis struct { + RPC []RPC `json:"rpc"` + Rest []Rest `json:"rest"` +} +type Explorers struct { + Kind string `json:"kind"` + URL string `json:"url"` + TxPage string `json:"tx_page"` + AccountPage string `json:"account_page"` +} + +func (v ChainRegistryFormat) SaveJSON(loc string) error { + bz, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + + return os.WriteFile(loc, bz, 0644) +} diff --git a/spawn/types/chain_registry_assets_list.go b/spawn/types/chain_registry_assets_list.go new file mode 100644 index 00000000..318bafd2 --- /dev/null +++ b/spawn/types/chain_registry_assets_list.go @@ -0,0 +1,53 @@ +package types + +import ( + "encoding/json" + "os" +) + +// Update: Images -> ImagesAssetLists +// - Fix: Assets.Images -> new type ImagesAssetLists + +type ChainRegistryAssetsList struct { + Schema string `json:"$schema"` + ChainName string `json:"chain_name"` + Assets []Assets `json:"assets"` +} +type DenomUnits struct { + Denom string `json:"denom"` + Exponent int `json:"exponent"` +} +type LogoURIs struct { + Png string `json:"png"` + Svg string `json:"svg"` +} +type ImagesAssetLists struct { + Png string `json:"png"` + Svg string `json:"svg"` + Theme Theme `json:"theme,omitempty"` +} +type Assets struct { + Description string `json:"description"` + DenomUnits []DenomUnits `json:"denom_units"` + Base string `json:"base"` + Name string `json:"name"` + Display string `json:"display"` + Symbol string `json:"symbol"` + LogoURIs LogoURIs `json:"logo_URIs"` + Images []ImagesAssetLists `json:"images"` + Socials Socials `json:"socials,omitempty"` +} + +type Socials struct { + Website string `json:"website,omitempty"` + Twitter string `json:"twitter,omitempty"` +} + +func (v ChainRegistryAssetsList) SaveJSON(loc string) error { + bz, err := json.MarshalIndent(v, "", " ") + if err != nil { + return err + } + + return os.WriteFile(loc, bz, 0644) +} diff --git a/spawn/errors.go b/spawn/types/errors.go similarity index 98% rename from spawn/errors.go rename to spawn/types/errors.go index 26500c3f..a47832ee 100644 --- a/spawn/errors.go +++ b/spawn/types/errors.go @@ -1,4 +1,4 @@ -package spawn +package types import ( "errors"