¿Cómo convertir una dirección a bytes en Solidity?

¿Cuál es la forma recomendada de convertir un addressa bytesen Solidity?

Respuestas (6)

Para ser aún más eficiente:

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
   }
}

Toma solo 695 de gas contra 2500 para la respuesta de Gokulnath y 5000 para la de Eth

Editar para solidez ^ 0.5.0:

Esto es casi tan eficiente y mucho más legible:

function toBytes(address a) public pure returns (bytes memory) {
    return abi.encodePacked(a);
}
¡Eso es genial!
¿Esto todavía funciona en solidez ^ 0.5.0?
Con algunos ajustes menores de sintaxis, sí

Aquí está mi pequeña línea para addressla bytes32conversión:

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

Si necesita bytesen lugar de bytes32:

abi.encodePacked(addr)
Esto responde a una pregunta diferente porque byteses diferente de bytes32.
Además, tenga en cuenta que esto rellenará los bytes32 a la derecha . Normalmente, en Ethereum, rellenamos a la izquierda . Simplemente omita el << 96para hacer eso.
Esta respuesta no funciona hoy. Dice que no se puede convertir el tipo de dirección a uint.
@YulePale, ¡arreglado!

No hay accesos directos actuales y necesita escribir su propia función.

Esta es la función sugerida por el autor de Solidity, 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)))));
}
Si desea convertir una dirección en una cadena, puede convertir los bytes en una cadena simplemente usando la conversión explícita, comostring(b)
Obtener este error en la solidez del navegador:Error: Type string memory is not implicitly convertible to expected type string storage pointer.
@koampapapa Lo investigué y respondí a su pregunta ethereum.stackexchange.com/questions/8346/… Si realmente es necesario, considere realizar conversiones en la UI/frontend/Javascript en lugar de Solidity para ahorrar gasolina.
¿Después podemos convertir bytes(b) a bytes32para almacenarlo en bytes32formato? @eth
@alper Sería mejor enviar directamente la dirección a un bytes20, que funcionará donde quiera usar bytes32.
Para usarlo como bytes32, podría hacer algo como: bytes memory b = toBytes(a); assembly { result := mload(add(b, 32)) } @eth

Aquí hay una solución de una línea.

abi.encodePacked(addr)

Es simple y cuesta poco

¡Bienvenido a Ethereum Stack Exchange! Es tentador escribir una respuesta corta, pero demasiado corta no es útil. Por ejemplo, ¿qué significa "cuesta poco"? ¿Hay una comparación de gas en comparación con la respuesta aceptada? ¿Para qué versiones de Solidity se puede utilizar?

Esto es similar a la respuesta dada anteriormente, pero es más eficiente con el gas, ya que está en el ensamblaje.

  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; 
  }
Realmente no hay necesidad de un bucle en absoluto, ya que estamos tratando con <32 bytes
Sí, no hay necesidad de bucle. bueno

En lugar de intentar convertir la dirección en bytes sin procesar, a menudo es más fácil usar la codificación ABI. La codificación ABI no es una traducción sin procesar de byte a byte, sino que agrega sus propios bytes de marcador a campos separados. Sin embargo, puede realizar esto con una función integrada.

en solidez


 /**
   * 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);
  }


En 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());
Esto puede ser claro para aquellos que ya saben lo que está haciendo, pero agregar algunos ejemplos ayudaría a que esto sea más claro para aquellos que no lo saben.