diff --git a/docs/web3-utils.rst b/docs/web3-utils.rst index 10f25af..23f7101 100644 --- a/docs/web3-utils.rst +++ b/docs/web3-utils.rst @@ -166,9 +166,13 @@ sha3 .. code-block:: javascript web3.utils.sha3(string) + web3.utils.keccak256(string) // ALIAS Will calculate the sha3 of the input. +.. note:: If given a HEX string it will be converted to a byte array first before hashed to match solidity's sha3. +``web3.utils.sha3.jsSha3`` exposes the underlying `js-sha3 library `_. Use to to hash without HEX conversion. + ---------- Parameters ---------- @@ -187,9 +191,69 @@ Example .. code-block:: javascript - web3.utils.sha3('234'); + web3.utils.sha3('234'); // taken as string > "0xc1912fee45d61c87cc5ea59dae311904cd86b84fee17cc96966216f811ce6a79" + web3.utils.sha3(new BN('234')); + > "0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a" + + web3.utils.sha3(234); + > null // can't calculate the has of a number + + web3.utils.sha3(0xea); // same as above, just the HEX representation of the number + > null + + web3.utils.sha3('0xea'); // will be converted to a byte array first, and then hashed + > "0x2f20677459120677484f7104c76deb6846a2c071f9b3152c103bb12cd54d1a4a" + + +------------------------------------------------------------------------------ + +isHex +===================== + +.. code-block:: javascript + + web3.utils.isHex(hex) + +Checks if a given string is a HEX string. + +---------- +Parameters +---------- + +1. ``hex`` - ``String|HEX``: The given HEX string. + +------- +Returns +------- + +``Boolean`` + +------- +Example +------- + +.. code-block:: javascript + + web3.utils.isHex('0xc1912'); + > true + + web3.utils.isHex(0xc1912); + > true + + web3.utils.isHex('c1912'); + > true + + web3.utils.isHex(345); + > true // this is tricky, as 345 can be a a HEX representation or a number, be careful when not having a 0x in front! + + web3.utils.isHex('0xZ1912'); + > false + + web3.utils.isHex('Hello'); + > false + ------------------------------------------------------------------------------ @@ -401,12 +465,12 @@ Example ------------------------------------------------------------------------------ -toNumberString +hexToNumberString ===================== .. code-block:: javascript - web3.utils.toNumberString(hex) + web3.utils.hexToNumberString(hex) Returns the number representation of a given HEX value as a string. @@ -428,19 +492,19 @@ Example .. code-block:: javascript - web3.utils.toNumberString('0xea'); + web3.utils.hexToNumberString('0xea'); > "234" ------------------------------------------------------------------------------ -toNumber +hexToNumber ===================== .. code-block:: javascript - web3.utils.toNumber(hex) - web3.utils.toDecimal(hex) // ALIAS: might be deprecated in the future + web3.utils.hexToNumber(hex) + web3.utils.toDecimal(hex) // ALIAS, deprecated Returns the number representation of a given HEX value. @@ -464,19 +528,19 @@ Example .. code-block:: javascript - web3.utils.toNumber('0xea'); + web3.utils.hexToNumber('0xea'); > 234 ------------------------------------------------------------------------------ -fromNumber +numberToHex ===================== .. code-block:: javascript - web3.utils.fromNumber(number) - web3.utils.fromDecimal(number) // ALIAS + web3.utils.numberToHex(number) + web3.utils.fromDecimal(number) // ALIAS, deprecated Returns the HEX representation of a given number value. @@ -498,20 +562,21 @@ Example .. code-block:: javascript - web3.utils.fromNumber('234'); + web3.utils.numberToHex('234'); > '0xea' ------------------------------------------------------------------------------ -toUtf8 +hexToUtf8 ===================== .. code-block:: javascript - web3.utils.toUtf8(hex) - web3.utils.toString(hex) // ALIAS + web3.utils.hexToUtf8(hex) + web3.utils.hexToString(hex) // ALIAS + web3.utils.toUtf8(hex) // ALIAS, deprecated Returns the UTF-8 string representation of a given HEX value. @@ -534,18 +599,19 @@ Example .. code-block:: javascript - web3.utils.toUtf8('0x49206861766520313030e282ac'); + web3.utils.hexToUtf8('0x49206861766520313030e282ac'); > "I have 100€" ------------------------------------------------------------------------------ -toAscii +hexToAscii ===================== .. code-block:: javascript - web3.utils.toAscii(hex) + web3.utils.hexToAscii(hex) + web3.utils.toAscii(hex) // ALIAS, deprecated Returns the ASCII string representation of a given HEX value. @@ -568,7 +634,7 @@ Example .. code-block:: javascript - web3.utils.toAscii('0x4920686176652031303021'); + web3.utils.hexToAscii('0x4920686176652031303021'); > "I have 100!" @@ -576,13 +642,14 @@ Example -fromUtf8 +utf8ToHex ===================== .. code-block:: javascript - web3.utils.fromUtf8(hex) - web3.utils.fromString(hex) // ALIAS + web3.utils.utf8ToHex(string) + web3.utils.stringToHex(string) // ALIAS + web3.utils.fromUtf8(string) // ALIAS, deprecated Returns the HEX representation of a given UTF-8 string. @@ -591,7 +658,7 @@ Returns the HEX representation of a given UTF-8 string. Parameters ---------- -1. ``hex`` - ``String``: A UTF-8 string to convert to a HEX string. +1. ``string`` - ``String``: A UTF-8 string to convert to a HEX string. ------- Returns @@ -605,18 +672,19 @@ Example .. code-block:: javascript - web3.utils.fromUtf8('I have 100€'); + web3.utils.utf8ToHex('I have 100€'); > "0x49206861766520313030e282ac" ------------------------------------------------------------------------------ -fromAscii +asciiToHex ===================== .. code-block:: javascript - web3.utils.fromAscii(hex) + web3.utils.asciiToHex(string) + web3.utils.fromAscii(string) // ALIAS, deprecated Returns the HEX representation of a given ASCII string. @@ -626,7 +694,7 @@ Returns the HEX representation of a given ASCII string. Parameters ---------- -1. ``hex`` - ``String``: A ASCII string to convert to a HEX string. +1. ``string`` - ``String``: A ASCII string to convert to a HEX string. ------- Returns @@ -640,10 +708,81 @@ Example .. code-block:: javascript - web3.utils.fromAscii('I have 100!'); + web3.utils.asciiToHex('I have 100!'); > "0x4920686176652031303021" +------------------------------------------------------------------------------ + +hexToBytes +===================== + +.. code-block:: javascript + + web3.utils.hexToBytes(hex) + +Returns a byte array from the given HEX string. + +---------- +Parameters +---------- + +1. ``hex`` - ``String|HEX``: A HEX to convert. + +------- +Returns +------- + +``Array``: The byte array. + +------- +Example +------- + +.. code-block:: javascript + + web3.utils.hexToBytes('0x000000ea'); + > [ 0, 0, 0, 234 ] + + web3.utils.hexToBytes(0x000000ea); + > [ 234 ] + + +------------------------------------------------------------------------------ + + +bytesToHex +===================== + +.. code-block:: javascript + + web3.utils.bytesToHex(byteArray) + +Returns a HEX string from a byte array. + +---------- +Parameters +---------- + +1. ``byteArray`` - ``Array``: A byte array to convert. + +------- +Returns +------- + +``String``: The HEX string. + +------- +Example +------- + +.. code-block:: javascript + + web3.utils.bytesToHex([ 72, 101, 108, 108, 111, 33, 36 ]); + > "0x48656c6c6f2125" + + + ------------------------------------------------------------------------------ toWei @@ -875,12 +1014,13 @@ Example ------------------------------------------------------------------------------ -padLeft +leftPad ===================== .. code-block:: javascript - web3.utils.padLeft(string, characterAmount [, sign]) + web3.utils.leftPad(string, characterAmount [, sign]) + web3.utils.leftPad(string, characterAmount [, sign]) // ALIAS Adds a padding on the left of a string, Useful for adding paddings to HEX strings. @@ -906,23 +1046,24 @@ Example .. code-block:: javascript - web3.utils.padLeft('0x3456ff', 20); + web3.utils.leftPad('0x3456ff', 20); > "0x000000000000003456ff" - web3.utils.padLeft(0x3456ff, 20); + web3.utils.leftPad(0x3456ff, 20); > "0x000000000000003456ff" - web3.utils.padLeft('Hello', 20, 'x'); + web3.utils.leftPad('Hello', 20, 'x'); > "xxxxxxxxxxxxxxxHello" ------------------------------------------------------------------------------ -padRight +rightPad ===================== .. code-block:: javascript - web3.utils.padRight(string, characterAmount [, sign]) + web3.utils.rightPad(string, characterAmount [, sign]) + web3.utils.rightPad(string, characterAmount [, sign]) // ALIAS Adds a padding on the right of a string, Useful for adding paddings to HEX strings. @@ -948,11 +1089,11 @@ Example .. code-block:: javascript - web3.utils.padRight('0x3456ff', 20); + web3.utils.rightPad('0x3456ff', 20); > "0x3456ff00000000000000" - web3.utils.padRight(0x3456ff, 20); + web3.utils.rightPad(0x3456ff, 20); > "0x3456ff00000000000000" - web3.utils.padRight('Hello', 20, 'x'); + web3.utils.rightPad('Hello', 20, 'x'); > "Helloxxxxxxxxxxxxxxx" diff --git a/packages/web3-core-helpers/src/formatters.js b/packages/web3-core-helpers/src/formatters.js index e01578d..9fa288b 100644 --- a/packages/web3-core-helpers/src/formatters.js +++ b/packages/web3-core-helpers/src/formatters.js @@ -86,7 +86,7 @@ var inputCallFormatter = function (options){ ['gasPrice', 'gas', 'gasLimit', 'value', 'nonce'].filter(function (key) { return options[key] !== undefined; }).forEach(function(key){ - options[key] = utils.fromNumber(options[key]); + options[key] = utils.numberToHex(options[key]); }); return options; @@ -96,7 +96,7 @@ var inputCallFormatter = function (options){ * Formats the input of a transaction and converts all values to HEX * * @method inputTransactionFormatter - * @param {Object} transaction options + * @param {Object} options * @returns object */ var inputTransactionFormatter = function (options){ @@ -115,7 +115,7 @@ var inputTransactionFormatter = function (options){ ['gasPrice', 'gas', 'value', 'nonce'].filter(function (key) { return options[key] !== undefined; }).forEach(function(key){ - options[key] = utils.fromNumber(options[key]); + options[key] = utils.numberToHex(options[key]); }); return options; @@ -130,11 +130,11 @@ var inputTransactionFormatter = function (options){ */ var outputTransactionFormatter = function (tx){ if(tx.blockNumber !== null) - tx.blockNumber = utils.toNumber(tx.blockNumber); + tx.blockNumber = utils.hexToNumber(tx.blockNumber); if(tx.transactionIndex !== null) - tx.transactionIndex = utils.toNumber(tx.transactionIndex); - tx.nonce = utils.toNumber(tx.nonce); - tx.gas = utils.toNumber(tx.gas); + tx.transactionIndex = utils.hexToNumber(tx.transactionIndex); + tx.nonce = utils.hexToNumber(tx.nonce); + tx.gas = utils.hexToNumber(tx.gas); tx.gasPrice = outputBigNumberFormatter(tx.gasPrice); tx.value = outputBigNumberFormatter(tx.value); @@ -161,11 +161,11 @@ var outputTransactionReceiptFormatter = function (receipt){ } if(receipt.blockNumber !== null) - receipt.blockNumber = utils.toNumber(receipt.blockNumber); + receipt.blockNumber = utils.hexToNumber(receipt.blockNumber); if(receipt.transactionIndex !== null) - receipt.transactionIndex = utils.toNumber(receipt.transactionIndex); - receipt.cumulativeGasUsed = utils.toNumber(receipt.cumulativeGasUsed); - receipt.gasUsed = utils.toNumber(receipt.gasUsed); + receipt.transactionIndex = utils.hexToNumber(receipt.transactionIndex); + receipt.cumulativeGasUsed = utils.hexToNumber(receipt.cumulativeGasUsed); + receipt.gasUsed = utils.hexToNumber(receipt.gasUsed); if(_.isArray(receipt.logs)) { receipt.logs = receipt.logs.map(outputLogFormatter); @@ -188,12 +188,12 @@ var outputTransactionReceiptFormatter = function (receipt){ var outputBlockFormatter = function(block) { // transform to number - block.gasLimit = utils.toNumber(block.gasLimit); - block.gasUsed = utils.toNumber(block.gasUsed); - block.size = utils.toNumber(block.size); - block.timestamp = utils.toNumber(block.timestamp); + block.gasLimit = utils.hexToNumber(block.gasLimit); + block.gasUsed = utils.hexToNumber(block.gasUsed); + block.size = utils.hexToNumber(block.size); + block.timestamp = utils.hexToNumber(block.timestamp); if (block.number !== null) - block.number = utils.toNumber(block.number); + block.number = utils.hexToNumber(block.number); if(block.difficulty) block.difficulty = outputBigNumberFormatter(block.difficulty); @@ -268,11 +268,11 @@ var outputLogFormatter = function(log) { } if (log.blockNumber !== null) - log.blockNumber = utils.toNumber(log.blockNumber); + log.blockNumber = utils.hexToNumber(log.blockNumber); if (log.transactionIndex !== null) - log.transactionIndex = utils.toNumber(log.transactionIndex); + log.transactionIndex = utils.hexToNumber(log.transactionIndex); if (log.logIndex !== null) - log.logIndex = utils.toNumber(log.logIndex); + log.logIndex = utils.hexToNumber(log.logIndex); if (log.address) log.address = utils.toChecksumAddress(log.address); @@ -292,11 +292,11 @@ var inputPostFormatter = function(post) { // post.payload = utils.toHex(post.payload); if (post.ttl) - post.ttl = utils.fromNumber(post.ttl); + post.ttl = utils.numberToHex(post.ttl); if (post.workToProve) - post.workToProve = utils.fromNumber(post.workToProve); + post.workToProve = utils.numberToHex(post.workToProve); if (post.priority) - post.priority = utils.fromNumber(post.priority); + post.priority = utils.numberToHex(post.priority); // fallback if (!_.isArray(post.topics)) { @@ -321,12 +321,12 @@ var inputPostFormatter = function(post) { */ var outputPostFormatter = function(post){ - post.expiry = utils.toNumber(post.expiry); - post.sent = utils.toNumber(post.sent); - post.ttl = utils.toNumber(post.ttl); - post.workProved = utils.toNumber(post.workProved); + post.expiry = utils.hexToNumber(post.expiry); + post.sent = utils.hexToNumber(post.sent); + post.ttl = utils.hexToNumber(post.ttl); + post.workProved = utils.hexToNumber(post.workProved); // post.payloadRaw = post.payload; - // post.payload = utils.toAscii(post.payload); + // post.payload = utils.hexToAscii(post.payload); // if (utils.isJson(post.payload)) { // post.payload = JSON.parse(post.payload); @@ -356,12 +356,12 @@ var inputAddressFormatter = function (address) { var outputSyncingFormatter = function(result) { - result.startingBlock = utils.toNumber(result.startingBlock); - result.currentBlock = utils.toNumber(result.currentBlock); - result.highestBlock = utils.toNumber(result.highestBlock); + result.startingBlock = utils.hexToNumber(result.startingBlock); + result.currentBlock = utils.hexToNumber(result.currentBlock); + result.highestBlock = utils.hexToNumber(result.highestBlock); if (result.knownStates) { - result.knownStates = utils.toNumber(result.knownStates); - result.pulledStates = utils.toNumber(result.pulledStates); + result.knownStates = utils.hexToNumber(result.knownStates); + result.pulledStates = utils.hexToNumber(result.pulledStates); } return result; diff --git a/packages/web3-eth-abi/package.json b/packages/web3-eth-abi/package.json index 32dea01..1bcd3b3 100644 --- a/packages/web3-eth-abi/package.json +++ b/packages/web3-eth-abi/package.json @@ -7,9 +7,10 @@ "main": "src/index.js", "dependencies": { "web3-core-helpers": "^1.0.0", - "web3-utils": "^1.0.0", "underscore": "^1.8.3", + "js-sha3": "^0.5.7", "number-to-bn": "^1.7.0", + "utf8": "^2.1.1", "bn.js": "^4.11.6" } } diff --git a/packages/web3-eth-abi/src/index.js b/packages/web3-eth-abi/src/index.js index c3626ea..7690a5a 100644 --- a/packages/web3-eth-abi/src/index.js +++ b/packages/web3-eth-abi/src/index.js @@ -15,7 +15,7 @@ along with web3.js. If not, see . */ /** - * @file coder.js + * @file index.js * @author Marek Kotewicz * @date 2015 */ @@ -35,6 +35,8 @@ var isDynamic = function (solidityType, type) { solidityType.isDynamicArray(type); }; + + /** * SolidityCoder prototype should be used to encode/decode solidity params of any type */ diff --git a/packages/web3-eth-abi/src/types/formatters.js b/packages/web3-eth-abi/src/types/formatters.js index d4a4925..4881180 100644 --- a/packages/web3-eth-abi/src/types/formatters.js +++ b/packages/web3-eth-abi/src/types/formatters.js @@ -21,50 +21,128 @@ */ var _ = require('underscore'); -var numberToBN = require('number-to-bn'); -var BigNumber = require('bn.js'); -var utils = require('web3-utils'); +var utf8 = require('utf8'); +var jsSha3 = require("js-sha3"); +var toBN = require('number-to-bn'); +var BN = require('bn.js'); var SolidityParam = require('./param'); /** - * Returns true if object is BigNumber, otherwise false + * Converts to a checksum address * - * @method isBigNumber - * @param {Object} - * @return {Boolean} + * @method toChecksumAddress + * @param {String} address the given HEX address + * @return {String} */ -var isBigNumber = function (object) { - return object instanceof BigNumber || - (object && object.constructor && object.constructor.name === 'BN'); +var toChecksumAddress = function (address) { + if (typeof address === 'undefined') return ''; + + if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) + throw new Error('Given address "'+ address +'" is not a valid Ethereum address.'); + + + + address = address.toLowerCase().replace(/^0x/i,''); + var addressHash = jsSha3.keccak_256(address).replace(/^0x/i,''); + var checksumAddress = '0x'; + + for (var i = 0; i < address.length; i++ ) { + // If ith character is 9 to f then make it uppercase + if (parseInt(addressHash[i], 16) > 7) { + checksumAddress += address[i].toUpperCase(); + } else { + checksumAddress += address[i]; + } + } + return checksumAddress; }; /** - * Takes an input and transforms it into an bignumber + * Should be called to pad string to expected length * - * @method toBN - * @param {Number|String|BigNumber} a number, string, HEX string or BigNumber - * @return {BigNumber} BigNumber + * @method rightPad + * @param {String} string to be padded + * @param {Number} chars that result string should have + * @param {String} sign, by default 0 + * @returns {String} right aligned string */ -var toBN = function(number) { - /*jshint maxcomplexity:5 */ - number = number || 0; - if (isBigNumber(number)) - return number; +var rightPad = function (string, chars, sign) { + var hasPrefix = /^0x/i.test(string) || typeof string === 'number'; + string = string.toString(16).replace(/^0x/i,''); - if (_.isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) { - return numberToBN(number); + var padding = (chars - string.length + 1 >= 0) ? chars - string.length + 1 : 0; + + return (hasPrefix ? '0x' : '') + string + (new Array(padding).join(sign ? sign : "0")); +}; + + +/** + * Should be called to get utf8 from it's hex representation + * + * @method hexToUtf8 + * @param {String} hex + * @returns {String} ascii string representation of hex value + */ +var hexToUtf8 = function(hex) { + + var str = ""; + var code = 0; + hex = hex.replace(/^0x/i,''); + + // remove 00 padding from either side + hex = hex.replace(/^(?:00)*/,''); + hex = hex.split("").reverse().join(""); + hex = hex.replace(/^(?:00)*/,''); + hex = hex.split("").reverse().join(""); + + var l = hex.length; + + for (var i=0; i < l; i+=2) { + code = parseInt(hex.substr(i, 2), 16); + // if (code !== 0) { + str += String.fromCharCode(code); + // } } - return new BigNumber(number.toString(10), 10); + return utf8.decode(str); }; /** - * Takes and input transforms it into bignumber and if it is negative value, into two's complement + * Should be called to get hex representation (prefixed by 0x) of utf8 string + * + * @method utf8ToHex + * @param {String} str + * @returns {String} hex representation of input string + */ +var utf8ToHex = function(str) { + str = utf8.encode(str); + var hex = ""; + + // remove \u0000 padding from either side + str = str.replace(/^(?:\u0000)*/,''); + str = str.split("").reverse().join(""); + str = str.replace(/^(?:\u0000)*/,''); + str = str.split("").reverse().join(""); + + for(var i = 0; i < str.length; i++) { + var code = str.charCodeAt(i); + // if (code !== 0) { + var n = code.toString(16); + hex += n.length < 2 ? '0' + n : n; + // } + } + + return "0x" + hex; +}; + + +/** + * Takes and input transforms it into BN and if it is negative value, into two's complement * * @method toTwosComplement - * @param {Number|String|BigNumber} - * @return {BigNumber} + * @param {Number|String|BN} + * @return {String} */ var toTwosComplement = function (number) { return toBN(number).toTwos(256).toString(16, 64); @@ -77,7 +155,7 @@ var toTwosComplement = function (number) { * If the value is floating point, round it down * * @method formatInputInt - * @param {String|Number|BigNumber} value that needs to be formatted + * @param {String|Number|BN} value that needs to be formatted * @returns {SolidityParam} */ var formatInputInt = function (value) { @@ -95,9 +173,9 @@ var formatInputInt = function (value) { * @returns {SolidityParam} */ var formatInputBytes = function (value) { - var result = utils.toHex(value).substr(2); + var result = value.substr(2); var l = Math.floor((result.length + 63) / 64); - result = utils.padRight(result, l * 64); + result = rightPad(result, l * 64); return new SolidityParam(result); }; @@ -109,10 +187,10 @@ var formatInputBytes = function (value) { * @returns {SolidityParam} */ var formatInputDynamicBytes = function (value) { - var result = utils.toHex(value).substr(2); + var result = value.substr(2); var length = result.length / 2; var l = Math.floor((result.length + 63) / 64); - result = utils.padRight(result, l * 64); + result = rightPad(result, l * 64); return new SolidityParam(formatInputInt(length).value + result); }; @@ -124,10 +202,10 @@ var formatInputDynamicBytes = function (value) { * @returns {SolidityParam} */ var formatInputString = function (value) { - var result = utils.fromUtf8(value).substr(2); + var result = utf8ToHex(value).substr(2); var length = result.length / 2; var l = Math.floor((result.length + 63) / 64); - result = utils.padRight(result, l * 64); + result = rightPad(result, l * 64); return new SolidityParam(formatInputInt(length).value + result); }; @@ -152,7 +230,7 @@ var formatInputBool = function (value) { * @returns {Boolean} true if it is negative, otherwise false */ var signedIsNegative = function (value) { - return (new BigNumber(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; + return (new BN(value.substr(0, 1), 16).toString(2).substr(0, 1)) === '1'; }; /** @@ -160,7 +238,7 @@ var signedIsNegative = function (value) { * * @method formatOutputInt * @param {SolidityParam} param - * @returns {BigNumber} right-aligned output bytes formatted to big number + * @returns {BN} right-aligned output bytes formatted to big number */ var formatOutputInt = function (param) { var value = param.staticPart() || "0"; @@ -168,9 +246,9 @@ var formatOutputInt = function (param) { // check if it's negative number // it it is, return two's complement if (signedIsNegative(value)) { - return new BigNumber(value, 16).fromTwos(256).toString(10); + return new BN(value, 16).fromTwos(256).toString(10); } - return new BigNumber(value, 16).toString(10); + return new BN(value, 16).toString(10); }; /** @@ -178,11 +256,11 @@ var formatOutputInt = function (param) { * * @method formatOutputUInt * @param {SolidityParam} - * @returns {BigNumber} right-aligned output bytes formatted to uint + * @returns {BN} right-aligned output bytes formatted to uint */ var formatOutputUInt = function (param) { var value = param.staticPart() || "0"; - return new BigNumber(value, 16).toString(10); + return new BN(value, 16).toString(10); }; @@ -220,7 +298,7 @@ var formatOutputBytes = function (param, name) { * @returns {String} hex string */ var formatOutputDynamicBytes = function (param) { - var length = (new BigNumber(param.dynamicPart().slice(0, 64), 16)).toNumber() * 2; + var length = (new BN(param.dynamicPart().slice(0, 64), 16)).toNumber() * 2; return '0x' + param.dynamicPart().substr(64, length); }; @@ -234,8 +312,8 @@ var formatOutputDynamicBytes = function (param) { var formatOutputString = function (param) { var hex = param.dynamicPart().slice(0, 64); if(hex) { - var length = (new BigNumber(hex, 16)).toNumber() * 2; - return utils.toUtf8(param.dynamicPart().substr(64, length)); + var length = (new BN(hex, 16)).toNumber() * 2; + return hexToUtf8(param.dynamicPart().substr(64, length)); } else { return "ERROR: Strings are not yet supported as return values"; } @@ -250,7 +328,7 @@ var formatOutputString = function (param) { */ var formatOutputAddress = function (param) { var value = param.staticPart(); - return utils.toChecksumAddress("0x" + value.slice(value.length - 40, value.length)); + return toChecksumAddress("0x" + value.slice(value.length - 40, value.length)); }; module.exports = { diff --git a/packages/web3-eth-contract/src/index.js b/packages/web3-eth-contract/src/index.js index 8f3d97c..b352459 100644 --- a/packages/web3-eth-contract/src/index.js +++ b/packages/web3-eth-contract/src/index.js @@ -37,7 +37,7 @@ var utils = require('web3-utils'); var Subscription = require('web3-core-subscriptions').subscription; var formatters = require('web3-core-helpers').formatters; var promiEvent = require('web3-core-promiEvent'); -var coder = require('web3-eth-abi'); +var abi = require('web3-eth-abi'); /** @@ -266,10 +266,10 @@ Contract.prototype._encodeEventABI = function (event, options) { if (_.isArray(value)) { return value.map(function (v) { - return '0x' + coder.encodeParam(i.type, v); + return '0x' + abi.encodeParam(i.type, v); }); } - return '0x' + coder.encodeParam(i.type, value); + return '0x' + abi.encodeParam(i.type, value); }); result.topics = result.topics.concat(indexedTopics); @@ -325,10 +325,10 @@ Contract.prototype._decodeEventABI = function (data) { var indexedData = argTopics.map(function (topics) { return topics.slice(2); }).join(''); // console.log('INDEXED', indexedTypes, indexedData); - var indexedParams = coder.decodeParams(indexedTypes, indexedData); + var indexedParams = abi.decodeParams(indexedTypes, indexedData); // console.log('NOT INDEXED', notIndexedTypes, data.data.slice(2)); - var notIndexedParams = coder.decodeParams(notIndexedTypes, data.data.slice(2)); + var notIndexedParams = abi.decodeParams(notIndexedTypes, data.data.slice(2)); var count = 0; @@ -380,7 +380,7 @@ Contract.prototype._encodeMethodABI = function _encodeMethodABI() { return input.type; }); }).map(function (types) { - return coder.encodeParams(types, args); + return abi.encodeParams(types, args); })[0] || ''; // return constructor @@ -421,7 +421,7 @@ Contract.prototype._decodeMethodReturn = function (outputs, returnValues) { }); returnValues = returnValues.length >= 2 ? returnValues.slice(2) : returnValues; - var result = coder.decodeParams(types, returnValues); + var result = abi.decodeParams(types, returnValues); result = result.length === 1 ? result[0] : result; if(result === '0x') result = null; diff --git a/packages/web3-eth-iban/src/index.js b/packages/web3-eth-iban/src/index.js index 785c62d..bc6a582 100644 --- a/packages/web3-eth-iban/src/index.js +++ b/packages/web3-eth-iban/src/index.js @@ -26,11 +26,10 @@ "use strict"; var utils = require('web3-utils'); - var BigNumber = require('bn.js'); -var padLeft = function (string, bytes) { +var leftPad = function (string, bytes) { var result = string; while (result.length < bytes * 2) { result = '0' + result; @@ -136,7 +135,7 @@ Iban.fromAddress = function (address) { var asBn = new BigNumber(address, 16); var base36 = asBn.toString(36); - var padded = padLeft(base36, 15); + var padded = leftPad(base36, 15); return Iban.fromBban(padded.toUpperCase()); }; diff --git a/packages/web3-eth/src/index.js b/packages/web3-eth/src/index.js index 0d616ac..22cd705 100644 --- a/packages/web3-eth/src/index.js +++ b/packages/web3-eth/src/index.js @@ -147,7 +147,7 @@ var methods = function () { name: 'getHashrate', call: 'eth_hashrate', params: 0, - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var isSyncing = new Method({ @@ -175,7 +175,7 @@ var methods = function () { name: 'getBlockNumber', call: 'eth_blockNumber', params: 0, - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var getBalance = new Method({ @@ -222,7 +222,7 @@ var methods = function () { call: getBlockTransactionCountCall, params: 1, inputFormatter: [formatters.inputBlockNumberFormatter], - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var getBlockUncleCount = new Method({ @@ -230,7 +230,7 @@ var methods = function () { call: uncleCountCall, params: 1, inputFormatter: [formatters.inputBlockNumberFormatter], - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var getTransaction = new Method({ @@ -262,7 +262,7 @@ var methods = function () { call: 'eth_getTransactionCount', params: 2, inputFormatter: [null, formatters.inputDefaultBlockNumberFormatter], - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var sendSignedTransaction = new Method({ @@ -272,6 +272,13 @@ var methods = function () { inputFormatter: [null] }); + var signTransaction = new Method({ + name: 'signTransaction', + call: 'eth_signTransaction', + params: 1, + inputFormatter: [formatters.inputTransactionFormatter] + }); + var sendTransaction = new Method({ name: 'sendTransaction', call: 'eth_sendTransaction', @@ -298,7 +305,7 @@ var methods = function () { call: 'eth_estimateGas', params: 1, inputFormatter: [formatters.inputCallFormatter], - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var getCompilers = new Method({ @@ -451,6 +458,7 @@ var methods = function () { call, estimateGas, sendSignedTransaction, + signTransaction, sendTransaction, sign, compileSolidity, diff --git a/packages/web3-net/src/index.js b/packages/web3-net/src/index.js index e2ead75..264329d 100755 --- a/packages/web3-net/src/index.js +++ b/packages/web3-net/src/index.js @@ -50,7 +50,7 @@ var methods = function () { name: 'getId', call: 'net_version', params: 0, - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); var isListening = new Method({ @@ -63,7 +63,7 @@ var methods = function () { name: 'getPeerCount', call: 'net_peerCount', params: 0, - outputFormatter: utils.toNumber + outputFormatter: utils.hexToNumber }); diff --git a/packages/web3-utils/src/index.js b/packages/web3-utils/src/index.js index 48209db..4ac0c05 100644 --- a/packages/web3-utils/src/index.js +++ b/packages/web3-utils/src/index.js @@ -27,7 +27,7 @@ var BN = require('bn.js'); var ethjsUnit = require('ethjs-unit'); var numberToBN = require('number-to-bn'); var utf8 = require('utf8'); -var keccak256 = require("js-sha3").keccak_256; // jshint ignore:line +var jsSha3 = require("js-sha3"); /** @@ -94,71 +94,289 @@ var _jsonInterfaceMethodToString = function (json) { return json.name + '(' + typeName + ')'; }; +/** + * Convert a hex string to a byte array + * + * Note: Implementation from crypto-js + * + * @method hexToBytes + * @param {string} hex + * @return {Array} the byte array + */ +var hexToBytes = function(hex) { + hex = hex.toString(16); + + if (!isHex(hex)) { + throw new Error('Given value "'+ hex +'" is not a valid hex string.'); + } + + hex = hex.replace(/^0x/i,''); + + for (var bytes = [], c = 0; c < hex.length; c += 2) + bytes.push(parseInt(hex.substr(c, 2), 16)); + return bytes; +}; + /** - * Sha3 encodes + * Convert a byte array to a hex string + * + * Note: Implementation from crypto-js + * + * @method bytesToHex + * @param {Array} bytes + * @return {String} the hex string + */ +var bytesToHex = function(bytes) { + for (var hex = [], i = 0; i < bytes.length; i++) { + /* jshint ignore:start */ + hex.push((bytes[i] >>> 4).toString(16)); + hex.push((bytes[i] & 0xF).toString(16)); + /* jshint ignore:end */ + } + return '0x'+ hex.join(""); +}; + + +/** + * Hashes values to a sha3 hash using keccak 256 + * + * To hash a HEX string the hex must have 0x in front. * * @method sha3 + * @return {String} the sha3 string + */ +var SHA3_NULL_S = '0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470'; + +var sha3 = function (value) { + if (isHex(value) && /^0x/i.test((value).toString())) { + value = hexToBytes(value); + } + + var returnValue = '0x'+ jsSha3.keccak_256(value); // jshint ignore:line + + if(returnValue === SHA3_NULL_S) { + return null; + } else { + return returnValue; + } +}; +// expose the under the hood keccak256 +sha3.jsSha3 = jsSha3; + + + +var _elementaryName = function (name) { + if (name.startsWith('int[')) { + return 'int256' + name.slice(3) + } else if (name === 'int') { + return 'int256'; + } else if (name.startsWith('uint[')) { + return 'uint256' + name.slice(4) + } else if (name === 'uint') { + return 'uint256'; + } else if (name.startsWith('fixed[')) { + return 'fixed128x128' + name.slice(5) + } else if (name === 'fixed') { + return 'fixed128x128'; + } else if (name.startsWith('ufixed[')) { + return 'ufixed128x128' + name.slice(6) + } else if (name === 'ufixed') { + return 'ufixed128x128'; + } + return name; +}; + +// Parse N from type +var _parseTypeN = function (type) { + return parseInt(/^\D+(\d+)$/.exec(type)[1], 10); +}; + +var _parseNumber = function (arg) { + var type = typeof arg; + if (type === 'string') { + if (isHex(arg)) { + return new BN(arg.replace(/^0x/i,''), 16); + } else { + return new BN(arg, 10); + } + } else if (type === 'number') { + return new BN(arg); + } else if (isBigNumber(arg)) { + // assume this is a BN for the moment, replace with BN.isBN soon + return new BN(arg.toString(10)); + } else if (isBN(arg)) { + // assume this is a BN for the moment, replace with BN.isBN soon + return arg; + } else { + throw new Error('Argument is not a number'); + } +}; + +var _solidityPack = function (types, values) { + if (types.length !== values.length) { + throw new Error('Number of types are not matching the values') + } + + var size, num; + var ret = []; + + for (var i = 0; i < types.length; i++) { + var type = _elementaryName(types[i]); + var value = values[i]; + + + + if (type === 'bytes') { + ret.push((_.isString(value) ? new Buffer(hexToBytes(value)) : value)); + } else if (type === 'string') { + ret.push(new Buffer(value, 'utf8')); + } else if (type === 'bool') { + ret.push(new Buffer(value ? '01' : '00', 'hex')); + } else if (type === 'address') { + ret.push(new Buffer(hexToBytes(leftPad(value, 40)))); + } else if (type.startsWith('bytes')) { + size = _parseTypeN(type); + + if (size < 1 || size > 32) { + throw new Error('Invalid bytes width: ' + size); + } + + ret.push(new Buffer(hexToBytes(rightPad(value, size * 2)))); + } else if (type.startsWith('uint')) { + size = _parseTypeN(type); + if ((size % 8) || (size < 8) || (size > 256)) { + throw new Error('Invalid uint width: ' + size); + } + + num = _parseNumber(value); + if (num.bitLength() > size) { + throw new Error('Supplied uint exceeds width: ' + size + ' vs ' + num.bitLength()); + } + + ret.push(num.toArrayLike(Buffer, 'be', size / 8)); + } else if (type.startsWith('int')) { + size = _parseTypeN(type); + if ((size % 8) || (size < 8) || (size > 256)) { + throw new Error('Invalid int width: ' + size); + } + + num = _parseNumber(value); + if (num.bitLength() > size) { + throw new Error('Supplied int exceeds width: ' + size + ' vs ' + num.bitLength()); + } + + ret.push(num.toTwos(size).toArrayLike(Buffer, 'be', size / 8)); + + } else { + // FIXME: support all other types + throw new Error('Unsupported or invalid type: ' + type); + } + } + + return Buffer.concat(ret); +}; + + +/** + * Hashes solidity values to a sha3 hash using keccak 256 + * + * @method soliditySha3 * @return {Object} the sha3 */ -var sha3 = function (value) { +var soliditySha3 = function () { + var args = Array.prototype.slice.call(arguments); - return '0x'+ keccak256(value); + var hexArgs = _.map(args, function (arg) { + var type, value = ''; + + // if type is given + if (_.isObject(arg) && (arg.hasOwnProperty('v') || arg.hasOwnProperty('t') || arg.hasOwnProperty('value') || arg.hasOwnProperty('type'))) { + type = arg.t || arg.type; + value = arg.v || arg.value; + + // otherwise try to guess the type + } else { + type = toHex(arg, true); + value = toHex(arg); + + if (!type.startsWith('int') && !type.startsWith('uint')) { + type = 'bytes'; + } + } + + if ((type.startsWith('int') || type.startsWith('uint')) && typeof value === 'string' && !/^0x/i.test(value)) { + value = new BN(value); + } + + var hexArg = _solidityPack([type],[value]);//abi.encodeParam(arg.type, arg.value); + + return hexArg.toString('hex').replace('0x',''); + }); + + // console.log(hexArgs); + console.log('0x'+ hexArgs.join('')); + + return sha3('0x'+ hexArgs.join('')); }; /** * Should be called to pad string to expected length * - * @method padLeft + * @method leftPad * @param {String} string to be padded * @param {Number} chars that result string should have * @param {String} sign, by default 0 * @returns {String} right aligned string */ -var padLeft = function (string, chars, sign) { +var leftPad = function (string, chars, sign) { var hasPrefix = /^0x/i.test(string) || typeof string === 'number'; string = string.toString(16).replace(/^0x/i,''); - return (hasPrefix ? '0x' : '') + new Array(chars - string.length + 1).join(sign ? sign : "0") + string; + var padding = (chars - string.length + 1 >= 0) ? chars - string.length + 1 : 0; + + return (hasPrefix ? '0x' : '') + new Array(padding).join(sign ? sign : "0") + string; }; /** * Should be called to pad string to expected length * - * @method padRight + * @method rightPad * @param {String} string to be padded * @param {Number} chars that result string should have * @param {String} sign, by default 0 * @returns {String} right aligned string */ -var padRight = function (string, chars, sign) { +var rightPad = function (string, chars, sign) { var hasPrefix = /^0x/i.test(string) || typeof string === 'number'; string = string.toString(16).replace(/^0x/i,''); - return (hasPrefix ? '0x' : '') + string + (new Array(chars - string.length + 1).join(sign ? sign : "0")); + var padding = (chars - string.length + 1 >= 0) ? chars - string.length + 1 : 0; + + return (hasPrefix ? '0x' : '') + string + (new Array(padding).join(sign ? sign : "0")); }; /** * Check if string is HEX * * @method isHex - * @param {String} string to be checked + * @param {String} hex to be checked * @returns {Boolean} */ -var isHex = function (string) { - return (_.isString(string) && /^(-)?(0x)?[0-9a-f]+$/i.test(string)); +var isHex = function (hex) { + return ((_.isString(hex) || _.isNumber(hex)) && /^(-)?(0x)?[0-9a-f]+$/i.test(hex)); }; /** * Should be called to get utf8 from it's hex representation * - * @method toUtf8 + * @method hexToUtf8 * @param {String} hex * @returns {String} ascii string representation of hex value */ -var toUtf8 = function(hex) { +var hexToUtf8 = function(hex) { if (!isHex(hex)) throw new Error('The parameter must be a valid HEX string.'); @@ -187,11 +405,11 @@ var toUtf8 = function(hex) { /** * Should be called to get hex representation (prefixed by 0x) of utf8 string * - * @method fromUtf8 + * @method utf8ToHex * @param {String} str * @returns {String} hex representation of input string */ -var fromUtf8 = function(str) { +var utf8ToHex = function(str) { str = utf8.encode(str); var hex = ""; @@ -215,11 +433,11 @@ var fromUtf8 = function(str) { /** * Should be called to get ascii from it's hex representation * - * @method toAscii + * @method hexToAscii * @param {String} hex * @returns {String} ascii string representation of hex value */ -var toAscii = function(hex) { +var hexToAscii = function(hex) { if (!isHex(hex)) throw new Error('The parameter must be a valid HEX string.'); @@ -239,11 +457,11 @@ var toAscii = function(hex) { /** * Should be called to get hex representation (prefixed by 0x) of ascii string * - * @method fromAscii + * @method asciiToHex * @param {String} str * @returns {String} hex representation of input string */ -var fromAscii = function(str) { +var asciiToHex = function(str) { var hex = ""; for(var i = 0; i < str.length; i++) { var code = str.charCodeAt(i); @@ -254,33 +472,15 @@ var fromAscii = function(str) { return "0x" + hex; }; -/** - * Should be called to get display name of contract function - * - * @method extractDisplayName - * @param {String} name of function/event - * @returns {String} display name for function/event eg. multiply(uint256) -> multiply - */ -// var extractDisplayName = function (name) { -// var length = name.indexOf('('); -// return length !== -1 ? name.substr(0, length) : name; -// }; -// -// /// @returns overloaded part of function/event name -// var extractTypeName = function (name) { -// /// TODO: make it invulnerable -// var length = name.indexOf('('); -// return length !== -1 ? name.substr(length + 1, name.length - 1 - (length + 1)).replace(' ', '') : ""; -// }; /** * Converts value to it's number representation * - * @method toNumber + * @method hexToNumber * @param {String|Number|BN} value * @return {String} */ -var toNumber = function (value) { +var hexToNumber = function (value) { if (!value) return value; return toBN(value).toNumber(); @@ -289,11 +489,11 @@ var toNumber = function (value) { /** * Converts value to it's decimal representation in string * - * @method toNumberString + * @method hexToNumberString * @param {String|Number|BN} value * @return {String} */ -var toNumberString = function (value) { +var hexToNumberString = function (value) { if (!value) return value; return toBN(value).toString(10); @@ -302,11 +502,11 @@ var toNumberString = function (value) { /** * Converts value to it's hex representation * - * @method fromNumber + * @method numberToHex * @param {String|Number|BN} value * @return {String} */ -var fromNumber = function (value) { +var numberToHex = function (value) { var number = toBN(value); var result = number.toString(16); @@ -320,35 +520,33 @@ var fromNumber = function (value) { * * @method toHex * @param {String|Number|BN|Object} value + * @param {Boolean} returnType * @return {String} */ -var toHex = function (value) { +var toHex = function (value, returnType) { /*jshint maxcomplexity: 10 */ if (_.isBoolean(value)) { - return fromNumber(+value); + return returnType ? 'bool' : numberToHex(+value); } - if (isBN(value)) { - return fromNumber(value); + + if (_.isObject(value) && !isBigNumber(value) && !isBN(value)) { + return returnType ? 'string' : utf8ToHex(JSON.stringify(value)); } - if (_.isObject(value) && !isBigNumber(value)) { - return fromUtf8(JSON.stringify(value)); - } - - // if its a negative number, pass it through fromNumber + // if its a negative number, pass it through numberToHex if (_.isString(value)) { if (value.indexOf('-0x') === 0 || value.indexOf('-0X') === 0) { - return fromNumber(value); + return returnType ? 'uint256' : numberToHex(value); } else if(value.indexOf('0x') === 0 || value.indexOf('0X') === 0) { - return value; + return returnType ? 'bytes' : value; } else if (!isFinite(value)) { - return fromUtf8(value); + return returnType ? 'string' : utf8ToHex(value); } } - return fromNumber(value); + return returnType ? 'uint256' : numberToHex(value); }; /** @@ -433,7 +631,7 @@ var toBN = function(number){ try { return numberToBN.apply(null, arguments); } catch(e) { - throw new Error(e + ' "'+ number +'"'); + throw new Error(e + ' Given value: "'+ number +'"'); } }; @@ -492,8 +690,8 @@ var checkAddressChecksum = function (address) { var toChecksumAddress = function (address) { if (typeof address === 'undefined') return ''; - if(!isAddress(address)) - throw new Error('Given address "'+ address +'" is not a valid ethereum address.'); + if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) + throw new Error('Given address "'+ address +'" is not a valid Ethereum address.'); @@ -546,28 +744,47 @@ module.exports = { BN: BN, isBN: isBN, isBigNumber: isBigNumber, + isHex: isHex, sha3: sha3, + keccak256: sha3, + soliditySha3: soliditySha3, isAddress: isAddress, checkAddressChecksum: checkAddressChecksum, toChecksumAddress: toChecksumAddress, toHex: toHex, toBN: toBN, - toNumberString: toNumberString, - toNumber: toNumber, - toDecimal: toNumber, // alias - fromNumber: fromNumber, - fromDecimal: fromNumber, // alias - toUtf8: toUtf8, - toString: toUtf8, - toAscii: toAscii, - fromUtf8: fromUtf8, - fromString: fromUtf8, - fromAscii: fromAscii, + + bytesToHex: bytesToHex, + hexToBytes: hexToBytes, + + hexToNumberString: hexToNumberString, + + hexToNumber: hexToNumber, + toDecimal: hexToNumber, // alias + + numberToHex: numberToHex, + fromDecimal: numberToHex, // alias + + hexToUtf8: hexToUtf8, + hexToString: hexToUtf8, + toUtf8: hexToUtf8, + + utf8ToHex: utf8ToHex, + stringToHex: utf8ToHex, + fromUtf8: utf8ToHex, + + hexToAscii: hexToAscii, + toAscii: hexToAscii, + asciiToHex: asciiToHex, + fromAscii: asciiToHex, + unitMap: ethjsUnit.unitMap, toWei: toWei, fromWei: fromWei, - padLeft: padLeft, - padRight: padRight + padLeft: leftPad, + leftPad: leftPad, + padRight: rightPad, + rightPad: rightPad }; diff --git a/packages/web3-utils/src/sha3.js b/packages/web3-utils/src/sha3.js deleted file mode 100644 index 9052e32..0000000 --- a/packages/web3-utils/src/sha3.js +++ /dev/null @@ -1,41 +0,0 @@ -/* - This file is part of web3.js. - - web3.js is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - web3.js is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with web3.js. If not, see . -*/ -/** - * @file sha3.js - * @author Marek Kotewicz - * @date 2015 - */ - -"use strict"; - -var CryptoJS = require('crypto-js'); -var sha3 = require('crypto-js/sha3'); -// var sha3 = require('js-sha3').sha3_256; -sha3 = require("ethjs-sha3"); - -module.exports = function (value, options) { - if (options && options.encoding === 'hex') { - if (value.length > 2 && value.substr(0, 2) === '0x') { - value = value.substr(2); - } - console.log(CryptoJS.enc.Hex.parse(value).toString(10)); - value = CryptoJS.enc.Hex.parse(value).toString(16); - } - - return sha3(value); //{outputLength: 256} -}; - diff --git a/test/utils.fromAscii.js b/test/utils.fromAscii.js index 7b62527..7972919 100644 --- a/test/utils.fromAscii.js +++ b/test/utils.fromAscii.js @@ -11,7 +11,7 @@ var tests = [ ]; describe('lib/utils/utils', function () { - describe('fromAscii', function () { + describe('asciiToHex', function () { tests.forEach(function (test) { it('should turn ' + test.value + ' to ' + test.expected, function () { assert.strictEqual(utils.fromAscii(test.value), test.expected); diff --git a/test/utils.fromNumber.js b/test/utils.fromNumber.js index 723ded4..febbe5c 100644 --- a/test/utils.fromNumber.js +++ b/test/utils.fromNumber.js @@ -34,10 +34,10 @@ var tests = [ ]; describe('lib/utils/utils', function () { - describe('fromNumber', function () { + describe('numberToHex', function () { tests.forEach(function (test) { it('should turn ' + test.value + ' to ' + test.expected, function () { - assert.equal(utils.fromNumber(test.value), test.expected); + assert.equal(utils.numberToHex(test.value), test.expected); }); }); }); diff --git a/test/utils.fromUtf8.js b/test/utils.fromUtf8.js index a565d6d..470b996 100644 --- a/test/utils.fromUtf8.js +++ b/test/utils.fromUtf8.js @@ -12,7 +12,7 @@ var tests = [ ]; describe('lib/utils/utils', function () { - describe('fromUtf8', function () { + describe('utf8ToHex', function () { tests.forEach(function (test) { it('should turn ' + test.value + ' to ' + test.expected, function () { assert.strictEqual(utils.fromUtf8(test.value), test.expected); diff --git a/test/utils.sha3.js b/test/utils.sha3.js index 32e9785..66e0bb9 100644 --- a/test/utils.sha3.js +++ b/test/utils.sha3.js @@ -28,10 +28,10 @@ describe('web3.sha3', function () { }).toString(); }; - // test3 = sha3('0x80', {encoding: 'hex'}); - // test4 = sha3('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1', {encoding: 'hex'}); - // assert.deepEqual(test3, '0x' + sha3Hex('0x80')); - // assert.deepEqual(test4, '0x' + sha3Hex('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1')); + test3 = sha3('0x80'); + test4 = sha3('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1'); + assert.deepEqual(test3, '0x' + sha3Hex('0x80')); + assert.deepEqual(test4, '0x' + sha3Hex('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1')); }); it('should return sha3 with hex prefix when hex input', function() { @@ -43,9 +43,9 @@ describe('web3.sha3', function () { test('test123', '0xf81b517a242b218999ec8eec0ea6e2ddbef2a367a14e93f4a32a39e260f686ad'); test('test(int)', '0xf4d03772bec1e62fbe8c5691e1a9101e520e8f8b5ca612123694632bf3cb51b1'); - test('0x80', '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421', { encoding: 'hex' }); + test('0x80', '0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421'); test('0x80', '0x6b03a5eef7706e3fb52a61c19ab1122fad7237726601ac665bd4def888f0e4a0'); - test('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1', '0x82ff40c0a986c6a5cfad4ddf4c3aa6996f1a7837f9c398e17e5de5cbd5a12b28', { encoding: 'hex' }); + test('0x3c9229289a6125f7fdf1885a77bb12c37a8d3b4962d936f7e3084dece32a3ca1', '0x82ff40c0a986c6a5cfad4ddf4c3aa6996f1a7837f9c398e17e5de5cbd5a12b28'); }); }); diff --git a/test/utils.soliditySha3.js b/test/utils.soliditySha3.js new file mode 100644 index 0000000..b9524a1 --- /dev/null +++ b/test/utils.soliditySha3.js @@ -0,0 +1,135 @@ +var _ = require('underscore'); +var BN = require('bn.js'); +var BigNumber = require('bignumber.js'); +var chai = require('chai'); +var assert = chai.assert; +var utils = require('../packages/web3-utils'); + +// each "values" is one kind of parameter of the same type +var tests = [{ + values: [ + true, + {value: true, type: 'bool'}, + {v: true, t: 'bool'}, + {v: true, type: 'bool'}, + {value: true, t: 'bool'} + ], expected: '0x5fe7f977e71dba2ea1a68e21057beebb9be2ac30c6410aa38d4f3fbe41dcffd2' +},{ + values: [ + false, + {value: false, type: 'bool'}, + {v: false, t: 'bool'}, + {v: false, type: 'bool'}, + {value: false, t: 'bool'} + ], expected: '0xbc36789e7a1e281436464229828f817d6612f7b477d66591ff96a9e064bcc98a' +},{ + values: [ + 'Hello!%', + {value: 'Hello!%', type: 'string'}, + {value: 'Hello!%', type: 'string'}, + {v: 'Hello!%', t: 'string'} + ], expected: '0x661136a4267dba9ccdf6bfddb7c00e714de936674c4bdb065a531cf1cb15c7fc' +},{ + values: [ + 2345676856, + '2345676856', + new BN('2345676856'), + new BigNumber('2345676856', 10), + {v: '2345676856', t: 'uint256'}, + {v: new BN('2345676856'), t: 'uint256'}, + {v: '2345676856', t: 'uint'} + ], expected: '0xc0a8dac986ad882fff6b05a7792e1259f2fd8fa72d632fb48f54affea59af6fc' +},{ + values: [ + '2342342342342342342345676856', + new BN('2342342342342342342345676856'), + new BigNumber('2342342342342342342345676856', 10), + {v: '2342342342342342342345676856', t: 'uint256'}, + {v: '2342342342342342342345676856', t: 'uint'} + ], expected: '0x8ac2efaaee0058e1f1fbcb59643f6799c31c27096a347651e40f98daf1905094' +},{ + values: [ + {v: '56', t: 'uint8'} + ], expected: '0xe4b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10' +},{ + values: [ + {v: '256', t: 'uint16'} + ], expected: '0x628bf3596747d233f1e6533345700066bf458fa48daedaf04a7be6c392902476' +},{ + values: [ + {v: '3256', t: 'uint32'} + ], expected: '0x720e835027b41b4b3e057ee9e6d4351ffc726d767652cdb0fc874869df88001c' +},{ + values: [ + {v: '454256', t: 'uint64'} + ], expected: '0x5ce6ff175acd532fb4dcef362c829e74a0ce1fde4a43885cca0d257b33d06d07' +},{ + values: [ + {v: '44454256', t: 'uint128'} + ], expected: '0x372b694bc0f2dd9229f39b3892621a6ae3ffe111c5096a0a9253c34558a92ab8' +},{ + values: [ + {v: '3435454256', t: 'uint160'} + ], expected: '0x89e0942df3602c010e0252becbbe1b4053bd4a871a021c02d8ab9878f1194b6b' +},{ + values: [ + '0x2345435675432144555ffffffffdd222222222222224444556553522', + {v: '0x2345435675432144555ffffffffdd222222222222224444556553522', t: 'bytes'}, + {v: '2345435675432144555ffffffffdd222222222222224444556553522', t: 'bytes'} + ], expected: '0xb7ecb0d74e96b792a62b4a9dad28f5b1795417a89679562178b1987e0767e009' +},{ + values: [ + {v: '0x22', t: 'bytes2'}, + {v: '22', t: 'bytes2'} + ], expected: '0xb07fb0a3471486f9ccb02aab1d525df60d82925cb2d27860f923e655d76f35fc' +}]; + + +describe('web3.soliditySha3', function () { + tests.forEach(function (test) { + test.values.forEach(function (value) { + it('should hash "'+ value +'" into "'+ test.expected +'"', function() { + + if (!_.isArray(value)) { + value = [value]; + } + + assert.deepEqual(utils.soliditySha3.apply(null, value), test.expected); + + }); + }); + }); + + it('should hash mixed boolean values in any order', function() { + + assert.deepEqual(utils.soliditySha3( + tests[0].values[1], // true + tests[1].values[0], // false + tests[1].values[2], // false + tests[0].values[3] // true + ), '0x4ba958c4829ba5d3f9eaa61058ef208aba8bc25c0b6e33044015e0af9fb1c35d'); + }); + + it('should hash mixed string and number values in any order', function() { + + assert.deepEqual(utils.soliditySha3( + tests[2].values[0], // 'Hello!%' + tests[3].values[2], // 2345676856 + tests[4].values[2], // '2342342342342342342345676856' + tests[2].values[3], // 'Hello!%' + tests[1].values[2] // false + ), '0x7eb45eb9a0e1f6904514bc34c8b43e71c2e1f96f21b45ea284a0418cb351ec69'); + }); + + it('should hash mixed number types in any order', function() { + + assert.deepEqual(utils.soliditySha3( + tests[5].values[0], // v: '56', t: 'uint8' + tests[6].values[0], // v: '256', t: 'uint16' + tests[7].values[0], // v: '3256', t: 'uint32' + tests[8].values[0], // v: '454256', t: 'uint64' + tests[9].values[0], // v: '44454256', t: 'uint128' + tests[10].values[0] // v: '3435454256', t: 'uint160' + ), '0x31d6c48574796dfb1a652f2e5c5a261db0677e39fff5c3032449c50eade4b6b6'); + }); +}); diff --git a/test/utils.toAscii.js b/test/utils.toAscii.js index fa0734f..1eb653e 100644 --- a/test/utils.toAscii.js +++ b/test/utils.toAscii.js @@ -11,7 +11,7 @@ var tests = [ ]; describe('lib/utils/utils', function () { - describe('toAscii', function () { + describe('hexToAscii', function () { tests.forEach(function (test) { it('should turn ' + test.value + ' to ' + test.expected, function () { assert.strictEqual(utils.toAscii(test.value), test.expected); diff --git a/test/utils.toNumber.js b/test/utils.toNumber.js index 68bf2b1..ccc519a 100644 --- a/test/utils.toNumber.js +++ b/test/utils.toNumber.js @@ -2,14 +2,14 @@ var assert = require('assert'); var utils = require('../packages/web3-utils'); describe('lib/utils/utils', function () { - describe('toNumberString', function () { + describe('hexToNumberString', function () { it('should return the correct value', function () { - assert.equal(utils.toNumberString("0x3e8"), 1000); - assert.equal(utils.toNumberString('0x1f0fe294a36'), 2134567897654); + assert.equal(utils.hexToNumberString("0x3e8"), 1000); + assert.equal(utils.hexToNumberString('0x1f0fe294a36'), 2134567897654); // allow compatiblity - assert.equal(utils.toNumberString(100000), 100000); - assert.equal(utils.toNumberString('100000'), 100000); + assert.equal(utils.hexToNumberString(100000), 100000); + assert.equal(utils.hexToNumberString('100000'), 100000); }); }); }); diff --git a/test/utils.toNumberString.js b/test/utils.toNumberString.js index a29b84a..680122c 100644 --- a/test/utils.toNumberString.js +++ b/test/utils.toNumberString.js @@ -2,14 +2,14 @@ var assert = require('assert'); var utils = require('../packages/web3-utils'); describe('lib/utils/utils', function () { - describe('toNumberString', function () { + describe('hexToNumberString', function () { it('should return the correct value', function () { - assert.equal(utils.toNumberString("0x3e8"), '1000'); - assert.equal(utils.toNumberString('0x1f0fe294a36'), '2134567897654'); + assert.equal(utils.hexToNumberString("0x3e8"), '1000'); + assert.equal(utils.hexToNumberString('0x1f0fe294a36'), '2134567897654'); // allow compatiblity - assert.equal(utils.toNumberString(100000), '100000'); - assert.equal(utils.toNumberString('100000'), '100000'); + assert.equal(utils.hexToNumberString(100000), '100000'); + assert.equal(utils.hexToNumberString('100000'), '100000'); }); }); }); diff --git a/test/utils.toUtf8.js b/test/utils.toUtf8.js index 03b6f80..22914e8 100644 --- a/test/utils.toUtf8.js +++ b/test/utils.toUtf8.js @@ -12,7 +12,7 @@ var tests = [ ]; describe('lib/utils/utils', function () { - describe('toUtf8', function () { + describe('hexToUtf8', function () { tests.forEach(function (test) { it('should turn ' + test.value + ' to ' + test.expected, function () { assert.strictEqual(utils.toUtf8(test.value), test.expected); diff --git a/test/utils_methods.js b/test/utils_methods.js index ffb7584..ca0450f 100644 --- a/test/utils_methods.js +++ b/test/utils_methods.js @@ -4,10 +4,10 @@ var utils = require('../packages/web3-utils'); describe('utils', function() { describe('methods', function () { u.methodExists(utils, 'sha3'); - u.methodExists(utils, 'toAscii'); - u.methodExists(utils, 'fromAscii'); - u.methodExists(utils, 'toNumberString'); - u.methodExists(utils, 'fromNumber'); + u.methodExists(utils, 'hexToAscii'); + u.methodExists(utils, 'asciiToHex'); + u.methodExists(utils, 'hexToNumberString'); + u.methodExists(utils, 'numberToHex'); u.methodExists(utils, 'fromWei'); u.methodExists(utils, 'toWei'); u.methodExists(utils, 'toBN');