39

In Solidity, how can I convert the sender address to a string?

The comments in How to convert an address to bytes in Solidity? did not provide a working solution

1
  • function toString(address x) internal pure returns (string) { bytes memory b = new bytes(20); for (uint i = 0; i < 20; i++) b[i] = byte(uint8(uint(x) / (2**(8*(19 - i))))); return string(b); } Use internal pure keyword, otherwise you will get a warning. For more information about pure function. Jun 18, 2018 at 11:12

5 Answers 5

42

Use abi.encodePacked(x)

where x is the address. (Thanks @k06a)

3
  • 5
    It works, but the result is not a human-readable string. For a human-readable string, see toAsciiString example in the other answer.
    – rustyx
    Apr 9, 2018 at 13:22
  • can not be used together with string.concat (0.8.x) ( error message: Invalid type for argument in the string.concat function call. string type is required, but t_bytes_memory_ptr provided ) , the toAsciiString works for me.
    – Siwei
    Jul 9, 2022 at 9:09
  • 1
    @Siwei Thanks, I upvoted that answer. This type of question puzzles me because it may be an anti-pattern: generally should try to avoid such conversions in a contract and do them elsewhere like the frontend...
    – eth
    Jul 11, 2022 at 5:16
27

I was not able to read the ABI-encoded string with web3.js. Therefore, I added some conversion to the ASCII characters:

function toAsciiString(address x) internal pure returns (string memory) {
    bytes memory s = new bytes(40);
    for (uint i = 0; i < 20; i++) {
        bytes1 b = bytes1(uint8(uint(uint160(x)) / (2**(8*(19 - i)))));
        bytes1 hi = bytes1(uint8(b) / 16);
        bytes1 lo = bytes1(uint8(b) - 16 * uint8(hi));
        s[2*i] = char(hi);
        s[2*i+1] = char(lo);            
    }
    return string(s);
}

function char(bytes1 b) internal pure returns (bytes1 c) {
    if (uint8(b) < 10) return bytes1(uint8(b) + 0x30);
    else return bytes1(uint8(b) + 0x57);
}
5
  • 1
    There was a problem with the function char(byte b). "TypeError: Operator < not compatible with types bytes1 and int_const 10" I suppose this comparison does work anyway since you probably meant if b is a number then add 0x30 to it. But how do you know if a byte is less than 10 or not anyways?
    – Billie
    Jan 16, 2019 at 12:25
  • if (b < 10) has to be changed to if (uint8(b) < 10), then the Operator < not compatible with types bytes1 ... error is fixed. I made an edit to the answer. Hope it gets approved. Sep 5, 2019 at 13:35
  • Thanks for the answer - so far this works in v0.5.10
    – pizzarob
    Sep 5, 2019 at 15:04
  • 1
    This conversion looses the address checksum, which is case sensitive. The checksum can be restored using Web3.utils.toChecksumAddress().
    – rbinnun
    Dec 24, 2021 at 15:35
  • The address is formated to lowercase without initial 0x
    – JTCon
    May 10, 2022 at 23:15
18

This is method to convert address to hex string:

function toString(address account) public pure returns(string memory) {
    return toString(abi.encodePacked(account));
}

function toString(uint256 value) public pure returns(string memory) {
    return toString(abi.encodePacked(value));
}

function toString(bytes32 value) public pure returns(string memory) {
    return toString(abi.encodePacked(value));
}

function toString(bytes memory data) public pure returns(string memory) {
    bytes memory alphabet = "0123456789abcdef";

    bytes memory str = new bytes(2 + data.length * 2);
    str[0] = "0";
    str[1] = "x";
    for (uint i = 0; i < data.length; i++) {
        str[2+i*2] = alphabet[uint(uint8(data[i] >> 4))];
        str[3+i*2] = alphabet[uint(uint8(data[i] & 0x0f))];
    }
    return string(str);
}
2
  • Beware!! Although the code is well engineered, it leads to this bug: github.com/ethers-io/ethers.js/issues/…
    – Huge
    Jun 1, 2021 at 11:21
  • 2
    As of solidity 0.8.x, explicit type conversion from address to uint256 is not allowed. So use, uint256 i = uint256(uint160(address(msg.sender))); Jun 29, 2021 at 5:36
15

You can cast address to uint160, then use OpenZeppelin Strings library.

Strings.toHexString(uint160(address), 20)

Reference:

Casting address to uint

OpenZeppelin Strings for bytes

1
  • 2
    Be careful, this will convert a checksummed address into a non-checksummed one
    – Madbreaks
    Oct 28, 2022 at 22:03
4

This works with solidity 0.6.0

function addressToString(address _pool) public pure returns (string memory _uintAsString) {
      uint _i = uint256(_pool);
      if (_i == 0) {
          return "0";
      }
      uint j = _i;
      uint len;
      while (j != 0) {
          len++;
          j /= 10;
      }
      bytes memory bstr = new bytes(len);
      uint k = len - 1;
      while (_i != 0) {
          bstr[k--] = byte(uint8(48 + _i % 10));
          _i /= 10;
      }
      return string(bstr);
    }

3
  • 1
    Works but pay attention: returns (string memory _uintAsString) !!! so it is a int, not the address string as you'd expect on first sight. This also means that if your address starts with one ore more zeros (0x0A1bC4...), then converting it to an int and then back to hex (address) again will result in this leading 0 missing. You'll need something like this: '0x' + BigInt(ethAddressAsInt).toString(16).padStart(40, '0') (40 being the length of an ethereum address, excluding the "0x") Dec 21, 2020 at 2:39
  • Could you edit the answer to include this in the function? Dec 21, 2020 at 2:50
  • using solidity 8.7, this doesn't compile. Gives "parser error - expected primary expression" on bstr[k--] = byte(uint8(48 + _i % 10)); ]
    – GGizmos
    Oct 10, 2021 at 21:47

Your Answer

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

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