aboutsummaryrefslogblamecommitdiffstats
path: root/ui/app/components/pending-tx/confirm-deploy-contract.js
blob: 49fbe63872fd0769e1e57ffb4b5ba27a43f1202b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11










                                                                
                                  
 
                                                               







                                                                                    
                    



                                                                                    
                    







                                        





















                                                                                   
                                                                      



































































                                                                                                    
                                                        


                                        
                                               


                           
                                














                                              
                       





                                                         
                                                        







                                        
                                                         



                                       
                                        



                            
                                













                                       
                       


                     
 
                                                            
                                        



                                                          
                                                                                    
                                              
                                                                                        










                                                                
                                        






                                                      

                                                                                             







                                                                  
                                        





                                                                   

                                                                            


                                              
                                                                                                     

























                                                                          
                                                          
                                                                
                        
                                                              
                                             






                                                                 
                             


                                                            
                                                                                                  



                                                   
                                                                    



                                                         







                                                                  




                                                                
                                                                                        






                                                                                                    
                                                                                      
                                                    
                                                                 









                                    
                                 

                                
                        
                                                                        
                                                         
                        

                        
                                                                          
 



         
const Component = require('react').Component
const { connect } = require('react-redux')
const h = require('react-hyperscript')
const inherits = require('util').inherits
const actions = require('../../actions')
const clone = require('clone')
const Identicon = require('../identicon')
const ethUtil = require('ethereumjs-util')
const BN = ethUtil.BN
const hexToBn = require('../../../../app/scripts/lib/hex-to-bn')
const { conversionUtil } = require('../../conversion-util')
const t = require('../../../i18n')

const { MIN_GAS_PRICE_HEX } = require('../send/send-constants')


module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract)

function mapStateToProps (state) {
  const {
    conversionRate,
    identities,
    currentCurrency,
  } = state.metamask
  const accounts = state.metamask.accounts
  const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0]
  return {
    currentCurrency,
    conversionRate,
    identities,
    selectedAddress,
  }
}

function mapDispatchToProps (dispatch) {
  return {
    backToAccountDetail: address => dispatch(actions.backToAccountDetail(address)),
    cancelTransaction: ({ id }) => dispatch(actions.cancelTx({ id })),
  }
}


inherits(ConfirmDeployContract, Component)
function ConfirmDeployContract () {
  Component.call(this)
  this.state = {}
  this.onSubmit = this.onSubmit.bind(this)
}

ConfirmDeployContract.prototype.onSubmit = function (event) {
  event.preventDefault()
  const txMeta = this.gatherTxMeta()
  const valid = this.checkValidity()
  this.setState({ valid, submitting: true })

  if (valid && this.verifyGasParams()) {
    this.props.sendTransaction(txMeta, event)
  } else {
    this.props.dispatch(actions.displayWarning(t('invalidGasParams')))
    this.setState({ submitting: false })
  }
}

ConfirmDeployContract.prototype.cancel = function (event, txMeta) {
  event.preventDefault()
  this.props.cancelTransaction(txMeta)
}

ConfirmDeployContract.prototype.checkValidity = function () {
  const form = this.getFormEl()
  const valid = form.checkValidity()
  return valid
}

ConfirmDeployContract.prototype.getFormEl = function () {
  const form = document.querySelector('form#pending-tx-form')
  // Stub out form for unit tests:
  if (!form) {
    return { checkValidity () { return true } }
  }
  return form
}

// After a customizable state value has been updated,
ConfirmDeployContract.prototype.gatherTxMeta = function () {
  const props = this.props
  const state = this.state
  const txData = clone(state.txData) || clone(props.txData)

  // log.debug(`UI has defaulted to tx meta ${JSON.stringify(txData)}`)
  return txData
}

ConfirmDeployContract.prototype.verifyGasParams = function () {
  // We call this in case the gas has not been modified at all
  if (!this.state) { return true }
  return (
    this._notZeroOrEmptyString(this.state.gas) &&
    this._notZeroOrEmptyString(this.state.gasPrice)
  )
}

ConfirmDeployContract.prototype._notZeroOrEmptyString = function (obj) {
  return obj !== '' && obj !== '0x0'
}

ConfirmDeployContract.prototype.bnMultiplyByFraction = function (targetBN, numerator, denominator) {
  const numBN = new BN(numerator)
  const denomBN = new BN(denominator)
  return targetBN.mul(numBN).div(denomBN)
}

ConfirmDeployContract.prototype.getData = function () {
  const { identities } = this.props
  const txMeta = this.gatherTxMeta()
  const txParams = txMeta.txParams || {}

  return {
    from: {
      address: txParams.from,
      name: identities[txParams.from].name,
    },
    memo: txParams.memo || '',
  }
}

ConfirmDeployContract.prototype.getAmount = function () {
  const { conversionRate, currentCurrency } = this.props
  const txMeta = this.gatherTxMeta()
  const txParams = txMeta.txParams || {}

  const FIAT = conversionUtil(txParams.value, {
    fromNumericBase: 'hex',
    toNumericBase: 'dec',
    fromCurrency: 'ETH',
    toCurrency: currentCurrency,
    numberOfDecimals: 2,
    fromDenomination: 'WEI',
    conversionRate,
  })
  const ETH = conversionUtil(txParams.value, {
    fromNumericBase: 'hex',
    toNumericBase: 'dec',
    fromCurrency: 'ETH',
    toCurrency: 'ETH',
    fromDenomination: 'WEI',
    conversionRate,
    numberOfDecimals: 6,
  })

  return {
    fiat: Number(FIAT),
    token: Number(ETH),
  }

}

ConfirmDeployContract.prototype.getGasFee = function () {
  const { conversionRate, currentCurrency } = this.props
  const txMeta = this.gatherTxMeta()
  const txParams = txMeta.txParams || {}

  // Gas
  const gas = txParams.gas
  const gasBn = hexToBn(gas)

  // Gas Price
  const gasPrice = txParams.gasPrice || MIN_GAS_PRICE_HEX
  const gasPriceBn = hexToBn(gasPrice)

  const txFeeBn = gasBn.mul(gasPriceBn)

  const FIAT = conversionUtil(txFeeBn, {
    fromNumericBase: 'BN',
    toNumericBase: 'dec',
    fromDenomination: 'WEI',
    fromCurrency: 'ETH',
    toCurrency: currentCurrency,
    numberOfDecimals: 2,
    conversionRate,
  })
  const ETH = conversionUtil(txFeeBn, {
    fromNumericBase: 'BN',
    toNumericBase: 'dec',
    fromDenomination: 'WEI',
    fromCurrency: 'ETH',
    toCurrency: 'ETH',
    numberOfDecimals: 6,
    conversionRate,
  })

  return {
    fiat: Number(FIAT),
    eth: Number(ETH),
  }
}

ConfirmDeployContract.prototype.renderGasFee = function () {
  const { currentCurrency } = this.props
  const { fiat: fiatGas, eth: ethGas } = this.getGasFee()

  return (
    h('section.flex-row.flex-center.confirm-screen-row', [
      h('span.confirm-screen-label.confirm-screen-section-column', [ t('gasFee') ]),
      h('div.confirm-screen-section-column', [
        h('div.confirm-screen-row-info', `${fiatGas} ${currentCurrency.toUpperCase()}`),

        h(
          'div.confirm-screen-row-detail',
          `${ethGas} ETH`
        ),
      ]),
    ])
  )
}

ConfirmDeployContract.prototype.renderHeroAmount = function () {
  const { currentCurrency } = this.props
  const { fiat: fiatAmount } = this.getAmount()
  const txMeta = this.gatherTxMeta()
  const txParams = txMeta.txParams || {}
  const { memo = '' } = txParams

  return (
    h('div.confirm-send-token__hero-amount-wrapper', [
      h('h3.flex-center.confirm-screen-send-amount', `${fiatAmount}`),
      h('h3.flex-center.confirm-screen-send-amount-currency', currentCurrency.toUpperCase()),
      h('div.flex-center.confirm-memo-wrapper', [
        h('h3.confirm-screen-send-memo', memo),
      ]),
    ])
  )
}

ConfirmDeployContract.prototype.renderTotalPlusGas = function () {
  const { currentCurrency } = this.props
  const { fiat: fiatAmount, token: tokenAmount } = this.getAmount()
  const { fiat: fiatGas, eth: ethGas } = this.getGasFee()

  return (
    h('section.flex-row.flex-center.confirm-screen-total-box ', [
      h('div.confirm-screen-section-column', [
        h('span.confirm-screen-label', [ t('total') + ' ' ]),
        h('div.confirm-screen-total-box__subtitle', [ t('amountPlusGas') ]),
      ]),

      h('div.confirm-screen-section-column', [
        h('div.confirm-screen-row-info', `${fiatAmount + fiatGas} ${currentCurrency.toUpperCase()}`),
        h('div.confirm-screen-row-detail', `${tokenAmount + ethGas} ETH`),
      ]),
    ])
  )
}

ConfirmDeployContract.prototype.render = function () {
  const { backToAccountDetail, selectedAddress } = this.props
  const txMeta = this.gatherTxMeta()

  const {
    from: {
      address: fromAddress,
      name: fromName,
    },
  } = this.getData()

  this.inputs = []

  return (
    h('div.flex-column.flex-grow.confirm-screen-container', {
      style: { minWidth: '355px' },
    }, [
      // Main Send token Card
      h('div.confirm-screen-wrapper.flex-column.flex-grow', [
        h('h3.flex-center.confirm-screen-header', [
          h('button.confirm-screen-back-button.allcaps', {
            onClick: () => backToAccountDetail(selectedAddress),
          }, t('back')),
          h('div.confirm-screen-title', t('confirmContract')),
          h('div.confirm-screen-header-tip'),
        ]),
        h('div.flex-row.flex-center.confirm-screen-identicons', [
          h('div.confirm-screen-account-wrapper', [
            h(
              Identicon,
              {
                address: fromAddress,
                diameter: 60,
              },
            ),
            h('span.confirm-screen-account-name', fromName),
            // h('span.confirm-screen-account-number', fromAddress.slice(fromAddress.length - 4)),
          ]),
          h('i.fa.fa-arrow-right.fa-lg'),
          h('div.confirm-screen-account-wrapper', [
            h('i.fa.fa-file-text-o'),
            h('span.confirm-screen-account-name', t('newContract')),
            h('span.confirm-screen-account-number', ' '),
          ]),
        ]),

        // h('h3.flex-center.confirm-screen-sending-to-message', {
        //   style: {
        //     textAlign: 'center',
        //     fontSize: '16px',
        //   },
        // }, [
        //   `You're deploying a new contract.`,
        // ]),

        this.renderHeroAmount(),

        h('div.confirm-screen-rows', [
          h('section.flex-row.flex-center.confirm-screen-row', [
            h('span.confirm-screen-label.confirm-screen-section-column', [ t('from') ]),
            h('div.confirm-screen-section-column', [
              h('div.confirm-screen-row-info', fromName),
              h('div.confirm-screen-row-detail', `...${fromAddress.slice(fromAddress.length - 4)}`),
            ]),
          ]),

          h('section.flex-row.flex-center.confirm-screen-row', [
            h('span.confirm-screen-label.confirm-screen-section-column', [ t('to') ]),
            h('div.confirm-screen-section-column', [
              h('div.confirm-screen-row-info', t('newContract')),
            ]),
          ]),

          this.renderGasFee(),

          this.renderTotalPlusGas(),

        ]),
      ]),

      h('form#pending-tx-form', {
        onSubmit: this.onSubmit,
      }, [
        // Cancel Button
        h('div.cancel.btn-light.confirm-screen-cancel-button.allcaps', {
          onClick: (event) => this.cancel(event, txMeta),
        }, t('cancel')),

        // Accept Button
        h('button.confirm-screen-confirm-button.allcaps', [t('confirm')]),

      ]),
    ])
  )
}