Alert Source Discuss
🚧 Stagnant Standards Track: ERC

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) 接口,则解析器必须将此视为此新规范的一个特例,具体如下:

  1. 从 EIP137 中的 addr(node) 返回的值应始终与从 addr(node, 60) 返回的值匹配(60 是以太坊的币种类型 ID)。
  2. 导致发出 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.