estimateGas.js 2.33 KiB
Newer Older
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
//
// SPDX-License-Identifier: BSD-3-Clause

import BigNumber from 'bignumber.js';
import memoize from 'lodash/memoize';
import { toWei } from '@parity/api/lib/util/wei';

import Debug from './debug';

const debug = Debug('estimateGas');
const GAS_MULT_FACTOR = 1.25; // Since estimateGas is not always accurate, we add a 33% factor for buffer.

/**
 * Estimate the amount of gas for our transaction.
 */
export const estimateGas = (tx, token, api) => {
  if (!tx || !Object.keys(tx).length) {
    return Promise.reject(new Error('Tx not set in sendStore.'));
  }

  if (token.address === 'ETH') {
    return estimateGasForEth(txForEth(tx), api).then(addBuffer);
  } else {
    return estimateGasForErc20(txForErc20(tx, token), api).then(addBuffer);
  }
};

/**
 * Estimate gas to transfer in ERC20 contract. Expensive function, so we
 * memoize it.
 */
const estimateGasForErc20 = memoize(
  txForErc20 =>
    this.contract.contractObject.instance.transfer.estimateGas(
      txForErc20.options,
      txForErc20.args
    ),
  JSON.stringify
);

/**
 * Estimate gas to transfer to an ETH address. Expensive function, so we
 * memoize it.
 */
const estimateGasForEth = memoize((txForEth, api) => {
  debug(`Estimating gas for tx.`, txForEth);
  return api.eth.estimateGas(txForEth);
}, JSON.stringify);

/**
 * Add some extra gas buffer just to be sure user has enough balance.
 *
 * @param {BigNumber} estimated - The estimated gas price returned by
 * estimateGas.
 */
const addBuffer = estimated => {
  const withBuffer = estimated.mul(GAS_MULT_FACTOR);
  debug(`Estimated gas ${+estimated}, with buffer ${+withBuffer}.`);
  return withBuffer;
};

/**
 * This.tx is a user-friendly tx object. We convert it now as it can be
 * passed to makeContract$.transfer(...).
 */
export const txForErc20 = (tx, token) => {
  return {
    args: [
      tx.to,
      new BigNumber(tx.amount).mul(new BigNumber(10).pow(token.decimals))
    ],
    options: {
      gasPrice: toWei(tx.gasPrice, 'shannon') // shannon == gwei
    }
  };
};

/**
 * This.tx is a user-friendly tx object. We convert it now as it can be
 * passed to post$(tx).
 */
export const txForEth = tx => {
  return {
    gasPrice: toWei(tx.gasPrice, 'shannon'), // shannon == gwei
    to: tx.to,
    value: toWei(tx.amount.toString())
  };
};