看完这篇!新手也能写NFT合约!

   2022-05-13 巴比特0
核心提示:在《区块链杀手级应用落地畅想(上)》中我们提到,2021年被称为NFT“元年”。在短时间内,NFT已不再局限于加密世界的投机价值,其释放的潜力吸引了越来越多的国际品牌,例如耐克将鞋子作为NFT专利,允许用户“繁殖”不同的鞋子来创造属于自己的

在《区块链杀手级应用落地畅想(上)》中我们提到,2021年被称为NFT“元年”。在短时间内,NFT已不再局限于加密世界的投机价值,其释放的潜力吸引了越来越多的国际品牌,例如耐克将鞋子作为NFT专利,允许用户“繁殖”不同的鞋子来创造属于自己的定制运动鞋;其他诸如美国国家篮球协会(NBA)、路易威登(LV)等国际知名品牌均在加速布局,可以说NFT正在为艺术收藏、音乐、游戏、体育、时尚圈等赋予新的价值加持

NFT应用场景丰富,初学者怎么入门?本文将帮助开发小白了解NFT合约的编写。原文见公众号:QTech


NFT合约标准介绍


目前,NFT(Non-Fungible Tokens)最为主流有三种合约:ERC-721ERC-1155ERC-998

在NFT的最初期,大家严格遵守NFT的定义规范,也就是ERC-721规范,早年非常火热的加密猫系列就是基于该规范开发的。从 ERC-721 协议标准来看,每一个基于ERC-721创建的NFT都是独一无二、不可复制的。用户可以在智能合约中编写一段代码来创建自己的NFT,该段代码遵循一个比较基础的通用模版格式,可通过该代码添加关于NFT的所有者名称、元数据或安全文件链接等细节。

ERC-721规范虽然可以很好的描述NFT,却存在着一些不足。例如,假设我想一次性铸造30个NFT,那么我就需要发起30次铸造NFT的交易,效率和用户体验并不友好。为此ERC-1155提出了“打包”的概念,可以将多个NFT封装成一个Collection,允许开发者在一个智能合约中实现无限数量的FT和NFT。正是由于“打包”的特性,相当于ERC-1155协议标准集成了ERC-20和ERC-721的能力,具有效率高、灵活性强等优势,目前已经为多款游戏提供了动力,例如游戏开发者可以在一个合约里定义多种物品(角色、武器、盔甲、药水、超能力)。

随着NFT概念的进一步火热,组合式NFT概念被提出。例如一个头像可以由眼睛、嘴巴和鼻子等元素组成,每个元素都是一个NFT或者FT,这些元素共同组成了一个独一无二的NFT头像。但是对于整个头像NFT而言,在过去传统合约中是没有所谓层级关系的,即鼻子部分并不知道自己属于哪个NFT,或者头像部分不知道自己是由哪些NFT或者FT组成的。为此,ERC-998便应运而生,也就是可组合Composable NFTs,缩写为CNFT,即一个ERC-998可以包含多个ERC-721和ERC-20形式的通证,而转移CNFT即是转移CNFT所拥有的整个层级结构和所属关系。

为帮助大家快速理解并入门,下文将先分析ERC-721和ERC-1155的合约设计理念,随后详细介绍如何编写ERC 721合约。


NFT合约设计理念 ERC-721


ERC-721作为最为基础的NFT合约,具有以下几个接口:

function balanceOf(address owner) -> uint256 balance /// @notice Find the owner of an NFT    /// @dev NFTs assigned to zero address are considered invalid, and queries    ///  about them do throw.    /// @param _tokenId The identifier for an NFT    /// @return The address of the owner of the NFT
function ownerOf(uint256 tokenId) -> address owner/// @notice Transfers the ownership of an NFT from one address to another address    /// @dev Throws unless `msg.sender` is the current owner, an authorized    ///  operator, or the approved address for this NFT. Throws if `_from` is    ///  not the current owner. Throws if `_to` is the zero address. Throws if    ///  `_tokenId` is not a valid NFT. When transfer is complete, this function    ///  checks if `_to` is a smart contract (code size > 0). If so, it calls    ///  `onERC721Received` on `_to` and throws if the return value is not    ///  `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`.    /// @param _from The current owner of the NFT    /// @param _to The new owner    /// @param _tokenId The NFT to transfer    /// @param data Additional data with no specified format, sent in call to `_to`
function safeTransferFrom(address from, address to, uint256 tokenId)/// @notice Transfers the ownership of an NFT from one address to another address    /// @dev This works identically to the other function with an extra data parameter,    ///  except this function just sets data to "".    /// @param _from The current owner of the NFT    /// @param _to The new owner    /// @param _tokenId The NFT to transfer    
function transferFrom(address from, address to, uint256 tokenId)    /// @notice Change or reaffirm the approved address for an NFT    /// @dev The zero address indicates there is no approved address.    ///  Throws unless `msg.sender` is the current NFT owner, or an authorized    ///  operator of the current owner.    /// @param _approved The new approved NFT controller    /// @param _tokenId The NFT to approve
function approve(address to, uint256 tokenId)/// @notice Enable or disable approval for a third party ("operator") to manage    ///  all of `msg.sender`'s assets    /// @dev Emits the ApprovalForAll event. The contract MUST allow    ///  multiple operators per owner.    /// @param _operator Address to add to the set of authorized operators    /// @param _approved True if the operator is approved, false to revoke approval
function getApproved(uint256 tokenId) -> address operator    /// @notice Query if an address is an authorized operator for another address    /// @param _owner The address that owns the NFTs    /// @param _operator The address that acts on behalf of the owner    /// @return True if `_operator` is an approved operator for `_owner`, false otherwise
function setApprovalForAll(address operator, bool _approved)/// @notice Get the approved address for a single NFT    /// @dev Throws if `_tokenId` is not a valid NFT.    /// @param _tokenId The NFT to find the approved address for    /// @return The approved address for this NFT, or the zero address if there is none
function isApprovedForAll(address owner, address operator) -> bool

其中每一个函数的意义可参见上述注释,接下来我们会简要分析底层存储逻辑

mapping (uint256 => address) internal idToOwnermapping (uint256 => address) internal idToApprovalmapping (address => uint256) private ownerToNFTokenCountmapping (address => mapping (address => bool)) internal ownerToOperators

上述的4个mapping维护了整个合约的存储结构:

  • idToOwner维护了谁拥有什么通证,映射关系是通证ID到其所有者地址;
  • idToApproval维护了谁被授权操作某个通证,映射关系是通证ID到被授权操作的地址;
  • ownerToNFTokenCount维护了某个地址所拥有的nft总量,映射关系是用户地址到代表总量的整数;
  • ownerToOperators维护了某个地址是否授权给了另外一个地址;

一个主要的modifiercanOperate:

// 查看是否具备操作某个nft的权限modifier canOperate(    uint256 _tokenId  )  {    // 找到对应token的所有者    address tokenOwner = idToOwner[_tokenId];    require(        // 需要操作者是所有者或者被所有者授权      tokenOwner == msg.sender || ownerToOperators[tokenOwner][msg.sender],      // 否则返回错误      NOT_OWNER_OR_OPERATOR    );    _;  }

同时,ERC-721还支持可选的实现项,metadata extension,主要用以返回NFT的描述信息。

ERC-1155

ERC-1155同上面的描述,因为实现了“打包”的功能,所以ERC-1155的大部分函数都支持batch的操作。相比于ERC-721,ERC-1155有很好的效率提升。

ERC-1155具有以下接口:

function balanceOf(address account, uint256 id) → uint256function balanceOfBatch(address[] accounts, uint256[] ids) → uint256[]function setApprovalForAll(address operator, bool approved)function isApprovedForAll(address account, address operator) -> boolfunction safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data)function safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data)

具体的接口也都比较明确,这里不再赘述。存储结构上,ERC-1155具有以下两个基本的结构:

mapping (uint256 => mapping(address => uint256)) internal balances;mapping (address => mapping(address => bool)) internal operatorApproval;
  • balances维护了某个账户拥有的某个NFT总量,基本的映射逻辑是id=>(owner=>balances)
  • operatorApproval维护了某个账户是否已经被另一个账户授权,主要逻辑同上;

同样的,ERC-1155具备一个可选的扩展合约ERC1155Metadata_URI,主要是返回某个通证的uri json。

ERC-721合约编写

由于目前社区已经有大量开源的ERC-721标准模板可供参考,在编写大部分的NFT合约时完全可以借鉴通用模板。若标准模板无法满足全部需求时,可在外部新建一个属于自己的合约(内部实现相应的业务逻辑),并且对标准合约进行继承。

下面的示例将以某开源标准ERC-721合约作为基础模板,展示在趣链BaaS平台内的Web IDE内进行进一步的合约开发。

1)进入Web IDE:如下图,在nf-token-mock合约中定义了mint NFT的方法,我们进入该合约并执行编译操作。

看完这篇!新手也能写NFT合约!

2)编译合约:具体结果如下。

看完这篇!新手也能写NFT合约!

3)Web IDE模拟部署与执行:不同于以太坊在线IDE编辑器如Remix,趣链BaaS的Web IDE直接提供模拟部署和执行环境,无需用户使用Metamask的测试网账户,相当于省去了用户在Metamask导入一个测试网账户并拥有测试通证的步骤,也无需在每次调用中进行签名授权,可提升调试效率。

因此,如下图我们可选择NFTTokenMock合约进行模拟部署,该合约中封装了NFT mint等方法,我们先进行mint后,可进一步执行balanceof(查询余额)、Approve(授权)等操作。

看完这篇!新手也能写NFT合约!

4)mint(铸造):向0xd69e9413029e7Fc483eFB5cB1aBCE4Ec44437F2C地址铸造一个通证ID为166的NFT

看完这篇!新手也能写NFT合约!

5)balanceof(查询余额):查询0xd69e9413029e7Fc483eFB5cB1aBCE4Ec44437F2C地址共有几个NFT

看完这篇!新手也能写NFT合约!

相似的,您可以参照合约设计中提到的不同接口信息,调用函数执行Approve(授权)等操作。

6)合约安全检测:如前所述,上述合约是基于社区开源的合约文件,对于安全性未可知。因此我们可以借助趣链Web IDE的静态分析和形式验证等合约安全检测工具对合约进行检测,帮助最大化规避合约潜在漏洞造成的风险。

看完这篇!新手也能写NFT合约!

7)个性化完善合约功能:本例的合约已经封装了很多函数方法,但开发者还可以根据需求编写更多功能,在模拟执行时还可以使用Debug操作帮助调试。

8)合约编译文件集成至SDK: 做完以上所有调试并编译完成后,可将最终的合约编译文件集成至趣链BaaS提供的SDK中,由此可通过SDK进行NFT合约的部署、调用等管理操作。

9)SDK集成至区块链应用:最后,开发者还需要打通业务系统和链上智能合约的交互,只需要将对应的SDK集成至自己的区块链应用项目中即可。

【备注】

在步骤8中介绍的是通过SDK部署合约,对于初学者依然存在一定的学习门槛。如下图趣链BaaS提供了一键可视化部署合约实例的功能。在部署完成后,可直接通过趣链BaaS平台进行智能合约的可视化调用。

部署界面

看完这篇!新手也能写NFT合约!

合约实例管理界面

看完这篇!新手也能写NFT合约!

合约实例调用界面

看完这篇!新手也能写NFT合约!

总结

NFT历经十年发展,出现了ERC-721,ERC-1155和ERC-998等为典型的主流合约,技术架构日趋完善。初学者除了查阅一些开源项目了解通用NFT合约文件外,还可以借助诸如趣链Web IDE等便捷的智能合约研发设施,可充分赋能智能合约研发、部署、调用、升级等全生命周期管理流程,加速相关区块链应用的落地。

《看完这篇!新手也能写NFT合约!》本文来源:巴比特

 
反对 0举报 0 评论 0
 

免责声明:本文仅代表作者个人观点,与爱美生活网(本网)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
    本网站有部分内容均转载自其它媒体,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,若因作品内容、知识产权、版权和其他问题,请及时提供相关证明等材料并与我们留言联系,本网站将在规定时间内给予删除等相关处理.

点击排行