@colony/purser-core
Version:
A collection of helpers, utils, validators and normalizers to assist the individual purser modules
369 lines (320 loc) • 12.3 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _utils = require("ethers/utils");
var _hdkey = _interopRequireDefault(require("hdkey"));
var _validators = require("./validators");
var _normalizers = require("./normalizers");
var _messages = require("./messages");
var _defaults = require("./defaults");
var _types = require("./types");
var GETTERS = _defaults.DESCRIPTORS.GETTERS,
SETTERS = _defaults.DESCRIPTORS.SETTERS,
WALLET_PROPS = _defaults.DESCRIPTORS.WALLET_PROPS,
GENERIC_PROPS = _defaults.DESCRIPTORS.GENERIC_PROPS;
/*
* "Private" (internal) variable(s).
*
* These are used as return values from getters which don't have an accompanying setter,
* but we still want to set them internally.
*/
var internalPublicKey;
var internalDerivationPath;
/*
* @TODO Support extra props
*
* Support the extra props required for the software wallet (privateKey, mnemonic, etc...)
* Also, we need to find a way to extend both this and the `ethers` wallet class
*/
var GenericWallet =
/*#__PURE__*/
function () {
/*
* Both `publicKey` and `derivationPath` are getters.
*/
/*
* @TODO Add specific Flow types
*
* For the three main wallet methods
*/
function GenericWallet(_ref) {
var _this = this;
var publicKey = _ref.publicKey,
chainCode = _ref.chainCode,
rootDerivationPath = _ref.rootDerivationPath,
_ref$addressCount = _ref.addressCount,
addressCount = _ref$addressCount === void 0 ? 10 : _ref$addressCount,
_ref$chainId = _ref.chainId,
chainId = _ref$chainId === void 0 ? _defaults.CHAIN_IDS.HOMESTEAD : _ref$chainId;
(0, _classCallCheck2.default)(this, GenericWallet);
/*
* Validate address count (this comes from the end user)
*/
(0, _validators.safeIntegerValidator)(addressCount);
/*
* Validate the `publicKey` and `chainCode` hex sequences. These come from
* various external services, and we shouldn't trust them.
*/
(0, _validators.hexSequenceValidator)(publicKey);
(0, _validators.hexSequenceValidator)(chainCode);
/*
* Derive the public key with the address index, so we can get the address
*/
var hdKey = new _hdkey.default();
/*
* Sadly Flow doesn't have the correct types for node's Buffer Object
*/
/* $FlowFixMe */
hdKey.publicKey = Buffer.from(publicKey, _defaults.HEX_HASH_TYPE);
/*
* Sadly Flow doesn't have the correct types for node's Buffer Object
*/
/* $FlowFixMe */
hdKey.chainCode = Buffer.from(chainCode, _defaults.HEX_HASH_TYPE);
var otherAddresses = Array.from(
/*
* We default to `1`, but this time, to prevent the case where the
* user passes in the value `0` manually (which will break the array map)
*/
new Array(addressCount || 1), function (value, index) {
var addressObject = {};
var derivationKey = hdKey.deriveChild(index);
/*
* Set this individual address's derivation path
*/
addressObject.derivationPath = rootDerivationPath.substr(-1) === _defaults.SPLITTER ? "".concat(rootDerivationPath).concat(index) : "".concat(rootDerivationPath).concat(_defaults.SPLITTER).concat(index);
/*
* This is the derrived public key, not the one originally fetched one
*/
var derivedPublicKey = derivationKey.publicKey.toString(_defaults.HEX_HASH_TYPE);
addressObject.publicKey = (0, _normalizers.hexSequenceNormalizer)(derivedPublicKey);
/*
* Generate the address from the derived public key
*/
var addressFromPublicKey = (0, _utils.computeAddress)(
/*
* Sadly Flow doesn't have the correct types for node's Buffer Object
*/
/* $FlowFixMe */
derivationKey.publicKey);
/*
* Also validate the address that comes from the `HDKey` library.
*/
(0, _validators.addressValidator)(addressFromPublicKey);
addressObject.address = (0, _normalizers.addressNormalizer)(addressFromPublicKey);
return addressObject;
});
/*
* Set the "private" (internal) variables values
*/
internalPublicKey = otherAddresses[0].publicKey;
internalDerivationPath = otherAddresses[0].derivationPath;
/*
* Set the Wallet Object's values
*
* We're using `defineProperties` instead of strait up assignment, so that
* we can customize the prop's descriptors
*
* @TODO Reduce code repetition when setting Class props
*
* We do this here and in the software wallet, so it might make sense to
* write a helper method for this.
*/
Object.defineProperties(this, {
address: Object.assign({}, {
value: otherAddresses[0].address
}, SETTERS),
chainId: Object.assign({}, {
value: chainId
}, WALLET_PROPS),
type: Object.assign({}, {
value: _types.TYPE_GENERIC
}, GENERIC_PROPS),
subtype: Object.assign({}, {
value: _types.SUBTYPE_GENERIC
}, GENERIC_PROPS),
/**
* Set the default address/public key/path one of the (other) addresses from the array.
* This is usefull since most methods (sign, signMessage) use this props as defaults.
*
* There's an argument to be made here that we can derive new addresses only when this
* method gets called.
*
* This would be helpful to offload the initial cost of deriving a number
* of `addressCount` addresses.
*
* On the other hand, if we do this, we won't be able to show the user what
* addresses are available up front.
*
* @method setDefaultAddress
*
* @param {number} addressIndex The address index from the array
*
* @return {Promise<boolean>} True if it was able to set it, false otherwise
*/
setDefaultAddress: Object.assign({}, {
/*
* @TODO Accept both number and object as argument
* To make the arguments consistent across the wallet instance methods
*/
value: function () {
var _value = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee() {
var addressIndex,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
addressIndex = _args.length > 0 && _args[0] !== undefined ? _args[0] : 0;
(0, _validators.safeIntegerValidator)(addressIndex);
if (!(addressIndex >= 0 && addressIndex < otherAddresses.length)) {
_context.next = 7;
break;
}
/*
* Address count will always be at least `1` (the first derived address).
*
* This method is useful (can be used) only when the user generated more than
* one address when instantiating the Wallet.
*/
_this.address = otherAddresses[addressIndex].address;
internalPublicKey = otherAddresses[addressIndex].publicKey;
internalDerivationPath = otherAddresses[addressIndex].derivationPath;
return _context.abrupt("return", true);
case 7:
throw new Error("".concat(_messages.genericClass.addressIndexOutsideRange, ": index (").concat(addressIndex, ") count (").concat(addressCount, ")"));
case 8:
case "end":
return _context.stop();
}
}
}, _callee, this);
}));
return function value() {
return _value.apply(this, arguments);
};
}()
}, WALLET_PROPS),
/*
* These are just a placeholder static methods. They should be replaced (or deleted at least)
* with methods that actually has some functionality.
*/
sign: Object.assign({}, {
value: function () {
var _value2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2() {
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
case "end":
return _context2.stop();
}
}
}, _callee2, this);
}));
return function value() {
return _value2.apply(this, arguments);
};
}()
}, GENERIC_PROPS),
signMessage: Object.assign({}, {
value: function () {
var _value3 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee3() {
return _regenerator.default.wrap(function _callee3$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
case "end":
return _context3.stop();
}
}
}, _callee3, this);
}));
return function value() {
return _value3.apply(this, arguments);
};
}()
}, GENERIC_PROPS),
verifyMessage: Object.assign({}, {
value: function () {
var _value4 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee4() {
return _regenerator.default.wrap(function _callee4$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
case "end":
return _context4.stop();
}
}
}, _callee4, this);
}));
return function value() {
return _value4.apply(this, arguments);
};
}()
}, GENERIC_PROPS)
});
/*
* The `otherAddresses` prop is only available if we have more than one.
*
* Otherwise it's pointless since it just repeats information (first index
* is also the default one).
*/
if (addressCount > 1) {
Object.defineProperty(this, 'otherAddresses', Object.assign({}, {
/*
* Map out the publicKey and derivation path from the `otherAddresses`
* array that gets assigned to the Wallet instance.
*
* The user should only have access to `the publicKey` and `derivationPath` from the
* default account (set via `setDefaultAddress()`)
*/
value: otherAddresses.map(function (_ref2) {
var address = _ref2.address;
return address;
})
}, WALLET_PROPS));
}
}
/*
* Public Key Getter
*/
/* eslint-disable-next-line class-methods-use-this */
(0, _createClass2.default)(GenericWallet, [{
key: "publicKey",
get: function get() {
return Promise.resolve(internalPublicKey);
}
/* eslint-disable-next-line class-methods-use-this */
}, {
key: "derivationPath",
get: function get() {
return Promise.resolve(internalDerivationPath);
}
}]);
return GenericWallet;
}();
/*
* We need to use `defineProperties` to make props enumerable.
* When adding them via a `Class` getter/setter it will prevent that by default
*/
exports.default = GenericWallet;
Object.defineProperties(GenericWallet.prototype, {
publicKey: GETTERS,
derivationPath: GETTERS
});