Browse Source

Errors for i18n

should protect the i18n with a ''
master
Gaëtan Renaudeau 7 years ago
parent
commit
055432e1d7
  1. 7
      src/api/Ethereum.js
  2. 5
      src/api/Fees.js
  3. 14
      src/api/Ledger.js
  4. 3
      src/bridge/BridgeSyncContext.js
  5. 15
      src/bridge/RippleJSBridge.js
  6. 5
      src/commands/index.js
  7. 7
      src/components/DeviceConnect/index.js
  8. 29
      src/components/EnsureDeviceApp/index.js
  9. 4
      src/components/GenuineCheckModal/index.js
  10. 5
      src/components/RequestAmount/index.js
  11. 5
      src/components/ThrowBlock.js
  12. 25
      src/components/TranslatedError.js
  13. 9
      src/components/base/FormattedVal/index.js
  14. 7
      src/components/base/Input/index.js
  15. 5
      src/components/modals/AddAccounts/index.js
  16. 6
      src/components/modals/AddAccounts/steps/02-step-connect-device.js
  17. 10
      src/components/modals/AddAccounts/steps/03-step-import.js
  18. 5
      src/components/modals/Receive/index.js
  19. 11
      src/components/modals/Send/04-step-confirmation.js
  20. 4
      src/components/modals/StepConnectDevice.js
  21. 13
      src/helpers/createCustomErrorClass.js
  22. 7
      src/helpers/getAddressForCurrency/btc.js
  23. 5
      src/helpers/libcore.js
  24. 8
      src/helpers/signTransactionForCurrency/ethereum.js
  25. 13
      static/i18n/en/errors.yml

7
src/api/Ethereum.js

@ -1,8 +1,11 @@
// @flow
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import network from './network'
import { blockchainBaseURL } from './Ledger'
export const LedgerAPINotAvailable = createCustomErrorClass('LedgerAPINotAvailable')
export type Block = { height: number } // TODO more fields actually
export type Tx = {
hash: string,
@ -42,7 +45,9 @@ export type API = {
export const apiForCurrency = (currency: CryptoCurrency): API => {
const baseURL = blockchainBaseURL(currency)
if (!baseURL) {
throw new Error(`ledger API not available for currency ${currency.id}`)
throw new LedgerAPINotAvailable(`LedgerAPINotAvailable ${currency.id}`, {
currencyName: currency.name,
})
}
return {
async getTransactions(address, blockHash) {

5
src/api/Fees.js

@ -1,9 +1,12 @@
// @flow
import invariant from 'invariant'
import type { Currency } from '@ledgerhq/live-common/lib/types'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { blockchainBaseURL } from './Ledger'
import network from './network'
const FeeEstimationFailed = createCustomErrorClass('FeeEstimationFailed')
export type Fees = {
[_: string]: number,
}
@ -15,5 +18,5 @@ export const getEstimatedFees = async (currency: Currency): Promise<Fees> => {
if (data) {
return data
}
throw new Error(`fee estimation failed. status=${status}`)
throw new FeeEstimationFailed(`FeeEstimationFailed ${status}`, { httpStatus: status })
}

14
src/api/Ledger.js

@ -1,9 +1,14 @@
// @flow
import type { Currency } from '@ledgerhq/live-common/lib/types'
import logger from 'logger'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
const BASE_URL = process.env.LEDGER_REST_API_BASE || 'https://api.ledgerwallet.com/'
export const LedgerAPIErrorWithMessage = createCustomErrorClass('LedgerAPIErrorWithMessage')
export const LedgerAPIError = createCustomErrorClass('LedgerAPIError')
export const NetworkDown = createCustomErrorClass('NetworkDown')
export const userFriendlyError = <A>(p: Promise<A>): Promise<A> =>
p.catch(error => {
if (error.response) {
@ -24,16 +29,17 @@ export const userFriendlyError = <A>(p: Promise<A>): Promise<A> =>
logger.warn("can't parse server result", e)
}
}
throw new Error(msg)
throw new LedgerAPIErrorWithMessage(msg)
}
}
logger.log('Ledger API: HTTP status', error.response.status, 'data: ', error.response.data)
throw new Error('A problem occurred with Ledger API. Please try again later.')
const { status } = error.response
logger.log('Ledger API: HTTP status', status, 'data: ', error.response.data)
throw new LedgerAPIError(`LedgerAPIError ${status}`, { status })
} else if (error.request) {
// The request was made but no response was received
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
// http.ClientRequest in node.js
throw new Error('Your network is down. Please try again later.')
throw new NetworkDown()
}
throw error
})

3
src/bridge/BridgeSyncContext.js

@ -3,6 +3,7 @@
// it handles automatically re-calling synchronize
// this is an even high abstraction than the bridge
import invariant from 'invariant'
import logger from 'logger'
import shuffle from 'lodash/shuffle'
import React, { Component } from 'react'
@ -65,7 +66,7 @@ class Provider extends Component<BridgeSyncProviderOwnProps, Sync> {
return
}
const account = this.props.accounts.find(a => a.id === accountId)
if (!account) throw new Error('account not found')
invariant(account, 'account not found')
const bridge = getBridgeForCurrency(account.currency)

15
src/bridge/RippleJSBridge.js

@ -1,4 +1,5 @@
// @flow
import invariant from 'invariant'
import { Observable } from 'rxjs'
import React from 'react'
import bs58check from 'ripple-bs58check'
@ -298,9 +299,10 @@ const RippleJSBridge: WalletBridge<Transaction> = {
if (finished) return
const balance = parseAPIValue(info.xrpBalance)
if (isNaN(balance) || !isFinite(balance)) {
throw new Error(`Ripple: invalid balance=${balance} for address ${address}`)
}
invariant(
!isNaN(balance) && isFinite(balance),
`Ripple: invalid balance=${balance} for address ${address}`,
)
const transactions = await api.getTransactions(address, {
minLedgerVersion,
@ -375,9 +377,10 @@ const RippleJSBridge: WalletBridge<Transaction> = {
}
const balance = parseAPIValue(info.xrpBalance)
if (isNaN(balance) || !isFinite(balance)) {
throw new Error(`Ripple: invalid balance=${balance} for address ${freshAddress}`)
}
invariant(
!isNaN(balance) && isFinite(balance),
`Ripple: invalid balance=${balance} for address ${freshAddress}`,
)
o.next(a => ({ ...a, balance }))

5
src/commands/index.js

@ -1,5 +1,6 @@
// @flow
import invariant from 'invariant'
import type { Command } from 'helpers/ipc'
import getAddress from 'commands/getAddress'
@ -53,9 +54,7 @@ const all: Array<Command<any, any>> = [
]
all.forEach(cmd => {
if (all.some(c => c !== cmd && c.id === cmd.id)) {
throw new Error(`duplicate command '${cmd.id}'`)
}
invariant(!all.some(c => c !== cmd && c.id === cmd.id), `duplicate command '${cmd.id}'`)
})
export default all

7
src/components/DeviceConnect/index.js

@ -12,6 +12,7 @@ import noop from 'lodash/noop'
import Box from 'components/base/Box'
import Spinner from 'components/base/Spinner'
import CryptoCurrencyIcon from 'components/CryptoCurrencyIcon'
import TranslatedError from 'components/TranslatedError'
import IconCheck from 'icons/Check'
import IconExclamationCircle from 'icons/ExclamationCircle'
@ -146,7 +147,7 @@ type Props = {
deviceSelected: ?Device,
onChangeDevice: Device => void,
t: T,
errorMessage: ?string,
error: ?Error,
}
const emitChangeDevice = props => {
@ -186,7 +187,7 @@ class DeviceConnect extends PureComponent<Props> {
genuineCheckStatus,
withGenuineCheck,
appOpened,
errorMessage,
error,
currency,
t,
onChangeDevice,
@ -306,7 +307,7 @@ class DeviceConnect extends PureComponent<Props> {
<Info hasErrors>
<IconInfoCircle size={12} />
<Box shrink selectable>
{String(errorMessage || '')}
<TranslatedError error={error} />
</Box>
</Info>
) : null}

29
src/components/EnsureDeviceApp/index.js

@ -13,9 +13,13 @@ import type { State as StoreState } from 'reducers/index'
import getAddress from 'commands/getAddress'
import { standardDerivation } from 'helpers/derivations'
import isDashboardOpen from 'commands/isDashboardOpen'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
import { CHECK_APP_INTERVAL_WHEN_VALID, CHECK_APP_INTERVAL_WHEN_INVALID } from 'config/constants'
export const WrongAppOpened = createCustomErrorClass('WrongAppOpened')
export const WrongDeviceForAccount = createCustomErrorClass('WrongDeviceForAccount')
type OwnProps = {
currency?: ?CryptoCurrency,
deviceSelected: ?Device,
@ -31,7 +35,7 @@ type OwnProps = {
devices: Device[],
deviceSelected: ?Device,
deviceStatus: DeviceStatus,
errorMessage: ?string,
error: ?Error,
}) => React$Element<*>,
}
@ -48,7 +52,7 @@ type GenuineCheckStatus = 'success' | 'fail' | 'progress'
type State = {
deviceStatus: DeviceStatus,
appStatus: AppStatus,
errorMessage: ?string,
error: ?Error,
genuineCheckStatus: GenuineCheckStatus,
}
@ -62,7 +66,7 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
state = {
appStatus: 'progress',
deviceStatus: this.props.deviceSelected ? 'connected' : 'unconnected',
errorMessage: null,
error: null,
genuineCheckStatus: 'progress',
}
@ -139,7 +143,7 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
e.message === 'Cannot write to HID device')
) {
logger.log(e)
throw new Error(`You must open application ‘${cur.name}’ on the device`)
throw new WrongAppOpened(`WrongAppOpened ${cur.id}`, { currencyName: cur.name })
}
throw e
})
@ -148,10 +152,13 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
const { freshAddress } = account
if (account && freshAddress !== address) {
logger.warn({ freshAddress, address })
throw new Error(`You must use the device associated to the account ‘${account.name}`)
throw new WrongDeviceForAccount(`WrongDeviceForAccount ${account.name}`, {
accountName: account.name,
})
}
}
} else {
logger.warn('EnsureDeviceApp for using dashboard is DEPRECATED !!!')
// FIXME REMOVE THIS ! should use EnsureDashboard dedicated component.
const isDashboard = isDashboardOpen.send({ devicePath: deviceSelected.path }).toPromise()
@ -166,7 +173,7 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
this.handleGenuineCheck()
}
} catch (e) {
this.handleStatusChange(this.state.deviceStatus, 'fail', e.message)
this.handleStatusChange(this.state.deviceStatus, 'fail', e)
isSuccess = false
}
@ -182,12 +189,12 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
_timeout: *
_unmounted = false
handleStatusChange = (deviceStatus, appStatus, errorMessage = null) => {
handleStatusChange = (deviceStatus, appStatus, error = null) => {
const { onStatusChange } = this.props
clearTimeout(this._timeout)
if (!this._unmounted) {
this.setState({ deviceStatus, appStatus, errorMessage })
onStatusChange && onStatusChange(deviceStatus, appStatus, errorMessage)
this.setState({ deviceStatus, appStatus, error })
onStatusChange && onStatusChange(deviceStatus, appStatus, error)
}
}
@ -202,7 +209,7 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
render() {
const { currency, account, devices, deviceSelected, render } = this.props
const { appStatus, deviceStatus, genuineCheckStatus, errorMessage } = this.state
const { appStatus, deviceStatus, genuineCheckStatus, error } = this.state
if (render) {
// if cur is not provided, we assume we want to check if user is on
@ -216,7 +223,7 @@ class EnsureDeviceApp extends PureComponent<Props, State> {
deviceSelected: deviceStatus === 'connected' ? deviceSelected : null,
deviceStatus,
genuineCheckStatus,
errorMessage,
error,
})
}

4
src/components/GenuineCheckModal/index.js

@ -45,7 +45,7 @@ class GenuineCheck extends PureComponent<Props, State> {
onStatusChange={status => {
logger.log(`status changed to ${status}`)
}}
render={({ appStatus, genuineCheckStatus, deviceSelected, errorMessage }) => (
render={({ appStatus, genuineCheckStatus, deviceSelected, error }) => (
<DeviceConnect
appOpened={
appStatus === 'success' ? 'success' : appStatus === 'fail' ? 'fail' : null
@ -54,7 +54,7 @@ class GenuineCheck extends PureComponent<Props, State> {
genuineCheckStatus={genuineCheckStatus}
devices={reducedDevicesList}
deviceSelected={deviceSelected}
errorMessage={errorMessage}
error={error}
/>
)}
/>

5
src/components/RequestAmount/index.js

@ -21,6 +21,9 @@ import InputCurrency from 'components/base/InputCurrency'
import Button from 'components/base/Button'
import Box from 'components/base/Box'
import type { State } from 'reducers'
import createCustomErrorClass from 'helpers/createCustomErrorClass'
const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
const InputRight = styled(Box).attrs({
ff: 'Rubik',
@ -145,7 +148,7 @@ export class RequestAmount extends PureComponent<Props> {
return (
<Box horizontal grow shrink>
<InputCurrency
error={canBeSpent ? null : 'Not enough balance'}
error={canBeSpent ? null : new NotEnoughBalance()}
containerProps={containerProps}
defaultUnit={account.unit}
value={value}

5
src/components/ThrowBlock.js

@ -12,6 +12,7 @@ import db from 'helpers/db'
import ExportLogsBtn from 'components/ExportLogsBtn'
import Box from 'components/base/Box'
import Button from 'components/base/Button'
import TranslatedError from './TranslatedError'
type Props = {
children: any,
@ -81,7 +82,9 @@ ${error.stack}
if (error) {
return (
<Container>
<Inner>{`Error: ${error.message}`}</Inner>
<Inner>
<TranslatedError error={error} />
</Inner>
<Box horizontal flow={2}>
<Button primary onClick={this.handleRestart}>
{'Restart app'}

25
src/components/TranslatedError.js

@ -0,0 +1,25 @@
// @flow
// Convention:
// - errors we throw on our app will use a different error.name per error type
// - an error can have parameters, to use them, just use field of the Error object, that's what we give to `t()`
// - returned value is intentially not styled (is universal). wrap this in whatever you need
import { PureComponent } from 'react'
import { translate } from 'react-i18next'
import type { T } from 'types/common'
type Props = {
error: ?Error,
t: T,
}
class TranslatedError extends PureComponent<Props> {
render() {
const { t, error } = this.props
if (!error) return null
if (typeof error === 'string') return error
return t(`errors:${error.name}`, error)
}
}
export default translate()(TranslatedError)

9
src/components/base/FormattedVal/index.js

@ -1,5 +1,6 @@
// @flow
import invariant from 'invariant'
import React from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
@ -76,9 +77,7 @@ function FormattedVal(props: Props) {
} = props
let { val } = props
if (isUndefined(val)) {
throw new Error('FormattedVal require a `val` prop. Received `undefined`')
}
invariant(!isUndefined(val), 'FormattedVal require a `val` prop. Received `undefined`')
const isNegative = val < 0
@ -88,9 +87,7 @@ function FormattedVal(props: Props) {
// FIXME move out the % feature of this component... totally unrelated to currency & annoying for flow type.
text = `${alwaysShowSign ? (isNegative ? '- ' : '+ ') : ''}${isNegative ? val * -1 : val} %`
} else {
if (!unit) {
throw new Error('FormattedVal require a `unit` prop. Received `undefined`')
}
invariant(unit, 'FormattedVal require a `unit` prop. Received `undefined`')
if (withIcon && isNegative) {
val *= -1

7
src/components/base/Input/index.js

@ -8,6 +8,7 @@ import noop from 'lodash/noop'
import fontFamily from 'styles/styled/fontFamily'
import Box from 'components/base/Box'
import TranslatedError from 'components/TranslatedError'
const Container = styled(Box).attrs({
horizontal: true,
@ -172,7 +173,11 @@ class Input extends PureComponent<Props, State> {
onChange={this.handleChange}
onKeyDown={this.handleKeyDown}
/>
{error && typeof error === 'string' ? <ErrorDisplay>{error}</ErrorDisplay> : null}
{error ? (
<ErrorDisplay>
<TranslatedError error={error} />
</ErrorDisplay>
) : null}
</Box>
{renderRight}
</Container>

5
src/components/modals/AddAccounts/index.js

@ -1,5 +1,6 @@
// @flow
import invariant from 'invariant'
import React, { PureComponent } from 'react'
import { compose } from 'redux'
import { connect } from 'react-redux'
@ -173,9 +174,7 @@ class AddAccounts extends PureComponent<Props, State> {
const stepIndex = this.STEPS.findIndex(s => s.id === stepId)
const step = this.STEPS[stepIndex]
if (!step) {
throw new Error(`AddAccountsModal: step ${stepId} doesn't exists`)
}
invariant(step, `AddAccountsModal: step ${stepId} doesn't exists`)
const { component: StepComponent, footer: StepFooter, hideFooter, onBack } = step

6
src/components/modals/AddAccounts/steps/02-step-connect-device.js

@ -1,5 +1,6 @@
// @flow
import invariant from 'invariant'
import React, { Fragment } from 'react'
import { Trans } from 'react-i18next'
@ -11,9 +12,8 @@ import { CurrencyCircleIcon } from 'components/base/CurrencyBadge'
import type { StepProps } from '../index'
function StepConnectDevice({ t, currency, currentDevice, setState }: StepProps) {
if (!currency) {
throw new Error('No currency given')
}
invariant(currency, 'No currency given')
return (
<Fragment>
<Box align="center" mb={6}>

10
src/components/modals/AddAccounts/steps/03-step-import.js

@ -1,5 +1,6 @@
// @flow
import invariant from 'invariant'
import React, { PureComponent, Fragment } from 'react'
import type { Account } from '@ledgerhq/live-common/lib/types'
import uniq from 'lodash/uniq'
@ -30,13 +31,8 @@ class StepImport extends PureComponent<StepProps> {
startScanAccountsDevice() {
const { currency, currentDevice, setState } = this.props
try {
if (!currency) {
throw new Error('No currency to scan')
}
if (!currentDevice) {
throw new Error('No device')
}
invariant(currency, 'No currency to scan')
invariant(currentDevice, 'No device')
const bridge = getBridgeForCurrency(currency)

5
src/components/modals/Receive/index.js

@ -18,6 +18,7 @@ import Breadcrumb from 'components/Breadcrumb'
import Button from 'components/base/Button'
import Modal, { ModalBody, ModalTitle, ModalContent, ModalFooter } from 'components/base/Modal'
import StepConnectDevice from 'components/modals/StepConnectDevice'
import { WrongDeviceForAccount } from 'components/EnsureDeviceApp'
import StepAccount from './01-step-account'
import StepConfirmAddress from './03-step-confirm-address'
@ -208,7 +209,9 @@ class ReceiveModal extends PureComponent<Props, State> {
.toPromise()
if (address !== account.freshAddress) {
throw new Error('Confirmed address is different')
throw new WrongDeviceForAccount(`WrongDeviceForAccount ${account.name}`, {
accountName: account.name,
})
}
this.setState({ addressVerified: true, stepIndex: 3 })

11
src/components/modals/Send/04-step-confirmation.js

@ -2,6 +2,7 @@
import React from 'react'
import styled from 'styled-components'
import type { Operation } from '@ledgerhq/live-common/lib/types'
import type { T } from 'types/common'
import Spinner from 'components/base/Spinner'
import IconCheckCircle from 'icons/CheckCircle'
@ -9,9 +10,7 @@ import IconExclamationCircleThin from 'icons/ExclamationCircleThin'
import Box from 'components/base/Box'
import { multiline } from 'styles/helpers'
import { colors } from 'styles/theme'
import { formatError } from 'helpers/errors'
import type { T } from 'types/common'
import TranslatedError from '../../TranslatedError'
const Container = styled(Box).attrs({
alignItems: 'center',
@ -65,7 +64,11 @@ function StepConfirmation(props: Props) {
</span>
<Title>{t(`${tPrefix}.title`)}</Title>
<Text style={{ userSelect: 'text' }}>
{optimisticOperation ? multiline(t(`${tPrefix}.text`)) : error ? formatError(error) : null}
{optimisticOperation ? (
multiline(t(`${tPrefix}.text`))
) : error ? (
<TranslatedError error={error} />
) : null}
</Text>
<Text style={{ userSelect: 'text' }}>
{optimisticOperation ? optimisticOperation.hash : ''}

4
src/components/modals/StepConnectDevice.js

@ -28,14 +28,14 @@ const StepConnectDevice = ({
currency={currency}
deviceSelected={deviceSelected}
onStatusChange={onStatusChange}
render={({ currency, appStatus, devices, deviceSelected, errorMessage }) => (
render={({ currency, appStatus, devices, deviceSelected, error }) => (
<DeviceConnect
currency={currency}
appOpened={appStatus === 'success' ? 'success' : appStatus === 'fail' ? 'fail' : null}
devices={devices}
deviceSelected={deviceSelected}
onChangeDevice={onChangeDevice}
errorMessage={errorMessage}
error={error}
/>
)}
/>

13
src/helpers/createCustomErrorClass.js

@ -0,0 +1,13 @@
// @flow
export default (name: string) => {
const C = function CustomError(message?: string, fields?: Object) {
this.name = name
this.message = message || name
this.stack = new Error().stack
Object.assign(this, fields)
}
// $FlowFixMe
C.prototype = new Error()
return C
}

7
src/helpers/getAddressForCurrency/btc.js

@ -4,6 +4,9 @@ import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import Btc from '@ledgerhq/hw-app-btc'
import type Transport from '@ledgerhq/hw-transport'
import getBitcoinLikeInfo from '../devices/getBitcoinLikeInfo'
import createCustomErrorClass from '../createCustomErrorClass'
const BtcUnmatchedApp = createCustomErrorClass('BtcUnmatchedApp')
export default async (
transport: Transport<*>,
@ -24,7 +27,9 @@ export default async (
if (bitcoinLikeInfo) {
const { P2SH, P2PKH } = await getBitcoinLikeInfo(transport)
if (P2SH !== bitcoinLikeInfo.P2SH || P2PKH !== bitcoinLikeInfo.P2PKH) {
throw new Error(`You must open application ‘${currency.name}’ on the device`)
throw new BtcUnmatchedApp(`BtcUnmatchedApp ${currency.id}`, {
currencyName: currency.name,
})
}
}

5
src/helpers/libcore.js

@ -10,9 +10,12 @@ import type { NJSAccount, NJSOperation } from '@ledgerhq/ledger-core/src/ledgerc
import { isSegwitAccount } from 'helpers/bip32'
import * as accountIdHelper from 'helpers/accountId'
import createCustomErrorClass from './createCustomErrorClass'
import { getAccountPlaceholderName, getNewAccountPlaceholderName } from './accountName'
const NoAddressesFound = createCustomErrorClass('NoAddressesFound')
type Props = {
core: *,
devicePath: string,
@ -248,7 +251,7 @@ async function buildAccountRaw({
}))
if (addresses.length === 0) {
throw new Error('no addresses found')
throw new NoAddressesFound()
}
const { str: freshAddress, path: freshAddressPath } = addresses[0]

8
src/helpers/signTransactionForCurrency/ethereum.js

@ -1,4 +1,5 @@
// @flow
import invariant from 'invariant'
import Eth from '@ledgerhq/hw-app-eth'
import type Transport from '@ledgerhq/hw-transport'
import EthereumTx from 'ethereumjs-tx'
@ -34,7 +35,7 @@ export default async (
// First, we need to create a partial tx and send to the device
const chainId = getNetworkId(currencyId)
if (!chainId) throw new Error(`chainId not found for currency=${currencyId}`)
invariant(chainId, `chainId not found for currency=${currencyId}`)
const tx = new EthereumTx({
nonce: t.nonce,
gasPrice: `0x${t.gasPrice.toString(16)}`,
@ -57,11 +58,10 @@ export default async (
tx.s = Buffer.from(result.s, 'hex')
const signedChainId = Math.floor((tx.v[0] - 35) / 2) // EIP155: v should be chain_id * 2 + {35, 36}
const validChainId = chainId & 0xff // eslint-disable-line no-bitwise
if (signedChainId !== validChainId) {
throw new Error(
invariant(
signedChainId === validChainId,
`Invalid chainId signature returned. Expected: ${chainId}, Got: ${signedChainId}`,
)
}
// Finally, we can send the transaction string to broadcast
return `0x${tx.serialize().toString('hex')}`

13
static/i18n/en/errors.yml

@ -0,0 +1,13 @@
RangeError: {{message}}
Error: {{message}}
LedgerAPIErrorWithMessage: {{message}}
TransportStatusError: {{message}}
FeeEstimationFailed: 'fee estimation failed (status: {{status}})'
NotEnoughBalance: 'Not enough balance'
BtcUnmatchedApp: 'You must open application ‘{{currencyName}}’ on the device'
WrongAppOpened: 'You must open application ‘{{currencyName}}’ on the device'
WrongDeviceForAccount: 'You must use the device associated to the account ‘{{accountName}}’'
LedgerAPINotAvailable: 'Ledger API is not available for currency {{currencyName}}'
LedgerAPIError: 'A problem occurred with Ledger API. Please try again later. (HTTP {{status}})'
NetworkDown: 'Your internet connection seems down. Please try again later.'
NoAddressesFound: 'No accounts found'
Loading…
Cancel
Save