Search code examples
ethereumsoliditysmartcontracts

How does this type casting msg.sender to uint32 work?


I ran into this example while working through "ethereumbook" on github. In the following code, how does casting the msg.sender address to a uint32 variable determine if the last 8 hexadecimal characters are zero?

contract HashForEther {

function withdrawWinnings() {
    // Winner if the last 8 hex characters of the address are 0
    require(uint32(msg.sender) == 0);
    _sendWinnings();
     }

 function _sendWinnings() {
     msg.sender.transfer(this.balance);
     }
}

I don't have a great understanding of how hex works, which probably isn't helping me but I don't see how changing msg.sender to a uint32 gives insight on only the last four characters. Is it because 4*8=32 and uint32 takes the value from smallest denomination to highest?


Solution

  • msg.sender is a global variable of type address, which has length of 160 bits (== 20 bytes).

    uint32 is an unsigned integer type of size 32 bits (== 4 bytes).

    Each byte can be represented as 2 hexadecimal characters. For example a byte consisting of all 8 binary ones (11111111) is represented as 0xff.

    Now, 32 bits, that's 4 bytes, and also 8 hex characters. So that's why the code comment mentiones 8 hex characters.


    When you're performing a type conversion into smaller type, it removes the higher-positioned bits.

    While direct conversion between address and uint<N> was available in previous Solidity versions (until v0.7.6), it is not available in the current version (0.8.x) and you need to do some workarounds to convert address into uint32, my example shows a more straightforward conversion just between numbers:

    pragma solidity ^0.8;
    
    contract MyContract {
        function foo() external pure returns (uint8) {
            uint16 larger = 512;           // binary 00000011 00000000
            uint8 smaller = uint8(larger); // binary          00000000
            return smaller;
        }
    }
    

    Docs: https://docs.soliditylang.org/en/v0.8.20/types.html#explicit-conversions


    Given your example, uint32(msg.sender) == 0 is true when the last 32 bits (== 8 hex characters) are zero.

    E.g. the hex representation of address 0xabcdabcdabcdabcdabcdabcdabcdabcd00000000 (ending with 8 zero hex characters) can be also represented as the following (ending with 32 zero bits).

    10101011 11001101 10101011 11001101 // hex `abcdabcd`
    10101011 11001101 10101011 11001101 // hex `abcdabcd`
    10101011 11001101 10101011 11001101 // hex `abcdabcd`
    10101011 11001101 10101011 11001101 // hex `abcdabcd`
    00000000 00000000 00000000 00000000 // hex `00000000`