aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Serrano <kevgagser@gmail.com>2017-03-09 08:54:15 +0800
committerGitHub <noreply@github.com>2017-03-09 08:54:15 +0800
commite602cb13c5266516aadeb1c6908575d43afe4164 (patch)
tree5868d5c05fdba7503d6c1acfab2de78e975700fb
parent1fbe4a801a05523cbdf97f7d8491affb49ed9bc6 (diff)
parentea59125ce1219d49fbfa517c0608a4ab2ffb863a (diff)
downloadtangerine-wallet-browser-e602cb13c5266516aadeb1c6908575d43afe4164.tar.gz
tangerine-wallet-browser-e602cb13c5266516aadeb1c6908575d43afe4164.tar.zst
tangerine-wallet-browser-e602cb13c5266516aadeb1c6908575d43afe4164.zip
Merge pull request #1197 from MetaMask/i1130-ResolveENS
Allow ENS Names in Send Form
-rw-r--r--CHANGELOG.md2
-rw-r--r--development/states/send.json89
-rw-r--r--package.json1
-rw-r--r--ui/app/components/ens-input.js145
-rw-r--r--ui/app/conf-tx.js2
-rw-r--r--ui/app/send.js17
6 files changed, 223 insertions, 33 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c0ba9b0b0..0f070d9a9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
## Current Master
+- Allow sending to ENS names in send form on Ropsten.
+
## 3.4.0 2017-3-8
- Add two most recently used custom RPCs to network dropdown menu.
diff --git a/development/states/send.json b/development/states/send.json
index c054af55b..3f52185af 100644
--- a/development/states/send.json
+++ b/development/states/send.json
@@ -2,73 +2,108 @@
"metamask": {
"isInitialized": true,
"isUnlocked": true,
- "currentDomain": "example.com",
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
- "name": "Wallet 1",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
- "mayBeFauceting": false
+ "name": "Account 1"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
- "name": "Wallet 2",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
- "mayBeFauceting": false
+ "name": "Account 2"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
- "name": "Wallet 3",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
- "mayBeFauceting": false
+ "name": "Account 3"
+ },
+ "0xd85a4b6a394794842887b8284293d69163007bbb": {
+ "address": "0xd85a4b6a394794842887b8284293d69163007bbb",
+ "name": "Account 4"
}
},
- "unconfTxs": {},
+ "unapprovedTxs": {},
"currentFiat": "USD",
- "conversionRate": 11.21283484,
- "conversionDate": 1472158984,
+ "conversionRate": 16.88200327,
+ "conversionDate": 1489013762,
+ "noActiveNotices": true,
+ "frequentRpcList": [],
+ "network": "3",
"accounts": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"code": "0x",
- "balance": "0x34693f54a1e25900",
- "nonce": "0x100013",
+ "balance": "0x47c9d71831c76efe",
+ "nonce": "0x1b",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"code": "0x",
- "nonce": "0x100000",
- "balance": "0x18af912cee770000",
+ "balance": "0x37452b1315889f80",
+ "nonce": "0xa",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"code": "0x",
- "nonce": "0x100000",
- "balance": "0x2386f26fc10000",
+ "balance": "0x0",
+ "nonce": "0x0",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
+ },
+ "0xd85a4b6a394794842887b8284293d69163007bbb": {
+ "code": "0x",
+ "balance": "0x0",
+ "nonce": "0x0",
+ "address": "0xd85a4b6a394794842887b8284293d69163007bbb"
}
},
- "transactions": [],
- "network": "2",
- "seedWords": null,
- "unconfMsgs": {},
- "messages": [],
- "shapeShiftTxList": [],
+ "transactions": {},
+ "selectedAddressTxList": [],
+ "unapprovedMsgs": {},
+ "unapprovedMsgCount": 0,
+ "unapprovedPersonalMsgs": {},
+ "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": {
"type": "testnet"
},
- "selectedAddress": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
+ "shapeShiftTxList": [],
+ "lostAccounts": []
},
"appState": {
"menuOpen": false,
"currentView": {
- "name": "sendTransaction"
+ "name": "sendTransaction",
+ "context": "0xd85a4b6a394794842887b8284293d69163007bbb"
},
"accountDetail": {
- "subview": "transactions"
+ "subview": "transactions",
+ "accountExport": "none",
+ "privateKey": ""
},
- "currentDomain": "127.0.0.1:9966",
"transForward": true,
"isLoading": false,
"warning": null,
- "detailView": {}
+ "scrollToBottom": false,
+ "forgottenPassword": null
},
"identities": {}
}
diff --git a/package.json b/package.json
index 475cdb2b3..96d58fa1b 100644
--- a/package.json
+++ b/package.json
@@ -60,6 +60,7 @@
"ethereumjs-tx": "^1.0.0",
"ethereumjs-util": "ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"ethereumjs-wallet": "^0.6.0",
+ "ethjs-ens": "^1.0.2",
"express": "^4.14.0",
"extension-link-enabler": "^1.0.0",
"extensionizer": "^1.0.0",
diff --git a/ui/app/components/ens-input.js b/ui/app/components/ens-input.js
new file mode 100644
index 000000000..ffc4eab4a
--- /dev/null
+++ b/ui/app/components/ens-input.js
@@ -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)
+ },
+ })
+ }
+}
diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js
index 7e93ea29f..07985094c 100644
--- a/ui/app/conf-tx.js
+++ b/ui/app/conf-tx.js
@@ -49,7 +49,7 @@ ConfirmTxScreen.prototype.render = function () {
var isNotification = isPopupOrNotification() === 'notification'
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 (
diff --git a/ui/app/send.js b/ui/app/send.js
index 581e3afa0..a281a5fcf 100644
--- a/ui/app/send.js
+++ b/ui/app/send.js
@@ -9,6 +9,7 @@ const numericBalance = require('./util').numericBalance
const addressSummary = require('./util').addressSummary
const isHex = require('./util').isHex
const EthBalance = require('./components/eth-balance')
+const EnsInput = require('./components/ens-input')
const ethUtil = require('ethereumjs-util')
module.exports = connect(mapStateToProps)(SendTransactionScreen)
@@ -18,6 +19,7 @@ function mapStateToProps (state) {
accounts: state.metamask.accounts,
identities: state.metamask.identities,
warning: state.appState.warning,
+ network: state.metamask.network,
}
result.error = result.warning && result.warning.split('.')[0]
@@ -41,6 +43,7 @@ SendTransactionScreen.prototype.render = function () {
var address = state.address
var account = state.account
var identity = state.identity
+ var network = state.network
return (
@@ -145,12 +148,11 @@ SendTransactionScreen.prototype.render = function () {
// 'to' field
h('section.flex-row.flex-center', [
- h('input.large-input', {
+ h(EnsInput, {
name: 'address',
placeholder: 'Recipient Address',
- dataset: {
- persistentFormId: 'recipient-address',
- },
+ onChange: this.recipientDidChange.bind(this),
+ network,
}),
]),
@@ -220,8 +222,13 @@ SendTransactionScreen.prototype.back = function () {
this.props.dispatch(actions.backToAccountDetail(address))
}
+SendTransactionScreen.prototype.recipientDidChange = function (recipient) {
+ this.setState({ recipient })
+}
+
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 value = util.normalizeEthStringToWei(input)
const txData = document.querySelector('input[name="txData"]').value