Browse Source

Merge pull request #348 from gre/eth-fixes

helpers/derivations to derivate different paths
master
Meriadec Pillet 7 years ago
committed by GitHub
parent
commit
da502ad7aa
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 91
      src/bridge/EthereumJSBridge.js
  2. 4
      src/components/EnsureDeviceApp/index.js
  3. 32
      src/helpers/bip32path.js
  4. 29
      src/helpers/derivations.js

91
src/bridge/EthereumJSBridge.js

@ -4,7 +4,7 @@ import EthereumKind from 'components/FeesField/EthereumKind'
import type { Account, Operation } from '@ledgerhq/live-common/lib/types' import type { Account, Operation } from '@ledgerhq/live-common/lib/types'
import { apiForCurrency } from 'api/Ethereum' import { apiForCurrency } from 'api/Ethereum'
import type { Tx } from 'api/Ethereum' import type { Tx } from 'api/Ethereum'
import { makeBip44Path } from 'helpers/bip32path' import { getDerivations } from 'helpers/derivations'
import getAddressCommand from 'commands/getAddress' import getAddressCommand from 'commands/getAddress'
import signTransactionCommand from 'commands/signTransaction' import signTransactionCommand from 'commands/signTransaction'
import type { EditProps, WalletBridge } from './types' import type { EditProps, WalletBridge } from './types'
@ -30,8 +30,8 @@ const toAccountOperation = (account: Account) => (tx: Tx): Operation => {
hash: tx.hash, hash: tx.hash,
address: sending ? tx.to : tx.from, address: sending ? tx.to : tx.from,
amount: (sending ? -1 : 1) * tx.value, amount: (sending ? -1 : 1) * tx.value,
blockHeight: tx.block.height, blockHeight: tx.block && tx.block.height,
blockHash: tx.block.hash, blockHash: tx.block && tx.block.hash,
accountId: account.id, accountId: account.id,
senders: [tx.from], senders: [tx.from],
recipients: [tx.to], recipients: [tx.to],
@ -86,37 +86,39 @@ const EthereumBridge: WalletBridge<Transaction> = {
async function stepAddress( async function stepAddress(
index, index,
{ address, path }, { address, path },
isStandard,
): { account?: Account, complete?: boolean } { ): { account?: Account, complete?: boolean } {
const balance = await api.getAccountBalance(address) const balance = await api.getAccountBalance(address)
if (finished) return {} if (finished) return {}
if (balance === 0) { if (balance === 0) {
if (balanceZerosCount === 0) { if (isStandard) {
// first zero account will emit one account as opportunity to create a new account.. if (balanceZerosCount === 0) {
const currentBlock = await lazyCurrentBlock() // first zero account will emit one account as opportunity to create a new account..
const accountId = `${currency.id}_${address}` const currentBlock = await lazyCurrentBlock()
const account: Account = { const accountId = `${currency.id}_${address}`
id: accountId, const account: Account = {
xpub: '', id: accountId,
path, // FIXME we probably not want the address path in the account.path xpub: '',
walletPath: String(index), path, // FIXME we probably not want the address path in the account.path
name: 'New Account', walletPath: String(index),
isSegwit: false, name: 'New Account',
address, isSegwit: false,
addresses: [{ str: address, path, }], address,
balance, addresses: [{ str: address, path, }],
blockHeight: currentBlock.height, balance,
archived: true, blockHeight: currentBlock.height,
index, archived: true,
currency, index,
operations: [], currency,
unit: currency.units[0], operations: [],
lastSyncDate: new Date(), unit: currency.units[0],
lastSyncDate: new Date(),
}
return { account, complete: true }
} }
// NB we currently stop earlier. in future we shouldn't stop here, just continue & user will stop at the end! balanceZerosCount++
// NB (what's the max tho?)
return { account, complete: true }
} }
balanceZerosCount++ // NB for legacy addresses we might not want to stop at first zero but continue forever
return { complete: true } return { complete: true }
} }
@ -149,24 +151,25 @@ const EthereumBridge: WalletBridge<Transaction> = {
async function main() { async function main() {
try { try {
for (let index = 0; index < 255; index++) { const derivations = getDerivations(currency)
const res = await getAddressCommand const last = derivations[derivations.length - 1]
.send({ for (const derivation of derivations) {
currencyId: currency.id, const isStandard = last === derivation
devicePath: deviceId, for (let index = 0; index < 255; index++) {
path: makeBip44Path({ const path = derivation({ currency, x: index, segwit: false })
currency, console.log(path)
x: index, const res = await getAddressCommand
}), .send({ currencyId: currency.id, devicePath: deviceId, path })
}) .toPromise()
.toPromise() const r = await stepAddress(index, res, isStandard)
const r = await stepAddress(index, res) console.log('=>', r.account)
if (r.account) next(r.account) if (r.account) next(r.account)
if (r.complete) { if (r.complete) {
complete() break
break }
} }
} }
complete()
} catch (e) { } catch (e) {
error(e) error(e)
} }

4
src/components/EnsureDeviceApp/index.js

@ -2,7 +2,7 @@
import invariant from 'invariant' import invariant from 'invariant'
import { PureComponent } from 'react' import { PureComponent } from 'react'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { makeBip44Path } from 'helpers/bip32path' import { standardDerivation } from 'helpers/derivations'
import type { Account, CryptoCurrency } from '@ledgerhq/live-common/lib/types' import type { Account, CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import type { Device } from 'types/common' import type { Device } from 'types/common'
@ -110,7 +110,7 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
options = { options = {
devicePath: deviceSelected.path, devicePath: deviceSelected.path,
currencyId: currency.id, currencyId: currency.id,
path: makeBip44Path({ currency }), path: standardDerivation({ currency, x: 0, segwit: false }),
} }
} else { } else {
throw new Error('either currency or account is required') throw new Error('either currency or account is required')

32
src/helpers/bip32path.js

@ -1,32 +0,0 @@
// @flow
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
function shouldDerivateChangeFieldInsteadOfAccount(c: CryptoCurrency) {
// ethereum have a special way of derivating things
return c.id.indexOf('ethereum') === 0
}
// https://github.com/bitcoin/bips/blob/master/bip-0044.mediawiki
// x is a derivation index. we don't always derivate the same part of the path
export function makeBip44Path({
currency,
segwit,
x,
}: {
currency: CryptoCurrency,
segwit?: boolean,
x?: number,
}): string {
const purpose = segwit ? 49 : 44
const coinType = currency.coinType
let path = `${purpose}'/${coinType}'`
if (shouldDerivateChangeFieldInsteadOfAccount(currency)) {
path += "/0'"
if (x !== undefined) {
path += `/${x}`
}
} else if (x !== undefined) {
path += `/${x}'`
}
return path
}

29
src/helpers/derivations.js

@ -0,0 +1,29 @@
// @flow
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
type Derivation = ({
currency: CryptoCurrency,
segwit: boolean,
x: number,
}) => string
const ethLegacyMEW: Derivation = ({ x }) => `44'/60'/0'/${x}`
const etcLegacyMEW: Derivation = ({ x }) => `44'/60'/160720'/${x}`
const legacyDerivations = {
ethereum: [ethLegacyMEW],
ethereum_classic: [etcLegacyMEW],
}
export const standardDerivation: Derivation = ({ currency, segwit, x }) => {
const purpose = segwit ? 49 : 44
const { coinType } = currency
return `${purpose}'/${coinType}'/${x}'/0/0`
}
// return an array of ways to derivate, by convention the latest is the standard one.
export const getDerivations = (currency: CryptoCurrency): Derivation[] => [
...(legacyDerivations[currency.id] || []),
standardDerivation,
]
Loading…
Cancel
Save