Sentry breadcrumb collection during initialization was broken in #20529
because we failed to consider that the `getSentryState` check was also
used for an opt-in check in the `beforeBreadcrumb` hook.
I had assumed that `getSentryState` was only used to get state to add
additional context to an error report. But the function has a second
purpose: to get state for the purposes of checking whether the user has
opted into MetaMetrics. In this second case, `mostRecentRetrievedState`
is sometimes unset (which violates an assumption made in #20529)
The `getMostRecentPersistedState` hook removed in #20529 has been
restored, ensuring that the `getSentryState` function returns Sentry
state after loading state for the first time, but before the first
error has occurred.
This mistake didn't cause e2e tests to fail because multiple errors are
currently thrown in the background upon initialization on `develop`
(relating to Snow scuttling). These errors were early enough that they
happened before the console logs that our breadcrumb test was testing
for. When #20529 was ported onto the v10.34.5 RC, these errors were not
present so the test failed correctly.
In the case where an error is thrown in the UI before initialization
has finished, we aren't capturing the application state correctly for
Sentry errors. We had a test case for this, but the test case was
broken due to a mistake in how the `network-store` was setup (it was
not matching the behavior of the real `local-tstore` module).
The pre-initialization state capture logic was updated to rely solely
upon the `localStore` instance used by Sentry to determine whether the
user had opted-in to metrics or not. This simplifies the logic a great
deal, removing the need for the `getMostRecentPersistedState` state
hook. It also ensures that state is captured corretly pre-
initialization in both the background and UI.
* Fix and test log.info calls run for each migration
In migrator/index.js, log.info is called before an after each migration.
These calls are intended to produce breadcrumbs to be captured by sentry
in cases where errors happen during or shortly after migrations are run.
These calls were not causing any output to the console because the log.setLevel
calls in ui/index.js were setting a 'warn value in local storage that was being
used by logLevel in the background.
This commit fixes the problem by setting the `persist` param of setLevel to
false, so that the background no longer reads the ui's log level.
Tests are added to verify that these logs are captured in sentry breadcrumbs
when there is a migration error due to an invariant state.
* Improve breadcrumb message matching
The test modified in this commit asserts eqaulity of messages from breadcrumbs
and hard coded expected results. This could cause failures, as sometimes the
messages contain whitespace characters. This commit ensures the assertions only
check that the expected string is within the message string, ignoring extra
characters.
* Improve Sentry state pre-initialization
Previously the masked state snapshot sent to Sentry would be blank for
errors that occured during initialization. Instead we'll now include
some basic information in all cases, and a masked copy of the persisted
state if it happens after the first time the persisted state is read.
* Add test
* Fix crash when persisted state not yet fetched
* Add descriptions for initial state hooks
* Update comments to reflect recent changes
* Re-order imports to follow conventions
* Move initial state hooks back to module-level
The initial state hooks are now setup at the top-level of their module.
This ensures that they're setup prior to later imports. Calling a
function to setup these hooks in the entrypoint module wouldn't
accomplish this even if it was run "before" the imports because ES6
imports always get hoisted to the top of the file.
The `localStore` instance wasn't available statically, so a new state
hook was introduced for retrieving the most recent retrieved persisted
state.
* Fix error e2e tests
Additional validation has been added for persisted state metadata.
Beforehand we just checked that the state itself wasn't falsy. Now we
ensure that the metadata is an object with a valid version as well.
The unflattened background state is now attached to any Sentry errors
from the background process. This provides a clearer picture of the
state of the wallet, and unblocks further improvements to Sentry state
which will come in later PRs.
The state mask used to anonymize the Sentry state snapshots has been
split into UI and background masks. This was done to simplify later
refactors. There should be no functional changes.
* Add AppMetadataController so current and previous application and migration version can be captured in sentry
* Add currentAppVersion, previousAppVersion, previousMigrationVersion, currentMigrationVersion to SENTRY_OBJECT
* Update app/scripts/controllers/app-metadata.ts
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
* Update app/scripts/controllers/app-metadata.ts
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
* Update app/scripts/controllers/app-metadata.ts
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
* Fix types
* Add tests for app-metadata.test.ts
* Lint fixes
* Modify loadStateFromPersistence to return the whole versionData object, so that the migration version can be passed to the metamask-controller on instantiation
* Remove reference to implementation details in test descriptions in app/scripts/controllers/app-metadata.test.ts
* Reset all mocks afterEach in AppMetadataController
* Refactor AppMetadataController to be passed version instead of calling platform.version directly (for ease of unit testing the MetaMask Controller)
* Make maybeUpdateAppVersion and maybeUpdateMigrationVersion private, and remove unit tests of those specific functions
---------
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
* Capture Sentry errors prior to initialization
Sentry errors captured before/during the wallet initialization are
currently not captured because we don't have the controller state yet
to determine whether the user has consented.
The Sentry setup has been updated to check the persisted state for
whether the user has consented, as a fallback in case the controller
state hasn't been initialized yet. This ensures that we capture errors
during initialization if the user has opted in.
* Always await async check for whether the user has opted in
* Remove unused import
* Update JSDoc return type
* Remove unused driver method
* Fix metametrics controller unit tests
* Fix e2e tests
* Fix e2e test on Firefox
* Start session upon install rather than toggle
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This commit fulfills a long-standing desire to get the extension using
the same network controller as mobile by removing NetworkController from
this repo and replacing it with NetworkController from the
`@metamask/network-controller` package.
The new version of NetworkController is different the old one in a few
ways:
- The new controller inherits from BaseControllerV2, so the `state`
property is used to access the state instead of `store.getState()`.
All references of the latter have been replaced with the former.
- As the new controller no longer has a `store` property, it cannot be
subscribed to; the controller takes a messenger which can be
subscribed to instead. There were various places within
MetamaskController where the old way of subscribing has been replaced
with the new way. In addition, DetectTokensController has been updated
to take a messenger object so that it can listen for NetworkController
state changes.
- The state of the new controller is not updatable from the outside.
This affected BackupController, which dumps state from
NetworkController (among other controllers), but also loads the same
state into NetworkController on import. A method `loadBackup` has been
added to NetworkController to facilitate this use case, and
BackupController is now using this method instead of attempting to
call `update` on NetworkController.
- The new controller does not have a `getCurrentChainId` method;
instead, the chain ID can be read from the provider config in state.
This affected MmiController. (MmiController was also updated to read
custom networks from the new network controller instead of the
preferences controller).
- The default network that the new controller is set to is always
Mainnet (previously it could be either localhost or Goerli in test
mode, depending on environment variables). This has been addressed
by feeding the NetworkController initial state using the old logic, so
this should not apply.
* Rename `provider` to `providerConfig`
The network controller `provider` state has been renamed to
`providerConfig`. This better reflects what this state is, and makes
this controller more closely aligned with the core network controller.
All references to the provider configuration have been updated to
prefer `providerConfig` over `provider`, to make the distinction clear
between a provider and provider config.
Closes#18902
* Add migration
* feat: add yaml feature management
Add yaml feature file per build type.
Also add method to parse yaml and set
enabled features env to true. The build
process will then replace any process.env[feature]
that exists on the config by its value
* chore: add example for desktop
* Added initial draft of build features
* [TMP] Sync between computers
* Is able to succesfully build stable extension with snaps feature
* Removing var context from builds.yml
* Add asssets to builds.yml
* Minor bug fixes and removing debug logs
* [WIP] Test changes
* Removed TODOs
* Fix regession bug
Also
* remove debug logs
* merge Variables.set and Variables.setMany with an overload
* Fix build, lint and a bunch of issues
* Update LavaMoat policies
* Re-add desktop build type
* Fix some tests
* Fix desktop build
* Define some env variables used by MV3
* Fix lint
* Fix remove-fenced-code tests
* Fix README typo
* Move new code
* Fix missing asset copy
* Move Jest env setup
* Fix path for test after rebase
* Fix code fences
* Fix fencing and LavaMoat policies
* Fix MMI code-fencing after rebase
* Fix MMI code fencing after merge
* Fix more MMI code fencing
---------
Co-authored-by: cryptotavares <joao.tavares@consensys.net>
Co-authored-by: Frederik Bolding <frederik.bolding@gmail.com>
Co-authored-by: Brad Decker <bhdecker84@gmail.com>
* UX: Multichain: App header
* Export app header, provide required information, put feature flag in place
* Provide available data
* Implement account picker -- centered and opens account popover
* Remove backgrounds, use isUnlocked
* Fix placement of the global menu
* Show logo when unlocked
* Add selector for getting current network, provide props to AvatarNetwork and PickerNetwork
* Wire up the network menu to the header
* fixed ui for all the screens
* updated story for header
* fixed import and header settings
* updated lint error
* fixed tests
* updated header
* removed test
* updated snapshot test
* updated network menu
* updated changes
* removed comment from menu bar
* updated css
* updated test for network list menu
* updated stylesheet
* updated ButtonIcon import
---------
Co-authored-by: NidhiKJha <menidhikjha@gmail.com>
* use session storage, instead of chrome.runtime.onStartup and globalThis, for firstTimeLoaded architecture
* Ensure account tracker accounts remain defined upon service worker restart
* lint fix
* Simplify code
* Only call browser.storage.session in mv3
* Only call browser.storage.session.set after resetStates in mv3
* fix metamask controller reset states unit tests
* fix test
* fix test
* Actually fix tests
* lint fix
We want to convert NetworkController to TypeScript in order to be able
to compare differences in the controller between in this repo and the
core repo. To do this, however, we need to convert the dependencies of
the controller to TypeScript.
As a part of this effort, this commit converts
`shared/constants/metametrics` to TypeScript. Note that simple objects
have been largely replaced with enums. There are some cases where I even
split up some of these objects into multiple enums.
Co-authored-by: Mark Stacey <markjstacey@gmail.com>
The `network` store of the network controller crams two types of data
into one place. It roughly tracks whether we have enough information to
make requests to the network and whether the network is capable of
receiving requests, but it also stores the ID of the network (as
obtained via `net_version`).
Generally we shouldn't be using the network ID for anything, as it has
been completely replaced by chain ID, which all custom RPC endpoints
have been required to support for over a year now. However, as the
network ID is used in various places within the extension codebase,
removing it entirely would be a non-trivial effort. So, minimally, this
commit splits `network` into two stores: `networkId` and
`networkStatus`. But it also expands the concept of network status.
Previously, the network was in one of two states: "loading" and
"not-loading". But now it can be in one of four states:
- `available`: The network is able to receive and respond to requests.
- `unavailable`: The network is not able to receive and respond to
requests for unknown reasons.
- `blocked`: The network is actively blocking requests based on the
user's geolocation. (This is specific to Infura.)
- `unknown`: We don't know whether the network can receive and respond
to requests, either because we haven't checked or we tried to check
and were unsuccessful.
This commit also changes how the network status is determined —
specifically, how many requests are used to determine that status, when
they occur, and whether they are awaited. Previously, the network
controller would make 2 to 3 requests during the course of running
`lookupNetwork`.
* First, if it was an Infura network, it would make a request for
`eth_blockNumber` to determine whether Infura was blocking requests or
not, then emit an appropriate event. This operation was not awaited.
* Then, regardless of the network, it would fetch the network ID via
`net_version`. This operation was awaited.
* Finally, regardless of the network, it would fetch the latest block
via `eth_getBlockByNumber`, then use the result to determine whether
the network supported EIP-1559. This operation was awaited.
Now:
* One fewer request is made, specifically `eth_blockNumber`, as we don't
need to make an extra request to determine whether Infura is blocking
requests; we can reuse `eth_getBlockByNumber`;
* All requests are awaited, which makes `lookupNetwork` run fully
in-band instead of partially out-of-band; and
* Both requests for `net_version` and `eth_getBlockByNumber` are
performed in parallel to make `lookupNetwork` run slightly faster.
The network controller has a variety of methods that just retrieve
controller state. These methods are not necessary because controller
state is already part of the public API of the controller and can be
accessed directly.
These methods are:
- getCurrentChainId
- getCurrentRpcUrl
- getNetworkIdentifier
- getNetworkState
- getProviderConfig
- isNetworkLoading
This is part of a larger effort to normalize the API of both network
controllers, to make them easier to merge.
Use DesktopManager in background script to redirect internal and external connections to the desktop app.
Include DesktopController in the MetaMask controller.
Support desktop keyrings in MetaMask controller via the overrides object.
Create middleware handler to connect to the desktop app while UI code is pending.
Add build system support for desktop specific configuration variables.
Support has been restored for Chromium v78. Previously the extension
would crash upon startup.
The main incompatibility was the use of ES2020 operators (the optional
chain and nullish coalesce operators) in the libraries
`@ethereumjs/util` and `superstruct`. This was resolved by transpiling
those libraries.
After fixing that, the extension no longer crashed but the UI refused
to connect. This was because the UI process was not being identified as
an internal process, because the code responsible for checking that was
relying on the `origin` property of `MessageSender` [1] which wasn't
added until Chromium v80. The check has been updated to use the `url`
property instead, which existed in older versions of Chrome.
Lastly, the content security policy was updated to include the default
content security policy alongside the intended modification. Newer
versions of Chrome will merge the configired CSP with the default, but
older versions required it to be explicitly specified. This should not
result in any functional change.
[1]: https://developer.chrome.com/docs/extensions/reference/runtime/#type-MessageSender
* Simplify MV3 initialization
The MV3 initialization logic was complicated and introduced race
difficult-to-reproduce race conditions when dapps connect during
initialization.
It seems that problems were encountered after the UI tried to connect
before the background was initialized. To address this, the
initialization step was _delayed_ until after the first connection.
That first connection was then passed into the initialization function,
and setup properly after initialization had begun.
However, this special treatment is only given for the first connection.
Subsequent connections that still occur during initialization would
fail. This also results in the initialization being needlessly delayed,
which is concerning given that our main performance goal is to speed it
up.
* Setup connect listeners before controller initialization
* Add comments
* Add comment explaining isInitialized step
* Show error message if service worker did not load (respond to the UI)
after 1 minute.
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* Remove console.log
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* New Error message design
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* Fix tests
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* Use lastTimeStamp instead of keeping track of message ids
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* Do not initial channe every second.
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* New logic to check if SW is stuck
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
Signed-off-by: Akintayo A. Olusegun <akintayo.segun@gmail.com>
* Updating controller dependency
* fix
* fix
* fix
* fix
* fixes
* Lavamoat auto
* Update URLs for phishing detection testcase
* update lavamoat files
* call phishingController.test synchronously again
* bump @metamask/controllers to v32.0.1
* lint
* update policy files
* bump controllers version again
* modify update phishing list strategy
* revert back to use isOutOfDate, but without blocking substream
* possible way to fix e2e tests?
* enable testing
* Remove promise return from setupController in background.js, as it is no longer used
* Ensure updatePhishingLists is called in MM contrller constructer, so that phishing lists are updated right away
Co-authored-by: seaona <mariona@gmx.es>
Co-authored-by: Alex <adonesky@gmail.com>
Co-authored-by: Dan Miller <danjm.com@gmail.com>
A patch made in #15672 was found to be unnecessary. Instead of setting
a `rootGlobals` object upon construction of the root compartment, we
are now creating a `sentryHooks` object in the initial top-level
compartment. I hadn't realized at the time that the root compartment
would inherit all properties of the initial compartment `globalThis`.
This accomplishes the same goals as #15672 except without needing a
patch.
Our Sentry setup relies upon application state, but it wasn't able to
access it in LavaMoat builds because it's running in a separate
Compartment.
A patch has been introduced to the LavaMoat runtime to allow the root
Compartment to mutate the `rootGlobals` object, which is accessible
from outside the compartment as well. This lets us expose application
state to our Sentry integration.