Skip to content

Update/interchainjs migration #175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,44 @@ Typescript types and interfaces are generated in separate files so they can be i
| `types.aliasExecuteMsg` | generate a type alias based on the contract name |
| `types.aliasEntryPoints` | generate type aliases for the entry points based on the contract name |

### BaseClient
The `baseClient.ts` will be generated as dependency for most files. It includes the base client for interchainjs.

#### Gas Configuration

The generated client provides flexible gas fee configuration options to handle different blockchain networks and fee settings.

##### Default Gas Settings

By default, the client uses a gas limit of `200000` for all transactions. You can customize this behavior through the `setDefaultGasAmount`.

##### ChainConfig Options

The `ChainConfig` interface supports two approaches for gas configuration:

1. Chain Registry Integration (Recommended)

When you provide chain information, the client automatically fetches gas prices from the chain registry:

```typescript
import { useChain } from '@interchain-kit/react';

const { chain } = useChain('osmosistestnet');
const chainConfig: ChainConfig = { chain: chain };
```

2. Manual Gas Price Configuration
You can explicitly set gas prices for more control:

```typescript
const chainConfig: ChainConfig = {
gasPrice: {
denom: 'uosmo',
amount: '0.025'
}
};
```

### Client

The `client` plugin will generate TS client classes for your contracts. This option generates a `QueryClient` for queries as well as a `Client` for queries and mutations.
Expand Down Expand Up @@ -173,7 +211,7 @@ Generate [recoil](https://recoiljs.org/) bindings for your contracts with the `r

### Message Composer

Generate pure message objects with the proper `utf8` encoding and `typeUrl` configured that you can broadcast yourself via `cosmjs` with the `message-composer` command.
Generate pure message objects with the proper `utf8` encoding and `typeUrl` configured that you can broadcast yourself via `interchainjs` with the `message-composer` command.

[see example output code](https://github.com/hyperweb-io/ts-codegen/blob/main/__output__/sg721/Sg721.message-composer.ts)

Expand Down
36 changes: 18 additions & 18 deletions __fixtures__/issues/98/out/98.client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/

import { CosmWasmClient, SigningCosmWasmClient, ExecuteResult } from "@cosmjs/cosmwasm-stargate";
import { StdFee } from "@cosmjs/amino";
import { ICosmWasmClient, ISigningCosmWasmClient } from "./baseClient";
import { DeliverTxResponse, StdFee } from "@interchainjs/types";
import { Uint128, InstantiateMsg, Coin, ExecuteMsg, InstallableExecMsg, Binary, ExecMsg, QueryMsg, InstallableQueryMsg, QueryMsg1, ConfigResponse, NullablePlugin, CanonicalAddr, Plugin, PluginsResponse } from "./98.types";
export interface 98ReadOnlyInterface {
contractAddress: string;
Expand All @@ -24,9 +24,9 @@ export interface 98ReadOnlyInterface {
}) => Promise<NullablePlugin>;
}
export class 98QueryClient implements 98ReadOnlyInterface {
client: CosmWasmClient;
client: ICosmWasmClient;
contractAddress: string;
constructor(client: CosmWasmClient, contractAddress: string) {
constructor(client: ICosmWasmClient, contractAddress: string) {
this.client = client;
this.contractAddress = contractAddress;
this.getConfig = this.getConfig.bind(this);
Expand Down Expand Up @@ -73,7 +73,7 @@ export interface 98Interface extends 98ReadOnlyInterface {
}: {
id: number;
instantiateMsg: Binary;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<ExecuteResult>;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<DeliverTxResponse>;
registerPlugin: ({
checksum,
codeId,
Expand All @@ -88,12 +88,12 @@ export interface 98Interface extends 98ReadOnlyInterface {
ipfsHash: string;
name: string;
version: string;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<ExecuteResult>;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<DeliverTxResponse>;
unregisterPlugin: ({
id
}: {
id: number;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<ExecuteResult>;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<DeliverTxResponse>;
updatePlugin: ({
checksum,
codeId,
Expand All @@ -110,23 +110,23 @@ export interface 98Interface extends 98ReadOnlyInterface {
ipfsHash?: string;
name?: string;
version?: string;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<ExecuteResult>;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<DeliverTxResponse>;
updateRegistryFee: ({
newFee
}: {
newFee: Coin;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<ExecuteResult>;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<DeliverTxResponse>;
updateDaoAddr: ({
newAddr
}: {
newAddr: string;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<ExecuteResult>;
}, fee_?: number | StdFee | "auto", memo_?: string, funds_?: Coin[]) => Promise<DeliverTxResponse>;
}
export class 98Client extends 98QueryClient implements 98Interface {
client: SigningCosmWasmClient;
client: ISigningCosmWasmClient;
sender: string;
contractAddress: string;
constructor(client: SigningCosmWasmClient, sender: string, contractAddress: string) {
constructor(client: ISigningCosmWasmClient, sender: string, contractAddress: string) {
super(client, contractAddress);
this.client = client;
this.sender = sender;
Expand All @@ -144,7 +144,7 @@ export class 98Client extends 98QueryClient implements 98Interface {
}: {
id: number;
instantiateMsg: Binary;
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<ExecuteResult> => {
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<DeliverTxResponse> => {
return await this.client.execute(this.sender, this.contractAddress, {
proxy_install_plugin: {
id,
Expand All @@ -166,7 +166,7 @@ export class 98Client extends 98QueryClient implements 98Interface {
ipfsHash: string;
name: string;
version: string;
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<ExecuteResult> => {
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<DeliverTxResponse> => {
return await this.client.execute(this.sender, this.contractAddress, {
register_plugin: {
checksum,
Expand All @@ -182,7 +182,7 @@ export class 98Client extends 98QueryClient implements 98Interface {
id
}: {
id: number;
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<ExecuteResult> => {
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<DeliverTxResponse> => {
return await this.client.execute(this.sender, this.contractAddress, {
unregister_plugin: {
id
Expand All @@ -205,7 +205,7 @@ export class 98Client extends 98QueryClient implements 98Interface {
ipfsHash?: string;
name?: string;
version?: string;
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<ExecuteResult> => {
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<DeliverTxResponse> => {
return await this.client.execute(this.sender, this.contractAddress, {
update_plugin: {
checksum,
Expand All @@ -222,7 +222,7 @@ export class 98Client extends 98QueryClient implements 98Interface {
newFee
}: {
newFee: Coin;
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<ExecuteResult> => {
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<DeliverTxResponse> => {
return await this.client.execute(this.sender, this.contractAddress, {
update_registry_fee: {
new_fee: newFee
Expand All @@ -233,7 +233,7 @@ export class 98Client extends 98QueryClient implements 98Interface {
newAddr
}: {
newAddr: string;
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<ExecuteResult> => {
}, fee_: number | StdFee | "auto" = "auto", memo_?: string, funds_?: Coin[]): Promise<DeliverTxResponse> => {
return await this.client.execute(this.sender, this.contractAddress, {
update_dao_addr: {
new_addr: newAddr
Expand Down
189 changes: 189 additions & 0 deletions __fixtures__/issues/98/out/baseClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/**
* This file was automatically generated by @cosmwasm/ts-codegen@latest.
* DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
* and run the @cosmwasm/ts-codegen generate command to regenerate this file.
*/


import { StdFee, Coin, DeliverTxResponse } from '@interchainjs/types';
import { SigningClient } from '@interchainjs/cosmos/signing-client';
import { getSmartContractState } from 'interchainjs/cosmwasm/wasm/v1/query.rpc.func';
import { executeContract } from 'interchainjs/cosmwasm/wasm/v1/tx.rpc.func';
import { QuerySmartContractStateRequest, QuerySmartContractStateResponse } from 'interchainjs/cosmwasm/wasm/v1/query';
import { MsgExecuteContract } from 'interchainjs/cosmwasm/wasm/v1/tx';
import { Chain } from '@chain-registry/v2-types';

// Encoding utility functions
const fromUint8Array = <T>(uint8Array: Uint8Array): T => {
const text = new TextDecoder().decode(uint8Array);
return JSON.parse(text);
};

const toUint8Array = (obj: any): Uint8Array => {
const text = JSON.stringify(obj);
return new TextEncoder().encode(text);
};

// Chain registry configuration
// The amount under gasPrice represents gas price per unit
export interface ChainConfig {
chain?: Chain;
gasPrice?: {
denom: string;
amount: string;
};
}

// Gas fee calculation utilities
export const calculateGasFromChain = (chain: Chain, gasAmount: string): StdFee => {
try {
const feeTokens = chain.fees?.feeTokens;

if (feeTokens && feeTokens.length > 0) {
const primaryToken = feeTokens[0];
// v2 chain-registry uses camelCase: averageGasPrice, lowGasPrice, fixedMinGasPrice
const gasPrice = primaryToken.averageGasPrice || primaryToken.lowGasPrice || primaryToken.fixedMinGasPrice || 0.025;
const gasAmountNum = parseInt(gasAmount);
const feeAmount = Math.ceil(gasAmountNum * gasPrice).toString();

return {
amount: [{
denom: primaryToken.denom,
amount: feeAmount
}],
gas: gasAmount
};
}
} catch (error) {
console.warn('Failed to calculate gas from chain registry:', error);
}

// Fallback to default
return { amount: [], gas: gasAmount };
};

// Default gas amount - users can easily change this
export let DEFAULT_GAS_AMOUNT = '200000';

// Allow users to set their preferred default gas amount
export const setDefaultGasAmount = (gasAmount: string): void => {
DEFAULT_GAS_AMOUNT = gasAmount;
};

// Get current default gas amount
export const getDefaultGasAmount = (): string => DEFAULT_GAS_AMOUNT;

export const getAutoGasFee = (chainConfig?: ChainConfig): StdFee => {
const gasAmount = DEFAULT_GAS_AMOUNT;

if (chainConfig?.chain) {
return calculateGasFromChain(chainConfig.chain, gasAmount);
}

if (chainConfig?.gasPrice) {
const gasAmountNum = parseInt(gasAmount);
const gasPriceNum = parseFloat(chainConfig.gasPrice.amount);
const feeAmount = Math.ceil(gasAmountNum * gasPriceNum).toString();

return {
amount: [{
denom: chainConfig.gasPrice.denom,
amount: feeAmount
}],
gas: gasAmount
};
}

// Fallback: no fee tokens, just gas amount
return { amount: [], gas: gasAmount };
};

// InterchainJS interfaces for CosmWasm clients
export interface ICosmWasmClient {
queryContractSmart(contractAddr: string, query: any): Promise<any>;
}

export interface ISigningCosmWasmClient {
execute(
sender: string,
contractAddress: string,
msg: any,
fee?: number | StdFee | "auto",
memo?: string,
funds?: Coin[],
chainConfig?: ChainConfig
): Promise<DeliverTxResponse>;
}

export interface ISigningClient {
signAndBroadcast(
signerAddress: string,
messages: any[],
fee: number | StdFee | "auto",
memo?: string
): Promise<DeliverTxResponse>;
}

// Helper functions to create InterchainJS clients
export function getCosmWasmClient(rpcEndpoint: string): ICosmWasmClient {
return {
queryContractSmart: async (contractAddr: string, query: any) => {
// Create the request object
const request: QuerySmartContractStateRequest = {
address: contractAddr,
queryData: toUint8Array(query)
};

// Execute the query using InterchainJS
const response: QuerySmartContractStateResponse = await getSmartContractState(rpcEndpoint, request);

// Parse and return the result
return fromUint8Array(response.data);
},
};
}

export function getSigningCosmWasmClient(signingClient: SigningClient): ISigningCosmWasmClient {
return {
execute: async (
sender: string,
contractAddress: string,
msg: any,
fee?: number | StdFee | "auto",
memo?: string,
funds?: Coin[],
chainConfig?: ChainConfig
) => {
// Handle fee conversion
let finalFee: StdFee;
if (typeof fee === 'number') {
finalFee = { amount: [], gas: fee.toString() };
} else if (fee === 'auto') {
finalFee = getAutoGasFee(chainConfig);
} else if (fee) {
finalFee = fee;
} else {
finalFee = getAutoGasFee(chainConfig);
}

// Create the message object
const message: MsgExecuteContract = {
sender,
contract: contractAddress,
msg: toUint8Array(msg),
funds: funds || []
};

// Execute the transaction using InterchainJS
const result = await executeContract(
signingClient as any,
sender,
message,
finalFee,
memo || ''
);

return result;
},
};
}
4 changes: 4 additions & 0 deletions __fixtures__/issues/98/out/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@
import * as _0 from "./98.types";
import * as _1 from "./98.client";
import * as _2 from "./98.react-query";
import * as _3 from "./baseClient";
export namespace contracts {
export const 98 = {
..._0,
..._1,
..._2
};
export const baseClient = {
..._3
};
}
Loading