Skip to main content
Glama

Osmosis

by jonator
account.ts6.69 kB
import type { Chain } from '@chain-registry/types' import type { FeeToken } from '@chain-registry/types/chain.schema.js' import type { StdFee } from '@cosmjs/amino' import { type SigningCosmWasmClient, createWasmAminoConverters, wasmTypes, } from '@cosmjs/cosmwasm-stargate' import { stringToPath } from '@cosmjs/crypto' import type { EncodeObject, OfflineSigner } from '@cosmjs/proto-signing' import { DirectSecp256k1HdWallet, Registry } from '@cosmjs/proto-signing' import { AminoTypes, GasPrice, type HttpEndpoint, SigningStargateClient, type SigningStargateClientOptions, calculateFee, createDefaultAminoConverters, defaultRegistryTypes, } from '@cosmjs/stargate' import type { CometClient } from '@cosmjs/tendermint-rpc' import { Comet38Client, Tendermint34Client, Tendermint37Client, } from '@cosmjs/tendermint-rpc' import { ripemd160 } from '@noble/hashes/ripemd160' import { sha256 } from '@noble/hashes/sha256' import { bech32, utf8 } from '@scure/base' import { HDKey } from '@scure/bip32' import { mnemonicToSeedSync } from '@scure/bip39' import { chains } from 'chain-registry/mainnet/index.js' import { osmosisAminoConverters, osmosisProtoRegistry } from 'osmojs' export interface CosmosSignData { msgs: EncodeObject[] memo?: string feeMultiplier?: number fee?: StdFee } type CosmosFee = { fee: StdFee gasPrice: GasPrice | undefined } export class Account { protected chain: Chain protected derivationPath: { path: string prefix: string } constructor( protected readonly mnemonic: string, protected readonly chainId = 'osmosis-1', ) { this.chain = chains.find((chain) => chain.chain_id === this.chainId)! this.derivationPath = { path: `m/44'/${this.chain.slip44}'/0'/0/0`, prefix: this.chain.bech32_prefix!, } } get address() { const seed = mnemonicToSeedSync(this.mnemonic) const hdkey = HDKey.fromMasterSeed(seed) const child = hdkey.derive(this.derivationPath.path) if (!child.publicKey) { throw new Error('Failed to derive public key') } const hash = ripemd160(sha256(child.publicKey)) return bech32.encode(this.derivationPath.prefix, bech32.toWords(hash)) } async estimateFees({ msgs, memo, feeMultiplier = 2, }: CosmosSignData): Promise<CosmosFee> { const wallet = await this.getWallet() const stargateClient = await getConsensusSigningStargateClient({ chain: this.chain, signer: wallet, }) const gasPrice = getGasPrice(this.chain) const fee = await estimateFee( stargateClient, this.address, msgs, gasPrice!, memo, feeMultiplier, ) return { fee, gasPrice, } } async signAndBroadcast({ msgs, fee, memo }: CosmosSignData) { const wallet = await this.getWallet() const stargateClient = await getConsensusSigningStargateClient({ chain: this.chain, signer: wallet, }) const gasPrice = getGasPrice(this.chain) return await stargateClient.signAndBroadcastSync( this.address, msgs, fee ?? (await estimateFee( stargateClient, this.address, msgs, gasPrice!, memo, )), memo ?? 'osmosis-agent-toolkit', ) } async signMessage(message: string) { const wallet = await this.getWallet() const messageHash = utf8.decode(message) const signDoc = { chainId: '', accountNumber: BigInt('0'), authInfoBytes: new Uint8Array(), sequence: '0', bodyBytes: messageHash, } return (await wallet.signDirect(this.address, signDoc)).signature.signature } protected getWallet() { return DirectSecp256k1HdWallet.fromMnemonic(this.mnemonic, { hdPaths: [stringToPath(this.derivationPath.path)], prefix: this.derivationPath.prefix, }) } } /** * Retrieve chain gas price so we can use fee auto. * * @param chain * @param feeDenom ex. uosmo * @returns */ function getGasPrice(chain: Chain, feeDenom?: string) { let gasPrice: GasPrice | undefined = undefined if (chain.fees && chain.fees.fee_tokens.length > 0) { let feeToken: FeeToken | undefined = undefined if (feeToken) { feeToken = chain.fees.fee_tokens.find((token) => token.denom === feeDenom) } else { feeToken = chain.fees.fee_tokens[0] } const averageGasPrice = feeToken?.average_gas_price const denom = feeToken?.denom if (averageGasPrice && denom && !denom.startsWith('ibc/')) { gasPrice = GasPrice.fromString(`${averageGasPrice}${denom}`) } else { gasPrice = GasPrice.fromString(`1${denom}`) } } return gasPrice } /** * It allow us to get right client to use, based in chain metadata info and also setup it with registry ecc. */ async function getConsensusSigningStargateClient({ chain, signer, options, }: { chain: Chain signer: OfflineSigner options?: SigningStargateClientOptions }) { const version = chain.codebase?.consensus?.version const type = chain.codebase?.consensus?.type const endpoint = chain.apis?.rpc?.[0]?.address if (!endpoint) { throw new Error('[Cosmos Signer]: No RPC endpoint found') } const cometClient = await getCometBftClient({ version, type, endpoint }) return SigningStargateClient.createWithSigner(cometClient, signer, { registry, aminoTypes, ...options, }) } const registry = new Registry([ ...defaultRegistryTypes, ...wasmTypes, ...osmosisProtoRegistry, ]) const aminoTypes = new AminoTypes({ ...createDefaultAminoConverters(), ...createWasmAminoConverters(), ...osmosisAminoConverters, }) async function getCometBftClient({ version, type, endpoint, }: { type?: string version?: string endpoint: string | HttpEndpoint }) { let out: CometClient const tm37Client = await Tendermint37Client.connect(endpoint) if (version) { if (type === 'cometbft') { tm37Client.disconnect() out = await Comet38Client.connect(endpoint) } else { if (version.startsWith('0.37.')) { out = tm37Client } else { tm37Client.disconnect() out = await Tendermint34Client.connect(endpoint) } } } else { tm37Client.disconnect() out = await Comet38Client.connect(endpoint) } return out } async function estimateFee( client: SigningStargateClient | SigningCosmWasmClient, sender: string, messages: EncodeObject[], gasPrice: string | GasPrice, memo?: string, multiplier = 1.4, ) { const gasEstimation = await client.simulate(sender, messages, memo) return calculateFee(Math.round(gasEstimation * multiplier), gasPrice) }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jonator/osmosis-agent-toolkit'

If you have feedback or need assistance with the MCP directory API, please join our Discord server