Added splitSignature and beginning of better error messages.
This commit is contained in:
parent
fdb7114511
commit
efb7dce524
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ethers",
|
||||
"version": "3.0.9",
|
||||
"version": "3.0.10",
|
||||
"description": "Ethereum wallet library.",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
|
@ -183,3 +183,31 @@ describe('Test Hash Functions', function() {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test Solidity splitSignature', function() {
|
||||
var convert = require('../utils/convert');
|
||||
|
||||
it('splits a canonical signature', function() {
|
||||
var r = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef';
|
||||
var s = '0xcafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7e';
|
||||
for (var v = 27; v <= 28; v++) {
|
||||
var signature = convert.concat([ r, s, [ v ] ]);
|
||||
var sig = convert.splitSignature(signature);
|
||||
assert.equal(sig.r, r, 'split r correctly');
|
||||
assert.equal(sig.s, s, 'split s correctly');
|
||||
assert.equal(sig.v, v, 'split v correctly');
|
||||
}
|
||||
});
|
||||
|
||||
it('splits a legacy signature', function() {
|
||||
var r = '0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef';
|
||||
var s = '0xcafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7ecafe1a7e';
|
||||
for (var v = 27; v <= 28; v++) {
|
||||
var signature = convert.concat([ r, s, [ v - 27 ] ]);
|
||||
var sig = convert.splitSignature(signature);
|
||||
assert.equal(sig.r, r, 'split r correctly');
|
||||
assert.equal(sig.s, s, 'split s correctly');
|
||||
assert.equal(sig.v, v, 'split v correctly');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -4,7 +4,8 @@
|
||||
*/
|
||||
|
||||
var defineProperty = require('./properties.js').defineProperty;
|
||||
var throwError = require('./throw-error');
|
||||
|
||||
var errors = require('./errors');
|
||||
|
||||
function addSlice(array) {
|
||||
if (array.slice) { return array; }
|
||||
@ -32,7 +33,10 @@ function isArrayish(value) {
|
||||
return true;
|
||||
}
|
||||
|
||||
function arrayify(value, name) {
|
||||
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();
|
||||
@ -48,13 +52,19 @@ function arrayify(value, name) {
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
throwError('invalid arrayify value', { name: name, input: value });
|
||||
errors.throwError('invalid arrayify value', { arg: 'value', value: value, type: typeof(value) });
|
||||
}
|
||||
|
||||
function concat(objects) {
|
||||
@ -113,7 +123,7 @@ function isHexString(value, length) {
|
||||
|
||||
var HexCharacters = '0123456789abcdef';
|
||||
|
||||
function hexlify(value, name) {
|
||||
function hexlify(value) {
|
||||
|
||||
if (value && value.toHexString) {
|
||||
return value.toHexString();
|
||||
@ -121,7 +131,7 @@ function hexlify(value, name) {
|
||||
|
||||
if (typeof(value) === 'number') {
|
||||
if (value < 0) {
|
||||
throwError('cannot hexlify negative value', { name: name, input: value });
|
||||
errors.throwError('cannot hexlify negative value', errors.INVALID_ARG, { arg: 'value', value: value });
|
||||
}
|
||||
|
||||
var hex = '';
|
||||
@ -154,7 +164,7 @@ function hexlify(value, name) {
|
||||
return '0x' + result.join('');
|
||||
}
|
||||
|
||||
throwError('invalid hexlify value', { name: name, input: value });
|
||||
errors.throwError('invalid hexlify value', { arg: 'value', value: value });
|
||||
}
|
||||
|
||||
function hexStripZeros(value) {
|
||||
@ -171,6 +181,31 @@ function hexZeroPad(value, length) {
|
||||
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,
|
||||
@ -180,6 +215,8 @@ module.exports = {
|
||||
padZeros: padZeros,
|
||||
stripZeros: stripZeros,
|
||||
|
||||
splitSignature: splitSignature,
|
||||
|
||||
hexlify: hexlify,
|
||||
isHexString: isHexString,
|
||||
hexStripZeros: hexStripZeros,
|
||||
|
54
utils/errors.js
Normal file
54
utils/errors.js
Normal file
@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
var defineProperty = require('./properties').defineProperty;
|
||||
|
||||
var codes = { };
|
||||
|
||||
[
|
||||
// Unknown Error
|
||||
'UNKNOWN_ERROR',
|
||||
|
||||
// Missing new operator to an object
|
||||
// - name: The name of the class
|
||||
'MISSING_NEW',
|
||||
|
||||
// Invalid argument to a function:
|
||||
// - arg: The argument name that was invalid
|
||||
'INVALID_ARGUMENT'
|
||||
|
||||
].forEach(function(code) {
|
||||
defineProperty(codes, code, code);
|
||||
});
|
||||
|
||||
|
||||
defineProperty(codes, 'throwError', function(message, code, params) {
|
||||
if (!code) { code = codes.UNKNOWN_ERROR; }
|
||||
if (!params) { params = {}; }
|
||||
|
||||
var messageDetails = [];
|
||||
Object.keys(params).forEach(function(key) {
|
||||
messageDetails.push(key + '=' + JSON.stringify(params[key]));
|
||||
});
|
||||
var reason = message;
|
||||
if (messageDetails.length) {
|
||||
message += ' (' + messageDetails.join(', ') + ')';
|
||||
}
|
||||
|
||||
var error = new Error(message);
|
||||
error.reason = reason;
|
||||
error.code = code
|
||||
|
||||
Object.keys(params).forEach(function(key) {
|
||||
error[key] = params[key];
|
||||
});
|
||||
|
||||
throw error;
|
||||
});
|
||||
|
||||
defineProperty(codes, 'checkNew', function(self, kind) {
|
||||
if (!(self instanceof kind)) {
|
||||
codes.throwError('missing new', codes.MISSING_NEW, { name: kind.name });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = codes;
|
@ -67,4 +67,6 @@ module.exports = {
|
||||
solidityPack: solidity.pack,
|
||||
solidityKeccak256: solidity.keccak256,
|
||||
soliditySha256: solidity.sha256,
|
||||
|
||||
splitSignature: convert.splitSignature,
|
||||
}
|
||||
|
@ -21,15 +21,28 @@ var utils = (function() {
|
||||
};
|
||||
})();
|
||||
|
||||
var errors = require('../utils/errors');
|
||||
|
||||
|
||||
function SigningKey(privateKey) {
|
||||
if (!(this instanceof SigningKey)) { throw new Error('missing new'); }
|
||||
errors.checkNew(this, SigningKey);
|
||||
|
||||
try {
|
||||
privateKey = utils.arrayify(privateKey);
|
||||
if (privateKey.length !== 32) {
|
||||
throw new Error('invalid private key');
|
||||
errors.throwError('exactly 32 bytes required', errors.INVALID_ARGUMENT, { value: privateKey });
|
||||
}
|
||||
} catch(error) {
|
||||
var params = { reason: error.reason, value: '[REDACTED]' }
|
||||
if (error.value) {
|
||||
if(typeof(error.value.length) === 'number') {
|
||||
params.length = error.value.length;
|
||||
}
|
||||
params.type = typeof(error.value);
|
||||
}
|
||||
errors.throwError('invalid private key', error.code, params);
|
||||
}
|
||||
|
||||
utils.defineProperty(this, 'privateKey', utils.hexlify(privateKey))
|
||||
|
||||
var keyPair = secp256k1.keyFromPrivate(privateKey);
|
||||
|
@ -28,6 +28,8 @@ var utils = (function() {
|
||||
};
|
||||
})();
|
||||
|
||||
var errors = require('../utils/errors');
|
||||
|
||||
var HDNode = require('./hdnode');
|
||||
|
||||
var secretStorage = require('./secret-storage');
|
||||
@ -49,7 +51,7 @@ var transactionFields = [
|
||||
];
|
||||
|
||||
function Wallet(privateKey, provider) {
|
||||
if (!(this instanceof Wallet)) { throw new Error('missing new'); }
|
||||
errors.checkNew(this, Wallet);
|
||||
|
||||
// Make sure we have a valid signing key
|
||||
var signingKey = privateKey;
|
||||
|
Loading…
Reference in New Issue
Block a user