5

when I am using below function to convert bytes memory to address, this is working fine.

Suppose input to the function is 0X0000000000000000000000004af3246b4fff356261136f113411cb187134D675

I am getting the output 0x4af3246b4fff356261136f113411cb187134D675

    function bytesToAddress(bytes memory bys) public pure returns (address addr) {

        assembly {
             addr := mload(add(add(bys, 32), 0))
       }
    }

Can, anyone explain me, what actually happening ?

2

The expression add(bys, 32):

Returns a pointer to the actual data, which starts after the first 32 bytes in the bys array (those first 32 bytes contain the length of the bys array).


The expression mload(x):

Loads the data pointed to by x, so you can just as well use mload(add(bys, 32)), because there is no added value in doing x + 0.


The expression addr := y:

Stores the value of y into the variable addr (in your case, since the value of y is 32-byte long and the type of addr is 20-byte long, only the 20 least significant bytes are stored).

| improve this answer | |
  • Okay ,but when I am giving 32 bytes (64 characters) input to the function having first 24 characters zeros ,, how I am getting 20 bytes (40 characters) as output. – Pardeep Thakur May 4 at 13:07
  • @PardeepThakur: Just as you would whenever you assign a larger-type variable into a smaller-type variable, for example, uint16 x = 0x1234; and then uint8 y = x;. The value of y would be the value of the 8 lower bits of x, i.e., 0x34. The only thing is, that in pure Solidity, the compiler would ask you to explicitly cast x to the type of y, i.e., uint8 y = uint8(x);. And in assembly, the compiler performs the down-cast implicitly. – goodvibration May 4 at 13:19
  • Thank you, I got it – Pardeep Thakur May 4 at 14:59
2

You may meet the following code in many projects:

contract A {

    event Log(address addr);

    function() external {
        emit Log(bytesToAddress(msg.data));
    }

    function bytesToAddress(bytes memory source) public pure returns(address addr) {
        assembly {
            addr := mload(add(source, 0x14))
        }
    }
}

Actually source when meet in assembly refers to 52 bytes:

0000000000000000000000000000000000000000000000000000000000000020
4af3246b4fff356261136f113411cb187134D675

So shifting 0x14 bytes (20 bytes) means capturing this value:

                                        V
0000000000000000000000000000000000000000000000000000000000000020
4af3246b4fff356261136f113411cb187134D675
                                       ^

This:

0000000000000000000000204af3246b4fff356261136f113411cb187134D675

But since return type is address Solidity compiler inserts code to erase top-12 bytes of address:

addr = addr & ((1 << 160) - 1)

Which leads to:

0000000000000000000000204af3246b4fff356261136f113411cb187134D675
&
000000000000000000000000ffffffffffffffffffffffffffffffffffffffff
=
0000000000000000000000004af3246b4fff356261136f113411cb187134D675
                      ^
| improve this answer | |

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.