// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; import "../../token/ERC777/IERC777.sol"; import "../../token/ERC777/IERC777Sender.sol"; import "../../token/ERC777/IERC777Recipient.sol"; import "../../utils/Context.sol"; import "../../utils/introspection/IERC1820Registry.sol"; import "../../utils/introspection/ERC1820Implementer.sol"; contract ERC777SenderRecipientMock is Context, IERC777Sender, IERC777Recipient, ERC1820Implementer { event TokensToSendCalled( address operator, address from, address to, uint256 amount, bytes data, bytes operatorData, address token, uint256 fromBalance, uint256 toBalance ); event TokensReceivedCalled( address operator, address from, address to, uint256 amount, bytes data, bytes operatorData, address token, uint256 fromBalance, uint256 toBalance ); // Emitted in ERC777Mock. Here for easier decoding event BeforeTokenTransfer(); bool private _shouldRevertSend; bool private _shouldRevertReceive; IERC1820Registry private _erc1820 = IERC1820Registry(0x1820a4B7618BdE71Dce8cdc73aAB6C95905faD24); bytes32 private constant _TOKENS_SENDER_INTERFACE_HASH = keccak256("ERC777TokensSender"); bytes32 private constant _TOKENS_RECIPIENT_INTERFACE_HASH = keccak256("ERC777TokensRecipient"); function tokensToSend( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external override { if (_shouldRevertSend) { revert(); } IERC777 token = IERC777(_msgSender()); uint256 fromBalance = token.balanceOf(from); // when called due to burn, to will be the zero address, which will have a balance of 0 uint256 toBalance = token.balanceOf(to); emit TokensToSendCalled( operator, from, to, amount, userData, operatorData, address(token), fromBalance, toBalance ); } function tokensReceived( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external override { if (_shouldRevertReceive) { revert(); } IERC777 token = IERC777(_msgSender()); uint256 fromBalance = token.balanceOf(from); // when called due to burn, to will be the zero address, which will have a balance of 0 uint256 toBalance = token.balanceOf(to); emit TokensReceivedCalled( operator, from, to, amount, userData, operatorData, address(token), fromBalance, toBalance ); } function senderFor(address account) public { _registerInterfaceForAddress(_TOKENS_SENDER_INTERFACE_HASH, account); address self = address(this); if (account == self) { registerSender(self); } } function registerSender(address sender) public { _erc1820.setInterfaceImplementer(address(this), _TOKENS_SENDER_INTERFACE_HASH, sender); } function recipientFor(address account) public { _registerInterfaceForAddress(_TOKENS_RECIPIENT_INTERFACE_HASH, account); address self = address(this); if (account == self) { registerRecipient(self); } } function registerRecipient(address recipient) public { _erc1820.setInterfaceImplementer(address(this), _TOKENS_RECIPIENT_INTERFACE_HASH, recipient); } function setShouldRevertSend(bool shouldRevert) public { _shouldRevertSend = shouldRevert; } function setShouldRevertReceive(bool shouldRevert) public { _shouldRevertReceive = shouldRevert; } function send(IERC777 token, address to, uint256 amount, bytes memory data) public { // This is 777's send function, not the Solidity send function token.send(to, amount, data); // solhint-disable-line check-send-result } function burn(IERC777 token, uint256 amount, bytes memory data) public { token.burn(amount, data); } }