21

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

eth
  • 85,679
  • 53
  • 285
  • 406

6 Answers6

32

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);
}
Tjaden Hess
  • 37,046
  • 10
  • 91
  • 118
17

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)
k06a
  • 3,016
  • 2
  • 21
  • 35
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)))));
}
eth
  • 85,679
  • 53
  • 285
  • 406
  • 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 '16 at 15:14
  • Getting this error in browser solidity:

    Error: Type string memory is not implicitly convertible to expected type string storage pointer.

    – nick carraway Aug 26 '16 at 23:27
  • 1
    @koampapapa I looked into it and answered your question http://ethereum.stackexchange.com/questions/8346/convert-address-to-string-msg-sender If really needed, consider doing conversions in the UI/frontend/Javascript instead of Solidity to save gas. – eth Aug 27 '16 at 02:01
  • Later can we convert bytes(b) to bytes32 to store it in bytes32 format? @eth – alper Mar 01 '19 at 07: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 01 '19 at 08:41
  • In order to user it as bytes32, could I do something like: bytes memory b = toBytes(a); assembly { result := mload(add(b, 32)) } @eth – alper Mar 01 '19 at 10:30
4

Here is an one-line solution.

abi.encodePacked(addr)

It's simple and costs little

WS LIM
  • 41
  • 2
  • 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 '18 at 23:46
1

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());
Mikko Ohtamaa
  • 22,269
  • 6
  • 62
  • 127
  • 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 '20 at 09:48
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; 
  }
ygnr
  • 56
  • 2