Search code examples
byteethereumblockchainsoliditysmartcontracts

uint256(uint160(msg.sender)) and uint256(bytes32(bytes20(msg.sender))) return different results


I don't know why uint256(uint160(msg.sender)) and uint256(bytes32(bytes20(msg.sender))) return different results .

contract test {
    
     function check1() public  view returns(uint ) {
        return uint256(uint160(msg.sender)) ; 
    }

     function check2() public  view returns(uint ) {
        return uint256(bytes32(bytes20(msg.sender))) ;
    }



}

The function check1() returns the value 520786028573371803640530888255888666801131675076 ; The function check2() returns the value 41260920106969412157321674113669319076297763250177730552014715551905833025536 which is vastly larger than the previous value .

in theory, both check2() and check3() should return the same numerical value representing the msg.sender address because there was no loss of information . msg.sender is indeed 20 bytes and uint160 . I don't know where , specifically , that both values become different .


Solution

  • Short answer: bytes32 pads the bytes20 object with zeros to the right.

    This can be seen by returning the bytes instead of trying to convert them to a uint256.

    
    pragma solidity ^0.8.20;
    
    contract Test {
        
         function check1() public  view returns(bytes20) {
            return bytes20(msg.sender) ; 
        }
    
         function check2() public  view returns(bytes32) {
            return bytes32(bytes20(msg.sender)) ;
        }
    
    }
    

    Calling check1() gives me: 0x5b38da6a701c568545dcfcb03fcb875f56beddc4
    Calling check2() gives me: 0x5b38da6a701c568545dcfcb03fcb875f56beddc4000000000000000000000000

    As for why, I'm not sure if this is because how memory gets read to the stack when returned or if this is something to do with explicit conversion and padding rules. If I figure it out, I'll let you know.