You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
5.9 KiB
221 lines
5.9 KiB
3 years ago
|
import { createSlice } from '@reduxjs/toolkit';
|
||
|
import log from 'loglevel';
|
||
|
import networkMap from 'ethereum-ens-network-map';
|
||
|
import { isConfusing } from 'unicode-confusables';
|
||
|
import { isHexString } from 'ethereumjs-util';
|
||
2 years ago
|
import { ethers } from 'ethers';
|
||
3 years ago
|
|
||
|
import { getCurrentChainId } from '../selectors';
|
||
|
import {
|
||
|
CHAIN_ID_TO_NETWORK_ID_MAP,
|
||
2 years ago
|
NETWORK_IDS,
|
||
2 years ago
|
NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP,
|
||
3 years ago
|
} from '../../shared/constants/network';
|
||
|
import {
|
||
|
CONFUSING_ENS_ERROR,
|
||
|
ENS_ILLEGAL_CHARACTER,
|
||
|
ENS_NOT_FOUND_ON_NETWORK,
|
||
|
ENS_NOT_SUPPORTED_ON_NETWORK,
|
||
|
ENS_NO_ADDRESS_FOR_NAME,
|
||
|
ENS_REGISTRATION_ERROR,
|
||
|
ENS_UNKNOWN_ERROR,
|
||
|
} from '../pages/send/send.constants';
|
||
|
import { isValidDomainName } from '../helpers/utils/util';
|
||
|
import { CHAIN_CHANGED } from '../store/actionConstants';
|
||
|
import {
|
||
|
BURN_ADDRESS,
|
||
|
isBurnAddress,
|
||
|
isValidHexAddress,
|
||
|
} from '../../shared/modules/hexstring-utils';
|
||
|
|
||
|
// Local Constants
|
||
|
const ZERO_X_ERROR_ADDRESS = '0x';
|
||
2 years ago
|
const ENS = 'ENS';
|
||
3 years ago
|
|
||
|
const initialState = {
|
||
|
stage: 'UNINITIALIZED',
|
||
|
resolution: null,
|
||
|
error: null,
|
||
|
warning: null,
|
||
|
network: null,
|
||
2 years ago
|
domainType: null,
|
||
|
domainName: null,
|
||
3 years ago
|
};
|
||
|
|
||
2 years ago
|
export const domainInitialState = initialState;
|
||
3 years ago
|
|
||
2 years ago
|
const name = 'DNS';
|
||
3 years ago
|
|
||
2 years ago
|
let web3Provider = null;
|
||
3 years ago
|
|
||
|
const slice = createSlice({
|
||
|
name,
|
||
|
initialState,
|
||
|
reducers: {
|
||
2 years ago
|
domainLookup: (state, action) => {
|
||
3 years ago
|
// first clear out the previous state
|
||
|
state.resolution = null;
|
||
|
state.error = null;
|
||
|
state.warning = null;
|
||
2 years ago
|
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;
|
||
|
}
|
||
3 years ago
|
} else {
|
||
|
state.error = ENS_NO_ADDRESS_FOR_NAME;
|
||
|
}
|
||
|
}
|
||
|
},
|
||
2 years ago
|
enableDomainLookup: (state, action) => {
|
||
3 years ago
|
state.stage = 'INITIALIZED';
|
||
|
state.error = null;
|
||
|
state.resolution = null;
|
||
|
state.warning = null;
|
||
|
state.network = action.payload;
|
||
|
},
|
||
2 years ago
|
disableDomainLookup: (state) => {
|
||
3 years ago
|
state.stage = 'NO_NETWORK_SUPPORT';
|
||
3 years ago
|
state.error = null;
|
||
3 years ago
|
state.warning = null;
|
||
|
state.resolution = null;
|
||
|
state.network = null;
|
||
|
},
|
||
3 years ago
|
ensNotSupported: (state) => {
|
||
3 years ago
|
state.resolution = null;
|
||
|
state.warning = null;
|
||
3 years ago
|
state.error = ENS_NOT_SUPPORTED_ON_NETWORK;
|
||
|
},
|
||
2 years ago
|
resetDomainResolution: (state) => {
|
||
3 years ago
|
state.resolution = null;
|
||
|
state.warning = null;
|
||
|
state.error = null;
|
||
3 years ago
|
},
|
||
|
},
|
||
|
extraReducers: (builder) => {
|
||
|
builder.addCase(CHAIN_CHANGED, (state, action) => {
|
||
|
if (action.payload !== state.currentChainId) {
|
||
|
state.stage = 'UNINITIALIZED';
|
||
2 years ago
|
web3Provider = null;
|
||
3 years ago
|
}
|
||
|
});
|
||
|
},
|
||
|
});
|
||
|
|
||
|
const { reducer, actions } = slice;
|
||
|
export default reducer;
|
||
|
|
||
|
const {
|
||
2 years ago
|
disableDomainLookup,
|
||
|
domainLookup,
|
||
|
enableDomainLookup,
|
||
3 years ago
|
ensNotSupported,
|
||
2 years ago
|
resetDomainResolution,
|
||
3 years ago
|
} = actions;
|
||
2 years ago
|
export { resetDomainResolution };
|
||
3 years ago
|
|
||
2 years ago
|
export function initializeDomainSlice() {
|
||
3 years ago
|
return (dispatch, getState) => {
|
||
|
const state = getState();
|
||
|
const chainId = getCurrentChainId(state);
|
||
|
const network = CHAIN_ID_TO_NETWORK_ID_MAP[chainId];
|
||
2 years ago
|
const networkName = NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP[network];
|
||
|
const ensAddress = networkMap[network];
|
||
|
const networkIsSupported = Boolean(ensAddress);
|
||
3 years ago
|
if (networkIsSupported) {
|
||
2 years ago
|
web3Provider = new ethers.providers.Web3Provider(
|
||
|
global.ethereumProvider,
|
||
|
{
|
||
|
chainId: parseInt(network, 10),
|
||
|
name: networkName,
|
||
|
ensAddress,
|
||
|
},
|
||
|
);
|
||
2 years ago
|
dispatch(enableDomainLookup(network));
|
||
3 years ago
|
} else {
|
||
2 years ago
|
web3Provider = null;
|
||
2 years ago
|
dispatch(disableDomainLookup());
|
||
3 years ago
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
2 years ago
|
export function lookupEnsName(domainName) {
|
||
3 years ago
|
return async (dispatch, getState) => {
|
||
2 years ago
|
const trimmedDomainName = domainName.trim();
|
||
3 years ago
|
let state = getState();
|
||
|
if (state[name].stage === 'UNINITIALIZED') {
|
||
2 years ago
|
await dispatch(initializeDomainSlice());
|
||
3 years ago
|
}
|
||
|
state = getState();
|
||
|
if (
|
||
|
state[name].stage === 'NO_NETWORK_SUPPORT' &&
|
||
|
!(
|
||
2 years ago
|
isBurnAddress(trimmedDomainName) === false &&
|
||
|
isValidHexAddress(trimmedDomainName, { mixedCaseUseChecksum: true })
|
||
3 years ago
|
) &&
|
||
2 years ago
|
!isHexString(trimmedDomainName)
|
||
3 years ago
|
) {
|
||
3 years ago
|
await dispatch(ensNotSupported());
|
||
3 years ago
|
} else {
|
||
2 years ago
|
log.info(`ENS attempting to resolve name: ${trimmedDomainName}`);
|
||
3 years ago
|
let address;
|
||
|
let error;
|
||
|
try {
|
||
2 years ago
|
address = await web3Provider.resolveName(trimmedDomainName);
|
||
3 years ago
|
} catch (err) {
|
||
|
error = err;
|
||
|
}
|
||
|
const chainId = getCurrentChainId(state);
|
||
|
const network = CHAIN_ID_TO_NETWORK_ID_MAP[chainId];
|
||
2 years ago
|
|
||
3 years ago
|
await dispatch(
|
||
2 years ago
|
domainLookup({
|
||
3 years ago
|
address,
|
||
|
error,
|
||
|
chainId,
|
||
|
network,
|
||
2 years ago
|
domainType: ENS,
|
||
|
domainName: trimmedDomainName,
|
||
3 years ago
|
}),
|
||
|
);
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
2 years ago
|
export function getDomainResolution(state) {
|
||
3 years ago
|
return state[name].resolution;
|
||
|
}
|
||
|
|
||
2 years ago
|
export function getDomainError(state) {
|
||
3 years ago
|
return state[name].error;
|
||
|
}
|
||
|
|
||
2 years ago
|
export function getDomainWarning(state) {
|
||
3 years ago
|
return state[name].warning;
|
||
|
}
|