diff --git a/src/hdwallet.js b/src/hdwallet.js index 20766ac..7df6207 100644 --- a/src/hdwallet.js +++ b/src/hdwallet.js @@ -12,14 +12,11 @@ var networks = require('./networks') var sec = require('./sec') var ecparams = sec("secp256k1") -function HDWallet(seed, networkString) { +function HDWallet(seed, network) { if (seed == undefined) return; // FIXME: Boo, should be stricter - this.network = networkString || 'bitcoin' - - if(!networks.hasOwnProperty(this.network)) { - throw new Error("Unknown network: " + this.network) - } + network = network || networks.bitcoin + assert(network.bip32, 'Unknown BIP32 constants for network') var I = crypto.HmacSHA512(seed, HDWallet.MASTER_SECRET) var IL = I.slice(0, 32) @@ -28,6 +25,7 @@ function HDWallet(seed, networkString) { // In case IL is 0 or >= n, the master key is invalid (handled by ECKey.fromBuffer) var pIL = BigInteger.fromBuffer(IL) + this.network = network this.priv = new ECKey(pIL, true) this.pub = this.priv.pub @@ -40,8 +38,8 @@ HDWallet.MASTER_SECRET = new Buffer('Bitcoin seed') HDWallet.HIGHEST_BIT = 0x80000000 HDWallet.LENGTH = 78 -HDWallet.fromSeedHex = function(hex, networkString) { - return new HDWallet(new Buffer(hex, 'hex'), networkString) +HDWallet.fromSeedHex = function(hex, network) { + return new HDWallet(new Buffer(hex, 'hex'), network) } HDWallet.fromBase58 = function(string) { @@ -66,14 +64,14 @@ HDWallet.fromBuffer = function(input) { var version = input.readUInt32BE(0) var type - for(var name in networks) { + for (var name in networks) { var network = networks[name] - for(var t in network.bip32) { + for (var t in network.bip32) { if (version != network.bip32[t]) continue type = t - hd.network = name + hd.network = network } } @@ -127,7 +125,7 @@ HDWallet.prototype.getAddress = function() { HDWallet.prototype.toBuffer = function(priv) { // Version - var version = networks[this.network].bip32[priv ? 'priv' : 'pub'] + var version = this.network.bip32[priv ? 'priv' : 'pub'] var buffer = new Buffer(HDWallet.LENGTH) // 4 bytes: version bytes @@ -254,7 +252,7 @@ HDWallet.prototype.derivePrivate = function(index) { } HDWallet.prototype.getKeyVersion = function() { - return networks[this.network].pubKeyHash + return this.network.pubKeyHash } HDWallet.prototype.toString = HDWallet.prototype.toBase58 diff --git a/src/wallet.js b/src/wallet.js index 206bf44..58b5748 100644 --- a/src/wallet.js +++ b/src/wallet.js @@ -1,14 +1,14 @@ -var Address = require('./address') -var HDNode = require('./hdwallet.js') var networks = require('./networks') var rng = require('secure-random') + +var Address = require('./address') +var HDNode = require('./hdwallet') var Transaction = require('./transaction').Transaction -function Wallet(seed, options) { +function Wallet(seed, network) { if (!(this instanceof Wallet)) { return new Wallet(seed, options); } - var options = options || {} - var network = options.network || 'bitcoin' + network = network || networks.bitcoin // Stored in a closure to make accidental serialization less likely var masterkey = null @@ -28,7 +28,7 @@ function Wallet(seed, options) { this.outputs = {} // Make a new master key - this.newMasterKey = function(seed, network) { + this.newMasterKey = function(seed) { seed = seed || new Buffer(rng(32)) masterkey = new HDNode(seed, network) @@ -43,7 +43,8 @@ function Wallet(seed, options) { me.outputs = {} } - this.newMasterKey(seed, network) + + this.newMasterKey(seed) this.generateAddress = function() { var key = externalAccount.derive(this.addresses.length) @@ -143,7 +144,7 @@ function Wallet(seed, options) { var address try { - address = Address.fromScriptPubKey(txOut.script, networks[network]).toString() + address = Address.fromScriptPubKey(txOut.script, network).toString() } catch(e) { if (!(e.message.match(/has no matching Address/))) throw e } diff --git a/test/hdwallet.js b/test/hdwallet.js index 0a826c7..03a7c85 100644 --- a/test/hdwallet.js +++ b/test/hdwallet.js @@ -1,4 +1,5 @@ var assert = require('assert') +var networks = require('../src/networks') var HDWallet = require('../src/hdwallet') var fixtures = require('./fixtures/hdwallet.json') @@ -68,6 +69,15 @@ describe('HDWallet', function() { buffer.writeUInt32BE(0xFFFFFFFF, 9) assert.throws(function() { HDWallet.fromBuffer(buffer) }, /Invalid index/) }) + + it('fails for an invalid network type', function() { + var buffer = new HDWallet(seed).toBuffer() + buffer.writeUInt32BE(0x00000000, 0) + + assert.throws(function() { + HDWallet.fromBuffer(buffer) + }, /Could not find version 0/) + }) }) }) @@ -119,24 +129,36 @@ describe('HDWallet', function() { }) describe('network types', function() { + var seed + + beforeEach(function() { + seed = new Buffer('foobar') + }) + + it('ensure that a bitcoin wallet is the default', function() { + var wallet = new HDWallet(seed) + + assert.equal(wallet.network, networks.bitcoin) + }) + it('ensures that a bitcoin Wallet generates bitcoin addresses', function() { - var wallet = new HDWallet(new Buffer('foobar'), 'bitcoin') - assert.equal(wallet.getAddress().toString(), '17SnB9hyGwJPoKpLb9eVPHjsujyEuBpMAA') + var wallet = new HDWallet(seed) + var address = wallet.getAddress().toString() + + assert.equal(address, '17SnB9hyGwJPoKpLb9eVPHjsujyEuBpMAA') }) it('ensures that a testnet Wallet generates testnet addresses', function() { - var wallet = new HDWallet(new Buffer('foobar'), 'testnet') - assert.equal(wallet.getAddress().toString(), 'mmxjUCnx5xjeaSHxJicsDCxCmjZwq8KTbv') - }) + var wallet = new HDWallet(seed, networks.testnet) + var address = wallet.getAddress().toString() - it('throws an exception when unknown network type is passed in', function() { - assert.throws(function() { new HDWallet(new Buffer('foobar'), 'doge') }, /Unknown network: doge/) + assert.equal(address, 'mmxjUCnx5xjeaSHxJicsDCxCmjZwq8KTbv') }) - it('throws an exception with bad network type using fromBuffer', function() { - var buffer = new HDWallet(new Buffer('foobar'), 'bitcoin').toBuffer() - buffer.writeUInt32BE(0x00000000, 0) - assert.throws(function() { HDWallet.fromBuffer(buffer) }, /Could not find version 0/) + it('throws an exception when unknown network type is passed in', function() { + assert.throws(function() { + new HDWallet(seed, {}) + }, /Unknown BIP32 constants for network/) }) }) }) diff --git a/test/wallet.js b/test/wallet.js index b5187d1..e54d603 100644 --- a/test/wallet.js +++ b/test/wallet.js @@ -1,5 +1,6 @@ var assert = require('assert') var crypto = require('../src/crypto') +var networks = require('../src/networks') var sinon = require('sinon') var Address = require('../src/address') @@ -29,7 +30,7 @@ describe('Wallet', function() { }) it('defaults to Bitcoin network', function() { - assert.equal(wallet.getMasterKey().network, 'bitcoin') + assert.equal(wallet.getMasterKey().network, networks.bitcoin) }) it("generates m/0' as the main account", function() { @@ -59,11 +60,11 @@ describe('Wallet', function() { describe('constructor options', function() { beforeEach(function() { - wallet = new Wallet(seed, {network: 'testnet'}) + wallet = new Wallet(seed, networks.testnet) }) it('uses the network if specified', function() { - assert.equal(wallet.getMasterKey().network, 'testnet') + assert.equal(wallet.getMasterKey().network, networks.testnet) }) }) }) @@ -98,7 +99,7 @@ describe('Wallet', function() { describe('generateAddress', function(){ it('generate receiving addresses', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) var expectedAddresses = [ "n1GyUANZand9Kw6hGSV9837cCC9FFUQzQa", "n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X" @@ -112,7 +113,7 @@ describe('Wallet', function() { describe('generateChangeAddress', function(){ it('generates change addresses', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) var expectedAddresses = ["mnXiDR4MKsFxcKJEZjx4353oXvo55iuptn"] assert.equal(wallet.generateChangeAddress(), expectedAddresses[0]) @@ -122,7 +123,7 @@ describe('Wallet', function() { describe('getPrivateKey', function(){ it('returns the private key at the given index of external account', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) assertEqual(wallet.getPrivateKey(0), wallet.getExternalAccount().derive(0).priv) assertEqual(wallet.getPrivateKey(1), wallet.getExternalAccount().derive(1).priv) @@ -131,7 +132,7 @@ describe('Wallet', function() { describe('getInternalPrivateKey', function(){ it('returns the private key at the given index of internal account', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) assertEqual(wallet.getInternalPrivateKey(0), wallet.getInternalAccount().derive(0).priv) assertEqual(wallet.getInternalPrivateKey(1), wallet.getInternalAccount().derive(1).priv) @@ -140,7 +141,7 @@ describe('Wallet', function() { describe('getPrivateKeyForAddress', function(){ it('returns the private key for the given address', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) wallet.generateChangeAddress() wallet.generateAddress() wallet.generateAddress() @@ -156,7 +157,7 @@ describe('Wallet', function() { }) it('raises an error when address is not found', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) assert.throws(function() { wallet.getPrivateKeyForAddress("n2fiWrHqD6GM5GiEqkbWAc6aaZQp3ba93X") }, /Unknown address. Make sure the address is from the keychain and has been generated./) @@ -434,9 +435,9 @@ describe('Wallet', function() { }) }) - describe('testnet', function(){ + describe(networks.testnet, function(){ it('should create transaction', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) var address = wallet.generateAddress() wallet.setUnspentOutputs([{ @@ -458,7 +459,7 @@ describe('Wallet', function() { describe('changeAddress', function(){ it('should allow custom changeAddress', function(){ - var wallet = new Wallet(seed, {network: 'testnet'}) + var wallet = new Wallet(seed, networks.testnet) var address = wallet.generateAddress() wallet.setUnspentOutputs([{