@silasdavis/legacy-contracts
Version:
Library with javascript bindings for Solidity contracts.
456 lines (419 loc) • 11.2 kB
JavaScript
/**
* @file utils.js
* @author Marek Kotewicz <marek@ethdev.com>
* @author Andreas Olofsson
* @date 2015
* @module utils/utils
*/
var BigNumber = require('bignumber.js')
var utf8 = require('utf8')
/**
* Should be called to pad string to expected length
*
* @method padLeft
* @param {String} string to be padded
* @param {Number} chars - characters that result string should have
* @param {String} sign, by default 0
* @returns {String} right aligned string
*/
var padLeft = function (string, chars, sign) {
return new Array(chars - string.length + 1).join(sign || '0') + string
}
/**
* Should be called to pad string to expected length
*
* @method padRight
* @param {String} string to be padded
* @param {Number} chars - characters that result string should have
* @param {String} sign, by default 0
* @returns {String} right aligned string
*/
var padRight = function (string, chars, sign) {
return string + (new Array(chars - string.length + 1).join(sign || '0'))
}
/**
* Shold be called to get hex representation (prefixed by 0x) of utf8 string
*
* @method fromUtf8
* @param {String} str - string
* @param {Number} optional padding
* @returns {String} hex representation of input string
*/
var fromUtf8 = function (str) {
str = utf8.encode(str)
var hex = ''
for (var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16)
hex += n.length < 2 ? '0' + n : n
}
return hex
}
/**
* Should be called to get utf8 from it's hex representation
*
* @method toUtf8
* @param {String} hex - string in hex
* @returns {String} ascii string representation of hex value
*/
var toUtf8 = function (hex) {
// Find termination
var str = ''
var i = 0
var l = hex.length
if (hex.substring(0, 2) === '0x') {
i = 2
}
for (; i < l; i += 2) {
var code = parseInt(hex.substr(i, 2), 16)
str += String.fromCharCode(code)
}
return utf8.decode(str)
}
/**
* Should be called to get sting from it's hex representation
*
* @method toAscii
* @param {String} hex - string in hex
* @returns {String} ascii string representation of hex value
*/
var hexToAscii = function (hex) {
// Find termination
var str = ''
var i = 0
var l = hex.length
if (hex.substring(0, 2) === '0x') {
i = 2
}
for (; i < l; i += 2) {
for (; i < l; i += 2) {
var code = parseInt(hex.substr(i, 2), 16)
str += String.fromCharCode(code)
}
}
return str
}
/**
* Should be called to get hex representation of ascii string
*
* @method toHexNative
* @param {String} str - string
* @param {Number} pad - optional padding
* @returns {String} hex representation of input string
*/
var asciiToHex = function (str, pad) {
var hex = ''
for (var i = 0; i < str.length; i++) {
var n = str.charCodeAt(i).toString(16)
hex += n.length < 2 ? '0' + n : n
}
pad = pad === undefined ? 0 : pad
while (hex.length < pad * 2) { hex += '00' }
return hex
}
/**
* Should be used to create full function/event name from json abi
*
* @method transformToFullName
* @param {Object} json - json-abi
* @return {String} full fnction/event name
*/
var transformToFullName = function (json) {
if (json.name.indexOf('(') !== -1) {
return json.name
}
var typeName = json.inputs.map(function (i) {
return i.type
}).join()
return json.name + '(' + typeName + ')'
}
/**
* 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
}
/**
*
* @param {String} name - the name.
* @returns {String} 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 decimal representation in string
*
* @method toDecimal
* @param {String|Number|BigNumber} value - the value
* @return {String}
*/
var toDecimal = function (value) {
return toBigNumber(value).toNumber()
}
/**
* Converts value to it's hex representation
*
* TODO why is this called 'fromDecimal' when a use case is to pass it a confirmed (signed) hex string.
*
* @method fromDecimal
* @param {String|Number|BigNumber} value - the value
* @return {String}
*/
var fromDecimal = function (value) {
var number = toBigNumber(value)
var result = number.toString(16)
return number.lessThan(0) ? '-0x' + result.substr(1) : result
}
/**
* Auto converts any given value into it's hex representation.
*
* @method toHex
* @param {boolean|String|Number|BigNumber|Object} val - the value.
* @return {String}
*/
var toHex = function (val) {
/* jshint maxcomplexity: 8 */
if (isBoolean(val)) {
return fromDecimal(+val)
} else if (isNumber(val)) {
return fromDecimal(val)
} else if (isBigNumber(val)) {
return fromDecimal(val)
} else if (isObject(val)) {
return asciiToHex(JSON.stringify(val))
} else if (isString(val)) {
// Zero-length strings are null hex-strings, which we allow.
if (val.length === 0) {
return val
} else if (val[0] === '-') {
// Switch on first char being a '-'. If this is the case, it's either
// a signed hex- or decimal-string, otherwise ascii.
if (isHex(val.substr(1)) || isDecimal(val.substr(1))) {
return fromDecimal(val)
} else {
return asciiToHex(val)
}
} else {
// We make sure any '0x' is removed before returning.
if (isHex(val)) {
if (val.length >= 2 && val.indexOf('0x') === 0) {
val = val.substr(2)
}
return val
} else if (isDecimal(val)) {
return fromDecimal(val)
} else {
return asciiToHex(val)
}
}
} else {
// If neither a boolean, number, bignumber or string, throw a type error.
throw new TypeError('No method for converting object into hex: ' + val.toString())
}
}
/**
* Takes an input and transforms it into an bignumber
*
* @method toBigNumber
* @param {Number|String|BigNumber} number - a number, string, HEX string or BigNumber
* @return {BigNumber} BigNumber
*/
var toBigNumber = function (number) {
/* jshint maxcomplexity:5 */
number = number || 0
if (isBigNumber(number)) { return number }
if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {
return new BigNumber(number.replace('0x', ''), 16)
}
return new BigNumber(number.toString(10), 10)
}
/**
* Takes and input transforms it into bignumber and if it is negative value, into two's complement
*
* @method toTwosComplement
* @param {Number|String|BigNumber} number - input number
* @return {BigNumber}
*/
var toTwosComplement = function (number) {
var bigNumber = toBigNumber(number)
if (bigNumber.lessThan(0)) {
return new BigNumber('FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF', 16).plus(bigNumber).plus(1)
}
return bigNumber
}
/**
* Checks if the given string is strictly an address
*
* @method isStrictAddress
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isStrictAddress = function (address) {
return /^0x[0-9a-fA-F]{40}$/.test(address)
}
/**
* Checks if the given string is an address
*
* @method isAddress
* @param {String} address the given HEX adress
* @return {Boolean}
*/
var isAddress = function (address) {
return /^(0x)?[0-9a-fA-F]{40}$/.test(address)
}
/**
* Checks if the given string is hex
*
* @method isHex
* @param {String} str - the string
* @return {Boolean}
*/
var isHex = function (str) {
return /^(0x)?[0-9a-fA-F]*$/.test(str)
}
/**
* Checks if the given string is decimal
*
* @method isDecimal
* @param {String} str - the string
* @return {Boolean}
*/
var isDecimal = function (str) {
return /^[0-9]*$/.test(str)
}
/**
* Transforms given string to valid 20 bytes-length addres with 0x prefix
*
* @method toAddress
* @param {String} address
* @return {String} formatted address
*/
var toAddress = function (address) {
if (isStrictAddress(address)) {
return address.substr(2)
}
if (/^[0-9a-f]{40}$/.test(address)) {
return address
}
return padLeft(toHex(address).substr(2), 40)
}
/**
* Returns true if object is BigNumber, otherwise false
*
* @method isBigNumber
* @param {Object} object - object to test
* @return {Boolean}
*/
var isBigNumber = function (object) {
return object instanceof BigNumber ||
(object && object.constructor && object.constructor.name === 'BigNumber')
}
/**
* Returns true if object is string, otherwise false
*
* @method isString
* @param {Object} object - object to test
* @return {Boolean}
*/
var isString = function (object) {
return typeof object === 'string' ||
(object && object.constructor && object.constructor.name === 'String')
}
/**
* Returns true if object is a number, otherwise false
*
* @method isString
* @param {Object} object - object to test
* @return {Boolean}
*/
var isNumber = function (object) {
return typeof object === 'number' ||
(object && object.constructor && object.constructor.name === 'Number')
}
/**
* Returns true if object is function, otherwise false
*
* @method isFunction
* @param {Object} object - object to test
* @return {Boolean}
*/
var isFunction = function (object) {
return typeof object === 'function'
}
/**
* Returns true if object is Objet, otherwise false
*
* @method isObject
* @param {Object} object - object to test
* @return {Boolean}
*/
var isObject = function (object) {
return typeof object === 'object'
}
/**
* Returns true if object is boolean, otherwise false
*
* @method isBoolean
* @param {Object} object - object to test
* @return {Boolean}
*/
var isBoolean = function (object) {
return typeof object === 'boolean'
}
/**
* Returns true if object is array, otherwise false
*
* @method isArray
* @param {Object} object - object to test
* @return {Boolean}
*/
var isArray = function (object) {
return object instanceof Array
}
/**
* Returns true if given string is valid json object
*
* @method isJson
* @param {String} str - the string to test
* @return {Boolean}
*/
var isJson = function (str) {
try {
return !!JSON.parse(str)
} catch (e) {
return false
}
}
module.exports = {
toHex: toHex,
padLeft: padLeft,
padRight: padRight,
hexToAscii: hexToAscii,
asciiToHex: asciiToHex,
fromDecimal: fromDecimal,
toDecimal: toDecimal,
transformToFullName: transformToFullName,
extractDisplayName: extractDisplayName,
extractTypeName: extractTypeName,
toTwosComplement: toTwosComplement,
toAddress: toAddress,
isBigNumber: isBigNumber,
isStrictAddress: isStrictAddress,
isAddress: isAddress,
isHex: isHex,
isFunction: isFunction,
isString: isString,
isObject: isObject,
isBoolean: isBoolean,
isArray: isArray,
isJson: isJson,
fromUtf8: fromUtf8,
toUtf8: toUtf8
}