@colony/purser-software
Version:
A javascript library to interact with a software Ethereum wallet, based on the ethers.js library
297 lines (255 loc) • 10.4 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.create = exports.open = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _wallet = require("ethers/wallet");
var _hdnode = require("ethers/utils/hdnode");
var _jsonWallet = require("ethers/utils/json-wallet");
var _helpers = require("@colony/purser-core/helpers");
var _utils = require("@colony/purser-core/utils");
var _defaults = require("@colony/purser-core/defaults");
var _class = _interopRequireDefault(require("./class"));
var _defaults2 = require("./defaults");
var _messages = require("./messages");
/**
* Open an existing wallet
* Using either `mnemonic`, `private key` or `encrypted keystore`
*
* This will try to extract the private key from a mnemonic (if available),
* and create a new SoftwareWallet instance using whichever key is available.
* (the on passed in or the one extracted from the mnemonic).
*
* @TODO Reduce code repetition
*
* With some clever refactoring we might be able to only call the SoftwareWallet
* constructor a single time for all three methods of opening the wallet
*
* @method open
*
* @param {string} password Optional password used to generate an encrypted keystore
* @param {string} privateKey Private key to open the wallet with
* @param {string} mnemonic Mnemonic string to open the wallet with
* @param {string} keystore JSON formatted keystore string to open the wallet with.
* Only works if you also send in a password
* @param {number} chainId The id of the network to use, defaults to mainnet (1)
*
* All the above params are sent in as props of an {WalletArgumentsType} object.
*
* @return {WalletType} A new wallet object (or undefined) if somehwere along
* the line an error is thrown.
*/
var open =
/*#__PURE__*/
function () {
var _ref = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee() {
var argumentObject,
password,
privateKey,
mnemonic,
keystore,
_argumentObject$chain,
chainId,
extractedPrivateKey,
derivationPath,
keystoreWallet,
mnemonicWallet,
privateKeyWallet,
_args = arguments;
return _regenerator.default.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
argumentObject = _args.length > 0 && _args[0] !== undefined ? _args[0] : {};
/*
* Validate the trasaction's object input
*/
(0, _helpers.userInputValidator)({
firstArgument: argumentObject,
requiredEither: _defaults2.REQUIRED_PROPS.OPEN_WALLET
});
password = argumentObject.password, privateKey = argumentObject.privateKey, mnemonic = argumentObject.mnemonic, keystore = argumentObject.keystore, _argumentObject$chain = argumentObject.chainId, chainId = _argumentObject$chain === void 0 ? _defaults.CHAIN_IDS.HOMESTEAD : _argumentObject$chain;
/*
* @TODO Re-add use ability to control derivation path
* When opening the wallet. But only if this proves to be a needed feature.
*/
derivationPath = (0, _helpers.derivationPathSerializer)({
change: _defaults.PATH.CHANGE,
addressIndex: _defaults.PATH.INDEX
});
_context.prev = 4;
if (!(keystore && (0, _jsonWallet.isSecretStorageWallet)(keystore) && password)) {
_context.next = 13;
break;
}
_context.next = 8;
return _wallet.Wallet.fromEncryptedJson(keystore, password);
case 8:
keystoreWallet = _context.sent;
/*
* Set the keystore and password props on the instance object.
*
* So that we can make use of them inside the SoftwareWallet
* constructor, as the Ethers Wallet instance object will
* be passed down.
*
* @TODO Better passing of values
*
* This needs to be refactored to pass values to the SoftwareWallet
* class in a less repetitious way
*/
keystoreWallet.keystore = keystore;
keystoreWallet.password = password;
keystoreWallet.chainId = chainId;
return _context.abrupt("return", new _class.default(keystoreWallet));
case 13:
/*
* @TODO Detect if existing but not valid mnemonic, and warn the user
*/
if (mnemonic && (0, _hdnode.isValidMnemonic)(mnemonic)) {
mnemonicWallet = (0, _hdnode.fromMnemonic)(mnemonic).derivePath(derivationPath);
extractedPrivateKey = mnemonicWallet.privateKey;
}
/*
* @TODO Detect if existing but not valid private key, and warn the user
*/
privateKeyWallet = new _wallet.Wallet(privateKey || extractedPrivateKey);
/*
* Set the mnemonic and password props on the instance object.
*
* So that we can make use of them inside the SoftwareWallet
* constructor, as the Ethers Wallet instance object will
* be passed down.
*
* @TODO Better passing of values
*
* This needs to be refactored to pass values to the SoftwareWallet
* class in a less repetitious way
*/
privateKeyWallet.password = password;
privateKeyWallet.chainId = chainId;
/*
* @NOTE mnemonic prop was renamed due to naming conflict with getter-only
* ethers prop
*/
privateKeyWallet.originalMnemonic = mnemonic;
return _context.abrupt("return", new _class.default(privateKeyWallet));
case 21:
_context.prev = 21;
_context.t0 = _context["catch"](4);
throw new Error("".concat(_messages.staticMethods.open, " ").concat((0, _utils.objectToErrorString)({
password: password,
privateKey: privateKey,
mnemonic: mnemonic,
keystore: keystore
}), " Error: ").concat(_context.t0.message));
case 24:
case "end":
return _context.stop();
}
}
}, _callee, this, [[4, 21]]);
}));
return function open() {
return _ref.apply(this, arguments);
};
}();
/**
* Create a new wallet.
*
* This will use EtherWallet's `createRandom()` (with defaults and entropy)
* and use the resulting private key to instantiate a new SoftwareWallet.
*
* @method create
*
* @param {Uint8Array} entropy An unsigned 8bit integer Array to provide extra randomness
* @param {string} password Optional password used to generate an encrypted keystore
* @param {number} chainId The id of the network to use, defaults to mainnet (1)
*
* All the above params are sent in as props of an {WalletArgumentsType} object.
*
* @return {WalletType} A new wallet object
*/
exports.open = open;
var create =
/*#__PURE__*/
function () {
var _ref2 = (0, _asyncToGenerator2.default)(
/*#__PURE__*/
_regenerator.default.mark(function _callee2() {
var argumentObject,
password,
_argumentObject$entro,
entropy,
_argumentObject$chain2,
chainId,
basicWallet,
_args2 = arguments;
return _regenerator.default.wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
argumentObject = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : {};
/*
* Validate the trasaction's object input
*/
(0, _helpers.userInputValidator)({
firstArgument: argumentObject
});
password = argumentObject.password, _argumentObject$entro = argumentObject.entropy, entropy = _argumentObject$entro === void 0 ? (0, _utils.getRandomValues)(new Uint8Array(65536)) : _argumentObject$entro, _argumentObject$chain2 = argumentObject.chainId, chainId = _argumentObject$chain2 === void 0 ? _defaults.CHAIN_IDS.HOMESTEAD : _argumentObject$chain2;
_context2.prev = 3;
if (!entropy || entropy && !(entropy instanceof Uint8Array)) {
(0, _utils.warning)(_messages.staticMethods.noEntrophy);
basicWallet = _wallet.Wallet.createRandom();
} else {
basicWallet = _wallet.Wallet.createRandom({
extraEntropy: entropy
});
}
/*
* Set the password prop on the instance object.
*
* So that we can make use of them inside the SoftwareWallet
* constructor, as the Ethers Wallet instance object will
* be passed down.
*
* @TODO Better passing of values
*
* This needs to be refactored to pass values to the SoftwareWallet
* class in a less repetitious way
*/
basicWallet.password = password;
basicWallet.chainId = chainId;
/*
* @NOTE mnemonic prop was renamed due to naming conflict with getter-only
* ethers prop
*/
basicWallet.originalMnemonic = basicWallet.mnemonic;
return _context2.abrupt("return", new _class.default(basicWallet));
case 11:
_context2.prev = 11;
_context2.t0 = _context2["catch"](3);
throw new Error("".concat(_messages.staticMethods.create, " Error: ").concat(_context2.t0.message));
case 14:
case "end":
return _context2.stop();
}
}
}, _callee2, this, [[3, 11]]);
}));
return function create() {
return _ref2.apply(this, arguments);
};
}();
exports.create = create;
var softwareWallet = {
open: open,
create: create
};
var _default = softwareWallet;
exports.default = _default;