# Telescope 🔭

<p align="center">
  <img width="280" src="https://user-images.githubusercontent.com/545047/175660665-5cbde84b-0928-4e59-ab56-be6adb2f3a7e.png"/>
</p>

<p align="center" width="100%">
  <a href="https://github.com/cosmology-tech/telescope/actions/workflows/run-tests.yaml">
    <img height="20" src="https://github.com/cosmology-tech/telescope/actions/workflows/run-tests.yaml/badge.svg" />
  </a>
   <a href="https://www.npmjs.com/package/@cosmology/telescope"><img height="20" src="https://img.shields.io/npm/dt/@osmonauts/telescope"></a>
   <a href="https://github.com/cosmology-tech/telescope/blob/main/LICENSE-MIT"><img height="20" src="https://img.shields.io/badge/license-MIT-blue.svg"/></a>
   <a href="https://github.com/cosmology-tech/telescope/blob/main/LICENSE-Apache"><img height="20" src="https://img.shields.io/badge/license-Apache-blue.svg"/></a>
   <a href="https://www.npmjs.com/package/@cosmology/telescope"><img height="20" src="https://img.shields.io/github/package-json/v/cosmology-tech/telescope?filename=packages%2Ftelescope%2Fpackage.json"/></a>
</p>

<p align="center">
  <img src="https://user-images.githubusercontent.com/545047/178129981-5a7d18ed-d2b5-4d85-b828-ca084d38501e.png"/>
</p>

A "babel for the Cosmos", Telescope is a TypeScript Transpiler for Cosmos Protobufs. Telescope is used to generate libraries for Cosmos blockchains. Simply point to your protobuffer files and create developer-friendly Typescript libraries for teams to build on your blockchain.

The following blockchain libraries (generated by Telescope) are available via npm

* [osmojs](https://www.npmjs.com/package/osmojs)
* [@dydxprotocol/v4-client-js](https://www.npmjs.com/package/@dydxprotocol/v4-client-js)
* [stargazejs](https://www.npmjs.com/package/stargazejs)
* [juno-network](https://www.npmjs.com/package/juno-network)
* [stridejs](https://www.npmjs.com/package/stridejs)
* [injectivejs](https://www.npmjs.com/package/injectivejs)
* [quicksilverjs](https://www.npmjs.com/package/quicksilverjs)

🎥 [Checkout our video playlist](https://www.youtube.com/watch?v=n82MsLe82mk&list=PL-lMkVv7GZwyQaK6bp6kMdOS5mzosxytC) to learn how to use `telescope`!

## Table of contents

- [Telescope 🔭](#telescope-)
  - [Table of contents](#table-of-contents)
  - [Quickstart](#quickstart)
    - [Generate](#generate)
    - [Add Protobufs](#add-protobufs)
    - [Transpile](#transpile)
    - [Build](#build)
- [Usage](#usage)
  - [Programatic Usage](#programatic-usage)
  - [Options](#options)
    - [Amino Encoding](#amino-encoding)
    - [Prototypes Options](#prototypes-options)
    - [Prototypes Methods](#prototypes-methods)
    - [LCD Client Options](#lcd-client-options)
    - [RPC Client Options](#rpc-client-options)
    - [Stargate Client Options](#stargate-client-options)
    - [State Management](#state-management)
      - [React Query](#react-query)
      - [Mobx](#mobx)
      - [Pinia](#pinia)
    - [Typings and Formating](#typings-and-formating)
    - [Protobuf parser](#protobuf-parser)
    - [Typescript Disabling](#typescript-disabling)
    - [ESLint Disabling](#eslint-disabling)
    - [Bundle](#bundle)
    - [Output](#output)
  - [Types](#types)
    - [Timestamp](#timestamp)
    - [Duration](#duration)
  - [Composing Messages](#composing-messages)
  - [Calculating Fees](#calculating-fees)
  - [Stargate Clients](#stargate-clients)
  - [Creating Signers](#creating-signers)
    - [Amino Signer](#amino-signer)
    - [Proto Signer](#proto-signer)
  - [Broadcasting messages](#broadcasting-messages)
  - [LCD Clients](#lcd-clients)
  - [LCD Clients Classes](#lcd-clients-classes)
  - [RPC Clients](#rpc-clients)
    - [Tendermint Client](#tendermint-client)
    - [gRPC-web Client](#grpc-web-client)
    - [gRPC-gateway Client](#grpc-gateway-client)
  - [RPC Client Classes](#rpc-client-classes)
  - [Instant RPC Methods](#instant-rpc-methods)
  - [Manually registering types](#manually-registering-types)
  - [CosmWasm](#cosmwasm)
  - [Dependencies](#dependencies)
  - [Troubleshooting](#troubleshooting)
    - [Create React App](#create-react-app)
    - [Babel](#babel)
  - [Developing](#developing)
  - [Sponsors](#sponsors)
  - [Related](#related)
  - [Credits](#credits)
  - [Disclaimer](#disclaimer)

## Quickstart

Follow the instructions below to generate a new Typescript package that you can publish to npm.

First, install `telescope`:

```sh
npm install -g @cosmology/telescope
```

### Generate

Use the `generate` command to create a new package.

```sh
telescope generate
cd ./your-new-project
yarn
```

### Add Protobufs

If you have `.proto` files, simply add them to a `./proto` folder.

However, if you want to get started quickly using existing protos from our registry, simply use the `install` command.

```sh
telescope install
```

It's not necessary, but you may also specify specific packages, e.g.

```sh
telescope install @protobufs/osmosis
```

### Transpile

To create the Typescript files, run the `transpile` command.

```sh
telescope transpile
```

You should now see some `.ts` files generated in `./src`. These are the real source files used in your application.

Examples:

```sh
# Telescope takes chain1 folder as input,
# and generate files in 'gen/src' folder.
telescope transpile --protoDirs ../../__fixtures__/chain1 --outPath gen/src
```

```sh
# Telescope takes chain1 folder as input,
# and generate files in 'gen/src' folder using default telescope options.
telescope transpile --protoDirs ../../__fixtures__/chain1 --outPath gen/src --useDefaults
```

```sh
# Telescope takes chain1 folder(from args) and chain2 folder(from config) as input,
# and generate files in 'gen/src'(defined in the config file, will override outPath in args) folder using a config file.
# Note: --config will override --useDefaults.
telescope transpile --protoDirs ../../__fixtures__/chain1 --config .telescope.json
```

```sh
# Telescope takes more than one config. The config afterward will override those in front. In this case values in .telescope-ext.json will override those in .telescope.json.
telescope transpile --config .telescope.json --config .telescope-ext.json
```

```json
//.telescope.json
{
  "protoDirs": [
    "../../fixtures/chain2"
  ],
  "outPath": "gen/src",
  "options": {
    // telescope options
    ...
  }
}
```

### Build

Finally, run `install` and `buidl` to generate the JS and types for publishing your module to npm.

```sh
yarn install
yarn buidl
```

Now you should have code inside of your `./src` folder, ready for publshing via `npm publish`. Or, if you used the defaults, you can start developing and your code can be imported from `./src/codegen`;

# Usage

## Programatic Usage

First add telescope to your `devDependencies`:

```sh
yarn add --dev @cosmology/telescope
```

Install helpers and cosmjs [dependencies listed here](#dependencies)

```js
import { join } from 'path';
import telescope from '@cosmology/telescope';
import { sync as rimraf } from 'rimraf';

const protoDirs = [join(__dirname, '/../proto')];
const outPath = join(__dirname, '../src/codegen');
rimraf(outPath);

telescope({
  protoDirs,
  outPath,

  // all options are totally optional ;)
  options: {
    aminoEncoding: {
        enabled: true
    },
    lcdClients: {
        enabled: false
    },
    rpcClients: {
        enabled: false,
        camelCase: true
    },

    // you can scope options to certain packages:
    packages: {
      nebula: {
        prototypes: {
          typingsFormat: {
            useExact: false
          }
        }
      },
      akash: {
        stargateClients: {
            enabled: true;
            includeCosmosDefaultTypes: false;
        },
        prototypes: {
          typingsFormat: {
              useExact: false
          }
        }
      }
    }
  }
}).then(()=>{
  console.log('✨ all done!');
}).catch(e=>{
  console.error(e);
  process.exit(1);
})
```

## Options

### Amino Encoding

| option                         | description                                                     | defaults   |
| ------------------------------ | --------------------------------------------------------------  | ---------- |
| `aminoEncoding.enabled`        | generate amino types and amino converters                       | `true`     |
| `aminoEncoding.disableMsgTypes`        | disable generating AminoMsg types                | `false`     |
| `aminoEncoding.casingFn`       | set the amino-casing function for a project                     | `snake()`  |
| `aminoEncoding.exceptions`     | set specific aminoType name exceptions                          | see code   |
| `aminoEncoding.typeUrlToAmino` | create functions for aminoType name exceptions                  | `undefined`|
| `aminoEncoding.useLegacyInlineEncoding` | @deprecated. To use legacy inline encoding instead of using v2 recursive encoding                  | `false`|
| `aminoEncoding.useRecursiveV2encoding` | this's been removed. See useLegacyInlineEncoding instead.                  |  |

### Implemented Interface Options

| option                                    | description                                                     | defaults   |
| ----------------------------------------- | --------------------------------------------------------------  | ---------- |
| `interfaces.enabled`                      | enables converters convert between Any type and specific implemented interfaces.                | `true`     |
| `interfaces.useGlobalDecoderRegistry`                      |    enables GlobalDecoderRegistry and related functions. Highly recommended to enable when dealing with fields with 'accepted_interface' option. Please see 'packages/telescope/__tests__/impl-interfaces.test.ts' for usage.             | `false`     |
| `interfaces.useUseInterfacesParams`                 | decides if add `useInterfaces` argument to `decode` and `toAmino` functions.                | `false`     |
| `interfaces.useByDefault`                 | decides if interface decoders are used by default (default for `useInterfaces` argument to `decode` and `toAmino` functions).                | `true`     |
| `interfaces.useByDefaultRpc`                 | decides if interface decoders are used by default by the RPC clients.                | `true`     |
| `interfaces.useUnionTypes`                | Generate Any type as union types(TextProposal \| RegisterIncentiveProposal) instead of intersection types(TextProposal & RegisterIncentiveProposal).                | `false`     |

### Prototypes Options

| option                                    | description                                                     | defaults   |
| ----------------------------------------- | --------------------------------------------------------------  | ---------- |
| `prototypes.enabled`                      | enables the generation of proto encoding methods                | `true`     |
| `prototypes.includePackageVar`            | export a `protoPackage` variable to indicate package name       | `false`    |
| `prototypes.includes.packages`            | include a set of packages when transpilation. (if a package both meet include and exclude, it'll be excluded)                    | `undefined`|
| `prototypes.includes.protos`              | include a set of proto files when transpilation. (if a proto both meet include and exclude, it'll be excluded)                 | `undefined`|
| `prototypes.excluded.packages`            | exclude a set of packages from transpilation                    | `undefined`|
| `prototypes.excluded.protos`              | try to exclude a set of proto files from transpilation. if files inside the list are dependencies to other files, they'll be still transpiled.                 | `undefined`|
| `prototypes.excluded.hardProtos`              | exclude a set of proto files from transpilation. Files in this list will be excluded no mater it's dependency to other files or not.                 | `undefined`|
| `prototypes.fieldDefaultIsOptional`       | boolean value representing default optionality of field         | `false`    |
| `prototypes.useOptionalNullable`          | use `(gogoproto.nullable)` values in determining optionality    | `true`     |
| `prototypes.allowUndefinedTypes`          | boolean value allowing `Type`s to be `undefined`                | `false`    |
| `prototypes.allowEncodeDefaultScalars`          | boolean value allowing encoders encoding default values of scalar types. e.g. empty string, 0 or false                | `false`    |
| `prototypes.optionalQueryParams`          | boolean value setting queryParams to be optional                | `false`    |
| `prototypes.optionalPageRequests`         | boolean value setting `PageRequest` fields to optional          | `false`    |
| `prototypes.addTypeUrlToDecoders`         | add $typeUrl field to generated interfaces          | `true`    |
| `prototypes.addAminoTypeToObjects`         | add aminoType field to generated Decoders          | `false`    |
| `prototypes.addTypeUrlToObjects`         | add typeUrl field to generated Decoders          | `true`    |
| `prototypes.enableRegistryLoader`         |    generate Registry loader to *.registry.ts files       | `true`    |
| `prototypes.enableMessageComposer`         |    generate MessageComposer to *.registry.ts files       | `true`    |

### Prototypes Methods

| option                             | description                                                        | defaults|
| ---------------------------------- | -----------------------------------------------------------------  | ------- |
| `prototypes.methods.encode`        | boolean to enable `encode` method on proto objects                 | `true`  |
| `prototypes.methods.decode`        | boolean to enable `decode` method on proto objects                 | `true`  |
| `prototypes.methods.fromJSON`      | boolean to enable `fromJSON` method on proto objects               | `true`  |
| `prototypes.methods.toJSON`        | boolean to enable `toJSON` method on proto objects                 | `true`  |
| `prototypes.methods.fromPartial`   | boolean to enable `fromPartial` method on proto objects            | `true`  |
| `prototypes.methods.fromSDK`       | boolean to enable `fromSDK` method on proto objects                | `false` |
| `prototypes.methods.toSDK`         | boolean to enable `toSDK` method on proto objects                  | `false` |

### LCD Client Options

| option                         | description                                                     | defaults   |
| ------------------------------ | --------------------------------------------------------------  | ---------- |
| `lcdClients.enabled`           | generate LCD clients that can query proto `Query` messages      | `true`     |
| `lcdClients.bundle`            | will generate factory bundle aggregate of all LCD Clients       | `true`     |
| `lcdClients.scoped`            | will generate factory of scoped LCD Clients                     | `undefined`|
| `lcdClients.scopedIsExclusive` | will allow both scoped bundles and all RPC Clients              | `true`     |

See [LCD Clients](#lcd-clients) for more info.

### RPC Client Options

| option                         | description                                                             | defaults                      |
| ------------------------------ | ----------------------------------------------------------------------  | ----------------------------- |
| `rpcClients.type`              | will generate this type of RPC client (`tendermint`, `gRPC-web`, `gRPC`)| `tendermint`                  |
| `rpcClients.enabled`           | generate RPC clients that can interact with proto messages              | `true`                        |
| `rpcClients.bundle`            | will generate factory bundle aggregate of all RPC Clients               | `true`                        |
| `rpcClients.camelCase`         | use camel-case for RPC methods when generating RPC clients              | `true`                        |
| `rpcClients.scoped`            | will generate factory of scoped RPC Clients                             | `undefined`                   |
| `rpcClients.scopedIsExclusive` | will allow both scoped bundles and all RPC Clients                      | `true`                        |
| `rpcClients.enabledServices`   | which services to enable                                                | [`Msg`,`Query`,`Service`]     |
| `rpcClients.instantOps` |        will generate instant rpc operations in the file `service-ops.ts` under root folder, which contains customized classes having selected rpc methods    | `undefined`                        |
| `rpcClients.serviceImplement` |     assign implement type of rpc methods, `Query` or `Tx`, by setting patterns under service types.       | `undefined`                        |

See [RPC Clients](#rpc-clients) for more info.

### Stargate Client Options

| option                                       | description                                                     | defaults |
| -------------------------------------------- | --------------------------------------------------------------  | ---------|
| `stargateClients.includeCosmosDefaultTypes`  | if true, will include the cosmjs defaults with stargate clients | `true` (except cosmos package) |
| `stargateClients.addGetTxRpc`  | if true, will add getSigningTxRpc to clients in namespaces | false |

### State Management

#### React Query

| option                           | description                                                             | defaults |
| -------------------------------- | ----------------------------------------------------------------------  | ---------|
| `reactQuery.enabled`             | if true, will create react hooks that use `@tanstack/react-query` hooks | `false`  |
| `reactQuery.needExtraQueryKey`       | if true, users can input extra react query key to some customized hooks. e.g.['rpcEndpoint', 'yourExtraKey'] | `false`  |
| `reactQuery.include.protos`      | if set, will create the hooks on matched proto filenames or patterns using minimatch           | `[]`     |
| `reactQuery.include.packages`    | if set, will create the hooks on matched packages files using minimatch           | `[]`     |
| `reactQuery.include.patterns`    | if set, will create the hooks on matched patterns of files using minimatch(deprecated in favor of packages and protos have been supported minimatch)           | `[]`     |
| `reactQuery.instantExport.include.patterns`    | if set, will expose instant hooks on matched patterns of packages + method(e.g. cosmos.bank.v1beta1.useBalance) using minimatch. If there're duplicated method names in multiple packages without setting `reactQuery.instantExport.nameMapping`, one duplicated name will created like: useCosmosBankV1beta1Balance           | `[]`     |
| `reactQuery.instantExport.nameMapping`    |   map an alias to a package + method in case of better naming of duplicated method names. (e.g. useBankBalance: cosmos.bank.v1beta1.useBalance) Customized hook name is set in front of pkg+method, by doing this we can prevent duplicate alias.        | `{}`     |

#### Mobx

| option                           | description                                                             | defaults |
| -------------------------------- | ----------------------------------------------------------------------  | ---------|
| `mobx.enabled`                   | if true, will create mobx stores that use `mobx`                        | `false`  |
| `mobx.include.protos`                            | if set, will create the mobx stores on matched proto filenames or patterns using minimatch           | `[]`     |
| `mobx.include.packages`                            | if set, will create the mobx stores on matched packages files using minimatch           | `[]`     |
| `mobx.include.patterns`                            | if set, will create the mobx stores on matched patterns of proto files using minimatch(deprecated in favor of packages and protos have been supported minimatch)           | `[]`     |

#### Pinia

| option                           | description                                                             | defaults |
| -------------------------------- | ----------------------------------------------------------------------  | ---------|
| `pinia.enabled`                  | if true, will create pinia stores that use `pinia`                      | `false`  |
| `mobx.include.protos`            | if set, will create the pinia stores on matched proto filenames or patterns using minimatch           | `[]`     |
| `mobx.include.packages`          | if set, will create the pinia stores on matched packages files using minimatch           | `[]`     |
| `mobx.include.patterns`          | if set, will create the pinia stores on matched patterns of proto files using minimatch(deprecated in favor of packages and protos have been supported minimatch)           | `[]`     |

### Typings and Formating

| option                                    | description                                                     | defaults  |
| ----------------------------------------- | --------------------------------------------------------------  | --------- |
| `prototypes.typingsFormat.customTypes.useCosmosSDKDec` | enable handling "prototypes.typingsFormat.customTypes.useCosmosSDKDec" proto custom type. Used to show decimal fields with the custom type correctly. Highly recommend set to true.    | `true`    |
| `prototypes.typingsFormat.num64` | 'long' or 'bigint', the way of generating int64 proto types, set to 'bigint' to enable using more stable built-in type   | `bigint`    |
| `prototypes.typingsFormat.useTelescopeGeneratedType` |  Discard GeneratedType from cosmjs, use TelescopeGeneratedType instead inside *.registry.ts files  | `false`    |
| `prototypes.typingsFormat.useDeepPartial` | defaults to true, but if disabled uses the `Partial` TS type    | `false`    |
| `prototypes.typingsFormat.useExact`       | defaults to false, but if enabled uses the `Exact` TS type      | `false`   |
| `prototypes.typingsFormat.timestamp`      | use either `date` or `timestamp` for `Timestamp` proto type     | "date"    |
| `prototypes.typingsFormat.duration`       | use either `duration` or `string` for `Duration` proto type     | "duration"|
| `prototypes.typingsFormat.setDefaultEnumToUnrecognized`       |  false: enum empty value would be 0, true: -1(value for enum unrecognized)    |true|
| `prototypes.typingsFormat.setDefaultCustomTypesToUndefined`       |  true: Timestamp,Duration,Any,Coin empty value would be undefined., false: using fromPartial to get an empty obj    |false|

### Protobuf parser

| option                                    | description                                                     | defaults  |
| ----------------------------------------- | --------------------------------------------------------------  | --------- |
| `prototypes.parser.keepCase`              | passes `keepCase` to protobuf `parse()` to keep original casing | `true`   |
| `prototypes.parser.alternateCommentMode`  | passes `alternateCommentMode` to protobuf `parse()` method      | `true`    |
| `prototypes.parser.preferTrailingComment` | passes `preferTrailingComment` to protobuf `parse()` method     | `false`   |

### Typescript Disabling

| option                                       | description                                                     | defaults |
| -------------------------------------------- | --------------------------------------------------------------  | ---------|
| `tsDisable.disableAll`                       | if true, will include `//@ts-nocheck` on every output file      | `false`  |
| `tsDisable.patterns`                         | if set, will include `//@ts-nocheck` on matched patterns        | `[]`     |
| `tsDisable.files`                            | if set, will include `//@ts-nocheck` on matched files           | `[]`     |

### ESLint Disabling

| option                                       | description                                                       | defaults |
| -------------------------------------------- | ----------------------------------------------------------------  | ---------|
| `eslintDisable.disableAll`                   | if true, will include `/* eslint-disable */` on every output file | `false`  |
| `eslintDisable.patterns`                     | if set, will include `/* eslint-disable */` on matched patterns   | `[]`     |
| `eslintDisable.files`                        | if set, will include `/* eslint-disable */` on matched files      | `[]`     |

### Bundle

| option                         | description                                                     | defaults   |
| ------------------------------ | --------------------------------------------------------------  | ---------- |
| `bundle.enabled`               | bundle all files into a scoped index file                       | `true`     |

### Output

| option                         | description                                                        | defaults   |
| ------------------------------ | -----------------------------------------------------------------  | ---------- |
| `env`          | 'default' or 'v-next', set to 'v-next' to enable yet to release features                                             | `default`     |
| `removeUnusedImports`          | removes unused imports                                             | `true`     |
| `classesUseArrowFunctions`     | classes use arrow functions instead of `bind()`ing in constructors | `false`    |
| `includeExternalHelpers`       | exports a few helpers functions in `extern.ts`                     | `false`    |

## Types

### Timestamp

The representation of `google.protobuf.Timestamp` is configurable by the `prototypes.typingsFormat.timestamp` option.

| Protobuf type    | Default/`date='date'` | `date='timestamp'`                      |
| --------------------------- | ---------------------- | ----------------------------------|
| `google.protobuf.Timestamp` | `Date`                 | `{ seconds: Long, nanos: number }`|

TODO

* [ ] add `date='string'` option

### Duration

The representation of `google.protobuf.Duration` is configurable by the `prototypes.typingsFormat.duration` option.

| Protobuf type    | Default/`duration='duration'` | `duration='string'`                      |  |
| --------------------------- | ---------------------- | ------------------------------------ | ---------------- |
| `google.protobuf.Duration` | `{ seconds: Long, nanos: number }`                 | `string` |  |

## Composing Messages

This example shows messages from the `osmojs`, which was built with Telescope.

Import the `osmosis` object from `osmojs`. In this case, we're show the messages available from the `osmosis.gamm.v1beta1` module:

```js
import { osmosis } from 'osmojs';

const {
    joinPool,
    exitPool,
    exitSwapExternAmountOut,
    exitSwapShareAmountIn,
    joinSwapExternAmountIn,
    joinSwapShareAmountOut,
    swapExactAmountIn,
    swapExactAmountOut
} = osmosis.gamm.v1beta1.MessageComposer.withTypeUrl;
```

Now you can construct messages. If you use vscode or another typescript-enabled IDE, you should also be able to use `ctrl+space` to see auto-completion of the fields required for the message.

```js
import { coin } from '@cosmjs/amino';

const msg = swapExactAmountIn({
  sender,
  routes,
  tokenIn: coin(amount, denom),
  tokenOutMinAmount
});
```

## Calculating Fees

Make sure to create a `fee` object in addition to your message.

```js
import { coins } from '@cosmjs/amino';

const fee = {
    amount: coins(0, 'uosmo'),
    gas: '250000'
}
```

if you are broadcasting multiple messages in a batch, you should `simulate` your tx and estimate the fee

```js
import { Dec, IntPretty } from '@keplr-wallet/unit';

const gasEstimated = await stargateClient.simulate(address, msgs, memo);
const fee = {
  amount: coins(0, 'uosmo'),
  gas: new IntPretty(new Dec(gasEstimated).mul(new Dec(1.3)))
    .maxDecimals(0)
    .locale(false)
    .toString()
};
```

## Stargate Clients

Every module gets their own signing client. This example demonstrates for the `osmosis` module.

Use `getSigningOsmosisClient` to get your `SigningStargateClient`, with the Osmosis proto/amino messages full-loaded. No need to manually add amino types, just require and initialize the client:

```js
import { getSigningOsmosisClient } from 'osmojs';

const client = await getSigningOsmosisClient({
  rpcEndpoint,
  signer // OfflineSigner
});
```

## Creating Signers

To broadcast messages, you'll want to use either [keplr](https://docs.keplr.app/api/cosmjs.html) or an `OfflineSigner` from `cosmjs` using mnemonics.

### Amino Signer

Likely you'll want to use the Amino, so unless you need proto, you should use this one:

```js
import { getOfflineSigner as getOfflineSignerAmino } from 'cosmjs-utils';
```

### Proto Signer

```js
import { getOfflineSigner as getOfflineSignerProto } from 'cosmjs-utils';
```

WARNING: NOT RECOMMENDED TO USE PLAIN-TEXT MNEMONICS. Please take care of your security and use best practices such as AES encryption and/or methods from 12factor applications.

```js
import { chains } from 'chain-registry';

const mnemonic =
  'unfold client turtle either pilot stock floor glow toward bullet car science';
  const chain = chains.find(({ chain_name }) => chain_name === 'osmosis');
  const signer = await getOfflineSigner({
    mnemonic,
    chain
  });
```

## Broadcasting messages

Now that you have your `client`, you can broadcast messages:

```js
import { signAndBroadcast } from '@osmosnauts/helpers';

const res = await signAndBroadcast({
  client, // SigningStargateClient
  chainId: 'osmosis-1', // use 'osmo-test-4' for testnet
  address,
  msgs: [msg],
  fee,
  memo: ''
});
```

## LCD Clients

For querying data via REST endpoints, you can use LCD Clients. For a better developer experience, you can generate a factory of scoped bundles of all LCD Clients with the `lcdClients` option.

```ts
const options: TelescopeOptions = {
    lcdClients: {
        enabled: true;
    }
};
```

If you use the `lcdClients.scoped` array, you can scope to only the modules of your interest.

```ts
const options: TelescopeOptions = {
  lcdClients: {
    enabled: true,
    scoped: [
      {
        dir: 'osmosis',
        filename: 'custom-lcd-client.ts',
        packages: [
          'cosmos.bank.v1beta1',
          'cosmos.gov.v1beta1',
          'osmosis.gamm.v1beta1'
        ],
        addToBundle: true,
        methodName: 'createCustomLCDClient'
      },
      {
        dir: 'evmos',
        filename: 'custom-lcd-client.ts',
        packages: [
          'cosmos.bank.v1beta1',
          'cosmos.gov.v1beta1',
          'evmos.erc20.v1'
        ],
        addToBundle: true,
        methodName: 'createEvmosLCDClient'
      }
    ]
  }
};
```

This will generate a nice helper in the `ClientFactory`, which you can then use to query multiple modules from a single object:

```js
import { osmosis } from './codegen';

const main = async () => {
   const client = await osmosis.ClientFactory.createLCDClient({ restEndpoint: REST_ENDPOINT });

   // now you can query the modules
   const pool = await client.osmosis.gamm.v1beta1.pool({ poolId: "1" });
   const balance = await client.cosmos.bank.v1beta1.allBalances({ address: 'osmo1addresshere' });
};
```

## LCD Clients Classes

If you want to instantiate a single client, for any module that has a `Query` type, there will be a `LCDQueryClient` object:

```js
import { osmosis } from "osmojs";

export const main = async () => {
    const requestClient = new LCDClient({ restEndpoint: REST_ENDPOINT });
    const client = new osmosis.gamm.v1beta1.LCDQueryClient({ requestClient });
    const pools = await client.pools();
    console.log(pools);
};

main().then(() => {
    console.log('all done')
})
```

## RPC Clients

### Tendermint Client

For querying data via RPC endpoints, you can use RPC Clients. For a better developer experience, you can generate a factory of scoped bundles of all RPC Clients with the `rpcClients` option.

```ts
const options: TelescopeOptions = {
  rpcClients: {
    type: 'tendermint',
    enabled: true,
    camelCase: true
  }
};
```

If you use the `rpcClients.scoped` array, you can scope to only the modules of your interest. `gRPC-web` and `gRPC-gateway` work the same way with this option.

```ts
const options: TelescopeOptions = {
  rpcClients: {
    enabled: true,
    camelCase: true,
    scoped: [
      {
        dir: 'osmosis',
        filename: 'osmosis-rpc-client.ts',
        packages: [
          'cosmos.bank.v1beta1',
          'cosmos.gov.v1beta1',
          'osmosis.gamm.v1beta1'
        ],
        addToBundle: true,
        methodNameQuery: 'createRPCQueryClient',
        methodNameTx: 'createRPCTxClient'
      }
    ]
  }
};
```

This will generate helpers `createRPCQueryClient` and `createRPCTxClient` in the `ClientFactory`, which you can then use to query multiple modules from a single object:

```js
import { osmosis } from './codegen';

const main = async () => {
  const client = await osmosis.ClientFactory.createRPCQueryClient({ rpcEndpoint });

  // now you can query the modules
  const pool = await client.osmosis.gamm.v1beta1.pool({ poolId: "1" });
  const balance = await client.cosmos.bank.v1beta1.allBalances({ address: 'osmo1addresshere' });
};
```

### gRPC-web Client

For querying data via gRPC-web endpoints, you can use gRPC-web Clients. For a better developer experience, you can generate a factory of scoped bundles of all gRPC-web Clients with the `rpcClients` option.

```ts
const options: TelescopeOptions = {
  rpcClients: {
    type: 'grpc-web',
    enabled: true,
    camelCase: true
  }
};
```

This will generate helpers `createGrpcWebClient` and `createGrpcMsgClient` in the `ClientFactory`, which you can then use to query multiple modules from a single object, if you need an example with scaffold and broadcast msg you can refer to the example below in `grpc-gateway`:

```js
import { osmosis } from './codegen';

const main = async () => {
  const client = await osmosis.ClientFactory.createGrpcWebClient({ endpoint });

  // now you can query the modules
  const pool = await client.osmosis.gamm.v1beta1.pool({ poolId: "1" });
  const balance = await client.cosmos.bank.v1beta1.allBalances({ address: 'osmo1addresshere' });
};
```

### gRPC-gateway Client

For querying data via gRPC-web endpoints, you can use gRPC-web Clients. For a better developer experience, you can generate a factory of scoped bundles of all gRPC-web Clients with the `rpcClients` option.

```ts
const options: TelescopeOptions = {
  rpcClients: {
    type: 'grpc-gateway',
    enabled: true,
    camelCase: true
  }
};
```

This will generate helpers `createGrpcGateWayClient` in the `ClientFactory`, which you can then use to query multiple modules from a single object:

```js
import { osmosis } from './codegen';

const main = async () => {
  // endpoint here is lcd endpoint
  const client = await osmosis.ClientFactory.createGrpcGateWayClient({ endpoint });

  // now you can query the modules
  const pool = await client.osmosis.gamm.v1beta1.pool({ poolId: "1" });
  const balance = await client.cosmos.bank.v1beta1.allBalances({ address: 'osmo1addresshere' });
};
```

Below will be an example of scaffold a `grant` Proto Msg for grpc-web and grpc-gateway and then broadcast it.

```js
  const { grant } = cosmos.authz.v1beta1.MessageComposer.withTypeUrl;
  const msg = grant({
      granter: 'granter_address',
      grantee: 'grantee_address',
      grant: {
        authorization: StakeAuthorization.toProtoMsg({
          maxTokens: {
                  denom: 'uosmo',
                  amount: '100000000'
                },
                authorizationType: AuthorizationType.AUTHORIZATION_TYPE_DELEGATE
              }),
            expiration: new Date(Date.now() + 60 * 60 * 24 * 7)
  }})

    const signed_tx = await signClient.sign('granter_address', [msg], fee, 'telescope: grant', signerData);
    const txRawBytes = Uint8Array.from(TxRaw.encode(signed_tx).finish());

    const res = await client.cosmos.tx.v1beta1.broadcastTx(
      {
        txBytes: txRawBytes,
        mode: BroadcastMode.BROADCAST_MODE_BLOCK
      }
    )

    console.log(res);

```

## RPC Client Classes

If you want to instantiate a single client, you can generate RPC classes with the `rpcClients` option;

For any module that has a `Msg`, `Query` or `Service` type, a

```js
import { osmosis, cosmos } from 'osmojs';

const MsgClient = osmosis.gamm.v1beta1.MsgClientImpl;
const QueryClient = osmosis.gamm.v1beta1.QueryClientImpl;
const ServiceClient = cosmos.base.tendermint.v1beta1.ServiceClientImpl;
```

Here is an example of making a query if you want to use the RPC client classes manually:

```js
import { osmosis } from "osmojs";
import { createProtobufRpcClient, QueryClient } from "@cosmjs/stargate";
import { Tendermint34Client } from "@cosmjs/tendermint-rpc";

export const main = async () => {
    const tmClient = await Tendermint34Client.connect(RPC_ENDPOINT);
    const QueryClientImpl = osmosis.gamm.v1beta1.QueryClientImpl;
    const client = new QueryClient(tmClient);
    const rpc = createProtobufRpcClient(client);
    const queryService = new QueryClientImpl(rpc);
    const pools = await queryService.pools({})
    console.log(pools);
};

main().then(() => {
    console.log('all done')
})
```

## Instant RPC Methods

Using instantOps option to expose instant RPC methods.

For example, for this config:
```json
    instantOps: [
      {
        className: "OsmosisClaim",
        include: {
          patterns: ["osmosis.**.*claim*"],
        },
      },
      {
        className: "CosmosAuthAccount",
        include: {
          patterns: [
            "cosmos.auth.**.*account*",
            "cosmos.auth.**.*Account*",
            "cosmos.gov.v1beta1.**",
          ],
        },
        nameMapping: {
          // name mapping rule for both Msg and Query methods.
          // moduleAccounts will be renamed to authModuleAccounts in generated class.
          All: {
            authModuleAccounts: "cosmos.auth.v1beta1.moduleAccounts",
          },
          // name mapping rule for Msg methods.
          Msg: {
            // deposit method under Msg will be renamed to txDeposit in generated class. While deposit method under Query will remain the same.
            txDeposit: "cosmos.gov.v1beta1.deposit",
            // Same for vote method.
            txVote: "cosmos.gov.v1beta1.vote",
          },
        },
      },
    ],
```

There'll be an extra file generated in the root folder called service-ops.ts:
```js
export interface OsmosisClaim extends _OsmosisClaimV1beta1Queryrpc.OsmosisClaim {}
export class OsmosisClaim {
  rpc: TxRpc;
  init(rpc: TxRpc) {
    this.rpc = rpc;
    this.claimRecord = _OsmosisClaimV1beta1Queryrpc.createClientImpl(rpc).claimRecord;
    this.claimableForAction = _OsmosisClaimV1beta1Queryrpc.createClientImpl(rpc).claimableForAction;
  }
}
export interface CosmosAuthAccount extends _CosmosAuthV1beta1Queryrpc.CosmosAuthAccount, _CosmosGovV1beta1Queryrpc.CosmosAuthAccount, _CosmosGovV1beta1Txrpc.CosmosAuthAccount {}
export class CosmosAuthAccount {
  rpc: TxRpc;
  init(rpc: TxRpc) {
    this.rpc = rpc;
    this.accounts = _CosmosAuthV1beta1Queryrpc.createClientImpl(rpc).accounts;
    this.account = _CosmosAuthV1beta1Queryrpc.createClientImpl(rpc).account;

    // moduleAccounts has been renamed to authModuleAccounts as the nameMapping in settings.
    this.authModuleAccounts = _CosmosAuthV1beta1Queryrpc.createClientImpl(rpc).moduleAccounts;

    this.proposal = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).proposal;
    this.proposals = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).proposals;

    // vote under Query remains the same.
    this.vote = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).vote;

    this.votes = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).votes;
    this.params = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).params;

    // deposit under Query remains the same.
    this.deposit = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).deposit;

    this.deposits = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).deposits;
    this.tallyResult = _CosmosGovV1beta1Queryrpc.createClientImpl(rpc).tallyResult;
    this.submitProposal = _CosmosGovV1beta1Txrpc.createClientImpl(rpc).submitProposal;

    //same as txDeposite for vote here.
    this.txVote = _CosmosGovV1beta1Txrpc.createClientImpl(rpc).vote;

    this.voteWeighted = _CosmosGovV1beta1Txrpc.createClientImpl(rpc).voteWeighted;

    // deposit method under Msg will be renamed to txDeposit in generated class. While deposit method under Query will remain the same.
    this.txDeposit = _CosmosGovV1beta1Txrpc.createClientImpl(rpc).deposit;
  }
}
```

## Manually registering types

This example is with `osmosis` module in `osmojs`, but it is the same pattern for any module.

NOTE: this is using `@cosmjs/stargate@0.28.4`

```js
import {
    AminoTypes,
    SigningStargateClient
} from '@cosmjs/stargate';
import { Registry } from '@cosmjs/proto-signing';
import { defaultRegistryTypes } from '@cosmjs/stargate';
import { OfflineSigner } from '@cosmjs/proto-signing'
import { osmosis } from 'osmojs';

export const getCustomSigningClient = async ({ rpcEndpoint, signer }: { rpcEndpoint: string, signer: OfflineSigner }) => {
  // registry
  const registry = new Registry(defaultRegistryTypes);

  // aminotypes
  const aminoTypes = new AminoTypes({
    ...osmosis.gamm.v1beta1.AminoConverter,
    ...osmosis.lockup.AminoConverter,
    ...osmosis.superfluid.AminoConverter
  });

  // load the
  osmosis.gamm.v1beta1.load(registry);
  osmosis.lockup.load(registry);
  osmosis.superfluid.load(registry);

  const client = await SigningStargateClient.connectWithSigner(
    rpcEndpoint,
    signer,
    { registry, aminoTypes }
  );

  return client;
};
```

## CosmWasm

Generate TypeScript SDKs for your CosmWasm smart contracts by using the `cosmwasm` option on `TelescopeOptions`. The `cosmwasm` option is actually a direct reference to the `TSBuilderInput` object, for the most up-to-date documentation, visit [@cosmwasm/ts-codegen](https://github.com/CosmWasm/ts-codegen).

```ts
import { TSBuilderInput } from '@cosmwasm/ts-codegen';
const options: TelescopeOptions = {
  cosmwasm: {
    contracts: [
      {
        name: 'SG721',
        dir: './path/to/sg721/schema'
      },
      {
        name: 'Minter',
        dir: './path/to/Minter/schema'
      }
    ],
    outPath: './path/to/code/src/'
  }
};
```

## Dependencies

If you don't use the boilerplate, you will need to manually install

* `@cosmjs/amino`
* `@cosmjs/proto-signing`
* `@cosmjs/stargate`
* `@cosmjs/tendermint-rpc`

```sh
yarn add @cosmjs/amino @cosmjs/proto-signing @cosmjs/stargate @cosmjs/tendermint-rpc
```

If you use the LCD Client generation, you'll need to add

* `@cosmology/lcd`

```sh
yarn add @cosmology/lcd
```

## Troubleshooting

### Create React App

CRA requires that you update Webpack configurations:

<https://github.com/cosmos/cosmjs/blob/656e02374898afe755e980e93390591b4b65fd86/README.md#webpack-configs>

Here is an example of a `config-overrides.js`:

<https://github.com/pyramation/osmosis-ui/blob/main/config-overrides.js>

### Babel

This should not be an issue, but if you experience problems with syntax or are not using `preset-env`, you may need these babel plugins:

* [babel-plugin-proposal-numeric-separator](https://babeljs.io/docs/en/babel-plugin-proposal-numeric-separator)
* [babel-plugin-proposal-optional-chaining](https://babeljs.io/docs/en/babel-plugin-proposal-optional-chaining)
* [babel-plugin-proposal-nullish-coalescing-operator](https://babeljs.io/docs/en/babel-plugin-proposal-nullish-coalescing-operator)

## Developing

See our [documentation](https://github.com/cosmology-tech/telescope/blob/main/docs/README.md) for how to contribute and develop Telescope.

## Sponsors

Kudos to our sponsors:

* [Osmosis](https://osmosis.zone) funded the creation of Telescope.

## Related

Checkout these related projects:

* [@cosmology/telescope](https://github.com/cosmology-tech/telescope) Your Frontend Companion for Building with TypeScript with Cosmos SDK Modules.
* [@cosmwasm/ts-codegen](https://github.com/CosmWasm/ts-codegen) Convert your CosmWasm smart contracts into dev-friendly TypeScript classes.
* [chain-registry](https://github.com/cosmology-tech/chain-registry) Everything from token symbols, logos, and IBC denominations for all assets you want to support in your application.
* [cosmos-kit](https://github.com/cosmology-tech/cosmos-kit) Experience the convenience of connecting with a variety of web3 wallets through a single, streamlined interface.
* [create-cosmos-app](https://github.com/cosmology-tech/create-cosmos-app) Set up a modern Cosmos app by running one command.
* [interchain-ui](https://github.com/cosmology-tech/interchain-ui) The Interchain Design System, empowering developers with a flexible, easy-to-use UI kit.
* [starship](https://github.com/cosmology-tech/starship) Unified Testing and Development for the Interchain.

## Credits

🛠 Built by Cosmology — if you like our tools, please consider delegating to [our validator ⚛️](https://cosmology.zone/validator)

Thanks to these engineers, teams and projects for inspiring Telescope:

* [@webmaster128](https://github.com/webmaster128)
* [@assafmo](https://github.com/assafmo)
* [osmosis-frontend](https://github.com/osmosis-labs/osmosis-frontend)
* [cosmjs](https://github.com/cosmos/cosmjs)
* [ts-proto](https://github.com/stephenh/ts-proto)
* [keplr-wallet](https://github.com/chainapsis/keplr-wallet)

## Disclaimer

AS DESCRIBED IN THE TELESCOPE LICENSES, THE SOFTWARE IS PROVIDED “AS IS”, AT YOUR OWN RISK, AND WITHOUT WARRANTIES OF ANY KIND.

No developer or entity involved in creating Telescope will be liable for any claims or damages whatsoever associated with your use, inability to use, or your interaction with other users of the Telescope code or Telescope CLI, including any direct, indirect, incidental, special, exemplary, punitive or consequential damages, or loss of profits, cryptocurrencies, tokens, or anything else of value.

