Skip to main content
Glama
wallet.ts4.13 kB
// Wallet utility functions for Osmosis MCP server import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing"; import { toBech32, fromBech32 } from "@cosmjs/encoding"; import { Secp256k1, EnglishMnemonic, Bip39 } from "@cosmjs/crypto"; export interface WalletInfo { address: string; publicKey: string; mnemonic?: string; } /** * Generates a new wallet with mnemonic phrase */ export async function generateWallet(wordCount: number = 24, prefix: string = "osmo"): Promise<WalletInfo> { try { const validWordCounts = [12, 15, 18, 21, 24]; const validWordCount = validWordCounts.includes(wordCount) ? wordCount as 12 | 15 | 18 | 21 | 24 : 24; const wallet = await DirectSecp256k1HdWallet.generate(validWordCount, { prefix: prefix, }); const [firstAccount] = await wallet.getAccounts(); return { address: firstAccount.address, publicKey: Buffer.from(firstAccount.pubkey).toString('hex'), mnemonic: wallet.mnemonic }; } catch (error) { throw new Error(`Failed to generate wallet: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Restores a wallet from mnemonic phrase */ export async function restoreWalletFromMnemonic( mnemonic: string, prefix: string = "osmo", accountIndex: number = 0 ): Promise<WalletInfo> { try { // Validate mnemonic first if (!validateMnemonic(mnemonic)) { throw new Error('Invalid mnemonic phrase'); } const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, { prefix: prefix }); const [firstAccount] = await wallet.getAccounts(); return { address: firstAccount.address, publicKey: Buffer.from(firstAccount.pubkey).toString('hex') // Don't return mnemonic for security }; } catch (error) { throw new Error(`Failed to restore wallet: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Gets address from mnemonic without exposing private key */ export async function getAddressFromMnemonic( mnemonic: string, prefix: string = "osmo", accountIndex: number = 0 ): Promise<string> { const walletInfo = await restoreWalletFromMnemonic(mnemonic, prefix, accountIndex); return walletInfo.address; } /** * Validates a BIP-39 mnemonic phrase */ export function validateMnemonic(mnemonic: string): boolean { try { const mnemonicChecked = new EnglishMnemonic(mnemonic); return Bip39.decode(mnemonicChecked).length > 0; } catch { return false; } } /** * Validates an address for a given prefix */ export function validateAddress(address: string, expectedPrefix: string = "osmo"): boolean { try { const { prefix } = fromBech32(address); return prefix === expectedPrefix; } catch { return false; } } /** * Derives address from public key */ export async function deriveAddressFromPubkey(publicKeyHex: string, prefix: string = "osmo"): Promise<string> { try { const publicKey = Buffer.from(publicKeyHex, 'hex'); if (publicKey.length !== 33) { throw new Error('Invalid public key length. Expected 33 bytes for compressed secp256k1 public key'); } // For now, return a placeholder - proper implementation would require additional crypto operations // This would need proper hash160 operation on the public key throw new Error('Address derivation from public key not yet implemented'); } catch (error) { throw new Error(`Failed to derive address: ${error instanceof Error ? error.message : 'Unknown error'}`); } } /** * Generates a deterministic wallet for testing (INSECURE - for development only) */ export async function generateTestWallet(seed: string = "test", prefix: string = "osmo"): Promise<WalletInfo> { // Create deterministic entropy from seed (INSECURE) const testMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"; console.warn('⚠️ WARNING: generateTestWallet creates deterministic wallets for testing only. Never use in production!'); return await restoreWalletFromMnemonic(testMnemonic, prefix); }

Latest Blog Posts

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/MyronKoch-dev/osmosis-mcp-server'

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