Solidity 0.5.x – Converting from Bytes

bytescontract-developmentsolidity

I'd like to convert bytes into any other type. I.e. "0x57D80C61128d608857d5310BB514223Bb6011CAB" into the address 0x57D80C61128d608857d5310BB514223Bb6011CAB, "5" into the uint256 5 and so on. I have followed all the snippets I could find but I can't get any of them working post 0.5.0. I believe the culprit is the change outlined here:

Conversions between bytesX and uintY of different size are now disallowed due to bytesX padding on the right and uintY padding on the left which may cause unexpected conversion results. The size must now be adjusted within the type before the conversion. For example, you can convert a bytes4 (4 bytes) to a uint64 (8 bytes) by first converting the bytes4 variable to bytes8 and then to uint64. You get the opposite padding when converting through uint32.

Taking the uint example, here is some code that would have worked prior to this version of the compiler:

function bytesToUInt(string memory _b) public returns (uint256){
  bytes memory b = bytes(_b);
  uint256 number;
  for(uint i=0;i<b.length;i++){
    number = number + uint(b[i])*(2**(8*(b.length-(i+1))));
  }
  return number;
}

But this now results in a TypeError: Explicit type conversion not allowed, I've tried moving things around and adding extra conversions but nothing has worked.

For bytes to address, I've tried this:

function bytesToAddress(string memory _b) public returns (address) {
    bytes20 b = bytes20(bytes(_b));
    return address(uint160(b));
}

But you can't explicitly convert from bytes memory to bytes20 and I couldn't get that working either.

Can someone show me how this is done properly? Thanks.

Best Answer

As far as I know, you will need inline assembly. Someone already posted some code applicable to previous solidity versions at least, although generally short and correct inline assembly should be pretty universal.

Here's some code that converts some bytes from memory to bytes20 (only the first 20, it gets truncated if over that of course).

contract t {
    function tb20(bytes memory _b) 
    public
    pure
    returns (bytes20 _result) {
        assembly {
            _result := mload(add(_b, 0x20))
        }
    }

    function bytesToAddress(bytes memory _b) 
    public 
    returns (address) {
        return address(tb20(_b));
    }
}

No guarantees or warranties on the code but it appears to work. Can of course change up tb20 to return an address instead, although you'll need shifts then.