wallet/bcoin: stop tracking network everywhere.

This commit is contained in:
Christopher Jeffrey 2017-10-20 06:04:40 -07:00
parent 40bb08aed6
commit f3b94ded65
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
24 changed files with 326 additions and 468 deletions

View File

@ -37,35 +37,32 @@ HD.fromBase58 = function fromBase58(xkey, network) {
* @param {Object} options * @param {Object} options
* @param {Buffer?} options.privateKey * @param {Buffer?} options.privateKey
* @param {Buffer?} options.entropy * @param {Buffer?} options.entropy
* @param {String?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HD.generate = function generate(network) { HD.generate = function generate() {
return HDPrivateKey.generate(network); return HDPrivateKey.generate();
}; };
/** /**
* Generate an {@link HDPrivateKey} from a seed. * Generate an {@link HDPrivateKey} from a seed.
* @param {Object|Mnemonic|Buffer} options - seed, * @param {Object|Mnemonic|Buffer} options - seed,
* mnemonic, mnemonic options. * mnemonic, mnemonic options.
* @param {String?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HD.fromSeed = function fromSeed(options, network) { HD.fromSeed = function fromSeed(options) {
return HDPrivateKey.fromSeed(options, network); return HDPrivateKey.fromSeed(options);
}; };
/** /**
* Instantiate an hd private key from a mnemonic. * Instantiate an hd private key from a mnemonic.
* @param {Mnemonic|Object} mnemonic * @param {Mnemonic|Object} mnemonic
* @param {String?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HD.fromMnemonic = function fromMnemonic(options, network) { HD.fromMnemonic = function fromMnemonic(options) {
return HDPrivateKey.fromMnemonic(options, network); return HDPrivateKey.fromMnemonic(options);
}; };
/** /**
@ -115,7 +112,7 @@ HD.from = function from(options, network) {
return HD.fromRaw(options, network); return HD.fromRaw(options, network);
if (options && typeof options === 'object') if (options && typeof options === 'object')
return HD.fromMnemonic(options, network); return HD.fromMnemonic(options);
throw new Error('Cannot create HD key from bad options.'); throw new Error('Cannot create HD key from bad options.');
}; };

View File

@ -38,7 +38,6 @@ const SEED_SALT = Buffer.from('Bitcoin seed', 'ascii');
* @param {Number?} options.childIndex * @param {Number?} options.childIndex
* @param {Buffer?} options.chainCode * @param {Buffer?} options.chainCode
* @param {Buffer?} options.privateKey * @param {Buffer?} options.privateKey
* @property {Network} network
* @property {Number} depth * @property {Number} depth
* @property {Number} parentFingerPrint * @property {Number} parentFingerPrint
* @property {Number} childIndex * @property {Number} childIndex
@ -50,7 +49,6 @@ function HDPrivateKey(options) {
if (!(this instanceof HDPrivateKey)) if (!(this instanceof HDPrivateKey))
return new HDPrivateKey(options); return new HDPrivateKey(options);
this.network = Network.primary;
this.depth = 0; this.depth = 0;
this.parentFingerPrint = 0; this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
@ -60,8 +58,6 @@ function HDPrivateKey(options) {
this.publicKey = encoding.ZERO_KEY; this.publicKey = encoding.ZERO_KEY;
this.fingerPrint = -1; this.fingerPrint = -1;
this._xprivkey = null;
this._hdPublicKey = null; this._hdPublicKey = null;
if (options) if (options)
@ -82,9 +78,6 @@ HDPrivateKey.prototype.fromOptions = function fromOptions(options) {
assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.privateKey)); assert(Buffer.isBuffer(options.privateKey));
if (options.network)
this.network = Network.get(options.network);
this.depth = options.depth; this.depth = options.depth;
this.parentFingerPrint = options.parentFingerPrint; this.parentFingerPrint = options.parentFingerPrint;
this.childIndex = options.childIndex; this.childIndex = options.childIndex;
@ -115,7 +108,6 @@ HDPrivateKey.prototype.toPublic = function toPublic() {
if (!key) { if (!key) {
key = new HDPublicKey(); key = new HDPublicKey();
key.network = this.network;
key.depth = this.depth; key.depth = this.depth;
key.parentFingerPrint = this.parentFingerPrint; key.parentFingerPrint = this.parentFingerPrint;
key.childIndex = this.childIndex; key.childIndex = this.childIndex;
@ -132,10 +124,8 @@ HDPrivateKey.prototype.toPublic = function toPublic() {
* @returns {Base58String} * @returns {Base58String}
*/ */
HDPrivateKey.prototype.xprivkey = function xprivkey() { HDPrivateKey.prototype.xprivkey = function xprivkey(network) {
if (!this._xprivkey) return this.toBase58(network);
this._xprivkey = this.toBase58();
return this._xprivkey;
}; };
/** /**
@ -143,8 +133,8 @@ HDPrivateKey.prototype.xprivkey = function xprivkey() {
* @returns {Base58String} * @returns {Base58String}
*/ */
HDPrivateKey.prototype.xpubkey = function xpubkey() { HDPrivateKey.prototype.xpubkey = function xpubkey(network) {
return this.toPublic().xpubkey(); return this.toPublic().xpubkey(network);
}; };
/** /**
@ -168,8 +158,6 @@ HDPrivateKey.prototype.destroy = function destroy(pub) {
this._hdPublicKey.destroy(); this._hdPublicKey.destroy();
this._hdPublicKey = null; this._hdPublicKey = null;
} }
this._xprivkey = null;
}; };
/** /**
@ -229,7 +217,6 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
} }
const child = new HDPrivateKey(); const child = new HDPrivateKey();
child.network = this.network;
child.depth = this.depth + 1; child.depth = this.depth + 1;
child.parentFingerPrint = this.fingerPrint; child.parentFingerPrint = this.fingerPrint;
child.childIndex = index; child.childIndex = index;
@ -250,26 +237,26 @@ HDPrivateKey.prototype.derive = function derive(index, hardened) {
*/ */
HDPrivateKey.prototype.getID = function getID(index) { HDPrivateKey.prototype.getID = function getID(index) {
return this.network.keyPrefix.xprivkey58 return 'v' + this.publicKey.toString('hex') + index;
+ this.publicKey.toString('hex')
+ index;
}; };
/** /**
* Derive a BIP44 account key. * Derive a BIP44 account key.
* @param {Number} purpose * @param {Number} purpose
* @param {Number} type
* @param {Number} account * @param {Number} account
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
* @throws Error if key is not a master key. * @throws Error if key is not a master key.
*/ */
HDPrivateKey.prototype.deriveAccount = function deriveAccount(purpose, account) { HDPrivateKey.prototype.deriveAccount = function deriveAccount(purpose, type, account) {
assert(util.isU32(purpose), 'Purpose must be a number.'); assert(util.isU32(purpose), 'Purpose must be a number.');
assert(util.isU32(type), 'Account index must be a number.');
assert(util.isU32(account), 'Account index must be a number.'); assert(util.isU32(account), 'Account index must be a number.');
assert(this.isMaster(), 'Cannot derive account index.'); assert(this.isMaster(), 'Cannot derive account index.');
return this return this
.derive(purpose, true) .derive(purpose, true)
.derive(this.network.keyPrefix.coinType, true) .derive(type, true)
.derive(account, true); .derive(account, true);
}; };
@ -382,8 +369,7 @@ HDPrivateKey.prototype.derivePath = function derivePath(path) {
HDPrivateKey.prototype.equals = function equals(obj) { HDPrivateKey.prototype.equals = function equals(obj) {
assert(HDPrivateKey.isHDPrivateKey(obj)); assert(HDPrivateKey.isHDPrivateKey(obj));
return this.network === obj.network return this.depth === obj.depth
&& this.depth === obj.depth
&& this.parentFingerPrint === obj.parentFingerPrint && this.parentFingerPrint === obj.parentFingerPrint
&& this.childIndex === obj.childIndex && this.childIndex === obj.childIndex
&& this.chainCode.equals(obj.chainCode) && this.chainCode.equals(obj.chainCode)
@ -431,10 +417,9 @@ HDPrivateKey.prototype.compare = function compare(key) {
* Inject properties from seed. * Inject properties from seed.
* @private * @private
* @param {Buffer} seed * @param {Buffer} seed
* @param {(Network|NetworkType)?} network
*/ */
HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) { HDPrivateKey.prototype.fromSeed = function fromSeed(seed) {
assert(Buffer.isBuffer(seed)); assert(Buffer.isBuffer(seed));
if (seed.length * 8 < common.MIN_ENTROPY if (seed.length * 8 < common.MIN_ENTROPY
@ -450,7 +435,6 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
if (!secp256k1.privateKeyVerify(left)) if (!secp256k1.privateKeyVerify(left))
throw new Error('Master private key is invalid.'); throw new Error('Master private key is invalid.');
this.network = Network.get(network);
this.depth = 0; this.depth = 0;
this.parentFingerPrint = 0; this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
@ -464,59 +448,54 @@ HDPrivateKey.prototype.fromSeed = function fromSeed(seed, network) {
/** /**
* Instantiate an hd private key from a 512 bit seed. * Instantiate an hd private key from a 512 bit seed.
* @param {Buffer} seed * @param {Buffer} seed
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HDPrivateKey.fromSeed = function fromSeed(seed, network) { HDPrivateKey.fromSeed = function fromSeed(seed) {
return new HDPrivateKey().fromSeed(seed, network); return new HDPrivateKey().fromSeed(seed);
}; };
/** /**
* Inject properties from a mnemonic. * Inject properties from a mnemonic.
* @private * @private
* @param {Mnemonic} mnemonic * @param {Mnemonic} mnemonic
* @param {(Network|NetworkType)?} network
*/ */
HDPrivateKey.prototype.fromMnemonic = function fromMnemonic(mnemonic, network) { HDPrivateKey.prototype.fromMnemonic = function fromMnemonic(mnemonic) {
assert(mnemonic instanceof Mnemonic); assert(mnemonic instanceof Mnemonic);
return this.fromSeed(mnemonic.toSeed(), network); return this.fromSeed(mnemonic.toSeed());
}; };
/** /**
* Instantiate an hd private key from a mnemonic. * Instantiate an hd private key from a mnemonic.
* @param {Mnemonic} mnemonic * @param {Mnemonic} mnemonic
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic, network) { HDPrivateKey.fromMnemonic = function fromMnemonic(mnemonic) {
return new HDPrivateKey().fromMnemonic(mnemonic, network); return new HDPrivateKey().fromMnemonic(mnemonic);
}; };
/** /**
* Inject properties from a mnemonic. * Inject properties from a mnemonic.
* @private * @private
* @param {String} mnemonic * @param {String} mnemonic
* @param {(Network|NetworkType)?} network
*/ */
HDPrivateKey.prototype.fromPhrase = function fromPhrase(phrase, network) { HDPrivateKey.prototype.fromPhrase = function fromPhrase(phrase) {
const mnemonic = Mnemonic.fromPhrase(phrase); const mnemonic = Mnemonic.fromPhrase(phrase);
this.fromMnemonic(mnemonic, network); this.fromMnemonic(mnemonic);
return this; return this;
}; };
/** /**
* Instantiate an hd private key from a phrase. * Instantiate an hd private key from a phrase.
* @param {String} phrase * @param {String} phrase
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HDPrivateKey.fromPhrase = function fromPhrase(phrase, network) { HDPrivateKey.fromPhrase = function fromPhrase(phrase) {
return new HDPrivateKey().fromPhrase(phrase, network); return new HDPrivateKey().fromPhrase(phrase);
}; };
/** /**
@ -524,13 +503,11 @@ HDPrivateKey.fromPhrase = function fromPhrase(phrase, network) {
* @private * @private
* @param {Buffer} key * @param {Buffer} key
* @param {Buffer} entropy * @param {Buffer} entropy
* @param {(Network|NetworkType)?} network
*/ */
HDPrivateKey.prototype.fromKey = function fromKey(key, entropy, network) { HDPrivateKey.prototype.fromKey = function fromKey(key, entropy) {
assert(Buffer.isBuffer(key) && key.length === 32); assert(Buffer.isBuffer(key) && key.length === 32);
assert(Buffer.isBuffer(entropy) && entropy.length === 32); assert(Buffer.isBuffer(entropy) && entropy.length === 32);
this.network = Network.get(network);
this.depth = 0; this.depth = 0;
this.parentFingerPrint = 0; this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
@ -544,24 +521,22 @@ HDPrivateKey.prototype.fromKey = function fromKey(key, entropy, network) {
* Create an hd private key from a key and entropy bytes. * Create an hd private key from a key and entropy bytes.
* @param {Buffer} key * @param {Buffer} key
* @param {Buffer} entropy * @param {Buffer} entropy
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HDPrivateKey.fromKey = function fromKey(key, entropy, network) { HDPrivateKey.fromKey = function fromKey(key, entropy) {
return new HDPrivateKey().fromKey(key, entropy, network); return new HDPrivateKey().fromKey(key, entropy);
}; };
/** /**
* Generate an hd private key. * Generate an hd private key.
* @param {(Network|NetworkType)?} network
* @returns {HDPrivateKey} * @returns {HDPrivateKey}
*/ */
HDPrivateKey.generate = function generate(network) { HDPrivateKey.generate = function generate() {
const key = secp256k1.generatePrivateKey(); const key = secp256k1.generatePrivateKey();
const entropy = random.randomBytes(32); const entropy = random.randomBytes(32);
return HDPrivateKey.fromKey(key, entropy, network); return HDPrivateKey.fromKey(key, entropy);
}; };
/** /**
@ -573,7 +548,6 @@ HDPrivateKey.generate = function generate(network) {
HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey, network) { HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey, network) {
assert(typeof xkey === 'string'); assert(typeof xkey === 'string');
this._xprivkey = xkey;
return this.fromRaw(base58.decode(xkey), network); return this.fromRaw(base58.decode(xkey), network);
}; };
@ -587,7 +561,8 @@ HDPrivateKey.prototype.fromBase58 = function fromBase58(xkey, network) {
HDPrivateKey.prototype.fromReader = function fromReader(br, network) { HDPrivateKey.prototype.fromReader = function fromReader(br, network) {
const version = br.readU32BE(); const version = br.readU32BE();
this.network = Network.fromPrivate(version, network); Network.fromPrivate(version, network);
this.depth = br.readU8(); this.depth = br.readU8();
this.parentFingerPrint = br.readU32BE(); this.parentFingerPrint = br.readU32BE();
this.childIndex = br.readU32BE(); this.childIndex = br.readU32BE();
@ -638,9 +613,6 @@ HDPrivateKey.prototype.getSize = function getSize() {
*/ */
HDPrivateKey.prototype.toWriter = function toWriter(bw, network) { HDPrivateKey.prototype.toWriter = function toWriter(bw, network) {
if (!network)
network = this.network;
network = Network.get(network); network = Network.get(network);
bw.writeU32BE(network.keyPrefix.xprivkey); bw.writeU32BE(network.keyPrefix.xprivkey);
@ -703,9 +675,9 @@ HDPrivateKey.fromRaw = function fromRaw(data, network) {
* @returns {Object} * @returns {Object}
*/ */
HDPrivateKey.prototype.toJSON = function toJSON() { HDPrivateKey.prototype.toJSON = function toJSON(network) {
return { return {
xprivkey: this.xprivkey() xprivkey: this.xprivkey(network)
}; };
}; };

View File

@ -29,7 +29,6 @@ const common = require('./common');
* @param {Number?} options.childIndex * @param {Number?} options.childIndex
* @param {Buffer?} options.chainCode * @param {Buffer?} options.chainCode
* @param {Buffer?} options.publicKey * @param {Buffer?} options.publicKey
* @property {Network} network
* @property {Number} depth * @property {Number} depth
* @property {Number} parentFingerPrint * @property {Number} parentFingerPrint
* @property {Number} childIndex * @property {Number} childIndex
@ -41,7 +40,6 @@ function HDPublicKey(options) {
if (!(this instanceof HDPublicKey)) if (!(this instanceof HDPublicKey))
return new HDPublicKey(options); return new HDPublicKey(options);
this.network = Network.primary;
this.depth = 0; this.depth = 0;
this.parentFingerPrint = 0; this.parentFingerPrint = 0;
this.childIndex = 0; this.childIndex = 0;
@ -50,8 +48,6 @@ function HDPublicKey(options) {
this.fingerPrint = -1; this.fingerPrint = -1;
this._xpubkey = null;
if (options) if (options)
this.fromOptions(options); this.fromOptions(options);
} }
@ -70,9 +66,6 @@ HDPublicKey.prototype.fromOptions = function fromOptions(options) {
assert(Buffer.isBuffer(options.chainCode)); assert(Buffer.isBuffer(options.chainCode));
assert(Buffer.isBuffer(options.publicKey)); assert(Buffer.isBuffer(options.publicKey));
if (options.network)
this.network = Network.get(options.network);
this.depth = options.depth; this.depth = options.depth;
this.parentFingerPrint = options.parentFingerPrint; this.parentFingerPrint = options.parentFingerPrint;
this.childIndex = options.childIndex; this.childIndex = options.childIndex;
@ -106,7 +99,7 @@ HDPublicKey.prototype.toPublic = function toPublic() {
* @returns {null} * @returns {null}
*/ */
HDPublicKey.prototype.xprivkey = function xprivkey() { HDPublicKey.prototype.xprivkey = function xprivkey(network) {
return null; return null;
}; };
@ -115,10 +108,8 @@ HDPublicKey.prototype.xprivkey = function xprivkey() {
* @returns {Base58String} * @returns {Base58String}
*/ */
HDPublicKey.prototype.xpubkey = function xpubkey() { HDPublicKey.prototype.xpubkey = function xpubkey(network) {
if (!this._xpubkey) return this.toBase58(network);
this._xpubkey = this.toBase58();
return this._xpubkey;
}; };
/** /**
@ -134,8 +125,6 @@ HDPublicKey.prototype.destroy = function destroy() {
cleanse(this.publicKey); cleanse(this.publicKey);
this.fingerPrint = -1; this.fingerPrint = -1;
this._xpubkey = null;
}; };
/** /**
@ -189,7 +178,6 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
} }
const child = new HDPublicKey(); const child = new HDPublicKey();
child.network = this.network;
child.depth = this.depth + 1; child.depth = this.depth + 1;
child.parentFingerPrint = this.fingerPrint; child.parentFingerPrint = this.fingerPrint;
child.childIndex = index; child.childIndex = index;
@ -209,22 +197,22 @@ HDPublicKey.prototype.derive = function derive(index, hardened) {
*/ */
HDPublicKey.prototype.getID = function getID(index) { HDPublicKey.prototype.getID = function getID(index) {
return this.network.keyPrefix.xpubkey58 return 'b' + this.publicKey.toString('hex') + index;
+ this.publicKey.toString('hex')
+ index;
}; };
/** /**
* Derive a BIP44 account key (does not derive, only ensures account key). * Derive a BIP44 account key (does not derive, only ensures account key).
* @method * @method
* @param {Number} purpose * @param {Number} purpose
* @param {Number} type
* @param {Number} account * @param {Number} account
* @returns {HDPublicKey} * @returns {HDPublicKey}
* @throws Error if key is not already an account key. * @throws Error if key is not already an account key.
*/ */
HDPublicKey.prototype.deriveAccount = function deriveAccount(purpose, account) { HDPublicKey.prototype.deriveAccount = function deriveAccount(purpose, type, account) {
assert(util.isU32(purpose)); assert(util.isU32(purpose));
assert(util.isU32(type));
assert(util.isU32(account)); assert(util.isU32(account));
assert(this.isAccount(account), 'Cannot derive account index.'); assert(this.isAccount(account), 'Cannot derive account index.');
return this; return this;
@ -295,8 +283,7 @@ HDPublicKey.prototype.derivePath = function derivePath(path) {
HDPublicKey.prototype.equals = function equals(obj) { HDPublicKey.prototype.equals = function equals(obj) {
assert(HDPublicKey.isHDPublicKey(obj)); assert(HDPublicKey.isHDPublicKey(obj));
return this.network === obj.network return this.depth === obj.depth
&& this.depth === obj.depth
&& this.parentFingerPrint === obj.parentFingerPrint && this.parentFingerPrint === obj.parentFingerPrint
&& this.childIndex === obj.childIndex && this.childIndex === obj.childIndex
&& this.chainCode.equals(obj.chainCode) && this.chainCode.equals(obj.chainCode)
@ -345,9 +332,9 @@ HDPublicKey.prototype.compare = function compare(key) {
* @returns {Object} * @returns {Object}
*/ */
HDPublicKey.prototype.toJSON = function toJSON() { HDPublicKey.prototype.toJSON = function toJSON(network) {
return { return {
xpubkey: this.xpubkey() xpubkey: this.xpubkey(network)
}; };
}; };
@ -432,7 +419,6 @@ HDPublicKey.isRaw = function isRaw(data, network) {
HDPublicKey.prototype.fromBase58 = function fromBase58(xkey, network) { HDPublicKey.prototype.fromBase58 = function fromBase58(xkey, network) {
assert(typeof xkey === 'string'); assert(typeof xkey === 'string');
this._xpubkey = xkey;
return this.fromRaw(base58.decode(xkey), network); return this.fromRaw(base58.decode(xkey), network);
}; };
@ -446,7 +432,8 @@ HDPublicKey.prototype.fromBase58 = function fromBase58(xkey, network) {
HDPublicKey.prototype.fromReader = function fromReader(br, network) { HDPublicKey.prototype.fromReader = function fromReader(br, network) {
const version = br.readU32BE(); const version = br.readU32BE();
this.network = Network.fromPublic(version, network); Network.fromPublic(version, network);
this.depth = br.readU8(); this.depth = br.readU8();
this.parentFingerPrint = br.readU32BE(); this.parentFingerPrint = br.readU32BE();
this.childIndex = br.readU32BE(); this.childIndex = br.readU32BE();
@ -486,9 +473,6 @@ HDPublicKey.prototype.toBase58 = function toBase58(network) {
*/ */
HDPublicKey.prototype.toWriter = function toWriter(bw, network) { HDPublicKey.prototype.toWriter = function toWriter(bw, network) {
if (!network)
network = this.network;
network = Network.get(network); network = Network.get(network);
bw.writeU32BE(network.keyPrefix.xpubkey); bw.writeU32BE(network.keyPrefix.xpubkey);

View File

@ -25,17 +25,15 @@ const bech32 = require('../utils/bech32');
* @property {Buffer} hash * @property {Buffer} hash
* @property {AddressPrefix} type * @property {AddressPrefix} type
* @property {Number} version * @property {Number} version
* @property {Network} network
*/ */
function Address(options) { function Address(options) {
if (!(this instanceof Address)) if (!(this instanceof Address))
return new Address(options); return new Address(options);
this.hash = encoding.ZERO_HASH160;
this.type = Address.types.PUBKEYHASH; this.type = Address.types.PUBKEYHASH;
this.version = -1; this.version = -1;
this.network = Network.primary; this.hash = encoding.ZERO_HASH160;
if (options) if (options)
this.fromOptions(options); this.fromOptions(options);
@ -69,12 +67,7 @@ Address.prototype.fromOptions = function fromOptions(options) {
if (typeof options === 'string') if (typeof options === 'string')
return this.fromString(options); return this.fromString(options);
return this.fromHash( return this.fromHash(options.hash, options.type, options.version);
options.hash,
options.type,
options.version,
options.network
);
}; };
/** /**
@ -128,8 +121,7 @@ Address.prototype.isNull = function isNull() {
Address.prototype.equals = function equals(addr) { Address.prototype.equals = function equals(addr) {
assert(addr instanceof Address); assert(addr instanceof Address);
return this.network === addr.network return this.type === addr.type
&& this.type === addr.type
&& this.version === addr.version && this.version === addr.version
&& this.hash.equals(addr.hash); && this.hash.equals(addr.hash);
}; };
@ -150,9 +142,6 @@ Address.prototype.getType = function getType() {
*/ */
Address.prototype.getPrefix = function getPrefix(network) { Address.prototype.getPrefix = function getPrefix(network) {
if (!network)
network = this.network;
network = Network.get(network); network = Network.get(network);
const prefixes = network.addressPrefix; const prefixes = network.addressPrefix;
@ -241,9 +230,6 @@ Address.prototype.toBech32 = function toBech32(network) {
assert(version !== -1, assert(version !== -1,
'Cannot convert non-program address to bech32.'); 'Cannot convert non-program address to bech32.');
if (!network)
network = this.network;
network = Network.get(network); network = Network.get(network);
const hrp = network.addressPrefix.bech32; const hrp = network.addressPrefix.bech32;
@ -322,10 +308,6 @@ Address.prototype.inspect = function inspect() {
Address.prototype.fromRaw = function fromRaw(data, network) { Address.prototype.fromRaw = function fromRaw(data, network) {
const br = new BufferReader(data, true); const br = new BufferReader(data, true);
if (data.length > 40)
throw new Error('Address is too long.');
const prefix = br.readU8(); const prefix = br.readU8();
network = Network.fromAddress(prefix, network); network = Network.fromAddress(prefix, network);
@ -333,18 +315,24 @@ Address.prototype.fromRaw = function fromRaw(data, network) {
const type = Address.getType(prefix, network); const type = Address.getType(prefix, network);
let version = -1; let version = -1;
if (data.length > 25) { if (type === Address.types.WITNESS) {
if (data.length > 38)
throw new Error('Address is too long.');
version = br.readU8(); version = br.readU8();
if (br.readU8() !== 0) if (br.readU8() !== 0)
throw new Error('Address version padding is non-zero.'); throw new Error('Address version padding is non-zero.');
} else {
if (data.length !== 25)
throw new Error('Address is too long.');
} }
const hash = br.readBytes(br.left() - 4); const hash = br.readBytes(br.left() - 4);
br.verifyChecksum(); br.verifyChecksum();
return this.fromHash(hash, type, version, network); return this.fromHash(hash, type, version);
}; };
/** /**
@ -402,9 +390,9 @@ Address.prototype.fromBech32 = function fromBech32(data, network) {
const addr = bech32.decode(data); const addr = bech32.decode(data);
network = Network.fromBech32(addr.hrp, network); Network.fromBech32(addr.hrp, network);
return this.fromHash(addr.hash, type, addr.version, network); return this.fromHash(addr.hash, type, addr.version);
}; };
/** /**
@ -574,11 +562,10 @@ Address.fromScript = function fromScript(script) {
* @param {Buffer|Hash} hash * @param {Buffer|Hash} hash
* @param {AddressPrefix} type * @param {AddressPrefix} type
* @param {Number} [version=-1] * @param {Number} [version=-1]
* @param {(Network|NetworkType)?} network
* @throws on bad hash size * @throws on bad hash size
*/ */
Address.prototype.fromHash = function fromHash(hash, type, version, network) { Address.prototype.fromHash = function fromHash(hash, type, version) {
if (typeof hash === 'string') if (typeof hash === 'string')
hash = Buffer.from(hash, 'hex'); hash = Buffer.from(hash, 'hex');
@ -593,8 +580,6 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
if (version == null) if (version == null)
version = -1; version = -1;
network = Network.get(network);
assert(Buffer.isBuffer(hash)); assert(Buffer.isBuffer(hash));
assert(util.isU8(type)); assert(util.isU8(type));
assert(util.isI8(version)); assert(util.isI8(version));
@ -618,7 +603,6 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
this.hash = hash; this.hash = hash;
this.type = type; this.type = type;
this.version = version; this.version = version;
this.network = network;
return this; return this;
}; };
@ -628,113 +612,104 @@ Address.prototype.fromHash = function fromHash(hash, type, version, network) {
* @param {Hash} hash * @param {Hash} hash
* @param {AddressPrefix} type * @param {AddressPrefix} type
* @param {Number} [version=-1] * @param {Number} [version=-1]
* @param {(Network|NetworkType)?} network
* @returns {Address} * @returns {Address}
* @throws on bad hash size * @throws on bad hash size
*/ */
Address.fromHash = function fromHash(hash, type, version, network) { Address.fromHash = function fromHash(hash, type, version) {
return new Address().fromHash(hash, type, version, network); return new Address().fromHash(hash, type, version);
}; };
/** /**
* Inject properties from pubkeyhash. * Inject properties from pubkeyhash.
* @private * @private
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromPubkeyhash = function fromPubkeyhash(hash, network) { Address.prototype.fromPubkeyhash = function fromPubkeyhash(hash) {
const type = Address.types.PUBKEYHASH; const type = Address.types.PUBKEYHASH;
assert(hash.length === 20, 'P2PKH must be 20 bytes.'); assert(hash.length === 20, 'P2PKH must be 20 bytes.');
return this.fromHash(hash, type, -1, network); return this.fromHash(hash, type, -1);
}; };
/** /**
* Instantiate address from pubkeyhash. * Instantiate address from pubkeyhash.
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.fromPubkeyhash = function fromPubkeyhash(hash, network) { Address.fromPubkeyhash = function fromPubkeyhash(hash) {
return new Address().fromPubkeyhash(hash, network); return new Address().fromPubkeyhash(hash);
}; };
/** /**
* Inject properties from scripthash. * Inject properties from scripthash.
* @private * @private
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromScripthash = function fromScripthash(hash, network) { Address.prototype.fromScripthash = function fromScripthash(hash) {
const type = Address.types.SCRIPTHASH; const type = Address.types.SCRIPTHASH;
assert(hash && hash.length === 20, 'P2SH must be 20 bytes.'); assert(hash && hash.length === 20, 'P2SH must be 20 bytes.');
return this.fromHash(hash, type, -1, network); return this.fromHash(hash, type, -1);
}; };
/** /**
* Instantiate address from scripthash. * Instantiate address from scripthash.
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.fromScripthash = function fromScripthash(hash, network) { Address.fromScripthash = function fromScripthash(hash) {
return new Address().fromScripthash(hash, network); return new Address().fromScripthash(hash);
}; };
/** /**
* Inject properties from witness pubkeyhash. * Inject properties from witness pubkeyhash.
* @private * @private
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) { Address.prototype.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(hash && hash.length === 20, 'P2WPKH must be 20 bytes.'); assert(hash && hash.length === 20, 'P2WPKH must be 20 bytes.');
return this.fromHash(hash, type, 0, network); return this.fromHash(hash, type, 0);
}; };
/** /**
* Instantiate address from witness pubkeyhash. * Instantiate address from witness pubkeyhash.
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash, network) { Address.fromWitnessPubkeyhash = function fromWitnessPubkeyhash(hash) {
return new Address().fromWitnessPubkeyhash(hash, network); return new Address().fromWitnessPubkeyhash(hash);
}; };
/** /**
* Inject properties from witness scripthash. * Inject properties from witness scripthash.
* @private * @private
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash, network) { Address.prototype.fromWitnessScripthash = function fromWitnessScripthash(hash) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(hash && hash.length === 32, 'P2WPKH must be 32 bytes.'); assert(hash && hash.length === 32, 'P2WPKH must be 32 bytes.');
return this.fromHash(hash, type, 0, network); return this.fromHash(hash, type, 0);
}; };
/** /**
* Instantiate address from witness scripthash. * Instantiate address from witness scripthash.
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.fromWitnessScripthash = function fromWitnessScripthash(hash, network) { Address.fromWitnessScripthash = function fromWitnessScripthash(hash) {
return new Address().fromWitnessScripthash(hash, network); return new Address().fromWitnessScripthash(hash);
}; };
/** /**
@ -742,11 +717,10 @@ Address.fromWitnessScripthash = function fromWitnessScripthash(hash, network) {
* @private * @private
* @param {Number} version * @param {Number} version
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.prototype.fromProgram = function fromProgram(version, hash, network) { Address.prototype.fromProgram = function fromProgram(version, hash) {
const type = Address.types.WITNESS; const type = Address.types.WITNESS;
assert(version >= 0, 'Bad version for witness program.'); assert(version >= 0, 'Bad version for witness program.');
@ -754,19 +728,18 @@ Address.prototype.fromProgram = function fromProgram(version, hash, network) {
if (typeof hash === 'string') if (typeof hash === 'string')
hash = Buffer.from(hash, 'hex'); hash = Buffer.from(hash, 'hex');
return this.fromHash(hash, type, version, network); return this.fromHash(hash, type, version);
}; };
/** /**
* Instantiate address from witness program. * Instantiate address from witness program.
* @param {Number} version * @param {Number} version
* @param {Buffer} hash * @param {Buffer} hash
* @param {Network?} network
* @returns {Address} * @returns {Address}
*/ */
Address.fromProgram = function fromProgram(version, hash, network) { Address.fromProgram = function fromProgram(version, hash) {
return new Address().fromProgram(version, hash, network); return new Address().fromProgram(version, hash);
}; };
/** /**
@ -863,11 +836,6 @@ Address.getHash = function getHash(data, enc, network) {
hash = data; hash = data;
} else if (data instanceof Address) { } else if (data instanceof Address) {
hash = data.hash; hash = data.hash;
if (network) {
network = Network.get(network);
if (data.network !== network)
throw new Error('Network mismatch for address.');
}
} else { } else {
throw new Error('Object is not an address.'); throw new Error('Object is not an address.');
} }

View File

@ -24,14 +24,12 @@ const secp256k1 = require('../crypto/secp256k1');
* @alias module:primitives.KeyRing * @alias module:primitives.KeyRing
* @constructor * @constructor
* @param {Object} options * @param {Object} options
* @param {Network} network
*/ */
function KeyRing(options, network) { function KeyRing(options) {
if (!(this instanceof KeyRing)) if (!(this instanceof KeyRing))
return new KeyRing(options, network); return new KeyRing(options);
this.network = Network.primary;
this.witness = false; this.witness = false;
this.nested = false; this.nested = false;
this.publicKey = encoding.ZERO_KEY; this.publicKey = encoding.ZERO_KEY;
@ -48,7 +46,7 @@ function KeyRing(options, network) {
this._scriptAddress = null; this._scriptAddress = null;
if (options) if (options)
this.fromOptions(options, network); this.fromOptions(options);
} }
/** /**
@ -57,10 +55,7 @@ function KeyRing(options, network) {
* @param {Object} options * @param {Object} options
*/ */
KeyRing.prototype.fromOptions = function fromOptions(options, network) { KeyRing.prototype.fromOptions = function fromOptions(options) {
if (!network)
network = options.network;
let key = toKey(options); let key = toKey(options);
if (options.witness != null) { if (options.witness != null) {
@ -74,7 +69,7 @@ KeyRing.prototype.fromOptions = function fromOptions(options, network) {
} }
if (Buffer.isBuffer(key)) if (Buffer.isBuffer(key))
return this.fromKey(key, network); return this.fromKey(key);
key = toKey(options.key); key = toKey(options.key);
@ -88,9 +83,9 @@ KeyRing.prototype.fromOptions = function fromOptions(options, network) {
const compress = options.compressed; const compress = options.compressed;
if (script) if (script)
return this.fromScript(key, script, compress, network); return this.fromScript(key, script, compress);
return this.fromKey(key, compress, network); return this.fromKey(key, compress);
}; };
/** /**
@ -123,19 +118,12 @@ KeyRing.prototype.refresh = function refresh() {
* @private * @private
* @param {Buffer} key * @param {Buffer} key
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(NetworkType|Network)?} network
*/ */
KeyRing.prototype.fromPrivate = function fromPrivate(key, compress, network) { KeyRing.prototype.fromPrivate = function fromPrivate(key, compress) {
assert(Buffer.isBuffer(key), 'Private key must be a buffer.'); assert(Buffer.isBuffer(key), 'Private key must be a buffer.');
assert(secp256k1.privateKeyVerify(key), 'Not a valid private key.'); assert(secp256k1.privateKeyVerify(key), 'Not a valid private key.');
if (typeof compress !== 'boolean') {
network = compress;
compress = null;
}
this.network = Network.get(network);
this.privateKey = key; this.privateKey = key;
this.publicKey = secp256k1.publicKeyCreate(key, compress !== false); this.publicKey = secp256k1.publicKeyCreate(key, compress !== false);
@ -146,25 +134,22 @@ KeyRing.prototype.fromPrivate = function fromPrivate(key, compress, network) {
* Instantiate keyring from a private key. * Instantiate keyring from a private key.
* @param {Buffer} key * @param {Buffer} key
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(NetworkType|Network)?} network
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromPrivate = function fromPrivate(key, compress, network) { KeyRing.fromPrivate = function fromPrivate(key, compress) {
return new KeyRing().fromPrivate(key, compress, network); return new KeyRing().fromPrivate(key, compress);
}; };
/** /**
* Inject data from public key. * Inject data from public key.
* @private * @private
* @param {Buffer} key * @param {Buffer} key
* @param {(NetworkType|Network)?} network
*/ */
KeyRing.prototype.fromPublic = function fromPublic(key, network) { KeyRing.prototype.fromPublic = function fromPublic(key) {
assert(Buffer.isBuffer(key), 'Public key must be a buffer.'); assert(Buffer.isBuffer(key), 'Public key must be a buffer.');
assert(secp256k1.publicKeyVerify(key), 'Not a valid public key.'); assert(secp256k1.publicKeyVerify(key), 'Not a valid public key.');
this.network = Network.get(network);
this.publicKey = key; this.publicKey = key;
return this; return this;
}; };
@ -173,41 +158,32 @@ KeyRing.prototype.fromPublic = function fromPublic(key, network) {
* Generate a keyring. * Generate a keyring.
* @private * @private
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(Network|NetworkType)?} network
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.prototype.generate = function generate(compress, network) { KeyRing.prototype.generate = function generate(compress) {
if (typeof compress !== 'boolean') {
network = compress;
compress = null;
}
const key = secp256k1.generatePrivateKey(); const key = secp256k1.generatePrivateKey();
return this.fromKey(key, compress);
return this.fromKey(key, compress, network);
}; };
/** /**
* Generate a keyring. * Generate a keyring.
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(Network|NetworkType)?} network
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.generate = function generate(compress, network) { KeyRing.generate = function generate(compress) {
return new KeyRing().generate(compress, network); return new KeyRing().generate(compress);
}; };
/** /**
* Instantiate keyring from a public key. * Instantiate keyring from a public key.
* @param {Buffer} publicKey * @param {Buffer} publicKey
* @param {(NetworkType|Network)?} network
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromPublic = function fromPublic(key, network) { KeyRing.fromPublic = function fromPublic(key) {
return new KeyRing().fromPublic(key, network); return new KeyRing().fromPublic(key);
}; };
/** /**
@ -215,33 +191,26 @@ KeyRing.fromPublic = function fromPublic(key, network) {
* @private * @private
* @param {Buffer} privateKey * @param {Buffer} privateKey
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(NetworkType|Network)?} network
*/ */
KeyRing.prototype.fromKey = function fromKey(key, compress, network) { KeyRing.prototype.fromKey = function fromKey(key, compress) {
assert(Buffer.isBuffer(key), 'Key must be a buffer.'); assert(Buffer.isBuffer(key), 'Key must be a buffer.');
if (typeof compress !== 'boolean') {
network = compress;
compress = null;
}
if (key.length === 32) if (key.length === 32)
return this.fromPrivate(key, compress !== false, network); return this.fromPrivate(key, compress !== false);
return this.fromPublic(key, network); return this.fromPublic(key);
}; };
/** /**
* Instantiate keyring from a public key. * Instantiate keyring from a public key.
* @param {Buffer} publicKey * @param {Buffer} publicKey
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(NetworkType|Network)?} network
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromKey = function fromKey(key, compress, network) { KeyRing.fromKey = function fromKey(key, compress) {
return new KeyRing().fromKey(key, compress, network); return new KeyRing().fromKey(key, compress);
}; };
/** /**
@ -250,18 +219,12 @@ KeyRing.fromKey = function fromKey(key, compress, network) {
* @param {Buffer} key * @param {Buffer} key
* @param {Script} script * @param {Script} script
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(NetworkType|Network)?} network
*/ */
KeyRing.prototype.fromScript = function fromScript(key, script, compress, network) { KeyRing.prototype.fromScript = function fromScript(key, script, compress) {
assert(script instanceof Script, 'Non-script passed into KeyRing.'); assert(script instanceof Script, 'Non-script passed into KeyRing.');
if (typeof compress !== 'boolean') { this.fromKey(key, compress);
network = compress;
compress = null;
}
this.fromKey(key, compress, network);
this.script = script; this.script = script;
return this; return this;
@ -272,12 +235,11 @@ KeyRing.prototype.fromScript = function fromScript(key, script, compress, networ
* @param {Buffer} key * @param {Buffer} key
* @param {Script} script * @param {Script} script
* @param {Boolean?} compress * @param {Boolean?} compress
* @param {(NetworkType|Network)?} network
* @returns {KeyRing} * @returns {KeyRing}
*/ */
KeyRing.fromScript = function fromScript(key, script, compress, network) { KeyRing.fromScript = function fromScript(key, script, compress) {
return new KeyRing().fromScript(key, script, compress, network); return new KeyRing().fromScript(key, script, compress);
}; };
/** /**
@ -311,9 +273,6 @@ KeyRing.prototype.toSecret = function toSecret(network) {
assert(this.privateKey, 'Cannot serialize without private key.'); assert(this.privateKey, 'Cannot serialize without private key.');
if (!network)
network = this.network;
network = Network.get(network); network = Network.get(network);
bw.writeU8(network.keyPrefix.privkey); bw.writeU8(network.keyPrefix.privkey);
@ -339,7 +298,7 @@ KeyRing.prototype.fromSecret = function fromSecret(data, network) {
const version = br.readU8(); const version = br.readU8();
network = Network.fromWIF(version, network); Network.fromWIF(version, network);
const key = br.readBytes(32); const key = br.readBytes(32);
@ -352,7 +311,7 @@ KeyRing.prototype.fromSecret = function fromSecret(data, network) {
br.verifyChecksum(); br.verifyChecksum();
return this.fromPrivate(key, compress, network); return this.fromPrivate(key, compress);
}; };
/** /**
@ -372,12 +331,12 @@ KeyRing.fromSecret = function fromSecret(data, network) {
* @returns {Buffer} Private key. * @returns {Buffer} Private key.
*/ */
KeyRing.prototype.getPrivateKey = function getPrivateKey(enc) { KeyRing.prototype.getPrivateKey = function getPrivateKey(enc, network) {
if (!this.privateKey) if (!this.privateKey)
return null; return null;
if (enc === 'base58') if (enc === 'base58')
return this.toSecret(); return this.toSecret(network);
if (enc === 'hex') if (enc === 'hex')
return this.privateKey.toString('hex'); return this.privateKey.toString('hex');
@ -459,21 +418,21 @@ KeyRing.prototype.getNestedHash = function getNestedHash(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getNestedAddress = function getNestedAddress(enc) { KeyRing.prototype.getNestedAddress = function getNestedAddress(enc, network) {
if (!this.witness) if (!this.witness)
return null; return null;
if (!this._nestedAddress) { if (!this._nestedAddress) {
const hash = this.getNestedHash(); const hash = this.getNestedHash();
const addr = Address.fromScripthash(hash, this.network); const addr = Address.fromScripthash(hash);
this._nestedAddress = addr; this._nestedAddress = addr;
} }
if (enc === 'base58') if (enc === 'base58')
return this._nestedAddress.toBase58(); return this._nestedAddress.toBase58(network);
if (enc === 'string') if (enc === 'string')
return this._nestedAddress.toString(); return this._nestedAddress.toString(network);
return this._nestedAddress; return this._nestedAddress;
}; };
@ -532,7 +491,7 @@ KeyRing.prototype.getScriptHash256 = function getScriptHash256(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) { KeyRing.prototype.getScriptAddress = function getScriptAddress(enc, network) {
if (!this.script) if (!this.script)
return null; return null;
@ -540,19 +499,19 @@ KeyRing.prototype.getScriptAddress = function getScriptAddress(enc) {
let addr; let addr;
if (this.witness) { if (this.witness) {
const hash = this.getScriptHash256(); const hash = this.getScriptHash256();
addr = Address.fromWitnessScripthash(hash, this.network); addr = Address.fromWitnessScripthash(hash);
} else { } else {
const hash = this.getScriptHash160(); const hash = this.getScriptHash160();
addr = Address.fromScripthash(hash, this.network); addr = Address.fromScripthash(hash);
} }
this._scriptAddress = addr; this._scriptAddress = addr;
} }
if (enc === 'base58') if (enc === 'base58')
return this._scriptAddress.toBase58(); return this._scriptAddress.toBase58(network);
if (enc === 'string') if (enc === 'string')
return this._scriptAddress.toString(); return this._scriptAddress.toString(network);
return this._scriptAddress; return this._scriptAddress;
}; };
@ -578,24 +537,24 @@ KeyRing.prototype.getKeyHash = function getKeyHash(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getKeyAddress = function getKeyAddress(enc) { KeyRing.prototype.getKeyAddress = function getKeyAddress(enc, network) {
if (!this._keyAddress) { if (!this._keyAddress) {
const hash = this.getKeyHash(); const hash = this.getKeyHash();
let addr; let addr;
if (this.witness) if (this.witness)
addr = Address.fromWitnessPubkeyhash(hash, this.network); addr = Address.fromWitnessPubkeyhash(hash);
else else
addr = Address.fromPubkeyhash(hash, this.network); addr = Address.fromPubkeyhash(hash);
this._keyAddress = addr; this._keyAddress = addr;
} }
if (enc === 'base58') if (enc === 'base58')
return this._keyAddress.toBase58(); return this._keyAddress.toBase58(network);
if (enc === 'string') if (enc === 'string')
return this._keyAddress.toString(); return this._keyAddress.toString(network);
return this._keyAddress; return this._keyAddress;
}; };
@ -622,14 +581,14 @@ KeyRing.prototype.getHash = function getHash(enc) {
* @returns {Address|Base58Address} * @returns {Address|Base58Address}
*/ */
KeyRing.prototype.getAddress = function getAddress(enc) { KeyRing.prototype.getAddress = function getAddress(enc, network) {
if (this.nested) if (this.nested)
return this.getNestedAddress(enc); return this.getNestedAddress(enc, network);
if (this.script) if (this.script)
return this.getScriptAddress(enc); return this.getScriptAddress(enc, network);
return this.getKeyAddress(enc); return this.getKeyAddress(enc, network);
}; };
/** /**
@ -771,16 +730,15 @@ KeyRing.prototype.inspect = function inspect() {
* @returns {Object} * @returns {Object}
*/ */
KeyRing.prototype.toJSON = function toJSON() { KeyRing.prototype.toJSON = function toJSON(network) {
return { return {
network: this.network.type,
witness: this.witness, witness: this.witness,
nested: this.nested, nested: this.nested,
publicKey: this.publicKey.toString('hex'), publicKey: this.publicKey.toString('hex'),
script: this.script ? this.script.toRaw().toString('hex') : null, script: this.script ? this.script.toRaw().toString('hex') : null,
program: this.witness ? this.getProgram().toRaw().toString('hex') : null, program: this.witness ? this.getProgram().toRaw().toString('hex') : null,
type: Address.typesByVal[this.getType()].toLowerCase(), type: Address.typesByVal[this.getType()].toLowerCase(),
address: this.getAddress('string') address: this.getAddress('string', network)
}; };
}; };
@ -792,13 +750,11 @@ KeyRing.prototype.toJSON = function toJSON() {
KeyRing.prototype.fromJSON = function fromJSON(json) { KeyRing.prototype.fromJSON = function fromJSON(json) {
assert(json); assert(json);
assert(typeof json.network === 'string');
assert(typeof json.witness === 'boolean'); assert(typeof json.witness === 'boolean');
assert(typeof json.nested === 'boolean'); assert(typeof json.nested === 'boolean');
assert(typeof json.publicKey === 'string'); assert(typeof json.publicKey === 'string');
assert(!json.script || typeof json.script === 'string'); assert(!json.script || typeof json.script === 'string');
this.nework = Network.get(json.network);
this.witness = json.witness; this.witness = json.witness;
this.nested = json.nested; this.nested = json.nested;
this.publicKey = Buffer.from(json.publicKey, 'hex'); this.publicKey = Buffer.from(json.publicKey, 'hex');
@ -882,12 +838,9 @@ KeyRing.prototype.toRaw = function toRaw() {
* Inject properties from buffer reader. * Inject properties from buffer reader.
* @private * @private
* @param {BufferReader} br * @param {BufferReader} br
* @param {Network?} network
*/ */
KeyRing.prototype.fromReader = function fromReader(br, network) { KeyRing.prototype.fromReader = function fromReader(br) {
this.network = Network.get(network);
const field = br.readU8(); const field = br.readU8();
this.witness = (field & 1) !== 0; this.witness = (field & 1) !== 0;
@ -916,11 +869,10 @@ KeyRing.prototype.fromReader = function fromReader(br, network) {
* Inject properties from serialized data. * Inject properties from serialized data.
* @private * @private
* @param {Buffer} data * @param {Buffer} data
* @param {Network?} network
*/ */
KeyRing.prototype.fromRaw = function fromRaw(data, network) { KeyRing.prototype.fromRaw = function fromRaw(data) {
return this.fromReader(new BufferReader(data), network); return this.fromReader(new BufferReader(data));
}; };
/** /**

View File

@ -250,9 +250,6 @@ Account.prototype.pushKey = function pushKey(key) {
if (typeof key === 'string') if (typeof key === 'string')
key = HD.PublicKey.fromBase58(key, this.network); key = HD.PublicKey.fromBase58(key, this.network);
assert(key.network === this.network,
'Network mismatch for account key.');
if (!HD.isPublic(key)) if (!HD.isPublic(key))
throw new Error('Must add HD keys to wallet.'); throw new Error('Must add HD keys to wallet.');
@ -290,9 +287,6 @@ Account.prototype.spliceKey = function spliceKey(key) {
if (typeof key === 'string') if (typeof key === 'string')
key = HD.PublicKey.fromBase58(key, this.network); key = HD.PublicKey.fromBase58(key, this.network);
assert(key.network === this.network,
'Network mismatch for account key.');
if (!HD.isPublic(key)) if (!HD.isPublic(key))
throw new Error('Must add HD keys to wallet.'); throw new Error('Must add HD keys to wallet.');
@ -404,21 +398,21 @@ Account.prototype.createKey = async function createKey(b, branch) {
key = this.deriveReceive(this.receiveDepth); key = this.deriveReceive(this.receiveDepth);
lookahead = this.deriveReceive(this.receiveDepth + this.lookahead); lookahead = this.deriveReceive(this.receiveDepth + this.lookahead);
await this.saveKey(b, lookahead); await this.saveKey(b, lookahead);
this.receiveDepth++; this.receiveDepth += 1;
this.receive = key; this.receive = key;
break; break;
case 1: case 1:
key = this.deriveChange(this.changeDepth); key = this.deriveChange(this.changeDepth);
lookahead = this.deriveReceive(this.changeDepth + this.lookahead); lookahead = this.deriveReceive(this.changeDepth + this.lookahead);
await this.saveKey(b, lookahead); await this.saveKey(b, lookahead);
this.changeDepth++; this.changeDepth += 1;
this.change = key; this.change = key;
break; break;
case 2: case 2:
key = this.deriveNested(this.nestedDepth); key = this.deriveNested(this.nestedDepth);
lookahead = this.deriveNested(this.nestedDepth + this.lookahead); lookahead = this.deriveNested(this.nestedDepth + this.lookahead);
await this.saveKey(b, lookahead); await this.saveKey(b, lookahead);
this.nestedDepth++; this.nestedDepth += 1;
this.nested = key; this.nested = key;
break; break;
default: default:
@ -511,7 +505,8 @@ Account.prototype.deriveKey = function deriveKey(branch, index, master) {
let key; let key;
if (master && master.key && !this.watchOnly) { if (master && master.key && !this.watchOnly) {
key = master.key.deriveAccount(44, this.accountIndex); const type = this.network.keyPrefix.coinType;
key = master.key.deriveAccount(44, type, this.accountIndex);
key = key.derive(branch).derive(index); key = key.derive(branch).derive(index);
} else { } else {
key = this.accountKey.derive(branch).derive(index); key = this.accountKey.derive(branch).derive(index);
@ -577,22 +572,16 @@ Account.prototype.initDepth = async function initDepth(b) {
// Receive Address // Receive Address
this.receiveDepth = 1; this.receiveDepth = 1;
await this.saveKey(b, this.deriveReceive(0)); for (let i = 0; i <= this.lookahead; i++) {
const key = this.deriveReceive(i);
// Lookahead
for (let i = 0; i < this.lookahead; i++) {
const key = this.deriveReceive(i + 1);
await this.saveKey(b, key); await this.saveKey(b, key);
} }
// Change Address // Change Address
this.changeDepth = 1; this.changeDepth = 1;
await this.saveKey(b, this.deriveChange(0)); for (let i = 0; i <= this.lookahead; i++) {
const key = this.deriveChange(i);
// Lookahead
for (let i = 0; i < this.lookahead; i++) {
const key = this.deriveChange(i + 1);
await this.saveKey(b, key); await this.saveKey(b, key);
} }
@ -600,11 +589,8 @@ Account.prototype.initDepth = async function initDepth(b) {
if (this.witness) { if (this.witness) {
this.nestedDepth = 1; this.nestedDepth = 1;
await this.saveKey(b, this.deriveNested(0)); for (let i = 0; i <= this.lookahead; i++) {
const key = this.deriveNested(i);
// Lookahead
for (let i = 0; i < this.lookahead; i++) {
const key = this.deriveNested(i + 1);
await this.saveKey(b, key); await this.saveKey(b, key);
} }
} }
@ -634,7 +620,6 @@ Account.prototype.syncDepth = async function syncDepth(b, receive, change, neste
await this.saveKey(b, key); await this.saveKey(b, key);
} }
this.receive = this.deriveReceive(receive - 1);
this.receiveDepth = receive; this.receiveDepth = receive;
derived = true; derived = true;
@ -651,7 +636,6 @@ Account.prototype.syncDepth = async function syncDepth(b, receive, change, neste
await this.saveKey(b, key); await this.saveKey(b, key);
} }
this.change = this.deriveChange(change - 1);
this.changeDepth = change; this.changeDepth = change;
derived = true; derived = true;
@ -667,7 +651,6 @@ Account.prototype.syncDepth = async function syncDepth(b, receive, change, neste
await this.saveKey(b, key); await this.saveKey(b, key);
} }
this.nested = this.deriveNested(nested - 1);
this.nestedDepth = nested; this.nestedDepth = nested;
derived = true; derived = true;
@ -694,7 +677,6 @@ Account.prototype.setLookahead = async function setLookahead(b, lookahead) {
const diff = this.lookahead - lookahead; const diff = this.lookahead - lookahead;
this.receiveDepth += diff; this.receiveDepth += diff;
this.changeDepth += diff; this.changeDepth += diff;
if (this.witness) if (this.witness)
@ -828,10 +810,14 @@ Account.prototype.nestedAddress = function nestedAddress() {
*/ */
Account.prototype.inspect = function inspect() { Account.prototype.inspect = function inspect() {
const receive = this.receiveAddress();
const change = this.changeAddress();
const nested = this.nestedAddress();
return { return {
wid: this.wid, wid: this.wid,
name: this.name, name: this.name,
network: this.network, network: this.network.type,
initialized: this.initialized, initialized: this.initialized,
witness: this.witness, witness: this.witness,
watchOnly: this.watchOnly, watchOnly: this.watchOnly,
@ -843,11 +829,11 @@ Account.prototype.inspect = function inspect() {
changeDepth: this.changeDepth, changeDepth: this.changeDepth,
nestedDepth: this.nestedDepth, nestedDepth: this.nestedDepth,
lookahead: this.lookahead, lookahead: this.lookahead,
receiveAddress: this.receiveAddress(), receiveAddress: receive ? receive.toString(this.network) : null,
changeAddress: this.changeAddress(), changeAddress: change ? change.toString(this.network) : null,
nestedAddress: this.nestedAddress(), nestedAddress: nested ? nested.toString(this.network) : null,
accountKey: this.accountKey.toBase58(), accountKey: this.accountKey.toBase58(this.network),
keys: this.keys.map(key => key.toBase58()) keys: this.keys.map(key => key.toBase58(this.network))
}; };
}; };
@ -877,11 +863,11 @@ Account.prototype.toJSON = function toJSON(minimal, balance) {
changeDepth: this.changeDepth, changeDepth: this.changeDepth,
nestedDepth: this.nestedDepth, nestedDepth: this.nestedDepth,
lookahead: this.lookahead, lookahead: this.lookahead,
receiveAddress: receive ? receive.toString() : null, receiveAddress: receive ? receive.toString(this.network) : null,
changeAddress: change ? change.toString() : null, changeAddress: change ? change.toString(this.network) : null,
nestedAddress: nested ? nested.toString() : null, nestedAddress: nested ? nested.toString(this.network) : null,
accountKey: this.accountKey.toBase58(), accountKey: this.accountKey.toBase58(this.network),
keys: this.keys.map(key => key.toBase58()), keys: this.keys.map(key => key.toBase58(this.network)),
balance: balance ? balance.toJSON(true) : null balance: balance ? balance.toJSON(true) : null
}; };
}; };
@ -919,11 +905,11 @@ Account.prototype.toRaw = function toRaw() {
bw.writeU32(this.changeDepth); bw.writeU32(this.changeDepth);
bw.writeU32(this.nestedDepth); bw.writeU32(this.nestedDepth);
bw.writeU8(this.lookahead); bw.writeU8(this.lookahead);
bw.writeBytes(this.accountKey.toRaw()); bw.writeBytes(this.accountKey.toRaw(this.network));
bw.writeU8(this.keys.length); bw.writeU8(this.keys.length);
for (const key of this.keys) for (const key of this.keys)
bw.writeBytes(key.toRaw()); bw.writeBytes(key.toRaw(this.network));
return bw.render(); return bw.render();
}; };
@ -949,14 +935,14 @@ Account.prototype.fromRaw = function fromRaw(data) {
this.changeDepth = br.readU32(); this.changeDepth = br.readU32();
this.nestedDepth = br.readU32(); this.nestedDepth = br.readU32();
this.lookahead = br.readU8(); this.lookahead = br.readU8();
this.accountKey = HD.PublicKey.fromRaw(br.readBytes(82)); this.accountKey = HD.PublicKey.fromRaw(br.readBytes(82), this.network);
assert(Account.typesByVal[this.type]); assert(Account.typesByVal[this.type]);
const count = br.readU8(); const count = br.readU8();
for (let i = 0; i < count; i++) { for (let i = 0; i < count; i++) {
const key = HD.PublicKey.fromRaw(br.readBytes(82)); const key = HD.PublicKey.fromRaw(br.readBytes(82), this.network);
this.pushKey(key); this.pushKey(key);
} }

View File

@ -572,7 +572,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
return; return;
} }
res.send(200, key.toJSON()); res.send(200, key.toJSON(this.network));
}); });
// Get private key // Get private key
@ -590,7 +590,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
return; return;
} }
res.send(200, { privateKey: key.toSecret() }); res.send(200, { privateKey: key.toSecret(this.network) });
}); });
// Create address // Create address
@ -599,7 +599,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
const acct = valid.str('account'); const acct = valid.str('account');
const address = await req.wallet.createReceive(acct); const address = await req.wallet.createReceive(acct);
res.send(200, address.toJSON()); res.send(200, address.toJSON(this.network));
}); });
// Create change address // Create change address
@ -608,7 +608,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
const acct = valid.str('account'); const acct = valid.str('account');
const address = await req.wallet.createChange(acct); const address = await req.wallet.createChange(acct);
res.send(200, address.toJSON()); res.send(200, address.toJSON(this.network));
}); });
// Create nested address // Create nested address
@ -617,7 +617,7 @@ HTTPServer.prototype.initRouter = function initRouter() {
const acct = valid.str('account'); const acct = valid.str('account');
const address = await req.wallet.createNested(acct); const address = await req.wallet.createNested(acct);
res.send(200, address.toJSON()); res.send(200, address.toJSON(this.network));
}); });
// Wallet Balance // Wallet Balance
@ -851,7 +851,7 @@ HTTPServer.prototype.initSockets = function initSockets() {
const json = []; const json = [];
for (const addr of receive) for (const addr of receive)
json.push(addr.toJSON()); json.push(addr.toJSON(this.network));
this.to(`w:${w.id}`, 'wallet address', json); this.to(`w:${w.id}`, 'wallet address', json);
}); });

View File

@ -7,6 +7,7 @@
'use strict'; 'use strict';
const assert = require('assert'); const assert = require('assert');
const Network = require('../protocol/network');
const util = require('../utils/util'); const util = require('../utils/util');
const Lock = require('../utils/lock'); const Lock = require('../utils/lock');
const random = require('../crypto/random'); const random = require('../crypto/random');
@ -92,6 +93,9 @@ MasterKey.algByVal = {
MasterKey.prototype.fromOptions = function fromOptions(options) { MasterKey.prototype.fromOptions = function fromOptions(options) {
assert(options); assert(options);
if (options.network != null)
this.network = Network.get(options.network);
if (options.encrypted != null) { if (options.encrypted != null) {
assert(typeof options.encrypted === 'boolean'); assert(typeof options.encrypted === 'boolean');
this.encrypted = options.encrypted; this.encrypted = options.encrypted;
@ -203,7 +207,7 @@ MasterKey.prototype._unlock = async function _unlock(passphrase, timeout) {
const key = await this.derive(passphrase); const key = await this.derive(passphrase);
const data = aes.decipher(this.ciphertext, key, this.iv); const data = aes.decipher(this.ciphertext, key, this.iv);
this.fromKeyRaw(data); this.readKey(data);
this.start(timeout); this.start(timeout);
@ -388,7 +392,7 @@ MasterKey.prototype._decrypt = async function _decrypt(passphrase, clean) {
const key = await this.derive(passphrase); const key = await this.derive(passphrase);
const data = aes.decipher(this.ciphertext, key, this.iv); const data = aes.decipher(this.ciphertext, key, this.iv);
this.fromKeyRaw(data); this.readKey(data);
this.encrypted = false; this.encrypted = false;
this.iv = null; this.iv = null;
this.ciphertext = null; this.ciphertext = null;
@ -430,7 +434,7 @@ MasterKey.prototype._encrypt = async function _encrypt(passphrase, clean) {
if (!passphrase) if (!passphrase)
throw new Error('No passphrase provided.'); throw new Error('No passphrase provided.');
const raw = this.toKeyRaw(); const raw = this.writeKey();
const iv = random.randomBytes(16); const iv = random.randomBytes(16);
this.stop(); this.stop();
@ -457,7 +461,7 @@ MasterKey.prototype._encrypt = async function _encrypt(passphrase, clean) {
* @returns {Number} * @returns {Number}
*/ */
MasterKey.prototype.getKeySize = function getKeySize() { MasterKey.prototype.keySize = function keySize() {
let size = 0; let size = 0;
size += this.key.getSize(); size += this.key.getSize();
@ -474,10 +478,10 @@ MasterKey.prototype.getKeySize = function getKeySize() {
* @returns {Buffer} * @returns {Buffer}
*/ */
MasterKey.prototype.toKeyRaw = function toKeyRaw() { MasterKey.prototype.writeKey = function writeKey() {
const bw = new StaticWriter(this.getKeySize()); const bw = new StaticWriter(this.keySize());
this.key.toWriter(bw); this.key.toWriter(bw, this.network);
if (this.mnemonic) { if (this.mnemonic) {
bw.writeU8(1); bw.writeU8(1);
@ -494,10 +498,10 @@ MasterKey.prototype.toKeyRaw = function toKeyRaw() {
* @param {Buffer} data * @param {Buffer} data
*/ */
MasterKey.prototype.fromKeyRaw = function fromKeyRaw(data) { MasterKey.prototype.readKey = function readKey(data) {
const br = new BufferReader(data); const br = new BufferReader(data);
this.key = HD.PrivateKey.fromReader(br); this.key = HD.PrivateKey.fromReader(br, this.network);
if (br.readU8() === 1) if (br.readU8() === 1)
this.mnemonic = Mnemonic.fromReader(br); this.mnemonic = Mnemonic.fromReader(br);
@ -522,7 +526,7 @@ MasterKey.prototype.getSize = function getSize() {
} }
size += 1; size += 1;
size += encoding.sizeVarlen(this.getKeySize()); size += encoding.sizeVarlen(this.keySize());
return size; return size;
}; };
@ -552,10 +556,10 @@ MasterKey.prototype.toRaw = function toRaw() {
bw.writeU8(0); bw.writeU8(0);
// NOTE: useless varint // NOTE: useless varint
const size = this.getKeySize(); const size = this.keySize();
bw.writeVarint(size); bw.writeVarint(size);
bw.writeBytes(this.key.toRaw()); bw.writeBytes(this.key.toRaw(this.network));
if (this.mnemonic) { if (this.mnemonic) {
bw.writeU8(1); bw.writeU8(1);
@ -573,9 +577,10 @@ MasterKey.prototype.toRaw = function toRaw() {
* @param {Buffer} raw * @param {Buffer} raw
*/ */
MasterKey.prototype.fromRaw = function fromRaw(raw) { MasterKey.prototype.fromRaw = function fromRaw(raw, network) {
const br = new BufferReader(raw); const br = new BufferReader(raw);
this.network = Network.get(network);
this.encrypted = br.readU8() === 1; this.encrypted = br.readU8() === 1;
if (this.encrypted) { if (this.encrypted) {
@ -596,7 +601,7 @@ MasterKey.prototype.fromRaw = function fromRaw(raw) {
// NOTE: useless varint // NOTE: useless varint
br.readVarint(); br.readVarint();
this.key = HD.PrivateKey.fromRaw(br.readBytes(82)); this.key = HD.PrivateKey.fromRaw(br.readBytes(82), this.network);
if (br.readU8() === 1) if (br.readU8() === 1)
this.mnemonic = Mnemonic.fromReader(br); this.mnemonic = Mnemonic.fromReader(br);
@ -609,8 +614,8 @@ MasterKey.prototype.fromRaw = function fromRaw(raw) {
* @returns {MasterKey} * @returns {MasterKey}
*/ */
MasterKey.fromRaw = function fromRaw(raw) { MasterKey.fromRaw = function fromRaw(raw, network) {
return new MasterKey().fromRaw(raw); return new MasterKey().fromRaw(raw, network);
}; };
/** /**
@ -620,12 +625,13 @@ MasterKey.fromRaw = function fromRaw(raw) {
* @param {Mnemonic?} mnemonic * @param {Mnemonic?} mnemonic
*/ */
MasterKey.prototype.fromKey = function fromKey(key, mnemonic) { MasterKey.prototype.fromKey = function fromKey(key, mnemonic, network) {
this.encrypted = false; this.encrypted = false;
this.iv = null; this.iv = null;
this.ciphertext = null; this.ciphertext = null;
this.key = key; this.key = key;
this.mnemonic = mnemonic || null; this.mnemonic = mnemonic || null;
this.network = Network.get(network);
return this; return this;
}; };
@ -636,8 +642,8 @@ MasterKey.prototype.fromKey = function fromKey(key, mnemonic) {
* @returns {MasterKey} * @returns {MasterKey}
*/ */
MasterKey.fromKey = function fromKey(key, mnemonic) { MasterKey.fromKey = function fromKey(key, mnemonic, network) {
return new MasterKey().fromKey(key, mnemonic); return new MasterKey().fromKey(key, mnemonic, network);
}; };
/** /**
@ -663,7 +669,7 @@ MasterKey.prototype.toJSON = function toJSON(unsafe) {
return { return {
encrypted: false, encrypted: false,
key: unsafe ? this.key.toJSON() : undefined, key: unsafe ? this.key.toJSON(this.network) : undefined,
mnemonic: unsafe && this.mnemonic ? this.mnemonic.toJSON() : undefined mnemonic: unsafe && this.mnemonic ? this.mnemonic.toJSON() : undefined
}; };
}; };
@ -677,7 +683,7 @@ MasterKey.prototype.inspect = function inspect() {
const json = this.toJSON(true); const json = this.toJSON(true);
if (this.key) if (this.key)
json.key = this.key.toJSON(); json.key = this.key.toJSON(this.network);
if (this.mnemonic) if (this.mnemonic)
json.mnemonic = this.mnemonic.toJSON(); json.mnemonic = this.mnemonic.toJSON();

View File

@ -277,8 +277,8 @@ Path.prototype.toPath = function toPath() {
* @returns {Address} * @returns {Address}
*/ */
Path.prototype.toAddress = function toAddress(network) { Path.prototype.toAddress = function toAddress() {
return Address.fromHash(this.hash, this.type, this.version, network); return Address.fromHash(this.hash, this.type, this.version);
}; };
/** /**

View File

@ -238,7 +238,7 @@ RPC.prototype.dumpPrivKey = async function dumpPrivKey(args, help) {
if (!ring) if (!ring)
throw new RPCError(errs.MISC_ERROR, 'Key not found.'); throw new RPCError(errs.MISC_ERROR, 'Key not found.');
return ring.toSecret(); return ring.toSecret(this.network);
}; };
RPC.prototype.dumpWallet = async function dumpWallet(args, help) { RPC.prototype.dumpWallet = async function dumpWallet(args, help) {
@ -279,7 +279,7 @@ RPC.prototype.dumpWallet = async function dumpWallet(args, help) {
if (ring.branch === 1) if (ring.branch === 1)
fmt = '%s %s change=1 addr=%s'; fmt = '%s %s change=1 addr=%s';
const str = util.fmt(fmt, ring.toSecret(), time, addr); const str = util.fmt(fmt, ring.toSecret(this.network), time, addr);
out.push(str); out.push(str);
} }

View File

@ -2137,6 +2137,11 @@ Balance.prototype.applyTo = function applyTo(balance) {
balance.coin += this.coin; balance.coin += this.coin;
balance.unconfirmed += this.unconfirmed; balance.unconfirmed += this.unconfirmed;
balance.confirmed += this.confirmed; balance.confirmed += this.confirmed;
assert(balance.tx >= 0);
assert(balance.coin >= 0);
assert(balance.unconfirmed >= 0);
assert(balance.confirmed >= 0);
}; };
/** /**
@ -2204,7 +2209,6 @@ Balance.prototype.toJSON = function toJSON(minimal) {
*/ */
Balance.prototype.inspect = function inspect() { Balance.prototype.inspect = function inspect() {
return this;
return '<Balance' return '<Balance'
+ ` tx=${this.tx}` + ` tx=${this.tx}`
+ ` coin=${this.coin}` + ` coin=${this.coin}`

View File

@ -109,13 +109,10 @@ Wallet.prototype.fromOptions = function fromOptions(options) {
'Must create wallet with hd private key.'); 'Must create wallet with hd private key.');
} else { } else {
mnemonic = new Mnemonic(options.mnemonic); mnemonic = new Mnemonic(options.mnemonic);
key = HD.fromMnemonic(mnemonic, this.network); key = HD.fromMnemonic(mnemonic);
} }
assert(key.network === this.network, this.master.fromKey(key, mnemonic, this.network);
'Network mismatch for master key.');
this.master.fromKey(key, mnemonic);
if (options.wid != null) { if (options.wid != null) {
assert(util.isU32(options.wid)); assert(util.isU32(options.wid));
@ -616,12 +613,10 @@ Wallet.prototype._createAccount = async function _createAccount(options, passphr
if (!HD.isPublic(key)) if (!HD.isPublic(key))
throw new Error('Must add HD public keys to watch only wallet.'); throw new Error('Must add HD public keys to watch only wallet.');
assert(key.network === this.network,
'Network mismatch for watch only key.');
} else { } else {
assert(this.master.key); assert(this.master.key);
key = this.master.key.deriveAccount(44, this.accountDepth); const type = this.network.keyPrefix.coinType;
key = this.master.key.deriveAccount(44, type, this.accountDepth);
key = key.toPublic(); key = key.toPublic();
} }
@ -1006,9 +1001,6 @@ Wallet.prototype.importKey = async function importKey(acct, ring, passphrase) {
*/ */
Wallet.prototype._importKey = async function _importKey(acct, ring, passphrase) { Wallet.prototype._importKey = async function _importKey(acct, ring, passphrase) {
assert(ring.network === this.network,
'Network mismatch for key.');
if (!this.watchOnly) { if (!this.watchOnly) {
if (!ring.privateKey) if (!ring.privateKey)
throw new Error('Cannot import pubkey into non watch-only wallet.'); throw new Error('Cannot import pubkey into non watch-only wallet.');
@ -1074,9 +1066,6 @@ Wallet.prototype.importAddress = async function importAddress(acct, address) {
*/ */
Wallet.prototype._importAddress = async function _importAddress(acct, address) { Wallet.prototype._importAddress = async function _importAddress(acct, address) {
assert(address.network === this.network,
'Network mismatch for address.');
if (!this.watchOnly) if (!this.watchOnly)
throw new Error('Cannot import address into non watch-only wallet.'); throw new Error('Cannot import address into non watch-only wallet.');
@ -1885,7 +1874,7 @@ Wallet.prototype._add = async function _add(tx, block) {
if (details) { if (details) {
const derived = await this.syncOutputDepth(tx); const derived = await this.syncOutputDepth(tx);
if (derived.length > 0) { if (derived.length > 0) {
this.wdb.emit('address', this.id, derived); this.wdb.emit('address', this, derived);
this.emit('address', derived); this.emit('address', derived);
} }
} }
@ -2350,6 +2339,8 @@ Wallet.prototype.fromRaw = function fromRaw(data) {
const br = new BufferReader(data); const br = new BufferReader(data);
const network = Network.fromMagic(br.readU32()); const network = Network.fromMagic(br.readU32());
assert(network === this.network, 'Wallet network mismatch.');
this.wid = br.readU32(); this.wid = br.readU32();
this.id = br.readVarString('ascii'); this.id = br.readVarString('ascii');
this.initialized = br.readU8() === 1; this.initialized = br.readU8() === 1;
@ -2357,9 +2348,7 @@ Wallet.prototype.fromRaw = function fromRaw(data) {
this.accountDepth = br.readU32(); this.accountDepth = br.readU32();
this.token = br.readBytes(32); this.token = br.readBytes(32);
this.tokenDepth = br.readU32(); this.tokenDepth = br.readU32();
this.master.fromRaw(br.readVarBytes()); this.master.fromRaw(br.readVarBytes(), this.network);
assert(network === this.wdb.network, 'Wallet network mismatch.');
return this; return this;
}; };

View File

@ -18,11 +18,11 @@ const Path = require('./path');
* @param {Object} options * @param {Object} options
*/ */
function WalletKey(options, network) { function WalletKey(options) {
if (!(this instanceof WalletKey)) if (!(this instanceof WalletKey))
return new WalletKey(options, network); return new WalletKey(options);
KeyRing.call(this, options, network); KeyRing.call(this, options);
this.keyType = Path.types.HD; this.keyType = Path.types.HD;
@ -48,56 +48,52 @@ WalletKey.fromOptions = function fromOptions(options) {
* Instantiate wallet key from a private key. * Instantiate wallet key from a private key.
* @param {Buffer} key * @param {Buffer} key
* @param {Boolean?} compressed * @param {Boolean?} compressed
* @param {(NetworkType|Network)} network
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromPrivate = function fromPrivate(key, compressed, network) { WalletKey.fromPrivate = function fromPrivate(key, compressed) {
return new WalletKey().fromPrivate(key, compressed, network); return new WalletKey().fromPrivate(key, compressed);
}; };
/** /**
* Generate a wallet key. * Generate a wallet key.
* @param {(Network|NetworkType)?} network * @param {Boolean?} compressed
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.generate = function generate(compressed, network) { WalletKey.generate = function generate(compressed) {
return new WalletKey().generate(compressed, network); return new WalletKey().generate(compressed);
}; };
/** /**
* Instantiate wallet key from a public key. * Instantiate wallet key from a public key.
* @param {Buffer} publicKey * @param {Buffer} publicKey
* @param {(NetworkType|Network)} network
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromPublic = function fromPublic(key, network) { WalletKey.fromPublic = function fromPublic(key) {
return new WalletKey().fromPublic(key, network); return new WalletKey().fromPublic(key);
}; };
/** /**
* Instantiate wallet key from a public key. * Instantiate wallet key from a public key.
* @param {Buffer} publicKey * @param {Buffer} publicKey
* @param {(NetworkType|Network)} network
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromKey = function fromKey(key, compressed, network) { WalletKey.fromKey = function fromKey(key, compressed) {
return new WalletKey().fromKey(key, compressed, network); return new WalletKey().fromKey(key, compressed);
}; };
/** /**
* Instantiate wallet key from script. * Instantiate wallet key from script.
* @param {Buffer} key * @param {Buffer} key
* @param {Script} script * @param {Script} script
* @param {(NetworkType|Network)} network
* @returns {WalletKey} * @returns {WalletKey}
*/ */
WalletKey.fromScript = function fromScript(key, script, compressed, network) { WalletKey.fromScript = function fromScript(key, script, compressed) {
return new WalletKey().fromScript(key, script, compressed, network); return new WalletKey().fromScript(key, script, compressed);
}; };
/** /**
@ -116,9 +112,8 @@ WalletKey.fromSecret = function fromSecret(data, network) {
* @returns {Object} * @returns {Object}
*/ */
WalletKey.prototype.toJSON = function toJSON() { WalletKey.prototype.toJSON = function toJSON(network) {
return { return {
network: this.network.type,
name: this.name, name: this.name,
account: this.account, account: this.account,
branch: this.branch, branch: this.branch,
@ -129,7 +124,7 @@ WalletKey.prototype.toJSON = function toJSON() {
script: this.script ? this.script.toRaw().toString('hex') : null, script: this.script ? this.script.toRaw().toString('hex') : null,
program: this.witness ? this.getProgram().toRaw().toString('hex') : null, program: this.witness ? this.getProgram().toRaw().toString('hex') : null,
type: Address.typesByVal[this.getType()].toLowerCase(), type: Address.typesByVal[this.getType()].toLowerCase(),
address: this.getAddress('string') address: this.getAddress('string', network)
}; };
}; };
@ -173,9 +168,9 @@ WalletKey.prototype.fromHD = function fromHD(account, key, branch, index) {
this.nested = branch === 2; this.nested = branch === 2;
if (key.privateKey) if (key.privateKey)
return this.fromPrivate(key.privateKey, account.network); return this.fromPrivate(key.privateKey);
return this.fromPublic(key.publicKey, account.network); return this.fromPublic(key.publicKey);
}; };
/** /**
@ -204,7 +199,7 @@ WalletKey.prototype.fromImport = function fromImport(account, data) {
this.name = account.name; this.name = account.name;
this.account = account.accountIndex; this.account = account.accountIndex;
this.witness = account.witness; this.witness = account.witness;
return this.fromRaw(data, account.network); return this.fromRaw(data);
}; };
/** /**
@ -231,7 +226,7 @@ WalletKey.prototype.fromRing = function fromRing(account, ring) {
this.name = account.name; this.name = account.name;
this.account = account.accountIndex; this.account = account.accountIndex;
this.witness = account.witness; this.witness = account.witness;
return this.fromOptions(ring, ring.network); return this.fromOptions(ring);
}; };
/** /**

View File

@ -329,7 +329,6 @@ function keyFromRaw(data, network) {
const ring = {}; const ring = {};
const p = new BufferReader(data); const p = new BufferReader(data);
ring.network = bcoin.network.get(network);
ring.witness = p.readU8() === 1; ring.witness = p.readU8() === 1;
const key = p.readVarBytes(); const key = p.readVarBytes();

View File

@ -13,7 +13,7 @@ describe('Address', function() {
const p2pkh = Buffer.from(raw, 'hex'); const p2pkh = Buffer.from(raw, 'hex');
const addr = Address.fromPubkeyhash(p2pkh); const addr = Address.fromPubkeyhash(p2pkh);
const expectedAddr = '1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX'; const expectedAddr = '1MirQ9bwyQcGVJPwKUgapu5ouK2E2Ey4gX';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('main'), expectedAddr);
}); });
it('should match mainnet p2pkh address 2', () => { it('should match mainnet p2pkh address 2', () => {
@ -21,15 +21,15 @@ describe('Address', function() {
const p2pkh = Buffer.from(raw, 'hex'); const p2pkh = Buffer.from(raw, 'hex');
const addr = Address.fromPubkeyhash(p2pkh); const addr = Address.fromPubkeyhash(p2pkh);
const expectedAddr = '12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG'; const expectedAddr = '12MzCDwodF9G1e7jfwLXfR164RNtx4BRVG';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('main'), expectedAddr);
}); });
it('should match testnet p2pkh address', () => { it('should match testnet p2pkh address', () => {
const raw = '78b316a08647d5b77283e512d3603f1f1c8de68f'; const raw = '78b316a08647d5b77283e512d3603f1f1c8de68f';
const p2pkh = Buffer.from(raw, 'hex'); const p2pkh = Buffer.from(raw, 'hex');
const addr = Address.fromPubkeyhash(p2pkh, 'testnet'); const addr = Address.fromPubkeyhash(p2pkh);
const expectedAddr = 'mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz'; const expectedAddr = 'mrX9vMRYLfVy1BnZbc5gZjuyaqH3ZW2ZHz';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('testnet'), expectedAddr);
}); });
it('should handle wrong p2pkh hash length', () => { it('should handle wrong p2pkh hash length', () => {
@ -59,7 +59,7 @@ describe('Address', function() {
const script = Script.fromRaw(p2sh); const script = Script.fromRaw(p2sh);
const addr = Address.fromScript(script); const addr = Address.fromScript(script);
const expectedAddr = '3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC'; const expectedAddr = '3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('main'), expectedAddr);
}); });
it('should match mainnet p2sh address obtained from script hash', () => { it('should match mainnet p2sh address obtained from script hash', () => {
@ -67,7 +67,7 @@ describe('Address', function() {
const p2sh = Buffer.from(raw, 'hex'); const p2sh = Buffer.from(raw, 'hex');
const addr = Address.fromScripthash(p2sh); const addr = Address.fromScripthash(p2sh);
const expectedAddr = '3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC'; const expectedAddr = '3QJmV3qfvL9SuYo34YihAf3sRCW3qSinyC';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('main'), expectedAddr);
}); });
it('should match mainnet p2sh address obtained from script 2', () => { it('should match mainnet p2sh address obtained from script 2', () => {
@ -75,15 +75,15 @@ describe('Address', function() {
const p2sh = Buffer.from(raw, 'hex'); const p2sh = Buffer.from(raw, 'hex');
const addr = Address.fromScripthash(p2sh); const addr = Address.fromScripthash(p2sh);
const expectedAddr = '3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8'; const expectedAddr = '3NukJ6fYZJ5Kk8bPjycAnruZkE5Q7UW7i8';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('main'), expectedAddr);
}); });
it('should match testnet p2sh address', () => { it('should match testnet p2sh address', () => {
const raw = 'c579342c2c4c9220205e2cdc285617040c924a0a'; const raw = 'c579342c2c4c9220205e2cdc285617040c924a0a';
const p2sh = Buffer.from(raw, 'hex'); const p2sh = Buffer.from(raw, 'hex');
const addr = Address.fromScripthash(p2sh, 'testnet'); const addr = Address.fromScripthash(p2sh);
const expectedAddr = '2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n'; const expectedAddr = '2NBFNJTktNa7GZusGbDbGKRZTxdK9VVez3n';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('testnet'), expectedAddr);
}); });
it('should match mainnet segwit p2wpkh v0 address', () => { it('should match mainnet segwit p2wpkh v0 address', () => {
@ -91,7 +91,7 @@ describe('Address', function() {
const p2wpkh = Buffer.from(raw, 'hex'); const p2wpkh = Buffer.from(raw, 'hex');
const addr = Address.fromWitnessPubkeyhash(p2wpkh); const addr = Address.fromWitnessPubkeyhash(p2wpkh);
const expectedAddr = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'; const expectedAddr = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('main'), expectedAddr);
}); });
it('should match mainnet segwit p2pwsh v0 address', () => { it('should match mainnet segwit p2pwsh v0 address', () => {
@ -101,16 +101,16 @@ describe('Address', function() {
+ '6c985678cd4d27a1' + '6c985678cd4d27a1'
+ 'b8c6329604903262', 'hex'); + 'b8c6329604903262', 'hex');
const addr = Address.fromWitnessScripthash(p2wpkh); const addr = Address.fromWitnessScripthash(p2wpkh);
assert.strictEqual(addr.toString(), assert.strictEqual(addr.toString('main'),
'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'); 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3');
}); });
it('should match testnet segwit p2wpkh v0 address', () => { it('should match testnet segwit p2wpkh v0 address', () => {
const raw = '751e76e8199196d454941c45d1b3a323f1433bd6'; const raw = '751e76e8199196d454941c45d1b3a323f1433bd6';
const p2wpkh = Buffer.from(raw, 'hex'); const p2wpkh = Buffer.from(raw, 'hex');
const addr = Address.fromWitnessPubkeyhash(p2wpkh, 'testnet'); const addr = Address.fromWitnessPubkeyhash(p2wpkh);
const expectedAddr = 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx'; const expectedAddr = 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx';
assert.strictEqual(addr.toString(), expectedAddr); assert.strictEqual(addr.toString('testnet'), expectedAddr);
}); });
it('should match testnet segwit p2pwsh v0 address', () => { it('should match testnet segwit p2pwsh v0 address', () => {
@ -119,8 +119,8 @@ describe('Address', function() {
+ '04bd19203356da13' + '04bd19203356da13'
+ '6c985678cd4d27a1' + '6c985678cd4d27a1'
+ 'b8c6329604903262', 'hex'); + 'b8c6329604903262', 'hex');
const addr = Address.fromWitnessScripthash(p2wpkh, 'testnet'); const addr = Address.fromWitnessScripthash(p2wpkh);
assert.strictEqual(addr.toString(), assert.strictEqual(addr.toString('testnet'),
'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7'); 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7');
}); });
@ -130,56 +130,56 @@ describe('Address', function() {
+ '21b2a187905e5266' + '21b2a187905e5266'
+ '362b99d5e91c6ce2' + '362b99d5e91c6ce2'
+ '4d165dab93e86433', 'hex'); + '4d165dab93e86433', 'hex');
const addr = Address.fromWitnessScripthash(p2wpkh, 'testnet'); const addr = Address.fromWitnessScripthash(p2wpkh);
assert.strictEqual(addr.toString(), assert.strictEqual(addr.toString('testnet'),
'tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy'); 'tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy');
}); });
it('should handle invalid segwit hrp', () => { it('should handle invalid segwit hrp', () => {
const addr = 'tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty'; const addr = 'tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle invalid segwit checksum', () => { it('should handle invalid segwit checksum', () => {
const addr = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5'; const addr = 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle invalid segwit version', () => { it('should handle invalid segwit version', () => {
const addr = 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2'; const addr = 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle invalid segwit program length', () => { it('should handle invalid segwit program length', () => {
const addr = 'bc1rw5uspcuh'; const addr = 'bc1rw5uspcuh';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle invalid segwit program length 2', () => { it('should handle invalid segwit program length 2', () => {
const addr = 'bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw5' const addr = 'bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw5'
+ '08d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90'; + '08d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle invalid segwit program length for witness v0', () => { it('should handle invalid segwit program length for witness v0', () => {
const addr = 'tb1pw508d6qejxtdg4y5r3zarqfsj6c3'; const addr = 'tb1pw508d6qejxtdg4y5r3zarqfsj6c3';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle segwit mixed case', () => { it('should handle segwit mixed case', () => {
const addr = 'tb1qrp33g0q5c5txsp9arysrx4k6z' const addr = 'tb1qrp33g0q5c5txsp9arysrx4k6z'
+ 'dkfs4nce4xj0gdcccefvpysxf3q0sL5k7'; + 'dkfs4nce4xj0gdcccefvpysxf3q0sL5k7';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle segwit zero padding of more than 4 bits', () => { it('should handle segwit zero padding of more than 4 bits', () => {
const addr = 'tb1pw508d6qejxtdg4y5r3zarqfsj6c3'; const addr = 'tb1pw508d6qejxtdg4y5r3zarqfsj6c3';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
it('should handle segwit non-zero padding in 8-to-5 conversion', () => { it('should handle segwit non-zero padding in 8-to-5 conversion', () => {
const addr = 'tb1qrp33g0q5c5txsp9arysrx4k6' const addr = 'tb1qrp33g0q5c5txsp9arysrx4k6'
+ 'zdkfs4nce4xj0gdcccefvpysxf3pjxtptv'; + 'zdkfs4nce4xj0gdcccefvpysxf3pjxtptv';
assert.throws(() => Address.fromString(addr)); assert.throws(() => Address.fromString(addr, 'main'));
}); });
}); });

View File

@ -182,16 +182,19 @@ describe('Bech32', function() {
for (const [addr, script] of validAddresses) { for (const [addr, script] of validAddresses) {
it(`should have valid address for ${addr}`, () => { it(`should have valid address for ${addr}`, () => {
let ret = null; let ret = null;
let network = null;
try { try {
ret = Address.fromBech32(addr, 'main'); network = 'main';
ret = Address.fromBech32(addr, network);
} catch (e) { } catch (e) {
ret = null; ret = null;
} }
if (ret === null) { if (ret === null) {
try { try {
ret = Address.fromBech32(addr, 'testnet'); network = 'testnet';
ret = Address.fromBech32(addr, network);
} catch (e) { } catch (e) {
ret = null; ret = null;
} }
@ -202,7 +205,7 @@ describe('Bech32', function() {
const output = createProgram(ret.version, ret.hash); const output = createProgram(ret.version, ret.hash);
assert.bufferEqual(output, script); assert.bufferEqual(output, script);
const recreate = ret.toBech32(); const recreate = ret.toBech32(network);
assert.strictEqual(recreate, addr.toLowerCase()); assert.strictEqual(recreate, addr.toLowerCase());
}); });
} }

View File

@ -29,49 +29,49 @@ describe('HD', function() {
it('should create master private key', () => { it('should create master private key', () => {
const seed = Buffer.from(vectors.seed, 'hex'); const seed = Buffer.from(vectors.seed, 'hex');
const key = HD.PrivateKey.fromSeed(seed); const key = HD.PrivateKey.fromSeed(seed);
assert.strictEqual(key.toBase58(), vectors.master_priv); assert.strictEqual(key.toBase58('main'), vectors.master_priv);
assert.strictEqual(key.toPublic().toBase58(), vectors.master_pub); assert.strictEqual(key.toPublic().toBase58('main'), vectors.master_pub);
master = key; master = key;
}); });
it('should derive(0) child from master', () => { it('should derive(0) child from master', () => {
const child1 = master.derive(0); const child1 = master.derive(0);
assert.strictEqual(child1.toBase58(), vectors.child1_priv); assert.strictEqual(child1.toBase58('main'), vectors.child1_priv);
assert.strictEqual(child1.toPublic().toBase58(), vectors.child1_pub); assert.strictEqual(child1.toPublic().toBase58('main'), vectors.child1_pub);
}); });
it('should derive(1) child from master public key', () => { it('should derive(1) child from master public key', () => {
const child2 = master.toPublic().derive(1); const child2 = master.toPublic().derive(1);
assert.strictEqual(child2.toBase58(), vectors.child2_pub); assert.strictEqual(child2.toBase58('main'), vectors.child2_pub);
}); });
it('should derive(1) child from master', () => { it('should derive(1) child from master', () => {
const child3 = master.derive(1); const child3 = master.derive(1);
assert.strictEqual(child3.toBase58(), vectors.child3_priv); assert.strictEqual(child3.toBase58('main'), vectors.child3_priv);
assert.strictEqual(child3.toPublic().toBase58(), vectors.child3_pub); assert.strictEqual(child3.toPublic().toBase58('main'), vectors.child3_pub);
}); });
it('should derive(2) child from master', () => { it('should derive(2) child from master', () => {
const child4 = master.derive(2); const child4 = master.derive(2);
assert.strictEqual(child4.toBase58(), vectors.child4_priv); assert.strictEqual(child4.toBase58('main'), vectors.child4_priv);
assert.strictEqual(child4.toPublic().toBase58(), vectors.child4_pub); assert.strictEqual(child4.toPublic().toBase58('main'), vectors.child4_pub);
child = child4; child = child4;
}); });
it('should derive(0) child from child(2)', () => { it('should derive(0) child from child(2)', () => {
const child5 = child.derive(0); const child5 = child.derive(0);
assert.strictEqual(child5.toBase58(), vectors.child5_priv); assert.strictEqual(child5.toBase58('main'), vectors.child5_priv);
assert.strictEqual(child5.toPublic().toBase58(), vectors.child5_pub); assert.strictEqual(child5.toPublic().toBase58('main'), vectors.child5_pub);
}); });
it('should derive(1) child from child(2)', () => { it('should derive(1) child from child(2)', () => {
const child6 = child.derive(1); const child6 = child.derive(1);
assert.strictEqual(child6.toBase58(), vectors.child6_priv); assert.strictEqual(child6.toBase58('main'), vectors.child6_priv);
assert.strictEqual(child6.toPublic().toBase58(), vectors.child6_pub); assert.strictEqual(child6.toPublic().toBase58('main'), vectors.child6_pub);
}); });
it('should derive correctly when private key has leading zeros', () => { it('should derive correctly when private key has leading zeros', () => {
const key = HD.PrivateKey.fromBase58(vectors.zero_priv); const key = HD.PrivateKey.fromBase58(vectors.zero_priv, 'main');
assert.strictEqual(key.privateKey.toString('hex'), assert.strictEqual(key.privateKey.toString('hex'),
'00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd'); '00000055378cf5fafb56c711c674143f9b0ee82ab0ba2924f19b64f5ae7cdbfd');
@ -82,17 +82,19 @@ describe('HD', function() {
}); });
it('should deserialize master private key', () => { it('should deserialize master private key', () => {
HD.PrivateKey.fromBase58(master.toBase58()); HD.PrivateKey.fromBase58(master.toBase58('main'), 'main');
}); });
it('should deserialize master public key', () => { it('should deserialize master public key', () => {
HD.PublicKey.fromBase58(master.toPublic().toBase58()); HD.PublicKey.fromBase58(master.toPublic().toBase58('main'), 'main');
}); });
it('should deserialize and reserialize json', () => { it('should deserialize and reserialize json', () => {
const key = HD.generate(); const key = HD.generate();
const json = key.toJSON(); const json = key.toJSON();
base58Equal(HD.fromJSON(json).toBase58(), key.toBase58()); base58Equal(
HD.fromJSON(json, 'main').toBase58('main'),
key.toBase58('main'));
}); });
for (const vector of [vector1, vector2]) { for (const vector of [vector1, vector2]) {
@ -103,8 +105,8 @@ describe('HD', function() {
const key = HD.PrivateKey.fromSeed(seed); const key = HD.PrivateKey.fromSeed(seed);
const pub = key.toPublic(); const pub = key.toPublic();
base58Equal(key.toBase58(), vector.m.prv); base58Equal(key.toBase58('main'), vector.m.prv);
base58Equal(pub.toBase58(), vector.m.pub); base58Equal(pub.toBase58('main'), vector.m.pub);
master = key; master = key;
}); });
@ -118,8 +120,8 @@ describe('HD', function() {
it(`should derive ${path} from master`, () => { it(`should derive ${path} from master`, () => {
const key = master.derivePath(path); const key = master.derivePath(path);
const pub = key.toPublic(); const pub = key.toPublic();
base58Equal(key.toBase58(), kp.prv); base58Equal(key.toBase58('main'), kp.prv);
base58Equal(pub.toBase58(), kp.pub); base58Equal(pub.toBase58('main'), kp.pub);
}); });
} }
} }

View File

@ -60,10 +60,10 @@ describe('HTTP', function() {
it('should get wallet info', async () => { it('should get wallet info', async () => {
const info = await wallet.getInfo(); const info = await wallet.getInfo();
assert.strictEqual(info.id, 'test'); assert.strictEqual(info.id, 'test');
assert.typeOf(info.account, 'object'); const acct = await wallet.getAccount('default');
const str = info.account.receiveAddress; const str = acct.receiveAddress;
assert.typeOf(str, 'string'); assert.typeOf(str, 'string');
addr = Address.fromString(str); addr = Address.fromString(str, node.network);
}); });
it('should fill with funds', async () => { it('should fill with funds', async () => {
@ -95,7 +95,7 @@ describe('HTTP', function() {
await co.timeout(300); await co.timeout(300);
assert(receive); assert(receive);
assert.strictEqual(receive.id, 'test'); assert.strictEqual(receive.name, 'default');
assert.strictEqual(receive.type, 'pubkeyhash'); assert.strictEqual(receive.type, 'pubkeyhash');
assert.strictEqual(receive.branch, 0); assert.strictEqual(receive.branch, 0);
assert(balance); assert(balance);
@ -116,7 +116,7 @@ describe('HTTP', function() {
rate: 10000, rate: 10000,
outputs: [{ outputs: [{
value: 10000, value: 10000,
address: addr.toString() address: addr.toString(node.network)
}] }]
}; };
@ -232,11 +232,11 @@ describe('HTTP', function() {
it('should validate an address', async () => { it('should validate an address', async () => {
const json = await wallet.client.rpc.execute('validateaddress', [ const json = await wallet.client.rpc.execute('validateaddress', [
addr.toString() addr.toString(node.network)
]); ]);
assert.deepStrictEqual(json, { assert.deepStrictEqual(json, {
isvalid: true, isvalid: true,
address: addr.toString(), address: addr.toString(node.network),
scriptPubKey: Script.fromAddress(addr).toRaw().toString('hex'), scriptPubKey: Script.fromAddress(addr).toRaw().toString('hex'),
ismine: false, ismine: false,
iswatchonly: false iswatchonly: false

View File

@ -51,7 +51,7 @@ describe('Input', function() {
const input = Input.fromRaw(raw); const input = Input.fromRaw(raw);
const type = input.getType(); const type = input.getType();
const addr = input.getAddress().toBase58(); const addr = input.getAddress().toBase58('main');
const prevout = input.prevout.toRaw(); const prevout = input.prevout.toRaw();
assert.strictEqual(type, 'pubkeyhash'); assert.strictEqual(type, 'pubkeyhash');
@ -100,7 +100,7 @@ describe('Input', function() {
const type = input.getType(); const type = input.getType();
const subtype = input.getSubtype(); const subtype = input.getSubtype();
const addr = input.getAddress().toBase58(); const addr = input.getAddress().toBase58('main');
const prevout = input.prevout.toRaw(); const prevout = input.prevout.toRaw();
const redeem = input.getRedeem().toRaw(); const redeem = input.getRedeem().toRaw();

View File

@ -7,10 +7,10 @@ const assert = require('./util/assert');
const KeyRing = require('../lib/primitives/keyring'); const KeyRing = require('../lib/primitives/keyring');
const uncompressed = KeyRing.fromSecret( const uncompressed = KeyRing.fromSecret(
'5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss'); '5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss', 'main');
const compressed = KeyRing.fromSecret( const compressed = KeyRing.fromSecret(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1'); 'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1', 'main');
describe('KeyRing', function() { describe('KeyRing', function() {
it('should get uncompressed public key', () => { it('should get uncompressed public key', () => {
@ -23,13 +23,13 @@ describe('KeyRing', function() {
it('should get uncompressed public key address', () => { it('should get uncompressed public key address', () => {
assert.strictEqual( assert.strictEqual(
'1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN', '1HZwkjkeaoZfTSaJxDw6aKkxp45agDiEzN',
uncompressed.getKeyAddress('base58')); uncompressed.getKeyAddress('base58', 'main'));
}); });
it('should get uncompressed WIF', () => { it('should get uncompressed WIF', () => {
assert.strictEqual( assert.strictEqual(
'5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss', '5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss',
uncompressed.toSecret()); uncompressed.toSecret('main'));
}); });
it('should get compressed public key', () => { it('should get compressed public key', () => {
@ -41,12 +41,12 @@ describe('KeyRing', function() {
it('should get compressed public key address', () => { it('should get compressed public key address', () => {
assert.strictEqual( assert.strictEqual(
'1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV', '1F3sAm6ZtwLAUnj7d38pGFxtP3RVEvtsbV',
compressed.getKeyAddress('base58')); compressed.getKeyAddress('base58', 'main'));
}); });
it('should get compressed WIF', () => { it('should get compressed WIF', () => {
assert.strictEqual( assert.strictEqual(
'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1', 'L4rK1yDtCWekvXuE6oXD9jCYfFNV2cWRpVuPLBcCU2z8TrisoyY1',
compressed.toSecret()); compressed.toSecret('main'));
}); });
}); });

View File

@ -36,7 +36,7 @@ describe('Mnemonic', function() {
assert.bufferEqual(mnemonic.toSeed(), seed); assert.bufferEqual(mnemonic.toSeed(), seed);
const key = HDPrivateKey.fromMnemonic(mnemonic); const key = HDPrivateKey.fromMnemonic(mnemonic);
assert.strictEqual(key.toBase58(), xpriv); assert.strictEqual(key.toBase58('main'), xpriv);
}); });
it(`should create a ${language} mnemonic from phrase (${i})`, () => { it(`should create a ${language} mnemonic from phrase (${i})`, () => {
@ -51,7 +51,7 @@ describe('Mnemonic', function() {
assert.bufferEqual(mnemonic.toSeed(), seed); assert.bufferEqual(mnemonic.toSeed(), seed);
const key = HDPrivateKey.fromMnemonic(mnemonic); const key = HDPrivateKey.fromMnemonic(mnemonic);
assert.strictEqual(key.toBase58(), xpriv); assert.strictEqual(key.toBase58('main'), xpriv);
}); });
i += 1; i += 1;

View File

@ -551,17 +551,15 @@ describe('Node', function() {
it('should validate an address', async () => { it('should validate an address', async () => {
const addr = new Address(); const addr = new Address();
addr.network = node.network;
const json = await node.rpc.call({ const json = await node.rpc.call({
method: 'validateaddress', method: 'validateaddress',
params: [addr.toString()] params: [addr.toString(node.network)]
}, {}); }, {});
assert.deepStrictEqual(json.result, { assert.deepStrictEqual(json.result, {
isvalid: true, isvalid: true,
address: addr.toString(), address: addr.toString(node.network),
scriptPubKey: Script.fromAddress(addr).toJSON(), scriptPubKey: Script.fromAddress(addr, node.network).toJSON(),
ismine: false, ismine: false,
iswatchonly: false iswatchonly: false
}); });

View File

@ -87,8 +87,10 @@ MemWallet.prototype.init = function init() {
if (!this.master) if (!this.master)
this.master = HD.PrivateKey.generate(); this.master = HD.PrivateKey.generate();
if (!this.key) if (!this.key) {
this.key = this.master.deriveAccount(44, this.account); const type = this.network.keyPrefix.coinType;
this.key = this.master.deriveAccount(44, type, this.account);
}
i = this.receiveDepth; i = this.receiveDepth;
while (i--) while (i--)
@ -132,7 +134,8 @@ MemWallet.prototype.derivePath = function derivePath(path) {
}; };
MemWallet.prototype.deriveKey = function deriveKey(branch, index) { MemWallet.prototype.deriveKey = function deriveKey(branch, index) {
let key = this.master.deriveAccount(44, this.account); const type = this.network.keyPrefix.coinType;
let key = this.master.deriveAccount(44, type, this.account);
key = key.derive(branch).derive(index); key = key.derive(branch).derive(index);
const ring = new KeyRing({ const ring = new KeyRing({
network: this.network, network: this.network,

View File

@ -73,7 +73,7 @@ async function testP2PKH(witness, nesting) {
const wallet = await wdb.create({ witness }); const wallet = await wdb.create({ witness });
const waddr = await wallet.receiveAddress(); const waddr = await wallet.receiveAddress();
const addr = Address.fromString(waddr.toString()); const addr = Address.fromString(waddr.toString(wdb.network), wdb.network);
assert.strictEqual(addr.type, type); assert.strictEqual(addr.type, type);
assert.strictEqual(addr.type, waddr.type); assert.strictEqual(addr.type, waddr.type);
@ -235,19 +235,19 @@ describe('Wallet', function() {
const addr1 = await wallet.receiveAddress(); const addr1 = await wallet.receiveAddress();
assert(addr1); assert(addr1);
const str = addr1.toString(); const str = addr1.toString(wdb.network);
const addr2 = Address.fromString(str); const addr2 = Address.fromString(str, wdb.network);
assert(addr2.equals(addr1)); assert(addr2.equals(addr1));
}); });
it('should validate existing address', () => { it('should validate existing address', () => {
assert(Address.fromString('1KQ1wMNwXHUYj1nV2xzsRcKUH8gVFpTFUc')); assert(Address.fromString('1KQ1wMNwXHUYj1nV2xzsRcKUH8gVFpTFUc', 'main'));
}); });
it('should fail to validate invalid address', () => { it('should fail to validate invalid address', () => {
assert.throws(() => { assert.throws(() => {
Address.fromString('1KQ1wMNwXHUYj1nv2xzsRcKUH8gVFpTFUc'); Address.fromString('1KQ1wMNwXHUYj1nv2xzsRcKUH8gVFpTFUc', 'main');
}); });
}); });
@ -277,7 +277,7 @@ describe('Wallet', function() {
}); });
const xpriv = HD.PrivateKey.generate(); const xpriv = HD.PrivateKey.generate();
const key = xpriv.deriveAccount(44, 0).toPublic(); const key = xpriv.deriveAccount(44, 0, 0).toPublic();
await wallet.addSharedKey(0, key); await wallet.addSharedKey(0, key);
@ -1303,7 +1303,7 @@ describe('Wallet', function() {
const details = await wallet.toDetails(txs); const details = await wallet.toDetails(txs);
assert(details.some((tx) => { assert(details.some((tx) => {
return tx.toJSON().outputs[0].path.name === 'foo'; return tx.toJSON(wdb.network).outputs[0].path.name === 'foo';
})); }));
}); });