Как мне сделать эквивалент байтов Solidity32 (a_signed_integer) в JavaScript?

У меня есть приложение, которое принимает различные виды ввода через HTML-форму, но всегда в конечном итоге отправляет его в контракт как bytes32. Ожидается, что другой контракт, который в конечном итоге потребляет данные, приведет их к ожидаемому типу, который может быть bytes32, uint256или int256.

Для целых чисел без знака я беру BigNumberобъект, вызываю toString(16)его, чтобы получить шестнадцатеричный код, затем дополняю его слева до 64 цифр и добавляю 0x. Но для целых чисел со знаком, которые могут быть отрицательными, мне, по-видимому, нужно обрабатывать систему дополнения до двух; Каков правильный способ сделать это?

BN.js (зависимость от web3 v1.0) имеет два метода toTwos, fromTwosкоторые можно использовать для получения дополнения до произвольной длины.

Ответы (3)

Использование BN.js, предложенное @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;
}

Этот код работает для меня:

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

```

Использование только BN.js

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

Использование web3.js

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

Это работает в смарт-контракте следующим образом:

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;
    }
}
Добро пожаловать на биржу стека Ethereum! Не могли бы вы отредактировать свой ответ и добавить еще немного? Вы пробовали с отрицательным числом, как задается вопрос?