Alert Source Discuss
⚠️ Draft Standards Track: ERC

ERC-7831: 多链寻址

地址和链的文本表示。

Authors Sam Wilson (@SamWilsn) <sam@binarycake.ca>
Created 2024-08-30
Discussion Link https://ethereum-magicians.org/t/erc-7831-multi-chain-addressing/21942
Requires EIP-55, EIP-137, EIP-155, EIP-165, EIP-2304

摘要

本提案引入了一种链特定的地址格式,允许指定一个账户以及该账户打算在其上进行交易的链。这些链特定的地址采用 (example.eth:optimism)6A10161835a36302BfD39bDA9B44f5734442234e:ethereum:11155111 等形式。目标链使用存储在 ENS 上的注册表来解析。

动机

以太坊生态系统正变得越来越分散。这意味着一个 20 字节的地址本身不足以完全指定一个账户。如果资金被发送到错误链上无法访问的地址,这可能会出现问题。

与其使用不易于人阅读的链标识符,不如使用易于人阅读的链名称扩展地址,然后可以将其解析为链标识符。EIP-155 以来,从链名称到标识符的映射一直使用中心化列表在链下维护。此解决方案有两个主要缺点:

  • 它无法随着 L2 数量的增长而扩展。
  • 列表维护者是受信任的中心化实体。

本 ERC 提议使用 ENS 将链名称映射到标识符,同时通过更改根链来保持最大的灵活性。

为什么不使用带有 ERC-2304 的 ENS?

虽然 ERC-2304 允许注册者指定每个链的地址,但它不提供接收资产的默认链(也不应该提供。)接收链的选择过多地依赖于链下因素,因此不需要通过交易来更改。

规范

本文档中的关键词“必须 (MUST)”、“禁止 (MUST NOT)”、“必需 (REQUIRED)”、“应该 (SHALL)”、“不应 (SHALL NOT)”、“应 (SHOULD)”、“不应 (SHOULD NOT)”、“推荐 (RECOMMENDED)”、“不推荐 (NOT RECOMMENDED)”、“可以 (MAY)”和“可选 (OPTIONAL)”应按照 RFC 2119RFC 8174 中的描述进行解释。

本提案中的语法片段以增强巴科斯范式 (ABNF) 给出,如 RFC 5234RFC 7405 中所定义。

定义

以下术语在本提案中使用:

  • agent - 负责将链特定地址解析为其精确账户和链条的软件/工具。
  • bridge - 将根链连接到目标链的合约(例如,用于转移代币、代理函数调用。)
  • root chain - 包含 bridge 和名称解析器合约的区块链。
  • target chain - 被识别账户打算在其上进行交易的区块链;可以是根链上具有 bridge 的任何链。

语法

从高层次上讲,链特定地址由三个组件组成,这些组件由冒号 (:) 分隔,从最右边的最通用到最左边的最具体排列:

  • 一个 local-part,用于标识目标链上的账户;
  • 一个 chain-part,用于标识目标链;和
  • 可选地,一个 root-part,用于标识根链。

这些组件可以用括号 (()) 括起来,以消除解析歧义。

更正式地说,有效的链特定地址必须符合以下语法:

address         = OPEN bare-address CLOSE /
                  bare-address

bare-address    = local-part SEP chain-part [SEP root-part]

OPEN            = '('
CLOSE           = ')'
SEP            = ':'

Local Part

local-part 是链特定地址中最具体的部分。它标识目标链上的账户。它可以是十六进制字符串 (hex-address) 或类似 ENS 的名称 (ens-like)。

有效的 local-part 片段必须匹配以下语法:

local-part      = hex-address /
                  ens-like
十六进制地址

local-part 是十六进制字符串时,它必须包括校验和字母大小写(参见 校验和),并且可以省略前导零。它不得包含前导 0x 前缀。

请注意,local-part 可以编码比 20 字节(40 个十六进制数字)更长或更短的地址。实现必须支持 1 个十六进制数字到 40 个数字的 local-part 长度。实现应该支持任意大小(在合理限制内)的 local-part 组件。

形式上,hex-address 必须匹配以下语法:

hex-address     = 1*HEXDIG
类似 ENS 的名称

为了区分 ENS 名称和十六进制字符串,与标准 ENS 名称不同,在链特定地址的 local-part 中使用的名称必须至少包含一个点 (.)。如果存在,则在解析名称之前应删除放置在最右侧位置的点(例如 eth.example.eth.)。除非不存在其他点,否则链特定地址不应在最右侧位置包含点。

以下语法仅用于说明。有关 ENS 名称的定义,请参见 ERC-137

; 粗略的 ENS 名称近似值,附加要求是它
; 至少包含一个“.”
ens-like        = 1*NOTSEP DOT *(1*NOTSEP [DOT])

NOTSEP          = %x01-39 / %x3b-ff

Chain Part

chain-part 标识目标链。它必须是 ERC-137 中定义的有效 ENS 名称。

以下语法仅用于说明。有关 ENS 名称的定义,请参见 ERC-137

chain-part      = ens-name

; ENS 名称的粗略近似值,没有其他要求
ens-name        = 1*NOTSEP

Root Part

root-part 标识针对其解析其他名称的根链。如果存在,root-part 应该是根链的 EIP-155 chainid,采用十进制格式。当 chainid == 1 时,不应存在 root-part,当 chainid != 1 时,必须存在 root-part

root-part = 1*DIGIT

解析

解析链特定地址从右侧开始,然后向左移动。

根链

如果不存在 root-part,则假定为 1。将根的 chainid 设置为 root-part 的值。代理必须能够针对此链解析 ENS 名称。这可能意味着它具有 RPC 访问权限和已知的 ENS 解析器地址,但是任何解析地址的方法都足够了。

请注意,这使得 example.eth:optimismexample.eth:optimism:10 不同。在前一种情况下,example.ethoptimism 都是使用部署在主网上的 ENS 解析的。在第二种情况下,这两个名称将针对部署在 Optimism 链上的 ENS 进行解析,这是一种不寻常的情况。

链标识符的分配在 EIP-155 中定义。

目标链

接下来,通过将 chain-part 的值与 .tbd.eth 连接起来,构造目标链的 ENS 名称(例如,example.eth:foobar 的目标链为 foobar.tbd.eth)。针对根链上的 ENS 部署解析目标链的地址(即使用 ERC-137addr)。此地址上的合约是“bridge 合约”。

代理必须验证 bridge 合约是否支持地址中的 chain-part。首先,代理必须使用 ChainMetadata 的接口标识符(参见 Bridge 接口)在 bridge 合约上调用 ERC-165supportsInterface,如果它返回 false,则代理应中止解析。接下来,代理必须使用与上述调用 addr 相同的名称哈希(参见 ERC-137)调用 bridge 合约的 acceptsName 函数。如果 acceptsName 返回 false,则代理应中止解析。

bridge 合约应提供使代理能够与目标链交互的功能/元数据。此外,它应支持用于接口发现的 ERC-165 机制,并且可以支持其他方法来完成相同的操作。Bridge 合约必须实现 ChainMetadata(参见 Bridge 接口)。有关桥接的更多细节留待以后的提案。

本地地址

十六进制

验证校验和(请参见 校验和)。

本地地址是目标链原生地址的二进制表示形式的十六进制编码。例如,对于原生以太坊地址 0x6A10161835a36302BfD39bDA9B44f5734442234e,本地地址将为 6A10161835a36302BfD39bDA9B44f5734442234e

类似 ENS

如果本地地址以点 (.) 结尾,请将其删除。使用 ERC-2304addr 针对根链上的 ENS 部署解析地址,其中 coinType 派生自目标链的 chainid(从 bridge 合约中检索)。

Bridge 接口

Bridge 合约必须实现以下接口:

interface ChainMetadata {
    function chainId() external view returns (uint64);
    function coinType() external view returns (uint256);
    function acceptsName(bytes32 keccak) external view returns (bool);
}

当使用 ERC-165supportsInterface 查询时,bridge 合约必须为 0x00000000 返回 true。

校验和

十六进制字符串根据略作修改的 ERC-55 算法区分大小写。该算法通过包装 nibble_index 以适合 keccak 哈希来修改。

修改后的 ERC-55 算法的 Python 实现 ```python from Crypto.Hash import keccak # from pycryptodome def checksum_encode(addr): hex_addr = addr.hex() checksummed_buffer = "" # Treat the hex address as ascii/utf-8 for keccak256 hashing # 将十六进制地址视为 ascii/utf-8 以进行 keccak256 哈希 k = keccak.new(digest_bits=256) k.update(hex_addr.encode("utf-8")) hashed_address = k.hexdigest() # Iterate over each character in the hex address # 迭代十六进制地址中的每个字符 for nibble_index, character in enumerate(hex_addr): if character in "0123456789": # We can't upper-case the decimal digits # 我们不能将十进制数字大写 checksummed_buffer += character elif character in "abcdef": # Check if the corresponding hex digit (nibble) in the hash is 8 or higher # 检查哈希中相应的十六进制数字(半字节)是否为 8 或更高 nibble_index_wrapped = nibble_index % len(hashed_address) hashed_address_nibble = int(hashed_address[nibble_index_wrapped], 16) if hashed_address_nibble > 7: checksummed_buffer += character.upper() else: checksummed_buffer += character else: raise Exception( f"Unrecognized hex character {character!r} at position {nibble_index}" ) return "0x" + checksummed_buffer def test(addr_str: str): padded_addr_str = addr_str.removeprefix("0x") if len(padded_addr_str) % 2 == 1: # Pad to an even number of nibbles. # 填充为偶数个半字节。 padded_addr_str = "0" + padded_addr_str addr_bytes = bytes.fromhex(padded_addr_str) checksum_encoded = checksum_encode(addr_bytes) if checksum_encoded != addr_str: print(f"{checksum_encoded} != expected {addr_str}") test("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed") test("0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359") test("0xdbF03B407c01E7cD3CBea99509d93f8DDDC8C6FB") test("0xD1220A0cf47c7B9Be7A2E6BA89F429762e7b9aDb") test("0x004f67dAbb603AAA58eD52641CCafF09C559704A") test("0x4F67dABB603aAa58Ed52641cCAff09C559704A") test( "0x" "5aaeB6053f3e94c9B9a09f33669435E7" "ef1BEaED5AaEB6053f3e94C9B9a09F33" "669435e7ef1bEAed5aaEb6053f3e94C9" "b9a09f33669435E7ef1beAED5aaEB605" "3f3e94c9b9a09F33669435e7ef1beAED" ) ```

例如,以下字符串的大小写正确:

  • 004f67dAbb603AAA58eD52641CCafF09C559704A
  • 04f67dAbb603AAA58eD52641CCafF09C559704A
  • 4F67dABB603aAa58Ed52641cCAff09C559704A

理由

组件顺序

组件的排序方式是从最具体到最概括,因为…

分隔符选择

冒号 (:) 是分隔符的合理选择,因为它不是 ENS 名称中允许的字符,并且很熟悉(例如,IPv6),并且不如 @ 符号那样重载。

替代方案:@

@ 符号是地址的常见选择,并在电子邮件和多种联合通信协议中使用。英语阅读(foo-AT-example-DOT-com)很自然,并暗示了左侧和右侧组件之间的层次结构。

不幸的是,由于 @ 符号被广泛使用,因此将其包含在链特定地址中会使所有这些协议标识符更加混乱(甚至无效)。例如,foo@foo.eth@ethereum 不是有效的电子邮件地址。

替代方案:/

作为子域的目标链

虽然在技术上可以将 chain-part 解析为根 ENS 名称(例如,ethereum.eth 而不是 ethereum.tbd.eth),但是使用子域允许预先注册众所周知的链名称,以便在切换到开放注册之前进行名称的初始分发。

如果没有这种预注册,攻击者可以在合法项目之前注册众所周知的名称。

在预注册期之后,开放注册是可以接受的,因为新链可以在公开宣布之前注册其名称。

向后兼容性

始终可以确定特定字符串是链特定地址、普通地址还是普通 ENS 名称。由于此属性,向后不兼容的机会很少:链特定地址不是有效的遗留地址或 ENS 名称,因此不支持它们的工具将直接拒绝它们。

测试用例

ENS 配置

主网 (1)

名字 代币类型 记录
ethereum.tbd.eth - 到主网的 bridge 合约 (1)
rollup1.tbd.eth - 到汇总 1 的 bridge 合约 (1608)
example.eth 2147483649 0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa
example.eth 2147485256 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB

Sepolia (11155111)

名字 代币类型 记录
ethereum.tbd.eth - 到 sepolia 的 bridge 合约 (11155111)
example.eth

输入和预期输出

有效

输入 目标链 本地地址
(example.eth:ethereum) 主网 (1) 0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa
example.eth:rollup1 汇总 1 (1608) 0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB
example.eth.:ethereum 主网 (1) 0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa
0:ethereum 主网 (1) 0x0000000000000000000000000000000000000000

无效

输入 失败原因
(0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa:ethereum) 无效的十六进制
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:ethereum) 无效校验和
(AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA:ethereum) 无效校验和
(eth:ethereum) 无效的十六进制
(:ethereum) 缺少 local-part

参考实现

安全考虑

Unicode 和域名抢注攻击

攻击者可以注册类似于众所周知的链名称的 ENS 名称。例如,etheriumehtereum 相当接近 ethereum。虽然许多 Unicode 同形字被 ENS 库捕获,但代理仍然应该意识到它们构成的风险。

版权

版权和相关权利已通过 CC0 放弃。

Citation

Please cite this document as:

Sam Wilson (@SamWilsn) <sam@binarycake.ca>, "ERC-7831: 多链寻址 [DRAFT]," Ethereum Improvement Proposals, no. 7831, August 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7831.