mirror of
https://github.com/BlueWallet/BlueWallet.git
synced 2024-11-19 18:00:17 +01:00
114 lines
3.4 KiB
JavaScript
114 lines
3.4 KiB
JavaScript
import b58 from 'bs58check';
|
|
import { HDSegwitBech32Wallet } from './hd-segwit-bech32-wallet';
|
|
import BIP32Factory from 'bip32';
|
|
import * as ecc from 'tiny-secp256k1';
|
|
|
|
const bitcoin = require('bitcoinjs-lib');
|
|
const mn = require('electrum-mnemonic');
|
|
const bip32 = BIP32Factory(ecc);
|
|
|
|
const PREFIX = mn.PREFIXES.segwit;
|
|
|
|
/**
|
|
* ElectrumSeed means that instead of BIP39 seed format it works with the format invented by Electrum wallet. Otherwise
|
|
* its a regular HD wallet that has all the properties of parent class.
|
|
*
|
|
* @see https://electrum.readthedocs.io/en/latest/seedphrase.html
|
|
*/
|
|
export class HDSegwitElectrumSeedP2WPKHWallet extends HDSegwitBech32Wallet {
|
|
static type = 'HDSegwitElectrumSeedP2WPKHWallet';
|
|
static typeReadable = 'HD Electrum (BIP32 P2WPKH)';
|
|
static derivationPath = "m/0'";
|
|
|
|
validateMnemonic() {
|
|
return mn.validateMnemonic(this.secret, PREFIX);
|
|
}
|
|
|
|
async generate() {
|
|
throw new Error('Not implemented');
|
|
}
|
|
|
|
getXpub() {
|
|
if (this._xpub) {
|
|
return this._xpub; // cache hit
|
|
}
|
|
const args = { prefix: PREFIX };
|
|
if (this.passphrase) args.passphrase = this.passphrase;
|
|
const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
|
|
const xpub = root.derivePath("m/0'").neutered().toBase58();
|
|
|
|
// bitcoinjs does not support zpub yet, so we just convert it from xpub
|
|
let data = b58.decode(xpub);
|
|
data = data.slice(4);
|
|
data = Buffer.concat([Buffer.from('04b24746', 'hex'), data]);
|
|
this._xpub = b58.encode(data);
|
|
|
|
return this._xpub;
|
|
}
|
|
|
|
_getInternalAddressByIndex(index) {
|
|
index = index * 1; // cast to int
|
|
if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit
|
|
|
|
const xpub = this._zpubToXpub(this.getXpub());
|
|
const node = bip32.fromBase58(xpub);
|
|
const address = bitcoin.payments.p2wpkh({
|
|
pubkey: node.derive(1).derive(index).publicKey,
|
|
}).address;
|
|
|
|
return (this.internal_addresses_cache[index] = address);
|
|
}
|
|
|
|
_getExternalAddressByIndex(index) {
|
|
index = index * 1; // cast to int
|
|
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
|
|
|
const xpub = this._zpubToXpub(this.getXpub());
|
|
const node = bip32.fromBase58(xpub);
|
|
const address = bitcoin.payments.p2wpkh({
|
|
pubkey: node.derive(0).derive(index).publicKey,
|
|
}).address;
|
|
|
|
return (this.external_addresses_cache[index] = address);
|
|
}
|
|
|
|
_getWIFByIndex(internal, index) {
|
|
if (!this.secret) return false;
|
|
const args = { prefix: PREFIX };
|
|
if (this.passphrase) args.passphrase = this.passphrase;
|
|
const root = bip32.fromSeed(mn.mnemonicToSeedSync(this.secret, args));
|
|
const path = `m/0'/${internal ? 1 : 0}/${index}`;
|
|
const child = root.derivePath(path);
|
|
|
|
return child.toWIF();
|
|
}
|
|
|
|
_getNodePubkeyByIndex(node, index) {
|
|
index = index * 1; // cast to int
|
|
|
|
if (node === 0 && !this._node0) {
|
|
const xpub = this._zpubToXpub(this.getXpub());
|
|
const hdNode = bip32.fromBase58(xpub);
|
|
this._node0 = hdNode.derive(node);
|
|
}
|
|
|
|
if (node === 1 && !this._node1) {
|
|
const xpub = this._zpubToXpub(this.getXpub());
|
|
const hdNode = bip32.fromBase58(xpub);
|
|
this._node1 = hdNode.derive(node);
|
|
}
|
|
|
|
if (node === 0) {
|
|
return this._node0.derive(index).publicKey;
|
|
}
|
|
|
|
if (node === 1) {
|
|
return this._node1.derive(index).publicKey;
|
|
}
|
|
}
|
|
|
|
isSegwit() {
|
|
return true;
|
|
}
|
|
}
|