Yes, token-transfer always has a value of 0 (as the value attribute is associated with Ether), but the data part will have some value when doing a token transfer. I have worked on this topic recently, I myself wanted to know the same. To understand it much better I had to filter some transactions and check myself how does an ETH transaction differ from token transfer. All the below transactions are taken from TESTNET:
ETH TRANSFER
Transaction Hash: 0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6
Transaction log:
> web3.eth.getTransaction("0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6");
{ blockHash: '0x06111bf75fb9108dc5596ddbb6e2e843ee13830987688a90df2ab0772815fa96',
blockNumber: 1488295,
from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619',
gas: 21000,
gasPrice: { [String: '31000000000'] s: 1, e: 10, c: [ 31000000000 ] },
hash: '0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6',
input: '0x',
nonce: 261,
to: '0xb1aa0ac057639e534a89b095853befc4d6d264cf',
transactionIndex: 0,
value: { [String: '1000000000000000000'] s: 1, e: 18, c: [ 10000 ] },
v: '0x2a',
r: '0x3b4202fda27b6fdfb6985e10ffcd7b5f9f2a64e31fc75d444d6a7684a75f3b',
s: '0x5bb67429e6cae209f53ad5c1538d0c3d0035f12e92a569c0b2898512d9cdeae5' }
Transaction Receipt:
> web3.eth.getTransactionReceipt("0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6");
{ blockHash: '0x06111bf75fb9108dc5596ddbb6e2e843ee13830987688a90df2ab0772815fa96',
blockNumber: 1488295,
contractAddress: null,
cumulativeGasUsed: 21000,
from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619',
gasUsed: 21000,
logs: [],
logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000',
root: '0x6a29376fb5c83a4617fecc1b95c1353f37711912128fd3b6bce9dde57b8130b3',
to: '0xb1aa0ac057639e534a89b095853befc4d6d264cf',
transactionHash: '0x27c3fe1bc90723e5d7e0dbc3429e71faa967a623c8e4c49df0739283c17718e6',
transactionIndex: 0 }
If you carefully check the above logs, the value property in the Transaction Log has the value of 1000000000000000000 wei i.e. 1 Ether. and the Input is 0x
Similarly the Logs in the Transaction Receipt is an empty object. Which will not be empty when a token transfer happens.
TOKEN TRANSFER
Ropesten Transaction Details: 0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677
Transaction Log
web3.eth.getTransaction("0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677");
{ blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834',
blockNumber: 1535104,
from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619',
gas: 223616,
gasPrice: { [String: '22000000000'] s: 1, e: 10, c: [ 22000000000 ] },
hash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677',
input: '0xa9059cbb0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e0000000000000000000000000000000000000000000000000000000000000001',
nonce: 267,
to: '0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9',
transactionIndex: 7,
value: { [String: '0'] s: 1, e: 0, c: [ 0 ] },
v: '0x1b',
r: '0x4ad36e9eefd233abce864b3e53b86d1b937bcea83223564e4f56cc7defbcde3e',
s: '0x22f256f9fe62187dc0e8942981ef52ae3643d04f50e00957c94e10b8da4e3116' }
If you check the above transaction Log, it clearly suggests that this transaction was a Token Transfer, as the below properties help us:
- Input: '0xa9059cbb0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e0000000000000000000000000000000000000000000000000000000000000001'
0xa9059cbb is the hex for transfer.
0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e is the address to which the token was sent with left padding upto 64 places
0000000000000000000000000000000000000000000000000000000000000001 is the number of tokens to be sent left padded upto 64 places.
value
property is 0x0 (this shows no ether were sent)
Transaction Receipt
web3.eth.getTransactionReceipt("0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677");
{ blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834',
blockNumber: 1535104,
contractAddress: null,
cumulativeGasUsed: 352435,
from: '0x76e0bb92b6f8d431af2fe1bafd304eb832241619',
gasUsed: 36979,
logs:
[ { address: '0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9',
topics: [Object],
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
blockNumber: 1535104,
transactionHash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677',
transactionIndex: 7,
blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834',
logIndex: 6,
removed: false } ],
logsBloom: '0x00000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008080000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000400000000000000000000000000000004000000000000000000000000000000400000000000000000001000000000000000000002000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000',
root: '0x9840ddaa4571522013623410420a11689fc44184d52d541d4f1067adcdde9e8c',
to: '0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9',
transactionHash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677',
transactionIndex: 7 }
As I said earlier, the logs property when a ETH trasnfer happens is empty but when a token transfer happens logs property has an object which helps in identifying to/from which address the token got transferred. the data property helps in knowing the amount of tokens transferred.
address:'0x5c99dadde01ce61ab5b5536d566bf41ecd17e3a9',
topics:
[ '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
'0x00000000000000000000000076e0bb92b6f8d431af2fe1bafd304eb832241619',
'0x0000000000000000000000002b3425ce986f9f0f599758f4fb33158ca671e83e' ],
data: '0x0000000000000000000000000000000000000000000000000000000000000001',
blockNumber: 1535104,
transactionHash: '0x14632d129a6aac7365483a3000470ece443a19a73f242cba1f1944f78889a677',
transactionIndex: 7,
blockHash: '0x34ee516310a59407712455ec87bd76046a1e68f5c631dc8e6b4bb903b8c92834',
logIndex: 6,
removed: false } ]
If I remember it correctly,to distinguish much more clearly between transactions, you can try using the a logParser made using SolidityEvent Library which can be found inside web3.js. Here is the link to the same.