Version v9.5.0 RC (#10944)

* add trezor HD path for ledger wallets (#10616)

Co-authored-by: Barry Gitarts <bgitarts@gmail.com>

* Replace logic for eth swap token in fetchQuotesAndSetQuoteState with getSwapsEthToken call (#10624)

* Ensure permission log will only store JSON-able data (#10524)

* remove transactionCategory in favor of more types (#10615)

* remove transactionCategory in favor of more types

* remove reference to STANDARD in stubs

* Removing double click bug from delete custom network modal (#10628)

Fixes MetaMask/metamask-extension#10626

* Hide zero balance tokens at useTokenTracker layer (#10630)

* Setting balance to 0x0 when the original value is undefined (#10634)

* fix: speedup cancellation (#10579)

fixes #7305

* no more node:console (#10640)

* prefer chainId over networkId in most cases (#10594)

* Move swaps constants to the shared constants directory (#10614)

* Position the 3dot menu in the same spot on asset screen and home screen (#10642)

* Ensure swaps detail height doesn't create jump in vertical height (#10644)

* Fix: ETH 'token' now only appears once in the swaps to and from dropdowns. (#10650)

* Prevent network menu highlighting (#10643)

* Allow TextField to receive min and max attributes (#10656)

* colocate tests in flat structure (#10655)

* Fixing migration script generation paths (#10664)

* Improve specificity of `test:unit:lax` npm script (#10661)

The unit test npm script `test:unit:lax` is now more specific about
which tests files to exclude. An `--ignore` CLI option is used to
specify the files to ignore, rather than using the braces glob syntax
to ignore them from the target glob itself.

This makes the option easier to update going forward as we move more
tests into the "strict" group, because the options are exactly the same
between the two scripts. It also ensures we don't accidentally exclude
other subdirectories that happen to also be named `permissions`.

In trying to implement this, I stumbled at first because mocha expects
the ignore pattern to be a relative path if the target is a relative
path (i.e. they need to both start with `./` or neither). The script
`test:unit:strict` has been updated to use a relative target pattern
for consistency.

* Swaps support for local testnet (#10658)

* Swaps support for local testnet

* Create util method for comparison of token addresses/symbols to default swaps token

* Get chainId from txMeta in _trackSwapsMetrics of transaction controller

* Add comment to document purpose of getTransactionGroupRecipientAddressFilter

* Use isSwapsDefaultTokenSymbol in place of repeated defaultTokenSymbol comparisons in build-quote.js

* fix: replace dnode background with JSON-RPC (#10627)

fixes #10090

* Don't render faucet row in deposit modal for custom chains (#10674)

Fixes MetaMask/metamask-extension#10038

* Change 'Send ETH' title to 'Send' (#10651)

* Fixing incorrectly typed token decimal attribute (#10666)

* refactor incoming tx controller (#10639)

* make migration more safe (#10689)

* Adding default properties to NetworkForm (#10682)

Fixes MetaMask/metamask-extension#10681

* deps - remove "remotedev-server" (#10687)

* deps - remove remotedev-server

* Remove stale references from allow-scripts config

Any packages that are no longer in the dependency tree have been
removed from the `allow-scripts` config.

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Excluding sourcemaps comment in production builds (#10695)

* Excluding sourcemaps comment in production builds

Fixes MetaMask/metamask-extension#7077

* Fix source map explorer script

The source map explorer script now re-adds the source map comment to
each file to ensure the source map visualization still works. Each
module with a sourcemap is copied to a temporary directory along with
the module it corresponds to, and from there it's passed into
`source-map-explorer`. This should ensure the resulting visualization
matches what it was before.

Everything has been moved inside of functions to generally improve
readability, and to allow the use of local variables.

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Delete setupFetchDebugging.js (#10636)

* Delete setupFetchDebugging.js

* remove fetch-debugging (now handled corrently by sentry)

* resolve issue with missing template error (#10692)

* resolve issue with missing template error

* also apply filtering to confirmation page

* rename variable

* Add MetaMask to list of BIP44 HD path examples (#10703)

The "BIP44 Standard" HD path option in the Ledger connect flow listed
only Trezor as an example. It seemed appropriate to include MetaMask as
well, since we use the same path. This helps users who have imported
their MetaMask seed phrase onto a Ledger device to discover this
option.

* Removing hard references to 12 word seed phrases in copy (#10704)

Adding translation entry for "Wallet Seed"

Fixed label padding issue by adding missing CSS rule

* rule out empty string for symbol (#10712)

* fix: remove unused `metamask.rpcUrl` from redux state + fix tests to reflect that (#10714)

* Fix 10706 - Prevent autocomplete from add token input (#10700)

* Fix mismatchedChain typo in custom network approval screen (#10723)

* Fix 10562 - Hide the suggested token pane when not on Mainnet or test network (#10702)

* Update @metamask/controllers to v6.2.1 (#10701)

* Additional swaps network support (#10721)

* Add swaps support for bnc chain

* Use single default token address in shared/constants/swaps

* ci - cache deps before patch-package (#10735)

* ci - cache deps before patch-package

* ci - bump dep cache number (cache break)

* build - refactor build system for easier configuration (#10718)

* build - refactor build system for easier configuration of before and after bundle

* build - fix dependenciesToBundle option

* build - fix bify external options and other config

* build - refactor for cleanliness

* build - fix minify argument

* build - fix sourcemaps setup

* scripts - refactor setupBundlerDefaults in anticipation of factor bundles

* build - scripts - remove unused pipeline label

* build - scripts - make filepath entry optional

* build - scripts - rename filepath and filename options to entryFilepath and destFilepath

* Update development/build/scripts.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* security - update SES lockdown (#10663)

* update ses

* build - reference ses directly

* deps - unify regenerator-runtime versions on 0.13.7

* patches - apply regenerator-runtime ses compat patch\nhttps://github.com/facebook/regenerator/pull/411

* patches - patch regenerator-runtime for latest ses fix

* reduc patch, new lockdown severe override taming

* updated redux patch

* update redux patch for production

* ignore lockdown in lint

* deps - bump patch-package just in case

* trailing comma

* remove ses as dep

* fix path for frozen promise

* remove js extension in lockdown require

* Revert "ignore lockdown in lint"

This reverts commit 8cefdc94dd25d7781bb09eed8af36441397676da.

* Revert "build - reference ses directly"

This reverts commit 30371a377dcdd781c1bf9abe55e9c8ae34da26b5.

* deps - update ses

* Revert "fix path for frozen promise"

This reverts commit 966e4c60921a25befe8ca8dea58313cc25852f72.

Co-authored-by: kumavis <aaron@kumavis.me>

* Allow 11 characters in symbol for RPC (#10670)

* Add error in RPC for zero length symbols

* Increase RPC symbol length allowed to 11

* Add RPC tests for new symbol length checks

* eth-block-tracker@5.0.1 (#10737)

* Ensure swaps gas prices are fetched from the correct chain specific endpoint (#10744)

* Ensure swaps gas prices are fetched from the correct chain specific endpoint

* Just rely on fetchWithCache to cache swaps gas prices, instead of directly using storage in getSwapsPriceEstimatesLastRetrieved

* Empty commit

* update @metamask/etherscan-link to v2.0.0 (#10747)

* Use correct block explorer name and link in swaps when on custom network (#10743)

* Use correct block explorer name and link in swaps when on custom network.

* Fix up custom etherscan link code in build-quote.js

* Use blockExplorerUrl hostname instead of 'blockExplorerBaseUrl'

* Use correct etherscan-link method for token links in build-quote

* Create correct token link in build-quote for mainnet AND custom networks

* Block explorer url improvements in awaiting-swap.js and build-quote.js

* Use swapVerifyTokenExplanation message with substitutable block explorer for all applicable locales

* Ensure that block explorer links are not shown in awaiting-swap if no url is available

* Add New Zealand Dollar to currency options (#10746)

* Ensure that the correct default currency symbols are used for fees on the view quote screen (#10753)

* Fix 10517 - Prevent tokens without addresses from being added to token list (#10593)

* Updating y18n and netmask to resolve dependency issues (#10765)

netmask@1.0.6 -> 2.0.1, y18n@3.2.1 -> 3.2.2, y18n@4.0.0 -> 4.0.1

* Refactor Tx State Manager (#10672)

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Ensure that the approval fee in the swaps custom gas modal is in network specific currency (#10763)

* Ensure that priceSlippage fiat amounts are always shown in view-quote.js (#10762)

* Use network specific swaps contract address when checking swap contract token approval (#10774)

* Build - refactor background process to use html (#10769)

* build - declare background as html

* build - fill in empty file when a missing file is expected

* lint - fix

* Update development/build/manifest.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Update development/build/manifest.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* build - fix use of empty file to replace unused js files (#10780)

* cache lint results for faster repeat execution (#10773)

* eslint perf improvement (#10775)

* Improve detection of task process exit (#10776)

Our build script waits for the `close` event to determine whether the
task has exited. The `exit` event is a better representation of this,
because if a stream is shared between multiple processes, the process
may exit without the `close` event being emitted.

We aren't sharing streams between processes, so this edge case doesn't
apply to us. This just seemed like a more suitable event to listen to,
since we care about the process exiting not the stream ending.

See this description of the `close` event from the Node.js
documentation [1]:

>The `'close'` event is emitted when the stdio streams of a child
>process have been closed. This is distinct from the `'exit'` event,
>since multiple processes might share the same stdio streams.

And see this description of the `exit` event:

>The `'exit'` event is emitted after the child process ends.

[1]: https://nodejs.org/docs/latest-v14.x/api/child_process.html#child_process_event_exit

* Rewrite changelog script from Bash to JavaScript (#10782)

The `auto-changelog` script has been rewritten from Bash to JavaScript.
Functionally it should behave identically.

* Refactoring ethereum-on.spec.js to use fixtures (#10778)

* Remove useless negation (#10787)

!contentComponent always evaluates to true

* Remove date from changelog release header (#10790)

New changelog release headers now omit the date. These headers are
added automatically when a new release branch is created, and that
rarely ends up being the actual date of the release, so these dates
have all been inaccurate anyway.

The date will be re-added to the changelog later as part of a new
script, after a release has been published.

* Remove script for creating master sync PR (#10791)

The script responsible for creating the "Sync `master` with `develop`"
PR has been removed. We will soon be eliminating the need for a
`master` branch altogether, so we don't need this anymore. Also, this
script hasn't been running correctly in a long time. We've been
creating this PR manually.

* Add changelog entries under release candidate header (#10784)

Instead of always placing new changelog entries under the "Current
Develop Branch" header, the changelog script now places them under the
header for the current release if that release has not yet been tagged.

This eliminates one manual step from the release process.

Relates to #10752

* Prevent duplicate changelog entries (#10786)

The changelog update script now prevents duplicate entries from being
added. Specifically, it will ensure that if a PR has been referenced
already in an entry, it will not add it again.

This should prevent it from adding duplicate entries for changes that
were cherry-picked into hotfix releases.

Note that this duplication prevention only works for entries containing
a PR number. We don't have any way to prevent duplicate entries yet in
cases where we don't know the associated PR. We will be preventing this
possibility entirely pretty soon in some upcoming release automation
changes though, so I'm not concerned about this omission.

* Set the BSC_CONTRACT_ADDRESS to lowercase (#10800)

* only applies rules to the appropriate files (#10788)

* upgrade eslint deps (#10789)

* Ensure correct primary currency image is displayed on home screen and token list (#10777)

* Add release header when updating changelog (#10794)

The changelog update script now adds a release header if it doesn't
find one already that matches the current release candidate version.

* remove node-sass dependency (#10797)

* Add support for locators into driver abstraction (#10802)

* Update changelog headers and fix dates (#10805)

The changelog release header format has been updated to match the "keep
a changelog" [1] format. Each header is now the bracketed version
number followed by a dash, then the release date in ISO-8601 format.

The release dates in each header were also updated to match the date of
the corresponding GitHub Release [2]. Many of these dates were
incorrect because they were set on the day we created the release
candidate, rather than on the day of release.

Any changelog release entries without a corresponding GitHub release
was left with the date already specified.

The three oldest release headers were missing dates. For the first two,
I used the date of the version bump commit. For the third, I removed it
since no changes were listed anyway, and it represented a range of
releases rather than a single one.

The `auto-changelog.js` script has been updated to account for this new
format as well.

[1]: https://keepachangelog.com/en/1.0.0/
[2]: https://github.com/MetaMask/metamask-extension/releases

* Update the changelog when creating an RC (#10795)

The changelog will now be automatically updated when a release branch
is created. A new release header along with changelog entries for any
new commits will be added.

Note that this changelog will still need to be manually cleaned up, but
it's one less manual step at least.

The old Bash script for adding a new release header to the changelog
has been removed, as that functionality is now built into the changelog
update script.

A new script has been added to commit any changes made to the manifest
and changelog. This step used to happen at the end of the bump manifest
version script, but now the changelog update relies upon the manifest
version bump happening first, so it needed to be re-ordered. The
changes should only be committed on the first run of the branch, as
it's contingent upon the manifest changing (due to the version bump).
Further changelog updates won't trigger new automatic commits.

* Refactoring address-book.spec.js to use fixtures (#10804)

* Refactoring send-edit.spec.js to use fixtures (#10792)

* Fix _getPermittedAccounts type safety (#10819)

* Removing unnecessary params from withFixtures function call. (#10831)

* Add links to release headers (#10808)

Each release header now includes a link to the range of commits
included with that release. These links are at the end of the document,
in accordance with the "keep a changelog" [1] format.

For the purpose of this changelog, the "previous release" is the most
recent release mentioned in the changelogs. The diffs ignore any
releases that were omitted from the changelog. This is mainly an issue
with older releases, so it seemed acceptable. All releases have been
documented for a couple of years now, and will be going forward as
well.

The name of the "Current Develop Branch" section was changed to
"Unreleased" to confirm with "keep a changelog".

The `auto-changelog.js` script has been updated to update/add these
links whenever adding a new release header as well.

[1]: https://keepachangelog.com/en/1.0.0/

* Refactoring permissions.spec.js to use fixtures (#10829)

* Add validation for the `fee` property from the `/trades` API response (#10836)

* Refactoring signature-request.spec.js to use fixtures (#10820)

* use locator abstraction in tests folder (#10833)

* Move BSC chain ID, rename some BSC-related vars (#10807)

* Add categories to each changelog release (#10837)

Each changelog release now has category headers. The standard "keep a
changelog" [1] categories are used, along with the addition of
"Uncategorized" for any changes that have not yet been categorized.

The changelog script has been updated to add this "Uncategorized"
header if it isn't already present, and to place any new commits under
this header.

The changelog has been updated to property categorize each change in
recent releases, and to place changes in older releases under the
header "Uncategorized".

[1]: https://keepachangelog.com/en/1.0.0/

* Remove unused CI script (#10840)

This script has not been used since #10795. It is now gone.

* Add `--rc` flag to changelog script (#10839)

The changelog script now accepts an `--rc` flag to tell it whether to
add new changes to `Unreleased` or to the header for the current
version.

Previously this was inferred from whether the current version matched
the most recent tag. However this method only works for the first
update. Using a flag simplifies this logic, and makes it possible to
manually re-run this for further updates to a release candidate.

* Add `--help` flag to changelog script (#10846)

The changelog script now accepts a `--help` flag, which prints a help
text explaining how the script works and what each flag does.

* add abstraction for waitForSelector (#10844)

* Adds jest dependency (#10845)

* Add Jest

* Refactor changelog parsing and generation (#10847)

The `auto-changelog.js` script has been refactoring into various
different modules. This was done in preparation for migrating this to
a separate repository, where it can be used in our libraries as well.

Functionally this should act _mostly_ the same way, but there have been
some changes. It was difficult to make this a pure refactor because of
the strategy used to validate the changelog and ensure each addition
remained valid. Instead of being updated in-place, the changelog is now
parsed upfront and stored as a "Changelog" instance, which is a new
class that was written to allow only valid changes. The new changelog
is then stringified and completely overwrites the old one.

The parsing had to be much more strict, as any unanticipated content
would otherwise be erased unintentionally. This script now also
normalizes the formatting of the changelog (though the individual
change descriptions are still unformatted).

The changelog stringification now accommodates non-linear releases as
well. For example, you can now release v1.0.1 *after* v2.0.0, and it
will be listed in chronological order while also correctly constructing
the `compare` URLs for each release.

* Increase default slippage from 2% to 3%, show Advanced Options by default (#10842)

* Increase default slippage from 2% to 3%, show Advanced Options by default

* Disable opening / closing of Advanced Options on the Swap page

* Pre-select previously used slippage value when going back to the Swap page

* Fix lint issues

* Use a callback for setting up an initial customValue

* Migrate unreleased changes in changelog (#10853)

When updating the changelog for a release candidate, any unreleased
changes are now migrated to the release header.

Generally we don't make a habit of adding changes to the changelog
prior to creating a release candidate, but if any are there we
certainly don't want them duplicated.

* @metamask/eslint-config*@6.0.0 (#10858)

* @metamask/eslint-config*@6.0.0

* Minor eslintrc reorg

* Refactoring threebox.spec.js to use fixtures (#10849)

* Adjust renderWithProvider to accommodate redux-less components (#10857)

* Jest config (#10855)

* Setup jest config

* Adjust test for jest.

* Adjust lint config

* Omit swaps ui folder for unit testing

* Omit swaps from test:unit:lax

* Add jest.config.js to script files

* Restore mocks rather than clearing them.

* Update jest config and adjust lint to include subdirs

* Convert view-quote-price-difference test to jest

* Add jest ci and ci coverage scripts. Add jest unit test to general test command

* Add test coverage to ci

* Use --ignore flag

* Fixup

* Add @metamask/eslint-config-jest

* Update .eslintrc.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Adds jest-coverage/

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Add jest-coverage/ to prettierignore (#10865)

* Add jest coverage (#10868)

* Add jest coverage

This will add coverage for any tests ran in jest under the `test:coverage:jest` command, which is currently being used in CI. I set the values to the current test coverage in `ui/app/pages/swaps`.

* Lint

* Fix crash when adding new changelog release header (#10870)

The `auto-changelog.js` script crashes when trying to add a new release
header. This bug was introduced in #10847. The cause was a simple
misnamed parameter.

* Change caching for Swaps APIs from 1 hour to 5 minutes (#10871)

* Change caching for the /tokens API from 1 hour to 5 minutes

* Use 5 minutes caching for /topAssets and /aggregatorMetadata APIs as well

* add key literals to driver (#10854)

* Quote globs in prettier scripts (#10867)

* use waitForSelector instead of until (#10852)

* complete abstraction of until method

* response to feedback

* Adding recovery phrase video to onboarding process (#10717)

* Adding recovery phrase video to onboarding process

Adding english subtitles

* Support textAlign in Box, converting sidebar to Box

* Reduce calls of the `/featureFlag` API (#10859)

* Remove periodic calls to the /featureFlag API

* Always show the Swap button on the main page

* Check if the Swaps feature is enabled, show loading animation while waiting

* Reuse an existing useEffect call

* Use ‘isFeatureFlagLoaded’ in React’s state, resolve lint issues

* Add a watch mode for Jest testing

* Add unit tests for Swaps: fetchSwapsLiveness, add /ducks/swaps into Jest testing

* Remove Swaps Jest tests from Mocha’s ESLint rules

* Ignore Swaps Jest tests while running Mocha, update paths

* Increase test coverage to the current max

* Fix ESLint issues for Swaps

* Enable the Swaps feature by default and after state reset, remove loading screen before seeing Swaps

* Update Jest config, fix tests

* Update Jest coverage threshold to the current maximum

* Update ESLint rule in jest.config.js

* Disable the “Review Swap” button if the feature flag hasn’t loaded yet

* Update jest threshold

* Fix 10036 - Prevent odd localStorage migration error in Firefox (#10884)

* Add jest watch mode script (#10869)

* Refactoring metamask-responsive-ui.spec.js to use fixtures  (#10866)

* Handling infura blockage (#10883)

* Handling infura blockage

* Adding blockage home notification

* Updating copy, adding temporary notification dismissal

* Addressing review feedback

* Using eth_blockNumber method to check Infura availability

* Handling network changes in availability check

* Use jest to run ui/**/*.test.js (#10885)

* upgrade ethereumjs util (#10886)

* Swaps: Show a network name dynamically in a tooltip (#10882)

* Swaps: Show a network name dynamically in a tooltip

* Replace “Ethereum” with “$1”, change “Test” to “Testnet”

* Replace 이더리움 with $1

* Translate network names, use ‘Ethereum’ by default if a translation is not available yet

* Reorder messages to resolve ESLint issues

* Add a snapshot test for the FeeCard component, increase Jest threshold

* Enable snapshot testing into external .snap files in ESLint

* Add the “networkNameEthereum” key in ko/messages.json, remove default “Ethereum” value

* Throw an error if chain ID is not supported by the Swaps feature

* Use string literals when calling the `t` fn,

* Adding option to set Custom Nonce to Confirm Approve Page (#10595)

* Dep Upgrades for Lavamoat Patches (#10902)

* dep upgrades

* apply more patches

* Dep upgrades and patches (#10903)

* apply patches

* lavamoat dep upgrades

* remove lavamoat browserify

* Increase Jest unit test coverage for the Swaps feature to ~25% (#10900)

* Swaps: Show a network name dynamically in a tooltip

* Replace “Ethereum” with “$1”, change “Test” to “Testnet”

* Replace 이더리움 with $1

* Translate network names, use ‘Ethereum’ by default if a translation is not available yet

* Reorder messages to resolve ESLint issues

* Add a snapshot test for the FeeCard component, increase Jest threshold

* Enable snapshot testing into external .snap files in ESLint

* Add the “networkNameEthereum” key in ko/messages.json, remove default “Ethereum” value

* Throw an error if chain ID is not supported by the Swaps feature

* Use string literals when calling the `t` fn,

* Watch Jest tests silently (no React warnings in terminal, only errors)

* Add @testing-library/jest-dom, import it before running Jest tests

* Add snapshot testing of Swaps’ React components for happy paths, increase minimum threshold for Jest

* Add the test/jest folder for Jest setup and shared functions, use it in Swaps Jest tests

* Fix ESLint issues, update linting config

* Enable ESLint for .snap files (Jest snapshots), throw an error if a snapshot is bigger than 50 lines

* Don’t run lint:fix for .snap files

* Move `createProps` outside of `describe` blocks, move store creation inside tests

* Use translations instead of keys, update a rendering function to load translations

* Make sure all Jest snapshots are shorter than 50 lines (default limit)

* Add / update props for Swaps tests

* Fix React warnings when running tests for Swaps

* Bump @metamask/contract-metadata from 1.23.0 to 1.25.0 (#10899)

Bumps [@metamask/contract-metadata](https://github.com/MetaMask/contract-metadata) from 1.23.0 to 1.25.0.
- [Release notes](https://github.com/MetaMask/contract-metadata/releases)
- [Commits](https://github.com/MetaMask/contract-metadata/compare/v1.23.0...v1.25.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Refactoring from-import-ui.spec.js to use fixtures (#10907)

* Fix 10458 - Understand where to get support (#10895)

* Add contract address validation for token swaps (#10912)

* Fixing ENS input entry in send flow (#10923)

* Fixing ENS input entry in send flow

Fixes MetaMask/metamask-extension#10691

* removed unnecessary apostrophe

* Refactoring incremental-security.spec.js to use fixtures (#10917)

* use one segment instance (#10915)

* Implement Ledger Live bridge (#10293)

* add view account-details menu item to token-options menu (#10932)

* add view account-details menu item to token-options menu

* add onViewAccountDetails propType

* Fix 10609 - Prevent overflow of confirmation page hostname (#10935)

* upgrade eth-keyring-controller (#10933)

* [Fix] 10365 My Accounts Removal (#10680)

* pushing my-accounts removal

* removed CONTACT_MY_ACCOUNTS_ROUTE

* removed CONTACT_MY_ACCOUNTS_VIEW_ROUTE

* removing CONTACT_MY_ACCOUNTS_EDIT_ROUTE

* removing CONTACT_MY_ACCOUNTS_EDIT_ROUTE

* removed showingMyAccounts dead code

* removed more dead code related to isMyAccountsPage

* removing more dead code

* fixed linting error(s)

* removing my-accounts component/folder

* added empty contact screen ui

* styled empty contact page ui

* fixed linting, removed add contacts button, and fixed errors

* localized text and centered No Contacts

* pushing localized verification and fixed e2e test

* added listRoute redirect

* added listroute and fixed linting error

* Increase Jest unit test coverage for the Swaps feature to ~43% (#10934)

* add hamburger menu to eth page (#10938)

* add hamburger menu to eth page

* change token-options to asset-options, use more direct selector for user address fetch

* use token custom icons where possible (#10939)

* Whats new popup (#10583)

* Add 'What's New' notification popup

* Move selectors from shared/notifications into ui/ directory

* Use keys for localized message in whats new notifications objects, to ensure notifications will be translated.

* Remove unused swaps intro popup locale messages

* Fix keys of whats new notification locales

* Remove notifications messages and descriptions from comment in shared/notifications

* Move notifcationActionFunctions to shared/notifications and make it stateless

* Get notification data from constants instead of state in whats-new-popup

* Code cleanup

* Fix build quote reference to swapsEthToken, broken during rebase

* Rename notificationFilters to notificationToExclude to clarify its purpose

* Documentation for getSortedNotificationsToShow

* Move notification action functions from shared/ to whats-new-popup.js

* Stop setting swapsWelcomeMessageHasBeenShown to state in app-state controller

* Update e2e tests for whats new popup changes

* Updating migration files

* Addressing feedback part 1

* Addressing feedback part 2

* Remove unnecessary div in whats-new-popup

* Change getNotificationsToExclude to getNotificationsToInclude for use in the getSortedNotificationsToShow selector

* Delete intro-popup directory and test files

* Lint fix

* Add notifiction state to address-entry fixture

* Use two separate functions for rendering first and subsequent notifications in the whats-new-popup

* Ensure that string literals are passed to t for whats new popup text

* Update import-ui fixtures to include notificaiton controller state

* Remove unnecessary, accidental change confirm-approve

* Remove swaps notification in favour of mobile swaps as first notifcation and TBD 3rd notification

* Update whats-new-popup to use intersection observer api to detect if notification has been seen

* Add notifications to send-edit and threebox e2e test fixtures

* Update ui/app/selectors/selectors.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Update ui/app/selectors/selectors.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Clean up locale code for whats-new-popup notifications

* Disconnect observers in whats-new-popup when their callback is first called

* Add test case for migration 58 for when the AppStateController does not exist

* Rename popover components containerRef to popoverWrapRef

* Fix messages.json

* Update notification messages and images

* Rename popoverWrapRef -> popoverRef in whats-new-popup and popover.component

* Only create one observer, and only after images have loaded, in whats-new-popup

* Set width and height on whats-new-popup image, instead of setting state on img load

* Update ui/app/components/app/whats-new-popup/whats-new-popup.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Code clean up in whats new popup re: notification rendering and action functions

* Code cleanup in render notification functions of whats-new-popup

* Update ui/app/components/app/whats-new-popup/whats-new-popup.js

Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* lint fix

* Update and localize  notification dates

* Clean up date code in shred/notifications/index.js

Co-authored-by: ryanml <ryanlanese@gmail.com>
Co-authored-by: Mark Stacey <markjstacey@gmail.com>

* Revert "Implement Ledger Live bridge (#10293)"

This reverts commit 15b596ad15.

* Version v9.5.0

* Update changelog for v9.5.0

* yarn allow-scripts and yarn lavamoat:auto for Version-v9.5.0 branch

* Anchor the Need Help text to the bottom of the expanded page (#10955)

* fix transaction sync logic (#10954)

* Add backwards compatibility for ETH <-> WETH contract address validation (#10962)

* Whats new popup design fixes (#10964)

* Remove padding on QR code image

* Allow the qr code to be below the description in the whats new popup

* Fix size and position of QR code in whats new notification

* Add right caret to action links in whats new popup

* Clean up placeImageBelowDescription logic

* Fix display of whats-new-popup image

* Improve spacing and sizing of whats new popup in both full screen and popup view

* refactor

* Ensure method of adding contact when contacts exist (#10963)

* Fixing alignment issue with bottom notification (#10979)

* Revert "Adding recovery phrase video to onboarding process (#10717)"

This reverts commit 9e918b6026.

* Removing recovery video entry from changelog

* Remove tests that are only needed for the commit reverted in 68c5defc

* Fix dependency vulnerability by upgrading xmlhttprequest-ssl via yarn.lock (#10990)

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
Co-authored-by: Barry Gitarts <bgitarts@gmail.com>
Co-authored-by: Dan J Miller <danjm.com@gmail.com>
Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com>
Co-authored-by: Brad Decker <git@braddecker.dev>
Co-authored-by: ryanml <ryanlanese@gmail.com>
Co-authored-by: David Walsh <davidwalsh83@gmail.com>
Co-authored-by: Niranjana Binoy <43930900+NiranjanaBinoy@users.noreply.github.com>
Co-authored-by: Shane <jonas.shane@gmail.com>
Co-authored-by: gitpurva <47534619+gitpurva@users.noreply.github.com>
Co-authored-by: kumavis <kumavis@users.noreply.github.com>
Co-authored-by: Etienne Dusseault <etienne.dusseault@gmail.com>
Co-authored-by: kumavis <aaron@kumavis.me>
Co-authored-by: Grant Bakker <grant@bakker.pw>
Co-authored-by: Michael Standen <screaminghawk@gmail.com>
Co-authored-by: Muhammet Kara <mrkara@users.noreply.github.com>
Co-authored-by: Daniel <80175477+dan437@users.noreply.github.com>
Co-authored-by: Thomas Huang <tmashuang@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Thomas <thomas.b.huang@gmail.com>
Co-authored-by: Alex Donesky <alex.donesky@consensys.net>
Co-authored-by: Austin Akers <austin.akers5@gmail.com>
Co-authored-by: MetaMask Bot <metamaskbot@users.noreply.github.com>
feature/default_network_editable
MetaMask Bot 4 years ago committed by GitHub
parent 9367426bdf
commit 333206ccb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      .circleci/config.yml
  2. 44
      .circleci/scripts/release-bump-changelog-version.sh
  3. 10
      .circleci/scripts/release-bump-manifest-version.sh
  4. 34
      .circleci/scripts/release-commit-version-bump.sh
  5. 52
      .circleci/scripts/release-create-master-pr.sh
  6. 155
      .eslintrc.js
  7. 2
      .gitignore
  8. 1
      .prettierignore
  9. 1
      .storybook/test-data.js
  10. 1421
      CHANGELOG.md
  11. 24
      app/_locales/am/messages.json
  12. 24
      app/_locales/ar/messages.json
  13. 24
      app/_locales/bg/messages.json
  14. 24
      app/_locales/bn/messages.json
  15. 24
      app/_locales/ca/messages.json
  16. 12
      app/_locales/cs/messages.json
  17. 24
      app/_locales/da/messages.json
  18. 24
      app/_locales/de/messages.json
  19. 24
      app/_locales/el/messages.json
  20. 137
      app/_locales/en/messages.json
  21. 53
      app/_locales/es/messages.json
  22. 53
      app/_locales/es_419/messages.json
  23. 24
      app/_locales/et/messages.json
  24. 24
      app/_locales/fa/messages.json
  25. 24
      app/_locales/fi/messages.json
  26. 24
      app/_locales/fil/messages.json
  27. 24
      app/_locales/fr/messages.json
  28. 24
      app/_locales/he/messages.json
  29. 53
      app/_locales/hi/messages.json
  30. 12
      app/_locales/hn/messages.json
  31. 24
      app/_locales/hr/messages.json
  32. 15
      app/_locales/ht/messages.json
  33. 24
      app/_locales/hu/messages.json
  34. 53
      app/_locales/id/messages.json
  35. 53
      app/_locales/it/messages.json
  36. 53
      app/_locales/ja/messages.json
  37. 24
      app/_locales/kn/messages.json
  38. 56
      app/_locales/ko/messages.json
  39. 24
      app/_locales/lt/messages.json
  40. 24
      app/_locales/lv/messages.json
  41. 24
      app/_locales/ms/messages.json
  42. 12
      app/_locales/nl/messages.json
  43. 21
      app/_locales/no/messages.json
  44. 3
      app/_locales/ph/messages.json
  45. 24
      app/_locales/pl/messages.json
  46. 12
      app/_locales/pt/messages.json
  47. 24
      app/_locales/pt_BR/messages.json
  48. 24
      app/_locales/ro/messages.json
  49. 53
      app/_locales/ru/messages.json
  50. 24
      app/_locales/sk/messages.json
  51. 24
      app/_locales/sl/messages.json
  52. 24
      app/_locales/sr/messages.json
  53. 24
      app/_locales/sv/messages.json
  54. 24
      app/_locales/sw/messages.json
  55. 12
      app/_locales/ta/messages.json
  56. 12
      app/_locales/th/messages.json
  57. 53
      app/_locales/tl/messages.json
  58. 12
      app/_locales/tr/messages.json
  59. 24
      app/_locales/uk/messages.json
  60. 53
      app/_locales/vi/messages.json
  61. 53
      app/_locales/zh_CN/messages.json
  62. 24
      app/_locales/zh_TW/messages.json
  63. 15
      app/background.html
  64. 1
      app/images/address-book.svg
  65. 1
      app/images/mobile-link-qr.svg
  66. 3
      app/images/support.svg
  67. 11
      app/manifest/_base.json
  68. 6
      app/scripts/account-import-strategies/account-import-strategies.test.js
  69. 15
      app/scripts/account-import-strategies/index.js
  70. 22
      app/scripts/background.js
  71. 10
      app/scripts/controllers/app-state.js
  72. 4
      app/scripts/controllers/cached-balances.test.js
  73. 8
      app/scripts/controllers/detect-tokens.test.js
  74. 6
      app/scripts/controllers/ens/index.js
  75. 4
      app/scripts/controllers/ens/index.test.js
  76. 293
      app/scripts/controllers/incoming-transactions.js
  77. 902
      app/scripts/controllers/incoming-transactions.test.js
  78. 26
      app/scripts/controllers/metametrics.js
  79. 18
      app/scripts/controllers/metametrics.test.js
  80. 4
      app/scripts/controllers/network/createInfuraClient.js
  81. 4
      app/scripts/controllers/network/createJsonRpcClient.js
  82. 4
      app/scripts/controllers/network/network-controller.test.js
  83. 4
      app/scripts/controllers/network/pending-middleware.test.js
  84. 8
      app/scripts/controllers/permissions/index.js
  85. 18
      app/scripts/controllers/permissions/permissions-controller.test.js
  86. 18
      app/scripts/controllers/permissions/permissions-log-controller.test.js
  87. 15
      app/scripts/controllers/permissions/permissions-middleware.test.js
  88. 6
      app/scripts/controllers/permissions/permissionsLog.js
  89. 2
      app/scripts/controllers/permissions/restricted-methods.test.js
  90. 11
      app/scripts/controllers/preferences.js
  91. 25
      app/scripts/controllers/preferences.test.js
  92. 98
      app/scripts/controllers/swaps.js
  93. 289
      app/scripts/controllers/swaps.test.js
  94. 2
      app/scripts/controllers/token-rates-controller.test.js
  95. 4
      app/scripts/controllers/token-rates.js
  96. 187
      app/scripts/controllers/transactions/index.js
  97. 304
      app/scripts/controllers/transactions/index.test.js
  98. 4
      app/scripts/controllers/transactions/lib/tx-state-history-helpers.test.js
  99. 60
      app/scripts/controllers/transactions/lib/util.js
  100. 2
      app/scripts/controllers/transactions/lib/util.test.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -123,12 +123,18 @@ jobs:
- checkout
- attach_workspace:
at: .
- run:
name: Bump manifest version
command: .circleci/scripts/release-bump-manifest-version.sh
- run:
name: Update changelog
command: yarn update-changelog --rc
- run:
name: Commit changes
command: .circleci/scripts/release-commit-version-bump.sh
- run:
name: Create GitHub Pull Request for version
command: |
.circleci/scripts/release-bump-changelog-version.sh
.circleci/scripts/release-bump-manifest-version.sh
.circleci/scripts/release-create-release-pr.sh
command: .circleci/scripts/release-create-release-pr.sh
prep-deps:
executor: node-browsers
@ -438,6 +444,9 @@ jobs:
- store_artifacts:
path: coverage
destination: coverage
- store_artifacts:
path: jest-coverage
destination: jest-coverage
- store_artifacts:
path: test-artifacts
destination: test-artifacts
@ -470,9 +479,6 @@ jobs:
name: Create GitHub release
command: |
.circleci/scripts/release-create-gh-release.sh
- run:
name: Create GitHub Pull Request to sync master with develop
command: .circleci/scripts/release-create-master-pr.sh
job-publish-storybook:
executor: node-browsers
@ -498,11 +504,15 @@ jobs:
- run:
name: test:coverage
command: yarn test:coverage
- run:
name: test:coverage:jest
command: yarn test:coverage:jest
- persist_to_workspace:
root: .
paths:
- .nyc_output
- coverage
- jest-coverage
test-unit-global:
executor: node-browsers
steps:

@ -1,44 +0,0 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
version="${CIRCLE_BRANCH/Version-v/}"
if ! grep --quiet --fixed-strings "$version" CHANGELOG.md
then
printf '%s\n' 'Adding this release to CHANGELOG.md'
date_str="$(date '+%a %b %d %Y')"
cp CHANGELOG.md{,.bak}
update_headers=$(cat <<END
/## Current Develop Branch/ {
print "## Current Develop Branch\n";
print "## ${version} ${date_str}";
next;
}
{
print;
}
END
)
awk "$update_headers" CHANGELOG.md.bak > CHANGELOG.md
rm CHANGELOG.md.bak
else
printf '%s\n' "CHANGELOG.md already includes a header for ${version}"
exit 0
fi

@ -26,14 +26,4 @@ yarn prettier --write app/manifest/_base.json
if [[ -z $(git status --porcelain) ]]
then
printf '%s\n' 'App manifest version already set'
exit 0
fi
git \
-c user.name='MetaMask Bot' \
-c user.email='metamaskbot@users.noreply.github.com' \
commit --message "${CIRCLE_BRANCH/-/ }" \
CHANGELOG.md app/manifest/_base.json
repo_slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
git push "https://$GITHUB_TOKEN_USER:$GITHUB_TOKEN@github.com/$repo_slug" "$CIRCLE_BRANCH"

@ -0,0 +1,34 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
printf '%s\n' 'Commit the manifest version and changelog if the manifest has changed'
if git diff --quiet app/manifest/_base.json;
then
printf '%s\n' 'No manifest changes to commit'
exit 0
fi
git \
-c user.name='MetaMask Bot' \
-c user.email='metamaskbot@users.noreply.github.com' \
commit --message "${CIRCLE_BRANCH/-/ }" \
CHANGELOG.md app/manifest/_base.json
repo_slug="$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
git push "https://$GITHUB_TOKEN_USER:$GITHUB_TOKEN@github.com/$repo_slug" "$CIRCLE_BRANCH"

@ -1,52 +0,0 @@
#!/usr/bin/env bash
set -e
set -u
set -o pipefail
if [[ "${CI:-}" != 'true' ]]
then
printf '%s\n' 'CI environment variable must be set to true'
exit 1
fi
if [[ "${CIRCLECI:-}" != 'true' ]]
then
printf '%s\n' 'CIRCLECI environment variable must be set to true'
exit 1
fi
if [[ -z "${GITHUB_TOKEN:-}" ]]
then
printf '%s\n' 'GITHUB_TOKEN environment variable must be set'
exit 1
fi
function install_github_cli ()
{
printf '%s\n' 'Installing hub CLI'
pushd "$(mktemp -d)"
curl -sSL 'https://github.com/github/hub/releases/download/v2.11.2/hub-linux-amd64-2.11.2.tgz' | tar xz
PATH="$PATH:$PWD/hub-linux-amd64-2.11.2/bin"
popd
}
base_branch='develop'
if [[ -n "${CI_PULL_REQUEST:-}" ]]
then
printf '%s\n' 'CI_PULL_REQUEST is set, pull request already exists for this build'
exit 0
fi
install_github_cli
printf '%s\n' "Creating a Pull Request to sync 'master' with 'develop'"
if ! hub pull-request \
--message "Master => develop" --message 'Merge latest release back into develop' \
--base "$CIRCLE_PROJECT_USERNAME:$base_branch" \
--head "$CIRCLE_PROJECT_USERNAME:$CIRCLE_BRANCH";
then
printf '%s\n' 'Pull Request already exists'
fi

@ -26,7 +26,8 @@ module.exports = {
'test-*/**',
'docs/**',
'coverage/',
'app/scripts/chromereload.js',
'jest-coverage/',
'development/chromereload.js',
'app/vendor/**',
'test/e2e/send-eth-with-private-key-test/**',
'nyc_output/**',
@ -36,13 +37,11 @@ module.exports = {
extends: [
'@metamask/eslint-config',
'@metamask/eslint-config/config/nodejs',
'@metamask/eslint-config/config/mocha',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'@metamask/eslint-config-nodejs',
'prettier',
],
plugins: ['@babel', 'react', 'import', 'prettier'],
plugins: ['@babel', 'import', 'prettier'],
globals: {
document: 'readonly',
@ -50,102 +49,18 @@ module.exports = {
},
rules: {
// Prettier changes and reasoning
'prettier/prettier': 'error',
// Our eslint config has the default setting for this as error. This
// include beforeBlockComment: true, but in order to match the prettier
// spec you have to enable before and after blocks, objects and arrays
// https://github.com/prettier/eslint-config-prettier#lines-around-comment
'lines-around-comment': [
'error',
{
beforeBlockComment: true,
afterLineComment: false,
allowBlockStart: true,
allowBlockEnd: true,
allowObjectStart: true,
allowObjectEnd: true,
allowArrayStart: true,
allowArrayEnd: true,
},
],
// Prettier has some opinions on mixed-operators, and there is ongoing work
// to make the output code clear. It is better today then it was when the first
// PR to add prettier. That being said, the workaround for keeping this rule enabled
// requires breaking parts of operations into different variables -- which I believe
// to be worse. https://github.com/prettier/eslint-config-prettier#no-mixed-operators
'no-mixed-operators': 'off',
// Prettier wraps single line functions with ternaries, etc in parens by default, but
// if the line is long enough it breaks it into a separate line and removes the parens.
// The second behavior conflicts with this rule. There is some guides on the repo about
// how you can keep it enabled:
// https://github.com/prettier/eslint-config-prettier#no-confusing-arrow
// However, in practice this conflicts with prettier adding parens around short lines,
// when autofixing in vscode and others.
'no-confusing-arrow': 'off',
// There is no configuration in prettier for how it stylizes regexes, which conflicts
// with wrap-regex.
'wrap-regex': 'off',
// Prettier handles all indentation automagically. it can be configured here
// https://prettier.io/docs/en/options.html#tab-width but the default matches our
// style.
indent: 'off',
// This rule conflicts with the way that prettier breaks code across multiple lines when
// it exceeds the maximum length. Prettier optimizes for readability while simultaneously
// maximizing the amount of code per line.
'function-paren-newline': 'off',
// This rule throws an error when there is a line break in an arrow function declaration
// but prettier breaks arrow function declarations to be as readable as possible while
// still conforming to the width rules.
'implicit-arrow-linebreak': 'off',
// This rule would result in an increase in white space in lines with generator functions,
// which impacts prettier's goal of maximizing code per line and readability. There is no
// current workaround.
'generator-star-spacing': 'off',
'default-param-last': 'off',
'prefer-object-spread': 'error',
'require-atomic-updates': 'off',
'import/no-unassigned-import': 'off',
'prefer-object-spread': 'error',
'react/no-unused-prop-types': 'error',
'react/no-unused-state': 'error',
'react/jsx-boolean-value': 'error',
'react/jsx-curly-brace-presence': [
'error',
{ props: 'never', children: 'never' },
],
'react/jsx-equals-spacing': 'error',
'react/no-deprecated': 'error',
'react/default-props-match-prop-types': 'error',
'react/jsx-closing-tag-location': [
'error',
{ selfClosing: 'tag-aligned', nonEmpty: 'tag-aligned' },
],
'react/jsx-no-duplicate-props': 'error',
'react/jsx-closing-bracket-location': 'error',
'react/jsx-first-prop-new-line': ['error', 'multiline'],
'react/jsx-max-props-per-line': [
'error',
{ maximum: 1, when: 'multiline' },
],
'react/jsx-tag-spacing': [
'error',
{
closingSlash: 'never',
beforeSelfClosing: 'always',
afterOpening: 'never',
},
],
'no-invalid-this': 'off',
'@babel/no-invalid-this': 'error',
// prettier handles these
semi: 'off',
// Prettier handles this
'@babel/semi': 'off',
'mocha/no-setup-in-describe': 'off',
'node/no-process-env': 'off',
// TODO: re-enable these rules
@ -155,9 +70,28 @@ module.exports = {
},
overrides: [
{
files: ['test/e2e/**/*.js'],
files: ['ui/**/*.js', 'test/lib/render-helpers.js', 'test/jest/*.js'],
plugins: ['react'],
extends: ['plugin:react/recommended', 'plugin:react-hooks/recommended'],
rules: {
'react/no-unused-prop-types': 'error',
'react/no-unused-state': 'error',
'react/jsx-boolean-value': 'error',
'react/jsx-curly-brace-presence': [
'error',
{ props: 'never', children: 'never' },
],
'react/no-deprecated': 'error',
'react/default-props-match-prop-types': 'error',
'react/jsx-no-duplicate-props': 'error',
},
},
{
files: ['test/e2e/**/*.spec.js'],
extends: ['@metamask/eslint-config-mocha'],
rules: {
'mocha/no-hooks-for-single-case': 'off',
'mocha/no-setup-in-describe': 'off',
},
},
{
@ -173,14 +107,38 @@ module.exports = {
},
},
{
files: ['test/**/*-test.js', 'test/**/*.spec.js'],
files: ['**/*.test.js'],
excludedFiles: ['ui/**/*.test.js', 'ui/app/__mocks__/*.js'],
extends: ['@metamask/eslint-config-mocha'],
rules: {
// Mocha will re-assign `this` in a test context
'@babel/no-invalid-this': 'off',
'mocha/no-setup-in-describe': 'off',
},
},
{
files: ['development/**/*.js', 'test/e2e/benchmark.js', 'test/helper.js'],
files: ['**/__snapshots__/*.snap'],
plugins: ['jest'],
rules: {
'jest/no-large-snapshots': [
'error',
{ maxSize: 50, inlineMaxSize: 50 },
],
},
},
{
files: ['ui/**/*.test.js', 'ui/app/__mocks__/*.js'],
extends: ['@metamask/eslint-config-jest'],
rules: {
'jest/no-restricted-matchers': 'off',
'import/unambiguous': 'off',
'import/named': 'off',
},
},
{
files: [
'development/**/*.js',
'test/e2e/benchmark.js',
'test/helpers/setup-helper.js',
],
rules: {
'node/no-process-exit': 'off',
'node/shebang': 'off',
@ -198,6 +156,7 @@ module.exports = {
'test/lib/wait-until-called.js',
'test/env.js',
'test/setup.js',
'jest.config.js',
],
parserOptions: {
sourceType: 'script',

2
.gitignore vendored

@ -8,6 +8,7 @@ audit.json
app/bower_components
test/bower_components
package
.eslintcache
# IDEs
.idea
@ -28,6 +29,7 @@ app/.DS_Store
storybook-build/
coverage/
jest-coverage/
dist
builds/
builds.zip

@ -4,6 +4,7 @@ dist/**
builds/**
test-*/**
coverage/
jest-coverage/
app/vendor/**
.nyc_output/**
.vscode/**

@ -5,7 +5,6 @@ const state = {
isInitialized: true,
isUnlocked: true,
featureFlags: { sendHexData: true },
rpcUrl: 'https://rawtestrpc.metamask.io/',
identities: {
'0xfdea65c8e26263f6d9a1b5de9555d2931a33b825': {
address: '0xfdea65c8e26263f6d9a1b5de9555d2931a33b825',

File diff suppressed because it is too large Load Diff

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "መለያን በዘር ሐረግ አስመጣ"
},
"importUsingSeed": {
"message": "የመለያ የዘር ሐረግ በመጠቀም ያስመጡ"
},
"importWallet": {
"message": "ቋት አስመጣ"
},
"importYourExisting": {
"message": "ባለ 12 ቃል የዘር ሐረግን በመጠቀም ነባር ቋትዎን ያስመጡ"
},
"imported": {
"message": "ከውጭ የመጣ",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "መረጃ እና እገዛ "
},
"initialTransactionConfirmed": {
"message": "የመጀመሪያ ግብይትዎ በአውታረ መረቡ ተረጋግጧል። ወደ ኋላ ለመመለስ እሺ የሚለውን ጠቅ ያድርጉ።"
},
@ -612,12 +603,6 @@
"myAccounts": {
"message": "የእኔ መለያዎች"
},
"myWalletAccounts": {
"message": "የቋት መለያዎቼ"
},
"myWalletAccountsDescription": {
"message": "በ MetaMask የተፈጠሩ መለያዎችዎ በሙሉ በራስ ሰር መንገድ ወደዚህ ክፍል ይታከላሉ።"
},
"needEtherInWallet": {
"message": "MetaMask በመጠቀም ያልተማከሉ መተግበሪያዎች ጋር ግንኙነት ለማድረግ፣ በቋትዎ ውስጥ Ether ያስፈልግዎታል።"
},
@ -835,9 +820,6 @@
"restoreAccountWithSeed": {
"message": "መለያዎን በዘር ሐረግ ወደነበረበት ይመልሱ"
},
"restoreFromSeed": {
"message": "መለያው ወደነበረበት ይመለስ?"
},
"revealSeedWords": {
"message": "የዘር ቃላትን ይግለጹ"
},
@ -892,9 +874,6 @@
"secretBackupPhraseWarning": {
"message": "ማስጠንቀቂያ፡ የመጠባበቂያ ምዕራፍዎን በጭራሽ አይግለጹ። ይህን ሐረገ የያዘ ማንኛውም ሰው የእርስዎን Ether እስከወዲያኛው ሊወስደው ይችላል።"
},
"secretPhrase": {
"message": "ካዝናዎን ወደነበረበት ለመመለስ ሚስጥራዊ ባለ አስራ ሁለት ቃል ሐረግዎን ያስገቡ።"
},
"securityAndPrivacy": {
"message": "ደህንነት እና ግላዊነት"
},
@ -934,9 +913,6 @@
"sendAmount": {
"message": "መጠኑን ላክ"
},
"sendETH": {
"message": "ETH ላክ"
},
"sendTokens": {
"message": "ተለዋጭ ስሞችን ላክ"
},

@ -495,22 +495,13 @@
"importAccountSeedPhrase": {
"message": "استيراد حساب باستخدام عبارة الأمان"
},
"importUsingSeed": {
"message": "استيراد باستخدام عبارة أمان الحساب"
},
"importWallet": {
"message": "استيراد المحفظة"
},
"importYourExisting": {
"message": "قم باستيراد محفظتك الحالية باستخدام جملة بذرية مكونة من 12 كلمة"
},
"imported": {
"message": "المستوردة",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "المعلومات والمساعدة"
},
"initialTransactionConfirmed": {
"message": "تم تأكيد المعاملة الأولية الخاصة بك بواسطة الشبكة. انقر فوق موافق للعودة."
},
@ -608,12 +599,6 @@
"myAccounts": {
"message": "حساباتي"
},
"myWalletAccounts": {
"message": "حسابات محفظتي"
},
"myWalletAccountsDescription": {
"message": "ستتم إضافة جميع حسابات MetaMask الخاصة بك والتي تم إنشاؤها تلقائياً إلى هذا القسم."
},
"needEtherInWallet": {
"message": "للتفاعل مع التطبيقات اللامركزية باستخدام MetaMask، ستحتاج إلى الإيثير في محفظتك."
},
@ -831,9 +816,6 @@
"restoreAccountWithSeed": {
"message": "قم باستعادة حسابك بواسطة عبارة الأمان"
},
"restoreFromSeed": {
"message": "هل تريد استعادة الحساب؟"
},
"revealSeedWords": {
"message": "كشف كلمات عبارات الأمان"
},
@ -888,9 +870,6 @@
"secretBackupPhraseWarning": {
"message": "تحذير: لا تكشف مطلقاً عن عبارة الدعم الخاصة بك. يمكن لأي شخص بهذه العبارة أن يستحوذ على الأثير الخاص بك إلى الأبد."
},
"secretPhrase": {
"message": "أدخل جملتك السرية المكونة من اثني عشر كلمة هنا لاستعادة خزنتك."
},
"securityAndPrivacy": {
"message": "الأمن والخصوصية"
},
@ -930,9 +909,6 @@
"sendAmount": {
"message": "إرسال المبلغ"
},
"sendETH": {
"message": "إرسال عملة إيثيريوم"
},
"sendTokens": {
"message": "إرسال عملات رمزية"
},

@ -495,22 +495,13 @@
"importAccountSeedPhrase": {
"message": "Импортирайте акаунт с фраза зародиш"
},
"importUsingSeed": {
"message": "Импортиране с помощта на фразата зародиш на профила"
},
"importWallet": {
"message": "Импортиране на портфейла"
},
"importYourExisting": {
"message": "Импортирайте съществуващия си портфейл с помощта на фраза зародиш с 12 думи"
},
"imported": {
"message": "Импортирани",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Информация и помощ"
},
"initialTransactionConfirmed": {
"message": "Първоначалната транзакция беше потвърдена от мрежата. Кликнете върху OK, за да се върнете обратно."
},
@ -611,12 +602,6 @@
"myAccounts": {
"message": "Моите акаунти"
},
"myWalletAccounts": {
"message": "Моите акаунти в портфейла"
},
"myWalletAccountsDescription": {
"message": "Всичките ви създадени от MetaMask акаунти ще бъдат автоматично добавени в този раздел."
},
"needEtherInWallet": {
"message": "За да взаимодействате с децентрализираните приложения, използвайки MetaMask, ще ви е необходим етер в портфейла ви."
},
@ -834,9 +819,6 @@
"restoreAccountWithSeed": {
"message": "Възстановете акаунта си с фраза зародиш"
},
"restoreFromSeed": {
"message": "Да се възстанови ли акаунта?"
},
"revealSeedWords": {
"message": "Разкрий думите зародиш"
},
@ -891,9 +873,6 @@
"secretBackupPhraseWarning": {
"message": "ВНИМАНИЕ: Никога не разкривайте резервната си фраза. Всеки с тази фраза може да вземе вашия етер завинаги."
},
"secretPhrase": {
"message": "Въведете своята тайна фраза от дванадесет думи тук, за да възстановите портфейла си."
},
"securityAndPrivacy": {
"message": "Сигурност и поверителност"
},
@ -933,9 +912,6 @@
"sendAmount": {
"message": "Изпратете сумата"
},
"sendETH": {
"message": "Изпрати ETH"
},
"sendTokens": {
"message": "Изпращане на жетони"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "সড ফজ দি একটিউনট আমদি করন"
},
"importUsingSeed": {
"message": "অউনট সড ফজ বযবহর কর আমদি করন"
},
"importWallet": {
"message": "ওয়ট আমদি করন"
},
"importYourExisting": {
"message": "একটি 12 শবর সড ফজ বযবহর কর আপনর বিযমন ওয়ট আমদি করন"
},
"imported": {
"message": "আমদিত",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "তথয ও সহয়ত"
},
"initialTransactionConfirmed": {
"message": "আপনর পরমিক লনদনটিটওয়ক নিিত করিল। ফিিক আছিক করন।"
},
@ -615,12 +606,6 @@
"myAccounts": {
"message": "আমর অউনটগি"
},
"myWalletAccounts": {
"message": "আমর ওয়ট অউনটগি"
},
"myWalletAccountsDescription": {
"message": "MetaMask এর তি কর আপনর সমসত অউনটগিবয়িয়ভ এই বিগ হয়।"
},
"needEtherInWallet": {
"message": "MetaMask বযবহর কর ছড়িিিিশনগির সগ করত, আপনর ওয় ইথর লগব।"
},
@ -838,9 +823,6 @@
"restoreAccountWithSeed": {
"message": "সড ফজ দি আপনর অউনট রির করন"
},
"restoreFromSeed": {
"message": "অউনট রির করবন?"
},
"revealSeedWords": {
"message": "সড শবদগিরকশ করন"
},
@ -895,9 +877,6 @@
"secretBackupPhraseWarning": {
"message": "সতরকত: কখনও আপনর বকআপ ফজ পরকশ করবন ন। এই ফজ পউ আপনর ইথর চিরকর জনয নিিরবন।"
},
"secretPhrase": {
"message": "আপনর ভলট রির করত এখ আপনর গপন ব শবর ফজ লিন।"
},
"securityAndPrivacy": {
"message": "নিপত এবপনয়ত"
},
@ -937,9 +916,6 @@
"sendAmount": {
"message": "প অরথরি"
},
"sendETH": {
"message": "ETH পন"
},
"sendTokens": {
"message": "টনগিন"
},

@ -486,22 +486,13 @@
"importAccountSeedPhrase": {
"message": "Importa un Compte amb Phrase de Recuperació"
},
"importUsingSeed": {
"message": "Importa utilitzant la frase de seeds del compte"
},
"importWallet": {
"message": "Importar Moneder"
},
"importYourExisting": {
"message": "Importa el teu moneder utilitzant la frase de recuperació de 12 paraules"
},
"imported": {
"message": "Importats",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informació i Ajuda"
},
"initialTransactionConfirmed": {
"message": "La teva transacció inicial ha sigut confirmada per la xarxa. Fes clic a OK per tornar enrere."
},
@ -599,12 +590,6 @@
"myAccounts": {
"message": "Els meus Comptes"
},
"myWalletAccounts": {
"message": "Els meus Comptes de Moneder"
},
"myWalletAccountsDescription": {
"message": "Tots els teus comptes creats a MetaMask s'afegiran automàticament a aquesta secció."
},
"needEtherInWallet": {
"message": "Per a interactuar amb aplicacions descentralitzades fent servir MetaMask, necessitaràs Ether al teu moneder."
},
@ -816,9 +801,6 @@
"restoreAccountWithSeed": {
"message": "Restaura el teu compte amb Frase de Recuperació"
},
"restoreFromSeed": {
"message": "Restaurar compte?"
},
"revealSeedWords": {
"message": "Revelar Paraules de Recuperació"
},
@ -873,9 +855,6 @@
"secretBackupPhraseWarning": {
"message": "ATENCIÓ: No divulguis mai la teva frase de recuperació. Qualsevol amb aquesta frase pot utilitzar el teu Ether per sempre."
},
"secretPhrase": {
"message": "Introdueix aquí la teva frase secreta de dotze paraules per a recuperar la teva caixa forta."
},
"securityAndPrivacy": {
"message": "Seguretat i privacitat"
},
@ -915,9 +894,6 @@
"sendAmount": {
"message": "Enviar Quantitat"
},
"sendETH": {
"message": "Envia ETH"
},
"sendTokens": {
"message": "Enviar Fitxes"
},

@ -192,9 +192,6 @@
"message": "Importováno",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informace a nápověda"
},
"insufficientFunds": {
"message": "Nedostatek finančních prostředků."
},
@ -326,9 +323,6 @@
"resetAccount": {
"message": "Resetovat účet"
},
"restoreFromSeed": {
"message": "Obnovit z seed fráze"
},
"revealSeedWords": {
"message": "Zobrazit slova klíčové fráze"
},
@ -344,9 +338,6 @@
"searchTokens": {
"message": "Hledat tokeny"
},
"secretPhrase": {
"message": "Zadejte svých 12 slov tajné fráze k obnovení trezoru."
},
"seedPhraseReq": {
"message": "klíčové fráze mají 12 slov"
},
@ -356,9 +347,6 @@
"send": {
"message": "Odeslat"
},
"sendETH": {
"message": "Odeslat ETH"
},
"sendTokens": {
"message": "Odeslat tokeny"
},

@ -492,22 +492,13 @@
"importAccountSeedPhrase": {
"message": "Importér en Konto med Seedfrase"
},
"importUsingSeed": {
"message": "Importér ved brug af kontoens seed-sætning"
},
"importWallet": {
"message": "Importér pung"
},
"importYourExisting": {
"message": "Importér din eksisterende pung med en 12-ords seedfrase"
},
"imported": {
"message": "Importeret",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & hjælp"
},
"initialTransactionConfirmed": {
"message": "Din indledende transaktion blev bekræftet af netværket. Klik OK for at gå tilbage."
},
@ -599,12 +590,6 @@
"myAccounts": {
"message": "Mine Konti"
},
"myWalletAccounts": {
"message": "Mine Pungkonti"
},
"myWalletAccountsDescription": {
"message": "Alle dine MetaMask-oprettede konti føjes automatisk til dette afsnit."
},
"needEtherInWallet": {
"message": "Du skal have Ether i din tegnebog for at interagere med decentraliserede applikationer, der bruger MetaMask."
},
@ -819,9 +804,6 @@
"restoreAccountWithSeed": {
"message": "Gendan din konto med Seed-sætning"
},
"restoreFromSeed": {
"message": "Genopret konto?"
},
"revealSeedWords": {
"message": "Vis Seedord"
},
@ -876,9 +858,6 @@
"secretBackupPhraseWarning": {
"message": "ADVARSEL: Afslør aldrig din backup-frase. Enhver med denne frase kan tage din Ether for altid."
},
"secretPhrase": {
"message": "Indtast din hemmelige tolv ord lange sætning for at gendanne din vault."
},
"securityAndPrivacy": {
"message": "Sikkerhed & Privatliv"
},
@ -915,9 +894,6 @@
"sendAmount": {
"message": "Send Beløb"
},
"sendETH": {
"message": "Vælg ETH"
},
"sendTokens": {
"message": "Send tokens"
},

@ -487,22 +487,13 @@
"importAccountSeedPhrase": {
"message": "Ein Konto mit einem Seed-Schlüssel importieren"
},
"importUsingSeed": {
"message": "Mittels mnemonischer Phrase des Kontos importieren"
},
"importWallet": {
"message": "Wallet importieren"
},
"importYourExisting": {
"message": "Importieren Sie Ihre bestehende Wallet mit einem 12-Wort-Seed-Schlüssel"
},
"imported": {
"message": "Importiert",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & Hilfe"
},
"initialTransactionConfirmed": {
"message": "Ihre erste Transaktion wurde vom Netzwerk bestätigt. Klicken Sie auf Okay, um zurückzukehren."
},
@ -594,12 +585,6 @@
"myAccounts": {
"message": "Meine Accounts"
},
"myWalletAccounts": {
"message": "Meine Wallet-Konten"
},
"myWalletAccountsDescription": {
"message": "Jedes Ihrer von MetaMask erstellten Konten wird automatisch zu diesem Abschnitt hinzugefügt."
},
"needEtherInWallet": {
"message": "Um dezentralisierte Applikationen mit MetaMask verwenden zu können, benötigst du Ether in deiner Wallet."
},
@ -807,9 +792,6 @@
"restoreAccountWithSeed": {
"message": "Ihr Konto mit mnemonischer Phrase wiederherstellen"
},
"restoreFromSeed": {
"message": "Mit Hilfe der Seed-Wörterfolge wiederherstellen."
},
"revealSeedWords": {
"message": "Seed-Wörterfolge anzeigen"
},
@ -864,9 +846,6 @@
"secretBackupPhraseWarning": {
"message": "WARNUNG: Legen Sie niemals Ihre Sicherungsphrase offen. Mit dieser Phrase kann sich jeder Ihr Ether für immer aneignen."
},
"secretPhrase": {
"message": "Gib die 12 Wörter deiner geheimem Wörterfolge ein um deinen Vault wiederherzustellen."
},
"securityAndPrivacy": {
"message": "Sicherheit & Datenschutz"
},
@ -906,9 +885,6 @@
"sendAmount": {
"message": "Betrag senden"
},
"sendETH": {
"message": "ETH senden"
},
"sendTokens": {
"message": "Token senden"
},

@ -496,22 +496,13 @@
"importAccountSeedPhrase": {
"message": "Εισαγωγή λογαριασμού με Φράση Φύτρου"
},
"importUsingSeed": {
"message": "Εισαγωγή με χρήση φάσης σπόρου λογαριασμού"
},
"importWallet": {
"message": "Εισαγωγή Πορτοφολιού"
},
"importYourExisting": {
"message": "Εισαγάγετε το υπάρχον πορτοφόλι σας χρησιμοποιώντας μια φράση φύτρου 12 λέξεων"
},
"imported": {
"message": "Έγινε εισαγωγή",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Πληροφορίες & Βοήθεια"
},
"initialTransactionConfirmed": {
"message": "Η αρχική σας συναλλαγή επιβεβαιώθηκε από το δίκτυο. Πατήστε ΕΝΤΑΞΕΙ για επιστροφή."
},
@ -612,12 +603,6 @@
"myAccounts": {
"message": "Οι Λογαριασμοί μου"
},
"myWalletAccounts": {
"message": "Λογαριασμοί Πορτοφολιού"
},
"myWalletAccountsDescription": {
"message": "Όλοι οι λογαριασμοί σας που έχετε δημιουργήσει στο MetaMask θα προστεθούν αυτόματα σε αυτήν την ενότητα."
},
"needEtherInWallet": {
"message": "Για να αλληλεπιδράσετε με αποκεντρωμένες εφαρμογές χρησιμοποιώντας το MetaMask, θα χρειαστείτε Ether στο πορτοφόλι σας."
},
@ -835,9 +820,6 @@
"restoreAccountWithSeed": {
"message": "Επαναφέρετε τον Λογαριασμό σας με Φράση Επαναφοράς"
},
"restoreFromSeed": {
"message": "Επαναφορά λογαριασμού;"
},
"revealSeedWords": {
"message": "Αποκάλυψη Λέξεων Φύτρου"
},
@ -892,9 +874,6 @@
"secretBackupPhraseWarning": {
"message": "ΠΡΟΕΙΔΟΠΟΙΗΣΗ: Ποτέ μην αποκαλύπτετε την εφεδρική φράση. Όποιος έχει αυτή τη φράση μπορεί να πάρει τα Ether σας για πάντα."
},
"secretPhrase": {
"message": "Εισαγάγετε εδώ τη μυστική φράση δώδεκα λέξεων για να επαναφέρετε το χρηματοκιβώτιό σας."
},
"securityAndPrivacy": {
"message": "Ασφάλεια και Απόρρητο"
},
@ -934,9 +913,6 @@
"sendAmount": {
"message": "Αποστολή Ποσού"
},
"sendETH": {
"message": "Στείλτε ETH"
},
"sendTokens": {
"message": "Στείλτε Tokens"
},

@ -43,15 +43,15 @@
"activityLog": {
"message": "activity log"
},
"addAccount": {
"message": "Add an account"
},
"addAcquiredTokens": {
"message": "Add the tokens you've acquired using MetaMask"
},
"addAlias": {
"message": "Add alias"
},
"addContact": {
"message": "Add contact"
},
"addEthereumChainConfirmationDescription": {
"message": "This will allow this network to be used within MetaMask."
},
@ -69,6 +69,9 @@
"addEthereumChainConfirmationTitle": {
"message": "Allow this site to add a network?"
},
"addFriendsAndAddresses": {
"message": "Add friends and addresses you trust"
},
"addNetwork": {
"message": "Add Network"
},
@ -176,6 +179,9 @@
"asset": {
"message": "Asset"
},
"assetOptions": {
"message": "Asset options"
},
"assets": {
"message": "Assets"
},
@ -243,6 +249,9 @@
"browserNotSupported": {
"message": "Your Browser is not supported..."
},
"builContactList": {
"message": "Build your contact list"
},
"builtInCalifornia": {
"message": "MetaMask is designed and built in California."
},
@ -574,6 +583,12 @@
"editContact": {
"message": "Edit Contact"
},
"editNonceField": {
"message": "Edit Nonce"
},
"editNonceMessage": {
"message": "This is an advanced feature, use cautiously."
},
"editPermission": {
"message": "Edit Permission"
},
@ -856,28 +871,29 @@
"importAccount": {
"message": "Import Account"
},
"importAccountLinkText": {
"message": "import using seed phrase"
},
"importAccountMsg": {
"message": " Imported accounts will not be associated with your originally created MetaMask account seedphrase. Learn more about imported accounts "
},
"importAccountSeedPhrase": {
"message": "Import an account with seed phrase"
},
"importUsingSeed": {
"message": "Import using account seed phrase"
"importAccountText": {
"message": "or $1",
"description": "$1 represents the text from `importAccountLinkText` as a link"
},
"importWallet": {
"message": "Import wallet"
},
"importYourExisting": {
"message": "Import your existing wallet using a 12 word seed phrase"
"message": "Import your existing wallet using a seed phrase"
},
"imported": {
"message": "Imported",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & Help"
},
"infuraBlockedNotification": {
"message": "MetaMask is unable to connect to the blockchain host. Review possible reasons $1.",
"description": "$1 is a clickable link with with text defined by the 'here' key"
@ -1064,7 +1080,7 @@
"message": "MetaMask would like to gather usage data to better understand how our users interact with the extension. This data will be used to continually improve the usability and user experience of our product and the Ethereum ecosystem."
},
"mismatchedChain": {
"message": "This network details for this Chain ID do not match our records. We recommend that you $1 before proceeding.",
"message": "The network details for this chain ID do not match our records. We recommend that you $1 before proceeding.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
@ -1080,15 +1096,16 @@
"myAccounts": {
"message": "My Accounts"
},
"myWalletAccounts": {
"message": "My Wallet Accounts"
},
"myWalletAccountsDescription": {
"message": "All of your MetaMask created accounts will automatically be added to this section."
},
"needEtherInWallet": {
"message": "To interact with decentralized applications using MetaMask, you’ll need Ether in your wallet."
},
"needHelp": {
"message": "Need help? Contact $1",
"description": "$1 represents `needHelpLinkText`, the text which goes in the help link"
},
"needHelpLinkText": {
"message": "MetaMask Support"
},
"needImportFile": {
"message": "You must select a file to import.",
"description": "User is important an account and needs to add a file to continue"
@ -1102,9 +1119,18 @@
"networkName": {
"message": "Network Name"
},
"networkNameBSC": {
"message": "BSC"
},
"networkNameDefinition": {
"message": "The name associated with this network."
},
"networkNameEthereum": {
"message": "Ethereum"
},
"networkNameTestnet": {
"message": "Testnet"
},
"networkSettingsChainIdDescription": {
"message": "The chain ID is used for signing transactions. It must match the chain ID returned by the network. You can enter a decimal or '0x'-prefixed hexadecimal number, but we will display the number in decimal."
},
@ -1185,6 +1211,9 @@
"noWebcamFoundTitle": {
"message": "Webcam not found"
},
"nonce": {
"message": "Nonce"
},
"nonceField": {
"message": "Customize transaction nonce"
},
@ -1200,6 +1229,38 @@
"notEnoughGas": {
"message": "Not Enough Gas"
},
"notifications1Description": {
"message": "MetaMask Mobile users can now swap tokens inside their mobile wallet. Scan the QR code to get the mobile app and start swapping.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
},
"notifications1Title": {
"message": "Swapping on mobile is here!",
"description": "Title for a notification in the 'See What's New' popup. Tells users that they can now use MetaMask Swaps on Mobile."
},
"notifications2ActionText": {
"message": "Start survey",
"description": "The 'call to action' label on the button, or link, of the 'Help improve MetaMask' 'See What's New' notification. Upon clicking, users will be taken to an external page where they can complete a survey."
},
"notifications2Description": {
"message": "Please share your experience in this 5 minute survey.",
"description": "Description of a notification in the 'See What's New' popup. Further clarifies how the users can help: by completing a 5 minute survey about MetaMask."
},
"notifications2Title": {
"message": "Help improve MetaMask",
"description": "Title for a notification in the 'See What's New' popup. Asks users to take action to make MetaMask better."
},
"notifications3ActionText": {
"message": "Read more",
"description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a page about security on the metamask support website."
},
"notifications3Description": {
"message": "Stay up to date on MetaMask security best practices and get the latest security tips from official MetaMask support.",
"description": "Description of a notification in the 'See What's New' popup. Describes the information they can get on security from the linked support page."
},
"notifications3Title": {
"message": "Stay secure",
"description": "Title for a notification in the 'See What's New' popup. Encourages users to consider security."
},
"ofTextNofM": {
"message": "of"
},
@ -1381,9 +1442,6 @@
"restoreAccountWithSeed": {
"message": "Restore your Account with Seed Phrase"
},
"restoreFromSeed": {
"message": "Restore account?"
},
"restoreWalletPreferences": {
"message": "A backup of your data from $1 has been found. Would you like to restore your wallet preferences?",
"description": "$1 is the date at which the data was backed up"
@ -1455,7 +1513,7 @@
"message": "WARNING: Never disclose your backup phrase. Anyone with this phrase can take your Ether forever."
},
"secretPhrase": {
"message": "Enter your secret twelve word phrase here to restore your vault."
"message": "Enter your secret phrase here to restore your vault."
},
"securityAndPrivacy": {
"message": "Security & Privacy"
@ -1511,9 +1569,6 @@
"sendAmount": {
"message": "Send Amount"
},
"sendETH": {
"message": "Send ETH"
},
"sendSpecifiedTokens": {
"message": "Send $1",
"description": "Symbol of the specified token"
@ -1660,6 +1715,9 @@
"submitted": {
"message": "Submitted"
},
"support": {
"message": "Support"
},
"supportCenter": {
"message": "Visit our Support Center"
},
@ -1745,24 +1803,6 @@
"swapHighSlippageWarning": {
"message": "Slippage amount is very high. Make sure you know what you are doing!"
},
"swapIntroLearnMoreHeader": {
"message": "Want to learn more?"
},
"swapIntroLearnMoreLink": {
"message": "Learn more about MetaMask Swaps"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Liquidity sources include:"
},
"swapIntroPopupSubTitle": {
"message": "You can now swap tokens directly in your MetaMask wallet. MetaMask Swaps combines multiple decentralized exchange aggregators, professional market makers, and individual DEXs to ensure MetaMask users always get the best price with the lowest network fees."
},
"swapIntroPopupTitle": {
"message": "Token swapping is here!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Review our official contracts audit"
},
"swapLowSlippageError": {
"message": "Transaction may fail, max slippage too low."
},
@ -1788,7 +1828,7 @@
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "The network fee covers the cost of processing your swap and storing it on the Ethereum network. MetaMask does not profit from this fee."
"message": "The network fee covers the cost of processing your swap and storing it on the $1 network. MetaMask does not profit from this fee."
},
"swapNewQuoteIn": {
"message": "New quotes in $1",
@ -1889,9 +1929,6 @@
"swapSourceInfo": {
"message": "We search multiple liquidity sources (exchanges, aggregators and professional market makers) to find the best rates and lowest network fees."
},
"swapStartSwapping": {
"message": "Start swapping"
},
"swapSwapFrom": {
"message": "Swap from"
},
@ -2057,9 +2094,6 @@
"tokenContractAddress": {
"message": "Token Contract Address"
},
"tokenOptions": {
"message": "Token options"
},
"tokenSymbol": {
"message": "Token Symbol"
},
@ -2222,6 +2256,9 @@
"walletSeed": {
"message": "Seed phrase"
},
"walletSeedRestore": {
"message": "Wallet Seed"
},
"web3ShimUsageNotification": {
"message": "We noticed that the current website tried to use the removed window.web3 API. If the site appears to be broken, please click $1 for more information.",
"description": "$1 is a clickable link."
@ -2232,6 +2269,10 @@
"welcomeBack": {
"message": "Welcome Back!"
},
"whatsNew": {
"message": "What's new",
"description": "This is the title of a popup that gives users notifications about new features and updates to MetaMask."
},
"whatsThis": {
"message": "What's this?"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "registro de actividades"
},
"addAccount": {
"message": "Agregar una cuenta"
},
"addAcquiredTokens": {
"message": "Agregar los tokens que has adquirido usando MetaMask"
},
@ -790,22 +787,13 @@
"importAccountSeedPhrase": {
"message": "Importar una cuenta con la frase semilla"
},
"importUsingSeed": {
"message": "Importar usando la frase semilla de la cuenta"
},
"importWallet": {
"message": "Importar Monedero"
},
"importYourExisting": {
"message": "Importa tu monedero existente usando la frase semilla de 12 palabras"
},
"imported": {
"message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Información y ayuda"
},
"initialTransactionConfirmed": {
"message": "La red confirmó tu transacción inicial. Hazle clic en Ok para volver."
},
@ -993,12 +981,6 @@
"myAccounts": {
"message": "Mis cuentas"
},
"myWalletAccounts": {
"message": "Mis cuentas de monedero"
},
"myWalletAccountsDescription": {
"message": "Todas tus cuentas creadas con MetaMask serán automáticamente agregadas a esta sección."
},
"needEtherInWallet": {
"message": "Para interactuar con una aplicación descentralizada usando MetaMask, necesitas tener Ether en tu monedero"
},
@ -1282,9 +1264,6 @@
"restoreAccountWithSeed": {
"message": "Restaurar tu Cuenta con la Frase Semilla"
},
"restoreFromSeed": {
"message": "¿Restaurar cuenta?"
},
"restoreWalletPreferences": {
"message": "Se ha encontrado una copia de seguridad de sus datos de $1. ¿Le gustaría restaurar sus preferencias de monedero?",
"description": "$1 is the date at which the data was backed up"
@ -1355,9 +1334,6 @@
"secretBackupPhraseWarning": {
"message": "ADVERTENCIA: Nunca revele su frase de respaldo. Cualquiera con esta frase puede tomar su Ether para siempre."
},
"secretPhrase": {
"message": "Ingresa tu frase de doce (12) palabras para restaurar tu bóveda."
},
"securityAndPrivacy": {
"message": "Seguridad y Privacidad"
},
@ -1409,9 +1385,6 @@
"sendAmount": {
"message": "Enviar cantidad"
},
"sendETH": {
"message": "Enviar ETH"
},
"sendSpecifiedTokens": {
"message": "Enviar $1",
"description": "Symbol of the specified token"
@ -1639,24 +1612,6 @@
"swapHighSlippageWarning": {
"message": "La cantidad de deslizamiento es muy alta. ¡Asegúrate de saber lo que estás haciendo!"
},
"swapIntroLearnMoreHeader": {
"message": "¿Quiere aprender más?"
},
"swapIntroLearnMoreLink": {
"message": "Más información sobre los Intercambios MetaMask"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Las fuentes de liquidez incluyen:"
},
"swapIntroPopupSubTitle": {
"message": "Ahora puede intercambiar tokens directamente en su monedero MetaMask. Intercambios MetaMask combina múltiples agregadores de intercambio descentralizados, creadores de mercado profesionales y DEX individuales para garantizar que los usuarios de MetaMask siempre obtengan el mejor precio con las tarifas de red más bajas."
},
"swapIntroPopupTitle": {
"message": "¡El intercambio de tokens está aquí!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Revise nuestra auditoría de contratos oficiales"
},
"swapLowSlippageError": {
"message": "La transacción puede fallar, el deslizamiento máximo es demasiado bajo."
},
@ -1682,7 +1637,7 @@
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "La tarifa de la red cubre el costo de procesar su intercambio y almacenarlo en la red Ethereum. MetaMask no se beneficia de esta tarifa."
"message": "La tarifa de la red cubre el costo de procesar su intercambio y almacenarlo en la red $1. MetaMask no se beneficia de esta tarifa."
},
"swapNewQuoteIn": {
"message": "Nuevas cotizaciones en $1",
@ -1777,9 +1732,6 @@
"swapSourceInfo": {
"message": "Buscamos múltiples fuentes de liquidez (exchanges, agregadores y creadores de mercado profesionales) para encontrar las mejores tarifas y las tarifas de red más bajas."
},
"swapStartSwapping": {
"message": "Comenzar intercambio"
},
"swapSwapFrom": {
"message": "Intercambiar desde"
},
@ -1915,9 +1867,6 @@
"tokenContractAddress": {
"message": "Dirección del contrato de token"
},
"tokenOptions": {
"message": "Opciones del Token"
},
"tokenSymbol": {
"message": "Símbolo del token"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "registro de actividad"
},
"addAccount": {
"message": "Agregar una cuenta"
},
"addAcquiredTokens": {
"message": "Agrega los tokens adquiridos con MetaMask"
},
@ -790,22 +787,13 @@
"importAccountSeedPhrase": {
"message": "Importar una cuenta con frase semilla"
},
"importUsingSeed": {
"message": "Importar usando la frase semilla de la cuenta"
},
"importWallet": {
"message": "Importar billetera"
},
"importYourExisting": {
"message": "Importa tu billetera existente con una frase semilla de 12 palabras"
},
"imported": {
"message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Información y ayuda"
},
"initialTransactionConfirmed": {
"message": "La red ha confirmado tu transacción inicial. Haz clic en Aceptar para volver."
},
@ -993,12 +981,6 @@
"myAccounts": {
"message": "Mis cuentas"
},
"myWalletAccounts": {
"message": "Las cuentas de mi billetera"
},
"myWalletAccountsDescription": {
"message": "Todas tus cuentas creadas en MetaMask se agregarán automáticamente a esta sección."
},
"needEtherInWallet": {
"message": "Necesitarás tener Ether en tu billetera para poder interactuar con aplicaciones descentralizadas a través de MetaMask."
},
@ -1282,9 +1264,6 @@
"restoreAccountWithSeed": {
"message": "Restaura tu Cuenta con la Frase Semilla"
},
"restoreFromSeed": {
"message": "¿Restaurar cuenta?"
},
"restoreWalletPreferences": {
"message": "Se ha encontrado una copia de seguridad de sus datos de $1. ¿Le gustaría restaurar sus preferencias de billetera?",
"description": "$1 is the date at which the data was backed up"
@ -1355,9 +1334,6 @@
"secretBackupPhraseWarning": {
"message": "ADVERTENCIA: Nunca reveles tu frase de respaldo. Cualquier persona que tenga acceso a esta frase puede llevarse tus Ether permanentemente."
},
"secretPhrase": {
"message": "Ingresa tu frase secreta de doce palabras para restaurar tu almacén."
},
"securityAndPrivacy": {
"message": "Seguridad y privacidad"
},
@ -1409,9 +1385,6 @@
"sendAmount": {
"message": "Enviar monto"
},
"sendETH": {
"message": "Enviar ETH"
},
"sendSpecifiedTokens": {
"message": "Enviar $1",
"description": "Symbol of the specified token"
@ -1639,24 +1612,6 @@
"swapHighSlippageWarning": {
"message": "La cantidad de deslizamiento es muy alta. ¡Asegúrate de saber lo que estás haciendo!"
},
"swapIntroLearnMoreHeader": {
"message": "¿Quiere aprender más?"
},
"swapIntroLearnMoreLink": {
"message": "Más información sobre los Intercambios MetaMask"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Las fuentes de liquidez incluyen:"
},
"swapIntroPopupSubTitle": {
"message": "Ahora puede intercambiar tokens directamente en su billetera MetaMask. Intercambios MetaMask combina múltiples agregadores de intercambio descentralizados, creadores de mercado profesionales y DEX individuales para garantizar que los usuarios de MetaMask siempre obtengan el mejor precio con las tarifas de red más bajas."
},
"swapIntroPopupTitle": {
"message": "¡El intercambio de tokens está aquí!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Revise nuestra auditoría de contratos oficiales"
},
"swapLowSlippageError": {
"message": "La transacción puede fallar, el deslizamiento máximo es demasiado bajo."
},
@ -1682,7 +1637,7 @@
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "La tarifa de la red cubre el costo de procesar su intercambio y almacenarlo en la red Ethereum. MetaMask no se beneficia de esta tarifa."
"message": "La tarifa de la red cubre el costo de procesar su intercambio y almacenarlo en la red $1. MetaMask no se beneficia de esta tarifa."
},
"swapNewQuoteIn": {
"message": "Nuevas cotizaciones en $1",
@ -1777,9 +1732,6 @@
"swapSourceInfo": {
"message": "Buscamos múltiples fuentes de liquidez (exchanges, agregadores y creadores de mercado profesionales) para encontrar las mejores tarifas y las tarifas de red más bajas."
},
"swapStartSwapping": {
"message": "Comenzar intercambio"
},
"swapSwapFrom": {
"message": "Intercambiar desde"
},
@ -1915,9 +1867,6 @@
"tokenContractAddress": {
"message": "Dirección de contrato del token"
},
"tokenOptions": {
"message": "Opciones del Token"
},
"tokenSymbol": {
"message": "Símbolo del token"
},

@ -495,22 +495,13 @@
"importAccountSeedPhrase": {
"message": "Impordi seemnefraasiga konto"
},
"importUsingSeed": {
"message": "Impordi konto seemnefraasi abil"
},
"importWallet": {
"message": "Importige rahakott"
},
"importYourExisting": {
"message": "Importige 12-sõnalise seemnefraasi abil olemasolev rahakott"
},
"imported": {
"message": "Imporditud",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Teave ja abi"
},
"initialTransactionConfirmed": {
"message": "Võrk kinnitas teie algse tehingu. Tagasi minemiseks klõpsake OK-nuppu."
},
@ -605,12 +596,6 @@
"myAccounts": {
"message": "Minu kontod"
},
"myWalletAccounts": {
"message": "Minu rahakotikontod"
},
"myWalletAccountsDescription": {
"message": "Sellesse jaotisesse lisatakse automaatselt kõik teie MetaMaski kontod."
},
"needEtherInWallet": {
"message": "Selleks, et suhelda MetaMaski abil detsentraliseeritud rakendustega, peab teil rahakotis eetrit olema."
},
@ -828,9 +813,6 @@
"restoreAccountWithSeed": {
"message": "Taastage konto seemnefraasi abil"
},
"restoreFromSeed": {
"message": "Taastada konto?"
},
"revealSeedWords": {
"message": "Kuva seemnesõnu"
},
@ -885,9 +867,6 @@
"secretBackupPhraseWarning": {
"message": "HOIATUS! Ärge avaldage kunagi oma varundusfraasi. Selle fraasiga on võimalik teie eeter igaveseks ära võtta."
},
"secretPhrase": {
"message": "Sisestage hoidla taastamiseks oma salajane 12-sõnaline fraas."
},
"securityAndPrivacy": {
"message": "Turvalisus ja privaatsus"
},
@ -927,9 +906,6 @@
"sendAmount": {
"message": "Saatke kogus"
},
"sendETH": {
"message": "Saada ETH"
},
"sendTokens": {
"message": "Saada lube"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "یک حساب با عبارت بازیاب را وارد کنید"
},
"importUsingSeed": {
"message": "وارد کردن با استفاده از عبارت بازیاب حساب"
},
"importWallet": {
"message": "وارد سازی کیف"
},
"importYourExisting": {
"message": "کیف موجود تان را با استفاده از عبارت رمزیاب 12 کلمه یی وارد کنید"
},
"imported": {
"message": "وارد شده",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "معلومات و کمک"
},
"initialTransactionConfirmed": {
"message": "معامله آغازین تان توسط شبکه تأیید شد. برای رفتن به عقب بالای OK کلیک کنید."
},
@ -615,12 +606,6 @@
"myAccounts": {
"message": "حساب های من"
},
"myWalletAccounts": {
"message": "حساب های کیف من"
},
"myWalletAccountsDescription": {
"message": "همه حساب های ایجاد شده MetaMask شما بصورت خودکار در این بخش اضافه خواهد شد."
},
"needEtherInWallet": {
"message": "برای تعامل با اپلیکیشن های غیر متمرکز شده با استفاده از MetaMask، شما نیاز به ایتر در کیف تان خواهید داشت."
},
@ -838,9 +823,6 @@
"restoreAccountWithSeed": {
"message": "حساب تان را با عبارت بازیاب، بازیابی کنید"
},
"restoreFromSeed": {
"message": "بازگرداندن حساب؟"
},
"revealSeedWords": {
"message": "کلمات بازیاب را آشکار کنید"
},
@ -895,9 +877,6 @@
"secretBackupPhraseWarning": {
"message": "هشدار: هرگز عبارت پشتیبان تان را به کسی فاش نسازید. هرکسیکه این عبارت را داشته باشد ایتر شما را برای همیشه خواهد گرفت."
},
"secretPhrase": {
"message": "جهت بازیابی خزانه تان عبارت دوازده کلمه یی تان را اینجا وارد کنید."
},
"securityAndPrivacy": {
"message": "امنیت و حریم خصوصی"
},
@ -937,9 +916,6 @@
"sendAmount": {
"message": "ارسال مبلغ"
},
"sendETH": {
"message": "ارسال ETH"
},
"sendTokens": {
"message": "رمزیاب ها را ارسال کنید"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "Tuo tili siemenlauseella"
},
"importUsingSeed": {
"message": "Tuo käyttäen tilin siemenlausetta"
},
"importWallet": {
"message": "Tuo kukkaro"
},
"importYourExisting": {
"message": "Tuo nykyinen lompakkosi käyttäen 12 sanan \n siemenlausetta"
},
"imported": {
"message": "Tuotu",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Tietoja ja ohje"
},
"initialTransactionConfirmed": {
"message": "Verkko hyväksyi alkuperäisen tapahtumasi. Siirry takaisin napsauttamalla OK-painiketta."
},
@ -615,12 +606,6 @@
"myAccounts": {
"message": "Omat tilit"
},
"myWalletAccounts": {
"message": "Omat kukkarotilini"
},
"myWalletAccountsDescription": {
"message": "Kaikki MetaMaskilla luodut tilisi lisätään automaattisesti tähän osastoon."
},
"needEtherInWallet": {
"message": "Ollaksesi vuorovaikutuksessa hajautettujen sovellusten kanssa sinulla on oltava lompakossasi Ether."
},
@ -835,9 +820,6 @@
"restoreAccountWithSeed": {
"message": "Palauta tilisi käyttäen salaustekstiä (seed phrase)"
},
"restoreFromSeed": {
"message": "Palautetaanko tili?"
},
"revealSeedWords": {
"message": "Paljasta salaussanat"
},
@ -892,9 +874,6 @@
"secretBackupPhraseWarning": {
"message": "VAROITUS: älä koskaan kerro varmuuskopiolausettasi kenellekään. Kuka tahansa tämän lauseen omaava voi napata Etherisi pysyvästi."
},
"secretPhrase": {
"message": "Palauta holvisi syöttämällä tähän salainen kahdentoista sanan tekstisi."
},
"securityAndPrivacy": {
"message": "Turva & yksityisyys"
},
@ -934,9 +913,6 @@
"sendAmount": {
"message": "Lähetä summa"
},
"sendETH": {
"message": "Lähetä ETH:iä"
},
"sendTokens": {
"message": "Lähetä tietueita"
},

@ -456,22 +456,13 @@
"importAccountSeedPhrase": {
"message": "Mag-import ng Account gamit ang Seed Phrase"
},
"importUsingSeed": {
"message": "Mag-import gamit ang seed phrase ng account"
},
"importWallet": {
"message": "Mag-import ng Wallet"
},
"importYourExisting": {
"message": "I-import ang kasalukuyan mong wallet gamit ang isang seed phrase na may 12 salita"
},
"imported": {
"message": "Na-import",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Impormasyon at Tulong"
},
"initialTransactionConfirmed": {
"message": "Nakumpirma ng network ang iyong unang transaksyon. I-click ang OK para bumalik."
},
@ -553,12 +544,6 @@
"myAccounts": {
"message": "Mga Account Ko"
},
"myWalletAccounts": {
"message": "Mga Wallet Account Ko"
},
"myWalletAccountsDescription": {
"message": "Ang lahat ng iyong account na ginawa sa MetaMask ay awtomatikong idadagdag sa seksyong ito."
},
"needEtherInWallet": {
"message": "Para gumamit ng mga decentralized na application gamit ang MetaMask, mangangailangan ka ng Ether sa iyong wallet."
},
@ -762,9 +747,6 @@
"restoreAccountWithSeed": {
"message": "I-restore ang iyong Account gamit ang Seed Phrase"
},
"restoreFromSeed": {
"message": "I-restore ang account?"
},
"revealSeedWords": {
"message": "Ipakita ang Seed Words"
},
@ -807,9 +789,6 @@
"secretBackupPhraseWarning": {
"message": "BABALA: Huwag ibunyag ang iyong backup phrase. Mananakaw ng kahit sinong may ganitong parirala ang iyong Ether at hindi na ito maibabalik."
},
"secretPhrase": {
"message": "Ilagay ang iyong lihim na pariralang may labindalawang salita para ma-restore ang iyong vault."
},
"securityAndPrivacy": {
"message": "Seguridad at Privacy"
},
@ -849,9 +828,6 @@
"sendAmount": {
"message": "Magpadala ng Halaga"
},
"sendETH": {
"message": "Magpadala ng ETH"
},
"sendTokens": {
"message": "Magpadala ng Mga Token"
},

@ -490,22 +490,13 @@
"importAccountSeedPhrase": {
"message": "Importez un compte avec une phrase mnémotechnique"
},
"importUsingSeed": {
"message": "Importer à partir de la phrase Seed du compte"
},
"importWallet": {
"message": "Importer le portefeuille"
},
"importYourExisting": {
"message": "Importez votre portefeuille existant à l'aide d'une phrase mnémotechnique de 12 mots"
},
"imported": {
"message": "Importé",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & Aide"
},
"initialTransactionConfirmed": {
"message": "Votre transaction initiale a été confirmée par le réseau. Cliquez sur OK pour retourner à l'écran précédent."
},
@ -600,12 +591,6 @@
"myAccounts": {
"message": "Mes comptes"
},
"myWalletAccounts": {
"message": "Mes comptes de portefeuille"
},
"myWalletAccountsDescription": {
"message": "Tous vos comptes MetaMask créés seront automatiquement ajoutés à cette section."
},
"needEtherInWallet": {
"message": "Pour interagir avec des applications décentralisées à l'aide de MetaMask, vous avez besoin d'Ether dans votre portefeuille."
},
@ -820,9 +805,6 @@
"restoreAccountWithSeed": {
"message": "Restaurer votre compte avec une phrase Seed."
},
"restoreFromSeed": {
"message": "Restaurer le compte ?"
},
"revealSeedWords": {
"message": "Révéler les mots Seed"
},
@ -877,9 +859,6 @@
"secretBackupPhraseWarning": {
"message": "AVERTISSEMENT : ne révélez jamais votre phrase de sauvegarde. N'importe qui avec cette phrase peut voler votre Ether pour toujours."
},
"secretPhrase": {
"message": "Entrez vos 12 mots secrets de votre phrase Seed pour restaurer votre coffre."
},
"securityAndPrivacy": {
"message": "Sécurité et confidentialité"
},
@ -919,9 +898,6 @@
"sendAmount": {
"message": "Envoyer le montant"
},
"sendETH": {
"message": "Envoyer des ETH"
},
"sendTokens": {
"message": "Envoyer des jetons"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "יבא חשבון באמצעות Seed Phrase"
},
"importUsingSeed": {
"message": "ייבא באמצעות צירוף הגרעין של החשבון"
},
"importWallet": {
"message": "ייבא ארנק"
},
"importYourExisting": {
"message": "יבא/י את הארנק הקיים שלך באמצעות seed phrase בן 12 מילים"
},
"imported": {
"message": "מיובאות",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "מידע ועזרה"
},
"initialTransactionConfirmed": {
"message": "העסקה הראשונית שלך אושרה על ידי הרשת. לחצ/י על אישור כדי לחזור."
},
@ -612,12 +603,6 @@
"myAccounts": {
"message": "החשבונות שלי"
},
"myWalletAccounts": {
"message": "חשבונות הארנק שלי"
},
"myWalletAccountsDescription": {
"message": "כל חשבונותיך שנוצרו ב-MetaMask יתווספו אוטומטית לחלק זה."
},
"needEtherInWallet": {
"message": "כדי לתקשר עם אפליקציות מבוזרות באמצעות MetaMask, צריך להיות לך את'ר בארנק."
},
@ -835,9 +820,6 @@
"restoreAccountWithSeed": {
"message": "שחזר את חשבונך באמצעות צירוף הגרעין"
},
"restoreFromSeed": {
"message": "לשחזר את החשבון?"
},
"revealSeedWords": {
"message": "גלה מילות Seed"
},
@ -889,9 +871,6 @@
"secretBackupPhraseWarning": {
"message": "אזהרה: לעולם אין לחשוף את צירוף הגיבוי שלך. כל מי שברשותו צירוף זה יכול לקחת את האת'ר שלך לצמיתות."
},
"secretPhrase": {
"message": "הזנ/י את הצירוף הסודי שלך של שתים-עשרה המילים כאן כדי לשחזר את הכספת שלך."
},
"securityAndPrivacy": {
"message": "אבטחה ופרטיות"
},
@ -931,9 +910,6 @@
"sendAmount": {
"message": "שלח סכום"
},
"sendETH": {
"message": "שלח/י ETH"
},
"sendTokens": {
"message": "שלח טוקנים"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "गतिििग"
},
"addAccount": {
"message": "एक ख"
},
"addAcquiredTokens": {
"message": "आपक MetaMask क उपयग करकत किए गए टकन ज"
},
@ -781,22 +778,13 @@
"importAccountSeedPhrase": {
"message": "सडफथ कई ख आयत कर"
},
"importUsingSeed": {
"message": "खडफ उपयग करक आयत कर"
},
"importWallet": {
"message": "वट आयत कर"
},
"importYourExisting": {
"message": "12 शबद कडफ उपयग करक अपनट क आयत कर"
},
"imported": {
"message": "आयित",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "जनक और मदद"
},
"initialTransactionConfirmed": {
"message": "नटवरक द आपकिक लनदन कि गई थ। वपस जिए ठक पर किक कर।"
},
@ -984,12 +972,6 @@
"myAccounts": {
"message": "म"
},
"myWalletAccounts": {
"message": "मट ख"
},
"myWalletAccountsDescription": {
"message": "आपक सभ MetaMask निित खवत इस अनग मिए ज।"
},
"needEtherInWallet": {
"message": "MetaMask क उपयग करकित एपिशन कथ सहभि करनिए, आपक अपनट म Ether क आवशयकत।"
},
@ -1273,9 +1255,6 @@
"restoreAccountWithSeed": {
"message": "सड फथ अपननरित कर"
},
"restoreFromSeed": {
"message": "खनरित कर?"
},
"restoreWalletPreferences": {
"message": "$1 स आपककअप मि। क आप अपनट वरयतनरित करनहत?",
"description": "$1 is the date at which the data was backed up"
@ -1346,9 +1325,6 @@
"secretBackupPhraseWarning": {
"message": "चवन: कभ अपनकअप वश क न कर। इस वश कथ कई भ आपक Ether क हमिए ल सकत।"
},
"secretPhrase": {
"message": "अपनिनरित करनिए अपनत बरह शबद वश क यह दरज कर।"
},
"securityAndPrivacy": {
"message": "सरक और गपनयत"
},
@ -1400,9 +1376,6 @@
"sendAmount": {
"message": "रि"
},
"sendETH": {
"message": "ETH भ"
},
"sendSpecifiedTokens": {
"message": "$1 भ",
"description": "Symbol of the specified token"
@ -1627,24 +1600,6 @@
"swapHighSlippageWarning": {
"message": "सिज रि बहत अधिक ह। सिित करि आप जनति आप क कर रह!"
},
"swapIntroLearnMoreHeader": {
"message": "अधिक सखनहत?"
},
"swapIntroLearnMoreLink": {
"message": "MetaMask सप क अधिक ज"
},
"swapIntroLiquiditySourcesLabel": {
"message": "चलनिििन शिल ह:"
},
"swapIntroPopupSubTitle": {
"message": "अब आप अपन MetaMask वट मकन सप कर सकत। MetaMask सप कई वित वििमय एगटर, पवर बर नि और वयकिगत DEX क, ति MetaMask उपयगकर हम सबस कम नटवरक शक कथ सबस अचय मिल सक।"
},
"swapIntroPopupTitle": {
"message": "टकन सिग यह उपलबध ह!"
},
"swapLearnMoreContractsAuditReview": {
"message": "हम आधििक अन ऑडिट क सम कर"
},
"swapLowSlippageError": {
"message": "लनदन विफल ह सकत, अधिकतम सिज बहत कम ह सकत।"
},
@ -1666,7 +1621,7 @@
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNetworkFeeSummary": {
"message": "नटवरक शक आपकप कित करनक और उस Ethereumटवरक पर सरह करन कवर करत। MetaMask इस शक सभ नह कम।"
"message": "नटवरक शक आपकप कित करनक और उस $1टवरक पर सरह करन कवर करत। MetaMask इस शक सभ नह कम।"
},
"swapNewQuoteIn": {
"message": "$1 म नए उदधरण",
@ -1747,9 +1702,6 @@
"swapSourceInfo": {
"message": "हम सरतम दर और ननतम नटवरक शक क पत लगिए कई चलनिि (एकसचज, एगटर और पवर बर नि) कज करत।"
},
"swapStartSwapping": {
"message": "सप करन कर"
},
"swapSwapFrom": {
"message": "इससप कर"
},
@ -1879,9 +1831,6 @@
"tokenContractAddress": {
"message": "टकन अनध पत"
},
"tokenOptions": {
"message": "टकन किकलप"
},
"tokenSymbol": {
"message": "टकन करतक"
},

@ -172,9 +172,6 @@
"message": "आयित",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "जनक और सहयत"
},
"insufficientFunds": {
"message": "अपरत धन"
},
@ -303,9 +300,6 @@
"resetAccount": {
"message": "खट कर"
},
"restoreFromSeed": {
"message": "बज वश सनरित कर"
},
"revealSeedWords": {
"message": "बज शबद परकट कर"
},
@ -324,9 +318,6 @@
"search": {
"message": "खज कर"
},
"secretPhrase": {
"message": "अपनत बरह शबद वश यह अपनिनरित करनिए दरज कर।"
},
"seedPhraseReq": {
"message": "बज वश 12 शबद ल"
},
@ -336,9 +327,6 @@
"send": {
"message": "भ"
},
"sendETH": {
"message": "भ ETH"
},
"sendTokens": {
"message": "भकन"
},

@ -495,22 +495,13 @@
"importAccountSeedPhrase": {
"message": "Uvezi račun početnom rečenicom"
},
"importUsingSeed": {
"message": "Uvezi početnom rečenicom za račun"
},
"importWallet": {
"message": "Uvezi novčanik"
},
"importYourExisting": {
"message": "Uvezite svoj postojeći novčanik početnom rečenicom od 12 riječi"
},
"imported": {
"message": "Uvezeno",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informacije i pomoć"
},
"initialTransactionConfirmed": {
"message": "Vašu je početnu transakciju potvrdila mreža. Kliknite na U REDU za natrag."
},
@ -608,12 +599,6 @@
"myAccounts": {
"message": "Moji računi"
},
"myWalletAccounts": {
"message": "Moji računi za novčanik"
},
"myWalletAccountsDescription": {
"message": "Svi se vaši računi za MetaMask automatski dodaju u ovaj odjeljak."
},
"needEtherInWallet": {
"message": "Trebate Ether u svojem novčaniku kako biste ostvarili interakciju s decentraliziranim aplikacijama uporabom usluge MetaMask. "
},
@ -831,9 +816,6 @@
"restoreAccountWithSeed": {
"message": "Obnovite svoj račun početnom rečenicom"
},
"restoreFromSeed": {
"message": "Obnoviti račun?"
},
"revealSeedWords": {
"message": "Otkrij početne riječi"
},
@ -888,9 +870,6 @@
"secretBackupPhraseWarning": {
"message": "UPOZORENJE: nikada ne otkrivajte svoju alternativnu rečenicu. Bilo tko ovom rečenicom može zauvijek preuzeti vaš Ether."
},
"secretPhrase": {
"message": "Ovdje upišite svoju tajnu rečenicu od 12 riječi kako biste obnovili svoj sef."
},
"securityAndPrivacy": {
"message": "Sigurnost i privatnost"
},
@ -930,9 +909,6 @@
"sendAmount": {
"message": "Odaberi iznos"
},
"sendETH": {
"message": "Pošalji ETH"
},
"sendTokens": {
"message": "Pošalji tokene"
},

@ -282,16 +282,10 @@
"importAccountMsg": {
"message": " Kont pòte pa pral asosye avèk orijinal ou te kreye nan kont MetaMask seed fraz. Aprann plis sou kont enpòte "
},
"importUsingSeed": {
"message": "Pòte lè sèvi avèk seed fraz"
},
"imported": {
"message": "Pòte",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Enfo & Èd"
},
"initialTransactionConfirmed": {
"message": "Premye tranzaksyon ou konfime sou rezo a. Klike sou OK pou tounen."
},
@ -516,9 +510,6 @@
"restoreAccountWithSeed": {
"message": "Retabli kont ou avèk yo Seed Fraz"
},
"restoreFromSeed": {
"message": "Restore kont?"
},
"revealSeedWords": {
"message": "Revele Seed Mo Yo"
},
@ -561,9 +552,6 @@
"searchTokens": {
"message": "Rechèch Tokens"
},
"secretPhrase": {
"message": "Antre fraz sekrè douz mo ou a pou w restore kòf ou a."
},
"seedPhraseReq": {
"message": "Seed fraz yo se 12 long mo"
},
@ -585,9 +573,6 @@
"send": {
"message": "Voye"
},
"sendETH": {
"message": "Voye ETH"
},
"sendTokens": {
"message": "Voye Tokens"
},

@ -495,22 +495,13 @@
"importAccountSeedPhrase": {
"message": "Fiók importálása seed mondat segítségével"
},
"importUsingSeed": {
"message": "Importálás a fiók seed mondatának használatával"
},
"importWallet": {
"message": "Pénztárca importálása"
},
"importYourExisting": {
"message": "Importálja meglévő pénztárcáját a 12 szóból álló seed mondat segítségével"
},
"imported": {
"message": "Importált",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Információk és súgó"
},
"initialTransactionConfirmed": {
"message": "Eredeti tranzakciódat jóváhagyta a hálózat. A visszatéréshez kattints az OK-ra."
},
@ -608,12 +599,6 @@
"myAccounts": {
"message": "Fiókjaim"
},
"myWalletAccounts": {
"message": "Saját tárca fiókjai"
},
"myWalletAccountsDescription": {
"message": "Az összes MetaMask által létrehozott fiókot automatikusan hozzáadja a munkamenethez."
},
"needEtherInWallet": {
"message": "Ha a MetaMaskon keresztül szeretne interakcióba lépni decentralizált alkalmazással, ahhoz a tárcájában Ethernek kell lennie."
},
@ -831,9 +816,6 @@
"restoreAccountWithSeed": {
"message": "Fiók helyreállítása a seed mondat segítségével"
},
"restoreFromSeed": {
"message": "Visszaállítja a fiókot? "
},
"revealSeedWords": {
"message": "Seed szavak megjelenítése"
},
@ -888,9 +870,6 @@
"secretBackupPhraseWarning": {
"message": "FIGYELEM: Senkise se adja meg a biztonsági szakaszát. Ennek tulajdonosa örökre elviheti Ether-jeit."
},
"secretPhrase": {
"message": "Tárolód helyreállításához írd be titkos tizenkét szavas szókapcsolatodat ide."
},
"securityAndPrivacy": {
"message": "Biztonság és adatvédelem"
},
@ -930,9 +909,6 @@
"sendAmount": {
"message": "Összeg küldése"
},
"sendETH": {
"message": "ETH küldése"
},
"sendTokens": {
"message": "Token küldése"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "log aktivitas"
},
"addAccount": {
"message": "Tambahkan akun"
},
"addAcquiredTokens": {
"message": "Tambahkan token yang Anda peroleh menggunakan MetaMask"
},
@ -781,22 +778,13 @@
"importAccountSeedPhrase": {
"message": "Impor akun dengan frasa pemulihan"
},
"importUsingSeed": {
"message": "Impor menggunakan frasa pemulihan akun"
},
"importWallet": {
"message": "Impor dompet"
},
"importYourExisting": {
"message": "Impor dompet Anda yang ada menggunakan frasa pemulihan 12 kata"
},
"imported": {
"message": "Diimpor",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informasi & Bantuan"
},
"initialTransactionConfirmed": {
"message": "Transaksi awal Anda dikonfirmasikan oleh jaringan. Klik Oke untuk kembali."
},
@ -984,12 +972,6 @@
"myAccounts": {
"message": "Akun Saya"
},
"myWalletAccounts": {
"message": "Akun Dompet Saya"
},
"myWalletAccountsDescription": {
"message": "Semua akun Anda yang dibuat MetaMask akan secara otomatis ditambahkan ke bagian ini."
},
"needEtherInWallet": {
"message": "Untuk berinteraksi dengan aplikasi yang terdesentralisasi menggunakan MetaMask, Anda memerlukan Ether di dompet Anda."
},
@ -1273,9 +1255,6 @@
"restoreAccountWithSeed": {
"message": "Memulihkan Akun dengan Frasa Pemulihan"
},
"restoreFromSeed": {
"message": "Pulihkan akun?"
},
"restoreWalletPreferences": {
"message": "Cadangan data Anda dari $1 telah ditemukan. Apakah Anda ingin memulihkan preferensi dompet Anda?",
"description": "$1 is the date at which the data was backed up"
@ -1346,9 +1325,6 @@
"secretBackupPhraseWarning": {
"message": "PERINGATAN: Jangan pernah ungkapkan frasa cadangan Anda. Siapa pun yang memiliki frasa ini dapat mengambil Ether Anda selamanya."
},
"secretPhrase": {
"message": "Masukkan frasa kata dua belas rahasia Anda di sini untuk memulihkan vault Anda."
},
"securityAndPrivacy": {
"message": "Keamanan & Privasi"
},
@ -1400,9 +1376,6 @@
"sendAmount": {
"message": "Kirim Jumlah"
},
"sendETH": {
"message": "Kirim ETH"
},
"sendSpecifiedTokens": {
"message": "Kirim $1",
"description": "Symbol of the specified token"
@ -1627,24 +1600,6 @@
"swapHighSlippageWarning": {
"message": "Jumlah slippage sangat tinggi. Pastikan Anda mengetahui yang Anda kerjakan!"
},
"swapIntroLearnMoreHeader": {
"message": "Ingin mempelajari selengkapnya?"
},
"swapIntroLearnMoreLink": {
"message": "Pelajari selengkapnya tentang Penukaran MetaMask"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Sumber likuiditas mencakup:"
},
"swapIntroPopupSubTitle": {
"message": "Sekarang, Anda bisa menukar token secara langsung di dompet MetaMask Anda. Penukaran MetaMask menggabungkan beberapa agregator penukaran terdesentralisasi, pembuat pasar profesional, dan DEX individu untuk memastikan pengguna MetaMask selalu mendapatkan harga terbaik dengan biaya jaringan terendah."
},
"swapIntroPopupTitle": {
"message": "Penukaran token ada di sini!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Tinjau audit kontrak resmi kami"
},
"swapLowSlippageError": {
"message": "Transaksi bisa gagal, slippage maks. terlalu rendah."
},
@ -1666,7 +1621,7 @@
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNetworkFeeSummary": {
"message": "Biaya jaringan mencakup biaya pemrosesan penukaran Anda dan menyimpannya di jaringan Ethereum. MetaMask tidak mendapatkan keuntungan dari biaya ini."
"message": "Biaya jaringan mencakup biaya pemrosesan penukaran Anda dan menyimpannya di jaringan $1. MetaMask tidak mendapatkan keuntungan dari biaya ini."
},
"swapNewQuoteIn": {
"message": "Kuota baru di $1",
@ -1747,9 +1702,6 @@
"swapSourceInfo": {
"message": "Kami mencari beberapa sumber likuiditas (penukaran, agregator, dan pembuat pasar profesional) untuk menemukan tarif terbaik dan biaya jaringan terendah."
},
"swapStartSwapping": {
"message": "Mulai menukar"
},
"swapSwapFrom": {
"message": "Tukar dari"
},
@ -1879,9 +1831,6 @@
"tokenContractAddress": {
"message": "Alamat Kontrak Token"
},
"tokenOptions": {
"message": "Opsi token"
},
"tokenSymbol": {
"message": "Simbol Token"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "log attività"
},
"addAccount": {
"message": "Aggiungi un account"
},
"addAcquiredTokens": {
"message": "Aggiungi i token che hai acquistato usando MetaMask"
},
@ -793,22 +790,13 @@
"importAccountSeedPhrase": {
"message": "Importa un Account con una Frase Seed"
},
"importUsingSeed": {
"message": "Importa account con frase seed"
},
"importWallet": {
"message": "Importa Portafoglio"
},
"importYourExisting": {
"message": "Importa il tuo portafoglio esistente usando la tua frase seed a 12 parole"
},
"imported": {
"message": "Importato",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informazioni & Aiuto"
},
"initialTransactionConfirmed": {
"message": "La transazione iniziale è stata confermata dalla rete. Clicca OK per tornare indietro."
},
@ -999,12 +987,6 @@
"myAccounts": {
"message": "Miei Account"
},
"myWalletAccounts": {
"message": "I miei account di portafoglio"
},
"myWalletAccountsDescription": {
"message": "Tutti gli account creati con MetaMask saranno automaticamente aggiunti a questa sezione."
},
"needEtherInWallet": {
"message": "Per interagire con applicazioni decentralizzate con MetaMask, devi possedere Ether nel tuo portafoglio."
},
@ -1288,9 +1270,6 @@
"restoreAccountWithSeed": {
"message": "Ripristina Account con la Frase Seed"
},
"restoreFromSeed": {
"message": "Ripristina da una frase seed"
},
"restoreWalletPreferences": {
"message": "È stato trovato un backup dei tuoi dati da $1. Vuoi ripristinare le preferenze del portafoglio?",
"description": "$1 is the date at which the data was backed up"
@ -1361,9 +1340,6 @@
"secretBackupPhraseWarning": {
"message": "ATTENZIONE: Non dire mai a nessuno questa frase di backup. Chiunque con questa frase può rubare i tuoi Ether per sempre."
},
"secretPhrase": {
"message": "Inserisci la tua frase segreta di dodici parole per ripristinare la cassaforte."
},
"securityAndPrivacy": {
"message": "Sicurezza & Privacy"
},
@ -1415,9 +1391,6 @@
"sendAmount": {
"message": "Invia Importo"
},
"sendETH": {
"message": "Invia ETH"
},
"sendSpecifiedTokens": {
"message": "Invia $1",
"description": "Symbol of the specified token"
@ -1645,24 +1618,6 @@
"swapHighSlippageWarning": {
"message": "L'importo di slippage è molto alto. Assicurati di sapere cosa stai facendo!"
},
"swapIntroLearnMoreHeader": {
"message": "Vuoi sapere di più?"
},
"swapIntroLearnMoreLink": {
"message": "Scopri di più su MetaMask Swaps"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Sorgenti di liquidità incluse:"
},
"swapIntroPopupSubTitle": {
"message": "Adesso puoi scambiare token direttamente dal tuo portafgolio MetaMask. MetaMask Swaps combina vari siti di scambio decentralizzati, aggregatori e market maker professionisti per assicurare che gli utenti di MetaMask ottengano sempre il miglior prezzo con le tasse di rete minori."
},
"swapIntroPopupTitle": {
"message": "Lo scambio di token è qui!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Esamina l'audit ufficiale dei nostri smart contracts"
},
"swapLowSlippageError": {
"message": "La transazione può fallire, il massimo slippage è troppo basso."
},
@ -1688,7 +1643,7 @@
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "La tassa di rete copre il costo di processamento dello scambio e della memorizzazione nella rete Ethereum. MetaMask non trae profitto da questa tassa."
"message": "La tassa di rete copre il costo di processamento dello scambio e della memorizzazione nella rete $1. MetaMask non trae profitto da questa tassa."
},
"swapNewQuoteIn": {
"message": "Nuove quotazioni in $1",
@ -1789,9 +1744,6 @@
"swapSourceInfo": {
"message": "Cerchiamo sorgenti di liquidità multiple (siti di scambio, aggregatori, market maker professionisti) per trovare le tariffe migliori e le tasse di rete minori."
},
"swapStartSwapping": {
"message": "Inizia a scambiare"
},
"swapSwapFrom": {
"message": "Scambia da"
},
@ -1938,9 +1890,6 @@
"tokenContractAddress": {
"message": "Indirizzo Contratto Token"
},
"tokenOptions": {
"message": "Opzioni token"
},
"tokenSymbol": {
"message": "Simbolo Token"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "アクティビティのログ"
},
"addAccount": {
"message": "アカウントの追加"
},
"addAcquiredTokens": {
"message": "MetaMaskで取得したトークンを追加する"
},
@ -790,22 +787,13 @@
"importAccountSeedPhrase": {
"message": "シードフレーズを使用してアカウントをインポート"
},
"importUsingSeed": {
"message": "アカウントのシードフレーズから復元する"
},
"importWallet": {
"message": "ウォレットのインポート"
},
"importYourExisting": {
"message": "12単語のシードフレーズを使用して既存のウォレットをインポートします"
},
"imported": {
"message": "インポート済",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "情報とヘルプ"
},
"initialTransactionConfirmed": {
"message": "最初のトランザクションがネットワークに確認されました。戻るにはOKをクリックします。"
},
@ -996,12 +984,6 @@
"myAccounts": {
"message": "マイアカウント"
},
"myWalletAccounts": {
"message": "このウォレットのアカウント"
},
"myWalletAccountsDescription": {
"message": "MetaMaskで作成したすべてのアカウントは、このセクションに自動的に追加されます。"
},
"needEtherInWallet": {
"message": "MetaMaskで分散型アプリケーションを操作するには、ウォレットにEtherが必要です。"
},
@ -1282,9 +1264,6 @@
"restoreAccountWithSeed": {
"message": "シードフレーズでアカウントを復元"
},
"restoreFromSeed": {
"message": "アカウントを復元しますか?"
},
"restoreWalletPreferences": {
"message": "$1 のデータバックアップが見つかりました。ウォレットの基本設定を復元しますか?",
"description": "$1 is the date at which the data was backed up"
@ -1355,9 +1334,6 @@
"secretBackupPhraseWarning": {
"message": "警告:シードフレーズは絶対に公開しないでください。シードフレーズを使うと、誰でもアカウントからETHを盗み出せます。"
},
"secretPhrase": {
"message": "アカウント情報を復元するには、12単語で構成されたシードフレーズを入力してください。"
},
"securityAndPrivacy": {
"message": "セキュリティとプライバシー"
},
@ -1409,9 +1385,6 @@
"sendAmount": {
"message": "送金額"
},
"sendETH": {
"message": "ETHの送金"
},
"sendSpecifiedTokens": {
"message": "$1 を送る",
"description": "Symbol of the specified token"
@ -1639,24 +1612,6 @@
"swapHighSlippageWarning": {
"message": "非常に大きいスリッページ額です。本当に実行するか確認してください。"
},
"swapIntroLearnMoreHeader": {
"message": "詳細を表示しますか?"
},
"swapIntroLearnMoreLink": {
"message": "MetaMask Swapsの詳細"
},
"swapIntroLiquiditySourcesLabel": {
"message": "流動性ソースには以下が含まれます。"
},
"swapIntroPopupSubTitle": {
"message": "トークンをMetaMaskで直接スワップできるようになりました。MetaMask Swapsは、多数の分散型取引所アグリゲーター、専門のマーケットメーカー、DEX取引所を統合し、ユーザーは常に最低のネットワーク手数料、最適な価格で取引できます。"
},
"swapIntroPopupTitle": {
"message": "トークンのスワップはこちら!"
},
"swapLearnMoreContractsAuditReview": {
"message": "MetaSwapのコントラクト監査のレビュー"
},
"swapLowSlippageError": {
"message": "トランザクションが失敗する可能性があります。最大スリッページが少なすぎます。"
},
@ -1682,7 +1637,7 @@
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "ネットワーク手数料には、スワップの結果をEthereumネットワークに保管する費用も含まれています。MetaMaskは手数料から利益を得ません。"
"message": "ネットワーク手数料には、スワップの結果を$1ネットワークに保管する費用も含まれています。MetaMaskは手数料から利益を得ません。"
},
"swapNewQuoteIn": {
"message": "見積の有効期限 $1",
@ -1777,9 +1732,6 @@
"swapSourceInfo": {
"message": "最良のレートと最小のネットワーク手数料を探すため、複数の流動性ソース(取引所、アグリゲーター、専門のマーケットメーカー)を検索します。"
},
"swapStartSwapping": {
"message": "スワップの開始"
},
"swapSwapFrom": {
"message": "スワップ元"
},
@ -1915,9 +1867,6 @@
"tokenContractAddress": {
"message": "トークンコントラクトのアドレス"
},
"tokenOptions": {
"message": "トークンのオプション"
},
"tokenSymbol": {
"message": "トークンシンボル"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "ಸಿಯನ ಆಮದಿ"
},
"importUsingSeed": {
"message": "ಸಯನ ಬಳಸಿ ಆಮದಿ"
},
"importWallet": {
"message": "ವ ಅನ ಆಮದಿ"
},
"importYourExisting": {
"message": "12 ಪದದ ಸ ಅನ ಬಳಸಿಿಮ ಅಸಿವದಲಿವ ವ ಅನ ಆಮದಿ"
},
"imported": {
"message": "ಆಮದಡಲಿ",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "ಮಿಿ & ಸಹಯ"
},
"initialTransactionConfirmed": {
"message": "ನಿಮ ಆರಿಕ ವಹಿಟನವರಲಕ ಖಚಿತಪಡಿಸಲಿ. ಹಿಿಗಲ ಸರಿಿಿ."
},
@ -615,12 +606,6 @@
"myAccounts": {
"message": "ನನನ ಖಗಳ"
},
"myWalletAccounts": {
"message": "ನನನ ವಗಳ"
},
"myWalletAccountsDescription": {
"message": "ನಿಮ MetaMask ರಚಿಿದ ಎಲಗಳನವಯಿತವಿ ಈ ವಿಗಕಿಸಲತದ."
},
"needEtherInWallet": {
"message": "MetaMask ಬಳಸಿಿತ ಖಗಳಿವಹನ ನಡಸಲ, ನಿಮ ವನಲಿಿಮಗ ಎಥರ ಅಗತಯವಿ."
},
@ -838,9 +823,6 @@
"restoreAccountWithSeed": {
"message": "ಸಿಿಮ ಖಯನ ಮರಿಿ"
},
"restoreFromSeed": {
"message": "ಖಯನ ಮರಿ?"
},
"revealSeedWords": {
"message": "ಸ ವರ ಬಹಿಗಪಡಿಿ"
},
@ -895,9 +877,6 @@
"secretBackupPhraseWarning": {
"message": "ಎಚಚರಿ: ನಿಮ ಬಕಪ ಅನಿ ಬಹಿರಗಪಡಿಸಬಿ. ಈ ಫ ಅನಿವ ಯದರಿಮ ಎಥರ ಅನವತವಿಳಬಹ."
},
"secretPhrase": {
"message": "ನಿಮ ವ ಅನ ಮರಿಸಲಿಮ ರಹಸಯ ಹನರಡ ಪದದ ಫ ಅನ ಇಲಿ ನಮಿಿ."
},
"securityAndPrivacy": {
"message": "ಭದರತ ಮತಯತ"
},
@ -937,9 +916,6 @@
"sendAmount": {
"message": "ಮತವನ ಕಳಿಿ"
},
"sendETH": {
"message": "ETH ಕಳಿಿ"
},
"sendTokens": {
"message": "ಟಕನಗಳನ ಕಳಿಿ"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "활동 로그"
},
"addAccount": {
"message": "계정 추가"
},
"addAcquiredTokens": {
"message": "MetaMask를 이용해 얻은 토큰 추가"
},
@ -781,22 +778,13 @@
"importAccountSeedPhrase": {
"message": "시드 구문으로 계정 가져오기"
},
"importUsingSeed": {
"message": "계정 시드 구문으로 가져오기"
},
"importWallet": {
"message": "지갑 가져오기"
},
"importYourExisting": {
"message": "12단어 시드 구문을 사용하여 지갑 가져오기"
},
"imported": {
"message": "가져옴",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "정보 및 도움말"
},
"initialTransactionConfirmed": {
"message": "최초 거래를 네트워크에서 확인했습니다. 확인을 클릭하여 뒤로 돌아가세요."
},
@ -984,12 +972,6 @@
"myAccounts": {
"message": "내 계정"
},
"myWalletAccounts": {
"message": "내 지갑 계정"
},
"myWalletAccountsDescription": {
"message": "MetaMask에서 생성한 모든 계정으로 이 섹션에 자동으로 추가됩니다."
},
"needEtherInWallet": {
"message": "MetaMask를 이용하는 분산형 애플리케이션과 상호작용하려면 지갑에 Ether가 있어야 합니다."
},
@ -1003,6 +985,9 @@
"networkName": {
"message": "네트워크 이름"
},
"networkNameEthereum": {
"message": "이더리움"
},
"networkSettingsChainIdDescription": {
"message": "체인 ID는 거래 서명에 사용합니다. 네트워크에서 반환하는 체인 ID와 일치해야 합니다. 십진수나 '0x'로 시작하는 16진수를 입력할 수 있지만, 표시될 때는 십진수로 표시됩니다."
},
@ -1270,9 +1255,6 @@
"restoreAccountWithSeed": {
"message": "시드 구문으로 계정 복구"
},
"restoreFromSeed": {
"message": "계정을 복구하시겠습니까?"
},
"restoreWalletPreferences": {
"message": "$1의 데이터 백업이 발견되었습니다. 지갑 환경설정을 복구하시겠습니까?",
"description": "$1 is the date at which the data was backed up"
@ -1343,9 +1325,6 @@
"secretBackupPhraseWarning": {
"message": "경고: 백업 구문은 절대로 공개하지 마세요. 이 구문이 있는 사람은 귀하의 Ether를 영원히 소유할 수 있습니다."
},
"secretPhrase": {
"message": "금고를 복구하려면 비밀 12단어 구문을 여기에 입력하세요."
},
"securityAndPrivacy": {
"message": "보안 및 개인정보 보호"
},
@ -1397,9 +1376,6 @@
"sendAmount": {
"message": "금액 보내기"
},
"sendETH": {
"message": "ETH 보내기"
},
"sendSpecifiedTokens": {
"message": "$1 보내기",
"description": "Symbol of the specified token"
@ -1624,24 +1600,6 @@
"swapHighSlippageWarning": {
"message": "슬리패지 금액이 아주 큽니다. 현재 어떤 작업을 하고 있는지 확인하세요!"
},
"swapIntroLearnMoreHeader": {
"message": "자세한 정보를 확인하고 싶으신가요?"
},
"swapIntroLearnMoreLink": {
"message": "MetaMask Swaps에 대해 자세히 알아보기"
},
"swapIntroLiquiditySourcesLabel": {
"message": "다음을 포함한 유동성 소스:"
},
"swapIntroPopupSubTitle": {
"message": "이제 MetaMask 지갑에서 토큰을 바로 스왑할 수 있습니다. MetaMask Swaps는 다양한 분산형 교환 애그리게이터, 투자전문기관, 개별 DEX를 결합하여 MetaMask 사용자가 언제든 최저 네트워크 요금으로 최상의 가격을 얻을 수 있게 합니다."
},
"swapIntroPopupTitle": {
"message": "토큰 스왑은 여기서 진행됩니다!"
},
"swapLearnMoreContractsAuditReview": {
"message": "당사의 공식 계약 감사 검토"
},
"swapLowSlippageError": {
"message": "거래가 실패할 수도 있습니다. 최대 슬리패지가 너무 낮습니다."
},
@ -1663,7 +1621,7 @@
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNetworkFeeSummary": {
"message": "네트워크 요금에는 스왑을 처리하고 이더리움 네트워크에 보관하는 비용이 적용됩니다. MetaMask는 이 요금을 이용해 이득을 얻지 않습니다."
"message": "네트워크 요금에는 스왑을 처리하고 $1 네트워크에 보관하는 비용이 적용됩니다. MetaMask는 이 요금을 이용해 이득을 얻지 않습니다."
},
"swapNewQuoteIn": {
"message": "$1 후에 새 견적",
@ -1744,9 +1702,6 @@
"swapSourceInfo": {
"message": "당사에서는 여러 유동성 소스(교환, 애그리게이터, 투자전문기관)를 검색하여 최상의 요율과 최저 네트워크 요금을 찾습니다."
},
"swapStartSwapping": {
"message": "스왑 시작"
},
"swapSwapFrom": {
"message": "다음에서 스왑"
},
@ -1876,9 +1831,6 @@
"tokenContractAddress": {
"message": "토큰 계약 주소"
},
"tokenOptions": {
"message": "토큰 옵션"
},
"tokenSymbol": {
"message": "토큰 기호"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "Importuoti paskyrą su atkūrimo fraze"
},
"importUsingSeed": {
"message": "Importuoti naudojant paskyros atkūrimo frazę"
},
"importWallet": {
"message": "Importuoti slaptažodinę"
},
"importYourExisting": {
"message": "Importuoti turimą piniginę naudojant 12 žodžių atkūrimo frazę"
},
"imported": {
"message": "Importuota",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informacija ir žinynas"
},
"initialTransactionConfirmed": {
"message": "Jūsų pradinė operacija patvirtinta tinkle. Norėdami grįžti, spustelėkite „Gerai“."
},
@ -615,12 +606,6 @@
"myAccounts": {
"message": "Mano paskyros"
},
"myWalletAccounts": {
"message": "Mano piniginės paskyros"
},
"myWalletAccountsDescription": {
"message": "Visos jūsų „MetaMask“ sukurtos paskyros bus automatiškai įtrauktos į šį skyrių."
},
"needEtherInWallet": {
"message": "Norėdami dirbti su decentralizuotomis programomis „MetaMask“, savo piniginėje turite turėti eterių."
},
@ -838,9 +823,6 @@
"restoreAccountWithSeed": {
"message": "Atkurti paskyrą naudojant atkūrimo frazę"
},
"restoreFromSeed": {
"message": "Atkurti paskyrą?"
},
"revealSeedWords": {
"message": "Atskleisti atkūrimo žodžius"
},
@ -895,9 +877,6 @@
"secretBackupPhraseWarning": {
"message": "ĮSPĖJIMAS. Niekada neatskleiskite savo atsarginės frazės. Bet kas, žinantis šią frazę, gali visiems laikams pasiimti jūsų eterius."
},
"secretPhrase": {
"message": "Savo saugyklai atkurti įveskite slaptą dvylikos žodžių frazę."
},
"securityAndPrivacy": {
"message": "Sauga ir privatumas"
},
@ -937,9 +916,6 @@
"sendAmount": {
"message": "Siųsti sumą"
},
"sendETH": {
"message": "Siųsti ETH"
},
"sendTokens": {
"message": "Siųsti žetonus"
},

@ -495,22 +495,13 @@
"importAccountSeedPhrase": {
"message": "Importēt kontu ar atkopšanas frāzi"
},
"importUsingSeed": {
"message": "Importēt, izmantojot konta atkopšanas frāzi"
},
"importWallet": {
"message": "Importēt maku"
},
"importYourExisting": {
"message": "Importējiet esošo maku, izmantojot 12 vārdu atkopšanas frāzi"
},
"imported": {
"message": "Importēts",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informācija un palīdzība"
},
"initialTransactionConfirmed": {
"message": "Jūsu sākotnējais darījums apstiprināts tīklā. Spiediet OK, lai atgrieztos."
},
@ -611,12 +602,6 @@
"myAccounts": {
"message": "Mani konti"
},
"myWalletAccounts": {
"message": "Mana maka konti"
},
"myWalletAccountsDescription": {
"message": "Visi jūsu izveidotie MetaMask konti tiks automātiski pievienoti šajā sadaļā."
},
"needEtherInWallet": {
"message": "Lai izmantotu decentralizētas lietotnes ar MetaMask, jūsu makā jābūt Ether."
},
@ -834,9 +819,6 @@
"restoreAccountWithSeed": {
"message": "Atjaunojiet savu kontu ar atkopšanas frāzi"
},
"restoreFromSeed": {
"message": "Atjaunot kontu?"
},
"revealSeedWords": {
"message": "Parādīt atkopšanas vārdus"
},
@ -891,9 +873,6 @@
"secretBackupPhraseWarning": {
"message": "BRĪDINĀJUMS! Nekādā gadījumā neizpaudiet savu rezerves frāzi. Ikviens, kam pieejama šī frāze, var uz visiem laikiem pārņemt jūsu Ether."
},
"secretPhrase": {
"message": "Ievadiet šeit slepeno divpadsmit vārdu frāzi, lai atjaunotu savu seifu."
},
"securityAndPrivacy": {
"message": "Drošība un konfidencialitāte"
},
@ -933,9 +912,6 @@
"sendAmount": {
"message": "Nosūtītā summa"
},
"sendETH": {
"message": "Sūtīt ETH"
},
"sendTokens": {
"message": "Nosūtīt marķierus"
},

@ -485,22 +485,13 @@
"importAccountSeedPhrase": {
"message": "Import Akaun dengan Frasa Benih"
},
"importUsingSeed": {
"message": "Import menggunakan frasa benih akaun"
},
"importWallet": {
"message": "Import Dompet"
},
"importYourExisting": {
"message": "Import dompet sedia ada anda menggunakan frasa benih 12 perkataan"
},
"imported": {
"message": "Diimport",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & Bantuan"
},
"initialTransactionConfirmed": {
"message": "Transaksi awal anda telah disahkan oleh rangkaian. Klik OK untuk kembali."
},
@ -595,12 +586,6 @@
"myAccounts": {
"message": "Akaun Saya"
},
"myWalletAccounts": {
"message": "Akaun Dompet Saya"
},
"myWalletAccountsDescription": {
"message": "Semua akaun ciptaan MetaMask anda akan ditambahkan secara automatik kepada bahagian ini."
},
"needEtherInWallet": {
"message": "Untuk berinteraksi dengan aplikasi ternyahpusat menggunakan MetaMask, anda memerlukan Ether di dalam dompet anda."
},
@ -815,9 +800,6 @@
"restoreAccountWithSeed": {
"message": "Pulihkan Akaun anda dengan Ungkapan Benih"
},
"restoreFromSeed": {
"message": "Pulihkan akaun?"
},
"revealSeedWords": {
"message": "Dedahkan Ungkapan Benih"
},
@ -872,9 +854,6 @@
"secretBackupPhraseWarning": {
"message": "AMARAN: Jangan sesekali dedahkan frasa sandaran anda. Sesiapa yang memperoleh frasa ini boleh mengambil Ether anda selama-lamanya."
},
"secretPhrase": {
"message": "Masukkan ungkapan rahsia dua belas perkataan di sini untuk memulihkan kekubah anda."
},
"securityAndPrivacy": {
"message": "Keselamatan & Privasi"
},
@ -914,9 +893,6 @@
"sendAmount": {
"message": "Hantar Amaun"
},
"sendETH": {
"message": "Hantar ETH"
},
"sendTokens": {
"message": "Hantar Token"
},

@ -166,9 +166,6 @@
"message": "geïmporteerd",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info en hulp"
},
"insufficientFunds": {
"message": "Onvoldoende fondsen."
},
@ -290,9 +287,6 @@
"resetAccount": {
"message": "Account opnieuw instellen"
},
"restoreFromSeed": {
"message": "Herstel vanuit back-up woorden"
},
"revealSeedWords": {
"message": "Onthul back-up woorden"
},
@ -311,9 +305,6 @@
"search": {
"message": "Zoeken"
},
"secretPhrase": {
"message": "Voer hier je geheime twaalfwoordfrase in om je kluis te herstellen."
},
"seedPhraseReq": {
"message": "Back-up woorden zijn 12 woorden lang"
},
@ -323,9 +314,6 @@
"send": {
"message": "Sturen"
},
"sendETH": {
"message": "Verzend ETH"
},
"sendTokens": {
"message": "Stuur tokens"
},

@ -486,22 +486,13 @@
"importAccountSeedPhrase": {
"message": "Importer en konto med den mnemoniske gjenopprettingsfrasen "
},
"importUsingSeed": {
"message": "Importer ved hjelp av kontoens mnemoniske gjenopprettingsfrase"
},
"importWallet": {
"message": "Importér lommebok "
},
"importYourExisting": {
"message": "Importer din eksisterende lommebok ved å bruk en tolvords seed-frase."
},
"imported": {
"message": "Importert",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informasjon og hjelp"
},
"initialTransactionConfirmed": {
"message": "Din opprinnelige transaksjon ble bekreftet av nettverket. Klikk OK for å gå tilbake."
},
@ -602,12 +593,6 @@
"myAccounts": {
"message": "Mine kontoer "
},
"myWalletAccounts": {
"message": "mine lommebokkontoer"
},
"myWalletAccountsDescription": {
"message": "Alle dine opprettede MetaMask-kontoer vil automatisk bli lagt til denne seksjonen. "
},
"needEtherInWallet": {
"message": "Du må ha Ether i lommeboken din for å samhandle med desentraliserte applikasjoner gjennom MateMask."
},
@ -825,9 +810,6 @@
"restoreAccountWithSeed": {
"message": "Gjenopprett konto med frøfrase"
},
"restoreFromSeed": {
"message": "Gjennopprett konto? "
},
"revealSeedWords": {
"message": "Vis frøord"
},
@ -879,9 +861,6 @@
"secretBackupPhraseWarning": {
"message": "ADVARSEL: Du må aldri avsløre gjenopprettingsfrasen din. Alle som har denne frasen kan ta fra deg Etheren din for alltid."
},
"secretPhrase": {
"message": "Skriv inn den tolv ord lange frasen her for å gjenopprette hvelvet ditt. "
},
"securityAndPrivacy": {
"message": "Sikkerhet og personvern"
},

@ -136,9 +136,6 @@
"message": "Na-import na",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Impormasyon at Tulong"
},
"invalidAddress": {
"message": "Invalid ang address"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "Zaimportuj konto za pomocą frazy seed"
},
"importUsingSeed": {
"message": "Importuj przy pomocy frazy seed konta"
},
"importWallet": {
"message": "Importuj portfel"
},
"importYourExisting": {
"message": "Zaimportuj istniejący portfel, wprowadzając 12 słów frazy seed"
},
"imported": {
"message": "Zaimportowane",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & pomoc"
},
"initialTransactionConfirmed": {
"message": "Twoja transakcja została potwierdzona w sieci. Kliknij OK żeby wrócić."
},
@ -612,12 +603,6 @@
"myAccounts": {
"message": "Moje konta"
},
"myWalletAccounts": {
"message": "Moja konta portfeli"
},
"myWalletAccountsDescription": {
"message": "Wszystkie Twoje konta utworzone w MetaMask zostaną automatycznie dodane do tej sekcji."
},
"needEtherInWallet": {
"message": "Żeby skorzystać ze zdecentraliowanych aplikacji (dApps) przy pomocy MetaMask, potrzebujesz Eteru w swoim portfelu."
},
@ -832,9 +817,6 @@
"restoreAccountWithSeed": {
"message": "Przywróć konto frazą seed"
},
"restoreFromSeed": {
"message": "Przywrócić konto?"
},
"revealSeedWords": {
"message": "Pokaż słowa seed"
},
@ -889,9 +871,6 @@
"secretBackupPhraseWarning": {
"message": "OSTRZEŻENIE: Nigdy nie ujawniaj swojej frazy zapasowej. Każdy, kto pozna tę frazę, może bezpowrotnie odebrać Ci kryptowalutę Ether."
},
"secretPhrase": {
"message": "Żeby otworzyć schowek, wpisz tutaj swoją frazę dwunastu słów."
},
"securityAndPrivacy": {
"message": "Bezpieczeństwo i prywatność"
},
@ -931,9 +910,6 @@
"sendAmount": {
"message": "Wyślij kwotę"
},
"sendETH": {
"message": "Wyślij ETH"
},
"sendTokens": {
"message": "Wyślij tokeny"
},

@ -172,9 +172,6 @@
"message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informação & Ajuda"
},
"insufficientFunds": {
"message": "Fundos insuficientes."
},
@ -300,9 +297,6 @@
"resetAccount": {
"message": "Reinicializar Conta"
},
"restoreFromSeed": {
"message": "Restaurar a partir da frase seed"
},
"revealSeedWords": {
"message": "Revelar Palavras Seed"
},
@ -321,9 +315,6 @@
"search": {
"message": "Procurar"
},
"secretPhrase": {
"message": "Introduza a sua frase secreta de 12 palavras para recuperar o seu ."
},
"seedPhraseReq": {
"message": "seed phrases are 12 words long"
},
@ -333,9 +324,6 @@
"send": {
"message": "Enviar"
},
"sendETH": {
"message": "Enviar ETH"
},
"sendTokens": {
"message": "Enviar Tokens"
},

@ -493,22 +493,13 @@
"importAccountSeedPhrase": {
"message": "Importar uma Conta com Frase-semente"
},
"importUsingSeed": {
"message": "Importe usando a seed phrase da conta"
},
"importWallet": {
"message": "Importar Carteira"
},
"importYourExisting": {
"message": "Importe sua carteira existente usando uma frase-semente de 12 palavras"
},
"imported": {
"message": "Importado",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informações e ajuda"
},
"initialTransactionConfirmed": {
"message": "Sua transação inicial foi confirmada pela rede. Clique em OK para voltar."
},
@ -603,12 +594,6 @@
"myAccounts": {
"message": "Minhas Contas"
},
"myWalletAccounts": {
"message": "Contas da Minha Carteira"
},
"myWalletAccountsDescription": {
"message": "Todas as suas contas criadas no MetaMask serão automaticamente adicionadas a esta seção."
},
"needEtherInWallet": {
"message": "Para interagir com aplicações descentralizadas usando o MetaMask, você precisará de Ether na sua carteira."
},
@ -826,9 +811,6 @@
"restoreAccountWithSeed": {
"message": "Restaurar sua conta com a frase semente"
},
"restoreFromSeed": {
"message": "Restaurar conta?"
},
"revealSeedWords": {
"message": "Revelar Palavras-semente"
},
@ -883,9 +865,6 @@
"secretBackupPhraseWarning": {
"message": "ATENÇÃO: Nunca revele sua frase de backup a ninguém. Qualquer pessoa com essa frase pode obter seu Ether para sempre."
},
"secretPhrase": {
"message": "Digite sua frase secreta de doze palavras aqui para restaurar seu cofre."
},
"securityAndPrivacy": {
"message": "Segurança & Privacidade"
},
@ -925,9 +904,6 @@
"sendAmount": {
"message": "Enviar Quantia"
},
"sendETH": {
"message": "Enviar ETH"
},
"sendTokens": {
"message": "Enviar Tokens"
},

@ -489,22 +489,13 @@
"importAccountSeedPhrase": {
"message": "Importați un cont cu fraza seed"
},
"importUsingSeed": {
"message": "Importare folosind fraza inițială a contului"
},
"importWallet": {
"message": "Importați portofel"
},
"importYourExisting": {
"message": "Importați portofelul existent folosind o frază seed de 12 cuvinte"
},
"imported": {
"message": "Importate",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informații și ajutor"
},
"initialTransactionConfirmed": {
"message": "Tranzacția inițială a fost confirmată de rețea. Clic pe OK pentru a reveni."
},
@ -602,12 +593,6 @@
"myAccounts": {
"message": "Conturile mele"
},
"myWalletAccounts": {
"message": "Conturi My Wallet"
},
"myWalletAccountsDescription": {
"message": "Toate conturile dvs. create pe MetaMask vor fi adăugate automat la această secțiune."
},
"needEtherInWallet": {
"message": "Pentru a interacționa cu aplicațiile descentralizate prin intermediul MetaMask, trebuie să aveți Ether în portofel."
},
@ -825,9 +810,6 @@
"restoreAccountWithSeed": {
"message": "Restaurați-vă contul folosind fraza inițială"
},
"restoreFromSeed": {
"message": "Restabiliți contul?"
},
"revealSeedWords": {
"message": "Arată cuvintele din seed"
},
@ -882,9 +864,6 @@
"secretBackupPhraseWarning": {
"message": "ATENȚIE: Nu dezvăluiți niciodată expresia dvs. de rezervă. Oricine are această expresie vă poate lua Ether-ul pentru totdeauna."
},
"secretPhrase": {
"message": "Introduceți aici expresia dvs. secretă din 12 cuvinte pentru a restabili seiful."
},
"securityAndPrivacy": {
"message": "Securitate și confidențialitate"
},
@ -924,9 +903,6 @@
"sendAmount": {
"message": "Suma trimisă"
},
"sendETH": {
"message": "Trimitere ETH"
},
"sendTokens": {
"message": "Trimiteți indicative"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "Журнал активности"
},
"addAccount": {
"message": "Добавить счет"
},
"addAcquiredTokens": {
"message": "Добавьте токены, которые вы приобрели с помощью MetaMask"
},
@ -781,22 +778,13 @@
"importAccountSeedPhrase": {
"message": "Импортировать счет с исходной фразой"
},
"importUsingSeed": {
"message": "Импортировать с использованием исходной фразы счета"
},
"importWallet": {
"message": "Импортировать кошелек"
},
"importYourExisting": {
"message": "Импортируйте существующий кошелек, используя начальную фразу из 12 слов"
},
"imported": {
"message": "Импортированный",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Информация и справка"
},
"initialTransactionConfirmed": {
"message": "Ваша первоначальная транзакция была подтверждена сетью. Нажмите ОК, чтобы вернуться."
},
@ -984,12 +972,6 @@
"myAccounts": {
"message": "Мои счета"
},
"myWalletAccounts": {
"message": "Счета моего кошелька"
},
"myWalletAccountsDescription": {
"message": "Все ваши счета, созданные в MetaMask, будут автоматически добавлены в этот раздел."
},
"needEtherInWallet": {
"message": "Для взаимодействия с децентрализованными приложениями с помощью MetaMask вам понадобится Ether в вашем кошельке."
},
@ -1273,9 +1255,6 @@
"restoreAccountWithSeed": {
"message": "Восстановите свой счет с помощью исходной фразы"
},
"restoreFromSeed": {
"message": "Восстановить счет?"
},
"restoreWalletPreferences": {
"message": "Найдена резервная копия ваших данных из $1. Хотите восстановить настройки кошелька?",
"description": "$1 is the date at which the data was backed up"
@ -1346,9 +1325,6 @@
"secretBackupPhraseWarning": {
"message": "ПРЕДУПРЕЖДЕНИЕ: Никогда не разглашайте резервную фразу. Любой, у кого есть эта фраза, может забрать ваш Ether навсегда."
},
"secretPhrase": {
"message": "Введите здесь свою секретную фразу из двенадцати слов, чтобы восстановить свой сейф."
},
"securityAndPrivacy": {
"message": "Безопасность и конфиденциальность"
},
@ -1400,9 +1376,6 @@
"sendAmount": {
"message": "Отправить сумму"
},
"sendETH": {
"message": "Отправить ETH"
},
"sendSpecifiedTokens": {
"message": "Отправить $1",
"description": "Symbol of the specified token"
@ -1627,24 +1600,6 @@
"swapHighSlippageWarning": {
"message": "Величина проскальзывания очень велика. Убедитесь, что вы знаете, что делаете!"
},
"swapIntroLearnMoreHeader": {
"message": "Хотите узнать больше?"
},
"swapIntroLearnMoreLink": {
"message": "Подробнее о свопах MetaMask"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Источники ликвидности включают:"
},
"swapIntroPopupSubTitle": {
"message": "Теперь вы можете обменивать токены прямо в кошельке MetaMask. MetaMask Swaps объединяет несколько децентрализованных агрегаторов обменов, профессиональных торговцев и отдельные DEX, чтобы пользователи MetaMask всегда получали лучшую цену с минимальными комиссиями сети."
},
"swapIntroPopupTitle": {
"message": "Обмен токенов здесь!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Ознакомьтесь с нашим официальным аудитом контрактов"
},
"swapLowSlippageError": {
"message": "Транзакции могут завершиться неудачей, максимальное проскальзывание слишком мало."
},
@ -1666,7 +1621,7 @@
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNetworkFeeSummary": {
"message": "Сетевая комиссия покрывает стоимость обработки вашего свопа и его хранения в сети Ethereum. MetaMask не получает прибыли от этой комиссии."
"message": "Сетевая комиссия покрывает стоимость обработки вашего свопа и его хранения в сети $1. MetaMask не получает прибыли от этой комиссии."
},
"swapNewQuoteIn": {
"message": "Новые котировки в $1",
@ -1747,9 +1702,6 @@
"swapSourceInfo": {
"message": "Мы ищем несколько источников ликвидности (биржи, агрегаторы и профессиональные продавцы), чтобы найти лучшие цены и самые низкие сетевые комиссии."
},
"swapStartSwapping": {
"message": "Начать обмен"
},
"swapSwapFrom": {
"message": "Своп с"
},
@ -1879,9 +1831,6 @@
"tokenContractAddress": {
"message": "Адрес контракта токена"
},
"tokenOptions": {
"message": "Опции токена"
},
"tokenSymbol": {
"message": "Символ токена"
},

@ -486,22 +486,13 @@
"importAccountSeedPhrase": {
"message": "Importovať účet so seed frázou"
},
"importUsingSeed": {
"message": "Importovať pomocou seed frázy účtu"
},
"importWallet": {
"message": "Importovať Peňaženku"
},
"importYourExisting": {
"message": "Importujte svoju existujúcu peňaženku pomocou 12-slovnej seed frázy"
},
"imported": {
"message": "Importováno",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Informace a nápověda"
},
"initialTransactionConfirmed": {
"message": "Sieť potvrdila vašu iniciálnu transakciu. Ak sa chcete vrátiť späť, kliknite na OK."
},
@ -587,12 +578,6 @@
"myAccounts": {
"message": "Moje účty"
},
"myWalletAccounts": {
"message": "Účty v Mojej peňaženke"
},
"myWalletAccountsDescription": {
"message": "Do tejto sekcie sa automaticky pridajú všetky vaše účty vytvorené pomocou MetaMask."
},
"needEtherInWallet": {
"message": "Potřebujete Ether v peněžence, abyste mohli pomocí MetaMasku interagovat s decentralizovanými aplikacemi."
},
@ -807,9 +792,6 @@
"restoreAccountWithSeed": {
"message": "Obnoviť účet pomocou seed frázy"
},
"restoreFromSeed": {
"message": "Obnovit z seed fráze"
},
"revealSeedWords": {
"message": "Zobrazit slova klíčové fráze"
},
@ -858,9 +840,6 @@
"secretBackupPhraseWarning": {
"message": "UPOZORNENIE: Nikdy nezverejňujte svoju backup frázu. Každý, kto má túto frázu, môže navždy vziať váš Ether."
},
"secretPhrase": {
"message": "Zadejte svých 12 slov tajné fráze k obnovení trezoru."
},
"securityAndPrivacy": {
"message": "Bezpečnosť a súkromie"
},
@ -900,9 +879,6 @@
"sendAmount": {
"message": "Poslať sumu"
},
"sendETH": {
"message": "Odeslat ETH"
},
"sendTokens": {
"message": "Odeslat tokeny"
},

@ -490,22 +490,13 @@
"importAccountSeedPhrase": {
"message": "Uvoz računa z geslom seed phrase"
},
"importUsingSeed": {
"message": "Uvozi z seed phase"
},
"importWallet": {
"message": "Uvozi denarnico"
},
"importYourExisting": {
"message": "Uvozite svojo obstoječo denarnico s pomočjo 12-besednega gesla seed phrase"
},
"imported": {
"message": "Uvoženo",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info & Pomoč"
},
"initialTransactionConfirmed": {
"message": "Vaša prvotna transakcija je bila potrjena. Pritisnite V redu in se vrnite nazaj."
},
@ -600,12 +591,6 @@
"myAccounts": {
"message": "Moji računi"
},
"myWalletAccounts": {
"message": "Moji računi Denarnice"
},
"myWalletAccountsDescription": {
"message": "Vsi vaši računi, ustvarjeni v MetaMasku, bodo samodejno dodani v ta razdelek."
},
"needEtherInWallet": {
"message": "Za interakcijo z decentraliziranimi aplikacijami boste v svoji denarnici potrebovali Eter."
},
@ -823,9 +808,6 @@
"restoreAccountWithSeed": {
"message": "Obnovi račun z seed phrase"
},
"restoreFromSeed": {
"message": "Obnovim račun?"
},
"revealSeedWords": {
"message": "Razkrij seed words"
},
@ -877,9 +859,6 @@
"secretBackupPhraseWarning": {
"message": "OPOZORILO: Nikoli nikomur ne razkrijte varnostne kopije. Kdorkoli lahko tem geslom vedno prevzame vaš Ether."
},
"secretPhrase": {
"message": "Vnesite vaših dvanajst besed za obnovitev vaših računov."
},
"securityAndPrivacy": {
"message": "Varnost in zasebnost"
},
@ -919,9 +898,6 @@
"sendAmount": {
"message": "Pošlji znesek"
},
"sendETH": {
"message": "Pošlji ETH"
},
"sendTokens": {
"message": "Pošlji žetone"
},

@ -496,22 +496,13 @@
"importAccountSeedPhrase": {
"message": "Uvezi račun sa frazom početnih vrednosti"
},
"importUsingSeed": {
"message": "Uvezite koristeći šifru za oporavak naloga (seed phrase)"
},
"importWallet": {
"message": "Uvezite novčanik"
},
"importYourExisting": {
"message": "Uvezite vaš postojeći novčanik koristeći seed frazu sa 12 reči"
},
"imported": {
"message": "Увезени",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info i pomoć"
},
"initialTransactionConfirmed": {
"message": "Vašu početnu transakciju je potvrdila mreža. Kliknite OK da biste se vratili."
},
@ -606,12 +597,6 @@
"myAccounts": {
"message": "Moji nalozi"
},
"myWalletAccounts": {
"message": "Moji nalozi novčanika"
},
"myWalletAccountsDescription": {
"message": "Svi vaši nalozi kreirani u aplikaciji MetaMask biće automatski dodati u ovaj deo."
},
"needEtherInWallet": {
"message": "Da biste stupili u interakciju sa decentralizovanim aplikacijama koristeći MetaMask, biće vam potreban Ether u vašem novčaniku."
},
@ -829,9 +814,6 @@
"restoreAccountWithSeed": {
"message": "Povratite svoj nalog uz pomoć seed fraze"
},
"restoreFromSeed": {
"message": "Obnoviti nalog?"
},
"revealSeedWords": {
"message": "Otkrivanje početnih reči"
},
@ -886,9 +868,6 @@
"secretBackupPhraseWarning": {
"message": "UPOZORENJE: Nikada ne otkrivajte svoju rezervnu frazu. Svako sa ovom frazom može zauvek da Vam uzme Vaš Ether."
},
"secretPhrase": {
"message": "Unesite ovde svoj tajni izraz od dvanaest reči kako biste povratili svoj trezor."
},
"securityAndPrivacy": {
"message": "Bezbednost i privatnost"
},
@ -928,9 +907,6 @@
"sendAmount": {
"message": "Pošaljite iznos"
},
"sendETH": {
"message": "Pošalji ETH"
},
"sendTokens": {
"message": "Pošalji tokene"
},

@ -489,22 +489,13 @@
"importAccountSeedPhrase": {
"message": "Importera konto med"
},
"importUsingSeed": {
"message": "Importera med kontots seedfras"
},
"importWallet": {
"message": "Importera plånbok"
},
"importYourExisting": {
"message": "Importera din existerande plånbok med hjälp av en 12 ord lång seedfras"
},
"imported": {
"message": "Importerade",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Info och hjälp"
},
"initialTransactionConfirmed": {
"message": "Din initiala transaktion har bekräftats av nätverket. Klicka på OK för att gå tillbaka."
},
@ -599,12 +590,6 @@
"myAccounts": {
"message": "Mina konton"
},
"myWalletAccounts": {
"message": "Mina plånbokskonton"
},
"myWalletAccountsDescription": {
"message": "Alla dina MetaMask-skapade konton läggs automatiskt till i denna avdelning."
},
"needEtherInWallet": {
"message": "För att interagera med decentraliserade applikationer med MetaMask behöver du Ether i din plånbok."
},
@ -822,9 +807,6 @@
"restoreAccountWithSeed": {
"message": "Återställ ditt konto med seedphrase"
},
"restoreFromSeed": {
"message": "Återställ konto?"
},
"revealSeedWords": {
"message": "Visa seed-ord"
},
@ -879,9 +861,6 @@
"secretBackupPhraseWarning": {
"message": "VARNING: avslöja aldrig din backup-fras. Någon som känner till denna fras kan ta dina Ether för alltid."
},
"secretPhrase": {
"message": "Ange din tolv ord långa hemliga fras här för att återställa ditt valv."
},
"securityAndPrivacy": {
"message": "Säkerhet och integritet"
},
@ -921,9 +900,6 @@
"sendAmount": {
"message": "Skicka belopp"
},
"sendETH": {
"message": "Skicka ETH"
},
"sendTokens": {
"message": "Skicka tokens"
},

@ -486,22 +486,13 @@
"importAccountSeedPhrase": {
"message": "Hamisha Akaunti kwa kutumia Kirai Kianzio"
},
"importUsingSeed": {
"message": "Hamisha kwa kutumia kirai kianzio cha akaunti"
},
"importWallet": {
"message": "Hamisha Waleti"
},
"importYourExisting": {
"message": "Hamisha waleti iliyopo kwa kutumia kirai kianzio cha maneno 12"
},
"imported": {
"message": "Zilizoingizwa",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Taarifa & Msaada"
},
"initialTransactionConfirmed": {
"message": "Muamala wako wa awali ulithibitishwa na mtandao. Bofya SWA ili urudi nyuma."
},
@ -593,12 +584,6 @@
"myAccounts": {
"message": "Akaunti zangu"
},
"myWalletAccounts": {
"message": "Akaunti angu za Waleti"
},
"myWalletAccountsDescription": {
"message": "Akaunti zako zote za MetaMask zilizofunguliwa zitaongezwa kiotomatiki kwenye sehemu hii."
},
"needEtherInWallet": {
"message": "Ili kuingiliana na programu zilizosambazwa kwa kutumia MetaMask, utahitaji kuwa na Ether kwenye waleti yako."
},
@ -816,9 +801,6 @@
"restoreAccountWithSeed": {
"message": "Rejesha Akaunti yako kwa kutumia Kirai Kianzio."
},
"restoreFromSeed": {
"message": "Rejesha akaunti?"
},
"revealSeedWords": {
"message": "Onyesha Maneno ya Kianzio"
},
@ -873,9 +855,6 @@
"secretBackupPhraseWarning": {
"message": "ONYO: Kamwe usiweke wazi kirai chako cha hifadhi mbadala. Mtu yeyote mwenye kirai hiki anaweza kuchukua Ether yako daima."
},
"secretPhrase": {
"message": "Ingiza hapa kirai chako cha siri cha maneno kumi na mawili ili urejeshe vault yako."
},
"securityAndPrivacy": {
"message": "Ulinzi na Faragha"
},
@ -915,9 +894,6 @@
"sendAmount": {
"message": "Tuma Kiasi"
},
"sendETH": {
"message": "Tuma ETH"
},
"sendTokens": {
"message": "Tuma Vianzio"
},

@ -226,9 +226,6 @@
"message": "இறகமதினத",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "தகவல மற உதவி"
},
"insufficientFunds": {
"message": "பன பணம இல."
},
@ -402,9 +399,6 @@
"restore": {
"message": "மடம"
},
"restoreFromSeed": {
"message": "விியதிிகவ"
},
"revealSeedWords": {
"message": "விகளிபடத"
},
@ -426,9 +420,6 @@
"searchTokens": {
"message": "தடலகன"
},
"secretPhrase": {
"message": "உஙகளடகதபதறக இங உஙகள ரகசிய பனிரணடர உளிடவ."
},
"seedPhraseReq": {
"message": "விியஙகள 12 வகளடவ"
},
@ -438,9 +429,6 @@
"send": {
"message": "அன"
},
"sendETH": {
"message": "ETH ஐ அன"
},
"sendTokens": {
"message": "டகனகள அனபவ"
},

@ -244,9 +244,6 @@
"message": "นำเขาเรยบรอย",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "ขอมลและความชวยเหลอ"
},
"insufficientFunds": {
"message": "เงนทนไมเพยงพอ"
},
@ -399,9 +396,6 @@
"resetAccount": {
"message": "รเซตบญช"
},
"restoreFromSeed": {
"message": "กนจากกลมคำชด"
},
"revealSeedWords": {
"message": "เปดเผยกลมคำชด"
},
@ -420,9 +414,6 @@
"search": {
"message": "คนหา"
},
"secretPhrase": {
"message": "ปอนกลมคำสบสองคำเพอกนตเซฟของคณ"
},
"seedPhraseReq": {
"message": "กลมคำชดมความยาว 12 คำ"
},
@ -441,9 +432,6 @@
"sendAmount": {
"message": "สงจำนวนเงนน"
},
"sendETH": {
"message": "สงอเธอร"
},
"sendTokens": {
"message": "สงโทเคน"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "log ng aktibidad"
},
"addAccount": {
"message": "Magdagdag ng account"
},
"addAcquiredTokens": {
"message": "Idagdag ang mga token na nakuha mo gamit ang MetaMask"
},
@ -781,22 +778,13 @@
"importAccountSeedPhrase": {
"message": "Mag-import ng account gamit ang seed phrase"
},
"importUsingSeed": {
"message": "I-import gamit ang seed phrase ng account"
},
"importWallet": {
"message": "I-import ang wallet"
},
"importYourExisting": {
"message": "I-import ang iyong kasalukuyang wallet gamit ang 12 salita na seed phrase"
},
"imported": {
"message": "Na-import",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Impormasyon at Tulong"
},
"initialTransactionConfirmed": {
"message": "Nakumpirma na ng network ang iyong inisyal na transaksyon. I-click ang OK para bumalik."
},
@ -984,12 +972,6 @@
"myAccounts": {
"message": "Mga Account Ko"
},
"myWalletAccounts": {
"message": "Mga Wallet Account Ko"
},
"myWalletAccountsDescription": {
"message": "Ang lahat ng iyong ginawang account sa MetaMask ay awtomatikong maidaragdag sa seksyong ito."
},
"needEtherInWallet": {
"message": "Para makaugnayan ang mga decentralized ma application gamit ang MetaMask, kakailanganin mo ang Ether sa iyong wallet."
},
@ -1270,9 +1252,6 @@
"restoreAccountWithSeed": {
"message": "I-restore ang iyong Account gamit ang Seed Phrase"
},
"restoreFromSeed": {
"message": "I-restore ang account?"
},
"restoreWalletPreferences": {
"message": "Nakita ang backup ng iyong data mula sa $1. Gusto mo bang i-restore ang mga kagustuhan mo sa wallet?",
"description": "$1 is the date at which the data was backed up"
@ -1343,9 +1322,6 @@
"secretBackupPhraseWarning": {
"message": "BABALA: Huwag kailanman ipaalam ang iyong phrase sa pag-back up. Ang sinumang may phrase na ito ay maaaring angkinin ang iyong Ether."
},
"secretPhrase": {
"message": "Ilagay ang iyong labindalawang lihim na phrase dito para ma-restore ang iyong vault."
},
"securityAndPrivacy": {
"message": "Seguridad at Pagkapribado"
},
@ -1397,9 +1373,6 @@
"sendAmount": {
"message": "Halaga ng Ipapadala"
},
"sendETH": {
"message": "Magpadala ng ETH"
},
"sendSpecifiedTokens": {
"message": "Magpadala ng $1",
"description": "Symbol of the specified token"
@ -1624,24 +1597,6 @@
"swapHighSlippageWarning": {
"message": "Sobrang laki ng halaga ng slippage. Tiyaking alam mo ang ginagawa mo!"
},
"swapIntroLearnMoreHeader": {
"message": "Gusto mo bang matuto pa?"
},
"swapIntroLearnMoreLink": {
"message": "Matuto pa tungkol sa MetaMask Swaps"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Kasama sa mga pinagkunan ng liquidity ang:"
},
"swapIntroPopupSubTitle": {
"message": "Puwede mo nang direktang i-swap ang mga token sa iyong MetaMask wallet. Pinagsasama-sama ng MetaMask Swaps ang maraming decentralized exchange aggregator, propesyonal na market maker, at indibidwal na DEX para matiyak na makukuha palagi ng mga user ng MetaMask ang pinakasulit na presyo nang may pinakamababang bayarin sa network."
},
"swapIntroPopupTitle": {
"message": "Ito na ang pag-swap ng token!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Suriin ang aming audit ng mga opisyal na kontrata"
},
"swapLowSlippageError": {
"message": "Maaaring hindi magtagumpay ang transaksyon, masyadong mababa ang max na slippage."
},
@ -1663,7 +1618,7 @@
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNetworkFeeSummary": {
"message": "Kasama sa bayarin sa network ang gastusin sa pagproseso ng iyong pag-swap at pag-store nito sa Ethereum network. Hindi kumikita ang MetaMask mula sa bayaring ito."
"message": "Kasama sa bayarin sa network ang gastusin sa pagproseso ng iyong pag-swap at pag-store nito sa $1 network. Hindi kumikita ang MetaMask mula sa bayaring ito."
},
"swapNewQuoteIn": {
"message": "Mga bagong quote sa $1",
@ -1744,9 +1699,6 @@
"swapSourceInfo": {
"message": "Naghahanap kami ng maraming pinagkukunan ng liquidity (mga exchange, aggregator at propesyonal na market maker) para mahanap ang mga pinakasulit na rate at pinakamababang bayarin sa network."
},
"swapStartSwapping": {
"message": "Simulang mag-swap"
},
"swapSwapFrom": {
"message": "Ipalit mula sa"
},
@ -1876,9 +1828,6 @@
"tokenContractAddress": {
"message": "Address ng Kontrata ng Token"
},
"tokenOptions": {
"message": "Mga opsyon ng token"
},
"tokenSymbol": {
"message": "Simbolo ng Token"
},

@ -196,9 +196,6 @@
"message": "Alındı",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Bilgi ve yardım"
},
"insufficientFunds": {
"message": "Yetersiz kaynak."
},
@ -342,9 +339,6 @@
"resetAccount": {
"message": "Hesabı sıfıla"
},
"restoreFromSeed": {
"message": "Kaynak ifadeden geri getir. Restore from seed phrase"
},
"revealSeedWords": {
"message": "Kaynak kelimelerini göster"
},
@ -366,9 +360,6 @@
"searchTokens": {
"message": "Jeton ara"
},
"secretPhrase": {
"message": "Kasanızı geri getirmek için gizli 12 kelimelik ifadenizi giriniz."
},
"seedPhraseReq": {
"message": "Kaynak ifadeleri 12 kelimedir."
},
@ -378,9 +369,6 @@
"send": {
"message": "Gönder"
},
"sendETH": {
"message": "ETH Gönder"
},
"sendTokens": {
"message": "Jeton Gönder"
},

@ -499,22 +499,13 @@
"importAccountSeedPhrase": {
"message": "Імпортувати обліковий запис з початковою фразою"
},
"importUsingSeed": {
"message": "Імпортувати, використовуючи початкову фразу облікового запису"
},
"importWallet": {
"message": "Імпортувати гаманець"
},
"importYourExisting": {
"message": "Імпортуйте ваш гаманець, що існує, використовуючи початкову фразу з 12 слів"
},
"imported": {
"message": "Імпортовано",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Інформація та допомога"
},
"initialTransactionConfirmed": {
"message": "Ваша початкова транзакція підтверджена мережею. Натисніть ОК для повернення."
},
@ -615,12 +606,6 @@
"myAccounts": {
"message": "Мої облікові записи"
},
"myWalletAccounts": {
"message": "Облікові записи мого гаманця"
},
"myWalletAccountsDescription": {
"message": "Усі ваші створені облікові записи MetaMask буде автоматично додано в цей розділ."
},
"needEtherInWallet": {
"message": "Щоб взаємодіяти з децентралізованими застосунками використовуючи MetaMask, вам буде потрібен Ether у вашому гаманці."
},
@ -838,9 +823,6 @@
"restoreAccountWithSeed": {
"message": "Відновіть ваш обліковий запис за допомогою seed-фрази"
},
"restoreFromSeed": {
"message": "Відновити обліковий запис?"
},
"revealSeedWords": {
"message": "Показати мнемонічні слова"
},
@ -895,9 +877,6 @@
"secretBackupPhraseWarning": {
"message": "ЗАСТЕРЕЖЕННЯ: Ніколи не розголошуйте вашу резервну фразу. Будь-хто з цією фразою зможе забрати ваш Ether назавжди."
},
"secretPhrase": {
"message": "Введіть секретну фразу з дванадцяти слів, щоб відновити своє сховище."
},
"securityAndPrivacy": {
"message": "Безпека й конфіденційність"
},
@ -937,9 +916,6 @@
"sendAmount": {
"message": "Надіслати суму"
},
"sendETH": {
"message": "Надіслати ETH"
},
"sendTokens": {
"message": "Надіслати токени"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "nhật ký hoạt động"
},
"addAccount": {
"message": "Thêm tài khoản"
},
"addAcquiredTokens": {
"message": "Thêm token mà bạn đã mua bằng MetaMask"
},
@ -781,22 +778,13 @@
"importAccountSeedPhrase": {
"message": "Nhập một tài khoản bằng cụm mật khẩu gốc"
},
"importUsingSeed": {
"message": "Nhập bằng cách sử dụng cụm mật khẩu gốc của tài khoản"
},
"importWallet": {
"message": "Nhập ví"
},
"importYourExisting": {
"message": "Nhập ví hiện có của bạn bằng cụm mật khẩu gốc gồm 12 từ"
},
"imported": {
"message": "Đã nhập",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "Thông tin và trợ giúp"
},
"initialTransactionConfirmed": {
"message": "Mạng đã xác nhận giao dịch ban đầu của bạn. Nhấp vào OK để quay lại."
},
@ -984,12 +972,6 @@
"myAccounts": {
"message": "Tài khoản của tôi"
},
"myWalletAccounts": {
"message": "Các tài khoản trong ví của tôi"
},
"myWalletAccountsDescription": {
"message": "Tất cả các tài khoản đã tạo của bạn trong MetaMask sẽ tự động được thêm vào phần này."
},
"needEtherInWallet": {
"message": "Để tương tác với các ứng dụng phi tập trung bằng MetaMask, bạn sẽ cần phải có Ether trong ví của mình."
},
@ -1273,9 +1255,6 @@
"restoreAccountWithSeed": {
"message": "Khôi phục tài khoản của bạn bằng cụm mật khẩu gốc"
},
"restoreFromSeed": {
"message": "Khôi phục tài khoản?"
},
"restoreWalletPreferences": {
"message": "Đã tìm thấy bản sao lưu dữ liệu của bạn từ $1. Bạn có muốn khôi phục các tùy chọn ưu tiên trong ví của mình không?",
"description": "$1 is the date at which the data was backed up"
@ -1346,9 +1325,6 @@
"secretBackupPhraseWarning": {
"message": "CẢNH BÁO: Tuyệt đối không để lộ cụm mật khẩu sao lưu của bạn. Bất kỳ ai có cụm mật khẩu này cũng có thể lấy Ether của bạn vĩnh viễn."
},
"secretPhrase": {
"message": "Nhập cụm mật khẩu bí mật gồm 12 từ vào đây để khôi phục két của bạn."
},
"securityAndPrivacy": {
"message": "Bảo mật và quyền riêng tư"
},
@ -1400,9 +1376,6 @@
"sendAmount": {
"message": "Gửi khoản tiền"
},
"sendETH": {
"message": "Gửi ETH"
},
"sendSpecifiedTokens": {
"message": "Gửi $1",
"description": "Symbol of the specified token"
@ -1627,24 +1600,6 @@
"swapHighSlippageWarning": {
"message": "Số tiền trượt giá rất cao. Hãy chắc chắn rằng bạn hiểu những gì mình đang làm!"
},
"swapIntroLearnMoreHeader": {
"message": "Bạn muốn tìm hiểu thêm?"
},
"swapIntroLearnMoreLink": {
"message": "Tìm hiểu thêm về MetaMask Swaps"
},
"swapIntroLiquiditySourcesLabel": {
"message": "Các nguồn thanh khoản bao gồm:"
},
"swapIntroPopupSubTitle": {
"message": "Giờ đây bạn có thể hoán đổi token ngay trong ví MetaMask của mình. MetaMask Swaps quy tụ nhiều trình tổng hợp sàn giao dịch phi tập trung, các nhà tạo lập thị trường chuyên nghiệp và các sàn giao dịch phi tập trung dành cho cá nhân nhằm đảm bảo người dùng MetaMask luôn nhận được mức giá tốt nhất với phí mạng thấp nhất."
},
"swapIntroPopupTitle": {
"message": "Tính năng hoán đổi token đã sẵn sàng!"
},
"swapLearnMoreContractsAuditReview": {
"message": "Xem xét quy trình kiểm tra hợp đồng chính thức của chúng tôi"
},
"swapLowSlippageError": {
"message": "Giao dịch có thể không thành công, mức trượt giá tối đa quá thấp."
},
@ -1666,7 +1621,7 @@
"description": "Provides information about the fee that metamask takes for swaps. $1 is a decimal number."
},
"swapNetworkFeeSummary": {
"message": "Phí mạng dùng để chi trả chi phí xử lý giao dịch hoán đổi của bạn và lưu trữ giao dịch đó trên mạng Ethereum. MetaMask không thu lợi từ khoản phí này."
"message": "Phí mạng dùng để chi trả chi phí xử lý giao dịch hoán đổi của bạn và lưu trữ giao dịch đó trên mạng $1. MetaMask không thu lợi từ khoản phí này."
},
"swapNewQuoteIn": {
"message": "Báo giá mới sẽ có sau $1",
@ -1747,9 +1702,6 @@
"swapSourceInfo": {
"message": "Chúng tôi tìm kiếm nhiều nguồn thanh khoản (các sàn giao dịch, trình tổng hợp và nhà tạo lập thị trường) để tìm được mức tỷ lệ tốt nhất và phí mạng thấp nhất."
},
"swapStartSwapping": {
"message": "Bắt đầu hoán đổi"
},
"swapSwapFrom": {
"message": "Hoán đổi từ"
},
@ -1879,9 +1831,6 @@
"tokenContractAddress": {
"message": "Địa chỉ hợp đồng token"
},
"tokenOptions": {
"message": "Tùy chọn token"
},
"tokenSymbol": {
"message": "Ký hiệu token"
},

@ -43,9 +43,6 @@
"activityLog": {
"message": "活动日志"
},
"addAccount": {
"message": "添加一个账户"
},
"addAcquiredTokens": {
"message": "在 MetaMask 上添加获得的代币"
},
@ -790,22 +787,13 @@
"importAccountSeedPhrase": {
"message": "使用账户助记词导入账户"
},
"importUsingSeed": {
"message": "使用账户助记词导入"
},
"importWallet": {
"message": "导入钱包"
},
"importYourExisting": {
"message": "使用 12 个单词的账户助记词导入您现有的钱包账户。"
},
"imported": {
"message": "已导入",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "信息 & 帮助"
},
"initialTransactionConfirmed": {
"message": "您的初始交易已通过网络确认。请点击“确定”返回。"
},
@ -996,12 +984,6 @@
"myAccounts": {
"message": "我的账户"
},
"myWalletAccounts": {
"message": "我的钱包账户"
},
"myWalletAccountsDescription": {
"message": "所有创建的 MetaMask 账户将自动添加到此部分。"
},
"needEtherInWallet": {
"message": "使用 MetaMask 与分布式应用交互,需要您的钱包里需要有 Ether。"
},
@ -1282,9 +1264,6 @@
"restoreAccountWithSeed": {
"message": "使用账户助记词恢复您的账户"
},
"restoreFromSeed": {
"message": "从助记词还原"
},
"restoreWalletPreferences": {
"message": "已找到于 $1 的数据备份。您想恢复您的钱包设置吗?",
"description": "$1 is the date at which the data was backed up"
@ -1355,9 +1334,6 @@
"secretBackupPhraseWarning": {
"message": "警告:切勿向他人透露您的账户助记词。任何人一旦持有该账户助记词,即可控制您的 Ether。"
},
"secretPhrase": {
"message": "输入 12 个单词组成的账户助记词恢复您的账户。"
},
"securityAndPrivacy": {
"message": "安全与隐私"
},
@ -1409,9 +1385,6 @@
"sendAmount": {
"message": "发送数额"
},
"sendETH": {
"message": "发送 ETH"
},
"sendSpecifiedTokens": {
"message": "发送 $1",
"description": "Symbol of the specified token"
@ -1639,24 +1612,6 @@
"swapHighSlippageWarning": {
"message": "滑点数量非常大。确保您知道您的操作!"
},
"swapIntroLearnMoreHeader": {
"message": "想了解更多信息?"
},
"swapIntroLearnMoreLink": {
"message": "了解更多关于 MetaMask Swap(兑换)"
},
"swapIntroLiquiditySourcesLabel": {
"message": "流动资金来源包括:"
},
"swapIntroPopupSubTitle": {
"message": "现在您可以直接在 MetaMask 钱包中兑换代币。MetaMask Swaps(兑换)结合了多个去中心化交易所聚合商、专业做市商和个人 DEX,确保 MetaMask 用户始终以最低的网络费用获得最佳价格。"
},
"swapIntroPopupTitle": {
"message": "代币兑换来了!"
},
"swapLearnMoreContractsAuditReview": {
"message": "查看我们的官方合约审计"
},
"swapLowSlippageError": {
"message": "交易可能失败,最大滑点过低。"
},
@ -1682,7 +1637,7 @@
"description": "$1 is the number of quotes that the user can select from when opening the list of quotes on the 'view quote' screen"
},
"swapNetworkFeeSummary": {
"message": "网络手续费包括处理您的兑换和在以太坊(Ethereum)网络上存储的成本。MetaMask 不从这笔费用中获利。"
"message": "网络手续费包括处理您的兑换和在以太坊($1)网络上存储的成本。MetaMask 不从这笔费用中获利。"
},
"swapNewQuoteIn": {
"message": "$1 后更新报价",
@ -1777,9 +1732,6 @@
"swapSourceInfo": {
"message": "我们搜索多个流动性来源(交易所、聚合商和专业做市商),以找到最好的利率和最低的网络手续费。"
},
"swapStartSwapping": {
"message": "开始兑换"
},
"swapSwapFrom": {
"message": "兑换自"
},
@ -1915,9 +1867,6 @@
"tokenContractAddress": {
"message": "代币合约地址"
},
"tokenOptions": {
"message": "代币选项"
},
"tokenSymbol": {
"message": "代币符号"
},

@ -508,22 +508,13 @@
"importAccountSeedPhrase": {
"message": "利用助憶詞還原"
},
"importUsingSeed": {
"message": "利用助憶詞匯入帳戶"
},
"importWallet": {
"message": "匯入錢包"
},
"importYourExisting": {
"message": "使用 12 字的助記詞來匯入你現有的錢包"
},
"imported": {
"message": "已匯入私鑰",
"description": "status showing that an account has been fully loaded into the keyring"
},
"infoHelp": {
"message": "說明 & 資訊"
},
"initialTransactionConfirmed": {
"message": "交易已確認"
},
@ -621,12 +612,6 @@
"myAccounts": {
"message": "我的帳戶"
},
"myWalletAccounts": {
"message": "我的錢包帳號"
},
"myWalletAccountsDescription": {
"message": "所有你在 MetaMask 創建的帳號將自動新增到此區塊。"
},
"needEtherInWallet": {
"message": "要使用 MetaMask 存取去中心化應用服務時,您的錢包中需要有以太幣。"
},
@ -832,9 +817,6 @@
"restoreAccountWithSeed": {
"message": "透過助憶詞還原您的帳戶"
},
"restoreFromSeed": {
"message": "還原帳戶?"
},
"revealSeedWords": {
"message": "顯示助憶詞"
},
@ -889,9 +871,6 @@
"secretBackupPhraseWarning": {
"message": "警告: 絕對不要洩漏您的助憶詞。任何人只要得知助憶詞代表他可以竊取您所有的以太幣和代幣。"
},
"secretPhrase": {
"message": "輸入您的12個助憶詞以回復金庫"
},
"securityAndPrivacy": {
"message": "安全&隱私"
},
@ -925,9 +904,6 @@
"sendAmount": {
"message": "發送數量"
},
"sendETH": {
"message": "發送以太幣"
},
"sendTokens": {
"message": "發送代幣"
},

@ -0,0 +1,15 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<script src="./globalthis.js" type="text/javascript" charset="utf-8"></script>
<script src="./initSentry.js" type="text/javascript" charset="utf-8"></script>
<script src="./lockdown.js" type="text/javascript" charset="utf-8"></script>
<script src="./runLockdown.js" type="text/javascript" charset="utf-8"></script>
<script src="./bg-libs.js" type="text/javascript" charset="utf-8"></script>
<script src="./background.js" type="text/javascript" charset="utf-8"></script>
<script src="./chromereload.js" type="text/javascript" charset="utf-8"></script>
</body>
</html>

@ -0,0 +1 @@
<svg width="56" height="64" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M54.5 20c.75 0 1.5-.625 1.5-1.5v-5c0-.75-.75-1.5-1.5-1.5H52V6c0-3.25-2.75-6-6-6H6C2.625 0 0 2.75 0 6v52c0 3.375 2.625 6 6 6h40c3.25 0 6-2.625 6-6v-6h2.5c.75 0 1.5-.625 1.5-1.5v-5c0-.75-.75-1.5-1.5-1.5H52v-8h2.5c.75 0 1.5-.625 1.5-1.5v-5c0-.75-.75-1.5-1.5-1.5H52v-8h2.5zM26 16c4.375 0 8 3.625 8 8 0 4.5-3.625 8-8 8-4.5 0-8-3.5-8-8 0-4.375 3.5-8 8-8zm14 29.625C40 47 38.75 48 37.125 48H14.75c-1.5 0-2.75-1-2.75-2.375V43.25c0-4 3.75-7.25 8.375-7.25H21c1.5.75 3.125 1 5 1 1.75 0 3.375-.25 4.875-1h.625c4.625 0 8.5 3.25 8.5 7.25v2.375z" fill="#D6D9DC"/></svg>

After

Width:  |  Height:  |  Size: 638 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

@ -0,0 +1,3 @@
<svg width="19" height="14" viewBox="0 0 19 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 5C14 2.25 11.0625 0 7.5 0C3.90625 0 1 2.25 1 5C1 6.09375 1.4375 7.0625 2.1875 7.875C1.75 8.84375 1.0625 9.59375 1.0625 9.59375C1 9.65625 0.96875 9.78125 1 9.875C1.0625 9.96875 1.125 10 1.25 10C2.375 10 3.3125 9.625 4 9.21875C5 9.71875 6.21875 10 7.5 10C11.0625 10 14 7.78125 14 5ZM17.8125 11.875C18.5312 11.0625 19 10.0938 19 9C19 6.9375 17.3125 5.125 14.9375 4.375C14.9688 4.59375 15 4.8125 15 5C15 8.3125 11.625 11 7.5 11C7.15625 11 6.8125 11 6.5 10.9688C7.46875 12.75 9.78125 14 12.5 14C13.7812 14 14.9688 13.7188 15.9688 13.2188C16.6562 13.625 17.5938 14 18.75 14C18.8438 14 18.9375 13.9688 18.9688 13.875C19 13.7812 19 13.6562 18.9062 13.5938C18.9062 13.5938 18.2188 12.8438 17.8125 11.875Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 827 B

@ -1,14 +1,7 @@
{
"author": "https://metamask.io",
"background": {
"scripts": [
"globalthis.js",
"initSentry.js",
"lockdown.js",
"runLockdown.js",
"bg-libs.js",
"background.js"
],
"page": "background.html",
"persistent": true
},
"browser_action": {
@ -78,6 +71,6 @@
"notifications"
],
"short_name": "__MSG_appName__",
"version": "9.4.0",
"version": "9.5.0",
"web_accessible_resources": ["inpage.js", "phishing.html"]
}

@ -1,6 +1,6 @@
import assert from 'assert';
import ethUtil from 'ethereumjs-util';
import accountImporter from '../../../app/scripts/account-import-strategies';
import { stripHexPrefix } from 'ethereumjs-util';
import accountImporter from '.';
describe('Account Import Strategies', function () {
const privkey =
@ -13,7 +13,7 @@ describe('Account Import Strategies', function () {
const importPrivKey = await accountImporter.importAccount('Private Key', [
privkey,
]);
assert.equal(importPrivKey, ethUtil.stripHexPrefix(privkey));
assert.equal(importPrivKey, stripHexPrefix(privkey));
});
it('throws an error for empty string private key', async function () {

@ -1,7 +1,12 @@
import log from 'loglevel';
import Wallet from 'ethereumjs-wallet';
import importers from 'ethereumjs-wallet/thirdparty';
import ethUtil from 'ethereumjs-util';
import {
toBuffer,
isValidPrivate,
bufferToHex,
stripHexPrefix,
} from 'ethereumjs-util';
import { addHexPrefix } from '../lib/util';
const accountImporter = {
@ -22,13 +27,13 @@ const accountImporter = {
}
const prefixed = addHexPrefix(privateKey);
const buffer = ethUtil.toBuffer(prefixed);
const buffer = toBuffer(prefixed);
if (!ethUtil.isValidPrivate(buffer)) {
if (!isValidPrivate(buffer)) {
throw new Error('Cannot import invalid private key.');
}
const stripped = ethUtil.stripHexPrefix(prefixed);
const stripped = stripHexPrefix(prefixed);
return stripped;
},
'JSON File': (input, password) => {
@ -47,7 +52,7 @@ const accountImporter = {
function walletToPrivateKey(wallet) {
const privateKeyBuffer = wallet.getPrivateKey();
return ethUtil.bufferToHex(privateKeyBuffer);
return bufferToHex(privateKeyBuffer);
}
export default accountImporter;

@ -1,12 +1,6 @@
/**
* @file The entry point for the web extension singleton process.
*/
// these need to run before anything else
/* eslint-disable import/first,import/order */
import setupFetchDebugging from './lib/setupFetchDebugging';
/* eslint-enable import/order */
setupFetchDebugging();
// polyfills
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch';
@ -70,21 +64,7 @@ if (inTest || process.env.METAMASK_DEBUG) {
initialize().catch(log.error);
/**
* An object representing a transaction, in whatever state it is in.
* @typedef TransactionMeta
*
* @property {number} id - An internally unique tx identifier.
* @property {number} time - Time the tx was first suggested, in unix epoch time (ms).
* @property {string} status - The current transaction status (unapproved, signed, submitted, dropped, failed, rejected), as defined in `tx-state-manager.js`.
* @property {string} metamaskNetworkId - The transaction's network ID, used for EIP-155 compliance.
* @property {boolean} loadingDefaults - TODO: Document
* @property {Object} txParams - The tx params as passed to the network provider.
* @property {Object[]} history - A history of mutations to this TransactionMeta object.
* @property {string} origin - A string representing the interface that suggested the transaction.
* @property {Object} nonceDetails - A metadata object containing information used to derive the suggested nonce, useful for debugging nonce issues.
* @property {string} rawTx - A hex string of the final signed transaction, ready to submit to the network.
* @property {string} hash - A hex string of the transaction hash, used to identify the transaction on the network.
* @property {number} submittedTime - The time the transaction was submitted to the network, in Unix epoch time (ms).
* @typedef {import('../../shared/constants/transaction').TransactionMeta} TransactionMeta
*/
/**

@ -22,7 +22,6 @@ export default class AppStateController extends EventEmitter {
this.store = new ObservableStore({
timeoutMinutes: 0,
connectedStatusPopoverHasBeenShown: true,
swapsWelcomeMessageHasBeenShown: false,
defaultHomeActiveTabName: null,
...initState,
});
@ -112,15 +111,6 @@ export default class AppStateController extends EventEmitter {
});
}
/**
* Record that the user has seen the swap screen welcome message
*/
setSwapsWelcomeMessageHasBeenShown() {
this.store.updateState({
swapsWelcomeMessageHasBeenShown: true,
});
}
/**
* Sets the last active time to the current time
* @returns {void}

@ -1,7 +1,7 @@
import assert from 'assert';
import sinon from 'sinon';
import CachedBalancesController from '../../../../app/scripts/controllers/cached-balances';
import { KOVAN_CHAIN_ID } from '../../../../shared/constants/network';
import { KOVAN_CHAIN_ID } from '../../../shared/constants/network';
import CachedBalancesController from './cached-balances';
describe('CachedBalancesController', function () {
describe('updateCachedBalances', function () {

@ -4,10 +4,10 @@ import { ObservableStore } from '@metamask/obs-store';
import contracts from '@metamask/contract-metadata';
import BigNumber from 'bignumber.js';
import DetectTokensController from '../../../../app/scripts/controllers/detect-tokens';
import NetworkController from '../../../../app/scripts/controllers/network/network';
import PreferencesController from '../../../../app/scripts/controllers/preferences';
import { MAINNET, ROPSTEN } from '../../../../shared/constants/network';
import { MAINNET, ROPSTEN } from '../../../shared/constants/network';
import DetectTokensController from './detect-tokens';
import NetworkController from './network';
import PreferencesController from './preferences';
describe('DetectTokensController', function () {
const sandbox = sinon.createSandbox();

@ -1,5 +1,5 @@
import punycode from 'punycode/punycode';
import ethUtil from 'ethereumjs-util';
import { toChecksumAddress } from 'ethereumjs-util';
import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel';
import { CHAIN_ID_TO_NETWORK_ID_MAP } from '../../../../shared/constants/network';
@ -43,7 +43,7 @@ export default class EnsController {
}
reverseResolveAddress(address) {
return this._reverseResolveAddress(ethUtil.toChecksumAddress(address));
return this._reverseResolveAddress(toChecksumAddress(address));
}
async _reverseResolveAddress(address) {
@ -79,7 +79,7 @@ export default class EnsController {
return undefined;
}
if (ethUtil.toChecksumAddress(registeredAddress) !== address) {
if (toChecksumAddress(registeredAddress) !== address) {
return undefined;
}

@ -1,6 +1,6 @@
import assert from 'assert';
import sinon from 'sinon';
import EnsController from '../../../../app/scripts/controllers/ens';
import EnsController from '.';
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000';
const ZERO_X_ERROR_ADDRESS = '0x';
@ -79,7 +79,7 @@ describe('EnsController', function () {
const ens = new EnsController({
ens: {
reverse: sinon.stub().withArgs(address).returns('peaksignal.eth'),
lookup: sinon.stub().withArgs('peaksignal.eth').returns('0xfoo'),
lookup: sinon.stub().withArgs('peaksignal.eth').returns('0x00'),
},
onNetworkDidChange,
getCurrentChainId,

@ -1,32 +1,48 @@
import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel';
import BN from 'bn.js';
import createId from '../lib/random-id';
import createId from '../../../shared/modules/random-id';
import { bnToHex } from '../lib/util';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import {
TRANSACTION_CATEGORIES,
TRANSACTION_TYPES,
TRANSACTION_STATUSES,
} from '../../../shared/constants/transaction';
import {
CHAIN_ID_TO_NETWORK_ID_MAP,
CHAIN_ID_TO_TYPE_MAP,
GOERLI,
GOERLI_CHAIN_ID,
KOVAN,
KOVAN_CHAIN_ID,
MAINNET,
MAINNET_CHAIN_ID,
RINKEBY,
RINKEBY_CHAIN_ID,
ROPSTEN,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
import { NETWORK_EVENTS } from './network';
const fetchWithTimeout = getFetchWithTimeout(30000);
/**
* @typedef {import('../../../shared/constants/transaction').TransactionMeta} TransactionMeta
*/
/**
* A transaction object in the format returned by the Etherscan API.
*
* Note that this is not an exhaustive type definiton; only the properties we use are defined
*
* @typedef {Object} EtherscanTransaction
* @property {string} blockNumber - The number of the block this transaction was found in, in decimal
* @property {string} from - The hex-prefixed address of the sender
* @property {string} gas - The gas limit, in decimal WEI
* @property {string} gasPrice - The gas price, in decimal WEI
* @property {string} hash - The hex-prefixed transaction hash
* @property {string} isError - Whether the transaction was confirmed or failed (0 for confirmed, 1 for failed)
* @property {string} nonce - The transaction nonce, in decimal
* @property {string} timeStamp - The timestamp for the transaction, in seconds
* @property {string} to - The hex-prefixed address of the recipient
* @property {string} value - The amount of ETH sent in this transaction, in decimal WEI
*/
/**
* This controller is responsible for retrieving incoming transactions. Etherscan is polled once every block to check
* for new incoming transactions for the current selected account on the current network
@ -44,35 +60,37 @@ const etherscanSupportedNetworks = [
export default class IncomingTransactionsController {
constructor(opts = {}) {
const { blockTracker, networkController, preferencesController } = opts;
const {
blockTracker,
onNetworkDidChange,
getCurrentChainId,
preferencesController,
} = opts;
this.blockTracker = blockTracker;
this.networkController = networkController;
this.getCurrentChainId = getCurrentChainId;
this.preferencesController = preferencesController;
this._onLatestBlock = async (newBlockNumberHex) => {
const selectedAddress = this.preferencesController.getSelectedAddress();
const newBlockNumberDec = parseInt(newBlockNumberHex, 16);
await this._update({
address: selectedAddress,
newBlockNumberDec,
});
await this._update(selectedAddress, newBlockNumberDec);
};
const initState = {
incomingTransactions: {},
incomingTxLastFetchedBlocksByNetwork: {
[GOERLI]: null,
[KOVAN]: null,
[MAINNET]: null,
[RINKEBY]: null,
[ROPSTEN]: null,
incomingTxLastFetchedBlockByChainId: {
[GOERLI_CHAIN_ID]: null,
[KOVAN_CHAIN_ID]: null,
[MAINNET_CHAIN_ID]: null,
[RINKEBY_CHAIN_ID]: null,
[ROPSTEN_CHAIN_ID]: null,
},
...opts.initState,
};
this.store = new ObservableStore(initState);
this.preferencesController.store.subscribe(
pairwise((prevState, currState) => {
previousValueComparator((prevState, currState) => {
const {
featureFlags: {
showIncomingTransactions: prevShowIncomingTransactions,
@ -94,29 +112,24 @@ export default class IncomingTransactionsController {
}
this.start();
}),
}, this.preferencesController.store.getState()),
);
this.preferencesController.store.subscribe(
pairwise(async (prevState, currState) => {
previousValueComparator(async (prevState, currState) => {
const { selectedAddress: prevSelectedAddress } = prevState;
const { selectedAddress: currSelectedAddress } = currState;
if (currSelectedAddress === prevSelectedAddress) {
return;
}
await this._update({
address: currSelectedAddress,
});
}),
await this._update(currSelectedAddress);
}, this.preferencesController.store.getState()),
);
this.networkController.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, async () => {
onNetworkDidChange(async () => {
const address = this.preferencesController.getSelectedAddress();
await this._update({
address,
});
await this._update(address);
});
}
@ -136,85 +149,79 @@ export default class IncomingTransactionsController {
this.blockTracker.removeListener('latest', this._onLatestBlock);
}
async _update({ address, newBlockNumberDec } = {}) {
const chainId = this.networkController.getCurrentChainId();
if (!etherscanSupportedNetworks.includes(chainId)) {
/**
* Determines the correct block number to begin looking for new transactions
* from, fetches the transactions and then saves them and the next block
* number to begin fetching from in state. Block numbers and transactions are
* stored per chainId.
* @private
* @param {string} address - address to lookup transactions for
* @param {number} [newBlockNumberDec] - block number to begin fetching from
* @returns {void}
*/
async _update(address, newBlockNumberDec) {
const chainId = this.getCurrentChainId();
if (!etherscanSupportedNetworks.includes(chainId) || !address) {
return;
}
try {
const dataForUpdate = await this._getDataForUpdate({
const currentState = this.store.getState();
const currentBlock = parseInt(this.blockTracker.getCurrentBlock(), 16);
const mostRecentlyFetchedBlock =
currentState.incomingTxLastFetchedBlockByChainId[chainId];
const blockToFetchFrom =
mostRecentlyFetchedBlock ?? newBlockNumberDec ?? currentBlock;
const newIncomingTxs = await this._getNewIncomingTransactions(
address,
blockToFetchFrom,
chainId,
newBlockNumberDec,
);
let newMostRecentlyFetchedBlock = blockToFetchFrom;
newIncomingTxs.forEach((tx) => {
if (
tx.blockNumber &&
parseInt(newMostRecentlyFetchedBlock, 10) <
parseInt(tx.blockNumber, 10)
) {
newMostRecentlyFetchedBlock = parseInt(tx.blockNumber, 10);
}
});
this.store.updateState({
incomingTxLastFetchedBlockByChainId: {
...currentState.incomingTxLastFetchedBlockByChainId,
[chainId]: newMostRecentlyFetchedBlock + 1,
},
incomingTransactions: newIncomingTxs.reduce(
(transactions, tx) => {
transactions[tx.hash] = tx;
return transactions;
},
{
...currentState.incomingTransactions,
},
),
});
this._updateStateWithNewTxData(dataForUpdate);
} catch (err) {
log.error(err);
}
}
async _getDataForUpdate({ address, chainId, newBlockNumberDec } = {}) {
const {
incomingTransactions: currentIncomingTxs,
incomingTxLastFetchedBlocksByNetwork: currentBlocksByNetwork,
} = this.store.getState();
const lastFetchBlockByCurrentNetwork =
currentBlocksByNetwork[CHAIN_ID_TO_TYPE_MAP[chainId]];
let blockToFetchFrom = lastFetchBlockByCurrentNetwork || newBlockNumberDec;
if (blockToFetchFrom === undefined) {
blockToFetchFrom = parseInt(this.blockTracker.getCurrentBlock(), 16);
}
const { latestIncomingTxBlockNumber, txs: newTxs } = await this._fetchAll(
address,
blockToFetchFrom,
chainId,
);
return {
latestIncomingTxBlockNumber,
newTxs,
currentIncomingTxs,
currentBlocksByNetwork,
fetchedBlockNumber: blockToFetchFrom,
chainId,
};
}
_updateStateWithNewTxData({
latestIncomingTxBlockNumber,
newTxs,
currentIncomingTxs,
currentBlocksByNetwork,
fetchedBlockNumber,
chainId,
}) {
const newLatestBlockHashByNetwork = latestIncomingTxBlockNumber
? parseInt(latestIncomingTxBlockNumber, 10) + 1
: fetchedBlockNumber + 1;
const newIncomingTransactions = {
...currentIncomingTxs,
};
newTxs.forEach((tx) => {
newIncomingTransactions[tx.hash] = tx;
});
this.store.updateState({
incomingTxLastFetchedBlocksByNetwork: {
...currentBlocksByNetwork,
[CHAIN_ID_TO_TYPE_MAP[chainId]]: newLatestBlockHashByNetwork,
},
incomingTransactions: newIncomingTransactions,
});
}
async _fetchAll(address, fromBlock, chainId) {
const fetchedTxResponse = await this._fetchTxs(address, fromBlock, chainId);
return this._processTxFetchResponse(fetchedTxResponse);
}
async _fetchTxs(address, fromBlock, chainId) {
/**
* fetches transactions for the given address and chain, via etherscan, then
* processes the data into the necessary shape for usage in this controller.
*
* @private
* @param {string} [address] - Address to fetch transactions for
* @param {number} [fromBlock] - Block to look for transactions at
* @param {string} [chainId] - The chainId for the current network
* @returns {TransactionMeta[]}
*/
async _getNewIncomingTransactions(address, fromBlock, chainId) {
const etherscanSubdomain =
chainId === MAINNET_CHAIN_ID
? 'api'
@ -227,16 +234,8 @@ export default class IncomingTransactionsController {
url += `&startBlock=${parseInt(fromBlock, 10)}`;
}
const response = await fetchWithTimeout(url);
const parsedResponse = await response.json();
return {
...parsedResponse,
address,
chainId,
};
}
_processTxFetchResponse({ status, result = [], address, chainId }) {
const { status, result } = await response.json();
let newIncomingTxs = [];
if (status === '1' && Array.isArray(result) && result.length > 0) {
const remoteTxList = {};
const remoteTxs = [];
@ -247,70 +246,70 @@ export default class IncomingTransactionsController {
}
});
const incomingTxs = remoteTxs.filter(
newIncomingTxs = remoteTxs.filter(
(tx) => tx.txParams?.to?.toLowerCase() === address.toLowerCase(),
);
incomingTxs.sort((a, b) => (a.time < b.time ? -1 : 1));
let latestIncomingTxBlockNumber = null;
incomingTxs.forEach((tx) => {
if (
tx.blockNumber &&
(!latestIncomingTxBlockNumber ||
parseInt(latestIncomingTxBlockNumber, 10) <
parseInt(tx.blockNumber, 10))
) {
latestIncomingTxBlockNumber = tx.blockNumber;
}
});
return {
latestIncomingTxBlockNumber,
txs: incomingTxs,
};
newIncomingTxs.sort((a, b) => (a.time < b.time ? -1 : 1));
}
return {
latestIncomingTxBlockNumber: null,
txs: [],
};
return newIncomingTxs;
}
_normalizeTxFromEtherscan(txMeta, chainId) {
const time = parseInt(txMeta.timeStamp, 10) * 1000;
/**
* Transmutes a EtherscanTransaction into a TransactionMeta
* @param {EtherscanTransaction} etherscanTransaction - the transaction to normalize
* @param {string} chainId - The chainId of the current network
* @returns {TransactionMeta}
*/
_normalizeTxFromEtherscan(etherscanTransaction, chainId) {
const time = parseInt(etherscanTransaction.timeStamp, 10) * 1000;
const status =
txMeta.isError === '0'
etherscanTransaction.isError === '0'
? TRANSACTION_STATUSES.CONFIRMED
: TRANSACTION_STATUSES.FAILED;
return {
blockNumber: txMeta.blockNumber,
blockNumber: etherscanTransaction.blockNumber,
id: createId(),
chainId,
metamaskNetworkId: CHAIN_ID_TO_NETWORK_ID_MAP[chainId],
status,
time,
txParams: {
from: txMeta.from,
gas: bnToHex(new BN(txMeta.gas)),
gasPrice: bnToHex(new BN(txMeta.gasPrice)),
nonce: bnToHex(new BN(txMeta.nonce)),
to: txMeta.to,
value: bnToHex(new BN(txMeta.value)),
from: etherscanTransaction.from,
gas: bnToHex(new BN(etherscanTransaction.gas)),
gasPrice: bnToHex(new BN(etherscanTransaction.gasPrice)),
nonce: bnToHex(new BN(etherscanTransaction.nonce)),
to: etherscanTransaction.to,
value: bnToHex(new BN(etherscanTransaction.value)),
},
hash: txMeta.hash,
transactionCategory: TRANSACTION_CATEGORIES.INCOMING,
hash: etherscanTransaction.hash,
type: TRANSACTION_TYPES.INCOMING,
};
}
}
function pairwise(fn) {
/**
* Returns a function with arity 1 that caches the argument that the function
* is called with and invokes the comparator with both the cached, previous,
* value and the current value. If specified, the initialValue will be passed
* in as the previous value on the first invocation of the returned method.
* @template A
* @params {A=} type of compared value
* @param {(prevValue: A, nextValue: A) => void} comparator - method to compare
* previous and next values.
* @param {A} [initialValue] - initial value to supply to prevValue
* on first call of the method.
* @returns {void}
*/
function previousValueComparator(comparator, initialValue) {
let first = true;
let cache;
return (value) => {
try {
if (first) {
first = false;
return fn(value, value);
return comparator(initialValue ?? value, value);
}
return fn(cache, value);
return comparator(cache, value);
} finally {
cache = value;
}

@ -1,6 +1,6 @@
import { merge, omit } from 'lodash';
import { ObservableStore } from '@metamask/obs-store';
import { bufferToHex, sha3 } from 'ethereumjs-util';
import { bufferToHex, keccak } from 'ethereumjs-util';
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
import {
METAMETRICS_ANONYMOUS_ID,
@ -57,8 +57,6 @@ export default class MetaMetricsController {
/**
* @param {Object} segment - an instance of analytics-node for tracking
* events that conform to the new MetaMetrics tracking plan.
* @param {Object} segmentLegacy - an instance of analytics-node for
* tracking legacy schema events. Will eventually be phased out
* @param {Object} preferencesStore - The preferences controller store, used
* to access and subscribe to preferences that will be attached to events
* @param {function} onNetworkDidChange - Used to attach a listener to the
@ -73,7 +71,6 @@ export default class MetaMetricsController {
*/
constructor({
segment,
segmentLegacy,
preferencesStore,
onNetworkDidChange,
getCurrentChainId,
@ -105,14 +102,15 @@ export default class MetaMetricsController {
this.network = getNetworkIdentifier();
});
this.segment = segment;
this.segmentLegacy = segmentLegacy;
}
generateMetaMetricsId() {
return bufferToHex(
sha3(
String(Date.now()) +
String(Math.round(Math.random() * Number.MAX_SAFE_INTEGER)),
keccak(
Buffer.from(
String(Date.now()) +
String(Math.round(Math.random() * Number.MAX_SAFE_INTEGER)),
),
),
);
}
@ -258,6 +256,12 @@ export default class MetaMetricsController {
}
payload[idType] = idValue;
// If this is an event on the old matomo schema, add a key to the payload
// to designate it as such
if (matomoEvent === true) {
payload.properties.legacy_event = true;
}
// Promises will only resolve when the event is sent to segment. For any
// event that relies on this promise being fulfilled before performing UI
// updates, or otherwise delaying user interaction, supply the
@ -276,11 +280,9 @@ export default class MetaMetricsController {
return resolve();
};
const target = matomoEvent === true ? this.segmentLegacy : this.segment;
target.track(payload, callback);
this.segment.track(payload, callback);
if (flushImmediately) {
target.flush();
this.segment.flush();
}
});
}

@ -1,17 +1,16 @@
import { strict as assert } from 'assert';
import sinon from 'sinon';
import MetaMetricsController from '../../../../app/scripts/controllers/metametrics';
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../../shared/constants/app';
import { createSegmentMock } from '../../../../app/scripts/lib/segment';
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
import { createSegmentMock } from '../lib/segment';
import {
METAMETRICS_ANONYMOUS_ID,
METAMETRICS_BACKGROUND_PAGE_OBJECT,
} from '../../../../shared/constants/metametrics';
import waitUntilCalled from '../../../lib/wait-until-called';
import { NETWORK_EVENTS } from '../../../../app/scripts/controllers/network';
} from '../../../shared/constants/metametrics';
import waitUntilCalled from '../../../test/lib/wait-until-called';
import MetaMetricsController from './metametrics';
import { NETWORK_EVENTS } from './network';
const segment = createSegmentMock(2, 10000);
const segmentLegacy = createSegmentMock(2, 10000);
const VERSION = '0.0.1-test';
const NETWORK = 'Mainnet';
@ -91,7 +90,6 @@ function getMetaMetricsController({
} = {}) {
return new MetaMetricsController({
segment,
segmentLegacy,
getNetworkIdentifier: networkController.getNetworkIdentifier.bind(
networkController,
),
@ -286,7 +284,7 @@ describe('MetaMetricsController', function () {
});
it('should track a legacy event', function () {
const mock = sinon.mock(segmentLegacy);
const mock = sinon.mock(segment);
const metaMetricsController = getMetaMetricsController();
mock
.expects('track')
@ -297,6 +295,7 @@ describe('MetaMetricsController', function () {
context: DEFAULT_TEST_CONTEXT,
properties: {
test: 1,
legacy_event: true,
...DEFAULT_EVENT_PROPERTIES,
},
});
@ -544,7 +543,6 @@ describe('MetaMetricsController', function () {
afterEach(function () {
// flush the queues manually after each test
segment.flush();
segmentLegacy.flush();
sinon.restore();
});
});

@ -6,7 +6,7 @@ import createInflightMiddleware from 'eth-json-rpc-middleware/inflight-cache';
import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector';
import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware';
import createInfuraMiddleware from 'eth-json-rpc-infura';
import BlockTracker from 'eth-block-tracker';
import { PollingBlockTracker } from 'eth-block-tracker';
import { NETWORK_TYPE_TO_ID_MAP } from '../../../../shared/constants/network';
@ -18,7 +18,7 @@ export default function createInfuraClient({ network, projectId }) {
source: 'metamask',
});
const infuraProvider = providerFromMiddleware(infuraMiddleware);
const blockTracker = new BlockTracker({ provider: infuraProvider });
const blockTracker = new PollingBlockTracker({ provider: infuraProvider });
const networkMiddleware = mergeMiddleware([
createNetworkAndChainIdMiddleware({ network }),

@ -5,7 +5,7 @@ import createBlockCacheMiddleware from 'eth-json-rpc-middleware/block-cache';
import createInflightMiddleware from 'eth-json-rpc-middleware/inflight-cache';
import createBlockTrackerInspectorMiddleware from 'eth-json-rpc-middleware/block-tracker-inspector';
import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddleware';
import BlockTracker from 'eth-block-tracker';
import { PollingBlockTracker } from 'eth-block-tracker';
const inTest = process.env.IN_TEST === 'true';
const blockTrackerOpts = inTest ? { pollingInterval: 1000 } : {};
@ -16,7 +16,7 @@ const getTestMiddlewares = () => {
export default function createJsonRpcClient({ rpcUrl, chainId }) {
const fetchMiddleware = createFetchMiddleware({ rpcUrl });
const blockProvider = providerFromMiddleware(fetchMiddleware);
const blockTracker = new BlockTracker({
const blockTracker = new PollingBlockTracker({
...blockTrackerOpts,
provider: blockProvider,
});

@ -1,7 +1,7 @@
import { strict as assert } from 'assert';
import sinon from 'sinon';
import NetworkController from '../../../../../app/scripts/controllers/network';
import { getNetworkDisplayName } from '../../../../../app/scripts/controllers/network/util';
import { getNetworkDisplayName } from './util';
import NetworkController from './network';
describe('NetworkController', function () {
describe('controller', function () {

@ -1,9 +1,9 @@
import assert from 'assert';
import { txMetaStub } from '../../../../test/stub/tx-meta-stub';
import {
createPendingNonceMiddleware,
createPendingTxMiddleware,
} from '../../../../../app/scripts/controllers/network/middleware/pending';
import { txMetaStub } from './stubs';
} from './middleware/pending';
describe('PendingNonceMiddleware', function () {
describe('#createPendingNonceMiddleware', function () {

@ -297,7 +297,7 @@ export class PermissionsController {
this.validatePermittedAccounts([account]);
const oldPermittedAccounts = this._getPermittedAccounts(origin);
if (!oldPermittedAccounts) {
if (oldPermittedAccounts.length === 0) {
throw new Error(`Origin does not have 'eth_accounts' permission`);
} else if (oldPermittedAccounts.includes(account)) {
throw new Error('Account is already permitted for origin');
@ -335,7 +335,7 @@ export class PermissionsController {
this.validatePermittedAccounts([account]);
const oldPermittedAccounts = this._getPermittedAccounts(origin);
if (!oldPermittedAccounts) {
if (oldPermittedAccounts.length === 0) {
throw new Error(`Origin does not have 'eth_accounts' permission`);
} else if (!oldPermittedAccounts.includes(account)) {
throw new Error('Account is not permitted for origin');
@ -612,7 +612,7 @@ export class PermissionsController {
* Get current set of permitted accounts for the given origin
*
* @param {string} origin - The origin to obtain permitted accounts for
* @returns {Array<string>|null} The list of permitted accounts
* @returns {Array<string>} The list of permitted accounts
*/
_getPermittedAccounts(origin) {
const permittedAccounts = this.permissions
@ -620,7 +620,7 @@ export class PermissionsController {
?.caveats?.find((caveat) => caveat.name === CAVEAT_NAMES.exposedAccounts)
?.value;
return permittedAccounts || null;
return permittedAccounts || [];
}
/**

@ -2,22 +2,20 @@ import { strict as assert } from 'assert';
import { find } from 'lodash';
import sinon from 'sinon';
import {
METADATA_STORE_KEY,
METADATA_CACHE_MAX_SIZE,
} from '../../../../../app/scripts/controllers/permissions/enums';
import { PermissionsController } from '../../../../../app/scripts/controllers/permissions';
import { getRequestUserApprovalHelper, grantPermissions } from './helpers';
import {
constants,
getters,
getNotifyDomain,
getNotifyAllDomains,
getPermControllerOpts,
} from './mocks';
} from '../../../../test/mocks/permission-controller';
import {
getRequestUserApprovalHelper,
grantPermissions,
} from '../../../../test/helpers/permission-controller-helpers';
import { METADATA_STORE_KEY, METADATA_CACHE_MAX_SIZE } from './enums';
import { PermissionsController } from '.';
const { ERRORS, NOTIFICATIONS, PERMS } = getters;

@ -3,16 +3,14 @@ import { ObservableStore } from '@metamask/obs-store';
import nanoid from 'nanoid';
import { useFakeTimers } from 'sinon';
import PermissionsLogController from '../../../../../app/scripts/controllers/permissions/permissionsLog';
import {
LOG_LIMIT,
LOG_METHOD_TYPES,
} from '../../../../../app/scripts/controllers/permissions/enums';
import { validateActivityEntry } from './helpers';
import { constants, getters, noop } from './mocks';
constants,
getters,
noop,
} from '../../../../test/mocks/permission-controller';
import { validateActivityEntry } from '../../../../test/helpers/permission-controller-helpers';
import PermissionsLogController from './permissionsLog';
import { LOG_LIMIT, LOG_METHOD_TYPES } from './enums';
const { PERMS, RPC_REQUESTS } = getters;
@ -50,7 +48,7 @@ const initMiddleware = (permLog) => {
const initClock = () => {
// useFakeTimers, is in fact, not a react-hook
// eslint-disable-next-line
clock = useFakeTimers(1)
clock = useFakeTimers(1);
};
const tearDownClock = () => {

@ -1,18 +1,19 @@
import { strict as assert } from 'assert';
import sinon from 'sinon';
import { METADATA_STORE_KEY } from '../../../../../app/scripts/controllers/permissions/enums';
import { PermissionsController } from '../../../../../app/scripts/controllers/permissions';
import { getUserApprovalPromise, grantPermissions } from './helpers';
import {
constants,
getters,
getPermControllerOpts,
getPermissionsMiddleware,
} from './mocks';
} from '../../../../test/mocks/permission-controller';
import {
getUserApprovalPromise,
grantPermissions,
} from '../../../../test/helpers/permission-controller-helpers';
import { METADATA_STORE_KEY } from './enums';
import { PermissionsController } from '.';
const { CAVEATS, ERRORS, PERMS, RPC_REQUESTS } = getters;

@ -1,4 +1,4 @@
import { cloneDeep } from 'lodash';
import stringify from 'fast-safe-stringify';
import { CAVEAT_NAMES } from '../../../../shared/constants/permissions';
import {
HISTORY_STORE_KEY,
@ -151,7 +151,7 @@ export default class PermissionsLogController {
? LOG_METHOD_TYPES.internal
: LOG_METHOD_TYPES.restricted,
origin: request.origin,
request: cloneDeep(request),
request: stringify(request, null, 2),
requestTime: Date.now(),
response: null,
responseTime: null,
@ -174,7 +174,7 @@ export default class PermissionsLogController {
return;
}
entry.response = cloneDeep(response);
entry.response = stringify(response, null, 2);
entry.responseTime = time;
entry.success = !response.error;
}

@ -1,7 +1,7 @@
import { strict as assert } from 'assert';
import pify from 'pify';
import getRestrictedMethods from '../../../../../app/scripts/controllers/permissions/restrictedMethods';
import getRestrictedMethods from './restrictedMethods';
describe('restricted methods', function () {
describe('eth_accounts', function () {

@ -380,7 +380,7 @@ export default class PreferencesController {
*/
async addToken(rawAddress, symbol, decimals, image) {
const address = normalizeAddress(rawAddress);
const newEntry = { address, symbol, decimals };
const newEntry = { address, symbol, decimals: Number(decimals) };
const { tokens, hiddenTokens } = this.store.getState();
const assetImages = this.getAssetImages();
const updatedHiddenTokens = hiddenTokens.filter(
@ -820,9 +820,14 @@ export default class PreferencesController {
if (typeof symbol !== 'string') {
throw ethErrors.rpc.invalidParams(`Invalid symbol: not a string.`);
}
if (!(symbol.length < 7)) {
if (!(symbol.length > 0)) {
throw ethErrors.rpc.invalidParams(
`Invalid symbol "${symbol}": longer than 6 characters.`,
`Invalid symbol "${symbol}": shorter than a character.`,
);
}
if (!(symbol.length < 12)) {
throw ethErrors.rpc.invalidParams(
`Invalid symbol "${symbol}": longer than 11 characters.`,
);
}
const numDecimals = parseInt(decimals, 10);

@ -1,10 +1,10 @@
import assert from 'assert';
import sinon from 'sinon';
import PreferencesController from '../../../../app/scripts/controllers/preferences';
import {
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
} from '../../../../shared/constants/network';
} from '../../../shared/constants/network';
import PreferencesController from './preferences';
describe('preferences controller', function () {
let preferencesController;
@ -539,6 +539,14 @@ describe('preferences controller', function () {
decimals: 0,
}),
);
assert.doesNotThrow(() =>
validate({
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: 'ABCDEFGHIJK',
decimals: 0,
}),
);
assert.throws(
() => validate({ symbol: 'ABC', decimals: 0 }),
'missing address should fail',
@ -563,10 +571,19 @@ describe('preferences controller', function () {
() =>
validate({
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: 'ABCDEFGHI',
symbol: 'ABCDEFGHIJKLM',
decimals: 0,
}),
'long symbol should fail',
);
assert.throws(
() =>
validate({
address: '0xd26114cd6EE289AccF82350c8d8487fedB8A0C07',
symbol: '',
decimals: 0,
}),
'invalid symbol should fail',
'empty symbol should fail',
);
assert.throws(
() =>

@ -70,7 +70,7 @@ const initialState = {
errorKey: '',
topAggId: null,
routeState: '',
swapsFeatureIsLive: false,
swapsFeatureIsLive: true,
swapsQuoteRefreshTime: FALLBACK_QUOTE_REFRESH_TIME,
},
};
@ -112,8 +112,6 @@ export default class SwapsController {
this.ethersProvider = new ethers.providers.Web3Provider(provider);
}
});
this._setupSwapsLivenessFetching();
}
// Sets the refresh rate for quote updates from the MetaSwap API
@ -478,7 +476,6 @@ export default class SwapsController {
swapsState: {
...initialState.swapsState,
tokens: swapsState.tokens,
swapsFeatureIsLive: swapsState.swapsFeatureIsLive,
swapsQuoteRefreshTime: swapsState.swapsQuoteRefreshTime,
},
});
@ -686,99 +683,6 @@ export default class SwapsController {
SWAPS_CHAINID_CONTRACT_ADDRESS_MAP[chainId],
);
}
/**
* Sets up the fetching of the swaps feature liveness flag from our API.
* Performs an initial fetch when called, then fetches on a 10-minute
* interval.
*
* If the browser goes offline, the interval is cleared and swaps are disabled
* until the value can be fetched again.
*/
_setupSwapsLivenessFetching() {
const TEN_MINUTES_MS = 10 * 60 * 1000;
let intervalId = null;
const fetchAndSetupInterval = () => {
if (window.navigator.onLine && intervalId === null) {
// Set the interval first to prevent race condition between listener and
// initial call to this function.
intervalId = setInterval(
this._fetchAndSetSwapsLiveness.bind(this),
TEN_MINUTES_MS,
);
this._fetchAndSetSwapsLiveness();
}
};
window.addEventListener('online', fetchAndSetupInterval);
window.addEventListener('offline', () => {
if (intervalId !== null) {
clearInterval(intervalId);
intervalId = null;
const { swapsState } = this.store.getState();
if (swapsState.swapsFeatureIsLive) {
this.setSwapsLiveness(false);
}
}
});
fetchAndSetupInterval();
}
/**
* This function should only be called via _setupSwapsLivenessFetching.
*
* Attempts to fetch the swaps feature liveness flag from our API. Tries
* to fetch three times at 5-second intervals before giving up, in which
* case the value defaults to 'false'.
*
* Only updates state if the fetched/computed flag value differs from current
* state.
*/
async _fetchAndSetSwapsLiveness() {
const { swapsState } = this.store.getState();
const { swapsFeatureIsLive: oldSwapsFeatureIsLive } = swapsState;
const chainId = this._getCurrentChainId();
let swapsFeatureIsLive = false;
let successfullyFetched = false;
let numAttempts = 0;
const fetchAndIncrementNumAttempts = async () => {
try {
swapsFeatureIsLive = Boolean(
await this._fetchSwapsFeatureLiveness(chainId),
);
successfullyFetched = true;
} catch (err) {
log.error(err);
numAttempts += 1;
}
};
await fetchAndIncrementNumAttempts();
// The loop conditions are modified by fetchAndIncrementNumAttempts.
// eslint-disable-next-line no-unmodified-loop-condition
while (!successfullyFetched && numAttempts < 3) {
await new Promise((resolve) => {
setTimeout(resolve, 5000); // 5 seconds
});
await fetchAndIncrementNumAttempts();
}
if (!successfullyFetched) {
log.error(
'Failed to fetch swaps feature flag 3 times. Setting to false and trying again next interval.',
);
}
if (swapsFeatureIsLive !== oldSwapsFeatureIsLive) {
this.setSwapsLiveness(swapsFeatureIsLive);
}
}
}
/**

@ -9,13 +9,11 @@ import {
ROPSTEN_NETWORK_ID,
MAINNET_NETWORK_ID,
MAINNET_CHAIN_ID,
} from '../../../../shared/constants/network';
import { ETH_SWAPS_TOKEN_OBJECT } from '../../../../shared/constants/swaps';
import { createTestProviderTools } from '../../../stub/provider';
import SwapsController, {
utils,
} from '../../../../app/scripts/controllers/swaps';
import { NETWORK_EVENTS } from '../../../../app/scripts/controllers/network';
} from '../../../shared/constants/network';
import { ETH_SWAPS_TOKEN_OBJECT } from '../../../shared/constants/swaps';
import { createTestProviderTools } from '../../../test/stub/provider';
import SwapsController, { utils } from './swaps';
import { NETWORK_EVENTS } from './network';
const MOCK_FETCH_PARAMS = {
slippage: 3,
@ -126,7 +124,7 @@ const EMPTY_INIT_STATE = {
errorKey: '',
topAggId: null,
routeState: '',
swapsFeatureIsLive: false,
swapsFeatureIsLive: true,
swapsQuoteRefreshTime: 60000,
},
};
@ -899,281 +897,6 @@ describe('SwapsController', function () {
});
});
});
describe('_setupSwapsLivenessFetching ', function () {
let clock;
const EXPECTED_TIME = 600000;
const getLivenessState = () => {
return swapsController.store.getState().swapsState.swapsFeatureIsLive;
};
// We have to do this to overwrite window.navigator.onLine
const stubWindow = () => {
sandbox.replace(global, 'window', {
addEventListener: window.addEventListener,
navigator: { onLine: true },
dispatchEvent: window.dispatchEvent,
Event: window.Event,
});
};
beforeEach(function () {
stubWindow();
clock = sandbox.useFakeTimers();
sandbox.spy(clock, 'setInterval');
sandbox
.stub(SwapsController.prototype, '_fetchAndSetSwapsLiveness')
.resolves(undefined);
sandbox.spy(SwapsController.prototype, '_setupSwapsLivenessFetching');
sandbox.spy(window, 'addEventListener');
});
afterEach(function () {
sandbox.restore();
});
it('calls _setupSwapsLivenessFetching in constructor', function () {
swapsController = getSwapsController();
assert.ok(
swapsController._setupSwapsLivenessFetching.calledOnce,
'should have called _setupSwapsLivenessFetching once',
);
assert.ok(window.addEventListener.calledWith('online'));
assert.ok(window.addEventListener.calledWith('offline'));
assert.ok(
clock.setInterval.calledOnceWithExactly(
sinon.match.func,
EXPECTED_TIME,
),
'should have set an interval',
);
});
it('handles browser being offline on boot, then coming online', async function () {
window.navigator.onLine = false;
swapsController = getSwapsController();
assert.ok(
swapsController._setupSwapsLivenessFetching.calledOnce,
'should have called _setupSwapsLivenessFetching once',
);
assert.ok(
swapsController._fetchAndSetSwapsLiveness.notCalled,
'should not have called _fetchAndSetSwapsLiveness',
);
assert.ok(
clock.setInterval.notCalled,
'should not have set an interval',
);
assert.strictEqual(
getLivenessState(),
false,
'swaps feature should be disabled',
);
const fetchPromise = new Promise((resolve) => {
const originalFunction = swapsController._fetchAndSetSwapsLiveness;
swapsController._fetchAndSetSwapsLiveness = () => {
originalFunction();
resolve();
swapsController._fetchAndSetSwapsLiveness = originalFunction;
};
});
// browser comes online
window.navigator.onLine = true;
window.dispatchEvent(new window.Event('online'));
await fetchPromise;
assert.ok(
swapsController._fetchAndSetSwapsLiveness.calledOnce,
'should have called _fetchAndSetSwapsLiveness once',
);
assert.ok(
clock.setInterval.calledOnceWithExactly(
sinon.match.func,
EXPECTED_TIME,
),
'should have set an interval',
);
});
it('clears interval if browser goes offline', async function () {
swapsController = getSwapsController();
// set feature to live
const { swapsState } = swapsController.store.getState();
swapsController.store.updateState({
swapsState: { ...swapsState, swapsFeatureIsLive: true },
});
sandbox.spy(swapsController.store, 'updateState');
assert.ok(
clock.setInterval.calledOnceWithExactly(
sinon.match.func,
EXPECTED_TIME,
),
'should have set an interval',
);
const clearIntervalPromise = new Promise((resolve) => {
const originalFunction = clock.clearInterval;
clock.clearInterval = (intervalId) => {
originalFunction(intervalId);
clock.clearInterval = originalFunction;
resolve();
};
});
// browser goes offline
window.navigator.onLine = false;
window.dispatchEvent(new window.Event('offline'));
// if this resolves, clearInterval was called
await clearIntervalPromise;
assert.ok(
swapsController._fetchAndSetSwapsLiveness.calledOnce,
'should have called _fetchAndSetSwapsLiveness once',
);
assert.ok(
swapsController.store.updateState.calledOnce,
'should have called updateState once',
);
assert.strictEqual(
getLivenessState(),
false,
'swaps feature should be disabled',
);
});
});
describe('_fetchAndSetSwapsLiveness', function () {
const getLivenessState = () => {
return swapsController.store.getState().swapsState.swapsFeatureIsLive;
};
beforeEach(function () {
fetchSwapsFeatureLivenessStub.reset();
sandbox.stub(SwapsController.prototype, '_setupSwapsLivenessFetching');
swapsController = getSwapsController();
});
afterEach(function () {
sandbox.restore();
});
it('fetches feature liveness as expected when API is live', async function () {
fetchSwapsFeatureLivenessStub.resolves(true);
assert.strictEqual(
getLivenessState(),
false,
'liveness should be false on boot',
);
await swapsController._fetchAndSetSwapsLiveness();
assert.ok(
fetchSwapsFeatureLivenessStub.calledOnce,
'should have called fetch function once',
);
assert.strictEqual(
getLivenessState(),
true,
'liveness should be true after call',
);
});
it('does not update state if fetched value is same as state value', async function () {
fetchSwapsFeatureLivenessStub.resolves(false);
sandbox.spy(swapsController.store, 'updateState');
assert.strictEqual(
getLivenessState(),
false,
'liveness should be false on boot',
);
await swapsController._fetchAndSetSwapsLiveness();
assert.ok(
fetchSwapsFeatureLivenessStub.calledOnce,
'should have called fetch function once',
);
assert.ok(
swapsController.store.updateState.notCalled,
'should not have called store.updateState',
);
assert.strictEqual(
getLivenessState(),
false,
'liveness should remain false after call',
);
});
it('tries three times before giving up if fetching fails', async function () {
const clock = sandbox.useFakeTimers();
fetchSwapsFeatureLivenessStub.rejects(new Error('foo'));
sandbox.spy(swapsController.store, 'updateState');
assert.strictEqual(
getLivenessState(),
false,
'liveness should be false on boot',
);
swapsController._fetchAndSetSwapsLiveness();
await clock.runAllAsync();
assert.ok(
fetchSwapsFeatureLivenessStub.calledThrice,
'should have called fetch function three times',
);
assert.ok(
swapsController.store.updateState.notCalled,
'should not have called store.updateState',
);
assert.strictEqual(
getLivenessState(),
false,
'liveness should remain false after call',
);
});
it('sets state after fetching on successful retry', async function () {
const clock = sandbox.useFakeTimers();
fetchSwapsFeatureLivenessStub.onCall(0).rejects(new Error('foo'));
fetchSwapsFeatureLivenessStub.onCall(1).rejects(new Error('foo'));
fetchSwapsFeatureLivenessStub.onCall(2).resolves(true);
assert.strictEqual(
getLivenessState(),
false,
'liveness should be false on boot',
);
swapsController._fetchAndSetSwapsLiveness();
await clock.runAllAsync();
assert.strictEqual(
fetchSwapsFeatureLivenessStub.callCount,
3,
'should have called fetch function three times',
);
assert.strictEqual(
getLivenessState(),
true,
'liveness should be true after call',
);
});
});
});
describe('utils', function () {

@ -1,7 +1,7 @@
import assert from 'assert';
import sinon from 'sinon';
import { ObservableStore } from '@metamask/obs-store';
import TokenRatesController from '../../../../app/scripts/controllers/token-rates';
import TokenRatesController from './token-rates';
describe('TokenRatesController', function () {
let nativeCurrency;

@ -1,7 +1,7 @@
import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel';
import { normalize as normalizeAddress } from 'eth-sig-util';
import ethUtil from 'ethereumjs-util';
import { toChecksumAddress } from 'ethereumjs-util';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
const fetchWithTimeout = getFetchWithTimeout(30000);
@ -45,7 +45,7 @@ export default class TokenRatesController {
this._tokens.forEach((token) => {
const price =
prices[token.address.toLowerCase()] ||
prices[ethUtil.toChecksumAddress(token.address)];
prices[toChecksumAddress(token.address)];
contractExchangeRates[normalizeAddress(token.address)] = price
? price[nativeCurrency]
: 0;

@ -1,6 +1,6 @@
import EventEmitter from 'safe-event-emitter';
import { ObservableStore } from '@metamask/obs-store';
import ethUtil from 'ethereumjs-util';
import { bufferToHex, keccak, toBuffer } from 'ethereumjs-util';
import Transaction from 'ethereumjs-tx';
import EthQuery from 'ethjs-query';
import { ethErrors } from 'eth-rpc-errors';
@ -19,7 +19,6 @@ import {
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys';
import { getSwapsTokensReceivedFromTxMeta } from '../../../../ui/app/pages/swaps/swaps.util';
import {
TRANSACTION_CATEGORIES,
TRANSACTION_STATUSES,
TRANSACTION_TYPES,
} from '../../../../shared/constants/transaction';
@ -151,8 +150,8 @@ export default class TransactionController extends EventEmitter {
Adds a tx to the txlist
@emits ${txMeta.id}:unapproved
*/
addTx(txMeta) {
this.txStateManager.addTx(txMeta);
addTransaction(txMeta) {
this.txStateManager.addTransaction(txMeta);
this.emit(`${txMeta.id}:unapproved`, txMeta);
}
@ -235,11 +234,10 @@ export default class TransactionController extends EventEmitter {
`generateTxMeta` adds the default txMeta properties to the passed object.
These include the tx's `id`. As we use the id for determining order of
txes in the tx-state-manager, it is necessary to call the asynchronous
method `this._determineTransactionCategory` after `generateTxMeta`.
method `this._determineTransactionType` after `generateTxMeta`.
*/
let txMeta = this.txStateManager.generateTxMeta({
txParams: normalizedTxParams,
type: TRANSACTION_TYPES.STANDARD,
});
if (origin === 'metamask') {
@ -265,33 +263,38 @@ export default class TransactionController extends EventEmitter {
txMeta.origin = origin;
const {
transactionCategory,
getCodeResponse,
} = await this._determineTransactionCategory(txParams);
txMeta.transactionCategory = transactionCategory;
const { type, getCodeResponse } = await this._determineTransactionType(
txParams,
);
txMeta.type = type;
// ensure value
txMeta.txParams.value = txMeta.txParams.value
? addHexPrefix(txMeta.txParams.value)
: '0x0';
this.addTx(txMeta);
this.addTransaction(txMeta);
this.emit('newUnapprovedTx', txMeta);
try {
txMeta = await this.addTxGasDefaults(txMeta, getCodeResponse);
} catch (error) {
log.warn(error);
txMeta = this.txStateManager.getTx(txMeta.id);
txMeta = this.txStateManager.getTransaction(txMeta.id);
txMeta.loadingDefaults = false;
this.txStateManager.updateTx(txMeta, 'Failed to calculate gas defaults.');
this.txStateManager.updateTransaction(
txMeta,
'Failed to calculate gas defaults.',
);
throw error;
}
txMeta.loadingDefaults = false;
// save txMeta
this.txStateManager.updateTx(txMeta, 'Added new unapproved transaction.');
this.txStateManager.updateTransaction(
txMeta,
'Added new unapproved transaction.',
);
return txMeta;
}
@ -309,7 +312,7 @@ export default class TransactionController extends EventEmitter {
} = await this._getDefaultGasLimit(txMeta, getCodeResponse);
// eslint-disable-next-line no-param-reassign
txMeta = this.txStateManager.getTx(txMeta.id);
txMeta = this.txStateManager.getTransaction(txMeta.id);
if (simulationFails) {
txMeta.simulationFails = simulationFails;
}
@ -347,7 +350,7 @@ export default class TransactionController extends EventEmitter {
return {};
} else if (
txMeta.txParams.to &&
txMeta.transactionCategory === TRANSACTION_CATEGORIES.SENT_ETHER
txMeta.type === TRANSACTION_TYPES.SENT_ETHER
) {
// if there's data in the params, but there's no contract code, it's not a valid transaction
if (txMeta.txParams.data) {
@ -388,8 +391,8 @@ export default class TransactionController extends EventEmitter {
* @param {string} [customGasPrice] - the hex value to use for the cancel transaction
* @returns {txMeta}
*/
async createCancelTransaction(originalTxId, customGasPrice) {
const originalTxMeta = this.txStateManager.getTx(originalTxId);
async createCancelTransaction(originalTxId, customGasPrice, customGasLimit) {
const originalTxMeta = this.txStateManager.getTransaction(originalTxId);
const { txParams } = originalTxMeta;
const { gasPrice: lastGasPrice, from, nonce } = txParams;
@ -401,7 +404,7 @@ export default class TransactionController extends EventEmitter {
from,
to: from,
nonce,
gas: '0x5208',
gas: customGasLimit || '0x5208',
value: '0x0',
gasPrice: newGasPrice,
},
@ -411,7 +414,7 @@ export default class TransactionController extends EventEmitter {
type: TRANSACTION_TYPES.CANCEL,
});
this.addTx(newTxMeta);
this.addTransaction(newTxMeta);
await this.approveTransaction(newTxMeta.id);
return newTxMeta;
}
@ -427,7 +430,7 @@ export default class TransactionController extends EventEmitter {
* @returns {txMeta}
*/
async createSpeedUpTransaction(originalTxId, customGasPrice, customGasLimit) {
const originalTxMeta = this.txStateManager.getTx(originalTxId);
const originalTxMeta = this.txStateManager.getTransaction(originalTxId);
const { txParams } = originalTxMeta;
const { gasPrice: lastGasPrice } = txParams;
@ -450,7 +453,7 @@ export default class TransactionController extends EventEmitter {
newTxMeta.txParams.gas = customGasLimit;
}
this.addTx(newTxMeta);
this.addTransaction(newTxMeta);
await this.approveTransaction(newTxMeta.id);
return newTxMeta;
}
@ -460,7 +463,10 @@ export default class TransactionController extends EventEmitter {
@param {Object} txMeta - the updated txMeta
*/
async updateTransaction(txMeta) {
this.txStateManager.updateTx(txMeta, 'confTx: user updated transaction');
this.txStateManager.updateTransaction(
txMeta,
'confTx: user updated transaction',
);
}
/**
@ -468,7 +474,10 @@ export default class TransactionController extends EventEmitter {
@param {Object} txMeta
*/
async updateAndApproveTransaction(txMeta) {
this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction');
this.txStateManager.updateTransaction(
txMeta,
'confTx: user approved transaction',
);
await this.approveTransaction(txMeta.id);
}
@ -495,7 +504,7 @@ export default class TransactionController extends EventEmitter {
// approve
this.txStateManager.setTxStatusApproved(txId);
// get next nonce
const txMeta = this.txStateManager.getTx(txId);
const txMeta = this.txStateManager.getTransaction(txId);
const fromAddress = txMeta.txParams.from;
// wait for a nonce
let { customNonceValue } = txMeta;
@ -516,7 +525,10 @@ export default class TransactionController extends EventEmitter {
if (customNonceValue) {
txMeta.nonceDetails.customNonceValue = customNonceValue;
}
this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction');
this.txStateManager.updateTransaction(
txMeta,
'transactions#approveTransaction',
);
// sign transaction
const rawTx = await this.signTransaction(txId);
await this.publishTransaction(txId, rawTx);
@ -546,7 +558,7 @@ export default class TransactionController extends EventEmitter {
@returns {string} rawTx
*/
async signTransaction(txId) {
const txMeta = this.txStateManager.getTx(txId);
const txMeta = this.txStateManager.getTransaction(txId);
// add network/chain id
const chainId = this.getChainId();
const txParams = { ...txMeta.txParams, chainId };
@ -557,18 +569,18 @@ export default class TransactionController extends EventEmitter {
// add r,s,v values for provider request purposes see createMetamaskMiddleware
// and JSON rpc standard for further explanation
txMeta.r = ethUtil.bufferToHex(ethTx.r);
txMeta.s = ethUtil.bufferToHex(ethTx.s);
txMeta.v = ethUtil.bufferToHex(ethTx.v);
txMeta.r = bufferToHex(ethTx.r);
txMeta.s = bufferToHex(ethTx.s);
txMeta.v = bufferToHex(ethTx.v);
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions#signTransaction: add r, s, v values',
);
// set state to signed
this.txStateManager.setTxStatusSigned(txMeta.id);
const rawTx = ethUtil.bufferToHex(ethTx.serialize());
const rawTx = bufferToHex(ethTx.serialize());
return rawTx;
}
@ -579,19 +591,22 @@ export default class TransactionController extends EventEmitter {
@returns {Promise<void>}
*/
async publishTransaction(txId, rawTx) {
const txMeta = this.txStateManager.getTx(txId);
const txMeta = this.txStateManager.getTransaction(txId);
txMeta.rawTx = rawTx;
if (txMeta.transactionCategory === TRANSACTION_CATEGORIES.SWAP) {
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
const preTxBalance = await this.query.getBalance(txMeta.txParams.from);
txMeta.preTxBalance = preTxBalance.toString(16);
}
this.txStateManager.updateTx(txMeta, 'transactions#publishTransaction');
this.txStateManager.updateTransaction(
txMeta,
'transactions#publishTransaction',
);
let txHash;
try {
txHash = await this.query.sendRawTransaction(rawTx);
} catch (error) {
if (error.message.toLowerCase().includes('known transaction')) {
txHash = ethUtil.sha3(addHexPrefix(rawTx)).toString('hex');
txHash = keccak(toBuffer(addHexPrefix(rawTx), 'hex')).toString('hex');
txHash = addHexPrefix(txHash);
} else {
throw error;
@ -611,7 +626,7 @@ export default class TransactionController extends EventEmitter {
async confirmTransaction(txId, txReceipt) {
// get the txReceipt before marking the transaction confirmed
// to ensure the receipt is gotten before the ui revives the tx
const txMeta = this.txStateManager.getTx(txId);
const txMeta = this.txStateManager.getTransaction(txId);
if (!txMeta) {
return;
@ -632,22 +647,22 @@ export default class TransactionController extends EventEmitter {
this.txStateManager.setTxStatusConfirmed(txId);
this._markNonceDuplicatesDropped(txId);
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions#confirmTransaction - add txReceipt',
);
if (txMeta.transactionCategory === TRANSACTION_CATEGORIES.SWAP) {
if (txMeta.type === TRANSACTION_TYPES.SWAP) {
const postTxBalance = await this.query.getBalance(txMeta.txParams.from);
const latestTxMeta = this.txStateManager.getTx(txId);
const latestTxMeta = this.txStateManager.getTransaction(txId);
const approvalTxMeta = latestTxMeta.approvalTxId
? this.txStateManager.getTx(latestTxMeta.approvalTxId)
? this.txStateManager.getTransaction(latestTxMeta.approvalTxId)
: null;
latestTxMeta.postTxBalance = postTxBalance.toString(16);
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
latestTxMeta,
'transactions#confirmTransaction - add postTxBalance',
);
@ -675,9 +690,9 @@ export default class TransactionController extends EventEmitter {
*/
setTxHash(txId, txHash) {
// Add the tx hash to the persisted meta-tx object
const txMeta = this.txStateManager.getTx(txId);
const txMeta = this.txStateManager.getTransaction(txId);
txMeta.hash = txHash;
this.txStateManager.updateTx(txMeta, 'transactions#setTxHash');
this.txStateManager.updateTransaction(txMeta, 'transactions#setTxHash');
}
//
@ -707,8 +722,7 @@ export default class TransactionController extends EventEmitter {
this.txStateManager.getPendingTransactions(account).length;
/** see txStateManager */
this.getFilteredTxList = (opts) =>
this.txStateManager.getFilteredTxList(opts);
this.getTransactions = (opts) => this.txStateManager.getTransactions(opts);
}
// called once on startup
@ -727,23 +741,25 @@ export default class TransactionController extends EventEmitter {
_onBootCleanUp() {
this.txStateManager
.getFilteredTxList({
status: TRANSACTION_STATUSES.UNAPPROVED,
loadingDefaults: true,
.getTransactions({
searchCriteria: {
status: TRANSACTION_STATUSES.UNAPPROVED,
loadingDefaults: true,
},
})
.forEach((tx) => {
this.addTxGasDefaults(tx)
.then((txMeta) => {
txMeta.loadingDefaults = false;
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions: gas estimation for tx on boot',
);
})
.catch((error) => {
const txMeta = this.txStateManager.getTx(tx.id);
const txMeta = this.txStateManager.getTransaction(tx.id);
txMeta.loadingDefaults = false;
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'failed to estimate gas during boot cleanup.',
);
@ -752,8 +768,10 @@ export default class TransactionController extends EventEmitter {
});
this.txStateManager
.getFilteredTxList({
status: TRANSACTION_STATUSES.APPROVED,
.getTransactions({
searchCriteria: {
status: TRANSACTION_STATUSES.APPROVED,
},
})
.forEach((txMeta) => {
const txSignError = new Error(
@ -774,7 +792,7 @@ export default class TransactionController extends EventEmitter {
);
this._setupBlockTrackerListener();
this.pendingTxTracker.on('tx:warning', (txMeta) => {
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions/pending-tx-tracker#event: tx:warning',
);
@ -793,7 +811,7 @@ export default class TransactionController extends EventEmitter {
this.pendingTxTracker.on('tx:block-update', (txMeta, latestBlockNumber) => {
if (!txMeta.firstRetryBlockNumber) {
txMeta.firstRetryBlockNumber = latestBlockNumber;
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions/pending-tx-tracker#event: tx:block-update',
);
@ -804,7 +822,7 @@ export default class TransactionController extends EventEmitter {
txMeta.retryCount = 0;
}
txMeta.retryCount += 1;
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions/pending-tx-tracker#event: tx:retry',
);
@ -812,10 +830,27 @@ export default class TransactionController extends EventEmitter {
}
/**
Returns a "type" for a transaction out of the following list: simpleSend, tokenTransfer, tokenApprove,
contractDeployment, contractMethodCall
*/
async _determineTransactionCategory(txParams) {
* @typedef { 'transfer' | 'approve' | 'transferfrom' | 'contractInteraction'| 'sentEther' } InferrableTransactionTypes
*/
/**
* @typedef {Object} InferTransactionTypeResult
* @property {InferrableTransactionTypes} type - The type of transaction
* @property {string} getCodeResponse - The contract code, in hex format if
* it exists. '0x0' or '0x' are also indicators of non-existent contract
* code
*/
/**
* Determines the type of the transaction by analyzing the txParams.
* This method will return one of the types defined in shared/constants/transactions
* It will never return TRANSACTION_TYPE_CANCEL or TRANSACTION_TYPE_RETRY as these
* represent specific events that we control from the extension and are added manually
* at transaction creation.
* @param {Object} txParams - Parameters for the transaction
* @returns {InferTransactionTypeResult}
*/
async _determineTransactionType(txParams) {
const { data, to } = txParams;
let name;
try {
@ -825,16 +860,16 @@ export default class TransactionController extends EventEmitter {
}
const tokenMethodName = [
TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE,
TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER,
TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER_FROM,
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
].find((methodName) => methodName === name && name.toLowerCase());
let result;
if (data && tokenMethodName) {
result = tokenMethodName;
} else if (data && !to) {
result = TRANSACTION_CATEGORIES.DEPLOY_CONTRACT;
result = TRANSACTION_TYPES.DEPLOY_CONTRACT;
}
let code;
@ -849,11 +884,11 @@ export default class TransactionController extends EventEmitter {
const codeIsEmpty = !code || code === '0x' || code === '0x0';
result = codeIsEmpty
? TRANSACTION_CATEGORIES.SENT_ETHER
: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION;
? TRANSACTION_TYPES.SENT_ETHER
: TRANSACTION_TYPES.CONTRACT_INTERACTION;
}
return { transactionCategory: result, getCodeResponse: code };
return { type: result, getCodeResponse: code };
}
/**
@ -864,9 +899,11 @@ export default class TransactionController extends EventEmitter {
*/
_markNonceDuplicatesDropped(txId) {
// get the confirmed transactions nonce and from address
const txMeta = this.txStateManager.getTx(txId);
const txMeta = this.txStateManager.getTransaction(txId);
const { nonce, from } = txMeta.txParams;
const sameNonceTxs = this.txStateManager.getFilteredTxList({ nonce, from });
const sameNonceTxs = this.txStateManager.getTransactions({
searchCriteria: { nonce, from },
});
if (!sameNonceTxs.length) {
return;
}
@ -876,7 +913,7 @@ export default class TransactionController extends EventEmitter {
return;
}
otherTxMeta.replacedBy = txMeta.hash;
this.txStateManager.updateTx(
this.txStateManager.updateTransaction(
txMeta,
'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce',
);
@ -922,9 +959,9 @@ export default class TransactionController extends EventEmitter {
*/
_updateMemstore() {
const unapprovedTxs = this.txStateManager.getUnapprovedTxList();
const currentNetworkTxList = this.txStateManager.getTxList(
MAX_MEMSTORE_TX_LIST_SIZE,
);
const currentNetworkTxList = this.txStateManager.getTransactions({
limit: MAX_MEMSTORE_TX_LIST_SIZE,
});
this.memStore.updateState({ unapprovedTxs, currentNetworkTxList });
}

@ -1,26 +1,28 @@
import { strict as assert } from 'assert';
import EventEmitter from 'events';
import ethUtil from 'ethereumjs-util';
import { toBuffer } from 'ethereumjs-util';
import EthTx from 'ethereumjs-tx';
import { ObservableStore } from '@metamask/obs-store';
import sinon from 'sinon';
import TransactionController from '../../../../../app/scripts/controllers/transactions';
import {
createTestProviderTools,
getTestAccounts,
} from '../../../../stub/provider';
} from '../../../../test/stub/provider';
import {
TRANSACTION_CATEGORIES,
TRANSACTION_STATUSES,
TRANSACTION_TYPES,
} from '../../../../../shared/constants/transaction';
import { METAMASK_CONTROLLER_EVENTS } from '../../../../../app/scripts/metamask-controller';
} from '../../../../shared/constants/transaction';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import TransactionController from '.';
const noop = () => true;
const currentNetworkId = '42';
const currentChainId = '0x2a';
const VALID_ADDRESS = '0x0000000000000000000000000000000000000000';
const VALID_ADDRESS_TWO = '0x0000000000000000000000000000000000000001';
describe('Transaction Controller', function () {
let txController, provider, providerResultStub, fromAccount;
@ -82,26 +84,35 @@ describe('Transaction Controller', function () {
describe('#getUnapprovedTxCount', function () {
it('should return the number of unapproved txs', function () {
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 2,
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 3,
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
]);
@ -112,26 +123,35 @@ describe('Transaction Controller', function () {
describe('#getPendingTxCount', function () {
it('should return the number of pending txs', function () {
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 2,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 3,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
]);
@ -147,7 +167,7 @@ describe('Transaction Controller', function () {
from: address,
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
};
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 0,
status: TRANSACTION_STATUSES.CONFIRMED,
@ -233,17 +253,19 @@ describe('Transaction Controller', function () {
txParams,
history: [{}],
};
txController.txStateManager._saveTxList([txMeta]);
txController.txStateManager._addTransactionsToState([txMeta]);
stub = sinon
.stub(txController, 'addUnapprovedTransaction')
.callsFake(() => {
txController.emit('newUnapprovedTx', txMeta);
return Promise.resolve(txController.txStateManager.addTx(txMeta));
return Promise.resolve(
txController.txStateManager.addTransaction(txMeta),
);
});
});
afterEach(function () {
txController.txStateManager._saveTxList([]);
txController.txStateManager._addTransactionsToState([]);
stub.restore();
});
@ -313,7 +335,7 @@ describe('Transaction Controller', function () {
'should have added 0x0 as the value',
);
const memTxMeta = txController.txStateManager.getTx(txMeta.id);
const memTxMeta = txController.txStateManager.getTransaction(txMeta.id);
assert.deepEqual(txMeta, memTxMeta);
});
@ -354,12 +376,15 @@ describe('Transaction Controller', function () {
describe('#addTxGasDefaults', function () {
it('should add the tx defaults if their are none', async function () {
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
]);
@ -387,13 +412,16 @@ describe('Transaction Controller', function () {
});
});
describe('#addTx', function () {
describe('#addTransaction', function () {
it('should emit updates', function (done) {
const txMeta = {
id: '1',
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
};
const eventNames = [
@ -420,7 +448,7 @@ describe('Transaction Controller', function () {
done();
})
.catch(done);
txController.addTx(txMeta);
txController.addTransaction(txMeta);
});
});
@ -432,6 +460,8 @@ describe('Transaction Controller', function () {
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: originalValue,
gas: originalValue,
gasPrice: originalValue,
@ -441,7 +471,7 @@ describe('Transaction Controller', function () {
this.timeout(15000);
const wrongValue = '0x05';
txController.addTx(txMeta);
txController.addTransaction(txMeta);
providerResultStub.eth_gasPrice = wrongValue;
providerResultStub.eth_estimateGas = '0x5209';
@ -457,7 +487,7 @@ describe('Transaction Controller', function () {
});
await txController.approveTransaction(txMeta.id);
const result = txController.txStateManager.getTx(txMeta.id);
const result = txController.txStateManager.getTransaction(txMeta.id);
const params = result.txParams;
assert.equal(params.gas, originalValue, 'gas unmodified');
@ -475,17 +505,20 @@ describe('Transaction Controller', function () {
describe('#sign replay-protected tx', function () {
it('prepares a tx with the chainId set', async function () {
txController.addTx(
txController.addTransaction(
{
id: '1',
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
},
noop,
);
const rawTx = await txController.signTransaction('1');
const ethTx = new EthTx(ethUtil.toBuffer(rawTx));
const ethTx = new EthTx(toBuffer(rawTx));
assert.equal(ethTx.getChainId(), 42);
});
});
@ -504,9 +537,9 @@ describe('Transaction Controller', function () {
},
metamaskNetworkId: currentNetworkId,
};
txController.txStateManager.addTx(txMeta);
txController.txStateManager.addTransaction(txMeta);
const approvalPromise = txController.updateAndApproveTransaction(txMeta);
const tx = txController.txStateManager.getTx(1);
const tx = txController.txStateManager.getTransaction(1);
assert.equal(tx.status, TRANSACTION_STATUSES.APPROVED);
await approvalPromise;
});
@ -521,53 +554,74 @@ describe('Transaction Controller', function () {
describe('#cancelTransaction', function () {
it('should emit a status change to rejected', function (done) {
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 0,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
{
id: 1,
status: TRANSACTION_STATUSES.REJECTED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
{
id: 2,
status: TRANSACTION_STATUSES.APPROVED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
{
id: 3,
status: TRANSACTION_STATUSES.SIGNED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
{
id: 4,
status: TRANSACTION_STATUSES.SUBMITTED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
{
id: 5,
status: TRANSACTION_STATUSES.CONFIRMED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
{
id: 6,
status: TRANSACTION_STATUSES.FAILED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
history: [{}],
},
@ -592,13 +646,13 @@ describe('Transaction Controller', function () {
});
describe('#createSpeedUpTransaction', function () {
let addTxSpy;
let addTransactionSpy;
let approveTransactionSpy;
let txParams;
let expectedTxParams;
beforeEach(function () {
addTxSpy = sinon.spy(txController, 'addTx');
addTransactionSpy = sinon.spy(txController, 'addTransaction');
approveTransactionSpy = sinon.spy(txController, 'approveTransaction');
txParams = {
@ -608,7 +662,7 @@ describe('Transaction Controller', function () {
gas: '0x5209',
gasPrice: '0xa',
};
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TRANSACTION_STATUSES.SUBMITTED,
@ -622,18 +676,18 @@ describe('Transaction Controller', function () {
});
afterEach(function () {
addTxSpy.restore();
addTransactionSpy.restore();
approveTransactionSpy.restore();
});
it('should call this.addTx and this.approveTransaction with the expected args', async function () {
it('should call this.addTransaction and this.approveTransaction with the expected args', async function () {
await txController.createSpeedUpTransaction(1);
assert.equal(addTxSpy.callCount, 1);
assert.equal(addTransactionSpy.callCount, 1);
const addTxArgs = addTxSpy.getCall(0).args[0];
assert.deepEqual(addTxArgs.txParams, expectedTxParams);
const addTransactionArgs = addTransactionSpy.getCall(0).args[0];
assert.deepEqual(addTransactionArgs.txParams, expectedTxParams);
const { lastGasPrice, type } = addTxArgs;
const { lastGasPrice, type } = addTransactionArgs;
assert.deepEqual(
{ lastGasPrice, type },
{
@ -675,7 +729,10 @@ describe('Transaction Controller', function () {
txMeta = {
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
metamaskNetworkId: currentNetworkId,
};
providerResultStub.eth_sendRawTransaction = hash;
@ -684,9 +741,9 @@ describe('Transaction Controller', function () {
it('should publish a tx, updates the rawTx when provided a one', async function () {
const rawTx =
'0x477b2e6553c917af0db0388ae3da62965ff1a184558f61b749d1266b2e6d024c';
txController.txStateManager.addTx(txMeta);
txController.txStateManager.addTransaction(txMeta);
await txController.publishTransaction(txMeta.id, rawTx);
const publishedTx = txController.txStateManager.getTx(1);
const publishedTx = txController.txStateManager.getTransaction(1);
assert.equal(publishedTx.hash, hash);
assert.equal(publishedTx.status, TRANSACTION_STATUSES.SUBMITTED);
});
@ -697,9 +754,9 @@ describe('Transaction Controller', function () {
};
const rawTx =
'0xf86204831e848082520894f231d46dd78806e1dd93442cf33c7671f853874880802ca05f973e540f2d3c2f06d3725a626b75247593cb36477187ae07ecfe0a4db3cf57a00259b52ee8c58baaa385fb05c3f96116e58de89bcc165cb3bfdfc708672fed8a';
txController.txStateManager.addTx(txMeta);
txController.txStateManager.addTransaction(txMeta);
await txController.publishTransaction(txMeta.id, rawTx);
const publishedTx = txController.txStateManager.getTx(1);
const publishedTx = txController.txStateManager.getTransaction(1);
assert.equal(
publishedTx.hash,
'0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09',
@ -710,62 +767,92 @@ describe('Transaction Controller', function () {
describe('#_markNonceDuplicatesDropped', function () {
it('should mark all nonce duplicates as dropped without marking the confirmed transaction as dropped', function () {
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TRANSACTION_STATUSES.CONFIRMED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
{
id: 2,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
{
id: 3,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
{
id: 4,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
{
id: 5,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
{
id: 6,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
{
id: 7,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
history: [{}],
txParams: { nonce: '0x01' },
txParams: {
to: VALID_ADDRESS_TWO,
from: VALID_ADDRESS,
nonce: '0x01',
},
},
]);
txController._markNonceDuplicatesDropped(1);
const confirmedTx = txController.txStateManager.getTx(1);
const droppedTxs = txController.txStateManager.getFilteredTxList({
nonce: '0x01',
status: TRANSACTION_STATUSES.DROPPED,
const confirmedTx = txController.txStateManager.getTransaction(1);
const droppedTxs = txController.txStateManager.getTransactions({
searchCriteria: {
nonce: '0x01',
status: TRANSACTION_STATUSES.DROPPED,
},
});
assert.equal(
confirmedTx.status,
@ -776,76 +863,76 @@ describe('Transaction Controller', function () {
});
});
describe('#_determineTransactionCategory', function () {
it('should return a simple send transactionCategory when to is truthy but data is falsy', async function () {
const result = await txController._determineTransactionCategory({
describe('#_determineTransactionType', function () {
it('should return a simple send type when to is truthy but data is falsy', async function () {
const result = await txController._determineTransactionType({
to: '0xabc',
data: '',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER,
type: TRANSACTION_TYPES.SENT_ETHER,
getCodeResponse: null,
});
});
it('should return a token transfer transactionCategory when data is for the respective method call', async function () {
const result = await txController._determineTransactionCategory({
it('should return a token transfer type when data is for the respective method call', async function () {
const result = await txController._determineTransactionType({
to: '0xabc',
data:
'0xa9059cbb0000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C970000000000000000000000000000000000000000000000000000000000000000a',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.TOKEN_METHOD_TRANSFER,
type: TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
getCodeResponse: undefined,
});
});
it('should return a token approve transactionCategory when data is for the respective method call', async function () {
const result = await txController._determineTransactionCategory({
it('should return a token approve type when data is for the respective method call', async function () {
const result = await txController._determineTransactionType({
to: '0xabc',
data:
'0x095ea7b30000000000000000000000002f318C334780961FB129D2a6c30D0763d9a5C9700000000000000000000000000000000000000000000000000000000000000005',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.TOKEN_METHOD_APPROVE,
type: TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
getCodeResponse: undefined,
});
});
it('should return a contract deployment transactionCategory when to is falsy and there is data', async function () {
const result = await txController._determineTransactionCategory({
it('should return a contract deployment type when to is falsy and there is data', async function () {
const result = await txController._determineTransactionType({
to: '',
data: '0xabd',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.DEPLOY_CONTRACT,
type: TRANSACTION_TYPES.DEPLOY_CONTRACT,
getCodeResponse: undefined,
});
});
it('should return a simple send transactionCategory with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () {
const result = await txController._determineTransactionCategory({
it('should return a simple send type with a 0x getCodeResponse when there is data and but the to address is not a contract address', async function () {
const result = await txController._determineTransactionType({
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
data: '0xabd',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER,
type: TRANSACTION_TYPES.SENT_ETHER,
getCodeResponse: '0x',
});
});
it('should return a simple send transactionCategory with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () {
const result = await txController._determineTransactionCategory({
it('should return a simple send type with a null getCodeResponse when to is truthy and there is data and but getCode returns an error', async function () {
const result = await txController._determineTransactionType({
to: '0xabc',
data: '0xabd',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.SENT_ETHER,
type: TRANSACTION_TYPES.SENT_ETHER,
getCodeResponse: null,
});
});
it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () {
it('should return a contract interaction type with the correct getCodeResponse when to is truthy and there is data and it is not a token transaction', async function () {
const _providerResultStub = {
// 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000',
@ -875,17 +962,17 @@ describe('Transaction Controller', function () {
}),
getParticipateInMetrics: () => false,
});
const result = await _txController._determineTransactionCategory({
const result = await _txController._determineTransactionType({
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
data: 'abd',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION,
type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
getCodeResponse: '0x0a',
});
});
it('should return a contract interaction transactionCategory with the correct getCodeResponse when to is a contract address and data is falsy', async function () {
it('should return a contract interaction type with the correct getCodeResponse when to is a contract address and data is falsy', async function () {
const _providerResultStub = {
// 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000',
@ -915,12 +1002,12 @@ describe('Transaction Controller', function () {
}),
getParticipateInMetrics: () => false,
});
const result = await _txController._determineTransactionCategory({
const result = await _txController._determineTransactionType({
to: '0x9e673399f795D01116e9A8B2dD2F156705131ee9',
data: '',
});
assert.deepEqual(result, {
transactionCategory: TRANSACTION_CATEGORIES.CONTRACT_INTERACTION,
type: TRANSACTION_TYPES.CONTRACT_INTERACTION,
getCodeResponse: '0x0a',
});
});
@ -928,53 +1015,74 @@ describe('Transaction Controller', function () {
describe('#getPendingTransactions', function () {
it('should show only submitted and approved transactions as pending transaction', function () {
txController.txStateManager._saveTxList([
txController.txStateManager._addTransactionsToState([
{
id: 1,
status: TRANSACTION_STATUSES.UNAPPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
},
{
id: 2,
status: TRANSACTION_STATUSES.REJECTED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 3,
status: TRANSACTION_STATUSES.APPROVED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 4,
status: TRANSACTION_STATUSES.SIGNED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 5,
status: TRANSACTION_STATUSES.SUBMITTED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 6,
status: TRANSACTION_STATUSES.CONFIRMED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
{
id: 7,
status: TRANSACTION_STATUSES.FAILED,
metamaskNetworkId: currentNetworkId,
txParams: {},
txParams: {
to: VALID_ADDRESS,
from: VALID_ADDRESS_TWO,
},
history: [{}],
},
]);

@ -1,11 +1,11 @@
import { strict as assert } from 'assert';
import testData from '../../../../../test/data/mock-tx-history.json';
import {
snapshotFromTxMeta,
migrateFromSnapshotsToDiffs,
replayHistory,
generateHistoryEntry,
} from '../../../../../app/scripts/controllers/transactions/lib/tx-state-history-helpers';
import testData from '../../../../data/mock-tx-history.json';
} from './tx-state-history-helpers';
describe('Transaction state history helper', function () {
describe('#snapshotFromTxMeta', function () {

@ -14,6 +14,12 @@ const normalizers = {
gasPrice: (gasPrice) => addHexPrefix(gasPrice),
};
export function normalizeAndValidateTxParams(txParams, lowerCase = true) {
const normalizedTxParams = normalizeTxParams(txParams, lowerCase);
validateTxParams(normalizedTxParams);
return normalizedTxParams;
}
/**
* Normalizes the given txParams
* @param {Object} txParams - The transaction params
@ -49,22 +55,48 @@ export function validateTxParams(txParams) {
);
}
validateFrom(txParams);
validateRecipient(txParams);
if ('value' in txParams) {
const value = txParams.value.toString();
if (value.includes('-')) {
throw ethErrors.rpc.invalidParams(
`Invalid transaction value "${txParams.value}": not a positive number.`,
);
}
Object.entries(txParams).forEach(([key, value]) => {
// validate types
switch (key) {
case 'from':
validateFrom(txParams);
break;
case 'to':
validateRecipient(txParams);
break;
case 'value':
if (typeof value !== 'string') {
throw ethErrors.rpc.invalidParams(
`Invalid transaction params: ${key} is not a string. got: (${value})`,
);
}
if (value.toString().includes('-')) {
throw ethErrors.rpc.invalidParams(
`Invalid transaction value "${value}": not a positive number.`,
);
}
if (value.includes('.')) {
throw ethErrors.rpc.invalidParams(
`Invalid transaction value of "${txParams.value}": number must be in wei.`,
);
if (value.toString().includes('.')) {
throw ethErrors.rpc.invalidParams(
`Invalid transaction value of "${value}": number must be in wei.`,
);
}
break;
case 'chainId':
if (typeof value !== 'number' && typeof value !== 'string') {
throw ethErrors.rpc.invalidParams(
`Invalid transaction params: ${key} is not a Number or hex string. got: (${value})`,
);
}
break;
default:
if (typeof value !== 'string') {
throw ethErrors.rpc.invalidParams(
`Invalid transaction params: ${key} is not a string. got: (${value})`,
);
}
}
}
});
}
/**

@ -1,5 +1,5 @@
import { strict as assert } from 'assert';
import * as txUtils from '../../../../../app/scripts/controllers/transactions/lib/util';
import * as txUtils from './util';
describe('txUtils', function () {
describe('#validateTxParams', function () {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save