1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00
metamask-extension/ui/app/send.js

310 lines
7.8 KiB
JavaScript
Raw Normal View History

const inherits = require('util').inherits
2016-08-25 23:10:07 +02:00
const PersistentForm = require('../lib/persistent-form')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
2016-05-18 21:13:19 +02:00
const Identicon = require('./components/identicon')
const actions = require('./actions')
const util = require('./util')
const numericBalance = require('./util').numericBalance
2016-05-18 21:13:19 +02:00
const addressSummary = require('./util').addressSummary
2016-10-19 23:33:30 +02:00
const isHex = require('./util').isHex
2016-09-07 02:28:25 +02:00
const EthBalance = require('./components/eth-balance')
const EnsInput = require('./components/ens-input')
const ethUtil = require('ethereumjs-util')
module.exports = connect(mapStateToProps)(SendTransactionScreen)
2016-06-21 22:18:32 +02:00
function mapStateToProps (state) {
var result = {
address: state.metamask.selectedAddress,
accounts: state.metamask.accounts,
identities: state.metamask.identities,
warning: state.appState.warning,
network: state.metamask.network,
addressBook: state.metamask.addressBook,
conversionRate: state.metamask.conversionRate,
currentCurrency: state.metamask.currentCurrency,
}
result.error = result.warning && result.warning.split('.')[0]
result.account = result.accounts[result.address]
result.identity = result.identities[result.address]
result.balance = result.account ? numericBalance(result.account.balance) : null
return result
}
2016-08-25 23:10:07 +02:00
inherits(SendTransactionScreen, PersistentForm)
2016-06-21 22:18:32 +02:00
function SendTransactionScreen () {
2016-08-25 23:10:07 +02:00
PersistentForm.call(this)
}
2016-06-21 22:18:32 +02:00
SendTransactionScreen.prototype.render = function () {
2016-08-25 23:10:07 +02:00
this.persistentFormParentId = 'send-tx-form'
2017-05-16 08:12:47 +02:00
const props = this.props
const {
address,
account,
identity,
network,
identities,
addressBook,
conversionRate,
currentCurrency,
2017-05-16 08:12:47 +02:00
} = props
return (
2016-05-18 21:13:19 +02:00
h('.send-screen.flex-column.flex-grow', [
2016-05-18 21:13:19 +02:00
//
// Sender Profile
//
2016-10-06 22:03:01 +02:00
h('.account-data-subsection.flex-row.flex-grow', {
2016-05-18 21:13:19 +02:00
style: {
margin: '0 20px',
},
}, [
// header - identicon + nav
h('.flex-row.flex-space-between', {
style: {
2016-10-06 22:03:01 +02:00
marginTop: '15px',
2016-05-18 21:13:19 +02:00
},
}, [
2016-06-24 20:44:18 +02:00
// back button
2016-05-18 21:13:19 +02:00
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
onClick: this.back.bind(this),
}),
// large identicon
h('.identicon-wrapper.flex-column.flex-center.select-none', [
h(Identicon, {
diameter: 62,
address: address,
}),
]),
2016-06-24 20:44:18 +02:00
// invisible place holder
2016-10-06 22:03:01 +02:00
h('i.fa.fa-users.fa-lg.invisible', {
style: {
marginTop: '28px',
},
}),
2016-05-18 21:13:19 +02:00
]),
// account label
2016-10-06 22:03:01 +02:00
h('.flex-column', {
2016-05-18 21:13:19 +02:00
style: {
2016-10-06 22:03:01 +02:00
marginTop: '10px',
alignItems: 'flex-start',
2016-05-18 21:13:19 +02:00
},
}, [
2016-10-06 22:03:01 +02:00
h('h2.font-medium.color-forest.flex-center', {
style: {
paddingTop: '8px',
marginBottom: '8px',
},
}, identity && identity.name),
2016-05-18 21:13:19 +02:00
2016-10-06 22:03:01 +02:00
// address and getter actions
h('.flex-row.flex-center', {
2016-05-18 21:13:19 +02:00
style: {
2016-10-06 22:03:01 +02:00
marginBottom: '8px',
2016-05-18 21:13:19 +02:00
},
2016-10-06 22:03:01 +02:00
}, [
2016-05-18 21:13:19 +02:00
2016-10-06 22:03:01 +02:00
h('div', {
style: {
lineHeight: '16px',
},
}, addressSummary(address)),
]),
2016-05-18 21:13:19 +02:00
2016-10-06 22:03:01 +02:00
// balance
h('.flex-row.flex-center', [
2016-05-18 21:13:19 +02:00
2016-10-06 22:03:01 +02:00
h(EthBalance, {
value: account && account.balance,
conversionRate,
currentCurrency,
2016-10-06 22:03:01 +02:00
}),
2016-05-18 21:13:19 +02:00
2016-10-06 22:03:01 +02:00
]),
2016-05-18 21:13:19 +02:00
]),
]),
2016-05-18 21:13:19 +02:00
//
// Required Fields
//
h('h3.flex-center.text-transform-uppercase', {
style: {
background: '#EBEBEB',
color: '#AEAEAE',
2016-10-06 22:03:01 +02:00
marginTop: '15px',
marginBottom: '16px',
2016-05-18 21:13:19 +02:00
},
}, [
'Send Transaction',
]),
// error message
props.error && h('span.error.flex-center', props.error),
2016-05-18 21:13:19 +02:00
// 'to' field
h('section.flex-row.flex-center', [
h(EnsInput, {
name: 'address',
placeholder: 'Recipient Address',
onChange: this.recipientDidChange.bind(this),
network,
2017-03-09 20:31:00 +01:00
identities,
addressBook,
2016-06-21 22:18:32 +02:00
}),
]),
2016-05-18 21:13:19 +02:00
// 'amount' and send button
h('section.flex-row.flex-center', [
h('input.large-input', {
name: 'amount',
placeholder: 'Amount',
type: 'number',
2016-05-18 21:13:19 +02:00
style: {
2016-10-06 22:03:01 +02:00
marginRight: '6px',
2016-05-18 21:13:19 +02:00
},
dataset: {
2016-08-25 23:10:07 +02:00
persistentFormId: 'tx-amount',
},
}),
2016-05-18 21:13:19 +02:00
h('button.primary', {
onClick: this.onSubmit.bind(this),
style: {
textTransform: 'uppercase',
},
2017-06-27 22:56:51 +02:00
}, 'Next'),
2016-05-18 21:13:19 +02:00
]),
2016-05-18 21:13:19 +02:00
//
// Optional Fields
//
h('h3.flex-center.text-transform-uppercase', {
style: {
background: '#EBEBEB',
color: '#AEAEAE',
2016-10-06 22:03:01 +02:00
marginTop: '16px',
marginBottom: '16px',
2016-05-18 21:13:19 +02:00
},
}, [
2016-10-20 02:39:41 +02:00
'Transaction Data (optional)',
]),
2016-05-18 21:13:19 +02:00
// 'data' field
2016-10-06 22:03:01 +02:00
h('section.flex-column.flex-center', [
h('input.large-input', {
name: 'txData',
2016-05-18 21:13:19 +02:00
placeholder: '0x01234',
style: {
width: '100%',
resize: 'none',
2016-06-21 22:18:32 +02:00
},
dataset: {
2016-08-25 23:10:07 +02:00
persistentFormId: 'tx-data',
},
2016-05-18 21:13:19 +02:00
}),
]),
])
)
}
2016-06-21 22:18:32 +02:00
SendTransactionScreen.prototype.navigateToAccounts = function (event) {
2016-05-18 21:13:19 +02:00
event.stopPropagation()
this.props.dispatch(actions.showAccountsPage())
}
2016-06-21 22:18:32 +02:00
SendTransactionScreen.prototype.back = function () {
var address = this.props.address
this.props.dispatch(actions.backToAccountDetail(address))
}
SendTransactionScreen.prototype.recipientDidChange = function (recipient, nickname) {
this.setState({
recipient: recipient,
nickname: nickname,
})
}
SendTransactionScreen.prototype.onSubmit = function () {
const state = this.state || {}
const recipient = state.recipient || document.querySelector('input[name="address"]').value.replace(/^[.\s]+|[.\s]+$/g, '')
const nickname = state.nickname || ' '
const input = document.querySelector('input[name="amount"]').value
const parts = input.split('')
let message
if (isNaN(input) || input === '') {
message = 'Invalid ether value.'
return this.props.dispatch(actions.displayWarning(message))
}
if (parts[1]) {
var decimal = parts[1]
if (decimal.length > 18) {
message = 'Ether amount is too precise.'
return this.props.dispatch(actions.displayWarning(message))
}
}
const value = util.normalizeEthStringToWei(input)
const txData = document.querySelector('input[name="txData"]').value
const balance = this.props.balance
if (value.gt(balance)) {
2016-06-21 22:56:04 +02:00
message = 'Insufficient funds.'
return this.props.dispatch(actions.displayWarning(message))
}
if (input < 0) {
message = 'Can not send negative amounts of ETH.'
return this.props.dispatch(actions.displayWarning(message))
}
if ((util.isInvalidChecksumAddress(recipient))) {
message = 'Recipient address checksum is invalid.'
return this.props.dispatch(actions.displayWarning(message))
}
2016-05-19 23:21:35 +02:00
if ((!util.isValidAddress(recipient) && !txData) || (!recipient && !txData)) {
2016-06-21 22:56:04 +02:00
message = 'Recipient address is invalid.'
return this.props.dispatch(actions.displayWarning(message))
}
2016-10-19 23:33:30 +02:00
if (!isHex(ethUtil.stripHexPrefix(txData)) && txData) {
message = 'Transaction data must be hex string.'
return this.props.dispatch(actions.displayWarning(message))
}
this.props.dispatch(actions.hideWarning())
this.props.dispatch(actions.addToAddressBook(recipient, nickname))
var txParams = {
from: this.props.address,
value: '0x' + value.toString(16),
}
2016-05-20 01:14:16 +02:00
if (recipient) txParams.to = ethUtil.addHexPrefix(recipient)
if (txData) txParams.data = txData
2016-10-13 04:35:09 +02:00
this.props.dispatch(actions.signTx(txParams))
}