1

is there a ERC/IERC20 function or util that ensures received payment is denominated in a specific token?

receive() external payable virtual {
    
    IERC20 token = IERC20(address(0x123...789));
    
    require(
    paymentToken == MYtoken,
    "Payment Must be MY token"
    );
    emit PaymentReceived(_msgSender(), msg.value);

1 Answers1

3

The receive() function is for your contract to accept ETH. Or generally - the native token of the network where the contract is deployed (BNB on BSC network, TRX on Tron network, ...).

But if your contract address receives a standard ERC-20 token, it doesn't get notified in any way.

Except for cases, where the token contract specifically calls the receiver to let them know about the transfer (as defined for example in the EIP-777 tokensReceived() hook). But this hook needs to be defined in the token contract in the first place, so that you can make use of it in your receiver contract. If it's not in the token contract, then your contract can't get directly notified about received tokens.

Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
  • Hello, thanks for the response, this is helpful. The hook you mentioned in the EIP-777 example, is it assigning the operator as the contract that receives the token? – Alec Jeffery Nov 10 '21 at 15:12
  • @AlecJeffery Not the receiver, but the address that performed the action. Which can be the sender directly (in most cases), but also it can be an operator sending someone else's tokens ... The standard defines _"`operator` MUST be the address which triggered the send or mint process"_ (for the `tokensReceived()` hook). So the token contract should pass `msg.sender` as the `operator` param of `tokensReceived()`. – Petr Hejda Nov 10 '21 at 15:21
  • I appreciate the description and background you're providing. It is very helpful to me in terms of getting myself knowledgeable here. The one thing that is still completely tripping me up is ensuring that the payment coming in matches a particular contract address. In the ideal world, the payable contract takes note of when a specific token is use to pay and then maps that msg.sender. As I understand it, it seems impossible with the ERC20 protocol. – Alec Jeffery Nov 11 '21 at 01:39
  • @AlecJeffery Not possible with the original ERC-20... It was introduced literally as the "Ethereum Improvement Proposal number 20" in 2015, when smart contracts weren't really used that much, so notifying them about received tokens wasn't a concern. When it became important to some developers, [ERC-223](https://callisto.network/erc223-token-standard/) and EIP-777 (and possibly others that I don't know about) started building on top of the original ERC-20... There's also the optional `onERC721Received()` in the original NFT standard ERC-721 that also notifies the receiving contract. – Petr Hejda Nov 11 '21 at 08:21
  • Petr, I'm sorta back to where I started. I have an ERC777 token (COIN), I set the operator as the address that mints the token. In a secondary contract I seek to received COIN tokens exclusively. I want to set up logic in the receive function that checks if the token is indeed COIN and then distribute it to various addresses. My confusion is whether I need to declare the contract address as an operator? Playing around on the ROP network I have deployed a simple ERC777 and I have determined that I can interact w/ the token to authorize Operators. – Alec Jeffery Nov 12 '21 at 17:22
  • @AlecJeffery You don't need to declare the receiving contract address as an operator, because it's going to be sending out tokens that were just sent to it. Only if the contract would need to send out someone else's tokens, it would have to be an operator... When the ERC777 calls your contract's `tokensReceived()`, you can check the `msg.sender` inside this function. It's going to be the ERC777 contract, as it's the current caller of your function. And you can wrap the check in a `require()` statement, so if anyone else executes the `tokensReceived()` function, their tx gets reverted. – Petr Hejda Nov 13 '21 at 09:33
  • function tokensReceived( address operator, address from, address to, uint256 amount, bytes calldata userData, bytes calldata operatorData ) external override{ require(msg.sender == address(_token), "Simple777Recipient: Invalid token"); emit DoneStuff(operator, from, to, amount, userData, operatorData); } – Alec Jeffery Nov 13 '21 at 18:01
  • Is something like the require statement in the above code what you have in mind? – Alec Jeffery Nov 13 '21 at 18:03
  • @AlecJeffery Exactly – Petr Hejda Nov 13 '21 at 19:25