Alert Source Discuss
⚠️ Review Standards Track: ERC

ERC-6734: L2 代币列表

代币列表,确保正确识别来自不同Layer 1、Layer 2或侧链的代币。

Authors Kelvin Fichter (@smartcontracts), Andreas Freund (@Therecanbeonlyone1969), Pavel Sinelnikov (@psinelnikov)
Created 2023-03-20
Requires EIP-155

摘要

本文档描述了一个 JSON 代币列表,用于确保两个或多个 Layer 1、Layer 2 或侧链可以识别来自不同 Layer 1、Layer 2 或侧链的代币。

动机

这项由 OASIS 管理的 EEA Communities Projects 的 L2 WG 开展的特定工作,一个开源倡议,其动机是围绕 Layer 1 (L1)、Layer 2 (L2) 和侧链系统上代币的定义和列表存在重大挑战。请注意,为简单起见,本文档将 L1、L2 和侧链系统统称为链,因为下面描述的挑战在所有此类系统中都有效:

  • 关于链 B 上与链 A 上的某些代币相对应的“规范”代币的共识。当一个人想要将代币 X 从链 A 桥接到链 B 时,必须在链 B 上创建该代币的一些新表示。值得注意的是,这个问题不仅限于 L2——每个通过桥连接的链都必须处理同样的问题。

与上述挑战相关的是关于桥列表及其跨不同链的路由的标准化。这将在单独的文档中讨论。

请注意,这两个问题对于当前的多链世界来说都是根本性问题。

因此,本文档的目标是帮助代币用户在其系统中操作和消除代币使用中的歧义。

对于规范代币列表,L2 当前维护他们自己的自定义版本的 Uniswap 代币列表。例如,Arbitrum 维护一个带有各种自定义扩展的代币列表。Optimism 也维护一个自定义代币列表,但带有不同的扩展。应该注意的是,这两个自定义扩展都指的是这些代币可以通过的桥。但是,这些不是代币可以通过的唯一桥,这意味着桥和代币列表应该分开。另请注意,目前,Optimism 和 Arbitrum 都将“规范性”基于代币名称 + 符号对。

下面给出了 Arbitrum 代币条目的一个例子:

{
logoURI: "https://assets.coingecko.com/coins/images/13469/thumb/1inch-token.png?1608803028",
chainId: 42161,
address: "0x6314C31A7a1652cE482cffe247E9CB7c3f4BB9aF",
name: "1INCH Token",
symbol: "1INCH",
decimals: 18,
extensions: {
  bridgeInfo: {
    1: {
    tokenAddress: "0x111111111117dc0aa78b770fa6a738034120c302",
    originBridgeAddress: "0x09e9222e96e7b4ae2a407b98d48e330053351eee",
    destBridgeAddress: "0xa3A7B6F88361F48403514059F1F16C8E78d60EeC"
     }
   }
  }
}

该标准将建立在当前框架的基础上,并使用来自 Decentralized Identifiers (DIDs) 的概念对其进行增强,这些概念基于 JSON 链接数据模型 JSON-LD,例如可解析的唯一资源标识符 (URI) 和 JSON-LD 模式,这使得使用现有工具可以更轻松地进行模式验证。

请注意,定义代币的标准不在本文档的范围内。

规范

关键词:

当且仅当本文档中以全部大写形式出现时,关键词“MUST(必须)”、“MUST NOT(禁止)”、“REQUIRED(必需)”、“SHALL(应)”、“SHALL NOT(不应)”、“SHOULD(应该)”、“SHOULD NOT(不应该)”、“RECOMMENDED(推荐)”、“NOT RECOMMENDED(不推荐)”、“MAY(可以)”和“OPTIONAL(可选)”应按照 [RFC2119] 中的描述进行解释。

印刷约定:需求 ID

需求由唯一 ID 唯一标识,该 ID 由其需求级别和需求编号组成,按照惯例 [RequirementLevelRequirementNumber]。 需求级别有四种,按照以下约定在需求 id 中编码:

[R] - 以字母 R 开头的 ID 的需求级别应解释为 MUST(必须),如 RFC2119 中所述。
[D] - 以字母 D 开头的 ID 的需求级别应解释为 SHOULD(应该),如 RFC2119 中所述。
[O] - 以字母 O 开头的 ID 的需求级别应解释为 MAY(可以),如 RFC2119 中所述。

请注意,需求在每个需求级别内按升序唯一编号。

示例:应理解为 [R1] 是规范的绝对要求,而 [D1] 是一个建议,[O1] 是真正可选的。

[R1] 以下数据元素必须存在于规范的代币列表中:

  • type
  • tokenListId
  • name
  • createdAt
  • updatedAt
  • versions
  • tokens

请注意, [R1] 中数据元素的详细定义以及描述和示例在下面的模式本身中给出。

[R1] 可测试性:请参阅下面数据模式的建议测试装置。

[R2] tokens 数据元素是一个复合元素,必须至少包含以下数据元素:

  • chainId
  • chainURI
  • tokenId
  • tokenType
  • address
  • name
  • symbol
  • decimals
  • createdAt
  • updatedAt

请注意, [R2] 中数据元素的详细定义以及描述和示例在下面的模式本身中给出。

[R2] 可测试性:请参阅下面此文档数据模式的建议测试装置。

[D1] 模式的所有其他数据元素都应该包含在规范代币列表的表示中。

[D1] 可测试性:请参阅下面此文档数据模式的建议测试装置。

[CR1]>[D1] 如果使用了扩展数据元素,则以下数据元素必须存在于模式表示中:

  • rootChainId
  • rootChainURI
  • rootAddress

请注意, [D1][CR1]>[D1] 中数据元素的详细定义以及描述和示例在下面的模式本身中给出。

[CR1]>[D1] 可测试性:请参阅下面此文档数据模式的建议测试装置。

[R3] 在描述中标识为通用资源标识符 (URI) 的模式中的所有属性必须遵循其语义 RFC 3986

[R3] 可测试性:RFC 3986 的所有要求都是可测试的。

[R4] 使用的 chainId 属性必须允许满足 EIP-155 标准的要求。

即,由 chainId 属性值标识的网络上的交易重放保护。请注意,为了保证重放保护,chainId 应该是唯一的。确保唯一的 chainId 不在本文档的范围内。

[R4] 可测试性:EIP-155 要求事务哈希派生自以下九个 RLP 编码元素 (nonce, gasprice, startgas, to, value, data, chainid, 0, 0) 的 keccak256 哈希,这可以使用现有的加密库轻松测试。EIP-155 进一步要求 secp256k1 签名的 v 值必须设置为 {0,1} + CHAIN_ID * 2 + 35,其中 {0,1} 是曲线点的 y 值的奇偶校验,其中签名 r 值为 secp256k1 签名过程中的 x 值。此要求可以使用可用的开源 secp256k1 数字签名套件进行测试。因此,[R4] 是可测试的。

[O1] 可以使用 humanReadableTokenSymbol 属性。

[O1] 可测试性:数据属性始终可以在模式中实现。

[CR2]>[O1] humanReadableTokenSymbol 属性必须构造为 tokenSymbolchainId 的带连字符的串联。

一个例子是:

"tokenSymbol" = ETH;
"chainId" = 1;
"humanReadableTokenSymbol" = ETH-1;

[CR2]>[O1] 可测试性:humanReadableTokenSymbol 可以使用现有的开源包进行解析和拆分,并将结果与数据模式中使用的 tokenSymbolchainId 进行比较。

规范代币列表的模式如下所示,如果使用 JSON-LD 上下文文件,则可以将其用作 JSON-LD 模式(有关标准上下文中的具体示例,请参阅 [W3C-DID]):

{
    "$id": "https://github.com/eea-oasis/l2/schemas/CanonicalTokenList.json",
    "$schema": "https://json-schema.org/draft-07/schema#",
    "$comment": "{\"term\": \"CanonicalTokenList\", \"@id\": \"https://github.com/eea-oasis/l2#CanonicalTokenList\"}",
    "title": "CanonicalTokenList",
    "description": "Canonical Token List",
    "type": "object",
    "required": [
        "type",
        "tokenListId",
        "name",
        "createdAt",
        "updatedAt",
        "versions",
        "tokens"
        ],
        "properties": {
            "@context": {
                "type": "array"
            },
            "type": {
                "oneOf": [
                    {
                        "type": "string"
                    },
                    {
                        "type": "array"
                    }
                ],
                "examples": ["CanonicalTokenList"]
            },
            "tokenListId": {
                "$comment": "{\"term\": \"tokenListId\", \"@id\": \"https://schema.org/identifier\"}",
                "title": "tokenListId",
                "description": "A resolvable URI to the publicly accessible place where this list can be found following the RFC 3986 standard.",
                "type": "string",
                "examples": ["https://ipfs.io/ipns/k51qzi5uqu5dkkciu33khkzbcmxtyhn376i1e83tya8kuy7z9euedzyr5nhoew"]
            },
            "name": {
                "$comment": "{\"term\": \"name\", \"@id\": \"https://schema.org/name\"}",
                "title": "name",
                "description": "Token List name",
                "type": "string",
                "examples": ["Aggregate Canonical Token List"]
            },
            "logoURI": {
                "$comment": "{\"term\": \"logoURI\", \"@id\": \"https://schema.org/identifier\"}",
                "title": "logoURI",
                "description": "URI or URL of the token list logo following the RFC 3986 standard",
                "type": "string",
                "examples": ["https://ipfs.io/ipns/k51qzi5uqu5dh5kbbff1ucw3ksphpy3vxx4en4dbtfh90pvw4mzd8nfm5r5fnl"]
            },
            "keywords": {
                "$comment": "{\"term\": \"keywords\", \"@id\": \"https://schema.org/DefinedTerm\"}",
                "title": "keywords",
                "description": "List of key words for the token list",
                "type": "array",
                "examples": [Aggregate Token List]
            },
            "createdAt": {
                "$comment": "{\"term\": \"createdAt\", \"@id\": \"https://schema.org/datePublished\"}",
                "title": "createdAt",
                "description": "Date and time token list was created",
                "type": "string",
                "examples": ["2022-05-08"]
            },
            "updatedAt": {
                "$comment": "{\"term\": \"updatedAt\", \"@id\": \"https://schema.org/dateModified\"}",
                "title": "updatedAt",
                "description": "Date and time token list was updated",
                "type": "string",
                 "examples": ["2022-05-09"]
            },
            "versions": {
                "$comment": "{\"term\": \"versions\", \"@id\": \"https://schema.org/version\"}",
                "title": "versions",
                "description": "Versions of the canonical token list",
                "type": "array",
                 "items": {
                    "type":"object",
                    "required":[
                        "major",
                        "minor",
                        "patch"
                    ],
                    "properties": {
                        "major": {
                            "$comment": "{\"term\": \"major\", \"@id\": \"https://schema.org/Number\"}",
                            "title": "major",
                            "description": "Major Version Number of the Token List",
                            "type": "integer",
                             "examples": [1]
                        },
                        "minor": {
                            "$comment": "{\"term\": \"minor\", \"@id\": \"https://schema.org/Number\"}",
                            "title": "minor",
                            "description": "Minor Version Number of the Token List",
                            "type": "integer",
                             "examples": [1]
                        },
                        "patch": {
                            "$comment": "{\"term\": \"patch\", \"@id\": \"https://schema.org/Number\"}",
                            "title": "patch",
                            "description": "Patch Number of the Token List",
                            "type": "integer",
                             "examples": [1]
                        },
                    }
                }
            },
            "tokens": {
                "title": "Listed Token Entry",
                "description": "Listed Token Entry",
                "type": "array",
                 "items": {
                    "type":"object",
                    "required": [
                        "chainId",
                        "chainURI",
                        "tokenId",
                        "tokenType",
                        "address",
                        "name",
                        "symbol",
                        "decimals",
                        "createdAt",
                        "updatedAt"
                    ],
                    "properties": {
                        "chainId": {
                            "$comment": "{\"term\": \"chainId\", \"@id\": \"https://schema.org/identifier\"}",
                            "title": "chainId",
                            "description": "The typically used number identifier for the chain on which the token was issued.",
                            "type": "number",
                            "examples": [137]
                        },
                        "chainURI": {
                            "$comment": "{\"term\": \"chainURI\", \"@id\": \"https://schema.org/identifier\"}",
                            "title": "chainURI",
                            "description": "A resolvable URI to the genesis block of the chain on which the token was issued following the RFC 3986 standard.",
                            "type": "string"
                             "examples": ["https://polygonscan.com/block/0"]
                        },
                        "genesisBlockHash": {
                            "$comment": "{\"term\": \"genesisBlockHash\", \"@id\": \"https://schema.org/sha256\"}",
                            "title": "genesisBlockHash",
                            "description": "The hash of the genesis block of the chain on which the token was issued.",
                            "type": "string",
                            "examples": ["0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b"]
                        },
                        "tokenIssuerId": {
                            "$comment": "{\"term\": \"tokenIssuerId\", \"@id\": \"https://schema.org/identifier\"}",
                            "title": "tokenIssuerId",
                            "description": "A resolvable URI identifying the token issuer following the RFC 3986 standard.",
                            "type": "string",
                            "examples": ["https://polygonscan.com/address/0xa9c28ce2141b56c474f1dc504bee9b01eb1bd7d1a507580d5519d4437a97de1b"]
                        },
                        "tokenIssuerName": {
                            "$comment": "{\"term\": \"tokenIssuerName\", \"@id\": \"https://schema.org/name\"}",
                            "title": "tokenIssuerName",
                            "description": "The name oof the token issuer.",
                            "type": "string"
                            "examples": ["Matic"]
                        },
                        "tokenId": {
                            "$comment": "{\"term\": \"tokenId\", \"@id\": \"https://schema.org/identifier\"}",
                            "title": "tokenId",
                            "description": "A resolvable URI of the token following the RFC 3986 standard to for example the deployment transaction of the token, or a DID identifying the token and its issuer.",
                            "type": "string",
                            "example": ["https://polygonscan.com/address/0x0000000000000000000000000000000000001010"]
                        },
                        "tokenType": {
                            "$comment": "{\"term\": \"tokenType\", \"@id\": \https://schema.org/StructuredValue\"}",
                            "title": "tokenType",
                            "description": "Describes the type of token.",
                            "type": "array"
                            "examples"[["fungible","transferable"]]
                        },
                        "tokenDesc": {
                            "$comment": "{\"term\": \"tokenDesc\", \"@id\": \"https://schema.org/description\"}",
                            "title": "tokenDesc",
                            "description": "Brief description of the token and its functionality.",
                            "type": "string",
                            "examples": ["Protocol Token for the Matic Network"]
                        },
                        "standard": {
                            "$comment": "{\"term\": \"standard\", \"@id\": \"https://schema.org/citation\"}",
                            "title": "standard",
                            "description": "A resolvable URI to the description of the token standard.",
                            "type": "string",
                            "examples": ["https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md"]
                        },
                        "address": {
                            "$comment": "{\"term\": \"address\", \"@id\": \"https://schema.org/identifier\"}",
                            "title": "address",
                            "description": "Address of the token smart contract.",
                            "type": "string",
                            "examples": ["0x0000000000000000000000000000000000001010"]
                        },
                        "addressType": {
                            "$comment": "{\"term\": \"address\", \"@id\": \"https://schema.org/Intangible\"}",
                            "title": "addressType",
                            "description": "AddressType of the token smart contract.",
                            "type": "string",
                            "examples": ["MaticNameSpace"]
                        },
                        "addressAlg": {
                            "$comment": "{\"term\": \"addressAlg\", \"@id\": \"https://schema.org/algorithm\"}",
                            "title": "addressAlg",
                            "description": "Algorithm used to create the address e.g. CREATE2 or the standard ethereum address construction which is the last 40 characters/20 bytes of the Keccak-256 hash of a secp256k1 public key.",
                            "type": "string",
                            "examples": ["CREATE2"]
                        },
                        "name": {
                            "$comment": "{\"term\": \"name\", \"@id\": \"https://schema.org/name\"}",
                            "title": "name",
                            "description": "Token name.",
                            "type": "string",
                            "examples": ["Matic"]
                        },
                        "symbol": {
                            "$comment": "{\"term\": \"symbol\", \"@id\": \"https://schema.org/currency\"}",
                            "title": "symbol",
                            "description": "Token symbol e.g. ETH.",
                            "type": "string",
                            "examples": ["MATIC"]
                        },
                        "humanReadableTokenSymbol": {
                            "$comment": "{\"term\": \"humanReadableTokenSymbol\", \"@id\": \"https://schema.org/currency\"}",
                            "title": "humanReadableTokenSymbol",
                            "description": "A Token symbol e.g. ETH, concatenated with the `chainId` the token was issued on or bridged to, e.g. ETH-1",
                            "type": "string",
                            "examples": ["MATIC-137"]
                        },
                        "decimals": {
                            "$comment": "{\"term\": \"decimals\", \"@id\": \"https://schema.org/Number\"}",
                            "title": "decimals",
                            "description": "Allowed number of decimals for the listed token. This property may be named differently by token standards e.g. granularity for ERC-777",
                            "type": "integer",
                            "examples": [18]
                        },
                        "logoURI": {
                            "$comment": "{\"term\": \"logoURI\", \"@id\": \"https://schema.org/identifier\"}",
                            "title": "logoURI",
                            "description": "URI or URL of the token logo following the RFC 3986 standard.",
                            "type": "string"
                            "examples": ["https://polygonscan.com/token/images/matic_32.png"]
                        },
                        "createdAt": {
                            "$comment": "{\"term\": \"createdAt\", \"@id\": \"https://schema.org/datePublished\"}",
                            "title": "createdAt",
                            "description": "Date and time token was created",
                            "type": "string",
                            "examples": ["2020-05-31"]
                        },
                        "updatedAt": {
                            "$comment": "{\"term\": \"updatedAt\", \"@id\": \"https://schema.org/dateModified\"}",
                            "title": "updatedAt",
                            "description": "Date and time token was updated",
                            "type": "string"
                            "examples": ["2020-05-31"]
                        },
                        "extensions": {
                            "title": "extensions",
                            "description": "Extension to the token list entry to specify an origin chain if the token entry refers to another chain other than the origin chain of the token",
                            "type": "array",
                            "items": {
                                "type":"object",
                                "required": [
                                    "rootChainId",
                                    "rootChainURI",
                                    "rootAddress",
                                ],
                                "properties": {
                                    "rootChainId": {
                                        "$comment": "{\"term\": \"rootChainId\", \"@id\": \"https://schema.org/identifier\"}",
                                        "title": "rootChainId",
                                        "description": "The typically used number identifier for the root chain on which the token was originally issued.",
                                        "type": "number",
                                        "examples": [137]
                                    },
                                    "rootChainURI": {
                                        "$comment": "{\"term\": \"rootChainURI\", \"@id\": \"https://schema.org/identifier\"}",
                                        "title": "rootChainURI",
                                        "description": "A resolvable URI to the genesis block of the root chain on which the token was originally issued following the RFC 3986 standard.",
                                        "type": "string",
                                        "examples": ["https://polygonscan.com/block/0"]
                                    },
                                    "rootAddress": {
                                        "$comment": "{\"term\": \"rootAddress\", \"@id\": \"https://schema.org/identifier\"}",
                                        "title": "rootAddress",
                                        "description": "Root address of the token smart contract.",
                                        "type": "string",
                                        "examples": ["0x0000000000000000000000000000000000001010"]
                                    }
                                }
                            }
                        }
                    }
                }
            }
        },
    "additionalProperties": false,
}

数据模式可测试性:由于上述数据模式遵循 JSON/JSON-LD 模式格式,并且由于已知此类格式可针对模式一致性进行测试(例如,请参阅 W3C CCG 可追溯性工作项),因此上述数据模式是可测试的。

一致性

本节描述了实现与本文档中的要求可证明一致所需的符合性条款和测试。

符合性目标

本文档尚未定义一组标准化的测试装置,其中包含所有 MUST、SHOULD 和 MAY 要求的测试输入,以及有条件 MUST 或 SHOULD 要求。

一组标准化的测试装置,其中包含所有 MUST、SHOULD 和 MAY 要求的测试输入,以及有条件 MUST 或 SHOULD 要求,计划与标准的下一个版本一起发布。

符合性级别

本节指定了此标准的符合性级别。符合性级别为实施者提供了几个级别的符合性。这些可以用于建立竞争差异化。

本文档将规范代币列表的符合性级别定义如下:

  • 级别 1: 通过测试报告证明,特定的实现满足所有 MUST 要求,该测试报告以易于理解的方式证明了该实现与每个要求的一致性,该一致性基于特定于实现的测试装置和特定于实现的测试装置输入。
  • 级别 2: 通过测试报告证明,特定的实现满足所有 MUST 和 SHOULD 要求,该测试报告以易于理解的方式证明了该实现与每个要求的一致性,该一致性基于特定于实现的测试装置和特定于实现的测试装置输入。
  • 级别 3: 通过测试报告证明,特定的实现满足所有 MUST、SHOULD 和 MAY 要求(具有有条件 MUST 或 SHOULD 要求),该测试报告以易于理解的方式证明了该实现与每个要求的一致性,该一致性基于特定于实现的测试装置和特定于实现的测试装置输入。

[D2] 声明规范代币列表实现符合此规范应描述为符合性所声明的每个要求执行的测试程序,该程序证明了关于该要求的声明是合理的。

[D2] 可测试性:由于本文档中每个非符合性目标要求都是可测试的,因此本文档中所有要求的总和也必须是可测试的。因此,可以存在所有要求的符合性测试,并且可以按照 [D2] 中的要求进行描述。

[R5] 声明规范代币列表实现在 级别 2 或更高级别符合此规范必须描述为每个 级别 2 或更高级别的要求执行的测试程序,该程序证明了对该要求的声明是合理的。

[R5] 可测试性:由于本文档中每个非符合性目标要求都是可测试的,因此本文档中所有要求的总和也必须是可测试的。因此,可以存在所有要求的符合性测试,并且可以按照 [R5] 中的要求进行描述、构建和实施,并且可以记录结果。

理由

本规范正在扩展和澄清当前的自定义列表,例如 动机 中引用的 Arbitrum 和 Optimism 中的列表,或 Uniswap 代币列表项目,以提高清晰度、安全性和鼓励非 Web3 原生实体的采用。

本规范正在利用当前的 JSON-LD 标准来描述代币列表,以便与自我主权身份框架(例如 W3C DID 和 W3C 可验证凭证标准)轻松集成,这些标准允许在识别代币列表相关实体(例如代币发行者)时跨 L2、侧链和 L1 实现互操作性。此外,与 W3C 使用的框架兼容允许实施者围绕 JSON-LD、W3C DID 和 W3C 可验证凭证使用现有的工具。从 schema.org 引用已知数据属性定义的选择进一步消除了术语的含义和用法的歧义。

安全考虑

除了警告说在此标准的实现中使用的 URI 可能会直接指向恶意资源(例如网站)之外,没有其他安全要求,并且实施者应确保用于规范代币列表的数据是安全且正确的。由于此标准侧重于数据模式及其数据属性,因此没有来自例如同形字攻击的其他安全考虑因素(请参阅 CVE-2021-42574 (2021-10-25T12:38:28))。

安全考虑:数据隐私

该标准未对遵守管辖区立法/法规提出任何要求。实施者有责任遵守适用的数据隐私法。

安全考虑:生产准备

该标准未对特定应用程序/工具/库等的使用提出任何要求。实施者在选择特定应用程序/工具/库时应进行尽职调查。

安全考虑:国际化和本地化

该标准鼓励实施者遵循 W3C“网络上的字符串:语言和方向元数据”最佳实践指南,以在适当的情况下识别网络上使用的字符串的语言和基本方向。

版权

版权及相关权利通过 CC0 放弃。

Citation

Please cite this document as:

Kelvin Fichter (@smartcontracts), Andreas Freund (@Therecanbeonlyone1969), Pavel Sinelnikov (@psinelnikov), "ERC-6734: L2 代币列表 [DRAFT]," Ethereum Improvement Proposals, no. 6734, March 2023. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-6734.