From 94573f74d69f910a6638bd419e2aabca0a9957e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Wed, 19 Jan 2022 16:27:18 +0000 Subject: [PATCH 1/7] Add support for main and test networks on Send requests. --- app/components/Views/Send/index.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/app/components/Views/Send/index.js b/app/components/Views/Send/index.js index 7cd3b7157ad..a32c64e9959 100644 --- a/app/components/Views/Send/index.js +++ b/app/components/Views/Send/index.js @@ -29,6 +29,7 @@ import { MAINNET } from '../../../constants/network'; import BigNumber from 'bignumber.js'; import { WalletDevice } from '@metamask/controllers/'; import { getTokenList } from '../../../reducers/tokens'; +import { getNetworkTypeById } from '../../../util/networks'; const REVIEW = 'review'; const EDIT = 'edit'; @@ -352,8 +353,31 @@ class Send extends PureComponent { * @param switchToChainId - Corresponding chain id for new network */ handleNetworkSwitch = (switchToChainId) => { + try { + const networkType = getNetworkTypeById(switchToChainId); + if (networkType) { + const { NetworkController, CurrencyRateController } = Engine.context; + CurrencyRateController.setNativeCurrency('ETH'); + NetworkController.setProviderType(networkType); + this.props.showAlert({ + isVisible: true, + autodismiss: 5000, + content: 'clipboard-alert', + data: { msg: strings('send.warn_network_change') + networkType }, + }); + return; + } + } catch (e) { + /** + * If we can't get the network type we don't need to throw an error, + * since it can still be a RPC network + */ + } + const { frequentRpcList } = this.props; + const rpc = frequentRpcList.find(({ chainId }) => chainId === switchToChainId); + if (rpc) { const { rpcUrl, chainId, ticker, nickname } = rpc; const { NetworkController, CurrencyRateController } = Engine.context; From 2fb1c8854307da5ad428d39041da8d41ec959951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Wed, 19 Jan 2022 16:58:27 +0000 Subject: [PATCH 2/7] Improve comment description --- app/components/Views/Send/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Views/Send/index.js b/app/components/Views/Send/index.js index a32c64e9959..46cb2cafb5e 100644 --- a/app/components/Views/Send/index.js +++ b/app/components/Views/Send/index.js @@ -370,7 +370,7 @@ class Send extends PureComponent { } catch (e) { /** * If we can't get the network type we don't need to throw an error, - * since it can still be a RPC network + * since it can still be a custom RPC network */ } From 468094e8d5f49e3e2fd4656a8dc3667eeb03f752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Fri, 4 Feb 2022 16:02:26 +0000 Subject: [PATCH 3/7] Improve network switch handling on Send requests received. --- app/components/Nav/App/index.js | 14 +++-- app/components/UI/ReceiveRequest/index.js | 2 +- app/components/Views/Send/index.js | 53 ---------------- app/core/DeeplinkManager.js | 76 +++++++++++++++++++---- ios/MetaMask.xcodeproj/project.pbxproj | 2 - locales/languages/en.json | 4 +- 6 files changed, 79 insertions(+), 72 deletions(-) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index fe19be99f27..c3020930eea 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -153,18 +153,24 @@ const App = ({ userLoggedIn }) => { [] ); + const frequentRpcList = useSelector((state) => state.engine.backgroundState.PreferencesController.frequentRpcList); + useEffect(() => { SharedDeeplinkManager.init({ - navigate: (routeName, opts) => { - const params = { name: routeName, params: opts }; - navigator.current?.dispatch?.(CommonActions.navigate(params)); + navigation: { + navigate: (routeName, opts) => { + const params = { name: routeName, params: opts }; + navigator.current?.dispatch?.(CommonActions.navigate(params)); + }, }, + frequentRpcList, + dispatch, }); unsubscribeFromBranch.current = branchSubscriber.subscribe(); return () => unsubscribeFromBranch.current?.(); - }, [branchSubscriber]); + }, [branchSubscriber, frequentRpcList, dispatch]); useEffect(() => { const initAnalytics = async () => { diff --git a/app/components/UI/ReceiveRequest/index.js b/app/components/UI/ReceiveRequest/index.js index 6c5a79addb9..be699eca136 100644 --- a/app/components/UI/ReceiveRequest/index.js +++ b/app/components/UI/ReceiveRequest/index.js @@ -237,7 +237,7 @@ class ReceiveRequest extends PureComponent { }} > diff --git a/app/components/Views/Send/index.js b/app/components/Views/Send/index.js index 46cb2cafb5e..1dc9941bb3b 100644 --- a/app/components/Views/Send/index.js +++ b/app/components/Views/Send/index.js @@ -29,7 +29,6 @@ import { MAINNET } from '../../../constants/network'; import BigNumber from 'bignumber.js'; import { WalletDevice } from '@metamask/controllers/'; import { getTokenList } from '../../../reducers/tokens'; -import { getNetworkTypeById } from '../../../util/networks'; const REVIEW = 'review'; const EDIT = 'edit'; @@ -111,10 +110,6 @@ class Send extends PureComponent { /* dApp transaction modal visible or not */ dappTransactionModalVisible: PropTypes.bool, - /** - * A list of custom RPCs to provide the user - */ - frequentRpcList: PropTypes.array, /** * List of tokens from TokenListController */ @@ -261,9 +256,6 @@ class Send extends PureComponent { parameters = null, }) => { const { addressBook, network, identities, selectedAddress } = this.props; - if (chain_id) { - this.handleNetworkSwitch(chain_id); - } let newTxMeta = {}; switch (action) { @@ -347,51 +339,6 @@ class Send extends PureComponent { this.mounted && this.setState({ ready: true, transactionKey: Date.now() }); }; - /** - * Method in charge of changing network if is needed - * - * @param switchToChainId - Corresponding chain id for new network - */ - handleNetworkSwitch = (switchToChainId) => { - try { - const networkType = getNetworkTypeById(switchToChainId); - if (networkType) { - const { NetworkController, CurrencyRateController } = Engine.context; - CurrencyRateController.setNativeCurrency('ETH'); - NetworkController.setProviderType(networkType); - this.props.showAlert({ - isVisible: true, - autodismiss: 5000, - content: 'clipboard-alert', - data: { msg: strings('send.warn_network_change') + networkType }, - }); - return; - } - } catch (e) { - /** - * If we can't get the network type we don't need to throw an error, - * since it can still be a custom RPC network - */ - } - - const { frequentRpcList } = this.props; - - const rpc = frequentRpcList.find(({ chainId }) => chainId === switchToChainId); - - if (rpc) { - const { rpcUrl, chainId, ticker, nickname } = rpc; - const { NetworkController, CurrencyRateController } = Engine.context; - CurrencyRateController.setNativeCurrency(ticker); - NetworkController.setRpcTarget(rpcUrl, chainId, ticker, nickname); - this.props.showAlert({ - isVisible: true, - autodismiss: 5000, - content: 'clipboard-alert', - data: { msg: strings('send.warn_network_change') + nickname }, - }); - } - }; - /** * Retrieves ERC20 asset information (symbol and decimals) to be used with deeplinks * diff --git a/app/core/DeeplinkManager.js b/app/core/DeeplinkManager.js index a277075f7da..09c923ddcb7 100644 --- a/app/core/DeeplinkManager.js +++ b/app/core/DeeplinkManager.js @@ -11,11 +11,14 @@ import { generateApproveData } from '../util/transactions'; import { strings } from '../../locales/i18n'; import { getNetworkTypeById } from '../util/networks'; import { WalletDevice } from '@metamask/controllers/'; +import { showAlert } from '../actions/alert'; class DeeplinkManager { - constructor(_navigation) { - this.navigation = _navigation; + constructor({ navigation, frequentRpcList, dispatch }) { + this.navigation = navigation; this.pendingDeeplink = null; + this.frequentRpcList = frequentRpcList; + this.dispatch = dispatch; } setDeeplink = (url) => (this.pendingDeeplink = url); @@ -24,6 +27,47 @@ class DeeplinkManager { expireDeeplink = () => (this.pendingDeeplink = null); + /** + * Method in charge of changing network if is needed + * + * @param switchToChainId - Corresponding chain id for new network + */ + handleNetworkSwitch = (switchToChainId) => { + const rpc = this.frequentRpcList.find(({ chainId }) => chainId === switchToChainId); + + if (rpc) { + const { rpcUrl, chainId, ticker, nickname } = rpc; + const { NetworkController, CurrencyRateController } = Engine.context; + CurrencyRateController.setNativeCurrency(ticker); + NetworkController.setRpcTarget(rpcUrl, chainId, ticker, nickname); + this.dispatch( + showAlert({ + isVisible: true, + autodismiss: 5000, + content: 'clipboard-alert', + data: { msg: strings('send.warn_network_change') + nickname }, + }) + ); + return; + } + + const networkType = getNetworkTypeById(switchToChainId); + + if (networkType) { + const { NetworkController, CurrencyRateController } = Engine.context; + CurrencyRateController.setNativeCurrency('ETH'); + NetworkController.setProviderType(networkType); + this.dispatch( + showAlert({ + isVisible: true, + autodismiss: 5000, + content: 'clipboard-alert', + data: { msg: strings('send.warn_network_change') + networkType }, + }) + ); + } + }; + async handleEthereumUrl(url, origin) { let ethUrl = ''; try { @@ -36,13 +80,23 @@ class DeeplinkManager { const functionName = ethUrl.function_name; if (!functionName) { const txMeta = { ...ethUrl, source: url }; - if (ethUrl.parameters?.value) { - this.navigation.navigate('SendView', { - screen: 'Send', - params: { txMeta: { ...txMeta, action: 'send-eth' } }, - }); - } else { - this.navigation.navigate('SendFlowView', { screen: 'SendTo', params: { txMeta } }); + // Validate if network exists before navigating to Send views + try { + this.handleNetworkSwitch(txMeta.chain_id); + + if (ethUrl.parameters?.value) { + this.navigation.navigate('SendView', { + screen: 'Send', + params: { txMeta: { ...txMeta, action: 'send-eth' } }, + }); + } else { + this.navigation.navigate('SendFlowView', { screen: 'SendTo', params: { txMeta } }); + } + } catch (e) { + Alert.alert( + strings('send.network_not_found_title'), + strings('send.network_not_found_description', { chain_id: txMeta.chain_id }) + ); } } else if (functionName === 'transfer') { const txMeta = { ...ethUrl, source: url }; @@ -202,8 +256,8 @@ class DeeplinkManager { let instance = null; const SharedDeeplinkManager = { - init: (navigation) => { - instance = new DeeplinkManager(navigation); + init: ({ navigation, frequentRpcList, dispatch }) => { + instance = new DeeplinkManager({ navigation, frequentRpcList, dispatch }); }, parse: (url, args) => instance.parse(url, args), setDeeplink: (url) => instance.setDeeplink(url), diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index 83c738bfa9a..5ab65590e87 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -961,7 +961,6 @@ COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -1004,7 +1003,6 @@ COPY_PHASE_STRIP = YES; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; - "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; diff --git a/locales/languages/en.json b/locales/languages/en.json index 805c2ac93e9..d7e9fb6f104 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -261,7 +261,9 @@ "warn_network_change": "Network changed to ", "send_to": "Send to", "amount": "Amount", - "confirm": "Confirm" + "confirm": "Confirm", + "network_not_found_title": "Network not found", + "network_not_found_description": "Network with chain id {{chain_id}} not found in your wallet. Please add it first." }, "deposit": { "title": "Deposit" From 33b3411bbb676eeadce942ef002ee3b3d7d7b300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Fri, 4 Feb 2022 16:44:19 +0000 Subject: [PATCH 4/7] Wrap handleEthereumUrl actions with networkSwitch handler --- app/core/DeeplinkManager.js | 74 +++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 40 deletions(-) diff --git a/app/core/DeeplinkManager.js b/app/core/DeeplinkManager.js index 09c923ddcb7..49b9f32d24c 100644 --- a/app/core/DeeplinkManager.js +++ b/app/core/DeeplinkManager.js @@ -77,13 +77,12 @@ class DeeplinkManager { return; } - const functionName = ethUrl.function_name; - if (!functionName) { - const txMeta = { ...ethUrl, source: url }; - // Validate if network exists before navigating to Send views - try { - this.handleNetworkSwitch(txMeta.chain_id); - + try { + // Validate and switch network before performing any other action + this.handleNetworkSwitch(ethUrl.chain_id); + const functionName = ethUrl.function_name; + if (!functionName) { + const txMeta = { ...ethUrl, source: url }; if (ethUrl.parameters?.value) { this.navigation.navigate('SendView', { screen: 'Send', @@ -92,40 +91,35 @@ class DeeplinkManager { } else { this.navigation.navigate('SendFlowView', { screen: 'SendTo', params: { txMeta } }); } - } catch (e) { - Alert.alert( - strings('send.network_not_found_title'), - strings('send.network_not_found_description', { chain_id: txMeta.chain_id }) - ); - } - } else if (functionName === 'transfer') { - const txMeta = { ...ethUrl, source: url }; - this.navigation.navigate('SendView', { - screen: 'Send', - params: { txMeta: { ...txMeta, action: 'send-token' } }, - }); - } else if (functionName === 'approve') { - // add approve transaction - const { - parameters: { address, uint256 }, - target_address, - chain_id, - } = ethUrl; - const { TransactionController, PreferencesController, NetworkController } = Engine.context; - if (chain_id) { - const newNetworkType = getNetworkTypeById(chain_id); - NetworkController.setProviderType(newNetworkType); + } else if (functionName === 'transfer') { + const txMeta = { ...ethUrl, source: url }; + this.navigation.navigate('SendView', { + screen: 'Send', + params: { txMeta: { ...txMeta, action: 'send-token' } }, + }); + } else if (functionName === 'approve') { + // add approve transaction + const { + parameters: { address, uint256 }, + target_address, + } = ethUrl; + const { TransactionController, PreferencesController } = Engine.context; + const txParams = {}; + txParams.to = `${target_address}`; + txParams.from = `${PreferencesController.state.selectedAddress}`; + txParams.value = '0x0'; + const uint256Number = Number(uint256); + if (Number.isNaN(uint256Number)) throw new Error('The parameter uint256 should be a number'); + if (!Number.isInteger(uint256Number)) throw new Error('The parameter uint256 should be an integer'); + const value = uint256Number.toString(16); + txParams.data = generateApproveData({ spender: address, value }); + TransactionController.addTransaction(txParams, origin, WalletDevice.MM_MOBILE); } - const txParams = {}; - txParams.to = `${target_address}`; - txParams.from = `${PreferencesController.state.selectedAddress}`; - txParams.value = '0x0'; - const uint256Number = Number(uint256); - if (Number.isNaN(uint256Number)) throw new Error('The parameter uint256 should be a number'); - if (!Number.isInteger(uint256Number)) throw new Error('The parameter uint256 should be an integer'); - const value = uint256Number.toString(16); - txParams.data = generateApproveData({ spender: address, value }); - TransactionController.addTransaction(txParams, origin, WalletDevice.MM_MOBILE); + } catch (e) { + Alert.alert( + strings('send.network_not_found_title'), + strings('send.network_not_found_description', { chain_id: ethUrl.chain_id }) + ); } } From fb7de440b9cd40ceca615cfac60bc8805d06dc0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Mon, 7 Feb 2022 14:51:42 +0000 Subject: [PATCH 5/7] Add undefined check --- app/components/Nav/App/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index c3020930eea..204dc3854c2 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -118,6 +118,9 @@ const App = ({ userLoggedIn }) => { const dispatch = useDispatch(); const triggerCheckedAuth = () => dispatch(checkedAuth('onboarding')); const triggerSetCurrentRoute = (route) => dispatch(setCurrentRoute(route)); + const frequentRpcList = useSelector( + (state) => state?.engine?.backgroundState?.PreferencesController?.frequentRpcList + ); const handleDeeplink = useCallback(({ error, params, uri }) => { if (error) { @@ -153,8 +156,6 @@ const App = ({ userLoggedIn }) => { [] ); - const frequentRpcList = useSelector((state) => state.engine.backgroundState.PreferencesController.frequentRpcList); - useEffect(() => { SharedDeeplinkManager.init({ navigation: { @@ -168,7 +169,6 @@ const App = ({ userLoggedIn }) => { }); unsubscribeFromBranch.current = branchSubscriber.subscribe(); - return () => unsubscribeFromBranch.current?.(); }, [branchSubscriber, frequentRpcList, dispatch]); From 614f149f17fe5f520dae85eb999e50be44770c38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Tue, 8 Feb 2022 15:56:00 +0000 Subject: [PATCH 6/7] Improved copy --- locales/languages/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/locales/languages/en.json b/locales/languages/en.json index d7e9fb6f104..7e1edaa8bf1 100644 --- a/locales/languages/en.json +++ b/locales/languages/en.json @@ -263,7 +263,7 @@ "amount": "Amount", "confirm": "Confirm", "network_not_found_title": "Network not found", - "network_not_found_description": "Network with chain id {{chain_id}} not found in your wallet. Please add it first." + "network_not_found_description": "Network with chain id {{chain_id}} not found in your wallet. Please add the network first." }, "deposit": { "title": "Deposit" From ffd1a58be54d6000b55bacf917279c4c2d22494f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Fatia?= Date: Tue, 8 Feb 2022 16:42:48 +0000 Subject: [PATCH 7/7] Add check to see if network is the same --- app/core/DeeplinkManager.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/core/DeeplinkManager.js b/app/core/DeeplinkManager.js index 49b9f32d24c..367a3e2ce4e 100644 --- a/app/core/DeeplinkManager.js +++ b/app/core/DeeplinkManager.js @@ -33,11 +33,17 @@ class DeeplinkManager { * @param switchToChainId - Corresponding chain id for new network */ handleNetworkSwitch = (switchToChainId) => { + const { NetworkController, CurrencyRateController } = Engine.context; + + // If current network is the same as the one we want to switch to, do nothing + if (NetworkController?.state?.provider?.chainId === switchToChainId) { + return; + } + const rpc = this.frequentRpcList.find(({ chainId }) => chainId === switchToChainId); if (rpc) { const { rpcUrl, chainId, ticker, nickname } = rpc; - const { NetworkController, CurrencyRateController } = Engine.context; CurrencyRateController.setNativeCurrency(ticker); NetworkController.setRpcTarget(rpcUrl, chainId, ticker, nickname); this.dispatch( @@ -54,7 +60,6 @@ class DeeplinkManager { const networkType = getNetworkTypeById(switchToChainId); if (networkType) { - const { NetworkController, CurrencyRateController } = Engine.context; CurrencyRateController.setNativeCurrency('ETH'); NetworkController.setProviderType(networkType); this.dispatch(