2

Here is a code snippet from the ERC223-token-standard.

function transfer(address _to, uint _value, bytes _data) {
    // Standard function transfer similar to ERC20 transfer with no _data .
    // Added due to backwards compatibility reasons .
    uint codeLength;

    assembly {
        // Retrieve the size of the code on target address, this needs assembly .
        codeLength := extcodesize(_to)
    }

    balances[msg.sender] = balances[msg.sender].sub(_value);
    balances[_to] = balances[_to].add(_value);
    if(codeLength>0) {
        ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
        receiver.tokenFallback(msg.sender, _value, _data);
    }
    Transfer(msg.sender, _to, _value, _data);
}

What I don't understand is that how do these two lines work:

ERC223ReceivingContract receiver = ERC223ReceivingContract(_to);
receiver.tokenFallback(msg.sender, _value, _data);

No new instance is created here but we are still calling the function. How can we call the contract function like that? There is no contstruct in the ERC223RecievingContract yet here the address is passed. What exactly is happening here?

3 Answers 3

4

Any smart contract wanting to interact with an ERC223 token is supposed to implement the tokenFallback() function to handle incoming token transfers.

Those 2 lines call that function on the target account (if it is a smart contract) so, the target smart contract MUST have previously implemented the tokenFallback() function.

As can be seen in the example implementation, the tokenFallback() function can be used to retrieve all the data that was sent by the transfer() call and use it however you want within your receiver contract:

https://github.com/Dexaran/ERC223-token-standard/blob/Recommended/Receiver_Interface.sol

2
  • ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); , this code does not make an instance of the receiving contract so how are we calling its function? Is ERC223ReceivingContract a constructor? Commented Dec 27, 2017 at 11:08
  • 2
    When you do ContractX x = ContractX(contract's Address) you are instantiating an existing contract at the address specified. If you know its functions you may call them from another contract. Commented Dec 27, 2017 at 12:39
2

It's the same as fallback functions for Ether.

from the docs:

ERC223 tokens should be sent by calling transfer function on token contract with no difference is receiver a contract or a wallet address. If the receiver is a wallet ERC223 token transfer will be same to ERC20 transfer. If the receiver is a contract ERC223 token contract will try to call tokenFallback function on receiver contract. If there is no tokenFallback function on receiver contract transaction will fail. tokenFallback function is analogue of fallback function for Ether transactions. It can be used to handle incoming transactions.

This might not be so clear but it entails the following:

ERC223 Tokens should be used by sending transfer. If the recipient is a wallet then there will be no issue. If the recipient is a contract then transfer will try to call the tokenFallback function. If no tokenFallback is present, the transaction will fail.

You can however choose to implement a tokenFallback to handle incoming token transactions to your contract. Following example will reject all incoming token transactions except for the ones issued by the crowdsale, those it will add back to the available crowdsale balance.

  function tokenFallback(address, uint _value, bytes)
      isToken
      public {
      _available = _available.add(_value);
  }

As previously stated by Pabloruiz55 it can also be used to get the transaction information : msg.sender, msg.value & msg.data you can also send these values along if you choose to implement a tokenFallback function since they are passed in as function parameters.

4
  • 1
    Can you tell me how this code is working : ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); Commented Dec 27, 2017 at 11:09
  • If the receiver (_to) is a contract you will instantiate the already defined ERC223ReceivingContract at that address from which you can then call the tokenFallback. ERC223ReceivingContract receiver = ERC223ReceivingContract(_to); defining variable 'type' (here instance of contract --- we call the variable receiver --- we invoke the contract with the parameter _to Commented Dec 27, 2017 at 13:01
  • 2
    Sorry I was wrong. You are not intantiating a new contract on the address of _to. You are only specifiying that contract can be found there if it is implemented. For more on this subject check out the following youtube video: youtube.com/watch?v=l_E5F5qnbtk Commented Dec 27, 2017 at 15:53
  • @Kyriediculous. Thanks, but how can Solidity restore the token balances? Please see my answer below...
    – Russo
    Commented Jan 10, 2018 at 10:47
0

Thanks to Kyriediculous for Polymorphism explanation at Tutorial 17 Polymorphism https://www.youtube.com/watch?v=l_E5F5qnbtk

   ContractReceiver receiver = ContractReceiver(_to);

we are only assuming at the address _to there is a contract(or interface implementation) called ContractReceiver

    receiver.tokenFallback(msg.sender, _value, _data);

and now we are assuming that such contract at _to has tokenFallback function

but if such function or such contract does not exist at such address, we get failure... then what?

I found it here: EIP Breakdown: The ERC 223 Token Standard https://www.youtube.com/watch?v=GS62VNyPVHs Also see "Ethereum Cross Chain Atomic Swaps" for atomic transactions https://medium.com/@DontPanicBurns/ethereum-cross-chain-atomic-swaps-5a91adca4f43

In Solidity, transactions are called atomic, that means either the entire transaction all succeed together, or all fail together. So even if there is one line( receiver.tokenFallback() ) in the function fails, the entire function will fail all together. Then the balances will be restored to their original values.

Solved for ERC223 tokens transfer to contract not compatible fail error/failure

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.