116孤荷凌寒自学第0202天_区块链第116天NFT013

孤荷凌寒自学第0202天

区块链学习第116天

NFT013继续erc721接口标准

(文末有具体的学习过程录屏视频地址等)

 

 

笔记合集在github上:

 https://github.com/lhghroom/Self-learning-blockchain-from-scratch

 

【主要内容】

今天继续学习了解ntf的相关知识,今天继续批注分析从github上获取的erc721合约的代码,添加自己的理解并批注,共耗时32分钟。

(此外整理作笔记花费了约12分钟)

详细学习过程见文末学习过程屏幕录像。

【今天批注的ERC721的智能合约】

文件:

ERC721Base.sol

已批注的部分内容如下:

```

pragma solidity ^0.4.18;

 

import './SafeMath.sol';  //这是一个library

 

import './AssetRegistryStorage.sol';  //资产登记所需要的基类全约,其中声明了各种需要登记到区块中的(变量类型为storage)mapping表变量

 

import './IERC721Base.sol';  //这儿声明了erc721的interface

 

import './IERC721Receiver.sol';  //在这个文件中声明了一个Interface,声明了让合约可以接收nft的函数onERC721Received

 

import './ERC165.sol';  //erc165的interface

 

contract ERC721Base is AssetRegistryStorage, IERC721Base, ERC165 {

  //作为基类合约的IERC721Base和ERC165中声明的只是一个interface,但仍然可以被当作基类合约使用。

  using SafeMath for uint256;  //这儿使用了库 SafeMath.sol中的内容

 

  // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`

  bytes4 private constant ERC721_RECEIVED = 0x150b7a02; //ERC165接口需要的常量,表示 合约是否可以接收 NFT资产的标识

 

  bytes4 private constant InterfaceId_ERC165 = 0x01ffc9a7; //ERC165需要的常量,表示合约是否支持erc165接口

  /*

   * 0x01ffc9a7 ===

   *   bytes4(keccak256('supportsInterface(bytes4)'))

   */

 

  bytes4 private constant Old_InterfaceId_ERC721 = 0x7c0633c6;

  bytes4 private constant InterfaceId_ERC721 = 0x80ac58cd;  //ERC721需要的常量,表示合约是否支持erc721接口

   /*

   * 0x80ac58cd ===

   *   bytes4(keccak256('balanceOf(address)')) ^

   *   bytes4(keccak256('ownerOf(uint256)')) ^

   *   bytes4(keccak256('approve(address,uint256)')) ^

   *   bytes4(keccak256('getApproved(uint256)')) ^

   *   bytes4(keccak256('setApprovalForAll(address,bool)')) ^

   *   bytes4(keccak256('isApprovedForAll(address,address)')) ^

   *   bytes4(keccak256('transferFrom(address,address,uint256)')) ^

   *   bytes4(keccak256('safeTransferFrom(address,address,uint256)')) ^

   *   bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)'))

   */

 

  //

  // Global Getters

  //

 

  /**

   * @dev Gets the total amount of assets stored by the contract 获取当前合约管理着多少个NFT的总数量

   * @return uint256 representing the total amount of assets

   */

  function totalSupply() external view returns (uint256) {

    return _totalSupply(); //通过调用下一个函数到获取

  }

  function _totalSupply() internal view returns (uint256) {

    return _count;  //状态变量(全局变量)_count是在sol文件AssetRegistryStorage.sol中声明的

  }

 

  //注意到,这儿的每一个方法,都进行了安全隔离,对外,采用external关键字修饰,对内(包括对下级合约——也就是把当前合约当作父级合约的子合约)使用internal关键字。

  /*

 

    public与private

    对于public和private,相信学过其他主流语言的人都能明白:

 

    public修饰的变量和函数,任何用户或者合约都能调用和访问。

    private修饰的变量和函数,只能在其所在的合约中调用和访问,即使是其子合约也没有权限访问。

    external和internal

    除 public 和 private 属性之外,Solidity 还使用了另外两个描述函数可见性的修饰词:internal(内部) 和 external(外部)。

 

    internal 和 private 类似,不过, 如果某个合约继承自其父合约,这个合约即可以访问父合约中定义的“内部”函数。

    external 与public 类似,只不过这些函数只能在合约之外调用 - 它们不能被合约内的其他函数调用。

 

    internal、private、external、public这4种关键字都是可见性修饰符,互不共存(也就是说,同一时间只能使用这四个修饰字中的一个)

    ————————————————

    版权声明:本文为CSDN博主「黄嘉成」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

    原文链接:https://blog.csdn.net/qq_33829547/java/article/details/80460013

 

  */

  //

  // Asset-centric getter functions 查询有关NFT的所有者等相关信息的操作

  //

 

  /**

   * @dev Queries what address owns an asset. This method does not throw. 传入NFT的ID值:assetId,以查询得到此NFT资产的拥有人是谁。

   * In order to check if the asset exists, use the `exists` function or check if the

   * return value of this call is `0`.

   * @return uint256 the assetId

   */

  function ownerOf(uint256 assetId) external view returns (address) {

    return _ownerOf(assetId);

  }

  function _ownerOf(uint256 assetId) internal view returns (address) {

    return _holderOf[assetId];  //状态变量(全局变量)_holderOf是在sol文件AssetRegistryStorage.sol中声明的

  }

 

  //

  // Holder-centric getter functions

  //

  /**

   * @dev Gets the balance of the specified address 查看一个节点(形参 owner指定)拥有总共多少个NFT

   * @param owner address to query the balance of

   * @return uint256 representing the amount owned by the passed address

   */

  function balanceOf(address owner) external view returns (uint256) {

    return _balanceOf(owner);

  }

  function _balanceOf(address owner) internal view returns (uint256) {

    return _assetsOf[owner].length; //状态变量(全局变量)_assetsOf是在sol文件AssetRegistryStorage.sol中声明的

  }

 

  //

  // Authorization getters  获取当前资产授权状态的函数方法

  //

 

  /**

   * @dev Query whether an address has been authorized to move any assets on behalf of someone else  查询 形参 assetHolder 节点 是否已经把 它的所有NFT资产都授权给了 形参 operator 节点,允许 形参 operator 节点 全权处理(包括移动)这些NFT资产。

   * @param operator the address that might be authorized

   * @param assetHolder the address that provided the authorization

   * @return bool true if the operator has been authorized to move any assets

   */

  function isApprovedForAll(address assetHolder, address operator)

    external view returns (bool)

  {

    return _isApprovedForAll(assetHolder, operator);

  }

  function _isApprovedForAll(address assetHolder, address operator)

    internal view returns (bool)

  {

    return _operators[assetHolder][operator]; //状态变量(全局变量)_operators是在sol文件AssetRegistryStorage.sol中声明的

  }

 

  /**

   * @dev Query what address has been particularly authorized to move an asset 查询指定ID的NFT资产(形参 assetId 指定) 当前 已经被 授权给哪个 节点 处理。

   * @param assetId the asset to be queried for

   * @return bool true if the asset has been approved by the holder

   */

  function getApproved(uint256 assetId) external view returns (address) {

    return _getApprovedAddress(assetId);

  }

  function getApprovedAddress(uint256 assetId) external view returns (address) {

    return _getApprovedAddress(assetId);

  }

  function _getApprovedAddress(uint256 assetId) internal view returns (address) {

    return _approval[assetId];

  }

 

  /**

   * @dev Query if an operator can move an asset. 查询 一个 节点(形参 operator 指定)是不是已经 被 授权处理 指定ID的NFT(形参 assetId)

   * @param operator the address that might be authorized

   * @param assetId the asset that has been `approved` for transfer

   * @return bool true if the asset has been approved by the holder

   */

  function isAuthorized(address operator, uint256 assetId) external view returns (bool) {

    return _isAuthorized(operator, assetId);

  }

  function _isAuthorized(address operator, uint256 assetId) internal view returns (bool)

  {

    require(operator != 0); //检查 节点地址是否为空

    address owner = _ownerOf(assetId);  //得到指定ID的NFT本身是属于哪个节点地址的

    if (operator == owner) {   //如果指定ID的NFT的归属节点就是当前 要查询 的operator 那么,就直接返回TRUE

      return true;

    }

    return _isApprovedForAll(owner, operator) || _getApprovedAddress(assetId) == operator;

    //双竖线左边是检查节点owner是否已经授权节点operator处理它的全部NFT资产,双竖线右边是获取指定id的assetId现在的授权处理节点地址是否等于Operator

    //如果以上两个条件二者之一符合,则会返回TRUE,否则 返回FALSE

  }

 

  //

  // Authorization  执行授权等操作的函数方法区域

  //

 

  /**

   * @dev Authorize a third party operator to manage (send) msg.sender's asset 当前调用合约的节点(msg.sender)调用此方法来向指定的节点(形参 operator 指定)授权允许其 操作自己的所有NFT资产,或撤消这个授权——是发起授权还是撤消授权由形参 authorized 的BOOL值决定

   * @param operator address to be approved

   * @param authorized bool set to true to authorize, false to withdraw authorization

   */

  function setApprovalForAll(address operator, bool authorized) external {

    return _setApprovalForAll(operator, authorized);

  }

  function _setApprovalForAll(address operator, bool authorized) internal {

    if (authorized) { //如果是发起授权

      require(!_isApprovedForAll(msg.sender, operator));

      _addAuthorization(operator, msg.sender);  //这个方法在本合约稍后定义的,直接操纵 映射表  _operators 来完成

    } else { //如果是撤消授权

      require(_isApprovedForAll(msg.sender, operator));

      _clearAuthorization(operator, msg.sender); //这个方法在本合约稍后定义的,直接操纵 映射表  _operators 来完成

    }

    emit ApprovalForAll(msg.sender, operator, authorized); //广播这个事件,事件的定义在sol文件IERC721Base.sol中声明的

  }

 

  /**

   * @dev Authorize a third party operator to manage one particular asset //这个函数是授权节点Operator可以操作调用合约节点(msg.sender)的指定ID的一个nft资产。

   * @param operator address to be approved

   * @param assetId asset to approve

   */

  function approve(address operator, uint256 assetId) external {

    address holder = _ownerOf(assetId);  //获取要操作的指定ID的NFT(这儿就是形参assetId)当前的所有者节点的地址

    require(msg.sender == holder || _isApprovedForAll(msg.sender, holder));

    //上一个语句,左边是检查当前合约调用节点是不是就是此ID的NFT资产的所有人,右边检查,当前调用合约的节点是不是已经把自己的所有NFT资产的操作权授权给了当前操作的指定ID的NFT资产的所有人(现在是变量holder表示)。

    //只要两者有其一是true ,语句将会继续 执行,如果两者都是false,则语句就不再继续往下执行。

    require(operator != holder); //如果要被授权的节点就是holder节点,那么就没有意义了,所以这儿要检测一下。

 

    //于是下一句话进行了进一步的检查,如果要被授权的节点operator已经是指定id的Nft资产可操作者,那就不必要进行重复授权操作了。

    if (_getApprovedAddress(assetId) != operator) {

      _approval[assetId] = operator; //直接将映射表_approval中指定ID的NFT资产的被授权操作节点修改为operator就可以了。

      emit Approval(holder, operator, assetId); //广播这个更改映射表的事件。

    }

  }

 

  //--下面这个函数 是为函数 _setApprovalForAll 准备的子函数

  function _addAuthorization(address operator, address holder) private {

    _operators[holder][operator] = true;

  }

 

  //--下面这个函数 是为函数 _setApprovalForAll 准备的子函数

  function _clearAuthorization(address operator, address holder) private {

    _operators[holder][operator] = false;

  }

 

  //

  // Internal Operations

  //

 

  //下面这个函数把指定ID的NFT资产(形参assetId指定)的 所有人 指定为 to这个节点 (变更资产所有人)

  function _addAssetTo(address to, uint256 assetId) internal {

    _holderOf[assetId] = to; //在资产所有人的映射表中,变更 此资产的所有人为to节点

 

    uint256 length = _balanceOf(to); //记录下to这个节点现在有多少个NFT资产

 

    _assetsOf[to].push(assetId); //向映射表_assetsOf中的to节点下添加新的NFT资产的ID

 

    _indexOfAsset[assetId] = length; //更改映射表 _indexOfAsset中指定的当前 ID的 NFT资产在to节点自己的资产登记表_assetOf中的Index值,现在发现,这个Index值 是从1开始的,而不是从零开始的。

 

    _count = _count.add(1); //这儿没有理解为什么_count需要增加1!!!!

  }

```

 

github: https://github.com/lhghroom/Self-learning-blockchain-from-scratch

原文地址:

 

 

【欢迎大家加入[就是要学]社群】

如今,这个世界的变化与科技的发展就像一个机器猛兽,它跑得越来越快,跑得越来越快,在我们身后追赶着我们。

很多人很早就放弃了成长,也就放弃了继续奔跑,多数人保持终身不变的样子,原地不动,成为那猛兽的肚中餐——当然那也不错,在猛兽的逼迫下,机械的重复着自我感觉还良好地稳定工作与生活——而且多半感觉不到这有什么不正常的地方,因为在猛兽肚子里的是大多数人,就好像大多数人都在一个大坑里,也就感觉不出来这是一个大坑了,反而坑外的世界显得有些不大正常。

为什么我们不要做坑里的大多数人?

因为真正的人生,应当有百万种可能 ;因为真正的一生可以有好多辈子组成,每一辈子都可以做自己喜欢的事情;因为真正的人生,应当有无数种可以选择的权利,而不是总觉得自己别无选择。因为我们要成为一九法则中为数不多的那个一;因为我们要成为自己人生的导演而不是*成为别人安排的戏目中的演员。

【请注意】

就是要学社群并不会告诉你怎样一夜暴富!也不会告诉你怎样不经努力就实现梦想!

【请注意】

就是要学社群并没有任何可以应付未来一切变化的独门绝技,也没有值得吹嘘的所谓价值连城的成功学方法论!

【请注意】

社群只会互相帮助,让每个人都看清自己在哪儿,自己是怎样的,重新看见心中的梦想,唤醒各自内心中的那个英雄,然后勇往直前,成为自己想要成为的样子!

期待与你并肩奔赴未来!

 

QQ群:646854445 (【就是要学】终身成长)

 

 

 

【原文地址】

https://www.941xue.com/content.aspx?id=1727

【同步语音笔记】

https://www.ximalaya.com/keji/19103006/357046001

 

【学习过程屏幕录屏】

https://www.bilibili.com/video/BV1NZ4y1N7aG/

 

 

上一篇:快速学习-ERC20 代币合约


下一篇:泰岳区块链---YRC20合约(ERC20)