17

What is the recommended way to convert an address to bytes in Solidity?

6 Answers 6

26

To be even more efficient:

function toBytes(address a) public pure returns (bytes memory b){
    assembly {
        let m := mload(0x40)
        a := and(a, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
        mstore(add(m, 20), xor(0x140000000000000000000000000000000000000000, a))
        mstore(0x40, add(m, 52))
        b := m
   }
}

Takes just 695 gas vs 2500 for Gokulnath's answer and 5000 for Eth's

Edit for solidity ^0.5.0:

This is almost as efficient and much more readable:

function toBytes(address a) public pure returns (bytes memory) {
    return abi.encodePacked(a);
}
3
  • That's awesome!
    – Eamorr
    Mar 31, 2017 at 21:24
  • Does this still work in solidity ^0.5.0?
    – Barrard
    Mar 15, 2019 at 12:12
  • With some minor syntax tweaks, yes Mar 15, 2019 at 14:04
14

Here is my tiny one-liner for address to bytes32 conversion:

bytes32(uint256(uint160(addr)) << 96);

If you need bytes instead of bytes32:

abi.encodePacked(addr)
5
  • 1
    This answers a different question because bytes is different from bytes32.
    – eth
    Mar 11, 2018 at 9:45
  • 2
    Also, note that this will pad the bytes32 to the right. Normally, in Ethereum, we pad to the left. Just omit the << 96 to do that. Feb 27, 2019 at 16:27
  • This answer does not work today. It says cannot convert address type to uint.
    – YulePale
    Jul 20, 2021 at 5:08
  • 1
    @YulePale, fixed!
    – k06a
    Jul 21, 2021 at 9:26
  • @k06a, Thank you.
    – YulePale
    Jul 21, 2021 at 14:13
6

There are no current shortcuts and you need to write your own function.

Here's the function suggested by Solidity's author, chriseth:

function toBytes(address x) returns (bytes b) {
    b = new bytes(20);
    for (uint i = 0; i < 20; i++)
        b[i] = byte(uint8(uint(x) / (2**(8*(19 - i)))));
}
6
  • 1
    If you want to convert an address to a string, you can then convert the bytes to a string just using explicit conversion, as string(b)
    – MrChico
    Mar 22, 2016 at 15:14
  • Getting this error in browser solidity: Error: Type string memory is not implicitly convertible to expected type string storage pointer. Aug 26, 2016 at 23:27
  • 1
    @koampapapa I looked into it and answered your question ethereum.stackexchange.com/questions/8346/… If really needed, consider doing conversions in the UI/frontend/Javascript instead of Solidity to save gas.
    – eth
    Aug 27, 2016 at 2:01
  • Later can we convert bytes(b) to bytes32 to store it in bytes32 format? @eth
    – alper
    Mar 1, 2019 at 7:54
  • @alper It would be better to directly cast the address to a bytes20, which will work wherever you wanted to use bytes32.
    – eth
    Mar 1, 2019 at 8:41
4

Here is an one-line solution.

abi.encodePacked(addr)

It's simple and costs little

1
  • 1
    Welcome to the Ethereum Stack Exchange! It is tempting to write a short answer, but too short is not helpful. For example, what does "costs little" mean? Is there a comparison of gas compared to the accepted answer? Which versions of Solidity can this be used for?
    – eth
    Nov 10, 2018 at 23:46
0

This is similar to the answer given above but is more gas efficient as it is in assembly.

  function addressToBytes(address i)  returns (bytes by) { 
    by = new bytes(20); 
    assembly { 
      let count := 0 
      let byptr := add(by, 32) 
      loop: 
          jumpi(end, eq(count, 20)) 
          mstore8(byptr, byte(add(count,12), i)) 
          byptr := add(byptr, 1) 
          count := add(count, 1) 
          jump(loop) 
      end: 
    } 
    return by; 
  }
2
  • 3
    There's really no need for a loop at all, since we're dealing with < 32 bytes Mar 29, 2017 at 5:09
  • Yes, there is no need of loop. Good one.
    – ygnr
    Mar 29, 2017 at 7:24
0

Instead of trying to convert address to raw bytes, it is often easier to use ABI encoding. ABI encoding is not raw byte-to-byte translation, but it adds its own marker bytes to separate fields. However you can perform this with one built-in function.

In Solidity


 /**
   * A test method exposed to be called from clients to compare that ABI packing and hashing
   * is same across different programming languages.
   *
   * Does ABI encoding for an address and then calculates KECCAK-256 hash over the bytes.
   *
   * https://web3js.readthedocs.io/en/v1.2.0/web3-utils.html#soliditysha3
   *
   */
  function calculateAddressHash(address a) public pure returns (bytes32 hash, bytes memory data) {

    // First we ABI encode the address to bytes.
    // This is so called "tight packing"
    // https://web3js.readthedocs.io/en/v1.2.0/web3-utils.html#soliditysha3
    bytes memory packed = abi.encodePacked(a);

    // Then we calculate keccak256 over the resulting bytes
    bytes32 hashResult = keccak256(packed);

    return(hashResult, packed);
  }


In JavaScript/TypeScript

  import { soliditySha3 } from 'web3-utils';

  // Sign address
  const { signature, v, r, s } = signAddress(user2);

  // This is an address is a hexadecimal format
  const ourData = user2.toLowerCase();

  // https://web3js.readthedocs.io/en/v1.2.0/web3-utils.html#id23
  // Convert address to bytes using "tight packing"
  // and them calculates keccak-256 over the resulting bytes
  const ourHash = soliditySha3({t: 'address', v: user2 });

  // We hash data in similar in TypeScript and Solidity
  const { hash, data } = await tokenSwap.calculateAddressHash(user2);
  assert(ourData.toLowerCase() == data.toLowerCase());
  assert(ourHash.toLowerCase() == hash.toLowerCase());
1
  • This may be clear to those who already know what you're doing, but adding some examples would help make this clearer to those who don't.
    – eth
    Mar 17, 2020 at 9:48

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.