16

How to convert bytes or string (eg: 0xf2bd5de8b57ebfc45dcee97524a7a08fccc80aef) to address in solidity?

10 Answers 10

4

I feel like there might be a more efficient way to do this but here's my naive solution:

function bytesToAddress (bytes b) constant returns (address) {
    uint result = 0;
    for (uint i = 0; i < b.length; i++) {
        uint c = uint(b[i]);
        if (c >= 48 && c <= 57) {
            result = result * 16 + (c - 48);
        }
        if(c >= 65 && c<= 90) {
            result = result * 16 + (c - 55);
        }
        if(c >= 97 && c<= 122) {
            result = result * 16 + (c - 87);
        }
    }
    return address(result);
}
5
  • Can you explain how this works?
    – Miguel
    Commented Oct 26, 2017 at 1:03
  • For sure! Assume our address is: 0x1A3b4 which you will give to the function as "1A3b4". What happens is: 1) We enter in the for loop 2) Grab the first character ("1") and cast it to a uint. In this case the ASCII corresponding to "1" is 49. 3) Since "1" = 49, we fall into the 1st "if" clause. It subtracts 48 to get integer 1. Then we take result, multiply it by 16 because address is base 16, and add it to the result.
    – erkt
    Commented Nov 6, 2017 at 9:12
  • We repeat with the next character in the byte ("A"). We cast that to a uint which gives us "A" == 65. We fall into the 2nd "if". We then take result which equals 1 multiply it by 16 and add 65-55 = 10, which is what A is in hex.
    – erkt
    Commented Nov 6, 2017 at 9:12
  • It also helps to think what happens in the case of base 10 strings. Because what were essentially doing in this function is taking the string representation of a number and converting it to a number type. Hope that helps @MiguelMota
    – erkt
    Commented Nov 6, 2017 at 9:13
  • for me uint c = uint(b[i]); should be uint c = uint(uint8(b[i]));
    – ASHKARAN
    Commented May 10, 2022 at 11:18
19

If the bytes argument is of length 20, that is, the length of an address, this assembly one-liner works for me:

function bytesToAddress(bytes bys) private pure returns (address addr) { assembly { addr := mload(add(bys,20)) } }

4
  • Best answer, for sure!
    – LampShade
    Commented Apr 16, 2020 at 0:57
  • 1
    Can you please explain why you add 20 to the start address? Commented Dec 14, 2021 at 10:13
  • 3
    Can't you just do (address addr) = abi.decode(theBytes, (address)); ? Commented Dec 14, 2021 at 10:44
  • @LukeHutchison you'd think, but I tried and the transaction got reverted with "Error: Transaction reverted and Hardhat couldn't infer the reason. Please report this to help us improve Hardhat" when I changed to the line you proposed
    – nnsk
    Commented Feb 16, 2022 at 5:30
4

Other solution:

function bytesToAddress(bytes calldata b) private pure returns (address) {
    return address(uint160(bytes20(b)));
}  
3

If the bytes argument has a standard length of 64, that is, the first 32 bytes specify its length and the second 32 bytes specify its content, do this:

function bytesToAddress(bytes bys) private pure returns (address addr) {
    assembly {
        addr := mload(add(bys, 32))
    } 
}

All credit goes to Paul Steckler

4
  • What specifies what format the data will be in, if this is referring to a way of decoding the bytes return value from address.call()? This is different from Paul Steckler's own answer, above. Commented Dec 14, 2021 at 10:26
  • @LukeHutchison if I understand correctly, you are calling an external contract via address.call(), then you are receiving some data, and you want to know what format that data has. Well, that totally depends on the contract you are calling. It can send whatever data using whatever format. However, there is a standard for encoding data, which is defined by Solidity and generally respected elsewhere. Take a look at it here: docs.soliditylang.org/en/v0.8.11/abi-spec.html#abi
    – e18r
    Commented Jan 11, 2022 at 22:45
  • thanks, yes, I have seen that link before. But what I was asking about was why this answer uses addr := mload(add(bys, 32)) while Paul Steckler's answer uses addr := mload(add(bys, 20)). Also there is no explanation of why the first 32 or 20 bytes are being skipped (is it just a matter of skipping padding?) Finally, does this work? (address addr) = abi.decode(theBytes, (address)); -- doesn't this avoid assembly altogether? Does it return the same result as one of the two assembly examples? Commented Jan 13, 2022 at 2:45
  • @LukeHutchison in my answer, the first 32 bytes specify the length of the string variable and the second 32 are the actual content. That's why I skip the first 32 bytes. As for Paul Steckler's answer, I'm not sure. And for your last question, I have no idea. I haven't used Solidity in a while. Sorry.
    – e18r
    Commented Jan 21, 2022 at 23:09
3

if address was packed using abi.encodedPacked(address) then this would work, since you need to pad left to get the correct bytes back

assembly {
    parsed := div(mload(add(data, 32)), 0x1000000000000000000000000)
}

or (div by 0x1.... is like doing >> 96)

assembly {
    parsed := shr(96, mload(add(data, 32)))
}
1
  • Is this true of bytes returned from address.call(), where the return type is address? Commented Dec 14, 2021 at 10:28
1

Converting from bytes (or string) to address:

  function bytesToAddress(bytes _address) public returns (address) {
    uint160 m = 0;
    uint160 b = 0;

    for (uint8 i = 0; i < 20; i++) {
      m *= 256;
      b = uint160(_address[i]);
      m += (b);
    }

    return address(m);
  }

Usage

address addr = bytesToAddress("0xa462d983B4b8C855e1876e8c24889CBa466A67EB");

If calling from Remix IDE, pass bytes like this:

["0xa4", "0x62", "0xd9", "0x83", "0xB4", "0xb8", "0xC8", "0x55", "0xe1", "0x87", "0x6e", "0x8c", "0x24", "0x88", "0x9C", "0xBa", "0x46", "0x6A", "0x67", "0xEB"]
1

erkt's answer didn't work for me this is the solution I wrote based on it. It converts the hex bytes to uint and sums them all up then converts the uint sum to an address:

function bytesToAddr (bytes b) constant returns (address) {
  uint result = 0;
  for (uint i = b.length-1; i+1 > 0; i--) {
    uint c = uint(b[i]);
    uint to_inc = c * ( 16 ** ((b.length - i-1) * 2));
    result += to_inc;
  }
  return address(result);
}
2
  • Likewise for me: the accepted answer (erkt) did not work. Your answer has worked for me though, at least for the inputs I have tried. Thanks! Commented Jan 5, 2018 at 19:31
  • Hey, I just tested my solution on Remix. Could you tell me what is wrong with my solution? Does it not compile? Or is the output wrong? If wrong output, I suspect it is because you are prefixing with "0x". So instead of doing "0xabc", just pass in "abc".
    – erkt
    Commented Jan 5, 2018 at 23:42
0

STRING to ADDRESS:

You can use Oraclize's own helper method:

contract usingOraclize { function parseAddr(string _a) internal returns (address); ... }

There https://github.com/oraclize/ethereum-api/blob/master/oraclizeAPI_pre0.4.sol#L149

    function parseAddr(string _a) internal returns (address){
     bytes memory tmp = bytes(_a);
     uint160 iaddr = 0;
     uint160 b1;
     uint160 b2;
     for (uint i=2; i<2+2*20; i+=2){
         iaddr *= 256;
         b1 = uint160(tmp[i]);
         b2 = uint160(tmp[i+1]);
         if ((b1 >= 97)&&(b1 <= 102)) b1 -= 87;
         else if ((b1 >= 48)&&(b1 <= 57)) b1 -= 48;
         if ((b2 >= 97)&&(b2 <= 102)) b2 -= 87;
         else if ((b2 >= 48)&&(b2 <= 57)) b2 -= 48;
         iaddr += (b1*16+b2);
     }
     return address(iaddr);
    }
0

Here is how I would do this:

// Convert 32 hexadecimal digits into 16 bytes.
function hexToBytes16 (bytes32 h) internal pure returns (bytes16 b) {
    unchecked {
        // Ensure all chars below 128
        require (h & 0x8080808080808080808080808080808080808080808080808080808080808080 == 0);

        // Subtract '0' from every char
        h = bytes32 (uint256 (h) - 0x3030303030303030303030303030303030303030303030303030303030303030);

        // Ensure all chars still below 128, i.e. no underflow in the previous line
        require (h & 0x8080808080808080808080808080808080808080808080808080808080808080 == 0);

        // Calculate mask for chars that originally were above '9'
        bytes32 ndm = bytes32 ((((uint256(h) + 0x7676767676767676767676767676767676767676767676767676767676767676) & 0x8080808080808080808080808080808080808080808080808080808080808080) >> 7) * 0xFF);

        // Subtract 7 ('A' - '0') from every char that originally was above '9'
        h = bytes32 (uint256 (h) - uint256 (ndm & 0x0707070707070707070707070707070707070707070707070707070707070707));

        // Ensure all chars still below 128, i.e. no underflow in the previous line
        require (h & 0x8080808080808080808080808080808080808080808080808080808080808080 == 0);

        // Ensure chars that originally were above '9' are now above 9
        require (uint256 (h) - uint256 (ndm & 0x0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A) & 0x8080808080808080808080808080808080808080808080808080808080808080 == 0);

        // Calculate Mask for chars that originally were above 'F'
        bytes32 lcm = bytes32 ((((uint256(h) + 0x7070707070707070707070707070707070707070707070707070707070707070) & 0x8080808080808080808080808080808080808080808080808080808080808080) >> 7) * 0xFF);

        // Subtract 32 ('a' - 'A') from all chars that oroginally were above 'F'
        h = bytes32 (uint256 (h) - uint256 (lcm & 0x2020202020202020202020202020202020202020202020202020202020202020));

        // Ensure chars that originally were above 'F' are now above 9
        require (uint256 (h) - uint256 (lcm & 0x0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A) & 0x8080808080808080808080808080808080808080808080808080808080808080 == 0);

        // Ensure all chars are below 16
        require (h & 0xF0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0 == 0);

        // 0x0A0B0C0D... -> 0xAB00CD00...
        h = (h & 0x0F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F00) << 4 | (h & 0x000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F000F) << 8;

        // 0xAA00BB00CC00DD00... -> 0xAABB0000CCDD0000...
        h = h & 0xFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF000000 | (h & 0x0000FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF00) << 8;

        // 0xAAAA0000BBBB0000CCCC0000DDDD0000... -> 0xAAAABBBB00000000CCCCDDDD00000000...
        h = h & 0xFFFF000000000000FFFF000000000000FFFF000000000000FFFF000000000000 | (h & 0x00000000FFFF000000000000FFFF000000000000FFFF000000000000FFFF0000) << 16;

        // 0xAAAAAAAA00000000BBBBBBBB00000000CCCCCCCC00000000DDDDDDDD00000000 -> 0xAAAAAAAABBBBBBBB0000000000000000CCCCCCCCDDDDDDDD0000000000000000
        h = h & 0xFFFFFFFF000000000000000000000000FFFFFFFF000000000000000000000000 | (h & 0x0000000000000000FFFFFFFF000000000000000000000000FFFFFFFF00000000) << 32;

        // 0xAAAAAAAAAAAAAAAA0000000000000000BBBBBBBBBBBBBBBB0000000000000000 -> 0xAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBB00000000000000000000000000000000
        h = h & 0xFFFFFFFFFFFFFFFF000000000000000000000000000000000000000000000000 | (h & 0x00000000000000000000000000000000FFFFFFFFFFFFFFFF0000000000000000) << 64;

        // Trim to 16 bytes
        b = bytes16 (h);
    }
}

function parseAddress (string memory s) public pure returns (address) {
    require (bytes(s).length == 42);
    bytes2 prefix;
    bytes32 leftHex;
    bytes32 rightHex;
    assembly {
        prefix := mload (add (s, 0x20))
        leftHex := mload (add (s, 0x22))
        rightHex := mload (add (s, 0x2A))
    }
    require (prefix == '0x');
    bytes16 left = hexToBytes16(leftHex);
    bytes16 right = hexToBytes16(rightHex);
    return address (bytes20 (left) | bytes20 (right) >> 32);
}

This approach is significantly more efficient, than the accepted answer. Also it reverts on invalid addresses.

-3

Not sure if this is what you mean:

Use mapping. Try something like this:

mapping (string => address) variable;

then assign: variable["hello"] = address;

variable["hello"]; // should return an address

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.