packages/oo7-parity/src/utils/index.js
- // (C) Copyright 2016-2017 Parity Technologies (UK) Ltd.
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
-
- /* global parity */
- const BigNumber = require('bignumber.js');
- const oo7 = require('oo7');
- const ParityApi = require('@parity/api');
-
- const asciiToHex = ParityApi.util.asciiToHex;
- const bytesToHex = ParityApi.util.bytesToHex;
- const hexToAscii = ParityApi.util.hexToAscii;
- const isAddressValid = h => oo7.Bond.instanceOf(h) ? h.map(ParityApi.util.isAddressValid) : ParityApi.util.isAddressValid(h);
- const toChecksumAddress = h => oo7.Bond.instanceOf(h) ? h.map(ParityApi.util.toChecksumAddress) : ParityApi.util.toChecksumAddress(h);
- const sha3 = h => oo7.Bond.instanceOf(h) ? h.map(ParityApi.util.sha3) : ParityApi.util.sha3(h);
-
- const denominations = [ 'wei', 'Kwei', 'Mwei', 'Gwei', 'szabo', 'finney', 'ether', 'grand', 'Mether', 'Gether', 'Tether', 'Pether', 'Eether', 'Zether', 'Yether', 'Nether', 'Dether', 'Vether', 'Uether' ];
-
- // Parity Utilities
- // TODO: move to parity.js, repackage or repot.
-
- /**
- * Capitalizes the first letter of a string
- *
- * @param {string} s
- * @returns {string}
- */
- function capitalizeFirstLetter (s) {
- return s.charAt(0).toUpperCase() + s.slice(1);
- }
-
- /**
- * Wrap `f` in a function that ensures it's called at most once.
- * The value returned from `f` is memoized and returned for all subsequent calls.
- *
- * @param {F} f
- * @returns {function(): F}
- */
- function singleton (f) {
- var instance = null;
- return function () {
- if (instance === null) { instance = f(); }
- return instance;
- };
- }
-
- /**
- * Returns a {@link BigNumber} multiplier for give string denominator
- *
- * @param {string} denominator denominator (wei, eth, finney, Gwei, etc)
- * @returns {BigNumber} multiplier
- */
- function denominationMultiplier (s) {
- let i = denominations.indexOf(s);
- if (i < 0) { throw new Error('Invalid denomination'); }
- return (new BigNumber(1000)).pow(i);
- }
-
- function interpretRender (s, defaultDenom = 6) {
- try {
- let m = s.toLowerCase().match(/([0-9,]+)(\.([0-9]*))? *([a-zA-Z]+)?/);
- let di = m[4] ? denominations.indexOf(m[4]) : defaultDenom;
- if (di === -1) {
- return null;
- }
- let n = (m[1].replace(',', '').replace(/^0*/, '')) || '0';
- let d = (m[3] || '').replace(/0*$/, '');
- return { denom: di, units: n, decimals: d, origNum: m[1] + (m[2] || ''), origDenom: m[4] || '' };
- } catch (e) {
- return null;
- }
- }
-
- function combineValue (v) {
- let d = (new BigNumber(1000)).pow(v.denom);
- let n = v.units;
- if (v.decimals) {
- n += v.decimals;
- d = d.div((new BigNumber(10)).pow(v.decimals.length));
- }
- return new BigNumber(n).mul(d);
- }
-
- /**
- * Add missing denominator to the value
- *
- * @param {BigNumber} v value
- * @param {string} d denominator
- * @returns {Value}
- */
- function defDenom (v, d) {
- if (v.denom === null) {
- v.denom = d;
- }
- return v;
- }
-
- /**
- * Formats a value with denominator
- *
- * @param {Value} n value with denominator
- * @returns {string}
- */
- function formatValue (n) {
- return `${formatValueNoDenom(n)} ${denominations[n.denom]}`;
- }
-
- /**
- * Format value without denominator
- * @param {Value} v
- * @returns {string}
- */
- function formatValueNoDenom (n) {
- return `${n.units.toString().replace(/(\d)(?=(\d{3})+$)/g, '$1,')}${n.decimals ? '.' + n.decimals : ''}`;
- }
-
- /**
- * Format value without denominator
- *
- * @param {number|BigNumber} v
- * @param {number| exponent
- * @returns {string}
- */
- function formatToExponential (v, n = 4) {
- return new BigNumber(v).toExponential(n);
- }
-
- function interpretQuantity (s) {
- try {
- let m = s.toLowerCase().match(/([0-9,]+)(\.([0-9]*))? *([a-zA-Z]+)?/);
- let d = denominationMultiplier(m[4] || 'ether');
- let n = +m[1].replace(',', '');
- if (m[2]) {
- n += m[3];
- for (let i = 0; i < m[3].length; ++i) {
- d = d.div(10);
- }
- }
- return new BigNumber(n).mul(d);
- } catch (e) {
- return null;
- }
- }
-
- /**
- * Split value into base and denominator
- *
- * @param {number|BigNumber} a
- * @returns {Value}
- */
- function splitValue (a) {
- var i = 0;
- a = new BigNumber('' + a);
- if (a.gte(new BigNumber('10000000000000000')) && a.lt(new BigNumber('100000000000000000000000'))) {
- i = 6;
- } else {
- for (var aa = a; aa.gte(1000) && i < denominations.length - 1; aa = aa.div(1000)) { i++; }
- }
-
- for (var j = 0; j < i; ++j) { a = a.div(1000); }
-
- return { base: a, denom: i };
- }
-
- /**
- * Display balance into human-readable format with denomnator
- *
- * @param {string|BigNumber} balance
- * @returns {string}
- */
- function formatBalance (n) {
- let a = splitValue(n);
- // let b = Math.floor(a.base * 1000) / 1000;
- return `${a.base} ${denominations[a.denom]}`;
- }
-
- /**
- * Format block number into human-readable representation.
- * @param {string|number|BigNumber} blockNumber
- * @returns {string}
- */
- function formatBlockNumber (n) {
- return '#' + ('' + n).replace(/(\d)(?=(\d{3})+$)/g, '$1,');
- }
-
- function isNullData (a) {
- return !a || typeof (a) !== 'string' || a.match(/^(0x)?0+$/) !== null;
- }
-
- function splitSignature (sig) {
- if ((sig.substr(2, 2) === '1b' || sig.substr(2, 2) === '1c') && (sig.substr(66, 2) !== '1b' && sig.substr(66, 2) !== '1c')) {
- // vrs
- return [sig.substr(0, 4), `0x${sig.substr(4, 64)}`, `0x${sig.substr(68, 64)}`];
- } else {
- // rsv
- return [`0x${sig.substr(130, 2)}`, `0x${sig.substr(2, 64)}`, `0x${sig.substr(66, 64)}`];
- }
- }
-
- function removeSigningPrefix (message) {
- if (!message.startsWith('\x19Ethereum Signed Message:\n')) {
- throw new Error('Invalid message - doesn\'t contain security prefix');
- }
- for (var i = 1; i < 6; ++i) {
- if (message.length === 26 + i + +message.substr(26, i)) {
- return message.substr(26 + i);
- }
- }
- throw new Error('Invalid message - invalid security prefix');
- }
-
- function cleanup (value, type = 'bytes32', api = parity.api) {
- // TODO: make work with arbitrary depth arrays
- if (value instanceof Array && type.match(/bytes[0-9]+/)) {
- // figure out if it's an ASCII string hiding in there:
- var ascii = '';
- for (var i = 0, ended = false; i < value.length && ascii !== null; ++i) {
- if (value[i] === 0) {
- ended = true;
- } else {
- ascii += String.fromCharCode(value[i]);
- }
- if ((ended && value[i] !== 0) || (!ended && (value[i] < 32 || value[i] >= 128))) {
- ascii = null;
- }
- }
- value = ascii === null ? '0x' + value.map(n => ('0' + n.toString(16)).slice(-2)).join('') : ascii;
- }
- if (type.substr(0, 4) === 'uint' && +type.substr(4) <= 48) {
- value = +value;
- }
- return value;
- }
-
- module.exports = {
- asciiToHex,
- bytesToHex,
- hexToAscii,
- isAddressValid,
- toChecksumAddress,
- sha3,
- capitalizeFirstLetter,
- singleton,
- denominations,
- denominationMultiplier,
- interpretRender,
- combineValue,
- defDenom,
- formatValue,
- formatValueNoDenom,
- formatToExponential,
- interpretQuantity,
- splitValue,
- formatBalance,
- formatBlockNumber,
- isNullData,
- splitSignature,
- removeSigningPrefix,
- cleanup
- };