@hyperweb/telescope 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1529 -0
- package/main/build.js +183 -0
- package/main/builder.js +229 -0
- package/main/bundle.js +162 -0
- package/main/bundler.js +100 -0
- package/main/cli.js +71 -0
- package/main/cmds.js +28 -0
- package/main/commands/download.js +122 -0
- package/main/commands/generate.js +151 -0
- package/main/commands/install.js +143 -0
- package/main/commands/transpile.js +197 -0
- package/main/contracts/generate.js +31 -0
- package/main/contracts/install.js +107 -0
- package/main/contracts/message-composer.js +31 -0
- package/main/contracts/react-query.js +31 -0
- package/main/contracts/recoil.js +31 -0
- package/main/file.js +20 -0
- package/main/generators/create-aggregated-lcd-client.js +87 -0
- package/main/generators/create-all-stargate-clients.js +96 -0
- package/main/generators/create-amino-converters.js +43 -0
- package/main/generators/create-bundle.js +83 -0
- package/main/generators/create-cosmwasm-bundle.js +15 -0
- package/main/generators/create-custom-stargate-clients.js +100 -0
- package/main/generators/create-helpers.js +119 -0
- package/main/generators/create-index.js +75 -0
- package/main/generators/create-lcd-client-all.js +116 -0
- package/main/generators/create-lcd-client-scoped.js +89 -0
- package/main/generators/create-lcd-clients.js +78 -0
- package/main/generators/create-mcp-server.js +1853 -0
- package/main/generators/create-mobx-bundle.js +52 -0
- package/main/generators/create-msg-funcs.js +132 -0
- package/main/generators/create-pinia-store-bundle.js +50 -0
- package/main/generators/create-pinia-store.js +90 -0
- package/main/generators/create-query-funcs.js +133 -0
- package/main/generators/create-react-query-bundle.js +103 -0
- package/main/generators/create-registries.js +49 -0
- package/main/generators/create-root-readme.js +259 -0
- package/main/generators/create-rpc-msg-client-all.js +135 -0
- package/main/generators/create-rpc-msg-client-scoped.js +114 -0
- package/main/generators/create-rpc-msg-clients.js +116 -0
- package/main/generators/create-rpc-ops-bundle.js +119 -0
- package/main/generators/create-rpc-query-client-all.js +137 -0
- package/main/generators/create-rpc-query-client-scoped.js +110 -0
- package/main/generators/create-rpc-query-clients.js +198 -0
- package/main/generators/create-sdk-module-stargate-clients.js +95 -0
- package/main/generators/create-stargate-clients.js +96 -0
- package/main/generators/create-types.js +164 -0
- package/main/generators/customize-utils.js +50 -0
- package/main/helpers/__test__/internalTimestamp.js +49 -0
- package/main/helpers/__test__/internalTimestampBigint.js +45 -0
- package/main/helpers/binary-coder.js +535 -0
- package/main/helpers/decimals.js +111 -0
- package/main/helpers/external-comet.js +52 -0
- package/main/helpers/external-icjs.js +36 -0
- package/main/helpers/external.js +31 -0
- package/main/helpers/grpc-gateway.js +348 -0
- package/main/helpers/grpc-web.js +14 -0
- package/main/helpers/helper-func-types-interface.js +106 -0
- package/main/helpers/helper-func-types.js +93 -0
- package/main/helpers/index.js +38 -0
- package/main/helpers/internal-for-bigint.js +259 -0
- package/main/helpers/internal.js +240 -0
- package/main/helpers/json-safe.js +12 -0
- package/main/helpers/mobx.js +80 -0
- package/main/helpers/pinia-endpoint.js +20 -0
- package/main/helpers/react-query-hooks-icjs.js +223 -0
- package/main/helpers/react-query-hooks.js +258 -0
- package/main/helpers/react-query.js +93 -0
- package/main/helpers/registry-helper.js +229 -0
- package/main/helpers/types-helper.js +165 -0
- package/main/helpers/utf8-helper.js +146 -0
- package/main/helpers/varint.js +486 -0
- package/main/helpers/vue-query-hooks.js +226 -0
- package/main/imports.js +416 -0
- package/main/index.js +24 -0
- package/main/parse.js +194 -0
- package/main/prompt.js +64 -0
- package/main/protod/bufbuild.js +87 -0
- package/main/protod/config.js +30 -0
- package/main/protod/git-repo.js +58 -0
- package/main/protod/index.js +17 -0
- package/main/protod/recursive.js +134 -0
- package/main/protod/types.js +2 -0
- package/main/protod/utils.js +91 -0
- package/main/telescope.js +10 -0
- package/main/types.js +2 -0
- package/main/utils/common-create-bundle.js +29 -0
- package/main/utils/contracts.js +39 -0
- package/main/utils/files.js +138 -0
- package/main/utils/index.js +163 -0
- package/main/utils/unused.js +73 -0
- package/module/build.js +176 -0
- package/module/builder.js +222 -0
- package/module/bundle.js +128 -0
- package/module/bundler.js +96 -0
- package/module/cli.js +44 -0
- package/module/cmds.js +22 -0
- package/module/commands/download.js +94 -0
- package/module/commands/generate.js +123 -0
- package/module/commands/install.js +141 -0
- package/module/commands/transpile.js +169 -0
- package/module/contracts/generate.js +29 -0
- package/module/contracts/install.js +105 -0
- package/module/contracts/message-composer.js +29 -0
- package/module/contracts/react-query.js +29 -0
- package/module/contracts/recoil.js +29 -0
- package/module/file.js +18 -0
- package/module/generators/create-aggregated-lcd-client.js +83 -0
- package/module/generators/create-all-stargate-clients.js +92 -0
- package/module/generators/create-amino-converters.js +39 -0
- package/module/generators/create-bundle.js +79 -0
- package/module/generators/create-cosmwasm-bundle.js +11 -0
- package/module/generators/create-custom-stargate-clients.js +96 -0
- package/module/generators/create-helpers.js +112 -0
- package/module/generators/create-index.js +45 -0
- package/module/generators/create-lcd-client-all.js +89 -0
- package/module/generators/create-lcd-client-scoped.js +62 -0
- package/module/generators/create-lcd-clients.js +74 -0
- package/module/generators/create-mcp-server.js +1849 -0
- package/module/generators/create-mobx-bundle.js +25 -0
- package/module/generators/create-msg-funcs.js +128 -0
- package/module/generators/create-pinia-store-bundle.js +23 -0
- package/module/generators/create-pinia-store.js +86 -0
- package/module/generators/create-query-funcs.js +129 -0
- package/module/generators/create-react-query-bundle.js +76 -0
- package/module/generators/create-registries.js +45 -0
- package/module/generators/create-root-readme.js +255 -0
- package/module/generators/create-rpc-msg-client-all.js +108 -0
- package/module/generators/create-rpc-msg-client-scoped.js +87 -0
- package/module/generators/create-rpc-msg-clients.js +112 -0
- package/module/generators/create-rpc-ops-bundle.js +92 -0
- package/module/generators/create-rpc-query-client-all.js +110 -0
- package/module/generators/create-rpc-query-client-scoped.js +83 -0
- package/module/generators/create-rpc-query-clients.js +198 -0
- package/module/generators/create-sdk-module-stargate-clients.js +91 -0
- package/module/generators/create-stargate-clients.js +92 -0
- package/module/generators/create-types.js +137 -0
- package/module/generators/customize-utils.js +46 -0
- package/module/helpers/__test__/internalTimestamp.js +39 -0
- package/module/helpers/__test__/internalTimestampBigint.js +38 -0
- package/module/helpers/binary-coder.js +531 -0
- package/module/helpers/decimals.js +108 -0
- package/module/helpers/external-comet.js +49 -0
- package/module/helpers/external-icjs.js +33 -0
- package/module/helpers/external.js +28 -0
- package/module/helpers/grpc-gateway.js +345 -0
- package/module/helpers/grpc-web.js +11 -0
- package/module/helpers/helper-func-types-interface.js +102 -0
- package/module/helpers/helper-func-types.js +89 -0
- package/module/helpers/index.js +22 -0
- package/module/helpers/internal-for-bigint.js +255 -0
- package/module/helpers/internal.js +236 -0
- package/module/helpers/json-safe.js +9 -0
- package/module/helpers/mobx.js +77 -0
- package/module/helpers/pinia-endpoint.js +17 -0
- package/module/helpers/react-query-hooks-icjs.js +219 -0
- package/module/helpers/react-query-hooks.js +254 -0
- package/module/helpers/react-query.js +89 -0
- package/module/helpers/registry-helper.js +225 -0
- package/module/helpers/types-helper.js +161 -0
- package/module/helpers/utf8-helper.js +143 -0
- package/module/helpers/varint.js +483 -0
- package/module/helpers/vue-query-hooks.js +222 -0
- package/module/imports.js +382 -0
- package/module/index.js +8 -0
- package/module/parse.js +185 -0
- package/module/prompt.js +58 -0
- package/module/protod/bufbuild.js +76 -0
- package/module/protod/config.js +27 -0
- package/module/protod/git-repo.js +54 -0
- package/module/protod/index.js +1 -0
- package/module/protod/recursive.js +125 -0
- package/module/protod/types.js +1 -0
- package/module/protod/utils.js +77 -0
- package/module/telescope.js +8 -0
- package/module/types.js +1 -0
- package/module/utils/common-create-bundle.js +25 -0
- package/module/utils/contracts.js +33 -0
- package/module/utils/files.js +106 -0
- package/module/utils/index.js +143 -0
- package/module/utils/unused.js +47 -0
- package/package.json +115 -0
- package/src/build.ts +255 -0
- package/src/builder.ts +302 -0
- package/src/bundle.ts +160 -0
- package/src/bundler.ts +153 -0
- package/src/cli.js +51 -0
- package/src/cmds.js +25 -0
- package/src/commands/download.ts +120 -0
- package/src/commands/generate.ts +156 -0
- package/src/commands/install.ts +154 -0
- package/src/commands/transpile.ts +198 -0
- package/src/contracts/generate.ts +33 -0
- package/src/contracts/install.ts +118 -0
- package/src/contracts/message-composer.ts +34 -0
- package/src/contracts/react-query.ts +33 -0
- package/src/contracts/recoil.ts +32 -0
- package/src/file.js +20 -0
- package/src/generators/create-aggregated-lcd-client.ts +133 -0
- package/src/generators/create-all-stargate-clients.ts +121 -0
- package/src/generators/create-amino-converters.ts +62 -0
- package/src/generators/create-bundle.ts +97 -0
- package/src/generators/create-cosmwasm-bundle.ts +17 -0
- package/src/generators/create-custom-stargate-clients.ts +128 -0
- package/src/generators/create-helpers.ts +196 -0
- package/src/generators/create-index.ts +72 -0
- package/src/generators/create-lcd-client-all.ts +139 -0
- package/src/generators/create-lcd-client-scoped.ts +109 -0
- package/src/generators/create-lcd-clients.ts +108 -0
- package/src/generators/create-mcp-server.ts +1902 -0
- package/src/generators/create-mobx-bundle.ts +31 -0
- package/src/generators/create-msg-funcs.ts +219 -0
- package/src/generators/create-pinia-store-bundle.ts +35 -0
- package/src/generators/create-pinia-store.ts +121 -0
- package/src/generators/create-query-funcs.ts +224 -0
- package/src/generators/create-react-query-bundle.ts +111 -0
- package/src/generators/create-registries.ts +70 -0
- package/src/generators/create-root-readme.ts +316 -0
- package/src/generators/create-rpc-msg-client-all.ts +167 -0
- package/src/generators/create-rpc-msg-client-scoped.ts +147 -0
- package/src/generators/create-rpc-msg-clients.ts +165 -0
- package/src/generators/create-rpc-ops-bundle.ts +155 -0
- package/src/generators/create-rpc-query-client-all.ts +173 -0
- package/src/generators/create-rpc-query-client-scoped.ts +142 -0
- package/src/generators/create-rpc-query-clients.ts +304 -0
- package/src/generators/create-sdk-module-stargate-clients.ts +120 -0
- package/src/generators/create-stargate-clients.ts +123 -0
- package/src/generators/create-types.ts +236 -0
- package/src/generators/customize-utils.ts +54 -0
- package/src/helpers/__test__/internalTimestamp.test.ts +79 -0
- package/src/helpers/__test__/internalTimestamp.ts +58 -0
- package/src/helpers/__test__/internalTimestampBigint.test.ts +78 -0
- package/src/helpers/__test__/internalTimestampBigint.ts +58 -0
- package/src/helpers/binary-coder.ts +533 -0
- package/src/helpers/decimals.ts +108 -0
- package/src/helpers/external-comet.ts +49 -0
- package/src/helpers/external-icjs.ts +33 -0
- package/src/helpers/external.ts +28 -0
- package/src/helpers/grpc-gateway.ts +345 -0
- package/src/helpers/grpc-web.ts +11 -0
- package/src/helpers/helper-func-types-interface.ts +104 -0
- package/src/helpers/helper-func-types.ts +91 -0
- package/src/helpers/index.ts +22 -0
- package/src/helpers/internal-for-bigint.ts +257 -0
- package/src/helpers/internal.ts +238 -0
- package/src/helpers/json-safe.ts +11 -0
- package/src/helpers/mobx.ts +77 -0
- package/src/helpers/pinia-endpoint.ts +17 -0
- package/src/helpers/react-query-hooks-icjs.ts +223 -0
- package/src/helpers/react-query-hooks.ts +266 -0
- package/src/helpers/react-query.ts +101 -0
- package/src/helpers/registry-helper.ts +227 -0
- package/src/helpers/types-helper.ts +169 -0
- package/src/helpers/utf8-helper.ts +143 -0
- package/src/helpers/varint.ts +483 -0
- package/src/helpers/vue-query-hooks.ts +224 -0
- package/src/imports.ts +499 -0
- package/src/index.ts +12 -0
- package/src/parse.ts +243 -0
- package/src/prompt.js +65 -0
- package/src/protod/bufbuild.spec.ts +80 -0
- package/src/protod/bufbuild.ts +95 -0
- package/src/protod/config.ts +30 -0
- package/src/protod/git-repo.ts +74 -0
- package/src/protod/index.ts +1 -0
- package/src/protod/recursive.spec.ts +164 -0
- package/src/protod/recursive.ts +180 -0
- package/src/protod/test-data/.protod.config.json +42 -0
- package/src/protod/test-data/buf.lock +23 -0
- package/src/protod/test-data/buf.yaml +25 -0
- package/src/protod/test-data/buf2.yaml +20 -0
- package/src/protod/test-data/cosmos/buf.lock +23 -0
- package/src/protod/test-data/cosmos/crypto/secp256k1/keys.proto +38 -0
- package/src/protod/test-data/model.proto +101 -0
- package/src/protod/types.ts +55 -0
- package/src/protod/utils.spec.ts +68 -0
- package/src/protod/utils.ts +90 -0
- package/src/telescope.js +9 -0
- package/src/types.ts +46 -0
- package/src/utils/common-create-bundle.ts +62 -0
- package/src/utils/contracts.ts +37 -0
- package/src/utils/files.ts +145 -0
- package/src/utils/index.ts +150 -0
- package/src/utils/unused.ts +52 -0
- package/types/build.d.ts +41 -0
- package/types/builder.d.ts +50 -0
- package/types/bundle.d.ts +30 -0
- package/types/bundler.d.ts +31 -0
- package/types/cli.d.ts +1 -0
- package/types/cmds.d.ts +11 -0
- package/types/commands/download.d.ts +5 -0
- package/types/commands/generate.d.ts +2 -0
- package/types/commands/install.d.ts +2 -0
- package/types/commands/transpile.d.ts +4 -0
- package/types/contracts/generate.d.ts +2 -0
- package/types/contracts/install.d.ts +2 -0
- package/types/contracts/message-composer.d.ts +2 -0
- package/types/contracts/react-query.d.ts +2 -0
- package/types/contracts/recoil.d.ts +2 -0
- package/types/file.d.ts +2 -0
- package/types/generators/create-aggregated-lcd-client.d.ts +2 -0
- package/types/generators/create-all-stargate-clients.d.ts +3 -0
- package/types/generators/create-amino-converters.d.ts +3 -0
- package/types/generators/create-bundle.d.ts +3 -0
- package/types/generators/create-combined-stargate-clients.d.ts +3 -0
- package/types/generators/create-cosmwasm-bundle.d.ts +2 -0
- package/types/generators/create-custom-stargate-clients.d.ts +3 -0
- package/types/generators/create-helpers.d.ts +2 -0
- package/types/generators/create-index.d.ts +2 -0
- package/types/generators/create-lcd-client-all.d.ts +3 -0
- package/types/generators/create-lcd-client-scoped.d.ts +3 -0
- package/types/generators/create-lcd-clients.d.ts +3 -0
- package/types/generators/create-mcp-server.d.ts +3 -0
- package/types/generators/create-mobx-bundle.d.ts +2 -0
- package/types/generators/create-msg-funcs.d.ts +3 -0
- package/types/generators/create-pinia-store-bundle.d.ts +2 -0
- package/types/generators/create-pinia-store.d.ts +3 -0
- package/types/generators/create-query-funcs.d.ts +3 -0
- package/types/generators/create-react-query-bundle.d.ts +2 -0
- package/types/generators/create-registries.d.ts +3 -0
- package/types/generators/create-root-readme.d.ts +2 -0
- package/types/generators/create-rpc-msg-client-all.d.ts +3 -0
- package/types/generators/create-rpc-msg-client-scoped.d.ts +3 -0
- package/types/generators/create-rpc-msg-clients.d.ts +3 -0
- package/types/generators/create-rpc-ops-bundle.d.ts +2 -0
- package/types/generators/create-rpc-query-client-all.d.ts +3 -0
- package/types/generators/create-rpc-query-client-scoped.d.ts +3 -0
- package/types/generators/create-rpc-query-clients.d.ts +3 -0
- package/types/generators/create-scoped-stargate-clients.d.ts +3 -0
- package/types/generators/create-sdk-module-stargate-clients.d.ts +3 -0
- package/types/generators/create-stargate-clients.d.ts +3 -0
- package/types/generators/create-types.d.ts +3 -0
- package/types/generators/create-unified-stargate-clients.d.ts +3 -0
- package/types/generators/customize-utils.d.ts +2 -0
- package/types/helpers/__test__/internalTimestamp.d.ts +21 -0
- package/types/helpers/__test__/internalTimestampBigint.d.ts +20 -0
- package/types/helpers/binary-coder.d.ts +2 -0
- package/types/helpers/decimals.d.ts +1 -0
- package/types/helpers/external-comet.d.ts +1 -0
- package/types/helpers/external-icjs.d.ts +1 -0
- package/types/helpers/external.d.ts +1 -0
- package/types/helpers/generated-type.d.ts +1 -0
- package/types/helpers/grpc-gateway.d.ts +1 -0
- package/types/helpers/grpc-web.d.ts +1 -0
- package/types/helpers/helper-func-types-interface.d.ts +2 -0
- package/types/helpers/helper-func-types.d.ts +2 -0
- package/types/helpers/index.d.ts +22 -0
- package/types/helpers/internal-for-bigint.d.ts +2 -0
- package/types/helpers/internal.d.ts +2 -0
- package/types/helpers/internalForBigInt.d.ts +1 -0
- package/types/helpers/json-safe.d.ts +1 -0
- package/types/helpers/mobx.d.ts +1 -0
- package/types/helpers/pinia-endpoint.d.ts +1 -0
- package/types/helpers/react-query-hooks-icjs.d.ts +2 -0
- package/types/helpers/react-query-hooks.d.ts +2 -0
- package/types/helpers/react-query.d.ts +2 -0
- package/types/helpers/registry-helper.d.ts +2 -0
- package/types/helpers/types-helper.d.ts +2 -0
- package/types/helpers/types.d.ts +1 -0
- package/types/helpers/utf8-helper.d.ts +1 -0
- package/types/helpers/varint.d.ts +1 -0
- package/types/helpers/vue-query-hooks.d.ts +2 -0
- package/types/helpers/vue-query.d.ts +2 -0
- package/types/imports.d.ts +17 -0
- package/types/index.d.ts +6 -0
- package/types/parse.d.ts +15 -0
- package/types/prompt.d.ts +3 -0
- package/types/protod/bufbuild.d.ts +6 -0
- package/types/protod/config.d.ts +7 -0
- package/types/protod/git-repo.d.ts +11 -0
- package/types/protod/index.d.ts +1 -0
- package/types/protod/proto-download.d.ts +2 -0
- package/types/protod/recursive.d.ts +4 -0
- package/types/protod/types.d.ts +49 -0
- package/types/protod/utils.d.ts +11 -0
- package/types/telescope.d.ts +2 -0
- package/types/types.d.ts +43 -0
- package/types/utils/common-create-bundle.d.ts +18 -0
- package/types/utils/contracts.d.ts +6 -0
- package/types/utils/files.d.ts +5 -0
- package/types/utils/index.d.ts +16 -0
- package/types/utils/unused.d.ts +5 -0
|
@@ -0,0 +1,1902 @@
|
|
|
1
|
+
import { TelescopeBuilder } from '../builder';
|
|
2
|
+
import { Bundler } from '../bundler';
|
|
3
|
+
import { writeFileSync, mkdirSync, cpSync, existsSync } from 'fs';
|
|
4
|
+
import { join, dirname, basename } from 'path';
|
|
5
|
+
|
|
6
|
+
export const plugin = (
|
|
7
|
+
builder: TelescopeBuilder,
|
|
8
|
+
bundler: Bundler
|
|
9
|
+
) => {
|
|
10
|
+
// Early return if MCP server is not enabled
|
|
11
|
+
if (!builder.options.mcpServer?.enabled) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Use the output directory name instead of bundle base
|
|
16
|
+
const outputDirName = basename(builder.outPath);
|
|
17
|
+
const packageName = outputDirName || bundler.bundle.base;
|
|
18
|
+
const parentDir = dirname(builder.outPath);
|
|
19
|
+
const mcpServerPath = join(parentDir, `${packageName}-mcp`);
|
|
20
|
+
|
|
21
|
+
// Ensure MCP server directory exists
|
|
22
|
+
mkdirSync(mcpServerPath, { recursive: true });
|
|
23
|
+
mkdirSync(join(mcpServerPath, 'src'), { recursive: true });
|
|
24
|
+
mkdirSync(join(mcpServerPath, 'src', 'prompts'), { recursive: true });
|
|
25
|
+
mkdirSync(join(mcpServerPath, 'src', 'telescope-examples'), { recursive: true });
|
|
26
|
+
|
|
27
|
+
// Generate package.json for MCP server
|
|
28
|
+
const packageJson = generateMcpPackageJson(packageName);
|
|
29
|
+
writeFileSync(
|
|
30
|
+
join(mcpServerPath, 'package.json'),
|
|
31
|
+
JSON.stringify(packageJson, null, 2)
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Generate main MCP server file
|
|
35
|
+
const indexContent = `#!/usr/bin/env node
|
|
36
|
+
|
|
37
|
+
import { readFileSync } from 'node:fs';
|
|
38
|
+
import { dirname, resolve } from 'node:path';
|
|
39
|
+
import { fileURLToPath } from 'node:url';
|
|
40
|
+
|
|
41
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
42
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
43
|
+
import { z } from 'zod';
|
|
44
|
+
|
|
45
|
+
// Get package.json version
|
|
46
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
47
|
+
const __dirname = dirname(__filename);
|
|
48
|
+
const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf8'));
|
|
49
|
+
const VERSION = packageJson.version;
|
|
50
|
+
|
|
51
|
+
async function main() {
|
|
52
|
+
const server = new McpServer({
|
|
53
|
+
name: '${packageName} MCP Server',
|
|
54
|
+
version: VERSION,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Add prompts for AI agents
|
|
58
|
+
server.prompt(
|
|
59
|
+
'codegen-usage',
|
|
60
|
+
'Guide for using telescope generated code',
|
|
61
|
+
async () => {
|
|
62
|
+
const promptPath = resolve(__dirname, 'prompts/codegen-usage.md');
|
|
63
|
+
const content = readFileSync(promptPath, 'utf-8');
|
|
64
|
+
return {
|
|
65
|
+
messages: [{
|
|
66
|
+
role: 'user',
|
|
67
|
+
content: {
|
|
68
|
+
type: 'text',
|
|
69
|
+
text: content
|
|
70
|
+
}
|
|
71
|
+
}]
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
server.prompt(
|
|
77
|
+
'agent-guidelines',
|
|
78
|
+
'Guidelines for MCP agents using ${packageName}',
|
|
79
|
+
async () => {
|
|
80
|
+
const promptPath = resolve(__dirname, 'prompts/agent-guidelines.md');
|
|
81
|
+
const content = readFileSync(promptPath, 'utf-8');
|
|
82
|
+
return {
|
|
83
|
+
messages: [{
|
|
84
|
+
role: 'user',
|
|
85
|
+
content: {
|
|
86
|
+
type: 'text',
|
|
87
|
+
text: content
|
|
88
|
+
}
|
|
89
|
+
}]
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
// Register blockchain function generator tool
|
|
95
|
+
server.tool(
|
|
96
|
+
'create-blockchain-function',
|
|
97
|
+
'Create custom blockchain functions by referencing telescope examples and generated code',
|
|
98
|
+
{
|
|
99
|
+
task: z.string().describe('The blockchain task to implement (e.g., "get balance", "check staking rewards", "query validators")').optional(),
|
|
100
|
+
chainName: z.string().describe('The blockchain name (e.g., cosmos, osmosis, injective)').optional(),
|
|
101
|
+
functionType: z.enum(['query', 'transaction', 'react-hook', 'utility']).describe('Type of function to create').optional(),
|
|
102
|
+
customRequirements: z.string().describe('Any specific requirements or modifications needed').optional()
|
|
103
|
+
},
|
|
104
|
+
async (args) => {
|
|
105
|
+
try {
|
|
106
|
+
const { task = 'get account balance', chainName = 'cosmos', functionType = 'query', customRequirements } = args;
|
|
107
|
+
|
|
108
|
+
// Read available examples
|
|
109
|
+
const examplesPath = resolve(__dirname, 'telescope-examples');
|
|
110
|
+
let availableExamples: string[] = [];
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
const fs = await import('fs');
|
|
114
|
+
availableExamples = fs.readdirSync(examplesPath)
|
|
115
|
+
.filter(file => file.endsWith('.ts'))
|
|
116
|
+
.map(file => file.replace('.ts', ''));
|
|
117
|
+
} catch (error) {
|
|
118
|
+
// If examples directory doesn't exist, provide default list
|
|
119
|
+
availableExamples = [
|
|
120
|
+
'config-example', 'useBalance', 'useBalanceFunc', 'getBalance',
|
|
121
|
+
'useAssets', 'useStakingData', 'useValidators', 'useVoting',
|
|
122
|
+
'useVotingData', 'useContractInfo', 'useQueryContract',
|
|
123
|
+
'useCodeDetails', 'useMyContracts', 'useGrants', 'useSendData',
|
|
124
|
+
'useTotalAssets', 'useBalanceReact'
|
|
125
|
+
];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const examplesList = availableExamples.map(example => \`- **\${example}.ts**: Reference implementation\`).join('\\n');
|
|
129
|
+
|
|
130
|
+
const relevantExamples = getRelevantExamples(task, availableExamples)
|
|
131
|
+
.map(example => \`- **\${example}**: \${getExampleDescription(example)}\`)
|
|
132
|
+
.join('\\n');
|
|
133
|
+
|
|
134
|
+
const codeBlockStart = '\`\`\`';
|
|
135
|
+
const codeBlockEnd = '\`\`\`';
|
|
136
|
+
|
|
137
|
+
const response = [
|
|
138
|
+
'# Blockchain Function Generator',
|
|
139
|
+
'',
|
|
140
|
+
\`## Task: \${task}\`,
|
|
141
|
+
\`## Chain: \${chainName}\`,
|
|
142
|
+
\`## Function Type: \${functionType}\`,
|
|
143
|
+
customRequirements ? \`## Custom Requirements: \${customRequirements}\` : '',
|
|
144
|
+
'',
|
|
145
|
+
'## Instructions for Implementation',
|
|
146
|
+
'',
|
|
147
|
+
'### Step 1: Review Available Examples',
|
|
148
|
+
'The following example files are available in \`src/telescope-examples/\`:',
|
|
149
|
+
'',
|
|
150
|
+
examplesList,
|
|
151
|
+
'',
|
|
152
|
+
'### Step 2: Identify Relevant Examples',
|
|
153
|
+
\`Based on your task "\${task}", you should primarily reference:\`,
|
|
154
|
+
'',
|
|
155
|
+
relevantExamples,
|
|
156
|
+
'',
|
|
157
|
+
'### Step 3: Implementation Pattern',
|
|
158
|
+
'',
|
|
159
|
+
\`**For Query Functions (\${functionType === 'query' ? 'SELECTED' : 'Available'}):**\`,
|
|
160
|
+
\`\${codeBlockStart}typescript\`,
|
|
161
|
+
"import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';",
|
|
162
|
+
'',
|
|
163
|
+
'export const customQueryFunction = async (params: QueryParams) => {',
|
|
164
|
+
\` const rpcEndpoint = 'https://\${chainName}-rpc.quickapi.com:443';\`,
|
|
165
|
+
' ',
|
|
166
|
+
' try {',
|
|
167
|
+
' const result = await getBalance(rpcEndpoint, params);',
|
|
168
|
+
' return {',
|
|
169
|
+
' success: true,',
|
|
170
|
+
' data: result,',
|
|
171
|
+
' };',
|
|
172
|
+
' } catch (error) {',
|
|
173
|
+
' return {',
|
|
174
|
+
' success: false,',
|
|
175
|
+
' error: (error as Error).message,',
|
|
176
|
+
' };',
|
|
177
|
+
' }',
|
|
178
|
+
'};',
|
|
179
|
+
codeBlockEnd,
|
|
180
|
+
'',
|
|
181
|
+
\`**For React Hooks (\${functionType === 'react-hook' ? 'SELECTED' : 'Available'}):**\`,
|
|
182
|
+
\`\${codeBlockStart}typescript\`,
|
|
183
|
+
"import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';",
|
|
184
|
+
"import { defaultContext } from '@tanstack/react-query';",
|
|
185
|
+
'',
|
|
186
|
+
'export const useCustomHook = (params: HookParams) => {',
|
|
187
|
+
\` const rpcEndpoint = 'https://\${chainName}-rpc.quickapi.com:443';\`,
|
|
188
|
+
' ',
|
|
189
|
+
' return useGetBalance({',
|
|
190
|
+
' request: params,',
|
|
191
|
+
' options: {',
|
|
192
|
+
' enabled: !!params.address,',
|
|
193
|
+
' context: defaultContext,',
|
|
194
|
+
' },',
|
|
195
|
+
' clientResolver: rpcEndpoint,',
|
|
196
|
+
' });',
|
|
197
|
+
'};',
|
|
198
|
+
codeBlockEnd,
|
|
199
|
+
'',
|
|
200
|
+
'### Step 4: Configuration Setup',
|
|
201
|
+
'Always include proper chain configuration. Reference \`config-example.ts\`:',
|
|
202
|
+
'',
|
|
203
|
+
\`\${codeBlockStart}typescript\`,
|
|
204
|
+
'import { assetLists, chains } from "@chain-registry/v2";',
|
|
205
|
+
'',
|
|
206
|
+
\`export const targetChainName = '\${chainName}';\`,
|
|
207
|
+
\`export const rpcEndpoint = 'https://\${chainName}-rpc.quickapi.com:443';\`,
|
|
208
|
+
'export const chain = chains.find((chain) => chain.chainName === targetChainName);',
|
|
209
|
+
'export const assetList = assetLists.find((assetList) => assetList.chainName === targetChainName);',
|
|
210
|
+
codeBlockEnd,
|
|
211
|
+
'',
|
|
212
|
+
'### Step 5: Error Handling & Best Practices',
|
|
213
|
+
'- Always wrap async calls in try-catch blocks',
|
|
214
|
+
'- Validate input parameters before making requests',
|
|
215
|
+
'- Handle network timeouts and connection errors',
|
|
216
|
+
'- Convert base units to human-readable amounts (uatom → ATOM)',
|
|
217
|
+
'- Include proper TypeScript types',
|
|
218
|
+
'',
|
|
219
|
+
'### Step 6: Testing Your Function',
|
|
220
|
+
\`\${codeBlockStart}typescript\`,
|
|
221
|
+
'// Example usage',
|
|
222
|
+
'const result = await customQueryFunction({',
|
|
223
|
+
" address: 'cosmos1...',",
|
|
224
|
+
" denom: 'uatom'",
|
|
225
|
+
'});',
|
|
226
|
+
'',
|
|
227
|
+
'if (result.success) {',
|
|
228
|
+
" console.log('Result:', result.data);",
|
|
229
|
+
'} else {',
|
|
230
|
+
" console.error('Error:', result.error);",
|
|
231
|
+
'}',
|
|
232
|
+
codeBlockEnd,
|
|
233
|
+
'',
|
|
234
|
+
'## Additional Resources',
|
|
235
|
+
'',
|
|
236
|
+
'- **Full codebase reference**: \`src/telescope/\` directory contains all generated types and functions',
|
|
237
|
+
'- **Configuration examples**: \`src/telescope-examples/config-example.ts\`',
|
|
238
|
+
'- **Chain registry data**: \`src/prompts/chains.json\`',
|
|
239
|
+
'- **Usage guidelines**: Use the \`codegen-usage\` and \`agent-guidelines\` prompts for detailed instructions',
|
|
240
|
+
'',
|
|
241
|
+
'## Next Steps',
|
|
242
|
+
'',
|
|
243
|
+
'1. Review the suggested example files above',
|
|
244
|
+
'2. Copy and modify the relevant pattern for your use case',
|
|
245
|
+
'3. Test your implementation with proper error handling',
|
|
246
|
+
'4. Ensure proper TypeScript types are used',
|
|
247
|
+
'',
|
|
248
|
+
'The examples in \`telescope-examples/\` are production-ready patterns that you can adapt for any blockchain task.'
|
|
249
|
+
].filter(line => line !== '').join('\\n');
|
|
250
|
+
|
|
251
|
+
return {
|
|
252
|
+
content: [{
|
|
253
|
+
type: "text",
|
|
254
|
+
text: response
|
|
255
|
+
}]
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
} catch (error) {
|
|
259
|
+
return {
|
|
260
|
+
content: [{
|
|
261
|
+
type: "text",
|
|
262
|
+
text: \`Error generating blockchain function guidance: \${(error as Error).message}\`
|
|
263
|
+
}]
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const transport = new StdioServerTransport();
|
|
270
|
+
await server.connect(transport);
|
|
271
|
+
console.log('${packageName} MCP server started on stdio');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// Helper functions for example recommendations
|
|
275
|
+
function getRelevantExamples(task: string, availableExamples: string[]): string[] {
|
|
276
|
+
const taskLower = task.toLowerCase();
|
|
277
|
+
const relevantExamples: string[] = [];
|
|
278
|
+
|
|
279
|
+
// Balance-related tasks
|
|
280
|
+
if (taskLower.includes('balance')) {
|
|
281
|
+
relevantExamples.push('useBalance', 'useBalanceFunc', 'getBalance');
|
|
282
|
+
if (taskLower.includes('react')) {
|
|
283
|
+
relevantExamples.push('useBalanceReact');
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Staking-related tasks
|
|
288
|
+
if (taskLower.includes('staking') || taskLower.includes('delegate') || taskLower.includes('validator')) {
|
|
289
|
+
relevantExamples.push('useStakingData', 'useValidators');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Governance/voting tasks
|
|
293
|
+
if (taskLower.includes('voting') || taskLower.includes('proposal') || taskLower.includes('governance')) {
|
|
294
|
+
relevantExamples.push('useVoting', 'useVotingData');
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Assets/portfolio tasks
|
|
298
|
+
if (taskLower.includes('asset') || taskLower.includes('portfolio') || taskLower.includes('total')) {
|
|
299
|
+
relevantExamples.push('useAssets', 'useTotalAssets');
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// Contract-related tasks
|
|
303
|
+
if (taskLower.includes('contract') || taskLower.includes('cosmwasm')) {
|
|
304
|
+
relevantExamples.push('useContractInfo', 'useQueryContract', 'useCodeDetails', 'useMyContracts');
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Transaction/sending tasks
|
|
308
|
+
if (taskLower.includes('send') || taskLower.includes('transaction') || taskLower.includes('transfer')) {
|
|
309
|
+
relevantExamples.push('useSendData', 'getBalance');
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
// Authorization tasks
|
|
313
|
+
if (taskLower.includes('grant') || taskLower.includes('authorization') || taskLower.includes('authz')) {
|
|
314
|
+
relevantExamples.push('useGrants');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// Always include config as it's fundamental
|
|
318
|
+
relevantExamples.unshift('config-example');
|
|
319
|
+
|
|
320
|
+
// Remove duplicates and ensure examples exist
|
|
321
|
+
return [...new Set(relevantExamples)].filter(example =>
|
|
322
|
+
availableExamples.includes(example)
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function getExampleDescription(example: string): string {
|
|
327
|
+
const descriptions: Record<string, string> = {
|
|
328
|
+
'config-example': 'Chain configuration and RPC endpoints setup',
|
|
329
|
+
'useBalance': 'React hook for querying account balance',
|
|
330
|
+
'useBalanceFunc': 'Direct function for balance queries',
|
|
331
|
+
'useBalanceReact': 'React hook with BigNumber for balance queries',
|
|
332
|
+
'getBalance': 'Basic balance query with transaction examples',
|
|
333
|
+
'useAssets': 'Query all token balances for an account',
|
|
334
|
+
'useStakingData': 'Comprehensive staking information (delegations, rewards, validators)',
|
|
335
|
+
'useValidators': 'Query active validators with sorting',
|
|
336
|
+
'useVoting': 'Active governance proposals in voting period',
|
|
337
|
+
'useVotingData': 'All governance proposals with categorization',
|
|
338
|
+
'useContractInfo': 'Smart contract information queries',
|
|
339
|
+
'useQueryContract': 'Execute smart contract queries',
|
|
340
|
+
'useCodeDetails': 'Contract code information and metadata',
|
|
341
|
+
'useMyContracts': 'Contracts created by specific address',
|
|
342
|
+
'useGrants': 'Authorization grants (granter/grantee)',
|
|
343
|
+
'useSendData': 'Prepare transaction data for token transfers',
|
|
344
|
+
'useTotalAssets': 'Portfolio summary with total asset calculations'
|
|
345
|
+
};
|
|
346
|
+
|
|
347
|
+
return descriptions[example] || 'Blockchain utility function';
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
main().catch((error) => {
|
|
351
|
+
console.error('Fatal error in main()', error);
|
|
352
|
+
process.exit(1);
|
|
353
|
+
});
|
|
354
|
+
`;
|
|
355
|
+
|
|
356
|
+
writeFileSync(
|
|
357
|
+
join(mcpServerPath, 'src', 'index.ts'),
|
|
358
|
+
indexContent
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
// Generate telescope loader utility
|
|
362
|
+
const telescopeLoaderCode = generateTelescopeLoader(packageName);
|
|
363
|
+
writeFileSync(
|
|
364
|
+
join(mcpServerPath, 'src', 'telescope-loader.ts'),
|
|
365
|
+
telescopeLoaderCode
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
// Generate TypeScript configuration
|
|
369
|
+
const tsConfig = generateTsConfig();
|
|
370
|
+
writeFileSync(
|
|
371
|
+
join(mcpServerPath, 'tsconfig.json'),
|
|
372
|
+
JSON.stringify(tsConfig, null, 2)
|
|
373
|
+
);
|
|
374
|
+
|
|
375
|
+
// Generate README
|
|
376
|
+
const readme = generateReadme(packageName);
|
|
377
|
+
writeFileSync(
|
|
378
|
+
join(mcpServerPath, 'README.md'),
|
|
379
|
+
readme
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
// Generate comprehensive prompts and guidelines
|
|
383
|
+
generateComprehensivePrompts(mcpServerPath, packageName);
|
|
384
|
+
|
|
385
|
+
// Generate telescope examples
|
|
386
|
+
generateTelescopeExamples(mcpServerPath, packageName);
|
|
387
|
+
|
|
388
|
+
// Copy entire telescope generated codebase for AI reference (excluded from build)
|
|
389
|
+
copyTelescopeCodebase(builder, mcpServerPath, packageName);
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
function generateMcpPackageJson(packageName: string) {
|
|
393
|
+
|
|
394
|
+
return {
|
|
395
|
+
name: `@${packageName}/mcp-server`,
|
|
396
|
+
version: "0.1.0",
|
|
397
|
+
description: `MCP server for ${packageName} blockchain interactions`,
|
|
398
|
+
main: "dist/index.js",
|
|
399
|
+
type: "module",
|
|
400
|
+
bin: {
|
|
401
|
+
[`@${packageName}/mcp-server`]: "./dist/index.js"
|
|
402
|
+
},
|
|
403
|
+
scripts: {
|
|
404
|
+
build: "rimraf dist && tsc",
|
|
405
|
+
clean: "rimraf dist",
|
|
406
|
+
test: "vitest",
|
|
407
|
+
inspector: "npm run build && npm exec @modelcontextprotocol/inspector node dist/index.js",
|
|
408
|
+
format: "biome check --write",
|
|
409
|
+
lint: "biome check"
|
|
410
|
+
},
|
|
411
|
+
dependencies: {
|
|
412
|
+
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
413
|
+
"zod": "^3.24.2"
|
|
414
|
+
},
|
|
415
|
+
devDependencies: {
|
|
416
|
+
"@biomejs/biome": "1.9.4",
|
|
417
|
+
"@types/node": "^22.13.10",
|
|
418
|
+
"rimraf": "^6.0.1",
|
|
419
|
+
"typescript": "^5.8.2",
|
|
420
|
+
"vitest": "^3.1.1"
|
|
421
|
+
},
|
|
422
|
+
files: ["dist"],
|
|
423
|
+
publishConfig: {
|
|
424
|
+
access: "public"
|
|
425
|
+
}
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function generateMcpServerCode(builder: TelescopeBuilder, bundler: Bundler) {
|
|
430
|
+
const outputDirName = basename(builder.outPath);
|
|
431
|
+
const packageName = outputDirName || bundler.bundle.base;
|
|
432
|
+
|
|
433
|
+
return `#!/usr/bin/env node
|
|
434
|
+
|
|
435
|
+
import { readFileSync } from 'node:fs';
|
|
436
|
+
import { dirname, resolve } from 'node:path';
|
|
437
|
+
import { fileURLToPath } from 'node:url';
|
|
438
|
+
|
|
439
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
440
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
441
|
+
import { z } from 'zod';
|
|
442
|
+
|
|
443
|
+
// NOTE: Tool imports are commented out since they are excluded from build
|
|
444
|
+
// Uncomment and modify these imports if you want to include tools in your build
|
|
445
|
+
/*
|
|
446
|
+
import { getBalanceTool } from './tools/getBalance.js';
|
|
447
|
+
import { getBalanceReactTool } from './tools/useBalance.js';
|
|
448
|
+
*/
|
|
449
|
+
|
|
450
|
+
// Get package.json version
|
|
451
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
452
|
+
const __dirname = dirname(__filename);
|
|
453
|
+
const packageJson = JSON.parse(readFileSync(resolve(__dirname, '../package.json'), 'utf8'));
|
|
454
|
+
const VERSION = packageJson.version;
|
|
455
|
+
|
|
456
|
+
async function main() {
|
|
457
|
+
const server = new McpServer({
|
|
458
|
+
name: '${packageName} MCP Server',
|
|
459
|
+
version: VERSION,
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
// Add prompts for AI agents
|
|
463
|
+
server.prompt(
|
|
464
|
+
'codegen-usage',
|
|
465
|
+
'Guide for using telescope generated code',
|
|
466
|
+
async () => {
|
|
467
|
+
const promptPath = resolve(__dirname, 'prompts/codegen-usage.md');
|
|
468
|
+
const content = readFileSync(promptPath, 'utf-8');
|
|
469
|
+
return {
|
|
470
|
+
messages: [{
|
|
471
|
+
role: 'user',
|
|
472
|
+
content: {
|
|
473
|
+
type: 'text',
|
|
474
|
+
text: content
|
|
475
|
+
}
|
|
476
|
+
}]
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
server.prompt(
|
|
482
|
+
'agent-guidelines',
|
|
483
|
+
'Guidelines for MCP agents using ${packageName}',
|
|
484
|
+
async () => {
|
|
485
|
+
const promptPath = resolve(__dirname, 'prompts/agent-guidelines.md');
|
|
486
|
+
const content = readFileSync(promptPath, 'utf-8');
|
|
487
|
+
return {
|
|
488
|
+
messages: [{
|
|
489
|
+
role: 'user',
|
|
490
|
+
content: {
|
|
491
|
+
type: 'text',
|
|
492
|
+
text: content
|
|
493
|
+
}
|
|
494
|
+
}]
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
);
|
|
498
|
+
|
|
499
|
+
// NOTE: Tool registrations are commented out since tool functions are not imported
|
|
500
|
+
// Uncomment and modify these registrations if you want to include tools in your build
|
|
501
|
+
/*
|
|
502
|
+
// Register tools
|
|
503
|
+
server.tool('get-balance', 'Get account balance for a specific token', {
|
|
504
|
+
address: z.string().describe('The account address'),
|
|
505
|
+
chainName: z.string().describe('The blockchain name (e.g., cosmos, osmosis)').optional(),
|
|
506
|
+
denom: z.string().describe('The token denomination (e.g., uatom, uosmo)').optional()
|
|
507
|
+
}, getBalanceTool);
|
|
508
|
+
|
|
509
|
+
server.tool('get-balance-react', 'Get balance using React hook pattern', {
|
|
510
|
+
address: z.string().describe('The account address'),
|
|
511
|
+
chainName: z.string().describe('The blockchain name').optional(),
|
|
512
|
+
displayDenom: z.string().describe('The display denomination').optional()
|
|
513
|
+
}, getBalanceReactTool);
|
|
514
|
+
*/
|
|
515
|
+
|
|
516
|
+
const transport = new StdioServerTransport();
|
|
517
|
+
await server.connect(transport);
|
|
518
|
+
console.log('${packageName} MCP server started on stdio');
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
main().catch((error) => {
|
|
522
|
+
console.error('Fatal error in main()', error);
|
|
523
|
+
process.exit(1);
|
|
524
|
+
});
|
|
525
|
+
`;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function generateTsConfig() {
|
|
529
|
+
return {
|
|
530
|
+
compilerOptions: {
|
|
531
|
+
target: "ES2022",
|
|
532
|
+
module: "ESNext",
|
|
533
|
+
moduleResolution: "node",
|
|
534
|
+
outDir: "./dist",
|
|
535
|
+
rootDir: "./src",
|
|
536
|
+
strict: true,
|
|
537
|
+
esModuleInterop: true,
|
|
538
|
+
skipLibCheck: true,
|
|
539
|
+
forceConsistentCasingInFileNames: true,
|
|
540
|
+
declaration: true,
|
|
541
|
+
declarationMap: true,
|
|
542
|
+
sourceMap: true,
|
|
543
|
+
allowSyntheticDefaultImports: true,
|
|
544
|
+
resolveJsonModule: true
|
|
545
|
+
},
|
|
546
|
+
include: ["src/**/*"],
|
|
547
|
+
exclude: ["node_modules", "dist", "src/telescope/**/*", "src/telescope-examples/**/*"]
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function generateReadme(packageName: string) {
|
|
552
|
+
|
|
553
|
+
return `# ${packageName.charAt(0).toUpperCase() + packageName.slice(1)} MCP Server
|
|
554
|
+
|
|
555
|
+
This MCP server provides AI agents with tools to interact with blockchain through generated TypeScript clients.
|
|
556
|
+
|
|
557
|
+
**Note**: This MCP server contains a complete copy of the telescope generated codebase in \`src/telescope/\` for AI agents to reference, but uses mock implementations for demonstration. The telescope code is excluded from the build process.
|
|
558
|
+
|
|
559
|
+
## Installation
|
|
560
|
+
|
|
561
|
+
\`\`\`bash
|
|
562
|
+
cd ${packageName}-mcp
|
|
563
|
+
npm install
|
|
564
|
+
npm run build
|
|
565
|
+
\`\`\`
|
|
566
|
+
|
|
567
|
+
## Usage with AI Agents
|
|
568
|
+
|
|
569
|
+
Add this configuration to your AI agent's MCP settings:
|
|
570
|
+
|
|
571
|
+
\`\`\`json
|
|
572
|
+
{
|
|
573
|
+
"mcpServers": {
|
|
574
|
+
"${packageName}-mcp-server": {
|
|
575
|
+
"command": "node",
|
|
576
|
+
"args": ["/path/to/${packageName}-mcp/dist/index.js"]
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
\`\`\`
|
|
581
|
+
|
|
582
|
+
## Available Features
|
|
583
|
+
|
|
584
|
+
This MCP server provides:
|
|
585
|
+
|
|
586
|
+
- **Comprehensive Examples**: Reference implementations in \`src/telescope-examples/\`
|
|
587
|
+
- **Function Generator Tool**: AI-powered tool that creates custom blockchain functions based on user requirements
|
|
588
|
+
- **AI Guidance**: Prompt files to help AI agents understand blockchain development
|
|
589
|
+
- **Complete Codebase**: Full telescope-generated code in \`src/telescope/\` for reference
|
|
590
|
+
|
|
591
|
+
**Note**: The MCP server uses a meta-tool approach - instead of predefined tools, it instructs agents to create custom functions by referencing the comprehensive examples.
|
|
592
|
+
|
|
593
|
+
## Development
|
|
594
|
+
|
|
595
|
+
\`\`\`bash
|
|
596
|
+
npm run build # Build the server
|
|
597
|
+
npm run inspector # Run MCP inspector for testing
|
|
598
|
+
npm run clean # Clean dist directory
|
|
599
|
+
\`\`\`
|
|
600
|
+
|
|
601
|
+
## Directory Structure
|
|
602
|
+
|
|
603
|
+
\`\`\`
|
|
604
|
+
${packageName}-mcp/
|
|
605
|
+
├── src/
|
|
606
|
+
│ ├── telescope/ # 📚 Telescope generated code (reference only, excluded from build)
|
|
607
|
+
│ │ ├── cosmos/ # Full cosmos SDK modules
|
|
608
|
+
│ │ │ ├── bank/ # Balance queries, transfers
|
|
609
|
+
│ │ │ ├── staking/ # Validator operations
|
|
610
|
+
│ │ │ └── ... # Other cosmos modules
|
|
611
|
+
│ │ ├── osmosis/ # Osmosis DEX functionality
|
|
612
|
+
│ │ ├── ibc/ # Inter-blockchain communication
|
|
613
|
+
│ │ └── index.ts # Main exports
|
|
614
|
+
│ ├── telescope-examples/ # 📖 Usage examples and patterns (excluded from build)
|
|
615
|
+
│ │ ├── config-example.ts # Chain configuration setup
|
|
616
|
+
│ │ ├── useBalance.ts # Balance query React hooks
|
|
617
|
+
│ │ ├── useBalanceFunc.ts # Direct balance functions
|
|
618
|
+
│ │ ├── getBalance.ts # Balance queries with examples
|
|
619
|
+
│ │ ├── useAssets.ts # Multi-token balance queries
|
|
620
|
+
│ │ ├── useStakingData.ts # Staking and delegation info
|
|
621
|
+
│ │ ├── useValidators.ts # Validator queries
|
|
622
|
+
│ │ ├── useVoting.ts # Governance proposals
|
|
623
|
+
│ │ ├── useContractInfo.ts # Smart contract queries
|
|
624
|
+
│ │ ├── useMyContracts.ts # User's contract list
|
|
625
|
+
│ │ ├── useGrants.ts # Authorization grants
|
|
626
|
+
│ │ └── useSendData.ts # Transaction preparation
|
|
627
|
+
│ ├── prompts/ # 🤖 Agent instruction files
|
|
628
|
+
│ │ ├── codegen-usage.md # Telescope usage guide
|
|
629
|
+
│ │ ├── agent-guidelines.md # Best practices for agents
|
|
630
|
+
│ │ └── chains.json # Chain registry data
|
|
631
|
+
│ ├── index.ts # MCP server with function generator tool
|
|
632
|
+
│ └── telescope-loader.ts # Utility for dynamic code loading
|
|
633
|
+
├── dist/ # Compiled JavaScript (excludes telescope/ and telescope-examples/)
|
|
634
|
+
└── package.json
|
|
635
|
+
\`\`\`
|
|
636
|
+
|
|
637
|
+
The \`src/telescope/\` and \`src/telescope-examples/\` directories contain reference code for AI agents but are excluded from the TypeScript build process.
|
|
638
|
+
|
|
639
|
+
Generated by [Telescope](https://github.com/hyperweb-io/telescope) 🔭
|
|
640
|
+
`;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function copyTelescopeCodebase(builder: TelescopeBuilder, mcpServerPath: string, packageName: string) {
|
|
644
|
+
const sourcePath = builder.outPath;
|
|
645
|
+
const destPath = join(mcpServerPath, 'src', 'telescope');
|
|
646
|
+
|
|
647
|
+
// Copy the entire telescope generated directory
|
|
648
|
+
if (existsSync(sourcePath)) {
|
|
649
|
+
// Skip copy if destination already exists (avoids Windows file permission issues)
|
|
650
|
+
if (existsSync(destPath)) {
|
|
651
|
+
console.log(`Telescope codebase already exists at ${destPath}, skipping copy to avoid Windows file permission issues`);
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
console.log(`Copying telescope codebase from ${sourcePath} to ${destPath}`);
|
|
656
|
+
|
|
657
|
+
// Ensure parent directory exists
|
|
658
|
+
mkdirSync(dirname(destPath), { recursive: true });
|
|
659
|
+
|
|
660
|
+
// Copy without removing destination first
|
|
661
|
+
try {
|
|
662
|
+
cpSync(sourcePath, destPath, { recursive: true, force: true });
|
|
663
|
+
} catch (error) {
|
|
664
|
+
console.warn(`Warning: Could not copy telescope codebase: ${error}`);
|
|
665
|
+
console.log('MCP server will still function, but AI agents will have limited code references');
|
|
666
|
+
// Don't throw error - let MCP server generation continue
|
|
667
|
+
}
|
|
668
|
+
} else {
|
|
669
|
+
console.warn(`Source path ${sourcePath} does not exist, skipping telescope codebase copy`);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// Removed retry logic - no longer needed since we skip copy if destination exists
|
|
674
|
+
|
|
675
|
+
function generateTelescopeLoader(packageName: string) {
|
|
676
|
+
return `import { readFileSync } from 'node:fs';
|
|
677
|
+
import { resolve, dirname } from 'node:path';
|
|
678
|
+
import { fileURLToPath } from 'node:url';
|
|
679
|
+
|
|
680
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
681
|
+
const __dirname = dirname(__filename);
|
|
682
|
+
|
|
683
|
+
/**
|
|
684
|
+
* Load telescope generated modules dynamically
|
|
685
|
+
* This utility helps MCP tools access the telescope codebase
|
|
686
|
+
*/
|
|
687
|
+
export class TelescopeLoader {
|
|
688
|
+
private basePath: string;
|
|
689
|
+
|
|
690
|
+
constructor() {
|
|
691
|
+
this.basePath = resolve(__dirname, 'telescope');
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Get available modules in the telescope codebase
|
|
696
|
+
*/
|
|
697
|
+
getAvailableModules(): string[] {
|
|
698
|
+
// This would typically read the directory structure
|
|
699
|
+
// For now, return common cosmos modules
|
|
700
|
+
return [
|
|
701
|
+
'cosmos/bank/v1beta1',
|
|
702
|
+
'cosmos/staking/v1beta1',
|
|
703
|
+
'cosmos/gov/v1beta1',
|
|
704
|
+
'cosmos/distribution/v1beta1',
|
|
705
|
+
'cosmwasm/wasm/v1',
|
|
706
|
+
'ibc/core/client/v1',
|
|
707
|
+
'osmosis/gamm/v1beta1'
|
|
708
|
+
];
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* Load module documentation/examples
|
|
713
|
+
*/
|
|
714
|
+
loadModuleInfo(modulePath: string) {
|
|
715
|
+
try {
|
|
716
|
+
const infoPath = resolve(this.basePath, modulePath, 'README.md');
|
|
717
|
+
return readFileSync(infoPath, 'utf-8');
|
|
718
|
+
} catch (error) {
|
|
719
|
+
return \`Module documentation not found for \${modulePath}\`;
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
/**
|
|
724
|
+
* Get module schema information
|
|
725
|
+
*/
|
|
726
|
+
getModuleSchema(modulePath: string) {
|
|
727
|
+
// Return basic schema info for the module
|
|
728
|
+
return {
|
|
729
|
+
module: modulePath,
|
|
730
|
+
package: '${packageName}',
|
|
731
|
+
queries: ['getBalance', 'getAllBalances'],
|
|
732
|
+
mutations: ['send', 'delegate'],
|
|
733
|
+
types: ['Coin', 'MsgSend', 'MsgDelegate']
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
export const telescopeLoader = new TelescopeLoader();
|
|
739
|
+
`;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function generateComprehensivePrompts(mcpServerPath: string, packageName: string) {
|
|
743
|
+
// Generate codegen-usage.md
|
|
744
|
+
const codegenUsageContent = `# Codegen Usage Guide
|
|
745
|
+
|
|
746
|
+
## Overview
|
|
747
|
+
This guide provides instructions for MCP agents on how to use the telescope generated code in the ${packageName} package.
|
|
748
|
+
|
|
749
|
+
## Category of Functions
|
|
750
|
+
|
|
751
|
+
### 1. **.rpc.func** - Direct Function Calls
|
|
752
|
+
These are direct async functions that make RPC calls to blockchain nodes. Use these for:
|
|
753
|
+
- Server-side operations
|
|
754
|
+
- Node.js scripts
|
|
755
|
+
- Direct blockchain queries outside React
|
|
756
|
+
|
|
757
|
+
**Import Pattern**:
|
|
758
|
+
\`\`\`typescript
|
|
759
|
+
import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
|
|
760
|
+
import { send } from '${packageName}/cosmos/bank/v1beta1/tx.rpc.func';
|
|
761
|
+
\`\`\`
|
|
762
|
+
|
|
763
|
+
**Usage Examples**:
|
|
764
|
+
|
|
765
|
+
**Query Balance**:
|
|
766
|
+
\`\`\`typescript
|
|
767
|
+
import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
|
|
768
|
+
|
|
769
|
+
// Basic balance query
|
|
770
|
+
const { balance } = await getBalance(rpcEndpoint, {
|
|
771
|
+
address: "cosmos1...",
|
|
772
|
+
denom: "uatom"
|
|
773
|
+
});
|
|
774
|
+
|
|
775
|
+
// With error handling
|
|
776
|
+
try {
|
|
777
|
+
const { balance } = await getBalance(rpcEndpoint, { address, denom });
|
|
778
|
+
const atomAmount = Number(balance?.amount || 0) / Math.pow(10, 6); // Convert uatom to ATOM
|
|
779
|
+
return atomAmount;
|
|
780
|
+
} catch (error) {
|
|
781
|
+
console.error('Error fetching balance:', error);
|
|
782
|
+
return null;
|
|
783
|
+
}
|
|
784
|
+
\`\`\`
|
|
785
|
+
|
|
786
|
+
### 2. **.rpc.react** - React Hooks
|
|
787
|
+
These are React hooks for frontend applications. They provide:
|
|
788
|
+
- Automatic caching and refetching
|
|
789
|
+
- Loading states
|
|
790
|
+
- Error handling
|
|
791
|
+
- Integration with React Query
|
|
792
|
+
|
|
793
|
+
**Import Pattern**:
|
|
794
|
+
\`\`\`typescript
|
|
795
|
+
import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
796
|
+
import { useSend } from '${packageName}/cosmos/bank/v1beta1/tx.rpc.react';
|
|
797
|
+
\`\`\`
|
|
798
|
+
|
|
799
|
+
## Chain Configuration Setup
|
|
800
|
+
|
|
801
|
+
### Import Chain Registry Data
|
|
802
|
+
\`\`\`typescript
|
|
803
|
+
import { assetLists, chains } from "@chain-registry/v2";
|
|
804
|
+
\`\`\`
|
|
805
|
+
|
|
806
|
+
### Basic Configuration
|
|
807
|
+
\`\`\`typescript
|
|
808
|
+
// Define your target chain
|
|
809
|
+
export const defaultChainName = 'cosmos'; // or 'osmosis', 'injective', etc.
|
|
810
|
+
|
|
811
|
+
// Find chain info from registry
|
|
812
|
+
export const defaultChain = chains.find((chain) => chain.chainName === defaultChainName);
|
|
813
|
+
|
|
814
|
+
// Get RPC endpoint
|
|
815
|
+
export const defaultRpcEndpoint = defaultChain?.apis?.rpc?.[0]?.address || 'http://localhost:26657';
|
|
816
|
+
\`\`\`
|
|
817
|
+
|
|
818
|
+
## Detailed Examples Reference
|
|
819
|
+
|
|
820
|
+
### Using src/telescope-examples Directory
|
|
821
|
+
When you need more specific implementation details or complex use cases, reference the example files in \`src/telescope-examples/\`. These are real-world examples for production usage.
|
|
822
|
+
|
|
823
|
+
### Using src/tools Directory
|
|
824
|
+
The \`src/tools/\` directory contains MCP tool implementations that demonstrate how to use the telescope-examples in MCP tools. These tools show patterns for:
|
|
825
|
+
- Importing functions from telescope-examples
|
|
826
|
+
- Handling errors and returning proper MCP responses
|
|
827
|
+
- Working with blockchain data in MCP context
|
|
828
|
+
|
|
829
|
+
Each tool in \`src/tools/\` corresponds to functionality in \`src/telescope-examples/\` and shows how to bridge the gap between React hooks/utility functions and MCP tool implementations.
|
|
830
|
+
|
|
831
|
+
## Important Notes
|
|
832
|
+
|
|
833
|
+
### Function Categories Usage
|
|
834
|
+
- **Use .rpc.func** for: Server-side scripts, CLI tools, backend services
|
|
835
|
+
- **Use .rpc.react** for: React applications, frontend components with state management
|
|
836
|
+
|
|
837
|
+
### Error Handling Patterns
|
|
838
|
+
\`\`\`typescript
|
|
839
|
+
// For .rpc.func
|
|
840
|
+
try {
|
|
841
|
+
const result = await getBalance(rpcEndpoint, { address, denom });
|
|
842
|
+
return result;
|
|
843
|
+
} catch (error) {
|
|
844
|
+
if (error.message.includes('not found')) {
|
|
845
|
+
return null; // Handle account not found
|
|
846
|
+
}
|
|
847
|
+
throw error; // Re-throw other errors
|
|
848
|
+
}
|
|
849
|
+
\`\`\`
|
|
850
|
+
`;
|
|
851
|
+
|
|
852
|
+
writeFileSync(join(mcpServerPath, 'src', 'prompts', 'codegen-usage.md'), codegenUsageContent);
|
|
853
|
+
|
|
854
|
+
// Generate agent-guidelines.md
|
|
855
|
+
const agentGuidelinesContent = `# MCP Agent Guidelines
|
|
856
|
+
|
|
857
|
+
## Overview
|
|
858
|
+
These guidelines help MCP agents provide helpful, accurate, and safe blockchain interactions using the ${packageName} library.
|
|
859
|
+
|
|
860
|
+
## General Principles
|
|
861
|
+
|
|
862
|
+
### 1. Safety First
|
|
863
|
+
- **Never expose private keys or mnemonics**
|
|
864
|
+
- **Always validate addresses before operations**
|
|
865
|
+
- **Warn users about irreversible operations**
|
|
866
|
+
- **Explain risks (slashing, unbonding periods, etc.)**
|
|
867
|
+
|
|
868
|
+
### 2. User-Friendly Communication
|
|
869
|
+
- **Convert base units to human-readable amounts** (uatom → ATOM)
|
|
870
|
+
- **Use clear, non-technical language when possible**
|
|
871
|
+
- **Provide context for blockchain-specific concepts**
|
|
872
|
+
- **Show approximate USD values when helpful**
|
|
873
|
+
|
|
874
|
+
### 3. Accuracy and Reliability
|
|
875
|
+
- **Always handle errors gracefully**
|
|
876
|
+
- **Provide accurate information about fees and timing**
|
|
877
|
+
- **Double-check calculations and conversions**
|
|
878
|
+
- **Verify data freshness and warn about stale data**
|
|
879
|
+
|
|
880
|
+
## Response Patterns
|
|
881
|
+
|
|
882
|
+
### When User Asks About Balances
|
|
883
|
+
\`\`\`
|
|
884
|
+
✅ Good Response:
|
|
885
|
+
"You have 12.5 ATOM (12,500,000 uatom) in your wallet. This is worth approximately $150 USD at current prices. You also have 0.05 ATOM available to pay for transaction fees."
|
|
886
|
+
|
|
887
|
+
❌ Poor Response:
|
|
888
|
+
"Balance: 12500000"
|
|
889
|
+
\`\`\`
|
|
890
|
+
|
|
891
|
+
## Data Formatting Guidelines
|
|
892
|
+
|
|
893
|
+
### Amounts
|
|
894
|
+
Always convert from base units:
|
|
895
|
+
\`\`\`typescript
|
|
896
|
+
// Good
|
|
897
|
+
const atomAmount = parseInt(balance.amount) / 1_000_000;
|
|
898
|
+
return \`$\{atomAmount} ATOM\`;
|
|
899
|
+
|
|
900
|
+
// Bad
|
|
901
|
+
return \`$\{balance.amount} uatom\`;
|
|
902
|
+
\`\`\`
|
|
903
|
+
|
|
904
|
+
### Addresses
|
|
905
|
+
Abbreviate long addresses for readability:
|
|
906
|
+
\`\`\`typescript
|
|
907
|
+
const formatAddress = (addr: string) => {
|
|
908
|
+
return \`$\{addr.slice(0, 10)}...$\{addr.slice(-4)}\`;
|
|
909
|
+
};
|
|
910
|
+
// cosmos1abc123...xyz9
|
|
911
|
+
\`\`\`
|
|
912
|
+
|
|
913
|
+
## Security Guidelines
|
|
914
|
+
|
|
915
|
+
### Address Validation
|
|
916
|
+
\`\`\`typescript
|
|
917
|
+
const validateCosmosAddress = (address: string): boolean => {
|
|
918
|
+
return address.startsWith('cosmos1') && address.length === 45;
|
|
919
|
+
};
|
|
920
|
+
\`\`\`
|
|
921
|
+
|
|
922
|
+
### Amount Validation
|
|
923
|
+
\`\`\`typescript
|
|
924
|
+
const validateAmount = (amount: string): boolean => {
|
|
925
|
+
const num = parseFloat(amount);
|
|
926
|
+
return !isNaN(num) && num > 0 && num < 1e15; // Reasonable limits
|
|
927
|
+
};
|
|
928
|
+
\`\`\`
|
|
929
|
+
`;
|
|
930
|
+
|
|
931
|
+
writeFileSync(join(mcpServerPath, 'src', 'prompts', 'agent-guidelines.md'), agentGuidelinesContent);
|
|
932
|
+
|
|
933
|
+
// Copy chains.json from chain-registry (this is a large static file)
|
|
934
|
+
const chainsJsonContent = `[
|
|
935
|
+
{
|
|
936
|
+
"$schema": "../chain.schema.json",
|
|
937
|
+
"chainName": "cosmos",
|
|
938
|
+
"status": "live",
|
|
939
|
+
"networkType": "mainnet",
|
|
940
|
+
"prettyName": "Cosmos Hub",
|
|
941
|
+
"chainId": "cosmoshub-4",
|
|
942
|
+
"bech32Prefix": "cosmos",
|
|
943
|
+
"daemonName": "gaiad",
|
|
944
|
+
"nodeHome": "$HOME/.gaia",
|
|
945
|
+
"slip44": 118,
|
|
946
|
+
"apis": {
|
|
947
|
+
"rpc": [
|
|
948
|
+
{
|
|
949
|
+
"address": "https://cosmos-rpc.quickapi.com:443"
|
|
950
|
+
}
|
|
951
|
+
],
|
|
952
|
+
"rest": [
|
|
953
|
+
{
|
|
954
|
+
"address": "https://cosmos-rest.quickapi.com:443"
|
|
955
|
+
}
|
|
956
|
+
]
|
|
957
|
+
}
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
"chainName": "osmosis",
|
|
961
|
+
"status": "live",
|
|
962
|
+
"networkType": "mainnet",
|
|
963
|
+
"prettyName": "Osmosis",
|
|
964
|
+
"chainId": "osmosis-1",
|
|
965
|
+
"bech32Prefix": "osmo",
|
|
966
|
+
"daemonName": "osmosisd",
|
|
967
|
+
"nodeHome": "$HOME/.osmosisd",
|
|
968
|
+
"slip44": 118,
|
|
969
|
+
"apis": {
|
|
970
|
+
"rpc": [
|
|
971
|
+
{
|
|
972
|
+
"address": "https://osmosis-rpc.quickapi.com:443"
|
|
973
|
+
}
|
|
974
|
+
],
|
|
975
|
+
"rest": [
|
|
976
|
+
{
|
|
977
|
+
"address": "https://osmosis-rest.quickapi.com:443"
|
|
978
|
+
}
|
|
979
|
+
]
|
|
980
|
+
}
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
"chainName": "injective",
|
|
984
|
+
"status": "live",
|
|
985
|
+
"networkType": "mainnet",
|
|
986
|
+
"prettyName": "Injective",
|
|
987
|
+
"chainId": "injective-1",
|
|
988
|
+
"bech32Prefix": "inj",
|
|
989
|
+
"daemonName": "injectived",
|
|
990
|
+
"nodeHome": "$HOME/.injectived",
|
|
991
|
+
"slip44": 60,
|
|
992
|
+
"apis": {
|
|
993
|
+
"rpc": [
|
|
994
|
+
{
|
|
995
|
+
"address": "https://injective-rpc.quickapi.com:443"
|
|
996
|
+
}
|
|
997
|
+
],
|
|
998
|
+
"rest": [
|
|
999
|
+
{
|
|
1000
|
+
"address": "https://injective-rest.quickapi.com:443"
|
|
1001
|
+
}
|
|
1002
|
+
]
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
]`;
|
|
1006
|
+
|
|
1007
|
+
writeFileSync(join(mcpServerPath, 'src', 'prompts', 'chains.json'), chainsJsonContent);
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
function generateTelescopeExamples(mcpServerPath: string, packageName: string) {
|
|
1011
|
+
const exampleFiles = [
|
|
1012
|
+
{
|
|
1013
|
+
name: 'config-example.ts',
|
|
1014
|
+
content: `import { assetLists, chains } from "@chain-registry/v2";
|
|
1015
|
+
|
|
1016
|
+
/**
|
|
1017
|
+
* mainnet: 'cosmos'
|
|
1018
|
+
* testnet: 'cosmoshub-testnet'
|
|
1019
|
+
* mainnet rpc: 'https://cosmos-rpc.quickapi.com:443'
|
|
1020
|
+
* testnet rpc: 'https://rpc.testnet.cosmos.network:443'
|
|
1021
|
+
*/
|
|
1022
|
+
export const defaultChainName = 'cosmos'
|
|
1023
|
+
export const defaultRpcEndpoint = 'https://cosmos-rpc.quickapi.com:443'
|
|
1024
|
+
|
|
1025
|
+
export const defaultChain = chains.find((chain) => chain.chainName === defaultChainName)
|
|
1026
|
+
|
|
1027
|
+
export const defaultAssetList = assetLists.find((assetList) => assetList.chainName === defaultChainName)
|
|
1028
|
+
`
|
|
1029
|
+
},
|
|
1030
|
+
{
|
|
1031
|
+
name: 'useBalance.ts',
|
|
1032
|
+
content: `import { useChain } from '@interchain-kit/react';
|
|
1033
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1034
|
+
import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
1035
|
+
|
|
1036
|
+
export const useBalance = (
|
|
1037
|
+
chainName: string,
|
|
1038
|
+
enabled: boolean = true,
|
|
1039
|
+
displayDenom?: string
|
|
1040
|
+
) => {
|
|
1041
|
+
const { address, assetList } = useChain(chainName);
|
|
1042
|
+
|
|
1043
|
+
let denom = assetList?.assets[0].base!;
|
|
1044
|
+
for (const asset of assetList?.assets || []) {
|
|
1045
|
+
if (asset.display.toLowerCase() === displayDenom?.toLowerCase()) {
|
|
1046
|
+
denom = asset.base;
|
|
1047
|
+
break;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443'; // Use dynamic endpoint
|
|
1052
|
+
|
|
1053
|
+
const isReady = !!address && !!rpcEndpoint;
|
|
1054
|
+
|
|
1055
|
+
const balanceQuery = useGetBalance({
|
|
1056
|
+
request: {
|
|
1057
|
+
denom,
|
|
1058
|
+
address: address || '',
|
|
1059
|
+
},
|
|
1060
|
+
options: {
|
|
1061
|
+
enabled: isReady && enabled,
|
|
1062
|
+
select: ({ balance }) => balance,
|
|
1063
|
+
context: defaultContext,
|
|
1064
|
+
},
|
|
1065
|
+
clientResolver: rpcEndpoint,
|
|
1066
|
+
customizedQueryKey: ['balance', address, denom],
|
|
1067
|
+
});
|
|
1068
|
+
|
|
1069
|
+
return {
|
|
1070
|
+
balance: balanceQuery.data,
|
|
1071
|
+
isLoading: balanceQuery.isFetching,
|
|
1072
|
+
};
|
|
1073
|
+
};
|
|
1074
|
+
`
|
|
1075
|
+
},
|
|
1076
|
+
{
|
|
1077
|
+
name: 'useBalanceReact.ts',
|
|
1078
|
+
content: `import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
1079
|
+
import { defaultRpcEndpoint as rpcEndpoint } from '@/config';
|
|
1080
|
+
import BigNumber from 'bignumber.js';
|
|
1081
|
+
import { defaultAssetList } from '@/config';
|
|
1082
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1083
|
+
|
|
1084
|
+
export default function useBalance({ address }: { address: string }) {
|
|
1085
|
+
const coin = defaultAssetList?.assets[0];
|
|
1086
|
+
|
|
1087
|
+
const denom = coin!.base!;
|
|
1088
|
+
|
|
1089
|
+
const COIN_DISPLAY_EXPONENT = coin!.denomUnits.find(
|
|
1090
|
+
(unit) => unit.denom === coin!.display
|
|
1091
|
+
)?.exponent as number;
|
|
1092
|
+
|
|
1093
|
+
const {
|
|
1094
|
+
data: balance,
|
|
1095
|
+
isSuccess: isBalanceLoaded,
|
|
1096
|
+
isLoading: isFetchingBalance,
|
|
1097
|
+
refetch: refetchBalance,
|
|
1098
|
+
} = useGetBalance({
|
|
1099
|
+
request: {
|
|
1100
|
+
address: address || '',
|
|
1101
|
+
denom,
|
|
1102
|
+
},
|
|
1103
|
+
options: {
|
|
1104
|
+
context: defaultContext,
|
|
1105
|
+
enabled: !!address,
|
|
1106
|
+
select: ({ balance }) =>
|
|
1107
|
+
new BigNumber(balance?.amount ?? 0).multipliedBy(
|
|
1108
|
+
10 ** -COIN_DISPLAY_EXPONENT
|
|
1109
|
+
),
|
|
1110
|
+
staleTime: 0,
|
|
1111
|
+
},
|
|
1112
|
+
clientResolver: rpcEndpoint,
|
|
1113
|
+
});
|
|
1114
|
+
|
|
1115
|
+
return {
|
|
1116
|
+
balance,
|
|
1117
|
+
isBalanceLoaded,
|
|
1118
|
+
isFetchingBalance,
|
|
1119
|
+
refetchBalance,
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
`
|
|
1123
|
+
},
|
|
1124
|
+
{
|
|
1125
|
+
name: 'useBalanceFunc.ts',
|
|
1126
|
+
content: `import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
|
|
1127
|
+
import { defaultRpcEndpoint } from '@/config';
|
|
1128
|
+
|
|
1129
|
+
export const useBalanceFunc = async (address: string, denom: string) => {
|
|
1130
|
+
try {
|
|
1131
|
+
const { balance } = await getBalance(defaultRpcEndpoint, {
|
|
1132
|
+
address,
|
|
1133
|
+
denom,
|
|
1134
|
+
});
|
|
1135
|
+
|
|
1136
|
+
return {
|
|
1137
|
+
balance: balance?.amount || '0',
|
|
1138
|
+
denom: balance?.denom || denom,
|
|
1139
|
+
};
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
console.error('Error fetching balance:', error);
|
|
1142
|
+
return {
|
|
1143
|
+
balance: '0',
|
|
1144
|
+
denom,
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
};
|
|
1148
|
+
`
|
|
1149
|
+
},
|
|
1150
|
+
{
|
|
1151
|
+
name: 'getBalance.ts',
|
|
1152
|
+
content: `import { getBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.func';
|
|
1153
|
+
import { send } from '${packageName}/cosmos/bank/v1beta1/tx.rpc.func';
|
|
1154
|
+
import { MsgSend } from '${packageName}/cosmos/bank/v1beta1/tx';
|
|
1155
|
+
|
|
1156
|
+
const main = async () => {
|
|
1157
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1158
|
+
const denom = 'uatom';
|
|
1159
|
+
const address = 'cosmos1...'; // Your address here
|
|
1160
|
+
|
|
1161
|
+
// Query balance
|
|
1162
|
+
const { balance } = await getBalance(rpcEndpoint, {
|
|
1163
|
+
address,
|
|
1164
|
+
denom,
|
|
1165
|
+
});
|
|
1166
|
+
|
|
1167
|
+
console.log(\`Balance: \${balance?.amount} \${denom}\`);
|
|
1168
|
+
|
|
1169
|
+
// Example: Send transaction (requires signer setup)
|
|
1170
|
+
/*
|
|
1171
|
+
const fee = {
|
|
1172
|
+
amount: [{ denom, amount: '5000' }],
|
|
1173
|
+
gas: '200000',
|
|
1174
|
+
};
|
|
1175
|
+
|
|
1176
|
+
const token = {
|
|
1177
|
+
amount: '1000000',
|
|
1178
|
+
denom,
|
|
1179
|
+
};
|
|
1180
|
+
|
|
1181
|
+
const msg = MsgSend.fromPartial({
|
|
1182
|
+
fromAddress: address,
|
|
1183
|
+
toAddress: 'cosmos1recipient...',
|
|
1184
|
+
amount: [token],
|
|
1185
|
+
});
|
|
1186
|
+
|
|
1187
|
+
// const tx = await send(signer, address, msg, fee, 'Payment');
|
|
1188
|
+
*/
|
|
1189
|
+
};
|
|
1190
|
+
|
|
1191
|
+
main().catch(console.error);
|
|
1192
|
+
`
|
|
1193
|
+
},
|
|
1194
|
+
{
|
|
1195
|
+
name: 'useAssets.ts',
|
|
1196
|
+
content: `import { useMemo } from 'react';
|
|
1197
|
+
import { useChain } from '@interchain-kit/react';
|
|
1198
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1199
|
+
import BigNumber from 'bignumber.js';
|
|
1200
|
+
import { useGetAllBalances } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
1201
|
+
import { Coin } from '${packageName}/types';
|
|
1202
|
+
|
|
1203
|
+
export const useAssets = (chainName: string) => {
|
|
1204
|
+
const { address } = useChain(chainName);
|
|
1205
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1206
|
+
|
|
1207
|
+
const isReady = !!address && !!rpcEndpoint;
|
|
1208
|
+
|
|
1209
|
+
const allBalancesQuery = useGetAllBalances({
|
|
1210
|
+
request: {
|
|
1211
|
+
address: address || '',
|
|
1212
|
+
pagination: {
|
|
1213
|
+
key: new Uint8Array(),
|
|
1214
|
+
offset: 0n,
|
|
1215
|
+
limit: 100n,
|
|
1216
|
+
countTotal: true,
|
|
1217
|
+
reverse: false,
|
|
1218
|
+
},
|
|
1219
|
+
resolveDenom: false,
|
|
1220
|
+
},
|
|
1221
|
+
options: {
|
|
1222
|
+
enabled: isReady,
|
|
1223
|
+
select: ({ balances }) => balances || [],
|
|
1224
|
+
context: defaultContext,
|
|
1225
|
+
},
|
|
1226
|
+
clientResolver: rpcEndpoint,
|
|
1227
|
+
customizedQueryKey: ['allBalances', address],
|
|
1228
|
+
});
|
|
1229
|
+
|
|
1230
|
+
const data = useMemo(() => {
|
|
1231
|
+
if (!allBalancesQuery.data) return;
|
|
1232
|
+
|
|
1233
|
+
const assets = allBalancesQuery.data.map(({ amount, denom }) => ({
|
|
1234
|
+
symbol: denom.toUpperCase(),
|
|
1235
|
+
displayAmount: new BigNumber(amount).dividedBy(1e6).toString(),
|
|
1236
|
+
amount,
|
|
1237
|
+
denom,
|
|
1238
|
+
}));
|
|
1239
|
+
|
|
1240
|
+
return { assets };
|
|
1241
|
+
}, [allBalancesQuery.data]);
|
|
1242
|
+
|
|
1243
|
+
return {
|
|
1244
|
+
data,
|
|
1245
|
+
isLoading: allBalancesQuery.isLoading,
|
|
1246
|
+
refetch: allBalancesQuery.refetch
|
|
1247
|
+
};
|
|
1248
|
+
};
|
|
1249
|
+
`
|
|
1250
|
+
},
|
|
1251
|
+
{
|
|
1252
|
+
name: 'useStakingData.ts',
|
|
1253
|
+
content: `import { useMemo } from 'react';
|
|
1254
|
+
import { useChain } from '@interchain-kit/react';
|
|
1255
|
+
import BigNumber from 'bignumber.js';
|
|
1256
|
+
import {
|
|
1257
|
+
BondStatus,
|
|
1258
|
+
bondStatusToJSON,
|
|
1259
|
+
} from '${packageName}/cosmos/staking/v1beta1/staking';
|
|
1260
|
+
import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
1261
|
+
import {
|
|
1262
|
+
useGetDelegatorValidators,
|
|
1263
|
+
useGetDelegatorDelegations,
|
|
1264
|
+
useGetValidators,
|
|
1265
|
+
useGetParams as useStakingParams,
|
|
1266
|
+
useGetPool,
|
|
1267
|
+
} from '${packageName}/cosmos/staking/v1beta1/query.rpc.react';
|
|
1268
|
+
import {
|
|
1269
|
+
useGetDelegationTotalRewards,
|
|
1270
|
+
useGetParams as useDistributionParams,
|
|
1271
|
+
} from '${packageName}/cosmos/distribution/v1beta1/query.rpc.react';
|
|
1272
|
+
import { useGetAnnualProvisions } from '${packageName}/cosmos/mint/v1beta1/query.rpc.react';
|
|
1273
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1274
|
+
|
|
1275
|
+
export const useStakingData = (chainName: string) => {
|
|
1276
|
+
const { address, assetList } = useChain(chainName);
|
|
1277
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1278
|
+
|
|
1279
|
+
const coin = assetList?.assets[0];
|
|
1280
|
+
const denom = coin?.base || 'uatom';
|
|
1281
|
+
|
|
1282
|
+
const isDataQueryEnabled = !!address && !!rpcEndpoint;
|
|
1283
|
+
|
|
1284
|
+
const balanceQuery = useGetBalance({
|
|
1285
|
+
request: {
|
|
1286
|
+
address: address || '',
|
|
1287
|
+
denom,
|
|
1288
|
+
},
|
|
1289
|
+
options: {
|
|
1290
|
+
context: defaultContext,
|
|
1291
|
+
enabled: isDataQueryEnabled,
|
|
1292
|
+
select: ({ balance }) => balance?.amount || '0',
|
|
1293
|
+
refetchOnMount: 'always',
|
|
1294
|
+
},
|
|
1295
|
+
clientResolver: rpcEndpoint,
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
const validatorsQuery = useGetValidators({
|
|
1299
|
+
request: {
|
|
1300
|
+
status: bondStatusToJSON(BondStatus.BOND_STATUS_BONDED),
|
|
1301
|
+
pagination: {
|
|
1302
|
+
key: new Uint8Array(),
|
|
1303
|
+
offset: 0n,
|
|
1304
|
+
limit: 200n,
|
|
1305
|
+
countTotal: true,
|
|
1306
|
+
reverse: false,
|
|
1307
|
+
},
|
|
1308
|
+
},
|
|
1309
|
+
options: {
|
|
1310
|
+
context: defaultContext,
|
|
1311
|
+
enabled: isDataQueryEnabled,
|
|
1312
|
+
select: ({ validators }) => {
|
|
1313
|
+
return validators.sort((a, b) =>
|
|
1314
|
+
new BigNumber(b.tokens).minus(a.tokens).toNumber(),
|
|
1315
|
+
);
|
|
1316
|
+
},
|
|
1317
|
+
},
|
|
1318
|
+
clientResolver: rpcEndpoint,
|
|
1319
|
+
customizedQueryKey: ['validators', chainName],
|
|
1320
|
+
});
|
|
1321
|
+
|
|
1322
|
+
const delegationsQuery = useGetDelegatorDelegations({
|
|
1323
|
+
request: {
|
|
1324
|
+
delegatorAddr: address || '',
|
|
1325
|
+
pagination: {
|
|
1326
|
+
key: new Uint8Array(),
|
|
1327
|
+
offset: 0n,
|
|
1328
|
+
limit: 100n,
|
|
1329
|
+
countTotal: true,
|
|
1330
|
+
reverse: false,
|
|
1331
|
+
},
|
|
1332
|
+
},
|
|
1333
|
+
options: {
|
|
1334
|
+
context: defaultContext,
|
|
1335
|
+
enabled: isDataQueryEnabled,
|
|
1336
|
+
select: ({ delegationResponses }) => delegationResponses,
|
|
1337
|
+
},
|
|
1338
|
+
clientResolver: rpcEndpoint,
|
|
1339
|
+
});
|
|
1340
|
+
|
|
1341
|
+
const rewardsQuery = useGetDelegationTotalRewards({
|
|
1342
|
+
request: {
|
|
1343
|
+
delegatorAddress: address || '',
|
|
1344
|
+
},
|
|
1345
|
+
options: {
|
|
1346
|
+
context: defaultContext,
|
|
1347
|
+
enabled: isDataQueryEnabled,
|
|
1348
|
+
select: (data) => data,
|
|
1349
|
+
},
|
|
1350
|
+
clientResolver: rpcEndpoint,
|
|
1351
|
+
});
|
|
1352
|
+
|
|
1353
|
+
const allQueries = {
|
|
1354
|
+
balance: balanceQuery,
|
|
1355
|
+
validators: validatorsQuery,
|
|
1356
|
+
delegations: delegationsQuery,
|
|
1357
|
+
rewards: rewardsQuery,
|
|
1358
|
+
};
|
|
1359
|
+
|
|
1360
|
+
const isLoading = Object.values(allQueries).some(
|
|
1361
|
+
({ isLoading }) => isLoading,
|
|
1362
|
+
);
|
|
1363
|
+
|
|
1364
|
+
const data = useMemo(() => {
|
|
1365
|
+
if (isLoading) return;
|
|
1366
|
+
|
|
1367
|
+
return {
|
|
1368
|
+
balance: balanceQuery.data,
|
|
1369
|
+
validators: validatorsQuery.data,
|
|
1370
|
+
delegations: delegationsQuery.data,
|
|
1371
|
+
rewards: rewardsQuery.data,
|
|
1372
|
+
};
|
|
1373
|
+
}, [isLoading, balanceQuery.data, validatorsQuery.data, delegationsQuery.data, rewardsQuery.data]);
|
|
1374
|
+
|
|
1375
|
+
const refetch = () => {
|
|
1376
|
+
Object.values(allQueries).forEach((query) => query.refetch());
|
|
1377
|
+
};
|
|
1378
|
+
|
|
1379
|
+
return { data, isLoading, refetch };
|
|
1380
|
+
};
|
|
1381
|
+
`
|
|
1382
|
+
},
|
|
1383
|
+
{
|
|
1384
|
+
name: 'useValidators.ts',
|
|
1385
|
+
content: `import { useMemo } from 'react';
|
|
1386
|
+
import { BondStatus, bondStatusToJSON } from '${packageName}/cosmos/staking/v1beta1/staking';
|
|
1387
|
+
import { useGetValidators } from '${packageName}/cosmos/staking/v1beta1/query.rpc.react';
|
|
1388
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1389
|
+
import BigNumber from 'bignumber.js';
|
|
1390
|
+
|
|
1391
|
+
export const useValidators = (chainName: string) => {
|
|
1392
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1393
|
+
|
|
1394
|
+
const validatorsQuery = useGetValidators({
|
|
1395
|
+
request: {
|
|
1396
|
+
status: bondStatusToJSON(BondStatus.BOND_STATUS_BONDED),
|
|
1397
|
+
pagination: {
|
|
1398
|
+
key: new Uint8Array(),
|
|
1399
|
+
offset: 0n,
|
|
1400
|
+
limit: 200n,
|
|
1401
|
+
countTotal: true,
|
|
1402
|
+
reverse: false,
|
|
1403
|
+
},
|
|
1404
|
+
},
|
|
1405
|
+
options: {
|
|
1406
|
+
context: defaultContext,
|
|
1407
|
+
enabled: !!rpcEndpoint,
|
|
1408
|
+
select: ({ validators }) => {
|
|
1409
|
+
return validators
|
|
1410
|
+
.sort((a, b) => new BigNumber(b.tokens).minus(a.tokens).toNumber())
|
|
1411
|
+
.map((validator) => ({
|
|
1412
|
+
operatorAddress: validator.operatorAddress,
|
|
1413
|
+
moniker: validator.description?.moniker || '',
|
|
1414
|
+
tokens: validator.tokens,
|
|
1415
|
+
delegatorShares: validator.delegatorShares,
|
|
1416
|
+
commission: validator.commission?.commissionRates?.rate || '0',
|
|
1417
|
+
status: validator.status,
|
|
1418
|
+
jailed: validator.jailed,
|
|
1419
|
+
}));
|
|
1420
|
+
},
|
|
1421
|
+
},
|
|
1422
|
+
clientResolver: rpcEndpoint,
|
|
1423
|
+
customizedQueryKey: ['validators', chainName],
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1426
|
+
return {
|
|
1427
|
+
data: validatorsQuery.data,
|
|
1428
|
+
isLoading: validatorsQuery.isLoading,
|
|
1429
|
+
refetch: validatorsQuery.refetch,
|
|
1430
|
+
};
|
|
1431
|
+
};
|
|
1432
|
+
`
|
|
1433
|
+
},
|
|
1434
|
+
{
|
|
1435
|
+
name: 'useVoting.ts',
|
|
1436
|
+
content: `import { useMemo } from 'react';
|
|
1437
|
+
import { useGetProposals } from '${packageName}/cosmos/gov/v1beta1/query.rpc.react';
|
|
1438
|
+
import { ProposalStatus, proposalStatusToJSON } from '${packageName}/cosmos/gov/v1beta1/gov';
|
|
1439
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1440
|
+
|
|
1441
|
+
export const useVoting = (chainName: string) => {
|
|
1442
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1443
|
+
|
|
1444
|
+
const proposalsQuery = useGetProposals({
|
|
1445
|
+
request: {
|
|
1446
|
+
proposalStatus: proposalStatusToJSON(ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD),
|
|
1447
|
+
voter: '',
|
|
1448
|
+
depositor: '',
|
|
1449
|
+
pagination: {
|
|
1450
|
+
key: new Uint8Array(),
|
|
1451
|
+
offset: 0n,
|
|
1452
|
+
limit: 50n,
|
|
1453
|
+
countTotal: true,
|
|
1454
|
+
reverse: true,
|
|
1455
|
+
},
|
|
1456
|
+
},
|
|
1457
|
+
options: {
|
|
1458
|
+
context: defaultContext,
|
|
1459
|
+
enabled: !!rpcEndpoint,
|
|
1460
|
+
select: ({ proposals }) => proposals,
|
|
1461
|
+
},
|
|
1462
|
+
clientResolver: rpcEndpoint,
|
|
1463
|
+
customizedQueryKey: ['proposals', chainName],
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
const data = useMemo(() => {
|
|
1467
|
+
if (!proposalsQuery.data) return;
|
|
1468
|
+
|
|
1469
|
+
return {
|
|
1470
|
+
proposals: proposalsQuery.data.map((proposal) => ({
|
|
1471
|
+
proposalId: proposal.proposalId.toString(),
|
|
1472
|
+
title: proposal.content?.title || '',
|
|
1473
|
+
description: proposal.content?.description || '',
|
|
1474
|
+
status: proposal.status,
|
|
1475
|
+
submitTime: proposal.submitTime,
|
|
1476
|
+
votingStartTime: proposal.votingStartTime,
|
|
1477
|
+
votingEndTime: proposal.votingEndTime,
|
|
1478
|
+
})),
|
|
1479
|
+
};
|
|
1480
|
+
}, [proposalsQuery.data]);
|
|
1481
|
+
|
|
1482
|
+
return {
|
|
1483
|
+
data,
|
|
1484
|
+
isLoading: proposalsQuery.isLoading,
|
|
1485
|
+
refetch: proposalsQuery.refetch,
|
|
1486
|
+
};
|
|
1487
|
+
};
|
|
1488
|
+
`
|
|
1489
|
+
},
|
|
1490
|
+
{
|
|
1491
|
+
name: 'useVotingData.ts',
|
|
1492
|
+
content: `import { useMemo } from 'react';
|
|
1493
|
+
import { useChain } from '@interchain-kit/react';
|
|
1494
|
+
import {
|
|
1495
|
+
useGetProposals,
|
|
1496
|
+
useGetVote,
|
|
1497
|
+
useGetTallyResult,
|
|
1498
|
+
} from '${packageName}/cosmos/gov/v1beta1/query.rpc.react';
|
|
1499
|
+
import { ProposalStatus, proposalStatusToJSON } from '${packageName}/cosmos/gov/v1beta1/gov';
|
|
1500
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1501
|
+
|
|
1502
|
+
export const useVotingData = (chainName: string) => {
|
|
1503
|
+
const { address } = useChain(chainName);
|
|
1504
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1505
|
+
|
|
1506
|
+
const isEnabled = !!rpcEndpoint;
|
|
1507
|
+
|
|
1508
|
+
const proposalsQuery = useGetProposals({
|
|
1509
|
+
request: {
|
|
1510
|
+
proposalStatus: proposalStatusToJSON(ProposalStatus.PROPOSAL_STATUS_UNSPECIFIED),
|
|
1511
|
+
voter: '',
|
|
1512
|
+
depositor: '',
|
|
1513
|
+
pagination: {
|
|
1514
|
+
key: new Uint8Array(),
|
|
1515
|
+
offset: 0n,
|
|
1516
|
+
limit: 100n,
|
|
1517
|
+
countTotal: true,
|
|
1518
|
+
reverse: true,
|
|
1519
|
+
},
|
|
1520
|
+
},
|
|
1521
|
+
options: {
|
|
1522
|
+
context: defaultContext,
|
|
1523
|
+
enabled: isEnabled,
|
|
1524
|
+
select: ({ proposals }) => proposals,
|
|
1525
|
+
},
|
|
1526
|
+
clientResolver: rpcEndpoint,
|
|
1527
|
+
customizedQueryKey: ['allProposals', chainName],
|
|
1528
|
+
});
|
|
1529
|
+
|
|
1530
|
+
const activeProposals = useMemo(() => {
|
|
1531
|
+
return proposalsQuery.data?.filter(
|
|
1532
|
+
(proposal) => proposal.status === ProposalStatus.PROPOSAL_STATUS_VOTING_PERIOD
|
|
1533
|
+
) || [];
|
|
1534
|
+
}, [proposalsQuery.data]);
|
|
1535
|
+
|
|
1536
|
+
const data = useMemo(() => {
|
|
1537
|
+
if (!proposalsQuery.data) return;
|
|
1538
|
+
|
|
1539
|
+
const categorized = {
|
|
1540
|
+
active: activeProposals,
|
|
1541
|
+
passed: proposalsQuery.data.filter(
|
|
1542
|
+
(p) => p.status === ProposalStatus.PROPOSAL_STATUS_PASSED
|
|
1543
|
+
),
|
|
1544
|
+
rejected: proposalsQuery.data.filter(
|
|
1545
|
+
(p) => p.status === ProposalStatus.PROPOSAL_STATUS_REJECTED
|
|
1546
|
+
),
|
|
1547
|
+
failed: proposalsQuery.data.filter(
|
|
1548
|
+
(p) => p.status === ProposalStatus.PROPOSAL_STATUS_FAILED
|
|
1549
|
+
),
|
|
1550
|
+
};
|
|
1551
|
+
|
|
1552
|
+
return {
|
|
1553
|
+
proposals: proposalsQuery.data,
|
|
1554
|
+
categorized,
|
|
1555
|
+
activeCount: categorized.active.length,
|
|
1556
|
+
};
|
|
1557
|
+
}, [proposalsQuery.data, activeProposals]);
|
|
1558
|
+
|
|
1559
|
+
return {
|
|
1560
|
+
data,
|
|
1561
|
+
isLoading: proposalsQuery.isLoading,
|
|
1562
|
+
refetch: proposalsQuery.refetch,
|
|
1563
|
+
};
|
|
1564
|
+
};
|
|
1565
|
+
`
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
name: 'useContractInfo.ts',
|
|
1569
|
+
content: `import { defaultContext } from '@tanstack/react-query';
|
|
1570
|
+
import { useGetContractInfo } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
|
|
1571
|
+
|
|
1572
|
+
export const useContractInfo = ({
|
|
1573
|
+
contractAddress,
|
|
1574
|
+
enabled = true,
|
|
1575
|
+
}: {
|
|
1576
|
+
contractAddress: string;
|
|
1577
|
+
enabled?: boolean;
|
|
1578
|
+
}) => {
|
|
1579
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1580
|
+
|
|
1581
|
+
return useGetContractInfo({
|
|
1582
|
+
request: {
|
|
1583
|
+
address: contractAddress,
|
|
1584
|
+
},
|
|
1585
|
+
options: {
|
|
1586
|
+
enabled: !!contractAddress && !!rpcEndpoint && enabled,
|
|
1587
|
+
context: defaultContext,
|
|
1588
|
+
},
|
|
1589
|
+
clientResolver: rpcEndpoint,
|
|
1590
|
+
});
|
|
1591
|
+
};
|
|
1592
|
+
`
|
|
1593
|
+
},
|
|
1594
|
+
{
|
|
1595
|
+
name: 'useQueryContract.ts',
|
|
1596
|
+
content: `import { defaultContext } from '@tanstack/react-query';
|
|
1597
|
+
import { useGetSmartContractState } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
|
|
1598
|
+
|
|
1599
|
+
export const useQueryContract = ({
|
|
1600
|
+
contractAddress,
|
|
1601
|
+
queryMsg,
|
|
1602
|
+
enabled = true,
|
|
1603
|
+
}: {
|
|
1604
|
+
contractAddress: string;
|
|
1605
|
+
queryMsg: object;
|
|
1606
|
+
enabled?: boolean;
|
|
1607
|
+
}) => {
|
|
1608
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1609
|
+
|
|
1610
|
+
return useGetSmartContractState({
|
|
1611
|
+
request: {
|
|
1612
|
+
address: contractAddress,
|
|
1613
|
+
queryData: new TextEncoder().encode(JSON.stringify(queryMsg)),
|
|
1614
|
+
},
|
|
1615
|
+
options: {
|
|
1616
|
+
enabled: !!contractAddress && !!queryMsg && !!rpcEndpoint && enabled,
|
|
1617
|
+
context: defaultContext,
|
|
1618
|
+
select: ({ data }) => {
|
|
1619
|
+
if (data) {
|
|
1620
|
+
return JSON.parse(new TextDecoder().decode(data));
|
|
1621
|
+
}
|
|
1622
|
+
return null;
|
|
1623
|
+
},
|
|
1624
|
+
},
|
|
1625
|
+
clientResolver: rpcEndpoint,
|
|
1626
|
+
});
|
|
1627
|
+
};
|
|
1628
|
+
`
|
|
1629
|
+
},
|
|
1630
|
+
{
|
|
1631
|
+
name: 'useCodeDetails.ts',
|
|
1632
|
+
content: `import { defaultContext } from '@tanstack/react-query';
|
|
1633
|
+
import { useGetCode } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
|
|
1634
|
+
|
|
1635
|
+
export const useCodeDetails = ({
|
|
1636
|
+
codeId,
|
|
1637
|
+
enabled = true,
|
|
1638
|
+
}: {
|
|
1639
|
+
codeId: string | number;
|
|
1640
|
+
enabled?: boolean;
|
|
1641
|
+
}) => {
|
|
1642
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1643
|
+
|
|
1644
|
+
return useGetCode({
|
|
1645
|
+
request: {
|
|
1646
|
+
codeId: BigInt(codeId),
|
|
1647
|
+
},
|
|
1648
|
+
options: {
|
|
1649
|
+
enabled: !!codeId && !!rpcEndpoint && enabled,
|
|
1650
|
+
context: defaultContext,
|
|
1651
|
+
},
|
|
1652
|
+
clientResolver: rpcEndpoint,
|
|
1653
|
+
});
|
|
1654
|
+
};
|
|
1655
|
+
`
|
|
1656
|
+
},
|
|
1657
|
+
{
|
|
1658
|
+
name: 'useMyContracts.ts',
|
|
1659
|
+
content: `import { useMemo } from 'react';
|
|
1660
|
+
import { useChain } from '@interchain-kit/react';
|
|
1661
|
+
import { useGetContractsByCreator } from '${packageName}/cosmwasm/wasm/v1/query.rpc.react';
|
|
1662
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1663
|
+
|
|
1664
|
+
export const useMyContracts = (chainName: string) => {
|
|
1665
|
+
const { address } = useChain(chainName);
|
|
1666
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1667
|
+
|
|
1668
|
+
const contractsQuery = useGetContractsByCreator({
|
|
1669
|
+
request: {
|
|
1670
|
+
creatorAddress: address || '',
|
|
1671
|
+
pagination: {
|
|
1672
|
+
key: new Uint8Array(),
|
|
1673
|
+
offset: 0n,
|
|
1674
|
+
limit: 100n,
|
|
1675
|
+
countTotal: true,
|
|
1676
|
+
reverse: false,
|
|
1677
|
+
},
|
|
1678
|
+
},
|
|
1679
|
+
options: {
|
|
1680
|
+
enabled: !!address && !!rpcEndpoint,
|
|
1681
|
+
context: defaultContext,
|
|
1682
|
+
select: ({ contractAddresses }) => contractAddresses,
|
|
1683
|
+
},
|
|
1684
|
+
clientResolver: rpcEndpoint,
|
|
1685
|
+
});
|
|
1686
|
+
|
|
1687
|
+
const data = useMemo(() => {
|
|
1688
|
+
if (!contractsQuery.data) return;
|
|
1689
|
+
|
|
1690
|
+
return {
|
|
1691
|
+
contracts: contractsQuery.data.map((address) => ({
|
|
1692
|
+
address,
|
|
1693
|
+
label: \`Contract \${address.slice(0, 8)}...\`,
|
|
1694
|
+
})),
|
|
1695
|
+
count: contractsQuery.data.length,
|
|
1696
|
+
};
|
|
1697
|
+
}, [contractsQuery.data]);
|
|
1698
|
+
|
|
1699
|
+
return {
|
|
1700
|
+
data,
|
|
1701
|
+
isLoading: contractsQuery.isLoading,
|
|
1702
|
+
refetch: contractsQuery.refetch,
|
|
1703
|
+
};
|
|
1704
|
+
};
|
|
1705
|
+
`
|
|
1706
|
+
},
|
|
1707
|
+
{
|
|
1708
|
+
name: 'useGrants.ts',
|
|
1709
|
+
content: `import { useMemo } from 'react';
|
|
1710
|
+
import { useChain } from '@interchain-kit/react';
|
|
1711
|
+
import { useGetGranterGrants, useGetGranteeGrants } from '${packageName}/cosmos/authz/v1beta1/query.rpc.react';
|
|
1712
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1713
|
+
|
|
1714
|
+
export const useGrants = (chainName: string) => {
|
|
1715
|
+
const { address } = useChain(chainName);
|
|
1716
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1717
|
+
|
|
1718
|
+
const granterQuery = useGetGranterGrants({
|
|
1719
|
+
request: {
|
|
1720
|
+
granter: address || '',
|
|
1721
|
+
pagination: {
|
|
1722
|
+
key: new Uint8Array(),
|
|
1723
|
+
offset: 0n,
|
|
1724
|
+
limit: 100n,
|
|
1725
|
+
countTotal: true,
|
|
1726
|
+
reverse: false,
|
|
1727
|
+
},
|
|
1728
|
+
},
|
|
1729
|
+
options: {
|
|
1730
|
+
enabled: !!address && !!rpcEndpoint,
|
|
1731
|
+
context: defaultContext,
|
|
1732
|
+
select: ({ grants }) => grants,
|
|
1733
|
+
},
|
|
1734
|
+
clientResolver: rpcEndpoint,
|
|
1735
|
+
});
|
|
1736
|
+
|
|
1737
|
+
const granteeQuery = useGetGranteeGrants({
|
|
1738
|
+
request: {
|
|
1739
|
+
grantee: address || '',
|
|
1740
|
+
pagination: {
|
|
1741
|
+
key: new Uint8Array(),
|
|
1742
|
+
offset: 0n,
|
|
1743
|
+
limit: 100n,
|
|
1744
|
+
countTotal: true,
|
|
1745
|
+
reverse: false,
|
|
1746
|
+
},
|
|
1747
|
+
},
|
|
1748
|
+
options: {
|
|
1749
|
+
enabled: !!address && !!rpcEndpoint,
|
|
1750
|
+
context: defaultContext,
|
|
1751
|
+
select: ({ grants }) => grants,
|
|
1752
|
+
},
|
|
1753
|
+
clientResolver: rpcEndpoint,
|
|
1754
|
+
});
|
|
1755
|
+
|
|
1756
|
+
const data = useMemo(() => {
|
|
1757
|
+
return {
|
|
1758
|
+
granterGrants: granterQuery.data || [],
|
|
1759
|
+
granteeGrants: granteeQuery.data || [],
|
|
1760
|
+
};
|
|
1761
|
+
}, [granterQuery.data, granteeQuery.data]);
|
|
1762
|
+
|
|
1763
|
+
const isLoading = granterQuery.isLoading || granteeQuery.isLoading;
|
|
1764
|
+
|
|
1765
|
+
return {
|
|
1766
|
+
data,
|
|
1767
|
+
isLoading,
|
|
1768
|
+
refetch: () => {
|
|
1769
|
+
granterQuery.refetch();
|
|
1770
|
+
granteeQuery.refetch();
|
|
1771
|
+
},
|
|
1772
|
+
};
|
|
1773
|
+
};
|
|
1774
|
+
`
|
|
1775
|
+
},
|
|
1776
|
+
{
|
|
1777
|
+
name: 'useSendData.ts',
|
|
1778
|
+
content: `import { useMemo } from 'react';
|
|
1779
|
+
import { useChain } from '@interchain-kit/react';
|
|
1780
|
+
import { useGetBalance } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
1781
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1782
|
+
import BigNumber from 'bignumber.js';
|
|
1783
|
+
|
|
1784
|
+
export const useSendData = (chainName: string) => {
|
|
1785
|
+
const { address, assetList } = useChain(chainName);
|
|
1786
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1787
|
+
|
|
1788
|
+
const coin = assetList?.assets[0];
|
|
1789
|
+
const denom = coin?.base || 'uatom';
|
|
1790
|
+
const exponent = coin?.denomUnits?.find(unit => unit.denom === coin.display)?.exponent || 6;
|
|
1791
|
+
|
|
1792
|
+
const balanceQuery = useGetBalance({
|
|
1793
|
+
request: {
|
|
1794
|
+
address: address || '',
|
|
1795
|
+
denom,
|
|
1796
|
+
},
|
|
1797
|
+
options: {
|
|
1798
|
+
enabled: !!address && !!rpcEndpoint,
|
|
1799
|
+
context: defaultContext,
|
|
1800
|
+
select: ({ balance }) => {
|
|
1801
|
+
const amount = balance?.amount || '0';
|
|
1802
|
+
const displayAmount = new BigNumber(amount).dividedBy(Math.pow(10, exponent));
|
|
1803
|
+
return {
|
|
1804
|
+
amount,
|
|
1805
|
+
displayAmount: displayAmount.toString(),
|
|
1806
|
+
denom: balance?.denom || denom,
|
|
1807
|
+
};
|
|
1808
|
+
},
|
|
1809
|
+
},
|
|
1810
|
+
clientResolver: rpcEndpoint,
|
|
1811
|
+
});
|
|
1812
|
+
|
|
1813
|
+
const data = useMemo(() => {
|
|
1814
|
+
if (!balanceQuery.data) return;
|
|
1815
|
+
|
|
1816
|
+
return {
|
|
1817
|
+
balance: balanceQuery.data,
|
|
1818
|
+
canSend: new BigNumber(balanceQuery.data.amount).isGreaterThan(0),
|
|
1819
|
+
fee: {
|
|
1820
|
+
amount: '5000',
|
|
1821
|
+
displayAmount: new BigNumber('5000').dividedBy(Math.pow(10, exponent)).toString(),
|
|
1822
|
+
denom,
|
|
1823
|
+
},
|
|
1824
|
+
};
|
|
1825
|
+
}, [balanceQuery.data, denom, exponent]);
|
|
1826
|
+
|
|
1827
|
+
return {
|
|
1828
|
+
data,
|
|
1829
|
+
isLoading: balanceQuery.isLoading,
|
|
1830
|
+
refetch: balanceQuery.refetch,
|
|
1831
|
+
};
|
|
1832
|
+
};
|
|
1833
|
+
`
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
name: 'useTotalAssets.ts',
|
|
1837
|
+
content: `import { useMemo } from 'react';
|
|
1838
|
+
import { useChain } from '@interchain-kit/react';
|
|
1839
|
+
import { useGetAllBalances } from '${packageName}/cosmos/bank/v1beta1/query.rpc.react';
|
|
1840
|
+
import { defaultContext } from '@tanstack/react-query';
|
|
1841
|
+
import BigNumber from 'bignumber.js';
|
|
1842
|
+
|
|
1843
|
+
export const getPagination = (limit: bigint) => ({
|
|
1844
|
+
key: new Uint8Array(),
|
|
1845
|
+
offset: 0n,
|
|
1846
|
+
limit,
|
|
1847
|
+
countTotal: true,
|
|
1848
|
+
reverse: false,
|
|
1849
|
+
});
|
|
1850
|
+
|
|
1851
|
+
export const useTotalAssets = (chainName: string) => {
|
|
1852
|
+
const { address, assetList } = useChain(chainName);
|
|
1853
|
+
const rpcEndpoint = 'https://cosmos-rpc.quickapi.com:443';
|
|
1854
|
+
|
|
1855
|
+
const allBalancesQuery = useGetAllBalances({
|
|
1856
|
+
request: {
|
|
1857
|
+
address: address || '',
|
|
1858
|
+
pagination: getPagination(100n),
|
|
1859
|
+
resolveDenom: false,
|
|
1860
|
+
},
|
|
1861
|
+
options: {
|
|
1862
|
+
enabled: !!address && !!rpcEndpoint,
|
|
1863
|
+
select: ({ balances }) => balances || [],
|
|
1864
|
+
context: defaultContext,
|
|
1865
|
+
},
|
|
1866
|
+
clientResolver: rpcEndpoint,
|
|
1867
|
+
customizedQueryKey: ['totalAssets', address],
|
|
1868
|
+
});
|
|
1869
|
+
|
|
1870
|
+
const data = useMemo(() => {
|
|
1871
|
+
if (!allBalancesQuery.data) return;
|
|
1872
|
+
|
|
1873
|
+
const totalValue = allBalancesQuery.data.reduce((sum, balance) => {
|
|
1874
|
+
return sum.plus(balance.amount);
|
|
1875
|
+
}, new BigNumber(0));
|
|
1876
|
+
|
|
1877
|
+
return {
|
|
1878
|
+
balances: allBalancesQuery.data,
|
|
1879
|
+
totalCount: allBalancesQuery.data.length,
|
|
1880
|
+
totalValue: totalValue.toString(),
|
|
1881
|
+
nonZeroBalances: allBalancesQuery.data.filter(
|
|
1882
|
+
balance => new BigNumber(balance.amount).isGreaterThan(0)
|
|
1883
|
+
),
|
|
1884
|
+
};
|
|
1885
|
+
}, [allBalancesQuery.data]);
|
|
1886
|
+
|
|
1887
|
+
return {
|
|
1888
|
+
data,
|
|
1889
|
+
isLoading: allBalancesQuery.isLoading,
|
|
1890
|
+
refetch: allBalancesQuery.refetch,
|
|
1891
|
+
};
|
|
1892
|
+
};
|
|
1893
|
+
`
|
|
1894
|
+
}
|
|
1895
|
+
];
|
|
1896
|
+
|
|
1897
|
+
// Write all example files
|
|
1898
|
+
exampleFiles.forEach(({ name, content }) => {
|
|
1899
|
+
writeFileSync(join(mcpServerPath, 'src', 'telescope-examples', name), content);
|
|
1900
|
+
});
|
|
1901
|
+
}
|
|
1902
|
+
|