on master help sign in
Use BN consistently for gas calculations
fa53035Fang
src/lib/reticket.js+3−3
@@ -12,7 +12,7 @@ import { addHexPrefix } from './wallet';
12import { sendAndAwaitAll } from './txn';
12import { sendAndAwaitAll } from './txn';
13import getSuggestedGasPrice from './getSuggestedGasPrice';
13import getSuggestedGasPrice from './getSuggestedGasPrice';
14import { GAS_LIMITS } from './constants';
14import { GAS_LIMITS } from './constants';
15−import { toWei } from 'web3-utils';
15+import { toWei, toBN } from 'web3-utils';
16
16
17// the initial network key revision is always 1
17// the initial network key revision is always 1
18const INITIAL_NETWORK_KEY_REVISION = 1;
18const INITIAL_NETWORK_KEY_REVISION = 1;
@@ -144,13 +144,13 @@ export async function reticketPointBetweenWallets({
144
144
145 const suggestedGasPrice = await getSuggestedGasPrice(networkType);
145 const suggestedGasPrice = await getSuggestedGasPrice(networkType);
146 const gasPrice = parseInt(toWei(suggestedGasPrice.toFixed(), 'gwei'), 10);
146 const gasPrice = parseInt(toWei(suggestedGasPrice.toFixed(), 'gwei'), 10);
147− let totalCost = 0;
147+ let totalCost = toBN(0);
148 let inviteNonce = await web3.eth.getTransactionCount(fromWallet.address);
148 let inviteNonce = await web3.eth.getTransactionCount(fromWallet.address);
149 txs = txs.map(tx => {
149 txs = txs.map(tx => {
150 tx.from = fromWallet.address;
150 tx.from = fromWallet.address;
151 tx.nonce = inviteNonce++;
151 tx.nonce = inviteNonce++;
152 tx.gasPrice = gasPrice;
152 tx.gasPrice = gasPrice;
153− totalCost = totalCost + tx.gasPrice * tx.gas;
153+ totalCost = totalCost.add(toBN(gasPrice).mul(toBN(tx.gas)));
154 return tx;
154 return tx;
155 });
155 });
156
156
src/lib/tank.js+22−14
@@ -1,6 +1,7 @@
1// /lib/tank: functions for funding transactions
1// /lib/tank: functions for funding transactions
2
2
3import retry from 'async-retry';
3import retry from 'async-retry';
4+import { toBN } from 'web3-utils';
4import { RETRY_OPTIONS, waitForTransactionConfirm } from './txn';
5import { RETRY_OPTIONS, waitForTransactionConfirm } from './txn';
5
6
6//NOTE if accessing this in a localhost configuration fails with "CORS request
7//NOTE if accessing this in a localhost configuration fails with "CORS request
@@ -53,9 +54,10 @@ const ensureFundsFor = async (
53 askForFunding,
54 askForFunding,
54 gotFunding
55 gotFunding
55) => {
56) => {
56− let balance = await web3.eth.getBalance(address);
57+ let balance = toBN(await web3.eth.getBalance(address));
58+ cost = toBN(cost);
57
59
58− if (web3.utils.toBN(cost).gt(web3.utils.toBN(balance))) {
60+ if (cost.gt(balance)) {
59 try {
61 try {
60 if (point !== null) {
62 if (point !== null) {
61 const fundsRemaining = await remainingTransactions(point);
63 const fundsRemaining = await remainingTransactions(point);
@@ -77,36 +79,42 @@ const ensureFundsFor = async (
77 let newBalance = await web3.eth.getBalance(address);
79 let newBalance = await web3.eth.getBalance(address);
78 console.log(
80 console.log(
79 'tank: funds have confirmed',
81 'tank: funds have confirmed',
80− balance >= cost,
82+ balance.toString(),
81− balance,
82 newBalance
83 newBalance
83 );
84 );
84 return true;
85 return true;
85 }
86 }
86 } catch (e) {
87 } catch (e) {
87 console.log('tank: funding failed', e);
88 console.log('tank: funding failed', e);
88− await waitForBalance(web3, address, cost, askForFunding, gotFunding);
89+ await waitForBalance(
90+ web3,
91+ address,
92+ cost.toString(),
93+ askForFunding,
94+ gotFunding
95+ );
89 }
96 }
90 } else {
97 } else {
98+ console.log(
91− console.log('tank: already have sufficient funds', cost, address, balance);
99+ 'tank: already have sufficient funds',
100+ cost.toString(),
101+ address,
102+ balance.toString()
103+ );
92 }
104 }
93 return false;
105 return false;
94};
106};
95
107
96// returns a promise that resolves when address has at least minBalance
108// returns a promise that resolves when address has at least minBalance
97function waitForBalance(web3, address, minBalance, askForFunding, gotFunding) {
109function waitForBalance(web3, address, minBalance, askForFunding, gotFunding) {
110+ minBalance = toBN(minBalance);
98 return retry(async (bail, n) => {
111 return retry(async (bail, n) => {
99− const balance = await web3.eth.getBalance(address);
112+ const balance = toBN(await web3.eth.getBalance(address));
100− if (web3.utils.toBN(balance).gte(web3.utils.toBN(minBalance))) {
113+ if (balance.gte(minBalance)) {
101 gotFunding && gotFunding();
114 gotFunding && gotFunding();
102 return;
115 return;
103 } else {
116 } else {
104− // TODO: minBalance is a `number` type
105− // but we want to display ETH, which will never accept a number
106− // but instead wants string or BN/BigNumber.
107− // this will be heavily refactored to correctly do BN math, but until
108− // then we'll manually convert this number to an integer string
109− askForFunding(address, minBalance.toFixed(), balance);
117+ askForFunding(address, minBalance, balance);
110 throw new Error('retrying');
118 throw new Error('retrying');
111 }
119 }
112 }, RETRY_OPTIONS);
120 }, RETRY_OPTIONS);
src/lib/useEthereumTransaction.js+2−2
@@ -1,6 +1,6 @@
1import { useCallback, useEffect, useState } from 'react';
1import { useCallback, useEffect, useState } from 'react';
2import { Just } from 'folktale/maybe';
2import { Just } from 'folktale/maybe';
3−import { toWei } from 'web3-utils';
3+import { toWei, toBN } from 'web3-utils';
4
4
5import { useNetwork } from 'store/network';
5import { useNetwork } from 'store/network';
6import { useWallet } from 'store/wallet';
6import { useWallet } from 'store/wallet';
@@ -136,7 +136,7 @@ export default function useEthereumTransaction(
136 setError(undefined);
136 setError(undefined);
137
137
138 const rawTx = hexify(signedTransaction.serialize());
138 const rawTx = hexify(signedTransaction.serialize());
139− const cost = toWei(gasPrice.toFixed(0), 'gwei') * gasLimit;
139+ const cost = toWei(toBN(gasLimit).mul(toBN(gasPrice)), 'gwei');
140
140
141 let usedTank = false;
141 let usedTank = false;
142 // if this ethereum transaction is being executed by a specific point
142 // if this ethereum transaction is being executed by a specific point
src/views/Invite/InviteEmail.js+7−2
@@ -18,7 +18,7 @@ import {
18 AccessoryIcon,
18 AccessoryIcon,
19} from 'indigo-react';
19} from 'indigo-react';
20import { uniq } from 'lodash';
20import { uniq } from 'lodash';
21−import { fromWei, toWei } from 'web3-utils';
21+import { fromWei, toWei, toBN } from 'web3-utils';
22import { FieldArray } from 'react-final-form-arrays';
22import { FieldArray } from 'react-final-form-arrays';
23
23
24import { usePointCursor } from 'store/pointCursor';
24import { usePointCursor } from 'store/pointCursor';
@@ -308,7 +308,12 @@ export default function InviteEmail() {
308 _web3,
308 _web3,
309 point,
309 point,
310 _wallet.address,
310 _wallet.address,
311− toWei((gasPrice * GAS_LIMIT * emails.length).toFixed(), 'gwei'),
311+ toWei(
312+ toBN(GAS_LIMIT)
313+ .mul(toBN(gasPrice))
314+ .mul(toBN(emails.length)),
315+ 'gwei'
316+ ),
312 names.map(name => invites[name].rawTx),
317 names.map(name => invites[name].rawTx),
313 (address, minBalance, balance) =>
318 (address, minBalance, balance) =>
314 setNeedFunds({ address, minBalance, balance }),
319 setNeedFunds({ address, minBalance, balance }),