If a token conforms to the ERC: Token standard #20, a transfer of tokens will normally invoke a transfer(address _to, uint256 _amount)
method.
Using The DAO as an example,
[1] contract TokenInterface
's transfer(...)
defines the following interface:
function transfer(address _to, uint256 _amount) returns (bool success);
[2] contract Token is TokenInterface
's transfer(...)
implements the following method:
function transfer(address _to, uint256 _amount) noEther returns (bool success) {
if (balances[msg.sender] >= _amount && _amount > 0) {
balances[msg.sender] -= _amount;
balances[_to] += _amount;
Transfer(msg.sender, _to, _amount);
return true;
} else {
return false;
}
}
[3] contract DAO is DAOInterface, Token, TokenCreation
's transfer(...)
overrides the method in [2] above:
function transfer(address _to, uint256 _value) returns (bool success) {
if (isFueled
&& now > closingTime
&& !isBlocked(msg.sender)
&& transferPaidOut(msg.sender, _to, _value)
&& super.transfer(_to, _value)) {
return true;
} else {
throw;
}
}
When you execute a The DAO transfer, you will be calling [3] above. [3] will call [2] which will perform the check on whether you have enough token balance to transfer. If you don't, then [2] will return false. When [3] receives a return status of false from [2], an error is thrown.
When an error is thrown, the Ethereum VM will consume gas equal to the amount of gas supplied. The only reliable way to check whether the transfer function has executed without any errors is to check the transaction status using the following logic as detailed in How can the transaction status from a thrown error be detected when gas can be exactly the same as the gasUsed for a successful transaction? :
> var status = debug.traceTransaction("{transaction id}")
undefined
> if (status.structLogs.length > 0) {
console.log(status.structLogs[status.structLogs.length-1].error)
}
"invalid jump destination (PUSH1) 2"
If the result of the check above is "" then no error occurred and your transfer(...)
call was successful. If the result is "Out of gas" or "invalid jump destination (PUSH1) 2", then an error occurred and your transfer(...)
call failed.
Example Of A Failed The DAO Transfer(...)
From https://etherscan.io/tx/0xde5f71e76dc87bfcc16649c16f512a5b3086efd4cdaa31b8ee848a978b53b8b7
And here is the debug.traceTransaction(...)
results run in geth
:
> var status = debug.traceTransaction("0xde5f71e76dc87bfcc16649c16f512a5b3086efd4cdaa31b8ee848a978b53b8b7")
undefined
> if (status.structLogs.length > 0) {
... console.log(status.structLogs[status.structLogs.length-1].error)
... }
invalid jump destination (PUSH1) 2