FIX: scan multisig cosigner in formats: plain Zpub, wallet descriptor

This commit is contained in:
Overtorment 2020-12-08 14:58:16 +00:00
parent cee135a183
commit a9aa213b21
2 changed files with 102 additions and 0 deletions

View File

@ -1,3 +1,6 @@
import b58 from 'bs58check';
const HDNode = require('bip32');
export class MultisigCosigner {
constructor(data) {
this._data = data;
@ -7,6 +10,50 @@ export class MultisigCosigner {
this._valid = false;
this._cosigners = [];
// is it plain simple Zpub/Ypub/xpub?
if (data.startsWith('Zpub') && MultisigCosigner.isXpubValid(data)) {
this._fp = '00000000';
this._xpub = data;
this._path = "m/48'/0'/0'/2'";
this._valid = true;
this._cosigners = [true];
return;
} else if (data.startsWith('Ypub') && MultisigCosigner.isXpubValid(data)) {
this._fp = '00000000';
this._xpub = data;
this._path = "m/48'/0'/0'/1'";
this._valid = true;
this._cosigners = [true];
return;
} else if (data.startsWith('xpub') && MultisigCosigner.isXpubValid(data)) {
this._fp = '00000000';
this._xpub = data;
this._path = "m/45'";
this._valid = true;
this._cosigners = [true];
return;
}
// is it wallet descriptor?
if (data.startsWith('[')) {
const end = data.indexOf(']');
const part = data.substr(1, end - 1).replace(/[h]/g, "'");
this._fp = part.split('/')[0];
const xpub = data.substr(end + 1);
if (MultisigCosigner.isXpubValid(xpub)) {
this._xpub = xpub;
this._path = 'm';
for (let c = 0; c < part.split('/').length; c++) {
if (c === 0) continue;
this._path += '/' + part.split('/')[c];
}
this._cosigners = [true];
this._valid = true;
return;
}
}
// is it cobo json?
try {
const json = JSON.parse(data);
@ -47,6 +94,26 @@ export class MultisigCosigner {
}
}
static _zpubToXpub(zpub) {
let data = b58.decode(zpub);
data = data.slice(4);
data = Buffer.concat([Buffer.from('0488b21e', 'hex'), data]);
return b58.encode(data);
}
static isXpubValid(key) {
let xpub;
try {
xpub = MultisigCosigner._zpubToXpub(key);
HDNode.fromBase58(xpub);
return true;
} catch (_) {}
return false;
}
static exportToJson(xfp, xpub, path) {
return JSON.stringify({
xfp: xfp,

View File

@ -1582,6 +1582,41 @@ describe('multisig-cosigner', () => {
assert.strictEqual(cosigner.howManyCosignersWeHave(), 1);
});
it('can parse plain Zpub', () => {
const cosigner = new MultisigCosigner(Zpub1);
assert.ok(cosigner.isValid());
assert.strictEqual(cosigner.getFp(), '00000000');
assert.strictEqual(cosigner.getXpub(), Zpub1);
assert.strictEqual(cosigner.getPath(), "m/48'/0'/0'/2'");
assert.strictEqual(cosigner.howManyCosignersWeHave(), 1);
});
it('can parse wallet descriptor', () => {
let cosigner = new MultisigCosigner(
'[73c5da0a/48h/0h/0h/2h]Zpub74Jru6aftwwHxCUCWEvP6DgrfFsdA4U6ZRtQ5i8qJpMcC39yZGv3egBhQfV3MS9pZtH5z8iV5qWkJsK6ESs6mSzt4qvGhzJxPeeVS2e1zUG',
);
assert.ok(cosigner.isValid());
assert.strictEqual(cosigner.getFp(), '73c5da0a');
assert.strictEqual(
cosigner.getXpub(),
'Zpub74Jru6aftwwHxCUCWEvP6DgrfFsdA4U6ZRtQ5i8qJpMcC39yZGv3egBhQfV3MS9pZtH5z8iV5qWkJsK6ESs6mSzt4qvGhzJxPeeVS2e1zUG',
);
assert.strictEqual(cosigner.getPath(), "m/48'/0'/0'/2'");
assert.strictEqual(cosigner.howManyCosignersWeHave(), 1);
cosigner = new MultisigCosigner(
'[73c5da0a/48h/0h/0h/2h]xpub6DkFAXWQ2dHxq2vatrt9qyA3bXYU4ToWQwCHbf5XB2mSTexcHZCeKS1VZYcPoBd5X8yVcbXFHJR9R8UCVpt82VX1VhR28mCyxUFL4r6KFrf',
);
assert.ok(cosigner.isValid());
assert.strictEqual(cosigner.getFp(), '73c5da0a');
assert.strictEqual(
cosigner.getXpub(),
'xpub6DkFAXWQ2dHxq2vatrt9qyA3bXYU4ToWQwCHbf5XB2mSTexcHZCeKS1VZYcPoBd5X8yVcbXFHJR9R8UCVpt82VX1VhR28mCyxUFL4r6KFrf',
);
assert.strictEqual(cosigner.getPath(), "m/48'/0'/0'/2'");
assert.strictEqual(cosigner.howManyCosignersWeHave(), 1);
});
it('cant parse bs', () => {
const cosigner = new MultisigCosigner('asdfasdgsqwrgqwegq');
assert.ok(!cosigner.isValid());