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
^