ERC-20
以太坊中的代币ETH是同质化代币(FT),一个ETH和另一个ETH两者是等价的。这使得 ERC20 代币可用于交换投票权、质押等媒介。因此我们需要使用一种同质化代币ERC-20标准。ERC-20接口如下:
pragma solidity ^0.8.0;
interface IERC20 {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(address indexed owner, address indexed spender, uint256 value);
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function approve(address spender, uint256 amount) external returns (bool);
function transferFrom(
address from,
address to,
uint256 amount
) external returns (bool);
}
totalSupply()
:返回总共的Token数量。balanceOf(address account)
:返回account
地址拥有的Token数量。transfer(address to, uint256 amount)
:将amount
数量的Token发送给to
地址,返回布尔值告知是否执行成功。触发Transfer
事件。allowance(address owner, address spender)
:返回授权花费者spender
通过transferFrom
代表所有者花费的剩余Token数量。默认情况下为零。当approve
和transferFrom
被调用时,值将改变。approve(address spender, uint256 amount)
:授权spender
可以花费amount
数量的Token,返回布尔值告知是否执行成功。触发Approval
事件。transferFrom(address from, address to, uint256 amount)
:将amount
数量的Token从from
地址发送到to
地址,返回布尔值告知是否执行成功。触发Transfer
事件。
事件(定义中的 *indexed
* 便于查找过滤):
Transfer(address from, address to, uint256 value)
:当代币被一个地址转移到另一个地址时触发。注意:转移的值可能是 0 。Approval(address owner, address spender, uint256 value)
:当代币所有者授权别人使用代币时触发,即调用approve
方法。
ERC-721
非同质化代币(NFT)用于以唯一的方式标识某人或者某物。与同质化代币(FT)不同,NFT具有独特、不可交换、不可分割的特性。**举个简单的例子,我的羽毛球拍和你的乒乓球拍之间存在差异,即不能直接进行简单的等价交换。而且我也无法给你0.5个羽毛球拍。**因此NFT需要一个适当的ERC-721标准。ERC-721接口如下:
pragma solidity ^0.4.20;
/// @title ERC-721 NFT标准
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// 继承自ERC-165标准
interface ERC721 is ERC165 {
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);
function balanceOf(address _owner) external view returns (uint256);
function ownerOf(uint256 _tokenId) external view returns (address);
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable;
function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
function approve(address _approved, uint256 _tokenId) external payable;
function setApprovalForAll(address _operator, bool _approved) external;
function getApproved(uint256 _tokenId) external view returns (address);
function isApprovedForAll(address _owner, address _operator) external view returns (bool);
}
其中:
- balanceOf(): 返回_owner持有的NFTs的数量。
- ownerOf(): 返回_tokenId代币持有者的地址。
- approve(): 授予地址to具有tokenId的控制权,方法成功后需触发Approval事件。
- setApprovalForAll(): 授予地址_operator具有所有NFTs的控制权,成功后需触发ApprovalForAll事件。
- getApproved()、isApprovedForAll(): 用来查询授权。
- safeTransferFrom(): 转移NFT所有权,一次成功的转移操作必须发起 Transer 事件。**在转账时需要做安全检查,防止因授权地址无效或错误转账导致用户的损失。**函数的实现需要做一下几种检查:
-
调用者msg.sender应该是当前tokenId的所有者或被授权的地址
-
_from 必须是 _tokenId的所有者
-
_tokenId 应该是当前合约正在监测的NFTs 中的任何一个
-
_to 地址不应该为 0
-
如果_to 是一个合约应该调用其onERC721Received方法, 并且检查其返回值,如果返回值不为
bytes4(keccak256("onERC721Received(address,uint256,bytes)"))
抛出异常。一个可接收NFT的合约必须实现ERC721TokenReceiver接口:
interface ERC721TokenReceiver {
/// @return `bytes4(keccak256("onERC721Received(address,uint256,bytes)"))`
function onERC721Received(address _from, uint256 _tokenId, bytes data) external returns(bytes4);
}
- transferFrom(): 用来转移NFTs, 方法成功后需触发Transfer事件。调用者自己确认_to地址能正常接收NFT,否则将丢失此NFT。此函数实现时需要检查上面条件的前4条。
ERC-165
ERC721标准同时要求必须符合ERC165标准 ,其接口如下:
interface ERC165 {
function supportsInterface(bytes4 interfaceID) external view returns (bool);
}
ERC165同样是一个合约标准,这个标准要求合约提供其实现了哪些接口,这样再与合约进行交互的时候可以先调用此接口进行查询。
interfaceID为函数选择器,计算方式有两种,如:bytes4(keccak256('supportsInterface(bytes4)'));
或ERC165.supportsInterface.selector
,多个函数的接口ID为函数选择器的异或值。
总结
ERC-20标准和ERC-721标准的最大区别在于Token之间是否可以进行直接、简单的互换以及分割。