目录
一、前言
二、批准Approve
1、讲解
2、实战1
1.要求
2.代码
3、实战2-takeOwnership
1.要求
2.代码
看了一些区块链的教程,论文,在网上刚刚找到了一个项目实战,CryptoZombies。
我们接着来讲ERC-721实战。
使用 approve
或者 takeOwnership
的时候,转移有2个步骤:
1.所有者用新主人的
address
和所有者希望新主人获取的_tokenId
来调用approve。
2.新主人用
_tokenId
来调用takeOwnership
,合约会检查确保他获得了批准,然后把代币转移给他。
因为这发生在2个函数的调用中,所以在函数调用之间,我们需要一个数据结构来存储什么人被批准获取什么。
1.首先,让我们来定义一个映射
zombieApprovals
。它应该将一个uint
映射到一个address
。这样一来,当有人用一个
_tokenId
调用takeOwnership
时,我们可以用这个映射来快速查找谁被批准获取那个代币。
2.
在函数approve
上, 我们想要确保只有代币所有者可以批准某人来获取代币。所以我们需要添加修饰符onlyOwnerOf
到approve
。3.函数的正文部分,将
_tokenId
的zombieApprovals
设置为和_to
相等。4.最后,在 ERC721 规范里有一个
Approval
事件。所以我们应该在这个函数的最后触发这个事件。(参考erc721.sol
来确认传入的参数,并确保_owner
是msg.sender
)
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);
}
}
我们还有一个函数kakeOwnership,用于检查确保msg.sender已被批准来提取这个代币或僵尸,确认即调用_transfer:
1.用一个
require
句式来检查_tokenId
的zombieApprovals
和msg.sender
相等。这样如果msg.sender
未被授权来提取这个代币,将抛出一个错误。2.为了调用
_transfer
,我们需要知道代币所有者的地址(它需要一个_from
来作为参数)。我们可以在我们的ownerOf
函数中来找到这个参数。所以,定义一个名为
owner
的address
变量,并使其等于ownerOf(_tokenId)
。3.最后,调用
_transfer
, 并传入所有必须的参数。(在这里你可以用msg.sender
作为_to
, 因为代币正是要发送给调用这个函数的人)。
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);
}
}