|
@ -2,22 +2,21 @@ |
|
|
|
|
|
|
|
|
import logger from 'logger' |
|
|
import logger from 'logger' |
|
|
import { BigNumber } from 'bignumber.js' |
|
|
import { BigNumber } from 'bignumber.js' |
|
|
import type { OperationRaw } from '@ledgerhq/live-common/lib/types' |
|
|
|
|
|
import Btc from '@ledgerhq/hw-app-btc' |
|
|
import Btc from '@ledgerhq/hw-app-btc' |
|
|
import { Observable } from 'rxjs' |
|
|
import { Observable } from 'rxjs' |
|
|
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies' |
|
|
import { isSegwitDerivationMode } from '@ledgerhq/live-common/lib/derivation' |
|
|
import { isSegwitPath, isUnsplitPath } from 'helpers/bip32' |
|
|
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/currencies' |
|
|
|
|
|
import type { OperationRaw, CryptoCurrency } from '@ledgerhq/live-common/lib/types' |
|
|
|
|
|
import { getWalletName } from '@ledgerhq/live-common/lib/account' |
|
|
import { |
|
|
import { |
|
|
libcoreAmountToBigNumber, |
|
|
libcoreAmountToBigNumber, |
|
|
bigNumberToLibcoreAmount, |
|
|
bigNumberToLibcoreAmount, |
|
|
getOrCreateWallet, |
|
|
getOrCreateWallet, |
|
|
} from 'helpers/libcore' |
|
|
} from 'helpers/libcore' |
|
|
import { splittedCurrencies } from 'config/cryptocurrencies' |
|
|
|
|
|
|
|
|
|
|
|
import withLibcore from 'helpers/withLibcore' |
|
|
import withLibcore from 'helpers/withLibcore' |
|
|
import { createCommand, Command } from 'helpers/ipc' |
|
|
import { createCommand, Command } from 'helpers/ipc' |
|
|
import { withDevice } from 'helpers/deviceAccess' |
|
|
import { withDevice } from 'helpers/deviceAccess' |
|
|
import * as accountIdHelper from 'helpers/accountId' |
|
|
|
|
|
|
|
|
|
|
|
type BitcoinLikeTransaction = { |
|
|
type BitcoinLikeTransaction = { |
|
|
amount: string, |
|
|
amount: string, |
|
@ -28,9 +27,9 @@ type BitcoinLikeTransaction = { |
|
|
type Input = { |
|
|
type Input = { |
|
|
accountId: string, |
|
|
accountId: string, |
|
|
currencyId: string, |
|
|
currencyId: string, |
|
|
|
|
|
derivationMode: string, |
|
|
|
|
|
seedIdentifier: string, |
|
|
xpub: string, |
|
|
xpub: string, |
|
|
freshAddress: string, |
|
|
|
|
|
freshAddressPath: string, |
|
|
|
|
|
index: number, |
|
|
index: number, |
|
|
transaction: BitcoinLikeTransaction, |
|
|
transaction: BitcoinLikeTransaction, |
|
|
deviceId: string, |
|
|
deviceId: string, |
|
@ -42,17 +41,18 @@ type Result = { type: 'signed' } | { type: 'broadcasted', operation: OperationRa |
|
|
|
|
|
|
|
|
const cmd: Command<Input, Result> = createCommand( |
|
|
const cmd: Command<Input, Result> = createCommand( |
|
|
'libcoreSignAndBroadcast', |
|
|
'libcoreSignAndBroadcast', |
|
|
({ accountId, currencyId, xpub, freshAddress, freshAddressPath, index, transaction, deviceId }) => |
|
|
({ accountId, currencyId, derivationMode, seedIdentifier, xpub, index, transaction, deviceId }) => |
|
|
Observable.create(o => { |
|
|
Observable.create(o => { |
|
|
let unsubscribed = false |
|
|
let unsubscribed = false |
|
|
|
|
|
const currency = getCryptoCurrencyById(currencyId) |
|
|
const isCancelled = () => unsubscribed |
|
|
const isCancelled = () => unsubscribed |
|
|
withLibcore(core => |
|
|
withLibcore(core => |
|
|
doSignAndBroadcast({ |
|
|
doSignAndBroadcast({ |
|
|
accountId, |
|
|
accountId, |
|
|
currencyId, |
|
|
currency, |
|
|
|
|
|
derivationMode, |
|
|
|
|
|
seedIdentifier, |
|
|
xpub, |
|
|
xpub, |
|
|
freshAddress, |
|
|
|
|
|
freshAddressPath, |
|
|
|
|
|
index, |
|
|
index, |
|
|
transaction, |
|
|
transaction, |
|
|
deviceId, |
|
|
deviceId, |
|
@ -78,28 +78,26 @@ const cmd: Command<Input, Result> = createCommand( |
|
|
|
|
|
|
|
|
async function signTransaction({ |
|
|
async function signTransaction({ |
|
|
hwApp, |
|
|
hwApp, |
|
|
currencyId, |
|
|
currency, |
|
|
transaction, |
|
|
transaction, |
|
|
|
|
|
derivationMode, |
|
|
sigHashType, |
|
|
sigHashType, |
|
|
supportsSegwit, |
|
|
|
|
|
isSegwit, |
|
|
|
|
|
hasTimestamp, |
|
|
hasTimestamp, |
|
|
}: { |
|
|
}: { |
|
|
hwApp: Btc, |
|
|
hwApp: Btc, |
|
|
currencyId: string, |
|
|
currency: CryptoCurrency, |
|
|
transaction: *, |
|
|
transaction: *, |
|
|
|
|
|
derivationMode: string, |
|
|
sigHashType: number, |
|
|
sigHashType: number, |
|
|
supportsSegwit: boolean, |
|
|
|
|
|
isSegwit: boolean, |
|
|
|
|
|
hasTimestamp: boolean, |
|
|
hasTimestamp: boolean, |
|
|
}) { |
|
|
}) { |
|
|
const additionals = [] |
|
|
const additionals = [] |
|
|
let expiryHeight |
|
|
let expiryHeight |
|
|
if (currencyId === 'bitcoin_cash' || currencyId === 'bitcoin_gold') additionals.push('bip143') |
|
|
if (currency.id === 'bitcoin_cash' || currency.id === 'bitcoin_gold') additionals.push('bip143') |
|
|
if (currencyId === 'zcash') expiryHeight = Buffer.from([0x00, 0x00, 0x00, 0x00]) |
|
|
if (currency.id === 'zcash') expiryHeight = Buffer.from([0x00, 0x00, 0x00, 0x00]) |
|
|
const rawInputs = transaction.getInputs() |
|
|
const rawInputs = transaction.getInputs() |
|
|
|
|
|
|
|
|
const hasExtraData = currencyId === 'zcash' |
|
|
const hasExtraData = currency.id === 'zcash' |
|
|
|
|
|
|
|
|
const inputs = await Promise.all( |
|
|
const inputs = await Promise.all( |
|
|
rawInputs.map(async input => { |
|
|
rawInputs.map(async input => { |
|
@ -107,7 +105,7 @@ async function signTransaction({ |
|
|
const hexPreviousTransaction = Buffer.from(rawPreviousTransaction).toString('hex') |
|
|
const hexPreviousTransaction = Buffer.from(rawPreviousTransaction).toString('hex') |
|
|
const previousTransaction = hwApp.splitTransaction( |
|
|
const previousTransaction = hwApp.splitTransaction( |
|
|
hexPreviousTransaction, |
|
|
hexPreviousTransaction, |
|
|
supportsSegwit, |
|
|
currency.supportsSegwit, |
|
|
hasTimestamp, |
|
|
hasTimestamp, |
|
|
hasExtraData, |
|
|
hasExtraData, |
|
|
) |
|
|
) |
|
@ -156,7 +154,7 @@ async function signTransaction({ |
|
|
outputScriptHex, |
|
|
outputScriptHex, |
|
|
lockTime, |
|
|
lockTime, |
|
|
sigHashType, |
|
|
sigHashType, |
|
|
isSegwit, |
|
|
isSegwitDerivationMode(derivationMode), |
|
|
initialTimestamp, |
|
|
initialTimestamp, |
|
|
additionals, |
|
|
additionals, |
|
|
expiryHeight, |
|
|
expiryHeight, |
|
@ -167,9 +165,10 @@ async function signTransaction({ |
|
|
|
|
|
|
|
|
export async function doSignAndBroadcast({ |
|
|
export async function doSignAndBroadcast({ |
|
|
accountId, |
|
|
accountId, |
|
|
currencyId, |
|
|
derivationMode, |
|
|
|
|
|
seedIdentifier, |
|
|
|
|
|
currency, |
|
|
xpub, |
|
|
xpub, |
|
|
freshAddressPath, |
|
|
|
|
|
index, |
|
|
index, |
|
|
transaction, |
|
|
transaction, |
|
|
deviceId, |
|
|
deviceId, |
|
@ -179,10 +178,10 @@ export async function doSignAndBroadcast({ |
|
|
onOperationBroadcasted, |
|
|
onOperationBroadcasted, |
|
|
}: { |
|
|
}: { |
|
|
accountId: string, |
|
|
accountId: string, |
|
|
currencyId: string, |
|
|
derivationMode: string, |
|
|
|
|
|
seedIdentifier: string, |
|
|
|
|
|
currency: CryptoCurrency, |
|
|
xpub: string, |
|
|
xpub: string, |
|
|
freshAddress: string, |
|
|
|
|
|
freshAddressPath: string, |
|
|
|
|
|
index: number, |
|
|
index: number, |
|
|
transaction: BitcoinLikeTransaction, |
|
|
transaction: BitcoinLikeTransaction, |
|
|
deviceId: string, |
|
|
deviceId: string, |
|
@ -191,11 +190,9 @@ export async function doSignAndBroadcast({ |
|
|
onSigned: () => void, |
|
|
onSigned: () => void, |
|
|
onOperationBroadcasted: (optimisticOp: $Exact<OperationRaw>) => void, |
|
|
onOperationBroadcasted: (optimisticOp: $Exact<OperationRaw>) => void, |
|
|
}): Promise<void> { |
|
|
}): Promise<void> { |
|
|
const { walletName } = accountIdHelper.decode(accountId) |
|
|
const walletName = getWalletName({ currency, seedIdentifier, derivationMode }) |
|
|
|
|
|
|
|
|
const isSegwit = isSegwitPath(freshAddressPath) |
|
|
const njsWallet = await getOrCreateWallet(core, walletName, { currency, derivationMode }) |
|
|
const isUnsplit = isUnsplitPath(freshAddressPath, splittedCurrencies[currencyId]) |
|
|
|
|
|
const njsWallet = await getOrCreateWallet(core, walletName, { currencyId, isSegwit, isUnsplit }) |
|
|
|
|
|
if (isCancelled()) return |
|
|
if (isCancelled()) return |
|
|
const njsAccount = await njsWallet.getAccount(index) |
|
|
const njsAccount = await njsWallet.getAccount(index) |
|
|
if (isCancelled()) return |
|
|
if (isCancelled()) return |
|
@ -221,17 +218,14 @@ export async function doSignAndBroadcast({ |
|
|
const hasTimestamp = !!njsWalletCurrency.bitcoinLikeNetworkParameters.UsesTimestampedTransaction |
|
|
const hasTimestamp = !!njsWalletCurrency.bitcoinLikeNetworkParameters.UsesTimestampedTransaction |
|
|
// TODO: const timestampDelay = njsWalletCurrency.bitcoinLikeNetworkParameters.TimestampDelay
|
|
|
// TODO: const timestampDelay = njsWalletCurrency.bitcoinLikeNetworkParameters.TimestampDelay
|
|
|
|
|
|
|
|
|
const currency = getCryptoCurrencyById(currencyId) |
|
|
|
|
|
|
|
|
|
|
|
const signedTransaction = await withDevice(deviceId)(async transport => |
|
|
const signedTransaction = await withDevice(deviceId)(async transport => |
|
|
signTransaction({ |
|
|
signTransaction({ |
|
|
hwApp: new Btc(transport), |
|
|
hwApp: new Btc(transport), |
|
|
currencyId, |
|
|
currency, |
|
|
transaction: builded, |
|
|
transaction: builded, |
|
|
sigHashType: parseInt(sigHashType, 16), |
|
|
sigHashType: parseInt(sigHashType, 16), |
|
|
supportsSegwit: !!currency.supportsSegwit, |
|
|
|
|
|
isSegwit: isSegwitPath(freshAddressPath), |
|
|
|
|
|
hasTimestamp, |
|
|
hasTimestamp, |
|
|
|
|
|
derivationMode, |
|
|
}), |
|
|
}), |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|