11

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

8 Answers 8

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? 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
    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
    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
    Nov 6, 2017 at 9:13
  • for me uint c = uint(b[i]); should be uint c = uint(uint8(b[i]));
    – ASHKARAN
    May 10 at 11:18
17

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
    Apr 16, 2020 at 0:57
  • Can you please explain why you add 20 to the start address? Dec 14, 2021 at 10:13
  • 1
    Can't you just do (address addr) = abi.decode(theBytes, (address)); ? 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
    Feb 16 at 5:30
2

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. 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
    Jan 11 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? Jan 13 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
    Jan 21 at 23:09
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! 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
    Jan 5, 2018 at 23:42
1

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? Dec 14, 2021 at 10:28
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);
    }
-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, privacy policy and cookie policy

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