mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Make chainId available in the metamask-inpage-provider (#7110)
* Make chainId available in the metamask-inpage-provider * Update metamask-inpage-provider to 2.1.0 * Add e2e tests for ethereum.on events * Move chainId constants to lib/enums.js * Don't use new chainId enums in createInfuraClient * Fix app/scripts/lib/select-chain-id.js
This commit is contained in:
parent
0ffee10f19
commit
7af902e500
@ -9,6 +9,12 @@ const PLATFORM_EDGE = 'Edge'
|
|||||||
const PLATFORM_FIREFOX = 'Firefox'
|
const PLATFORM_FIREFOX = 'Firefox'
|
||||||
const PLATFORM_OPERA = 'Opera'
|
const PLATFORM_OPERA = 'Opera'
|
||||||
|
|
||||||
|
const MAINNET_CHAIN_ID = '0x1'
|
||||||
|
const ROPSTEN_CHAIN_ID = '0x3'
|
||||||
|
const RINKEBY_CHAIN_ID = '0x4'
|
||||||
|
const KOVAN_CHAIN_ID = '0x2a'
|
||||||
|
const GOERLI_CHAIN_ID = '0x5'
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
ENVIRONMENT_TYPE_POPUP,
|
ENVIRONMENT_TYPE_POPUP,
|
||||||
ENVIRONMENT_TYPE_NOTIFICATION,
|
ENVIRONMENT_TYPE_NOTIFICATION,
|
||||||
@ -19,4 +25,9 @@ module.exports = {
|
|||||||
PLATFORM_EDGE,
|
PLATFORM_EDGE,
|
||||||
PLATFORM_FIREFOX,
|
PLATFORM_FIREFOX,
|
||||||
PLATFORM_OPERA,
|
PLATFORM_OPERA,
|
||||||
|
MAINNET_CHAIN_ID,
|
||||||
|
ROPSTEN_CHAIN_ID,
|
||||||
|
RINKEBY_CHAIN_ID,
|
||||||
|
KOVAN_CHAIN_ID,
|
||||||
|
GOERLI_CHAIN_ID,
|
||||||
}
|
}
|
||||||
|
22
app/scripts/lib/select-chain-id.js
Normal file
22
app/scripts/lib/select-chain-id.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
const {
|
||||||
|
MAINNET_CHAIN_ID,
|
||||||
|
ROPSTEN_CHAIN_ID,
|
||||||
|
RINKEBY_CHAIN_ID,
|
||||||
|
KOVAN_CHAIN_ID,
|
||||||
|
GOERLI_CHAIN_ID,
|
||||||
|
} = require('./enums')
|
||||||
|
|
||||||
|
const standardNetworkId = {
|
||||||
|
'1': MAINNET_CHAIN_ID,
|
||||||
|
'3': ROPSTEN_CHAIN_ID,
|
||||||
|
'4': RINKEBY_CHAIN_ID,
|
||||||
|
'42': KOVAN_CHAIN_ID,
|
||||||
|
'5': GOERLI_CHAIN_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
function selectChainId (metamaskState) {
|
||||||
|
const { network, provider: { chaindId } } = metamaskState
|
||||||
|
return standardNetworkId[network] || `0x${parseInt(chaindId, 10).toString(16)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = selectChainId
|
@ -41,6 +41,7 @@ const ProviderApprovalController = require('./controllers/provider-approval')
|
|||||||
const nodeify = require('./lib/nodeify')
|
const nodeify = require('./lib/nodeify')
|
||||||
const accountImporter = require('./account-import-strategies')
|
const accountImporter = require('./account-import-strategies')
|
||||||
const getBuyEthUrl = require('./lib/buy-eth-url')
|
const getBuyEthUrl = require('./lib/buy-eth-url')
|
||||||
|
const selectChainId = require('./lib/select-chain-id')
|
||||||
const {Mutex} = require('await-semaphore')
|
const {Mutex} = require('await-semaphore')
|
||||||
const {version} = require('../manifest.json')
|
const {version} = require('../manifest.json')
|
||||||
const {BN} = require('ethereumjs-util')
|
const {BN} = require('ethereumjs-util')
|
||||||
@ -360,7 +361,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
publicConfigStore.putState(publicState)
|
publicConfigStore.putState(publicState)
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPublicState ({ isUnlocked, selectedAddress, network, completedOnboarding }) {
|
function selectPublicState ({ isUnlocked, selectedAddress, network, completedOnboarding, provider }) {
|
||||||
const isEnabled = checkIsEnabled()
|
const isEnabled = checkIsEnabled()
|
||||||
const isReady = isUnlocked && isEnabled
|
const isReady = isUnlocked && isEnabled
|
||||||
const result = {
|
const result = {
|
||||||
@ -369,6 +370,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
selectedAddress: isReady ? selectedAddress : undefined,
|
selectedAddress: isReady ? selectedAddress : undefined,
|
||||||
networkVersion: network,
|
networkVersion: network,
|
||||||
onboardingcomplete: completedOnboarding,
|
onboardingcomplete: completedOnboarding,
|
||||||
|
chainId: selectChainId({ network, provider }),
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
@ -114,7 +114,7 @@
|
|||||||
"lodash.shuffle": "^4.2.0",
|
"lodash.shuffle": "^4.2.0",
|
||||||
"loglevel": "^1.4.1",
|
"loglevel": "^1.4.1",
|
||||||
"luxon": "^1.8.2",
|
"luxon": "^1.8.2",
|
||||||
"metamask-inpage-provider": "^2.0.3",
|
"metamask-inpage-provider": "^2.1.0",
|
||||||
"metamask-logo": "^2.1.4",
|
"metamask-logo": "^2.1.4",
|
||||||
"mkdirp": "^0.5.1",
|
"mkdirp": "^0.5.1",
|
||||||
"multihashes": "^0.4.12",
|
"multihashes": "^0.4.12",
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
/*global ethereum*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
The `piggybankContract` is compiled from:
|
The `piggybankContract` is compiled from:
|
||||||
|
|
||||||
@ -164,4 +166,22 @@ web3.currentProvider.enable().then(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ethereum.autoRefreshOnNetworkChange = false
|
||||||
|
|
||||||
|
const networkDiv = document.getElementById('network')
|
||||||
|
const chainIdDiv = document.getElementById('chainId')
|
||||||
|
const accountsDiv = document.getElementById('accounts')
|
||||||
|
|
||||||
|
ethereum.on('networkChanged', (networkId) => {
|
||||||
|
networkDiv.innerHTML = networkId
|
||||||
|
})
|
||||||
|
|
||||||
|
ethereum.on('chainIdChanged', (chainId) => {
|
||||||
|
chainIdDiv.innerHTML = chainId
|
||||||
|
})
|
||||||
|
|
||||||
|
ethereum.on('accountsChanged', (accounts) => {
|
||||||
|
accountsDiv.innerHTML = accounts
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -31,6 +31,12 @@
|
|||||||
<button id="approveTokensWithoutGas">Approve Tokens Without Gas</button>
|
<button id="approveTokensWithoutGas">Approve Tokens Without Gas</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div style="display: flex; flex-flow: column;">
|
||||||
|
<div>Network: <div id="network"></div></div>
|
||||||
|
<div>ChainId: <div id="chainId"></div></div>
|
||||||
|
<div>Accounts: <div id="accounts"></div></div>
|
||||||
|
<div style="display: flex;">
|
||||||
|
</div>
|
||||||
|
|
||||||
<script src="contract.js"></script>
|
<script src="contract.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
229
test/e2e/ethereum-on.spec.js
Normal file
229
test/e2e/ethereum-on.spec.js
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const assert = require('assert')
|
||||||
|
const webdriver = require('selenium-webdriver')
|
||||||
|
const { By, until } = webdriver
|
||||||
|
const {
|
||||||
|
delay,
|
||||||
|
buildChromeWebDriver,
|
||||||
|
buildFirefoxWebdriver,
|
||||||
|
installWebExt,
|
||||||
|
getExtensionIdChrome,
|
||||||
|
getExtensionIdFirefox,
|
||||||
|
} = require('./func')
|
||||||
|
const {
|
||||||
|
checkBrowserForConsoleErrors,
|
||||||
|
closeAllWindowHandlesExcept,
|
||||||
|
findElement,
|
||||||
|
findElements,
|
||||||
|
openNewPage,
|
||||||
|
verboseReportOnFailure,
|
||||||
|
waitUntilXWindowHandles,
|
||||||
|
switchToWindowWithTitle,
|
||||||
|
} = require('./helpers')
|
||||||
|
const fetchMockResponses = require('./fetch-mocks.js')
|
||||||
|
|
||||||
|
describe('MetaMask', function () {
|
||||||
|
let extensionId
|
||||||
|
let driver
|
||||||
|
let publicAddress
|
||||||
|
|
||||||
|
const tinyDelayMs = 200
|
||||||
|
const regularDelayMs = tinyDelayMs * 2
|
||||||
|
const largeDelayMs = regularDelayMs * 2
|
||||||
|
|
||||||
|
this.timeout(0)
|
||||||
|
this.bail(true)
|
||||||
|
|
||||||
|
before(async function () {
|
||||||
|
let extensionUrl
|
||||||
|
switch (process.env.SELENIUM_BROWSER) {
|
||||||
|
case 'chrome': {
|
||||||
|
const extPath = path.resolve('dist/chrome')
|
||||||
|
driver = buildChromeWebDriver(extPath)
|
||||||
|
extensionId = await getExtensionIdChrome(driver)
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
extensionUrl = `chrome-extension://${extensionId}/home.html`
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'firefox': {
|
||||||
|
const extPath = path.resolve('dist/firefox')
|
||||||
|
driver = buildFirefoxWebdriver()
|
||||||
|
await installWebExt(driver, extPath)
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
extensionId = await getExtensionIdFirefox(driver)
|
||||||
|
extensionUrl = `moz-extension://${extensionId}/home.html`
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Depending on the state of the application built into the above directory (extPath) and the value of
|
||||||
|
// METAMASK_DEBUG we will see different post-install behaviour and possibly some extra windows. Here we
|
||||||
|
// are closing any extraneous windows to reset us to a single window before continuing.
|
||||||
|
const [tab1] = await driver.getAllWindowHandles()
|
||||||
|
await closeAllWindowHandlesExcept(driver, [tab1])
|
||||||
|
await driver.switchTo().window(tab1)
|
||||||
|
await driver.get(extensionUrl)
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async function () {
|
||||||
|
await driver.executeScript(
|
||||||
|
'window.origFetch = window.fetch.bind(window);' +
|
||||||
|
'window.fetch = ' +
|
||||||
|
'(...args) => { ' +
|
||||||
|
'if (args[0] === "https://ethgasstation.info/json/ethgasAPI.json") { return ' +
|
||||||
|
'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.ethGasBasic + '\')) }); } else if ' +
|
||||||
|
'(args[0] === "https://ethgasstation.info/json/predictTable.json") { return ' +
|
||||||
|
'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.ethGasPredictTable + '\')) }); } else if ' +
|
||||||
|
'(args[0].match(/chromeextensionmm/)) { return ' +
|
||||||
|
'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.metametrics + '\')) }); } else if ' +
|
||||||
|
'(args[0] === "https://dev.blockscale.net/api/gasexpress.json") { return ' +
|
||||||
|
'Promise.resolve({ json: () => Promise.resolve(JSON.parse(\'' + fetchMockResponses.gasExpress + '\')) }); } ' +
|
||||||
|
'return window.origFetch(...args); };' +
|
||||||
|
'function cancelInfuraRequest(requestDetails) {' +
|
||||||
|
'console.log("Canceling: " + requestDetails.url);' +
|
||||||
|
'return {' +
|
||||||
|
'cancel: true' +
|
||||||
|
'};' +
|
||||||
|
' }' +
|
||||||
|
'window.chrome && window.chrome.webRequest && window.chrome.webRequest.onBeforeRequest.addListener(' +
|
||||||
|
'cancelInfuraRequest,' +
|
||||||
|
'{urls: ["https://*.infura.io/*"]},' +
|
||||||
|
'["blocking"]' +
|
||||||
|
');'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async function () {
|
||||||
|
if (process.env.SELENIUM_BROWSER === 'chrome') {
|
||||||
|
const errors = await checkBrowserForConsoleErrors(driver)
|
||||||
|
if (errors.length) {
|
||||||
|
const errorReports = errors.map(err => err.message)
|
||||||
|
const errorMessage = `Errors found in browser console:\n${errorReports.join('\n')}`
|
||||||
|
console.error(new Error(errorMessage))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.currentTest.state === 'failed') {
|
||||||
|
await verboseReportOnFailure(driver, this.currentTest)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
after(async function () {
|
||||||
|
await driver.quit()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Going through the first time flow, but skipping the seed phrase challenge', () => {
|
||||||
|
it('clicks the continue button on the welcome screen', async () => {
|
||||||
|
await findElement(driver, By.css('.welcome-page__header'))
|
||||||
|
const welcomeScreenBtn = await findElement(driver, By.css('.first-time-flow__button'))
|
||||||
|
welcomeScreenBtn.click()
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clicks the "Create New Wallet" option', async () => {
|
||||||
|
const customRpcButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Create a Wallet')]`))
|
||||||
|
customRpcButton.click()
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clicks the "No thanks" option on the metametrics opt-in screen', async () => {
|
||||||
|
const optOutButton = await findElement(driver, By.css('.btn-default'))
|
||||||
|
optOutButton.click()
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('accepts a secure password', async () => {
|
||||||
|
const passwordBox = await findElement(driver, By.css('.first-time-flow__form #create-password'))
|
||||||
|
const passwordBoxConfirm = await findElement(driver, By.css('.first-time-flow__form #confirm-password'))
|
||||||
|
const button = await findElement(driver, By.css('.first-time-flow__form button'))
|
||||||
|
|
||||||
|
await passwordBox.sendKeys('correct horse battery staple')
|
||||||
|
await passwordBoxConfirm.sendKeys('correct horse battery staple')
|
||||||
|
|
||||||
|
const tosCheckBox = await findElement(driver, By.css('.first-time-flow__checkbox'))
|
||||||
|
await tosCheckBox.click()
|
||||||
|
|
||||||
|
await button.click()
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('skips the seed phrase challenge', async () => {
|
||||||
|
const buttons = await findElements(driver, By.css('.first-time-flow__button'))
|
||||||
|
await buttons[0].click()
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
|
||||||
|
const detailsButton = await findElement(driver, By.css('.account-details__details-button'))
|
||||||
|
await detailsButton.click()
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('gets the current accounts address', async () => {
|
||||||
|
const addressInput = await findElement(driver, By.css('.qr-ellip-address'))
|
||||||
|
publicAddress = await addressInput.getAttribute('value')
|
||||||
|
const accountModal = await driver.findElement(By.css('span .modal'))
|
||||||
|
|
||||||
|
await driver.executeScript("document.querySelector('.account-modal-close').click()")
|
||||||
|
|
||||||
|
await driver.wait(until.stalenessOf(accountModal))
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('provider listening for events', () => {
|
||||||
|
let extension
|
||||||
|
let popup
|
||||||
|
let dapp
|
||||||
|
it('switches to a dapp', async () => {
|
||||||
|
await openNewPage(driver, 'http://127.0.0.1:8080/')
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
|
||||||
|
await waitUntilXWindowHandles(driver, 3)
|
||||||
|
const windowHandles = await driver.getAllWindowHandles()
|
||||||
|
|
||||||
|
extension = windowHandles[0]
|
||||||
|
popup = await switchToWindowWithTitle(driver, 'MetaMask Notification', windowHandles)
|
||||||
|
dapp = windowHandles.find(handle => handle !== extension && handle !== popup)
|
||||||
|
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
const approveButton = await findElement(driver, By.xpath(`//button[contains(text(), 'Connect')]`))
|
||||||
|
await approveButton.click()
|
||||||
|
|
||||||
|
await driver.switchTo().window(dapp)
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('has not set the network within the dapp', async () => {
|
||||||
|
const networkDiv = await findElement(driver, By.css('#network'))
|
||||||
|
assert.equal(await networkDiv.getText(), '')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('changes the network', async () => {
|
||||||
|
await driver.switchTo().window(extension)
|
||||||
|
|
||||||
|
const networkDropdown = await findElement(driver, By.css('.network-name'))
|
||||||
|
await networkDropdown.click()
|
||||||
|
await delay(regularDelayMs)
|
||||||
|
|
||||||
|
const ropstenButton = await findElement(driver, By.xpath(`//span[contains(text(), 'Ropsten')]`))
|
||||||
|
await ropstenButton.click()
|
||||||
|
await delay(largeDelayMs)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets the network div within the dapp', async () => {
|
||||||
|
await driver.switchTo().window(dapp)
|
||||||
|
const networkDiv = await findElement(driver, By.css('#network'))
|
||||||
|
assert.equal(await networkDiv.getText(), '3')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets the chainId div within the dapp', async () => {
|
||||||
|
await driver.switchTo().window(dapp)
|
||||||
|
const chainIdDiv = await findElement(driver, By.css('#chainId'))
|
||||||
|
assert.equal(await chainIdDiv.getText(), '0x3')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets the account div within the dapp', async () => {
|
||||||
|
await driver.switchTo().window(dapp)
|
||||||
|
const accountsDiv = await findElement(driver, By.css('#accounts'))
|
||||||
|
assert.equal(await accountsDiv.getText(), publicAddress.toLowerCase())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -46,6 +46,14 @@ concurrently --kill-others \
|
|||||||
'sleep 5 && mocha test/e2e/send-edit.spec'
|
'sleep 5 && mocha test/e2e/send-edit.spec'
|
||||||
|
|
||||||
|
|
||||||
|
concurrently --kill-others \
|
||||||
|
--names 'ganache,dapp,e2e' \
|
||||||
|
--prefix '[{time}][{name}]' \
|
||||||
|
--success first \
|
||||||
|
'yarn ganache:start' \
|
||||||
|
'yarn dapp' \
|
||||||
|
'sleep 5 && mocha test/e2e/ethereum-on.spec'
|
||||||
|
|
||||||
export GANACHE_ARGS="${BASE_GANACHE_ARGS} --deterministic --account=0x250F458997A364988956409A164BA4E16F0F99F916ACDD73ADCD3A1DE30CF8D1,0 --account=0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9,25000000000000000000"
|
export GANACHE_ARGS="${BASE_GANACHE_ARGS} --deterministic --account=0x250F458997A364988956409A164BA4E16F0F99F916ACDD73ADCD3A1DE30CF8D1,0 --account=0x53CB0AB5226EEBF4D872113D98332C1555DC304443BEE1CF759D15798D3C55A9,25000000000000000000"
|
||||||
concurrently --kill-others \
|
concurrently --kill-others \
|
||||||
--names 'ganache,sendwithprivatedapp,e2e' \
|
--names 'ganache,sendwithprivatedapp,e2e' \
|
||||||
|
@ -14593,10 +14593,10 @@ mersenne-twister@^1.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"
|
resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a"
|
||||||
integrity sha1-+RZhjuQ9cXnvz2Qb7EUx65Zwl4o=
|
integrity sha1-+RZhjuQ9cXnvz2Qb7EUx65Zwl4o=
|
||||||
|
|
||||||
metamask-inpage-provider@^2.0.3:
|
metamask-inpage-provider@^2.1.0:
|
||||||
version "2.0.3"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/metamask-inpage-provider/-/metamask-inpage-provider-2.0.3.tgz#8a8ccf73d830ec76b3c746265d5977edf36a5c2f"
|
resolved "https://registry.yarnpkg.com/metamask-inpage-provider/-/metamask-inpage-provider-2.1.0.tgz#69e23d63893a5e2bb7a09a6ec96c6f1500588673"
|
||||||
integrity sha512-8/c77tyM56RgKIEUDTenORVmX2xy5a5isOWVRqE8w8u584WTrf56iWewzFpU2KxbHDF3Drx+jR9tII3Qwx83kg==
|
integrity sha512-1+m8Mp8/RM9JMTvDHAMt6a7aqwigRMLvU/VKKmHQFi7AZaagG8Fe4wBe8HdAMysRF3NHV/qOMw0UwP3w9m1Vaw==
|
||||||
dependencies:
|
dependencies:
|
||||||
json-rpc-engine "^5.1.3"
|
json-rpc-engine "^5.1.3"
|
||||||
json-rpc-middleware-stream "^2.1.1"
|
json-rpc-middleware-stream "^2.1.1"
|
||||||
|
Loading…
Reference in New Issue
Block a user