mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2025-03-04 04:13:49 +01:00
FIX: import multisig from caravan & fullynoded
This commit is contained in:
parent
299535a570
commit
d17b746cdf
3 changed files with 99 additions and 8 deletions
|
@ -452,6 +452,72 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
|
|||
}
|
||||
}
|
||||
|
||||
// is it wallet descriptor?
|
||||
// @see https://github.com/bitcoin/bitcoin/blob/master/doc/descriptors.md
|
||||
// @see https://github.com/Fonta1n3/FullyNoded/blob/master/Docs/Wallets/Wallet-Export-Spec.md
|
||||
if (secret.indexOf('sortedmulti(') !== -1 && json.descriptor) {
|
||||
if (json.label) this.setLabel(json.label);
|
||||
if (json.descriptor.startsWith('wsh(')) {
|
||||
this.setNativeSegwit();
|
||||
}
|
||||
if (json.descriptor.startsWith('sh(')) {
|
||||
this.setLegacy();
|
||||
}
|
||||
if (json.descriptor.startsWith('sh(wsh(')) {
|
||||
this.setLegacy();
|
||||
}
|
||||
|
||||
const s2 = json.descriptor.substr(json.descriptor.indexOf('sortedmulti(') + 12);
|
||||
const s3 = s2.split(',');
|
||||
const m = parseInt(s3[0]);
|
||||
if (m) this.setM(m);
|
||||
|
||||
for (let c = 1; c < s3.length; c++) {
|
||||
const re = /\[([^\]]+)\](.*)/;
|
||||
const m = s3[c].match(re);
|
||||
if (m && m.length === 3) {
|
||||
let hexFingerprint = m[1].split('/')[0];
|
||||
if (hexFingerprint.length === 8) {
|
||||
hexFingerprint = Buffer.from(hexFingerprint, 'hex').reverse().toString('hex');
|
||||
}
|
||||
|
||||
const path = 'm/' + m[1].split('/').slice(1).join('/').replace(/[h]/g, "'");
|
||||
let xpub = m[2];
|
||||
if (xpub.indexOf('/') !== -1) {
|
||||
xpub = xpub.substr(0, xpub.indexOf('/'));
|
||||
}
|
||||
|
||||
// console.warn('m[2] = ', m[2], {hexFingerprint, path, xpub});
|
||||
this.addCosigner(xpub, hexFingerprint.toUpperCase(), path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// is it caravan?
|
||||
if (json && json.network === 'mainnet' && json.quorum) {
|
||||
this.setM(+json.quorum.requiredSigners);
|
||||
if (json.name) this.setLabel(json.name);
|
||||
|
||||
switch (json.addressType.toLowerCase()) {
|
||||
case 'P2SH':
|
||||
this.setLegacy();
|
||||
break;
|
||||
case 'P2SH-P2WSH':
|
||||
this.setWrappedSegwit();
|
||||
break;
|
||||
default:
|
||||
case 'P2WSH':
|
||||
this.setNativeSegwit();
|
||||
break;
|
||||
}
|
||||
|
||||
for (const pk of json.extendedPublicKeys) {
|
||||
const path = this.constructor.isPathValid(json.bip32Path) ? json.bip32Path : "m/1'";
|
||||
// wtf, where caravan stores fingerprints..?
|
||||
this.addCosigner(pk.xpub, '00000000', path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.getLabel()) this.setLabel('Multisig vault');
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@
|
|||
"setupFiles": [
|
||||
"./tests/setup.js"
|
||||
],
|
||||
"watchPathIgnorePatterns": [
|
||||
"<rootDir>/node_modules"
|
||||
],
|
||||
"setupFilesAfterEnv": [
|
||||
"./tests/setupAfterEnv.js"
|
||||
]
|
||||
|
|
|
@ -597,6 +597,7 @@ describe('multisig-wallet (native segwit)', () => {
|
|||
assert.ok(MultisigHDWallet.isPathValid("m/45'"));
|
||||
assert.ok(MultisigHDWallet.isPathValid("m/48'/0'/0'/2'"));
|
||||
assert.ok(!MultisigHDWallet.isPathValid('ROFLBOATS'));
|
||||
assert.ok(!MultisigHDWallet.isPathValid(''));
|
||||
});
|
||||
|
||||
it('basic operations work', async () => {
|
||||
|
@ -1184,7 +1185,7 @@ describe('multisig-wallet (native segwit)', () => {
|
|||
assert.strictEqual(w.getN(), 0);
|
||||
});
|
||||
|
||||
it.skip('can import from caravan', () => {
|
||||
it('can import from caravan', () => {
|
||||
const json = JSON.stringify({
|
||||
name: 'My Multisig Wallet',
|
||||
addressType: 'P2WSH',
|
||||
|
@ -1268,17 +1269,15 @@ describe('multisig-wallet (native segwit)', () => {
|
|||
|
||||
assert.strictEqual(w.getM(), 2);
|
||||
assert.strictEqual(w.getN(), 2);
|
||||
// assert.strictEqual(w.getCosigner(1), Zpub1);
|
||||
// assert.strictEqual(w.getCosigner(2), Zpub2);
|
||||
assert.strictEqual(w.getFingerprint(1), fp1cobo);
|
||||
assert.strictEqual(w.getFingerprint(2), fp2coldcard);
|
||||
assert.strictEqual(w.getFingerprint(1), '00000000'); // should be fp1cobo, but stupid caravan doesnt store fp
|
||||
assert.strictEqual(w.getFingerprint(2), '00000000'); // should be fp2coldcard, but stupid caravan doesnt store fp
|
||||
assert.strictEqual(w.howManySignaturesCanWeMake(), 0);
|
||||
assert.ok(!w.isWrappedSegwit());
|
||||
assert.ok(w.isNativeSegwit());
|
||||
assert.ok(!w.isLegacy());
|
||||
});
|
||||
|
||||
it.skip('can import from specter-desktop/fullynoded', () => {
|
||||
it('can import from specter-desktop/fullynoded', () => {
|
||||
// @see https://github.com/Fonta1n3/FullyNoded/blob/master/Docs/Wallets/Wallet-Export-Spec.md
|
||||
const json = JSON.stringify({
|
||||
label: 'Multisig',
|
||||
|
@ -1288,12 +1287,35 @@ describe('multisig-wallet (native segwit)', () => {
|
|||
});
|
||||
const w = new MultisigHDWallet();
|
||||
w.setSecret(json);
|
||||
assert.strictEqual(w._getExternalAddressByIndex(0), 'bc1q338rmdygx0weah4pdrp9xyycxlv2t48276gk3gxmg6m7xdkkglsqgzm6mz');
|
||||
assert.strictEqual(w._getInternalAddressByIndex(0), 'bc1qcgn73pjlwtt6krs2u6as0kh2jp486fa0t93yyq4d7xxxc37rf24qg67ewq');
|
||||
assert.strictEqual(w.getM(), 2);
|
||||
assert.strictEqual(w.getN(), 3);
|
||||
assert.strictEqual(w._getExternalAddressByIndex(0), 'bc1q338rmdygx0weah4pdrp9xyycxlv2t48276gk3gxmg6m7xdkkglsqgzm6mz');
|
||||
assert.strictEqual(w._getInternalAddressByIndex(0), 'bc1qcgn73pjlwtt6krs2u6as0kh2jp486fa0t93yyq4d7xxxc37rf24qg67ewq');
|
||||
assert.strictEqual(w.getLabel(), 'Multisig');
|
||||
assert.ok(!w.isWrappedSegwit());
|
||||
assert.ok(w.isNativeSegwit());
|
||||
assert.ok(!w.isLegacy());
|
||||
|
||||
assert.strictEqual(w.getFingerprint(1), '2D440411');
|
||||
assert.strictEqual(w.getFingerprint(2), 'F863CE8C');
|
||||
assert.strictEqual(w.getFingerprint(3), '7BBD27BF');
|
||||
|
||||
assert.strictEqual(
|
||||
w.getCosigner(1),
|
||||
'xpub6ERaLLFZ3qu7X4cpiMAvSZ6UZVXJfxY5FoNvVJgai1V78DmeNHTcNVfu4cK2RmvTNXU4s1tFpGMPTwqoQ1RraE2o9iiNw2s2aHESpandSFY',
|
||||
);
|
||||
assert.strictEqual(
|
||||
w.getCosigner(2),
|
||||
'xpub6FCSLcRY99737oUAnvXd1k2gSz9P4zi4gQJ8UChSPSCxCK7XS9kLzoLHKNBiR26d3ivT7w3oka9f4BepVLoQ875XzgejjbDo626R6NBUJDW',
|
||||
);
|
||||
assert.strictEqual(
|
||||
w.getCosigner(3),
|
||||
'xpub6FE9uTPh1RxPRAfFVaET75vdfdQzXKZrT7LxukkqY4KhwUm4haMSPCwERfPouG6da6uZTRCXettvYFDck7nbw6JdBztGr1VBLonWch7NpJo',
|
||||
);
|
||||
|
||||
assert.strictEqual(w.getCustomDerivationPathForCosigner(1), "m/48'/0'/0'/2'");
|
||||
assert.strictEqual(w.getCustomDerivationPathForCosigner(2), "m/48'/0'/0'/2'");
|
||||
assert.strictEqual(w.getCustomDerivationPathForCosigner(3), "m/48'/0'/0'/2'");
|
||||
assert.strictEqual(w.getDerivationPath(), '');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue