12

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

18

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);
}
| improve this answer | |
  • That's awesome! – Eamorr Mar 31 '17 at 21:24
  • Does this still work in solidity ^0.5.0? – Barrard Mar 15 '19 at 12:12
  • With some minor syntax tweaks, yes – Tjaden Hess Mar 15 '19 at 14:04
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)))));
}
| improve this answer | |
  • 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 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 '16 at 2:01
  • Later can we convert bytes(b) to bytes32 to store it in bytes32 format? @eth – alper Mar 1 '19 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 '19 at 8:41
6

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

bytes32(uint256(addr) << 96);
| improve this answer | |
  • This answers a different question because bytes is different from bytes32. – eth Mar 11 '18 at 9:45
  • 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. – Paul Razvan Berg Feb 27 '19 at 16:27
4

Here is an one-line solution.

abi.encodePacked(addr)

It's simple and costs little

| improve this answer | |
  • 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
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; 
  }
| improve this answer | |
  • 3
    There's really no need for a loop at all, since we're dealing with < 32 bytes – Tjaden Hess Mar 29 '17 at 5:09
  • Yes, there is no need of loop. Good one. – ygnr Mar 29 '17 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());
| improve this answer | |
  • 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 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.