上一篇文章介绍了ERC777的规范以及一些基本函数,这篇会继续上篇讲解其他与ERC20不同的函数
一、重要函数
isOperatorFor
用于判断指定地址是否是操作者(可以控制使用代币持有者的代币)。
函数提供了三种判断方法:
1)该操作者是代币持有者(tokenHolder
确实可以使用自己的代币,也算是操作者)
2)该操作者地址是默认操作者并且不是被移除的默认操作者之一(_defaultOperators
)
3)该操作者是指定操作者之一(_operators
)
function isOperatorFor(address operator, address tokenHolder) public view virtual override returns (bool) {
return
operator == tokenHolder ||
(_defaultOperators[operator] && !_revokedDefaultOperators[tokenHolder][operator]) ||
_operators[tokenHolder][operator];
}
authorizeOperator
用于授权某用户为操作者
函数逻辑:
1)先判断该地址是否是msg.sender
2) 如果该地址是默认操作者,检查撤销操作者队列,如果该地址存在,则删除队列中的地址,不存在,则不用。
3)如果该地址不是默认操作者,则授权为指定操作者。
function authorizeOperator(address operator) public virtual override {
require(_msgSender() != operator, "ERC777: authorizing self as operator");
if (_defaultOperators[operator]) {
delete _revokedDefaultOperators[_msgSender()][operator];
} else {
_operators[_msgSender()][operator] = true;
}
emit AuthorizedOperator(operator, _msgSender());
}
revokedOperator
用于撤销操作者权限
函数逻辑:
1)先判断被撤销操作者的地址是否是msg.sender
2) 如果是默认操作者,则使用_revokedDefaultOperators
撤销该操作者
3)如果不是默认操作者,则从_operators
撤销该操作者
function revokeOperator(address operator) public virtual override {
require(operator != _msgSender(), "ERC777: revoking self as operator");
if (_defaultOperators[operator]) {//如果operator是默认操作者
_revokedDefaultOperators[_msgSender()][operator] = true;//撤销该操作者
} else {//不是默认操作者,而是指定操作者
delete _operators[_msgSender()][operator];//撤销该指定操作者
}
emit RevokedOperator(operator, _msgSender());
}
allowance
是和ERC20的同名函数一样,允许某个用户可以使用自己一定数量的代币
被允许的spender
不一定是操作者,操作者不一定是spender
function allowance(address holder, address spender) public view virtual override returns (uint256) {
return _allowances[holder][spender];
}
approve
和ERC20的同名函数一样,允许操作者使用自己多少数量的代币。
注意:不能让操作者来授权
function approve(address spender, uint256 value) public virtual override returns (bool) {
address holder = _msgSender();
_approve(holder, spender, value);
return true;
}
-
send()
用于代币转账交易,send
是内部函数,用于transferFrom调用 -
move()
实现了转账功能
函数逻辑:
1)判断msg.sender
的余额是否大于要转账的数量
2)msg.sender
的余额减去转账的数量
3)给接受者地址加转账的数量
function _send(
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
) internal virtual {
require(from != address(0), "ERC777: transfer from the zero address");
require(to != address(0), "ERC777: transfer to the zero address");
address operator = _msgSender();
_callTokensToSend(operator, from, to, amount, userData, operatorData);
_move(operator, from, to, amount, userData, operatorData);
_callTokensReceived(operator, from, to, amount, userData, operatorData, requireReceptionAck);
}
function _move(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData
) private {
_beforeTokenTransfer(operator, from, to, amount);
uint256 fromBalance = _balances[from];
require(fromBalance >= amount, "ERC777: transfer amount exceeds balance");
unchecked {
_balances[from] = fromBalance - amount;
}
_balances[to] += amount;
emit Sent(operator, from, to, amount, userData, operatorData);
emit Transfer(from, to, amount);
}
_callTokensToSend()
用于判断发送者地址是否为0地址,可以防止重入攻击_callTokensReceived()
用于判断接收者地址是否为0地址,如果是0地址,则转账终止
这两个函数是ERC20和ERC777的一个重要区别
function _callTokensToSend(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData
) private {
address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(from, _TOKENS_SENDER_INTERFACE_HASH);
if (implementer != address(0)) {
IERC777Sender(implementer).tokensToSend(operator, from, to, amount, userData, operatorData);
}
}
function _callTokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
) private {
address implementer = _ERC1820_REGISTRY.getInterfaceImplementer(to, _TOKENS_RECIPIENT_INTERFACE_HASH);
if (implementer != address(0)) {
IERC777Recipient(implementer).tokensReceived(operator, from, to, amount, userData, operatorData);
} else if (requireReceptionAck) {
require(!to.isContract(), "ERC777: token recipient contract has no implementer for ERC777TokensRecipient");
}
}