我最近在重新学solidity,巩固一下细节,也写一个“Solidity极简入门”,供小白们使用(编程大佬可以另找教程),每周更新1-3讲。
欢迎关注我的推特:@0xAA_Science
WTF技术社群discord,内有加微信群方法:链接
所有代码和教程开源在github(1024个star发课程认证,2048个star发社群NFT): github.com/AmazingAng/WTFSolidity
不知不觉我已经完成了Solidity极简教程的前13讲(基础),内容包括:Helloworld.sol,变量类型,存储位置,函数,控制流,构造函数,修饰器,事件,继承,抽象合约,接口,库,异常。在进阶内容之前,我决定做一个ERC721
的专题,把之前的内容综合运用,帮助大家更好的复习基础知识,并且更深刻的理解ERC721
合约。希望在学习完这个专题之后,每个人都能发行自己的NFT
。
ERC721
的主合约一共引用了4个接口合约:IERC721.sol
, IERC721Receiver.sol
, IERC721Metadata.sol
,和间接引用的ERC165
的IERC165.sol
。这一讲我们将逐个介绍这4个接口合约。
首先我们介绍一下EIP165
(以太坊改进建议第165条
),他的目的是创建一个标准方法来发布和检测智能合约实现的接口。讲一个去年年底发生的真实事件,PeopleDAO
有个朋友错转了4000w枚PEOPLE
到代币合约。但合约没有实现转出代币的功能,只能进不能出,这些代币直接锁死在里面销毁了。试想一下,如果在转账的时候自动判断接收方合约是否实现了相应的接口,没实现的话就revert
交易,很多错转代币的悲剧都不会发生。EIP165
就是干这个的,而ERC165
就是EIP165
的实现。
IERC165
是ERC165
的接口合约,只有一个函数supportsInterface()
,输入想查询的接口的interfaceId
,返回一个bool
告诉你合约是否实现了该接口。
interface IERC165 {
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}
ERC721
主合约对supportsInterface()
的实现如下:
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
可以看到,ERC721
实现了IERC721
,IERC721Metadata
和IERC165
的接口,查询的时候会返回true
;否则返回false
。我会在进阶内容中更详细的介绍function selector
和interfaceId
。
IERC721
是ERC721
的接口合约,里面包括3个event
和9个function
:
interface IERC721 is IERC165 {
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 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
}
其中event
包括:
Transfer
事件:在转账时被释放,记录代币的发出地址from
,接收地址to
和tokenid
。Approval
事件:在授权时释放,记录approve
的发出地址owner
,被授权地址approved
和tokenid
。ApprovalForAll
事件:在批量授权时释放,记录approve
的发出地址owner
,被授权地址operator
和是否被授权approved
。其中function
包括:
balanceOf
:参数为要查询的地address
,返回该地址的NFT
持有量balance
。ownerOf
:参数为要查询的tokenId
,返回这个tokenId
的主人owner
。safeTransferFrom
:安全转账(如果接收方是合约地址,会要求实现ERC721
的接收接口)。参数为转出地址from
,接收地址to
和tokenId
。transferFrom
:普通转账(不检查对方是否实现ERC721
的接收接口),参数为转出地址from
,接收地址to
和tokenId
。approve
:授权,批准另一个地址使用你的NFT
。参数为被授权地址approve
和tokenId
。getApproved
:查询NFT
被批准给了哪个地址,参数为tokenId
,返回被批准的地址approve
。setApprovalForAll
:将自己持有的这类NFT
批量授权给某个地址,参数为被授权的地址operator
和是否授权approved
。isApprovedForAll
:查询某人的NFT
是否批量授权给了某个地址,参数为授权方owner和被授权地址operator
,返回bool
。safeTransferFrom
:安全转账,与3.
不同的地方在于参数里面包含了data
,可以做额外处理。interface IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
IERC721Receiver
接口包含了一个函数onERC721Received()
。这个函数会在safeTransferFrom()
中被调用,代币的接收合约必须实现这个接口才能转账成功。
interface IERC721Metadata is IERC721 {
function name() external view returns (string memory);
function symbol() external view returns (string memory);
function tokenURI(uint256 tokenId) external view returns (string memory);
}
IERC721Metadata
是ERC721
的拓展接口,实现了3个查询metadata的常用函数:
name()
:返回代币名称。symbol()
:返回代币代号tokenURI()
:通过tokenId
查询metadata
所在url
。本文是ERC721
专题的第二讲,我们介绍了ERC721
主合约调用的4个接口合约IERC165
,IERC721
,IERC721Receiver
和IERC721Metadata
。下一讲终于该介绍ERC721主合约了!LFG!