|
|
@ -11,7 +11,7 @@ import Eth from 'ethjs'; |
|
|
|
import EthQuery from 'eth-query'; |
|
|
|
import EthQuery from 'eth-query'; |
|
|
|
import StreamProvider from 'web3-stream-provider'; |
|
|
|
import StreamProvider from 'web3-stream-provider'; |
|
|
|
import log from 'loglevel'; |
|
|
|
import log from 'loglevel'; |
|
|
|
import launchMetaMaskUi from '../../ui'; |
|
|
|
import launchMetaMaskUi, { updateBackgroundConnection } from '../../ui'; |
|
|
|
import { |
|
|
|
import { |
|
|
|
ENVIRONMENT_TYPE_FULLSCREEN, |
|
|
|
ENVIRONMENT_TYPE_FULLSCREEN, |
|
|
|
ENVIRONMENT_TYPE_POPUP, |
|
|
|
ENVIRONMENT_TYPE_POPUP, |
|
|
@ -24,34 +24,37 @@ import { setupMultiplex } from './lib/stream-utils'; |
|
|
|
import { getEnvironmentType } from './lib/util'; |
|
|
|
import { getEnvironmentType } from './lib/util'; |
|
|
|
import metaRPCClientFactory from './lib/metaRPCClientFactory'; |
|
|
|
import metaRPCClientFactory from './lib/metaRPCClientFactory'; |
|
|
|
|
|
|
|
|
|
|
|
start().catch(log.error); |
|
|
|
const container = document.getElementById('app-content'); |
|
|
|
|
|
|
|
|
|
|
|
async function start() { |
|
|
|
|
|
|
|
async function displayCriticalError(container, err, metamaskState) { |
|
|
|
|
|
|
|
const html = await getErrorHtml(SUPPORT_LINK, metamaskState); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = html; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const button = document.getElementById('critical-error-button'); |
|
|
|
const WORKER_KEEP_ALIVE_INTERVAL = 1000; |
|
|
|
|
|
|
|
const WORKER_KEEP_ALIVE_MESSAGE = 'WORKER_KEEP_ALIVE_MESSAGE'; |
|
|
|
|
|
|
|
|
|
|
|
button.addEventListener('click', (_) => { |
|
|
|
/* |
|
|
|
browser.runtime.reload(); |
|
|
|
* As long as UI is open it will keep sending messages to service worker |
|
|
|
}); |
|
|
|
* In service worker as this message is received |
|
|
|
|
|
|
|
* if service worker is inactive it is reactivated and script re-loaded |
|
|
|
|
|
|
|
* Time has been kept to 1000ms but can be reduced for even faster re-activation of service worker |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (isManifestV3()) { |
|
|
|
|
|
|
|
setInterval(() => { |
|
|
|
|
|
|
|
browser.runtime.sendMessage({ name: WORKER_KEEP_ALIVE_MESSAGE }); |
|
|
|
|
|
|
|
}, WORKER_KEEP_ALIVE_INTERVAL); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
log.error(err.stack); |
|
|
|
start().catch(log.error); |
|
|
|
throw err; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function start() { |
|
|
|
// create platform global
|
|
|
|
// create platform global
|
|
|
|
global.platform = new ExtensionPlatform(); |
|
|
|
global.platform = new ExtensionPlatform(); |
|
|
|
|
|
|
|
|
|
|
|
// identify window type (popup, notification)
|
|
|
|
// identify window type (popup, notification)
|
|
|
|
const windowType = getEnvironmentType(); |
|
|
|
const windowType = getEnvironmentType(); |
|
|
|
|
|
|
|
|
|
|
|
// setup stream to background
|
|
|
|
let isUIInitialised = false; |
|
|
|
const extensionPort = browser.runtime.connect({ name: windowType }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const connectionStream = new PortStream(extensionPort); |
|
|
|
// setup stream to background
|
|
|
|
|
|
|
|
let extensionPort = browser.runtime.connect({ name: windowType }); |
|
|
|
|
|
|
|
let connectionStream = new PortStream(extensionPort); |
|
|
|
|
|
|
|
|
|
|
|
const activeTab = await queryCurrentActiveTab(windowType); |
|
|
|
const activeTab = await queryCurrentActiveTab(windowType); |
|
|
|
|
|
|
|
|
|
|
@ -60,23 +63,52 @@ async function start() { |
|
|
|
* Code below ensures that UI is rendered only after background is ready. |
|
|
|
* Code below ensures that UI is rendered only after background is ready. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (isManifestV3()) { |
|
|
|
if (isManifestV3()) { |
|
|
|
extensionPort.onMessage.addListener((message) => { |
|
|
|
/* |
|
|
|
|
|
|
|
* In case of MV3 the issue of blank screen was very frequent, it is caused by UI initialising before background is ready to send state. |
|
|
|
|
|
|
|
* Code below ensures that UI is rendered only after CONNECTION_READY message is received thus background is ready. |
|
|
|
|
|
|
|
* In case the UI is already rendered, only update the streams. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
const messageListener = (message) => { |
|
|
|
if (message?.name === 'CONNECTION_READY') { |
|
|
|
if (message?.name === 'CONNECTION_READY') { |
|
|
|
|
|
|
|
if (isUIInitialised) { |
|
|
|
|
|
|
|
updateUiStreams(); |
|
|
|
|
|
|
|
} else { |
|
|
|
initializeUiWithTab(activeTab); |
|
|
|
initializeUiWithTab(activeTab); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// resetExtensionStreamAndListeners takes care to remove listeners from closed streams
|
|
|
|
|
|
|
|
// it also creates new streams and attach event listeners to them
|
|
|
|
|
|
|
|
const resetExtensionStreamAndListeners = () => { |
|
|
|
|
|
|
|
extensionPort.onMessage.removeListener(messageListener); |
|
|
|
|
|
|
|
extensionPort.onDisconnect.removeListener( |
|
|
|
|
|
|
|
resetExtensionStreamAndListeners, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
// message below will try to activate service worker
|
|
|
|
|
|
|
|
// in MV3 is likely that reason of stream closing is service worker going in-active
|
|
|
|
|
|
|
|
browser.runtime.sendMessage({ name: WORKER_KEEP_ALIVE_MESSAGE }); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensionPort = browser.runtime.connect({ name: windowType }); |
|
|
|
|
|
|
|
connectionStream = new PortStream(extensionPort); |
|
|
|
|
|
|
|
extensionPort.onMessage.addListener(messageListener); |
|
|
|
|
|
|
|
extensionPort.onDisconnect.addListener(resetExtensionStreamAndListeners); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
extensionPort.onMessage.addListener(messageListener); |
|
|
|
|
|
|
|
extensionPort.onDisconnect.addListener(resetExtensionStreamAndListeners); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
initializeUiWithTab(activeTab); |
|
|
|
initializeUiWithTab(activeTab); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function initializeUiWithTab(tab) { |
|
|
|
function initializeUiWithTab(tab) { |
|
|
|
const container = document.getElementById('app-content'); |
|
|
|
initializeUi(tab, connectionStream, (err, store) => { |
|
|
|
initializeUi(tab, container, connectionStream, (err, store) => { |
|
|
|
|
|
|
|
if (err) { |
|
|
|
if (err) { |
|
|
|
// if there's an error, store will be = metamaskState
|
|
|
|
// if there's an error, store will be = metamaskState
|
|
|
|
displayCriticalError(container, err, store); |
|
|
|
displayCriticalError(err, store); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
isUIInitialised = true; |
|
|
|
|
|
|
|
|
|
|
|
const state = store.getState(); |
|
|
|
const state = store.getState(); |
|
|
|
const { metamask: { completedOnboarding } = {} } = state; |
|
|
|
const { metamask: { completedOnboarding } = {} } = state; |
|
|
@ -86,6 +118,18 @@ async function start() { |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Function to update new backgroundConnection in the UI
|
|
|
|
|
|
|
|
function updateUiStreams() { |
|
|
|
|
|
|
|
connectToAccountManager(connectionStream, (err, backgroundConnection) => { |
|
|
|
|
|
|
|
if (err) { |
|
|
|
|
|
|
|
displayCriticalError(err); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateBackgroundConnection(backgroundConnection); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async function queryCurrentActiveTab(windowType) { |
|
|
|
async function queryCurrentActiveTab(windowType) { |
|
|
@ -112,7 +156,7 @@ async function queryCurrentActiveTab(windowType) { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function initializeUi(activeTab, container, connectionStream, cb) { |
|
|
|
function initializeUi(activeTab, connectionStream, cb) { |
|
|
|
connectToAccountManager(connectionStream, (err, backgroundConnection) => { |
|
|
|
connectToAccountManager(connectionStream, (err, backgroundConnection) => { |
|
|
|
if (err) { |
|
|
|
if (err) { |
|
|
|
cb(err, null); |
|
|
|
cb(err, null); |
|
|
@ -130,6 +174,21 @@ function initializeUi(activeTab, container, connectionStream, cb) { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async function displayCriticalError(err, metamaskState) { |
|
|
|
|
|
|
|
const html = await getErrorHtml(SUPPORT_LINK, metamaskState); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
container.innerHTML = html; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const button = document.getElementById('critical-error-button'); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
button.addEventListener('click', (_) => { |
|
|
|
|
|
|
|
browser.runtime.reload(); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
log.error(err.stack); |
|
|
|
|
|
|
|
throw err; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Establishes a connection to the background and a Web3 provider |
|
|
|
* Establishes a connection to the background and a Web3 provider |
|
|
|
* |
|
|
|
* |
|
|
|