From c53aba42d3678fdff4aa25d2853a28fb5c5153a9 Mon Sep 17 00:00:00 2001 From: Fang Date: Thu, 30 Jan 2020 17:50:30 +0100 Subject: [PATCH] lib: implement and use safe fromWei and toWei functions These always convert the number argument toBN, and include extra details in the error message of failing cases. --- src/components/NeedFundsNotice.js | 6 +++--- src/lib/error.js | 6 +++--- src/lib/lib.js | 27 +++++++++++++++++++++++++++ src/lib/reticket.js | 5 +++-- src/lib/txn.js | 7 ++++--- src/lib/useEthereumTransaction.js | 5 +++-- src/lib/useInviter.js | 5 +++-- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/components/NeedFundsNotice.js b/src/components/NeedFundsNotice.js index 7c70bc611..c98385887 100644 --- a/src/components/NeedFundsNotice.js +++ b/src/components/NeedFundsNotice.js @@ -1,5 +1,5 @@ import React from 'react'; -import { fromWei, toBN } from 'web3-utils'; +import { safeFromWei } from '../lib/lib'; import Highlighted from './Highlighted'; import CopiableAddress from './CopiableAddress'; @@ -16,8 +16,8 @@ export default function NeedFundsNotice({ Your ownership address {address}{' '} - needs at least {fromWei(toBN(minBalance))} ETH and currently has{' '} - {fromWei(toBN(balance))} ETH. The transaction will automatically resume + needs at least {safeFromWei(minBalance)} ETH and currently has{' '} + {safeFromWei(balance)} ETH. The transaction will automatically resume once enough ETH is available. Waiting... diff --git a/src/lib/error.js b/src/lib/error.js index 743a79151..88690916b 100644 --- a/src/lib/error.js +++ b/src/lib/error.js @@ -1,4 +1,4 @@ -import { fromWei, toBN } from 'web3-utils'; +import { safeFromWei } from './lib'; const BRIDGE_ERROR = { MISSING_WEB3: 'no web3 object found', @@ -18,13 +18,13 @@ const BRIDGE_ERROR = { const renderTxnError = (web3, msg) => { const txnCost = (web3, msg) => { const costWei = msg.match(/upfront cost is: ([0-9]+)/); - const costEth = fromWei(toBN(costWei[1]), 'ether'); + const costEth = safeFromWei(costWei[1], 'ether'); return parseFloat(costEth).toFixed(4); }; const acctBalance = (web3, msg) => { const balWei = msg.match(/sender's account only has: ([0-9]+)/); - const balEth = fromWei(toBN(balWei[1]), 'ether'); + const balEth = safeFromWei(balWei[1], 'ether'); return parseFloat(balEth).toFixed(4); }; diff --git a/src/lib/lib.js b/src/lib/lib.js index 7c8162207..73954bb28 100644 --- a/src/lib/lib.js +++ b/src/lib/lib.js @@ -1,5 +1,30 @@ import ob from 'urbit-ob'; import patp2dec from './patp2dec'; +import { fromWei, toWei, toBN } from 'web3-utils'; + +const safeFromWei = (num, target) => { + try { + return fromWei(toBN(num), target); + } catch (e) { + e.message = + `(safeFromWei got ${typeof num} (${num}), made ${typeof toBN( + num + )}. Please report this issue!) ` + e.message; + throw e; + } +}; + +const safeToWei = (num, source) => { + try { + return toWei(toBN(num), source); + } catch (e) { + e.message = + `(safeToWei got ${typeof num} (${num}), made ${typeof toBN( + num + )}. Please report this issue!) ` + e.message; + throw e; + } +}; const compose = (...fs) => fs.reduceRight((pF, nF) => (...args) => nF(pF(...args)), v => v); @@ -43,6 +68,8 @@ const patpStringLength = byteLength => byteLength * 3 + Math.ceil(byteLength / 2); export { + safeFromWei, + safeToWei, compose, allFalse, isLast, diff --git a/src/lib/reticket.js b/src/lib/reticket.js index 6a8a4ad20..6e06d4364 100644 --- a/src/lib/reticket.js +++ b/src/lib/reticket.js @@ -12,7 +12,8 @@ import { addHexPrefix } from './wallet'; import { sendAndAwaitAll } from './txn'; import getSuggestedGasPrice from './getSuggestedGasPrice'; import { GAS_LIMITS } from './constants'; -import { toWei, toBN } from 'web3-utils'; +import { toBN } from 'web3-utils'; +import { safeToWei } from './lib'; // the initial network key revision is always 1 const INITIAL_NETWORK_KEY_REVISION = 1; @@ -143,7 +144,7 @@ export async function reticketPointBetweenWallets({ progress(TRANSACTION_PROGRESS.SIGNING); const suggestedGasPrice = await getSuggestedGasPrice(networkType); - const gasPrice = toWei(suggestedGasPrice.toFixed(), 'gwei'); + const gasPrice = safeToWei(suggestedGasPrice.toFixed(), 'gwei'); const gasPriceBN = toBN(gasPrice); let totalCost = toBN(0); let inviteNonce = await web3.eth.getTransactionCount(fromWallet.address); diff --git a/src/lib/txn.js b/src/lib/txn.js index 7d1caa628..1603d8ae3 100644 --- a/src/lib/txn.js +++ b/src/lib/txn.js @@ -1,5 +1,6 @@ import Tx from 'ethereumjs-tx'; -import { toWei, fromWei, toHex, toBN } from 'web3-utils'; +import { toHex } from 'web3-utils'; +import { safeFromWei, safeToWei } from './lib'; import retry from 'async-retry'; import { NETWORK_TYPES } from './network'; @@ -31,7 +32,7 @@ const signTransaction = async ({ // TODO: require these in txn object nonce = toHex(nonce); chainId = toHex(chainId); - gasPrice = toHex(toWei(gasPrice, 'gwei')); + gasPrice = toHex(safeToWei(gasPrice, 'gwei')); gasLimit = toHex(gasLimit); const txParams = { nonce, chainId, gasPrice, gasLimit }; @@ -193,7 +194,7 @@ const getTxnInfo = async (web3, addr) => { return { nonce: nonce, chainId: chainId, - gasPrice: fromWei(toBN(gasPrice), 'gwei'), + gasPrice: safeFromWei(gasPrice, 'gwei'), }; }; diff --git a/src/lib/useEthereumTransaction.js b/src/lib/useEthereumTransaction.js index 9bb227ea0..cb2010498 100644 --- a/src/lib/useEthereumTransaction.js +++ b/src/lib/useEthereumTransaction.js @@ -1,6 +1,6 @@ import { useCallback, useEffect, useState } from 'react'; import { Just } from 'folktale/maybe'; -import { toWei, toBN } from 'web3-utils'; +import { toBN } from 'web3-utils'; import { useNetwork } from 'store/network'; import { useWallet } from 'store/wallet'; @@ -22,6 +22,7 @@ import { ensureFundsFor } from 'lib/tank'; import useDeepEqualReference from 'lib/useDeepEqualReference'; import useGasPrice from 'lib/useGasPrice'; import timeout from 'lib/timeout'; +import { safeToWei } from 'lib/lib'; const STATE = { NONE: 'NONE', @@ -148,7 +149,7 @@ export default function useEthereumTransaction( const costGwei = toBN(gasLimit) .mul(toBN(gasPrice)) .mul(toBN(rawTxs.length)); - const cost = toWei(costGwei.toString(), 'gwei'); + const cost = safeToWei(costGwei, 'gwei'); let usedTank = false; // if this ethereum transaction is being executed by a specific point // see if we can use the tank diff --git a/src/lib/useInviter.js b/src/lib/useInviter.js index d300b8057..1026a7e98 100644 --- a/src/lib/useInviter.js +++ b/src/lib/useInviter.js @@ -1,5 +1,5 @@ import { useState, useCallback, useEffect } from 'react'; -import { toWei, toBN } from 'web3-utils'; +import { toBN } from 'web3-utils'; import * as azimuth from 'azimuth-js'; import { FORM_ERROR } from 'final-form'; @@ -16,6 +16,7 @@ import { } from 'lib/txn'; import useGasPrice from 'lib/useGasPrice'; import { MIN_PLANET } from 'lib/constants'; +import { safeToWei } from 'lib/lib'; import { useNetwork } from 'store/network'; import { useWallet } from 'store/wallet'; @@ -148,7 +149,7 @@ const useInviter = () => { _web3, point, _wallet.address, - toWei(totalCost.toString(), 'gwei'), + safeToWei(totalCost, 'gwei'), Object.keys(invites).map(name => invites[name].rawTx), (address, minBalance, balance) => setNeedFunds({ address, minBalance, balance }),