Openzeppelin
文章目录
Hooks
Hooks函数帮助合约在每次执行例如转账等操作时执行需要的逻辑,而避免重复在不同的函数中编写这段逻辑。hooks函数会在每次该动作执行前或执行后被触发,其中,_beforeTokenTransfer(address from, address to, uint256 amount) 是最常见的hook,会在transfer之前被调用,包括mint和burn的场景
一、_beforeTokenTransfer()应用示例
1.实现ERC20的SafeTransfer,即使用_beforeTokenTransfer在每次转账前检查to地址的合法性
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract ERC20WithSafeTransfer is ERC20 {
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal virtual override
{
super._beforeTokenTransfer(from, to, amount);
require(_validRecipient(to), "ERC20WithSafeTransfer: invalid recipient");
}
function _validRecipient(address to) private view returns (bool) {
...
}
...
}
2.ERC20Pausable实现
Override _beforeTokenTransfer函数并加上whenNotPause修饰器,以在每次转账前判断
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Pausable, Ownable {
constructor() ERC20("MyToken", "MTK") {
}
function pause() public onlyOwner {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal
whenNotPaused
override
{
super._beforeTokenTransfer(from, to, amount);
}
}
二、注意事项
1.使用virtual
当希望合约可以被继承并实现_beforeTokenTransfer函数的更多功能时,对_beforeTokenTransfer函数使用virtual关键字
2.使用super
重写_beforeTokenTransfer函数时,使用super继承parent合约的hooks函数
contract MyToken is ERC20 {
function _beforeTokenTransfer(address from, address to, uint256 amount)
internal virtual override // Add virtual here!
{
super._beforeTokenTransfer(from, to, amount); // Call parent hook
...
}
}
其他
- 除了_beforeTokenTransfer,还有_afterTokenTransfer,即在transfer后被调用
- ERC721的hooks参数有所不同:_beforeTokenTransfer(address from, address to, uint256 tokenId),第三个参数为tokenId而不是amount