mirror of
https://github.com/status-im/MyCrypto.git
synced 2025-02-10 10:07:00 +00:00
Provide consistency in naming, fix more sagas
This commit is contained in:
parent
7fbe1966de
commit
46cbade177
@ -96,6 +96,13 @@ export function setLatestBlock(payload: string): interfaces.SetLatestBlockAction
|
||||
};
|
||||
}
|
||||
|
||||
export function web3SetNode(payload: interfaces.Web3setNodeAction['payload']) {
|
||||
return {
|
||||
type: TypeKeys.CONFIG_NODE_WEB3_SET,
|
||||
payload
|
||||
};
|
||||
}
|
||||
|
||||
export type TWeb3UnsetNode = typeof web3UnsetNode;
|
||||
export function web3UnsetNode(): interfaces.Web3UnsetNodeAction {
|
||||
return {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { TypeKeys } from './constants';
|
||||
import { CustomNodeConfig } from 'types/node';
|
||||
import { CustomNodeConfig, Web3NodeConfig } from 'types/node';
|
||||
import { CustomNetworkConfig } from 'types/network';
|
||||
|
||||
/*** Toggle Offline ***/
|
||||
@ -22,8 +22,8 @@ export interface ChangeNodeAction {
|
||||
type: TypeKeys.CONFIG_NODE_CHANGE;
|
||||
// FIXME $keyof?
|
||||
payload: {
|
||||
nodeName: string;
|
||||
networkName: string;
|
||||
nodeId: string;
|
||||
networkId: string;
|
||||
};
|
||||
}
|
||||
|
||||
@ -73,11 +73,21 @@ export interface Web3UnsetNodeAction {
|
||||
type: TypeKeys.CONFIG_NODE_WEB3_UNSET;
|
||||
}
|
||||
|
||||
/*** Set Web3 as a Node ***/
|
||||
export interface Web3setNodeAction {
|
||||
type: TypeKeys.CONFIG_NODE_WEB3_SET;
|
||||
payload: { id: 'web3'; config: Web3NodeConfig };
|
||||
}
|
||||
|
||||
export type CustomNetworkAction = AddCustomNetworkAction | RemoveCustomNetworkAction;
|
||||
|
||||
export type CustomNodeAction = AddCustomNodeAction | RemoveCustomNodeAction;
|
||||
|
||||
export type NodeAction = ChangeNodeAction | ChangeNodeIntentAction | Web3UnsetNodeAction;
|
||||
export type NodeAction =
|
||||
| ChangeNodeAction
|
||||
| ChangeNodeIntentAction
|
||||
| Web3UnsetNodeAction
|
||||
| Web3setNodeAction;
|
||||
|
||||
export type MetaAction =
|
||||
| ChangeLanguageAction
|
||||
|
@ -1,14 +1,19 @@
|
||||
export enum TypeKeys {
|
||||
CONFIG_LANGUAGE_CHANGE = 'CONFIG_LANGUAGE_CHANGE',
|
||||
CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE',
|
||||
CONFIG_NODE_CHANGE_INTENT = 'CONFIG_NODE_CHANGE_INTENT',
|
||||
|
||||
CONFIG_TOGGLE_OFFLINE = 'CONFIG_TOGGLE_OFFLINE',
|
||||
CONFIG_TOGGLE_AUTO_GAS_LIMIT = 'CONFIG_TOGGLE_AUTO_GAS_LIMIT',
|
||||
CONFIG_POLL_OFFLINE_STATUS = 'CONFIG_POLL_OFFLINE_STATUS',
|
||||
CONFIG_SET_LATEST_BLOCK = 'CONFIG_SET_LATEST_BLOCK',
|
||||
|
||||
CONFIG_NODE_WEB3_SET = 'CONFIG_NODE_WEB3_SET',
|
||||
CONFIG_NODE_WEB3_UNSET = 'CONFIG_NODE_WEB3_UNSET',
|
||||
CONFIG_NODE_CHANGE = 'CONFIG_NODE_CHANGE',
|
||||
CONFIG_NODE_CHANGE_INTENT = 'CONFIG_NODE_CHANGE_INTENT',
|
||||
|
||||
CONFIG_ADD_CUSTOM_NODE = 'CONFIG_ADD_CUSTOM_NODE',
|
||||
CONFIG_REMOVE_CUSTOM_NODE = 'CONFIG_REMOVE_CUSTOM_NODE',
|
||||
|
||||
CONFIG_ADD_CUSTOM_NETWORK = 'CONFIG_ADD_CUSTOM_NETWORK',
|
||||
CONFIG_REMOVE_CUSTOM_NETWORK = 'CONFIG_REMOVE_CUSTOM_NETWORK',
|
||||
CONFIG_SET_LATEST_BLOCK = 'CONFIG_SET_LATEST_BLOCK',
|
||||
CONFIG_NODE_WEB3_UNSET = 'CONFIG_NODE_WEB3_UNSET'
|
||||
CONFIG_REMOVE_CUSTOM_NETWORK = 'CONFIG_REMOVE_CUSTOM_NETWORK'
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ interface State {
|
||||
url: string;
|
||||
port: string;
|
||||
network: string;
|
||||
customNetworkName: string;
|
||||
customNetworkId: string;
|
||||
customNetworkUnit: string;
|
||||
customNetworkChainId: string;
|
||||
hasAuth: boolean;
|
||||
@ -59,7 +59,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
url: '',
|
||||
port: '',
|
||||
network: Object.keys(this.props.staticNetworks)[0],
|
||||
customNetworkName: '',
|
||||
customNetworkId: '',
|
||||
customNetworkUnit: '',
|
||||
customNetworkChainId: '',
|
||||
hasAuth: false,
|
||||
@ -150,7 +150,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
<label className="is-required">Network Name</label>
|
||||
{this.renderInput(
|
||||
{
|
||||
name: 'customNetworkName',
|
||||
name: 'customNetworkId',
|
||||
placeholder: 'My Custom Network'
|
||||
},
|
||||
invalids
|
||||
@ -265,7 +265,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
username,
|
||||
password,
|
||||
network,
|
||||
customNetworkName,
|
||||
customNetworkId,
|
||||
customNetworkUnit,
|
||||
customNetworkChainId
|
||||
} = this.state;
|
||||
@ -302,8 +302,8 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
|
||||
// If they have a custom network, make sure info is provided
|
||||
if (network === CUSTOM) {
|
||||
if (!customNetworkName) {
|
||||
invalids.customNetworkName = true;
|
||||
if (!customNetworkId) {
|
||||
invalids.customNetworkId = true;
|
||||
}
|
||||
if (!customNetworkUnit) {
|
||||
invalids.customNetworkUnit = true;
|
||||
@ -327,7 +327,7 @@ class CustomNodeModal extends React.Component<Props, State> {
|
||||
|
||||
return {
|
||||
isCustom: true,
|
||||
name: this.state.customNetworkName,
|
||||
name: this.state.customNetworkId,
|
||||
unit: this.state.customNetworkUnit,
|
||||
chainId: this.state.customNetworkChainId ? parseInt(this.state.customNetworkChainId, 10) : 0,
|
||||
dPathFormats
|
||||
|
@ -30,7 +30,7 @@ import {
|
||||
getOffline,
|
||||
isNodeChanging,
|
||||
getLanguageSelection,
|
||||
getNodeName,
|
||||
getNodeId,
|
||||
getNodeConfig,
|
||||
CustomNodeOption,
|
||||
NodeOption,
|
||||
@ -53,7 +53,7 @@ interface StateProps {
|
||||
network: NetworkConfig;
|
||||
languageSelection: AppState['config']['meta']['languageSelection'];
|
||||
node: NodeConfig;
|
||||
nodeSelection: AppState['config']['nodes']['selectedNode']['nodeName'];
|
||||
nodeSelection: AppState['config']['nodes']['selectedNode']['nodeId'];
|
||||
isChangingNode: AppState['config']['nodes']['selectedNode']['pending'];
|
||||
isOffline: AppState['config']['meta']['offline'];
|
||||
nodeOptions: (CustomNodeOption | NodeOption)[];
|
||||
@ -63,7 +63,7 @@ const mapStateToProps = (state: AppState): StateProps => ({
|
||||
isOffline: getOffline(state),
|
||||
isChangingNode: isNodeChanging(state),
|
||||
languageSelection: getLanguageSelection(state),
|
||||
nodeSelection: getNodeName(state),
|
||||
nodeSelection: getNodeId(state),
|
||||
node: getNodeConfig(state),
|
||||
nodeOptions: getNodeOptions(state),
|
||||
network: getNetworkConfig(state)
|
||||
@ -104,23 +104,23 @@ class Header extends Component<Props, State> {
|
||||
const LanguageDropDown = Dropdown as new () => Dropdown<typeof selectedLanguage>;
|
||||
const options = nodeOptions.map(n => {
|
||||
if (n.isCustom) {
|
||||
const { name: { networkName, nodeName }, isCustom, id, ...rest } = n;
|
||||
const { name: { networkId, nodeId }, isCustom, id, ...rest } = n;
|
||||
return {
|
||||
...rest,
|
||||
name: (
|
||||
<span>
|
||||
{networkName} - {nodeName} <small>(custom)</small>
|
||||
{networkId} - {nodeId} <small>(custom)</small>
|
||||
</span>
|
||||
),
|
||||
onRemove: () => this.props.removeCustomNode({ id })
|
||||
};
|
||||
} else {
|
||||
const { name: { networkName, service }, isCustom, ...rest } = n;
|
||||
const { name: { networkId, service }, isCustom, ...rest } = n;
|
||||
return {
|
||||
...rest,
|
||||
name: (
|
||||
<span>
|
||||
{networkName} <small>({service})</small>
|
||||
{networkId} <small>({service})</small>
|
||||
</span>
|
||||
)
|
||||
};
|
||||
|
@ -49,6 +49,7 @@ import {
|
||||
} from 'config';
|
||||
import { unSupportedWalletFormatsOnNetwork } from 'utils/network';
|
||||
import { getNetworkConfig, getOffline } from '../../selectors/config';
|
||||
import { isWeb3NodeAvailable } from 'libs/nodes/web3';
|
||||
|
||||
interface OwnProps {
|
||||
hidden?: boolean;
|
||||
|
@ -53,3 +53,38 @@ export default class Web3Node extends RPCNode {
|
||||
export function isWeb3Node(nodeLib: INode | Web3Node): nodeLib is Web3Node {
|
||||
return nodeLib instanceof Web3Node;
|
||||
}
|
||||
|
||||
export const Web3Service = 'MetaMask / Mist';
|
||||
|
||||
export async function setupWeb3Node() {
|
||||
const { web3 } = window as any;
|
||||
|
||||
if (!web3 || !web3.currentProvider || !web3.currentProvider.sendAsync) {
|
||||
throw new Error(
|
||||
'Web3 not found. Please check that MetaMask is installed, or that MyEtherWallet is open in Mist.'
|
||||
);
|
||||
}
|
||||
|
||||
const lib = new Web3Node();
|
||||
const networkId = await lib.getNetVersion();
|
||||
const accounts = await lib.getAccounts();
|
||||
|
||||
if (!accounts.length) {
|
||||
throw new Error('No accounts found in MetaMask / Mist.');
|
||||
}
|
||||
|
||||
if (networkId === 'loading') {
|
||||
throw new Error('MetaMask / Mist is still loading. Please refresh the page and try again.');
|
||||
}
|
||||
|
||||
return { networkId, lib };
|
||||
}
|
||||
|
||||
export async function isWeb3NodeAvailable(): Promise<boolean> {
|
||||
try {
|
||||
await setupWeb3Node();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Wei, toTokenBase } from 'libs/units';
|
||||
import { addHexPrefix } from 'ethereumjs-util';
|
||||
import BN from 'bn.js';
|
||||
import { StaticNetworkNames } from 'types/network';
|
||||
import { StaticNetworkIds } from 'types/network';
|
||||
|
||||
export function stripHexPrefix(value: string) {
|
||||
return value.replace('0x', '');
|
||||
@ -24,7 +24,7 @@ export function sanitizeHex(hex: string) {
|
||||
return hex !== '' ? `0x${padLeftEven(hexStr)}` : '';
|
||||
}
|
||||
|
||||
export function networkIdToName(networkId: string | number): StaticNetworkNames {
|
||||
export function networkIdToName(networkId: string | number): StaticNetworkIds {
|
||||
switch (networkId.toString()) {
|
||||
case '1':
|
||||
return 'ETH';
|
||||
|
@ -2,15 +2,15 @@ import { NodeAction, TypeKeys, ChangeNodeAction } from 'actions/config';
|
||||
import { INITIAL_STATE as INITIAL_NODE_STATE } from '../nodes/selectedNode'; // could probably consolidate this in the index file of 'nodes' to make it easier to import
|
||||
import { INITIAL_STATE as INITIAL_DEFAULT_NODE_STATE } from '../nodes/staticNodes';
|
||||
import { NonWeb3NodeConfigs } from 'types/node';
|
||||
import { StaticNetworkNames } from 'types/network';
|
||||
import { StaticNetworkIds } from 'types/network';
|
||||
|
||||
const initalNode =
|
||||
INITIAL_DEFAULT_NODE_STATE[INITIAL_NODE_STATE.nodeName as keyof NonWeb3NodeConfigs];
|
||||
INITIAL_DEFAULT_NODE_STATE[INITIAL_NODE_STATE.nodeId as keyof NonWeb3NodeConfigs];
|
||||
|
||||
export type State = string | StaticNetworkNames;
|
||||
export type State = string | StaticNetworkIds;
|
||||
const INITIAL_STATE: State = initalNode.network;
|
||||
|
||||
const handleNodeChange = (_: State, { payload }: ChangeNodeAction) => payload.networkName;
|
||||
const handleNodeChange = (_: State, { payload }: ChangeNodeAction) => payload.networkId;
|
||||
|
||||
export const selectedNetwork = (state: State = INITIAL_STATE, action: NodeAction) => {
|
||||
switch (action.type) {
|
||||
|
@ -10,9 +10,9 @@ import {
|
||||
UBQ_DEFAULT
|
||||
} from 'config/dpaths';
|
||||
import { ConfigAction } from 'actions/config';
|
||||
import { StaticNetworkNames, StaticNetworkConfig, BlockExplorerConfig } from 'types/network';
|
||||
import { StaticNetworkIds, StaticNetworkConfig, BlockExplorerConfig } from 'types/network';
|
||||
|
||||
export type State = { [key in StaticNetworkNames]: StaticNetworkConfig };
|
||||
export type State = { [key in StaticNetworkIds]: StaticNetworkConfig };
|
||||
|
||||
// Must be a website that follows the ethplorer convention of /tx/[hash] and
|
||||
// address/[address] to generate the correct functions.
|
||||
|
@ -2,23 +2,23 @@ import { ChangeNodeAction, ChangeNodeIntentAction, NodeAction, TypeKeys } from '
|
||||
|
||||
interface NodeLoaded {
|
||||
pending: false;
|
||||
nodeName: string;
|
||||
nodeId: string;
|
||||
}
|
||||
|
||||
interface NodeChangePending {
|
||||
pending: true;
|
||||
nodeName: string;
|
||||
nodeId: string;
|
||||
}
|
||||
|
||||
export type State = NodeLoaded | NodeChangePending;
|
||||
|
||||
export const INITIAL_STATE: NodeLoaded = {
|
||||
nodeName: 'eth_mew',
|
||||
nodeId: 'eth_mew',
|
||||
pending: false
|
||||
};
|
||||
|
||||
const changeNode = (_: State, { payload }: ChangeNodeAction): State => ({
|
||||
nodeName: payload.networkName,
|
||||
nodeId: payload.networkId,
|
||||
pending: false
|
||||
});
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { EtherscanNode, InfuraNode, RPCNode } from 'libs/nodes';
|
||||
import { ConfigAction } from 'actions/config';
|
||||
import { Web3NodeConfig, NonWeb3NodeConfigs } from 'types/node';
|
||||
import { ConfigAction, TypeKeys } from 'actions/config';
|
||||
import { NonWeb3NodeConfigs, Web3NodeConfigs } from 'types/node';
|
||||
|
||||
export type State = NonWeb3NodeConfigs & Web3NodeConfig;
|
||||
export type State = NonWeb3NodeConfigs & Web3NodeConfigs;
|
||||
|
||||
export const INITIAL_STATE: State = {
|
||||
eth_mew: {
|
||||
@ -93,6 +93,12 @@ export const INITIAL_STATE: State = {
|
||||
|
||||
export const staticNodes = (state: State = INITIAL_STATE, action: ConfigAction) => {
|
||||
switch (action.type) {
|
||||
case TypeKeys.CONFIG_NODE_WEB3_SET:
|
||||
return { ...state, [action.payload.id]: action.payload.config };
|
||||
case TypeKeys.CONFIG_NODE_WEB3_UNSET:
|
||||
const stateCopy = { ...state };
|
||||
Reflect.deleteProperty(stateCopy, 'web3');
|
||||
return stateCopy;
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
@ -1,58 +0,0 @@
|
||||
import { Web3Node } from 'libs/nodes';
|
||||
import { networkIdToName } from 'libs/values';
|
||||
|
||||
/**
|
||||
* TODO: Put this in a saga that runs on app mount
|
||||
*/
|
||||
interface Web3NodeInfo {
|
||||
networkId: string;
|
||||
lib: Web3Node;
|
||||
}
|
||||
|
||||
export async function setupWeb3Node(): Promise<Web3NodeInfo> {
|
||||
const { web3 } = window as any;
|
||||
|
||||
if (!web3 || !web3.currentProvider || !web3.currentProvider.sendAsync) {
|
||||
throw new Error(
|
||||
'Web3 not found. Please check that MetaMask is installed, or that MyEtherWallet is open in Mist.'
|
||||
);
|
||||
}
|
||||
|
||||
const lib = new Web3Node();
|
||||
const networkId = await lib.getNetVersion();
|
||||
const accounts = await lib.getAccounts();
|
||||
|
||||
if (!accounts.length) {
|
||||
throw new Error('No accounts found in MetaMask / Mist.');
|
||||
}
|
||||
|
||||
if (networkId === 'loading') {
|
||||
throw new Error('MetaMask / Mist is still loading. Please refresh the page and try again.');
|
||||
}
|
||||
|
||||
return { networkId, lib };
|
||||
}
|
||||
|
||||
export async function isWeb3NodeAvailable(): Promise<boolean> {
|
||||
try {
|
||||
await setupWeb3Node();
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const Web3Service = 'MetaMask / Mist';
|
||||
|
||||
export async function initWeb3Node(): Promise<void> {
|
||||
const { networkId, lib } = await setupWeb3Node();
|
||||
const web3 = {
|
||||
network: networkIdToName(networkId),
|
||||
service: Web3Service,
|
||||
lib,
|
||||
estimateGas: false,
|
||||
hidden: true
|
||||
};
|
||||
|
||||
NODES.web3 = web3;
|
||||
}
|
@ -13,19 +13,16 @@ import {
|
||||
} from 'redux-saga/effects';
|
||||
import { makeCustomNetworkId } from 'utils/network';
|
||||
import {
|
||||
getNodeName,
|
||||
getNodeId,
|
||||
getNodeConfig,
|
||||
getCustomNodeConfigs,
|
||||
getCustomNetworkConfigs,
|
||||
getOffline,
|
||||
getNetworkConfig,
|
||||
isStaticNodeName,
|
||||
isStaticNodeId,
|
||||
getCustomNodeFromId,
|
||||
getStaticNodeFromId,
|
||||
getNetworkConfigById,
|
||||
getStaticAltNodeToWeb3
|
||||
getNetworkConfigById
|
||||
} from 'selectors/config';
|
||||
import { AppState } from 'reducers';
|
||||
import { TypeKeys } from 'actions/config/constants';
|
||||
import {
|
||||
toggleOfflineConfig,
|
||||
@ -38,14 +35,9 @@ import {
|
||||
} from 'actions/config';
|
||||
import { showNotification } from 'actions/notifications';
|
||||
import { translateRaw } from 'translations';
|
||||
import { Web3Wallet } from 'libs/wallet';
|
||||
import { TypeKeys as WalletTypeKeys } from 'actions/wallet/constants';
|
||||
import { State as ConfigState } from 'reducers/config';
|
||||
import { StaticNodeConfig, CustomNodeConfig, NodeConfig } from 'types/node';
|
||||
import { CustomNetworkConfig, StaticNetworkConfig } from 'types/network';
|
||||
import { Web3Service } from 'reducers/config/nodes/typings';
|
||||
|
||||
export const getConfig = (state: AppState): ConfigState => state.config;
|
||||
import { Web3Service } from 'libs/nodes/web3';
|
||||
|
||||
let hasCheckedOnline = false;
|
||||
export function* pollOfflineStatus(): SagaIterator {
|
||||
@ -119,13 +111,13 @@ export function* reload(): SagaIterator {
|
||||
export function* handleNodeChangeIntent({
|
||||
payload: nodeIdToSwitchTo
|
||||
}: ChangeNodeIntentAction): SagaIterator {
|
||||
const isStaticNode: boolean = yield select(isStaticNodeName, nodeIdToSwitchTo);
|
||||
const isStaticNode: boolean = yield select(isStaticNodeId, nodeIdToSwitchTo);
|
||||
const currentConfig: NodeConfig = yield select(getNodeConfig);
|
||||
|
||||
function* bailOut(message: string) {
|
||||
const currentNodeName: string = yield select(getNodeName);
|
||||
const currentNodeId: string = yield select(getNodeId);
|
||||
yield put(showNotification('danger', message, 5000));
|
||||
yield put(changeNode({ networkName: currentConfig.network, nodeName: currentNodeName }));
|
||||
yield put(changeNode({ networkId: currentConfig.network, nodeId: currentNodeId }));
|
||||
}
|
||||
|
||||
let nextNodeConfig: CustomNodeConfig | StaticNodeConfig;
|
||||
@ -177,7 +169,7 @@ export function* handleNodeChangeIntent({
|
||||
}
|
||||
|
||||
yield put(setLatestBlock(currentBlock));
|
||||
yield put(changeNode({ networkName: nextNodeConfig.network, nodeName: nodeIdToSwitchTo }));
|
||||
yield put(changeNode({ networkId: nextNodeConfig.network, nodeId: nodeIdToSwitchTo }));
|
||||
|
||||
// TODO - re-enable once DeterministicWallet state is fixed to flush properly.
|
||||
// DeterministicWallet keeps path related state we need to flush before we can stop reloading
|
||||
@ -214,40 +206,10 @@ export function* cleanCustomNetworks(): SagaIterator {
|
||||
}
|
||||
}
|
||||
|
||||
// unset web3 as the selected node if a non-web3 wallet has been selected
|
||||
export function* unsetWeb3NodeOnWalletEvent(action): SagaIterator {
|
||||
const node = yield select(getNodeName);
|
||||
const newWallet = action.payload;
|
||||
const isWeb3Wallet = newWallet instanceof Web3Wallet;
|
||||
|
||||
if (node !== 'web3' || isWeb3Wallet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const altNode = yield select(getStaticAltNodeToWeb3);
|
||||
// switch back to a node with the same network as MetaMask/Mist
|
||||
yield put(changeNodeIntent(altNode));
|
||||
}
|
||||
|
||||
export function* unsetWeb3Node(): SagaIterator {
|
||||
const node = yield select(getNodeName);
|
||||
|
||||
if (node !== 'web3') {
|
||||
return;
|
||||
}
|
||||
|
||||
const altNode = yield select(getStaticAltNodeToWeb3);
|
||||
// switch back to a node with the same network as MetaMask/Mist
|
||||
yield put(changeNodeIntent(altNode));
|
||||
}
|
||||
|
||||
export default function* configSaga(): SagaIterator {
|
||||
yield takeLatest(TypeKeys.CONFIG_POLL_OFFLINE_STATUS, handlePollOfflineStatus);
|
||||
yield takeEvery(TypeKeys.CONFIG_NODE_CHANGE_INTENT, handleNodeChangeIntent);
|
||||
yield takeEvery(TypeKeys.CONFIG_LANGUAGE_CHANGE, reload);
|
||||
yield takeEvery(TypeKeys.CONFIG_ADD_CUSTOM_NODE, switchToNewNode);
|
||||
yield takeEvery(TypeKeys.CONFIG_REMOVE_CUSTOM_NODE, cleanCustomNetworks);
|
||||
yield takeEvery(TypeKeys.CONFIG_NODE_WEB3_UNSET, unsetWeb3Node);
|
||||
yield takeEvery(WalletTypeKeys.WALLET_SET, unsetWeb3NodeOnWalletEvent);
|
||||
yield takeEvery(WalletTypeKeys.WALLET_RESET, unsetWeb3NodeOnWalletEvent);
|
||||
}
|
||||
|
57
common/sagas/web3.ts
Normal file
57
common/sagas/web3.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { networkIdToName } from 'libs/values';
|
||||
import { TypeKeys as WalletTypeKeys } from 'actions/wallet/constants';
|
||||
import { Web3Wallet } from 'libs/wallet';
|
||||
import { SagaIterator } from 'redux-saga';
|
||||
import { select, put, takeEvery, call } from 'redux-saga/effects';
|
||||
import { changeNodeIntent, TypeKeys, web3SetNode } from 'actions/config';
|
||||
import { getNodeId, getStaticAltNodeToWeb3 } from 'selectors/config';
|
||||
import { setupWeb3Node, Web3Service } from 'libs/nodes/web3';
|
||||
import { Web3NodeConfig } from '../../shared/types/node';
|
||||
|
||||
export function* initWeb3Node(): SagaIterator {
|
||||
const { networkId, lib } = yield call(setupWeb3Node);
|
||||
const config: Web3NodeConfig = {
|
||||
isCustom: false,
|
||||
network: networkIdToName(networkId),
|
||||
service: Web3Service,
|
||||
lib,
|
||||
estimateGas: false,
|
||||
hidden: true
|
||||
};
|
||||
|
||||
yield put(web3SetNode({ id: 'web3', config }));
|
||||
}
|
||||
|
||||
// unset web3 as the selected node if a non-web3 wallet has been selected
|
||||
export function* unsetWeb3NodeOnWalletEvent(action): SagaIterator {
|
||||
const node = yield select(getNodeId);
|
||||
const newWallet = action.payload;
|
||||
const isWeb3Wallet = newWallet instanceof Web3Wallet;
|
||||
|
||||
if (node !== 'web3' || isWeb3Wallet) {
|
||||
return;
|
||||
}
|
||||
|
||||
const altNode = yield select(getStaticAltNodeToWeb3);
|
||||
// switch back to a node with the same network as MetaMask/Mist
|
||||
yield put(changeNodeIntent(altNode));
|
||||
}
|
||||
|
||||
export function* unsetWeb3Node(): SagaIterator {
|
||||
const node = yield select(getNodeId);
|
||||
|
||||
if (node !== 'web3') {
|
||||
return;
|
||||
}
|
||||
|
||||
const altNode = yield select(getStaticAltNodeToWeb3);
|
||||
// switch back to a node with the same network as MetaMask/Mist
|
||||
yield put(changeNodeIntent(altNode));
|
||||
}
|
||||
|
||||
export const web3 = [
|
||||
takeEvery(TypeKeys.CONFIG_NODE_WEB3_SET, initWeb3Node),
|
||||
takeEvery(TypeKeys.CONFIG_NODE_WEB3_UNSET, unsetWeb3Node),
|
||||
takeEvery(WalletTypeKeys.WALLET_SET, unsetWeb3NodeOnWalletEvent),
|
||||
takeEvery(WalletTypeKeys.WALLET_RESET, unsetWeb3NodeOnWalletEvent)
|
||||
];
|
@ -3,30 +3,29 @@ import { getConfig } from 'selectors/config';
|
||||
import {
|
||||
CustomNetworkConfig,
|
||||
StaticNetworkConfig,
|
||||
StaticNetworkNames,
|
||||
StaticNetworkIds,
|
||||
NetworkContract
|
||||
} from 'types/network';
|
||||
|
||||
export const getNetworks = (state: AppState) => getConfig(state).networks;
|
||||
|
||||
export const getNetworkConfigById = (state: AppState, networkId: string) =>
|
||||
isStaticNetworkName(state, networkId)
|
||||
isStaticNetworkId(state, networkId)
|
||||
? getStaticNetworkConfigs(state)[networkId]
|
||||
: getCustomNetworkConfigs(state)[networkId];
|
||||
|
||||
export const getStaticNetworkNames = (state: AppState): StaticNetworkNames[] =>
|
||||
Object.keys(getNetworks(state).staticNetworks) as StaticNetworkNames[];
|
||||
export const getStaticNetworkIds = (state: AppState): StaticNetworkIds[] =>
|
||||
Object.keys(getNetworks(state).staticNetworks) as StaticNetworkIds[];
|
||||
|
||||
export const isStaticNetworkName = (
|
||||
export const isStaticNetworkId = (
|
||||
state: AppState,
|
||||
networkName: string
|
||||
): networkName is StaticNetworkNames =>
|
||||
Object.keys(getStaticNetworkConfigs(state)).includes(networkName);
|
||||
networkId: string
|
||||
): networkId is StaticNetworkIds => Object.keys(getStaticNetworkConfigs(state)).includes(networkId);
|
||||
|
||||
export const getStaticNetworkConfig = (state: AppState): StaticNetworkConfig | undefined => {
|
||||
const { staticNetworks, selectedNetwork } = getNetworks(state);
|
||||
|
||||
const defaultNetwork = isStaticNetworkName(state, selectedNetwork)
|
||||
const defaultNetwork = isStaticNetworkId(state, selectedNetwork)
|
||||
? staticNetworks[selectedNetwork]
|
||||
: undefined;
|
||||
return defaultNetwork;
|
||||
|
@ -3,69 +3,64 @@ import {
|
||||
getConfig,
|
||||
getStaticNetworkConfigs,
|
||||
getCustomNetworkConfigs,
|
||||
isStaticNetworkName
|
||||
isStaticNetworkId
|
||||
} from 'selectors/config';
|
||||
import { CustomNodeConfig, StaticNodeConfig, StaticNodeName, Web3NodeConfig } from 'types/node';
|
||||
import { CustomNodeConfig, StaticNodeConfig, StaticNodeId, Web3NodeConfig } from 'types/node';
|
||||
import { INITIAL_STATE as SELECTED_NODE_INITIAL_STATE } from 'reducers/config/nodes/selectedNode';
|
||||
|
||||
export const getNodes = (state: AppState) => getConfig(state).nodes;
|
||||
|
||||
export function isNodeCustom(state: AppState, nodeName: string): CustomNodeConfig | undefined {
|
||||
return getCustomNodeConfigs(state)[nodeName];
|
||||
export function isNodeCustom(state: AppState, nodeId: string): CustomNodeConfig | undefined {
|
||||
return getCustomNodeConfigs(state)[nodeId];
|
||||
}
|
||||
|
||||
export const getCustomNodeFromId = (
|
||||
state: AppState,
|
||||
nodeName: string
|
||||
): CustomNodeConfig | undefined => getCustomNodeConfigs(state)[nodeName];
|
||||
nodeId: string
|
||||
): CustomNodeConfig | undefined => getCustomNodeConfigs(state)[nodeId];
|
||||
|
||||
export const getStaticAltNodeToWeb3 = (state: AppState) => {
|
||||
const { web3, ...configs } = getStaticNodeConfigs(state);
|
||||
if (!web3) {
|
||||
return SELECTED_NODE_INITIAL_STATE.nodeName;
|
||||
return SELECTED_NODE_INITIAL_STATE.nodeId;
|
||||
}
|
||||
const res = Object.entries(configs).find(
|
||||
([_, config]: [StaticNodeName, StaticNodeConfig]) => web3.network === config.network
|
||||
([_, config]: [StaticNodeId, StaticNodeConfig]) => web3.network === config.network
|
||||
);
|
||||
if (res) {
|
||||
return res[0];
|
||||
}
|
||||
return SELECTED_NODE_INITIAL_STATE.nodeName;
|
||||
return SELECTED_NODE_INITIAL_STATE.nodeId;
|
||||
};
|
||||
|
||||
export const getStaticNodeFromId = (state: AppState, nodeName: StaticNodeName) =>
|
||||
getStaticNodeConfigs(state)[nodeName];
|
||||
export const getStaticNodeFromId = (state: AppState, nodeId: StaticNodeId) =>
|
||||
getStaticNodeConfigs(state)[nodeId];
|
||||
|
||||
export const isStaticNodeName = (state: AppState, nodeName: string): nodeName is StaticNodeName =>
|
||||
Object.keys(getStaticNodeConfigs(state)).includes(nodeName);
|
||||
export const isStaticNodeId = (state: AppState, nodeId: string): nodeId is StaticNodeId =>
|
||||
Object.keys(getStaticNodeConfigs(state)).includes(nodeId);
|
||||
|
||||
const getStaticNodeConfigs = (state: AppState) => getNodes(state).staticNodes;
|
||||
|
||||
export const getStaticNodeConfig = (state: AppState): StaticNodeConfig | undefined => {
|
||||
const { staticNodes, selectedNode: { nodeName } } = getNodes(state);
|
||||
const { staticNodes, selectedNode: { nodeId } } = getNodes(state);
|
||||
|
||||
const defaultNetwork = isStaticNodeName(state, nodeName) ? staticNodes[nodeName] : undefined;
|
||||
const defaultNetwork = isStaticNodeId(state, nodeId) ? staticNodes[nodeId] : undefined;
|
||||
return defaultNetwork;
|
||||
};
|
||||
|
||||
export const getWeb3Node = (state: AppState): Web3NodeConfig | null => {
|
||||
const currNode = getStaticNodeConfig(state);
|
||||
const currNodeName = getNodeName(state);
|
||||
if (
|
||||
currNode &&
|
||||
currNodeName &&
|
||||
isStaticNodeName(state, currNodeName) &&
|
||||
currNodeName === 'web3'
|
||||
) {
|
||||
const currNodeId = getNodeId(state);
|
||||
if (currNode && currNodeId && isStaticNodeId(state, currNodeId) && currNodeId === 'web3') {
|
||||
return currNode;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export const getCustomNodeConfig = (state: AppState): CustomNodeConfig | undefined => {
|
||||
const { customNodes, selectedNode: { nodeName } } = getNodes(state);
|
||||
const { customNodes, selectedNode: { nodeId } } = getNodes(state);
|
||||
|
||||
const customNode = customNodes[nodeName];
|
||||
const customNode = customNodes[nodeId];
|
||||
return customNode;
|
||||
};
|
||||
|
||||
@ -81,12 +76,12 @@ export function isNodeChanging(state): boolean {
|
||||
return getNodes(state).selectedNode.pending;
|
||||
}
|
||||
|
||||
export function getNodeName(state: AppState): string {
|
||||
return getNodes(state).selectedNode.nodeName;
|
||||
export function getNodeId(state: AppState): string {
|
||||
return getNodes(state).selectedNode.nodeId;
|
||||
}
|
||||
|
||||
export function getIsWeb3Node(state: AppState): boolean {
|
||||
return getNodeName(state) === 'web3';
|
||||
return getNodeId(state) === 'web3';
|
||||
}
|
||||
|
||||
export function getNodeConfig(state: AppState): StaticNodeConfig | CustomNodeConfig {
|
||||
@ -94,9 +89,7 @@ export function getNodeConfig(state: AppState): StaticNodeConfig | CustomNodeCon
|
||||
|
||||
if (!config) {
|
||||
const { selectedNode } = getNodes(state);
|
||||
throw Error(
|
||||
`No node config found for ${selectedNode.nodeName} in either static or custom nodes`
|
||||
);
|
||||
throw Error(`No node config found for ${selectedNode.nodeId} in either static or custom nodes`);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
@ -112,34 +105,32 @@ export function getNodeLib(state: AppState) {
|
||||
export interface NodeOption {
|
||||
isCustom: false;
|
||||
value: string;
|
||||
name: { networkName?: string; service: string };
|
||||
name: { networkId?: string; service: string };
|
||||
color?: string;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export function getStaticNodeOptions(state: AppState): NodeOption[] {
|
||||
const staticNetworkConfigs = getStaticNetworkConfigs(state);
|
||||
return Object.entries(getStaticNodes(state)).map(
|
||||
([nodeName, node]: [string, StaticNodeConfig]) => {
|
||||
const networkName = node.network;
|
||||
const associatedNetwork = staticNetworkConfigs[networkName];
|
||||
const opt: NodeOption = {
|
||||
isCustom: node.isCustom,
|
||||
value: nodeName,
|
||||
name: { networkName, service: node.service },
|
||||
color: associatedNetwork.color,
|
||||
hidden: node.hidden
|
||||
};
|
||||
return opt;
|
||||
}
|
||||
);
|
||||
return Object.entries(getStaticNodes(state)).map(([nodeId, node]: [string, StaticNodeConfig]) => {
|
||||
const networkId = node.network;
|
||||
const associatedNetwork = staticNetworkConfigs[networkId];
|
||||
const opt: NodeOption = {
|
||||
isCustom: node.isCustom,
|
||||
value: nodeId,
|
||||
name: { networkId, service: node.service },
|
||||
color: associatedNetwork.color,
|
||||
hidden: node.hidden
|
||||
};
|
||||
return opt;
|
||||
});
|
||||
}
|
||||
|
||||
export interface CustomNodeOption {
|
||||
isCustom: true;
|
||||
id: string;
|
||||
value: string;
|
||||
name: { networkName?: string; nodeName: string };
|
||||
name: { networkId?: string; nodeId: string };
|
||||
color?: string;
|
||||
hidden?: boolean;
|
||||
}
|
||||
@ -148,15 +139,15 @@ export function getCustomNodeOptions(state: AppState): CustomNodeOption[] {
|
||||
const staticNetworkConfigs = getStaticNetworkConfigs(state);
|
||||
const customNetworkConfigs = getCustomNetworkConfigs(state);
|
||||
return Object.entries(getCustomNodeConfigs(state)).map(
|
||||
([nodeName, node]: [string, CustomNodeConfig]) => {
|
||||
const networkName = node.network;
|
||||
const associatedNetwork = isStaticNetworkName(state, networkName)
|
||||
? staticNetworkConfigs[networkName]
|
||||
: customNetworkConfigs[networkName];
|
||||
([nodeId, node]: [string, CustomNodeConfig]) => {
|
||||
const networkId = node.network;
|
||||
const associatedNetwork = isStaticNetworkId(state, networkId)
|
||||
? staticNetworkConfigs[networkId]
|
||||
: customNetworkConfigs[networkId];
|
||||
const opt: CustomNodeOption = {
|
||||
isCustom: node.isCustom,
|
||||
value: node.id,
|
||||
name: { networkName, nodeName },
|
||||
name: { networkId, nodeId },
|
||||
color: associatedNetwork.isCustom ? undefined : associatedNetwork.color,
|
||||
hidden: false,
|
||||
id: node.id
|
||||
|
86
common/selectors/config/wallet.ts
Normal file
86
common/selectors/config/wallet.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { InsecureWalletName, SecureWalletName, WalletName, walletNames } from 'config';
|
||||
import { EXTRA_PATHS } from 'config/dpaths';
|
||||
import sortedUniq from 'lodash/sortedUniq';
|
||||
import difference from 'lodash/difference';
|
||||
import {
|
||||
CustomNetworkConfig,
|
||||
StaticNetworkConfig,
|
||||
NetworkConfig,
|
||||
DPathFormats
|
||||
} from 'types/network';
|
||||
import { AppState } from 'reducers';
|
||||
import { getStaticNetworkConfigs, getStaticNetworkConfig } from 'selectors/config';
|
||||
type PathType = keyof DPathFormats;
|
||||
|
||||
type DPathFormat =
|
||||
| SecureWalletName.TREZOR
|
||||
| SecureWalletName.LEDGER_NANO_S
|
||||
| InsecureWalletName.MNEMONIC_PHRASE;
|
||||
|
||||
export function getPaths(state: AppState, pathType: PathType): DPath[] {
|
||||
const paths = Object.values(getStaticNetworkConfigs(state))
|
||||
.reduce(
|
||||
(networkPaths: DPath[], { dPathFormats }) =>
|
||||
dPathFormats ? [...networkPaths, dPathFormats[pathType]] : networkPaths,
|
||||
|
||||
[]
|
||||
)
|
||||
.concat(EXTRA_PATHS);
|
||||
return sortedUniq(paths);
|
||||
}
|
||||
|
||||
export function getSingleDPath(state: AppState, format: DPathFormat): DPath {
|
||||
const network = getStaticNetworkConfig(state);
|
||||
if (!network) {
|
||||
throw Error('No static network config loaded');
|
||||
}
|
||||
const dPathFormats = network.dPathFormats;
|
||||
return dPathFormats[format];
|
||||
}
|
||||
|
||||
export function isNetworkUnit(state: AppState, unit: string) {
|
||||
const currentNetwork = getStaticNetworkConfig(state);
|
||||
//TODO: logic check
|
||||
if (!currentNetwork) {
|
||||
return false;
|
||||
}
|
||||
const networks = getStaticNetworkConfigs(state);
|
||||
const validNetworks = Object.values(networks).filter((n: StaticNetworkConfig) => n.unit === unit);
|
||||
return validNetworks.includes(currentNetwork);
|
||||
}
|
||||
|
||||
export function isWalletFormatSupportedOnNetwork(state: AppState, format: WalletName): boolean {
|
||||
const network = getStaticNetworkConfig(state);
|
||||
|
||||
const CHECK_FORMATS: DPathFormat[] = [
|
||||
SecureWalletName.LEDGER_NANO_S,
|
||||
SecureWalletName.TREZOR,
|
||||
InsecureWalletName.MNEMONIC_PHRASE
|
||||
];
|
||||
|
||||
const isHDFormat = (f: string): f is DPathFormat => CHECK_FORMATS.includes(f as DPathFormat);
|
||||
|
||||
// Ensure DPath's are found
|
||||
if (isHDFormat(format)) {
|
||||
if (!network) {
|
||||
return false;
|
||||
}
|
||||
const dPath = network.dPathFormats && network.dPathFormats[format];
|
||||
return !!dPath;
|
||||
}
|
||||
|
||||
// Ensure Web3 is only enabled on ETH or ETH Testnets (MetaMask does not support other networks)
|
||||
if (format === SecureWalletName.WEB3) {
|
||||
return isNetworkUnit(state, 'ETH');
|
||||
}
|
||||
|
||||
// All other wallet formats are supported
|
||||
return true;
|
||||
}
|
||||
|
||||
export function unSupportedWalletFormatsOnNetwork(state: AppState): WalletName[] {
|
||||
const supportedFormats = walletNames.filter(walletName =>
|
||||
isWalletFormatSupportedOnNetwork(state, walletName)
|
||||
);
|
||||
return difference(walletNames, supportedFormats);
|
||||
}
|
@ -17,8 +17,6 @@ import createSagaMiddleware from 'redux-saga';
|
||||
import { loadStatePropertyOrEmptyObject, saveState } from 'utils/localStorage';
|
||||
import RootReducer from './reducers';
|
||||
import promiseMiddleware from 'redux-promise-middleware';
|
||||
import { getNodeConfigFromId } from 'utils/node';
|
||||
import { getNetworkConfigFromId } from 'utils/network';
|
||||
import { dedupeCustomTokens } from 'utils/tokens';
|
||||
import sagas from './sagas';
|
||||
import { gasPricetoBase } from 'libs/units';
|
||||
@ -62,7 +60,7 @@ const configureStore = () => {
|
||||
|
||||
const savedTransactionState = loadStatePropertyOrEmptyObject<TransactionState>('transaction');
|
||||
const savedConfigState = loadStatePropertyOrEmptyObject<ConfigState>('config');
|
||||
|
||||
/*
|
||||
// If they have a saved node, make sure we assign that too. The node selected
|
||||
// isn't serializable, so we have to assign it here.
|
||||
if (savedConfigState && savedConfigState.nodes.selectedNode.nodeName) {
|
||||
@ -88,7 +86,7 @@ const configureStore = () => {
|
||||
const initialNetwork =
|
||||
(savedConfigState && savedConfigState.network) || configInitialState.network;
|
||||
const customTokens = dedupeCustomTokens(initialNetwork.tokens, savedCustomTokensState);
|
||||
|
||||
*/
|
||||
const persistedInitialState = {
|
||||
config: {
|
||||
...configInitialState,
|
||||
@ -107,7 +105,7 @@ const configureStore = () => {
|
||||
: transactionInitialState.fields.gasPrice
|
||||
}
|
||||
},
|
||||
customTokens,
|
||||
// customTokens,
|
||||
// ONLY LOAD SWAP STATE FROM LOCAL STORAGE IF STEP WAS 3
|
||||
swap: swapState
|
||||
};
|
||||
@ -129,13 +127,14 @@ const configureStore = () => {
|
||||
throttle(() => {
|
||||
const state = store.getState();
|
||||
saveState({
|
||||
/*
|
||||
config: {
|
||||
nodeSelection: state.config.nodeSelection,
|
||||
languageSelection: state.config.languageSelection,
|
||||
customNodes: state.config.customNodes,
|
||||
customNetworks: state.config.customNetworks,
|
||||
setGasLimit: state.config.setGasLimit
|
||||
},
|
||||
},*/
|
||||
transaction: {
|
||||
fields: {
|
||||
gasPrice: state.transaction.fields.gasPrice
|
||||
|
@ -2,104 +2,8 @@ import { InsecureWalletName, SecureWalletName, WalletName, walletNames } from 'c
|
||||
import { EXTRA_PATHS } from 'config/dpaths';
|
||||
import sortedUniq from 'lodash/sortedUniq';
|
||||
import difference from 'lodash/difference';
|
||||
import {
|
||||
CustomNetworkConfig,
|
||||
StaticNetworkConfig,
|
||||
NetworkConfig,
|
||||
DPathFormats
|
||||
} from 'types/network';
|
||||
import { CustomNetworkConfig } from 'types/network';
|
||||
|
||||
export function makeCustomNetworkId(config: CustomNetworkConfig): string {
|
||||
return config.chainId ? `${config.chainId}` : `${config.name}:${config.unit}`;
|
||||
}
|
||||
|
||||
export function makeNetworkConfigFromCustomConfig(
|
||||
config: CustomNetworkConfig
|
||||
): StaticNetworkConfig {
|
||||
// TODO - re-enable this block and classify customConfig after user-inputted dPaths are implemented
|
||||
// -------------------------------------------------
|
||||
// this still provides the type safety we want
|
||||
// as we know config coming in is CustomNetworkConfig
|
||||
// meaning name will be a string
|
||||
// then we cast it as any to keep it as a network key
|
||||
// interface Override extends StaticNetworkConfig {
|
||||
// name: any;
|
||||
// }
|
||||
// -------------------------------------------------
|
||||
|
||||
// TODO - allow for user-inputted dPaths so we don't need to use any below and can use supplied dPaths
|
||||
// In the meantime, networks with an unknown chainId will have HD wallets disabled
|
||||
const customConfig: any = {
|
||||
...config,
|
||||
color: '#000',
|
||||
tokens: [],
|
||||
contracts: []
|
||||
};
|
||||
|
||||
return customConfig;
|
||||
}
|
||||
|
||||
type PathType = keyof DPathFormats;
|
||||
|
||||
type DPathFormat =
|
||||
| SecureWalletName.TREZOR
|
||||
| SecureWalletName.LEDGER_NANO_S
|
||||
| InsecureWalletName.MNEMONIC_PHRASE;
|
||||
|
||||
export function getPaths(pathType: PathType): DPath[] {
|
||||
const networkPaths: DPath[] = [];
|
||||
Object.values(NETWORKS).forEach(networkConfig => {
|
||||
const path = networkConfig.dPathFormats ? networkConfig.dPathFormats[pathType] : [];
|
||||
if (path) {
|
||||
networkPaths.push(path as DPath);
|
||||
}
|
||||
});
|
||||
const paths = networkPaths.concat(EXTRA_PATHS);
|
||||
return sortedUniq(paths);
|
||||
}
|
||||
|
||||
export function getSingleDPath(format: DPathFormat, network: NetworkConfig): DPath {
|
||||
const dPathFormats = network.dPathFormats;
|
||||
return dPathFormats[format];
|
||||
}
|
||||
|
||||
export function isNetworkUnit(network: NetworkConfig, unit: string) {
|
||||
const validNetworks = Object.values(NETWORKS).filter((n: NetworkConfig) => n.unit === unit);
|
||||
return validNetworks.includes(network);
|
||||
}
|
||||
|
||||
export function isWalletFormatSupportedOnNetwork(
|
||||
format: WalletName,
|
||||
network: NetworkConfig
|
||||
): boolean {
|
||||
const CHECK_FORMATS: DPathFormat[] = [
|
||||
SecureWalletName.LEDGER_NANO_S,
|
||||
SecureWalletName.TREZOR,
|
||||
InsecureWalletName.MNEMONIC_PHRASE
|
||||
];
|
||||
|
||||
const isHDFormat = (f: string): f is DPathFormat => CHECK_FORMATS.includes(f as DPathFormat);
|
||||
|
||||
// Ensure DPath's are found
|
||||
if (isHDFormat(format)) {
|
||||
const dPath = network.dPathFormats && network.dPathFormats[format];
|
||||
return !!dPath;
|
||||
}
|
||||
|
||||
// Ensure Web3 is only enabled on ETH or ETH Testnets (MetaMask does not support other networks)
|
||||
if (format === SecureWalletName.WEB3) {
|
||||
return isNetworkUnit(network, 'ETH');
|
||||
}
|
||||
|
||||
// All other wallet formats are supported
|
||||
return true;
|
||||
}
|
||||
|
||||
export function allWalletFormatsSupportedOnNetwork(network: NetworkConfig): WalletName[] {
|
||||
return walletNames.filter(walletName => isWalletFormatSupportedOnNetwork(walletName, network));
|
||||
}
|
||||
|
||||
export function unSupportedWalletFormatsOnNetwork(network: NetworkConfig): WalletName[] {
|
||||
const supportedFormats = allWalletFormatsSupportedOnNetwork(network);
|
||||
return difference(walletNames, supportedFormats);
|
||||
}
|
||||
|
8
shared/types/network.d.ts
vendored
8
shared/types/network.d.ts
vendored
@ -1,6 +1,6 @@
|
||||
import { StaticNetworksState, CustomNetworksState } from 'reducers/config/networks';
|
||||
|
||||
type StaticNetworkNames = 'ETH' | 'Ropsten' | 'Kovan' | 'Rinkeby' | 'ETC' | 'UBQ' | 'EXP';
|
||||
type StaticNetworkIds = 'ETH' | 'Ropsten' | 'Kovan' | 'Rinkeby' | 'ETC' | 'UBQ' | 'EXP';
|
||||
|
||||
interface BlockExplorerConfig {
|
||||
origin: string;
|
||||
@ -16,7 +16,7 @@ interface Token {
|
||||
}
|
||||
|
||||
interface NetworkContract {
|
||||
name: StaticNetworkNames;
|
||||
name: StaticNetworkIds;
|
||||
address?: string;
|
||||
abi: string;
|
||||
}
|
||||
@ -29,7 +29,7 @@ interface DPathFormats {
|
||||
|
||||
interface StaticNetworkConfig {
|
||||
isCustom: false; // used for type guards
|
||||
name: StaticNetworkNames;
|
||||
name: StaticNetworkIds;
|
||||
unit: string;
|
||||
color?: string;
|
||||
blockExplorer?: BlockExplorerConfig;
|
||||
@ -53,4 +53,4 @@ interface CustomNetworkConfig {
|
||||
dPathFormats: DPathFormats | null;
|
||||
}
|
||||
|
||||
type NetworkConfig = StaticNetworksState[StaticNetworkNames] | CustomNetworksState[string];
|
||||
type NetworkConfig = StaticNetworksState[StaticNetworkIds] | CustomNetworksState[string];
|
||||
|
12
shared/types/node.d.ts
vendored
12
shared/types/node.d.ts
vendored
@ -1,5 +1,5 @@
|
||||
import { RPCNode, Web3Node } from 'libs/nodes';
|
||||
import { StaticNetworkNames } from './network';
|
||||
import { StaticNetworkIds } from './network';
|
||||
import { StaticNodesState, CustomNodesState } from 'reducers/config/nodes';
|
||||
import CustomNode from 'libs/nodes/custom';
|
||||
|
||||
@ -20,7 +20,7 @@ interface CustomNodeConfig {
|
||||
|
||||
interface StaticNodeConfig {
|
||||
isCustom: false;
|
||||
network: StaticNetworkNames;
|
||||
network: StaticNetworkIds;
|
||||
lib: RPCNode | Web3Node;
|
||||
service: string;
|
||||
estimateGas?: boolean;
|
||||
@ -31,7 +31,7 @@ interface Web3NodeConfig extends StaticNodeConfig {
|
||||
lib: Web3Node;
|
||||
}
|
||||
|
||||
declare enum StaticNodeName {
|
||||
declare enum StaticNodeId {
|
||||
ETH_MEW = 'eth_mew',
|
||||
ETH_MYCRYPTO = 'eth_mycrypto',
|
||||
ETH_ETHSCAN = 'eth_ethscan',
|
||||
@ -46,10 +46,10 @@ declare enum StaticNodeName {
|
||||
EXP_TECH = 'exp_tech'
|
||||
}
|
||||
|
||||
type NonWeb3NodeConfigs = { [key in StaticNodeName]: StaticNodeConfig };
|
||||
type NonWeb3NodeConfigs = { [key in StaticNodeId]: StaticNodeConfig };
|
||||
|
||||
interface Web3NodeConfig {
|
||||
interface Web3NodeConfigs {
|
||||
web3?: Web3NodeConfig;
|
||||
}
|
||||
|
||||
type NodeConfig = StaticNodesState[StaticNodeName] | CustomNodesState[string];
|
||||
type NodeConfig = StaticNodesState[StaticNodeId] | CustomNodesState[string];
|
||||
|
@ -13,7 +13,7 @@ import {
|
||||
reload
|
||||
} from 'sagas/config';
|
||||
import {
|
||||
getNodeName,
|
||||
getNodeId,
|
||||
getNodeConfig,
|
||||
getOffline,
|
||||
getCustomNodeConfigs,
|
||||
@ -176,7 +176,7 @@ describe('handleNodeChangeIntent*', () => {
|
||||
});
|
||||
|
||||
it('should select getNode', () => {
|
||||
expect(data.gen.next().value).toEqual(select(getNodeName));
|
||||
expect(data.gen.next().value).toEqual(select(getNodeId));
|
||||
});
|
||||
|
||||
it('should select nodeConfig', () => {
|
||||
@ -263,7 +263,7 @@ describe('unsetWeb3Node*', () => {
|
||||
const gen = unsetWeb3Node();
|
||||
|
||||
it('should select getNode', () => {
|
||||
expect(gen.next().value).toEqual(select(getNodeName));
|
||||
expect(gen.next().value).toEqual(select(getNodeId));
|
||||
});
|
||||
|
||||
it('should select getNodeConfig', () => {
|
||||
@ -293,7 +293,7 @@ describe('unsetWeb3NodeOnWalletEvent*', () => {
|
||||
const gen = unsetWeb3NodeOnWalletEvent(fakeAction);
|
||||
|
||||
it('should select getNode', () => {
|
||||
expect(gen.next().value).toEqual(select(getNodeName));
|
||||
expect(gen.next().value).toEqual(select(getNodeId));
|
||||
});
|
||||
|
||||
it('should select getNodeConfig', () => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user