¿Cómo hago el equivalente de bytes32 (a_signed_integer) de Solidity en JavaScript?

Tengo una aplicación que acepta varios tipos de entrada a través de un formulario HTML, pero siempre termina enviándolo a un contrato como bytes32. La expectativa es que otro contrato que finalmente consuma los datos los transformará en el tipo que espera, que puede ser bytes32, uint256o int256.

Para enteros sin signo, tomo un BigNumberobjeto, toString(16)lo llamo para obtener hexadecimal, luego lo relleno a la izquierda a 64 dígitos y agrego 0x. Pero para los enteros con signo, que pueden ser negativos, presumiblemente necesito manejar el sistema de complemento a dos; ¿Cuál es la forma adecuada de hacer esto?

BN.js (una dependencia de web3 v1.0) tiene dos métodos toTwosque fromTwosse pueden usar para obtener el complemento a dos en una longitud arbitraria.

Respuestas (3)

Usando BN.js como lo sugiere @Ismael:

function numStringToBytes32(num) { 
   var bn = new BN(num).toTwos(256);
   return padToBytes32(bn.toString(16));
}

function bytes32ToNumString(bytes32str) {
    bytes32str = bytes32str.replace(/^0x/, '');
    var bn = new BN(bytes32str, 16).fromTwos(256);
    return bn.toString();
}

function padToBytes32(n) {
    while (n.length < 64) {
        n = "0" + n;
    }
    return "0x" + n;
}

Este código funciona para mí:

var utf8 = require('utf8');

function padToBytes32(n) {
    while (n.length < 64) {
        n = n + "0";
    }
    return "0x" + n;
}

function fromUtf8(str) {
    str = utf8.encode(str);
    var hex = "";
    for (var i = 0; i < str.length; i++) {
        var code = str.charCodeAt(i);
        if (code === 0) {
            break;
        }
        var n = code.toString(16);
        hex += n.length < 2 ? '0' + n : n;
    }

    return padToBytes32(hex);
};

// not tested yet...
function toUtf8(hex) {
    // Find termination
    var str = "";
    var i = 0, l = hex.length;
    if (hex.substring(0, 2) === '0x') {
        i = 2;
    }
    for (; i < l; i += 2) {
        var code = parseInt(hex.substr(i, 2), 16);
        if (code === 0) {
            break;
        }
        str += String.fromCharCode(code);
    }

    return utf8.decode(str);
};

module.exports = {
    fromUtf8,
    toUtf8
};

```

Usando solo BN.js

let num = -1234;
let bytes32 = "0x"+(new BN(String(num))).toTwos(256).toString('hex',64);

Usando web3.js

let num = -1234;
let bytes32 = web3.eth.abi.encodeParameter('int256', String(num));

Esto está funcionando en un contrato inteligente como este:

pragma solidity ^0.5.0;
contract TestConversion {
    int256 val;
    function set(bytes32 _val) public {
        val = int256(_val);
    }
    function get() public view returns(int256){
        return val;
    }
}
¡Bienvenido a Ethereum Stack Exchange! ¿Puedes editar tu respuesta y agregar un poco más? ¿Intentaste con un número negativo como dice la pregunta?