parent
39365f2cc4
commit
c77029ea90
@ -0,0 +1,344 @@ |
||||
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 MIN_GAS_PRICE_GWEI_BN = new BN(1) |
||||
const GWEI_FACTOR = new BN(1e9) |
||||
const MIN_GAS_PRICE_BN = MIN_GAS_PRICE_GWEI_BN.mul(GWEI_FACTOR) |
||||
|
||||
|
||||
module.exports = connect(mapStateToProps, mapDispatchToProps)(ConfirmDeployContract) |
||||
|
||||
function mapStateToProps (state) { |
||||
const { |
||||
conversionRate, |
||||
identities, |
||||
} = state.metamask |
||||
const accounts = state.metamask.accounts |
||||
const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0] |
||||
return { |
||||
conversionRate, |
||||
identities, |
||||
selectedAddress, |
||||
} |
||||
} |
||||
|
||||
function mapDispatchToProps (dispatch) { |
||||
return { |
||||
setCurrentCurrencyToUSD: () => dispatch(actions.setCurrentCurrency('USD')), |
||||
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('Invalid Gas Parameters')) |
||||
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 } = this.props |
||||
const txMeta = this.gatherTxMeta() |
||||
const txParams = txMeta.txParams || {} |
||||
|
||||
const USD = conversionUtil(txParams.value, { |
||||
fromNumericBase: 'hex', |
||||
toNumericBase: 'dec', |
||||
fromCurrency: 'ETH', |
||||
toCurrency: 'USD', |
||||
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(USD), |
||||
token: Number(ETH), |
||||
} |
||||
|
||||
} |
||||
|
||||
ConfirmDeployContract.prototype.getGasFee = function () { |
||||
const { conversionRate } = 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_BN.toString(16) |
||||
const gasPriceBn = hexToBn(gasPrice) |
||||
|
||||
const txFeeBn = gasBn.mul(gasPriceBn) |
||||
|
||||
const USD = conversionUtil(txFeeBn, { |
||||
fromNumericBase: 'BN', |
||||
toNumericBase: 'dec', |
||||
fromDenomination: 'WEI', |
||||
fromCurrency: 'ETH', |
||||
toCurrency: 'USD', |
||||
numberOfDecimals: 2, |
||||
conversionRate, |
||||
}) |
||||
const ETH = conversionUtil(txFeeBn, { |
||||
fromNumericBase: 'BN', |
||||
toNumericBase: 'dec', |
||||
fromDenomination: 'WEI', |
||||
fromCurrency: 'ETH', |
||||
toCurrency: 'ETH', |
||||
numberOfDecimals: 6, |
||||
conversionRate, |
||||
}) |
||||
|
||||
return { |
||||
fiat: Number(USD), |
||||
eth: Number(ETH), |
||||
} |
||||
} |
||||
ConfirmDeployContract.prototype.renderGasFee = function () { |
||||
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', [ 'Gas Fee' ]), |
||||
h('div.confirm-screen-section-column', [ |
||||
h('div.confirm-screen-row-info', `$${fiatGas} USD`), |
||||
|
||||
h( |
||||
'div.confirm-screen-row-detail', |
||||
`${ethGas} ETH` |
||||
), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
ConfirmDeployContract.prototype.renderHeroAmount = function () { |
||||
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', 'USD'), |
||||
h('div.flex-center.confirm-memo-wrapper', [ |
||||
h('h3.confirm-screen-send-memo', memo), |
||||
]), |
||||
]) |
||||
) |
||||
} |
||||
|
||||
ConfirmDeployContract.prototype.renderTotalPlusGas = function () { |
||||
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', [ 'Total ' ]), |
||||
h('div.confirm-screen-total-box__subtitle', [ 'Amount + Gas' ]), |
||||
]), |
||||
|
||||
h('div.confirm-screen-section-column', [ |
||||
h('div.confirm-screen-row-info', `$${fiatAmount + fiatGas} USD`), |
||||
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', { |
||||
onClick: () => backToAccountDetail(selectedAddress), |
||||
}, 'BACK'), |
||||
h('div.confirm-screen-title', 'Confirm Transaction'), |
||||
]), |
||||
h('div.flex-row.flex-center.confirm-screen-identicons', [ |
||||
h('div.confirm-screen-account-wrapper', [ |
||||
h( |
||||
Identicon, |
||||
{ |
||||
address: fromAddress, |
||||
diameter: 100, |
||||
}, |
||||
), |
||||
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', 'New Contract'), |
||||
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', [ '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', [ 'To' ]), |
||||
h('div.confirm-screen-section-column', [ |
||||
h('div.confirm-screen-row-info', 'New Contract'), |
||||
]), |
||||
]), |
||||
|
||||
this.renderGasFee(), |
||||
|
||||
this.renderTotalPlusGas(), |
||||
|
||||
]), |
||||
]), |
||||
|
||||
h('form#pending-tx-form.flex-column.flex-center', { |
||||
onSubmit: this.onSubmit, |
||||
}, [ |
||||
|
||||
// Accept Button
|
||||
h('button.confirm-screen-confirm-button', ['CONFIRM']), |
||||
|
||||
// Cancel Button
|
||||
h('div.cancel.btn-light.confirm-screen-cancel-button', { |
||||
onClick: (event) => this.cancel(event, txMeta), |
||||
}, 'CANCEL'), |
||||
]), |
||||
]) |
||||
) |
||||
} |
Loading…
Reference in new issue