solidity实现ERC721代币标准发布NFT
文章目录
- 1、非同质化货币(NFT)- 维基百科
- 2、IERC165
- 3、IERC721
- 4、IERC721Receiver
- 5、IERC721Metadata
- 6、ERC721
- 7、ERC721 NFT 的实现
- 8、编译部署
1、非同质化货币(NFT)- 维基百科
非同质化代币(英语:Non-Fungible Token,简称:NFT),是一种众筹扶持项目方的方式,也是区块链(数位账本)上的一种数据单位,每个代币可以代表一个独特的数字资料,作为虚拟商品所有权的电子认证或证书。由于其不能互换的特性,非同质化代币可以代表数字资产,如画作、艺术品、声音、影片、游戏中的项目或其他形式的创意作品。虽然作品本身是可以无限复制的,但这些代表它们的代币在其底层区块链上能被完整追踪,故能为买家提供所有权证明。诸如以太币、比特币等加密货币都有自己的代币标准以定义对NFT的使用。
2、IERC165
ERC165 是一个非常简单的以太坊标准,主要用于检测该合约是否支持查询的接口。调用者只需要传入想要检测的接口的ID(如ERC-165的ID是0x01ffc9a7),该函数以布尔值的方式(true支持,false不支持)告诉调用者该合约是否实现了这个接口。
IERC165 是 ERC165 标准的接口合约,规定了ERC165要实现的基本函数 supportsInterface
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;interface IERC165 {// ERC165 代币标准就是检查一个智能合约是不是支持了例如 ERC721 ,ERC1155 的接口。 // 如果支持,返回truefunction supportsInterface(bytes4 interfaceId) external view returns (bool);
}
3、IERC721
IERC721 是 ERC721 标准的接口规范,它定义和规范了一个标准 ERC721 代币合约应该实现的功能。这里让 ERC721 合约直接继承自 IERC721() 接口。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./IERC165.sol";// ERC721标准接口.
interface IERC721 is IERC165 {// 转账时触发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);// 返回某地址的NFT持有量balancefunction balanceOf(address owner) external view returns (uint256 balance);// 返回某 tokenId 的主人 ownerfunction ownerOf(uint256 tokenId) external view returns (address owner);// 实现了 ERC721Receiver 接口的安全转账和重载函数 function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;function safeTransferFrom(address from,address to,uint256 tokenId) external;// 普通转账,参数为转出地址from,接收地址to和tokenId。function transferFrom(address from,address to,uint256 tokenId) external;// 授权NFT给另外一个地址 tofunction approve(address to, uint256 tokenId) external;// 持有的该系列NFT批量授权给某个地址operatorfunction setApprovalForAll(address operator, bool _approved) external;// 查询tokenId被批准给了哪个地址。function getApproved(uint256 tokenId) external view returns (address operator);// 查询某地址的NFT是否批量授权给了另一个operator地址function isApprovedForAll(address owner, address operator) external view returns (bool);
}
4、IERC721Receiver
为了防止 NFT 转入黑洞合约,ERC721 实现了 safeTransferFrom() 安全转账函数,目标合约必须实现了 IERC721Receiver 接口才能接收ERC721代币,不然会 revert 。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;interface IERC721Receiver {function onERC721Received(address operator,address from,uint tokenId,bytes calldata data) external returns (bytes4);
}
5、IERC721Metadata
IERC721Metadata 是 ERC721 的拓展接口,它定义了合约的元数据信息,包括合约名字、标志以及每个代币的 tokenURI。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;interface IERC721Metadata {// 代币名称function name() external view returns (string memory);// 代币符号 function symbol() external view returns (string memory);// 通过 tokenId 查询 metadata 的链接urlfunction tokenURI(uint256 tokenId) external view returns (string memory);
}
6、ERC721
ERC-721 - 非同质化代币标准,主要用于发行独一无二的代币化资产如加密收藏品、游戏装备等。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./IERC165.sol";
import "./IERC721.sol";
import "./IERC721Receiver.sol";
import "./IERC721Metadata.sol";
import "./Address.sol";
import "./Strings.sol";contract ERC721 is IERC721, IERC721Metadata {using Address for address; // 使用Address库,用isContract来判断地址是否为合约using Strings for uint256; // 使用String库,// Token名称 string public override name;// Token代号 string public override symbol;// tokenId 到 owner address 的持有人映射mapping(uint => address) private _owners;// address 到持仓数量的持仓量映射mapping(address => uint) private _balances;// tokenID 到授权地址的授权映射mapping(uint => address) private _tokenApprovals;// owner地址。到operator地址的批量授权映射mapping(address => mapping(address => bool)) private _operatorApprovals;// 构造函数,初始化`name` 和`symbol` .constructor(string memory name_, string memory symbol_) {name = name_;symbol = symbol_;}// 实现IERC165接口 supportsInterfacefunction supportsInterface(bytes4 interfaceId) external pure override returns (bool) {return interfaceId == type(IERC721).interfaceId ||interfaceId == type(IERC165).interfaceId ||interfaceId == type(IERC721Metadata).interfaceId;}// 实现IERC721的balanceOf,利用_balances变量查询owner地址的balance。function balanceOf(address owner) external view override returns (uint) {require(owner != address(0), "owner = zero address");return _balances[owner];}// 实现IERC721的ownerOf,利用_owners变量查询tokenId的owner。function ownerOf(uint tokenId) public view override returns (address owner) {owner = _owners[tokenId];require(owner != address(0), "token doesn't exist");} // 实现IERC721的isApprovedForAll,利用_operatorApprovals变量查询owner地址是否将所持NFT批量授权给了operator地址。function isApprovedForAll(address owner, address operator) external view override returns (bool) {return _operatorApprovals[owner][operator];}// 实现IERC721的setApprovalForAll,将持有代币全部授权给operator地址。function setApprovalForAll(address operator, bool approved) external override {_operatorApprovals[msg.sender][operator] = approved;emit ApprovalForAll(msg.sender, operator, approved);}// 实现IERC721的getApproved,利用_tokenApprovals变量查询tokenId的授权地址。function getApproved(uint tokenId) external view override returns (address) {require(_owners[tokenId] != address(0), "token doesn't exist");return _tokenApprovals[tokenId];}// 授权函数。通过调整_tokenApprovals来,授权 to 地址操作 tokenId,同时释放Approval事件。function _approve(address owner, address to, uint tokenId) private {_tokenApprovals[tokenId] = to;emit Approval(owner, to, tokenId);}// 实现IERC721的approve,将tokenId授权给 to 地址。function approve(address to, uint tokenId) external override {address owner = _owners[tokenId];require(msg.sender == owner || _operatorApprovals[owner][msg.sender],"not owner nor approved for all");_approve(owner, to, tokenId);}// 查询 spender地址是否可以使用tokenId(他是owner或被授权地址)。function _isApprovedOrOwner(address owner, address spender, uint tokenId) private view returns (bool) {return (spender == owner ||_tokenApprovals[tokenId] == spender ||_operatorApprovals[owner][spender]);}// 转账函数function _transfer( address owner, address from, address to, uint tokenId) private {require(from == owner, "not owner");require(to != address(0), "transfer to the zero address");_approve(owner, address(0), tokenId); // 清空token的授权 _balances[from] -= 1;_balances[to] += 1;_owners[tokenId] = to;emit Transfer(from, to, tokenId);}// 实现IERC721的transferFrom,非安全转账,不建议使用。调用_transfer函数function transferFrom(address from, address to, uint tokenId) external override {address owner = ownerOf(tokenId);require(_isApprovedOrOwner(owner, msg.sender, tokenId),"not owner nor approved");_transfer(owner, from, to, tokenId);}// 安全转账,安全地将 tokenId 代币从 from 转移到 tofunction _safeTransfer( address owner, address from, address to, uint tokenId, bytes memory _data ) private {_transfer(owner, from, to, tokenId);require(_checkOnERC721Received(from, to, tokenId, _data), "not ERC721Receiver");}// 实现IERC721的safeTransferFrom,安全转账,调用了_safeTransfer函数。function safeTransferFrom(address from, address to, uint tokenId, bytes memory _data) public override {address owner = ownerOf(tokenId);require(_isApprovedOrOwner(owner, msg.sender, tokenId), "not owner nor approved");_safeTransfer(owner, from, to, tokenId, _data);}// safeTransferFrom重载函数function safeTransferFrom( address from, address to, uint tokenId) external override {safeTransferFrom(from, to, tokenId, "");}// 铸造函数。通过调整_balances和_owners变量来铸造tokenId并转账给 to,同时释放Transfer事件。。function _mint(address to, uint tokenId) internal virtual {require(to != address(0), "mint to zero address");require(_owners[tokenId] == address(0), "token already minted");_balances[to] += 1;_owners[tokenId] = to;emit Transfer(address(0), to, tokenId);}// 销毁函数,通过调整_balances和_owners变量来销毁tokenId,同时释放Transfer事件。function _burn(uint tokenId) internal virtual {address owner = ownerOf(tokenId);require(msg.sender == owner, "not owner of token");_approve(owner, address(0), tokenId);_balances[owner] -= 1;delete _owners[tokenId];emit Transfer(owner, address(0), tokenId);}// 调用IERC721Receiver-onERC721Received, 以防 tokenId 被不小心转入黑洞。function _checkOnERC721Received(address from, address to, uint tokenId, bytes memory _data) private returns (bool) {if (to.isContract()) {// 是否实现了 IERC721Receiver接口return IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, _data) == IERC721Receiver.onERC721Received.selector;} else {return true;}}// 实现IERC721Metadata的tokenURI函数,查询metadata。function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {require(_owners[tokenId] != address(0), "Token Not Exist");string memory baseURI = _baseURI();return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";}// 计算{tokenURI}的BaseURI,tokenURI就是把baseURI和tokenId拼接在一起,需要开发重写。function _baseURI() internal view virtual returns (string memory) {return "";}
}
7、ERC721 NFT 的实现
再写一个合约继承 ERC721 , 并写好 MAX_APES 状态变量、构造函数、baseURI 函数以及锻造 mint 函数。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;import "./ERC721.sol";contract NFTSang is ERC721 {uint public MAX_APES = 10000; // 总量// 构造函数constructor(string memory name_, string memory symbol_) ERC721(name_, symbol_){}// ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariAR3jxcaWtq/function _baseURI() internal pure override returns (string memory) {return "ipfs://QmeSjSinHpPnmXmspMjwiXyN6zS4E9zccariAR3jxcaWtq/";}// 铸造函数function mint(address to, uint tokenId) external {require(tokenId >= 0 && tokenId < MAX_APES, "tokenId out of range");_mint(to, tokenId);}
}
8、编译部署
redmix 可以直接编译运行。
免费锻造代币,正式使用需要开发者继续完善,比如规定哪些人有锻造此代币的权限。
相关文章:

solidity实现ERC721代币标准发布NFT
文章目录 1、非同质化货币(NFT)- 维基百科2、IERC1653、IERC7214、IERC721Receiver5、IERC721Metadata6、ERC7217、ERC721 NFT 的实现8、编译部署 1、非同质化货币(NFT)- 维基百科 非同质化代币(英语:Non-F…...
Failed building wheel for opencv-python which use PEP 517
这主要是opencv-python版本更新以后wheels也更新了,但是相关安装软件没有及时适配,所以不管是使用pip直接安装还是换源其实效果都是报错,解决方法就是直接指定安装旧版opencv-python完事儿,例如: pip3 install opencv…...

HTML5 的全局属性 hidden 和 display:none 的关系
目录 1,hidden 和 display:none 的关系2,其他隐藏元素的方式2.1,语意上的隐藏2.2,视觉上的隐藏 1,hidden 和 display:none 的关系 hidden - MDN 参考 一句话总结:hidden 是HTML5 新增的全局布尔属性&…...

CCKS2023-面向上市公司主营业务的实体链接评测-亚军方案
赛题分析 大赛地址 https://tianchi.aliyun.com/competition/entrance/532097/information 任务描述 本次任务主要针对上市公司的主营业务进行产品实体链接。需要获得主营业务中的产品实体,将该实体链接到产品数据库中的某一个标准产品实体。产品数据库将发布在竞赛…...
关于我离破500粉丝感受
嘿嘿快破500粉丝啦,加油喔,感谢支持 首先,恭喜我在CSDN上的粉丝数量即将突破500大关!这说明你在这个平台上的内容受到了很多人的关注和认可。 1. 保持高质量的内容输出:粉丝数量的增长与你在CSDN上发布的内容质量密切…...

锁表的原因及解决办法
引言 作为开发人员,我们经常会和数据库打交道。 当我们对数据库进行修改操作的时候,例如添加字段,更新记录等,没有正确评估该表在这一时刻的使用频率,直接进行修改,致使修改操作长时间无法响应࿰…...

Kettle 安装配置
文章目录 Kettle 安装配置Kettle 安装Kettle 配置连接 Hive Kettle 安装配置 Kettle 安装 在安装Kettle之前,需要确定已经安装Java运行环境。Kettle需要Java的支持才能运行,JDK的版本最好是8.x的太新的也会出现bug。Kettle的7.1版本的太旧了࿰…...

Webgis学习总结
前言: 作者跟随视频学习了webgis内容进行如下学习复习总结 参考:新中地学习笔记 WebGIS第一课:测试高德API并通过: 注册申请高德API成为开发者,创建自己的项目和key进行项目初始化,可以使用JS API官方文…...

【开源】基于Vue+SpringBoot的音乐平台
项目编号: S 055 ,文末获取源码。 \color{red}{项目编号:S055,文末获取源码。} 项目编号:S055,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示 四、核心代码4.1 查询单首…...

20、Resnet 为什么这么重要
(本文已加入“计算机视觉入门与调优”专栏,点击专栏查看更多文章信息)r esnet 这一网络的重要性,上一节大概介绍了一下,可以从以下两个方面来有所体现:第一是 resnet 广泛的作为其他神经网络的 back bone;第二是 resnet 是 AI 芯片厂家对标性能时,在视觉领域尤其是图像…...

Git Bash环境下用perl脚本获取uuid值
在Linux环境下,比如在ubuntu就直接有uuidgen命令直接获取uuid值。在Windows环境下常用的git bash中没有对应的命令,略有不便。这里用脚本写一个uuidgen,模拟Linux环境下的uuidgen命令。 #! /usr/bin/perl use v5.14; use Win32;sub uuidGen {…...

linux安装部署redis
1、下载redis包2、解压3、进入解压路径编译安装4、修改配置文件使redis后台运行5、启动 1、下载redis包 https://redis.io/download/ 2、解压 tar -zxvf redis-7.2.3.tar.gz3、进入解压路径编译安装 cd redis-7.2.3 make && make install默认安装路径: …...

Redis 数据结构详解
分类 编程技术 Redis 数据类型分为:字符串类型、散列类型、列表类型、集合类型、有序集合类型。 Redis 这么火,它运行有多块?一台普通的笔记本电脑,可以在1秒钟内完成十万次的读写操作。 原子操作:最小的操作单位&a…...

03-IDEA集成Git,初始化本地库,添加远程仓库,提交,拉取,推送,分支的快捷操作
IDEA集成Git 创建Git忽略文件 不同的IDE开发工具有不同的特点文件,这些文件与项目的实际功能无关且不参与服务器上的部署运行, 把它们忽略掉能够屏蔽之间的差异 局部忽略配置文件: 在本地仓库的根目录即项目根目录下直接创建.gitignore文件, 以文件后缀或目录名的方式忽略指定…...

Python---格式化输出与%百分号----涉及转义符 \ 反斜杠的使用
相关链接Python--格式化输出中的转义符号----\t 制表符(空格的)和\n(换行的)_唯元素的博客-CSDN博客 Python---字符串(用单、双引号、 三单/双引号定义。反斜杠 \ 转义,单在双内/双在单内 )-CS…...
大华技术GIS开发工程师24届秋招三场面试Offer面经
本文介绍2024届秋招中,大华技术股份有限公司的GIS开发工程师岗位的3场面试基本情况、提问问题等。 10月投递了大华技术股份有限公司的GIS开发工程师岗位,所在部门为研发中心。目前完成了一面、二面与三面等全部流程,并有幸获得Offerÿ…...

前端三大MV*模式:MVC、mvvm、mvp模式介绍
MVC(同步通信为主):Model、View、Controller MVP(异步通信为主):Model、View、Presenter MVVM(异步通信为主):Model、View、ViewModel mvc模式介绍 MVC(Model–View–Controller)模式是软件…...
分享一些Git的常用命令
常用命令 命令名称作git config —global user.name 用户名设置用户签名git config —global user.email 邮箱设置用户签名git init初始化本地库git status查看本地库状态git add 文件名添加到暂存区git commit -m “日志信息” 文件名提交到本地库git reflog查看历史记录git r…...
C语言第四十二弹---使用多种方法实现字符串左旋转
使用多种方法实现字符串左旋转 一、 左移法 思路:每一次通过移动第一个字符,然后把后面的字符前移,然后再进行移动第一个字符再前移。故需要使用嵌套循环,外层循环控制移动第一个字符的次数,第二个循环进行字符前移 …...

REST-Assured--JAVA REST服务自动化测试的Swiss Army Knife
什么是REST-Assured REST Assured是一套基于 Java 语言实现的开源 REST API 测试框架 Testing and validation of REST services in Java is harder than in dynamic languages such as Ruby and Groovy. REST Assured brings the simplicity of using these languages into t…...

CentOS下的分布式内存计算Spark环境部署
一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架,相比 MapReduce 具有以下核心优势: 内存计算:数据可常驻内存,迭代计算性能提升 10-100 倍(文档段落:3-79…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...

IT供电系统绝缘监测及故障定位解决方案
随着新能源的快速发展,光伏电站、储能系统及充电设备已广泛应用于现代能源网络。在光伏领域,IT供电系统凭借其持续供电性好、安全性高等优势成为光伏首选,但在长期运行中,例如老化、潮湿、隐裂、机械损伤等问题会影响光伏板绝缘层…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...