import React, { Component } from 'react' import PropTypes from 'prop-types' import c from 'classnames' import { isValidENSAddress, isValidAddress } from '../../../../helpers/utils/util' import {ellipsify} from '../../send.utils' import debounce from 'debounce' import copyToClipboard from 'copy-to-clipboard/index' import ENS from 'ethjs-ens' import networkMap from 'ethjs-ens/lib/network-map.json' import log from 'loglevel' // Local Constants const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000' const ZERO_X_ERROR_ADDRESS = '0x' export default class EnsInput extends Component { static contextTypes = { t: PropTypes.func, } static propTypes = { className: PropTypes.string, network: PropTypes.string, selectedAddress: PropTypes.string, selectedName: PropTypes.string, onChange: PropTypes.func, updateSendTo: PropTypes.func, updateEnsResolution: PropTypes.func, scanQrCode: PropTypes.func, updateEnsResolutionError: PropTypes.func, addressBook: PropTypes.array, onPaste: PropTypes.func, onReset: PropTypes.func, } state = { recipient: null, input: '', toError: null, toWarning: null, } componentDidMount () { const network = this.props.network const networkHasEnsSupport = getNetworkEnsSupport(network) this.setState({ ensResolution: ZERO_ADDRESS }) if (networkHasEnsSupport) { const provider = global.ethereumProvider this.ens = new ENS({ provider, network }) this.checkName = debounce(this.lookupEnsName, 200) } } // If an address is sent without a nickname, meaning not from ENS or from // the user's own accounts, a default of a one-space string is used. componentDidUpdate (prevProps) { const { input, } = this.state const { network, } = this.props if (prevProps.network !== network) { const provider = global.ethereumProvider this.ens = new ENS({ provider, network }) this.onChange({ target: { value: input } }) } } resetInput = () => { const { updateEnsResolution, updateEnsResolutionError, onReset } = this.props this.onChange({ target: { value: '' } }) onReset() updateEnsResolution('') updateEnsResolutionError('') } lookupEnsName = (recipient) => { recipient = recipient.trim() log.info(`ENS attempting to resolve name: ${recipient}`) this.ens.lookup(recipient) .then((address) => { if (address === ZERO_ADDRESS) throw new Error(this.context.t('noAddressForName')) if (address === ZERO_X_ERROR_ADDRESS) throw new Error(this.context.t('ensRegistrationError')) this.props.updateEnsResolution(address) }) .catch((reason) => { if (isValidENSAddress(recipient) && reason.message === 'ENS name not defined.') { this.props.updateEnsResolutionError(this.context.t('ensNotFoundOnCurrentNetwork')) } else { log.error(reason) this.props.updateEnsResolutionError(reason.message) } }) } onPaste = event => { event.clipboardData.items[0].getAsString(text => { if (isValidAddress(text)) { this.props.onPaste(text) } }) } onChange = e => { const { network, onChange, updateEnsResolution, updateEnsResolutionError } = this.props const input = e.target.value const networkHasEnsSupport = getNetworkEnsSupport(network) this.setState({ input }, () => onChange(input)) // Empty ENS state if input is empty // maybe scan ENS if (!input || isValidAddress(input) || !networkHasEnsSupport) { updateEnsResolution('') updateEnsResolutionError(!networkHasEnsSupport ? 'Network does not support ENS' : '') return } if (isValidENSAddress(input)) { this.lookupEnsName(input) } else { updateEnsResolution('') updateEnsResolutionError('') } } render () { const { t } = this.context const { className, selectedAddress } = this.props const { input } = this.state if (selectedAddress) { return this.renderSelected() } return (
{ if (input) { this.resetInput() } else { this.props.scanQrCode() } }} />
) } renderSelected () { const { t } = this.context const { className, selectedAddress, selectedName, addressBook } = this.props const contact = addressBook.filter(item => item.address === selectedAddress)[0] || {} const name = contact.name || selectedName return (
{name || ellipsify(selectedAddress)}
{ name &&
{selectedAddress}
}
) } ensIcon (recipient) { const { hoverText } = this.state return ( { this.ensIconContents(recipient) } ) } ensIconContents () { const { loadingEns, ensFailure, ensResolution, toError } = this.state || { ensResolution: ZERO_ADDRESS } if (toError) return if (loadingEns) { return ( ) } if (ensFailure) { return } if (ensResolution && (ensResolution !== ZERO_ADDRESS)) { return ( { event.preventDefault() event.stopPropagation() copyToClipboard(ensResolution) }} /> ) } } } function getNetworkEnsSupport (network) { return Boolean(networkMap[network]) }