text: const BN = require('ethereumjs-util').BN
  const normalize = require('eth-sig-util').normalize
  
  class PendingBalanceCalculator {
  
    /**
     * Used for calculating a users "pending balance": their current balance minus the total possible cost of all their
     * pending transactions.
     *
     * @typedef {Object} PendingBalanceCalculator
     * @param {Function} getBalance Returns a promise of a BN of the current balance in Wei
     * @param {Function} getPendingTransactions Returns an array of TxMeta Objects, which have txParams properties,
     * which include value, gasPrice, and gas, all in a base=16 hex format.
     *
     */
    constructor ({ getBalance, getPendingTransactions }) {
      this.getPendingTransactions = getPendingTransactions
      this.getNetworkBalance = getBalance
    }
  
    /**
     * Returns the users "pending balance": their current balance minus the total possible cost of all their
     * pending transactions.
     *
     * @returns {Promise<string>} Promises a base 16 hex string that contains the user's "pending balance"
     *
     */
    async getBalance () {
      const results = await Promise.all([
        this.getNetworkBalance(),
        this.getPendingTransactions(),
      ])
  
      const [ balance, pending ] = results
      if (!balance) return undefined
  
      const pendingValue = pending.reduce((total, tx) => {
        return total.add(this.calculateMaxCost(tx))
      }, new BN(0))
  
      return `0x${balance.sub(pendingValue).toString(16)}`
    }
  
    /**
     * Calculates the maximum possible cost of a single transaction, based on the value, gas price and gas limit.
     *
     * @param {object} tx Contains all that data about a transaction.
     * @property {object} tx.txParams Contains data needed to calculate the maximum cost of the transaction: gas,
     * gasLimit and value.
     *
     * @returns {string} Returns a base 16 hex string that contains the maximum possible cost of the transaction.
     */
    calculateMaxCost (tx) {
      const txValue = tx.txParams.value
      const value = this.hexToBn(txValue)
      const gasPrice = this.hexToBn(tx.txParams.gasPrice)
  
      const gas = tx.txParams.gas
      const gasLimit = tx.txParams.gasLimit
      const gasLimitBn = this.hexToBn(gas || gasLimit)
  
      const gasCost = gasPrice.mul(gasLimitBn)
      return value.add(gasCost)
    }
  
    /**
     * Converts a hex string to a BN object
     *
     * @param {string} hex A number represented as a hex string
     * @returns {Object} A BN object
     *
     */
    hexToBn (hex) {
      return new BN(normalize(hex).substring(2), 16)
    }
  
  }
  
  module.exports = PendingBalanceCalculator
  