4

If someone implements the ERC20 transfer() function without the return value as follows:

function transfer(address to, uint256 value) public {
    require( ... usual checks ... );
    balances_[msg.sender] -= value;
    balances_[to] += value;

    emit Transfer(to, value);
}

But a calling contract expects the return value:

  function transfer(address to, uint256 value) public returns (bool)

and calls the function somehow like:

ERC20 token = (ERC20)someaddress;
if (!token.transfer(to,amt)) { ... }

Assuming someaddress is correct, what happens?

I imagine that the transfer function would run ok but return nothing, causing the caller to receive a false. The balances would be updated and an event would be emitted.

Am I correct? Would the call fail? Some exception?

Thanks!

3

The Yellow Paper provides the answer. And the answer is that the behavior is undefined and unforeseeable. The call will not fail, so tokens will be transferred, but the return value cannot be trusted and is undefined (in the sense that in the general case, we cannot predict what it will be).

The 2nd image below shows that the memory of the caller (the smart contract making the call to the other contract) will not be updated by this function call. So the caller will read from a part of its own memory that may be zero and may be anything else and evaluate that as a boolean value, the returned value -- meaning that it will be false if the memory was previously undeclared or set to zero, and that it will be true if that part of memory was set to a non-zero value but the compiler determined that that non-zero value was no longer needed.

Definition of the ouput data

Part of the definition of the CALL opcode
This last picture shows a part of the definition of the opcode CALL. µ[5] indicates the start of the memory where the result from the callee will be stored, µ[6] is the output size that the caller expects, and n is in our case the size of the output from the callee, which is 0. So no memory in the caller VM will be updated so the caller will simply read what is present on the memory location µ[5] to µ[5]+µ[6] before the call takes place and interpret that as the return value. I believe that this value will in most (all?) cases be 0x0 (false) so the caller will interpret the result of the callee as false.

  • I have not run this code, I have only deduced the answer. If you want to be certain that this answer is correct, you should perform some tests yourself or hope that someone smarter than me will answer :) – Thorkil Værge Apr 27 '18 at 12:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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