ethers.js/utils/convert.js

225 lines
5.3 KiB
JavaScript

/**
* Conversion Utilities
*
*/
var defineProperty = require('./properties.js').defineProperty;
var errors = require('./errors');
function addSlice(array) {
if (array.slice) { return array; }
array.slice = function() {
var args = Array.prototype.slice.call(arguments);
return new Uint8Array(Array.prototype.slice.apply(array, args));
}
return array;
}
function isArrayish(value) {
if (!value || parseInt(value.length) != value.length || typeof(value) === 'string') {
return false;
}
for (var i = 0; i < value.length; i++) {
var v = value[i];
if (v < 0 || v >= 256 || parseInt(v) != v) {
return false;
}
}
return true;
}
function arrayify(value) {
if (value == null) {
errors.throwError('cannot convert null value to array', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
if (value && value.toHexString) {
value = value.toHexString();
}
if (isHexString(value)) {
value = value.substring(2);
if (value.length % 2) { value = '0' + value; }
var result = [];
for (var i = 0; i < value.length; i += 2) {
result.push(parseInt(value.substr(i, 2), 16));
}
return addSlice(new Uint8Array(result));
} else if (typeof(value) === 'string') {
if (value.match(/^[0-9a-fA-F]*$/)) {
errors.throwError('hex string must have 0x prefix', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
errors.throwError('invalid hexidecimal string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
if (isArrayish(value)) {
return addSlice(new Uint8Array(value));
}
errors.throwError('invalid arrayify value', { arg: 'value', value: value, type: typeof(value) });
}
function concat(objects) {
var arrays = [];
var length = 0;
for (var i = 0; i < objects.length; i++) {
var object = arrayify(objects[i])
arrays.push(object);
length += object.length;
}
var result = new Uint8Array(length);
var offset = 0;
for (var i = 0; i < arrays.length; i++) {
result.set(arrays[i], offset);
offset += arrays[i].length;
}
return addSlice(result);
}
function stripZeros(value) {
value = arrayify(value);
if (value.length === 0) { return value; }
// Find the first non-zero entry
var start = 0;
while (value[start] === 0) { start++ }
// If we started with zeros, strip them
if (start) {
value = value.slice(start);
}
return value;
}
function padZeros(value, length) {
value = arrayify(value);
if (length < value.length) { throw new Error('cannot pad'); }
var result = new Uint8Array(length);
result.set(value, length - value.length);
return addSlice(result);
}
function isHexString(value, length) {
if (typeof(value) !== 'string' || !value.match(/^0x[0-9A-Fa-f]*$/)) {
return false
}
if (length && value.length !== 2 + 2 * length) { return false; }
return true;
}
var HexCharacters = '0123456789abcdef';
function hexlify(value) {
if (value && value.toHexString) {
return value.toHexString();
}
if (typeof(value) === 'number') {
if (value < 0) {
errors.throwError('cannot hexlify negative value', errors.INVALID_ARG, { arg: 'value', value: value });
}
var hex = '';
while (value) {
hex = HexCharacters[value & 0x0f] + hex;
value = parseInt(value / 16);
}
if (hex.length) {
if (hex.length % 2) { hex = '0' + hex; }
return '0x' + hex;
}
return '0x00';
}
if (isHexString(value)) {
if (value.length % 2) {
value = '0x0' + value.substring(2);
}
return value;
}
if (isArrayish(value)) {
var result = [];
for (var i = 0; i < value.length; i++) {
var v = value[i];
result.push(HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f]);
}
return '0x' + result.join('');
}
errors.throwError('invalid hexlify value', { arg: 'value', value: value });
}
function hexStripZeros(value) {
while (value.length > 3 && value.substring(0, 3) === '0x0') {
value = '0x' + value.substring(3);
}
return value;
}
function hexZeroPad(value, length) {
while (value.length < 2 * length + 2) {
value = '0x0' + value.substring(2);
}
return value;
}
/* @TODO: Add something like this to make slicing code easier to understand
function hexSlice(hex, start, end) {
hex = hexlify(hex);
return '0x' + hex.substring(2 + start * 2, 2 + end * 2);
}
*/
function splitSignature(signature) {
signature = arrayify(signature);
if (signature.length !== 65) {
throw new Error('invalid signature');
}
var v = signature[64];
if (v !== 27 && v !== 28) {
v = 27 + (v % 2);
}
return {
r: hexlify(signature.slice(0, 32)),
s: hexlify(signature.slice(32, 64)),
v: v
}
}
module.exports = {
arrayify: arrayify,
isArrayish: isArrayish,
concat: concat,
padZeros: padZeros,
stripZeros: stripZeros,
splitSignature: splitSignature,
hexlify: hexlify,
isHexString: isHexString,
hexStripZeros: hexStripZeros,
hexZeroPad: hexZeroPad,
};