mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-20 02:09:10 +01:00
Merge pull request #6064 from BlueWallet/fix-5681
ADD: support more wallet export files from Coldcard (closes #5681)
This commit is contained in:
commit
ad51a03779
@ -219,6 +219,7 @@ export class AbstractWallet {
|
||||
}
|
||||
|
||||
setSecret(newSecret: string): this {
|
||||
const origSecret = newSecret;
|
||||
this.secret = newSecret.trim().replace('bitcoin:', '').replace('BITCOIN:', '');
|
||||
|
||||
if (this.secret.startsWith('BC1')) this.secret = this.secret.toLowerCase();
|
||||
@ -238,7 +239,7 @@ export class AbstractWallet {
|
||||
|
||||
if (derivationPath.startsWith("m/84'/0'/") && this.secret.toLowerCase().startsWith('xpub')) {
|
||||
// need to convert xpub to zpub
|
||||
this.secret = this._xpubToZpub(this.secret);
|
||||
this.secret = this._xpubToZpub(this.secret.split('/')[0]);
|
||||
}
|
||||
|
||||
if (derivationPath.startsWith("m/49'/0'/") && this.secret.toLowerCase().startsWith('xpub')) {
|
||||
@ -288,6 +289,7 @@ export class AbstractWallet {
|
||||
? parsedSecret.AccountKeyPath
|
||||
: `m/${parsedSecret.AccountKeyPath}`;
|
||||
if (parsedSecret.CoboVaultFirmwareVersion) this.use_with_hardware_wallet = true;
|
||||
return this;
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
@ -322,6 +324,31 @@ export class AbstractWallet {
|
||||
}
|
||||
}
|
||||
|
||||
// is it new-wasabi.json exported from coldcard?
|
||||
try {
|
||||
const json = JSON.parse(origSecret);
|
||||
if (json.MasterFingerprint && json.ExtPubKey) {
|
||||
// technically we should allow choosing which format user wants, BIP44 / BIP49 / BIP84, but meh...
|
||||
this.secret = this._xpubToZpub(json.ExtPubKey);
|
||||
const mfp = Buffer.from(json.MasterFingerprint, 'hex').reverse().toString('hex');
|
||||
this.masterFingerprint = parseInt(mfp, 16);
|
||||
return this;
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
// is it sparrow-export ?
|
||||
try {
|
||||
const json = JSON.parse(origSecret);
|
||||
if (json.chain && json.chain === 'BTC' && json.xfp && json.bip84) {
|
||||
// technically we should allow choosing which format user wants, BIP44 / BIP49 / BIP84, but meh...
|
||||
this.secret = json.bip84._pub;
|
||||
const mfp = Buffer.from(json.xfp, 'hex').reverse().toString('hex');
|
||||
this.masterFingerprint = parseInt(mfp, 16);
|
||||
this._derivationPath = json.bip84.deriv;
|
||||
return this;
|
||||
}
|
||||
} catch (_) {}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
} from '../../class';
|
||||
import startImport from '../../class/wallet-import';
|
||||
import * as BlueElectrum from '../../blue_modules/BlueElectrum';
|
||||
const fs = require('fs');
|
||||
|
||||
jest.setTimeout(90 * 1000);
|
||||
|
||||
@ -504,4 +505,55 @@ describe('import procedure', () => {
|
||||
assert.strictEqual(store.state.wallets[1].type, HDSegwitBech32Wallet.type);
|
||||
assert.strictEqual(store.state.wallets.length, 2);
|
||||
});
|
||||
|
||||
it('can import coldcard mk4 descriptor.txt', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport(
|
||||
fs.readFileSync('tests/unit/fixtures/coldcardmk4/descriptor.txt').toString('utf8'),
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
|
||||
assert.strictEqual(store.state.wallets.length, 1);
|
||||
assert.strictEqual(store.state.wallets[0].type, WatchOnlyWallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getMasterFingerprintHex(), '086ee178');
|
||||
assert.strictEqual(store.state.wallets[0].getDerivationPath(), "m/84'/0'/0'");
|
||||
assert.strictEqual(store.state.wallets[0]._getExternalAddressByIndex(0), 'bc1q5y4r767v5fzx74ez4nw36hjqrhr4ayeyut5px6');
|
||||
});
|
||||
|
||||
it('can import coldcard mk4 new-wasabi.json', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport(
|
||||
fs.readFileSync('tests/unit/fixtures/coldcardmk4/new-wasabi.json').toString('utf8'),
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
|
||||
assert.strictEqual(store.state.wallets.length, 1);
|
||||
assert.strictEqual(store.state.wallets[0].type, WatchOnlyWallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getMasterFingerprintHex(), '086ee178');
|
||||
assert.strictEqual(store.state.wallets[0].getDerivationPath(), "m/84'/0'/0'");
|
||||
assert.strictEqual(store.state.wallets[0]._getExternalAddressByIndex(0), 'bc1q5y4r767v5fzx74ez4nw36hjqrhr4ayeyut5px6');
|
||||
});
|
||||
|
||||
it('can import coldcard mk4 sparrow-export.json', async () => {
|
||||
const store = createStore();
|
||||
const { promise } = startImport(
|
||||
fs.readFileSync('tests/unit/fixtures/coldcardmk4/sparrow-export.json').toString('utf8'),
|
||||
false,
|
||||
false,
|
||||
...store.callbacks,
|
||||
);
|
||||
await promise;
|
||||
|
||||
assert.strictEqual(store.state.wallets.length, 1);
|
||||
assert.strictEqual(store.state.wallets[0].type, WatchOnlyWallet.type);
|
||||
assert.strictEqual(store.state.wallets[0].getMasterFingerprintHex(), '086ee178');
|
||||
assert.strictEqual(store.state.wallets[0].getDerivationPath(), "m/84'/0'/0'");
|
||||
assert.strictEqual(store.state.wallets[0]._getExternalAddressByIndex(0), 'bc1q5y4r767v5fzx74ez4nw36hjqrhr4ayeyut5px6');
|
||||
});
|
||||
});
|
||||
|
1
tests/unit/fixtures/coldcardmk4/descriptor.txt
Normal file
1
tests/unit/fixtures/coldcardmk4/descriptor.txt
Normal file
@ -0,0 +1 @@
|
||||
wpkh([086ee178/84h/0h/0h]xpub6CqWTnie1ut9ZDD9xDeCn1VXk83VdAPSm8ZPfPNbb8w5z1e7jyy8zuX721uKj8u4GNxXqAevgEZjciUansnyz6ZhnSKyQWZwx2dpAxuCuDe/<0;1>/*)#mthwej8w
|
1
tests/unit/fixtures/coldcardmk4/new-wasabi.json
Normal file
1
tests/unit/fixtures/coldcardmk4/new-wasabi.json
Normal file
@ -0,0 +1 @@
|
||||
{"ColdCardFirmwareVersion": "5.2.2", "MasterFingerprint": "086EE178", "ExtPubKey": "xpub6CqWTnie1ut9ZDD9xDeCn1VXk83VdAPSm8ZPfPNbb8w5z1e7jyy8zuX721uKj8u4GNxXqAevgEZjciUansnyz6ZhnSKyQWZwx2dpAxuCuDe"}
|
1
tests/unit/fixtures/coldcardmk4/sparrow-export.json
Normal file
1
tests/unit/fixtures/coldcardmk4/sparrow-export.json
Normal file
@ -0,0 +1 @@
|
||||
{"chain": "BTC", "xfp": "086EE178", "account": 0, "xpub": "xpub661MyMwAqRbcFA7Da9RWMKATMVYCGLC1JMGGPXs9cWHQnUJFFJ4Eo8PVwAcZP1EPa3rJNC192YA7ZLgN8BqETEK2mky8Co8V77aXB86sW9S", "bip44": {"name": "p2pkh", "xfp": "0949B877", "deriv": "m/44'/0'/0'", "xpub": "xpub6DNdnDgd2ULEUeRfpQhqJ8S9aqxZCWi9e4YijwPX1DsVfzPRPn2fk9jy72pn7rS2SAMWgfQK1JU3WsusseeConHH2LVjPEZkhxRBhFTdX69", "desc": "pkh([086ee178/44h/0h/0h]xpub6DNdnDgd2ULEUeRfpQhqJ8S9aqxZCWi9e4YijwPX1DsVfzPRPn2fk9jy72pn7rS2SAMWgfQK1JU3WsusseeConHH2LVjPEZkhxRBhFTdX69/<0;1>/*)#estefkna", "first": "1CuhYHhWe4awuUtgX5qREo5xYaoReXPLnZ"}, "bip49": {"name": "p2sh-p2wpkh", "xfp": "17BEC390", "deriv": "m/49'/0'/0'", "xpub": "xpub6CryNpp881kryGrBGvt2PB7gxCueY5bejof1qFcW1jMXPmcUByWeuhR2PAAhdTZe5viheDXkbvLY1jewwr7e1BMdBH1GiPnJU5A6JGHyV95", "desc": "sh(wpkh([086ee178/49h/0h/0h]xpub6CryNpp881kryGrBGvt2PB7gxCueY5bejof1qFcW1jMXPmcUByWeuhR2PAAhdTZe5viheDXkbvLY1jewwr7e1BMdBH1GiPnJU5A6JGHyV95/<0;1>/*))#76em9dr6", "_pub": "ypub6XhEgVV3GhJLpa3J7HfebGDC8B46Uhb9evBEceWPPjjQSsRhSdgDXm5AQN8HdNDZVZqWPh8K4ah5u2GWfYXeoR3E3chhJJbnjoDjgnzrviL", "first": "3DCeGZNxxhQDh5kAMi1EQQcpbBpo6pocHU"}, "bip84": {"name": "p2wpkh", "xfp": "7461A59E", "deriv": "m/84'/0'/0'", "xpub": "xpub6CqWTnie1ut9ZDD9xDeCn1VXk83VdAPSm8ZPfPNbb8w5z1e7jyy8zuX721uKj8u4GNxXqAevgEZjciUansnyz6ZhnSKyQWZwx2dpAxuCuDe", "desc": "wpkh([086ee178/84h/0h/0h]xpub6CqWTnie1ut9ZDD9xDeCn1VXk83VdAPSm8ZPfPNbb8w5z1e7jyy8zuX721uKj8u4GNxXqAevgEZjciUansnyz6ZhnSKyQWZwx2dpAxuCuDe/<0;1>/*)#mthwej8w", "_pub": "zpub6rW3584UKGy7FobPcwDTCBgY64LPWQNSbMbqEBANM9gr6DGaFJJGF2qP4RpVixCu5fC9L7r3bZGqPHhiEGd1aZvuX7ipaLCvVUm6xBzBhzQ", "first": "bc1q5y4r767v5fzx74ez4nw36hjqrhr4ayeyut5px6"}, "bip48_1": {"name": "p2sh-p2wsh", "xfp": "87843A8F", "deriv": "m/48'/0'/0'/1'", "xpub": "xpub6FAiR9GaPmCUdaQsWZuFEAMHiQnucQWs3681hXX3HnFDRXaksPSpFXD7Fw1216kng1uRCU8J5ULsfyoepFcu6foFEfFHQC8cFJUMLvy8gLd", "desc": "sh(wsh(sortedmulti(M,[086ee178/48'/0'/0'/1']xpub6FAiR9GaPmCUdaQsWZuFEAMHiQnucQWs3681hXX3HnFDRXaksPSpFXD7Fw1216kng1uRCU8J5ULsfyoepFcu6foFEfFHQC8cFJUMLvy8gLd/0/*,...)))", "_pub": "Ypub6ku4r3fw7QJKuSmNHb9rGKnbcAycmPBxGUHuQBgU3ZTW6oxttSzexhjB5qv5ZSdcK86CpXiyRM5vgS2yqBBs3PbWwU47PWR6QkosKWT9sZt"}, "bip48_2": {"name": "p2wsh", "xfp": "A57AB9B4", "deriv": "m/48'/0'/0'/2'", "xpub": "xpub6FAiR9GaPmCUfYtaQCR8Q8GH3bz5h9AQX8wu7up4MUdRdpY63R1KM9jJM6AqFiRpHn5dN15ewLxomv2UZ34aXsSB4b2SpgasgwPYBTwSJW9", "desc": "wsh(sortedmulti(M,[086ee178/48'/0'/0'/2']xpub6FAiR9GaPmCUfYtaQCR8Q8GH3bz5h9AQX8wu7up4MUdRdpY63R1KM9jJM6AqFiRpHn5dN15ewLxomv2UZ34aXsSB4b2SpgasgwPYBTwSJW9/0/*,...))", "_pub": "Zpub75jL9iLrG5qoniSC1aTMeNo67LKEnjpzfde1bxsNVGDbNCjTK8iigPuWCD3UoxxZLXPDjYGtjt4QfesNHf3ZGpv3djXhPugr87nhYb91mrY"}, "bip45": {"name": "p2sh", "xfp": "5D5A20AA", "deriv": "m/45'", "xpub": "xpub67x6MAer9yqzxozdhCAd1LNV2m8c34Vahi8AfNjRu8tndg3BvTb2FpotopkC1w98q29nUnGZ1eq6vWCjGMjx5m62Jk1L2koGDjnR69C1HcK", "desc": "sh(sortedmulti(M,[086ee178/45']xpub67x6MAer9yqzxozdhCAd1LNV2m8c34Vahi8AfNjRu8tndg3BvTb2FpotopkC1w98q29nUnGZ1eq6vWCjGMjx5m62Jk1L2koGDjnR69C1HcK/0/*,...))"}}
|
Loading…
Reference in New Issue
Block a user