You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义HD路径的DirectSecp256k1HdWallet导出Injective地址不符问题

助记词导出Injective地址与Keplr/Leap不一致的原因及解决方法

核心差异原因

两者的地址生成逻辑完全不同:

  • 你的CosmJS代码逻辑:遵循Cosmos生态标准流程:私钥→压缩公钥→SHA256哈希→RIPEMD160哈希→Bech32编码(前缀inj)。
  • Keplr/Leap的以太坊路径逻辑:遵循以太坊地址生成规则:私钥→未压缩公钥→Keccak256哈希→取最后20字节→将该字节数组转为Bech32编码(前缀inj)。

因为你指定了以太坊HD路径(m/44'/60'/0'/0/0),Keplr/Leap会自动切换到以太坊风格的地址生成逻辑,而CosmJS的DirectSecp256k1HdWallet默认沿用Cosmos标准,导致最终地址不一致。

解决代码实现

你需要手动实现以太坊风格的地址生成流程,再转换为Injective的Bech32格式。以下是两种可行方案:

方案一:基于DirectSecp256k1HdWallet扩展处理

import { DirectSecp256k1HdWallet } from '@cosmjs/proto-signing';
import { stringToPath } from '@cosmjs/crypto';
import { keccak256 } from '@ethersproject/keccak256';
import { bech32 } from 'bech32';
import * as secp256k1 from 'secp256k1';

const mnemonic = 'belt purity enforce meadow peanut pupil ignore inform skill common connect source';
const path = "m/44'/60'/0'/0/0";

// 初始化钱包获取压缩公钥
const wallet = await DirectSecp256k1HdWallet.fromMnemonic(mnemonic, {
  prefix: 'inj',
  hdPaths: [stringToPath(path)],
});
const [account] = await wallet.getAccounts();

// 压缩公钥转未压缩格式(以太坊需要未压缩公钥)
const compressedPubKey = Buffer.from(account.pubkey);
const uncompressedPubKey = secp256k1.publicKeyConvert(compressedPubKey, false);

// 生成以太坊风格的20字节地址
const ethAddressBytes = Buffer.from(keccak256(uncompressedPubKey).slice(2), 'hex').slice(-20);

// 转换为Injective的Bech32地址
const bech32Words = bech32.toWords(ethAddressBytes);
const injAddress = bech32.encode('inj', bech32Words);

console.log('匹配Keplr/Leap的Injective地址:', injAddress);
// 输出:inj1kux4gh5svddeey4tpsgdqr357rjf4wx2az8tyr

方案二:直接从种子导出私钥处理(更轻量)

import { Bip39, Slip10, Slip10Curve, stringToPath } from '@cosmjs/crypto';
import { keccak256 } from '@ethersproject/keccak256';
import { bech32 } from 'bech32';
import * as secp256k1 from 'secp256k1';

const mnemonic = 'belt purity enforce meadow peanut pupil ignore inform skill common connect source';
const path = stringToPath("m/44'/60'/0'/0/0");

// 从助记词生成种子
const seed = await Bip39.mnemonicToSeed(mnemonic);
// 导出指定路径的私钥
const { privkey } = Slip10.derivePath(Slip10Curve.Secp256k1, seed, path);
// 生成未压缩公钥
const uncompressedPubKey = secp256k1.publicKeyCreate(privkey, false);
// 生成20字节以太坊地址字节数组
const ethAddressBytes = Buffer.from(keccak256(uncompressedPubKey).slice(2), 'hex').slice(-20);
// 编码为Injective Bech32地址
const bech32Words = bech32.toWords(ethAddressBytes);
const injAddress = bech32.encode('inj', bech32Words);

console.log('匹配Keplr/Leap的Injective地址:', injAddress);
// 输出:inj1kux4gh5svddeey4tpsgdqr357rjf4wx2az8tyr

依赖说明

执行代码前需要安装对应依赖包:

npm install @cosmjs/crypto @cosmjs/proto-signing @ethersproject/keccak256 bech32 secp256k1

内容的提问来源于stack exchange,提问作者Eric Lee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 22:07:08