diff --git a/changelog.md b/changelog.md index 9df923d297..dc9cbd494b 100644 --- a/changelog.md +++ b/changelog.md @@ -9,7 +9,7 @@ ### Fixes - [#4686](https://github.com/ignite/cli/pull/4686) Filter discovered protos to only messages. -- [#4691](https://github.com/ignite/cli/pull/4691), [#4706](https://github.com/ignite/cli/pull/4706), [#4725](https://github.com/ignite/cli/pull/4725) Fix ts-client query template and solely Go template for `ts-client` generation. +- [#4691](https://github.com/ignite/cli/pull/4691), [#4706](https://github.com/ignite/cli/pull/4706), [#4725](https://github.com/ignite/cli/pull/4725), [#4737](https://github.com/ignite/cli/pull/4737) Fix ts-client query template and solely Go template for `ts-client` generation. ## [`v28.10.0`](https://github.com/ignite/cli/releases/tag/v28.10.0) diff --git a/ignite/pkg/cosmosbuf/buf.go b/ignite/pkg/cosmosbuf/buf.go index 51937d127e..1a7af9b5f3 100644 --- a/ignite/pkg/cosmosbuf/buf.go +++ b/ignite/pkg/cosmosbuf/buf.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "path/filepath" + "strings" "github.com/gobwas/glob" "golang.org/x/sync/errgroup" @@ -67,6 +68,7 @@ type ( fileByFile bool includeImports bool includeWKT bool + moduleName string } // GenOption configures code generation. @@ -80,6 +82,7 @@ func newGenOptions() genOptions { fileByFile: false, includeWKT: false, includeImports: false, + moduleName: "", } } @@ -115,6 +118,13 @@ func IncludeWKT() GenOption { } } +// WithModuleName sets the module name to filter protos for. +func WithModuleName(value string) GenOption { + return func(o *genOptions) { + o.moduleName = value + } +} + // FileByFile runs the generate command for each proto file. func FileByFile() GenOption { return func(o *genOptions) { @@ -197,9 +207,13 @@ func (b Buf) Generate( for _, apply := range options { apply(&opts) } - + modulePath := protoPath + if opts.moduleName != "" { + path := append([]string{protoPath}, strings.Split(opts.moduleName, ".")...) + modulePath = filepath.Join(path...) + } // find all proto files into the path. - foundFiles, err := xos.FindFilesExtension(protoPath, xos.ProtoFile) + foundFiles, err := xos.FindFilesExtension(modulePath, xos.ProtoFile) if err != nil || len(foundFiles) == 0 { return err } diff --git a/ignite/pkg/cosmosgen/generate_typescript.go b/ignite/pkg/cosmosgen/generate_typescript.go index c8a5e1d7da..26b84204f8 100644 --- a/ignite/pkg/cosmosgen/generate_typescript.go +++ b/ignite/pkg/cosmosgen/generate_typescript.go @@ -59,6 +59,11 @@ func (g *generator) generateTS(ctx context.Context) error { return err } + // add third party modules to for the root template. + for _, modules := range g.thirdModules { + data.Modules = append(data.Modules, modules...) + } + return tsg.generateRootTemplates(data) } @@ -132,6 +137,7 @@ func (g *tsGenerator) generateModuleTemplate( // All "cosmossdk.io" module packages must use SDK's // proto path which is where the proto files are stored. protoPath := filepath.Join(appPath, g.g.protoDir) // use module app path + if module.IsCosmosSDKPackage(appPath) { protoPath = filepath.Join(g.g.sdkDir, "proto") } @@ -144,7 +150,7 @@ func (g *tsGenerator) generateModuleTemplate( g.g.tsTemplate(), cosmosbuf.ExcludeFiles("module.proto"), cosmosbuf.IncludeWKT(), - // TODO: we should exclude folders that are irrelevant for the module. + cosmosbuf.WithModuleName(m.Pkg.Name), ); err != nil { return err } diff --git a/ignite/pkg/cosmosgen/generate_typescript_test.go b/ignite/pkg/cosmosgen/generate_typescript_test.go index ee7f6106fc..0e8b6abd9a 100644 --- a/ignite/pkg/cosmosgen/generate_typescript_test.go +++ b/ignite/pkg/cosmosgen/generate_typescript_test.go @@ -2,8 +2,10 @@ package cosmosgen import ( "context" + "fmt" "os" "path/filepath" + "strings" "testing" "github.com/ettle/strcase" @@ -39,9 +41,10 @@ func TestGenerateTypeScript(t *testing.T) { buf: buf, appModules: m, opts: &generateOptions{ - useCache: false, + tsClientRootPath: tsClientDir, + useCache: false, jsOut: func(m module.Module) string { - return filepath.Join(tsClientDir, strcase.ToKebab(m.Name)) + return filepath.Join(tsClientDir, fmt.Sprintf("%s.%s.%s", "ignite", "planet", strcase.ToKebab(m.Name))) }, }, }) @@ -49,6 +52,12 @@ func TestGenerateTypeScript(t *testing.T) { err = g.generateModuleTemplate(context.Background(), appDir, m[0]) require.NoError(err, "failed to generate TypeScript files") + err = g.generateRootTemplates(generatePayload{ + Modules: m, + PackageNS: strings.ReplaceAll(appDir, "/", "-"), + }) + require.NoError(err) + // compare all generated files to golden files goldenDir := filepath.Join(testdataDir, "expected_files", "ts-client") _ = filepath.Walk(goldenDir, func(path string, info os.FileInfo, err error) error { diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/client.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/client.ts new file mode 100755 index 0000000000..663979e017 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/client.ts @@ -0,0 +1,164 @@ +/// +import { + GeneratedType, + OfflineSigner, + EncodeObject, + Registry, +} from "@cosmjs/proto-signing"; +import { SigningStargateClient, StdFee } from "@cosmjs/stargate"; +import { Env } from "./env"; +import { UnionToIntersection, Return, Constructor } from "./helpers"; +import { IgntModule } from "./modules"; +import { EventEmitter } from "events"; +import { ChainInfo } from "@keplr-wallet/types"; + +const defaultFee = { + amount: [], + gas: "200000", +}; + +export class IgniteClient extends EventEmitter { + static plugins: IgntModule[] = []; + env: Env; + signer?: OfflineSigner; + registry: Array<[string, GeneratedType]> = []; + static plugin(plugin: T) { + const currentPlugins = this.plugins; + + class AugmentedClient extends this { + static plugins = currentPlugins.concat(plugin); + } + + if (Array.isArray(plugin)) { + type Extension = UnionToIntersection['module']> + return AugmentedClient as typeof IgniteClient & Constructor; + } + + type Extension = Return['module'] + return AugmentedClient as typeof IgniteClient & Constructor; + } + + async signAndBroadcast(msgs: EncodeObject[], fee: StdFee, memo: string) { + if (this.signer) { + const { address } = (await this.signer.getAccounts())[0]; + const signingClient = await SigningStargateClient.connectWithSigner(this.env.rpcURL, this.signer, { registry: new Registry(this.registry) }); + return await signingClient.signAndBroadcast(address, msgs, fee ? fee : defaultFee, memo) + } else { + throw new Error(" Signer is not present."); + } + } + + constructor(env: Env, signer?: OfflineSigner) { + super(); + this.env = env; + this.setMaxListeners(0); + this.signer = signer; + const classConstructor = this.constructor as typeof IgniteClient; + classConstructor.plugins.forEach(plugin => { + const pluginInstance = plugin(this); + Object.assign(this, pluginInstance.module) + if (this.registry) { + this.registry = this.registry.concat(pluginInstance.registry) + } + }); + } + useSigner(signer: OfflineSigner) { + this.signer = signer; + this.emit("signer-changed", this.signer); + } + removeSigner() { + this.signer = undefined; + this.emit("signer-changed", this.signer); + } + async useKeplr(keplrChainInfo: Partial = {}) { + // Using queryClients directly because BaseClient has no knowledge of the modules at this stage + try { + const queryClient = ( + await import("./cosmos.base.tendermint.v1beta1/module") + ).queryClient; + const bankQueryClient = (await import("./cosmos.bank.v1beta1/module")) + .queryClient; + const stakingQueryClient = (await import("./cosmos.staking.v1beta1/module")).queryClient; + const stakingqc = stakingQueryClient({ addr: this.env.apiURL }); + const staking = await (await stakingqc.queryParams()).data; + const qc = queryClient({ addr: this.env.apiURL }); + const node_info = await (await qc.serviceGetNodeInfo()).data; + const chainId = node_info.default_node_info?.network ?? ""; + const chainName = chainId?.toUpperCase() + " Network"; + const bankqc = bankQueryClient({ addr: this.env.apiURL }); + const tokens = await (await bankqc.queryTotalSupply()).data; + const addrPrefix = this.env.prefix ?? "cosmos"; + const rpc = this.env.rpcURL; + const rest = this.env.apiURL; + + let bip44 = { + coinType: 118, + }; + + let bech32Config = { + bech32PrefixAccAddr: addrPrefix, + bech32PrefixAccPub: addrPrefix + "pub", + bech32PrefixValAddr: addrPrefix + "valoper", + bech32PrefixValPub: addrPrefix + "valoperpub", + bech32PrefixConsAddr: addrPrefix + "valcons", + bech32PrefixConsPub: addrPrefix + "valconspub", + }; + + let currencies = + tokens.supply?.map((x) => { + const y = { + coinDenom: x.denom?.toUpperCase() ?? "", + coinMinimalDenom: x.denom ?? "", + coinDecimals: 0, + }; + return y; + }) ?? []; + + let stakeCurrency = { + coinDenom: staking.params?.bond_denom?.toUpperCase() ?? "", + coinMinimalDenom: staking.params?.bond_denom ?? "", + coinDecimals: 0, + }; + + let feeCurrencies = + tokens.supply?.map((x) => { + const y = { + coinDenom: x.denom?.toUpperCase() ?? "", + coinMinimalDenom: x.denom ?? "", + coinDecimals: 0, + }; + return y; + }) ?? []; + + if (chainId) { + const suggestOptions: ChainInfo = { + chainId, + chainName, + rpc, + rest, + stakeCurrency, + bip44, + bech32Config, + currencies, + feeCurrencies, + ...keplrChainInfo, + }; + await window.keplr.experimentalSuggestChain(suggestOptions); + + window.keplr.defaultOptions = { + sign: { + preferNoSetFee: true, + preferNoSetMemo: true, + }, + }; + } + await window.keplr.enable(chainId); + this.signer = window.keplr.getOfflineSigner(chainId); + this.emit("signer-changed", this.signer); + } catch (e) { + throw new Error( + "Could not load tendermint, staking and bank modules. Please ensure your client loads them to use useKeplr()" + ); + } + } +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/env.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/env.ts new file mode 100755 index 0000000000..92558e4be6 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/env.ts @@ -0,0 +1,7 @@ +import { OfflineSigner } from "@cosmjs/proto-signing"; + +export interface Env { + apiURL: string + rpcURL: string + prefix?: string +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/helpers.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/helpers.ts new file mode 100755 index 0000000000..d8ccd3d0b5 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/helpers.ts @@ -0,0 +1,32 @@ +export type Constructor = new (...args: any[]) => T; + +export type AnyFunction = (...args: any) => any; + +export type UnionToIntersection = + (Union extends any + ? (argument: Union) => void + : never + ) extends (argument: infer Intersection) => void + ? Intersection + : never; + +export type Return = + T extends AnyFunction + ? ReturnType + : T extends AnyFunction[] + ? UnionToIntersection> + : never + + +export const MissingWalletError = new Error("wallet is required"); + +export function getStructure(template) { + let structure = { fields: [] as Array} + for (const [key, value] of Object.entries(template)) { + let field: any = {} + field.name = key + field.type = typeof value + structure.fields.push(field) + } + return structure +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/index.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/index.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/index.ts rename to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/index.ts diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/module.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/module.ts similarity index 97% rename from ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/module.ts rename to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/module.ts index 5c2775ac94..407fb04bd8 100755 --- a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/module.ts +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/module.ts @@ -6,8 +6,8 @@ import { msgTypes } from './registry'; import { IgniteClient } from "../client" import { MissingWalletError } from "../helpers" import { Api } from "./rest"; -import { MsgMyMessageRequest } from "./types/planet/mars/mars"; -import { MsgBarRequest } from "./types/planet/mars/mars"; +import { MsgMyMessageRequest } from "./types/ignite/planet/mars/mars"; +import { MsgBarRequest } from "./types/ignite/planet/mars/mars"; import { AnotherType as typeAnotherType} from "./types" diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/registry.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/registry.ts similarity index 66% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/registry.ts rename to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/registry.ts index d94c1d053e..585b8c64a1 100755 --- a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/registry.ts +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/registry.ts @@ -1,6 +1,6 @@ import { GeneratedType } from "@cosmjs/proto-signing"; -import { MsgMyMessageRequest } from "./types/planet/mars/mars"; -import { MsgBarRequest } from "./types/planet/mars/mars"; +import { MsgMyMessageRequest } from "./types/ignite/planet/mars/mars"; +import { MsgBarRequest } from "./types/ignite/planet/mars/mars"; const msgTypes: Array<[string, GeneratedType]> = [ ["/ignite.planet.mars.MsgMyMessageRequest", MsgMyMessageRequest], diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/rest.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/rest.ts similarity index 93% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/rest.ts rename to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/rest.ts index b4bd30275d..f239419cb3 100755 --- a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/rest.ts +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/rest.ts @@ -1,15 +1,15 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios"; -import { QuerySimpleResponse } from "./types/planet/mars/mars"; -import { QuerySimpleParamsResponse } from "./types/planet/mars/mars"; -import { QueryWithPaginationResponse } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsResponse } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsWithPaginationResponse } from "./types/planet/mars/mars"; +import { QuerySimpleResponse } from "./types/ignite/planet/mars/mars"; +import { QuerySimpleParamsResponse } from "./types/ignite/planet/mars/mars"; +import { QueryWithPaginationResponse } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsResponse } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsWithPaginationResponse } from "./types/ignite/planet/mars/mars"; -import { QuerySimpleRequest } from "./types/planet/mars/mars"; -import { QuerySimpleParamsRequest } from "./types/planet/mars/mars"; -import { QueryWithPaginationRequest } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsRequest } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsWithPaginationRequest } from "./types/planet/mars/mars"; +import { QuerySimpleRequest } from "./types/ignite/planet/mars/mars"; +import { QuerySimpleParamsRequest } from "./types/ignite/planet/mars/mars"; +import { QueryWithPaginationRequest } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsRequest } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsWithPaginationRequest } from "./types/ignite/planet/mars/mars"; import type {SnakeCasedPropertiesDeep} from 'type-fest'; diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types.ts new file mode 100755 index 0000000000..c9d8622576 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types.ts @@ -0,0 +1,7 @@ +import { AnotherType } from "./types/ignite/planet/mars/mars" + + +export { + AnotherType, + + } \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types/planet/mars/mars.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types/ignite/planet/mars/mars.ts similarity index 99% rename from ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types/planet/mars/mars.ts rename to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types/ignite/planet/mars/mars.ts index d7dd4ba1bc..adb90423fc 100644 --- a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types/planet/mars/mars.ts +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types/ignite/planet/mars/mars.ts @@ -2,11 +2,11 @@ // versions: // protoc-gen-ts_proto v2.6.1 // protoc unknown -// source: planet/mars/mars.proto +// source: ignite/planet/mars/mars.proto /* eslint-disable */ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -import { PageRequest, PageResponse } from "../../cosmos/base/query/v1beta1/pagination"; +import { PageRequest, PageResponse } from "../../../cosmos/base/query/v1beta1/pagination"; export const protobufPackage = "ignite.planet.mars"; diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types/route-name.eta b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types/route-name.eta similarity index 100% rename from ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types/route-name.eta rename to ignite/pkg/cosmosgen/testdata/expected_files/ts-client/ignite.planet.mars/types/route-name.eta diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/index.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/index.ts new file mode 100755 index 0000000000..80ec020167 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/index.ts @@ -0,0 +1,21 @@ +// Generated by Ignite ignite.com/cli +import { Registry } from '@cosmjs/proto-signing' +import { IgniteClient } from "./client"; +import { MissingWalletError } from "./helpers"; +import { IgntModule as IgnitePlanetMars, msgTypes as IgnitePlanetMarsMsgTypes } from './ignite.planet.mars' + + +const Client = IgniteClient.plugin([ + IgnitePlanetMars +]); + +const registry = new Registry([ + ...IgnitePlanetMarsMsgTypes, + +]) + +export { + Client, + registry, + MissingWalletError +} diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types.ts deleted file mode 100755 index 2d65d3295f..0000000000 --- a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AnotherType } from "./types/planet/mars/mars" - - -export { - AnotherType, - - } \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/modules.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/modules.ts new file mode 100755 index 0000000000..e8e4a78272 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/modules.ts @@ -0,0 +1,5 @@ +import { IgniteClient } from "./client"; +import { GeneratedType } from "@cosmjs/proto-signing"; + +export type IgntModuleInterface = { [key: string]: any } +export type IgntModule = (instance: IgniteClient) => { module: IgntModuleInterface, registry: [string, GeneratedType][] } diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/package.json b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/package.json new file mode 100755 index 0000000000..0ddf03fd45 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/package.json @@ -0,0 +1,39 @@ +{ + "name": "testdata-testchain-client-ts", + "version": "0.0.1", + "description": "Autogenerated Typescript Client", + "author": "Ignite Codegen ", + "license": "Apache-2.0", + "licenses": [ + { + "type": "Apache-2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "main": "lib/index.js", + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "NODE_OPTIONS='--max-old-space-size=16384' tsc" + }, + "dependencies": { + "@cosmjs/proto-signing": "0.33.1", + "@cosmjs/stargate": "0.33.1", + "@keplr-wallet/types": "^0.12.234", + "axios": "1.9.0", + "buffer": "^6.0.3", + "events": "^3.3.0" + }, + "peerDependencies": { + "@cosmjs/proto-signing": "0.33.1", + "@cosmjs/stargate": "0.33.1" + }, + "devDependencies": { + "@bufbuild/protobuf": "^2.4.0", + "@types/events": "^3.0.3", + "qs": "^6.14.0", + "type-fest": "^4.41.0", + "typescript": "^5.8.3" + } +} diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/tsconfig.json b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/tsconfig.json new file mode 100755 index 0000000000..9f65e2249e --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "outDir": "./lib", + "declaration": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": false, + "strict": false, + "skipLibCheck": true + } + } \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/types.d.ts b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/types.d.ts new file mode 100755 index 0000000000..268332bcb7 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/types.d.ts @@ -0,0 +1,21 @@ +import { Keplr, Window as KeplrWindow } from '@keplr-wallet/types'; + +declare global { + interface KeplrIntereactionOptions { + readonly sign?: KeplrSignOptions; + } + + export interface KeplrSignOptions { + readonly preferNoSetFee?: boolean; + readonly preferNoSetMemo?: boolean; + readonly disableBalanceCheck?: boolean; + } + interface CustomKeplr extends Keplr { + enable(chainId: string | string[]): Promise; + + defaultOptions: KeplrIntereactionOptions; + } + interface Window extends KeplrWindow { + keplr: CustomKeplr; + } +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/proto/planet/mars/mars.proto b/ignite/pkg/cosmosgen/testdata/testchain/proto/ignite/planet/mars/mars.proto similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/proto/planet/mars/mars.proto rename to ignite/pkg/cosmosgen/testdata/testchain/proto/ignite/planet/mars/mars.proto diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/client.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/client.ts new file mode 100755 index 0000000000..663979e017 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/client.ts @@ -0,0 +1,164 @@ +/// +import { + GeneratedType, + OfflineSigner, + EncodeObject, + Registry, +} from "@cosmjs/proto-signing"; +import { SigningStargateClient, StdFee } from "@cosmjs/stargate"; +import { Env } from "./env"; +import { UnionToIntersection, Return, Constructor } from "./helpers"; +import { IgntModule } from "./modules"; +import { EventEmitter } from "events"; +import { ChainInfo } from "@keplr-wallet/types"; + +const defaultFee = { + amount: [], + gas: "200000", +}; + +export class IgniteClient extends EventEmitter { + static plugins: IgntModule[] = []; + env: Env; + signer?: OfflineSigner; + registry: Array<[string, GeneratedType]> = []; + static plugin(plugin: T) { + const currentPlugins = this.plugins; + + class AugmentedClient extends this { + static plugins = currentPlugins.concat(plugin); + } + + if (Array.isArray(plugin)) { + type Extension = UnionToIntersection['module']> + return AugmentedClient as typeof IgniteClient & Constructor; + } + + type Extension = Return['module'] + return AugmentedClient as typeof IgniteClient & Constructor; + } + + async signAndBroadcast(msgs: EncodeObject[], fee: StdFee, memo: string) { + if (this.signer) { + const { address } = (await this.signer.getAccounts())[0]; + const signingClient = await SigningStargateClient.connectWithSigner(this.env.rpcURL, this.signer, { registry: new Registry(this.registry) }); + return await signingClient.signAndBroadcast(address, msgs, fee ? fee : defaultFee, memo) + } else { + throw new Error(" Signer is not present."); + } + } + + constructor(env: Env, signer?: OfflineSigner) { + super(); + this.env = env; + this.setMaxListeners(0); + this.signer = signer; + const classConstructor = this.constructor as typeof IgniteClient; + classConstructor.plugins.forEach(plugin => { + const pluginInstance = plugin(this); + Object.assign(this, pluginInstance.module) + if (this.registry) { + this.registry = this.registry.concat(pluginInstance.registry) + } + }); + } + useSigner(signer: OfflineSigner) { + this.signer = signer; + this.emit("signer-changed", this.signer); + } + removeSigner() { + this.signer = undefined; + this.emit("signer-changed", this.signer); + } + async useKeplr(keplrChainInfo: Partial = {}) { + // Using queryClients directly because BaseClient has no knowledge of the modules at this stage + try { + const queryClient = ( + await import("./cosmos.base.tendermint.v1beta1/module") + ).queryClient; + const bankQueryClient = (await import("./cosmos.bank.v1beta1/module")) + .queryClient; + const stakingQueryClient = (await import("./cosmos.staking.v1beta1/module")).queryClient; + const stakingqc = stakingQueryClient({ addr: this.env.apiURL }); + const staking = await (await stakingqc.queryParams()).data; + const qc = queryClient({ addr: this.env.apiURL }); + const node_info = await (await qc.serviceGetNodeInfo()).data; + const chainId = node_info.default_node_info?.network ?? ""; + const chainName = chainId?.toUpperCase() + " Network"; + const bankqc = bankQueryClient({ addr: this.env.apiURL }); + const tokens = await (await bankqc.queryTotalSupply()).data; + const addrPrefix = this.env.prefix ?? "cosmos"; + const rpc = this.env.rpcURL; + const rest = this.env.apiURL; + + let bip44 = { + coinType: 118, + }; + + let bech32Config = { + bech32PrefixAccAddr: addrPrefix, + bech32PrefixAccPub: addrPrefix + "pub", + bech32PrefixValAddr: addrPrefix + "valoper", + bech32PrefixValPub: addrPrefix + "valoperpub", + bech32PrefixConsAddr: addrPrefix + "valcons", + bech32PrefixConsPub: addrPrefix + "valconspub", + }; + + let currencies = + tokens.supply?.map((x) => { + const y = { + coinDenom: x.denom?.toUpperCase() ?? "", + coinMinimalDenom: x.denom ?? "", + coinDecimals: 0, + }; + return y; + }) ?? []; + + let stakeCurrency = { + coinDenom: staking.params?.bond_denom?.toUpperCase() ?? "", + coinMinimalDenom: staking.params?.bond_denom ?? "", + coinDecimals: 0, + }; + + let feeCurrencies = + tokens.supply?.map((x) => { + const y = { + coinDenom: x.denom?.toUpperCase() ?? "", + coinMinimalDenom: x.denom ?? "", + coinDecimals: 0, + }; + return y; + }) ?? []; + + if (chainId) { + const suggestOptions: ChainInfo = { + chainId, + chainName, + rpc, + rest, + stakeCurrency, + bip44, + bech32Config, + currencies, + feeCurrencies, + ...keplrChainInfo, + }; + await window.keplr.experimentalSuggestChain(suggestOptions); + + window.keplr.defaultOptions = { + sign: { + preferNoSetFee: true, + preferNoSetMemo: true, + }, + }; + } + await window.keplr.enable(chainId); + this.signer = window.keplr.getOfflineSigner(chainId); + this.emit("signer-changed", this.signer); + } catch (e) { + throw new Error( + "Could not load tendermint, staking and bank modules. Please ensure your client loads them to use useKeplr()" + ); + } + } +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/env.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/env.ts new file mode 100755 index 0000000000..92558e4be6 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/env.ts @@ -0,0 +1,7 @@ +import { OfflineSigner } from "@cosmjs/proto-signing"; + +export interface Env { + apiURL: string + rpcURL: string + prefix?: string +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/helpers.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/helpers.ts new file mode 100755 index 0000000000..d8ccd3d0b5 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/helpers.ts @@ -0,0 +1,32 @@ +export type Constructor = new (...args: any[]) => T; + +export type AnyFunction = (...args: any) => any; + +export type UnionToIntersection = + (Union extends any + ? (argument: Union) => void + : never + ) extends (argument: infer Intersection) => void + ? Intersection + : never; + +export type Return = + T extends AnyFunction + ? ReturnType + : T extends AnyFunction[] + ? UnionToIntersection> + : never + + +export const MissingWalletError = new Error("wallet is required"); + +export function getStructure(template) { + let structure = { fields: [] as Array} + for (const [key, value] of Object.entries(template)) { + let field: any = {} + field.name = key + field.type = typeof value + structure.fields.push(field) + } + return structure +} \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/index.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/index.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/index.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/index.ts diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/module.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/module.ts similarity index 97% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/module.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/module.ts index 5c2775ac94..407fb04bd8 100755 --- a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/module.ts +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/module.ts @@ -6,8 +6,8 @@ import { msgTypes } from './registry'; import { IgniteClient } from "../client" import { MissingWalletError } from "../helpers" import { Api } from "./rest"; -import { MsgMyMessageRequest } from "./types/planet/mars/mars"; -import { MsgBarRequest } from "./types/planet/mars/mars"; +import { MsgMyMessageRequest } from "./types/ignite/planet/mars/mars"; +import { MsgBarRequest } from "./types/ignite/planet/mars/mars"; import { AnotherType as typeAnotherType} from "./types" diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/registry.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/registry.ts similarity index 66% rename from ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/registry.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/registry.ts index d94c1d053e..585b8c64a1 100755 --- a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/registry.ts +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/registry.ts @@ -1,6 +1,6 @@ import { GeneratedType } from "@cosmjs/proto-signing"; -import { MsgMyMessageRequest } from "./types/planet/mars/mars"; -import { MsgBarRequest } from "./types/planet/mars/mars"; +import { MsgMyMessageRequest } from "./types/ignite/planet/mars/mars"; +import { MsgBarRequest } from "./types/ignite/planet/mars/mars"; const msgTypes: Array<[string, GeneratedType]> = [ ["/ignite.planet.mars.MsgMyMessageRequest", MsgMyMessageRequest], diff --git a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/rest.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/rest.ts similarity index 93% rename from ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/rest.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/rest.ts index b4bd30275d..f239419cb3 100755 --- a/ignite/pkg/cosmosgen/testdata/expected_files/ts-client/mars/rest.ts +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/rest.ts @@ -1,15 +1,15 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, ResponseType } from "axios"; -import { QuerySimpleResponse } from "./types/planet/mars/mars"; -import { QuerySimpleParamsResponse } from "./types/planet/mars/mars"; -import { QueryWithPaginationResponse } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsResponse } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsWithPaginationResponse } from "./types/planet/mars/mars"; +import { QuerySimpleResponse } from "./types/ignite/planet/mars/mars"; +import { QuerySimpleParamsResponse } from "./types/ignite/planet/mars/mars"; +import { QueryWithPaginationResponse } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsResponse } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsWithPaginationResponse } from "./types/ignite/planet/mars/mars"; -import { QuerySimpleRequest } from "./types/planet/mars/mars"; -import { QuerySimpleParamsRequest } from "./types/planet/mars/mars"; -import { QueryWithPaginationRequest } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsRequest } from "./types/planet/mars/mars"; -import { QueryWithQueryParamsWithPaginationRequest } from "./types/planet/mars/mars"; +import { QuerySimpleRequest } from "./types/ignite/planet/mars/mars"; +import { QuerySimpleParamsRequest } from "./types/ignite/planet/mars/mars"; +import { QueryWithPaginationRequest } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsRequest } from "./types/ignite/planet/mars/mars"; +import { QueryWithQueryParamsWithPaginationRequest } from "./types/ignite/planet/mars/mars"; import type {SnakeCasedPropertiesDeep} from 'type-fest'; diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types.ts new file mode 100755 index 0000000000..c9d8622576 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types.ts @@ -0,0 +1,7 @@ +import { AnotherType } from "./types/ignite/planet/mars/mars" + + +export { + AnotherType, + + } \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/cosmos/base/query/v1beta1/pagination.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/cosmos/base/query/v1beta1/pagination.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/cosmos/base/query/v1beta1/pagination.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/cosmos/base/query/v1beta1/pagination.ts diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/cosmos_proto/cosmos.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/cosmos_proto/cosmos.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/cosmos_proto/cosmos.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/cosmos_proto/cosmos.ts diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/google/api/annotations.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/google/api/annotations.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/google/api/annotations.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/google/api/annotations.ts diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/google/api/http.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/google/api/http.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/google/api/http.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/google/api/http.ts diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/google/protobuf/descriptor.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/google/protobuf/descriptor.ts similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/google/protobuf/descriptor.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/google/protobuf/descriptor.ts diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/planet/mars/mars.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/ignite/planet/mars/mars.ts similarity index 99% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/planet/mars/mars.ts rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/ignite/planet/mars/mars.ts index d7dd4ba1bc..adb90423fc 100644 --- a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/planet/mars/mars.ts +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/ignite/planet/mars/mars.ts @@ -2,11 +2,11 @@ // versions: // protoc-gen-ts_proto v2.6.1 // protoc unknown -// source: planet/mars/mars.proto +// source: ignite/planet/mars/mars.proto /* eslint-disable */ import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; -import { PageRequest, PageResponse } from "../../cosmos/base/query/v1beta1/pagination"; +import { PageRequest, PageResponse } from "../../../cosmos/base/query/v1beta1/pagination"; export const protobufPackage = "ignite.planet.mars"; diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/route-name.eta b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/route-name.eta similarity index 100% rename from ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types/route-name.eta rename to ignite/pkg/cosmosgen/testdata/testchain/ts-client/ignite.planet.mars/types/route-name.eta diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/index.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/index.ts new file mode 100755 index 0000000000..80ec020167 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/index.ts @@ -0,0 +1,21 @@ +// Generated by Ignite ignite.com/cli +import { Registry } from '@cosmjs/proto-signing' +import { IgniteClient } from "./client"; +import { MissingWalletError } from "./helpers"; +import { IgntModule as IgnitePlanetMars, msgTypes as IgnitePlanetMarsMsgTypes } from './ignite.planet.mars' + + +const Client = IgniteClient.plugin([ + IgnitePlanetMars +]); + +const registry = new Registry([ + ...IgnitePlanetMarsMsgTypes, + +]) + +export { + Client, + registry, + MissingWalletError +} diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types.ts deleted file mode 100755 index 2d65d3295f..0000000000 --- a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/mars/types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { AnotherType } from "./types/planet/mars/mars" - - -export { - AnotherType, - - } \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/modules.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/modules.ts new file mode 100755 index 0000000000..e8e4a78272 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/modules.ts @@ -0,0 +1,5 @@ +import { IgniteClient } from "./client"; +import { GeneratedType } from "@cosmjs/proto-signing"; + +export type IgntModuleInterface = { [key: string]: any } +export type IgntModule = (instance: IgniteClient) => { module: IgntModuleInterface, registry: [string, GeneratedType][] } diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/package.json b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/package.json new file mode 100755 index 0000000000..0ddf03fd45 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/package.json @@ -0,0 +1,39 @@ +{ + "name": "testdata-testchain-client-ts", + "version": "0.0.1", + "description": "Autogenerated Typescript Client", + "author": "Ignite Codegen ", + "license": "Apache-2.0", + "licenses": [ + { + "type": "Apache-2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0" + } + ], + "main": "lib/index.js", + "publishConfig": { + "access": "public" + }, + "scripts": { + "build": "NODE_OPTIONS='--max-old-space-size=16384' tsc" + }, + "dependencies": { + "@cosmjs/proto-signing": "0.33.1", + "@cosmjs/stargate": "0.33.1", + "@keplr-wallet/types": "^0.12.234", + "axios": "1.9.0", + "buffer": "^6.0.3", + "events": "^3.3.0" + }, + "peerDependencies": { + "@cosmjs/proto-signing": "0.33.1", + "@cosmjs/stargate": "0.33.1" + }, + "devDependencies": { + "@bufbuild/protobuf": "^2.4.0", + "@types/events": "^3.0.3", + "qs": "^6.14.0", + "type-fest": "^4.41.0", + "typescript": "^5.8.3" + } +} diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/tsconfig.json b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/tsconfig.json new file mode 100755 index 0000000000..9f65e2249e --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ES2020", + "moduleResolution": "node", + "outDir": "./lib", + "declaration": true, + "allowSyntheticDefaultImports": true, + "esModuleInterop": false, + "strict": false, + "skipLibCheck": true + } + } \ No newline at end of file diff --git a/ignite/pkg/cosmosgen/testdata/testchain/ts-client/types.d.ts b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/types.d.ts new file mode 100755 index 0000000000..268332bcb7 --- /dev/null +++ b/ignite/pkg/cosmosgen/testdata/testchain/ts-client/types.d.ts @@ -0,0 +1,21 @@ +import { Keplr, Window as KeplrWindow } from '@keplr-wallet/types'; + +declare global { + interface KeplrIntereactionOptions { + readonly sign?: KeplrSignOptions; + } + + export interface KeplrSignOptions { + readonly preferNoSetFee?: boolean; + readonly preferNoSetMemo?: boolean; + readonly disableBalanceCheck?: boolean; + } + interface CustomKeplr extends Keplr { + enable(chainId: string | string[]): Promise; + + defaultOptions: KeplrIntereactionOptions; + } + interface Window extends KeplrWindow { + keplr: CustomKeplr; + } +} \ No newline at end of file