Michael.W基于Foundry精读Openzeppelin第24期——ERC165Storage.sol

news2024/11/28 1:51:24

0. 版本

[openzeppelin]:v4.8.3,[forge-std]:v1.5.6

0.1 ERC165Storage.sol

Github: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.8.3/contracts/utils/introspection/ERC165Storage.sol

ERC165Storage合约是ERC165的一种拓展。IERC165的supportsInterface(bytes4 interfaceId)函数的标准实现方式是静态地将已实现接口的interface id硬编码到bytecode中,而ERC165Storage合约则可在合约部署完成后动态地添加已支持的interface id。

1. 目标合约

继承ERC165Storage成为一个可调用合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/src/utils/introspection/MockERC165Storage.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import "openzeppelin-contracts/contracts/utils/introspection/ERC165Storage.sol";
import "openzeppelin-contracts/contracts/token/ERC20/ERC20.sol";

interface ICustomized {
    function helloMichael(string memory str) external;
}

contract MockERC165Storage is ERC165Storage, ERC20("", ""), ICustomized {
    string _str;

    // implementation of interface ICustomized
    function helloMichael(string memory str) external {
        _str = str;
    }

    function registerInterface(bytes4 interfaceId) external {
        _registerInterface(interfaceId);
    }
}

同时该合约实现了一个自定义interface——ICustomized。

全部foundry测试合约:

Github: https://github.com/RevelationOfTuring/foundry-openzeppelin-contracts/blob/master/test/utils/introspection/ERC165Storage.t.sol

2. 代码精读

2.1 _registerInterface(bytes4 interfaceId)

动态添加已支持的interface id。

注:IERC165的interface id已经在父合约ERC165中默认支持了,所以不需要使用该方法来动态添加对IERC165的支持。

    // 用于存放interface id与本合约是否支持该interface id之间映射关系的mapping
    mapping(bytes4 => bool) private _supportedInterfaces;
    
    function _registerInterface(bytes4 interfaceId) internal virtual {
    	// 按照EIP-165规范,任何接口的interface id都不应该是0xffffffff。所以当输入的interface id为0xffffffff时,直接revert
       	require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
       	// 在mapping _supportedInterfaces中将输入interface id为key的value置为true,表示本合约已经支持了该interface
       	_supportedInterfaces[interfaceId] = true;
    }

2.2 supportsInterface(bytes4 interfaceId)

对外提供本合约是否实现了传入interfaceId标识的interface的查询功能。

注:ERC165Storage由于继承了ERC165合约,此处是对ERC165中同名方法的重写。

    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
    	// 如果ERC165.supportsInterface()对传入interface id的查询结果为true或_supportedInterfaces中记录了已支持该传入interface id时,该方法返回true。简而言之,当传入的interface id为IERC165的interface id或_supportedInterfaces已记录的value为true的interface id,该方法返回true,否则返回false
        return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId];
    }

2.3 foundry代码验证

contract ERC165StorageTest is Test {
    MockERC165Storage me = new MockERC165Storage();

    function test_ERC165Storage() external {
        // only support IERC165 in initial status
        assertTrue(me.supportsInterface(type(IERC165).interfaceId));
        assertFalse(me.supportsInterface(type(IERC20).interfaceId));
        assertFalse(me.supportsInterface(type(IERC20Metadata).interfaceId));
        assertFalse(me.supportsInterface(type(ICustomized).interfaceId));

        // register interfaces
        me.registerInterface(type(IERC20).interfaceId);
        me.registerInterface(type(IERC20Metadata).interfaceId);
        me.registerInterface(type(ICustomized).interfaceId);
        // revert if try to register invalid interface id (0xffffffff) in IERC165
        vm.expectRevert("ERC165: invalid interface id");
        me.registerInterface(0xffffffff);

        // check
        assertTrue(me.supportsInterface(type(IERC20).interfaceId));
        assertTrue(me.supportsInterface(type(IERC20Metadata).interfaceId));
        assertTrue(me.supportsInterface(type(ICustomized).interfaceId));
    }
}

ps:
本人热爱图灵,热爱中本聪,热爱V神。
以下是我个人的公众号,如果有技术问题可以关注我的公众号来跟我交流。
同时我也会在这个公众号上每周更新我的原创文章,喜欢的小伙伴或者老伙计可以支持一下!
如果需要转发,麻烦注明作者。十分感谢!

在这里插入图片描述

公众号名称:后现代泼痞浪漫主义奠基人

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/866864.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

工作:MODBUS通讯协议知识

工作:MODBUS通讯协议知识 一、Modbus三种通讯分类 Modbus TCP/IP 使用网口通讯,更多是用于快速网络设备,如机器人,上位机视觉。 Modbus RTU 使用RS232或者RS485/RS422接口,通讯方式是串口通讯,是直接传输…

Dynamics 365 字段类型介绍

实体的本质是数据库表,所以每种字段类型都有自己对应的数据库类型。不同的类型也有自己不同的展示界面。 1 字段类型总览 Dynamics365中支持的类型如图,其在C#中对应的类型在括号中 文本类型:单行文本(string)、多行文本(string) 数字类型:整数(int)、浮点数(double)、十…

fork--创建进程

fork–创建进程 fork函数基本知识 pid_t fork(void) 返回值:在父进程中,成功的话返回子进程的pid,失败返回-1在子进程中,返回值pid为0fork()函数将运行着的进程分裂出另一个子进程,它通过拷贝父进程的方式创建子进程…

FFmpeg常见命令行(五):FFmpeg滤镜使用

前言 在Android音视频开发中,网上知识点过于零碎,自学起来难度非常大,不过音视频大牛Jhuster提出了《Android 音视频从入门到提高 - 任务列表》,结合我自己的工作学习经历,我准备写一个音视频系列blog。本文是音视频系…

PHP最简单自定义自己的框架model使用(七)

1、实现model使用效果 2、自动加载model,KJ.php //自动加载文件public static function _autoload($className){switch ($className){//自动model类case substr($className,-5)Model:$path MODEL./.$className..php;if(is_file($path)) include $path;break;//自动加载控制器…

性能测试工具——LoadRunner(1)

一、LoadRunner三大组件 1.1每个组件是干什么的 VUG:录制脚本(编写脚本) Controller:设计场景,运行场景 Analysis:产生性能测试报告 1.2三大组件之间的关系 二、LoadRunner脚本录制 2.1了解WebTours系统 启动WebTours&#xf…

《Linux从练气到飞升》No.12 Linux进程概念

🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux菜鸟刷题集 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的…

Oracle 知识篇+分区表上的索引由global改为local注意事项

★ 知识点 二、知识点 Local型索引有如下优点 1.Only one index partition must be rebuilt when a maintenance operation other than SPLIT PARTITION or ADD PARTITION is performed on an underlying table partition. 2.The duration of a partition maintenance opera…

ubuntu虚拟机磁盘压缩:vmware-toolbox-cmd命令实现

压缩之前,虚拟机占用磁盘空间 虚拟机必须已经安装vmware-tool,运行如下命令,参看磁盘的挂载点 sudo /usr/bin/vmware-toolbox-cmd disk list $sudo /usr/bin/vmware-toolbox-cmd disk list [sudo] password for lkmao: Shrink disk is disab…

RabbitMQ 消息队列(Spring boot AMQP)

文章目录 🍰有几个原因可以解释为什么要选择 RabbitMQ:🥩mq之间的对比🌽RabbitMQ vs Apache Kafka🌽RabbitMQ vs ActiveMQ🌽RabbitMQ vs RocketMQ🌽RabbitMQ vs Redis 🥩linux docke…

v-md-editor自定义锚点(生成目录)数组转树结构

接前两篇博文,最终方案终于定了,也把之前做的编辑器模式给否决了,原因是系统中有老的文档需要平替,因此就不能通过编辑器这种模式了,太麻烦了。 最终方案:线下手动pandoc word转markdown,然后将…

Nginx安装和配置文件详解

目录 1.安装Nginx1.yum安装2.编译安装3.Nginx命令 2.配置文件详解 1.安装Nginx 1.yum安装 [rootdocker ~]# yum -y install nginx通过 rpm -ql nginx 查看安装信息 2.编译安装 2.1安装所需要的依赖 yum install -y gcc gcc-c make libtool wget pcre pcre-devel zlib zlib-…

【雕爷学编程】Arduino动手做(13)---TTP223B电容式触摸模块之通过串口监视器检测电容触摸键的状态与控制继电器

37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&#x…

学习three.js —— 第一天

1.创建三要素 场景 // 创建场景 const scene new THREE.Scene() 相机 // 创建透视相机 const camera new THREE.PerspectiveCamera(a,b,c,d) // 参数含义 // a:相机可视垂直角度;b:相机可视长宽比;c:近端距离;d:远端…

YOLOv5改进系列(19)——替换主干网络之Swin TransformerV1(参数量更小的ViT模型)

【YOLOv5改进系列】前期回顾: YOLOv5改进系列(0)——重要性能指标与训练结果评价及分析 YOLOv5改进系列(1)——添加SE注意力机制

小结:基于 JavaWeb 的宠物店管理系统

宠物店管理系统 系统介绍系统展示登录界面用户注册页面 店主主界面宠物信息管理页面修改宠物信息 宠物出入库管理页面宠物订单查询页面宠物账单查看页面用户信息管理页面修改用户信息 用户主界面宠物订购页面用户订购支付页面 个人资料编辑页面个人订单查看页面 系统说明开发环…

尚硅谷大数据项目《在线教育之采集系统》笔记005

视频地址:尚硅谷大数据项目《在线教育之采集系统》_哔哩哔哩_bilibili 目录 P057 P058 P059 P060 P061 P062 P063 P064 P065 P066 P067 P068 P069 P070 P071 P072 P073 P057 #!/bin/bashMAXWELL_HOME/opt/module/maxwell/maxwell-1.29.2status_ma…

虚拟机的创建与使用

一、虚拟机的下载 链接:百度网盘下载链接 提取码:a9p4 二、新建虚拟机系统 需要有版本序列号 注意: 选择 第一个是纯dos 的窗口指令 桌面没有任何东西 选择第二个就是正常的操作系统.有文件夹 我的电脑之类的 三、从主机中复制文件到虚拟机中需要安装 …

【自用】JAVA复习(初级到循环 0-156集):break、while、for、continue、return

总览 1.break 2.while 3.for 4.continue 5.return 一、break 1.作用 跳出当前的循环。 2.break 在多重循环中的使用&#xff1a;配合标签使用 二、while 三、for 1.for( ; ; )、for( ; i<10 ; ) 四、continue 1.作用 用于结束本次循环&#xff0c;开始下一次循环 …

C语言笔试训练【第九天】

文章目录 &#x1f47f;1、下列程序的输出是&#xff08; &#xff09;&#x1f48e;2、二维数组X按行顺序存储&#xff0c;其中每个元素占1个存储单元。若 X[4][4] 的存储地址为 Oxf8b82140 , X[9][9] 的存储地址为 Oxf8b8221c ,则 X[7][7] 的存储地址为&#xff08; &#xf…