allow addressManager to handle BIP44 derivations
This commit is contained in:
parent
a6362524f5
commit
a4f1169aa9
|
@ -1,4 +1,10 @@
|
||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
var $ = require('preconditions').singleton();
|
||||||
|
|
||||||
|
var STRATEGIES = {
|
||||||
|
BIP44: 'BIP44',
|
||||||
|
BIP45: 'BIP45',
|
||||||
|
};
|
||||||
|
|
||||||
var SHARED_INDEX = 0x80000000 - 1;
|
var SHARED_INDEX = 0x80000000 - 1;
|
||||||
|
|
||||||
|
@ -9,7 +15,10 @@ AddressManager.create = function(opts) {
|
||||||
|
|
||||||
var x = new AddressManager();
|
var x = new AddressManager();
|
||||||
|
|
||||||
x.version = '1.0.0';
|
x.version = 2;
|
||||||
|
x.derivationStrategy = opts.derivationStrategy || STRATEGIES.BIP44;
|
||||||
|
$.checkState(_.contains(_.values(STRATEGIES), x.derivationStrategy));
|
||||||
|
|
||||||
x.receiveAddressIndex = 0;
|
x.receiveAddressIndex = 0;
|
||||||
x.changeAddressIndex = 0;
|
x.changeAddressIndex = 0;
|
||||||
x.copayerIndex = (opts && _.isNumber(opts.copayerIndex)) ? opts.copayerIndex : SHARED_INDEX;
|
x.copayerIndex = (opts && _.isNumber(opts.copayerIndex)) ? opts.copayerIndex : SHARED_INDEX;
|
||||||
|
@ -17,11 +26,11 @@ AddressManager.create = function(opts) {
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
AddressManager.fromObj = function(obj) {
|
AddressManager.fromObj = function(obj) {
|
||||||
var x = new AddressManager();
|
var x = new AddressManager();
|
||||||
|
|
||||||
x.version = obj.version;
|
x.version = obj.version;
|
||||||
|
x.derivationStrategy = obj.derivationStrategy || STRATEGIES.BIP45;
|
||||||
x.receiveAddressIndex = obj.receiveAddressIndex;
|
x.receiveAddressIndex = obj.receiveAddressIndex;
|
||||||
x.changeAddressIndex = obj.changeAddressIndex;
|
x.changeAddressIndex = obj.changeAddressIndex;
|
||||||
x.copayerIndex = obj.copayerIndex;
|
x.copayerIndex = obj.copayerIndex;
|
||||||
|
@ -29,6 +38,10 @@ AddressManager.fromObj = function(obj) {
|
||||||
return x;
|
return x;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AddressManager.prototype.supportsDerivation = function() {
|
||||||
|
// BIP44 does not support copayer specific indexes
|
||||||
|
return !(this.derivationStrategy == STRATEGIES.BIP44 && this.copayerIndex != SHARED_INDEX);
|
||||||
|
};
|
||||||
|
|
||||||
AddressManager.prototype._incrementIndex = function(isChange) {
|
AddressManager.prototype._incrementIndex = function(isChange) {
|
||||||
if (isChange) {
|
if (isChange) {
|
||||||
|
@ -49,7 +62,7 @@ AddressManager.prototype.rewindIndex = function(isChange, n) {
|
||||||
|
|
||||||
AddressManager.prototype.getCurrentAddressPath = function(isChange) {
|
AddressManager.prototype.getCurrentAddressPath = function(isChange) {
|
||||||
return 'm/' +
|
return 'm/' +
|
||||||
this.copayerIndex + '/' +
|
(this.derivationStrategy == STRATEGIES.BIP45 ? this.copayerIndex + '/' : '') +
|
||||||
(isChange ? 1 : 0) + '/' +
|
(isChange ? 1 : 0) + '/' +
|
||||||
(isChange ? this.changeAddressIndex : this.receiveAddressIndex);
|
(isChange ? this.changeAddressIndex : this.receiveAddressIndex);
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,34 +8,62 @@ var AddressManager = require('../../lib/model/addressmanager');
|
||||||
|
|
||||||
|
|
||||||
describe('AddressManager', function() {
|
describe('AddressManager', function() {
|
||||||
|
describe('#create', function() {
|
||||||
|
it('should create BIP44 address manager by default', function() {
|
||||||
|
var am = AddressManager.create();
|
||||||
|
am.derivationStrategy.should.equal('BIP44');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#fromObj', function() {
|
||||||
|
it('should assume legacy address manager uses BIP45', function() {
|
||||||
|
var obj = {
|
||||||
|
version: '1.0.0',
|
||||||
|
receiveAddressIndex: 2,
|
||||||
|
changeAddressIndex: 0,
|
||||||
|
copayerIndex: 4
|
||||||
|
};
|
||||||
|
var am = AddressManager.fromObj(obj);
|
||||||
|
am.derivationStrategy.should.equal('BIP45');
|
||||||
|
am.getCurrentAddressPath(false).should.equal('m/4/0/2');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('BIP45', function() {
|
||||||
describe('#getCurrentAddressPath', function() {
|
describe('#getCurrentAddressPath', function() {
|
||||||
it('should return a valid BIP32 path for given index', function() {
|
it('should return a valid BIP32 path for given index', function() {
|
||||||
var am = AddressManager.create({
|
var am = AddressManager.create({
|
||||||
copayerIndex: 4
|
derivationStrategy: 'BIP45',
|
||||||
|
copayerIndex: 4,
|
||||||
});
|
});
|
||||||
|
am.supportsDerivation().should.be.true;
|
||||||
am.getCurrentAddressPath(false).should.equal('m/4/0/0');
|
am.getCurrentAddressPath(false).should.equal('m/4/0/0');
|
||||||
am.getCurrentAddressPath(true).should.equal('m/4/1/0');
|
am.getCurrentAddressPath(true).should.equal('m/4/1/0');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#getCurrentAddressPath', function() {
|
|
||||||
it('should return a valid BIP32 path for defaut Index', function() {
|
it('should return a valid BIP32 path for defaut Index', function() {
|
||||||
var am = AddressManager.create();
|
var am = AddressManager.create({
|
||||||
|
derivationStrategy: 'BIP45',
|
||||||
|
});
|
||||||
|
am.supportsDerivation().should.be.true;
|
||||||
am.getCurrentAddressPath(false).should.equal('m/2147483647/0/0');
|
am.getCurrentAddressPath(false).should.equal('m/2147483647/0/0');
|
||||||
am.getCurrentAddressPath(true).should.equal('m/2147483647/1/0');
|
am.getCurrentAddressPath(true).should.equal('m/2147483647/1/0');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
describe('#getNewAddressPath', function() {
|
describe('#getNewAddressPath', function() {
|
||||||
it('should return a new valid BIP32 path for given index', function() {
|
it('should return a new valid BIP32 path for given index', function() {
|
||||||
var am = AddressManager.create({
|
var am = AddressManager.create({
|
||||||
copayerIndex: 2
|
derivationStrategy: 'BIP45',
|
||||||
|
copayerIndex: 2,
|
||||||
});
|
});
|
||||||
am.getNewAddressPath(false).should.equal('m/2/0/0');
|
am.getNewAddressPath(false).should.equal('m/2/0/0');
|
||||||
am.getNewAddressPath(true).should.equal('m/2/1/0');
|
am.getNewAddressPath(true).should.equal('m/2/1/0');
|
||||||
|
am.getNewAddressPath(false).should.equal('m/2/0/1');
|
||||||
|
am.getNewAddressPath(true).should.equal('m/2/1/1');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
describe('#rewindIndex', function() {
|
describe('#rewindIndex', function() {
|
||||||
it('should rewind main index', function() {
|
it('should rewind main index', function() {
|
||||||
var am = AddressManager.create({});
|
var am = AddressManager.create({
|
||||||
|
derivationStrategy: 'BIP45',
|
||||||
|
});
|
||||||
am.getNewAddressPath(false).should.equal('m/2147483647/0/0');
|
am.getNewAddressPath(false).should.equal('m/2147483647/0/0');
|
||||||
am.getNewAddressPath(false).should.equal('m/2147483647/0/1');
|
am.getNewAddressPath(false).should.equal('m/2147483647/0/1');
|
||||||
am.getNewAddressPath(false).should.equal('m/2147483647/0/2');
|
am.getNewAddressPath(false).should.equal('m/2147483647/0/2');
|
||||||
|
@ -43,7 +71,9 @@ describe('AddressManager', function() {
|
||||||
am.getNewAddressPath(false).should.equal('m/2147483647/0/1');
|
am.getNewAddressPath(false).should.equal('m/2147483647/0/1');
|
||||||
});
|
});
|
||||||
it('should rewind change index', function() {
|
it('should rewind change index', function() {
|
||||||
var am = AddressManager.create({});
|
var am = AddressManager.create({
|
||||||
|
derivationStrategy: 'BIP45',
|
||||||
|
});
|
||||||
am.getNewAddressPath(true).should.equal('m/2147483647/1/0');
|
am.getNewAddressPath(true).should.equal('m/2147483647/1/0');
|
||||||
am.rewindIndex(false, 1);
|
am.rewindIndex(false, 1);
|
||||||
am.getNewAddressPath(true).should.equal('m/2147483647/1/1');
|
am.getNewAddressPath(true).should.equal('m/2147483647/1/1');
|
||||||
|
@ -51,10 +81,64 @@ describe('AddressManager', function() {
|
||||||
am.getNewAddressPath(true).should.equal('m/2147483647/1/0');
|
am.getNewAddressPath(true).should.equal('m/2147483647/1/0');
|
||||||
});
|
});
|
||||||
it('should stop at 0', function() {
|
it('should stop at 0', function() {
|
||||||
var am = AddressManager.create({});
|
var am = AddressManager.create({
|
||||||
|
derivationStrategy: 'BIP45',
|
||||||
|
});
|
||||||
am.getNewAddressPath(false).should.equal('m/2147483647/0/0');
|
am.getNewAddressPath(false).should.equal('m/2147483647/0/0');
|
||||||
am.rewindIndex(false, 20);
|
am.rewindIndex(false, 20);
|
||||||
am.getNewAddressPath(false).should.equal('m/2147483647/0/0');
|
am.getNewAddressPath(false).should.equal('m/2147483647/0/0');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
describe('BIP44', function() {
|
||||||
|
describe('#getCurrentAddressPath', function() {
|
||||||
|
it('should return first address path', function() {
|
||||||
|
var am = AddressManager.create();
|
||||||
|
am.supportsDerivation().should.be.true;
|
||||||
|
am.getCurrentAddressPath(false).should.equal('m/0/0');
|
||||||
|
am.getCurrentAddressPath(true).should.equal('m/1/0');
|
||||||
|
});
|
||||||
|
it('should return address path independently of copayerIndex', function() {
|
||||||
|
var am = AddressManager.create({
|
||||||
|
copayerIndex: 4,
|
||||||
|
});
|
||||||
|
am.supportsDerivation().should.be.false;
|
||||||
|
am.getCurrentAddressPath(false).should.equal('m/0/0');
|
||||||
|
am.getCurrentAddressPath(true).should.equal('m/1/0');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#getNewAddressPath', function() {
|
||||||
|
it('should return a new path', function() {
|
||||||
|
var am = AddressManager.create();
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/0');
|
||||||
|
am.getNewAddressPath(true).should.equal('m/1/0');
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/1');
|
||||||
|
am.getNewAddressPath(true).should.equal('m/1/1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('#rewindIndex', function() {
|
||||||
|
it('should rewind main index', function() {
|
||||||
|
var am = AddressManager.create();
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/0');
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/1');
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/2');
|
||||||
|
am.rewindIndex(false, 2);
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/1');
|
||||||
|
});
|
||||||
|
it('should rewind change index', function() {
|
||||||
|
var am = AddressManager.create();
|
||||||
|
am.getNewAddressPath(true).should.equal('m/1/0');
|
||||||
|
am.rewindIndex(false, 1);
|
||||||
|
am.getNewAddressPath(true).should.equal('m/1/1');
|
||||||
|
am.rewindIndex(true, 2);
|
||||||
|
am.getNewAddressPath(true).should.equal('m/1/0');
|
||||||
|
});
|
||||||
|
it('should stop at 0', function() {
|
||||||
|
var am = AddressManager.create();
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/0');
|
||||||
|
am.rewindIndex(false, 20);
|
||||||
|
am.getNewAddressPath(false).should.equal('m/0/0');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue