ERC-2304: 用于 ENS 的多链地址解析
Authors | Nick Johnson <nick@ens.domains> |
---|---|
Created | 2019-09-09 |
Discussion Link | https://discuss.ens.domains/t/new-standard-proposal-ens-multicoin-support/1148 |
Requires | EIP-137 |
摘要
本 EIP 为 ENS 解析器引入了 addr
字段的新重载,允许通过 ENS 解析其他区块链的地址。
动机
随着多币种钱包越来越多地采用 ENS,钱包作者要求能够在 ENS 内部解析非以太坊链的地址。本规范标准化了一种以跨客户端方式输入和检索这些地址的方法。
规范
指定了解析器的新访问器函数:
function addr(bytes32 node, uint coinType) external view returns(bytes memory);
此函数的 EIP165 接口 ID 为 0xf1cb7e06。
当在解析器上调用时,此函数必须返回指定名称哈希和币种类型的加密货币地址。如果指定节点上不存在指定的币种 ID,则必须返回零长度字符串。
coinType
是来自 SLIP44 的加密货币币种类型索引。
返回值是加密货币地址的本机二进制格式。下面地址编码部分提供了几个流行链的二进制编码的详细描述。
定义了解析器的新事件:
event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
解析器必须在每次更改名称和币种类型的地址时发出此事件。
推荐的访问器函数
以下函数提供了更改为节点存储的地址的推荐接口。解析器应该实现此接口来设置地址,除非它们的需求需要不同的接口。
function setAddr(bytes32 node, uint coinType, bytes calldata addr);
setAddr
添加或替换给定节点和币种类型的地址。此函数的参数与上面 addr()
中描述的参数相同。
此函数发出带有新地址的 AddressChanged
事件;另请参阅下面的向后兼容性部分,了解也支持 addr(bytes32)
的解析器。
地址编码
一般来说,应该使用地址的本机二进制表示形式,没有任何文本表示形式中常用的校验和。
提供了一个常见区块链的编码表,然后是每个格式的更详细描述。在该表中,“encodings”列出了该链支持的地址编码,以及任何相关参数。这些地址编码的详细信息在以下部分中描述。
加密货币 | 币种类型 | 编码 |
---|---|---|
Bitcoin | 0 | P2PKH(0x00), P2SH(0x05), SegWit(‘bc’) |
Litecoin | 2 | P2PKH(0x30), P2SH(0x32), P2SH(0x05), SegWit(‘ltc’) |
Dogecoin | 3 | P2PKH(0x1e), P2SH(0x16) |
Monacoin | 22 | P2PKH(0x32), P2SH(0x05) |
Ethereum | 60 | ChecksummedHex |
Ethereum Classic | 61 | ChecksummedHex |
Rootstock | 137 | ChecksummedHex(30) |
Ripple | 144 | Ripple |
Bitcoin Cash | 145 | P2PKH(0x00), P2SH(0x05), CashAddr |
Binance | 714 | Bech32(‘bnb’) |
P2PKH(version)
Pay to Public Key Hash 地址是 base58check 编码的。解码后,第一个字节是版本字节。例如,比特币地址 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa
base58check 解码为 21 个字节 0062e907b15cbf27d5425399ebf6f0fb50ebb88f18
。
P2PKH 地址具有一个版本字节,后跟一个 20 字节的 pubkey 哈希。它们的规范编码是它们的 scriptPubkey 编码(此处 指定)是 OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
。
因此,上面的示例地址编码为 25 个字节 76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac
。
P2SH(version)
P2SH 地址以与 P2PKH 地址相同的方式进行 base58check 编码。
P2SH 地址具有一个版本,后跟一个 20 字节的脚本哈希。它们的 scriptPubkey 编码(此处 指定)是 OP_HASH160 <scriptHash> OP_EQUAL
。比特币地址 3Ai1JZ8pdJb2ksieUV8FsxSNVJCpoPi8W6
解码为 21 个字节 0562e907b15cbf27d5425399ebf6f0fb50ebb88f18
,并编码为 23 个字节 a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1887
。
SegWit(hrp)
SegWit 地址使用 bech32 进行编码。 Bech32 地址由 human-readable 部分(比特币主网的“bc”)和 machine-readable 部分组成。对于 SegWit 地址,这会解码为 0 到 15 之间的“witness version”和一个“witness program”,如 BIP141 中所定义。
bech32 地址的 scriptPubkey 编码(如 BIP141 中所定义)是 OP_n
,其中 n
是 witness version,后跟 witness program 的推送。请注意来自 BIP173 的此警告:
在将地址转换为 scriptPubkey 时,实现应特别小心,其中 witness version n 存储为 OP_n。 OP_0 编码为 0x00,但 OP_1 到 OP_16 编码为 0x51 到 0x60(十进制为 81 到 96)。如果将 bech32 地址转换为不正确的 scriptPubKey,则结果很可能无法支出或不安全。
例如,比特币 SegWit 地址 BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4
解码为版本 0
和 witness 脚本 751e76e8199196d454941c45d1b3a323f1433bd6
,然后编码为 scriptPubkey 0014751e76e8199196d454941c45d1b3a323f1433bd6
。
ChecksummedHex(chainId?)
要将文本格式的校验和十六进制地址转换为二进制格式,只需删除“0x”前缀并进行十六进制解码。 0x314159265dD8dbb310642f98f50C066173C1259b
被十六进制解码并存储为 20 个字节 314159265dd8dbb310642f98f50c066173c1259b
。
校验和格式由 EIP-55 指定,并由 RSKIP60 扩展,后者指定了一种在校验和中包含链 ID 的方法。必须检查文本格式地址上的校验和。具有无效校验和且并非全部大写或全部小写的地址必须被拒绝并出现错误。实现可以选择是否接受非校验和地址,但作者建议至少在这种情况下向用户发出警告。
当将地址从二进制编码为文本时,必须使用 EIP55/RSKIP60 校验和 - 因此,上述地址对于以太坊的正确编码为 0x314159265dD8dbb310642f98f50C066173C1259b
。
Ripple
Ripple 地址使用具有替代字母表的 base58check 版本进行编码,此处 进行了描述。支持两种类型的 ripple 地址,“r-addresses”和“X-addresss”。 r-addresses 由一个版本字节后跟一个 20 字节的哈希组成,而 X-addresses 由一个版本字节、一个 20 字节的哈希和一个标签组成,此处指定。
两种地址类型都应通过执行 ripple 版本的 base58check 解码并直接存储它们(包括版本字节)来存储在 ENS 中。例如,ripple 地址 rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn
解码为并存储为 004b4e9c06f24296074f7bc48f92a97916c6dc5ea9
,而地址 X7qvLs7gSnNoKvZzNWUT2e8st17QPY64PPe7zriLNuJszeg
解码为并存储为 05444b4e9c06f24296074f7bc48f92a97916c6dc5ea9000000000000000000
。
CashAddr
Bitcoin Cash 定义了一种称为“CashAddr”的新地址格式,此处 进行了指定。这使用 bech32 编码的变体来编码和解码(非 segwit)Bitcoin Cash 地址,使用前缀“bitcoincash:”。应使用此 bech32 变体解码 CashAddr,然后根据其类型(P2PKH 或 P2SH)进行转换和存储,如上面相关部分中所述。
Bech32
Bech32 地址由 human-readable 部分(例如,Binance 的“bnb”)和 machine-readable 部分组成。编码数据只是地址,可以将其转换为二进制并直接存储。
例如,BNB 地址 bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2
解码为二进制表示形式 40c2979694bbc961023d1d27be6fc4d21a9febe6
,该表示形式直接存储在 ENS 中。
示例
此处提供了支持此 EIP 的解析器的示例实现:
pragma solidity ^0.5.8;
contract AddrResolver is ResolverBase {
bytes4 constant private ADDR_INTERFACE_ID = 0x3b3b57de;
bytes4 constant private ADDRESS_INTERFACE_ID = 0xf1cb7e06;
uint constant private COIN_TYPE_ETH = 60;
event AddrChanged(bytes32 indexed node, address a);
event AddressChanged(bytes32 indexed node, uint coinType, bytes newAddress);
mapping(bytes32=>mapping(uint=>bytes)) _addresses;
/**
* Sets the address associated with an ENS node.
* May only be called by the owner of that node in the ENS registry.
* @param node The node to update.
* @param a The address to set.
*/
function setAddr(bytes32 node, address a) external authorised(node) {
setAddr(node, COIN_TYPE_ETH, addressToBytes(a));
}
/**
* Returns the address associated with an ENS node.
* @param node The ENS node to query.
* @return The associated address.
*/
function addr(bytes32 node) public view returns (address) {
bytes memory a = addr(node, COIN_TYPE_ETH);
if(a.length == 0) {
return address(0);
}
return bytesToAddress(a);
}
function setAddr(bytes32 node, uint coinType, bytes memory a) public authorised(node) {
emit AddressChanged(node, coinType, a);
if(coinType == COIN_TYPE_ETH) {
emit AddrChanged(node, bytesToAddress(a));
}
_addresses[node][coinType] = a;
}
function addr(bytes32 node, uint coinType) public view returns(bytes memory) {
return _addresses[node][coinType];
}
function supportsInterface(bytes4 interfaceID) public pure returns(bool) {
return interfaceID == ADDR_INTERFACE_ID || interfaceID == ADDRESS_INTERFACE_ID || super.supportsInterface(interfaceID);
}
}
实现
此接口的实现在 ensdomains/resolvers 存储库中提供。
向后兼容性
如果解析器支持 EIP137 中定义的 addr(bytes32)
接口,则解析器必须将此视为此新规范的一个特例,具体如下:
- 从 EIP137 中的
addr(node)
返回的值应始终与从addr(node, 60)
返回的值匹配(60 是以太坊的币种类型 ID)。 - 导致发出 EIP137 中的
AddrChanged
事件的任何操作也必须从此 EIP 发出AddressChanged
事件,其中coinType
指定为 60,反之亦然。
测试
下表指定了上述每种加密货币的有效地址编码的测试向量。
加密货币 | 币种类型 | 文本 | 链上 (hex) |
---|---|---|---|
Bitcoin | 0 | 1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa |
76a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1888ac |
3Ai1JZ8pdJb2ksieUV8FsxSNVJCpoPi8W6 |
a91462e907b15cbf27d5425399ebf6f0fb50ebb88f1887 |
||
BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4 |
0014751e76e8199196d454941c45d1b3a323f1433bd6 |
||
Litecoin | 2 | LaMT348PWRnrqeeWArpwQPbuanpXDZGEUz |
76a914a5f4d12ce3685781b227c1f39548ddef429e978388ac |
MQMcJhpWHYVeQArcZR3sBgyPZxxRtnH441 |
a914b48297bff5dadecc5f36145cec6a5f20d57c8f9b87 |
||
ltc1qdp7p2rpx4a2f80h7a4crvppczgg4egmv5c78w8 |
0014687c150c26af5493befeed7036043812115ca36c |
||
Dogecoin | 3 | DBXu2kgc3xtvCUWFcxFE3r9hEYgmuaaCyD |
76a9144620b70031f0e9437e374a2100934fba4911046088ac |
AF8ekvSf6eiSBRspJjnfzK6d1EM6pnPq3G |
a914f8f5d99a9fc21aa676e74d15e7b8134557615bda87 |
||
Monacoin | 22 | MHxgS2XMXjeJ4if2PRRbWYcdwZPWfdwaDT |
76a9146e5bb7226a337fe8307b4192ae5c3fab9fa9edf588ac |
Ethereum | 60 | 0x314159265dD8dbb310642f98f50C066173C1259b |
314159265dd8dbb310642f98f50c066173c1259b |
Ethereum Classic | 61 | 0x314159265dD8dbb310642f98f50C066173C1259b |
314159265dd8dbb310642f98f50c066173c1259b |
Rootstock | 137 | 0x5aaEB6053f3e94c9b9a09f33669435E7ef1bEAeD |
5aaeb6053f3e94c9b9a09f33669435e7ef1beaed |
Ripple | 144 | rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn |
004b4e9c06f24296074f7bc48f92a97916c6dc5ea9 |
X7qvLs7gSnNoKvZzNWUT2e8st17QPY64PPe7zriLNuJszeg |
05444b4e9c06f24296074f7bc48f92a97916c6dc5ea9000000000000000000 |
||
Bitcoin Cash | 145 | 1BpEi6DfDAUFd7GtittLSdBeYJvcoaVggu |
76a91476a04053bda0a88bda5177b86a15c3b29f55987388ac |
bitcoincash:qpm2qsznhks23z7629mms6s4cwef74vcwvy22gdx6a |
76a91476a04053bda0a88bda5177b86a15c3b29f55987388ac |
||
3CWFddi6m4ndiGyKqzYvsFYagqDLPVMTzC |
a91476a04053bda0a88bda5177b86a15c3b29f55987387 |
||
bitcoincash:ppm2qsznhks23z7629mms6s4cwef74vcwvn0h829pq |
a91476a04053bda0a88bda5177b86a15c3b29f55987387 |
||
Binance | 714 | bnb1grpf0955h0ykzq3ar5nmum7y6gdfl6lxfn46h2 |
40c2979694bbc961023d1d27be6fc4d21a9febe6 |
版权
Copyright and related rights waived via CC0.
Citation
Please cite this document as:
Nick Johnson <nick@ens.domains>, "ERC-2304: 用于 ENS 的多链地址解析 [DRAFT]," Ethereum Improvement Proposals, no. 2304, September 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2304.