Merge pull request #2057 from BlueWallet/fix-ms-sparrow-import

FIX: import multisig from some formats
This commit is contained in:
GLaDOS 2020-11-04 17:27:53 +00:00 committed by GitHub
commit 6385251116
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 84 additions and 3 deletions

View File

@ -87,12 +87,15 @@ const showFilePickerAndReadFile = async function () {
: [DocumentPicker.types.allFiles],
});
const uri = Platform.OS === 'ios' ? decodeURI(res.uri) : res.uri;
// ^^ some weird difference on how spaces in filenames are treated on ios and android
let file = false;
if (res.uri.toLowerCase().endsWith('.psbt')) {
// this is either binary file from ElectrumDesktop OR string file with base64 string in there
file = await _readPsbtFileIntoBase64(decodeURI(res.uri));
file = await _readPsbtFileIntoBase64(uri);
} else {
file = await RNFS.readFile(decodeURI(res.uri));
file = await RNFS.readFile(uri);
}
return { data: file, uri: decodeURI(res.uri) };

View File

@ -144,6 +144,16 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
return false;
}
static isXprvValid(xprv) {
try {
xprv = MultisigHDWallet.convertMultisigXprvToRegularXprv(xprv);
bitcoin.bip32.fromBase58(xprv);
return true;
} catch (_) {
return false;
}
}
/**
*
* @param key {string} Either xpub or mnemonic phrase
@ -485,7 +495,7 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
: cosignerData.root_fingerprint?.toUpperCase()) || '00000000';
if (cosignerData.seed) {
this.addCosigner(ELECTRUM_SEED_PREFIX + cosignerData.seed, fingerprint, cosignerData.derivation);
} else if (cosignerData.xprv) {
} else if (cosignerData.xprv && MultisigHDWallet.isXprvValid(cosignerData.xprv)) {
this.addCosigner(cosignerData.xprv, fingerprint, cosignerData.derivation);
} else {
this.addCosigner(cosignerData.xpub, fingerprint, cosignerData.derivation);
@ -577,6 +587,9 @@ export class MultisigHDWallet extends AbstractHDElectrumWallet {
if (xpub.indexOf('/') !== -1) {
xpub = xpub.substr(0, xpub.indexOf('/'));
}
if (xpub.indexOf(')') !== -1) {
xpub = xpub.substr(0, xpub.indexOf(')'));
}
this.addCosigner(xpub, hexFingerprint.toUpperCase(), path);
}

View File

@ -0,0 +1,10 @@
# Coldcard Multisig setup file (created by Sparrow)
#
Name: name
Policy: 2 of 3
Derivation: m/48'/0'/0'/2'
Format: P2WSH
A3909080: xpub6EJoguJn6okK6ymxkU53BZgjf4kqrL19uvTwqVnPRaV8qYvx1RhGtyKZxLhzY4YLCYtvB6DsGk1uR3GFBMvwgc5qz19WAxm2nSXZcoyNftY
7AB71DF0: xpub6FL52qF9cn2nL7T8gv6gStR8GcezKF4LgY53VLbi5sqRjc4PpBuYFp3nfep884hkuF9dC7KZ11mkthE1NVzbX98QmoJQqBFxQbHnpJ5vQKB
F11B9FF2: xpub6ERjK6ubp5p7UUByXGadKvHcqEUMxvWPr7DkzqHz7GnnZEqdR9ffE3Y1DffYqRjJzeGWL1st1qH4kEaZCzjVnJoZ2PJUcnThi48D71zd6sJ

View File

@ -0,0 +1,21 @@
{
"x1/": {
"xpub": "Zpub74sRRUP3y8PeE9KaMr7GRpDYio5zwvfk4RA4KYqhZN5JZw8KH9QgEDVmoTae6K55FJCWYdR75H7WJn78uyuvRZZiZ9ekkBs1DcviysT968p",
"type": "bip32",
"pw_hash_version": 1
},
"x2/": {
"xpub": "Zpub75tgmQKRV6g7TGzkJJ8uh8wwLLz9Qqivq2m9yPf2DfRbTzFm5ucwb4DzWmgmgKEVwzTDZeWnoYsMnS4u77yaG6cHLwofQQMvqmgxBKiWEav",
"xprv": "ZprvAjNnvkiSoWRpoiQR4Jkr5TwqbRVtCUZHCDKwfZkjyaSzsY9NPEHKtXb7fCyoQn8nqNgvjasBQMSMooMM9KegJKc1kAsr2asWgpnYkRYFU1o",
"type": "bip32",
"pw_hash_version": 1
},
"x3/": {
"xpub": "Zpub74zM3fysgQTSbdjb8ecraApRtxoX4XAyzbusUtMJF4NxHd2zgsP4ZHiD4nYCPgG43Pa6hZ57pNNfdyRSwciUXGHRbXojC1Zg9EXNU3hjVG1",
"type": "bip32",
"pw_hash_version": 1
},
"wallet_type": "2of3",
"use_encryption": false,
"seed_type": "bip39"
}

View File

@ -0,0 +1,5 @@
{
"label": "name",
"blockheight": 655372,
"descriptor": "wsh(sortedmulti(2,[a3909080/48'/0'/0'/2']xpub6EJoguJn6okK6ymxkU53BZgjf4kqrL19uvTwqVnPRaV8qYvx1RhGtyKZxLhzY4YLCYtvB6DsGk1uR3GFBMvwgc5qz19WAxm2nSXZcoyNftY,[7ab71df0/48'/0'/0'/2']xpub6FL52qF9cn2nL7T8gv6gStR8GcezKF4LgY53VLbi5sqRjc4PpBuYFp3nfep884hkuF9dC7KZ11mkthE1NVzbX98QmoJQqBFxQbHnpJ5vQKB,[f11b9ff2/48'/0'/0'/2']xpub6ERjK6ubp5p7UUByXGadKvHcqEUMxvWPr7DkzqHz7GnnZEqdR9ffE3Y1DffYqRjJzeGWL1st1qH4kEaZCzjVnJoZ2PJUcnThi48D71zd6sJ))#8xvx6q6r"
}

View File

@ -601,6 +601,20 @@ describe('multisig-wallet (native segwit)', () => {
assert.ok(MultisigHDWallet.isPathValid("m/48'/0'/0'/2'"));
assert.ok(!MultisigHDWallet.isPathValid('ROFLBOATS'));
assert.ok(!MultisigHDWallet.isPathValid(''));
assert.ok(
MultisigHDWallet.isXprvValid(
'ZprvAkUsoZMLiqxrhaM8VpmVJ6QhjH4dZnYpTNNHGMZ3VoE6vRv7xfDeMEiKAeH1eUcN3CFUP87CgM1anM2UytMkykUMtVmXkkohRsiVGth1VMG',
),
);
assert.ok(!MultisigHDWallet.isXprvValid(''));
assert.ok(!MultisigHDWallet.isXprvValid('Zprvlabla'));
assert.ok(!MultisigHDWallet.isXprvValid('xprvblabla'));
assert.ok(
!MultisigHDWallet.isXprvValid(
'xprv9tpBCBeAwBnVgYroSvicqDR2XhAj6sth3idqBWhRqnrq99x17WZvZHQup679rXc3ndPLN3fwbpLkv4WTQhfhZN89B2NbTMmYFePPPHJ5jVP',
),
); // invalid fp
});
it('basic operations work', async () => {
@ -1579,4 +1593,19 @@ describe('multisig-cosigner', () => {
assert.strictEqual(c3.getFp(), '168DD603');
assert.strictEqual(c3.getPath(), "m/48'/0'/0'/2'");
});
it('can parse files from sparrow wallet', () => {
const secrets = [
JSON.stringify(require('./fixtures/fromsparrow-electrum.json')),
require('fs').readFileSync('./tests/unit/fixtures/fromsparrow-coldcard.txt', 'ascii'),
JSON.stringify(require('./fixtures/fromsparrow-specter.json')),
];
for (const s of secrets) {
const w = new MultisigHDWallet();
w.setSecret(s);
assert.strictEqual(w._getExternalAddressByIndex(0), 'bc1qtysquqsjqjfqvhd6l2h470hdgwhcahs4nq2ca49cyxftwjnjt9ssh8emel');
}
});
});