【从0学习Solidity】14. 抽象合约和接口
- 博主简介:不写代码没饭吃,一名全栈领域的创作者,专注于研究互联网产品的解决方案和技术。熟悉云原生、微服务架构,分享一些项目实战经验以及前沿技术的见解。
- 关注我们的主页,探索全栈开发,期待与您一起在移动开发的世界中,不断进步和创造!
- 本文收录于 不写代码没饭吃 的学习汇报系列,大家有兴趣的可以看一看。
- 欢迎访问我们的微信公众号:不写代码没饭吃,获取更多精彩内容、实用技巧、行业资讯等。您关注的是我们前进的动力!
这一讲,我们用ERC721
的接口合约为例介绍solidity
中的抽象合约(abstract
)和接口(interface
),帮助大家更好的理解ERC721
标准。
抽象合约
如果一个智能合约里至少有一个未实现的函数,即某个函数缺少主体{}
中的内容,则必须将该合约标为abstract
,不然编译会报错;另外,未实现的函数需要加virtual
,以便子合约重写。拿我们之前的插入排序合约为例,如果我们还没想好具体怎么实现插入排序函数,那么可以把合约标为abstract
,之后让别人补写上。
abstract contract InsertionSort{
function insertionSort(uint[] memory a) public pure virtual returns(uint[] memory);
}
接口
接口类似于抽象合约,但它不实现任何功能。接口的规则:
- 不能包含状态变量
- 不能包含构造函数
- 不能继承除接口外的其他合约
- 所有函数都必须是external且不能有函数体
- 继承接口的非抽象合约必须实现接口定义的所有功能
虽然接口不实现任何功能,但它非常重要。接口是智能合约的骨架,定义了合约的功能以及如何触发它们:如果智能合约实现了某种接口(比如ERC20
或ERC721
),其他Dapps和智能合约就知道如何与它交互。因为接口提供了两个重要的信息:
- 合约里每个函数的
bytes4
选择器,以及函数签名函数名(每个参数类型)
。 - 接口id(更多信息见EIP165)
另外,接口与合约ABI
(Application Binary Interface)等价,可以相互转换:编译接口可以得到合约的ABI
,利用abi-to-sol工具也可以将ABI json
文件转换为接口sol
文件。
我们以ERC721
接口合约IERC721
为例,它定义了3个event
和9个function
,所有ERC721
标准的NFT都实现了这些函数。我们可以看到,接口和常规合约的区别在于每个函数都以;
代替函数体{ }
结尾。
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;
}
IERC721事件
IERC721
包含3个事件,其中Transfer
和Approval
事件在ERC20
中也有。
-
Transfer
事件:在转账时被释放,记录代币的发出地址from
,接收地址to
和tokenid
。 -
Approval
事件:在授权时释放,记录授权地址owner
,被授权地址approved
和tokenid
。 -
ApprovalForAll
事件:在批量授权时释放,记录批量授权的发出地址owner
,被授权地址operator
和授权与否的approved
。
IERC721函数
-
balanceOf
:返回某地址的NFT持有量balance
。 -
ownerOf
:返回某tokenId
的主人owner
。 -
transferFrom
:普通转账,参数为转出地址from
,接收地址to
和tokenId
。 -
safeTransferFrom
:安全转账(如果接收方是合约地址,会要求实现ERC721Receiver
接口)。参数为转出地址from
,接收地址to
和tokenId
。 -
approve
:授权另一个地址使用你的NFT。参数为被授权地址approve
和tokenId
。 -
getApproved
:查询tokenId
被批准给了哪个地址。 -
setApprovalForAll
:将自己持有的该系列NFT批量授权给某个地址operator
。 -
isApprovedForAll
:查询某地址的NFT是否批量授权给了另一个operator
地址。 -
safeTransferFrom
:安全转账的重载函数,参数里面包含了data
。
什么时候使用接口?
如果我们知道一个合约实现了IERC721
接口,我们不需要知道它具体代码实现,就可以与它交互。
无聊猿BAYC
属于ERC721
代币,实现了IERC721
接口的功能。我们不需要知道它的源代码,只需知道它的合约地址,用IERC721
接口就可以与它交互,比如用balanceOf()
来查询某个地址的BAYC
余额,用safeTransferFrom()
来转账BAYC
。
contract interactBAYC {
// 利用BAYC地址创建接口合约变量(ETH主网)
IERC721 BAYC = IERC721(0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D);
// 通过接口调用BAYC的balanceOf()查询持仓量
function balanceOfBAYC(address owner) external view returns (uint256 balance){
return BAYC.balanceOf(owner);
}
// 通过接口调用BAYC的safeTransferFrom()安全转账
function safeTransferFromBAYC(address from, address to, uint256 tokenId) external{
BAYC.safeTransferFrom(from, to, tokenId);
}
}
在Remix上验证
- 抽象合约示例(简单的演示代码如图所示)
- 接口示例(简单的演示代码如图所示)
总结
这一讲,我介绍了solidity
中的抽象合约(abstract
)和接口(interface
),他们都可以写模版并且减少代码冗余。我们还讲了ERC721
接口合约IERC721
,以及如何利用它与无聊猿BAYC
合约进行交互。
如果这份博客对大家有帮助,希望各位给作者一个免费的点赞
标签:function,14,tokenId,Solidity,接口,地址,address,合约 From: https://blog.51cto.com/u_15344421/7625382