ERC721解读

NFT(非同质化代币):类似于明朝、宋朝的青花瓷。虽然都是青花瓷。但是都具有唯一的典藏价值。而且价值可能不同。 NFT就是具有唯一价值的代币。

ERC721: 是以太坊规定实现NFT的一种标准了。实现ERC21标准的智能合约就是NFT代币了。

1.接口

1.ERC721

  定义接口参考:ERC 721 - OpenZeppelin 文档

下面是以太坊官方定义的标准,由于就是我写的代码运行环境不支持payable关键字,因此我打算围绕官方接口定义,按照自己要求稍微增删一下。

pragma solidity ^0.4.25;interface ERC721 {///Event///event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);///Function///function balanceOf(address _owner) external view returns (uint256); // 返回所有者代币的总个数function ownerOf(uint256 _tokenId) external view returns (address); // 返回代币id对应所有者的账户地址// 安全的转账//  _to:是已经被指定 id 代币的所有者授予的账户 and (接受者不是智能合约 or 接受者实现ERC721Receiver接口的智能合约// 将给定id的代币转移到接受者账户// data是元数据,可有可不有(我觉得)function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external; function safeTransferFrom(address _from, address _to, uint256 _tokenId) external;// 这个转账对比上述安全转账(少了一个接受者地址实现是否是ERC721Receiver接口的智能合约地址的判断)function transferFrom(address _from, address _to, uint256 _tokenId) external;// 授权将代币转移到另一个账户的权限function approve(address _approved, uint256 _tokenId) external;// 授权接受者使用所有代币function setApprovalForAll(address _operator, bool _approved) external;// 返回授权指定id 代币的接受者账户function getApproved(uint256 _tokenId) external view returns (address);// 判断某账户代币的拥有者是否能被某账户全部使用function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}

2.ERC721Metadata

以下就是ERC21的元数据接口,这是可选地。名称、标识符、每一个token对应的tokenURI。

pragma solidity ^0.4.25;interface ERC721Metadata {function name() external view returns (string);function symbol() external view returns (string);function tokenURI(uint256 tokenId) external view returns (string); // 返回指定id的代币所对对应的uri
}

3.ERC721Enumerable

另一个额外的可选接口是枚举, 它包含了按索引获取到对应的代币。

pragma solidity ^0.4.25;interface ERC721Enumerable {// 确定合约当前全部的nft数量(出去销毁)function totalSupply() external view returns (uint256);// 从代币列表返回第n个代币function tokenByIndex(uint256 _index) external view returns (uint256);// 返回所有者代币列表的第n个代币function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256);
}

4.ERC721Receiver

pragma solidity ^0.4.25;// 资产合约
interface ERC721Receiver {function onERC721Received(address operator, address from, uint256 tokenId, bytes data) externalreturns (bytes);
}

2.实现

1.Jzm721

这是我针对ERC721接口的合约实现。基本满足官方接口标准。

pragma solidity ^0.4.25;
import "./ERC721.sol";
import "./ERC721Metadata.sol";
contract Jzm721 is ERC721,ERC721Metadata {///Filed///string public name;string public symbol;uint256  nftCount;mapping (address => uint[])  balanceMap; // owner => tokenId[]mapping (uint256=>string)  tokenURIMap; // tokenId => tokenURImapping (uint256=>address)  tokenIdMap; // tokenId => ownermapping (uint256 => address) approveMap; // tokenId => operator(经营方)mapping (address=>mapping (address=>bool)) approveAllMap; // operator =>(owner => true/false)///Function///constructor(string memory _name,string memory _symbol) public {name = _name;symbol = _symbol;}function name() external view returns (string) {return name;}function symbol() external view returns (string) {return symbol;}function tokenURI(uint256 tokenId) external view returns (string) {return tokenURIMap[tokenId];}// 创建代币function mint(address _owner,string _tokenURI) external  returns (uint256) {require(_owner != address(0),"owner is not empty address!");uint256 tokenId = _mint(_owner);_setTokenURI(tokenId, _tokenURI);return tokenId;}function balanceOf(address _owner) external view returns (uint256) {return balanceMap[_owner].length;}function ownerOf(uint256 _tokenId) external view returns (address) {return tokenIdMap[_tokenId];}// 这里我忽略了data这个元数据的作用function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external {_transferFrom(_from, _to, _tokenId);if(_isContractAdd(_to)) {if(_checkIfFunctionExists(_to)) {_externalTransfer(_from, _to, _tokenId);emit Transfer(_from, _to, _tokenId);}  }}function safeTransferFrom(address _from, address _to, uint256 _tokenId) external {_transferFrom(_from, _to, _tokenId);if(_isContractAdd(_to)) {if(_checkIfFunctionExists(_to)) {_externalTransfer(_from, _to, _tokenId);emit Transfer(_from, _to, _tokenId);}}}function transferFrom(address _from, address _to, uint256 _tokenId) external {_transferFrom(_from, _to, _tokenId);}function approve(address _approved, uint256 _tokenId) external {require(_approved != address(0),"approved is not empty address!");address owner = msg.sender;approveMap[_tokenId] = _approved; emit Approval(owner,_approved,_tokenId);}function setApprovalForAll(address _operator, bool _approved) external {require(_operator != address(0),"operator is not empty address!");address owner = msg.sender;approveAllMap[_operator][owner] = _approved;emit  ApprovalForAll(owner,_operator,_approved);}function getApproved(uint256 _tokenId) external view returns (address) {return _getApproved(_tokenId);}function isApprovedForAll(address _owner, address _operator) external view returns (bool) {return _isApprovedForAll(_owner,_operator);}function _checkIfFunctionExists(address _add)public  returns (bool) {bytes4 functionSelector = bytes4(keccak256("onERC721Received(address,address,uint256,bytes)")); // 函数选择器,基础原型前4个字节bytes memory data = abi.encodeWithSelector(functionSelector, address(0),address(0),0,"");bool success = _add.call(data);return success;}function _transferFrom(address _from, address _to, uint256 _tokenId) private {// from不能是零地址。require(_from != address(0),"from is not empty address!");// to不能是零地址。require(_to != address(0),"from is not empty address!");// tokenId令牌必须存在并由from拥有。require(tokenIdMap[_tokenId] == _from,"The tokenId  must exist and be owned by from!");// 接受者一方不是合约地址if (!_isContractAdd(_to)) {if (_isApproved(_from, _to, _tokenId)) { // TODO_externalTransfer(_from, _to, _tokenId);emit Transfer(_from, _to, _tokenId);}}}function _externalTransfer(address _from,address _to,uint256 _tokenId) private {// 删除代币批准if(_getApproved(_tokenId) == _to) {approveMap[_tokenId] = address(0);   }// 转账_deleteAccountToken(_from,_tokenId);tokenIdMap[_tokenId] = _to;balanceMap[_to].push(_tokenId);}function _deleteAccountToken(address _owner,uint256 _tokenId) private {uint256[] storage tokenIds = balanceMap[_owner];uint len =  tokenIds.length;for (uint i = 0; i < len; i++) {if(tokenIds[i] == _tokenId) {// 交换uint swap;swap = tokenIds[i];tokenIds[i] = tokenIds[len - 1];tokenIds[len - 1] = swap;}}tokenIds.length--;}function _mint(address _owner) private  returns (uint256) {nftCount += 1;uint256 tokenId = nftCount + block.timestamp;balanceMap[_owner].push(tokenId);tokenIdMap[tokenId] = _owner;emit Transfer(address(0),_owner,tokenId);return tokenId;}function _setTokenURI(uint256 _tokenId,string _tokenURI) private{tokenURIMap[_tokenId] = _tokenURI;}// 判断该地址是否合约地址function _isContractAdd(address  _addr) private view returns (bool) {uint size;assembly {size := extcodesize(_addr) // 返回地址关联代码的长度}return size > 0;}function _getApproved(uint256 _tokenId) private view returns(address) {return approveMap[_tokenId];}function _isApproved(address _owner, address _operator,uint256 _tokenId) private view returns (bool) {bool approved = _getApproved(_tokenId) == _operator;return approved || _isApprovedForAll(_owner, _operator);}function _isApprovedForAll(address _owner, address _operator) private view returns(bool) {return approveAllMap[_operator][_owner];}}

2.Jzm721Receiver

在这里我就是想要满足合约地址的合约实现ERC721Receiver接口的标准。原合约,这里该函数涉及代币的转账,由于环境的原因,不支持payable关键字,我这里是无法满足的。

pragma solidity ^0.4.25;
import "./ERC721Receiver.sol";contract Jzm721Receiver is ERC721Receiver {function onERC721Received(address operator, address from, uint256 tokenId, bytes data) externalreturns (bytes) {return data;}
}

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

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

相关文章

vue.js中slot插槽的作用

作为一种流行的JavaScript框架&#xff0c;vue.js提供了很多功能强大的特性&#xff0c;其中之一就是插槽&#xff08;slot&#xff09;。插槽是一种能够让父组件向子组件传递内容的机制&#xff0c;它为我们构建可复用的组件提供了更大的灵活性和可扩展性。以下介绍Vue中插槽的…

《Docker极简教程》--Docker服务管理和监控--Docker服务的监控

Docker监控的必要性在于确保容器化环境的稳定性、性能和安全性。以下是几个关键原因&#xff1a; 性能优化和故障排除&#xff1a;监控可以帮助识别容器化应用程序的性能问题&#xff0c;并快速进行故障排除。通过监控关键指标&#xff0c;如CPU利用率、内存使用、网络流量等&…

ElementUI table表格组件实现双击编辑单元格失去焦点还原,支持多单元格

在使用ElementUI table表格组件时有时需要双击单元格显示编辑状态&#xff0c;失去焦点时还原表格显示。 实现思路&#xff1a; 在数据中增加isFocus:false.控制是否显示在table中用cell-dblclick双击方法 先看效果&#xff1a; 上源码&#xff1a;在表格模板中用scope.row…

springboot集成mqtt

文章目录 前言一、MQTT是什么&#xff1f;二、继承步骤1.安装MQTT2.创建项目&#xff0c;引入依赖3. 对应步骤2的代码3 测试 总结mqtt 启动后访问地址 前言 随着物联网的火热,MQTT的应用逐渐增多 曾经也有幸使用过mqtt,今天正好总结下MQTT的使用; 一、MQTT是什么&#xff1f;…

从扩散模型基础到DIT

Diffusion model 扩散模型如何工作&#xff1f; 输入随机噪声和文本内容&#xff0c;通过多次预测并去除图片中的噪声后&#xff0c;最终生成清晰的图像。 以上左边这张图&#xff0c;刚开始是随机噪声&#xff0c;999为时间序列。 为什么不直接预测下一张图片呢&#xff1f;…

springboot+vue的宠物咖啡馆平台(前后端分离)

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

《卓有成效的管理者》

前言 管理工作在很大程度上是要言传身教的&#xff0c;如果管理者不懂得如何在自己的工作中做到卓有成效&#xff0c;就会给其他人树立错误的榜样。 第 1 章 卓有成效是可以学习的 关于体力工作&#xff0c;我们已有一套完整的衡量方法和制度&#xff0c;从工程设计到质量控制…

Java中常用的类(一)

一、API应用程序编程接口&#xff1a; API&#xff1a;指的是官方给开发人员提供的一个说明文档&#xff0c;对于语言有哪些类&#xff0c;类中有哪些方法进行说明 二、Object类 Object是java中所有类的父类&#xff0c;体系结构中最顶层的类&#xff0c;位置是java.lang.Ob…

【深度学习笔记】3_4 逻辑回归之softmax-regression

3.4 softmax回归 Softmax回归&#xff08;Softmax Regression&#xff09;&#xff0c;也称为多类逻辑回归&#xff08;Multinomial Logistic Regression&#xff09;&#xff0c;是一种用于多分类问题的分类算法。虽然名字里面带回归&#xff0c;实际上是分类。 前几节介绍的…

Socks5代理与代理IP的应用

在全球化的背景下&#xff0c;跨界电商和游戏行业正经历着蓬勃发展的时代。然而&#xff0c;随之而来的网络安全挑战也日益突出。为了应对这些挑战&#xff0c;Socks5代理与代理IP等技术成为了保障网络安全的重要工具。本文将探讨这些技术在跨界电商和游戏行业中的应用&#xf…

Python模块百科_时间的访问和转换(time)_下

TOC 一、概述 time模块提供了各种与时间相关的函数。相关功能还可以参阅datetime 和 calendar模块。 尽管所有平台皆可引用此模块&#xff0c;但模块内的函数并不是所有平台都可用。此模块中定义的大多数函数的实现都是调用其所在平台的C语言库的同名函数。因为这些函数的语义…

Rust之构建命令行程序(四):用TDD(测试-驱动-开发)模式来开发库的功能

开发环境 Windows 11Rust 1.75.0 VS Code 1.86.2 项目工程 这次创建了新的工程minigrep. 用测试-驱动模式来开发库的功能 既然我们已经将逻辑提取到src/lib.rs中&#xff0c;并将参数收集和错误处理留在src/main.rs中&#xff0c;那么为代码的核心功能编写测试就容易多了。我…

C#浮点运算出错问题

在计算单价等活动的时候&#xff0c;我们经常会用到double 浮点进行运算&#xff0c;但是在乘除的时候经常出现精度丢失问题 decimal 关键字表示 128 位数据类型。 同浮点型相比&#xff0c;decimal 类型具有更高的精度和更小的范围&#xff0c;这使它适合于财务和货币计算 dou…

【MATLAB源码-第146期】基于matlab的信源编码仿真GUI,对比霍夫曼编码,算术编码和LZ编码。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 霍夫曼编码、算术编码和LZ编码是三种广泛应用于数据压缩领域的编码技术。它们各自拥有独特的设计哲学、实现方式和适用场景&#xff0c;因此在压缩效率、编解码速度和内存使用等方面表现出不同的特点。接下来详细描述这三种编…

【大厂AI课学习笔记】【2.2机器学习开发任务实例】(7)特征构造

特征分析之后&#xff0c;就是特征构造。 特征构造第一步 特征构造往往要进行数据的归一化。 在本案例中&#xff0c;我们将所有的数据&#xff0c;将所有特征区间调整为0~1之间。 如上图。 那么&#xff0c;为什么要进行归一化&#xff0c;又如何将数据&#xff0c;调整为…

信号处理与 signal.h 库

C 语言中的 signal.h 头文件提供了一种处理程序执行期间报告的不同信号的机制。它定义了一些变量类型、宏和函数&#xff0c;让程序能够更灵活地响应来自操作系统或其他进程的信号。 sig_atomic_t 类型 sig_atomic_t 类型是一种在信号处理程序中使用的整数类型。它保证在信号…

QtCreator“设计”按钮灰色无法点击,如何解决

Mac中安装QML Designer插件&#xff1a; 首选项-> 关于插件 -> 勾选QT Quick下的QML Designer 点击确定安装插件&#xff0c;重启Qt Creator后生效

【Langchain多Agent实践】一个有推销功能的旅游聊天机器人

【LangchainStreamlit】旅游聊天机器人_langchain streamlit-CSDN博客 视频讲解地址&#xff1a;【Langchain Agent】带推销功能的旅游聊天机器人_哔哩哔哩_bilibili 体验地址&#xff1a; http://101.33.225.241:8503/ github地址&#xff1a;GitHub - jerry1900/langcha…

C++惯用法之CRTP(奇异递归模板模式)

相关系列文章 C惯用法之Pimpl C之数据转换(全) 目录 1.介绍 2.CRTP的使用场景 2.1.实现静态多态 2.2.代码复用和扩展性 3.总结 1.介绍 CRTP的全称是Curiously Recurring Template Pattern&#xff0c;即奇异递归模板模式&#xff0c;简称CRTP。CRTP是一种特殊的模板技术和…

【达梦数据库】数据库的方言问题导致的启动失败

问题场景 在项目中采用了hibernate &#xff0c;连接数据库原本为ORACLE&#xff0c;后续打算改造为国产数据库 达梦 链接配置&#xff1a; # 达梦写法&#xff0c; index:driver-class-name: dm.jdbc.driver.DmDriverjdbc-url: jdbc:dm://192.168.220.225:5236/IDX4username:…