diff --git a/.storybook/test-data.js b/.storybook/test-data.js index eabd90864..b2e1691c1 100644 --- a/.storybook/test-data.js +++ b/.storybook/test-data.js @@ -517,8 +517,8 @@ const state = { maxModeOn: false, editingTransactionId: null, toNickname: 'Account 2', - ensResolution: null, - ensResolutionError: '', + domainResolution: null, + domainResolutionError: '', token: { address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D', symbol: 'DAI', diff --git a/ui/ducks/ens.js b/ui/ducks/domains.js similarity index 60% rename from ui/ducks/ens.js rename to ui/ducks/domains.js index 8f0cfb488..c04988ebd 100644 --- a/ui/ducks/ens.js +++ b/ui/ducks/domains.js @@ -30,6 +30,7 @@ import { // Local Constants const ZERO_X_ERROR_ADDRESS = '0x'; +const ENS = 'ENS'; const initialState = { stage: 'UNINITIALIZED', @@ -37,11 +38,13 @@ const initialState = { error: null, warning: null, network: null, + domainType: null, + domainName: null, }; -export const ensInitialState = initialState; +export const domainInitialState = initialState; -const name = 'ENS'; +const name = 'DNS'; let web3Provider = null; @@ -49,51 +52,54 @@ const slice = createSlice({ name, initialState, reducers: { - ensLookup: (state, action) => { + domainLookup: (state, action) => { // first clear out the previous state state.resolution = null; state.error = null; state.warning = null; - const { address, ensName, error, network } = action.payload; - - if (error) { - if ( - isValidDomainName(ensName) && - error.message === 'ENS name not defined.' - ) { - state.error = - network === NETWORK_IDS.MAINNET - ? ENS_NO_ADDRESS_FOR_NAME - : ENS_NOT_FOUND_ON_NETWORK; - } else if (error.message === 'Illegal character for ENS.') { - state.error = ENS_ILLEGAL_CHARACTER; + const { address, error, network, domainType, domainName } = + action.payload; + state.domainType = domainType; + if (state.domainType === ENS) { + if (error) { + if ( + isValidDomainName(domainName) && + error.message === 'ENS name not defined.' + ) { + state.error = + network === NETWORK_IDS.MAINNET + ? ENS_NO_ADDRESS_FOR_NAME + : 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 { - 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 { - state.error = ENS_NO_ADDRESS_FOR_NAME; } }, - enableEnsLookup: (state, action) => { + enableDomainLookup: (state, action) => { state.stage = 'INITIALIZED'; state.error = null; state.resolution = null; state.warning = null; state.network = action.payload; }, - disableEnsLookup: (state) => { + disableDomainLookup: (state) => { state.stage = 'NO_NETWORK_SUPPORT'; state.error = null; state.warning = null; @@ -105,7 +111,7 @@ const slice = createSlice({ state.warning = null; state.error = ENS_NOT_SUPPORTED_ON_NETWORK; }, - resetEnsResolution: (state) => { + resetDomainResolution: (state) => { state.resolution = null; state.warning = null; state.error = null; @@ -125,15 +131,15 @@ const { reducer, actions } = slice; export default reducer; const { - disableEnsLookup, - ensLookup, - enableEnsLookup, + disableDomainLookup, + domainLookup, + enableDomainLookup, ensNotSupported, - resetEnsResolution, + resetDomainResolution, } = actions; -export { resetEnsResolution }; +export { resetDomainResolution }; -export function initializeEnsSlice() { +export function initializeDomainSlice() { return (dispatch, getState) => { const state = getState(); const chainId = getCurrentChainId(state); @@ -150,69 +156,65 @@ export function initializeEnsSlice() { ensAddress, }, ); - dispatch(enableEnsLookup(network)); + dispatch(enableDomainLookup(network)); } else { web3Provider = null; - dispatch(disableEnsLookup()); + dispatch(disableDomainLookup()); } }; } -export function lookupEnsName(ensName) { +export function lookupEnsName(domainName) { return async (dispatch, getState) => { - const trimmedEnsName = ensName.trim(); + const trimmedDomainName = domainName.trim(); let state = getState(); if (state[name].stage === 'UNINITIALIZED') { - await dispatch(initializeEnsSlice()); + await dispatch(initializeDomainSlice()); } state = getState(); if ( state[name].stage === 'NO_NETWORK_SUPPORT' && !( - isBurnAddress(trimmedEnsName) === false && - isValidHexAddress(trimmedEnsName, { mixedCaseUseChecksum: true }) + isBurnAddress(trimmedDomainName) === false && + isValidHexAddress(trimmedDomainName, { mixedCaseUseChecksum: true }) ) && - !isHexString(trimmedEnsName) + !isHexString(trimmedDomainName) ) { await dispatch(ensNotSupported()); } else { - log.info(`ENS attempting to resolve name: ${trimmedEnsName}`); + log.info(`ENS attempting to resolve name: ${trimmedDomainName}`); let address; let error; try { - // the writable property on the 'provider' object on the 'web3Provider' flips to false when stale - // 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); + address = await web3Provider.resolveName(trimmedDomainName); } catch (err) { error = err; } const chainId = getCurrentChainId(state); const network = CHAIN_ID_TO_NETWORK_ID_MAP[chainId]; + await dispatch( - ensLookup({ - ensName: trimmedEnsName, + domainLookup({ address, error, chainId, network, + domainType: ENS, + domainName: trimmedDomainName, }), ); } }; } -export function getEnsResolution(state) { +export function getDomainResolution(state) { return state[name].resolution; } -export function getEnsError(state) { +export function getDomainError(state) { return state[name].error; } -export function getEnsWarning(state) { +export function getDomainWarning(state) { return state[name].warning; } diff --git a/ui/ducks/index.js b/ui/ducks/index.js index 11b525e4c..517c2ec70 100644 --- a/ui/ducks/index.js +++ b/ui/ducks/index.js @@ -3,7 +3,7 @@ import { ALERT_TYPES } from '../../shared/constants/alerts'; import metamaskReducer from './metamask/metamask'; import localeMessagesReducer from './locale/locale'; import sendReducer from './send/send'; -import ensReducer from './ens'; +import domainReducer from './domains'; import appStateReducer from './app/app'; import confirmTransactionReducer from './confirm-transaction/confirm-transaction.duck'; import gasReducer from './gas/gas.duck'; @@ -17,7 +17,7 @@ export default combineReducers({ activeTab: (s) => (s === undefined ? null : s), metamask: metamaskReducer, appState: appStateReducer, - ENS: ensReducer, + DNS: domainReducer, history: historyReducer, send: sendReducer, confirmTransaction: confirmTransactionReducer, diff --git a/ui/ducks/send/send.js b/ui/ducks/send/send.js index f73a95120..9eb05519d 100644 --- a/ui/ducks/send/send.js +++ b/ui/ducks/send/send.js @@ -82,7 +82,7 @@ import { getUnapprovedTxs, } from '../metamask/metamask'; -import { resetEnsResolution } from '../ens'; +import { resetDomainResolution } from '../domains'; import { isBurnAddress, isValidHexAddress, @@ -2199,7 +2199,7 @@ export function resetRecipientInput() { await dispatch(addHistoryEntry(`sendFlow - user cleared recipient input`)); await dispatch(updateRecipientUserInput('')); await dispatch(updateRecipient({ address: '', nickname: '' })); - await dispatch(resetEnsResolution()); + await dispatch(resetDomainResolution()); await dispatch(validateRecipientUserInput({ chainId })); }; } diff --git a/ui/ducks/send/send.test.js b/ui/ducks/send/send.test.js index 539f013c3..f068305ae 100644 --- a/ui/ducks/send/send.test.js +++ b/ui/ducks/send/send.test.js @@ -2108,7 +2108,7 @@ describe('Send Slice', () => { expect(actionResult[8].type).toStrictEqual( 'send/computeEstimatedGasLimit/rejected', ); - expect(actionResult[9].type).toStrictEqual('ENS/resetEnsResolution'); + expect(actionResult[9].type).toStrictEqual('DNS/resetDomainResolution'); expect(actionResult[10].type).toStrictEqual( 'send/validateRecipientUserInput', ); diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.component.js b/ui/pages/send/send-content/add-recipient/add-recipient.component.js index 71f922db5..47ff7c97f 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.component.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.component.js @@ -16,9 +16,9 @@ export default class AddRecipient extends Component { ownedAccounts: PropTypes.array, addressBook: PropTypes.array, updateRecipient: PropTypes.func, - ensResolution: PropTypes.string, - ensError: PropTypes.string, - ensWarning: PropTypes.string, + domainResolution: PropTypes.string, + domainError: PropTypes.string, + domainWarning: PropTypes.string, addressBookEntryName: PropTypes.string, contacts: PropTypes.array, nonContacts: PropTypes.array, @@ -102,7 +102,7 @@ export default class AddRecipient extends Component { render() { const { - ensResolution, + domainResolution, recipient, userInput, addressBookEntryName, @@ -117,9 +117,9 @@ export default class AddRecipient extends Component { recipient.nickname, 'validated user input', ); - } else if (ensResolution && !recipient.error) { + } else if (domainResolution && !recipient.error) { content = this.renderExplicitAddress( - ensResolution, + domainResolution, addressBookEntryName || userInput, 'ENS resolution', ); @@ -233,19 +233,19 @@ export default class AddRecipient extends Component { } renderDialogs() { - const { ensError, recipient, ensWarning } = this.props; + const { domainError, recipient, domainWarning } = this.props; const { t } = this.context; - if (ensError || (recipient.error && recipient.error !== 'required')) { + if (domainError || (recipient.error && recipient.error !== 'required')) { return ( ); - } else if (ensWarning || recipient.warning) { + } else if (domainWarning || recipient.warning) { return ( ); } diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.component.test.js b/ui/pages/send/send-content/add-recipient/add-recipient.component.test.js index 7c58d36fa..7de303274 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.component.test.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.component.test.js @@ -136,7 +136,7 @@ describe('AddRecipient Component', () => { it('should render error when query has no results', () => { wrapper.setProps({ addressBook: [], - ensError: 'bad', + domainError: 'bad', contacts: [], nonContacts: [], }); @@ -151,7 +151,7 @@ describe('AddRecipient Component', () => { it('should render error when query has ens does not resolve', () => { wrapper.setProps({ addressBook: [], - ensError: 'very bad', + domainError: 'very bad', contacts: [], nonContacts: [], }); @@ -166,8 +166,8 @@ describe('AddRecipient Component', () => { it('should render error when ens resolved but ens error exists', () => { wrapper.setProps({ addressBook: [], - ensError: 'bad', - ensResolution: '0x128', + domainError: 'bad', + domainResolution: '0x128', }); const dialog = wrapper.find(Dialog); diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.container.js b/ui/pages/send/send-content/add-recipient/add-recipient.container.js index 4491ef56c..3f4455f78 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.container.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.container.js @@ -16,20 +16,20 @@ import { addHistoryEntry, } from '../../../../ducks/send'; import { - getEnsResolution, - getEnsError, - getEnsWarning, -} from '../../../../ducks/ens'; + getDomainResolution, + getDomainError, + getDomainWarning, +} from '../../../../ducks/domains'; import AddRecipient from './add-recipient.component'; export default connect(mapStateToProps, mapDispatchToProps)(AddRecipient); function mapStateToProps(state) { - const ensResolution = getEnsResolution(state); + const domainResolution = getDomainResolution(state); let addressBookEntryName = ''; - if (ensResolution) { - const addressBookEntry = getAddressBookEntry(state, ensResolution) || {}; + if (domainResolution) { + const addressBookEntry = getAddressBookEntry(state, domainResolution) || {}; addressBookEntryName = addressBookEntry.name; } @@ -41,9 +41,9 @@ function mapStateToProps(state) { addressBook, addressBookEntryName, contacts: addressBook.filter(({ name }) => Boolean(name)), - ensResolution, - ensError: getEnsError(state), - ensWarning: getEnsWarning(state), + domainResolution, + domainError: getDomainError(state), + domainWarning: getDomainWarning(state), nonContacts: addressBook.filter(({ name }) => !name), ownedAccounts, isUsingMyAccountsForRecipientSearch: diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.container.test.js b/ui/pages/send/send-content/add-recipient/add-recipient.container.test.js index a78e51134..9343a2f8a 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.container.test.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.container.test.js @@ -18,10 +18,10 @@ jest.mock('../../../../selectors', () => ({ ], })); -jest.mock('../../../../ducks/ens', () => ({ - getEnsResolution: (s) => `mockSendEnsResolution:${s}`, - getEnsError: (s) => `mockSendEnsResolutionError:${s}`, - getEnsWarning: (s) => `mockSendEnsResolutionWarning:${s}`, +jest.mock('../../../../ducks/domains', () => ({ + getDomainResolution: (s) => `mockSendDomainResolution:${s}`, + getDomainError: (s) => `mockSendDomainResolutionError:${s}`, + getDomainWarning: (s) => `mockSendDomainResolutionWarning:${s}`, useMyAccountsForRecipientSearch: (s) => `useMyAccountsForRecipientSearch:${s}`, })); @@ -49,9 +49,9 @@ describe('add-recipient container', () => { addressBook: [{ name: 'mockAddressBook:mockState' }], addressBookEntryName: undefined, contacts: [{ name: 'mockAddressBook:mockState' }], - ensResolution: 'mockSendEnsResolution:mockState', - ensError: 'mockSendEnsResolutionError:mockState', - ensWarning: 'mockSendEnsResolutionWarning:mockState', + domainResolution: 'mockSendDomainResolution:mockState', + domainError: 'mockSendDomainResolutionError:mockState', + domainWarning: 'mockSendDomainResolutionWarning:mockState', nonContacts: [], ownedAccounts: [ { name: 'account1:mockState' }, diff --git a/ui/pages/send/send-content/add-recipient/add-recipient.stories.js b/ui/pages/send/send-content/add-recipient/add-recipient.stories.js index cc31bacf7..4d2d7cddc 100644 --- a/ui/pages/send/send-content/add-recipient/add-recipient.stories.js +++ b/ui/pages/send/send-content/add-recipient/add-recipient.stories.js @@ -29,13 +29,13 @@ export default { updateRecipient: { action: 'updateRecipient', }, - ensResolution: { + domainResolution: { control: 'text', }, - ensError: { + domainError: { control: 'text', }, - ensWarning: { + domainWarning: { control: 'text', }, addressBookEntryName: { @@ -96,8 +96,8 @@ export const ErrorStory = (args) => { }; ErrorStory.argTypes = { - // ensError must be the key for a translation - ensError: { type: 'text', defaultValue: 'loading' }, + // domainError must be the key for a translation + domainError: { type: 'text', defaultValue: 'loading' }, }; ErrorStory.storyName = 'Error'; @@ -115,8 +115,8 @@ export const WarningStory = (args) => { }; WarningStory.argTypes = { - // ensWarning must be the key for a translation - ensWarning: { type: 'text', defaultValue: 'loading' }, + // domainWarning must be the key for a translation + domainWarning: { type: 'text', defaultValue: 'loading' }, }; WarningStory.storyName = 'Warning'; diff --git a/ui/pages/send/send-content/add-recipient/ens-input.component.js b/ui/pages/send/send-content/add-recipient/domain-input.component.js similarity index 95% rename from ui/pages/send/send-content/add-recipient/ens-input.component.js rename to ui/pages/send/send-content/add-recipient/domain-input.component.js index d220d753e..710ce8126 100644 --- a/ui/pages/send/send-content/add-recipient/ens-input.component.js +++ b/ui/pages/send/send-content/add-recipient/domain-input.component.js @@ -9,7 +9,7 @@ import { isValidHexAddress, } from '../../../../../shared/modules/hexstring-utils'; -export default class EnsInput extends Component { +export default class DomainInput extends Component { static contextTypes = { t: PropTypes.func, metricsEvent: PropTypes.func, @@ -27,12 +27,12 @@ export default class EnsInput extends Component { onChange: PropTypes.func.isRequired, onReset: PropTypes.func.isRequired, lookupEnsName: PropTypes.func.isRequired, - initializeEnsSlice: PropTypes.func.isRequired, - resetEnsResolution: PropTypes.func.isRequired, + initializeDomainSlice: PropTypes.func.isRequired, + resetDomainResolution: PropTypes.func.isRequired, }; componentDidMount() { - this.props.initializeEnsSlice(); + this.props.initializeDomainSlice(); } onPaste = (event) => { @@ -56,7 +56,7 @@ export default class EnsInput extends Component { internalSearch, onChange, lookupEnsName, - resetEnsResolution, + resetDomainResolution, } = this.props; const input = value.trim(); @@ -69,7 +69,7 @@ export default class EnsInput extends Component { if (isValidDomainName(input)) { lookupEnsName(input); } else { - resetEnsResolution(); + resetDomainResolution(); if ( onValidAddressTyped && !isBurnAddress(input) && diff --git a/ui/pages/send/send-content/add-recipient/domain-input.container.js b/ui/pages/send/send-content/add-recipient/domain-input.container.js new file mode 100644 index 000000000..eaa850ecc --- /dev/null +++ b/ui/pages/send/send-content/add-recipient/domain-input.container.js @@ -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); diff --git a/ui/pages/send/send-content/add-recipient/domain-input.js b/ui/pages/send/send-content/add-recipient/domain-input.js new file mode 100644 index 000000000..88f6956fd --- /dev/null +++ b/ui/pages/send/send-content/add-recipient/domain-input.js @@ -0,0 +1 @@ +export { default } from './domain-input.container'; diff --git a/ui/pages/send/send-content/add-recipient/ens-input.container.js b/ui/pages/send/send-content/add-recipient/ens-input.container.js deleted file mode 100644 index bf0650b0e..000000000 --- a/ui/pages/send/send-content/add-recipient/ens-input.container.js +++ /dev/null @@ -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); diff --git a/ui/pages/send/send-content/add-recipient/ens-input.js b/ui/pages/send/send-content/add-recipient/ens-input.js deleted file mode 100644 index 16c5c26ab..000000000 --- a/ui/pages/send/send-content/add-recipient/ens-input.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ens-input.container'; diff --git a/ui/pages/send/send.js b/ui/pages/send/send.js index ad10615a7..a23c29a0f 100644 --- a/ui/pages/send/send.js +++ b/ui/pages/send/send.js @@ -25,7 +25,7 @@ import SendHeader from './send-header'; import AddRecipient from './send-content/add-recipient'; import SendContent from './send-content'; 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) => isCustomPriceExcessive(state, true); @@ -112,7 +112,7 @@ export default function SendTransactionScreen() { return (