The `disable-console` script introduced in #10040 used an arrow-
function no-op function to replace `console.log` and `console.info`.
This replacement function was early-bound to the `this` context of the
`disable-console` script, because that's how arrow functions work.
This violates an assumption baked into Sentry, which also replaces the
`console` functions. It wraps them in a function it uses to track
console logs as breadcrumbs. This wrapper function blows up for some
reason if the "original" `console` function is early-bound to a `this`
value of `undefined`.
This resulted in various UI freezes. One example is during onboarding,
when using Firefox with Enhanced Tracking Protection set in "strict"
mode. After submitting a password in the 'Create wallet' flow, the
Sentry `console` wrapper would throw and leave the user stuck on the
loading screen.
By replacing the no-op arrow function with a no-op function
declaration, the problem has been resolved.
Relates to #10097
Ensures that `hideLoadingIndication` is always called in all actions that call `showLoadingIndication`. It's unclear how many of these actions were failing to hide the loading indication, because other actions superset `hideLoadingIndication`.
At the very least, `updateTransaction` was probably failing to hide the loading indication in the error case.
This PR also refactors a lot of actions to call `hideLoadingIndication` once in `finally` blocks as opposed to multiple times across `try` and `catch` blocks. We avoided making changes to functions using `Promise` methods, because `Promise.finally` is not supported by Waterfox, and it's not properly transpiled by Babel.
Failure to persist state will now only report to Sentry if the last
attempt to save state succeeded. This ensures that if anyone is stuck
in a state where state can't be saved (e.g. low disk space), we aren't
flooded with repeated errors on Sentry.
This update comes with a breaking change to the Approval controller. It
now requires a `defaultApprovalType` parameter.
I don't think we have any use for a default approval type, but I've
added a "NO_TYPE" one for now because it's a strict requirement. We
should consider making this parameter optional in the future, for cases
like this where it's not needed.
This update will hopefully address some caching issues we've been
seeing with our phishing configuration. See here for more details:
https://github.com/MetaMask/controllers/pull/297
* origin/develop: (46 commits)
Fetch swap quote refresh time from API (#10069)
Fix `fetch-with-cache` handling of interwoven requests (#10079)
Fix 9874 - Improve gas maximum estimation (#10043)
Add eth_getProof to safe methods (#10070)
fix metametrics option tracking (#10071)
Disable console in contentscript (#10040)
Use Boolean for filters (#10066)
Add approval controller (#9401)
Cache dependencies (#10065)
Bump ini from 1.3.5 to 1.3.7 (#10064)
Add HTML coverage report to MetaMask bot comment (#10061)
Remove coveralls (#10063)
Prevent metaMaskFee prop error in FeeCard (#10047)
Display boolean values when signing typed data (#10048)
Use CircleCI executors to simplify CI config (#10055)
Use `.zip` for Firefox e2e tests (#10056)
Update `selenium-webdriver` and `geckodriver` (#10057)
Update Firefox version used on CI for e2e tests (#10058)
Add web3 shim usage notification (#10039)
Refactor home notification (#10046)
...
A data race was introduced in #9919 when the old synchronous storage
API was replaced with an async storage API. The problem arises when
`fetchWithCache` is called a second time while it's still processing
another call. In this case, the `cachedFetch` object can become
stale while blocked waiting for a fetch response, and result in a cache
being overwritten unintentionally.
See this example (options omitted for simplicity, and assuming an empty
initial cache):
```
await Promise.all([
fetchWithCache('https://metamask.io/foo'),
fetchWithCache('https://metamask.io/bar'),
]
```
The order of events could be as follows:
1. Empty cache retrieved for `/foo` route
2. Empty cache retrieved for `/bar` route
3. Call made to `/foo` route
4. Call made to `/bar` route
5. `/foo` response is added to the empty cache object retrieved in
step 1, then is saved in the cache.
6. `/bar` response is added to the empty cache object retrieved in
step 2, then is saved in the cache.
In step 6, the cache object saved would not contain the `/foo`
response set in step 5. As a result, `/foo` would never be cached.
This problem was resolved by embedding the URL being cached directly in
the cache key. This prevents simultaneous responses from overwriting
each others caches.
Technically a data race still exists when handing simultaneous
responses to the same route, but the result would be that the last call
to finish would overwrite the previous. This seems acceptable.
A data race was introduced in #9919 when the old synchronous storage
API was replaced with an async storage API. The problem arises when
`fetchWithCache` is called a second time while it's still processing
another call. In this case, the `cachedFetch` object can become
stale while blocked waiting for a fetch response, and result in a cache
being overwritten unintentionally.
See this example (options omitted for simplicity, and assuming an empty
initial cache):
```
await Promise.all([
fetchWithCache('https://metamask.io/foo'),
fetchWithCache('https://metamask.io/bar'),
]
```
The order of events could be as follows:
1. Empty cache retrieved for `/foo` route
2. Empty cache retrieved for `/bar` route
3. Call made to `/foo` route
4. Call made to `/bar` route
5. `/foo` response is added to the empty cache object retrieved in
step 1, then is saved in the cache.
6. `/bar` response is added to the empty cache object retrieved in
step 2, then is saved in the cache.
In step 6, the cache object saved would not contain the `/foo`
response set in step 5. As a result, `/foo` would never be cached.
This problem was resolved by embedding the URL being cached directly in
the cache key. This prevents simultaneous responses from overwriting
each others caches.
Technically a data race still exists when handing simultaneous
responses to the same route, but the result would be that the last call
to finish would overwrite the previous. This seems acceptable.
`eth_getProof` is an unpermissioned, read-only RPC method for getting account-related Merkle proofs, specified here: https://eips.ethereum.org/EIPS/eip-1186
It's been supported by major Ethereum clients, and Infura, for some time. By adding it to the safe methods list, we enable this method for our users.
* Maintain console logging in dev mode
Co-authored-by: kumavis <aaron@kumavis.me>
Co-authored-by: Erik Marks <rekmarks@protonmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Additional validation was added in #9907 to ensure that the "Known
contract address" warning was shown when sending tokens to another
token address after switching assets on the Send screen. Unfortunately
this change had the unintended side-effect of preventing _all_ token
sends after switching assets, so long as the recipient was not an
internal address.
The problem is that the `validate` function expects to be passed the
address of the token send recipient in the case where a token is
selected. Instead the token address was being passed to the validate
function.
The `query` state is now used, which should always contain the
recipient address. This is the same state used in the only other place
the `validate` function is called.
On Firefox 56 and Waterfox Classic, our `runLockdown.js` script throws
an error. This is fine on the HTML pages, as the next script tags still
get run without issue (though they don't benefit from the SES lockdown
sadly). But in the `contentscript`, an exception thrown here appears to
halt the execution of subsequent scripts.
To prevent the `contentscript` from crashing completely, lockdown
errors are now caught and logged. They are also logged to Sentry on the
pages where Sentry is setup.
The `eth_decrypt` used to fail on Firefox with a recursion error.
Updating these `tweetnacl` dependencies seemed to have fixed the issue
the last time I tested this.
When I tried to reproduce the failure today, it failed due to a
different reason, both before and after this update.
But nonetheless, it still seems like a good idea to update. These newer
versions have no breaking changes and contain important bug fixes.
`eth_getProof` is an unpermissioned, read-only RPC method for getting account-related Merkle proofs, specified here: https://eips.ethereum.org/EIPS/eip-1186
It's been supported by major Ethereum clients, and Infura, for some time. By adding it to the safe methods list, we enable this method for our users.
* Maintain console logging in dev mode
Co-authored-by: kumavis <aaron@kumavis.me>
Co-authored-by: Erik Marks <rekmarks@protonmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This PR introduces the new approval controller to the extension codebase. We use it for the permissions controller's pending approval functionality.
The approval controller sets us up for a new pattern of requesting and managing user confirmations in RPC methods. Along with the generic RPC method middleware, the approval controller will allow us to eliminate our message managers, and decouple various method handlers from our provider stack, making the implementations more portable between the extension and mobile.
Dependencies are now cached between builds, using a checksum of the
`yarn.lock` file as the cache key. The `node_modules` directory and the
`.har` file from the install are cached and restored, so that we ensure
the record of the install is always preserved alongside the
dependencies.
The consolidation of the `collect-har-artifact` script was to make it
easier to cache the `.har` file along with the dependencies.
We don't look at coveralls very much. We might occasionally consult it
to see a report on our code coverage, but that report is already
generated entirely locally, and has been added to the MetaMask bot
comment in #10061.
The CI config has been updated to use CircleCI executors. This allows
us to define the container environments used in one place, and reuse
these environment definitions between jobs.
This should result in no functional changes.
The Firefox e2e tests now use the `.zip` file for testing the
extension. We've found this to produce more similar results to
production, compared to the old method of loading the unzipped
directory.
Passing in a `.zip` file to the Chrome driver didn't seem to work. I
didn't investigate this further to see if it was possible, but I'm not
sure it makes a difference on Chrome anyway.
Update `geckodriver` to the latest version, and `selenium-webdriver`
to the second-most-recent version. Updates include various dependency
updates, bug fixes, and minor features. None of the updates seem to
directly affect us, aside from one new feature of `selenium-webdriver`
that updates the `installAddon` function to support `.zip` files, which
will be used in a subsequent PR.
`selenium-webdriver` was pinned one version behind latest because the
latest version caused our Chrome e2e tests to fail with a mysterious
error whenever `getAttribute` was called on a WebElement.
Additional validation was added in #9907 to ensure that the "Known
contract address" warning was shown when sending tokens to another
token address after switching assets on the Send screen. Unfortunately
this change had the unintended side-effect of preventing _all_ token
sends after switching assets, so long as the recipient was not an
internal address.
The problem is that the `validate` function expects to be passed the
address of the token send recipient in the case where a token is
selected. Instead the token address was being passed to the validate
function.
The `query` state is now used, which should always contain the
recipient address. This is the same state used in the only other place
the `validate` function is called.