Make ENS named elements domain generic (#16166)

Co-authored-by: Olaf Tomalka <olaf.tomalka@gmail.com>
Co-authored-by: Vincent Shadbolt <vince.shadbolt@gmail.com>
Co-authored-by: Brad Decker <bhdecker84@gmail.com>
Co-authored-by: Brad Decker <git@braddecker.dev>
feature/default_network_editable
Ben Behrman 2 years ago committed by GitHub
parent b675a12dbf
commit 086003555c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      .storybook/test-data.js
  2. 122
      ui/ducks/domains.js
  3. 4
      ui/ducks/index.js
  4. 4
      ui/ducks/send/send.js
  5. 2
      ui/ducks/send/send.test.js
  6. 22
      ui/pages/send/send-content/add-recipient/add-recipient.component.js
  7. 8
      ui/pages/send/send-content/add-recipient/add-recipient.component.test.js
  8. 20
      ui/pages/send/send-content/add-recipient/add-recipient.container.js
  9. 14
      ui/pages/send/send-content/add-recipient/add-recipient.container.test.js
  10. 14
      ui/pages/send/send-content/add-recipient/add-recipient.stories.js
  11. 12
      ui/pages/send/send-content/add-recipient/domain-input.component.js
  12. 24
      ui/pages/send/send-content/add-recipient/domain-input.container.js
  13. 1
      ui/pages/send/send-content/add-recipient/domain-input.js
  14. 18
      ui/pages/send/send-content/add-recipient/ens-input.container.js
  15. 1
      ui/pages/send/send-content/add-recipient/ens-input.js
  16. 4
      ui/pages/send/send.js
  17. 12
      ui/pages/send/send.test.js
  18. 29
      ui/pages/settings/contact-list-tab/add-contact/add-contact.component.js
  19. 14
      ui/pages/settings/contact-list-tab/add-contact/add-contact.container.js

@ -517,8 +517,8 @@ const state = {
maxModeOn: false, maxModeOn: false,
editingTransactionId: null, editingTransactionId: null,
toNickname: 'Account 2', toNickname: 'Account 2',
ensResolution: null, domainResolution: null,
ensResolutionError: '', domainResolutionError: '',
token: { token: {
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D', address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D',
symbol: 'DAI', symbol: 'DAI',

@ -30,6 +30,7 @@ import {
// Local Constants // Local Constants
const ZERO_X_ERROR_ADDRESS = '0x'; const ZERO_X_ERROR_ADDRESS = '0x';
const ENS = 'ENS';
const initialState = { const initialState = {
stage: 'UNINITIALIZED', stage: 'UNINITIALIZED',
@ -37,11 +38,13 @@ const initialState = {
error: null, error: null,
warning: null, warning: null,
network: null, network: null,
domainType: null,
domainName: null,
}; };
export const ensInitialState = initialState; export const domainInitialState = initialState;
const name = 'ENS'; const name = 'DNS';
let web3Provider = null; let web3Provider = null;
@ -49,51 +52,54 @@ const slice = createSlice({
name, name,
initialState, initialState,
reducers: { reducers: {
ensLookup: (state, action) => { domainLookup: (state, action) => {
// first clear out the previous state // first clear out the previous state
state.resolution = null; state.resolution = null;
state.error = null; state.error = null;
state.warning = null; state.warning = null;
const { address, ensName, error, network } = action.payload; const { address, error, network, domainType, domainName } =
action.payload;
if (error) { state.domainType = domainType;
if ( if (state.domainType === ENS) {
isValidDomainName(ensName) && if (error) {
error.message === 'ENS name not defined.' if (
) { isValidDomainName(domainName) &&
state.error = error.message === 'ENS name not defined.'
network === NETWORK_IDS.MAINNET ) {
? ENS_NO_ADDRESS_FOR_NAME state.error =
: ENS_NOT_FOUND_ON_NETWORK; network === NETWORK_IDS.MAINNET
} else if (error.message === 'Illegal character for ENS.') { ? ENS_NO_ADDRESS_FOR_NAME
state.error = ENS_ILLEGAL_CHARACTER; : ENS_NOT_FOUND_ON_NETWORK;
} else if (error.message === 'Illegal character for ENS.') {
state.error = ENS_ILLEGAL_CHARACTER;
} else {
log.error(error);
state.error = ENS_UNKNOWN_ERROR;
}
} else if (address) {
if (address === BURN_ADDRESS) {
state.error = ENS_NO_ADDRESS_FOR_NAME;
} else if (address === ZERO_X_ERROR_ADDRESS) {
state.error = ENS_REGISTRATION_ERROR;
} else {
state.resolution = address;
}
if (isValidDomainName(address) && isConfusing(address)) {
state.warning = CONFUSING_ENS_ERROR;
}
} else { } else {
log.error(error);
state.error = ENS_UNKNOWN_ERROR;
}
} else if (address) {
if (address === BURN_ADDRESS) {
state.error = ENS_NO_ADDRESS_FOR_NAME; state.error = ENS_NO_ADDRESS_FOR_NAME;
} else if (address === ZERO_X_ERROR_ADDRESS) {
state.error = ENS_REGISTRATION_ERROR;
} else {
state.resolution = address;
} }
if (isValidDomainName(address) && isConfusing(address)) {
state.warning = CONFUSING_ENS_ERROR;
}
} else {
state.error = ENS_NO_ADDRESS_FOR_NAME;
} }
}, },
enableEnsLookup: (state, action) => { enableDomainLookup: (state, action) => {
state.stage = 'INITIALIZED'; state.stage = 'INITIALIZED';
state.error = null; state.error = null;
state.resolution = null; state.resolution = null;
state.warning = null; state.warning = null;
state.network = action.payload; state.network = action.payload;
}, },
disableEnsLookup: (state) => { disableDomainLookup: (state) => {
state.stage = 'NO_NETWORK_SUPPORT'; state.stage = 'NO_NETWORK_SUPPORT';
state.error = null; state.error = null;
state.warning = null; state.warning = null;
@ -105,7 +111,7 @@ const slice = createSlice({
state.warning = null; state.warning = null;
state.error = ENS_NOT_SUPPORTED_ON_NETWORK; state.error = ENS_NOT_SUPPORTED_ON_NETWORK;
}, },
resetEnsResolution: (state) => { resetDomainResolution: (state) => {
state.resolution = null; state.resolution = null;
state.warning = null; state.warning = null;
state.error = null; state.error = null;
@ -125,15 +131,15 @@ const { reducer, actions } = slice;
export default reducer; export default reducer;
const { const {
disableEnsLookup, disableDomainLookup,
ensLookup, domainLookup,
enableEnsLookup, enableDomainLookup,
ensNotSupported, ensNotSupported,
resetEnsResolution, resetDomainResolution,
} = actions; } = actions;
export { resetEnsResolution }; export { resetDomainResolution };
export function initializeEnsSlice() { export function initializeDomainSlice() {
return (dispatch, getState) => { return (dispatch, getState) => {
const state = getState(); const state = getState();
const chainId = getCurrentChainId(state); const chainId = getCurrentChainId(state);
@ -150,69 +156,65 @@ export function initializeEnsSlice() {
ensAddress, ensAddress,
}, },
); );
dispatch(enableEnsLookup(network)); dispatch(enableDomainLookup(network));
} else { } else {
web3Provider = null; web3Provider = null;
dispatch(disableEnsLookup()); dispatch(disableDomainLookup());
} }
}; };
} }
export function lookupEnsName(ensName) { export function lookupEnsName(domainName) {
return async (dispatch, getState) => { return async (dispatch, getState) => {
const trimmedEnsName = ensName.trim(); const trimmedDomainName = domainName.trim();
let state = getState(); let state = getState();
if (state[name].stage === 'UNINITIALIZED') { if (state[name].stage === 'UNINITIALIZED') {
await dispatch(initializeEnsSlice()); await dispatch(initializeDomainSlice());
} }
state = getState(); state = getState();
if ( if (
state[name].stage === 'NO_NETWORK_SUPPORT' && state[name].stage === 'NO_NETWORK_SUPPORT' &&
!( !(
isBurnAddress(trimmedEnsName) === false && isBurnAddress(trimmedDomainName) === false &&
isValidHexAddress(trimmedEnsName, { mixedCaseUseChecksum: true }) isValidHexAddress(trimmedDomainName, { mixedCaseUseChecksum: true })
) && ) &&
!isHexString(trimmedEnsName) !isHexString(trimmedDomainName)
) { ) {
await dispatch(ensNotSupported()); await dispatch(ensNotSupported());
} else { } else {
log.info(`ENS attempting to resolve name: ${trimmedEnsName}`); log.info(`ENS attempting to resolve name: ${trimmedDomainName}`);
let address; let address;
let error; let error;
try { try {
// the writable property on the 'provider' object on the 'web3Provider' flips to false when stale address = await web3Provider.resolveName(trimmedDomainName);
// This helps handle the case where the provider is becomes unresponsive if/when, in MV3, the service worker dies after the ENS slice is instantiated
const isProviderActive = web3Provider.provider?.writable;
if (!isProviderActive) {
await dispatch(initializeEnsSlice());
}
address = await web3Provider.resolveName(trimmedEnsName);
} catch (err) { } catch (err) {
error = err; error = err;
} }
const chainId = getCurrentChainId(state); const chainId = getCurrentChainId(state);
const network = CHAIN_ID_TO_NETWORK_ID_MAP[chainId]; const network = CHAIN_ID_TO_NETWORK_ID_MAP[chainId];
await dispatch( await dispatch(
ensLookup({ domainLookup({
ensName: trimmedEnsName,
address, address,
error, error,
chainId, chainId,
network, network,
domainType: ENS,
domainName: trimmedDomainName,
}), }),
); );
} }
}; };
} }
export function getEnsResolution(state) { export function getDomainResolution(state) {
return state[name].resolution; return state[name].resolution;
} }
export function getEnsError(state) { export function getDomainError(state) {
return state[name].error; return state[name].error;
} }
export function getEnsWarning(state) { export function getDomainWarning(state) {
return state[name].warning; return state[name].warning;
} }

@ -3,7 +3,7 @@ import { ALERT_TYPES } from '../../shared/constants/alerts';
import metamaskReducer from './metamask/metamask'; import metamaskReducer from './metamask/metamask';
import localeMessagesReducer from './locale/locale'; import localeMessagesReducer from './locale/locale';
import sendReducer from './send/send'; import sendReducer from './send/send';
import ensReducer from './ens'; import domainReducer from './domains';
import appStateReducer from './app/app'; import appStateReducer from './app/app';
import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck'; import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck';
import gasReducer from './gas/gas.duck'; import gasReducer from './gas/gas.duck';
@ -17,7 +17,7 @@ export default combineReducers({
activeTab: (s) => (s === undefined ? null : s), activeTab: (s) => (s === undefined ? null : s),
metamask: metamaskReducer, metamask: metamaskReducer,
appState: appStateReducer, appState: appStateReducer,
ENS: ensReducer, DNS: domainReducer,
history: historyReducer, history: historyReducer,
send: sendReducer, send: sendReducer,
confirmTransaction: confirmTransactionReducer, confirmTransaction: confirmTransactionReducer,

@ -82,7 +82,7 @@ import {
getUnapprovedTxs, getUnapprovedTxs,
} from '../metamask/metamask'; } from '../metamask/metamask';
import { resetEnsResolution } from '../ens'; import { resetDomainResolution } from '../domains';
import { import {
isBurnAddress, isBurnAddress,
isValidHexAddress, isValidHexAddress,
@ -2199,7 +2199,7 @@ export function resetRecipientInput() {
await dispatch(addHistoryEntry(`sendFlow - user cleared recipient input`)); await dispatch(addHistoryEntry(`sendFlow - user cleared recipient input`));
await dispatch(updateRecipientUserInput('')); await dispatch(updateRecipientUserInput(''));
await dispatch(updateRecipient({ address: '', nickname: '' })); await dispatch(updateRecipient({ address: '', nickname: '' }));
await dispatch(resetEnsResolution()); await dispatch(resetDomainResolution());
await dispatch(validateRecipientUserInput({ chainId })); await dispatch(validateRecipientUserInput({ chainId }));
}; };
} }

@ -2108,7 +2108,7 @@ describe('Send Slice', () => {
expect(actionResult[8].type).toStrictEqual( expect(actionResult[8].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'send/computeEstimatedGasLimit/rejected',
); );
expect(actionResult[9].type).toStrictEqual('ENS/resetEnsResolution'); expect(actionResult[9].type).toStrictEqual('DNS/resetDomainResolution');
expect(actionResult[10].type).toStrictEqual( expect(actionResult[10].type).toStrictEqual(
'send/validateRecipientUserInput', 'send/validateRecipientUserInput',
); );

@ -16,9 +16,9 @@ export default class AddRecipient extends Component {
ownedAccounts: PropTypes.array, ownedAccounts: PropTypes.array,
addressBook: PropTypes.array, addressBook: PropTypes.array,
updateRecipient: PropTypes.func, updateRecipient: PropTypes.func,
ensResolution: PropTypes.string, domainResolution: PropTypes.string,
ensError: PropTypes.string, domainError: PropTypes.string,
ensWarning: PropTypes.string, domainWarning: PropTypes.string,
addressBookEntryName: PropTypes.string, addressBookEntryName: PropTypes.string,
contacts: PropTypes.array, contacts: PropTypes.array,
nonContacts: PropTypes.array, nonContacts: PropTypes.array,
@ -102,7 +102,7 @@ export default class AddRecipient extends Component {
render() { render() {
const { const {
ensResolution, domainResolution,
recipient, recipient,
userInput, userInput,
addressBookEntryName, addressBookEntryName,
@ -117,9 +117,9 @@ export default class AddRecipient extends Component {
recipient.nickname, recipient.nickname,
'validated user input', 'validated user input',
); );
} else if (ensResolution && !recipient.error) { } else if (domainResolution && !recipient.error) {
content = this.renderExplicitAddress( content = this.renderExplicitAddress(
ensResolution, domainResolution,
addressBookEntryName || userInput, addressBookEntryName || userInput,
'ENS resolution', 'ENS resolution',
); );
@ -233,19 +233,19 @@ export default class AddRecipient extends Component {
} }
renderDialogs() { renderDialogs() {
const { ensError, recipient, ensWarning } = this.props; const { domainError, recipient, domainWarning } = this.props;
const { t } = this.context; const { t } = this.context;
if (ensError || (recipient.error && recipient.error !== 'required')) { if (domainError || (recipient.error && recipient.error !== 'required')) {
return ( return (
<Dialog type="error" className="send__error-dialog"> <Dialog type="error" className="send__error-dialog">
{t(ensError ?? recipient.error)} {t(domainError ?? recipient.error)}
</Dialog> </Dialog>
); );
} else if (ensWarning || recipient.warning) { } else if (domainWarning || recipient.warning) {
return ( return (
<Dialog type="warning" className="send__error-dialog"> <Dialog type="warning" className="send__error-dialog">
{t(ensWarning ?? recipient.warning)} {t(domainWarning ?? recipient.warning)}
</Dialog> </Dialog>
); );
} }

@ -136,7 +136,7 @@ describe('AddRecipient Component', () => {
it('should render error when query has no results', () => { it('should render error when query has no results', () => {
wrapper.setProps({ wrapper.setProps({
addressBook: [], addressBook: [],
ensError: 'bad', domainError: 'bad',
contacts: [], contacts: [],
nonContacts: [], nonContacts: [],
}); });
@ -151,7 +151,7 @@ describe('AddRecipient Component', () => {
it('should render error when query has ens does not resolve', () => { it('should render error when query has ens does not resolve', () => {
wrapper.setProps({ wrapper.setProps({
addressBook: [], addressBook: [],
ensError: 'very bad', domainError: 'very bad',
contacts: [], contacts: [],
nonContacts: [], nonContacts: [],
}); });
@ -166,8 +166,8 @@ describe('AddRecipient Component', () => {
it('should render error when ens resolved but ens error exists', () => { it('should render error when ens resolved but ens error exists', () => {
wrapper.setProps({ wrapper.setProps({
addressBook: [], addressBook: [],
ensError: 'bad', domainError: 'bad',
ensResolution: '0x128', domainResolution: '0x128',
}); });
const dialog = wrapper.find(Dialog); const dialog = wrapper.find(Dialog);

@ -16,20 +16,20 @@ import {
addHistoryEntry, addHistoryEntry,
} from '../../../../ducks/send'; } from '../../../../ducks/send';
import { import {
getEnsResolution, getDomainResolution,
getEnsError, getDomainError,
getEnsWarning, getDomainWarning,
} from '../../../../ducks/ens'; } from '../../../../ducks/domains';
import AddRecipient from './add-recipient.component'; import AddRecipient from './add-recipient.component';
export default connect(mapStateToProps, mapDispatchToProps)(AddRecipient); export default connect(mapStateToProps, mapDispatchToProps)(AddRecipient);
function mapStateToProps(state) { function mapStateToProps(state) {
const ensResolution = getEnsResolution(state); const domainResolution = getDomainResolution(state);
let addressBookEntryName = ''; let addressBookEntryName = '';
if (ensResolution) { if (domainResolution) {
const addressBookEntry = getAddressBookEntry(state, ensResolution) || {}; const addressBookEntry = getAddressBookEntry(state, domainResolution) || {};
addressBookEntryName = addressBookEntry.name; addressBookEntryName = addressBookEntry.name;
} }
@ -41,9 +41,9 @@ function mapStateToProps(state) {
addressBook, addressBook,
addressBookEntryName, addressBookEntryName,
contacts: addressBook.filter(({ name }) => Boolean(name)), contacts: addressBook.filter(({ name }) => Boolean(name)),
ensResolution, domainResolution,
ensError: getEnsError(state), domainError: getDomainError(state),
ensWarning: getEnsWarning(state), domainWarning: getDomainWarning(state),
nonContacts: addressBook.filter(({ name }) => !name), nonContacts: addressBook.filter(({ name }) => !name),
ownedAccounts, ownedAccounts,
isUsingMyAccountsForRecipientSearch: isUsingMyAccountsForRecipientSearch:

@ -18,10 +18,10 @@ jest.mock('../../../../selectors', () => ({
], ],
})); }));
jest.mock('../../../../ducks/ens', () => ({ jest.mock('../../../../ducks/domains', () => ({
getEnsResolution: (s) => `mockSendEnsResolution:${s}`, getDomainResolution: (s) => `mockSendDomainResolution:${s}`,
getEnsError: (s) => `mockSendEnsResolutionError:${s}`, getDomainError: (s) => `mockSendDomainResolutionError:${s}`,
getEnsWarning: (s) => `mockSendEnsResolutionWarning:${s}`, getDomainWarning: (s) => `mockSendDomainResolutionWarning:${s}`,
useMyAccountsForRecipientSearch: (s) => useMyAccountsForRecipientSearch: (s) =>
`useMyAccountsForRecipientSearch:${s}`, `useMyAccountsForRecipientSearch:${s}`,
})); }));
@ -49,9 +49,9 @@ describe('add-recipient container', () => {
addressBook: [{ name: 'mockAddressBook:mockState' }], addressBook: [{ name: 'mockAddressBook:mockState' }],
addressBookEntryName: undefined, addressBookEntryName: undefined,
contacts: [{ name: 'mockAddressBook:mockState' }], contacts: [{ name: 'mockAddressBook:mockState' }],
ensResolution: 'mockSendEnsResolution:mockState', domainResolution: 'mockSendDomainResolution:mockState',
ensError: 'mockSendEnsResolutionError:mockState', domainError: 'mockSendDomainResolutionError:mockState',
ensWarning: 'mockSendEnsResolutionWarning:mockState', domainWarning: 'mockSendDomainResolutionWarning:mockState',
nonContacts: [], nonContacts: [],
ownedAccounts: [ ownedAccounts: [
{ name: 'account1:mockState' }, { name: 'account1:mockState' },

@ -29,13 +29,13 @@ export default {
updateRecipient: { updateRecipient: {
action: 'updateRecipient', action: 'updateRecipient',
}, },
ensResolution: { domainResolution: {
control: 'text', control: 'text',
}, },
ensError: { domainError: {
control: 'text', control: 'text',
}, },
ensWarning: { domainWarning: {
control: 'text', control: 'text',
}, },
addressBookEntryName: { addressBookEntryName: {
@ -96,8 +96,8 @@ export const ErrorStory = (args) => {
}; };
ErrorStory.argTypes = { ErrorStory.argTypes = {
// ensError must be the key for a translation // domainError must be the key for a translation
ensError: { type: 'text', defaultValue: 'loading' }, domainError: { type: 'text', defaultValue: 'loading' },
}; };
ErrorStory.storyName = 'Error'; ErrorStory.storyName = 'Error';
@ -115,8 +115,8 @@ export const WarningStory = (args) => {
}; };
WarningStory.argTypes = { WarningStory.argTypes = {
// ensWarning must be the key for a translation // domainWarning must be the key for a translation
ensWarning: { type: 'text', defaultValue: 'loading' }, domainWarning: { type: 'text', defaultValue: 'loading' },
}; };
WarningStory.storyName = 'Warning'; WarningStory.storyName = 'Warning';

@ -9,7 +9,7 @@ import {
isValidHexAddress, isValidHexAddress,
} from '../../../../../shared/modules/hexstring-utils'; } from '../../../../../shared/modules/hexstring-utils';
export default class EnsInput extends Component { export default class DomainInput extends Component {
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
metricsEvent: PropTypes.func, metricsEvent: PropTypes.func,
@ -27,12 +27,12 @@ export default class EnsInput extends Component {
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
onReset: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired,
lookupEnsName: PropTypes.func.isRequired, lookupEnsName: PropTypes.func.isRequired,
initializeEnsSlice: PropTypes.func.isRequired, initializeDomainSlice: PropTypes.func.isRequired,
resetEnsResolution: PropTypes.func.isRequired, resetDomainResolution: PropTypes.func.isRequired,
}; };
componentDidMount() { componentDidMount() {
this.props.initializeEnsSlice(); this.props.initializeDomainSlice();
} }
onPaste = (event) => { onPaste = (event) => {
@ -56,7 +56,7 @@ export default class EnsInput extends Component {
internalSearch, internalSearch,
onChange, onChange,
lookupEnsName, lookupEnsName,
resetEnsResolution, resetDomainResolution,
} = this.props; } = this.props;
const input = value.trim(); const input = value.trim();
@ -69,7 +69,7 @@ export default class EnsInput extends Component {
if (isValidDomainName(input)) { if (isValidDomainName(input)) {
lookupEnsName(input); lookupEnsName(input);
} else { } else {
resetEnsResolution(); resetDomainResolution();
if ( if (
onValidAddressTyped && onValidAddressTyped &&
!isBurnAddress(input) && !isBurnAddress(input) &&

@ -0,0 +1,24 @@
import { debounce } from 'lodash';
import { connect } from 'react-redux';
import {
lookupEnsName,
initializeDomainSlice,
resetDomainResolution,
} from '../../../../ducks/domains';
import DomainInput from './domain-input.component';
function mapDispatchToProps(dispatch) {
return {
lookupEnsName: debounce(
(domainName) => dispatch(lookupEnsName(domainName)),
150,
),
initializeDomainSlice: () => dispatch(initializeDomainSlice()),
resetDomainResolution: debounce(
() => dispatch(resetDomainResolution()),
300,
),
};
}
export default connect(null, mapDispatchToProps)(DomainInput);

@ -0,0 +1 @@
export { default } from './domain-input.container';

@ -1,18 +0,0 @@
import { debounce } from 'lodash';
import { connect } from 'react-redux';
import {
lookupEnsName,
initializeEnsSlice,
resetEnsResolution,
} from '../../../../ducks/ens';
import EnsInput from './ens-input.component';
function mapDispatchToProps(dispatch) {
return {
lookupEnsName: debounce((ensName) => dispatch(lookupEnsName(ensName)), 150),
initializeEnsSlice: () => dispatch(initializeEnsSlice()),
resetEnsResolution: debounce(() => dispatch(resetEnsResolution()), 300),
};
}
export default connect(null, mapDispatchToProps)(EnsInput);

@ -1 +0,0 @@
export { default } from './ens-input.container';

@ -25,7 +25,7 @@ import SendHeader from './send-header';
import AddRecipient from './send-content/add-recipient'; import AddRecipient from './send-content/add-recipient';
import SendContent from './send-content'; import SendContent from './send-content';
import SendFooter from './send-footer'; import SendFooter from './send-footer';
import EnsInput from './send-content/add-recipient/ens-input'; import DomainInput from './send-content/add-recipient/domain-input';
const sendSliceIsCustomPriceExcessive = (state) => const sendSliceIsCustomPriceExcessive = (state) =>
isCustomPriceExcessive(state, true); isCustomPriceExcessive(state, true);
@ -112,7 +112,7 @@ export default function SendTransactionScreen() {
return ( return (
<div className="page-container"> <div className="page-container">
<SendHeader history={history} /> <SendHeader history={history} />
<EnsInput <DomainInput
userInput={userInput} userInput={userInput}
className="send__to-row" className="send__to-row"
onChange={(address) => dispatch(updateRecipientUserInput(address))} onChange={(address) => dispatch(updateRecipientUserInput(address))}

@ -3,7 +3,7 @@ import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk'; import thunk from 'redux-thunk';
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { SEND_STAGES, startNewDraftTransaction } from '../../ducks/send'; import { SEND_STAGES, startNewDraftTransaction } from '../../ducks/send';
import { ensInitialState } from '../../ducks/ens'; import { domainInitialState } from '../../ducks/domains';
import { renderWithProvider } from '../../../test/jest'; import { renderWithProvider } from '../../../test/jest';
import { CHAIN_IDS } from '../../../shared/constants/network'; import { CHAIN_IDS } from '../../../shared/constants/network';
import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas'; import { GAS_ESTIMATE_TYPES } from '../../../shared/constants/gas';
@ -54,7 +54,7 @@ jest.mock('ethers', () => {
}); });
const baseStore = { const baseStore = {
send: INITIAL_SEND_STATE_FOR_EXISTING_DRAFT, send: INITIAL_SEND_STATE_FOR_EXISTING_DRAFT,
ENS: ensInitialState, DNS: domainInitialState,
gas: { gas: {
customData: { limit: null, price: null }, customData: { limit: null, price: null },
}, },
@ -132,7 +132,7 @@ describe('Send Page', () => {
expect(actions).toStrictEqual( expect(actions).toStrictEqual(
expect.arrayContaining([ expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
type: 'ENS/enableEnsLookup', type: 'DNS/enableDomainLookup',
}), }),
]), ]),
); );
@ -146,7 +146,7 @@ describe('Send Page', () => {
expect(actions).toStrictEqual( expect(actions).toStrictEqual(
expect.arrayContaining([ expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
type: 'ENS/enableEnsLookup', type: 'DNS/enableDomainLookup',
}), }),
expect.objectContaining({ expect.objectContaining({
type: 'UI_MODAL_OPEN', type: 'UI_MODAL_OPEN',
@ -165,7 +165,7 @@ describe('Send Page', () => {
expect(getByText('Send to')).toBeTruthy(); expect(getByText('Send to')).toBeTruthy();
}); });
it('should render the EnsInput field', () => { it('should render the DomainInput field', () => {
const store = configureMockStore(middleware)(baseStore); const store = configureMockStore(middleware)(baseStore);
const { getByPlaceholderText } = renderWithProvider(<Send />, store); const { getByPlaceholderText } = renderWithProvider(<Send />, store);
expect( expect(
@ -209,7 +209,7 @@ describe('Send Page', () => {
expect(getByText('Send')).toBeTruthy(); expect(getByText('Send')).toBeTruthy();
}); });
it('should render the EnsInput field', () => { it('should render the DomainInput field', () => {
const store = configureMockStore(middleware)(baseStore); const store = configureMockStore(middleware)(baseStore);
const { getByPlaceholderText } = renderWithProvider(<Send />, store); const { getByPlaceholderText } = renderWithProvider(<Send />, store);
expect( expect(

@ -5,7 +5,7 @@ import Identicon from '../../../../components/ui/identicon';
import TextField from '../../../../components/ui/text-field'; import TextField from '../../../../components/ui/text-field';
import { CONTACT_LIST_ROUTE } from '../../../../helpers/constants/routes'; import { CONTACT_LIST_ROUTE } from '../../../../helpers/constants/routes';
import { isValidDomainName } from '../../../../helpers/utils/util'; import { isValidDomainName } from '../../../../helpers/utils/util';
import EnsInput from '../../../send/send-content/add-recipient/ens-input'; import DomainInput from '../../../send/send-content/add-recipient/domain-input';
import PageContainerFooter from '../../../../components/ui/page-container/page-container-footer'; import PageContainerFooter from '../../../../components/ui/page-container/page-container-footer';
import { import {
isBurnAddress, isBurnAddress,
@ -25,9 +25,9 @@ export default class AddContact extends PureComponent {
qrCodeData: qrCodeData:
PropTypes.object /* eslint-disable-line react/no-unused-prop-types */, PropTypes.object /* eslint-disable-line react/no-unused-prop-types */,
qrCodeDetected: PropTypes.func, qrCodeDetected: PropTypes.func,
ensResolution: PropTypes.string, domainResolution: PropTypes.string,
ensError: PropTypes.string, domainError: PropTypes.string,
resetEnsResolution: PropTypes.func, resetDomainResolution: PropTypes.func,
}; };
state = { state = {
@ -45,10 +45,10 @@ export default class AddContact extends PureComponent {
UNSAFE_componentWillReceiveProps(nextProps) { UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.qrCodeData) { if (nextProps.qrCodeData) {
if (nextProps.qrCodeData.type === 'address') { if (nextProps.qrCodeData.type === 'address') {
const { ensResolution } = this.props; const { domainResolution } = this.props;
const scannedAddress = const scannedAddress =
nextProps.qrCodeData.values.address.toLowerCase(); nextProps.qrCodeData.values.address.toLowerCase();
const currentAddress = ensResolution || this.state.ethAddress; const currentAddress = domainResolution || this.state.ethAddress;
if (currentAddress.toLowerCase() !== scannedAddress) { if (currentAddress.toLowerCase() !== scannedAddress) {
this.setState({ input: scannedAddress }); this.setState({ input: scannedAddress });
this.validate(scannedAddress); this.validate(scannedAddress);
@ -79,7 +79,7 @@ export default class AddContact extends PureComponent {
renderInput() { renderInput() {
return ( return (
<EnsInput <DomainInput
scanQrCode={(_) => { scanQrCode={(_) => {
this.props.scanQrCode(); this.props.scanQrCode();
}} }}
@ -89,7 +89,7 @@ export default class AddContact extends PureComponent {
this.validate(text); this.validate(text);
}} }}
onReset={() => { onReset={() => {
this.props.resetEnsResolution(); this.props.resetDomainResolution();
this.setState({ ethAddress: '', input: '' }); this.setState({ ethAddress: '', input: '' });
}} }}
userInput={this.state.input} userInput={this.state.input}
@ -99,17 +99,18 @@ export default class AddContact extends PureComponent {
render() { render() {
const { t } = this.context; const { t } = this.context;
const { history, addToAddressBook, ensError, ensResolution } = this.props; const { history, addToAddressBook, domainError, domainResolution } =
this.props;
const errorToRender = ensError || this.state.error; const errorToRender = domainError || this.state.error;
return ( return (
<div className="settings-page__content-row address-book__add-contact"> <div className="settings-page__content-row address-book__add-contact">
{ensResolution && ( {domainResolution && (
<div className="address-book__view-contact__group"> <div className="address-book__view-contact__group">
<Identicon address={ensResolution} diameter={60} /> <Identicon address={domainResolution} diameter={60} />
<div className="address-book__view-contact__group__value"> <div className="address-book__view-contact__group__value">
{ensResolution} {domainResolution}
</div> </div>
</div> </div>
)} )}
@ -145,7 +146,7 @@ export default class AddContact extends PureComponent {
disabled={Boolean(this.state.error)} disabled={Boolean(this.state.error)}
onSubmit={async () => { onSubmit={async () => {
await addToAddressBook( await addToAddressBook(
ensResolution || this.state.ethAddress, domainResolution || this.state.ethAddress,
this.state.newName, this.state.newName,
); );
history.push(CONTACT_LIST_ROUTE); history.push(CONTACT_LIST_ROUTE);

@ -8,17 +8,17 @@ import {
} from '../../../../store/actions'; } from '../../../../store/actions';
import { getQrCodeData } from '../../../../ducks/app/app'; import { getQrCodeData } from '../../../../ducks/app/app';
import { import {
getEnsError, getDomainError,
getEnsResolution, getDomainResolution,
resetEnsResolution, resetDomainResolution,
} from '../../../../ducks/ens'; } from '../../../../ducks/domains';
import AddContact from './add-contact.component'; import AddContact from './add-contact.component';
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
qrCodeData: getQrCodeData(state), qrCodeData: getQrCodeData(state),
ensError: getEnsError(state), domainError: getDomainError(state),
ensResolution: getEnsResolution(state), domainResolution: getDomainResolution(state),
}; };
}; };
@ -28,7 +28,7 @@ const mapDispatchToProps = (dispatch) => {
dispatch(addToAddressBook(recipient, nickname)), dispatch(addToAddressBook(recipient, nickname)),
scanQrCode: () => dispatch(showQrScanner()), scanQrCode: () => dispatch(showQrScanner()),
qrCodeDetected: (data) => dispatch(qrCodeDetected(data)), qrCodeDetected: (data) => dispatch(qrCodeDetected(data)),
resetEnsResolution: () => dispatch(resetEnsResolution()), resetDomainResolution: () => dispatch(resetDomainResolution()),
}; };
}; };

Loading…
Cancel
Save