bip45 wallet
This commit is contained in:
parent
28a2cab787
commit
eacd1e2ece
@ -42,18 +42,6 @@ function Address(options) {
|
||||
compressed: options.compressed
|
||||
});
|
||||
|
||||
// Compatability
|
||||
if (options.multisig) {
|
||||
if (options.multisig.type)
|
||||
options.type = options.multisig.type;
|
||||
if (options.multisig.keys)
|
||||
options.keys = options.multisig.keys;
|
||||
if (options.multisig.m)
|
||||
options.m = options.multisig.m;
|
||||
if (options.multisig.n)
|
||||
options.n = options.multisig.n;
|
||||
}
|
||||
|
||||
this.type = options.type || 'pubkeyhash';
|
||||
this.subtype = options.subtype;
|
||||
this.keys = [];
|
||||
@ -141,8 +129,8 @@ Address.prototype.removeKey = function removeKey(key) {
|
||||
|
||||
key = utils.toBuffer(key);
|
||||
|
||||
var index = this.keys.map(function(key, i) {
|
||||
return utils.isEqual(key, pub) ? i : null;
|
||||
var index = this.keys.map(function(pub, i) {
|
||||
return utils.isEqual(pub, key) ? i : null;
|
||||
}).filter(function(i) {
|
||||
return i !== null;
|
||||
})[0];
|
||||
@ -226,9 +214,6 @@ Address.prototype.getScriptAddress = function getScriptAddress() {
|
||||
};
|
||||
|
||||
Address.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
if (!this.key.priv)
|
||||
return;
|
||||
|
||||
if (!enc) {
|
||||
if (this._pub)
|
||||
return this._pub;
|
||||
@ -241,6 +226,32 @@ Address.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
return this.key.getPublic(enc);
|
||||
};
|
||||
|
||||
Address.prototype.getHDPublicKey = function getPublicKey(enc) {
|
||||
if (!this.key.hd)
|
||||
return;
|
||||
|
||||
if (enc === 'base58')
|
||||
return this.key.hd.xpubkey;
|
||||
|
||||
if (this.key.hd.isPublic)
|
||||
return this.key.hd;
|
||||
|
||||
return this.key.hd.hdpub;
|
||||
};
|
||||
|
||||
Address.prototype.getHDPrivateKey = function getPublicKey(enc) {
|
||||
if (!this.key.hd)
|
||||
return;
|
||||
|
||||
if (!this.key.hd.isPrivate)
|
||||
return;
|
||||
|
||||
if (enc === 'base58')
|
||||
return this.key.hd.xprivkey;
|
||||
|
||||
return this.key.hd;
|
||||
};
|
||||
|
||||
Address.prototype.getKeyHash = function getKeyHash() {
|
||||
if (this._hash)
|
||||
return this._hash;
|
||||
@ -521,6 +532,20 @@ Address.prototype.__defineGetter__('address', function() {
|
||||
return this.getAddress();
|
||||
});
|
||||
|
||||
Address.prototype.__defineGetter__('realType', function() {
|
||||
if (this.type === 'scripthash')
|
||||
return this.subtype;
|
||||
return this.type;
|
||||
});
|
||||
|
||||
Address.prototype.__defineGetter__('hdPrivateKey', function() {
|
||||
return this.getHDPrivateKey();
|
||||
});
|
||||
|
||||
Address.prototype.__defineGetter__('hdPublicKey', function() {
|
||||
return this.getHDPublicKey();
|
||||
});
|
||||
|
||||
Address.prototype.toJSON = function toJSON(encrypt) {
|
||||
return {
|
||||
v: 1,
|
||||
|
||||
@ -252,12 +252,19 @@ HDPrivateKey.prototype.scan44 = function scan44(options, txByAddress, callback)
|
||||
})(0);
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.deriveRoot44 = function deriveRoot44(options) {
|
||||
var coinType = options.coinType;
|
||||
var accountIndex = options.accountIndex;
|
||||
HDPrivateKey.prototype.deriveAccount44 = function deriveAccount44(options) {
|
||||
var coinType, accountIndex, child;
|
||||
|
||||
if (this instanceof HDPublicKey)
|
||||
if (typeof options === 'number')
|
||||
options = { accountIndex: options };
|
||||
|
||||
coinType = options.coinType;
|
||||
accountIndex = options.accountIndex;
|
||||
|
||||
if (this instanceof HDPublicKey) {
|
||||
assert(this.isAccount44());
|
||||
return this;
|
||||
}
|
||||
|
||||
if (coinType == null)
|
||||
coinType = network.type === 'main' ? 0 : 1;
|
||||
@ -265,13 +272,17 @@ HDPrivateKey.prototype.deriveRoot44 = function deriveRoot44(options) {
|
||||
assert(utils.isFinite(coinType));
|
||||
assert(utils.isFinite(accountIndex));
|
||||
|
||||
return this
|
||||
child = this
|
||||
.derive(44, true)
|
||||
.derive(coinType, true)
|
||||
.derive(accountIndex, true);
|
||||
|
||||
assert(child.isAccount44());
|
||||
|
||||
return child;
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.deriveBIP44 = function deriveBIP44(options, isPublic) {
|
||||
HDPrivateKey.prototype.deriveBIP44 = function deriveBIP44(options) {
|
||||
var chain = options.chain;
|
||||
var addressIndex = options.addressIndex;
|
||||
|
||||
@ -282,7 +293,7 @@ HDPrivateKey.prototype.deriveBIP44 = function deriveBIP44(options, isPublic) {
|
||||
assert(utils.isFinite(addressIndex));
|
||||
|
||||
return this
|
||||
.deriveRoot44(options)
|
||||
.deriveAccount44(options)
|
||||
.derive(chain)
|
||||
.derive(addressIndex);
|
||||
};
|
||||
@ -317,7 +328,7 @@ HDPrivateKey.prototype.scan45 = function scan45(options, txByAddress, callback)
|
||||
var keys = [];
|
||||
var root;
|
||||
|
||||
root = this.deriveRoot45(options);
|
||||
root = this.derivePurpose45(options);
|
||||
|
||||
return (function chainCheck(chainConstant) {
|
||||
return (function scanner(cosignerIndex) {
|
||||
@ -372,10 +383,19 @@ HDPrivateKey.prototype.scan45 = function scan45(options, txByAddress, callback)
|
||||
})(0);
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.deriveRoot45 = function deriveRoot45(options) {
|
||||
if (this instanceof HDPublicKey)
|
||||
HDPrivateKey.prototype.derivePurpose45 = function derivePurpose45(options) {
|
||||
var child;
|
||||
|
||||
if (this instanceof HDPublicKey) {
|
||||
assert(this.isPurpose45());
|
||||
return this;
|
||||
return this.derive(45, true);
|
||||
}
|
||||
|
||||
child = this.derive(45, true);
|
||||
|
||||
assert(child.isPurpose45());
|
||||
|
||||
return child;
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.deriveBIP45 = function deriveBIP45(options) {
|
||||
@ -391,7 +411,7 @@ HDPrivateKey.prototype.deriveBIP45 = function deriveBIP45(options) {
|
||||
assert(utils.isFinite(addressIndex));
|
||||
|
||||
return this
|
||||
.deriveRoot45(options)
|
||||
.derivePurpose45(options)
|
||||
.derive(cosignerIndex)
|
||||
.derive(chain)
|
||||
.derive(addressIndex);
|
||||
@ -413,6 +433,14 @@ HDPrivateKey.prototype.deriveCosignerAddress = function deriveCosignerAddress(co
|
||||
});
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.isPurpose45 = function isPurpose45(options) {
|
||||
return new bn(this.childIndex).toNumber() === constants.hd.hardened + 45;
|
||||
};
|
||||
|
||||
HDPrivateKey.prototype.isAccount44 = function isAccount44(options) {
|
||||
return new bn(this.depth).toNumber() === 3;
|
||||
};
|
||||
|
||||
HDPrivateKey.getPath = function getPath(options) {
|
||||
var purpose, coinType, accountIndex, chain, addressIndex;
|
||||
|
||||
@ -765,17 +793,20 @@ function HDPublicKey(options) {
|
||||
}
|
||||
|
||||
HDPublicKey.prototype.scan44 = HDPrivateKey.prototype.scan44;
|
||||
HDPublicKey.prototype.deriveRoot44 = HDPrivateKey.prototype.deriveRoot44;
|
||||
HDPublicKey.prototype.deriveAccount44 = HDPrivateKey.prototype.deriveAccount44;
|
||||
HDPublicKey.prototype.deriveBIP44 = HDPrivateKey.prototype.deriveBIP44;
|
||||
HDPublicKey.prototype.deriveChange = HDPrivateKey.prototype.deriveChange;
|
||||
HDPublicKey.prototype.deriveAddress = HDPrivateKey.prototype.deriveAddress;
|
||||
|
||||
HDPublicKey.prototype.scan45 = HDPrivateKey.prototype.scan45;
|
||||
HDPublicKey.prototype.deriveRoot45 = HDPrivateKey.prototype.deriveRoot45;
|
||||
HDPublicKey.prototype.derivePurpose45 = HDPrivateKey.prototype.derivePurpose45;
|
||||
HDPublicKey.prototype.deriveBIP45 = HDPrivateKey.prototype.deriveBIP45;
|
||||
HDPublicKey.prototype.deriveCosignerChange = HDPrivateKey.prototype.deriveCosignerChange;
|
||||
HDPublicKey.prototype.deriveCosignerAddress = HDPrivateKey.prototype.deriveCosignerAddress;
|
||||
|
||||
HDPublicKey.prototype.isPurpose45 = HDPrivateKey.prototype.isPurpose45;
|
||||
HDPublicKey.prototype.isAccount44 = HDPrivateKey.prototype.isAccount44;
|
||||
|
||||
HDPublicKey.isExtended = function isExtended(data) {
|
||||
if (typeof data !== 'string')
|
||||
return false;
|
||||
|
||||
@ -33,6 +33,12 @@ function KeyPair(options) {
|
||||
this.hd = options.hd || null;
|
||||
this.compressed = options.compressed !== false;
|
||||
|
||||
if (options.privateKey)
|
||||
options.priv = options.privateKey;
|
||||
|
||||
if (options.publicKey)
|
||||
options.pub = options.publicKey;
|
||||
|
||||
if (options.priv instanceof bcoin.hd.priv) {
|
||||
this.hd = options.priv;
|
||||
this._key = options.priv.pair;
|
||||
|
||||
@ -763,6 +763,12 @@ utils.sortKeys = function sortKeys(keys) {
|
||||
});
|
||||
};
|
||||
|
||||
utils.sortHDKeys = function sortHDKeys(keys) {
|
||||
return keys.slice().sort(function(a, b) {
|
||||
return new bn(a.publicKey).cmp(new bn(b.publicKey)) > 0;
|
||||
});
|
||||
};
|
||||
|
||||
utils.uniq = function(obj) {
|
||||
var out = [];
|
||||
var i = 0;
|
||||
|
||||
@ -31,67 +31,323 @@ function Wallet(options) {
|
||||
|
||||
options = utils.merge({}, options);
|
||||
|
||||
if (options.hd) {
|
||||
options.master = options.hd !== true
|
||||
? bcoin.hd.priv(options.hd)
|
||||
: bcoin.hd.priv();
|
||||
delete options.hd;
|
||||
}
|
||||
|
||||
if (options.priv
|
||||
|| options.pub
|
||||
|| options.key
|
||||
|| options.personalization
|
||||
|| options.entropy
|
||||
|| options.compressed) {
|
||||
if ((options.key instanceof bcoin.hd.priv)
|
||||
|| options.key instanceof bcoin.hd.pub) {
|
||||
options.master = options.key;
|
||||
delete options.key;
|
||||
} else if (options.priv instanceof bcoin.hd.priv) {
|
||||
options.master = options.priv;
|
||||
delete options.priv;
|
||||
} else if (options.pub instanceof bcoin.hd.pub) {
|
||||
options.master = options.pub;
|
||||
delete options.pub;
|
||||
}
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
this.addresses = [];
|
||||
this.master = options.master || null;
|
||||
|
||||
if (this.master && !(this.master instanceof bcoin.keypair))
|
||||
this.master = bcoin.keypair({ hd: this.master });
|
||||
|
||||
this._addressTable = {};
|
||||
this._labelMap = {};
|
||||
|
||||
this.accountIndex = options.accountIndex || 0;
|
||||
this.addressDepth = options.addressDepth || 0;
|
||||
this.changeDepth = options.changeDepth || 0;
|
||||
this.cosignerIndex = 0;
|
||||
this.purposeKeys = options.purposeKeys || [];
|
||||
this.keys = options.keys || [];
|
||||
|
||||
this.hd = false;
|
||||
this.hdpm = false;
|
||||
this.multisig = false;
|
||||
|
||||
this.type = options.type || 'pubkeyhash';
|
||||
this.subtype = options.subtype;
|
||||
this.keys = [];
|
||||
this.m = options.m || 1;
|
||||
this.n = options.n || 1;
|
||||
this.nmax = this.type === 'scripthash'
|
||||
? (this.compressed !== false ? 15 : 7)
|
||||
: 3;
|
||||
|
||||
if (this.n > 1) {
|
||||
if (this.type !== 'multisig')
|
||||
this.type = 'scripthash';
|
||||
if (this.type === 'scripthash')
|
||||
this.subtype = 'multisig';
|
||||
}
|
||||
|
||||
if (this.master)
|
||||
this.hd = true;
|
||||
|
||||
if (this.master && this.type === 'scripthash' && this.subtype === 'multisig')
|
||||
this.hdpm = true;
|
||||
|
||||
if (this.type === 'multisig' || this.subtype === 'multisig')
|
||||
this.multisig = true;
|
||||
|
||||
if (network.prefixes[this.type] == null)
|
||||
throw new Error('Unknown prefix: ' + this.type);
|
||||
|
||||
if (this.m < 1 || this.m > this.n)
|
||||
throw new Error('m ranges between 1 and n');
|
||||
|
||||
if (this.n < 1 || this.n > this.nmax)
|
||||
throw new Error('n ranges between 1 and ' + this.nmax);
|
||||
|
||||
if (this.hdpm) {
|
||||
this.purposeKey = this.master.hd.isPublic
|
||||
? this.master.hd
|
||||
: this.master.hd.derivePurpose45();
|
||||
} else if (this.hd) {
|
||||
this.accountKey = this.master.hd.isPublic
|
||||
? this.master.hd
|
||||
: this.master.hd.deriveAccount44(this.accountIndex);
|
||||
}
|
||||
|
||||
if (!options.addresses)
|
||||
options.addresses = [];
|
||||
|
||||
if (!options.addresses.length)
|
||||
options.addresses.push(utils.merge({}, options));
|
||||
|
||||
options.addresses.forEach(function(address) {
|
||||
this.addAddress(address);
|
||||
}, this);
|
||||
|
||||
// Create a non-master account address if we don't have one.
|
||||
if (this.master) {
|
||||
for (i = 0; i < this.addresses.length; i++) {
|
||||
if (this.addresses[i].key.hd && !this.addresses[i].change)
|
||||
break;
|
||||
}
|
||||
if (i === this.addresses.length)
|
||||
this.createNewAddress(this._cleanOptions(options.addresses[0]));
|
||||
if (options.priv
|
||||
|| options.pub
|
||||
|| options.key
|
||||
|| options.personalization
|
||||
|| options.entropy
|
||||
|| options.compressed) {
|
||||
options.addresses.push({
|
||||
priv: options.priv,
|
||||
pub: options.pub,
|
||||
key: options.key,
|
||||
personalization: options.personalization,
|
||||
entropy: options.entropy,
|
||||
compressed: options.compressed,
|
||||
type: this.type,
|
||||
subtype: this.subtype,
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
keys: [],
|
||||
change: false
|
||||
});
|
||||
}
|
||||
|
||||
// Find the last change address if there is one.
|
||||
for (i = this.addresses.length - 1; i >= 0; i--) {
|
||||
if (this.addresses[i].change)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i === -1)
|
||||
this.changeAddress = this.createChangeAddress();
|
||||
else
|
||||
this.changeAddress = this.addresses[i];
|
||||
|
||||
this.storage = options.storage;
|
||||
this.loading = true;
|
||||
this.lastTs = 0;
|
||||
|
||||
if (!this.hdpm) {
|
||||
if (options.addresses.length) {
|
||||
this.current = bcoin.address(options.addresses[options.addresses.length - 1]);
|
||||
this._firstKey = {
|
||||
priv: this.current.key._key.getPrivate().toArray(),
|
||||
pub: this.current.key._key.getPublic(true, 'array')
|
||||
};
|
||||
} else {
|
||||
this._firstKey = this.createKey(false, Math.max(0, this.addressDepth - 1));
|
||||
this.current = bcoin.address({ priv: this._firstKey.priv });
|
||||
}
|
||||
}
|
||||
|
||||
if (this.hdpm)
|
||||
this.addKey(this.purposeKey);
|
||||
else
|
||||
this.addKey(this.current.publicKey);
|
||||
|
||||
(options.keys || []).forEach(function(key) {
|
||||
this.addKey(key);
|
||||
}, this);
|
||||
}
|
||||
|
||||
inherits(Wallet, EventEmitter);
|
||||
|
||||
Wallet.prototype._initAddresses = function() {
|
||||
var options = this.options;
|
||||
|
||||
options.addresses.forEach(function(address) {
|
||||
address = this.addAddress(address);
|
||||
if (!address.change)
|
||||
this.current = address;
|
||||
}, this);
|
||||
|
||||
if (this.hd) {
|
||||
for (i = 0; i < this.addressDepth; i++)
|
||||
this.createAddress(false, i);
|
||||
|
||||
for (i = 0; i < this.changeDepth; i++)
|
||||
this.createAddress(true, i);
|
||||
}
|
||||
|
||||
// Create a non-master account address if we don't have one.
|
||||
if (this.addresses.length === 0)
|
||||
this.createAddress();
|
||||
|
||||
// Find the last change address if there is one.
|
||||
if (this.hd) {
|
||||
if (this.changeDepth === 0)
|
||||
this.changeAddress = this.createAddress(true);
|
||||
else
|
||||
this.changeAddress = this.addresses[this.addresses.length - 1];
|
||||
} else {
|
||||
for (i = this.addresses.length - 1; i >= 0; i--) {
|
||||
if (this.addresses[i].change)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i === -1)
|
||||
this.changeAddress = this.createAddress(true);
|
||||
else
|
||||
this.changeAddress = this.addresses[i];
|
||||
}
|
||||
|
||||
assert(this.current);
|
||||
assert(!this.current.change);
|
||||
assert(this.changeAddress.change);
|
||||
|
||||
this.prefix = 'bt/wallet/' + this.getKeyAddress() + '/';
|
||||
|
||||
this.tx = new bcoin.txPool(this);
|
||||
|
||||
this._init();
|
||||
}
|
||||
};
|
||||
|
||||
inherits(Wallet, EventEmitter);
|
||||
Wallet.prototype.addKey = function addKey(key) {
|
||||
var hdKey, has, i;
|
||||
|
||||
Wallet.prototype._cleanOptions = function _cleanOptions(options) {
|
||||
return utils.merge(options, {
|
||||
key: null,
|
||||
priv: null,
|
||||
pub: null,
|
||||
hd: null
|
||||
if (bcoin.hd.priv.isExtended(key))
|
||||
key = bcoin.hd.priv(key);
|
||||
else if (bcoin.hd.pub.isExtended(key))
|
||||
key = bcoin.hd.pub(key);
|
||||
|
||||
if (key instanceof bcoin.keypair)
|
||||
key = key.hd;
|
||||
|
||||
if (key instanceof bcoin.hd.priv)
|
||||
key = key.hdpub;
|
||||
|
||||
if (key instanceof bcoin.hd.pub) {
|
||||
hdKey = key;
|
||||
key = hdKey.publicKey;
|
||||
}
|
||||
|
||||
if (this.hdpm) {
|
||||
if (!hdKey || !hdKey.isPurpose45())
|
||||
throw new Error('Must add HD purpose keys to HD wallet.');
|
||||
|
||||
has = this.purposeKeys.some(function(pub) {
|
||||
return pub.xpubkey === hdKey.xpubkey;
|
||||
});
|
||||
|
||||
if (has)
|
||||
return;
|
||||
|
||||
this.purposeKeys.push(hdKey);
|
||||
|
||||
if (this.purposeKeys.length === this.n)
|
||||
this.finalizeKeys();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
key = utils.toBuffer(key);
|
||||
|
||||
has = this.keys.some(function(k) {
|
||||
return utils.isEqual(k, key);
|
||||
});
|
||||
|
||||
if (has)
|
||||
return;
|
||||
|
||||
this.keys.push(key);
|
||||
|
||||
if (this.keys.length === this.n)
|
||||
this.finalizeKeys();
|
||||
};
|
||||
|
||||
Wallet.prototype.finalizeKeys = function finalizeKeys(key) {
|
||||
if (this.hdpm) {
|
||||
this.purposeKeys = utils.sortHDKeys(this.purposeKeys);
|
||||
|
||||
for (i = 0; i < this.purposeKeys.length; i++) {
|
||||
if (utils.isEqual(this.purposeKeys[i].publicKey, this.purposeKey.publicKey)) {
|
||||
this.cosignerIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this._initAddresses();
|
||||
return;
|
||||
}
|
||||
|
||||
this.keys = utils.sortKeys(this.keys);
|
||||
|
||||
this._initAddresses();
|
||||
};
|
||||
|
||||
Wallet.prototype.removeKey = function removeKey(key) {
|
||||
var hdKey, index;
|
||||
|
||||
if (bcoin.hd.priv.isExtended(key))
|
||||
key = bcoin.hd.priv(key);
|
||||
else if (bcoin.hd.pub.isExtended(key))
|
||||
key = bcoin.hd.pub(key);
|
||||
|
||||
if (key instanceof bcoin.keypair)
|
||||
key = key.hd;
|
||||
|
||||
if (key instanceof bcoin.hd.priv)
|
||||
key = key.hdpub;
|
||||
|
||||
if (key instanceof bcoin.hd.pub) {
|
||||
hdKey = key;
|
||||
key = hd.publicKey;
|
||||
}
|
||||
|
||||
if (this.hdpm) {
|
||||
if (!hdKey || !hdKey.isPurpose45())
|
||||
throw new Error('Must add HD purpose keys to HD wallet.');
|
||||
|
||||
index = this.purposeKeys.map(function(pub, i) {
|
||||
return pub.xpubkey === hdKey.xpubkey ? i : null;
|
||||
}).filter(function(i) {
|
||||
return i !== null;
|
||||
})[0];
|
||||
|
||||
if (index == null)
|
||||
return;
|
||||
|
||||
this.purposeKeys.splice(index, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
key = utils.toBuffer(key);
|
||||
|
||||
index = this.keys.map(function(pub, i) {
|
||||
return utils.isEqual(pub, key) ? i : null;
|
||||
}).filter(function(i) {
|
||||
return i !== null;
|
||||
})[0];
|
||||
|
||||
if (index == null)
|
||||
return;
|
||||
|
||||
this.keys.splice(index, 1);
|
||||
};
|
||||
|
||||
Wallet.prototype._init = function init() {
|
||||
@ -134,7 +390,7 @@ Wallet.prototype._init = function init() {
|
||||
};
|
||||
|
||||
Wallet.prototype.__defineGetter__('primary', function() {
|
||||
return this.addresses[0];
|
||||
return this.current;
|
||||
});
|
||||
|
||||
Wallet.prototype._getAddressTable = function() {
|
||||
@ -171,30 +427,52 @@ Wallet.prototype._addressIndex = function _addressIndex(address) {
|
||||
return -1;
|
||||
};
|
||||
|
||||
Wallet.prototype.createChangeAddress = function createChangeAddress(options) {
|
||||
if (!options)
|
||||
options = {};
|
||||
Wallet.prototype.createAddress = function createAddress(change, index) {
|
||||
var self = this;
|
||||
var key = this.createKey(change, index);
|
||||
var address;
|
||||
|
||||
options.change = true;
|
||||
var options = {
|
||||
priv: key.priv,
|
||||
pub: key.pub,
|
||||
type: this.type,
|
||||
subtype: this.subtype,
|
||||
m: this.m,
|
||||
n: this.n,
|
||||
keys: [],
|
||||
change: change
|
||||
};
|
||||
|
||||
if (this.master) {
|
||||
options.priv =
|
||||
this.master.key.hd.deriveChange(this.accountIndex, this.changeDepth++);
|
||||
if (this.hdpm) {
|
||||
this.purposeKeys.forEach(function(key, cosignerIndex) {
|
||||
key = key
|
||||
.derive(cosignerIndex)
|
||||
.derive(change ? 1 : 0)
|
||||
.derive(change ? self.changeDepth : self.addressDepth);
|
||||
options.keys.push(key.publicKey);
|
||||
});
|
||||
this.keys = utils.sortKeys(options.keys);
|
||||
} else {
|
||||
this.keys.forEach(function(key, i) {
|
||||
options.keys.push(key);
|
||||
});
|
||||
}
|
||||
|
||||
return this.addAddress(options);
|
||||
};
|
||||
|
||||
Wallet.prototype.createNewAddress = function createNewAddress(options) {
|
||||
if (!options)
|
||||
options = {};
|
||||
|
||||
if (this.master) {
|
||||
options.priv =
|
||||
this.master.key.hd.deriveAddress(this.accountIndex, this.addressDepth++);
|
||||
if (index == null) {
|
||||
if (this.hd) {
|
||||
if (change)
|
||||
this.changeDepth++;
|
||||
else
|
||||
this.addressDepth++;
|
||||
}
|
||||
}
|
||||
|
||||
return this.addAddress(options);
|
||||
address = this.addAddress(options);
|
||||
|
||||
if (!change)
|
||||
this.current = address;
|
||||
|
||||
return address;
|
||||
};
|
||||
|
||||
Wallet.prototype.hasAddress = function hasAddress(address) {
|
||||
@ -220,12 +498,6 @@ Wallet.prototype.addAddress = function addAddress(address) {
|
||||
if (this._addressIndex(address) !== -1)
|
||||
return;
|
||||
|
||||
if (address.key.hd && address.key.hd.isMaster) {
|
||||
assert(!this.master);
|
||||
this.master = address;
|
||||
return;
|
||||
}
|
||||
|
||||
if (address._wallet)
|
||||
address._wallet.removeAddress(address);
|
||||
|
||||
@ -282,14 +554,6 @@ Wallet.prototype.removeAddress = function removeAddress(address) {
|
||||
return address;
|
||||
};
|
||||
|
||||
Wallet.prototype.addKey = function addKey(key, i) {
|
||||
return this.primary.addKey(key);
|
||||
};
|
||||
|
||||
Wallet.prototype.removeKey = function removeKey(key) {
|
||||
return this.primary.removeKey(key);
|
||||
};
|
||||
|
||||
Wallet.prototype.getPrivateKey = function getPrivateKey(enc) {
|
||||
return this.primary.getPrivateKey(enc);
|
||||
};
|
||||
@ -305,13 +569,49 @@ Wallet.prototype.getScripthash = function getScripthash() {
|
||||
|
||||
Wallet.prototype.getScriptAddress =
|
||||
Wallet.prototype.getScriptaddress = function getScriptaddress() {
|
||||
return this.primary.getScriptAddress();
|
||||
return this.current.getScriptAddress();
|
||||
};
|
||||
|
||||
Wallet.prototype.getPublicKey = function getPublicKey(enc) {
|
||||
return this.primary.getPublicKey(enc);
|
||||
};
|
||||
|
||||
Wallet.prototype.createKey = function createKey(change, index) {
|
||||
var key, pub, priv;
|
||||
|
||||
if (!this.hd) {
|
||||
if (this._firstKey) {
|
||||
key = this._firstKey;
|
||||
delete this._firstKey;
|
||||
return key;
|
||||
}
|
||||
key = bcoin.ecdsa.genKeyPair();
|
||||
return {
|
||||
priv: key.getPrivate().toArray(),
|
||||
pub: key.getPublic(true, 'array')
|
||||
};
|
||||
}
|
||||
|
||||
if (index == null)
|
||||
index = change ? this.changeDepth : this.addressDepth;
|
||||
|
||||
if (this.hdpm) {
|
||||
key = this.purposeKey
|
||||
.derive(this.cosignerIndex)
|
||||
.derive(change ? 1 : 0)
|
||||
.derive(index);
|
||||
} else {
|
||||
key = this.accountKey
|
||||
.derive(change ? 1 : 0)
|
||||
.derive(index);
|
||||
}
|
||||
|
||||
return {
|
||||
priv: key.privateKey,
|
||||
pub: key.publicKey
|
||||
};
|
||||
};
|
||||
|
||||
Wallet.prototype.getKeyHash =
|
||||
Wallet.prototype.getKeyhash = function getKeyhash() {
|
||||
return this.primary.getKeyHash();
|
||||
@ -327,7 +627,7 @@ Wallet.prototype.getHash = function getHash() {
|
||||
};
|
||||
|
||||
Wallet.prototype.getAddress = function getAddress() {
|
||||
return this.primary.getAddress();
|
||||
return this.current.getAddress();
|
||||
};
|
||||
|
||||
Wallet.prototype.ownInput = function ownInput(tx, index) {
|
||||
|
||||
@ -74,11 +74,9 @@ describe('Wallet', function() {
|
||||
|
||||
it('should multisign/verify TX', function() {
|
||||
var w = bcoin.wallet({
|
||||
multisig: {
|
||||
type: 'multisig',
|
||||
m: 1,
|
||||
n: 2
|
||||
}
|
||||
type: 'multisig',
|
||||
m: 1,
|
||||
n: 2
|
||||
});
|
||||
// var k2 = w.getPublicKey().concat(1);
|
||||
var k2 = bcoin.ecdsa.genKeyPair().getPublic(true, 'array');
|
||||
@ -265,37 +263,38 @@ describe('Wallet', function() {
|
||||
it('should verify 2-of-3 p2sh tx', function(cb) {
|
||||
// Create 3 2-of-3 wallets with our pubkeys as "shared keys"
|
||||
var w1 = bcoin.wallet({
|
||||
multisig: {
|
||||
type: 'scripthash',
|
||||
m: 2,
|
||||
n: 3
|
||||
}
|
||||
hd: true,
|
||||
type: 'scripthash',
|
||||
subtype: 'multisig',
|
||||
m: 2,
|
||||
n: 3
|
||||
});
|
||||
|
||||
var w2 = bcoin.wallet({
|
||||
multisig: {
|
||||
type: 'scripthash',
|
||||
m: 2,
|
||||
n: 3
|
||||
}
|
||||
hd: true,
|
||||
type: 'scripthash',
|
||||
subtype: 'multisig',
|
||||
m: 2,
|
||||
n: 3
|
||||
});
|
||||
|
||||
var w3 = bcoin.wallet({
|
||||
hd: true,
|
||||
multisig: {
|
||||
type: 'scripthash',
|
||||
m: 2,
|
||||
n: 3
|
||||
}
|
||||
type: 'scripthash',
|
||||
subtype: 'multisig',
|
||||
m: 2,
|
||||
n: 3
|
||||
});
|
||||
w3 = bcoin.wallet.fromJSON(w3.toJSON());
|
||||
// w3 = bcoin.wallet.fromJSON(w3.toJSON());
|
||||
|
||||
var receive = bcoin.wallet();
|
||||
|
||||
w1.addKey(w2.getPublicKey());
|
||||
w1.addKey(w3.getPublicKey());
|
||||
w2.addKey(w1.getPublicKey());
|
||||
w2.addKey(w3.getPublicKey());
|
||||
w3.addKey(w1.getPublicKey());
|
||||
w3.addKey(w2.getPublicKey());
|
||||
w1.addKey(w2.purposeKey);
|
||||
w1.addKey(w3.purposeKey);
|
||||
w2.addKey(w1.purposeKey);
|
||||
w2.addKey(w3.purposeKey);
|
||||
w3.addKey(w1.purposeKey);
|
||||
w3.addKey(w2.purposeKey);
|
||||
|
||||
// Our p2sh address
|
||||
var addr = w1.getAddress();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user