Skip to content

Commit aa36a62

Browse files
Added gas fee calculation on client level
1 parent f712d40 commit aa36a62

File tree

8 files changed

+675
-35
lines changed

8 files changed

+675
-35
lines changed

__fixtures__/issues/98/out/baseClient.ts

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getSmartContractState } from 'interchainjs/cosmwasm/wasm/v1/query.rpc.f
1111
import { executeContract } from 'interchainjs/cosmwasm/wasm/v1/tx.rpc.func';
1212
import { QuerySmartContractStateRequest, QuerySmartContractStateResponse } from 'interchainjs/cosmwasm/wasm/v1/query';
1313
import { MsgExecuteContract } from 'interchainjs/cosmwasm/wasm/v1/tx';
14+
import { Chain } from '@chain-registry/v2-types';
1415

1516
// Encoding utility functions
1617
const fromUint8Array = <T>(uint8Array: Uint8Array): T => {
@@ -23,13 +24,95 @@ const toUint8Array = (obj: any): Uint8Array => {
2324
return new TextEncoder().encode(text);
2425
};
2526

27+
// Chain registry configuration
28+
// The amount under gasPrice represents gas price per unit
29+
export interface ChainConfig {
30+
chain?: Chain;
31+
gasPrice?: {
32+
denom: string;
33+
amount: string;
34+
};
35+
}
36+
37+
// Gas fee calculation utilities
38+
export const calculateGasFromChain = (chain: Chain, gasAmount: string): StdFee => {
39+
try {
40+
const feeTokens = chain.fees?.feeTokens;
41+
42+
if (feeTokens && feeTokens.length > 0) {
43+
const primaryToken = feeTokens[0];
44+
// v2 chain-registry uses camelCase: averageGasPrice, lowGasPrice, fixedMinGasPrice
45+
const gasPrice = primaryToken.averageGasPrice || primaryToken.lowGasPrice || primaryToken.fixedMinGasPrice || 0.025;
46+
const gasAmountNum = parseInt(gasAmount);
47+
const feeAmount = Math.ceil(gasAmountNum * gasPrice).toString();
48+
49+
return {
50+
amount: [{
51+
denom: primaryToken.denom,
52+
amount: feeAmount
53+
}],
54+
gas: gasAmount
55+
};
56+
}
57+
} catch (error) {
58+
console.warn('Failed to calculate gas from chain registry:', error);
59+
}
60+
61+
// Fallback to default
62+
return { amount: [], gas: gasAmount };
63+
};
64+
65+
// Default gas amount - users can easily change this
66+
export let DEFAULT_GAS_AMOUNT = '200000';
67+
68+
// Allow users to set their preferred default gas amount
69+
export const setDefaultGasAmount = (gasAmount: string): void => {
70+
DEFAULT_GAS_AMOUNT = gasAmount;
71+
};
72+
73+
// Get current default gas amount
74+
export const getDefaultGasAmount = (): string => DEFAULT_GAS_AMOUNT;
75+
76+
export const getAutoGasFee = (chainConfig?: ChainConfig): StdFee => {
77+
const gasAmount = DEFAULT_GAS_AMOUNT;
78+
79+
if (chainConfig?.chain) {
80+
return calculateGasFromChain(chainConfig.chain, gasAmount);
81+
}
82+
83+
if (chainConfig?.gasPrice) {
84+
const gasAmountNum = parseInt(gasAmount);
85+
const gasPriceNum = parseFloat(chainConfig.gasPrice.amount);
86+
const feeAmount = Math.ceil(gasAmountNum * gasPriceNum).toString();
87+
88+
return {
89+
amount: [{
90+
denom: chainConfig.gasPrice.denom,
91+
amount: feeAmount
92+
}],
93+
gas: gasAmount
94+
};
95+
}
96+
97+
// Fallback: no fee tokens, just gas amount
98+
return { amount: [], gas: gasAmount };
99+
};
100+
26101
// InterchainJS interfaces for CosmWasm clients
27102
export interface ICosmWasmClient {
28103
queryContractSmart(contractAddr: string, query: any): Promise<any>;
29104
}
30105

31106
export interface ISigningCosmWasmClient {
32-
execute(sender: string, contractAddress: string, msg: any, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise<DeliverTxResponse>;
107+
execute(
108+
sender: string,
109+
contractAddress: string,
110+
msg: any,
111+
fee?: number | StdFee | "auto",
112+
memo?: string,
113+
funds?: Coin[],
114+
chainConfig?: ChainConfig
115+
): Promise<DeliverTxResponse>;
33116
}
34117

35118
export interface ISigningClient {
@@ -62,17 +145,25 @@ export function getCosmWasmClient(rpcEndpoint: string): ICosmWasmClient {
62145

63146
export function getSigningCosmWasmClient(signingClient: SigningClient): ISigningCosmWasmClient {
64147
return {
65-
execute: async (sender: string, contractAddress: string, msg: any, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => {
148+
execute: async (
149+
sender: string,
150+
contractAddress: string,
151+
msg: any,
152+
fee?: number | StdFee | "auto",
153+
memo?: string,
154+
funds?: Coin[],
155+
chainConfig?: ChainConfig
156+
) => {
66157
// Handle fee conversion
67158
let finalFee: StdFee;
68159
if (typeof fee === 'number') {
69160
finalFee = { amount: [], gas: fee.toString() };
70161
} else if (fee === 'auto') {
71-
finalFee = { amount: [], gas: '200000' }; // default gas for auto
162+
finalFee = getAutoGasFee(chainConfig);
72163
} else if (fee) {
73164
finalFee = fee;
74165
} else {
75-
finalFee = { amount: [], gas: '200000' }; // default fee
166+
finalFee = getAutoGasFee(chainConfig);
76167
}
77168

78169
// Create the message object
@@ -85,7 +176,7 @@ export function getSigningCosmWasmClient(signingClient: SigningClient): ISigning
85176

86177
// Execute the transaction using InterchainJS
87178
const result = await executeContract(
88-
signingClient,
179+
signingClient as any,
89180
sender,
90181
message,
91182
finalFee,

__output__/builder/bundler_test/contracts/baseClient.ts

Lines changed: 96 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { getSmartContractState } from 'interchainjs/cosmwasm/wasm/v1/query.rpc.f
1111
import { executeContract } from 'interchainjs/cosmwasm/wasm/v1/tx.rpc.func';
1212
import { QuerySmartContractStateRequest, QuerySmartContractStateResponse } from 'interchainjs/cosmwasm/wasm/v1/query';
1313
import { MsgExecuteContract } from 'interchainjs/cosmwasm/wasm/v1/tx';
14+
import { Chain } from '@chain-registry/v2-types';
1415

1516
// Encoding utility functions
1617
const fromUint8Array = <T>(uint8Array: Uint8Array): T => {
@@ -23,13 +24,95 @@ const toUint8Array = (obj: any): Uint8Array => {
2324
return new TextEncoder().encode(text);
2425
};
2526

27+
// Chain registry configuration
28+
// The amount under gasPrice represents gas price per unit
29+
export interface ChainConfig {
30+
chain?: Chain;
31+
gasPrice?: {
32+
denom: string;
33+
amount: string;
34+
};
35+
}
36+
37+
// Gas fee calculation utilities
38+
export const calculateGasFromChain = (chain: Chain, gasAmount: string): StdFee => {
39+
try {
40+
const feeTokens = chain.fees?.feeTokens;
41+
42+
if (feeTokens && feeTokens.length > 0) {
43+
const primaryToken = feeTokens[0];
44+
// v2 chain-registry uses camelCase: averageGasPrice, lowGasPrice, fixedMinGasPrice
45+
const gasPrice = primaryToken.averageGasPrice || primaryToken.lowGasPrice || primaryToken.fixedMinGasPrice || 0.025;
46+
const gasAmountNum = parseInt(gasAmount);
47+
const feeAmount = Math.ceil(gasAmountNum * gasPrice).toString();
48+
49+
return {
50+
amount: [{
51+
denom: primaryToken.denom,
52+
amount: feeAmount
53+
}],
54+
gas: gasAmount
55+
};
56+
}
57+
} catch (error) {
58+
console.warn('Failed to calculate gas from chain registry:', error);
59+
}
60+
61+
// Fallback to default
62+
return { amount: [], gas: gasAmount };
63+
};
64+
65+
// Default gas amount - users can easily change this
66+
export let DEFAULT_GAS_AMOUNT = '200000';
67+
68+
// Allow users to set their preferred default gas amount
69+
export const setDefaultGasAmount = (gasAmount: string): void => {
70+
DEFAULT_GAS_AMOUNT = gasAmount;
71+
};
72+
73+
// Get current default gas amount
74+
export const getDefaultGasAmount = (): string => DEFAULT_GAS_AMOUNT;
75+
76+
export const getAutoGasFee = (chainConfig?: ChainConfig): StdFee => {
77+
const gasAmount = DEFAULT_GAS_AMOUNT;
78+
79+
if (chainConfig?.chain) {
80+
return calculateGasFromChain(chainConfig.chain, gasAmount);
81+
}
82+
83+
if (chainConfig?.gasPrice) {
84+
const gasAmountNum = parseInt(gasAmount);
85+
const gasPriceNum = parseFloat(chainConfig.gasPrice.amount);
86+
const feeAmount = Math.ceil(gasAmountNum * gasPriceNum).toString();
87+
88+
return {
89+
amount: [{
90+
denom: chainConfig.gasPrice.denom,
91+
amount: feeAmount
92+
}],
93+
gas: gasAmount
94+
};
95+
}
96+
97+
// Fallback: no fee tokens, just gas amount
98+
return { amount: [], gas: gasAmount };
99+
};
100+
26101
// InterchainJS interfaces for CosmWasm clients
27102
export interface ICosmWasmClient {
28103
queryContractSmart(contractAddr: string, query: any): Promise<any>;
29104
}
30105

31106
export interface ISigningCosmWasmClient {
32-
execute(sender: string, contractAddress: string, msg: any, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]): Promise<DeliverTxResponse>;
107+
execute(
108+
sender: string,
109+
contractAddress: string,
110+
msg: any,
111+
fee?: number | StdFee | "auto",
112+
memo?: string,
113+
funds?: Coin[],
114+
chainConfig?: ChainConfig
115+
): Promise<DeliverTxResponse>;
33116
}
34117

35118
export interface ISigningClient {
@@ -62,17 +145,25 @@ export function getCosmWasmClient(rpcEndpoint: string): ICosmWasmClient {
62145

63146
export function getSigningCosmWasmClient(signingClient: SigningClient): ISigningCosmWasmClient {
64147
return {
65-
execute: async (sender: string, contractAddress: string, msg: any, fee?: number | StdFee | "auto", memo?: string, funds?: Coin[]) => {
148+
execute: async (
149+
sender: string,
150+
contractAddress: string,
151+
msg: any,
152+
fee?: number | StdFee | "auto",
153+
memo?: string,
154+
funds?: Coin[],
155+
chainConfig?: ChainConfig
156+
) => {
66157
// Handle fee conversion
67158
let finalFee: StdFee;
68159
if (typeof fee === 'number') {
69160
finalFee = { amount: [], gas: fee.toString() };
70161
} else if (fee === 'auto') {
71-
finalFee = { amount: [], gas: '200000' }; // default gas for auto
162+
finalFee = getAutoGasFee(chainConfig);
72163
} else if (fee) {
73164
finalFee = fee;
74165
} else {
75-
finalFee = { amount: [], gas: '200000' }; // default fee
166+
finalFee = getAutoGasFee(chainConfig);
76167
}
77168

78169
// Create the message object
@@ -85,7 +176,7 @@ export function getSigningCosmWasmClient(signingClient: SigningClient): ISigning
85176

86177
// Execute the transaction using InterchainJS
87178
const result = await executeContract(
88-
signingClient,
179+
signingClient as any,
89180
sender,
90181
message,
91182
finalFee,

0 commit comments

Comments
 (0)