ethers.js/utils/bytes.js

256 lines
7.8 KiB
JavaScript
Raw Normal View History

2018-06-17 23:47:28 +03:00
"use strict";
2017-02-24 22:57:46 +03:00
/**
* Conversion Utilities
*
*/
2018-06-17 23:47:28 +03:00
Object.defineProperty(exports, "__esModule", { value: true });
var errors = require("./errors");
2018-07-12 09:42:46 +03:00
exports.AddressZero = '0x0000000000000000000000000000000000000000';
exports.HashZero = '0x0000000000000000000000000000000000000000000000000000000000000000';
2018-06-17 23:47:28 +03:00
function isBigNumber(value) {
2018-06-13 22:39:39 +03:00
return !!value._bn;
}
2018-06-17 23:47:28 +03:00
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));
2018-06-17 23:47:28 +03:00
};
return array;
}
2018-06-17 23:47:28 +03:00
function isArrayish(value) {
if (!value || parseInt(String(value.length)) != value.length || typeof (value) === 'string') {
2017-02-24 22:57:46 +03:00
return false;
}
for (var i = 0; i < value.length; i++) {
var v = value[i];
if (v < 0 || v >= 256 || parseInt(String(v)) != v) {
2017-02-24 22:57:46 +03:00
return false;
}
}
return true;
}
2018-06-17 23:47:28 +03:00
exports.isArrayish = isArrayish;
function arrayify(value) {
if (value == null) {
errors.throwError('cannot convert null value to array', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
2018-06-13 22:39:39 +03:00
if (isBigNumber(value)) {
2017-02-24 22:57:46 +03:00
value = value.toHexString();
}
2018-06-17 23:47:28 +03:00
if (typeof (value) === 'string') {
var match = value.match(/^(0x)?[0-9a-fA-F]*$/);
2018-06-13 22:39:39 +03:00
if (!match) {
errors.throwError('invalid hexidecimal string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
if (match[1] !== '0x') {
2018-06-17 23:47:28 +03:00
errors.throwError('hex string must have 0x prefix', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
2018-06-13 22:39:39 +03:00
}
2017-02-24 22:57:46 +03:00
value = value.substring(2);
2018-06-17 23:47:28 +03:00
if (value.length % 2) {
value = '0' + value;
}
2017-02-24 22:57:46 +03:00
var result = [];
for (var i = 0; i < value.length; i += 2) {
result.push(parseInt(value.substr(i, 2), 16));
}
return addSlice(new Uint8Array(result));
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
else if (typeof (value) === 'string') {
}
2017-02-24 22:57:46 +03:00
if (isArrayish(value)) {
return addSlice(new Uint8Array(value));
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
errors.throwError('invalid arrayify value', null, { arg: 'value', value: value, type: typeof (value) });
2018-06-13 22:39:39 +03:00
return null;
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
exports.arrayify = arrayify;
function concat(objects) {
2017-02-24 22:57:46 +03:00
var arrays = [];
var length = 0;
for (var i = 0; i < objects.length; i++) {
2018-06-17 23:47:28 +03:00
var object = arrayify(objects[i]);
2017-02-24 22:57:46 +03:00
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);
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
exports.concat = concat;
function stripZeros(value) {
var result = arrayify(value);
if (result.length === 0) {
return result;
}
2017-02-24 22:57:46 +03:00
// Find the first non-zero entry
var start = 0;
2018-06-17 23:47:28 +03:00
while (result[start] === 0) {
start++;
}
2017-02-24 22:57:46 +03:00
// If we started with zeros, strip them
if (start) {
2018-06-13 22:39:39 +03:00
result = result.slice(start);
2017-02-24 22:57:46 +03:00
}
2018-06-13 22:39:39 +03:00
return result;
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
exports.stripZeros = stripZeros;
function padZeros(value, length) {
value = arrayify(value);
2018-06-17 23:47:28 +03:00
if (length < value.length) {
throw new Error('cannot pad');
}
2017-02-24 22:57:46 +03:00
var result = new Uint8Array(length);
result.set(value, length - value.length);
return addSlice(result);
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
exports.padZeros = padZeros;
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;
2017-02-24 22:57:46 +03:00
}
return true;
}
2018-06-17 23:47:28 +03:00
exports.isHexString = isHexString;
var HexCharacters = '0123456789abcdef';
function hexlify(value) {
2018-06-13 22:39:39 +03:00
if (isBigNumber(value)) {
2017-02-24 22:57:46 +03:00
return value.toHexString();
}
2018-06-17 23:47:28 +03:00
if (typeof (value) === 'number') {
2017-02-24 22:57:46 +03:00
if (value < 0) {
2018-06-13 22:39:39 +03:00
errors.throwError('cannot hexlify negative value', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
2017-02-24 22:57:46 +03:00
}
var hex = '';
while (value) {
hex = HexCharacters[value & 0x0f] + hex;
value = Math.floor(value / 16);
2017-02-24 22:57:46 +03:00
}
if (hex.length) {
2018-06-17 23:47:28 +03:00
if (hex.length % 2) {
hex = '0' + hex;
}
2017-02-24 22:57:46 +03:00
return '0x' + hex;
}
return '0x00';
}
2018-06-17 23:47:28 +03:00
if (typeof (value) === 'string') {
var match = value.match(/^(0x)?[0-9a-fA-F]*$/);
2018-06-13 22:39:39 +03:00
if (!match) {
errors.throwError('invalid hexidecimal string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
if (match[1] !== '0x') {
2018-06-17 23:47:28 +03:00
errors.throwError('hex string must have 0x prefix', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
2018-06-13 22:39:39 +03:00
}
2017-02-24 22:57:46 +03:00
if (value.length % 2) {
value = '0x0' + value.substring(2);
}
return value;
}
if (isArrayish(value)) {
var result = [];
for (var i = 0; i < value.length; i++) {
2018-06-17 23:47:28 +03:00
var v = value[i];
result.push(HexCharacters[(v & 0xf0) >> 4] + HexCharacters[v & 0x0f]);
2017-02-24 22:57:46 +03:00
}
return '0x' + result.join('');
}
2018-06-13 22:39:39 +03:00
errors.throwError('invalid hexlify value', null, { arg: 'value', value: value });
return 'never';
2017-02-24 22:57:46 +03:00
}
2018-06-17 23:47:28 +03:00
exports.hexlify = hexlify;
function hexDataLength(data) {
if (!isHexString(data) || (data.length % 2) !== 0) {
return null;
}
return (data.length - 2) / 2;
}
2018-06-17 23:47:28 +03:00
exports.hexDataLength = hexDataLength;
function hexDataSlice(data, offset, length) {
if (!isHexString(data)) {
errors.throwError('invalid hex data', errors.INVALID_ARGUMENT, { arg: 'value', value: data });
}
if ((data.length % 2) !== 0) {
errors.throwError('hex data length must be even', errors.INVALID_ARGUMENT, { arg: 'value', value: data });
}
offset = 2 + 2 * offset;
if (length != null) {
return '0x' + data.substring(offset, offset + 2 * length);
}
return '0x' + data.substring(offset);
}
2018-06-17 23:47:28 +03:00
exports.hexDataSlice = hexDataSlice;
function hexStripZeros(value) {
2018-06-13 22:39:39 +03:00
if (!isHexString(value)) {
errors.throwError('invalid hex string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
while (value.length > 3 && value.substring(0, 3) === '0x0') {
value = '0x' + value.substring(3);
}
return value;
}
2018-06-17 23:47:28 +03:00
exports.hexStripZeros = hexStripZeros;
function hexZeroPad(value, length) {
2018-06-13 22:39:39 +03:00
if (!isHexString(value)) {
errors.throwError('invalid hex string', errors.INVALID_ARGUMENT, { arg: 'value', value: value });
}
while (value.length < 2 * length + 2) {
value = '0x0' + value.substring(2);
}
return value;
}
2018-06-17 23:47:28 +03:00
exports.hexZeroPad = hexZeroPad;
2018-07-12 09:42:46 +03:00
function isSignature(value) {
return (value && value.r != null && value.s != null);
}
2018-06-17 23:47:28 +03:00
function splitSignature(signature) {
2018-07-12 09:42:46 +03:00
var v = 0;
var r = '0x', s = '0x';
if (isSignature(signature)) {
r = hexZeroPad(signature.r, 32);
s = hexZeroPad(signature.s, 32);
var recoveryParam = signature.recoveryParam;
if (recoveryParam == null && signature.v != null) {
recoveryParam = 1 - (signature.v % 2);
}
v = 27 + recoveryParam;
}
2018-07-12 09:42:46 +03:00
else {
var bytes = arrayify(signature);
if (bytes.length !== 65) {
throw new Error('invalid signature');
}
r = hexlify(bytes.slice(0, 32));
s = hexlify(bytes.slice(32, 64));
v = bytes[64];
if (v !== 27 && v !== 28) {
v = 27 + (v % 2);
}
}
return {
2018-07-12 09:42:46 +03:00
r: r,
s: s,
recoveryParam: (v - 27),
v: v
2018-06-17 23:47:28 +03:00
};
}
2018-06-17 23:47:28 +03:00
exports.splitSignature = splitSignature;
2018-06-18 12:42:41 +03:00
function joinSignature(signature) {
2018-07-12 09:42:46 +03:00
signature = splitSignature(signature);
2018-06-18 12:42:41 +03:00
return hexlify(concat([
2018-07-12 09:42:46 +03:00
signature.r,
signature.s,
2018-06-18 12:42:41 +03:00
(signature.recoveryParam ? '0x1c' : '0x1b')
]));
}
exports.joinSignature = joinSignature;