Hi!
I was looking to discuss a feature I noticed today while developing an ERC777. Here is the code of the transfer function for the ERC777:
function transfer(address recipient, uint256 amount) external returns (bool) {
require(recipient != address(0), "ERC777: transfer to the zero address");
address from = msg.sender;
_callTokensToSend(from, from, recipient, amount, "", "");
_move(from, from, recipient, amount, "", "");
_callTokensReceived(from, from, recipient, amount, "", "", false);
return true;
}
I will focus on the _callTokensReceived
hook, through this might applicable to _callTokensToSend
aswell, to a lesser extent.
function _callTokensReceived(
address operator,
address from,
address to,
uint256 amount,
bytes memory userData,
bytes memory operatorData,
bool requireReceptionAck
)
private
{
address implementer = _erc1820.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");
}
}
The transfer
function does not require the recipient to implement the tokensReceived
hook, because it is passing false
to the requireReceptionAck
boolean in _callTokensReceived
. Still, in the event that the recipient has registered an implementer of this function, it will trigger the mentioned tokensReceived
hook.
I 'd argue that if I am looking to use vanilla ERC20 transfer, this hook should not be called. For example, if I am implementing an automated payments contract and I want to trigger a batch transfer in a single transaction (and yes, I am pushing the payment here), I prefer ERC20 's transfer()
instead of ERC777 's send()
because I do not want to check things like reentrancy or gas harvesting attacks, which I am exposed to due to the tokensReceived
hook.
Maybe I am missing something, so… thoughts on this?