Merge pull request #1197 from MetaMask/i1130-ResolveENS

Allow ENS Names in Send Form
feature/default_network_editable
Kevin Serrano 8 years ago committed by GitHub
commit e602cb13c5
  1. 2
      CHANGELOG.md
  2. 89
      development/states/send.json
  3. 1
      package.json
  4. 145
      ui/app/components/ens-input.js
  5. 2
      ui/app/conf-tx.js
  6. 17
      ui/app/send.js

@ -2,6 +2,8 @@
## Current Master ## Current Master
- Allow sending to ENS names in send form on Ropsten.
## 3.4.0 2017-3-8 ## 3.4.0 2017-3-8
- Add two most recently used custom RPCs to network dropdown menu. - Add two most recently used custom RPCs to network dropdown menu.

@ -2,73 +2,108 @@
"metamask": { "metamask": {
"isInitialized": true, "isInitialized": true,
"isUnlocked": true, "isUnlocked": true,
"currentDomain": "example.com",
"rpcTarget": "https://rawtestrpc.metamask.io/", "rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": { "identities": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"name": "Wallet 1",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825", "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"mayBeFauceting": false "name": "Account 1"
}, },
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"name": "Wallet 2",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb", "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"mayBeFauceting": false "name": "Account 2"
}, },
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"name": "Wallet 3",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d", "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"mayBeFauceting": false "name": "Account 3"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"address": "0xd85a4b6a394794842887b8284293d69163007bbb",
"name": "Account 4"
} }
}, },
"unconfTxs": {}, "unapprovedTxs": {},
"currentFiat": "USD", "currentFiat": "USD",
"conversionRate": 11.21283484, "conversionRate": 16.88200327,
"conversionDate": 1472158984, "conversionDate": 1489013762,
"noActiveNotices": true,
"frequentRpcList": [],
"network": "3",
"accounts": { "accounts": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": { "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"code": "0x", "code": "0x",
"balance": "0x34693f54a1e25900", "balance": "0x47c9d71831c76efe",
"nonce": "0x100013", "nonce": "0x1b",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" "address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
}, },
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": { "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"code": "0x", "code": "0x",
"nonce": "0x100000", "balance": "0x37452b1315889f80",
"balance": "0x18af912cee770000", "nonce": "0xa",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb" "address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
}, },
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": { "0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"code": "0x", "code": "0x",
"nonce": "0x100000", "balance": "0x0",
"balance": "0x2386f26fc10000", "nonce": "0x0",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d" "address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0xd85a4b6a394794842887b8284293d69163007bbb"
} }
}, },
"transactions": [], "transactions": {},
"network": "2", "selectedAddressTxList": [],
"seedWords": null, "unapprovedMsgs": {},
"unconfMsgs": {}, "unapprovedMsgCount": 0,
"messages": [], "unapprovedPersonalMsgs": {},
"shapeShiftTxList": [], "unapprovedPersonalMsgCount": 0,
"keyringTypes": [
"Simple Key Pair",
"HD Key Tree"
],
"keyrings": [
{
"type": "HD Key Tree",
"accounts": [
"fdea65c8e26263f6d9a1b5de9555d2931a33b825",
"c5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"2f8d4a878cfa04a6e60d46362f5644deab66572d"
]
},
{
"type": "Simple Key Pair",
"accounts": [
"0xd85a4b6a394794842887b8284293d69163007bbb"
]
}
],
"selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb",
"currentCurrency": "USD",
"provider": { "provider": {
"type": "testnet" "type": "testnet"
}, },
"selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825" "shapeShiftTxList": [],
"lostAccounts": []
}, },
"appState": { "appState": {
"menuOpen": false, "menuOpen": false,
"currentView": { "currentView": {
"name": "sendTransaction" "name": "sendTransaction",
"context": "0xd85a4b6a394794842887b8284293d69163007bbb"
}, },
"accountDetail": { "accountDetail": {
"subview": "transactions" "subview": "transactions",
"accountExport": "none",
"privateKey": ""
}, },
"currentDomain": "127.0.0.1:9966",
"transForward": true, "transForward": true,
"isLoading": false, "isLoading": false,
"warning": null, "warning": null,
"detailView": {} "scrollToBottom": false,
"forgottenPassword": null
}, },
"identities": {} "identities": {}
} }

@ -60,6 +60,7 @@
"ethereumjs-tx": "^1.0.0", "ethereumjs-tx": "^1.0.0",
"ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9", "ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"ethereumjs-wallet": "^0.6.0", "ethereumjs-wallet": "^0.6.0",
"ethjs-ens": "^1.0.2",
"express": "^4.14.0", "express": "^4.14.0",
"extension-link-enabler": "^1.0.0", "extension-link-enabler": "^1.0.0",
"extensionizer": "^1.0.0", "extensionizer": "^1.0.0",

@ -0,0 +1,145 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const extend = require('xtend')
const debounce = require('debounce')
const copyToClipboard = require('copy-to-clipboard')
const ENS = require('ethjs-ens')
const ensRE = /.+\.eth$/
const networkResolvers = {
'3': '112234455c3a32fd11230c42e7bccd4a84e02010',
}
module.exports = EnsInput
inherits(EnsInput, Component)
function EnsInput () {
Component.call(this)
}
EnsInput.prototype.render = function () {
const props = this.props
const opts = extend(props, {
onChange: () => {
const network = this.props.network
let resolverAddress = networkResolvers[network]
if (!resolverAddress) return
const recipient = document.querySelector('input[name="address"]').value
if (recipient.match(ensRE) === null) {
return this.setState({
loadingEns: false,
ensResolution: null,
ensFailure: null,
})
}
this.setState({
loadingEns: true,
})
this.checkName()
},
})
return h('div', {
style: { width: '100%' },
}, [
h('input.large-input', opts),
this.ensIcon(),
])
}
EnsInput.prototype.componentDidMount = function () {
const network = this.props.network
let resolverAddress = networkResolvers[network]
if (resolverAddress) {
const provider = web3.currentProvider
this.ens = new ENS({ provider, network })
this.checkName = debounce(this.lookupEnsName.bind(this), 200)
}
}
EnsInput.prototype.lookupEnsName = function () {
const recipient = document.querySelector('input[name="address"]').value
const { ensResolution } = this.state
if (!this.ens) {
return this.setState({
loadingEns: false,
ensFailure: true,
hoverText: 'ENS is not supported on your current network.',
})
}
log.info(`ENS attempting to resolve name: ${recipient}`)
this.ens.lookup(recipient.trim())
.then((address) => {
if (address !== ensResolution) {
this.setState({
loadingEns: false,
ensResolution: address,
hoverText: address + '\nClick to Copy',
})
}
})
.catch((reason) => {
return this.setState({
loadingEns: false,
ensFailure: true,
hoverText: reason.message,
})
})
}
EnsInput.prototype.componentDidUpdate = function (prevProps, prevState) {
const state = this.state || {}
const { ensResolution } = state
if (ensResolution && this.props.onChange &&
ensResolution !== prevState.ensResolution) {
this.props.onChange(ensResolution)
}
}
EnsInput.prototype.ensIcon = function (recipient) {
const { hoverText } = this.state || {}
return h('span', {
title: hoverText,
style: {
position: 'absolute',
padding: '9px',
transform: 'translatex(-40px)',
},
}, this.ensIconContents(recipient))
}
EnsInput.prototype.ensIconContents = function (recipient) {
const { loadingEns, ensFailure, ensResolution } = this.state || {}
if (loadingEns) {
return h('img', {
src: 'images/loading.svg',
style: {
width: '30px',
height: '30px',
transform: 'translateY(-6px)',
},
})
}
if (ensFailure) {
return h('i.fa.fa-warning.fa-lg.warning')
}
if (ensResolution) {
return h('i.fa.fa-check-circle.fa-lg.cursor-pointer', {
style: { color: 'green' },
onClick: (event) => {
event.preventDefault()
event.stopPropagation()
copyToClipboard(ensResolution)
},
})
}
}

@ -49,7 +49,7 @@ ConfirmTxScreen.prototype.render = function () {
var isNotification = isPopupOrNotification() === 'notification' var isNotification = isPopupOrNotification() === 'notification'
log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`) log.info(`rendering a combined ${unconfTxList.length} unconf msg & txs`)
if (unconfTxList.length === 0) return h(Loading) if (unconfTxList.length === 0) return h(Loading, { isLoading: true })
return ( return (

@ -9,6 +9,7 @@ const numericBalance = require('./util').numericBalance
const addressSummary = require('./util').addressSummary const addressSummary = require('./util').addressSummary
const isHex = require('./util').isHex const isHex = require('./util').isHex
const EthBalance = require('./components/eth-balance') const EthBalance = require('./components/eth-balance')
const EnsInput = require('./components/ens-input')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
module.exports = connect(mapStateToProps)(SendTransactionScreen) module.exports = connect(mapStateToProps)(SendTransactionScreen)
@ -18,6 +19,7 @@ function mapStateToProps (state) {
accounts: state.metamask.accounts, accounts: state.metamask.accounts,
identities: state.metamask.identities, identities: state.metamask.identities,
warning: state.appState.warning, warning: state.appState.warning,
network: state.metamask.network,
} }
result.error = result.warning && result.warning.split('.')[0] result.error = result.warning && result.warning.split('.')[0]
@ -41,6 +43,7 @@ SendTransactionScreen.prototype.render = function () {
var address = state.address var address = state.address
var account = state.account var account = state.account
var identity = state.identity var identity = state.identity
var network = state.network
return ( return (
@ -145,12 +148,11 @@ SendTransactionScreen.prototype.render = function () {
// 'to' field // 'to' field
h('section.flex-row.flex-center', [ h('section.flex-row.flex-center', [
h('input.large-input', { h(EnsInput, {
name: 'address', name: 'address',
placeholder: 'Recipient Address', placeholder: 'Recipient Address',
dataset: { onChange: this.recipientDidChange.bind(this),
persistentFormId: 'recipient-address', network,
},
}), }),
]), ]),
@ -220,8 +222,13 @@ SendTransactionScreen.prototype.back = function () {
this.props.dispatch(actions.backToAccountDetail(address)) this.props.dispatch(actions.backToAccountDetail(address))
} }
SendTransactionScreen.prototype.recipientDidChange = function (recipient) {
this.setState({ recipient })
}
SendTransactionScreen.prototype.onSubmit = function () { SendTransactionScreen.prototype.onSubmit = function () {
const recipient = document.querySelector('input[name="address"]').value const state = this.state || {}
const recipient = state.recipient || document.querySelector('input[name="address"]').value
const input = document.querySelector('input[name="amount"]').value const input = document.querySelector('input[name="amount"]').value
const value = util.normalizeEthStringToWei(input) const value = util.normalizeEthStringToWei(input)
const txData = document.querySelector('input[name="txData"]').value const txData = document.querySelector('input[name="txData"]').value

Loading…
Cancel
Save