The ERC-20 standard doesn't define how to notify a receiver contract about the incoming transfer. So you'll need to use either another standard (e.g. ERC-777) or build a custom notification hook.
Here's an example of such custom notification. It builds on top of the OpenZeppelin ERC-20 implementation, checks if the receiver is a contract - and if it is a contract, tries to call its onERC20Receive()
function.
You can test it by deploying two separate contracts - MyToken
and SomeReceiver
- and then sending tokens from the deployer address to SomeReceiver
. You can see that the ReceivedTokens
event was emitted, as a result of invoking the function onERC20Receive
when SomeReceiver
received the tokens.
pragma solidity ^0.8.16;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor() ERC20("MyToken", "MyT") {
_mint(msg.sender, 1000 * 1e18);
}
function _afterTokenTransfer(address from, address to, uint256 amount) internal override {
if (to.code.length > 0) {
// token recipient is a contract, notify them
try IERC20Receiver(to).onERC20Receive(from, amount) returns (bool success) {
// the recipient returned a bool, TODO validate if they returned true
} catch {
// the notification failed (maybe they don't implement the `IERC20Receiver` interface?)
}
}
}
}
interface IERC20Receiver {
function onERC20Receive(address from, uint256 amount) external returns (bool);
}
contract SomeReceiver is IERC20Receiver {
event ReceivedTokens(address from, uint256 amount);
function onERC20Receive(address from, uint256 amount) external returns (bool) {
emit ReceivedTokens(from, amount);
return true;
}
}