原文作者:PapeMoon团队
Polkadot Hub 原生采用 Polkadot 的 32 字节账户体系,同时通过自动转换机制,实现对以太坊 20 字节地址的兼容。在与智能合约交互时:
- 以太坊兼容钱包(如 MetaMask)可继续使用熟悉的 20 字节地址。
- Polkadot 账户继续使用原生的 32 字节格式。
- Polkadot Hub 会在底层自动处理两种格式之间的转换:
- 20 字节以太坊地址会在末尾补齐 12 个 0xEE 字节,生成合法的 32 字节 Polkadot 账户。
- 32 字节 Polkadot 账户可选择注册映射关系,以获得以太坊兼容性。
这种双格式设计,使 Polkadot Hub 在保持以太坊工具兼容性的同时,也能完整融入 Polkadot 生态体系。
地址类型与映射机制
平台支持两种地址格式:
以太坊到Polkadot 映射
pallet_revive 中的 AccountId32Mapper 负责核心地址转换逻辑。
当将 20 字节以太坊地址转换为 32 字节 Polkadot 地址时,采用简单拼接方式:
- 在 20 字节地址末尾追加 12 个 0xEE 字节,扩展为 32 字节。
该方案的优势包括:
- 完全可逆,可恢复为原始以太坊地址。
- 通过 0xEE 后缀明确标识以太坊来源账户。
- 具备 2⁹⁶ 的安全难度,难以伪造该模式。
Polkadot到以太坊映射
由于这种转换过程本身会造成信息丢失,将 32 字节的 Polkadot 账户转换为 20 字节的以太坊地址 比反向转换更加复杂。AccountId32Mapper 通过两种不同的方式来处理这一过程:
1. 以太坊派生账户
对于源自以太坊的账户:系统会使用 is_eth_derived 函数来识别最初来源于以太坊地址的账户(通过 0xEE 后缀模式进行判断)。对于这类账户,转换时会移除末尾的 12 个字节,从而还原原始的 20 字节以太坊地址。
2. 原生 Polkadot 账户
对于原生 Polkadot 账户:由于这类账户使用完整的 32 字节空间,且并非源自以太坊地址,若直接截断将导致信息丢失。因此,系统采用以下方式进行转换:
- 使用 Keccak-256 对完整的 32 字节账户进行哈希计算;
- 取哈希结果的后 20 个字节作为以太坊地址。
- 该方式在避免简单截断的同时,保证了映射结果的确定性。
整个转换过程由 to_address 函数实现,该函数会自动识别账户类型,并应用相应的转换方法。
用于可逆性的有状态映射机制
由于从 32 字节地址转换为 20 字节地址在本质上会造成信息丢失,系统通过 OriginalAccount 存储提供了一种可选的有状态映射机制。
当 Polkadot 账户通过 map 函数注册映射关系时,系统会保存其原始的 32 字节账户 ID,从而使 to_account_id 函数能够准确恢复原始账户,而不是退回使用默认的转换方式。
未映射 Substrate 账户的交互限制
尚未显式映射的原生 Polkadot 账户(32 字节格式) 在以太坊兼容的智能合约层中具有较为有限的交互能力。对于使用 Polkadot Hub 智能合约的开发者而言,理解这些限制以及何时需要进行账户映射至关重要。
未映射账户的限制
使用 Ed25519 / Sr25519 密钥对创建的账户,若未映射,将存在以下问题:
- 无法通过 MetaMask 等以太坊钱包发起交易
- 无法使用 Ethereum RPC 调用合约
- 无法与 20 字节地址直接转账
- 与 EVM 工具生态兼容性有限
系统可以在由 32 字节账户派生出的哈希化 20 字节地址上接收资金,但在尚未建立正式映射关系之前,原始账户的持有者无法通过以太坊兼容方式对这些资金进行控制或访问。
何时需要账户映射
必须映射的场景
当你需要:
- 使用 MetaMask / Web3.js / Ethers.js
- 以 20 字节地址转账
- 将现有 Polkadot 账户接入 EVM 工具
- 实现双向地址兼容
则必须进行映射。
不需要映射的场景
当你:
• 仅使用 Substrate 原生接口
• 与非 EVM 层平行链交互
• 使用 secp256k1 密钥创建账户
则无需映射。
原生账户映射流程
如果你拥有一个使用 Polkadot / Substrate 密钥对(Ed25519 / Sr25519)创建的原生 Polkadot 账户(32 字节格式),而非以太坊兼容的密钥对(secp256k1),则需要对该账户进行映射,才能启用以太坊兼容能力。
要完成账户映射,请使用你的原始 Substrate 账户调用 pallet_revive 模块中的 map_account 外部交易(extrinsic)。该操作会创建一个有状态映射,使你的 32 字节账户能够与以太坊兼容的智能合约系统进行交互。
映射方法
调用 pallet_revive.map_account() 外部交易。
流程如下:
-
使用 Substrate 钱包发起调用
-
支付保证金(可退还)
-
完成映射确认
映射后能力
完成映射后,你可以:
• 在 20 字节地址间转账
• 使用 MetaMask 调用合约
• 保留 32 字节账户可逆性
• 同时访问两种格式地址的资产
映射必要性说明
未映射账户无法与 Hub 的 EVM 层交互。
向未映射账户的派生地址转账,可能导致资产无法通过以太坊工具访问。
账户注册机制
映射过程由map函数实现,主要包括:
• 检查是否已映射
• 计算并收取保证金
• 存储地址后缀
• 管理资产锁定
回退账户机制(Fallback)
to_account_id 中集成了回退机制,用于保障转换安全性:
• 优先查询 OriginalAccount
• 若无记录则使用默认哈希转换
• 保持系统一致性
未映射账户的回退流程
当一个未映射的 32 字节 Polkadot 账户需要被表示为 20 字节以太坊地址时,系统会按照以下流程处理:
- 检查是否存在显式映射:
首先查询 OriginalAccount 存储,确认该账户是否已通过 map_account 进行了显式映射。
- 应用回退转换机制:
如果不存在映射关系,系统会自动将 32 字节账户转换为 20 字节地址,具体方式为:
- 使用 Keccak-256 对完整的 32 字节账户进行哈希计算;
- 取哈希结果的后 20 个字节作为以太坊地址。
使用派生地址:
该回退生成的地址可以接收资金,但在未进行显式映射之前,账户所有者无法通过以太坊兼容接口支配或使用这些资金。
⚠️ 注意:
• 回退地址不可逆
• 无映射无法恢复原账户
• 资金需映射后才能通过 EVM 使用
• 建议尽早建立显式映射
合约地址生成方式
系统支持两种部署方式:
CREATE1
• 基于部署者地址和 nonce
• 生成确定性地址
CREATE2
• 基于部署者、初始化代码、salt 等
• 支持预测地址
安全性设计
地址映射系统通过以下设计保障安全:
• 无状态映射无需特权操作
• 有状态映射受保证金约束
• 显式校验防止错误
• 防止重复映射
• 使用 ensure!(!Self::is_mapped(account_id)) 保护
原文链接:https://docs.polkadot.com/smart-contracts/for-eth-devs/accounts/