Meriadec Pillet
7 years ago
committed by
GitHub
22 changed files with 275 additions and 230 deletions
@ -1,141 +0,0 @@ |
|||
/* eslint-disable no-console */ |
|||
|
|||
const CommNodeHid = require('@ledgerhq/hw-transport-node-hid').default |
|||
const Btc = require('@ledgerhq/hw-app-btc').default |
|||
|
|||
const { CREATE } = process.env |
|||
|
|||
const { |
|||
createWallet, |
|||
createAccount, |
|||
createAmount, |
|||
getCurrency, |
|||
getWallet, |
|||
syncAccount, |
|||
signTransaction, |
|||
} = require('@ledgerhq/ledger-core') |
|||
|
|||
async function getOrCreateWallet(currencyId) { |
|||
try { |
|||
const wallet = await getWallet(currencyId) |
|||
return wallet |
|||
} catch (err) { |
|||
const currency = await getCurrency(currencyId) |
|||
const wallet = await createWallet(currencyId, currency) |
|||
return wallet |
|||
} |
|||
} |
|||
|
|||
async function scanNextAccount(wallet, hwApp, accountIndex = 0) { |
|||
console.log(`creating an account with index ${accountIndex}`) |
|||
const account = await createAccount(wallet, hwApp) |
|||
console.log(`synchronizing account ${accountIndex}`) |
|||
await syncAccount(account) |
|||
console.log(`finished sync`) |
|||
const utxoCount = await account.asBitcoinLikeAccount().getUTXOCount() |
|||
console.log(`utxoCount = ${utxoCount}`) |
|||
} |
|||
|
|||
async function scanAccountsOnDevice(props) { |
|||
try { |
|||
const { devicePath, currencyId } = props |
|||
console.log(`get or create wallet`) |
|||
const wallet = await getOrCreateWallet(currencyId) |
|||
console.log(`open device`) |
|||
const transport = await CommNodeHid.open(devicePath) |
|||
console.log(`create app`) |
|||
const hwApp = new Btc(transport) |
|||
console.log(`scan account`) |
|||
const accounts = await scanNextAccount(wallet, hwApp) |
|||
console.log(accounts) |
|||
return [] |
|||
} catch (err) { |
|||
console.log(err) |
|||
} |
|||
} |
|||
|
|||
waitForDevices(async device => { |
|||
// const accounts = await scanAccountsOnDevice({
|
|||
// devicePath: device.path,
|
|||
// currencyId: 'bitcoin_testnet',
|
|||
// })
|
|||
// console.log(accounts)
|
|||
try { |
|||
console.log(`> Creating transport`) |
|||
const transport = await CommNodeHid.open(device.path) |
|||
|
|||
// transport.setDebugMode(true)
|
|||
|
|||
console.log(`> Instanciate BTC app`) |
|||
const hwApp = new Btc(transport) |
|||
|
|||
console.log(`> Get currency`) |
|||
const currency = await getCurrency('bitcoin_testnet') |
|||
|
|||
console.log(`> Create wallet`) |
|||
const wallet = CREATE ? await createWallet('khalil', currency) : await getWallet('khalil') |
|||
|
|||
console.log(`> Create account`) |
|||
const account = CREATE ? await createAccount(wallet, hwApp) : await wallet.getAccount(0) |
|||
|
|||
console.log(`> Sync account`) |
|||
if (CREATE) { |
|||
await syncAccount(account) |
|||
} |
|||
|
|||
console.log(`> Create transaction`) |
|||
const transaction = await createTransaction(wallet, account) |
|||
const signedTransaction = await signTransaction(hwApp, transaction) |
|||
|
|||
await account.asBitcoinLikeAccount().broadcastRawTransaction(signedTransaction) |
|||
// console.log(signedTransaction);
|
|||
|
|||
process.exit(0) |
|||
// console.log(account.getIndex());
|
|||
// console.log(account.isSynchronizing());
|
|||
} catch (err) { |
|||
console.log(err.message) |
|||
process.exit(1) |
|||
} |
|||
}) |
|||
|
|||
function waitForDevices(onDevice) { |
|||
console.log(`> Waiting for device...`) |
|||
CommNodeHid.listen({ |
|||
error: () => {}, |
|||
complete: () => {}, |
|||
next: async e => { |
|||
if (!e.device) { |
|||
return |
|||
} |
|||
if (e.type === 'add') { |
|||
console.log(`> Detected ${e.device.manufacturer} ${e.device.product}`) |
|||
onDevice(e.device) |
|||
} |
|||
if (e.type === 'remove') { |
|||
console.log(`removed ${JSON.stringify(e)}`) |
|||
} |
|||
}, |
|||
}) |
|||
} |
|||
|
|||
async function createTransaction(wallet, account) { |
|||
const ADDRESS_TO_SEND = 'n2jdejywRogCunR2ozZAfXp1jMnfGpGXGR' |
|||
|
|||
const bitcoinLikeAccount = account.asBitcoinLikeAccount() |
|||
const walletCurrency = wallet.getCurrency() |
|||
const amount = createAmount(walletCurrency, 10000) |
|||
|
|||
console.log(`--------------------------------`) |
|||
console.log(amount.toLong()) |
|||
console.log(`-----------------after `) |
|||
const fees = createAmount(walletCurrency, 1000) |
|||
|
|||
const transactionBuilder = bitcoinLikeAccount.buildTransaction() |
|||
transactionBuilder.sendToAddress(amount, ADDRESS_TO_SEND) |
|||
// TODO: don't use hardcoded value for sequence (and first also maybe)
|
|||
transactionBuilder.pickInputs(0, 0xffffff) |
|||
transactionBuilder.setFeesPerByte(fees) |
|||
|
|||
return transactionBuilder.build() |
|||
} |
@ -0,0 +1,22 @@ |
|||
// @flow
|
|||
|
|||
import React from 'react' |
|||
import type { Account } from '@ledgerhq/live-common/lib/types' |
|||
|
|||
import CurrentAddress from 'components/CurrentAddress' |
|||
|
|||
type Props = { |
|||
account: Account, |
|||
} |
|||
|
|||
export default function CurrentAddressForAccount(props: Props) { |
|||
const { account, ...p } = props |
|||
|
|||
// TODO: handle other cryptos than BTC-like
|
|||
let freshAddress = account.addresses[0] |
|||
if (!freshAddress) { |
|||
freshAddress = { str: '', path: '' } |
|||
} |
|||
|
|||
return <CurrentAddress accountName={account.name} address={freshAddress.str} {...p} /> |
|||
} |
@ -0,0 +1,71 @@ |
|||
// @flow
|
|||
|
|||
import Btc from '@ledgerhq/hw-app-btc' |
|||
import CommNodeHid from '@ledgerhq/hw-transport-node-hid' |
|||
import type { AccountRaw } from '@ledgerhq/live-common/lib/types' |
|||
|
|||
import type Transport from '@ledgerhq/hw-transport' |
|||
|
|||
import type { IPCSend } from 'types/electron' |
|||
import { getWalletIdentifier } from '../scanAccountsOnDevice' |
|||
|
|||
type BitcoinLikeTransaction = { |
|||
amount: number, |
|||
feePerByte: number, |
|||
recipient: string, |
|||
} |
|||
|
|||
export default async function signAndBroadcastTransactionBTCLike( |
|||
send: IPCSend, |
|||
{ |
|||
account, |
|||
transaction, |
|||
deviceId, // which is in fact `devicePath`
|
|||
}: { |
|||
account: AccountRaw, |
|||
transaction: BitcoinLikeTransaction, |
|||
deviceId: string, |
|||
}, |
|||
) { |
|||
try { |
|||
// TODO: investigate why importing it on file scope causes trouble
|
|||
const core = require('init-ledger-core')() |
|||
|
|||
// instanciate app on device
|
|||
const transport: Transport<*> = await CommNodeHid.open(deviceId) |
|||
const hwApp = new Btc(transport) |
|||
|
|||
const WALLET_IDENTIFIER = await getWalletIdentifier({ |
|||
hwApp, |
|||
isSegwit: account.isSegwit, |
|||
currencyId: account.currencyId, |
|||
devicePath: deviceId, |
|||
}) |
|||
|
|||
const njsWallet = await core.getWallet(WALLET_IDENTIFIER) |
|||
const njsAccount = await njsWallet.getAccount(account.index) |
|||
const bitcoinLikeAccount = njsAccount.asBitcoinLikeAccount() |
|||
const njsWalletCurrency = njsWallet.getCurrency() |
|||
const amount = core.createAmount(njsWalletCurrency, transaction.amount) |
|||
const fees = core.createAmount(njsWalletCurrency, transaction.feePerByte) |
|||
const transactionBuilder = bitcoinLikeAccount.buildTransaction() |
|||
|
|||
// TODO: check if is valid address. if not, it will fail silently on invalid
|
|||
|
|||
transactionBuilder.sendToAddress(amount, transaction.recipient) |
|||
// TODO: don't use hardcoded value for sequence (and first also maybe)
|
|||
transactionBuilder.pickInputs(0, 0xffffff) |
|||
transactionBuilder.setFeesPerByte(fees) |
|||
|
|||
const builded = await transactionBuilder.build() |
|||
const signedTransaction = await core.signTransaction(hwApp, builded) |
|||
|
|||
const txHash = await njsAccount |
|||
.asBitcoinLikeAccount() |
|||
.broadcastRawTransaction(signedTransaction) |
|||
|
|||
send('accounts.signAndBroadcastTransactionBTCLike.success', txHash) |
|||
} catch (err) { |
|||
send('accounts.signAndBroadcastTransactionBTCLike.fail', err) |
|||
} |
|||
} |
Loading…
Reference in new issue