|
@ -96,27 +96,27 @@ helpers.createAndJoinWallet = function(m, n, opts, cb) { |
|
|
var copayerIds = []; |
|
|
var copayerIds = []; |
|
|
var offset = opts.offset || 0; |
|
|
var offset = opts.offset || 0; |
|
|
|
|
|
|
|
|
|
|
|
var supportBIP44 = _.isBoolean(opts.supportBIP44) ? opts.supportBIP44 : true |
|
|
var walletOpts = { |
|
|
var walletOpts = { |
|
|
name: 'a wallet', |
|
|
name: 'a wallet', |
|
|
m: m, |
|
|
m: m, |
|
|
n: n, |
|
|
n: n, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
derivationStrategy: opts.derivationStrategy || 'BIP44', |
|
|
supportBIP44: supportBIP44, |
|
|
}; |
|
|
}; |
|
|
server.createWallet(walletOpts, function(err, walletId) { |
|
|
server.createWallet(walletOpts, function(err, walletId) { |
|
|
if (err) return cb(err); |
|
|
if (err) return cb(err); |
|
|
|
|
|
|
|
|
async.each(_.range(n), function(i, cb) { |
|
|
async.each(_.range(n), function(i, cb) { |
|
|
var copayerData = TestData.copayers[i + offset]; |
|
|
var copayerData = TestData.copayers[i + offset]; |
|
|
var bip = opts.derivationStrategy || 'BIP44'; |
|
|
|
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
walletId: walletId, |
|
|
walletId: walletId, |
|
|
name: 'copayer ' + (i + 1), |
|
|
name: 'copayer ' + (i + 1), |
|
|
xPubKey: bip == 'BIP44' ? copayerData.xPubKey_44H_0H_0H : copayerData.xPubKey_45H, |
|
|
xPubKey: (n == 1 && supportBIP44) ? copayerData.xPubKey_44H_0H_0H : copayerData.xPubKey_45H, |
|
|
requestPubKey: copayerData.pubKey_1H_0, |
|
|
requestPubKey: copayerData.pubKey_1H_0, |
|
|
customData: 'custom data ' + (i + 1), |
|
|
customData: 'custom data ' + (i + 1), |
|
|
derivationStrategy: bip, |
|
|
|
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
server.joinWallet(copayerOpts, function(err, result) { |
|
|
server.joinWallet(copayerOpts, function(err, result) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
copayerIds.push(result.copayerId); |
|
|
copayerIds.push(result.copayerId); |
|
@ -495,7 +495,7 @@ describe('Wallet service', function() { |
|
|
txpId = txp.id; |
|
|
txpId = txp.id; |
|
|
async.eachSeries(_.range(2), function(i, next) { |
|
|
async.eachSeries(_.range(2), function(i, next) { |
|
|
var copayer = TestData.copayers[i]; |
|
|
var copayer = TestData.copayers[i]; |
|
|
helpers.getAuthServer(copayer.id44, function(server) { |
|
|
helpers.getAuthServer(copayer.id45, function(server) { |
|
|
var signatures = helpers.clientSign(txp, copayer.xPrivKey); |
|
|
var signatures = helpers.clientSign(txp, copayer.xPrivKey); |
|
|
server.signTx({ |
|
|
server.signTx({ |
|
|
txProposalId: txp.id, |
|
|
txProposalId: txp.id, |
|
@ -553,7 +553,7 @@ describe('Wallet service', function() { |
|
|
txpId = txp.id; |
|
|
txpId = txp.id; |
|
|
async.eachSeries(_.range(1, 3), function(i, next) { |
|
|
async.eachSeries(_.range(1, 3), function(i, next) { |
|
|
var copayer = TestData.copayers[i]; |
|
|
var copayer = TestData.copayers[i]; |
|
|
helpers.getAuthServer(copayer.id44, function(server) { |
|
|
helpers.getAuthServer(copayer.id45, function(server) { |
|
|
server.rejectTx({ |
|
|
server.rejectTx({ |
|
|
txProposalId: txp.id, |
|
|
txProposalId: txp.id, |
|
|
}, next); |
|
|
}, next); |
|
@ -1012,9 +1012,8 @@ describe('Wallet service', function() { |
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
walletId: wallet.id, |
|
|
walletId: wallet.id, |
|
|
name: 'me', |
|
|
name: 'me', |
|
|
xPubKey: TestData.copayers[1].xPubKey_45H, |
|
|
xPubKey: TestData.copayers[1].xPubKey_44H_0H_0H, |
|
|
requestPubKey: TestData.copayers[1].pubKey_1H_0, |
|
|
requestPubKey: TestData.copayers[1].pubKey_1H_0, |
|
|
derivationStrategy: 'BIP44', |
|
|
|
|
|
}); |
|
|
}); |
|
|
server.joinWallet(copayerOpts, function(err) { |
|
|
server.joinWallet(copayerOpts, function(err) { |
|
|
should.exist(err); |
|
|
should.exist(err); |
|
@ -1155,84 +1154,53 @@ describe('Wallet service', function() { |
|
|
describe('Address derivation strategy', function() { |
|
|
describe('Address derivation strategy', function() { |
|
|
var server; |
|
|
var server; |
|
|
beforeEach(function() { |
|
|
beforeEach(function() { |
|
|
server = WalletService.getInstance({ |
|
|
server = WalletService.getInstance(); |
|
|
clientVersion: 'bwc-0.2.0', |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
}); |
|
|
it('should fail to join BIP45 wallet with BIP44 copayer opts', function(done) { |
|
|
it('should use BIP44 for 1-of-1 wallet if supported', function(done) { |
|
|
var walletOpts = { |
|
|
var walletOpts = { |
|
|
name: 'my wallet', |
|
|
name: 'my wallet', |
|
|
m: 2, |
|
|
m: 1, |
|
|
n: 3, |
|
|
n: 1, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
derivationStrategy: 'BIP45', |
|
|
supportBIP44: true, |
|
|
}; |
|
|
}; |
|
|
server.createWallet(walletOpts, function(err, wid) { |
|
|
server.createWallet(walletOpts, function(err, wid) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
server.storage.fetchWallet(wid, function(err, wallet) { |
|
|
walletId: wid, |
|
|
should.not.exist(err); |
|
|
name: 'me', |
|
|
wallet.derivationStrategy.should.equal('BIP44'); |
|
|
xPubKey: TestData.copayers[0].xPubKey_44H_0H_0H, |
|
|
|
|
|
requestPubKey: TestData.copayers[0].pubKey_1H_0, |
|
|
|
|
|
customData: 'dummy custom data', |
|
|
|
|
|
derivationStrategy: 'BIP44', |
|
|
|
|
|
}); |
|
|
|
|
|
server.joinWallet(copayerOpts, function(err, result) { |
|
|
|
|
|
should.exist(err); |
|
|
|
|
|
err.message.toLowerCase().should.contain('address derivation strategy'); |
|
|
|
|
|
done(); |
|
|
done(); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
it('should fail to join BIP44 wallet with BIP45 copayer opts', function(done) { |
|
|
it('should use BIP45 for 1-of-1 wallet if BIP44 not supported', function(done) { |
|
|
var walletOpts = { |
|
|
var walletOpts = { |
|
|
name: 'my wallet', |
|
|
name: 'my wallet', |
|
|
m: 2, |
|
|
m: 1, |
|
|
n: 3, |
|
|
n: 1, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
derivationStrategy: 'BIP44', |
|
|
|
|
|
}; |
|
|
}; |
|
|
server.createWallet(walletOpts, function(err, wid) { |
|
|
server.createWallet(walletOpts, function(err, wid) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
server.storage.fetchWallet(wid, function(err, wallet) { |
|
|
walletId: wid, |
|
|
should.not.exist(err); |
|
|
name: 'me', |
|
|
wallet.derivationStrategy.should.equal('BIP45'); |
|
|
xPubKey: TestData.copayers[0].xPubKey_45H, |
|
|
|
|
|
requestPubKey: TestData.copayers[0].pubKey_1H_0, |
|
|
|
|
|
customData: 'dummy custom data', |
|
|
|
|
|
derivationStrategy: 'BIP45', |
|
|
|
|
|
}); |
|
|
|
|
|
server.joinWallet(copayerOpts, function(err, result) { |
|
|
|
|
|
should.exist(err); |
|
|
|
|
|
err.message.toLowerCase().should.contain('address derivation strategy'); |
|
|
|
|
|
done(); |
|
|
done(); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
it('should require upgrade when joining BIP44 wallet with BIP45 copayer opts from old client app', function(done) { |
|
|
it('should always use BIP45 for shared wallets', function(done) { |
|
|
var walletOpts = { |
|
|
var walletOpts = { |
|
|
name: 'my wallet', |
|
|
name: 'my wallet', |
|
|
m: 2, |
|
|
m: 2, |
|
|
n: 3, |
|
|
n: 3, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
pubKey: TestData.keyPair.pub, |
|
|
derivationStrategy: 'BIP44', |
|
|
|
|
|
}; |
|
|
}; |
|
|
server.createWallet(walletOpts, function(err, wid) { |
|
|
server.createWallet(walletOpts, function(err, wid) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
var copayerOpts = helpers.getSignedCopayerOpts({ |
|
|
server.storage.fetchWallet(wid, function(err, wallet) { |
|
|
walletId: wid, |
|
|
should.not.exist(err); |
|
|
name: 'me', |
|
|
wallet.derivationStrategy.should.equal('BIP45'); |
|
|
xPubKey: TestData.copayers[0].xPubKey_45H, |
|
|
|
|
|
requestPubKey: TestData.copayers[0].pubKey_1H_0, |
|
|
|
|
|
customData: 'dummy custom data', |
|
|
|
|
|
derivationStrategy: 'BIP45', |
|
|
|
|
|
}); |
|
|
|
|
|
server = WalletService.getInstance({ |
|
|
|
|
|
clientVersion: 'bwc-0.1.4', |
|
|
|
|
|
}); |
|
|
|
|
|
server.joinWallet(copayerOpts, function(err, result) { |
|
|
|
|
|
should.exist(err); |
|
|
|
|
|
err.code.should.equal('UPGRADE_NEEDED'); |
|
|
|
|
|
done(); |
|
|
done(); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
@ -1242,9 +1210,7 @@ describe('Wallet service', function() { |
|
|
describe('#getStatus', function() { |
|
|
describe('#getStatus', function() { |
|
|
var server, wallet; |
|
|
var server, wallet; |
|
|
beforeEach(function(done) { |
|
|
beforeEach(function(done) { |
|
|
helpers.createAndJoinWallet(1, 1, { |
|
|
helpers.createAndJoinWallet(1, 2, function(s, w) { |
|
|
derivationStrategy: 'BIP45' |
|
|
|
|
|
}, function(s, w) { |
|
|
|
|
|
server = s; |
|
|
server = s; |
|
|
wallet = w; |
|
|
wallet = w; |
|
|
done(); |
|
|
done(); |
|
@ -1258,7 +1224,7 @@ describe('Wallet service', function() { |
|
|
should.exist(status.wallet); |
|
|
should.exist(status.wallet); |
|
|
status.wallet.name.should.equal(wallet.name); |
|
|
status.wallet.name.should.equal(wallet.name); |
|
|
should.exist(status.wallet.copayers); |
|
|
should.exist(status.wallet.copayers); |
|
|
status.wallet.copayers.length.should.equal(1); |
|
|
status.wallet.copayers.length.should.equal(2); |
|
|
should.exist(status.balance); |
|
|
should.exist(status.balance); |
|
|
status.balance.totalAmount.should.equal(0); |
|
|
status.balance.totalAmount.should.equal(0); |
|
|
should.exist(status.preferences); |
|
|
should.exist(status.preferences); |
|
@ -1364,76 +1330,78 @@ describe('Wallet service', function() { |
|
|
|
|
|
|
|
|
describe('#createAddress', function() { |
|
|
describe('#createAddress', function() { |
|
|
var server, wallet; |
|
|
var server, wallet; |
|
|
beforeEach(function(done) { |
|
|
|
|
|
helpers.createAndJoinWallet(2, 2, function(s, w) { |
|
|
describe('shared wallets (BIP45)', function() { |
|
|
server = s; |
|
|
beforeEach(function(done) { |
|
|
wallet = w; |
|
|
helpers.createAndJoinWallet(2, 2, function(s, w) { |
|
|
done(); |
|
|
server = s; |
|
|
|
|
|
wallet = w; |
|
|
|
|
|
done(); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should create address', function(done) { |
|
|
it('should create address', function(done) { |
|
|
server.createAddress({}, function(err, address) { |
|
|
server.createAddress({}, function(err, address) { |
|
|
should.not.exist(err); |
|
|
|
|
|
should.exist(address); |
|
|
|
|
|
address.walletId.should.equal(wallet.id); |
|
|
|
|
|
address.network.should.equal('livenet'); |
|
|
|
|
|
address.address.should.equal('36q2G5FMGvJbPgAVEaiyAsFGmpkhPKwk2r'); |
|
|
|
|
|
address.isChange.should.be.false; |
|
|
|
|
|
address.path.should.equal('m/0/0'); |
|
|
|
|
|
server.getNotifications({}, function(err, notifications) { |
|
|
|
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
var notif = _.find(notifications, { |
|
|
should.exist(address); |
|
|
type: 'NewAddress' |
|
|
address.walletId.should.equal(wallet.id); |
|
|
|
|
|
address.network.should.equal('livenet'); |
|
|
|
|
|
address.address.should.equal('3BVJZ4CYzeTtawDtgwHvWV5jbvnXtYe97i'); |
|
|
|
|
|
address.isChange.should.be.false; |
|
|
|
|
|
address.path.should.equal('m/2147483647/0/0'); |
|
|
|
|
|
server.getNotifications({}, function(err, notifications) { |
|
|
|
|
|
should.not.exist(err); |
|
|
|
|
|
var notif = _.find(notifications, { |
|
|
|
|
|
type: 'NewAddress' |
|
|
|
|
|
}); |
|
|
|
|
|
should.exist(notif); |
|
|
|
|
|
notif.data.address.should.equal(address.address); |
|
|
|
|
|
done(); |
|
|
}); |
|
|
}); |
|
|
should.exist(notif); |
|
|
|
|
|
notif.data.address.should.equal('36q2G5FMGvJbPgAVEaiyAsFGmpkhPKwk2r'); |
|
|
|
|
|
done(); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should create many addresses on simultaneous requests', function(done) { |
|
|
it('should create many addresses on simultaneous requests', function(done) { |
|
|
var N = 5; |
|
|
var N = 5; |
|
|
async.map(_.range(N), function(i, cb) { |
|
|
async.map(_.range(N), function(i, cb) { |
|
|
server.createAddress({}, cb); |
|
|
server.createAddress({}, cb); |
|
|
}, function(err, addresses) { |
|
|
}, function(err, addresses) { |
|
|
addresses.length.should.equal(N); |
|
|
addresses.length.should.equal(N); |
|
|
_.each(_.range(N), function(i) { |
|
|
_.each(_.range(N), function(i) { |
|
|
addresses[i].path.should.equal('m/0/' + i); |
|
|
addresses[i].path.should.equal('m/2147483647/0/' + i); |
|
|
}); |
|
|
}); |
|
|
// No two identical addresses
|
|
|
// No two identical addresses
|
|
|
_.uniq(_.pluck(addresses, 'address')).length.should.equal(N); |
|
|
_.uniq(_.pluck(addresses, 'address')).length.should.equal(N); |
|
|
done(); |
|
|
done(); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should not create address if unable to store it', function(done) { |
|
|
it('should not create address if unable to store it', function(done) { |
|
|
sinon.stub(server.storage, 'storeAddressAndWallet').yields('dummy error'); |
|
|
sinon.stub(server.storage, 'storeAddressAndWallet').yields('dummy error'); |
|
|
server.createAddress({}, function(err, address) { |
|
|
server.createAddress({}, function(err, address) { |
|
|
should.exist(err); |
|
|
should.exist(err); |
|
|
should.not.exist(address); |
|
|
should.not.exist(address); |
|
|
|
|
|
|
|
|
server.getMainAddresses({}, function(err, addresses) { |
|
|
server.getMainAddresses({}, function(err, addresses) { |
|
|
addresses.length.should.equal(0); |
|
|
addresses.length.should.equal(0); |
|
|
|
|
|
|
|
|
server.storage.storeAddressAndWallet.restore(); |
|
|
server.storage.storeAddressAndWallet.restore(); |
|
|
server.createAddress({}, function(err, address) { |
|
|
server.createAddress({}, function(err, address) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
should.exist(address); |
|
|
should.exist(address); |
|
|
done(); |
|
|
done(); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
describe('BIP45', function() { |
|
|
describe('1-of-1 (BIP44)', function() { |
|
|
beforeEach(function(done) { |
|
|
beforeEach(function(done) { |
|
|
helpers.createAndJoinWallet(2, 2, { |
|
|
helpers.createAndJoinWallet(1, 1, function(s, w) { |
|
|
derivationStrategy: 'BIP45' |
|
|
|
|
|
}, function(s, w) { |
|
|
|
|
|
server = s; |
|
|
server = s; |
|
|
wallet = w; |
|
|
wallet = w; |
|
|
|
|
|
w.copayers[0].id.should.equal(TestData.copayers[0].id44); |
|
|
done(); |
|
|
done(); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
@ -1444,16 +1412,16 @@ describe('Wallet service', function() { |
|
|
should.exist(address); |
|
|
should.exist(address); |
|
|
address.walletId.should.equal(wallet.id); |
|
|
address.walletId.should.equal(wallet.id); |
|
|
address.network.should.equal('livenet'); |
|
|
address.network.should.equal('livenet'); |
|
|
address.address.should.equal('3BVJZ4CYzeTtawDtgwHvWV5jbvnXtYe97i'); |
|
|
address.address.should.equal('3J4J9nkFpzQjUGDh5hLKMKztFSPWMKejKE'); |
|
|
address.isChange.should.be.false; |
|
|
address.isChange.should.be.false; |
|
|
address.path.should.equal('m/2147483647/0/0'); |
|
|
address.path.should.equal('m/0/0'); |
|
|
server.getNotifications({}, function(err, notifications) { |
|
|
server.getNotifications({}, function(err, notifications) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
var notif = _.find(notifications, { |
|
|
var notif = _.find(notifications, { |
|
|
type: 'NewAddress' |
|
|
type: 'NewAddress' |
|
|
}); |
|
|
}); |
|
|
should.exist(notif); |
|
|
should.exist(notif); |
|
|
notif.data.address.should.equal('3BVJZ4CYzeTtawDtgwHvWV5jbvnXtYe97i'); |
|
|
notif.data.address.should.equal(address.address); |
|
|
done(); |
|
|
done(); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
@ -1466,7 +1434,7 @@ describe('Wallet service', function() { |
|
|
}, function(err, addresses) { |
|
|
}, function(err, addresses) { |
|
|
addresses.length.should.equal(N); |
|
|
addresses.length.should.equal(N); |
|
|
_.each(_.range(N), function(i) { |
|
|
_.each(_.range(N), function(i) { |
|
|
addresses[i].path.should.equal('m/2147483647/0/' + i); |
|
|
addresses[i].path.should.equal('m/0/' + i); |
|
|
}); |
|
|
}); |
|
|
// No two identical addresses
|
|
|
// No two identical addresses
|
|
|
_.uniq(_.pluck(addresses, 'address')).length.should.equal(N); |
|
|
_.uniq(_.pluck(addresses, 'address')).length.should.equal(N); |
|
@ -1679,10 +1647,10 @@ describe('Wallet service', function() { |
|
|
reqPrivKey = new Bitcore.PrivateKey(); |
|
|
reqPrivKey = new Bitcore.PrivateKey(); |
|
|
var requestPubKey = reqPrivKey.toPublicKey(); |
|
|
var requestPubKey = reqPrivKey.toPublicKey(); |
|
|
|
|
|
|
|
|
var xPrivKey = TestData.copayers[0].xPrivKey_44H_0H_0H; |
|
|
var xPrivKey = TestData.copayers[0].xPrivKey_45H; |
|
|
var sig = WalletUtils.signRequestPubKey(requestPubKey, xPrivKey); |
|
|
var sig = WalletUtils.signRequestPubKey(requestPubKey, xPrivKey); |
|
|
|
|
|
|
|
|
var copayerId = WalletUtils.xPubToCopayerId(TestData.copayers[0].xPubKey_44H_0H_0H); |
|
|
var copayerId = WalletUtils.xPubToCopayerId(TestData.copayers[0].xPubKey_45H); |
|
|
opts = { |
|
|
opts = { |
|
|
copayerId: copayerId, |
|
|
copayerId: copayerId, |
|
|
requestPubKey: requestPubKey, |
|
|
requestPubKey: requestPubKey, |
|
@ -1693,7 +1661,9 @@ describe('Wallet service', function() { |
|
|
|
|
|
|
|
|
describe('#addAccess 1-1', function() { |
|
|
describe('#addAccess 1-1', function() { |
|
|
beforeEach(function(done) { |
|
|
beforeEach(function(done) { |
|
|
helpers.createAndJoinWallet(1, 1, function(s, w) { |
|
|
helpers.createAndJoinWallet(1, 1, { |
|
|
|
|
|
supportBIP44: false |
|
|
|
|
|
}, function(s, w) { |
|
|
server = s; |
|
|
server = s; |
|
|
wallet = w; |
|
|
wallet = w; |
|
|
|
|
|
|
|
@ -1703,7 +1673,7 @@ describe('Wallet service', function() { |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
it('should be able to re-gain access from xPrivKey', function(done) { |
|
|
it('should be able to re-gain access from xPrivKey', function(done) { |
|
|
ws.addAccess(opts, function(err, res) { |
|
|
ws.addAccess(opts, function(err, res) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
res.wallet.copayers[0].requestPubKeys.length.should.equal(2); |
|
|
res.wallet.copayers[0].requestPubKeys.length.should.equal(2); |
|
@ -4387,124 +4357,125 @@ describe('Wallet service', function() { |
|
|
describe('#scan', function() { |
|
|
describe('#scan', function() { |
|
|
var server, wallet; |
|
|
var server, wallet; |
|
|
var scanConfigOld = WalletService.SCAN_CONFIG; |
|
|
var scanConfigOld = WalletService.SCAN_CONFIG; |
|
|
beforeEach(function(done) { |
|
|
|
|
|
this.timeout(5000); |
|
|
|
|
|
WalletService.SCAN_CONFIG.scanWindow = 2; |
|
|
|
|
|
WalletService.SCAN_CONFIG.derivationDelay = 0; |
|
|
|
|
|
|
|
|
|
|
|
helpers.createAndJoinWallet(1, 2, function(s, w) { |
|
|
describe('1-of-1 wallet (BIP44)', function() { |
|
|
server = s; |
|
|
beforeEach(function(done) { |
|
|
wallet = w; |
|
|
this.timeout(5000); |
|
|
done(); |
|
|
WalletService.SCAN_CONFIG.scanWindow = 2; |
|
|
|
|
|
WalletService.SCAN_CONFIG.derivationDelay = 0; |
|
|
|
|
|
|
|
|
|
|
|
helpers.createAndJoinWallet(1, 1, function(s, w) { |
|
|
|
|
|
server = s; |
|
|
|
|
|
wallet = w; |
|
|
|
|
|
done(); |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
afterEach(function() { |
|
|
|
|
|
WalletService.SCAN_CONFIG = scanConfigOld; |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
afterEach(function() { |
|
|
|
|
|
WalletService.SCAN_CONFIG = scanConfigOld; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should scan main addresses', function(done) { |
|
|
it('should scan main addresses', function(done) { |
|
|
helpers.stubAddressActivity( |
|
|
helpers.stubAddressActivity( |
|
|
['3Jc2hcN13vGBCdWR4SMNRoL9EUiBHuf4LT', // m/0/0
|
|
|
['3J4J9nkFpzQjUGDh5hLKMKztFSPWMKejKE', // m/0/0
|
|
|
'3Pk2Cn3TW6JLhGEnHg8iM2qtmx2T1uHyZM', // m/0/2
|
|
|
'384JHSf9kVBs3yXsPwCzEScRs395u8hwxj', // m/0/2
|
|
|
'3GqrwYwyLt1czKMvvqFwYj2ZeooiHtbgbc', // m/1/0
|
|
|
'3NgXBiMQvwcRU8khVoPFJ6gsbGg9ZYrRzH', // m/1/0
|
|
|
]); |
|
|
]); |
|
|
var expectedPaths = [ |
|
|
var expectedPaths = [ |
|
|
'm/0/0', |
|
|
'm/0/0', |
|
|
'm/0/1', |
|
|
'm/0/1', |
|
|
'm/0/2', |
|
|
'm/0/2', |
|
|
'm/0/3', |
|
|
'm/0/3', |
|
|
'm/1/0', |
|
|
'm/1/0', |
|
|
'm/1/1', |
|
|
'm/1/1', |
|
|
]; |
|
|
]; |
|
|
server.scan({}, function(err) { |
|
|
server.scan({}, function(err) { |
|
|
should.not.exist(err); |
|
|
|
|
|
server.getWallet({}, function(err, wallet) { |
|
|
|
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
wallet.scanStatus.should.equal('success'); |
|
|
server.getWallet({}, function(err, wallet) { |
|
|
server.storage.fetchAddresses(wallet.id, function(err, addresses) { |
|
|
should.not.exist(err); |
|
|
should.exist(addresses); |
|
|
wallet.scanStatus.should.equal('success'); |
|
|
addresses.length.should.equal(expectedPaths.length); |
|
|
server.storage.fetchAddresses(wallet.id, function(err, addresses) { |
|
|
var paths = _.pluck(addresses, 'path'); |
|
|
should.exist(addresses); |
|
|
_.difference(paths, expectedPaths).length.should.equal(0); |
|
|
addresses.length.should.equal(expectedPaths.length); |
|
|
server.createAddress({}, function(err, address) { |
|
|
var paths = _.pluck(addresses, 'path'); |
|
|
should.not.exist(err); |
|
|
_.difference(paths, expectedPaths).length.should.equal(0); |
|
|
address.path.should.equal('m/0/4'); |
|
|
server.createAddress({}, function(err, address) { |
|
|
done(); |
|
|
should.not.exist(err); |
|
|
|
|
|
address.path.should.equal('m/0/4'); |
|
|
|
|
|
done(); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
it('should restore wallet balance', function(done) { |
|
|
it('should restore wallet balance', function(done) { |
|
|
async.waterfall([ |
|
|
async.waterfall([ |
|
|
|
|
|
|
|
|
|
|
|
function(next) { |
|
|
function(next) { |
|
|
helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { |
|
|
helpers.stubUtxos(server, wallet, [1, 2, 3], function(utxos) { |
|
|
should.exist(utxos); |
|
|
should.exist(utxos); |
|
|
helpers.stubAddressActivity(_.pluck(utxos, 'address')); |
|
|
helpers.stubAddressActivity(_.pluck(utxos, 'address')); |
|
|
server.getBalance({}, function(err, balance) { |
|
|
server.getBalance({}, function(err, balance) { |
|
|
balance.totalAmount.should.equal(helpers.toSatoshi(6)); |
|
|
balance.totalAmount.should.equal(helpers.toSatoshi(6)); |
|
|
next(null, server, wallet); |
|
|
next(null, server, wallet); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
function(server, wallet, next) { |
|
|
function(server, wallet, next) { |
|
|
server.removeWallet({}, function(err) { |
|
|
server.removeWallet({}, function(err) { |
|
|
next(err); |
|
|
next(err); |
|
|
|
|
|
}); |
|
|
|
|
|
}, |
|
|
|
|
|
function(next) { |
|
|
|
|
|
// NOTE: this works because it creates the exact same wallet!
|
|
|
|
|
|
helpers.createAndJoinWallet(1, 2, function(server, wallet) { |
|
|
|
|
|
server.getBalance({}, function(err, balance) { |
|
|
|
|
|
balance.totalAmount.should.equal(0); |
|
|
|
|
|
next(null, server, wallet); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
function(next) { |
|
|
function(server, wallet, next) { |
|
|
// NOTE: this works because it creates the exact same wallet!
|
|
|
server.scan({}, function(err) { |
|
|
helpers.createAndJoinWallet(1, 1, function(server, wallet) { |
|
|
should.not.exist(err); |
|
|
server.getBalance({}, function(err, balance) { |
|
|
server.getBalance(wallet.id, function(err, balance) { |
|
|
balance.totalAmount.should.equal(0); |
|
|
balance.totalAmount.should.equal(helpers.toSatoshi(6)); |
|
|
next(null, server, wallet); |
|
|
next(); |
|
|
}); |
|
|
}) |
|
|
}); |
|
|
}); |
|
|
}, |
|
|
}, |
|
|
function(server, wallet, next) { |
|
|
], function(err) { |
|
|
server.scan({}, function(err) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
done(); |
|
|
server.getBalance(wallet.id, function(err, balance) { |
|
|
}); |
|
|
balance.totalAmount.should.equal(helpers.toSatoshi(6)); |
|
|
}); |
|
|
next(); |
|
|
it('should abort scan if there is an error checking address activity', function(done) { |
|
|
}) |
|
|
blockchainExplorer.getAddressActivity = sinon.stub().callsArgWith(1, 'dummy error'); |
|
|
}); |
|
|
server.scan({}, function(err) { |
|
|
}, |
|
|
should.exist(err); |
|
|
], function(err) { |
|
|
err.toString().should.equal('dummy error'); |
|
|
|
|
|
server.getWallet({}, function(err, wallet) { |
|
|
|
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
wallet.scanStatus.should.equal('error'); |
|
|
done(); |
|
|
wallet.addressManager.receiveAddressIndex.should.equal(0); |
|
|
}); |
|
|
wallet.addressManager.changeAddressIndex.should.equal(0); |
|
|
}); |
|
|
server.storage.fetchAddresses(wallet.id, function(err, addresses) { |
|
|
it('should abort scan if there is an error checking address activity', function(done) { |
|
|
|
|
|
blockchainExplorer.getAddressActivity = sinon.stub().callsArgWith(1, 'dummy error'); |
|
|
|
|
|
server.scan({}, function(err) { |
|
|
|
|
|
should.exist(err); |
|
|
|
|
|
err.toString().should.equal('dummy error'); |
|
|
|
|
|
server.getWallet({}, function(err, wallet) { |
|
|
should.not.exist(err); |
|
|
should.not.exist(err); |
|
|
addresses.should.be.empty; |
|
|
wallet.scanStatus.should.equal('error'); |
|
|
done(); |
|
|
wallet.addressManager.receiveAddressIndex.should.equal(0); |
|
|
|
|
|
wallet.addressManager.changeAddressIndex.should.equal(0); |
|
|
|
|
|
server.storage.fetchAddresses(wallet.id, function(err, addresses) { |
|
|
|
|
|
should.not.exist(err); |
|
|
|
|
|
addresses.should.be.empty; |
|
|
|
|
|
done(); |
|
|
|
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
describe('BIP45', function() { |
|
|
describe('shared wallet (BIP45)', function() { |
|
|
|
|
|
|
|
|
beforeEach(function(done) { |
|
|
beforeEach(function(done) { |
|
|
this.timeout(5000); |
|
|
this.timeout(5000); |
|
|
WalletService.SCAN_CONFIG.scanWindow = 2; |
|
|
WalletService.SCAN_CONFIG.scanWindow = 2; |
|
|
WalletService.SCAN_CONFIG.derivationDelay = 0; |
|
|
WalletService.SCAN_CONFIG.derivationDelay = 0; |
|
|
|
|
|
|
|
|
helpers.createAndJoinWallet(1, 2, { |
|
|
helpers.createAndJoinWallet(1, 2, function(s, w) { |
|
|
derivationStrategy: 'BIP45' |
|
|
|
|
|
}, function(s, w) { |
|
|
|
|
|
server = s; |
|
|
server = s; |
|
|
wallet = w; |
|
|
wallet = w; |
|
|
done(); |
|
|
done(); |
|
@ -4591,7 +4562,7 @@ describe('Wallet service', function() { |
|
|
WalletService.SCAN_CONFIG.scanWindow = 2; |
|
|
WalletService.SCAN_CONFIG.scanWindow = 2; |
|
|
WalletService.SCAN_CONFIG.derivationDelay = 0; |
|
|
WalletService.SCAN_CONFIG.derivationDelay = 0; |
|
|
|
|
|
|
|
|
helpers.createAndJoinWallet(1, 2, function(s, w) { |
|
|
helpers.createAndJoinWallet(1, 1, function(s, w) { |
|
|
server = s; |
|
|
server = s; |
|
|
wallet = w; |
|
|
wallet = w; |
|
|
done(); |
|
|
done(); |
|
@ -4604,9 +4575,9 @@ describe('Wallet service', function() { |
|
|
|
|
|
|
|
|
it('should start an asynchronous scan', function(done) { |
|
|
it('should start an asynchronous scan', function(done) { |
|
|
helpers.stubAddressActivity( |
|
|
helpers.stubAddressActivity( |
|
|
['3Jc2hcN13vGBCdWR4SMNRoL9EUiBHuf4LT', // m/0/0
|
|
|
['3J4J9nkFpzQjUGDh5hLKMKztFSPWMKejKE', // m/0/0
|
|
|
'3Pk2Cn3TW6JLhGEnHg8iM2qtmx2T1uHyZM', // m/0/2
|
|
|
'384JHSf9kVBs3yXsPwCzEScRs395u8hwxj', // m/0/2
|
|
|
'3GqrwYwyLt1czKMvvqFwYj2ZeooiHtbgbc', // m/1/0
|
|
|
'3NgXBiMQvwcRU8khVoPFJ6gsbGg9ZYrRzH', // m/1/0
|
|
|
]); |
|
|
]); |
|
|
var expectedPaths = [ |
|
|
var expectedPaths = [ |
|
|
'm/0/0', |
|
|
'm/0/0', |
|
|