diff options
Diffstat (limited to 'app/scripts/inpage.js')
-rw-r--r-- | app/scripts/inpage.js | 128 |
1 files changed, 36 insertions, 92 deletions
diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index 68394d1ae..a4fb552f1 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -7,32 +7,12 @@ const setupDappAutoReload = require('./lib/auto-reload.js') const MetamaskInpageProvider = require('metamask-inpage-provider') const createStandardProvider = require('./createStandardProvider').default -let isEnabled = false let warned = false -let providerHandle -let isApprovedHandle -let isUnlockedHandle restoreContextAfterImports() log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') -/** - * Adds a postMessage listener for a specific message type - * - * @param {string} messageType - postMessage type to listen for - * @param {Function} handler - event handler - * @param {boolean} remove - removes this handler after being triggered - */ -function onMessage (messageType, callback, remove) { - const handler = function ({ data }) { - if (!data || data.type !== messageType) { return } - remove && window.removeEventListener('message', handler) - callback.apply(window, arguments) - } - window.addEventListener('message', handler) -} - // // setup plugin communication // @@ -49,45 +29,16 @@ const inpageProvider = new MetamaskInpageProvider(metamaskStream) // set a high max listener count to avoid unnecesary warnings inpageProvider.setMaxListeners(100) -// set up a listener for when MetaMask is locked -onMessage('metamasksetlocked', () => { isEnabled = false }) - -// set up a listener for privacy mode responses -onMessage('ethereumproviderlegacy', ({ data: { selectedAddress } }) => { - isEnabled = true - setTimeout(() => { - inpageProvider.publicConfigStore.updateState({ selectedAddress }) - }, 0) -}, true) - // augment the provider with its enable method inpageProvider.enable = function ({ force } = {}) { return new Promise((resolve, reject) => { - providerHandle = ({ data: { error, selectedAddress } }) => { - if (typeof error !== 'undefined') { - reject({ - message: error, - code: 4001, - }) + inpageProvider.sendAsync({ method: 'eth_requestAccounts', params: [force] }, (error, response) => { + if (error) { + reject(error) } else { - window.removeEventListener('message', providerHandle) - setTimeout(() => { - inpageProvider.publicConfigStore.updateState({ selectedAddress }) - }, 0) - - // wait for the background to update with an account - inpageProvider.sendAsync({ method: 'eth_accounts', params: [] }, (error, response) => { - if (error) { - reject(error) - } else { - isEnabled = true - resolve(response.result) - } - }) + resolve(response.result) } - } - onMessage('ethereumprovider', providerHandle, true) - window.postMessage({ type: 'ETHEREUM_ENABLE_PROVIDER', force }, '*') + }) }) } @@ -98,31 +49,23 @@ inpageProvider.autoRefreshOnNetworkChange = true // add metamask-specific convenience methods inpageProvider._metamask = new Proxy({ /** - * Determines if this domain is currently enabled + * Synchronously determines if this domain is currently enabled, with a potential false negative if called to soon * - * @returns {boolean} - true if this domain is currently enabled + * @returns {boolean} - returns true if this domain is currently enabled */ isEnabled: function () { - return isEnabled + const { isEnabled } = inpageProvider.publicConfigStore.getState() + return Boolean(isEnabled) }, /** - * Determines if this domain has been previously approved + * Asynchronously determines if this domain is currently enabled * - * @returns {Promise<boolean>} - Promise resolving to true if this domain has been previously approved + * @returns {Promise<boolean>} - Promise resolving to true if this domain is currently enabled */ - isApproved: function () { - return new Promise((resolve) => { - isApprovedHandle = ({ data: { caching, isApproved } }) => { - if (caching) { - resolve(!!isApproved) - } else { - resolve(false) - } - } - onMessage('ethereumisapproved', isApprovedHandle, true) - window.postMessage({ type: 'ETHEREUM_IS_APPROVED' }, '*') - }) + isApproved: async function () { + const { isEnabled } = await getPublicConfigWhenReady() + return Boolean(isEnabled) }, /** @@ -130,14 +73,9 @@ inpageProvider._metamask = new Proxy({ * * @returns {Promise<boolean>} - Promise resolving to true if MetaMask is currently unlocked */ - isUnlocked: function () { - return new Promise((resolve) => { - isUnlockedHandle = ({ data: { isUnlocked } }) => { - resolve(!!isUnlocked) - } - onMessage('metamaskisunlocked', isUnlockedHandle, true) - window.postMessage({ type: 'METAMASK_IS_UNLOCKED' }, '*') - }) + isUnlocked: async function () { + const { isUnlocked } = await getPublicConfigWhenReady() + return Boolean(isUnlocked) }, }, { get: function (obj, prop) { @@ -149,6 +87,19 @@ inpageProvider._metamask = new Proxy({ }, }) +// publicConfig isn't populated until we get a message from background. +// Using this getter will ensure the state is available +async function getPublicConfigWhenReady () { + const store = inpageProvider.publicConfigStore + let state = store.getState() + // if state is missing, wait for first update + if (!state.networkVersion) { + state = await new Promise(resolve => store.once('update', resolve)) + console.log('new state', state) + } + return state +} + // Work around for web3@1.0 deleting the bound `sendAsync` but not the unbound // `sendAsync` method on the prototype, causing `this` reference issues with drizzle const proxiedInpageProvider = new Proxy(inpageProvider, { @@ -159,19 +110,6 @@ const proxiedInpageProvider = new Proxy(inpageProvider, { window.ethereum = createStandardProvider(proxiedInpageProvider) -// detect eth_requestAccounts and pipe to enable for now -function detectAccountRequest (method) { - const originalMethod = inpageProvider[method] - inpageProvider[method] = function ({ method }) { - if (method === 'eth_requestAccounts') { - return window.ethereum.enable() - } - return originalMethod.apply(this, arguments) - } -} -detectAccountRequest('send') -detectAccountRequest('sendAsync') - // // setup web3 // @@ -218,6 +156,12 @@ inpageProvider.publicConfigStore.subscribe(function (state) { web3.eth.defaultAccount = state.selectedAddress }) +inpageProvider.publicConfigStore.subscribe(function (state) { + if (state.onboardingcomplete) { + window.postMessage('onboardingcomplete', '*') + } +}) + // need to make sure we aren't affected by overlapping namespaces // and that we dont affect the app with our namespace // mostly a fix for web3's BigNumber if AMD's "define" is defined... |