【CryptoZombies - 2 Solidity 进阶】010 ERC-721实战2(批准)

目录

一、前言

二、批准Approve

1、讲解

2、实战1

1.要求

2.代码

3、实战2-takeOwnership

1.要求

2.代码


一、前言

看了一些区块链的教程,论文,在网上刚刚找到了一个项目实战,CryptoZombies。

我们接着来讲ERC-721实战。

二、批准Approve

1、讲解

使用 approve 或者 takeOwnership 的时候,转移有2个步骤:

1.所有者用新主人的 address 和所有者希望新主人获取的 _tokenId 来调用 approve。

2.新主人用 _tokenId 来调用 takeOwnership,合约会检查确保他获得了批准,然后把代币转移给他。

因为这发生在2个函数的调用中,所以在函数调用之间,我们需要一个数据结构来存储什么人被批准获取什么。 

2、实战1

1.要求

1.首先,让我们来定义一个映射 zombieApprovals。它应该将一个 uint 映射到一个 address

这样一来,当有人用一个 _tokenId 调用 takeOwnership 时,我们可以用这个映射来快速查找谁被批准获取那个代币。

2.在函数 approve 上, 我们想要确保只有代币所有者可以批准某人来获取代币。所以我们需要添加修饰符 onlyOwnerOf 到 approve

3.函数的正文部分,将 _tokenId 的 zombieApprovals 设置为和 _to 相等。

4.最后,在 ERC721 规范里有一个 Approval 事件。所以我们应该在这个函数的最后触发这个事件。(参考 erc721.sol 来确认传入的参数,并确保 _owner 是 msg.sender

2.代码

pragma solidity >=0.5.0 <0.6.0;

import "./zombieattack.sol";
import "./erc721.sol";

contract ZombieOwnership is ZombieAttack, ERC721 {

  mapping (uint => address) zombieApprovals;

  function balanceOf(address _owner) external view returns (uint256) {
    return ownerZombieCount[_owner];
  }

  function ownerOf(uint256 _tokenId) external view returns (address) {
    return zombieToOwner[_tokenId];
  }

  function _transfer(address _from, address _to, uint256 _tokenId) private {
    ownerZombieCount[_to]++;
    ownerZombieCount[_from]--;
    zombieToOwner[_tokenId] = _to;
    emit Transfer(_from, _to, _tokenId);
  }

  function transferFrom(address _from, address _to, uint256 _tokenId) external payable {
    require (zombieToOwner[_tokenId] == msg.sender || zombieApprovals[_tokenId] == msg.sender);
    _transfer(_from, _to, _tokenId);
  }

  // 1. Add function modifier here
  function approve(address _approved, uint256 _tokenId) external payable onlyOwnerOf(_tokenId){
    // 2. Define function here
    zombieApprovals[_tokenId] = _approved;
    emit Approval(msg.sender, _approved, _tokenId);

  }


}

3、实战2-takeOwnership

我们还有一个函数kakeOwnership,用于检查确保msg.sender已被批准来提取这个代币或僵尸,确认即调用_transfer:

1.要求

1.用一个 require 句式来检查 _tokenId 的 zombieApprovals 和 msg.sender 相等。这样如果 msg.sender 未被授权来提取这个代币,将抛出一个错误。

2.为了调用 _transfer,我们需要知道代币所有者的地址(它需要一个 _from 来作为参数)。我们可以在我们的 ownerOf 函数中来找到这个参数。

所以,定义一个名为 owner 的 address 变量,并使其等于 ownerOf(_tokenId)

3.最后,调用 _transfer, 并传入所有必须的参数。(在这里你可以用 msg.sender 作为 _to, 因为代币正是要发送给调用这个函数的人)。

2.代码

pragma solidity >=0.5.0 <0.6.0;

import "./zombieattack.sol";
import "./erc721.sol";

contract ZombieOwnership is ZombieAttack, ERC721 {

  mapping (uint => address) zombieApprovals;

  function balanceOf(address _owner) public view returns (uint256 _balance) {
    return ownerZombieCount[_owner];
  }

  function ownerOf(uint256 _tokenId) public view returns (address _owner) {
    return zombieToOwner[_tokenId];
  }

  function _transfer(address _from, address _to, uint256 _tokenId) private {
    ownerZombieCount[_to]++;
    ownerZombieCount[_from]--;
    zombieToOwner[_tokenId] = _to;
    Transfer(_from, _to, _tokenId);
  }

  function transfer(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    _transfer(msg.sender, _to, _tokenId);
  }

  function approve(address _to, uint256 _tokenId) public onlyOwnerOf(_tokenId) {
    zombieApprovals[_tokenId] = _to;
    Approval(msg.sender, _to, _tokenId);
  }

  function takeOwnership(uint256 _tokenId) public {
    // start here
    require(zombieApprovals[_tokenId] == msg.sender);
    address owner = ownerOf(_tokenId);
    _transfer(owner, msg.sender, _tokenId);
  }
}
原创文章 287 获赞 708 访问量 83万+

猜你喜欢

转载自blog.csdn.net/shuiyixin/article/details/104600164