bitcore-wallet-service
Version:
A service for Mutisig HD Bitcoin Wallets
193 lines • 8.1 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Wallet = void 0;
const lodash_1 = __importDefault(require("lodash"));
const config_1 = __importDefault(require("../../config"));
const index_1 = require("../chain/index");
const common_1 = require("../common");
const logger_1 = __importDefault(require("../logger"));
const address_1 = require("./address");
const addressmanager_1 = require("./addressmanager");
const copayer_1 = require("./copayer");
const $ = require('preconditions').singleton();
const Uuid = require('uuid');
const Constants = common_1.Common.Constants, Defaults = common_1.Common.Defaults, Utils = common_1.Common.Utils;
const Bitcore = {
btc: require('bitcore-lib'),
bch: require('bitcore-lib-cash'),
eth: require('bitcore-lib'),
matic: require('bitcore-lib'),
arb: require('bitcore-lib'),
base: require('bitcore-lib'),
op: require('bitcore-lib'),
xrp: require('bitcore-lib'),
doge: require('bitcore-lib-doge'),
ltc: require('bitcore-lib-ltc'),
sol: require('bitcore-lib'),
};
class Wallet {
static create(opts) {
opts = opts || {};
const chain = opts.chain || opts.coin;
let x = new Wallet();
$.shouldBeNumber(opts.m);
$.shouldBeNumber(opts.n);
$.checkArgument(Utils.checkValueInCollection(chain, Constants.CHAINS));
$.checkArgument(Utils.checkValueInCollection(opts.network, Constants.NETWORKS[chain]));
x.version = '1.0.0';
x.createdOn = Math.floor(Date.now() / 1000);
x.id = opts.id || Uuid.v4();
x.name = opts.name;
x.m = opts.m;
x.n = opts.n;
x.singleAddress = !!opts.singleAddress;
x.status = 'pending';
x.publicKeyRing = [];
x.addressIndex = 0;
x.copayers = [];
x.pubKey = opts.pubKey;
x.coin = opts.coin;
x.chain = opts.chain || index_1.ChainService.getChain(x.coin);
x.network = opts.network;
x.derivationStrategy = opts.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45;
x.addressType = opts.addressType || Constants.SCRIPT_TYPES.P2SH;
x.addressManager = addressmanager_1.AddressManager.create({
derivationStrategy: x.derivationStrategy
});
x.usePurpose48 = opts.usePurpose48;
x.scanStatus = null;
x.beRegistered = false;
x.beAuthPrivateKey2 = null;
x.beAuthPublicKey2 = null;
x.nativeCashAddr = lodash_1.default.isUndefined(opts.nativeCashAddr) ? (x.chain == 'bch' ? true : null) : opts.nativeCashAddr;
x.hardwareSourcePublicKey = opts.hardwareSourcePublicKey;
x.clientDerivedPublicKey = opts.clientDerivedPublicKey;
return x;
}
static fromObj(obj) {
let x = new Wallet();
$.shouldBeNumber(obj.m);
$.shouldBeNumber(obj.n);
x.version = obj.version;
x.createdOn = obj.createdOn;
x.id = obj.id;
x.name = obj.name;
x.m = obj.m;
x.n = obj.n;
x.singleAddress = !!obj.singleAddress;
x.status = obj.status;
x.publicKeyRing = obj.publicKeyRing;
x.copayers = lodash_1.default.map(obj.copayers, copayer => {
return copayer_1.Copayer.fromObj(copayer);
});
x.pubKey = obj.pubKey;
x.coin = obj.coin || Defaults.COIN;
x.chain = obj.chain || index_1.ChainService.getChain(x.coin);
x.network = obj.network;
if (!x.network) {
x.network = obj.isTestnet ? Utils.getNetworkName(x.chain, 'testnet') : 'livenet';
}
x.derivationStrategy = obj.derivationStrategy || Constants.DERIVATION_STRATEGIES.BIP45;
x.addressType = obj.addressType || Constants.SCRIPT_TYPES.P2SH;
x.addressManager = addressmanager_1.AddressManager.fromObj(obj.addressManager);
x.scanStatus = obj.scanStatus;
x.beRegistered = obj.beRegistered;
x.beAuthPrivateKey2 = obj.beAuthPrivateKey2;
x.beAuthPublicKey2 = obj.beAuthPublicKey2;
x.nativeCashAddr = obj.nativeCashAddr;
x.usePurpose48 = obj.usePurpose48;
x.hardwareSourcePublicKey = obj.hardwareSourcePublicKey;
x.clientDerivedPublicKey = obj.clientDerivedPublicKey;
return x;
}
toObject() {
let x = lodash_1.default.cloneDeep(this);
x.isShared = this.isShared();
return x;
}
static getMaxRequiredCopayers(totalCopayers) {
return Wallet.COPAYER_PAIR_LIMITS[totalCopayers];
}
static verifyCopayerLimits(m, n) {
return n >= 1 && n <= 15 && m >= 1 && m <= n;
}
isShared() {
return this.n > 1;
}
isUTXOChain() {
return !!Constants.UTXO_CHAINS[this.chain.toUpperCase()];
}
updateBEKeys() {
$.checkState(this.isComplete(), 'Failed state: wallet incomplete at <updateBEKeys()>');
const chain = this.chain || index_1.ChainService.getChain(this.coin);
const bitcore = Bitcore[chain];
const salt = config_1.default.BE_KEY_SALT || Defaults.BE_KEY_SALT;
var seed = lodash_1.default.map(this.copayers, 'xPubKey')
.sort()
.join('') +
Utils.getGenericName(this.network) +
this.coin +
salt;
seed = bitcore.crypto.Hash.sha256(Buffer.from(seed));
const priv = bitcore.PrivateKey(seed, this.network);
this.beAuthPrivateKey2 = priv.toString();
this.beAuthPublicKey2 = priv.toPublicKey().toString();
}
_updatePublicKeyRing() {
this.publicKeyRing = lodash_1.default.map(this.copayers, copayer => {
return lodash_1.default.pick(copayer, ['xPubKey', 'requestPubKey']);
});
}
addCopayer(copayer) {
$.checkState(copayer.coin == this.coin, 'Failed state: copayer.coin not equal to this.coin at <addCopayer()>');
this.copayers.push(copayer);
if (this.copayers.length < this.n)
return;
this.status = 'complete';
this._updatePublicKeyRing();
}
addCopayerRequestKey(copayerId, requestPubKey, signature, restrictions, name) {
$.checkState(this.copayers.length == this.n, 'Failed state: this.copayers.length == this.n at addCopayerRequestKey()');
const c = this.getCopayer(copayerId);
c.requestPubKeys.unshift({
key: requestPubKey.toString(),
signature,
selfSigned: true,
restrictions: restrictions || {},
name: name || null
});
}
getCopayer(copayerId) {
return this.copayers.find(c => c.id == copayerId);
}
isComplete() {
return this.status == 'complete';
}
isScanning() {
return this.scanning;
}
isZceCompatible() {
return this.coin === 'bch' && this.addressType === 'P2PKH';
}
createAddress(isChange, step, escrowInputs) {
$.checkState(this.isComplete(), 'Failed state: this.isComplete() at <createAddress()>');
const path = this.addressManager.getNewAddressPath(isChange, step);
logger_1.default.debug('Deriving addr:' + path);
const scriptType = escrowInputs ? 'P2SH' : this.addressType;
return address_1.Address.derive(this.id, scriptType, this.publicKeyRing, path, this.m, this.coin, this.network, isChange, this.chain, !this.nativeCashAddr, escrowInputs, this.hardwareSourcePublicKey, this.clientDerivedPublicKey);
}
getSkippedAddress() {
$.checkState(this.isComplete(), 'Failed state: this.isComplete() at <getSkipeedAddress()>');
const next = this.addressManager.getNextSkippedPath();
if (!next)
return;
const address = address_1.Address.derive(this.id, this.addressType, this.publicKeyRing, next.path, this.m, this.coin, this.network, next.isChange, this.chain);
return address;
}
}
exports.Wallet = Wallet;
Wallet.COPAYER_PAIR_LIMITS = {};
//# sourceMappingURL=wallet.js.map