import React, { Component } from 'react' import PropTypes from 'prop-types' import classnames from 'classnames' import { debounce } from 'lodash' import copyToClipboard from 'copy-to-clipboard/index' import ENS from 'ethjs-ens' import networkMap from 'ethereum-ens-network-map' import log from 'loglevel' import { ellipsify } from '../../send.utils' import { isValidDomainName, isValidAddress, isValidAddressHead, } from '../../../../helpers/utils/util' import { MAINNET_NETWORK_ID } from '../../../../../../shared/constants/network' // 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, updateEnsResolution: PropTypes.func, scanQrCode: PropTypes.func, updateEnsResolutionError: PropTypes.func, onPaste: PropTypes.func, onReset: PropTypes.func, onValidAddressTyped: PropTypes.func, contact: PropTypes.object, value: PropTypes.string, internalSearch: PropTypes.bool, } state = { input: '', toError: null, ensResolution: undefined, } componentDidMount() { const { network, internalSearch } = this.props const networkHasEnsSupport = getNetworkEnsSupport(network) this.setState({ ensResolution: ZERO_ADDRESS }) if (networkHasEnsSupport && !internalSearch) { const provider = global.ethereumProvider this.ens = new ENS({ provider, network }) this.checkName = debounce(this.lookupEnsName, 200) } } componentDidUpdate(prevProps) { const { input } = this.state const { network, value, internalSearch } = this.props let newValue // Set the value of our input based on QR code provided by parent const newProvidedValue = input !== value && prevProps.value !== value if (newProvidedValue) { newValue = value } if (prevProps.network !== network) { const provider = global.ethereumProvider this.ens = new ENS({ provider, network }) if (!newProvidedValue) { newValue = input } } if (newValue !== undefined) { this.onChange({ target: { value: newValue } }) } if (!internalSearch && prevProps.internalSearch) { this.resetInput() } } resetInput = () => { const { updateEnsResolution, updateEnsResolutionError, onReset, } = this.props this.onChange({ target: { value: '' } }) onReset() updateEnsResolution('') updateEnsResolutionError('') } lookupEnsName = (ensName) => { const { network } = this.props const recipient = ensName.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 ( isValidDomainName(recipient) && reason.message === 'ENS name not defined.' ) { this.props.updateEnsResolutionError( network === MAINNET_NETWORK_ID ? this.context.t('noAddressForName') : 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, internalSearch, } = this.props const input = e.target.value const networkHasEnsSupport = getNetworkEnsSupport(network) this.setState({ input }, () => onChange(input)) if (internalSearch) { return null } // 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 null } if (isValidDomainName(input)) { this.lookupEnsName(input) } else if (onValidAddressTyped && isValidAddress(input)) { onValidAddressTyped(input) } else { updateEnsResolution('') updateEnsResolutionError('') } return null } render() { const { t } = this.context const { className, selectedAddress } = this.props const { input } = this.state if (selectedAddress) { return this.renderSelected() } return (