diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js
index 02bcf916939e..af9f410cd985 100644
--- a/app/scripts/controllers/app-state.js
+++ b/app/scripts/controllers/app-state.js
@@ -53,6 +53,7 @@ export default class AppStateController extends EventEmitter {
showAccountBanner: true,
trezorModel: null,
currentPopupId: undefined,
+ currentExtensionPopupId: undefined,
// This key is only used for checking if the user had set advancedGasFee
// prior to Migration 92.3 where we split out the setting to support
// multiple networks.
@@ -523,6 +524,10 @@ export default class AppStateController extends EventEmitter {
});
}
+ setCurrentExtensionPopupId(currentExtensionPopupId) {
+ this.store.updateState({ currentExtensionPopupId });
+ }
+
/**
* A getter to retrieve currentPopupId saved in the appState
*/
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 84c20573479e..d47b49ba7d90 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -3105,6 +3105,8 @@ export default class MetamaskController extends EventEmitter {
// AppStateController
setLastActiveTime:
appStateController.setLastActiveTime.bind(appStateController),
+ setCurrentExtensionPopupId:
+ appStateController.setCurrentExtensionPopupId.bind(appStateController),
setDefaultHomeActiveTabName:
appStateController.setDefaultHomeActiveTabName.bind(appStateController),
setConnectedStatusPopoverHasBeenShown:
diff --git a/ui/index.js b/ui/index.js
index e1c01714ceab..99ba9980b9aa 100644
--- a/ui/index.js
+++ b/ui/index.js
@@ -23,6 +23,7 @@ import {
getSelectedInternalAccount,
getUnapprovedTransactions,
getAutomaticSwitchNetwork,
+ getUseRequestQueue,
} from './selectors';
import { ALERT_STATE } from './ducks/alerts';
import {
@@ -211,6 +212,18 @@ async function startApp(metamaskState, backgroundConnection, opts) {
},
};
+ // Register this window as the current popup
+ // and set in background state
+ if (
+ process.env.MULTICHAIN &&
+ getUseRequestQueue(state) &&
+ getEnvironmentType() === ENVIRONMENT_TYPE_POPUP
+ ) {
+ const thisPopupId = Date.now();
+ global.metamask.id = thisPopupId;
+ actions.setCurrentExtensionPopupId(thisPopupId);
+ }
+
// start app
render(, opts.container);
diff --git a/ui/pages/routes/routes.component.js b/ui/pages/routes/routes.component.js
index 6b9137b15d4d..7d3c51350fd1 100644
--- a/ui/pages/routes/routes.component.js
+++ b/ui/pages/routes/routes.component.js
@@ -198,6 +198,8 @@ export default class Routes extends Component {
neverShowSwitchedNetworkMessage: PropTypes.bool.isRequired,
autoSwitchNetwork: PropTypes.func.isRequired,
unapprovedTransactions: PropTypes.number.isRequired,
+ currentExtensionPopupId: PropTypes.number,
+ useRequestQueue: PropTypes.bool,
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
isShowKeyringSnapRemovalResultModal: PropTypes.bool.isRequired,
hideShowKeyringSnapRemovalResultModal: PropTypes.func.isRequired,
@@ -254,9 +256,12 @@ export default class Routes extends Component {
networkToAutomaticallySwitchTo,
activeTabOrigin,
unapprovedTransactions,
+ useRequestQueue,
+ currentExtensionPopupId,
allNetworks,
isUnlocked,
} = this.props;
+
if (theme !== prevProps.theme) {
this.setTheme();
}
@@ -283,6 +288,18 @@ export default class Routes extends Component {
);
}
}
+
+ // Terminate the popup when another popup is opened
+ // if the user is using RPC queueing
+ if (
+ useRequestQueue &&
+ process.env.MULTICHAIN &&
+ currentExtensionPopupId !== undefined &&
+ global.metamask.id !== undefined &&
+ currentExtensionPopupId !== global.metamask.id
+ ) {
+ window.close();
+ }
}
UNSAFE_componentWillMount() {
diff --git a/ui/pages/routes/routes.container.js b/ui/pages/routes/routes.container.js
index 225b9e57a22f..2c3862b10a04 100644
--- a/ui/pages/routes/routes.container.js
+++ b/ui/pages/routes/routes.container.js
@@ -23,6 +23,7 @@ import {
getNeverShowSwitchedNetworkMessage,
getAutomaticSwitchNetwork,
getNumberOfAllUnapprovedTransactions,
+ getUseRequestQueue,
} from '../../selectors';
import {
lockMetamask,
@@ -114,6 +115,9 @@ function mapStateToProps(state) {
unapprovedTransactions: getNumberOfAllUnapprovedTransactions(state),
allNetworks: getAllNetworks(state),
neverShowSwitchedNetworkMessage: getNeverShowSwitchedNetworkMessage(state),
+ currentExtensionPopupId: state.metamask.currentExtensionPopupId,
+ useRequestQueue: getUseRequestQueue(state),
+
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
isShowKeyringSnapRemovalResultModal:
state.appState.showKeyringRemovalSnapModal,
diff --git a/ui/store/actions.ts b/ui/store/actions.ts
index c0d0799ad161..2fa356a68d99 100644
--- a/ui/store/actions.ts
+++ b/ui/store/actions.ts
@@ -4950,6 +4950,16 @@ export function updateInterfaceState(
}) as any;
}
+/**
+ * Update the currentPopupid generated when the user opened the popup
+ *
+ * @param id - The Snap interface ID.
+ * @returns Promise Resolved on successfully submitted background request.
+ */
+export async function setCurrentExtensionPopupId(id: number) {
+ await submitRequestToBackground('setCurrentExtensionPopupId', [id]);
+}
+
/**
* Delete the Snap interface from state.
*