You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
153 lines
3.8 KiB
153 lines
3.8 KiB
// @flow
|
|
|
|
/* eslint-disable no-bitwise */
|
|
|
|
import bitcoin from 'bitcoinjs-lib'
|
|
import bs58check from 'bs58check'
|
|
import Btc from '@ledgerhq/hw-app-btc'
|
|
|
|
import { getAccount, getHDNode, networks } from 'helpers/btc'
|
|
|
|
type Coin = 0 | 1
|
|
|
|
function getCompressPublicKey(publicKey) {
|
|
let compressedKeyIndex
|
|
if (parseInt(publicKey.substring(128, 130), 16) % 2 !== 0) {
|
|
compressedKeyIndex = '03'
|
|
} else {
|
|
compressedKeyIndex = '02'
|
|
}
|
|
const result = compressedKeyIndex + publicKey.substring(2, 66)
|
|
return result
|
|
}
|
|
|
|
function parseHexString(str: any) {
|
|
const result = []
|
|
while (str.length >= 2) {
|
|
result.push(parseInt(str.substring(0, 2), 16))
|
|
str = str.substring(2, str.length)
|
|
}
|
|
return result
|
|
}
|
|
|
|
function createXpub({ depth, fingerprint, childnum, chainCode, publicKey, network }) {
|
|
return [
|
|
network.toString(16).padStart(8, '0'),
|
|
depth.toString(16).padStart(2, '0'),
|
|
fingerprint.toString(16).padStart(8, '0'),
|
|
childnum.toString(16).padStart(8, '0'),
|
|
chainCode,
|
|
publicKey,
|
|
].join('')
|
|
}
|
|
|
|
function encodeBase58Check(vchIn) {
|
|
vchIn = parseHexString(vchIn)
|
|
|
|
return bs58check.encode(Buffer.from(vchIn))
|
|
}
|
|
|
|
function getPath({ coin, account, segwit }: { coin: Coin, account?: any, segwit: boolean }) {
|
|
return `${segwit ? 49 : 44}'/${coin}'${account !== undefined ? `/${account}'` : ''}`
|
|
}
|
|
|
|
export function verifyAddress({
|
|
transport,
|
|
path,
|
|
segwit = true,
|
|
}: {
|
|
transport: Object,
|
|
path: string,
|
|
segwit?: boolean,
|
|
}) {
|
|
const btc = new Btc(transport)
|
|
|
|
return btc.getWalletPublicKey(path, true, segwit)
|
|
}
|
|
|
|
export default async ({
|
|
transport,
|
|
currentAccounts,
|
|
onProgress,
|
|
coin = 1,
|
|
segwit = true,
|
|
}: {
|
|
transport: Object,
|
|
currentAccounts: Array<*>,
|
|
onProgress: Function,
|
|
coin?: Coin,
|
|
segwit?: boolean,
|
|
}) => {
|
|
const btc = new Btc(transport)
|
|
|
|
const network = networks[coin]
|
|
|
|
const [p2pkh, p2sh, fam] = [network.pubKeyHash, network.scriptHash, network.family].map(v =>
|
|
v.toString(16).padStart(4, 0),
|
|
)
|
|
|
|
await transport.exchange(Buffer.from(`e014000005${p2pkh}${p2sh}${fam.substr(-2)}`), [0x9000])
|
|
|
|
const getPublicKey = path => btc.getWalletPublicKey(path)
|
|
|
|
let result = bitcoin.crypto.sha256(
|
|
await getPublicKey(getPath({ segwit, coin })).then(
|
|
({ publicKey }) => new Uint8Array(parseHexString(getCompressPublicKey(publicKey))),
|
|
),
|
|
)
|
|
result = bitcoin.crypto.ripemd160(result)
|
|
|
|
onProgress(null)
|
|
|
|
const fingerprint = ((result[0] << 24) | (result[1] << 16) | (result[2] << 8) | result[3]) >>> 0
|
|
|
|
const getXpub58ByPath = async ({ path, account, network }) => {
|
|
const { publicKey, chainCode } = await getPublicKey(path)
|
|
const compressPublicKey = getCompressPublicKey(publicKey)
|
|
|
|
const childnum = (0x80000000 | account) >>> 0
|
|
|
|
const xpub = createXpub({
|
|
depth: 3,
|
|
fingerprint,
|
|
childnum,
|
|
chainCode,
|
|
publicKey: compressPublicKey,
|
|
network: network.bip32.public,
|
|
})
|
|
|
|
return encodeBase58Check(xpub)
|
|
}
|
|
|
|
const getAllAccounts = async (currentAccount = 0, accounts = []) => {
|
|
const path = getPath({ segwit, coin, account: currentAccount })
|
|
const xpub58 = await getXpub58ByPath({ path, account: currentAccount, network })
|
|
|
|
if (currentAccounts.includes(xpub58)) {
|
|
return getAllAccounts(currentAccount + 1, accounts) // Skip existing account
|
|
}
|
|
|
|
const hdnode = getHDNode({ xpub58, network })
|
|
const account = await getAccount({ path, hdnode, network, segwit, asyncDelay: 0 })
|
|
|
|
onProgress({
|
|
account: currentAccount,
|
|
transactions: account.transactions.length,
|
|
})
|
|
|
|
const hasTransactions = account.transactions.length > 0
|
|
|
|
accounts.push({
|
|
id: xpub58,
|
|
...account,
|
|
})
|
|
|
|
if (hasTransactions) {
|
|
return getAllAccounts(currentAccount + 1, accounts)
|
|
}
|
|
|
|
return accounts
|
|
}
|
|
|
|
return getAllAccounts()
|
|
}
|
|
|