Browse Source

Migrate the app to BigNumber.js

master
Gaëtan Renaudeau 7 years ago
parent
commit
ae2fe0401c
  1. 3
      package.json
  2. 6
      src/api/Ethereum.js
  3. 5
      src/api/Ripple.js
  4. 44
      src/bridge/EthereumJSBridge.js
  5. 39
      src/bridge/LibcoreBridge.js
  6. 36
      src/bridge/RippleJSBridge.js
  7. 7
      src/bridge/UnsupportedBridge.js
  8. 2
      src/bridge/makeMockBridge.js
  9. 9
      src/bridge/types.js
  10. 21
      src/commands/libcoreGetFees.js
  11. 24
      src/commands/libcoreSignAndBroadcast.js
  12. 7
      src/components/AccountPage/AccountBalanceSummaryHeader.js
  13. 2
      src/components/AccountPage/AccountHeaderActions.js
  14. 2
      src/components/AccountPage/index.js
  15. 11
      src/components/AdvancedOptions/EthereumKind.js
  16. 11
      src/components/BalanceSummary/BalanceInfos.js
  17. 18
      src/components/BalanceSummary/index.js
  18. 17
      src/components/CalculateBalance.js
  19. 5
      src/components/CounterValue/index.js
  20. 2
      src/components/DashboardPage/AccountCard.js
  21. 13
      src/components/DeltaChange.js
  22. 21
      src/components/FeesField/BitcoinKind.js
  23. 9
      src/components/FeesField/EthereumKind.js
  24. 7
      src/components/FeesField/RippleKind.js
  25. 2
      src/components/OperationsList/AmountCell.js
  26. 3
      src/components/RecipientAddress/index.js
  27. 2
      src/components/base/Chart/handleMouseEvents.js
  28. 2
      src/components/base/Chart/index.js
  29. 4
      src/components/base/Chart/refreshDraw.js
  30. 3
      src/components/base/Chart/stories.js
  31. 8
      src/components/base/Chart/types.js
  32. 3
      src/components/base/FlipTicker/stories.js
  33. 16
      src/components/base/FormattedVal/index.js
  34. 34
      src/components/base/InputCurrency/index.js
  35. 2
      src/components/modals/OperationDetails.js
  36. 7
      src/components/modals/Send/steps/01-step-amount.js
  37. 11
      src/helpers/libcore.js
  38. 13
      src/helpers/signTransactionForCurrency/ethereum.js
  39. 11
      yarn.lock

3
package.json

@ -37,12 +37,13 @@
"@ledgerhq/hw-transport": "^4.13.0",
"@ledgerhq/hw-transport-node-hid": "^4.13.0",
"@ledgerhq/ledger-core": "2.0.0-rc.4",
"@ledgerhq/live-common": "^2.35.0",
"@ledgerhq/live-common": "3.0.0-beta.2",
"animated": "^0.2.2",
"async": "^2.6.1",
"axios": "^0.18.0",
"babel-runtime": "^6.26.0",
"bcryptjs": "^2.4.3",
"bignumber.js": "^7.2.1",
"bitcoinjs-lib": "^3.3.2",
"bs58": "^4.0.1",
"color": "^3.0.0",

6
src/api/Ethereum.js

@ -1,5 +1,6 @@
// @flow
import type { CryptoCurrency } from '@ledgerhq/live-common/lib/types'
import { BigNumber } from 'bignumber.js'
import { createCustomErrorClass } from 'helpers/errors'
import network from './network'
import { blockchainBaseURL } from './Ledger'
@ -39,7 +40,7 @@ export type API = {
getCurrentBlock: () => Promise<Block>,
getAccountNonce: (address: string) => Promise<number>,
broadcastTransaction: (signedTransaction: string) => Promise<string>,
getAccountBalance: (address: string) => Promise<number>,
getAccountBalance: (address: string) => Promise<BigNumber>,
}
export const apiForCurrency = (currency: CryptoCurrency): API => {
@ -85,7 +86,8 @@ export const apiForCurrency = (currency: CryptoCurrency): API => {
method: 'GET',
url: `${baseURL}/addresses/${address}/balance`,
})
return data[0].balance
// FIXME precision lost here. nothing we can do easily
return BigNumber(data[0].balance)
},
}
}

5
src/api/Ripple.js

@ -1,5 +1,6 @@
// @flow
import logger from 'logger'
import { BigNumber } from 'bignumber.js'
import { RippleAPI } from 'ripple-lib'
import {
parseCurrencyUnit,
@ -31,12 +32,12 @@ export const parseAPICurrencyObject = ({
}) => {
if (currency !== 'XRP') {
logger.warn(`RippleJS: attempt to parse unknown currency ${currency}`)
return 0
return BigNumber(0)
}
return parseAPIValue(value)
}
export const formatAPICurrencyXRP = (amount: number) => {
export const formatAPICurrencyXRP = (amount: BigNumber) => {
const value = formatCurrencyUnit(rippleUnit, amount, {
showAllDigits: true,
disableRounding: true,

44
src/bridge/EthereumJSBridge.js

@ -1,5 +1,6 @@
// @flow
import { Observable } from 'rxjs'
import { BigNumber } from 'bignumber.js'
import React from 'react'
import FeesField from 'components/FeesField/EthereumKind'
import AdvancedOptions from 'components/AdvancedOptions/EthereumKind'
@ -21,12 +22,19 @@ const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
// TODO in future it would be neat to support eip55
type Transaction = {
amount: number,
recipient: string,
gasPrice: number,
gasLimit: number,
amount: BigNumber,
gasPrice: BigNumber,
gasLimit: BigNumber,
}
const serializeTransaction = t => ({
recipient: t.recipient,
amount: `0x${BigNumber(t.amount).toString(16)}`,
gasPrice: `0x${BigNumber(t.gasPrice).toString(16)}`,
gasLimit: `0x${BigNumber(t.gasLimit).toString(16)}`,
})
const EditFees = ({ account, onChange, value }: EditProps<Transaction>) => (
<FeesField
onChange={gasPrice => {
@ -60,8 +68,8 @@ const txToOps = (account: Account) => (tx: Tx): Operation[] => {
id: `${account.id}-${tx.hash}-OUT`,
hash: tx.hash,
type: 'OUT',
value: tx.value,
fee,
value: BigNumber(tx.value), // FIXME problem with our api, precision lost here...
fee: BigNumber(fee), // FIXME problem with our api, precision lost here...
blockHeight: tx.block && tx.block.height,
blockHash: tx.block && tx.block.hash,
accountId: account.id,
@ -75,8 +83,8 @@ const txToOps = (account: Account) => (tx: Tx): Operation[] => {
id: `${account.id}-${tx.hash}-IN`,
hash: tx.hash,
type: 'IN',
value: tx.value,
fee,
value: BigNumber(tx.value), // FIXME problem with our api, precision lost here...
fee: BigNumber(fee), // FIXME problem with our api, precision lost here...
blockHeight: tx.block && tx.block.height,
blockHash: tx.block && tx.block.hash,
accountId: account.id,
@ -115,7 +123,7 @@ const signAndBroadcast = async ({
currencyId: a.currency.id,
devicePath: deviceId,
path: a.freshAddressPath,
transaction: { ...t, nonce },
transaction: { ...serializeTransaction(t), nonce },
})
.toPromise()
@ -129,7 +137,7 @@ const signAndBroadcast = async ({
hash,
type: 'OUT',
value: t.amount,
fee: t.gasPrice * t.gasLimit,
fee: t.gasPrice.times(t.gasLimit),
blockHeight: null,
blockHash: null,
accountId: a.id,
@ -351,10 +359,10 @@ const EthereumBridge: WalletBridge<Transaction> = {
isRecipientValid: (currency, recipient) => Promise.resolve(isRecipientValid(currency, recipient)),
createTransaction: () => ({
amount: 0,
amount: BigNumber(0),
recipient: '',
gasPrice: 0,
gasLimit: 0x5208,
gasPrice: BigNumber(0),
gasLimit: BigNumber(0x5208),
}),
editTransactionAmount: (account, t, amount) => ({
@ -371,16 +379,20 @@ const EthereumBridge: WalletBridge<Transaction> = {
getTransactionRecipient: (a, t) => t.recipient,
isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false,
isValidTransaction: (a, t) => (!t.amount.isZero() && t.recipient && true) || false,
EditFees,
EditAdvancedOptions,
checkCanBeSpent: (a, t) =>
t.amount <= a.balance ? Promise.resolve() : Promise.reject(new NotEnoughBalance()),
getTotalSpent: (a, t) => Promise.resolve(t.amount + t.gasPrice * t.gasLimit),
getMaxAmount: (a, t) => Promise.resolve(a.balance - t.gasPrice * t.gasLimit),
t.amount.isLessThanOrEqualTo(a.balance)
? Promise.resolve()
: Promise.reject(new NotEnoughBalance()),
getTotalSpent: (a, t) => Promise.resolve(t.amount.plus(t.gasPrice.times(t.gasLimit))),
getMaxAmount: (a, t) => Promise.resolve(a.balance.minus(t.gasPrice.times(t.gasLimit))),
signAndBroadcast: (a, t, deviceId) =>
Observable.create(o => {

39
src/bridge/LibcoreBridge.js

@ -1,5 +1,6 @@
// @flow
import React from 'react'
import { BigNumber } from 'bignumber.js'
import { Observable } from 'rxjs'
import LRU from 'lru-cache'
import { map } from 'rxjs/operators'
@ -20,11 +21,17 @@ const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
const notImplemented = new Error('LibcoreBridge: not implemented')
type Transaction = {
amount: number,
feePerByte: number,
amount: BigNumber,
feePerByte: BigNumber,
recipient: string,
}
const serializeTransaction = t => ({
recipient: t.recipient,
amount: t.amount.toString(),
feePerByte: t.feePerByte.toString(),
})
const decodeOperation = (encodedAccount, rawOp) =>
decodeAccount({ ...encodedAccount, operations: [rawOp] }).operations[0]
@ -70,7 +77,7 @@ const isRecipientValid = (currency, recipient) => {
const feesLRU = LRU({ max: 100 })
const getFeesKey = (a, t) =>
`${a.id}_${a.blockHeight || 0}_${t.amount}_${t.recipient}_${t.feePerByte}`
`${a.id}_${a.blockHeight || 0}_${t.amount.toString()}_${t.recipient}_${t.feePerByte.toString()}`
const getFees = async (a, transaction) => {
const isValid = await isRecipientValid(a.currency, transaction.recipient)
@ -79,9 +86,13 @@ const getFees = async (a, transaction) => {
let promise = feesLRU.get(key)
if (promise) return promise
promise = libcoreGetFees
.send({ accountId: a.id, accountIndex: a.index, transaction })
.send({
accountId: a.id,
accountIndex: a.index,
transaction: serializeTransaction(transaction),
})
.toPromise()
.then(r => r.totalFees)
.then(r => BigNumber(r.totalFees))
feesLRU.set(key, promise)
return promise
}
@ -168,9 +179,9 @@ const LibcoreBridge: WalletBridge<Transaction> = {
isRecipientValid,
createTransaction: () => ({
amount: 0,
amount: BigNumber(0),
recipient: '',
feePerByte: 0,
feePerByte: BigNumber(0),
isRBF: false,
}),
@ -192,28 +203,28 @@ const LibcoreBridge: WalletBridge<Transaction> = {
// EditAdvancedOptions,
isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false,
isValidTransaction: (a, t) => (!t.amount.isZero() && t.recipient && true) || false,
checkCanBeSpent,
getTotalSpent: (a, t) =>
!t.amount
? Promise.resolve(0)
? Promise.resolve(BigNumber(0))
: getFees(a, t)
.then(totalFees => t.amount + (totalFees || 0))
.catch(() => 0),
.then(totalFees => t.amount.plus(totalFees || 0))
.catch(() => BigNumber(0)),
getMaxAmount: (a, t) =>
getFees(a, t)
.catch(() => 0)
.then(totalFees => a.balance - (totalFees || 0)),
.catch(() => BigNumber(0))
.then(totalFees => a.balance.minus(totalFees || 0)),
signAndBroadcast: (account, transaction, deviceId) => {
const encodedAccount = encodeAccount(account) // FIXME no need to send the whole account over the threads
return libcoreSignAndBroadcast
.send({
account: encodedAccount,
transaction,
transaction: serializeTransaction(transaction),
deviceId,
})
.pipe(

36
src/bridge/RippleJSBridge.js

@ -1,5 +1,6 @@
// @flow
import invariant from 'invariant'
import { BigNumber } from 'bignumber.js'
import { Observable } from 'rxjs'
import React from 'react'
import bs58check from 'ripple-bs58check'
@ -25,9 +26,9 @@ import type { WalletBridge, EditProps } from './types'
const NotEnoughBalance = createCustomErrorClass('NotEnoughBalance')
type Transaction = {
amount: number,
amount: BigNumber,
recipient: string,
fee: number,
fee: BigNumber,
tag: ?number,
}
@ -196,11 +197,11 @@ const txToOperation = (account: Account) => ({
specification: { source, destination },
}: Tx): ?Operation => {
const type = source.address === account.freshAddress ? 'OUT' : 'IN'
let value = deliveredAmount ? parseAPICurrencyObject(deliveredAmount) : 0
let value = deliveredAmount ? parseAPICurrencyObject(deliveredAmount) : BigNumber(0)
const feeValue = parseAPIValue(fee)
if (type === 'OUT') {
if (!isNaN(feeValue)) {
value += feeValue
value = value.plus(feeValue)
}
}
@ -292,7 +293,7 @@ const RippleJSBridge: WalletBridge<Transaction> = {
name: getNewAccountPlaceholderName(currency, index),
freshAddress,
freshAddressPath,
balance: 0,
balance: BigNumber(0),
blockHeight: maxLedgerVersion,
index,
currency,
@ -309,8 +310,8 @@ const RippleJSBridge: WalletBridge<Transaction> = {
if (finished) return
const balance = parseAPIValue(info.xrpBalance)
invariant(
!isNaN(balance) && isFinite(balance),
`Ripple: invalid balance=${balance} for address ${address}`,
!balance.isNaN() && balance.isFinite(),
`Ripple: invalid balance=${balance.toString()} for address ${address}`,
)
const transactions = await api.getTransactions(address, {
@ -393,8 +394,8 @@ const RippleJSBridge: WalletBridge<Transaction> = {
const balance = parseAPIValue(info.xrpBalance)
invariant(
!isNaN(balance) && isFinite(balance),
`Ripple: invalid balance=${balance} for address ${freshAddress}`,
!balance.isNaN() && balance.isFinite(),
`Ripple: invalid balance=${balance.toString()} for address ${freshAddress}`,
)
o.next(a => ({ ...a, balance }))
@ -448,9 +449,9 @@ const RippleJSBridge: WalletBridge<Transaction> = {
isRecipientValid: (currency, recipient) => Promise.resolve(isRecipientValid(currency, recipient)),
createTransaction: () => ({
amount: 0,
amount: BigNumber(0),
recipient: '',
fee: 0,
fee: BigNumber(0),
tag: undefined,
}),
@ -472,19 +473,24 @@ const RippleJSBridge: WalletBridge<Transaction> = {
getTransactionRecipient: (a, t) => t.recipient,
isValidTransaction: (a, t) => (t.amount > 0 && t.recipient && true) || false,
isValidTransaction: (a, t) => (!t.amount.isZero() && t.recipient && true) || false,
checkCanBeSpent: async (a, t) => {
const r = await getServerInfo(a.endpointConfig)
if (t.amount + t.fee + parseAPIValue(r.validatedLedger.reserveBaseXRP) <= a.balance) {
if (
t.amount
.plus(t.fee)
.plus(parseAPIValue(r.validatedLedger.reserveBaseXRP))
.isLessThanOrEqualTo(a.balance)
) {
return
}
throw new NotEnoughBalance()
},
getTotalSpent: (a, t) => Promise.resolve(t.amount + t.fee),
getTotalSpent: (a, t) => Promise.resolve(t.amount.plus(t.fee)),
getMaxAmount: (a, t) => Promise.resolve(a.balance - t.fee),
getMaxAmount: (a, t) => Promise.resolve(a.balance.minus(t.fee)),
signAndBroadcast: (a, t, deviceId) =>
Observable.create(o => {

7
src/bridge/UnsupportedBridge.js

@ -1,5 +1,6 @@
// @flow
import { Observable } from 'rxjs'
import { BigNumber } from 'bignumber.js'
import type { WalletBridge } from './types'
const genericError = new Error('UnsupportedBridge')
@ -23,7 +24,7 @@ const UnsupportedBridge: WalletBridge<*> = {
editTransactionAmount: () => null,
getTransactionAmount: () => 0,
getTransactionAmount: () => BigNumber(0),
isValidTransaction: () => false,
@ -33,9 +34,9 @@ const UnsupportedBridge: WalletBridge<*> = {
checkCanBeSpent: () => Promise.resolve(),
getTotalSpent: () => Promise.resolve(0),
getTotalSpent: () => Promise.resolve(BigNumber(0)),
getMaxAmount: () => Promise.resolve(0),
getMaxAmount: () => Promise.resolve(BigNumber(0)),
signAndBroadcast: () =>
Observable.create(o => {

2
src/bridge/makeMockBridge.js

@ -58,7 +58,7 @@ function makeMockBridge(opts?: Opts): WalletBridge<*> {
account = { ...account }
account.blockHeight++
for (const op of ops) {
account.balance += getOperationAmountNumber(op)
account.balance = account.balance.plus(getOperationAmountNumber(op))
}
return account
})

9
src/bridge/types.js

@ -1,6 +1,7 @@
// @flow
import type { Observable } from 'rxjs'
import type { BigNumber } from 'bignumber.js'
import type { Account, Operation, Currency } from '@ledgerhq/live-common/lib/types'
// a WalletBridge is implemented on renderer side.
@ -62,9 +63,9 @@ export interface WalletBridge<Transaction> {
createTransaction(account: Account): Transaction;
editTransactionAmount(account: Account, transaction: Transaction, amount: number): Transaction;
editTransactionAmount(account: Account, transaction: Transaction, amount: BigNumber): Transaction;
getTransactionAmount(account: Account, transaction: Transaction): number;
getTransactionAmount(account: Account, transaction: Transaction): BigNumber;
editTransactionRecipient(
account: Account,
@ -84,10 +85,10 @@ export interface WalletBridge<Transaction> {
checkCanBeSpent(account: Account, transaction: Transaction): Promise<void>;
getTotalSpent(account: Account, transaction: Transaction): Promise<number>;
getTotalSpent(account: Account, transaction: Transaction): Promise<BigNumber>;
// NB this is not used yet but we'll use it when we have MAX
getMaxAmount(account: Account, transaction: Transaction): Promise<number>;
getMaxAmount(account: Account, transaction: Transaction): Promise<BigNumber>;
/**
* finalize the transaction by

21
src/commands/libcoreGetFees.js

@ -1,18 +1,19 @@
// @flow
import { Observable } from 'rxjs'
import { BigNumber } from 'bignumber.js'
import withLibcore from 'helpers/withLibcore'
import { createCommand, Command } from 'helpers/ipc'
import * as accountIdHelper from 'helpers/accountId'
import { isValidAddress } from 'helpers/libcore'
import { isValidAddress, libcoreAmountToBigNumber, bigNumberToLibcoreAmount } from 'helpers/libcore'
import { createCustomErrorClass } from 'helpers/errors'
const InvalidAddress = createCustomErrorClass('InvalidAddress')
type BitcoinLikeTransaction = {
// TODO we rename this Transaction concept into transactionInput
amount: number,
feePerByte: number,
amount: string,
feePerByte: string,
recipient: string,
}
@ -22,7 +23,7 @@ type Input = {
transaction: BitcoinLikeTransaction,
}
type Result = { totalFees: number }
type Result = { totalFees: string }
const cmd: Command<Input, Result> = createCommand(
'libcoreGetFees',
@ -39,13 +40,15 @@ const cmd: Command<Input, Result> = createCommand(
if (isCancelled()) return
const bitcoinLikeAccount = njsAccount.asBitcoinLikeAccount()
const njsWalletCurrency = njsWallet.getCurrency()
const amount = new core.NJSAmount(njsWalletCurrency, transaction.amount).fromLong(
const amount = bigNumberToLibcoreAmount(
core,
njsWalletCurrency,
transaction.amount,
BigNumber(transaction.amount),
)
const feesPerByte = new core.NJSAmount(njsWalletCurrency, transaction.feePerByte).fromLong(
const feesPerByte = bigNumberToLibcoreAmount(
core,
njsWalletCurrency,
transaction.feePerByte,
BigNumber(transaction.feePerByte),
)
const transactionBuilder = bitcoinLikeAccount.buildTransaction()
if (!isValidAddress(core, njsWalletCurrency, transaction.recipient)) {
@ -56,7 +59,7 @@ const cmd: Command<Input, Result> = createCommand(
transactionBuilder.pickInputs(0, 0xffffff)
transactionBuilder.setFeesPerByte(feesPerByte)
const builded = await transactionBuilder.build()
const totalFees = builded.getFees().toLong()
const totalFees = libcoreAmountToBigNumber(builded.getFees()).toString()
o.next({ totalFees })
}).then(() => o.complete(), e => o.error(e))

24
src/commands/libcoreSignAndBroadcast.js

@ -1,11 +1,13 @@
// @flow
import logger from 'logger'
import { BigNumber } from 'bignumber.js'
import type { AccountRaw, OperationRaw } from '@ledgerhq/live-common/lib/types'
import Btc from '@ledgerhq/hw-app-btc'
import { Observable } from 'rxjs'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import { isSegwitAccount } from 'helpers/bip32'
import { libcoreAmountToBigNumber, bigNumberToLibcoreAmount } from 'helpers/libcore'
import withLibcore from 'helpers/withLibcore'
import { createCommand, Command } from 'helpers/ipc'
@ -13,8 +15,8 @@ import { withDevice } from 'helpers/deviceAccess'
import * as accountIdHelper from 'helpers/accountId'
type BitcoinLikeTransaction = {
amount: number,
feePerByte: number,
amount: string,
feePerByte: string,
recipient: string,
}
@ -169,14 +171,8 @@ export async function doSignAndBroadcast({
if (isCancelled()) return
const bitcoinLikeAccount = njsAccount.asBitcoinLikeAccount()
const njsWalletCurrency = njsWallet.getCurrency()
const amount = new core.NJSAmount(njsWalletCurrency, transaction.amount).fromLong(
njsWalletCurrency,
transaction.amount,
)
const fees = new core.NJSAmount(njsWalletCurrency, transaction.feePerByte).fromLong(
njsWalletCurrency,
transaction.feePerByte,
)
const amount = bigNumberToLibcoreAmount(core, njsWalletCurrency, BigNumber(transaction.amount))
const fees = bigNumberToLibcoreAmount(core, njsWalletCurrency, BigNumber(transaction.feePerByte))
const transactionBuilder = bitcoinLikeAccount.buildTransaction()
// TODO: check if is valid address. if not, it will fail silently on invalid
@ -218,15 +214,17 @@ export async function doSignAndBroadcast({
.asBitcoinLikeAccount()
.broadcastRawTransaction(Array.from(Buffer.from(signedTransaction, 'hex')))
const fee = builded.getFees().toLong()
const fee = libcoreAmountToBigNumber(builded.getFees())
// NB we don't check isCancelled() because the broadcast is not cancellable now!
onOperationBroadcasted({
id: `${account.xpub}-${txHash}-OUT`,
hash: txHash,
type: 'OUT',
value: transaction.amount + fee,
fee,
value: BigNumber(transaction.amount)
.plus(fee)
.toString(),
fee: fee.toString(),
blockHash: null,
blockHeight: null,
senders: [account.freshAddress],

7
src/components/AccountPage/AccountBalanceSummaryHeader.js

@ -1,6 +1,7 @@
// @flow
import React, { PureComponent } from 'react'
import type { BigNumber } from 'bignumber.js'
import { createStructuredSelector } from 'reselect'
import { compose } from 'redux'
import { connect } from 'react-redux'
@ -25,9 +26,9 @@ import PillsDaysCount from 'components/PillsDaysCount'
type OwnProps = {
isAvailable: boolean,
totalBalance: number,
sinceBalance: number,
refBalance: number,
totalBalance: BigNumber,
sinceBalance: BigNumber,
refBalance: BigNumber,
accountId: string,
}

2
src/components/AccountPage/AccountHeaderActions.js

@ -62,7 +62,7 @@ class AccountHeaderActions extends PureComponent<Props> {
const { account, openModal, t } = this.props
return (
<Box horizontal alignItems="center" justifyContent="flex-end" flow={2}>
{account.operations.length > 0 || account.balance > 0 ? (
{account.operations.length > 0 || !account.balance.isZero() ? (
<Fragment>
<Button small primary onClick={() => openModal(MODAL_SEND, { account })}>
<Box horizontal flow={1} alignItems="center">

2
src/components/AccountPage/index.js

@ -82,7 +82,7 @@ class AccountPage extends PureComponent<Props> {
<AccountHeaderActions account={account} />
</Box>
{account.operations.length > 0 || account.balance > 0 ? (
{account.operations.length > 0 || !account.balance.isZero() ? (
<Fragment>
<Box mb={7}>
<BalanceSummary

11
src/components/AdvancedOptions/EthereumKind.js

@ -1,5 +1,6 @@
// @flow
import React from 'react'
import { BigNumber } from 'bignumber.js'
import { translate } from 'react-i18next'
import Box from 'components/base/Box'
@ -8,8 +9,8 @@ import Label from 'components/base/Label'
import Spoiler from 'components/base/Spoiler'
type Props = {
gasLimit: number,
onChangeGasLimit: (?number) => void,
gasLimit: BigNumber,
onChangeGasLimit: BigNumber => void,
t: *,
}
@ -25,9 +26,9 @@ export default translate()(({ gasLimit, onChangeGasLimit, t }: Props) => (
<Input
value={gasLimit}
onChange={str => {
const gasLimit = parseInt(str || 0, 10)
if (!isNaN(gasLimit) && isFinite(gasLimit)) onChangeGasLimit(gasLimit)
else onChangeGasLimit(0x5208)
const gasLimit = BigNumber(str || 0)
if (!gasLimit.isNaN() && gasLimit.isFinite()) onChangeGasLimit(gasLimit)
else onChangeGasLimit(BigNumber(0x5208))
}}
/>
</Box>

11
src/components/BalanceSummary/BalanceInfos.js

@ -1,6 +1,7 @@
// @flow
import React from 'react'
import type { BigNumber } from 'bignumber.js'
import styled from 'styled-components'
import type { Unit, Currency } from '@ledgerhq/live-common/lib/types'
@ -20,9 +21,9 @@ const Sub = styled(Box).attrs({
type BalanceSinceProps = {
since: string,
totalBalance: number,
sinceBalance: number,
refBalance: number,
totalBalance: BigNumber,
sinceBalance: BigNumber,
refBalance: BigNumber,
isAvailable: boolean,
t: T,
}
@ -31,7 +32,7 @@ type BalanceTotalProps = {
children?: any,
unit: Unit,
isAvailable: boolean,
totalBalance: number,
totalBalance: BigNumber,
showCryptoEvenIfNotAvailable?: boolean,
}
@ -77,7 +78,7 @@ export function BalanceSinceDiff(props: Props) {
unit={counterValue.units[0]}
fontSize={7}
showCode
val={totalBalance - sinceBalance}
val={totalBalance.minus(sinceBalance)}
withIcon
/>
)}

18
src/components/BalanceSummary/index.js

@ -1,6 +1,7 @@
// @flow
import React, { Fragment } from 'react'
import { BigNumber } from 'bignumber.js'
import moment from 'moment'
import { formatShort } from '@ledgerhq/live-common/lib/helpers/currencies'
import type { Currency, Account } from '@ledgerhq/live-common/lib/types'
@ -19,9 +20,9 @@ type Props = {
daysCount: number,
renderHeader?: ({
selectedTimeRange: *,
totalBalance: number,
sinceBalance: number,
refBalance: number,
totalBalance: BigNumber,
sinceBalance: BigNumber,
refBalance: BigNumber,
isAvailable: boolean,
}) => *,
}
@ -64,11 +65,12 @@ const BalanceSummary = ({
? balanceHistory
: balanceHistory.map(i => ({
...i,
value:
value: BigNumber(
10000 *
(1 +
0.1 * Math.sin(i.date * Math.cos(i.date)) + // random-ish
0.5 * Math.cos(i.date / 2000000000 + Math.sin(i.date / 1000000000))), // general curve trend
(1 +
0.1 * Math.sin(i.date * Math.cos(i.date)) + // random-ish
0.5 * Math.cos(i.date / 2000000000 + Math.sin(i.date / 1000000000))),
), // general curve trend
}))
}
height={200}
@ -76,7 +78,7 @@ const BalanceSummary = ({
cvCode={counterValue.ticker}
tickXScale={selectedTimeRange}
renderTickY={
isAvailable ? val => formatShort(counterValue.units[0], val) : () => ''
isAvailable ? val => formatShort(counterValue.units[0], BigNumber(val)) : () => ''
}
isInteractive={isAvailable}
renderTooltip={

17
src/components/CalculateBalance.js

@ -3,6 +3,7 @@
import { Component } from 'react'
import { connect } from 'react-redux'
import { BigNumber } from 'bignumber.js'
import type { Account } from '@ledgerhq/live-common/lib/types'
import { getBalanceHistorySum } from '@ledgerhq/live-common/lib/helpers/account'
@ -23,14 +24,14 @@ type OwnProps = {
type Item = {
date: Date,
value: number,
originalValue: number,
value: BigNumber,
originalValue: BigNumber,
}
type Props = OwnProps & {
balanceHistory: Item[],
balanceStart: number,
balanceEnd: number,
balanceStart: BigNumber,
balanceEnd: BigNumber,
isAvailable: boolean,
hash: string,
}
@ -61,15 +62,15 @@ const mapStateToProps = (state: State, props: OwnProps) => {
toExchange: counterValueExchange,
to: counterValueCurrency,
})
if (!cv && cv !== 0) {
if (!cv) {
isAvailable = false
return 0
return BigNumber(0)
}
return cv
},
).map((item, i) =>
// reconciliate balance history with original values
({ ...item, originalValue: originalValues[i] || 0 }),
({ ...item, originalValue: originalValues[i] || BigNumber(0) }),
)
const balanceEnd = balanceHistory[balanceHistory.length - 1].value
@ -81,7 +82,7 @@ const mapStateToProps = (state: State, props: OwnProps) => {
balanceEnd,
hash: `${props.accounts.length > 0 ? props.accounts[0].id : ''}_${
balanceHistory.length
}_${balanceEnd}_${isAvailable.toString()}`,
}_${balanceEnd.toString()}_${isAvailable.toString()}`,
}
}

5
src/components/CounterValue/index.js

@ -1,5 +1,6 @@
// @flow
import type { BigNumber } from 'bignumber.js'
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import type { Currency } from '@ledgerhq/live-common/lib/types'
@ -23,7 +24,7 @@ type OwnProps = {
// when? if not given: take latest
date?: Date,
value: number,
value: BigNumber,
alwaysShowSign?: boolean,
}
@ -61,7 +62,7 @@ class CounterValue extends PureComponent<Props> {
}
render() {
const { value, counterValueCurrency, date, alwaysShowSign, ...props } = this.props
if (!value && value !== 0) {
if (!value) {
return null
}
return (

2
src/components/DashboardPage/AccountCard.js

@ -78,7 +78,7 @@ class AccountCard extends PureComponent<{
) : null}
</Box>
<Box grow justifyContent="center">
{balanceStart && isAvailable ? (
{isAvailable && !balanceStart.isZero() ? (
<DeltaChange from={balanceStart} to={balanceEnd} alwaysShowSign fontSize={3} />
) : null}
</Box>

13
src/components/DeltaChange.js

@ -1,14 +1,21 @@
// @flow
import React, { PureComponent } from 'react'
import { BigNumber } from 'bignumber.js'
import FormattedVal from 'components/base/FormattedVal'
class DeltaChange extends PureComponent<{
from: number,
to: number,
from: BigNumber,
to: BigNumber,
}> {
render() {
const { from, to, ...rest } = this.props
const val = from ? Math.floor(((to - from) / from) * 100) : 0
const val = !from.isZero()
? to
.minus(from)
.div(from)
.times(100)
.integerValue()
: BigNumber(0)
// TODO in future, we also want to diverge rendering when the % is way too high (this can easily happen)
return <FormattedVal isPercent val={val} {...rest} />
}

21
src/components/FeesField/BitcoinKind.js

@ -1,6 +1,7 @@
// @flow
import React, { Component } from 'react'
import { BigNumber } from 'bignumber.js'
import type { Account } from '@ledgerhq/live-common/lib/types'
import styled from 'styled-components'
import { translate } from 'react-i18next'
@ -16,16 +17,16 @@ import Box from '../base/Box'
type Props = {
account: Account,
feePerByte: number,
onChange: number => void,
feePerByte: BigNumber,
onChange: BigNumber => void,
t: T,
}
type FeeItem = {
label: string,
value: string,
value: *,
blockCount: number,
feePerByte: number,
feePerByte: BigNumber,
}
const InputRight = styled(Box).attrs({
@ -47,7 +48,7 @@ const customItem = {
label: 'Custom',
value: 'custom',
blockCount: 0,
feePerByte: 0,
feePerByte: BigNumber(0),
}
type State = { isFocused: boolean, items: FeeItem[], selectedItem: FeeItem }
@ -64,9 +65,9 @@ class FeesField extends Component<Props & { fees?: Fees, error?: Error }, State>
let items: FeeItem[] = []
if (fees) {
for (const key of Object.keys(fees)) {
const feePerByte = Math.ceil(fees[key] / 1000)
const feePerByte = BigNumber(Math.ceil(fees[key] / 1000))
const blockCount = parseInt(key, 10)
if (!isNaN(blockCount) && !isNaN(feePerByte)) {
if (!isNaN(blockCount) && !feePerByte.isNaN()) {
items.push({
blockCount,
label: blockCountNameConvention[blockCount] || `${blockCount} blocks`,
@ -88,7 +89,7 @@ class FeesField extends Component<Props & { fees?: Fees, error?: Error }, State>
componentDidUpdate() {
const { feePerByte, fees, onChange } = this.props
const { items, isFocused } = this.state
if (fees && !feePerByte && !isFocused) {
if (fees && feePerByte.isZero() && !isFocused) {
// initialize with the median
const feePerByte = (items.find(item => item.blockCount === defaultBlockCount) || items[0])
.feePerByte
@ -103,11 +104,11 @@ class FeesField extends Component<Props & { fees?: Fees, error?: Error }, State>
onSelectChange = selectedItem => {
const { onChange } = this.props
const patch: $Shape<State> = { selectedItem }
if (selectedItem.feePerByte) {
if (!selectedItem.feePerByte.isZero()) {
onChange(selectedItem.feePerByte)
} else {
const { input } = this
if (!selectedItem.feePerByte && input.current) {
if (selectedItem.feePerByte.isZero() && input.current) {
patch.isFocused = true
input.current.select()
}

9
src/components/FeesField/EthereumKind.js

@ -1,6 +1,7 @@
// @flow
import React, { Component } from 'react'
import { BigNumber } from 'bignumber.js'
import type { Account } from '@ledgerhq/live-common/lib/types'
import InputCurrency from 'components/base/InputCurrency'
@ -10,8 +11,8 @@ import GenericContainer from './GenericContainer'
type Props = {
account: Account,
gasPrice: number,
onChange: number => void,
gasPrice: BigNumber,
onChange: BigNumber => void,
}
class FeesField extends Component<Props & { fees?: Fees, error?: Error }, *> {
@ -21,8 +22,8 @@ class FeesField extends Component<Props & { fees?: Fees, error?: Error }, *> {
componentDidUpdate() {
const { gasPrice, fees, onChange } = this.props
const { isFocused } = this.state
if (!gasPrice && fees && fees.gas_price && !isFocused) {
onChange(fees.gas_price) // we want to set the default to gas_price
if (gasPrice.isZero() && fees && fees.gas_price && !isFocused) {
onChange(BigNumber(fees.gas_price)) // we want to set the default to gas_price
}
}
onChangeFocus = isFocused => {

7
src/components/FeesField/RippleKind.js

@ -1,6 +1,7 @@
// @flow
import React, { Component } from 'react'
import type { BigNumber } from 'bignumber.js'
import type { Account } from '@ledgerhq/live-common/lib/types'
import { apiForEndpointConfig, parseAPIValue } from 'api/Ripple'
import InputCurrency from 'components/base/InputCurrency'
@ -8,8 +9,8 @@ import GenericContainer from './GenericContainer'
type Props = {
account: Account,
fee: number,
onChange: number => void,
fee: BigNumber,
onChange: BigNumber => void,
}
type State = {
@ -35,7 +36,7 @@ class FeesField extends Component<Props, State> {
const info = await api.getServerInfo()
if (syncId !== this.syncId) return
const serverFee = parseAPIValue(info.validatedLedger.baseFeeXRP)
if (!this.props.fee) {
if (this.props.fee.isZero()) {
this.props.onChange(serverFee)
}
} catch (error) {

2
src/components/OperationsList/AmountCell.js

@ -34,7 +34,7 @@ class AmountCell extends PureComponent<Props> {
showCode
fontSize={4}
alwaysShowSign
color={amount < 0 ? 'smoke' : undefined}
color={amount.isNegative() ? 'smoke' : undefined}
/>
<CounterValue
color="grey"

3
src/components/RecipientAddress/index.js

@ -1,5 +1,6 @@
// @flow
import type { BigNumber } from 'bignumber.js'
import React, { PureComponent, Fragment } from 'react'
import styled from 'styled-components'
import noop from 'lodash/noop'
@ -46,7 +47,7 @@ const BackgroundLayer = styled(Box)`
type Props = {
value: string,
// return false if it can't be changed (invalid info)
onChange: (string, ?{ amount?: number, currency?: CryptoCurrency }) => ?boolean,
onChange: (string, ?{ amount?: BigNumber, currency?: CryptoCurrency }) => ?boolean,
withQrCode: boolean,
}

2
src/components/base/Chart/handleMouseEvents.js

@ -85,7 +85,7 @@ export default function handleMouseEvents({
return
}
onTooltipUpdate(d)
NODES.focus.attr('transform', `translate(${x(d.parsedDate)},${y(d.value)})`)
NODES.focus.attr('transform', `translate(${x(d.parsedDate)},${y(d.value.toNumber())})`)
NODES.tooltip
.html(
renderToString(

2
src/components/base/Chart/index.js

@ -142,7 +142,7 @@ class Chart extends PureComponent<Props> {
const x = d3.scaleTime().range([0, ctx.WIDTH])
const y = d3.scaleLinear().range([ctx.HEIGHT, 0])
x.domain(d3.extent(ctx.DATA, d => d.parsedDate))
y.domain([0, d3.max(ctx.DATA, d => d.value)])
y.domain([0, d3.max(ctx.DATA, d => d.value.toNumber())])
ctx.x = x
ctx.y = y

4
src/components/base/Chart/refreshDraw.js

@ -39,12 +39,12 @@ export default function refreshDraw({ ctx, props }: { ctx: CTX, props: Props })
.area()
.x(d => x(d.parsedDate))
.y0(HEIGHT)
.y1(d => y(d.value))
.y1(d => y(d.value.toNumber()))
const valueline = d3
.line()
.x(d => x(d.parsedDate))
.y(d => y(d.value))
.y(d => y(d.value.toNumber()))
// Resize container
NODES.svg

3
src/components/base/Chart/stories.js

@ -1,6 +1,7 @@
// @flow
import React, { Component, Fragment } from 'react'
import { BigNumber } from 'bignumber.js'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
import Chance from 'chance'
import moment from 'moment'
@ -77,7 +78,7 @@ function generateRandomData(n) {
const data = []
const chance = new Chance()
while (!day.isSame(today)) {
const value = chance.integer({ min: 0.5e8, max: 1e8 })
const value = BigNumber(chance.integer({ min: 0.5e8, max: 1e8 }))
data.push({
date: day.toDate(),
value,

8
src/components/base/Chart/types.js

@ -1,14 +1,16 @@
// @flow
import type { BigNumber } from 'bignumber.js'
export type Item = {
date: Date,
value: number,
originalValue: number,
value: BigNumber,
originalValue: BigNumber,
}
type EnrichedItem = {
date: string,
value: number,
value: BigNumber,
parsedDate: Date,
ref: Item,
}

3
src/components/base/FlipTicker/stories.js

@ -1,6 +1,7 @@
// @flow
import React, { Component } from 'react'
import { BigNumber } from 'bignumber.js'
import { storiesOf } from '@storybook/react'
import {
@ -19,7 +20,7 @@ const unit = getFiatCurrencyByTicker('USD').units[0]
const chance = new Chance()
function getValue() {
return formatCurrencyUnit(unit, chance.floating({ min: 1000, max: 100000 }), {
return formatCurrencyUnit(unit, BigNumber(chance.floating({ min: 1000, max: 100000 })), {
showCode: true,
})
}

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

@ -1,12 +1,11 @@
// @flow
import type { BigNumber } from 'bignumber.js'
import invariant from 'invariant'
import React from 'react'
import styled from 'styled-components'
import { connect } from 'react-redux'
import isUndefined from 'lodash/isUndefined'
import type { Unit } from '@ledgerhq/live-common/lib/types'
import type { State } from 'reducers'
@ -41,7 +40,7 @@ I.defaultProps = {
type OwnProps = {
unit?: Unit,
val: number,
val: BigNumber,
alwaysShowSign?: boolean,
showCode?: boolean,
withIcon?: boolean,
@ -77,20 +76,23 @@ function FormattedVal(props: Props) {
} = props
let { val } = props
invariant(!isUndefined(val), 'FormattedVal require a `val` prop. Received `undefined`')
invariant(val, 'FormattedVal require a `val` prop. Received `undefined`')
const isNegative = val < 0
const isNegative = val.isNegative() && !val.isZero()
let text = ''
if (isPercent) {
// FIXME move out the % feature of this component... totally unrelated to currency & annoying for flow type.
text = `${alwaysShowSign ? (isNegative ? '- ' : '+ ') : ''}${isNegative ? val * -1 : val} %`
text = `${alwaysShowSign ? (isNegative ? '- ' : '+ ') : ''}${(isNegative
? val.negated()
: val
).toString()} %`
} else {
invariant(unit, 'FormattedVal require a `unit` prop. Received `undefined`')
if (withIcon && isNegative) {
val *= -1
val = val.negated()
}
text = formatCurrencyUnit(unit, val, {

34
src/components/base/InputCurrency/index.js

@ -1,6 +1,7 @@
// @flow
import React, { PureComponent } from 'react'
import { BigNumber } from 'bignumber.js'
import uncontrollable from 'uncontrollable'
import styled from 'styled-components'
import { formatCurrencyUnit } from '@ledgerhq/live-common/lib/helpers/currencies'
@ -52,13 +53,13 @@ const sanitizeValueString = (
return { display, value }
}
function format(unit: Unit, value: number, { isFocused, showAllDigits, subMagnitude }) {
function format(unit: Unit, value: BigNumber, { isFocused, showAllDigits, subMagnitude }) {
// FIXME do we need locale for the input too ?
return formatCurrencyUnit(unit, value, {
useGrouping: !isFocused,
disableRounding: true,
showAllDigits: !!showAllDigits && !isFocused,
subMagnitude: value < 1 ? subMagnitude : 0,
subMagnitude: value.isLessThan(1) ? subMagnitude : 0,
})
}
@ -75,12 +76,12 @@ function stopPropagation(e) {
type Props = {
onChangeFocus: boolean => void,
onChange: (number, Unit) => void, // FIXME Unit shouldn't be provided (this is not "standard" onChange)
onChange: (BigNumber, Unit) => void, // FIXME Unit shouldn't be provided (this is not "standard" onChange)
onChangeUnit: Unit => void,
renderRight: any,
unit: Unit,
units: Unit[],
value: number,
value: BigNumber,
showAllDigits?: boolean,
subMagnitude: number,
}
@ -96,7 +97,7 @@ class InputCurrency extends PureComponent<Props, State> {
onChange: noop,
renderRight: null,
units: [],
value: 0,
value: BigNumber(0),
showAllDigits: false,
subMagnitude: 0,
}
@ -120,14 +121,13 @@ class InputCurrency extends PureComponent<Props, State> {
if (needsToBeReformatted) {
const { isFocused } = this.state
this.setState({
displayValue:
nextProps.value === 0
? ''
: format(nextProps.unit, nextProps.value, {
isFocused,
showAllDigits: nextProps.showAllDigits,
subMagnitude: nextProps.subMagnitude,
}),
displayValue: nextProps.value.isZero()
? ''
: format(nextProps.unit, nextProps.value, {
isFocused,
showAllDigits: nextProps.showAllDigits,
subMagnitude: nextProps.subMagnitude,
}),
})
}
}
@ -135,8 +135,8 @@ class InputCurrency extends PureComponent<Props, State> {
handleChange = (v: string) => {
const { onChange, unit, value } = this.props
const r = sanitizeValueString(unit, v)
const satoshiValue = parseInt(r.value, 10)
if (value !== satoshiValue) {
const satoshiValue = BigNumber(r.value)
if (!value.isEqualTo(satoshiValue)) {
onChange(satoshiValue, unit)
}
this.setState({ displayValue: r.display })
@ -157,7 +157,7 @@ class InputCurrency extends PureComponent<Props, State> {
this.setState({
isFocused,
displayValue:
value === '' || value === 0
!value || value.isZero()
? ''
: format(unit, value, { isFocused, showAllDigits, subMagnitude }),
})
@ -214,7 +214,7 @@ class InputCurrency extends PureComponent<Props, State> {
onFocus={this.handleFocus}
onBlur={this.handleBlur}
renderRight={renderRight || this.renderListUnits()}
placeholder={format(unit, 0, { isFocused: false, showAllDigits, subMagnitude })}
placeholder={format(unit, BigNumber(0), { isFocused: false, showAllDigits, subMagnitude })}
/>
)
}

2
src/components/modals/OperationDetails.js

@ -150,7 +150,7 @@ const OperationDetails = connect(mapStateToProps)((props: Props) => {
<Box my={4} alignItems="center">
<Box>
<FormattedVal
color={amount < 0 ? 'smoke' : undefined}
color={amount.isNegative() ? 'smoke' : undefined}
unit={unit}
alwaysShowSign
showCode

7
src/components/modals/Send/steps/01-step-amount.js

@ -1,6 +1,7 @@
// @flow
import React, { PureComponent, Fragment } from 'react'
import { BigNumber } from 'bignumber.js'
import logger from 'logger'
import Box from 'components/base/Box'
@ -83,14 +84,14 @@ export default ({
export class StepAmountFooter extends PureComponent<
StepProps<*>,
{
totalSpent: number,
totalSpent: BigNumber,
canNext: boolean,
isSyncing: boolean,
},
> {
state = {
isSyncing: false,
totalSpent: 0,
totalSpent: BigNumber(0),
canNext: false,
}
@ -141,7 +142,7 @@ export class StepAmountFooter extends PureComponent<
this.setState({ totalSpent, canNext, isSyncing: false })
} catch (err) {
logger.critical(err)
this.setState({ totalSpent: 0, canNext: false, isSyncing: false })
this.setState({ totalSpent: BigNumber(0), canNext: false, isSyncing: false })
}
}

11
src/helpers/libcore.js

@ -1,6 +1,9 @@
// @flow
// TODO split these into many files
import logger from 'logger'
import { BigNumber } from 'bignumber.js'
import Btc from '@ledgerhq/hw-app-btc'
import { withDevice } from 'helpers/deviceAccess'
import { getCryptoCurrencyById } from '@ledgerhq/live-common/lib/helpers/currencies'
@ -531,3 +534,11 @@ export async function syncAccount({ rawAccount, core }: { core: *, rawAccount: A
return syncedRawAccount
}
export function libcoreAmountToBigNumber(njsAmount: *): BigNumber {
return BigNumber(njsAmount.toBigInt().toString(10))
}
export function bigNumberToLibcoreAmount(core: *, njsWalletCurrency: *, bigNumber: BigNumber) {
return new core.NJSAmount(njsWalletCurrency, 0).fromHex(njsWalletCurrency, bigNumber.toString(16))
}

13
src/helpers/signTransactionForCurrency/ethereum.js

@ -27,9 +27,10 @@ export default async (
t: {
nonce: string,
recipient: string,
gasPrice: number,
gasLimit: number,
amount: number,
// these are in hexa string format (e.g. '0xABCDEF')
gasPrice: string,
gasLimit: string,
amount: string,
},
) => {
// First, we need to create a partial tx and send to the device
@ -38,10 +39,10 @@ export default async (
invariant(chainId, `chainId not found for currency=${currencyId}`)
const tx = new EthereumTx({
nonce: t.nonce,
gasPrice: `0x${t.gasPrice.toString(16)}`,
gasLimit: `0x${t.gasLimit.toString(16)}`,
gasPrice: t.gasPrice,
gasLimit: t.gasLimit,
to: t.recipient,
value: `0x${t.amount.toString(16)}`,
value: t.amount,
chainId,
})
tx.raw[6] = Buffer.from([chainId]) // v

11
yarn.lock

@ -1534,11 +1534,12 @@
npm "^5.7.1"
prebuild-install "^2.2.2"
"@ledgerhq/live-common@^2.35.0":
version "2.35.0"
resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-2.35.0.tgz#526bfb94f1a2f1449674c7854cf2c7a162385018"
"@ledgerhq/live-common@3.0.0-beta.2":
version "3.0.0-beta.2"
resolved "https://registry.yarnpkg.com/@ledgerhq/live-common/-/live-common-3.0.0-beta.2.tgz#9280694bcfb6f8819bc90538dbdfcfa260e3454e"
dependencies:
axios "^0.18.0"
bignumber.js "^7.2.1"
invariant "^2.2.2"
lodash "^4.17.4"
numeral "^2.0.6"
@ -3579,6 +3580,10 @@ bignumber.js@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-4.1.0.tgz#db6f14067c140bd46624815a7916c92d9b6c24b1"
bignumber.js@^7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-7.2.1.tgz#80c048759d826800807c4bfd521e50edbba57a5f"
bin-links@^1.1.0, bin-links@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/bin-links/-/bin-links-1.1.2.tgz#fb74bd54bae6b7befc6c6221f25322ac830d9757"

Loading…
Cancel
Save