如何将Hedera原生地址转换为非长零格式EVM地址?
解决Hedera账户ID转非长零格式EVM地址问题
你当前用AccountId.toSolidityAddress()得到的是long-zero格式的地址,这是将账户ID的shard.realm.num编码为20字节的结果(仅取num部分补零填充),但智能合约中msg.sender显示的是账户关联的ECDSA公钥生成的EVM地址,需要通过以下步骤获取:
核心逻辑
非长零格式的EVM地址由账户的ECDSA公钥生成:取公钥的字节数据,计算Keccak-256哈希,截取最后20字节并添加0x前缀。
实现代码(Hedera SDK JS v2)
import { Client, AccountId, AccountInfoQuery, PublicKey } from "@hashgraph/sdk"; import { keccak256 } from "ethers/lib/utils"; // 也可使用其他支持Keccak-256的加密库 async function getNonLongZeroEvmAddress(accountIdStr, client) { // 1. 查询账户信息,获取关联公钥 const accountId = AccountId.fromString(accountIdStr); const accountInfo = await new AccountInfoQuery() .setAccountId(accountId) .execute(client); const publicKey = accountInfo.key; // 仅ECDSA类型账户支持生成该格式地址,ED25519账户无对应EVM地址 if (!(publicKey instanceof PublicKey) || !publicKey.isEcdsa()) { throw new Error("该账户不是ECDSA类型,无法生成非长零格式EVM地址"); } // 2. 提取公钥的有效字节(去掉非压缩公钥的0x04前缀) const publicKeyBytes = publicKey.toBytesRaw(); const validPublicKeyBytes = publicKey.isCompressed() ? publicKey.decompress().toBytesRaw().slice(1) : publicKeyBytes.slice(1); // 3. 计算Keccak-256哈希并截取最后20字节 const hash = keccak256(validPublicKeyBytes); const evmAddress = `0x${hash.slice(-40)}`; return evmAddress; } // 使用示例 async function main() { const client = Client.forTestnet(); // 根据环境切换主网/预览网 client.setOperator(process.env.OPERATOR_ID, process.env.OPERATOR_KEY); const targetAccountId = "0.0.3996280"; const evmAddress = await getNonLongZeroEvmAddress(targetAccountId, client); console.log(evmAddress); // 输出对应非长零格式地址 } main().catch(console.error);
关键说明
- 只有ECDSA类型的Hedera账户能生成该格式地址,ED25519账户因EVM仅支持ECDSA签名体系,无法生成对应地址。
- 生成的地址与Hashscan显示的账户EVM地址、合约中
msg.sender的值完全一致,可直接用于智能合约交互。
内容的提问来源于stack exchange,提问作者bguiz
相关产品推荐
相关产品推荐

