EVM链注册表:跨链生态的标准化数据枢纽
本项目是一个面向EVM(以太坊虚拟机)兼容区块链的标准化数据注册表,旨在为开发者、钱包和跨链桥提供可靠且统一的链配置信息。通过严格的验证流程和工具链,确保每条链的数据完整、符合规范,并防范潜在的安全风险(如重放攻击)。
功能特性
- 标准化链数据格式:遵循CAIP-2标准,每条链独立存储为JSON文件。
- 严格的验证机制:自动检查文件名与
chainId的一致性,并校验JSON Schema完整性。 - 安全优先:禁止删除链定义(仅可标记为
deprecated),防止历史链被移除导致的重放攻击风险。 - 图标与资源管理:通过IPFS存储链和浏览器的图标,限定大小与格式,确保资源可解析且轻量。
- 扩展支持:支持L2链或分片链关联父链,并可配置跨链桥信息。
- CI友好:提供本地验证脚本,可轻松集成至持续集成流程中。
安装指南
前置要求
- Node.js (v12或更高版本)
- npm 或 yarn
步骤
-
克隆项目仓库:
git clone https://github.com/ethereum-lists/chains.git cd chains -
安装依赖(用于本地验证工具):
npm install -
运行数据验证(确保修改符合规范):
node scripts/index.js # 移除过时的network字段(如需要) npm run validate # 执行完整的Schema与文件名检查
依赖项
ajv: JSON Schema验证器fs,path: Node.js内置文件系统模块
使用说明
添加或修改一条链
- 在
_data/chains/目录下,按照{namespace}-{reference}.json的格式命名文件(例如eip155-1.json)。 - 文件内容需符合以下模板:
{
"name": "Ethereum Mainnet",
"chain": "ETH",
"rpc": ["https://mainnet.infura.io/v3/${INFURA_API_KEY}"],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
"symbol": "ETH",
"decimals": 18
},
"features": [{ "name": "EIP155" }, { "name": "EIP1559" }],
"infoURL": "https://ethereum.org",
"shortName": "eth",
"chainId": 1,
"networkId": 1,
"icon": "ethereum",
"explorers": [
{
"name": "etherscan",
"url": "https://etherscan.io",
"icon": "etherscan",
"standard": "EIP3091"
}
]
}
- 如果链属于L2或分片,可添加
parent字段:
"parent": {
"type": "L2",
"chain": "eip155-1",
"bridges": [{ "url": "https://bridge.arbitrum.io" }]
}
添加图标
- 在
_data/icons/下创建与icon字段同名的JSON文件(例如ethereum.json)。 - 图标文件内容示例:
[
{
"url": "ipfs://QmdwQDr6vmBtXmK2TmknkEuZNoaDqTasFdZdu3DRw8b2wt",
"width": 1000,
"height": 1628,
"format": "png"
}
]
注意:图标URL必须可通过IPFS解析,且文件小于250KB。
验证数据完整性
使用提供的验证脚本检查所有链配置:
npm run validate
该脚本将:
- 检查文件名是否与文件内的
chainId匹配。 - 验证JSON Schema是否符合预定义规范。
- 输出错误列表并返回非零退出码(用于CI失败标记)。
核心代码
链数据清理工具 (index.js)
移除历史遗留的 network 字段,保持数据结构纯净。
const fs = require('fs');
const chainFiles = fs.readdirSync('../_data/chains/');
for (const chainFile of chainFiles) {
const fileLocation = `../_data/chains/${chainFile}`
const fileData = fs.readFileSync(fileLocation, 'utf8')
const fileDataJson = JSON.parse(fileData)
if (fileDataJson.network) {
delete fileDataJson.network
fs.writeFileSync(fileLocation, JSON.stringify(fileDataJson, null, 2))
}
}
验证脚本 (validate.js)
完整的链数据验证逻辑,包括文件名与chainId一致性、Schema校验。
const fs = require("fs")
const Ajv = require("ajv")
const ajv = new Ajv()
const schema = require("./schema/chainSchema.json")
const { exit } = require("process")
const path = require('path')
const resolve = (_path) => path.resolve(__dirname, _path)
const chainFiles = fs.readdirSync(resolve("../_data/chains/"))
const parseChainId = (chainId) =>
/^(?<namespace>[-a-z0-9]{3,8})-(?<reference>[-a-zA-Z0-9]{1,32})$/u.exec(
chainId
)
const filesWithErrors = []
for (const chainFile of chainFiles) {
const fileLocation = resolve(`../_data/chains/${chainFile}`)
const fileData = fs.readFileSync(fileLocation, "utf8")
const fileDataJson = JSON.parse(fileData)
const fileName = chainFile.split(".")[0]
const parsedChainId = parseChainId(fileName)?.groups
const chainIdFromFileName = parsedChainId?.reference
if (chainIdFromFileName != fileDataJson.chainId) {
throw new Error(`File Name does not match with ChainID in ${chainFile}`)
}
const valid = ajv.validate(schema, fileDataJson)
if (!valid) {
console.error(ajv.errors)
filesWithErrors.push(chainFile)
}
}
if (filesWithErrors.length > 0) {
filesWithErrors.forEach(file => {
console.error(`Invalid JSON Schema in ${file}`)
})
exit(-1);
}
else {
console.info("Schema check completed successfully");
exit(0);
}
GVT9NGsW4qUHR+TkzmCCGfUB9PP7a+z/fAZNhckVobk=