Hi what does these lines mean?

function tokenFallback(address _from, uint _value, bytes _data) {
    uint32 u = uint32(_data[3]) + (uint32(_data[2]) << 8) + (uint32(_data[1]) << 16) + (uint32(_data[0]) << 24);
    tkn.sig = bytes4(u);

I know tkn.sig is the 4 bytes signature of function. But could someone explain how those two lines work?


tokenFallback receives a third parameter, _data, which can be any arbitrary data. How it gets interpreted by the contract is very much contract-specific. The code you pasted seems to just be converting the first four bytes of _data into a bytes4 to store at tkn.sig. I can't speculate as to why without seeing the rest of the code. (E.g., it would be interesting to see how tkn is being used.)


It looks like the code comes from https://github.com/Dexaran/ERC223-token-standard/blob/Recommended/Receiver_Interface.sol#L17. The rest of the function, including the comment, is illuminating:

function tokenFallback(address _from, uint _value, bytes _data){
    TKN memory tkn;
    tkn.sender = _from;
    tkn.value = _value;
    tkn.data = _data;
    uint32 u = uint32(_data[3]) + (uint32(_data[2]) << 8) + (uint32(_data[1]) << 16) + (uint32(_data[0]) << 24);
    tkn.sig = bytes4(u);

    /* tkn variable is analogue of msg variable of Ether transaction
    *  tkn.sender is person who initiated this token transaction   (analogue of msg.sender)
    *  tkn.value the number of tokens that were sent   (analogue of msg.value)
    *  tkn.data is data of token transaction   (analogue of msg.data)
    *  tkn.sig is 4 bytes signature of function
    *  if data of token transaction is a function execution

I surmise that _data here is being treated like in a non-token scenario, where the first four bytes are a function selector (the first four bytes of the keccak256 hash of the function signature). Presumably this is so the token receiver can invoke a function to handle the inbound tokens, much like a payable function handles inbound transactions.

| improve this answer | |

Fixed-size byte arrays
bytes1, bytes2, bytes3, …, bytes32. byte is an alias for bytes1.
Dynamically-sized byte array bytes: Dynamically-sized byte array, see Arrays. Not a value-type!
Variables of type bytes and string are special arrays. A bytes is similar to byte[], but it is packed tightly in calldata. string is equal to bytes but does not allow length or index access (for now). So bytes should always be preferred over byte[] because it is cheaper.
So the argument bytes _data means: _data is a Dynamically-sized byte array, and each element is of type byte1
_data[3], _data[2], _data[1], _data[0] are the first 4 elements of _data
uint32(_data[3]) is to convert _data[3] into a number of uint32
** (exponentiation), << (left shift), >> (right shift)
The expression x << y is equivalent to x * 2**y, and x >> y is equivalent to x / 2**y
So uint32(_data[2]) << 8 is equivalent to uint32(_data[2]) * 2**8
the same for _data[1] and _data[0]
then add them all together to make uint32 u
then convert u into bytes4 by bytes4(u)
Wow, that is complicated ... I hope I didn't make any mistakes :)

| improve this answer | |
  • 1
    That all looks right. – user19510 Jan 13 '18 at 16:36

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.