import React, { Component } from 'react' import PropTypes from 'prop-types' import c from 'classnames' import { isValidENSAddress, isValidAddress, isValidAddressHead } 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, onPaste: PropTypes.func, onReset: PropTypes.func, onValidAddressTyped: PropTypes.func, contact: PropTypes.object, } state = { input: '', toError: null, ensResolution: undefined, } 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, onValidAddressTyped } = 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 (!networkHasEnsSupport && !isValidAddress(input) && !isValidAddressHead(input)) { updateEnsResolution('') updateEnsResolutionError(!networkHasEnsSupport ? 'Network does not support ENS' : '') return } if (isValidENSAddress(input)) { this.lookupEnsName(input) } else if (onValidAddressTyped && isValidAddress(input)) { onValidAddressTyped(input) } else { updateEnsResolution('') updateEnsResolutionError('') } } render () { const { t } = this.context const { className, selectedAddress } = this.props const { input } = this.state if (selectedAddress) { return this.renderSelected() } return (