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.
 
 
 
 

135 lines
4.3 KiB

// This is a work in progress
// The goal is to provide a cli which allow interact
// with device & libcore for faster iterations
require('babel-polyfill')
require('babel-register')
const chalk = require('chalk')
const inquirer = require('inquirer')
const path = require('path')
const TransportNodeHid = require('@ledgerhq/hw-transport-node-hid').default
const { serializeAccounts, encodeAccount, decodeAccount } = require('../src/reducers/accounts')
const { doSignAndBroadcast } = require('../src/commands/libcoreSignAndBroadcast')
const coreHelper = require('../src/helpers/libcore')
const withLibcore = require('../src/helpers/withLibcore').default
if (!process.env.LEDGER_LIVE_SQLITE_PATH) {
throw new Error('you must define process.env.LEDGER_LIVE_SQLITE_PATH first')
}
const LOCAL_DIRECTORY_PATH = path.resolve(process.env.LEDGER_LIVE_SQLITE_PATH, '../')
gimmeDeviceAndLibCore(async ({ device, core, njsWalletPool }) => {
const raw = require(path.join(LOCAL_DIRECTORY_PATH, 'accounts.json')) // eslint-disable-line import/no-dynamic-require
const accounts = serializeAccounts(raw.data)
const accountToUse = await chooseAccount('Which account to use?', accounts)
await actionLoop({ account: accountToUse, accounts, core, njsWalletPool, device })
process.exit(0)
})
async function actionLoop(props) {
try {
const { account, accounts, core, njsWalletPool, device } = props
const actionToDo = await chooseAction(`What do you want to do with [${account.name}] ?`)
if (actionToDo === 'send funds') {
const transport = await TransportNodeHid.open(device.path)
const accountToReceive = await chooseAccount('To which account?', accounts)
const receiveAddress = await getFreshAddress({
account: accountToReceive,
core,
njsWalletPool,
})
console.log(`the receive address is ${receiveAddress}`)
const rawAccount = encodeAccount(account)
console.log(`trying to sign and broadcast...`)
const rawOp = await doSignAndBroadcast({
account: rawAccount,
transaction: {
amount: 4200000,
recipient: receiveAddress,
feePerByte: 16,
isRBF: false,
},
deviceId: device.path,
core,
transport,
})
console.log(rawOp)
} else if (actionToDo === 'sync') {
console.log(`\nLaunch sync...\n`)
const rawAccount = encodeAccount(account)
const syncedAccount = await coreHelper.syncAccount({ rawAccount, core, njsWalletPool })
console.log(`\nEnd sync...\n`)
console.log(`updated account: `, displayAccount(syncedAccount, 'red'))
} else if (actionToDo === 'quit') {
return true
}
} catch (err) {
console.log(`x Something went wrong`)
console.log(err)
process.exit(1)
}
return actionLoop(props)
}
async function chooseInList(msg, list, formatItem = i => i) {
const choices = list.map(formatItem)
const { choice } = await inquirer.prompt([
{
type: 'list',
name: 'choice',
message: msg,
choices,
},
])
const index = choices.indexOf(choice)
return list[index]
}
async function chooseAction(msg) {
return chooseInList(msg, ['sync', 'send funds', 'quit'])
}
function chooseAccount(msg, accounts) {
return chooseInList(msg, accounts, acc => displayAccount(acc))
}
async function gimmeDeviceAndLibCore(cb) {
withLibcore((core, njsWalletPool) => {
TransportNodeHid.listen({
error: () => {},
complete: () => {},
next: async e => {
if (!e.device) {
return
}
if (e.type === 'add') {
const { device } = e
cb({ device, core, njsWalletPool })
}
},
})
})
}
function displayAccount(acc, color = null) {
const isRawAccount = typeof acc.lastSyncDate === 'string'
if (isRawAccount) {
acc = decodeAccount(acc)
}
const str = `[${acc.name}] ${acc.isSegwit ? '' : '(legacy) '}${acc.unit.code} ${acc.balance} - ${
acc.operations.length
} txs`
return color ? chalk[color](str) : str
}
async function getFreshAddress({ account, core, njsWalletPool }) {
const njsAccount = await coreHelper.getNJSAccount({ account, njsWalletPool })
const unsub = await core.syncAccount(njsAccount)
unsub()
const rawAddresses = await njsAccount.getFreshPublicAddresses()
return rawAddresses[0]
}