理解ERC1820标准

  • De7e
  • 更新于 2024-09-13 14:57
  • 阅读 866

下面要介绍的ERC1820是以太坊区块链世界中的"中心化注册表",任何人可以通过它查询哪些合约或EOA地址是否支持哪些接口,以更加确定性的方式去交互。

当然你也可以为一个地址注册接口,使别人也可以随时查询到你的合约或EOA地址是否支持指定的接口。

之前学习了下ERC165标准,理解ERC165标准,发现ERC标准是一环扣一环,怪是越打越多的。希望以本文记录一下ERC1820的一些细节和主要实现,不会具体分析合约方法。

【ERC1820总览】

下面要介绍的ERC1820是以太坊区块链世界中的"中心化注册表",任何人可以通过它查询哪些合约或EOA地址是否支持哪些接口,以更加确定性的方式去交互。

当然你也可以为一个地址注册接口,使别人也可以随时查询到你的合约或EOA地址是否支持指定的接口。

. ERC1820标准的功能主要为查询、和注册。

查询 查询一个指定的地址(可以是EOA,也可以是合约),是否实现了指定的接口(这里兼容ERC165接口)。

. 注册 注册可以达到三个效果,你可以选择如何注册。

  1. 为一个合约地址注册指定的已经实现的接口
  2. 为一个合约地址注册指定的已经实现的接口,但是可以注册为代理实现者(一个外部合约实现这个接口)。
  3. 为一个EOA地址,注册一个接口,并指定代理实现合约地址。

.

通过不同的身份理解ERC1820

ERC1820有三个身份,分别是 目标地址(target)管理者(manager)实现者(implementer),这三个身份分别有不同的作用。

目标地址(target)

1.默认要为哪个地址查询(或实现)接口 2.查询接口也是通过这个地址 + 要查的接口Hash 来进行查询

管理者(manager)

1.只有manager才能改变一个地址的接口

  1. 一个目标地址的默认manager是这个目标地址本身 3.manager可以设置修改一个新的manager

实现者(implementer)

1.默认是目标地址自身 2.当为EOA地址注册接口,或希望为合约代理实现接口,此时implementer就是那个代理实现合约。 3.在通过erc1820查询接口是否注册时,返回的就是implementer地址。

了解了这三个身份,就可以很好的理解ERC1820的设计。

【主要方法理解】

下面列出ERC1820的主要方法,并了解如何使用。

//【作用:查询一个目标地址是否实现了某个接口】
//1.未注册返回0地址,注册则返回 实现者(implementer)地址 
//2.接口Hash(_interfaceHash)的计算方法
//keccak256(abi.encodePacked(_interfaceName));

//3.这里参数_interfaceName 就是接口的字符串,比如"IERC20Token"
//4._interfaceHash也可以兼容传入erc165接口ID,但需要填充满bytes32(erc165接口ID是bytes4)
function getInterfaceImplementer(address _addr, bytes32 _interfaceHash) external view returns (address);

// 【作用:设置接口实现者】
//1._addr必须是msg.sender,所以这就意味着EOA地址的接口注册也需要这个EOA来完成。

//2.若是为自己实现接口,默认_addr和_implementer是同一个地址

//3.ERC1820中只能兼容查ERC165接口,但不能为ERC165注册。 所以_interfaceHash只能是ERC1820接口。

//4.为了方便多签,若把_addr传入0地址,则默认会把_addr设为msg.sender。这样多签可以复用同样的交易数据。
function setInterfaceImplementer(address _addr, bytes32 _interfaceHash, address _implementer) external;

// 【作用:设置地址的管理者】

//_addr必须为原manager,默认是目标地址
function setManager(address _addr, address _newManager) external;

// 【作用:获取地址的管理者】
function getManager(address _addr) external view returns(address);

//【 作用:计算接口哈希值】

//此方法是ERC1820标准为了方便人们算接口Hash提供的,其实也只是keccak256 + encodePacked 接口名称。
function interfaceHash(string calldata _interfaceName) external pure returns(bytes32);

// 【作用:更新 ERC165 缓存】
//此方法必须手动调用更新缓存,ERC1820不会主动更新缓存。

//如果你想通过ERC1820储存你项目的ERC165接口,那么当你每次接口改变,最好同时也调用此方法更新缓存记录。
function updateERC165Cache(address _contract, bytes4 _interfaceId) external;

// 检查合约是否实现了 ERC165 接口
function implementsERC165Interface(address _contract, bytes4 _interfaceId) external view returns (bool);

// 当没有ERC165缓存时,以staticall方式去目标合约查。
function implementsERC165InterfaceNoCache(address _contract, bytes4 _interfaceId) external view returns (bool);

.

. 【ERC165和1820查询实现不同细节对比】 ERC1820的实现中有很多值得学习和需要细心发现的细节。

  • ERC165和ERC1820接口查询区别
    1. ERC165中使用bytes4查询
    2. ERC1820中使用Bytes32查询 -即使兼容ERC165查询,也需要用bytes32查 .
  • ERC165通过返回的bool,而ERC1820则通过返回的"地址"判断接口是否存在
    • 1.ERC1820中对于代理实现的合约需要返回 ERC1820_ACCEPT_MAGIC 标识符,这是因为要防止代理合约没有实现canImplementInterfaceForAddress,但却因为实现了带bool返回值的fallback方法而出现误判。
    • 2.所以从这个角度来看,ERC165标准要发送两次staticcall(一次预期返回false,一次要查询的接口)来确认一个ERC1665接口是否存在其实是必要的。

【部署】

部署原理

对于ERC1820的部署,其实需要先简单理解一下交易签名。

  • 1.以太坊区块链上所有的write操作(包括write合约方法和交易),无论通过什么方式发送,本质上都是打包你交易中的nonce、from、to、data、gas、r、v、s等信息。然后使用ECDSA签名,得到一个交易字符串。
  • 2.ERC1820官方提案中就是提供了这样一个用于部署的交易字符串

    为了实现任何人可以在任何链上,都能够部署得到同样的ERC1820合约地址,达到统一的效果,采用了一种无需私钥的部署方式。

    知识点:

    1. 以太坊交易签名的时候,from地址由于可控,所以是不被包含在签名里面的。
    2. .最终上链的交易中的from地址,是节点通过签名恢复出的from地址。但你可以自定义签名(比如r、v、s),其中很多签名都可以恢复出一个对应的随机地址。 3.所以ERC1820的合约部署的r、v、s是自定义的

如下:ERC1820的签名r、v、s数据

v: 27,
r: 0x1820182018201820182018201820182018201820182018201820182018201820'
s: 0x1820182018201820182018201820182018201820182018201820182018201820'

这里有一些细节

  • 1为了实现在所有链部署都得到同样的地址,所以不能使用EIP155的标准。
    • EIP155比默认情况下多一个链ID,会导致同样的交易数据在不同的链部署后地址不同。
  • .这种方式恢复出的地址,是一次性的,部署后的from会是"0xa990077c3205cbDf861e17Fa532eeB069cE9fF96"
    • 但之后由于相同的nonce已经使用,无法再恢复出这个地址。
  • 部署后的ERC1820合约地址,在任何链上都会是:0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24
  • 这个交易中默认给了比较高的gas price 100 gwei,也是为了在链上gas波动情况下,增加保障。

部署步骤

上面是分析了一下部署原理,下面说一下步骤。 由于部署后的from是0xa990077c3205cbDf861e17Fa532eeB069cE9fF96

  • 1.所以部署前需要先转入0.08ETH到这个地址。
  • 2.使用交易发送方法如ethers.js的 sendTransaction() 方法,发送提案中提供的原始部署交易。

【思考与总结】

关于ERC1820可以为EOA地址注册接口实现的思考

理想来说,作为开发者或项目方,你可以为一个指定的用户(EOA)地址,实现一些特定的逻辑。

比如当用户收到代币、就代他进行投票、或存款之类的操作。 如ERC777就默认实现了转账接收钩子(tokensReceived)。

但这个为EOA地址实现接口功能,2点原因导致使用受限;

  • 1.需要是标准场景下的操作
    • 比如ERC777的默认转账回调,在用户收到代币的情况下,才会执行。
    • 缺少场景丰富又同时有共识的标准。
  • 2.或者是自身项目内部生态
    • 如果想为指定EOA用户实现指定的接口功能实现,那你可能要自己定义接口,又要为用户去注册和实现。这种情况也许只在自己项目生态中比较好实现了。

另外还有一个不算友好的地方,ERC1820中只能由msg.sender来为自己注册接口,所以这个EOA用户也只能自己去调用方法,对用户的要求比较"高"。

【总结】

最近抽空学习ERC1820的官方提案,断断续续用了大概一周多的时间。

ERC1820的合约实现的也有很多很巧妙的地方,很值得去学习。这过程中涉及到一些相关的内容、比如以太坊的签名与交易、无秘钥部署、EIP155、ERC165等..

感觉想把ERC1820通过一篇文章写的非常清晰,是挺不容易的,只能算一些笔,还是感觉有不少收获的。

另外看到以太坊主网的ERC1820合约部署五年多,也没几个人调用注册,真是可惜了这么好的合约。


参考来源 EIP1820官方提案:https://eips.ethereum.org/EIPS/eip-1820 ERC1820优质文章:https://www.decipherclub.com/erc-1820/

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
De7e
De7e
0xE799...0daE
V:wjynydkyd 擅长口算keccak256