Merge remote-tracking branch 'origin/develop' into master-sync

feature/default_network_editable
ryanml 2 years ago
commit 46c110b70c
  1. 74
      .circleci/config.yml
  2. 68
      .circleci/scripts/bundle-stats-commit.sh
  3. 9
      .eslintrc.base.js
  4. 15
      .eslintrc.js
  5. 2
      .github/ISSUE_TEMPLATE/config.yml
  6. 2
      .iyarc
  7. 4
      .metamaskrc.dist
  8. 8
      .storybook/2.DOCUMENTATION.stories.mdx
  9. 10
      .storybook/3.COLORS.stories.mdx
  10. 307
      .storybook/4.SHADOW.stories.mdx
  11. 125
      .storybook/5.BREAKPOINTS.stories.mdx
  12. 5
      .storybook/preview.js
  13. 394
      .storybook/test-data.js
  14. 1
      CHANGELOG.md
  15. 3
      README.md
  16. 65
      app/_locales/de/messages.json
  17. 119
      app/_locales/el/messages.json
  18. 139
      app/_locales/en/messages.json
  19. 119
      app/_locales/es/messages.json
  20. 8
      app/_locales/es_419/messages.json
  21. 479
      app/_locales/fr/messages.json
  22. 135
      app/_locales/hi/messages.json
  23. 119
      app/_locales/id/messages.json
  24. 123
      app/_locales/ja/messages.json
  25. 119
      app/_locales/ko/messages.json
  26. 8
      app/_locales/ph/messages.json
  27. 123
      app/_locales/pt/messages.json
  28. 8
      app/_locales/pt_BR/messages.json
  29. 117
      app/_locales/ru/messages.json
  30. 113
      app/_locales/tl/messages.json
  31. 119
      app/_locales/tr/messages.json
  32. 119
      app/_locales/vi/messages.json
  33. 115
      app/_locales/zh/messages.json
  34. 8
      app/_locales/zh_CN/messages.json
  35. 8
      app/manifest/v3/_base.json
  36. 120
      app/scripts/app-init.js
  37. 36
      app/scripts/background.js
  38. 14
      app/scripts/constants/contracts.js
  39. 14
      app/scripts/contentscript.js
  40. 8
      app/scripts/controllers/alert.js
  41. 2
      app/scripts/controllers/app-state.js
  42. 8
      app/scripts/controllers/cached-balances.js
  43. 25
      app/scripts/controllers/detect-tokens.js
  44. 38
      app/scripts/controllers/detect-tokens.test.js
  45. 17
      app/scripts/controllers/ens/ens.js
  46. 2
      app/scripts/controllers/ens/index.test.js
  47. 5
      app/scripts/controllers/incoming-transactions.js
  48. 111
      app/scripts/controllers/incoming-transactions.test.js
  49. 37
      app/scripts/controllers/metametrics.js
  50. 10
      app/scripts/controllers/metametrics.test.js
  51. 13
      app/scripts/controllers/network/network-controller.test.js
  52. 10
      app/scripts/controllers/network/network.js
  53. 3
      app/scripts/controllers/network/pending-middleware.test.js
  54. 12
      app/scripts/controllers/network/util.test.js
  55. 4
      app/scripts/controllers/onboarding.js
  56. 5
      app/scripts/controllers/permissions/caveat-mutators.test.js
  57. 24
      app/scripts/controllers/permissions/permission-log.js
  58. 6
      app/scripts/controllers/permissions/permission-log.test.js
  59. 2
      app/scripts/controllers/permissions/specifications.js
  60. 18
      app/scripts/controllers/preferences.js
  61. 35
      app/scripts/controllers/swaps.js
  62. 66
      app/scripts/controllers/swaps.test.js
  63. 5
      app/scripts/controllers/threebox.js
  64. 162
      app/scripts/controllers/transactions/index.js
  65. 43
      app/scripts/controllers/transactions/index.test.js
  66. 10
      app/scripts/controllers/transactions/lib/tx-state-history-helpers.js
  67. 18
      app/scripts/controllers/transactions/lib/util.js
  68. 25
      app/scripts/controllers/transactions/pending-tx-tracker.js
  69. 39
      app/scripts/controllers/transactions/pending-tx-tracker.test.js
  70. 17
      app/scripts/controllers/transactions/tx-gas-utils.js
  71. 6
      app/scripts/controllers/transactions/tx-state-manager.js
  72. 2
      app/scripts/disable-console.js
  73. 6
      app/scripts/first-time-state.js
  74. 12
      app/scripts/lib/ComposableObservableStore.js
  75. 90
      app/scripts/lib/account-tracker.js
  76. 10
      app/scripts/lib/buy-url.js
  77. 5
      app/scripts/lib/buy-url.test.js
  78. 228
      app/scripts/lib/createRPCMethodTrackingMiddleware.js
  79. 217
      app/scripts/lib/createRPCMethodTrackingMiddleware.test.js
  80. 22
      app/scripts/lib/decrypt-message-manager.js
  81. 22
      app/scripts/lib/encryption-public-key-manager.js
  82. 5
      app/scripts/lib/ens-ipfs/resolver.js
  83. 3
      app/scripts/lib/ens-ipfs/setup.js
  84. 8
      app/scripts/lib/getObjStructure.js
  85. 8
      app/scripts/lib/local-store.js
  86. 22
      app/scripts/lib/message-manager.js
  87. 6
      app/scripts/lib/migrator/index.js
  88. 5
      app/scripts/lib/network-store.js
  89. 33
      app/scripts/lib/personal-message-manager.js
  90. 2
      app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js
  91. 55
      app/scripts/lib/rpc-method-middleware/handlers/add-ethereum-chain.js
  92. 4
      app/scripts/lib/rpc-method-middleware/handlers/get-provider-state.js
  93. 2
      app/scripts/lib/rpc-method-middleware/handlers/log-web3-shim-usage.js
  94. 6
      app/scripts/lib/rpc-method-middleware/handlers/watch-asset.js
  95. 31
      app/scripts/lib/typed-message-manager.js
  96. 2
      app/scripts/lib/util.js
  97. 2
      app/scripts/lockdown-more.js
  98. 1128
      app/scripts/metamask-controller.js
  99. 58
      app/scripts/metamask-controller.test.js
  100. 7
      app/scripts/migrations/022.test.js
  101. Some files were not shown because too many files have changed in this diff Show More

@ -53,6 +53,9 @@ workflows:
- prep-build-test:
requires:
- prep-deps
- prep-build-test-mv3:
requires:
- prep-deps
- prep-build-test-flask:
requires:
- prep-deps
@ -133,6 +136,9 @@ workflows:
- benchmark:
requires:
- prep-build-test
- stats-module-load-init:
requires:
- prep-build-test-mv3
- job-publish-prerelease:
requires:
- prep-deps
@ -140,7 +146,9 @@ workflows:
- prep-build-beta
- prep-build-flask
- prep-build-storybook
- prep-build-test-mv3
- benchmark
- stats-module-load-init
- all-tests-pass
- job-publish-release:
filters:
@ -200,8 +208,8 @@ jobs:
- persist_to_workspace:
root: .
paths:
- node_modules
- build-artifacts
- node_modules
- build-artifacts
validate-lavamoat-config:
executor: node-browsers-medium-plus
@ -305,6 +313,26 @@ jobs:
- dist-test-flask
- builds-test-flask
prep-build-test-mv3:
executor: node-browsers-medium-plus
steps:
- checkout
- attach_workspace:
at: .
- run:
name: Build extension in mv3 for testing
command: yarn build:test:mv3
- run:
name: Move test build to 'dist-test' to avoid conflict with production build
command: mv ./dist ./dist-test-mv3
- run:
name: Move test zips to 'builds-test' to avoid conflict with production build
command: mv ./builds ./builds-test-mv3
- persist_to_workspace:
root: .
paths:
- dist-test-mv3
- builds-test-mv3
prep-build-test:
executor: node-browsers-medium-plus
@ -419,7 +447,6 @@ jobs:
name: Validate release candidate changelog
command: yarn lint:changelog:rc
test-deps-audit:
executor: node-browsers
steps:
@ -574,6 +601,43 @@ jobs:
paths:
- test-artifacts
stats-module-load-init:
executor: node-browsers-medium-plus
steps:
- checkout
- run:
name: Re-Install Chrome
command: ./.circleci/scripts/chrome-install.sh
- attach_workspace:
at: .
- run:
name: Move test build to dist
command: mv ./dist-test-mv3 ./dist
- run:
name: Move test zips to builds
command: mv ./builds-test-mv3 ./builds
- run:
name: Run page load benchmark
command: |
mkdir -p test-artifacts/chrome/mv3
cp -R development/charts/flamegraph test-artifacts/chrome/mv3/initialisation
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/background
cp -R development/charts/flamegraph/chart test-artifacts/chrome/mv3/initialisation/ui
cp -R development/charts/table test-artifacts/chrome/mv3/load_time
- run:
name: Run page load benchmark
command: yarn mv3:stats:chrome --out test-artifacts/chrome/mv3
- run:
name: Record bundle size at commit
command: ./.circleci/scripts/bundle-stats-commit.sh
- store_artifacts:
path: test-artifacts
destination: test-artifacts
- persist_to_workspace:
root: .
paths:
- test-artifacts
job-publish-prerelease:
executor: node-browsers
steps:
@ -648,7 +712,7 @@ jobs:
steps:
- add_ssh_keys:
fingerprints:
- "3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8"
- '3d:49:29:f4:b2:e8:ea:af:d1:32:eb:2a:fc:15:85:d8'
- checkout
- attach_workspace:
at: .
@ -670,7 +734,7 @@ jobs:
- run:
name: test:coverage:jest
command: yarn test:coverage:jest
- run:
- run:
name: Validate coverage thresholds
command: |
if ! git diff --exit-code jest.config.js development/jest.config.js; then

@ -0,0 +1,68 @@
#!/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 [[ "${CIRCLE_BRANCH}" != "develop" ]]
then
printf 'This is not develop branch'
exit 0
fi
if [[ -z "${GITHUB_TOKEN:-}" ]]
then
printf '%s\n' 'GITHUB_TOKEN environment variable must be set'
exit 1
elif [[ -z "${GITHUB_TOKEN_USER:-}" ]]
then
printf '%s\n' 'GITHUB_TOKEN_USER environment variable must be set'
exit 1
fi
mkdir temp
git config --global user.email "metamaskbot@users.noreply.github.com"
git config --global user.name "MetaMask Bot"
git clone git@github.com:MetaMask/extension_bundlesize_stats.git temp
if [[ -f "temp/stats/bundle_size_stats-${CIRCLE_SHA1}.json" ]]
then
printf 'Bundle size of the commit is already recorded'
cd ..
rm -rf temp
exit 0
fi
cp -R test-artifacts/chrome/mv3/bundle_size_stats.json temp/stats
echo " bundle_size_stats-${CIRCLE_SHA1}.json" >> temp/stats/fileList.txt
mv temp/stats/bundle_size_stats.json "temp/stats/bundle_size_stats-${CIRCLE_SHA1}.json"
cd temp
git add .
git commit --message "Bundle size at commit: ${CIRCLE_SHA1}"
repo_slug="$CIRCLE_PROJECT_USERNAME/extension_bundlesize_stats"
git push "https://$GITHUB_TOKEN_USER:$GITHUB_TOKEN@github.com/$repo_slug" main
cd ..
rm -rf temp

@ -63,5 +63,14 @@ module.exports = {
// a browser context. For instance, we may import polyfills which change
// global variables, or we may import stylesheets.
'import/no-unassigned-import': 'off',
// import/no-named-as-default-member checks if default imports also have
// named exports matching properties used on the default import. Example:
// in confirm-seed-phrase-component.test.js we import sinon from 'sinon'
// and later access sinon.spy. spy is also exported from sinon directly and
// thus triggers the error. Turning this rule off to prevent churn when
// upgrading eslint and dependencies. This rule should be evaluated and
// if agreeable turned on upstream in @metamask/eslint-config
'import/no-named-as-default-member': 'off',
},
};

@ -8,6 +8,7 @@ module.exports = {
'app/vendor/**',
'builds/**/*',
'development/chromereload.js',
'development/charts/**',
'dist/**/*',
'node_modules/**/*',
],
@ -277,6 +278,20 @@ module.exports = {
{ maxSize: 50, inlineMaxSize: 50 },
],
'jest/no-restricted-matchers': 'off',
/**
* jest/prefer-to-be is a new rule that was disabled to reduce churn
* when upgrading eslint. It should be considered for use and enabled
* in a future PR if agreeable.
*/
'jest/prefer-to-be': 'off',
/**
* jest/lowercase-name was renamed to jest/prefer-lowercase-title this
* change was made to essentially retain the same state as the original
* eslint-config-jest until it is updated. At which point the following
* two lines can be deleted.
*/
'jest/lowercase-name': 'off',
'jest/prefer-lowercase-title': ['error', { ignore: ['describe'] }],
},
},
/**

@ -4,5 +4,5 @@ contact_links:
url: https://community.metamask.io/c/feature-requests-ideas/
about: Request new features and vote on the ones that are important to you
- name: Get support or ask a question
url: https://metamask.zendesk.com/hc/en-us/requests/new
url: https://metamask.zendesk.com/hc/en-us
about: Use the MetaMask support system to get help and ask questions

@ -2,4 +2,4 @@
GHSA-93q8-gq69-wqmw
GHSA-257v-vj4p-3w2h
GHSA-wm7h-9275-46v2
GHSA-pfrx-2q88-qq97
GHSA-pfrx-2q88-qq97

@ -6,7 +6,9 @@ ONBOARDING_V2=
SWAPS_USE_DEV_APIS=
COLLECTIBLES_V1=
TOKEN_DETECTION_V2=
ADD_POPULAR_NETWORKS=
; Set this to '1' to enable support for Sign-In with Ethereum [EIP-4361](https://eips.ethereum.org/EIPS/eip-4361)
SIWE_V1=
; Set this to test changes to the phishing warning page.
PHISHING_WARNING_PAGE_URL=

@ -50,7 +50,7 @@ import React from 'react';
import BuyIcon from '../icon/overview-buy-icon.component';
// The mdx file to document component API and usage
// The mdx file to document props and usage
import README from './README.mdx';
import Button from '.';
@ -149,7 +149,7 @@ Now the storybook components are complete, the `README.mdx` documentation should
import { Story, Canvas, ArgsTable } from '@storybook/addon-docs';
<!-- import the component to use for the ArgsTable under ## Component API -->
<!-- import the component to use for the ArgsTable under ## Props -->
import Button from '.';
@ -167,9 +167,9 @@ Buttons communicate actions that users can take.
<Story id="ui-components-ui-button-button-stories-js--default-story" />
</Canvas>
## Component API
## Props
<!-- Display the component API using the ArgsTable. Use JSDoc style comments in the PropTypes of your component to add descriptions for props. See button.component.js Button.propTypes for an example of jsDoc style comments
<!-- Display the Props using the ArgsTable. Use JSDoc style comments in the PropTypes of your component to add descriptions for props. See button.component.js Button.propTypes for an example of jsDoc style comments
-->
<ArgsTable of={Button} />

@ -1,20 +1,12 @@
import { Meta } from '@storybook/addon-docs';
import ActionaleMessage from '../ui/components/ui/actionable-message';
import designTokenDiagramImage from './images/design.token.graphic.svg';
<Meta title="Design Tokens / Color" />
<Meta title="Foundations / Color" />
# Color
Color is used to express style and communicate meaning.
<ActionaleMessage
type="warning"
message="We are in the process of consolidating all of our colors, making them accessible and enabling theming. Many of the colors used throughout the codebase are deprecated please follow the guide below to ensure you are using the correct colors when building MetaMask UI"
/>
<br />
## Design tokens
We are importing design tokens as CSS variables from [@metamask/design-tokens](https://github.com/MetaMask/design-tokens) repo to help consolidate colors and enable theming across all MetaMask products.

@ -0,0 +1,307 @@
import { Meta, Canvas, Story } from '@storybook/addon-docs';
<Meta title="Foundations / Shadow" />
# Shadow
Shadows convey elevation of elements on a surface
## Size
There are 4 different sizes of shadow in MetaMask
<div
style={{
display: 'grid',
gap: '32px',
gridTemplateColumns: 'repeat(auto-fill, 200px)',
marginTop: 16,
marginBottom: 16,
}}
>
<div
style={{
height: 100,
backgroundColor: 'var(--color-background-default)',
boxShadow: 'var(--shadow-size-xs) var(--color-shadow-default',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
}}
>
XS
</div>
<div
style={{
height: 100,
backgroundColor: 'var(--color-background-default)',
boxShadow: 'var(--shadow-size-sm) var(--color-shadow-default',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
}}
>
SM
</div>
<div
style={{
height: 100,
backgroundColor: 'var(--color-background-default)',
boxShadow: 'var(--shadow-size-md) var(--color-shadow-default',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
}}
>
MD
</div>
<div
style={{
height: 100,
backgroundColor: 'var(--color-background-default)',
boxShadow: 'var(--shadow-size-lg) var(--color-shadow-default',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
}}
>
LG
</div>
</div>
| Size | CSS |
| ------ | ----------------------- |
| **XS** | `var(--shadow-size-xs)` |
| **SM** | `var(--shadow-size-sm)` |
| **MD** | `var(--shadow-size-md)` |
| **LG** | `var(--shadow-size-lg)` |
## Color
As well as the neutral colors for shadow 2 other colors exist that are used for the primary and error/danger button hover states
<div
style={{
display: 'grid',
gap: '32px',
gridTemplateColumns: 'repeat(auto-fill, 200px)',
marginTop: 16,
marginBottom: 16,
}}
>
<div
style={{
height: 100,
backgroundColor: 'var(--color-background-default)',
boxShadow: 'var(--shadow-size-lg) var(--color-shadow-default',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
}}
color="default"
>
<span>Default</span>
</div>
<div
style={{
height: 100,
backgroundColor: 'var(--color-primary-default)',
boxShadow: 'var(--shadow-size-lg) var(--color-primary-shadow',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
color: 'var(--color-primary-inverse)',
}}
>
<span>Primary</span>
</div>
<div
style={{
height: 100,
backgroundColor: 'var(--color-error-default)',
boxShadow: 'var(--shadow-size-lg) var(--color-error-shadow',
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
color: 'var(--color-error-inverse)',
}}
>
<span>Error/Danger</span>
</div>
</div>
| Color | CSS |
| ----------- | ----------------------------- |
| **neutral** | `var(--color-shadow-default)` |
| **primary** | `var(--color-primary-shadow)` |
| **danger** | `var(--color-error-shadow)` |
## Example usage
Using both size and color tokens, different shadows can be applied to components
<div>
<div
style={{
display: 'grid',
gap: '32px',
gridTemplateColumns: 'repeat(auto-fill, 200px)',
marginBottom: '64px',
}}
>
<div
style={{
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
height: 100,
textAlign: 'center',
boxShadow: 'var(--shadow-size-xs) var(--color-shadow-default)',
}}
>
<span>Card</span>
</div>
<div
style={{
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
height: 100,
textAlign: 'center',
boxShadow: 'var(--shadow-size-sm) var(--color-shadow-default)',
}}
>
<span>Dropdown</span>
</div>
<div
style={{
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
height: 100,
textAlign: 'center',
boxShadow: 'var(--shadow-size-md) var(--color-shadow-default)',
}}
>
<span>Toast</span>
</div>
<div
style={{
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
height: 100,
textAlign: 'center',
boxShadow: 'var(--shadow-size-lg) var(--color-shadow-default)',
}}
>
<span>Modal</span>
</div>
</div>
<div
style={{
display: 'grid',
gap: '32px',
gridTemplateColumns: 'repeat(auto-fill, 200px)',
}}
>
<div
style={{
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
height: 100,
textAlign: 'center',
boxShadow: 'var(--component-button-primary-shadow)',
backgroundColor: 'var(--color-primary-default)',
color: 'var(--color-primary-inverse)',
}}
>
<span>Button Primary Hover</span>
</div>
<div
style={{
borderRadius: '4px',
display: 'grid',
alignContent: 'center',
justifyContent: 'center',
spanAlign: 'center',
height: 100,
textAlign: 'center',
boxShadow: 'var(--component-button-danger-shadow)',
backgroundColor: 'var(--color-error-default)',
color: 'var(--color-error-inverse)',
}}
>
<span>Button Error/Danger Hover</span>
</div>
</div>
</div>
| Component | JS | CSS |
| ------------------------ | ---------------------------------------------------------------- | --- |
| **Card** | `box-shadow: var(--shadow-size-xs) var(--color-shadow-default);` |
| **Dropdown** | `box-shadow: var(--shadow-size-sm) var(--color-shadow-default);` |
| **Toast** | `box-shadow: var(--shadow-size-md) var(--color-shadow-default);` |
| **Modal** | `box-shadow: var(--shadow-size-lg) var(--color-shadow-default);` |
| **Button Primary Hover** | `box-shadow: var(--shadow-size-sm) var(--color-primary-shadow);` |
| **Button Danger Hover** | `box-shadow: var(--shadow-size-sm) var(--color-error-shadow);` |
## Takeaways
- Try to avoid using static media queries in your code
- Try to use the provided SCSS mixins
### ❌ Don't do this
Don't use static media queries in your code
```css
/**
* Don't do this
* Static box-shadows create inconsistency in elevation of elements
**/
.card {
box-shadow: 0 0 5px 0 rgba(0, 0, 0, 0.2);
}
```
### ✅ Do this
Do use the provided shadow design token css variables
```css
.card {
box-shadow: var(--shadow-size-xs) var(--color-shadow-default);
}
```
## References
- [Shadow design tokens](https://metamask.github.io/design-tokens/?path=/docs/shadows-shadows--shadow)
- [Figma light theme colors library(shadows page)](https://www.figma.com/file/kdFzEC7xzSNw7cXteqgzDW/%5BColor%5D-Light-Theme?node-id=753%3A719)(internal use only)
- [Figma dark theme colors library(shadows page)](https://www.figma.com/file/rLKsoqpjyoKauYnFDcBIbO/%5BColor%5D-Dark-Theme?node-id=522%3A1022)(internal use only)

@ -0,0 +1,125 @@
import { Meta } from '@storybook/addon-docs';
<Meta title="Foundations / Breakpoints" />
# Breakpoints
Breakpoints are used for responsive layout
## Screen Sizes
There are 4 screen sizes that make up the breakpoints for the MetaMask extension
- base: `0px`
- sm: `576px`
- md: `768px`
- lg: `1280px`
### SCSS
There are Sass variables and mixins available for use for both min and max screens sizes
### Variables
```css
$screen-sm-max /* 575px */
$screen-md-max /* 767px */
$screen-lg-max /* 1279px */
$screen-sm-min /* 576px */
$screen-md-min /* 768px */
$screen-lg-min /* 1280px */
```
### Mixins
```css
/* Max screen size */
@include screen-sm-max {
/* equivalent css @media screen and (max-width: 575px) */
}
@include screen-md-max {
/* equivalent css @media screen and (max-width: 767px) */
}
@include screen-lg-max {
/* equivalent css @media screen and (max-width: 1279px) */
}
/* Min screen size */
@include screen-sm-min {
/* equivalent css @media screen and (min-width: 576px) */
}
@include screen-md-min {
/* equivalent css @media screen and (min-width: 768px) */
}
@include screen-lg-min {
/* equivalent css @media screen and (min-width: 1280px) */
}
```
Migrating from the old sass variables to the new mixins looks like this
```css
/* Max width */
/* Instead of the media query and sass variable */
@media screen and (max-width: $break-small) {
right: 16px;
}
/* Use the sass mixin */
@include screen-sm-max {
right: 16px;
}
/* Min width */
/* Instead of the media query and sass variable */
@media screen and (min-width: $break-large) {
left: 16px;
}
/* Use the sass mixin */
@include screen-sm-min {
left: 16px;
}
```
## Takeaways
- Try to avoid using static media queries in your code.
- Try to use the provided SCSS mixins
### ❌ Don't do this
Don't use static media queries in your code.
```css
/**
* Don't do this
* Static media queries create inconsistency and could break the UI if we want to update them in future
**/
.account-menu {
@media screen and (min-width: 769px) {
right: calc((100vw - 80vw) / 2);
}
@media screen and (min-width: 1281px) {
right: calc((100vw - 65vw) / 2);
}
}
```
### ✅ Do this
Do use the provided Sass mixins
```css
.account-menu {
@include screen-md-min {
right: calc((100vw - 80vw) / 2);
}
@include screen-lg-min {
right: calc((100vw - 65vw) / 2);
}
}
```

@ -30,9 +30,10 @@ addParameters({
storySort: {
order: [
'Getting Started',
'Design Tokens',
'Foundations',
['Color', 'Shadow', 'Breakpoints'],
'Components',
['UI', 'App'],
['UI', 'App', 'Component Library'],
'Pages',
],
},

@ -1,3 +1,4 @@
import { draftTransactionInitialState } from '../ui/ducks/send';
const state = {
invalidCustomNetwork: {
state: 'CLOSED',
@ -15,99 +16,99 @@ const state = {
},
networkList: [
{
blockExplorerUrl: "https://etherscan.io",
chainId: "0x1",
blockExplorerUrl: 'https://etherscan.io',
chainId: '0x1',
iconColor: 'var(--mainnet)',
isATestNetwork: false,
labelKey: "mainnet",
providerType: "mainnet",
rpcUrl: "https://mainnet.infura.io/v3/",
ticker: "ETH",
labelKey: 'mainnet',
providerType: 'mainnet',
rpcUrl: 'https://mainnet.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://ropsten.etherscan.io",
chainId: "0x3",
blockExplorerUrl: 'https://ropsten.etherscan.io',
chainId: '0x3',
iconColor: 'var(--ropsten)',
isATestNetwork: true,
labelKey: "ropsten",
providerType: "ropsten",
rpcUrl: "https://ropsten.infura.io/v3/",
ticker: "ETH",
labelKey: 'ropsten',
providerType: 'ropsten',
rpcUrl: 'https://ropsten.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://rinkeby.etherscan.io",
chainId: "0x4",
blockExplorerUrl: 'https://rinkeby.etherscan.io',
chainId: '0x4',
iconColor: 'var(--rinkeby)',
isATestNetwork: true,
labelKey: "rinkeby",
providerType: "rinkeby",
rpcUrl: "https://rinkeby.infura.io/v3/",
ticker: "ETH",
labelKey: 'rinkeby',
providerType: 'rinkeby',
rpcUrl: 'https://rinkeby.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://goerli.etherscan.io",
chainId: "0x5",
blockExplorerUrl: 'https://goerli.etherscan.io',
chainId: '0x5',
iconColor: 'var(--goerli)',
isATestNetwork: true,
labelKey: "goerli",
providerType: "goerli",
rpcUrl: "https://goerli.infura.io/v3/",
ticker: "ETH",
labelKey: 'goerli',
providerType: 'goerli',
rpcUrl: 'https://goerli.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "https://kovan.etherscan.io",
chainId: "0x2a",
blockExplorerUrl: 'https://kovan.etherscan.io',
chainId: '0x2a',
iconColor: 'var(--kovan)',
isATestNetwork: true,
labelKey: "kovan",
providerType: "kovan",
rpcUrl: "https://kovan.infura.io/v3/",
ticker: "ETH",
labelKey: 'kovan',
providerType: 'kovan',
rpcUrl: 'https://kovan.infura.io/v3/',
ticker: 'ETH',
viewOnly: true,
},
{
blockExplorerUrl: "",
chainId: "0x539",
blockExplorerUrl: '',
chainId: '0x539',
iconColor: 'var(--localhost)',
isATestNetwork: true,
label: "Localhost 8545",
providerType: "rpc",
rpcUrl: "http://localhost:8545",
ticker: "ETH",
label: 'Localhost 8545',
providerType: 'rpc',
rpcUrl: 'http://localhost:8545',
ticker: 'ETH',
},
{
blockExplorerUrl: "https://bscscan.com",
chainId: "0x38",
blockExplorerUrl: 'https://bscscan.com',
chainId: '0x38',
iconColor: 'var(--localhost)',
isATestNetwork: false,
label: "Binance Smart Chain",
providerType: "rpc",
rpcUrl: "https://bsc-dataseed.binance.org/",
ticker: "BNB",
label: 'Binance Smart Chain',
providerType: 'rpc',
rpcUrl: 'https://bsc-dataseed.binance.org/',
ticker: 'BNB',
},
{
blockExplorerUrl: "https://cchain.explorer.avax.network/",
chainId: "0xa86a",
blockExplorerUrl: 'https://cchain.explorer.avax.network/',
chainId: '0xa86a',
iconColor: 'var(--localhost)',
isATestNetwork: false,
label: "Avalanche",
providerType: "rpc",
rpcUrl: "https://api.avax.network/ext/bc/C/rpc",
ticker: "AVAX",
label: 'Avalanche',
providerType: 'rpc',
rpcUrl: 'https://api.avax.network/ext/bc/C/rpc',
ticker: 'AVAX',
},
{
blockExplorerUrl: "https://polygonscan.com",
chainId: "0x89",
blockExplorerUrl: 'https://polygonscan.com',
chainId: '0x89',
iconColor: 'var(--localhost)',
isATestNetwork: false,
label: "Polygon",
providerType: "rpc",
rpcUrl: "https://polygon-rpc.com",
ticker: "MATIC",
label: 'Polygon',
providerType: 'rpc',
rpcUrl: 'https://polygon-rpc.com',
ticker: 'MATIC',
},
],
metamask: {
@ -132,7 +133,7 @@ const state = {
'0x',
],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0xc00e94cb662c3520282e6f5717214004a7f26888': {
address: '0xc00e94cb662c3520282e6f5717214004a7f26888',
@ -153,23 +154,18 @@ const state = {
'0x',
],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0xfffffffff15abf397da76f1dcc1a1604f45126db': {
address: '0xfffffffff15abf397da76f1dcc1a1604f45126db',
symbol: 'FSW',
decimals: 18,
name: 'Falconswap',
iconUrl: 'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184',
aggregators: [
'CoinGecko',
'1inch',
'Paraswap',
'Zapper',
'Zerion',
],
iconUrl:
'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184',
aggregators: ['CoinGecko', '1inch', 'Paraswap', 'Zapper', 'Zerion'],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f': {
address: '0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f',
@ -192,70 +188,70 @@ const state = {
'0x',
],
occurrences: 12,
unlisted: false
unlisted: false,
},
'0x6b175474e89094c44da98b954eedeac495271d0f': {
address: '0x6b175474e89094c44da98b954eedeac495271d0f',
symbol: 'META',
decimals: 18,
image: 'metamark.svg',
unlisted: false
unlisted: false,
},
'0xB8c77482e45F1F44dE1745F52C74426C631bDD52': {
address: '0xB8c77482e45F1F44dE1745F52C74426C631bDD52',
symbol: '0X',
decimals: 18,
image: '0x.svg',
unlisted: false
unlisted: false,
},
'0x1f9840a85d5af5bf1d1762f925bdaddc4201f984': {
address: '0x1f9840a85d5af5bf1d1762f925bdaddc4201f984',
symbol: 'AST',
decimals: 18,
image: 'ast.png',
unlisted: false
unlisted: false,
},
'0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2': {
address: '0x9f8f72aa9304c8b593d555f12ef6589cc3a579a2',
symbol: 'BAT',
decimals: 18,
image: 'BAT_icon.svg',
unlisted: false
unlisted: false,
},
'0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1': {
address: '0xe83cccfabd4ed148903bf36d4283ee7c8b3494d1',
symbol: 'CVL',
decimals: 18,
image: 'CVL_token.svg',
unlisted: false
unlisted: false,
},
'0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e': {
address: '0x0bc529c00C6401aEF6D220BE8C6Ea1667F6Ad93e',
symbol: 'GLA',
decimals: 18,
image: 'gladius.svg',
unlisted: false
unlisted: false,
},
'0x467Bccd9d29f223BcE8043b84E8C8B282827790F': {
address: '0x467Bccd9d29f223BcE8043b84E8C8B282827790F',
symbol: 'GNO',
decimals: 18,
image: 'gnosis.svg',
unlisted: false
unlisted: false,
},
'0xff20817765cb7f73d4bde2e66e067e58d11095c2': {
address: '0xff20817765cb7f73d4bde2e66e067e58d11095c2',
symbol: 'OMG',
decimals: 18,
image: 'omg.jpg',
unlisted: false
unlisted: false,
},
'0x8e870d67f660d95d5be530380d0ec0bd388289e1': {
address: '0x8e870d67f660d95d5be530380d0ec0bd388289e1',
symbol: 'WED',
decimals: 18,
image: 'wed.png',
unlisted: false
unlisted: false,
},
},
networkDetails: {
@ -281,83 +277,84 @@ const state = {
swapsFeatureIsLive: false,
swapsQuoteRefreshTime: 60000,
},
"snapStates": {},
"snaps": {
"local:http://localhost:8080/": {
"enabled": true,
"id": "local:http://localhost:8080/",
"initialPermissions": {
"snap_confirm": {}
snapStates: {},
snaps: {
'local:http://localhost:8080/': {
enabled: true,
id: 'local:http://localhost:8080/',
initialPermissions: {
snap_confirm: {},
},
"manifest": {
"description": "An example MetaMask Snap.",
"initialPermissions": {
"snap_confirm": {}
manifest: {
description: 'An example MetaMask Snap.',
initialPermissions: {
snap_confirm: {},
},
"manifestVersion": "0.1",
"proposedName": "MetaMask Example Snap",
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/snaps-skunkworks.git"
manifestVersion: '0.1',
proposedName: 'MetaMask Example Snap',
repository: {
type: 'git',
url: 'https://github.com/MetaMask/snaps-skunkworks.git',
},
"source": {
"location": {
"npm": {
"filePath": "dist/bundle.js",
"iconPath": "images/icon.svg",
"packageName": "@metamask/example-snap",
"registry": "https://registry.npmjs.org/"
}
source: {
location: {
npm: {
filePath: 'dist/bundle.js',
iconPath: 'images/icon.svg',
packageName: '@metamask/example-snap',
registry: 'https://registry.npmjs.org/',
},
},
"shasum": "3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE="
shasum: '3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE=',
},
"version": "0.6.0"
version: '0.6.0',
},
"permissionName": "wallet_snap_local:http://localhost:8080/",
"sourceCode": "(...)",
"status": "stopped",
"svgIcon": "<svg>...</svg>",
"version": "0.6.0"
},
"Filecoin Snap": {
"enabled": true,
"id": "npm:http://localhost:8080/",
"initialPermissions": {
"snap_confirm": {},
"eth_accounts": {},
"snap_manageState": {},
permissionName: 'wallet_snap_local:http://localhost:8080/',
sourceCode: '(...)',
status: 'stopped',
svgIcon: '<svg>...</svg>',
version: '0.6.0',
},
'Filecoin Snap': {
enabled: true,
id: 'npm:http://localhost:8080/',
initialPermissions: {
snap_confirm: {},
eth_accounts: {},
snap_manageState: {},
},
"manifest": {
"description": "This swap provides developers everywhere access to an entirely new data storage paradigm, even letting your programs store data autonomously. Learn more.",
"initialPermissions": {
"snap_confirm": {},
"eth_accounts": {},
"snap_manageState": {},
manifest: {
description:
'This swap provides developers everywhere access to an entirely new data storage paradigm, even letting your programs store data autonomously. Learn more.',
initialPermissions: {
snap_confirm: {},
eth_accounts: {},
snap_manageState: {},
},
"manifestVersion": "0.1",
"proposedName": "Filecoin Snap",
"repository": {
"type": "git",
"url": "https://github.com/MetaMask/snaps-skunkworks.git"
manifestVersion: '0.1',
proposedName: 'Filecoin Snap',
repository: {
type: 'git',
url: 'https://github.com/MetaMask/snaps-skunkworks.git',
},
"source": {
"location": {
"npm": {
"filePath": "dist/bundle.js",
"iconPath": "images/icon.svg",
"packageName": "@metamask/example-snap",
"registry": "https://registry.npmjs.org/"
}
source: {
location: {
npm: {
filePath: 'dist/bundle.js',
iconPath: 'images/icon.svg',
packageName: '@metamask/example-snap',
registry: 'https://registry.npmjs.org/',
},
},
"shasum": "3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE="
shasum: '3lEt0yUu080DwV78neROaAAIQWXukSkMnP4OBhOhBnE=',
},
"version": "0.6.0"
version: '0.6.0',
},
"permissionName": "wallet_snap_npm:http://localhost:8080/",
"sourceCode": "(...)",
"status": "stopped",
"svgIcon": "<svg>...</svg>",
"version": "0.6.0"
permissionName: 'wallet_snap_npm:http://localhost:8080/',
sourceCode: '(...)',
status: 'stopped',
svgIcon: '<svg>...</svg>',
version: '0.6.0',
},
},
accountArray: [
@ -486,32 +483,46 @@ const state = {
],
detectedTokens: [
{
address: "0x514910771AF9Ca656af840dff83E8264EcF986CA",
address: '0x514910771AF9Ca656af840dff83E8264EcF986CA',
decimals: 18,
symbol: "LINK",
image: "https://crypto.com/price/coin-data/icon/LINK/color_icon.png",
aggregators:[
"coinGecko","oneInch","paraswap","zapper","zerion"
]
symbol: 'LINK',
image: 'https://crypto.com/price/coin-data/icon/LINK/color_icon.png',
aggregators: ['coinGecko', 'oneInch', 'paraswap', 'zapper', 'zerion'],
},
{
address: "0xc00e94Cb662C3520282E6f5717214004A7f26888",
address: '0xc00e94Cb662C3520282E6f5717214004A7f26888',
decimals: 18,
symbol: "COMP",
image: "https://crypto.com/price/coin-data/icon/COMP/color_icon.png",
aggregators:[
"bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"
]
symbol: 'COMP',
image: 'https://crypto.com/price/coin-data/icon/COMP/color_icon.png',
aggregators: [
'bancor',
'cmc',
'cryptocom',
'coinGecko',
'oneInch',
'paraswap',
'pmm',
'zapper',
'zerion',
'zeroEx',
],
},
{
address: "0xfffffffFf15AbF397dA76f1dcc1A1604F45126DB",
address: '0xfffffffFf15AbF397dA76f1dcc1A1604F45126DB',
decimals: 18,
symbol: "FSW",
image: "https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184",
aggregators:[
"aave", "cmc","coinGecko","oneInch","paraswap","zapper","zerion"
]
}
symbol: 'FSW',
image:
'https://assets.coingecko.com/coins/images/12256/thumb/falconswap.png?1598534184',
aggregators: [
'aave',
'cmc',
'coinGecko',
'oneInch',
'paraswap',
'zapper',
'zerion',
],
},
],
pendingTokens: {},
customNonceValue: '',
@ -559,18 +570,18 @@ const state = {
swapsWelcomeMessageHasBeenShown: true,
defaultHomeActiveTabName: 'Assets',
provider: {
type: 'ropsten',
type: 'rinkeby',
ticker: 'ETH',
nickname: '',
rpcUrl: '',
chainId: '0x3',
chainId: '0x4',
},
previousProviderStore: {
type: 'ropsten',
type: 'rinkeby',
ticker: 'ETH',
nickname: '',
rpcUrl: '',
chainId: '0x3',
chainId: '0x4',
},
network: '3',
accounts: {
@ -1304,7 +1315,7 @@ const state = {
subjects: {
'https://app.uniswap.org': {
permissions: {
'eth_accounts': {
eth_accounts: {
invoker: 'https://app.uniswap.org',
parentCapability: 'eth_accounts',
id: 'a7342e4b-beae-4525-a36c-c0635fd03359',
@ -1318,14 +1329,14 @@ const state = {
},
},
},
"local:http://localhost:8080/": {
'local:http://localhost:8080/': {
permissions: {
'snap_confirm': {
invoker: "local:http://localhost:8080/",
snap_confirm: {
invoker: 'local:http://localhost:8080/',
parentCapability: 'snap_confirm',
id: 'a7342F4b-beae-4525-a36c-c0635fd03359',
date: 1620710693178,
caveats: []
caveats: [],
},
},
},
@ -1423,30 +1434,30 @@ const state = {
pendingApprovals: {},
pendingApprovalCount: 0,
subjectMetadata: {
"http://localhost:8080": {
'http://localhost:8080': {
extensionId: null,
iconUrl: null,
name: "Hello, Snaps!",
origin: "http://localhost:8080",
subjectType: "website"
name: 'Hello, Snaps!',
origin: 'http://localhost:8080',
subjectType: 'website',
},
"https://metamask.github.io": {
'https://metamask.github.io': {
extensionId: null,
iconUrl: null,
name: "Snaps Iframe Execution Environment",
origin: "https://metamask.github.io",
subjectType: "website"
name: 'Snaps Iframe Execution Environment',
origin: 'https://metamask.github.io',
subjectType: 'website',
},
"local:http://localhost:8080/": {
'local:http://localhost:8080/': {
extensionId: null,
iconUrl: null,
name: "MetaMask Example Snap",
origin: "local:http://localhost:8080/",
subjectType: "snap",
svgIcon: "<svg>...</svg>",
version: "0.6.0"
}
}
name: 'MetaMask Example Snap',
origin: 'local:http://localhost:8080/',
subjectType: 'snap',
svgIcon: '<svg>...</svg>',
version: '0.6.0',
},
},
},
appState: {
shouldClose: false,
@ -1455,7 +1466,14 @@ const state = {
open: false,
modalState: {
name: null,
props: {},
props: {
token: {
address: '0xaD6D458402F60fD3Bd25163575031ACDce07538D',
symbol: 'DAI',
decimals: 18,
},
history: {},
},
},
previousModalState: {
name: null,
@ -1507,6 +1525,12 @@ const state = {
amount: {
error: 'amount',
},
currentTransactionUUID: 'test-uuid',
draftTransactions: {
'test-uuid': {
...draftTransactionInitialState,
},
},
},
confirmTransaction: {
txData: {

@ -3110,6 +3110,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.3...HEAD
[10.18.3]: https://github.com/MetaMask/metamask-extension/compare/v10.18.2...v10.18.3
[10.18.2]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...v10.18.2
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.18.1...HEAD
[10.18.1]: https://github.com/MetaMask/metamask-extension/compare/v10.18.0...v10.18.1
[10.18.0]: https://github.com/MetaMask/metamask-extension/compare/v10.17.0...v10.18.0
[10.17.0]: https://github.com/MetaMask/metamask-extension/compare/v10.16.2...v10.17.0

@ -14,7 +14,7 @@ To learn how to contribute to the MetaMask project itself, visit our [Internal D
## Building locally
- Install [Node.js](https://nodejs.org) version 14
- Install [Node.js](https://nodejs.org) version 16
- If you are using [nvm](https://github.com/creationix/nvm#installation) (recommended) running `nvm use` will automatically choose the right node version for you.
- Install [Yarn](https://yarnpkg.com/en/docs/install)
- Install dependencies: `yarn setup` (not the usual install command)
@ -118,3 +118,4 @@ Whenever you change dependencies (adding, removing, or updating, either in `pack
- [How to generate a visualization of this repository's development](./development/gource-viz.sh)
[1]: http://www.nomnoml.com/#view/%5B%3Cactor%3Euser%5D%0A%0A%5Bmetamask-ui%7C%0A%20%20%20%5Btools%7C%0A%20%20%20%20%20react%0A%20%20%20%20%20redux%0A%20%20%20%20%20thunk%0A%20%20%20%20%20ethUtils%0A%20%20%20%20%20jazzicon%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20account-detail%0A%20%20%20%20%20accounts%0A%20%20%20%20%20locked-screen%0A%20%20%20%20%20restore-vault%0A%20%20%20%20%20identicon%0A%20%20%20%20%20config%0A%20%20%20%20%20info%0A%20%20%20%5D%0A%20%20%20%5Breducers%7C%0A%20%20%20%20%20app%0A%20%20%20%20%20metamask%0A%20%20%20%20%20identities%0A%20%20%20%5D%0A%20%20%20%5Bactions%7C%0A%20%20%20%20%20%5BbackgroundConnection%5D%0A%20%20%20%5D%0A%20%20%20%5Bcomponents%5D%3A-%3E%5Bactions%5D%0A%20%20%20%5Bactions%5D%3A-%3E%5Breducers%5D%0A%20%20%20%5Breducers%5D%3A-%3E%5Bcomponents%5D%0A%5D%0A%0A%5Bweb%20dapp%7C%0A%20%20%5Bui%20code%5D%0A%20%20%5Bweb3%5D%0A%20%20%5Bmetamask-inpage%5D%0A%20%20%0A%20%20%5B%3Cactor%3Eui%20developer%5D%0A%20%20%5Bui%20developer%5D-%3E%5Bui%20code%5D%0A%20%20%5Bui%20code%5D%3C-%3E%5Bweb3%5D%0A%20%20%5Bweb3%5D%3C-%3E%5Bmetamask-inpage%5D%0A%5D%0A%0A%5Bmetamask-background%7C%0A%20%20%5Bprovider-engine%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bid%20store%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%3E%5Bhooked%20wallet%20subprovider%5D%0A%20%20%5Bhooked%20wallet%20subprovider%5D%3C-%3E%5Bid%20store%5D%0A%20%20%5Bconfig%20manager%7C%0A%20%20%20%20%5Brpc%20configuration%5D%0A%20%20%20%20%5Bencrypted%20keys%5D%0A%20%20%20%20%5Bwallet%20nicknames%5D%0A%20%20%5D%0A%20%20%0A%20%20%5Bprovider-engine%5D%3C-%5Bconfig%20manager%5D%0A%20%20%5Bid%20store%5D%3C-%3E%5Bconfig%20manager%5D%0A%5D%0A%0A%5Buser%5D%3C-%3E%5Bmetamask-ui%5D%0A%0A%5Buser%5D%3C%3A--%3A%3E%5Bweb%20dapp%5D%0A%0A%5Bmetamask-contentscript%7C%0A%20%20%5Bplugin%20restart%20detector%5D%0A%20%20%5Brpc%20passthrough%5D%0A%5D%0A%0A%5Brpc%20%7C%0A%20%20%5Bethereum%20blockchain%20%7C%0A%20%20%20%20%5Bcontracts%5D%0A%20%20%20%20%5Baccounts%5D%0A%20%20%5D%0A%5D%0A%0A%5Bweb%20dapp%5D%3C%3A--%3A%3E%5Bmetamask-contentscript%5D%0A%5Bmetamask-contentscript%5D%3C-%3E%5Bmetamask-background%5D%0A%5Bmetamask-background%5D%3C-%3E%5Bmetamask-ui%5D%0A%5Bmetamask-background%5D%3C-%3E%5Brpc%5D%0A

@ -157,6 +157,9 @@
"addMemo": {
"message": "Notiz hinzufügen"
},
"addMoreNetworks": {
"message": "weitere Netzwerke manuell hinzufügen"
},
"addNetwork": {
"message": "Netzwerk hinzufügen"
},
@ -282,9 +285,6 @@
"approvedAsset": {
"message": "Genehmigtes Asset"
},
"areYouDeveloper": {
"message": "Sind Sie ein Entwickler?"
},
"areYouSure": {
"message": "Sind Sie sicher?"
},
@ -438,7 +438,7 @@
"message": "$1 mit Wyre kaufen"
},
"buyWithWyreDescription": {
"message": "Wyre ermöglicht Ihnen die Verwendung einer Kreditkarte zum direkten Einzahlen von $1 auf Ihr MetaMask-Konto."
"message": "Einfaches Onboarding für Käufe bis zu 1000 $. Schnelle interaktive Überprüfung von Käufen mit hohem Limit. Unterstützt Debit-/Kreditkarte, Apple Pay, Banküberweisungen. Verfügbar in über 100 Ländern. Einzahlung von Token auf Ihr MetaMask-Konto"
},
"bytes": {
"message": "Bytes"
@ -466,6 +466,13 @@
"message": "Für eine Transaktion im Wert von $1 muss die Gasgebühr um mindestens 10 % erhöht werden, damit sie vom Netz erkannt wird.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Tausch für 1 $ abbrechen",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Tausch kostenlos abbrechen"
},
"cancellationGasFee": {
"message": "Stornierungs-Gasgebühr"
},
@ -1888,10 +1895,6 @@
"metametricsTitle": {
"message": "6M+ Benutzern beitreten um MetaMask zu verbessern"
},
"mismatchedChain": {
"message": "Die Netzwerkdetails für diese Ketten-ID stimmen nicht mit unseren Aufzeichnungen überein. Wir empfehlen Ihnen $1, bevor Sie fortfahren.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "die Netzwerkdetails überprüfen",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -1947,6 +1950,9 @@
"network": {
"message": "Netzwerk:"
},
"networkAddedSuccessfully": {
"message": "Netzwerk erfolgreich hinzugefügt!"
},
"networkDetails": {
"message": "Netzwerkdetails"
},
@ -2063,6 +2069,9 @@
"message": "Nonce ist höher als vorgeschlagen nonce von $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Token-ID eingeben"
},
@ -2266,7 +2275,7 @@
"message": "Alle als gelesen markieren"
},
"numberOfNewTokensDetected": {
"message": "$1 neue Tokens in diesem Konto gefunden\n",
"message": "$1 neue Tokens in diesem Konto gefunden",
"description": "$1 is the number of new tokens detected"
},
"ofTextNofM": {
@ -2348,9 +2357,6 @@
"message": "Öffnen Sie MetaMask im Vollbildmodus, um Ihren Ledger über WebHID zu verbinden.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Prüfen Sie den Quellcode"
},
"optional": {
"message": "Optional"
},
@ -2881,6 +2887,12 @@
"showAdvancedGasInlineDescription": {
"message": "Wählen Sie dies aus, um den Gaspreis und die Limitkontrollen direkt auf den Senden- und Bestätigen-Bildschirmen anzuzeigen."
},
"showCustomNetworkList": {
"message": "Benutzerdefinierte Netzwerkliste anzeigen"
},
"showCustomNetworkListDescription": {
"message": "Diese Option zeigt eine Liste von Netzwerken mit vorausgefüllten Details an, sobald ein neues Netzwerk hinzugefügt wird."
},
"showFiatConversionInTestnets": {
"message": "Umwandlung auf Testnets anzeigen"
},
@ -2971,10 +2983,6 @@
"snapInstallWarningCheck": {
"message": "Um zu bestätigen, dass Sie alles verstanden haben, kreuzen Sie alles an."
},
"snapInstallWarningKeyAccess": {
"message": "Sie gewähren dem Snap „$1“ wichtige Zugriffsrechte. Dies kann nicht rückgängig gemacht werden und gibt „$1“ Kontrolle über Ihre Konten und Vermögenswerte. Stellen Sie sicher, dass Sie „$1“ vertrauen, bevor Sie fortfahren.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Für diesen Snap werden die folgenden Berechtigungen beantragt:"
},
@ -2990,6 +2998,9 @@
"snapsToggle": {
"message": "Ein Snap wird nur ausgeführt, wenn er aktiviert ist"
},
"someNetworksMayPoseSecurity": {
"message": "Einige Netzwerke können Sicherheits- und/oder Datenschutzrisiken bergen. Informieren Sie sich über die Risiken, bevor Sie ein Netzwerk hinzufügen und nutzen."
},
"somethingWentWrong": {
"message": "Hoppla! Da hat etwas nicht geklappt."
},
@ -3079,7 +3090,7 @@
"message": "Status"
},
"statusConnected": {
"message": "Verbunden"
"message": "Verbinden"
},
"statusNotConnected": {
"message": "Nicht verbunden"
@ -3552,6 +3563,10 @@
"switchNetworks": {
"message": "Netzwerk wechseln"
},
"switchToNetwork": {
"message": "Zu 1 $ wechseln",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Zu diesem Konto wechseln"
},
@ -3855,6 +3870,9 @@
"unknownCameraErrorTitle": {
"message": "Hoppla! Etwas ist schiefgegangen ..."
},
"unknownCollection": {
"message": "Unbenannte Sammlung"
},
"unknownNetwork": {
"message": "Unbekanntes privates Netzwerk"
},
@ -3874,10 +3892,6 @@
"message": "Dieses benutzerdefinierte Netzwerk ist nicht erkannt. Wir empfehlen, dass Sie $1 bevor Sie fortfahren",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "die Netzwerkdetails überprüfen",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Verwenden von Sammelbaren (ERC-721) Token wird derzeit nicht unterstützt",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3970,7 +3984,7 @@
"description": "$1 is the action type. e.g (Account, Transaction, Swap)"
},
"visitWebSite": {
"message": "Gehe zu unserer Webseite"
"message": "Besuchen Sie unsere Webseite"
},
"walletConnectionGuide": {
"message": "unsere Hardware-Wallet-Verbindungsanleitung"
@ -3995,6 +4009,9 @@
"walletCreationSuccessTitle": {
"message": "Wallet-Erstellung erfolgreich"
},
"wantToAddThisNetwork": {
"message": "Möchten Sie dieses Netzwerk hinzufügen?"
},
"warning": {
"message": "Warnung"
},
@ -4057,6 +4074,10 @@
"yesLetsTry": {
"message": "Ja, versuchen wir es"
},
"youHaveAddedAll": {
"message": "Sie haben alle beliebten Netzwerke hinzugefügt. Sie können weitere Netzwerke entdecken 1 $ oder Sie können 2 $",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Sie müssen Zugriff auf die Kamera erlauben, um diese Funktion nutzen zu können."
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "Προσθήκη σημειώματος"
},
"addMoreNetworks": {
"message": "προσθέστε περισσότερα δίκτυα χειροκίνητα"
},
"addNetwork": {
"message": "Προσθήκη Δικτύου"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Ειδοποιήσεις"
},
"allOfYour": {
"message": "Όλα σας τα $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Επιτρέψτε σε αυτή την εξωτερική επέκταση να:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Έγκριση"
},
"approveAllTokensTitle": {
"message": "Δίνετε άδεια για να αποκτήσετε πρόσβαση σε όλα σας τα $1;",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Έγκριση και Εγκατάσταση"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Εγκεκριμένο περιουσιακό στοιχείο"
},
"areYouDeveloper": {
"message": "Είστε προγραμματιστής;"
},
"areYouSure": {
"message": "Είστε βέβαιος/η;"
},
@ -438,7 +446,7 @@
"message": "Αγοράστε $1 με το Wyre"
},
"buyWithWyreDescription": {
"message": "Το Wyre σας επιτρέπει να χρησιμοποιήσετε μια πιστωτική κάρτα για να καταθέσετε $1 απευθείας στον λογαριασμό σας MetaTask."
"message": "Εύκολη ενσωμάτωση για αγορές μέχρι και $ 1000. Γρήγορη διαδραστική επαλήθευση αγοράς υψηλού ορίου. Υποστηρίζει χρεωστικές/πιστωτικές κάρτες, Apple Pay, Τραπεζικές Μεταφορές. Διαθέσιμο σε 100+ χώρες. Καταθέσεις token στον λογαριασμό σας MetaMask"
},
"bytes": {
"message": "Bytes"
@ -466,6 +474,13 @@
"message": "Για να $1 τη συναλλαγή, τα τέλη συναλλαγής πρέπει να αυξηθούν κατά τουλάχιστον 10% ώστε να αναγνωριστούν από το δίκτυο.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Ακυρώστε τη συναλλαγή για ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Ακυρώστε τη συναλλαγή δωρεάν"
},
"cancellationGasFee": {
"message": "Ακύρωση Χρέωσης Αερίου"
},
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Λειτουργία: Έγκριση"
},
"functionSetApprovalForAll": {
"message": "Λειτουργία: SetApprovalForAll"
},
"functionType": {
"message": "Τύπος Λειτουργίας"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Μη έγκυρη Μυστική Φράση Ανάκτησής"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Μη έγκυρη εισαγωγή! Η Μυστική σας Φράση Ανάκτησης κάνει διάκριση πεζών-κεφαλαίων."
},
"ipfsGateway": {
"message": "Πύλη IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Συμμετάσχετε σε 6εκ+ χρήστες για να βελτιώσετε το MetaMask"
},
"mismatchedChain": {
"message": "Οι λεπτομέρειες δικτύου για αυτό το αναγνωριστικό αλυσίδας δεν ταιριάζουν με τις εγγραφές μας. Σας συνιστούμε να $1 πριν συνεχίσετε.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "επαληθεύστε τα στοιχεία δικτύου",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Σας προτείνουμε να $1 πριν συνεχίσετε.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Σύμφωνα με τις καταχωρήσεις μας, το όνομα δικτύου ίσως δεν ταιριάζει με το αναγνωριστικό αλυσίδας."
},
"mismatchedNetworkSymbol": {
"message": "Το σύμβολο νομίσματος που υποβλήθηκε δεν ταιριάζει με αυτό που αναμενόταν για αυτό το αναγνωριστικό αλυσίδας."
},
"mismatchedRpcUrl": {
"message": "Σύμφωνα με τις καταχωρήσεις μας, η τιμή RPC URL που υποβλήθηκε δεν ταιριάζει με κάποιον γνωστό πάροχο για αυτό το αναγνωριστικό αλυσίδας."
},
"missingNFT": {
"message": "Δεν βλέπετε το NFT σας;"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Δίκτυο:"
},
"networkAddedSuccessfully": {
"message": "Το δίκτυο προστέθηκε επιτυχώς!"
},
"networkDetails": {
"message": "Λεπτομέρειες Δικτύου"
},
@ -2063,6 +2096,9 @@
"message": "Το Nonce είναι υψηλότερο από το προτεινόμενο nonce του $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Εισάγετε το συλλεκτικό αναγνωριστικό"
},
@ -2158,11 +2194,21 @@
"message": "Ενεργοποίηση dark mode"
},
"notifications12Description": {
"message": "Το Dark Mode (σκουρόχρωμη λειτουργία) θα ενεργοποιηθεί για νέους χρήστες ανάλογα με τις προτιμήσεις του συστήματός τους. Εάν είστε ήδη χρήστης, ενεργοποιήστε τo dark mode με μη αυτόματο τρόπο στην ενότητα Ρυθμίσεις -> Πειραματικές."
"message": "Έφτασε επιτέλους το Dark Mode (σκουρόχρωμη λειτουργία)! Για να το ενεργοποιήσετε, μεταβείτε στις Ρυθμίσεις -> Πειραματικό και επιλέξτε μία από τις επιλογές εμφάνισης: Light, Dark, Σύστημα."
},
"notifications12Title": {
"message": "Θέλετε dark mode; Τώρα έχετε dark mode! 🕶🦊"
},
"notifications13ActionText": {
"message": "Προβολή λίστας προσαρμοσμένων δικτύων"
},
"notifications13Description": {
"message": "Τώρα μπορείτε να προσθέσετε εύκολα τα ακόλουθα δημοφιλή προσαρμοσμένα δίκτυα: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm and Polygon! Για να ενεργοποιήσετε αυτήν τη λειτουργία, πηγάινετε στις Ρυθμίσεις -> Πειραματικό και ενεργοποιήστε το «Προβολή λίστας προσαρμοσμένων δικτύων»!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Προσθήκη Δημοφιλών Δικτύων"
},
"notifications1Description": {
"message": "Οι χρήστες του MetaMask Mobile μπορούν τώρα να ανταλλάξουν tokens μέσα στο κινητό τους πορτοφόλι. Σαρώστε τον κωδικό QR για να πάρετε την εφαρμογή για κινητά και να αρχίσετε να ανταλλάζετε.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Ανοίξτε το MetaMask σε πλήρη οθόνη για να συνδέσετε το ledger σας μέσω WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Ελέγξτε τον πηγαίο κώδικα"
},
"optional": {
"message": "Προαιρετικό"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Αποκάλυψη φράσης ανάκτησης"
},
"revokeAllTokensTitle": {
"message": "Ανάκληση άδειας πρόσβασης σε όλα σας τα $1;",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "Με την ανάκληση της άδειας, το ακόλουθο $1 δεν θα έχει πλέον πρόσβαση στο $2 σας",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Δοκιμαστικό Δίκτυο Rinkeby"
},
@ -2856,12 +2907,23 @@
"message": "Αποστολή $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Προειδοποίηση: πρόκειται να στείλετε ένα συμβόλαιο token το οποίο ίσως καταλήξει σε απώλεια χρημάτων. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Ορίστε ρυθμίσεις απορρήτου για προχωρημένους"
},
"setAdvancedPrivacySettingsDetails": {
"message": "Το MetaMask χρησιμοποιεί αυτές τις αξιόπιστες υπηρεσίες τρίτων για να ενισχύσει τη χρηστικότητα και την ασφάλεια των προϊόντων."
},
"setApprovalForAll": {
"message": "Ρύθμιση Έγκρισης Όλων"
},
"setApprovalForAllTitle": {
"message": "Έγκριση $1 χωρίς όριο δαπανών",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Ρυθμίσεις"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Επιλέξτε αυτό για να εμφανίσετε τις τιμές αερίου και να περιορίσετε τα στοιχεία ελέγχου απευθείας στις οθόνες αποστολής και επιβεβαίωσης."
},
"showCustomNetworkList": {
"message": "Προβολή Λίστας Προσαρμοσμένων Δικτύων"
},
"showCustomNetworkListDescription": {
"message": "Επιλέξτε αυτό για να εμφανιστεί μια λίστα δικτύων με προσυμπληρωμένα στοιχεία κατά την προσθήκη ενός νέου δικτύου."
},
"showFiatConversionInTestnets": {
"message": "Εμφάνιση Μετατροπής σε Δοκιμαστικά Δίκτυα"
},
@ -2924,7 +2992,7 @@
"message": "Υπογραφή"
},
"signNotice": {
"message": "Η υπογραφή αυτού του μηνύματος μπορεί να έχει\nεπικίνδυνες παρενέργειες. Υπογράφετε μηνύματα μόνο από\nτοποθεσίες που εμπιστεύεστε πλήρως με ολόκληρο τον λογαριασμό σας.\n  Αυτή η επικίνδυνη μέθοδος θα καταργηθεί σε μια μελλοντική έκδοση."
"message": "Η υπογραφή αυτού του μηνύματος μπορεί να έχει\nεπικίνδυνες παρενέργειες. Υπογράφετε μηνύματα μόνο από\nτοποθεσίες που εμπιστεύεστε πλήρως με ολόκληρο τον λογαριασμό σας.\n Αυτή η επικίνδυνη μέθοδος θα καταργηθεί σε μια μελλοντική έκδοση."
},
"signatureRequest": {
"message": "Αίτημα Υπογραφής"
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Για να επιβεβαιώσετε ότι καταλαβαίνετε, επιλέξτε όλα τα πλαίσια ελέγχου."
},
"snapInstallWarningKeyAccess": {
"message": "Παρέχετε βασική πρόσβαση στο snap \"$1\". Αυτή η ενέργεια είναι μη αναστρέψιμη και παραχωρεί στο \"$1\" τον έλεγχο των λογαριασμών και των περιουσιακών σας στοιχείων. Βεβαιωθείτε ότι εμπιστεύεστε το \"$1\" πριν συνεχίσετε.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Αυτό το snap αιτείται τις παρακάτω άδειες:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Ένα snap θα εκτελεστεί μόνο εάν είναι ενεργοποιημένο"
},
"someNetworksMayPoseSecurity": {
"message": "Ορισμένα δίκτυα ενδέχεται να ενέχουν κινδύνους για την ασφάλεια ή/και το απόρρητο. Ενημερωθείτε για τους κινδύνους πριν προσθέσετε και χρησιμοποιήσετε ένα δίκτυο."
},
"somethingWentWrong": {
"message": "Ουπς! Κάτι πήγε στραβά."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Αλλαγή Δικτύων"
},
"switchToNetwork": {
"message": "Εναλλαγή σε $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Εναλλαγή σε αυτόν τον λογαριασμό"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Ουπς! Κάτι πήγε στραβά...."
},
"unknownCollection": {
"message": "Ανώνυμη συλλογή"
},
"unknownNetwork": {
"message": "Άγνωστο Ιδιωτικό Δίκτυο"
},
@ -3874,10 +3948,6 @@
"message": "Αυτό το προσαρμοσμένο δίκτυο δεν αναγνωρίζεται. Σας συνιστούμε να $1 πριν προχωρήσετε",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "επαληθεύστε τα στοιχεία δικτύου",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Η αποστολή συλλεκτικών (ERC-721) δεν υποστηρίζεται προς το παρόν",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Επιτυχής δημιουργία πορτοφολιού"
},
"wantToAddThisNetwork": {
"message": "Θέλετε να προσθέσετε αυτό το δίκτυο;"
},
"warning": {
"message": "Προειδοποίηση"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Ναι, ας δοκιμάσουμε"
},
"youHaveAddedAll": {
"message": "Προσθέσατε όλα τα δημοφιλή δίκτυα. Μπορείτε να ανακαλύψετε περισσότερα δίκτυα $1 Ή μπορείτε να \n $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Πρέπει να επιτρέψετε πρόσβαση στην κάμερα για να χρησιμοποιήσετε αυτήν τη λειτουργία."
},

@ -44,6 +44,60 @@
"QRHardwareWalletSteps2Description": {
"message": "Ngrave (Coming Soon)"
},
"SIWEAddressInvalid": {
"message": "The address in the sign-in request does not match the address of the account you are using to sign in."
},
"SIWEDomainInvalid": {
"message": "The website you are attempting to sign in to ($1) does not match the domain in the sign-in request. Proceed with caution.",
"description": "$1 represents the website domain"
},
"SIWEDomainWarningBody": {
"message": "The website ($1) is asking you to sign in to the wrong domain. This may be a phishing attack.",
"description": "$1 represents the website domain"
},
"SIWELabelChainID": {
"message": "Chain ID:"
},
"SIWELabelExpirationTime": {
"message": "Expires At:"
},
"SIWELabelIssuedAt": {
"message": "Issued At:"
},
"SIWELabelMessage": {
"message": "Message:"
},
"SIWELabelNonce": {
"message": "Nonce:"
},
"SIWELabelNotBefore": {
"message": "Not Before:"
},
"SIWELabelRequestID": {
"message": "Request ID:"
},
"SIWELabelResources": {
"message": "Resources: $1",
"description": "$1 represents the number of resources"
},
"SIWELabelURI": {
"message": "URI:"
},
"SIWELabelVersion": {
"message": "Version:"
},
"SIWESiteRequestSubtitle": {
"message": "This site is requesting to sign in with"
},
"SIWESiteRequestTitle": {
"message": "Sign-in request"
},
"SIWEWarningSubtitle": {
"message": "To confirm you understand, check:"
},
"SIWEWarningTitle": {
"message": "Are you sure?"
},
"about": {
"message": "About"
},
@ -121,6 +175,9 @@
"addAlias": {
"message": "Add alias"
},
"addBlockExplorer": {
"message": "Add a block explorer"
},
"addContact": {
"message": "Add contact"
},
@ -275,7 +332,10 @@
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Approve & Install"
"message": "Approve & install"
},
"approveAndUpdate": {
"message": "Approve & update"
},
"approveButtonText": {
"message": "Approve"
@ -293,8 +353,9 @@
"approvedAsset": {
"message": "Approved asset"
},
"areYouDeveloper": {
"message": "Are you a developer?"
"approvedOn": {
"message": "Approved on $1",
"description": "$1 is the approval date for a permission"
},
"areYouSure": {
"message": "Are you sure?"
@ -1638,6 +1699,9 @@
"invalidSeedPhrase": {
"message": "Invalid Secret Recovery Phrase"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Invalid input! Secret Recovery Phrase is case sensitive."
},
"ipfsGateway": {
"message": "IPFS Gateway"
},
@ -1909,14 +1973,23 @@
"metametricsTitle": {
"message": "Join 6M+ users to improve MetaMask"
},
"mismatchedChain": {
"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": {
"message": "verify the network details",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "We recommend that you $1 before proceeding.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "According to our record the network name may not correctly match this chain ID."
},
"mismatchedNetworkSymbol": {
"message": "The submitted currency symbol does not match what we expect for this chain ID."
},
"mismatchedRpcUrl": {
"message": "According to our records the submitted RPC URL value does not match a known provider for this chain ID."
},
"missingNFT": {
"message": "Don't see your NFT?"
},
@ -2190,6 +2263,16 @@
"notifications12Title": {
"message": "Wen dark mode? Now dark mode! 🕶🦊"
},
"notifications13ActionText": {
"message": "Show custom network list"
},
"notifications13Description": {
"message": "You can now add the following popular custom networks easily: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm and Polygon! To enable this feature, go to Settings -> Experimental and turn \"Show custom network list\" on!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Add Popular Networks"
},
"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."
@ -2375,9 +2458,6 @@
"message": "Open MetaMask in full screen to connect your ledger via WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Check the source code"
},
"optional": {
"message": "Optional"
},
@ -2450,6 +2530,12 @@
"permissionRequestCapitalized": {
"message": "Permission Request"
},
"permissionRequested": {
"message": "Requested now"
},
"permissionRevoked": {
"message": "Revoked in this update"
},
"permission_accessNetwork": {
"message": "Access the Internet.",
"description": "The description of the `endowment:network-access` permission."
@ -2987,6 +3073,9 @@
"signed": {
"message": "Signed"
},
"signin": {
"message": "Sign-In"
},
"simulationErrorMessageV2": {
"message": "We were not able to estimate gas. There might be an error in the contract and this transaction may fail."
},
@ -3021,15 +3110,25 @@
"message": "Install Snap"
},
"snapInstallWarningCheck": {
"message": "To confirm you understand, check all."
"message": "To confirm that you understand, check the box."
},
"snapInstallWarningCheckPlural": {
"message": "To confirm that you understand, check all the boxes."
},
"snapInstallWarningKeyAccess": {
"message": "You are granting key access to the snap \"$1\". This is irrevocable and grants \"$1\" control of your accounts and assets. Make sure you trust \"$1\" before proceeding.",
"description": "The parameter is the name of the snap"
"message": "You are granting $2 key access to the snap \"$1\". This is irrevocable and grants \"$1\" control of your $2 accounts and assets. Make sure you trust \"$1\" before proceeding.",
"description": "The first parameter is the name of the snap and the second one is the protocol"
},
"snapRequestsPermission": {
"message": "This snap is requesting the following permissions:"
},
"snapUpdate": {
"message": "Update Snap"
},
"snapUpdateExplanation": {
"message": "$1 needs a newer version of your snap.",
"description": "$1 is the dapp that is requesting an update to the snap."
},
"snaps": {
"message": "Snaps"
},
@ -3195,7 +3294,7 @@
"message": "Swap would have failed"
},
"stxCancelledDescription": {
"message": "Your transaction would have failed and was canceled to protect you from paying unnecessary gas fees."
"message": "Your transaction would have failed and was cancelled to protect you from paying unnecessary gas fees."
},
"stxCancelledSubDescription": {
"message": "Try your swap again. We’ll be here to protect you against similar risks next time."
@ -3261,10 +3360,10 @@
"message": "A transaction has been successful but we’re unsure what it is. This may be due to submitting another transaction while this swap was processing."
},
"stxUserCancelled": {
"message": "Swap canceled"
"message": "Swap cancelled"
},
"stxUserCancelledDescription": {
"message": "Your transaction has been canceled and you did not pay any unnecessary gas fees."
"message": "Your transaction has been cancelled and you did not pay any unnecessary gas fees."
},
"stxYouCanOptOut": {
"message": "You can opt-out in advanced settings any time."
@ -3933,12 +4032,12 @@
"message": "The decentralized web awaits"
},
"unrecognizedChain": {
"message": "This custom network is not recognized. We recommend that you $1 before proceeding",
"message": "This custom network is not recognized",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verify the network details",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
"unrecognizedProtocol": {
"message": "$1 (Unrecognized protocol)",
"description": "Shown when the protocol is unknown by the extension. $1 is the protocol code."
},
"unsendableAsset": {
"message": "Sending collectible (ERC-721) tokens is not currently supported",

@ -157,6 +157,9 @@
"addMemo": {
"message": "Añadir memo"
},
"addMoreNetworks": {
"message": "agregar más redes manualmente"
},
"addNetwork": {
"message": "Agregar red"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Alertas"
},
"allOfYour": {
"message": "Todo su $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Permitir que esta extensión externa haga lo siguiente:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Aprobar límite de gastos"
},
"approveAllTokensTitle": {
"message": "¿Dar permiso para acceder a todo su $1?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Aprobar e instalar"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Activo aprobado"
},
"areYouDeveloper": {
"message": "¿Usted es desarrollador?"
},
"areYouSure": {
"message": "¿Está seguro?"
},
@ -438,7 +446,7 @@
"message": "Comprar $1 con Wyre"
},
"buyWithWyreDescription": {
"message": "Acceso fácil a transacciones de $ 1,000 o menos con verificación rápida y efectiva. Aceptamos tarjetas débito, crédito, Apple Pay y transferencias bancarias en más de 100 países. Tokens serán depósitados en su MetaMask."
"message": "Acceso fácil a compras de hasta $1,000. Verificación interactiva rápida de compra de límite alto. Acepta tarjeta de débito/crédito, Apple Pay y transferencias bancarias. Disponible para más de 100 países. Los tokens se depositarán en su cuenta MetaMask"
},
"bytes": {
"message": "Bytes"
@ -466,6 +474,13 @@
"message": "Para $1 una transacción, la tarifa de gas debe aumentar al menos un 10% para que sea reconocida por la red.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Cancelar el swap por ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Cancelar el swap gratuitamente"
},
"cancellationGasFee": {
"message": "Cuota de gas por cancelación"
},
@ -650,7 +665,7 @@
"message": "Interacción con el contrato"
},
"convertTokenToNFTDescription": {
"message": "Hemos detectado que este activo es un NFT. MetaMask ahora tiene soporte nativo completo para NFTs. ¿Quieres eliminarlo de tu lista de tokens y añadirlo como un NFT?"
"message": "Hemos detectado que este activo es un NFT. MetaMask ahora tiene soporte nativo completo para NFT. ¿Quiere eliminarlo de su lista de tokens y añadirlo como un NFT?"
},
"convertTokenToNFTExistDescription": {
"message": "Hemos detectado que este recurso se ha agregado como NFT. ¿Quiere eliminarlo de su lista de tokens?"
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Función: Aprobar"
},
"functionSetApprovalForAll": {
"message": "Función: SetApprovalForAll"
},
"functionType": {
"message": "Tipo de función"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Frase secreta de recuperación no válida"
},
"invalidSeedPhraseCaseSensitive": {
"message": "¡Entrada inválida! La frase secreta de recuperación distingue entre mayúsculas y minúsculas."
},
"ipfsGateway": {
"message": "Puerta de enlace de IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Únase a más de 6 millones de usuarios para mejorar MetaMask"
},
"mismatchedChain": {
"message": "Los detalles de la red de este identificador de cadena no coinciden con nuestros registros. Antes de continuar, le recomendamos que $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Recomendamos que usted $1 antes de proceder.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Según nuestros registros, es posible que el nombre de la red no coincida correctamente con este ID de cadena."
},
"mismatchedNetworkSymbol": {
"message": "El símbolo de moneda enviado no coincide con lo que esperamos para este ID de cadena."
},
"mismatchedRpcUrl": {
"message": "Según nuestros registros, el valor de la URL de RPC enviado no coincide con un proveedor conocido para este ID de cadena."
},
"missingNFT": {
"message": "¿No ve su NFT?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Red:"
},
"networkAddedSuccessfully": {
"message": "¡Red añadida exitosamente!"
},
"networkDetails": {
"message": "Detalles de la red"
},
@ -2063,6 +2096,9 @@
"message": "El nonce es superior al nonce sugerido de $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Ingresa el ID del token"
},
@ -2158,11 +2194,21 @@
"message": "Habilitar modo oscuro"
},
"notifications12Description": {
"message": "¡El modo oscuro en Extension finalmente está aquí! Para encenderlo, vaya a Configuración -> Experimental y seleccione una de las opciones de visualización: Claro, Oscuro, Sistema."
"message": "¡El modo oscuro en Extensión finalmente está aquí! Para activarlo, vaya a Configuración -> Experimental y seleccione una de las opciones de visualización: Claro, Oscuro, Sistema."
},
"notifications12Title": {
"message": "¿Cuándo estará disponible el modo oscuro? ¡Ahora! 🕶🦊"
},
"notifications13ActionText": {
"message": "Mostrar lista de redes personalizadas"
},
"notifications13Description": {
"message": "Ahora puede agregar fácilmente las siguientes redes personalizadas populares: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm y Polygon. Para habilitar esta función, vaya a Configuración -> Experimental y ¡active \"Mostrar lista de redes personalizadas\"!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Añadir redes populares"
},
"notifications1Description": {
"message": "Los usuarios de la aplicación móvil de MetaMask ahora pueden canjear tokens en su cartera móvil. Escanee el código QR para obtener la aplicación móvil y comience a canjear.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Abra MetaMask en pantalla completa para conectar su Ledger a través de WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Compruebe el código fuente"
},
"optional": {
"message": "Opcional"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Revelar frase semilla"
},
"revokeAllTokensTitle": {
"message": "¿Revocar permiso para acceder a todo su $1?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "Al revocar permisos, el/la siguiente $1 no tendrá más acceso a su $2",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Red de prueba Rinkeby"
},
@ -2856,12 +2907,23 @@
"message": "Enviando $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Advertencia: está a punto de enviar un contrato de token que podría dar lugar a una pérdida de fondos. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Configuración avanzada de privacidad"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask utiliza estos servicios de terceros de confianza para mejorar la usabilidad y la seguridad de los productos."
},
"setApprovalForAll": {
"message": "Establecer aprobación para todos"
},
"setApprovalForAllTitle": {
"message": "Aprobar $1 sin límite preestablecido",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Configuración"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Seleccione esta opción para mostrar el precio del gas y limitar los controles directamente en las pantallas de envío y confirmación."
},
"showCustomNetworkList": {
"message": "Mostrar lista de redes personalizadas"
},
"showCustomNetworkListDescription": {
"message": "Seleccione esto para mostrar una lista de redes con detalles precargados al agregar una red nueva."
},
"showFiatConversionInTestnets": {
"message": "Mostrar conversión en redes de prueba"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Para confirmar que comprende, marque todo."
},
"snapInstallWarningKeyAccess": {
"message": "Está otorgando acceso clave al complemento \"$1\". Esto es irrevocable y le otorga a \"$1\" el control de sus cuentas y activos. Asegúrese de confiar en \"$1\" antes de continuar.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Este complemento solicita los siguientes permisos:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Un complemento solo se ejecutará si está habilitado"
},
"someNetworksMayPoseSecurity": {
"message": "Algunas redes pueden presentar riesgos de seguridad y/o privacidad. Comprenda los riesgos antes de agregar y utilizar una red."
},
"somethingWentWrong": {
"message": "Lo lamentamos, se produjo un error."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Cambiar redes"
},
"switchToNetwork": {
"message": "Cambiar a $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Cambiar a esta cuenta"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Lo lamentamos, se produjo un error…"
},
"unknownCollection": {
"message": "Colección sin nombre"
},
"unknownNetwork": {
"message": "Red privada desconocida"
},
@ -3874,10 +3948,6 @@
"message": "No se reconoce esta red personalizada. Antes de continuar, le recomendamos que $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Creación exitosa de la cartera"
},
"wantToAddThisNetwork": {
"message": "¿Desea añadir esta red?"
},
"warning": {
"message": "Advertencia"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Sí, intentémoslo"
},
"youHaveAddedAll": {
"message": "Ha agregado todas las redes populares. Puede descubrir más redes $1 o puede $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Necesita permitir el acceso a la cámara para usar esta función."
},

@ -1643,10 +1643,6 @@
"metametricsTitle": {
"message": "Únase a más de 6 millones de usuarios para mejorar MetaMask"
},
"mismatchedChain": {
"message": "Los detalles de la red de este ID de cadena no coinciden con nuestros registros. Antes de continuar, le recomendamos que $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3215,10 +3211,6 @@
"message": "No se reconoce esta red personalizada. Antes de continuar, le recomendamos que $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique los detalles de la red",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "El envío de tokens coleccionables (ERC-721) no se admite actualmente",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

File diff suppressed because it is too large Load Diff

@ -157,6 +157,9 @@
"addMemo": {
"message": "म"
},
"addMoreNetworks": {
"message": "मअल रप स अधिक नटवरक ज"
},
"addNetwork": {
"message": "नटवरक ज"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "चवनि"
},
"allOfYour": {
"message": "आपक सभ $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "इस बहर एकसटशन क इसक अनमति:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "खरच स अनित कर"
},
"approveAllTokensTitle": {
"message": "आपक सभ $1 क एकस करनिए अनमति",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "सि और इल कर"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "सत एसट"
},
"areYouDeveloper": {
"message": "क आप एक डवलपर ह?"
},
"areYouSure": {
"message": "क आप सिित ह?"
},
@ -435,10 +443,10 @@
"description": "$1 represents the crypto symbol to be purchased"
},
"buyWithWyre": {
"message": "Wyre क जरि $1 खर"
"message": "Wyre क $1 खर"
},
"buyWithWyreDescription": {
"message": "Wyre आपक अपन MetaMask ख $1 जम करनिए डिट कड क उपयग करनि"
"message": "$1000 तक क खरिए आसन ऑनबिग। तटरिव उचच स खरद सतपन। डिट / किट कड, ऐपपल प, बक टसफर क समरथन करत। 100+ द उपलबध ह। टकन आपकक ख जम"
},
"bytes": {
"message": "बइट"
@ -466,6 +474,13 @@
"message": "किनदन क $1 करनिए गस शक म कम स कम 10% कििए ति उसटवरक दयतिल सक।",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "~$1 मप रदद कर",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "मत मप रदद कर"
},
"cancellationGasFee": {
"message": "रदकरण गस शक"
},
@ -650,7 +665,7 @@
"message": "अनध इटरशन"
},
"convertTokenToNFTDescription": {
"message": "हमनि एसट एक एनएफट। MetaMask कस अब एनएफटिए पण सय सप। क आप इस अपनकन स हटहत और इस एनएफटप महत?"
"message": "हमनिह सपति एक एनएफट। मक कस अब एनएफटिए पण द समरथन। क आप इस अपनकन स हटहत और इस एनएफटप महत?"
},
"convertTokenToNFTExistDescription": {
"message": "हमनि इस एसट क एक एनएफटप म गय। क आप इस अपनकन स हटहत?"
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "फशन: अनित कर"
},
"functionSetApprovalForAll": {
"message": "कय: सभिए सिट कर"
},
"functionType": {
"message": "फशन करकर"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "अमय गत रिकवरज"
},
"invalidSeedPhraseCaseSensitive": {
"message": "अमय निश! गत पनरिश कस स।"
},
"ipfsGateway": {
"message": "IPFS गटव"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "MetaMask कहतर बनिए 6M+ उपयगकर"
},
"mismatchedChain": {
"message": "इस चन ID किए नटवरक विवरण हमिड सल नह। हम अन करति आप आग बढ पहल $1।",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "नटवरक विवरण सतित कर",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "हम सििश करति आग बढ पहल आप $1 कर।",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "हमिड क अनर, नटवरक कम इस चन आईडक सल नह सकत।"
},
"mismatchedNetworkSymbol": {
"message": "सबमिट कि गयत इस चन आईडिए हम अपल नह।"
},
"mismatchedRpcUrl": {
"message": "हमिड क अनर, सबमिट कि गय RPC URL मन इस चन आईडित पइडर सल नह।"
},
"missingNFT": {
"message": "अपन NFT नहख रह?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "नटवरक:"
},
"networkAddedSuccessfully": {
"message": "नटवरक सफलतवक ज गय!"
},
"networkDetails": {
"message": "नटवरक विवरण"
},
@ -2063,6 +2096,9 @@
"message": "नस $1 कए गए नस स अधिक ह",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "एनएफट"
},
"nftTokenIdPlaceholder": {
"message": "सरहणय ID दरज कर"
},
@ -2158,11 +2194,21 @@
"message": "डक मड सकषम कर"
},
"notifications12Description": {
"message": "नए उपयगकरिए उनकिटम पथमिकत आधर पर डक मड सकषम किएग। म उपयगकरिए, सिग->एकसपिटल कअल रप सक मड सकषम कर।"
"message": "एकसटशन पर डक मड आखिरकर आ गय! इस करनिए, सिग -> पिक पर ज और परदरशन विकल एक क चयन कर: लइट, डक, सिटम।"
},
"notifications12Title": {
"message": "वन डक मड? अब डक मड! 🕶🦊"
},
"notifications13ActionText": {
"message": "कसटम नटवरक सि"
},
"notifications13Description": {
"message": "अब आप निनलिित लकपिय कसटम नटवरस आस सकत: आरिरम, एवलश, बिस सट चन, फटम, हमन, ऑपििम, पम एड पन! इस फचर क एनबल करनिए, सिस ->एकसपिटल पर ज और \"श कसटम नटवरक लिट\" ऑन कर!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "लकपिय नटवरस ज"
},
"notifications1Description": {
"message": "MetaMask Mobile उपयगकर अब अपनइल वट कदर टकन सप कर सकत। मइल ऐप पत करनिए QR कड कन कर और सप करन कर।",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2259,11 +2305,11 @@
"message": "सचन"
},
"notificationsInfos": {
"message": "$1 $2",
"message": "$1 $2 स",
"description": "$1 is the date at which the notification has been dispatched and $2 is the link to the snap that dispatched the notification."
},
"notificationsMarkAllAsRead": {
"message": "सभ पढ कर"
"message": "सभ पढिि कर"
},
"numberOfNewTokensDetected": {
"message": "इस ख $1 क नए टकन पए गए",
@ -2348,9 +2394,6 @@
"message": "अपनजर क WebHID कयम स कनट करनिए MetaMask कण सन म।",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "सस कड ज"
},
"optional": {
"message": "वकलिक"
},
@ -2650,7 +2693,7 @@
"message": "आग बढ पहलिित करि आप सहट रिकवर इसल कर रह। इस आप अनड नह कर प।"
},
"restartMetamask": {
"message": "क कनर कर"
"message": "MetaMask किर स कर"
},
"restore": {
"message": "पनरित कर"
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "सड फि"
},
"revokeAllTokensTitle": {
"message": "अपन सभ $1 क एकस करन अनमतििरसत कर?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "अनमतििरसत करन, निनलिित $1 अब आपक $2 क एकस नह कर सक",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rinkeby टट नटवरक"
},
@ -2856,12 +2907,23 @@
"message": "$1 भ रह",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "चवन: आप एक टकन अनध कजनिसक परिमसवरप धन कि सकत। $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "एडवस गपनयतिस निित कर"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask उतद क उपयि और सरक बढिए इन विवसनय तसर-पकष क उपयग करत।"
},
"setApprovalForAll": {
"message": "सभिए सिट कर"
},
"setApprovalForAllTitle": {
"message": "बिि खरच स $1 सत कर",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "सिग"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "गस मय और सिरण कजन और पि करनन पर दििए इसक चयन कर।"
},
"showCustomNetworkList": {
"message": "कसटम नटवरक कि"
},
"showCustomNetworkListDescription": {
"message": "नयटवरक ज समय पहल भरए विवरण वटवरििए इस।"
},
"showFiatConversionInTestnets": {
"message": "टट नटवरक पर रतरण दि"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "यि करनिए कि आप समझत, सभ पर सहिन लग।"
},
"snapInstallWarningKeyAccess": {
"message": "आप सप \"$1\" क महतवपण एकस परदन कर रह। यह अपरिवरतनय ह और आपक अकस और एसस पर \"$1\" किरण परदन करत। आग बढ पहलिित करि आप \"$1\" पर भर करत।",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "यप निनलिित अनमति अनध कर रह:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "कई सप तभ चल जब उस सकषम कि गय"
},
"someNetworksMayPoseSecurity": {
"message": "कछ नटवरक सरक और/यपनयतिम प कर सकत। नटवरक ज और उपयग करन पहलि समझ।"
},
"somethingWentWrong": {
"message": "ओह! कछ गलत ह गय।"
},
@ -3168,10 +3235,10 @@
"message": "सट लनदन अनपलबध ह पर भ आप अपनकनप कर सकत।"
},
"stxPendingPrivatelySubmittingSwap": {
"message": "आपकप निप स रह..."
"message": "आपकप निप स सबमिट कि रह..."
},
"stxPendingPubliclySubmittingSwap": {
"message": "आपकप सवजनिक रप स रह..."
"message": "आपकप सवजनिक रप स सबमिट कि रह..."
},
"stxSubDescription": {
"message": "* सट लनदन आपकनदन किर पर, अनक बर जम करनरयस कर। यदि सभरयस विफल ह, तनदन कवजनिक रप सरसित किएगि यह सिित ह सकि आपकप सफलतवक प।"
@ -3184,7 +3251,7 @@
"description": "$1 is a token symbol, e.g. ETH"
},
"stxSwapCompleteIn": {
"message": "स< म",
"message": "सष समय <",
"description": "'<' means 'less than', e.g. Swap will complete in < 2:59"
},
"stxTooltip": {
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "नटवरक सिच कर"
},
"switchToNetwork": {
"message": "$1 पर सिच कर",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "इस ख पर सिच कर"
},
@ -3809,7 +3880,7 @@
"description": "$1 is the wallet device name; $2 is a link to wallet connection guide"
},
"troubleStarting": {
"message": "क क करनिकत हई। यह तिक-रक कर ह सकत, इसलिए एकसटशन क नरभ करनरयस कर।"
"message": "MetaMask क करन परई। यह तिक-रक कर ह सकत, इसलिए एकसटशन क िर स करक।"
},
"troubleTokenBalances": {
"message": "हम आपककन कषरिड करन परई। आप उनख सकत ",
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "ओह! कछ गलत ह गय...."
},
"unknownCollection": {
"message": "अनम सरह"
},
"unknownNetwork": {
"message": "अजत निटवरक"
},
@ -3874,10 +3948,6 @@
"message": "यह कसटम नटवरक पहच नह गय। हम अन करति आप आग बढ पहल $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "नटवरक विवरण सतित कर",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "वरतमन मरहणय (ERC-721) टकन भजन समरित नह",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "वट किण सफल हआ"
},
"wantToAddThisNetwork": {
"message": "इस नटवरक कहत?"
},
"warning": {
"message": "चवन"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "ह, आइए आजम"
},
"youHaveAddedAll": {
"message": "आपन सभकपिय नटवरक जिए ह। आप अधिक नटवरक खज सकत $1 य आप $2 कर सकत",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "आपक इस सि उपयग करनिए कमर तक पहच क अनमति आवशयकत।"
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "Tambahkan memo"
},
"addMoreNetworks": {
"message": "tambahkan jaringan secara manual"
},
"addNetwork": {
"message": "Tambahkan Jaringan"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Peringatan"
},
"allOfYour": {
"message": "Seluruh $1 Anda",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Izinkan ekstensi eksternal ini untuk:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Setujui batas penggunaan"
},
"approveAllTokensTitle": {
"message": "Berikan izin untuk mengakses seluruh $1 Anda?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Setujui & Instal"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Aset yang disetujui"
},
"areYouDeveloper": {
"message": "Anda seorang pengembang?"
},
"areYouSure": {
"message": "Anda yakin?"
},
@ -438,7 +446,7 @@
"message": "Beli $1 dengan Wyre"
},
"buyWithWyreDescription": {
"message": "Wyre memungkinkan Anda menggunakan kartu debit untuk menyetorkan ETH langsung di akun MetaMask Anda."
"message": "Orientasi mudah untuk pembelian hingga $ 1000. Verifikasi pembelian limit tinggi interaktif yang cepat. Mendukung Kartu Debit/Kredit, Apple Pay, Transfer Bank. Tersedia di 100+ negara. Token disetor ke Akun MetaMask Anda"
},
"bytes": {
"message": "Byte"
@ -466,6 +474,13 @@
"message": "Untuk $1 suatu transaksi, biaya gas harus dinaikkan minimal 10% agar dapat dikenali oleh jaringan.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Batalkan swap untuk ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Batalkan swap gratis"
},
"cancellationGasFee": {
"message": "Biaya Pembatalan Gas"
},
@ -650,7 +665,7 @@
"message": "Interaksi Kontrak"
},
"convertTokenToNFTDescription": {
"message": "Kami mendeteksi bahwa aset ini merupakan NFT. Kini MetaMask memiliki dukungan asli penuh untuk NFT. Anda ingin menghapusnya dari daftar token dan menambahkannya sebagai NFT?"
"message": "Kami mendeteksi bahwa aset ini merupakan NFT. Kini MetaMask memiliki dukungan asli penuh untuk NFT. Ingin menghapusnya dari daftar token dan menambahkannya sebagai NFT?"
},
"convertTokenToNFTExistDescription": {
"message": "Kami mendeteksi bahwa aset ini telah ditambahkan sebagai NFT. Anda ingin menghapusnya dari daftar token?"
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Fungsi: Setujui"
},
"functionSetApprovalForAll": {
"message": "Fungsi: SetApprovalForAll"
},
"functionType": {
"message": "Jenis Fungsi"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Frasa Pemulihan Rahasia Tidak Valid"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Masukan tidak valid! Frasa Pemulihan Rahasia peka terhadap huruf besar/kecil."
},
"ipfsGateway": {
"message": "Gateway IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Bergabunglah bersama 6 Jt+ pengguna untuk meningkatkan MetaMask"
},
"mismatchedChain": {
"message": "Detail jaringan untuk ID rantai ini tidak cocok dengan catatan kami. Kami menyarankan agar Anda $1 sebelum melanjutkan.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "memverifikasi detail jaringan",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Kami menyarankan agar Anda $1 sebelum melanjutkan.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Menurut catatan kami, nama jaringan mungkin tidak sepenuhnya sesuai dengan ID rantai ini."
},
"mismatchedNetworkSymbol": {
"message": "Simbol mata uang yang dikirimkan tidak sesuai dengan yang kami harapkan untuk ID rantai ini."
},
"mismatchedRpcUrl": {
"message": "Menurut catatan kami, nilai URL RPC yang dikirimkan tidak sesuai dengan penyedia yang dikenal untuk ID rantai ini."
},
"missingNFT": {
"message": "Tidak melihat NFT Anda?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Jaringan:"
},
"networkAddedSuccessfully": {
"message": "Jaringan berhasil ditambahkan!"
},
"networkDetails": {
"message": "Detail Jaringan"
},
@ -2063,6 +2096,9 @@
"message": "Nonce lebih tinggi dari nonce $1 yang disarankan",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Masukkan ID koleksi"
},
@ -2158,11 +2194,21 @@
"message": "Aktifkan mode gelap"
},
"notifications12Description": {
"message": "Mode Gelap akan diaktifkan untuk pengguna baru tergantung preferensi sistem mereka. Untuk pengguna lama, aktifkan Mode Gelap secara manual di bawah Pengaturan -> Eksperimental."
"message": "Mode gelap pada Ekstensi akhirnya hadir! Untuk menyalakannya, buka Pengaturan -> Eksperimental dan pilih salah satu opsi tampilan: Terang, Gelap, Sistem."
},
"notifications12Title": {
"message": "Kapan mode gelap? Ini saatnya mode gelap! 🕶🦊"
},
"notifications13ActionText": {
"message": "Tampilkan daftar jaringan khusus"
},
"notifications13Description": {
"message": "Kini Anda dapat menambahkan jaringan khusus populer berikut dengan mudah: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm, dan Polygon! Untuk mengaktifkan fitur ini, buka Pengaturan -> Eksperimental dan aktifkan \"Tampilkan daftar jaringan khusus\"!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Tambahkan Jaringan Populer"
},
"notifications1Description": {
"message": "Pengguna MetaMask Mobile kini bisa menukar token di dalam dompet seluler mereka. Pindai kode QR untuk mendapatkan aplikasi seluler dan mulai menukar.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Buka MetaMask dalam layar penuh untuk menghubungkan ledger Anda melalui WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Periksa kode sumbernya"
},
"optional": {
"message": "Opsional"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Ungkap frasa seed"
},
"revokeAllTokensTitle": {
"message": "Cabut izin untuk mengakses seluruh $1 Anda?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "Dengan mencabut izin, $1 berikut tidak lagi dapat mengakses $2 Anda",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Jaringan Uji Rinkeby"
},
@ -2856,12 +2907,23 @@
"message": "Mengirim $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Peringatan: Anda akan mengirim kontrak token yang berpotensi mengakibatkan hilangnya dana. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Atur pengaturan privasi lanjutan"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask menggunakan layanan pihak ketiga tepercaya ini untuk meningkatkan kegunaan dan keamanan produk."
},
"setApprovalForAll": {
"message": "Atur Persetujuan untuk Semua"
},
"setApprovalForAllTitle": {
"message": "Setujui $1 tanpa batas penggunaan",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Pengaturan"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Pilih ini untuk menampilkan biaya gas dan kontrol batas secara langsung di layar kirim dan konfirmasi."
},
"showCustomNetworkList": {
"message": "Tampilkan Daftar Jaringan Khusus"
},
"showCustomNetworkListDescription": {
"message": "Pilih ini untuk menampilkan daftar jaringan dengan detail yang telah diisi saat menambahkan jaringan baru."
},
"showFiatConversionInTestnets": {
"message": "Tampilkan Konversi di Testnet"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Untuk mengonfirmasikan Anda sudah paham, centang semua."
},
"snapInstallWarningKeyAccess": {
"message": "Anda memberikan akses kunci ke snap \"$1\". Tindakan ini tidak dapat dibatalkan dan memberikan kendali \"$1\" atas akun dan aset Anda. Sebelum melanjutkan, pastikan \"$1\" aman.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Snap ini meminta izin berikut:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Snap hanya akan beroperasi jika diaktifkan"
},
"someNetworksMayPoseSecurity": {
"message": "Beberapa jaringan dapat menimbulkan risiko keamanan dan/atau privasi. Pahami risikonya sebelum menambahkan & menggunakan jaringan."
},
"somethingWentWrong": {
"message": "Ups! Ada yang salah."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Beralih Jaringan"
},
"switchToNetwork": {
"message": "Beralih ke $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Beralih ke akun ini"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Ups! Ada yang salah..."
},
"unknownCollection": {
"message": "Koleksi tanpa nama"
},
"unknownNetwork": {
"message": "Jaringan Privat Tidak Dikenal"
},
@ -3874,10 +3948,6 @@
"message": "Jaringan kustom ini tidak dikenali. Kami menyarankan agar Anda $1 sebelum melanjutkan",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "memverifikasi detail jaringan",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Tidak mendukung pengiriman token koleksi (ERC-721) untuk saat ini",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Dompet berhasil dibuat"
},
"wantToAddThisNetwork": {
"message": "Ingin menambahkan jaringan ini?"
},
"warning": {
"message": "Peringatan"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Ya, mari kita coba"
},
"youHaveAddedAll": {
"message": "Anda telah menambahkan semua jaringan populer. Anda dapat menemukan lebih banyak jaringan $1 atau dapat $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Anda harus mengizinkan akses kamera untuk menggunakan fitur ini."
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "メモを追加"
},
"addMoreNetworks": {
"message": "他のネットワークを手動で追加"
},
"addNetwork": {
"message": "ネットワークを追加"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "アラート"
},
"allOfYour": {
"message": "すべての $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "この外部拡張機能に次の操作を許可します"
},
@ -263,6 +270,10 @@
"approve": {
"message": "使用限度額の承認"
},
"approveAllTokensTitle": {
"message": "すべての $1 へのアクセスを許可しますか?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "承認してインストール"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "承認済みのアセット"
},
"areYouDeveloper": {
"message": "開発者の方ですか?"
},
"areYouSure": {
"message": "よろしいですか?"
},
@ -435,10 +443,10 @@
"description": "$1 represents the crypto symbol to be purchased"
},
"buyWithWyre": {
"message": "Wyreで $1 を購入"
"message": "Wyreで$1を購入"
},
"buyWithWyreDescription": {
"message": "Wyreを使用すると、デビット カードを使用して、$1 をMetaMaskアカウントに直接デポジットできます。"
"message": "簡単なオンボーディングプロセスで最高 $ 1000 購入可能。迅速かつインタラクティブな高限度額の購入検証。デビット・クレジットカード、Apple Pay、銀行送金に対応。100か国以上で利用可能。トークンは MetaMask アカウントに入金されます。"
},
"bytes": {
"message": "バイト"
@ -466,6 +474,13 @@
"message": "トランザクションを$1するには、ネットワークに認識されるようにガス代を 10% 以上増額する必要があります。",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "$1 以下でスワップをキャンセル",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "無料でスワップをキャンセル"
},
"cancellationGasFee": {
"message": "キャンセルのガス代"
},
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "機能: 承認"
},
"functionSetApprovalForAll": {
"message": "関数: SetApprovalForAll"
},
"functionType": {
"message": "機能の種類"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "無効なシークレットリカバリーフレーズ"
},
"invalidSeedPhraseCaseSensitive": {
"message": "入力値が無効です!秘密のリカバリーフレーズは大文字・小文字が区別されます。"
},
"ipfsGateway": {
"message": "IPFSゲートウェイ"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "6百万人以上のユーザーと共に、MetaMaskの改善にご協力ください"
},
"mismatchedChain": {
"message": "このチェーンIDのネットワーク詳細が、レコードと一致しません。続行する前に$1をお勧めします。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "ネットワークの詳細の確認",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "先に進む前に$1をお勧めします。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "弊社の記録によると、ネットワーク名がこのチェーン ID と正しく一致していない可能性があります。"
},
"mismatchedNetworkSymbol": {
"message": "送信された通貨記号がこのチェーン ID に関して予想されるものと一致していません。"
},
"mismatchedRpcUrl": {
"message": "弊社の記録によると、送信された RPC URL の値がこのチェーン ID の既知のプロバイダーと一致しません。"
},
"missingNFT": {
"message": "NFTが見当たりませんか?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "ネットワーク:"
},
"networkAddedSuccessfully": {
"message": "ネットワークが追加されました!"
},
"networkDetails": {
"message": "ネットワークの詳細"
},
@ -2063,6 +2096,9 @@
"message": "ナンスが提案され$1よりも大きいです",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "コレクティブルIDを入力してください"
},
@ -2158,11 +2194,21 @@
"message": "ダークモードを有効にする"
},
"notifications12Description": {
"message": "新規ユーザーの場合、システム設定に従ってダークモードが有効になります。既存のユーザーは、設定 -> 実験的機能で、ダークモードを手動で有効にできます。"
"message": "拡張機能のダークモードがついに追加されました!オンにするには、設定 - 実験的機能の順に移動し、ライト、ダーク、システムの表示オプションから一つを選択してください。"
},
"notifications12Title": {
"message": "いつダークモードに?今ダークモードです!🕶🦊"
},
"notifications13ActionText": {
"message": "カスタムネットワークリストを表示"
},
"notifications13Description": {
"message": "人気のカスタムネットワーク(Arbitrum、Avalanche、Binance Smart Chain、Fantom、Harmony、Optimism、Palm、Polygon)が簡単に追加できるようになりました!この機能を有効にするには、設定 -> 実験的機能に移動し、「カスタムネットワークリストを表示」をオンにしてください!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "人気のネットワークを追加"
},
"notifications1Description": {
"message": "MetaMask Mobileのユーザーが、モバイルウォレット内でトークンを交換できるようになりました。QRコードをスキャンしてモバイルアプリを取得し、スワップを開始します。",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "WebHIDでLedgerを接続するには、MetaMaskを全画面モードで開いてください。",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "ソースコードを確認"
},
"optional": {
"message": "任意"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "シードフレーズを表示"
},
"revokeAllTokensTitle": {
"message": "すべての $1 へのアクセス許可を取り消しますか?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "アクセス許可を取り消すと、次の $1 が今後 $2 にアクセスできなくなります",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rinkebyテストネットワーク"
},
@ -2856,12 +2907,23 @@
"message": "$1を送信中",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "警告: 資金の喪失に繋がる可能性のあるトークンコントラクトに送信しようとしています。$1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "高度なプライバシー設定を設定"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMaskはこれらの信頼できるサードパーティーサービスを使用して、製品の使いやすさと安全性を向上させています。"
},
"setApprovalForAll": {
"message": "すべてを承認に設定"
},
"setApprovalForAllTitle": {
"message": "使用限度額なしで $1 を承認",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "設定"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "これを選択すると、ガス代と限度額のコントロールが送金画面と確認画面に直接表示されます。"
},
"showCustomNetworkList": {
"message": "カスタムネットワークリストを表示"
},
"showCustomNetworkListDescription": {
"message": "新規ネットワークの追加時に事前に情報が入力済みのネットワークのリストを表示するには、これを選択します。"
},
"showFiatConversionInTestnets": {
"message": "テストネット上に変換を表示"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "理解したことを確認するために、すべての項目にチェックを入れてください。"
},
"snapInstallWarningKeyAccess": {
"message": "スナップ「$1」に重要なアクセス権を付与しようとしています。これは取り消し不可能で、「$1」によるアカウントとアセットのコントロールが可能になります。続行する前に、「$1」が信頼できることを確認してください。",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "このスナップが次のパーミッションをリクエストしています:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "スナップは有効になっている場合にのみ実行されます"
},
"someNetworksMayPoseSecurity": {
"message": "ネットワークによっては、セキュリティやプライバシーの面でリスクが伴う可能性があります。ネットワークを追加・使用する前にリスクを理解するようにしてください。"
},
"somethingWentWrong": {
"message": "申し訳ありません。問題が発生しました。"
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "ネットワークを切り替える"
},
"switchToNetwork": {
"message": "$1 に切り替える",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "このアカウントに切り替える"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "申し訳ありません。問題が発生しました..."
},
"unknownCollection": {
"message": "無名のコレクション"
},
"unknownNetwork": {
"message": "不明なプライベートネットワーク"
},
@ -3874,10 +3948,6 @@
"message": "このカスタムネットワークは認識されません。続行する前に$1をお勧めします",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "ネットワークの詳細の確認",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "コレクティブル (ERC-721) トークンの送信は現在サポートされていません",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3970,7 +4040,7 @@
"description": "$1 is the action type. e.g (Account, Transaction, Swap)"
},
"visitWebSite": {
"message": "弊社Webサイトにアクセス"
"message": "弊社 Web サイトにアクセス"
},
"walletConnectionGuide": {
"message": "弊社のハードウェアウォレット接続ガイド"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "ウォレットが作成されました"
},
"wantToAddThisNetwork": {
"message": "このネットワークを追加しますか?"
},
"warning": {
"message": "警告"
},
@ -4057,11 +4130,15 @@
"yesLetsTry": {
"message": "はい、やってみます"
},
"youHaveAddedAll": {
"message": "すべての人気ネットワークを追加しました。$1で他のネットワークを発見するか、$2できます。",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "この機能を使用するには、カメラへのアクセスを許可する必要があります。"
},
"youSign": {
"message": "名しています"
"message": "名しています"
},
"yourPrivateSeedPhrase": {
"message": "秘密のシークレットリカバリーフレーズ"

@ -157,6 +157,9 @@
"addMemo": {
"message": "메모 추가"
},
"addMoreNetworks": {
"message": "네트워크 직접 추가"
},
"addNetwork": {
"message": "네트워크 추가"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "경고"
},
"allOfYour": {
"message": "내 $1 모두",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "이 외부 확장을 통해 다음을 허용:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "지출 한도 승인"
},
"approveAllTokensTitle": {
"message": "내 모든 $1에 액세스할 수 있는 권한을 부여할까요?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "승인 및 설치"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "승인된 자산"
},
"areYouDeveloper": {
"message": "개발자이신가요?"
},
"areYouSure": {
"message": "확실한가요?"
},
@ -438,7 +446,7 @@
"message": "Wyre로 $1 구매"
},
"buyWithWyreDescription": {
"message": "Wyre를 사용하면 체크카드를 이용하여 $1 를 MetaMask 계정에 바로 예치할 수 있습니다."
"message": "최대 $ 1000 구매까지 간편한 온보딩. 신속한 대화형 상한 구매 확인. 직불/신용 카드, Apple Pay, 은행 송금 지원. 100여국 이상에서 사용 가능. MetaMask 계정으로 토큰 입금"
},
"bytes": {
"message": "바이트"
@ -466,6 +474,13 @@
"message": "거래를 $1하려면 가스비를 최소 10%를 인상해야 네트워크에서 인식될 수 있습니다.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "~$1 비용으로 스왑 취소",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "무료로 스왑 취소"
},
"cancellationGasFee": {
"message": "가스 수수료 취소"
},
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "기능: 승인"
},
"functionSetApprovalForAll": {
"message": "기능: 모두승인설정"
},
"functionType": {
"message": "기능 유형"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "잘못된 비밀 복구 구문"
},
"invalidSeedPhraseCaseSensitive": {
"message": "입력 오류! 비밀 복구 구문은 대소문자를 구분해야 합니다."
},
"ipfsGateway": {
"message": "IPFS 게이트웨이"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "6백만 명 이상의 사용자와 함께 MetaMask 기능 향상에 동참하세요."
},
"mismatchedChain": {
"message": "이 체인 ID의 네트워크 세부 정보가 기록과 일치하지 않습니다. 진행하기 전에 $1을(를) 권장합니다.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "네트워크 세부 정보 검증",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "계속 진행하기 전에 $1 확인을 권합니다.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "기록에 따르면 네트워크 이름이 이 체인 ID와 일치하지 않는 것 같습니다."
},
"mismatchedNetworkSymbol": {
"message": "제출하신 환율 기호가 이 체인 ID의 환율과 일치하지 않습니다."
},
"mismatchedRpcUrl": {
"message": "기록에 따르면 제출하신 RPC URL 값이 이 체인 ID에 대해 알려진 공급업체와 일치하지 않습니다."
},
"missingNFT": {
"message": "NFT가 보이지 않나요?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "네트워크:"
},
"networkAddedSuccessfully": {
"message": "성공적으로 네트워크를 추가했습니다!"
},
"networkDetails": {
"message": "네트워크 세부 정보"
},
@ -2063,6 +2096,9 @@
"message": "임시값이 권장 임시값인 $1보다 큽니다.",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT\n"
},
"nftTokenIdPlaceholder": {
"message": "수집 가능한 ID를 입력하세요."
},
@ -2158,11 +2194,21 @@
"message": "다크모드 활성화"
},
"notifications12Description": {
"message": "신규 사용자의 경우 시스템 설정에 따라 다크모드가 활성화됩니다. 기존의 사용자는 설정 -> 실험에서 직접 다크 모드를 활성화해야 합니다."
"message": "다크모드가 마침내 활성화되었습니다! 설정(Settings) -> 시험 기능(Experimental)으로 이동하여 라이트, 다크, 시스템 중 선택하세요."
},
"notifications12Title": {
"message": "다크모드를 원하세요? 이제 다크모드를 사용하세요! 🕶🦊"
},
"notifications13ActionText": {
"message": "사용자 정의 네트워크 목록 보기"
},
"notifications13Description": {
"message": "이제 Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm 및 Polygon과 같은 인기 있는 사용자 정의 네트워크를 쉽게 추가할 수 있습니다! 이 기능을 활성화하려면 설정 -> 실험으로 이동하여 \"사용자 지정 네트워크 목록 표시\"를 켜세요!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "인기 네트워크 추가"
},
"notifications1Description": {
"message": "MetaMask 모바일 사용자는 이제 모바일 지갑에서 토큰을 스왑할 수 있습니다. QR 코드를 스캔하여 모바일 앱을 설치하고 스왑을 시작하세요.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "전체 화면에서 MetaMask를 열어 WebHID를 통해 Ledger를 연결합니다.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "소스 코드를 확인하세요"
},
"optional": {
"message": "옵션"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "시드 구문 보기"
},
"revokeAllTokensTitle": {
"message": "내 모든 $1에 액세스할 수 있는 권한을 취소할까요?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "권한을 취소하면 다음 $1의 $2 권한은 더 이상 유효하지 않습니다",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rinkeby 테스트 네트워크"
},
@ -2856,12 +2907,23 @@
"message": "$1 보내기",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "경고: 토큰 주소를 전송하면 토큰이 손실될 수 있습니다. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "개인정보 설정 고급 지정"
},
"setAdvancedPrivacySettingsDetails": {
"message": "이와 같이 MetaMask는 신용있는 타사의 서비스를 사용하여 제품 가용성과 안전성을 향상합니다."
},
"setApprovalForAll": {
"message": "모두 승인 설정"
},
"setApprovalForAllTitle": {
"message": "$1 무제한 지출 승인",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "설정"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "이 항목을 선택하면 보내기 및 확인 화면에서 바로 가스 가격과 한도 조절을 확인할 수 있습니다."
},
"showCustomNetworkList": {
"message": "사용자 정의 네트워크 보기"
},
"showCustomNetworkListDescription": {
"message": "이를 선택하면 새로 네트워크를 추가할 때 네트워크 목록에 상세 설명이 함께 나타납니다."
},
"showFiatConversionInTestnets": {
"message": "테스트넷에 전환 표시"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "이해하셨으면 모두 체크해 주세요."
},
"snapInstallWarningKeyAccess": {
"message": "'$1' 스냅 이용에 필요한 키 액세스 권한을 부여하고 있습니다. 이 작업은 사용자의 계정과 자산에 '$1' 제어 권한을 부여하며 취소가 불가능합니다. '$1의 신뢰성을 확인한 후에 진행하세요.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "이 스냅이 다음 권한을 요청하고 있습니다."
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "스냅은 활성화된 상태에서만 작동합니다."
},
"someNetworksMayPoseSecurity": {
"message": "네트워크에 따라 보안이나 개인 정보 유출의 위험이 있을 수 있습니다. 네트워크 추가 및 사용 이전에 위험 요소를 파악하세요."
},
"somethingWentWrong": {
"message": "죄송합니다! 문제가 생겼습니다."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "네트워크 전환"
},
"switchToNetwork": {
"message": "$1 네트워크로 전환",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "이 계정으로 전환"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "죄송합니다! 문제가 생겼습니다...."
},
"unknownCollection": {
"message": "제목 미지정 콜렉션"
},
"unknownNetwork": {
"message": "알 수 없는 비공개 네트워크"
},
@ -3874,10 +3948,6 @@
"message": "이 맞춤형 네트워크는 인식되지 않습니다. 진행하기 전에 $1을(를) 권장합니다.",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "네트워크 세부 정보 검증",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "수집 가능한(ERC-721) 토큰 전송은 현재 지원되지 않습니다.",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3970,7 +4040,7 @@
"description": "$1 is the action type. e.g (Account, Transaction, Swap)"
},
"visitWebSite": {
"message": "당사 웹사이트 방문하기"
"message": "웹사이트를 방문하세요"
},
"walletConnectionGuide": {
"message": "당사의 하드웨어 지갑 연결 가이드"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "지갑 생성 성공"
},
"wantToAddThisNetwork": {
"message": "이 네트워크를 추가할까요?"
},
"warning": {
"message": "경고"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "예, 시도하겠습니다."
},
"youHaveAddedAll": {
"message": "모든 인기 네트워크를 추가했습니다. $1에서 더 많은 네트워크를 확인하거나 $2 할 수 있습니다.",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "이 기능을 사용하려면 카메라 액세스를 허용해야 합니다."
},

@ -1039,10 +1039,6 @@
"metametricsOptInDescription": {
"message": "Gustong kunin ng MetaMask ang data ng paggamit para mas maunawaan kung paano ginagamit ng mga user namin ang extension. Gagamitin ang data na ito para patuloy na mapahusay ang kakayahang magamit at karanasan ng user sa paggamit ng produkto namin at Ethereum ecosystem."
},
"mismatchedChain": {
"message": "Ang mga detalye ng network para sa chain ID na ito ay hindi tumutugma sa aming mga record. Inirerekomenda naming $1 ka bago magpatuloy.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -2161,10 +2157,6 @@
"message": "Hindi kinikilala ang custom na network na ito. Inirerekomenda naming $1 ka bago magpatuloy",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"updatedWithDate": {
"message": "Na-update noong $1"
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "Adicionar observação"
},
"addMoreNetworks": {
"message": "adicionar mais redes manualmente"
},
"addNetwork": {
"message": "Adicionar rede"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Alertas"
},
"allOfYour": {
"message": "Todos os seus $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Permitir que essa extensão externa:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Aprovar"
},
"approveAllTokensTitle": {
"message": "Dar permissão para acessar todos os seus $1?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Aprovar e instalar"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Ativo aprovado"
},
"areYouDeveloper": {
"message": "Você é desenvolvedor?"
},
"areYouSure": {
"message": "Tem certeza?"
},
@ -435,10 +443,10 @@
"description": "$1 represents the crypto symbol to be purchased"
},
"buyWithWyre": {
"message": "Comprar $1 com Wyre"
"message": "Comprar $1 com o Wyre"
},
"buyWithWyreDescription": {
"message": "Com o Wyre, você pode usar um cartão de débito para depositar $1 diretamente na sua conta da MetaMask."
"message": "Integração fácil para compras de até US$ 1.000. Verificação de compra de alto limite rápida e interativa. Aceita cartão de crédito/débito, Apple Pay, transferências bancárias. Disponível em mais de 100 países. Depósito de tokens em sua conta na MetaMask"
},
"bytes": {
"message": "Bytes"
@ -466,6 +474,13 @@
"message": "Para $1 uma transação, a taxa de gás deve ser aumentada em pelo menos 10% para que seja reconhecida pela rede.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Cancelar swap por ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Cancelar swap gratuitamente"
},
"cancellationGasFee": {
"message": "Taxa de gás por cancelamento"
},
@ -650,7 +665,7 @@
"message": "Interação com contrato"
},
"convertTokenToNFTDescription": {
"message": "Detectamos que esse ativo é um NFT. A MetaMask agora oferece suporte nativo a NFTs. Gostaria de removê-lo da sua lista de tokens e adicioná-lo como NFT?"
"message": "Detectamos que esse ativo é um NFT. A MetaMask agora oferece suporte nativo a NFTs. Gostaria de removê-lo de sua lista de tokens e adicioná-lo como NFT?"
},
"convertTokenToNFTExistDescription": {
"message": "Detectamos que esse ativo foi adicionado como NFT. Deseja removê-lo da sua lista de tokens?"
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Função: aprovar"
},
"functionSetApprovalForAll": {
"message": "Função: SetApprovalForAll"
},
"functionType": {
"message": "Tipo de função"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Frase Secreta de Recuperação inválida"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Entrada inválida! A frase secreta de recuperação diferencia maiúsculas e minúsculas."
},
"ipfsGateway": {
"message": "Gateway IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Junte-se a mais de 6 milhões de usuários para melhorar a MetaMask"
},
"mismatchedChain": {
"message": "Os detalhes da rede para esse ID da cadeia não correspondem aos dos nossos registros. Recomendamos que você $1 antes de continuar.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Recomendamos que você $1 antes de prosseguir.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "De acordo com os nossos registros, o nome da rede pode não corresponder à ID desta cadeia."
},
"mismatchedNetworkSymbol": {
"message": "O símbolo de moeda enviado não corresponde ao esperado para a ID desta cadeia."
},
"mismatchedRpcUrl": {
"message": "De acordo com os nossos registros, o valor da URL da RPC enviado não corresponde a um provedor conhecido da ID desta cadeia."
},
"missingNFT": {
"message": "Não está vendo o seu NFT?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Ethereum:"
},
"networkAddedSuccessfully": {
"message": "Rede adicionada com sucesso!"
},
"networkDetails": {
"message": "Detalhes da rede"
},
@ -2063,6 +2096,9 @@
"message": "Nonce é maior que o nonce sugerido de $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Insira o ID do token"
},
@ -2158,11 +2194,21 @@
"message": "Ativar o modo escuro"
},
"notifications12Description": {
"message": "O Modo Escuro será ativado para novos usuários de acordo com suas preferências de sistema. Para usuários antigos, ative o Modo Escuro manualmente em Configurações -> Experimental."
"message": "O modo escuro na extensão finalmente chegou! Para ativá-lo, acesse Configurações -> Experimental e selecione uma das opções de exibição: claro, escuro, sistema."
},
"notifications12Title": {
"message": "Modo escuro quando? Modo escuro agora! 🕶🦊"
},
"notifications13ActionText": {
"message": "Exibir lista de redes personalizadas"
},
"notifications13Description": {
"message": "Agora você pode adicionar facilmente as seguintes redes personalizadas que são populares: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm e Polygon. Para ativar esse recurso, acesse Configurações -> Experimentais e ative \"Exibir lista de redes personalizadas\".",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Adicionar redes populares"
},
"notifications1Description": {
"message": "Usuários da MetaMask Mobile agora podem trocar tokens dentro de sua carteira mobile. Leia o QR code para obter o aplicativo para dispositivos móveis e comece a trocar.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Abra a MetaMask em tela cheia para conectar sua ledger por meio do WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Verifique o código-fonte"
},
"optional": {
"message": "Opcional"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Revelar a frase de recuperação"
},
"revokeAllTokensTitle": {
"message": "Revogar permissão de acesso a todos os seus $1?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "Ao revogar a permissão, o $1 a seguir não terá mais acesso ao seu $2",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rede de Teste Rinkeby"
},
@ -2856,12 +2907,23 @@
"message": "Enviando $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Aviso: você está prestes a enviar a um contrato de token que pode resultar em perda de fundos. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Definir configurações avançadas de privacidade"
},
"setAdvancedPrivacySettingsDetails": {
"message": "A MetaMask utiliza esses serviços terceirizados de confiança para aumentar a usabilidade e a segurança dos produtos."
},
"setApprovalForAll": {
"message": "Definir aprovação para todos"
},
"setApprovalForAllTitle": {
"message": "Aprovar $1 sem limite de gastos",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Definições"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Selecione isso para mostrar o preço do gás e limitar os controles diretamente nas telas de envio e de confirmação."
},
"showCustomNetworkList": {
"message": "Exibir lista de redes personalizadas"
},
"showCustomNetworkListDescription": {
"message": "Selecione esta opção para exibir uma lista de redes com as informações pré-preenchidas ao adicionar uma nova rede."
},
"showFiatConversionInTestnets": {
"message": "Mostrar conversão nas redes de teste"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Para confirmar que você entende, marque todas."
},
"snapInstallWarningKeyAccess": {
"message": "Você está concedendo ao snap \"$1\" acesso à sua chave. Isso é irrevogável e concede a \"$1\" controle sobre suas contas e ativos. Certifique-se de que confia em \"$1\" antes de prosseguir.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Esse snap está solicitando as seguintes permissões:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "O snap só será executado se estiver ativado"
},
"someNetworksMayPoseSecurity": {
"message": "Algumas redes podem representar riscos de segurança e/ou privacidade. Tenha os riscos em mente antes de adicionar e usar uma rede."
},
"somethingWentWrong": {
"message": "Ops! Algo deu errado."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Trocar redes"
},
"switchToNetwork": {
"message": "Trocar para $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Trocar para esta conta"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Ops! Algo deu errado...."
},
"unknownCollection": {
"message": "Coleção sem nome"
},
"unknownNetwork": {
"message": "Rede Privada Desconhecida"
},
@ -3874,10 +3948,6 @@
"message": "Essa rede personalizada não foi reconhecida. Recomendamos que você $1 antes de continuar",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3970,7 +4040,7 @@
"description": "$1 is the action type. e.g (Account, Transaction, Swap)"
},
"visitWebSite": {
"message": "Visite o nosso site"
"message": "Visite nosso site"
},
"walletConnectionGuide": {
"message": "nosso guia de conexão com a carteira de hardware"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Carteira criada com sucesso"
},
"wantToAddThisNetwork": {
"message": "Desejar adicionar esta rede?"
},
"warning": {
"message": "Atenção"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Sim, vamos tentar"
},
"youHaveAddedAll": {
"message": "Você adicionou todas as redes populares. Você pode descobrir mais redes $1 Ou você pode $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Você precisa permitir o acesso à câmera para usar esse recurso."
},

@ -1627,10 +1627,6 @@
"metametricsTitle": {
"message": "Junte-se a mais de 6 milhões de usuários para melhorar a MetaMask"
},
"mismatchedChain": {
"message": "Os detalhes da rede para esse ID da cadeia não correspondem aos dos nossos registros. Recomendamos que você $1 antes de continuar.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3199,10 +3195,6 @@
"message": "Essa rede personalizada não foi reconhecida. Recomendamos que você $1 antes de continuar",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "verifique os detalhes da rede",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "O envio de tokens colecionáveis (ERC-721) não é suportado no momento",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -157,6 +157,9 @@
"addMemo": {
"message": "Добавить примечание"
},
"addMoreNetworks": {
"message": "добавить другие сети вручную"
},
"addNetwork": {
"message": "Добавить сеть"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Предупреждения"
},
"allOfYour": {
"message": "Все ваши $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Разрешить этому внешнему расширению:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Одобрить лимит расходов"
},
"approveAllTokensTitle": {
"message": "Разрешить доступ к всем вашим $1?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Одобрить и установить"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Одобренный актив"
},
"areYouDeveloper": {
"message": "Вы разработчик?"
},
"areYouSure": {
"message": "Вы уверены?"
},
@ -435,10 +443,10 @@
"description": "$1 represents the crypto symbol to be purchased"
},
"buyWithWyre": {
"message": "Купить $1 с помощью Wyre"
"message": "Купить 1 $ с помощью Wyre"
},
"buyWithWyreDescription": {
"message": "Wyre позволяет использовать дебетовую карту для внесения $1 прямо на ваш счет MetaMask."
"message": "Простая регистрация для покупок на сумму до 1000 $. Быстрая интерактивная проверка покупки с высоким лимитом. Поддерживает дебетовые/кредитные карты, Apple Pay, банковские переводы. Доступно в более чем 100 странах. Токены зачисляются на ваш счет MetaMask"
},
"bytes": {
"message": "Байты"
@ -466,6 +474,13 @@
"message": "Чтобы $1 транзакции плата за газ должна быть увеличена как минимум на 10%. Это позволит обеспечить прием транзакции сетью.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Отменить обмен на ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Отменить обмен бесплатно"
},
"cancellationGasFee": {
"message": "Плата за газ при отмене"
},
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Функция: Одобрить"
},
"functionSetApprovalForAll": {
"message": "Функция: SetApprovalForAll"
},
"functionType": {
"message": "Тип функции"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Неверная секретная фраза для восстановления"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Неправильный ввод! Секретная фраза для восстановления чувствительна к регистру."
},
"ipfsGateway": {
"message": "Шлюз IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Присоединяйтесь к более чем 6 млн пользователей, чтобы улучшить MetaMask"
},
"mismatchedChain": {
"message": "Сведения о сети для этого ID цепочки не совпадают с указанными в записях. Мы рекомендуем $1 до того, как продолжить.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "проверить сведения о сети",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Мы рекомендуем вам $1, прежде чем продолжить.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Согласно нашим данным, имя сети может не соответствовать этому идентификатору блокчейна."
},
"mismatchedNetworkSymbol": {
"message": "Представленный символ валюты не соответствует тому, что мы ожидаем для этого идентификатора блокчейна."
},
"mismatchedRpcUrl": {
"message": "Согласно нашим записям, отправленное значение URL-адреса RPC не соответствует известному поставщику для этого идентификатора блокчейна."
},
"missingNFT": {
"message": "Не видите свои NFT?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Сеть:"
},
"networkAddedSuccessfully": {
"message": "Сеть успешно добавлена!"
},
"networkDetails": {
"message": "Сведения о сети"
},
@ -2063,6 +2096,9 @@
"message": "Одноразовый номер больше, чем предложенный одноразовый номер $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Введите ид. коллекционного актива"
},
@ -2163,6 +2199,16 @@
"notifications12Title": {
"message": "Когда появится темный режим? Он уже появился! "
},
"notifications13ActionText": {
"message": "Показать пользовательский список сетей"
},
"notifications13Description": {
"message": "Теперь вы можете легко добавить следующие популярные пользовательские сети: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm и Polygon! Чтобы включить эту функцию, перейдите в «Настройки» -> «Экспериментальная версия» и включите «Показать пользовательский список сетей»!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Добавить популярные сети"
},
"notifications1Description": {
"message": "Теперь пользователи MetaMask Mobile могут обменивать токены в своем мобильном кошельке. Отсканируйте QR-код, чтобы скачать мобильное приложение и начать обмен.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Откройте MetaMask в полноэкранном режиме, чтобы подключить свой леджер через WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Проверьте исходный код"
},
"optional": {
"message": "Необязательно"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Показать сид-фразу"
},
"revokeAllTokensTitle": {
"message": "Отозвать разрешение на доступ ко всем вашим $1?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "При отмене разрешения следующий $1 больше не сможет получить доступ к вашему $2",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Тестовая сеть Rinkeby"
},
@ -2856,12 +2907,23 @@
"message": "Отправка $1...",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Предупреждение: вы собираетесь отправить токен-контракт, что может привести к потере средств. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Задать дополнительные настройки конфиденциальности"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask использует эти доверенные сторонние сервисы для повышения удобства использования и безопасности продукта."
},
"setApprovalForAll": {
"message": "Установить одобрение для всех"
},
"setApprovalForAllTitle": {
"message": "Одобрить $1 без ограничений по расходам",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Настройки"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Выберите это, чтобы отображать цену газа и управление лимитами непосредственно на экранах отправки и подтверждения."
},
"showCustomNetworkList": {
"message": "Показать пользовательский список сетей"
},
"showCustomNetworkListDescription": {
"message": "Выберите это, чтобы отобразить список сетей с предварительно заполненными данными при добавлении новой сети."
},
"showFiatConversionInTestnets": {
"message": "Показывать конвертацию в тестовых сетях"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Чтобы подтвердить, что вы понимаете, отметьте все."
},
"snapInstallWarningKeyAccess": {
"message": "Вы предоставляете ключевой доступ к снапу «$1». Это действие является безотзывным и предоставляет «$1» контроль над вашими счетами и активами. Прежде чем продолжить, убедитесь, что вы доверяете «$1».",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Этот снап запрашивает следующие разрешения:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Снап будет работать только в том случае, если он включен"
},
"someNetworksMayPoseSecurity": {
"message": "Некоторые сети могут представлять угрозу безопасности и/или конфиденциальности. Прежде чем добавлять и использовать сеть, ознакомьтесь с рисками."
},
"somethingWentWrong": {
"message": "Ой! Что-то пошло не так."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Сменить сети"
},
"switchToNetwork": {
"message": "Переключиться на $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Переключиться на этот счет"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Ой! Что-то пошло не так...."
},
"unknownCollection": {
"message": "Безымянная коллекция"
},
"unknownNetwork": {
"message": "Неизвестная частная сеть"
},
@ -3874,10 +3948,6 @@
"message": "Эта пользовательская сеть не распознана. Мы рекомендуем $1, прежде чем продолжить",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "проверить сведения о сети",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Отправка коллекционных активов (ERC-721) сейчас не поддерживается",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Кошелек создан"
},
"wantToAddThisNetwork": {
"message": "Хотите добавить эту сеть?"
},
"warning": {
"message": "Предупреждение"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Да, давайте попробуем"
},
"youHaveAddedAll": {
"message": "Вы добавили все популярные сети. Вы можете открыть для себя больше сетей $1 или можете $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Для использования этой функции вам необходимо предоставить доступ к камере."
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "Magdagdag ng memo"
},
"addMoreNetworks": {
"message": "magdagdag pa ng mga network nang mano-mano"
},
"addNetwork": {
"message": "Magdagdag ng Network"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Mga Alerto"
},
"allOfYour": {
"message": "Lahat ng iyong $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Payagan ang external extension na ito na:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Aprubahan ang limitasyon sa paggastos"
},
"approveAllTokensTitle": {
"message": "Magbigay ng pahintulot na i-access ang lahat ng iyong $1?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Aprubahan at I-install"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Aprubadong asset"
},
"areYouDeveloper": {
"message": "Isa ka bang developer?"
},
"areYouSure": {
"message": "Sigurado ka ba?"
},
@ -466,6 +474,13 @@
"message": "Sa $1 na transaksyon ang singil sa gas ay dapat tumaas nang hindi bababa sa 10% para ito ay makilala ng network.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Kanselahin ang swap sa halagang ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Kanselahin ang swap nang libre"
},
"cancellationGasFee": {
"message": "Bayarin sa Gasolina para sa Pagkansela"
},
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Function: Aprubahan"
},
"functionSetApprovalForAll": {
"message": "Function: ItakdaAngPag-aprubaParaSaLahat"
},
"functionType": {
"message": "Uri ng Function"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Hindi valid ang Secret Recovery Phrase"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Di-wastong input! Ang Secret Recovery Phrase ay case sensitive."
},
"ipfsGateway": {
"message": "Gateway na IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Sumali sa 6M+ user upang mapabuti ang MetaMask"
},
"mismatchedChain": {
"message": "Ang mga detalye ng network para sa chain ID na ito ay hindi tumutugma sa aming mga talaan. Inirerekomenda namin na $1 ka bago magpatuloy.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Inirerekomenda namin na $1 ka bago magpatuloy.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Ayon sa aming talaan, ang pangalan ng network ay maaaring hindi tumugma nang tama sa chain ID na ito."
},
"mismatchedNetworkSymbol": {
"message": "Ang isinumiteng simbolo ng currency ay hindi tumutugma sa inaasahan namin para sa chain ID na ito."
},
"mismatchedRpcUrl": {
"message": "Ayon sa aming mga talaan, ang isinumiteng RPC URL value ay hindi tumutugma sa isang kilalang provider para sa chain ID na ito."
},
"missingNFT": {
"message": "Hindi makita ang NFT mo?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Network:"
},
"networkAddedSuccessfully": {
"message": "Matagumpay na naidagdag ang network!"
},
"networkDetails": {
"message": "Mga Detalye ng Network"
},
@ -2063,6 +2096,9 @@
"message": "Mas mataas ang noncesa iminumungkahing nonce na $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Ilagay ang collectible ID"
},
@ -2163,6 +2199,16 @@
"notifications12Title": {
"message": "Wen dark mode? Ngayon dark mode! 🕶🦊"
},
"notifications13ActionText": {
"message": "Ipakita ang listahan ng custom na network"
},
"notifications13Description": {
"message": "Madali mo na ngayong maidagdag ang mga sumusunod na sikat na custom na network: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm at Polygon! Para i-enable ang feature na ito, pumunta sa Mga Setting -> Experimental at i-on ang \"Ipakita ang listahan ng custom na network\"!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Magdagdag ng mga Sikat na Network"
},
"notifications1Description": {
"message": "Ang mga user ng MetaMask Mobile ay maaari na ngayong mag-swap ng mga token sa loob ng kanilang mobile wallet. I-scan ang QR code para makuha ang mobile app at magsimulang mag-swap.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Buksan ang MetaMask sa buong screen para ikonekta ang ledger mo sa pamamagitan ng WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Suriin ang code ng pinagmulan"
},
"optional": {
"message": "Opsyonal"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Ipakita ang seed phrase"
},
"revokeAllTokensTitle": {
"message": "Bawiin ang pahintulot na i-access ang lahat ng iyong $1?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "Sa pamamagitan ng pagbawi ng pahintulot, hindi na maa-access ng sumusunod na $1 ang iyong $2",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rinkeby Test Network"
},
@ -2856,12 +2907,23 @@
"message": "Nagpapadala ng $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Babala: magpapadala ka sa isang kontrata ng token na maaaring magresulta sa pagkawala ng mga pondo. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Magtakda ng advanced privacy settings"
},
"setAdvancedPrivacySettingsDetails": {
"message": "Ginagamit ng MetaMask ang mga pinagkakatiwalaang serbisyo ng third-party na ito para mapahusay ang kakayahang magamit at kaligtasan ng produkto."
},
"setApprovalForAll": {
"message": "Itakda ang Pag-apruba para sa Lahat"
},
"setApprovalForAllTitle": {
"message": "Aprubahan ang $1 nang walang limitasyon sa paggastos",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Mga Setting"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Piliin ito para direktang maipakita ang presyo ng gas at mga kontrol sa limitasyon sa mga screen ng pagpapadala at pagkumpirma."
},
"showCustomNetworkList": {
"message": "Ipakita ang Listahan ng Custom na Network"
},
"showCustomNetworkListDescription": {
"message": "Piliin ito para magpakita ng listahan ng mga network na may prefilled na mga detalye kapag nagdaragdag ng bagong network."
},
"showFiatConversionInTestnets": {
"message": "Ipakita ang Conversion sa Testnets"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Para kumpirmahing naunawaan mo, tsekan lahat."
},
"snapInstallWarningKeyAccess": {
"message": "Ipinagkakaloob mo ang key access sa snap \"$1\". Hindi ito maaaring bawiin at ipinagkakaloob sa \"$1\" ang kontrol sa iyong mga account at mga asset. Tiyaking pinagkakatiwalaan mo ang \"$1\" bago magpatuloy.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Hinihiling ng snap na ito ang mga sumusunod na pahintulot:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Tatakbo lamang ang snap kapag pinagana ito"
},
"someNetworksMayPoseSecurity": {
"message": "Maaaring magdulot ang ilang network ng mga panganib sa seguridad at/o pagkapribado. Unawain ang mga panganib bago idagdag o gamitin ang isang network."
},
"somethingWentWrong": {
"message": "Oops! Nagkaproblema."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Lumipat ng Network"
},
"switchToNetwork": {
"message": "Lumipat sa $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Lumipat sa account na ito"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Ooops! Nagkaproblema...."
},
"unknownCollection": {
"message": "Walang pangalang koleksyon"
},
"unknownNetwork": {
"message": "Hindi Alam na Pribadong Network"
},
@ -3874,10 +3948,6 @@
"message": "Hindi nakikilala ang custom network na ito. Nirerekomenda namin na ikaw ay $1 bago magpatuloy",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "i-verify ang mga detalye ng network",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Ang pagpapadala ng collectible (ERC-721) token ay kasalukuyang hindi magagamit",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Matagumpay ang paggawa ng wallet"
},
"wantToAddThisNetwork": {
"message": "Gusto mo bang idagdag ang network na ito?"
},
"warning": {
"message": "Babala"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Oo, subukan natin"
},
"youHaveAddedAll": {
"message": "Idinagdag mo ang lahat ng sikat na network. Maaari kang makatuklas ng higit pang mga network $1 O maaari kang",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Kailangan mong payagan ang pag-access sa camera para magamit ang feature na ito."
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "Not ekleyin"
},
"addMoreNetworks": {
"message": "manuel olarak daha fazla ağ ekleyin"
},
"addNetwork": {
"message": "Ağ ekle"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Uyarılar"
},
"allOfYour": {
"message": "Sahip olduğunuz tüm $1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Bu harici uzantının şunu yapmasına izin ver:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Harcama limitini onayla"
},
"approveAllTokensTitle": {
"message": "Sahip olduğunuz tüm $1 için erişim izni verilsin mi?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Onayla ve Yükle"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Onaylanan varlık"
},
"areYouDeveloper": {
"message": "Geliştirici misin?"
},
"areYouSure": {
"message": "Emin misin?"
},
@ -438,7 +446,7 @@
"message": "Wyre ile $1 satın al"
},
"buyWithWyreDescription": {
"message": "Wyre, doğrudan MetaMask hesabınıza $1 yatırma işlemleri için banka kartı kullanmanıza izin verir."
"message": "1000$'a kadar satın alma işlemlerinde kolay oryantasyon. Banka Kartı/Kredi Kartı, Apple Pay, Banka Transferlerini destekler. +100 ülkede kullanılabilir. Token'lar MetaMask Hesabına yatırılır"
},
"bytes": {
"message": "Bayt"
@ -466,6 +474,13 @@
"message": "İşlemi $1 için, gaz ücretinin ağ tarafından tanınması amacıyla en az %10 oranında artırılması gerekir.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "~$1 için swap işlemini iptal edin",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Swap işlemini ücretsiz iptal edin"
},
"cancellationGasFee": {
"message": "İptal İşlemi Gaz Ücreti"
},
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "İşlev: Onayla"
},
"functionSetApprovalForAll": {
"message": "İşlev: TümüİçinOnayVer"
},
"functionType": {
"message": "İşlev Türü"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Gizli Kurtarma İfadesi geçersiz"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Giriş geçersiz! Gizli Kurtarma İfadesi büyük/küçük harf duyarlıdır."
},
"ipfsGateway": {
"message": "IPFS Ağ Geçidi"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "MetaMask'i geliştirmek için 6 milyondan fazla kullanıcıya katılın"
},
"mismatchedChain": {
"message": "Bu zincir kimliği için ağ ayrıntıları kayıtlarımızla uyumlu değil. Devam etmeden önce şunu yapmanızı öneriyoruz: $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "ağ bilgilerini doğrula",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "İlerlemeden önce şunu öneririz: $1.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Kayıtlarımıza göre, ağ adı bu zincir kimliği ile doğru bir şekilde uyumlu olmayabilir."
},
"mismatchedNetworkSymbol": {
"message": "Sunulan para birimi sembolü bu zincir kimliği için beklediğimiz sembolle uyumlu değil."
},
"mismatchedRpcUrl": {
"message": "Kayıtlarımıza göre, sunulan RPC URL adresi değeri bu zincir kimliğinin bilinen bir sağlayıcısı ile uyumlu değil."
},
"missingNFT": {
"message": "NFT'nizi görmüyor musunuz?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Ağ:"
},
"networkAddedSuccessfully": {
"message": "Ağ başarılı bir şekilde eklendi!"
},
"networkDetails": {
"message": "Ağ Bilgileri"
},
@ -2063,6 +2096,9 @@
"message": "Geçici anahtar, önerilen $1 geçici anahtarından daha büyük",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Toplanabilir kimliğini girin"
},
@ -2158,11 +2194,21 @@
"message": "Karanlık modu etkinleştir"
},
"notifications12Description": {
"message": "Karanlık Mod, sistem tercihlerine bağlı olarak yeni kullanıcılar için etkinleştirilecektir. Mevcut kullanıcılar için, Ayarlar -> Deneysel altında Karanlık Modu manuel olarak etkinleştir."
"message": "Uzantıda karanlık mod sonunda burada! Bunu açmak için Ayarlar -> Deneysel kısmına git ve ekran seçeneklerinden birini seç: Aydınlık, Karanlık, Sistem."
},
"notifications12Title": {
"message": "Karanlık mod mu? Şimdi karanlık mod! 🕶🦊"
},
"notifications13ActionText": {
"message": "Özel ağ listesini göster"
},
"notifications13Description": {
"message": "Artık şu popüler özel ağları kolayca ekleyebilirsiniz: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm ve Polygon! Bu özelliği etkinleştirmek için Ayarlar -> Deneysel kısmına gidip \"Özel ağ listesini göster\" seçeneğini açın!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Popüler Ağları Ekle"
},
"notifications1Description": {
"message": "MetaMask Mobil kullanıcıları artık mobil cüzdanları içinde token takas edebilirler. Mobil uygulamayı edinmek ve takas yapmaya başlamak için QR kodunu tarayın.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Kayıt defterinizi WebHID üzerinden bağlamak için MetaMask'i tam ekran açın.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Kaynak kodunu kontrol et"
},
"optional": {
"message": "İsteğe bağlı"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Tohum ifadesini ortaya çıkar"
},
"revokeAllTokensTitle": {
"message": "Sahip olduğunuz tüm $1 için izin geri çekilsin mi?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "İzni geri çektiğinizde aşağıdaki $1 artık $2 alanınıza erişim sağlayamayacak",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rinkeby Test Ağı"
},
@ -2856,12 +2907,23 @@
"message": "$1 Gönderiliyor",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Uyarı: Para kaybı ile sonuçlanabilecek bir token sözleşmesi göndermek üzeresiniz. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Gelişmiş gizlilik ayarlarını yapın"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask, ürünün kullanılabilirliğini ve güvenliğini iyileştirmek amacıyla bu güvenilir üçüncü taraf hizmetlerini kullanır."
},
"setApprovalForAll": {
"message": "Tümüne Onay Ver"
},
"setApprovalForAllTitle": {
"message": "$1 için harcama limiti olmadan onay ver",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Ayarlar"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Gaz fiyatı ve limit kontrollerini doğrudan gönder ve onayla ekranlarında göstermek için bunu seçin."
},
"showCustomNetworkList": {
"message": "Özel Ağ Listesini Göster"
},
"showCustomNetworkListDescription": {
"message": "Yeni bir ağ eklerken önceden doldurulan bilgilerle ağ listesini görüntülenmesi için bunu seçin."
},
"showFiatConversionInTestnets": {
"message": "Test ağlarında Dönüşümü göster"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Anladığını doğrulamak için hepsini kontrol et."
},
"snapInstallWarningKeyAccess": {
"message": "\"$1\" snap'ine anahtar erişimi veriyorsun. Bu geri alınamaz ve hesapların ve varlıkların üzerinde \"1$\" kontrol sağlar. Devam etmeden önce \"$1\" öğesine güvendiğinden emin ol.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Bu ek, aşağıdaki izinleri istiyor:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Bir snap yalnızca etkinleştirilmişse çalışır"
},
"someNetworksMayPoseSecurity": {
"message": "Bazı ağlar güvenlik ve/veya gizlilik riskleri teşkil edebilir. Bir ağ eklemeden ve kullanmadan önce riskleri anlayın."
},
"somethingWentWrong": {
"message": "Eyvah! Bir şeyler ters gitti."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Ağları Değiştir"
},
"switchToNetwork": {
"message": "$1 ağına geçin",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Bu hesaba geç"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Eyvah! Bir şeyler ters gitti...."
},
"unknownCollection": {
"message": "İsimsiz koleksiyon"
},
"unknownNetwork": {
"message": "Bilinmeyen Özel Ağ"
},
@ -3874,10 +3948,6 @@
"message": "Bu özel ağ tanınmadı. Devam etmeden önce $1 öneririz",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "ağ bilgilerini doğrula",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Toplanabilir (ERC-721) tokenlerin gönderilmesi şu anda desteklenmiyor",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3970,7 +4040,7 @@
"description": "$1 is the action type. e.g (Account, Transaction, Swap)"
},
"visitWebSite": {
"message": "Web sitemizi ziyaret edin"
"message": "Web sitemizi ziyaret et"
},
"walletConnectionGuide": {
"message": "donanım cüzdanı bağlantı kılavuzumuz"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Cüzdan oluşturma başarılı"
},
"wantToAddThisNetwork": {
"message": "Bu ağı eklemek istiyor musunuz?"
},
"warning": {
"message": "Uyarı"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Evet, deneyelim"
},
"youHaveAddedAll": {
"message": "Tüm popüler ağları eklediniz. $1 daha fazla ağ gekşefedebilir veya $2 seçeneğini seçebilirsiniz",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Bu özelliği kullanmak için kamera erişimine izin vermeniz gerekir."
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "Thêm bản ghi nhớ"
},
"addMoreNetworks": {
"message": "thêm thủ công các mạng khác"
},
"addNetwork": {
"message": "Thêm mạng"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "Cảnh báo"
},
"allOfYour": {
"message": "Tất cả $1 của bạn",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "Cho phép tiện ích bên ngoài này:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "Phê duyệt giới hạn chi tiêu"
},
"approveAllTokensTitle": {
"message": "Cấp quyền truy cập vào tất cả $1 của bạn?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "Chấp nhận và cài đặt"
},
@ -282,9 +293,6 @@
"approvedAsset": {
"message": "Tài sản được chấp nhận"
},
"areYouDeveloper": {
"message": "Bạn có phải là lập trình viên không?"
},
"areYouSure": {
"message": "Bạn có chắc chắn không?"
},
@ -438,7 +446,7 @@
"message": "Mua $1 qua Wyre"
},
"buyWithWyreDescription": {
"message": "Wyre cho phép bạn dùng thẻ ghi nợ để nạp $1 trực tiếp vào tài khoản MetaMask của mình."
"message": "Dễ dàng tham gia đối với các giao dịch mua lên đến $1.000. Xác minh mua hàng giới hạn cao và tương tác nhanh. Hỗ trợ Thẻ Tín dụng/Ghi nợ, Apple Pay, Chuyển khoản Ngân hàng. Hiện có tại hơn 100 quốc gia. Nạp token vào Tài khoản MetaMask của bạn"
},
"bytes": {
"message": "Byte"
@ -466,6 +474,13 @@
"message": "Để $1 một giao dịch, phí gas phải tăng tối thiểu 10% để mạng nhận ra giao dịch này.",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "Hủy hoán đổi với giá ~$1",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "Hủy hoán đổi miễn phí"
},
"cancellationGasFee": {
"message": "Phí gas hủy"
},
@ -650,7 +665,7 @@
"message": "Tương tác với hợp đồng"
},
"convertTokenToNFTDescription": {
"message": "Chúng tôi phát hiện tài sản này là một NFT. MetaMask hiện đã hỗ trợ gốc đầy đủ cho NFT. Bạn có muốn xóa tài sản khỏi danh sách token và thêm tài sản dưới dạng NFT không?"
"message": "Chúng tôi phát hiện tài sản này là một NFT. MetaMask hiện đã hỗ trợ toàn diện và đầy đủ cho NFT. Bạn có muốn xóa tài sản khỏi danh sách token và thêm tài sản dưới dạng NFT không?"
},
"convertTokenToNFTExistDescription": {
"message": "Chúng tôi phát hiện tài sản này đã được thêm dưới dạng NFT. Bạn có muốn xóa tài sản khỏi danh sách token không?"
@ -1277,6 +1292,9 @@
"functionApprove": {
"message": "Chức năng: Phê duyệt"
},
"functionSetApprovalForAll": {
"message": "Chức năng: SetApprovalForAll"
},
"functionType": {
"message": "Loại chức năng"
},
@ -1617,6 +1635,9 @@
"invalidSeedPhrase": {
"message": "Cụm mật khẩu khôi phục bí mật không hợp lệ"
},
"invalidSeedPhraseCaseSensitive": {
"message": "Nội dung nhập không hợp lệ! Cụm từ khôi phục bí mật phân biệt chữ hoa và chữ thường."
},
"ipfsGateway": {
"message": "Cổng kết nối IPFS"
},
@ -1888,14 +1909,23 @@
"metametricsTitle": {
"message": "Tham gia cùng hơn 6 Triệu người dùng để cải thiện MetaMask"
},
"mismatchedChain": {
"message": "Thông tin về mạng cho mã chuỗi này không khớp với hồ sơ của chúng tôi. Bạn nên $1 trước khi tiếp tục.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "xác minh thông tin về mạng",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "Bạn nên $1 trước khi tiếp tục.",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "Theo hồ sơ của chúng tôi, tên mạng có thể không khớp hoàn toàn với ID chuỗi này."
},
"mismatchedNetworkSymbol": {
"message": "Ký hiệu đơn vị tiền tệ đã gửi không khớp với những gì chúng tôi mong đợi cho ID chuỗi này."
},
"mismatchedRpcUrl": {
"message": "Theo hồ sơ của chúng tôi, giá trị RPC URL đã gửi không khớp với một nhà cung cấp đã biết cho ID chuỗi này."
},
"missingNFT": {
"message": "Không thấy NFT của mình?"
},
@ -1947,6 +1977,9 @@
"network": {
"message": "Mạng:"
},
"networkAddedSuccessfully": {
"message": "Đã thêm mạng thành công!"
},
"networkDetails": {
"message": "Thông tin về mạng"
},
@ -2063,6 +2096,9 @@
"message": "Số chỉ dùng một lần lớn hơn số chỉ dùng một lần gợi ý là $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "NFT"
},
"nftTokenIdPlaceholder": {
"message": "Nhập ID bộ sưu tập"
},
@ -2158,11 +2194,21 @@
"message": "Bật chế độ tối"
},
"notifications12Description": {
"message": "Chế độ tối sẽ được kích hoạt dành cho người dùng mới tùy theo tùy chọn hệ thống của họ. Đối với người dùng hiện tại, có thể bật Chế độ tối theo cách thủ công trong phần Cài đặt -> Thử nghiệm."
"message": "Tiện ích Chế độ tối hiện đã ra mắt! Để bật, hãy vào Cài đặt -> Thử nghiệm và chọn một trong các tùy chọn hiển thị: Sáng, Tối, Hệ thống."
},
"notifications12Title": {
"message": "Dùng chế độ tối khi nào? Ngay bây giờ! 🕶🦊"
},
"notifications13ActionText": {
"message": "Hiển thị danh sách mạng tùy chỉnh"
},
"notifications13Description": {
"message": "Giờ đây, bạn có thể dễ dàng thêm các mạng tùy chỉnh phổ biến sau: Arbitrum, Avalanche, Binance Smart Chain, Fantom, Harmony, Optimism, Palm và Polygon! Để bật tính năng này, hãy chuyển đến Cài đặt -> Thử nghiệm và bật \"Hiển thị danh sách mạng tùy chỉnh\"!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "Thêm các mạng phổ biến"
},
"notifications1Description": {
"message": "Giờ đây, người dùng MetaMask trên điện thoại di động có thể hoán đổi token trong ví di động của họ. Quét mã QR để tải ứng dụng di động và bắt đầu hoán đổi.",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2348,9 +2394,6 @@
"message": "Mở MetaMask ở chế độ toàn màn hình để kết nối thiết bị Ledger của bạn qua WebHID.",
"description": "Shown to the user on the confirm screen when they are viewing MetaMask in a popup window but need to connect their ledger via webhid."
},
"openSourceCode": {
"message": "Kiểm tra mã nguồn"
},
"optional": {
"message": "Không bắt buộc"
},
@ -2680,6 +2723,14 @@
"revealTheSeedPhrase": {
"message": "Hiện cụm từ khôi phục bí mật"
},
"revokeAllTokensTitle": {
"message": "Thu hồi quyền truy cập vào tất cả $1 của bạn?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "Bằng cách thu hồi quyền truy cập, $1 sau đây sẽ không thể truy cập vào $2 của bạn nữa",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Mạng thử nghiệm Rinkeby"
},
@ -2856,12 +2907,23 @@
"message": "Gửi $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "Cảnh báo: bạn sắp gửi đến một hợp đồng token và điều này có thể dẫn đến nguy cơ mất tiền. $1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "Thiết lập cài đặt quyền riêng tư nâng cao"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask sử dụng các dịch vụ của bên thứ ba đáng tin cậy này để nâng cao sự hữu ích và an toàn của sản phẩm."
},
"setApprovalForAll": {
"message": "Cài đặt phê duyệt tất cả"
},
"setApprovalForAllTitle": {
"message": "Phê duyệt $1 không có giới hạn chi tiêu",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "Cài đặt"
},
@ -2881,6 +2943,12 @@
"showAdvancedGasInlineDescription": {
"message": "Chọn tùy chọn này để hiển thị các quyền kiểm soát giá gas và giới hạn ngay trên màn hình gửi và xác nhận."
},
"showCustomNetworkList": {
"message": "Hiển thị danh sách mạng tùy chỉnh"
},
"showCustomNetworkListDescription": {
"message": "Chọn tùy chọn này để hiển thị danh sách các mạng có thông tin được điền sẵn khi thêm mạng mới."
},
"showFiatConversionInTestnets": {
"message": "Hiển thị tỷ lệ quy đổi trên các mạng thử nghiệm"
},
@ -2971,10 +3039,6 @@
"snapInstallWarningCheck": {
"message": "Để xác nhận rằng bạn hiểu, hãy đánh dấu vào tất cả."
},
"snapInstallWarningKeyAccess": {
"message": "Bạn đang cấp quyền truy cập khóa cho Snap \"$1\". Hành động này không thể hủy bỏ và sẽ cấp quyền kiểm soát tài khoản và tài sản của bạn cho \"$1\". Đảm bảo bạn tin tưởng \"$1\" trước khi tiếp tục.",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "Snap này đang yêu cầu các quyền sau:"
},
@ -2990,6 +3054,9 @@
"snapsToggle": {
"message": "Snap chỉ hoạt động khi đã bật"
},
"someNetworksMayPoseSecurity": {
"message": "Một số mạng có thể gây ra rủi ro về bảo mật và/hoặc quyền riêng tư. Bạn cần hiểu rõ các rủi ro này trước khi thêm và sử dụng mạng."
},
"somethingWentWrong": {
"message": "Rất tiếc! Đã xảy ra sự cố."
},
@ -3552,6 +3619,10 @@
"switchNetworks": {
"message": "Chuyển mạng"
},
"switchToNetwork": {
"message": "Chuyển sang $1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "Chuyển sang tài khoản này"
},
@ -3855,6 +3926,9 @@
"unknownCameraErrorTitle": {
"message": "Rất tiếc! Đã xảy ra sự cố...."
},
"unknownCollection": {
"message": "Bộ sưu tập chưa có tên"
},
"unknownNetwork": {
"message": "Mạng riêng không xác định"
},
@ -3874,10 +3948,6 @@
"message": "Không nhận ra mạng tùy chỉnh này. Bạn nên $1 trước khi tiếp tục",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "xác minh thông tin về mạng",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "Hiện không hỗ trợ gửi token sưu tập (ERC-721)",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4065,9 @@
"walletCreationSuccessTitle": {
"message": "Tạo ví thành công"
},
"wantToAddThisNetwork": {
"message": "Bạn muốn thêm mạng này?"
},
"warning": {
"message": "Cảnh báo"
},
@ -4057,6 +4130,10 @@
"yesLetsTry": {
"message": "Có, hãy thử"
},
"youHaveAddedAll": {
"message": "Bạn đã thêm tất cả các mạng phổ biến. Bạn có thể khám phá thêm nhiều mạng khác $1 Hoặc bạn có thể $2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "Bạn cần cho phép truy cập vào máy ảnh để sử dụng tính năng này."
},

@ -157,6 +157,9 @@
"addMemo": {
"message": "添加备忘录"
},
"addMoreNetworks": {
"message": "手动添加更多网络"
},
"addNetwork": {
"message": "添加网络"
},
@ -227,6 +230,10 @@
"alerts": {
"message": "提醒"
},
"allOfYour": {
"message": "您的所有$1",
"description": "$1 is the symbol or name of the token that the user is approving spending"
},
"allowExternalExtensionTo": {
"message": "允许此外部扩展程序:"
},
@ -263,6 +270,10 @@
"approve": {
"message": "批准消费限额"
},
"approveAllTokensTitle": {
"message": "是否允许访问您的所有$1?",
"description": "$1 is the symbol of the token for which the user is granting approval"
},
"approveAndInstall": {
"message": "批准并安装"
},
@ -435,10 +446,10 @@
"description": "$1 represents the crypto symbol to be purchased"
},
"buyWithWyre": {
"message": "使用 Wyre 购买 $1"
"message": "使用Wyre购买$1"
},
"buyWithWyreDescription": {
"message": "您可以通过 Wyre 使用借记卡将 $1 存入您的 MetaMask 账户。"
"message": "购买不超过$1000可以轻松开通。快速交互式上限购买验证。支持借记卡/信用卡、Apple Pay、银行转账。适用于100多个国家。代币存入您的MetaMask账户"
},
"bytes": {
"message": "字节"
@ -466,6 +477,13 @@
"message": "若要$1交易,燃料费用必须增加至少10%才能被网络认可。",
"description": "$1 is string 'cancel' or 'speed up'"
},
"cancelSwapForFee": {
"message": "以~$1取消兑换",
"description": "$1 could be e.g. $2.98, it is a cost for cancelling a Smart Transaction"
},
"cancelSwapForFree": {
"message": "免费取消兑换"
},
"cancellationGasFee": {
"message": "取消燃料费用"
},
@ -1277,6 +1295,9 @@
"functionApprove": {
"message": "功能:批准"
},
"functionSetApprovalForAll": {
"message": "功能:SetApprovalForAll"
},
"functionType": {
"message": "功能类型"
},
@ -1617,6 +1638,9 @@
"invalidSeedPhrase": {
"message": "助记词无效"
},
"invalidSeedPhraseCaseSensitive": {
"message": "输入无效!助记词须区分大小写。"
},
"ipfsGateway": {
"message": "IPFS 网关"
},
@ -1646,7 +1670,7 @@
"message": "已知合约地址。"
},
"knownTokenWarning": {
"message": "此操作将编辑已经在您的钱包中列出的代币,有能被用来欺骗您。只有确定要更改这些代币的内容时,才通过此操作。了解更多关于 $1"
"message": "此操作将编辑已经在您的钱包中列出的代币,有能被用来欺骗您。只有确定要更改这些代币的内容时,才通过此操作。了解更多关于 $1"
},
"kovan": {
"message": "Kovan 测试网络"
@ -1888,14 +1912,23 @@
"metametricsTitle": {
"message": "和600多万用户一起改进 MetaMask"
},
"mismatchedChain": {
"message": "此链 ID 的网络信息与我们的记录不符。我们建议您在继续操作之前 $1。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "验证网络信息",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
},
"mismatchedChainRecommendation": {
"message": "我们建议您在继续之前$1。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key. The link will open to instructions for users to validate custom network details."
},
"mismatchedNetworkName": {
"message": "根据我们的记录,该网络名称可能与此链ID不匹配。"
},
"mismatchedNetworkSymbol": {
"message": "所提交的货币符号与我们对此链ID的预期不匹配。"
},
"mismatchedRpcUrl": {
"message": "根据我们的记录,所提交的RPC URL值与此链ID的已知提供者不匹配。"
},
"missingNFT": {
"message": "找不到您的 NFT?"
},
@ -1947,6 +1980,9 @@
"network": {
"message": "网络: "
},
"networkAddedSuccessfully": {
"message": "网络添加成功!"
},
"networkDetails": {
"message": "网络详情"
},
@ -2063,6 +2099,9 @@
"message": "Nonce 高于建议的 nouce 值 $1",
"description": "The next nonce according to MetaMask's internal logic"
},
"nft": {
"message": "非同质化代币(NFT)"
},
"nftTokenIdPlaceholder": {
"message": "输入代币ID"
},
@ -2158,11 +2197,21 @@
"message": "启用黑暗模式"
},
"notifications12Description": {
"message": "将根据新用户的系统偏好设置为其启用黑暗模式。对于现有用户,请在“设置 -> 实验项”下手动启用黑暗模式。"
"message": "扩展程序的深色模式终于来了!若要开启,请前往“设置 -> 实验项”,然后选择一个显示选项:浅色、深色、系统。"
},
"notifications12Title": {
"message": "何时启用黑暗模式?现在启用黑暗模式! 🕶🦊"
},
"notifications13ActionText": {
"message": "显示自定义网络列表"
},
"notifications13Description": {
"message": "您现在可以轻松添加以下热门自定义网络:Arbitrum、Avalanche、Binance Smart Chain、Fantom、Harmony、Optimism、Palm和Polygon!如需启用此功能,请转到“设置” -> “实验”,然后打开“显示自定义网络列表”!",
"description": "Description of a notification in the 'See What's New' popup. Describes popular network feature."
},
"notifications13Title": {
"message": "添加热门网络"
},
"notifications1Description": {
"message": "MetaMask Mobile 用户现在可以在他们的移动钱包中交换代币。扫描二维码以获取移动应用程序并开始交换。",
"description": "Description of a notification in the 'See What's New' popup. Describes the swapping on mobile feature."
@ -2680,6 +2729,14 @@
"revealTheSeedPhrase": {
"message": "显示助记词"
},
"revokeAllTokensTitle": {
"message": "撤销访问您的所有$1的权限?",
"description": "$1 is the symbol of the token for which the user is revoking approval"
},
"revokeApproveForAllDescription": {
"message": "通过撤销权限,以下$1将无法再访问您的$2",
"description": "$1 is either key 'account' or 'contract', and $2 is either a string or link of a given token symbol or name"
},
"rinkeby": {
"message": "Rinkeby 测试网络"
},
@ -2856,12 +2913,23 @@
"message": "正在发送 $1",
"description": "$1 represents the native currency symbol for the current network (e.g. ETH or BNB)"
},
"sendingToTokenContractWarning": {
"message": "警告:您将要发送到代币合约,这可能会导致资金损失。$1",
"description": "$1 is a clickable link with text defined by the 'learnMoreUpperCase' key. The link will open to a support article regarding the known contract address warning"
},
"setAdvancedPrivacySettings": {
"message": "设置高级隐私设置"
},
"setAdvancedPrivacySettingsDetails": {
"message": "MetaMask 使用这些可信的第三方服务来提高产品可用性和安全性。"
},
"setApprovalForAll": {
"message": "设置批准所有"
},
"setApprovalForAllTitle": {
"message": "批准$1,且无消费限制",
"description": "The token symbol that is being approved"
},
"settings": {
"message": "设置"
},
@ -2881,6 +2949,12 @@
"showAdvancedGasInlineDescription": {
"message": "选择此项可直接在发送和确认界面显示燃料价格和上限控制。"
},
"showCustomNetworkList": {
"message": "显示自定义网络列表"
},
"showCustomNetworkListDescription": {
"message": "选择此项,在添加新网络时就会显示附有预填详细信息的网络列表。"
},
"showFiatConversionInTestnets": {
"message": "在测试网络上显示转换"
},
@ -2971,10 +3045,6 @@
"snapInstallWarningCheck": {
"message": "请勾选全部以确认您理解。"
},
"snapInstallWarningKeyAccess": {
"message": "您正在向snap \"$1\"授予密钥访问权限。此操作不可撤销,并会向\"$1\"授予对您的账户和资产的控制权。在继续之前,请确保您信任\"$1\"。",
"description": "The parameter is the name of the snap"
},
"snapRequestsPermission": {
"message": "此Snap正在请求以下权限:"
},
@ -2990,6 +3060,9 @@
"snapsToggle": {
"message": "Snap仅在启用后才会运行"
},
"someNetworksMayPoseSecurity": {
"message": "某些网络可能会带来安全和/或隐私风险。在添加和使用网络之前,请先了解风险。"
},
"somethingWentWrong": {
"message": "哎呀!出了点问题。"
},
@ -3552,6 +3625,10 @@
"switchNetworks": {
"message": "切换网络"
},
"switchToNetwork": {
"message": "切换至$1",
"description": "$1 represents the custom network that has previously been added"
},
"switchToThisAccount": {
"message": "切换到该账户"
},
@ -3855,6 +3932,9 @@
"unknownCameraErrorTitle": {
"message": "糟糕!出问题了...."
},
"unknownCollection": {
"message": "未命名的收藏"
},
"unknownNetwork": {
"message": "未知的私有网络"
},
@ -3874,10 +3954,6 @@
"message": "这个自定义网络无法识别。我们建议您在继续操作之前 $1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "验证网络信息",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "当前不支持发送可收藏的 (ERC-721) 代币",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"
@ -3995,6 +4071,9 @@
"walletCreationSuccessTitle": {
"message": "钱包创建成功"
},
"wantToAddThisNetwork": {
"message": "想要添加此网络吗?"
},
"warning": {
"message": "警告"
},
@ -4057,6 +4136,10 @@
"yesLetsTry": {
"message": "是的,我们试一下"
},
"youHaveAddedAll": {
"message": "您已经添加了所有热门网络。您可以探索更多网络$1,或者您可以$2",
"description": "$1 is a link with the text 'here' and $2 is a button with the text 'add more networks manually'"
},
"youNeedToAllowCameraAccess": {
"message": "需要开启相机访问权限,才能使用该功能。"
},

@ -1597,10 +1597,6 @@
"metametricsTitle": {
"message": "加入 6M+ 用户来改进MetaMask"
},
"mismatchedChain": {
"message": "此链路的网络详细信息与我们的记录不匹配。我们建议您在继续操作之前$1。",
"description": "$1 is a clickable link with text defined by the 'mismatchedChainLinkText' key"
},
"mismatchedChainLinkText": {
"message": "验证网络详细信息",
"description": "Serves as link text for the 'mismatchedChain' key. This text will be embedded inside the translation for that key."
@ -3157,10 +3153,6 @@
"message": "这个自定义网络无法识别。我们建议您在继续操作之前$1",
"description": "$1 is a clickable link with text defined by the 'unrecognizedChanLinkText' key. The link will open to instructions for users to validate custom network details."
},
"unrecognizedChainLinkText": {
"message": "验证网络详细信息",
"description": "Serves as link text for the 'unrecognizedChain' key. This text will be embedded inside the translation for that key."
},
"unsendableAsset": {
"message": "当前不支持发送可收藏的 (ERC-721) 代币",
"description": "This is an error message we show the user if they attempt to send a collectible asset type, for which currently don't support sending"

@ -72,11 +72,5 @@
"*://*.eth/",
"notifications"
],
"short_name": "__MSG_appName__",
"web_accessible_resources": [
{
"resources": ["inpage.js", "phishing.html"],
"matches": ["http://*/*", "https://*/*"]
}
]
"short_name": "__MSG_appName__"
}

@ -1,42 +1,87 @@
/* global chrome */
// This file is used only for manifest version 3
// Represents if importAllScripts has been run
// eslint-disable-next-line
let scriptsLoadInitiated = false;
const testMode = process.env.IN_TEST;
const loadTimeLogs = [];
// eslint-disable-next-line import/unambiguous
function tryImport(...fileNames) {
try {
const startTime = new Date().getTime();
// eslint-disable-next-line
importScripts(...fileNames);
const endTime = new Date().getTime();
loadTimeLogs.push({
name: fileNames[0],
value: endTime - startTime,
children: [],
startTime,
endTime,
});
return true;
} catch (e) {
console.error(e);
return false;
}
return false;
}
function importAllScripts() {
// Bail if we've already imported scripts
if (scriptsLoadInitiated) {
return;
}
scriptsLoadInitiated = true;
const files = [];
// In testMode individual files are imported, this is to help capture load time stats
const loadFile = (fileName) => {
if (testMode) {
tryImport(fileName);
} else {
files.push(fileName);
}
};
const startImportScriptsTime = Date.now();
// value of applyLavaMoat below is dynamically replaced at build time with actual value
const applyLavaMoat = true;
const applyLavaMoat = process.env.APPLY_LAVAMOAT;
if (typeof applyLavaMoat !== 'boolean') {
throw new Error('Missing APPLY_LAVAMOAT environment variable');
}
tryImport('./globalthis.js');
tryImport('./sentry-install.js');
loadFile('./globalthis.js');
loadFile('./sentry-install.js');
if (applyLavaMoat) {
tryImport('./runtime-lavamoat.js');
tryImport('./lockdown-more.js');
tryImport('./policy-load.js');
// Always apply LavaMoat in e2e test builds, so that we can capture initialization stats
if (testMode || applyLavaMoat) {
loadFile('./runtime-lavamoat.js');
loadFile('./lockdown-more.js');
loadFile('./policy-load.js');
} else {
tryImport('./init-globals.js');
tryImport('./lockdown-install.js');
tryImport('./lockdown-run.js');
tryImport('./lockdown-more.js');
tryImport('./runtime-cjs.js');
loadFile('./init-globals.js');
loadFile('./lockdown-install.js');
loadFile('./lockdown-run.js');
loadFile('./lockdown-more.js');
loadFile('./runtime-cjs.js');
}
const fileList = [
// The list of files is injected at build time by replacing comment below with comma separated strings of file names
// https://github.com/MetaMask/metamask-extension/blob/496d9d81c3367931031edc11402552690c771acf/development/build/scripts.js#L406
/** FILE NAMES */
];
// This environment variable is set to a string of comma-separated relative file paths.
const rawFileList = process.env.FILE_NAMES;
const fileList = rawFileList.split(',');
fileList.forEach((fileName) => loadFile(fileName));
// Import all required resources
tryImport(...files);
fileList.forEach((fileName) => tryImport(fileName));
const endImportScriptsTime = Date.now();
// for performance metrics/reference
console.log(
@ -44,7 +89,40 @@ function importAllScripts() {
(Date.now() - startImportScriptsTime) / 1000
}`,
);
// In testMode load time logs are output to console
if (testMode) {
console.log(
`Time for each import: ${JSON.stringify(
{
name: 'Total',
children: loadTimeLogs,
startTime: startImportScriptsTime,
endTime: endImportScriptsTime,
value: endImportScriptsTime - startImportScriptsTime,
version: 1,
},
undefined,
' ',
)}`,
);
}
}
// Placing script import call here ensures that scripts are inported each time service worker is activated.
importAllScripts();
// Ref: https://stackoverflow.com/questions/66406672/chrome-extension-mv3-modularize-service-worker-js-file
// eslint-disable-next-line no-undef
self.addEventListener('install', importAllScripts);
/*
* A keepalive message listener to prevent Service Worker getting shut down due to inactivity.
* UI sends the message periodically, in a setInterval.
* Chrome will revive the service worker if it was shut down, whenever a new message is sent, but only if a listener was defined here.
*
* chrome below needs to be replaced by cross-browser object,
* but there is issue in importing webextension-polyfill into service worker.
* chrome does seems to work in at-least all chromium based browsers
*/
chrome.runtime.onMessage.addListener(() => {
importAllScripts();
return false;
});

@ -114,33 +114,33 @@ if (isManifestV3()) {
* @property {boolean} isInitialized - Whether the first vault has been created.
* @property {boolean} isUnlocked - Whether the vault is currently decrypted and accounts are available for selection.
* @property {boolean} isAccountMenuOpen - Represents whether the main account selection UI is currently displayed.
* @property {Object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys.
* @property {Object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions.
* @property {object} identities - An object matching lower-case hex addresses to Identity objects with "address" and "name" (nickname) keys.
* @property {object} unapprovedTxs - An object mapping transaction hashes to unapproved transactions.
* @property {Array} frequentRpcList - A list of frequently used RPCs, including custom user-provided ones.
* @property {Array} addressBook - A list of previously sent to addresses.
* @property {Object} contractExchangeRates - Info about current token prices.
* @property {object} contractExchangeRates - Info about current token prices.
* @property {Array} tokens - Tokens held by the current user, including their balances.
* @property {Object} send - TODO: Document
* @property {object} send - TODO: Document
* @property {boolean} useBlockie - Indicates preferred user identicon format. True for blockie, false for Jazzicon.
* @property {Object} featureFlags - An object for optional feature flags.
* @property {object} featureFlags - An object for optional feature flags.
* @property {boolean} welcomeScreen - True if welcome screen should be shown.
* @property {string} currentLocale - A locale string matching the user's preferred display language.
* @property {Object} provider - The current selected network provider.
* @property {object} provider - The current selected network provider.
* @property {string} provider.rpcUrl - The address for the RPC API, if using an RPC API.
* @property {string} provider.type - An identifier for the type of network selected, allows MetaMask to use custom provider strategies for known networks.
* @property {string} network - A stringified number of the current network ID.
* @property {Object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values.
* @property {object} accounts - An object mapping lower-case hex addresses to objects with "balance" and "address" keys, both storing hex string values.
* @property {hex} currentBlockGasLimit - The most recently seen block gas limit, in a lower case hex prefixed string.
* @property {TransactionMeta[]} currentNetworkTxList - An array of transactions associated with the currently selected network.
* @property {Object} unapprovedMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {object} unapprovedMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {number} unapprovedMsgCount - The number of messages in unapprovedMsgs.
* @property {Object} unapprovedPersonalMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {object} unapprovedPersonalMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {number} unapprovedPersonalMsgCount - The number of messages in unapprovedPersonalMsgs.
* @property {Object} unapprovedEncryptionPublicKeyMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {object} unapprovedEncryptionPublicKeyMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {number} unapprovedEncryptionPublicKeyMsgCount - The number of messages in EncryptionPublicKeyMsgs.
* @property {Object} unapprovedDecryptMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {object} unapprovedDecryptMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {number} unapprovedDecryptMsgCount - The number of messages in unapprovedDecryptMsgs.
* @property {Object} unapprovedTypedMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {object} unapprovedTypedMsgs - An object of messages pending approval, mapping a unique ID to the options.
* @property {number} unapprovedTypedMsgCount - The number of messages in unapprovedTypedMsgs.
* @property {number} pendingApprovalCount - The number of pending request in the approval controller.
* @property {string[]} keyringTypes - An array of unique keyring identifying strings, representing available strategies for creating accounts.
@ -304,7 +304,7 @@ async function loadStateFromPersistence() {
* Streams emitted state updates to platform-specific storage strategy.
* Creates platform listeners for new Dapps/Contexts, and sets up their data connections to the controller.
*
* @param {Object} initState - The initial state to start the controller with, matches the state that is emitted from the controller.
* @param {object} initState - The initial state to start the controller with, matches the state that is emitted from the controller.
* @param {string} initLangCode - The region code for the language preferred by the current user.
* @param {string} remoteSourcePort - remote application port connecting to extension.
* @returns {Promise} After setup is complete.
@ -361,7 +361,7 @@ function setupController(initState, initLangCode, remoteSourcePort) {
/**
* Assigns the given state to the versioned object (with metadata), and returns that.
*
* @param {Object} state - The state object as emitted by the MetaMaskController.
* @param {object} state - The state object as emitted by the MetaMaskController.
* @returns {VersionedData} The state object wrapped in an object that includes a metadata key.
*/
function versionifyData(state) {
@ -615,11 +615,11 @@ function setupController(initState, initLangCode, remoteSourcePort) {
const { unapprovedMsgCount } = controller.messageManager;
const { unapprovedPersonalMsgCount } = controller.personalMessageManager;
const { unapprovedDecryptMsgCount } = controller.decryptMessageManager;
const {
unapprovedEncryptionPublicKeyMsgCount,
} = controller.encryptionPublicKeyManager;
const { unapprovedEncryptionPublicKeyMsgCount } =
controller.encryptionPublicKeyManager;
const { unapprovedTypedMessagesCount } = controller.typedMessageManager;
const pendingApprovalCount = controller.approvalController.getTotalApprovalCount();
const pendingApprovalCount =
controller.approvalController.getTotalApprovalCount();
const waitingForUnlockCount =
controller.appStateController.waitingForUnlock.length;
return (

@ -6,3 +6,17 @@ export const SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN =
'0xb8e671734ce5c8d7dfbbea5574fa4cf39f7a54a4';
export const SINGLE_CALL_BALANCES_ADDRESS_KOVAN =
'0xb1d3fbb2f83aecd196f474c16ca5d9cffa0d0ffc';
export const SINGLE_CALL_BALANCES_ADDRESS_GOERLI =
'0x9788C4E93f9002a7ad8e72633b11E8d1ecd51f9b';
export const SINGLE_CALL_BALANCES_ADDRESS_BSC =
'0x2352c63A83f9Fd126af8676146721Fa00924d7e4';
export const SINGLE_CALL_BALANCES_ADDRESS_OPTIMISM =
'0xB1c568e9C3E6bdaf755A60c7418C269eb11524FC';
export const SINGLE_CALL_BALANCES_ADDRESS_POLYGON =
'0x2352c63A83f9Fd126af8676146721Fa00924d7e4';
export const SINGLE_CALL_BALANCES_ADDRESS_AVALANCHE =
'0xD023D153a0DFa485130ECFdE2FAA7e612EF94818';
export const SINGLE_CALL_BALANCES_ADDRESS_FANTOM =
'0x07f697424ABe762bB808c109860c04eA488ff92B';
export const SINGLE_CALL_BALANCES_ADDRESS_ARBITRUM =
'0x151E24A486D7258dd7C33Fb67E4bB01919B7B32c';

@ -1,4 +1,3 @@
import querystring from 'querystring';
import pump from 'pump';
import { WindowPostMessageStream } from '@metamask/post-message-stream';
import ObjectMultiplex from 'obj-multiplex';
@ -358,12 +357,15 @@ function blockedDomainCheck() {
/**
* Redirects the current page to a phishing information page
*
* @param data
*/
function redirectToPhishingWarning() {
function redirectToPhishingWarning(data = {}) {
console.debug('MetaMask: Routing to Phishing Warning page.');
const { hostname, href } = window.location;
const { newIssueUrl } = data;
const baseUrl = process.env.PHISHING_WARNING_PAGE_URL;
window.location.href = `${baseUrl}#${querystring.stringify({
hostname: window.location.hostname,
href: window.location.href,
})}`;
const querystring = new URLSearchParams({ hostname, href, newIssueUrl });
window.location.href = `${baseUrl}#${querystring}`;
}

@ -5,16 +5,16 @@ import {
} from '../../../shared/constants/alerts';
/**
* @typedef {Object} AlertControllerInitState
* @property {Object} alertEnabledness - A map of alerts IDs to booleans, where
* @typedef {object} AlertControllerInitState
* @property {object} alertEnabledness - A map of alerts IDs to booleans, where
* `true` indicates that the alert is enabled and shown, and `false` the opposite.
* @property {Object} unconnectedAccountAlertShownOrigins - A map of origin
* @property {object} unconnectedAccountAlertShownOrigins - A map of origin
* strings to booleans indicating whether the "switch to connected" alert has
* been shown (`true`) or otherwise (`false`).
*/
/**
* @typedef {Object} AlertControllerOptions
* @typedef {object} AlertControllerOptions
* @property {AlertControllerInitState} initState - The initial controller state
*/

@ -5,7 +5,7 @@ import { MINUTE } from '../../../shared/constants/time';
export default class AppStateController extends EventEmitter {
/**
* @param {Object} opts
* @param {object} opts
*/
constructor(opts = {}) {
const {

@ -1,10 +1,10 @@
import { ObservableStore } from '@metamask/obs-store';
/**
* @typedef {Object} CachedBalancesOptions
* @property {Object} accountTracker An {@code AccountTracker} reference
* @typedef {object} CachedBalancesOptions
* @property {object} accountTracker An {@code AccountTracker} reference
* @property {Function} getCurrentChainId A function to get the current chain id
* @property {Object} initState The initial controller state
* @property {object} initState The initial controller state
*/
/**
@ -33,7 +33,7 @@ export default class CachedBalancesController {
* Updates the cachedBalances property for the current chain. Cached balances will be updated to those in the passed accounts
* if balances in the passed accounts are truthy.
*
* @param {Object} obj - The the recently updated accounts object for the current chain
* @param {object} obj - The the recently updated accounts object for the current chain
* @param obj.accounts
* @returns {Promise<void>}
*/

@ -6,8 +6,10 @@ import { MINUTE } from '../../../shared/constants/time';
import { MAINNET_CHAIN_ID } from '../../../shared/constants/network';
import { isTokenDetectionEnabledForNetwork } from '../../../shared/modules/network.utils';
import { isEqualCaseInsensitive } from '../../../shared/modules/string-utils';
import { TOKEN_STANDARDS } from '../../../ui/helpers/constants/common';
import { ASSET_TYPES } from '../../../shared/constants/transaction';
import {
ASSET_TYPES,
TOKEN_STANDARDS,
} from '../../../shared/constants/transaction';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
// By default, poll every 3 minutes
@ -21,7 +23,7 @@ export default class DetectTokensController {
/**
* Creates a DetectTokensController
*
* @param {Object} [config] - Options to configure controller
* @param {object} [config] - Options to configure controller
* @param config.interval
* @param config.preferences
* @param config.network
@ -172,13 +174,8 @@ export default class DetectTokensController {
if (result) {
const nonZeroTokenAddresses = Object.keys(result);
for (const nonZeroTokenAddress of nonZeroTokenAddresses) {
const {
address,
symbol,
decimals,
iconUrl,
aggregators,
} = tokenList[nonZeroTokenAddress];
const { address, symbol, decimals, iconUrl, aggregators } =
tokenList[nonZeroTokenAddress];
eventTokensDetails.push(`${symbol} - ${address}`);
@ -250,7 +247,7 @@ export default class DetectTokensController {
}
/**
* @type {Object}
* @type {object}
*/
set network(network) {
if (!network) {
@ -263,7 +260,7 @@ export default class DetectTokensController {
/**
* In setter when isUnlocked is updated to true, detectNewTokens and restart polling
*
* @type {Object}
* @type {object}
*/
set keyringMemStore(keyringMemStore) {
if (!keyringMemStore) {
@ -281,7 +278,7 @@ export default class DetectTokensController {
}
/**
* @type {Object}
* @type {object}
*/
set tokenList(tokenList) {
if (!tokenList) {
@ -293,7 +290,7 @@ export default class DetectTokensController {
/**
* Internal isActive state
*
* @type {Object}
* @type {object}
*/
get isActive() {
return this.isOpen && this.isUnlocked;

@ -8,12 +8,19 @@ import {
TokenListController,
TokensController,
} from '@metamask/controllers';
import { MAINNET, ROPSTEN } from '../../../shared/constants/network';
import {
MAINNET,
MAINNET_NETWORK_ID,
ROPSTEN,
} from '../../../shared/constants/network';
import { toChecksumHexAddress } from '../../../shared/modules/hexstring-utils';
import DetectTokensController from './detect-tokens';
import NetworkController from './network';
import PreferencesController from './preferences';
const tokenIconsApiBaseUrl =
'https://static.metaswap.codefi.network/api/v1/tokenIcons';
describe('DetectTokensController', function () {
let tokenListController;
const sandbox = sinon.createSandbox();
@ -127,7 +134,6 @@ describe('DetectTokensController', function () {
});
tokenListController = new TokenListController({
chainId: '1',
useStaticTokenList: false,
onNetworkStateChange: sinon.spy(),
onPreferencesStateChange: sinon.spy(),
messenger: tokenListMessenger,
@ -179,7 +185,6 @@ describe('DetectTokensController', function () {
});
tokenListController = new TokenListController({
chainId: '3',
useStaticTokenList: false,
onNetworkStateChange: sinon.spy(),
onPreferencesStateChange: sinon.spy(),
messenger: tokenListMessengerRopsten,
@ -241,7 +246,7 @@ describe('DetectTokensController', function () {
),
);
await tokensController.removeAndIgnoreToken(tokenAddressToSkip);
await tokensController.ignoreTokens([tokenAddressToSkip]);
await controller.detectNewTokens();
assert.deepEqual(tokensController.state.tokens, [
@ -249,7 +254,8 @@ describe('DetectTokensController', function () {
address: toChecksumHexAddress(existingTokenAddress),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
image: undefined,
aggregators: [],
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${existingTokenAddress}.png`,
isERC721: false,
},
]);
@ -285,9 +291,8 @@ describe('DetectTokensController', function () {
const contractAddressesToDetect = erc20ContractAddresses.filter(
(address) => address !== existingTokenAddress,
);
const indexOfTokenToAdd = contractAddressesToDetect.indexOf(
tokenAddressToAdd,
);
const indexOfTokenToAdd =
contractAddressesToDetect.indexOf(tokenAddressToAdd);
const balances = new Array(contractAddressesToDetect.length);
balances[indexOfTokenToAdd] = new BigNumber(10);
@ -303,14 +308,16 @@ describe('DetectTokensController', function () {
decimals: existingToken.decimals,
symbol: existingToken.symbol,
isERC721: false,
image: undefined,
aggregators: [],
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${existingTokenAddress}.png`,
},
{
address: toChecksumHexAddress(tokenAddressToAdd),
decimals: tokenToAdd.decimals,
symbol: tokenToAdd.symbol,
image: undefined,
isERC721: false,
aggregators: [],
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${tokenAddressToAdd}.png`,
},
]);
});
@ -345,9 +352,8 @@ describe('DetectTokensController', function () {
const contractAddressesToDetect = erc20ContractAddresses.filter(
(address) => address !== existingTokenAddress,
);
const indexOfTokenToAdd = contractAddressesToDetect.indexOf(
tokenAddressToAdd,
);
const indexOfTokenToAdd =
contractAddressesToDetect.indexOf(tokenAddressToAdd);
const balances = new Array(contractAddressesToDetect.length);
balances[indexOfTokenToAdd] = new BigNumber(10);
@ -363,15 +369,17 @@ describe('DetectTokensController', function () {
address: toChecksumHexAddress(existingTokenAddress),
decimals: existingToken.decimals,
symbol: existingToken.symbol,
image: undefined,
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${existingTokenAddress}.png`,
isERC721: false,
aggregators: [],
},
{
address: toChecksumHexAddress(tokenAddressToAdd),
decimals: tokenToAdd.decimals,
symbol: tokenToAdd.symbol,
image: undefined,
image: `${tokenIconsApiBaseUrl}/${MAINNET_NETWORK_ID}/${tokenAddressToAdd}.png`,
isERC721: false,
aggregators: [],
},
]);
});

@ -1,5 +1,6 @@
import EthJsEns from 'ethjs-ens';
import { ethers } from 'ethers';
import ensNetworkMap from 'ethereum-ens-network-map';
import { NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP } from '../../../../shared/constants/network';
export default class Ens {
static getNetworkEnsSupport(network) {
@ -7,17 +8,21 @@ export default class Ens {
}
constructor({ network, provider } = {}) {
this._ethJsEns = new EthJsEns({
network,
provider,
const networkName = NETWORK_ID_TO_ETHERS_NETWORK_NAME_MAP[network];
const ensAddress = ensNetworkMap[network];
const ethProvider = new ethers.providers.Web3Provider(provider, {
chainId: parseInt(network, 10),
name: networkName,
ensAddress,
});
this._ethProvider = ethProvider;
}
lookup(ensName) {
return this._ethJsEns.lookup(ensName);
return this._ethProvider.resolveName(ensName);
}
reverse(address) {
return this._ethJsEns.reverse(address);
return this._ethProvider.lookupAddress(address);
}
}

@ -20,7 +20,7 @@ describe('EnsController', function () {
describe('#constructor', function () {
it('should construct the controller given a provider and a network', async function () {
const ens = new EnsController({
provider: {},
provider: sinon.fake(),
getCurrentChainId,
onNetworkDidChange,
});

@ -18,9 +18,8 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
} from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
/**
* @typedef {import('../../../shared/constants/transaction').TransactionMeta} TransactionMeta
@ -31,7 +30,7 @@ const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
*
* Note that this is not an exhaustive type definiton; only the properties we use are defined
*
* @typedef {Object} EtherscanTransaction
* @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 GWEI

@ -104,7 +104,7 @@ function getMockBlockTracker() {
* Returns a transaction object matching the expected format returned
* by the Etherscan API
*
* @param {Object} [params] - options bag
* @param {object} [params] - options bag
* @param {string} [params.toAddress] - The hex-prefixed address of the recipient
* @param {number} [params.blockNumber] - The block number for the transaction
* @param {boolean} [params.useEIP1559] - Use EIP-1559 gas fields
@ -190,9 +190,8 @@ describe('IncomingTransactionsController', function () {
);
assert(mockedNetworkMethods.onNetworkDidChange.calledOnce);
const networkControllerListenerCallback = mockedNetworkMethods.onNetworkDidChange.getCall(
0,
).args[0];
const networkControllerListenerCallback =
mockedNetworkMethods.onNetworkDidChange.getCall(0).args[0];
assert.strictEqual(incomingTransactionsController._update.callCount, 0);
networkControllerListenerCallback('testNetworkType');
assert.strictEqual(incomingTransactionsController._update.callCount, 1);
@ -253,8 +252,10 @@ describe('IncomingTransactionsController', function () {
initState: getNonEmptyInitState(),
},
);
const startBlock = getNonEmptyInitState()
.incomingTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID];
const startBlock =
getNonEmptyInitState().incomingTxLastFetchedBlockByChainId[
ROPSTEN_CHAIN_ID
];
nock('https://api-ropsten.etherscan.io')
.get(
`/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`,
@ -546,8 +547,10 @@ describe('IncomingTransactionsController', function () {
},
);
const NEW_MOCK_SELECTED_ADDRESS = `${MOCK_SELECTED_ADDRESS}9`;
const startBlock = getNonEmptyInitState()
.incomingTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID];
const startBlock =
getNonEmptyInitState().incomingTxLastFetchedBlockByChainId[
ROPSTEN_CHAIN_ID
];
nock('https://api-ropsten.etherscan.io')
.get(
`/api?module=account&action=txlist&address=${NEW_MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`,
@ -572,9 +575,10 @@ describe('IncomingTransactionsController', function () {
incomingTransactionsController.store,
);
const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall(
1,
).args[0];
const subscription =
incomingTransactionsController.preferencesController.store.subscribe.getCall(
1,
).args[0];
// The incoming transactions controller will always skip the first event
// We need to call subscription twice to test the event handling
// TODO: stop skipping the first event
@ -658,9 +662,10 @@ describe('IncomingTransactionsController', function () {
incomingTransactionsController.store,
);
const subscription = incomingTransactionsController.preferencesController.store.subscribe.getCall(
1,
).args[0];
const subscription =
incomingTransactionsController.preferencesController.store.subscribe.getCall(
1,
).args[0];
// The incoming transactions controller will always skip the first event
// We need to call subscription twice to test the event handling
// TODO: stop skipping the first event
@ -682,9 +687,8 @@ describe('IncomingTransactionsController', function () {
});
it('should update when switching to a supported network', async function () {
const mockedNetworkMethods = getMockNetworkControllerMethods(
ROPSTEN_CHAIN_ID,
);
const mockedNetworkMethods =
getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID);
const incomingTransactionsController = new IncomingTransactionsController(
{
blockTracker: getMockBlockTracker(),
@ -693,8 +697,10 @@ describe('IncomingTransactionsController', function () {
initState: getNonEmptyInitState(),
},
);
const startBlock = getNonEmptyInitState()
.incomingTxLastFetchedBlockByChainId[ROPSTEN_CHAIN_ID];
const startBlock =
getNonEmptyInitState().incomingTxLastFetchedBlockByChainId[
ROPSTEN_CHAIN_ID
];
nock('https://api-ropsten.etherscan.io')
.get(
`/api?module=account&action=txlist&address=${MOCK_SELECTED_ADDRESS}&tag=latest&page=1&startBlock=${startBlock}`,
@ -715,8 +721,8 @@ describe('IncomingTransactionsController', function () {
incomingTransactionsController.store,
);
const subscription = mockedNetworkMethods.onNetworkDidChange.getCall(0)
.args[0];
const subscription =
mockedNetworkMethods.onNetworkDidChange.getCall(0).args[0];
await subscription(ROPSTEN_CHAIN_ID);
await updateStateCalled();
@ -763,9 +769,8 @@ describe('IncomingTransactionsController', function () {
});
it('should not update when switching to an unsupported network', async function () {
const mockedNetworkMethods = getMockNetworkControllerMethods(
ROPSTEN_CHAIN_ID,
);
const mockedNetworkMethods =
getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID);
const incomingTransactionsController = new IncomingTransactionsController(
{
blockTracker: getMockBlockTracker(),
@ -796,8 +801,8 @@ describe('IncomingTransactionsController', function () {
incomingTransactionsController.store,
);
const subscription = mockedNetworkMethods.onNetworkDidChange.getCall(0)
.args[0];
const subscription =
mockedNetworkMethods.onNetworkDidChange.getCall(0).args[0];
incomingTransactionsController.getCurrentChainId = () => FAKE_CHAIN_ID;
await subscription();
@ -820,15 +825,14 @@ describe('IncomingTransactionsController', function () {
describe('_update', function () {
describe('when state is empty (initialized)', function () {
it('should use provided block number and update the latest block seen', async function () {
const incomingTransactionsController = new IncomingTransactionsController(
{
const incomingTransactionsController =
new IncomingTransactionsController({
blockTracker: getMockBlockTracker(),
...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID),
preferencesController: getMockPreferencesController(),
initState: getEmptyInitState(),
getCurrentChainId: () => ROPSTEN_CHAIN_ID,
},
);
});
sinon.spy(incomingTransactionsController.store, 'updateState');
incomingTransactionsController._getNewIncomingTransactions = sinon
@ -857,15 +861,14 @@ describe('IncomingTransactionsController', function () {
});
it('should update the last fetched block for network to highest block seen in incoming txs', async function () {
const incomingTransactionsController = new IncomingTransactionsController(
{
const incomingTransactionsController =
new IncomingTransactionsController({
blockTracker: getMockBlockTracker(),
...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID),
preferencesController: getMockPreferencesController(),
initState: getEmptyInitState(),
getCurrentChainId: () => ROPSTEN_CHAIN_ID,
},
);
});
const NEW_TRANSACTION_ONE = {
id: 555,
@ -911,15 +914,14 @@ describe('IncomingTransactionsController', function () {
describe('when state is populated with prior data for network', function () {
it('should use the last fetched block for the current network and increment by 1 in state', async function () {
const incomingTransactionsController = new IncomingTransactionsController(
{
const incomingTransactionsController =
new IncomingTransactionsController({
blockTracker: getMockBlockTracker(),
...getMockNetworkControllerMethods(ROPSTEN_CHAIN_ID),
preferencesController: getMockPreferencesController(),
initState: getNonEmptyInitState(),
getCurrentChainId: () => ROPSTEN_CHAIN_ID,
},
);
});
sinon.spy(incomingTransactionsController.store, 'updateState');
incomingTransactionsController._getNewIncomingTransactions = sinon
.stub()
@ -1105,11 +1107,12 @@ describe('IncomingTransactionsController', function () {
},
);
const result = await incomingTransactionsController._getNewIncomingTransactions(
ADDRESS_TO_FETCH_FOR,
'789',
ROPSTEN_CHAIN_ID,
);
const result =
await incomingTransactionsController._getNewIncomingTransactions(
ADDRESS_TO_FETCH_FOR,
'789',
ROPSTEN_CHAIN_ID,
);
assert(mockFetch.calledOnce);
assert.deepStrictEqual(result, [
@ -1137,11 +1140,12 @@ describe('IncomingTransactionsController', function () {
},
);
const result = await incomingTransactionsController._getNewIncomingTransactions(
ADDRESS_TO_FETCH_FOR,
'789',
ROPSTEN_CHAIN_ID,
);
const result =
await incomingTransactionsController._getNewIncomingTransactions(
ADDRESS_TO_FETCH_FOR,
'789',
ROPSTEN_CHAIN_ID,
);
assert.deepStrictEqual(result, []);
window.fetch = tempFetchStatusZero;
mockFetchStatusZero.reset();
@ -1164,11 +1168,12 @@ describe('IncomingTransactionsController', function () {
},
);
const result = await incomingTransactionsController._getNewIncomingTransactions(
ADDRESS_TO_FETCH_FOR,
'789',
ROPSTEN_CHAIN_ID,
);
const result =
await incomingTransactionsController._getNewIncomingTransactions(
ADDRESS_TO_FETCH_FOR,
'789',
ROPSTEN_CHAIN_ID,
);
assert.deepStrictEqual(result, []);
window.fetch = tempFetchEmptyResult;
mockFetchEmptyResult.reset();

@ -44,7 +44,7 @@ const exceptionsToFilter = {
*/
/**
* @typedef {Object} MetaMetricsControllerState
* @typedef {object} MetaMetricsControllerState
* @property {string} [metaMetricsId] - The user's metaMetricsId that will be
* attached to all non-anonymized event payloads
* @property {boolean} [participateInMetaMetrics] - The user's preference for
@ -57,9 +57,9 @@ const exceptionsToFilter = {
export default class MetaMetricsController {
/**
* @param {object} options
* @param {Object} options.segment - an instance of analytics-node for tracking
* @param {object} options.segment - an instance of analytics-node for tracking
* events that conform to the new MetaMetrics tracking plan.
* @param {Object} options.preferencesStore - The preferences controller store, used
* @param {object} options.preferencesStore - The preferences controller store, used
* to access and subscribe to preferences that will be attached to events
* @param {Function} options.onNetworkDidChange - Used to attach a listener to the
* networkDidChange event emitted by the networkController
@ -295,7 +295,7 @@ export default class MetaMetricsController {
* Calls this._identify with validated metaMetricsId and user traits if user is participating
* in the MetaMetrics analytics program
*
* @param {Object} userTraits
* @param {object} userTraits
*/
identify(userTraits) {
const { metaMetricsId, participateInMetaMetrics } = this.state;
@ -558,15 +558,16 @@ export default class MetaMetricsController {
[TRAITS.NETWORKS_ADDED]: metamaskState.frequentRpcListDetail.map(
(rpc) => rpc.chainId,
),
[TRAITS.NETWORKS_WITHOUT_TICKER]: metamaskState.frequentRpcListDetail.reduce(
(networkList, currentNetwork) => {
if (!currentNetwork.ticker) {
networkList.push(currentNetwork.chainId);
}
return networkList;
},
[],
),
[TRAITS.NETWORKS_WITHOUT_TICKER]:
metamaskState.frequentRpcListDetail.reduce(
(networkList, currentNetwork) => {
if (!currentNetwork.ticker) {
networkList.push(currentNetwork.chainId);
}
return networkList;
},
[],
),
[TRAITS.NFT_AUTODETECTION_ENABLED]: metamaskState.useCollectibleDetection,
[TRAITS.NUMBER_OF_ACCOUNTS]: Object.values(metamaskState.identities)
.length,
@ -604,8 +605,8 @@ export default class MetaMetricsController {
* Returns a new object of all valid user traits. For dates, we transform them into ISO-8601 timestamp strings.
*
* @see {@link https://segment.com/docs/connections/spec/common/#timestamps}
* @param {Object} userTraits
* @returns {Object}
* @param {object} userTraits
* @returns {object}
*/
_buildValidTraits(userTraits) {
return Object.entries(userTraits).reduce((validTraits, [key, value]) => {
@ -626,7 +627,7 @@ export default class MetaMetricsController {
* Returns an array of all of the collectibles/NFTs the user
* possesses across all networks and accounts.
*
* @param {Object} allCollectibles
* @param {object} allCollectibles
* @returns {[]}
*/
_getAllNFTsFlattened = memoize((allCollectibles = {}) => {
@ -639,7 +640,7 @@ export default class MetaMetricsController {
* Returns the number of unique collectible/NFT addresses the user
* possesses across all networks and accounts.
*
* @param {Object} allCollectibles
* @param {object} allCollectibles
* @returns {number}
*/
_getAllUniqueNFTAddressesLength(allCollectibles = {}) {
@ -668,7 +669,7 @@ export default class MetaMetricsController {
*
* @see {@link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#identify}
* @private
* @param {Object} userTraits
* @param {object} userTraits
*/
_identify(userTraits) {
const { metaMetricsId } = this.state;

@ -132,12 +132,10 @@ function getMetaMetricsController({
} = {}) {
return new MetaMetricsController({
segment,
getNetworkIdentifier: networkController.getNetworkIdentifier.bind(
networkController,
),
getCurrentChainId: networkController.getCurrentChainId.bind(
networkController,
),
getNetworkIdentifier:
networkController.getNetworkIdentifier.bind(networkController),
getCurrentChainId:
networkController.getCurrentChainId.bind(networkController),
onNetworkDidChange: networkController.on.bind(
networkController,
NETWORK_EVENTS.NETWORK_DID_CHANGE,

@ -34,8 +34,8 @@ describe('NetworkController', () => {
describe('#provider', () => {
it('provider should be updatable without reassignment', () => {
networkController.initializeProvider(networkControllerProviderConfig);
const providerProxy = networkController.getProviderAndBlockTracker()
.provider;
const providerProxy =
networkController.getProviderAndBlockTracker().provider;
expect(providerProxy.test).toBeUndefined();
providerProxy.setTarget({ test: true });
expect(providerProxy.test).toStrictEqual(true);
@ -79,7 +79,8 @@ describe('NetworkController', () => {
describe('#getEIP1559Compatibility', () => {
it('should return false when baseFeePerGas is not in the block header', async () => {
networkController.initializeProvider(networkControllerProviderConfig);
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
const supportsEIP1559 =
await networkController.getEIP1559Compatibility();
expect(supportsEIP1559).toStrictEqual(false);
});
@ -88,7 +89,8 @@ describe('NetworkController', () => {
getLatestBlockStub.callsFake(() =>
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
const supportsEIP1559 =
await networkController.getEIP1559Compatibility();
expect(supportsEIP1559).toStrictEqual(true);
});
@ -98,7 +100,8 @@ describe('NetworkController', () => {
Promise.resolve({ baseFeePerGas: '0xa ' }),
);
await networkController.getEIP1559Compatibility();
const supportsEIP1559 = await networkController.getEIP1559Compatibility();
const supportsEIP1559 =
await networkController.getEIP1559Compatibility();
expect(getLatestBlockStub.calledOnce).toStrictEqual(true);
expect(supportsEIP1559).toStrictEqual(true);
});

@ -20,7 +20,6 @@ import {
INFURA_BLOCKED_KEY,
TEST_NETWORK_TICKER_MAP,
} from '../../../../shared/constants/network';
import { SECOND } from '../../../../shared/constants/time';
import {
isPrefixedFormattedHexString,
isSafeChainId,
@ -31,7 +30,7 @@ import createInfuraClient from './createInfuraClient';
import createJsonRpcClient from './createJsonRpcClient';
const env = process.env.METAMASK_ENV;
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
let defaultProviderConfigOpts;
if (process.env.IN_TEST) {
@ -142,7 +141,7 @@ export default class NetworkController extends EventEmitter {
/**
* Method to return the latest block for the current network
*
* @returns {Object} Block header
* @returns {object} Block header
*/
getLatestBlock() {
return new Promise((resolve, reject) => {
@ -272,6 +271,11 @@ export default class NetworkController extends EventEmitter {
return NETWORK_TYPE_TO_ID_MAP[type]?.chainId || configChainId;
}
getCurrentRpcUrl() {
const { rpcUrl } = this.getProviderConfig();
return rpcUrl;
}
setRpcTarget(rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
assert.ok(
isPrefixedFormattedHexString(chainId),

@ -68,8 +68,7 @@ describe('PendingNonceMiddleware', () => {
from: '0xf231d46dd78806e1dd93442cf33c7671f8538748',
gas: GAS_LIMITS.SIMPLE,
gasPrice: '0x1e8480',
hash:
'0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09',
hash: '0x2cc5a25744486f7383edebbf32003e5a66e18135799593d6b5cdd2bb43674f09',
input: '0x',
nonce: '0x4',
type: TRANSACTION_ENVELOPE_TYPES.LEGACY,

@ -25,8 +25,7 @@ describe('network utils', () => {
chainId: '0x3',
time: 1624408066355,
metamaskNetworkId: '3',
hash:
'0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
hash: '0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
r: '0x4c3111e42ed5eec3dcecba1e234700f387e8693c373c61c3e54a762a26f1570e',
s: '0x18bfc4eeb7ebcfacc3bd59ea100a6834ea3265e65945dbec69aa2a06564fafff',
v: '0x29',
@ -38,8 +37,7 @@ describe('network utils', () => {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
gas: '0x7b0d',
gasPrice: '0x77359400',
hash:
'0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
hash: '0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
input: '0x',
maxFeePerGas: '0x77359400',
maxPriorityFeePerGas: '0x77359400',
@ -72,8 +70,7 @@ describe('network utils', () => {
chainId: '0x3',
time: 1624408066355,
metamaskNetworkId: '3',
hash:
'0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
hash: '0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
r: '0x4c3111e42ed5eec3dcecba1e234700f387e8693c373c61c3e54a762a26f1570e',
s: '0x18bfc4eeb7ebcfacc3bd59ea100a6834ea3265e65945dbec69aa2a06564fafff',
v: '0x29',
@ -84,8 +81,7 @@ describe('network utils', () => {
blockNumber: null,
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
gas: '0x7b0d',
hash:
'0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
hash: '0x4bcb6cd6b182209585f8ad140260ddb35c81a575dd40f508d9767e652a9f60e7',
input: '0x',
gasPrice: '0x77359400',
nonce: '0x4b',

@ -2,13 +2,13 @@ import { ObservableStore } from '@metamask/obs-store';
import log from 'loglevel';
/**
* @typedef {Object} InitState
* @typedef {object} InitState
* @property {boolean} seedPhraseBackedUp Indicates whether the user has completed the seed phrase backup challenge
* @property {boolean} completedOnboarding Indicates whether the user has completed the onboarding flow
*/
/**
* @typedef {Object} OnboardingOptions
* @typedef {object} OnboardingOptions
* @property {InitState} initState The initial controller state
*/

@ -4,9 +4,8 @@ import { CaveatMutatorFactories } from './caveat-mutators';
describe('caveat mutators', () => {
describe('restrictReturnedAccounts', () => {
const { removeAccount } = CaveatMutatorFactories[
CaveatTypes.restrictReturnedAccounts
];
const { removeAccount } =
CaveatMutatorFactories[CaveatTypes.restrictReturnedAccounts];
describe('removeAccount', () => {
it('returns the no-op operation if the target account is not permitted', () => {

@ -27,7 +27,7 @@ export class PermissionLogController {
/**
* Get the restricted method activity log.
*
* @returns {Array<Object>} The activity log.
* @returns {Array<object>} The activity log.
*/
getActivityLog() {
return this.store.getState().permissionActivityLog;
@ -36,7 +36,7 @@ export class PermissionLogController {
/**
* Update the restricted method activity log.
*
* @param {Array<Object>} logs - The new activity log array.
* @param {Array<object>} logs - The new activity log array.
*/
updateActivityLog(logs) {
this.store.updateState({ permissionActivityLog: logs });
@ -45,7 +45,7 @@ export class PermissionLogController {
/**
* Get the permission history log.
*
* @returns {Object} The permissions history log.
* @returns {object} The permissions history log.
*/
getHistory() {
return this.store.getState().permissionHistory;
@ -54,7 +54,7 @@ export class PermissionLogController {
/**
* Update the permission history log.
*
* @param {Object} history - The new permissions history log object.
* @param {object} history - The new permissions history log object.
*/
updateHistory(history) {
this.store.updateState({ permissionHistory: history });
@ -146,7 +146,7 @@ export class PermissionLogController {
/**
* Creates and commits an activity log entry, without response data.
*
* @param {Object} request - The request object.
* @param {object} request - The request object.
* @param {boolean} isInternal - Whether the request is internal.
*/
logRequest(request, isInternal) {
@ -169,8 +169,8 @@ export class PermissionLogController {
* Adds response data to an existing activity log entry.
* Entry assumed already committed (i.e., in the log).
*
* @param {Object} entry - The entry to add a response to.
* @param {Object} response - The response object.
* @param {object} entry - The entry to add a response to.
* @param {object} response - The response object.
* @param {number} time - Output from Date.now()
*/
logResponse(entry, response, time) {
@ -190,7 +190,7 @@ export class PermissionLogController {
* Commit a new entry to the activity log.
* Removes the oldest entry from the log if it exceeds the log limit.
*
* @param {Object} entry - The activity log entry.
* @param {object} entry - The activity log entry.
*/
commitNewActivity(entry) {
const logs = this.getActivityLog();
@ -277,7 +277,7 @@ export class PermissionLogController {
* with the same key (permission name).
*
* @param {string} origin - The requesting origin.
* @param {Object} newEntries - The new entries to commit.
* @param {object} newEntries - The new entries to commit.
*/
commitNewHistory(origin, newEntries) {
// a simple merge updates most permissions
@ -318,7 +318,7 @@ export class PermissionLogController {
/**
* Get all requested methods from a permissions request.
*
* @param {Object} request - The request object.
* @param {object} request - The request object.
* @returns {Array<string>} The names of the requested permissions.
*/
getRequestedMethods(request) {
@ -337,7 +337,7 @@ export class PermissionLogController {
* Get the permitted accounts from an eth_accounts permissions object.
* Returns an empty array if the permission is not eth_accounts.
*
* @param {Object} perm - The permissions object.
* @param {object} perm - The permissions object.
* @returns {Array<string>} The permitted accounts.
*/
getAccountsFromPermission(perm) {
@ -367,7 +367,7 @@ export class PermissionLogController {
*
* @param {Array<string>} accounts - An array of addresses.
* @param {number} time - A time, e.g. Date.now().
* @returns {Object} A string:number map of addresses to time.
* @returns {object} A string:number map of addresses to time.
*/
function getAccountToTimeMap(accounts, time) {
return accounts.reduce((acc, account) => ({ ...acc, [account]: time }), {});

@ -639,9 +639,9 @@ describe('PermissionLogController', () => {
* Validates an activity log entry with respect to a request, response, and
* relevant metadata.
*
* @param {Object} entry - The activity log entry to validate.
* @param {Object} req - The request that generated the entry.
* @param {Object} [res] - The response for the request, if any.
* @param {object} entry - The activity log entry to validate.
* @param {object} req - The request that generated the entry.
* @param {object} [res] - The response for the request, if any.
* @param {'restricted'|'internal'} methodType - The method log controller method type of the request.
* @param {boolean} success - Whether the request succeeded or not.
*/

@ -31,7 +31,7 @@ const CaveatFactories = Object.freeze({
/**
* A PreferencesController identity object.
*
* @typedef {Object} Identity
* @typedef {object} Identity
* @property {string} address - The address of the identity.
* @property {string} name - The name of the identity.
* @property {number} [lastSelected] - Unix timestamp of when the identity was

@ -14,17 +14,17 @@ import { NETWORK_EVENTS } from './network';
export default class PreferencesController {
/**
*
* @typedef {Object} PreferencesController
* @param {Object} opts - Overrides the defaults for the initial state of this.store
* @property {Object} store The stored object containing a users preferences, stored in local storage
* @typedef {object} PreferencesController
* @param {object} opts - Overrides the defaults for the initial state of this.store
* @property {object} store The stored object containing a users preferences, stored in local storage
* @property {Array} store.frequentRpcList A list of custom rpcs to provide the user
* @property {boolean} store.useBlockie The users preference for blockie identicons within the UI
* @property {boolean} store.useNonceField The users preference for nonce field within the UI
* @property {Object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the
* @property {object} store.featureFlags A key-boolean map, where keys refer to features and booleans to whether the
* user wishes to see that feature.
*
* Feature flags can be set by the global function `setPreference(feature, enabled)`, and so should not expose any sensitive behavior.
* @property {Object} store.knownMethodData Contains all data methods known by the user
* @property {object} store.knownMethodData Contains all data methods known by the user
* @property {string} store.currentLocale The preferred language locale key
* @property {string} store.selectedAddress A hex string that matches the currently selected address in the app
*/
@ -376,12 +376,12 @@ export default class PreferencesController {
/**
* updates custom RPC details
*
* @param {Object} newRpcDetails - Options bag.
* @param {object} newRpcDetails - Options bag.
* @param {string} newRpcDetails.rpcUrl - The RPC url to add to frequentRpcList.
* @param {string} newRpcDetails.chainId - The chainId of the selected network.
* @param {string} [newRpcDetails.ticker] - Optional ticker symbol of the selected network.
* @param {string} [newRpcDetails.nickname] - Optional nickname of the selected network.
* @param {Object} [newRpcDetails.rpcPrefs] - Optional RPC preferences, such as the block explorer URL
* @param {object} [newRpcDetails.rpcPrefs] - Optional RPC preferences, such as the block explorer URL
*/
async updateRpc(newRpcDetails) {
const rpcList = this.getFrequentRpcListDetail();
@ -456,7 +456,7 @@ export default class PreferencesController {
* @param {string} chainId - The chainId of the selected network.
* @param {string} [ticker] - Ticker symbol of the selected network.
* @param {string} [nickname] - Nickname of the selected network.
* @param {Object} [rpcPrefs] - Optional RPC preferences, such as the block explorer URL
* @param {object} [rpcPrefs] - Optional RPC preferences, such as the block explorer URL
*/
addToFrequentRpcList(
rpcUrl,
@ -550,7 +550,7 @@ export default class PreferencesController {
/**
* A getter for the `preferences` property
*
* @returns {Object} A key-boolean map of user-selected preferences.
* @returns {object} A key-boolean map of user-selected preferences.
*/
getPreferences() {
return this.store.getState().preferences;

@ -90,7 +90,8 @@ const initialState = {
swapsQuoteRefreshTime: FALLBACK_QUOTE_REFRESH_TIME,
swapsQuotePrefetchingRefreshTime: FALLBACK_QUOTE_REFRESH_TIME,
swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime:
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxMaxFeeMultiplier: FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
swapsFeatureFlags: {},
},
@ -336,10 +337,8 @@ export default class SwapsController {
if (Object.values(newQuotes).length === 0) {
this.setSwapsErrorKey(QUOTES_NOT_AVAILABLE_ERROR);
} else {
const [
_topAggId,
quotesWithSavingsAndFeeData,
] = await this._findTopQuoteAndCalculateSavings(newQuotes);
const [_topAggId, quotesWithSavingsAndFeeData] =
await this._findTopQuoteAndCalculateSavings(newQuotes);
topAggId = _topAggId;
newQuotes = quotesWithSavingsAndFeeData;
}
@ -486,10 +485,8 @@ export default class SwapsController {
const quoteToUpdate = { ...swapsState.quotes[initialAggId] };
const {
gasLimit: newGasEstimate,
simulationFails,
} = await this.timedoutGasReturn(quoteToUpdate.trade);
const { gasLimit: newGasEstimate, simulationFails } =
await this.timedoutGasReturn(quoteToUpdate.trade);
if (newGasEstimate && !simulationFails) {
const gasEstimateWithRefund = calculateGasEstimateWithRefund(
@ -637,9 +634,8 @@ export default class SwapsController {
}
async _findTopQuoteAndCalculateSavings(quotes = {}) {
const {
contractExchangeRates: tokenConversionRates,
} = this.getTokenRatesState();
const { contractExchangeRates: tokenConversionRates } =
this.getTokenRatesState();
const {
swapsState: { customGasPrice, customMaxPriorityFeePerGas },
} = this.store.getState();
@ -652,10 +648,8 @@ export default class SwapsController {
const newQuotes = cloneDeep(quotes);
const {
gasFeeEstimates,
gasEstimateType,
} = await this._getEIP1559GasFeeEstimates();
const { gasFeeEstimates, gasEstimateType } =
await this._getEIP1559GasFeeEstimates();
let usedGasPrice = '0x0';
@ -756,9 +750,8 @@ export default class SwapsController {
const tokenPercentageOfPreFeeDestAmount = new BigNumber(100, 10)
.minus(metaMaskFee, 10)
.div(100);
const destinationAmountBeforeMetaMaskFee = decimalAdjustedDestinationAmount.div(
tokenPercentageOfPreFeeDestAmount,
);
const destinationAmountBeforeMetaMaskFee =
decimalAdjustedDestinationAmount.div(tokenPercentageOfPreFeeDestAmount);
const metaMaskFeeInTokens = destinationAmountBeforeMetaMaskFee.minus(
decimalAdjustedDestinationAmount,
);
@ -883,7 +876,7 @@ export default class SwapsController {
* Calculates the median overallValueOfQuote of a sample of quotes.
*
* @param {Array} _quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth, and ethValueOfTokens properties
* @returns {Object} An object with the ethValueOfTokens, ethFee, and metaMaskFeeInEth of the quote with the median overallValueOfQuote
* @returns {object} An object with the ethValueOfTokens, ethFee, and metaMaskFeeInEth of the quote with the median overallValueOfQuote
*/
function getMedianEthValueQuote(_quotes) {
if (!Array.isArray(_quotes) || _quotes.length === 0) {
@ -960,7 +953,7 @@ function getMedianEthValueQuote(_quotes) {
*
* @param {Array} quotes - A sample of quote objects with overallValueOfQuote, ethFee, metaMaskFeeInEth and
* ethValueOfTokens properties
* @returns {Object} An object with the arithmetic mean each of the ethFee, metaMaskFeeInEth and ethValueOfTokens of
* @returns {object} An object with the arithmetic mean each of the ethFee, metaMaskFeeInEth and ethValueOfTokens of
* the passed quote objects
*/
function meansOfQuotesFeesAndValue(quotes) {

@ -42,8 +42,7 @@ const TEST_AGG_ID_APPROVAL = 'TEST_AGG_APPROVAL';
const POLLING_TIMEOUT = SECOND * 1000;
const MOCK_APPROVAL_NEEDED = {
data:
'0x095ea7b300000000000000000000000095e6f48254609a6ee006f7d493c8e5fb97094cef0000000000000000000000000000000000000000004a817c7ffffffdabf41c00',
data: '0x095ea7b300000000000000000000000095e6f48254609a6ee006f7d493c8e5fb97094cef0000000000000000000000000000000000000000004a817c7ffffffdabf41c00',
to: '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2',
amount: '0',
from: '0x2369267687A84ac7B494daE2f1542C40E37f4455',
@ -139,7 +138,8 @@ const EMPTY_INIT_STATE = {
swapsQuoteRefreshTime: 60000,
swapsQuotePrefetchingRefreshTime: 60000,
swapsStxBatchStatusRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime: FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxGetTransactionsRefreshTime:
FALLBACK_SMART_TRANSACTIONS_REFRESH_TIME,
swapsStxMaxFeeMultiplier: FALLBACK_SMART_TRANSACTIONS_MAX_FEE_MULTIPLIER,
swapsUserFeeLevel: '',
saveFetchedQuotes: false,
@ -370,13 +370,10 @@ describe('SwapsController', function () {
baseGasEstimate,
);
const {
gasLimit: bufferedGasLimit,
} = await swapsController.getBufferedGasLimit();
const {
gasEstimate,
gasEstimateWithRefund,
} = swapsController.store.getState().swapsState.quotes[initialAggId];
const { gasLimit: bufferedGasLimit } =
await swapsController.getBufferedGasLimit();
const { gasEstimate, gasEstimateWithRefund } =
swapsController.store.getState().swapsState.quotes[initialAggId];
assert.strictEqual(gasEstimate, bufferedGasLimit);
assert.strictEqual(
gasEstimateWithRefund,
@ -416,12 +413,10 @@ describe('SwapsController', function () {
});
it('returns the top aggId and quotes with savings and fee values if passed necessary data and an even number of quotes', async function () {
const [
topAggId,
resultQuotes,
] = await swapsController._findTopQuoteAndCalculateSavings(
getTopQuoteAndSavingsMockQuotes(),
);
const [topAggId, resultQuotes] =
await swapsController._findTopQuoteAndCalculateSavings(
getTopQuoteAndSavingsMockQuotes(),
);
assert.equal(topAggId, TEST_AGG_ID_1);
assert.deepStrictEqual(
resultQuotes,
@ -442,10 +437,8 @@ describe('SwapsController', function () {
medianMetaMaskFee: '0.0202',
};
const [
topAggId,
resultQuotes,
] = await swapsController._findTopQuoteAndCalculateSavings(testInput);
const [topAggId, resultQuotes] =
await swapsController._findTopQuoteAndCalculateSavings(testInput);
assert.equal(topAggId, TEST_AGG_ID_1);
assert.deepStrictEqual(resultQuotes, expectedResultQuotes);
});
@ -485,10 +478,8 @@ describe('SwapsController', function () {
},
};
const [
topAggId,
resultQuotes,
] = await swapsController._findTopQuoteAndCalculateSavings(testInput);
const [topAggId, resultQuotes] =
await swapsController._findTopQuoteAndCalculateSavings(testInput);
assert.equal(topAggId, TEST_AGG_ID_1);
assert.deepStrictEqual(resultQuotes, expectedResultQuotes);
});
@ -503,7 +494,8 @@ describe('SwapsController', function () {
trade: { value: '0x8ac7230489e80000' },
}),
);
const baseExpectedResultQuotes = getTopQuoteAndSavingsBaseExpectedResults();
const baseExpectedResultQuotes =
getTopQuoteAndSavingsBaseExpectedResults();
const expectedResultQuotes = {
[TEST_AGG_ID_1]: {
...baseExpectedResultQuotes[TEST_AGG_ID_1],
@ -549,10 +541,8 @@ describe('SwapsController', function () {
},
};
const [
topAggId,
resultQuotes,
] = await swapsController._findTopQuoteAndCalculateSavings(testInput);
const [topAggId, resultQuotes] =
await swapsController._findTopQuoteAndCalculateSavings(testInput);
assert.equal(topAggId, TEST_AGG_ID_1);
assert.deepStrictEqual(resultQuotes, expectedResultQuotes);
});
@ -569,7 +559,8 @@ describe('SwapsController', function () {
);
// 0.04 ETH fee included in trade value
testInput[TEST_AGG_ID_1].trade.value = '0x8b553ece48ec0000';
const baseExpectedResultQuotes = getTopQuoteAndSavingsBaseExpectedResults();
const baseExpectedResultQuotes =
getTopQuoteAndSavingsBaseExpectedResults();
const expectedResultQuotes = {
[TEST_AGG_ID_1]: {
...baseExpectedResultQuotes[TEST_AGG_ID_1],
@ -626,10 +617,8 @@ describe('SwapsController', function () {
delete expectedResultQuotes[TEST_AGG_ID_1].isBestQuote;
delete expectedResultQuotes[TEST_AGG_ID_1].savings;
const [
topAggId,
resultQuotes,
] = await swapsController._findTopQuoteAndCalculateSavings(testInput);
const [topAggId, resultQuotes] =
await swapsController._findTopQuoteAndCalculateSavings(testInput);
assert.equal(topAggId, TEST_AGG_ID_2);
assert.deepStrictEqual(resultQuotes, expectedResultQuotes);
});
@ -638,7 +627,8 @@ describe('SwapsController', function () {
const testInput = getTopQuoteAndSavingsMockQuotes();
// 0.04 ETH fee included in trade value
testInput[TEST_AGG_ID_1].trade.value = '0x8e1bc9bf040000';
const baseExpectedResultQuotes = getTopQuoteAndSavingsBaseExpectedResults();
const baseExpectedResultQuotes =
getTopQuoteAndSavingsBaseExpectedResults();
const expectedResultQuotes = {
...baseExpectedResultQuotes,
[TEST_AGG_ID_1]: {
@ -662,10 +652,8 @@ describe('SwapsController', function () {
delete expectedResultQuotes[TEST_AGG_ID_1].isBestQuote;
delete expectedResultQuotes[TEST_AGG_ID_1].savings;
const [
topAggId,
resultQuotes,
] = await swapsController._findTopQuoteAndCalculateSavings(testInput);
const [topAggId, resultQuotes] =
await swapsController._findTopQuoteAndCalculateSavings(testInput);
assert.equal(topAggId, TEST_AGG_ID_2);
assert.deepStrictEqual(resultQuotes, expectedResultQuotes);
});

@ -225,9 +225,8 @@ export default class ThreeBoxController {
PreferencesController: preferences,
AddressBookController: addressBook,
};
const initialMigrationState = migrator.generateInitialState(
formattedStateBackup,
);
const initialMigrationState =
migrator.generateInitialState(formattedStateBackup);
const migratedState = await migrator.migrateData(initialMigrationState);
return {
preferences: migratedState.data.PreferencesController,

@ -85,7 +85,7 @@ const VALID_UNAPPROVED_TRANSACTION_TYPES = [
const METRICS_STATUS_FAILED = 'failed on-chain';
/**
* @typedef {Object} CustomGasSettings
* @typedef {object} CustomGasSettings
* @property {string} [gas] - The gas limit to use for the transaction
* @property {string} [gasPrice] - The gasPrice to use for a legacy transaction
* @property {string} [maxFeePerGas] - The maximum amount to pay per gas on a
@ -109,16 +109,16 @@ const METRICS_STATUS_FAILED = 'failed on-chain';
* - nonceTracker
* calculating nonces
*
* @param {Object} opts
* @param {Object} opts.initState - initial transaction list default is an empty array
* @param {Object} opts.networkStore - an observable store for network number
* @param {Object} opts.blockTracker - An instance of eth-blocktracker
* @param {Object} opts.provider - A network provider.
* @param {object} opts
* @param {object} opts.initState - initial transaction list default is an empty array
* @param {object} opts.networkStore - an observable store for network number
* @param {object} opts.blockTracker - An instance of eth-blocktracker
* @param {object} opts.provider - A network provider.
* @param {Function} opts.signTransaction - function the signs an @ethereumjs/tx
* @param {Object} opts.getPermittedAccounts - get accounts that an origin has permissions for
* @param {object} opts.getPermittedAccounts - get accounts that an origin has permissions for
* @param {Function} opts.signTransaction - ethTx signer that returns a rawTx
* @param {number} [opts.txHistoryLimit] - number *optional* for limiting how many transactions are in state
* @param {Object} opts.preferencesStore
* @param {object} opts.preferencesStore
*/
export default class TransactionController extends EventEmitter {
@ -174,9 +174,8 @@ export default class TransactionController extends EventEmitter {
);
return [...pendingTransactions, ...externalPendingTransactions];
},
getConfirmedTransactions: this.txStateManager.getConfirmedTransactions.bind(
this.txStateManager,
),
getConfirmedTransactions:
this.txStateManager.getConfirmedTransactions.bind(this.txStateManager),
});
this.pendingTxTracker = new PendingTransactionTracker({
@ -189,9 +188,8 @@ export default class TransactionController extends EventEmitter {
return [...pending, ...approved];
},
approveTransaction: this.approveTransaction.bind(this),
getCompletedTransactions: this.txStateManager.getConfirmedTransactions.bind(
this.txStateManager,
),
getCompletedTransactions:
this.txStateManager.getConfirmedTransactions.bind(this.txStateManager),
});
this.txStateManager.store.subscribe(() =>
@ -227,10 +225,10 @@ export default class TransactionController extends EventEmitter {
}
async getEIP1559Compatibility(fromAddress) {
const currentNetworkIsCompatible = await this._getCurrentNetworkEIP1559Compatibility();
const fromAccountIsCompatible = await this._getCurrentAccountEIP1559Compatibility(
fromAddress,
);
const currentNetworkIsCompatible =
await this._getCurrentNetworkEIP1559Compatibility();
const fromAccountIsCompatible =
await this._getCurrentAccountEIP1559Compatibility(fromAddress);
return currentNetworkIsCompatible && fromAccountIsCompatible;
}
@ -313,8 +311,8 @@ export default class TransactionController extends EventEmitter {
* Add a new unapproved transaction to the pipeline
*
* @returns {Promise<string>} the hash of the transaction after being submitted to the network
* @param {Object} txParams - txParams for the transaction
* @param {Object} opts - with the key origin to put the origin on the txMeta
* @param {object} txParams - txParams for the transaction
* @param {object} opts - with the key origin to put the origin on the txMeta
*/
async newUnapprovedTransaction(txParams, opts = {}) {
log.debug(
@ -802,7 +800,7 @@ export default class TransactionController extends EventEmitter {
/**
* Adds the tx gas defaults: gas && gasPrice
*
* @param {Object} txMeta - the txMeta object
* @param {object} txMeta - the txMeta object
* @param getCodeResponse
* @returns {Promise<object>} resolves with txMeta
*/
@ -815,10 +813,8 @@ export default class TransactionController extends EventEmitter {
maxFeePerGas: defaultMaxFeePerGas,
maxPriorityFeePerGas: defaultMaxPriorityFeePerGas,
} = await this._getDefaultGasFees(txMeta, eip1559Compatibility);
const {
gasLimit: defaultGasLimit,
simulationFails,
} = await this._getDefaultGasLimit(txMeta, getCodeResponse);
const { gasLimit: defaultGasLimit, simulationFails } =
await this._getDefaultGasLimit(txMeta, getCodeResponse);
// eslint-disable-next-line no-param-reassign
txMeta = this.txStateManager.getTransaction(txMeta.id);
@ -945,7 +941,7 @@ export default class TransactionController extends EventEmitter {
/**
* Gets default gas fees, or returns `undefined` if gas fees are already set
*
* @param {Object} txMeta - The txMeta object
* @param {object} txMeta - The txMeta object
* @param eip1559Compatibility
* @returns {Promise<string|undefined>} The default gas price
*/
@ -960,10 +956,8 @@ export default class TransactionController extends EventEmitter {
}
try {
const {
gasFeeEstimates,
gasEstimateType,
} = await this._getEIP1559GasFeeEstimates();
const { gasFeeEstimates, gasEstimateType } =
await this._getEIP1559GasFeeEstimates();
if (
eip1559Compatibility &&
gasEstimateType === GAS_ESTIMATE_TYPES.FEE_MARKET
@ -1005,8 +999,8 @@ export default class TransactionController extends EventEmitter {
/**
* Gets default gas limit, or debug information about why gas estimate failed.
*
* @param {Object} txMeta - The txMeta object
* @returns {Promise<Object>} Object containing the default gas limit, or the simulation failure object
* @param {object} txMeta - The txMeta object
* @returns {Promise<object>} Object containing the default gas limit, or the simulation failure object
*/
async _getDefaultGasLimit(txMeta) {
const chainId = this._getCurrentChainId();
@ -1025,11 +1019,8 @@ export default class TransactionController extends EventEmitter {
return { gasLimit: GAS_LIMITS.SIMPLE };
}
const {
blockGasLimit,
estimatedGasHex,
simulationFails,
} = await this.txGasUtil.analyzeGasUsage(txMeta);
const { blockGasLimit, estimatedGasHex, simulationFails } =
await this.txGasUtil.analyzeGasUsage(txMeta);
// add additional gas buffer to our estimation for safety
const gasLimit = this.txGasUtil.addGasBuffer(
@ -1203,6 +1194,7 @@ export default class TransactionController extends EventEmitter {
loadingDefaults: false,
status: TRANSACTION_STATUSES.APPROVED,
type: TRANSACTION_TYPES.RETRY,
originalType: originalTxMeta.type,
});
if (estimatedBaseFee) {
@ -1217,7 +1209,7 @@ export default class TransactionController extends EventEmitter {
/**
* updates the txMeta in the txStateManager
*
* @param {Object} txMeta - the updated txMeta
* @param {object} txMeta - the updated txMeta
*/
async updateTransaction(txMeta) {
this.txStateManager.updateTransaction(
@ -1229,7 +1221,7 @@ export default class TransactionController extends EventEmitter {
/**
* updates and approves the transaction
*
* @param {Object} txMeta
* @param {object} txMeta
*/
async updateAndApproveTransaction(txMeta) {
this.txStateManager.updateTransaction(
@ -1531,9 +1523,8 @@ export default class TransactionController extends EventEmitter {
const metricsParams = { gas_used: gasUsed };
if (submittedTime) {
metricsParams.completion_time = this._getTransactionCompletionTime(
submittedTime,
);
metricsParams.completion_time =
this._getTransactionCompletionTime(submittedTime);
}
if (txReceipt.status === '0x0') {
@ -1592,9 +1583,8 @@ export default class TransactionController extends EventEmitter {
const metricsParams = { gas_used: gasUsed };
if (submittedTime) {
metricsParams.completion_time = this._getTransactionCompletionTime(
submittedTime,
);
metricsParams.completion_time =
this._getTransactionCompletionTime(submittedTime);
}
if (txReceipt.status === '0x0') {
@ -1659,10 +1649,8 @@ export default class TransactionController extends EventEmitter {
*/
async createTransactionEventFragment(transactionId, event) {
const txMeta = this.txStateManager.getTransaction(transactionId);
const {
properties,
sensitiveProperties,
} = await this._buildEventFragmentProperties(txMeta);
const { properties, sensitiveProperties } =
await this._buildEventFragmentProperties(txMeta);
this._createTransactionEventFragment(
txMeta,
event,
@ -1676,7 +1664,7 @@ export default class TransactionController extends EventEmitter {
//
/** maps methods for convenience*/
_mapMethods() {
/** @returns {Object} the state in transaction controller */
/** @returns {object} the state in transaction controller */
this.getState = () => this.memStore.getState();
/** @returns {string|number} the network number stored in networkStore */
@ -1840,6 +1828,7 @@ export default class TransactionController extends EventEmitter {
return;
}
otherTxMeta.replacedBy = txMeta.hash;
otherTxMeta.replacedById = txMeta.id;
this.txStateManager.updateTransaction(
txMeta,
'transactions/pending-tx-tracker#event: tx:confirmed reference to confirmed txHash with same nonce',
@ -1978,6 +1967,7 @@ export default class TransactionController extends EventEmitter {
async _buildEventFragmentProperties(txMeta, extraParams) {
const {
id,
type,
time,
status,
@ -1992,8 +1982,11 @@ export default class TransactionController extends EventEmitter {
estimateUsed,
},
defaultGasEstimates,
originalType,
replacedById,
metamaskNetworkId: network,
} = txMeta;
const { transactions } = this.store.getState();
const source = referrer === ORIGIN_METAMASK ? 'user' : 'dapp';
const { assetType, tokenStandard } = await determineTransactionAssetType(
@ -2035,7 +2028,8 @@ export default class TransactionController extends EventEmitter {
if (gasFeeEstimates?.[estimateType]?.suggestedMaxPriorityFeePerGas) {
defaultMaxPriorityFeePerGas =
gasFeeEstimates[estimateType]?.suggestedMaxPriorityFeePerGas;
gasParams.default_max_priority_fee_per_gas = defaultMaxPriorityFeePerGas;
gasParams.default_max_priority_fee_per_gas =
defaultMaxPriorityFeePerGas;
}
}
}
@ -2068,12 +2062,54 @@ export default class TransactionController extends EventEmitter {
eip1559Version = eip1559V2Enabled ? '2' : '1';
}
const contractInteractionTypes = [
TRANSACTION_TYPES.CONTRACT_INTERACTION,
TRANSACTION_TYPES.TOKEN_METHOD_APPROVE,
TRANSACTION_TYPES.TOKEN_METHOD_SAFE_TRANSFER_FROM,
TRANSACTION_TYPES.TOKEN_METHOD_SET_APPROVAL_FOR_ALL,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER,
TRANSACTION_TYPES.TOKEN_METHOD_TRANSFER_FROM,
TRANSACTION_TYPES.SMART,
TRANSACTION_TYPES.SWAP,
TRANSACTION_TYPES.SWAP_APPROVAL,
].includes(type);
let transactionType = TRANSACTION_TYPES.SIMPLE_SEND;
let transactionContractMethod;
if (type === TRANSACTION_TYPES.CANCEL) {
transactionType = TRANSACTION_TYPES.CANCEL;
} else if (type === TRANSACTION_TYPES.RETRY) {
transactionType = originalType;
} else if (type === TRANSACTION_TYPES.DEPLOY_CONTRACT) {
transactionType = TRANSACTION_TYPES.DEPLOY_CONTRACT;
} else if (contractInteractionTypes) {
transactionType = TRANSACTION_TYPES.CONTRACT_INTERACTION;
transactionContractMethod = transactions[id]?.contractMethodName;
}
const replacedTxMeta = this._getTransaction(replacedById);
const TRANSACTION_REPLACEMENT_METHODS = {
RETRY: TRANSACTION_TYPES.RETRY,
CANCEL: TRANSACTION_TYPES.CANCEL,
SAME_NONCE: 'other',
};
let transactionReplaced;
if (extraParams?.dropped) {
transactionReplaced = TRANSACTION_REPLACEMENT_METHODS.SAME_NONCE;
if (replacedTxMeta?.type === TRANSACTION_TYPES.CANCEL) {
transactionReplaced = TRANSACTION_REPLACEMENT_METHODS.CANCEL;
} else if (replacedTxMeta?.type === TRANSACTION_TYPES.RETRY) {
transactionReplaced = TRANSACTION_REPLACEMENT_METHODS.RETRY;
}
}
const properties = {
chain_id: chainId,
referrer,
source,
network,
type,
eip_1559_version: eip1559Version,
gas_edit_type: 'none',
gas_edit_attempted: 'none',
@ -2081,6 +2117,8 @@ export default class TransactionController extends EventEmitter {
device_model: await this.getDeviceModel(this.getSelectedAddress()),
asset_type: assetType,
token_standard: tokenStandard,
transaction_type: transactionType,
transaction_speed_up: type === TRANSACTION_TYPES.RETRY,
};
const sensitiveProperties = {
@ -2090,6 +2128,8 @@ export default class TransactionController extends EventEmitter {
: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
first_seen: time,
gas_limit: gasLimit,
transaction_contract_method: transactionContractMethod,
transaction_replaced: transactionReplaced,
...extraParams,
...gasParamsInGwei,
};
@ -2106,8 +2146,8 @@ export default class TransactionController extends EventEmitter {
* @param {TransactionMeta} txMeta - Transaction meta object
* @param {TransactionMetaMetricsEventString} event - The event type that
* triggered fragment creation
* @param {Object} properties - properties to include in the fragment
* @param {Object} [sensitiveProperties] - sensitive properties to include in
* @param {object} properties - properties to include in the fragment
* @param {object} [sensitiveProperties] - sensitive properties to include in
* the fragment
*/
_createTransactionEventFragment(
@ -2220,18 +2260,16 @@ export default class TransactionController extends EventEmitter {
* object and uses them to create and send metrics for various transaction
* events.
*
* @param {Object} txMeta - the txMeta object
* @param {object} txMeta - the txMeta object
* @param {TransactionMetaMetricsEventString} event - the name of the transaction event
* @param {Object} extraParams - optional props and values to include in sensitiveProperties
* @param {object} extraParams - optional props and values to include in sensitiveProperties
*/
async _trackTransactionMetricsEvent(txMeta, event, extraParams = {}) {
if (!txMeta) {
return;
}
const {
properties,
sensitiveProperties,
} = await this._buildEventFragmentProperties(txMeta, extraParams);
const { properties, sensitiveProperties } =
await this._buildEventFragmentProperties(txMeta, extraParams);
// Create event fragments for event types that spawn fragments, and ensure
// existence of fragments for event types that act upon them.
@ -2300,6 +2338,8 @@ export default class TransactionController extends EventEmitter {
_dropTransaction(txId) {
this.txStateManager.setTxStatusDropped(txId);
const txMeta = this.txStateManager.getTransaction(txId);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.FINALIZED);
this._trackTransactionMetricsEvent(txMeta, TRANSACTION_EVENTS.FINALIZED, {
dropped: true,
});
}
}

@ -17,6 +17,7 @@ import {
TRANSACTION_ENVELOPE_TYPES,
TRANSACTION_EVENTS,
ASSET_TYPES,
TOKEN_STANDARDS,
} from '../../../../shared/constants/transaction';
import { SECOND } from '../../../../shared/constants/time';
@ -26,7 +27,6 @@ import {
} from '../../../../shared/constants/gas';
import { TRANSACTION_ENVELOPE_TYPE_NAMES } from '../../../../ui/helpers/constants/transactions';
import { METAMASK_CONTROLLER_EVENTS } from '../../metamask-controller';
import { TOKEN_STANDARDS } from '../../../../ui/helpers/constants/common';
import { ORIGIN_METAMASK } from '../../../../shared/constants/app';
import TransactionController from '.';
@ -1471,17 +1471,20 @@ describe('Transaction Controller', function () {
network: '42',
referrer: ORIGIN_METAMASK,
source: EVENT.SOURCE.TRANSACTION.USER,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
@ -1550,17 +1553,20 @@ describe('Transaction Controller', function () {
network: '42',
referrer: ORIGIN_METAMASK,
source: EVENT.SOURCE.TRANSACTION.USER,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
@ -1639,17 +1645,20 @@ describe('Transaction Controller', function () {
network: '42',
referrer: 'other',
source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
@ -1720,17 +1729,20 @@ describe('Transaction Controller', function () {
network: '42',
referrer: 'other',
source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
default_gas: '0.000031501',
default_gas_price: '2',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
@ -1801,15 +1813,18 @@ describe('Transaction Controller', function () {
network: '42',
referrer: 'other',
source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
@ -1860,7 +1875,7 @@ describe('Transaction Controller', function () {
network: '42',
referrer: 'other',
source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
chain_id: '0x2a',
eip_1559_version: '0',
gas_edit_attempted: 'none',
@ -1869,12 +1884,15 @@ describe('Transaction Controller', function () {
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
baz: 3.0,
foo: 'bar',
gas_price: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.LEGACY,
status: 'unapproved',
@ -1937,11 +1955,12 @@ describe('Transaction Controller', function () {
network: '42',
referrer: 'other',
source: EVENT.SOURCE.TRANSACTION.DAPP,
type: TRANSACTION_TYPES.SIMPLE_SEND,
transaction_type: TRANSACTION_TYPES.SIMPLE_SEND,
account_type: 'MetaMask',
asset_type: ASSET_TYPES.NATIVE,
token_standard: TOKEN_STANDARDS.NONE,
device_model: 'N/A',
transaction_speed_up: false,
},
sensitiveProperties: {
baz: 3.0,
@ -1949,6 +1968,8 @@ describe('Transaction Controller', function () {
max_fee_per_gas: '2',
max_priority_fee_per_gas: '2',
gas_limit: '0x7b0d',
transaction_contract_method: undefined,
transaction_replaced: undefined,
first_seen: 1624408066355,
transaction_envelope_type: TRANSACTION_ENVELOPE_TYPE_NAMES.FEE_MARKET,
status: 'unapproved',
@ -2277,8 +2298,7 @@ describe('Transaction Controller', function () {
providerResultStub.eth_getCode = '0xab';
// test update gasFees
await txController.updateEditableParams('1', {
data:
'0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
data: '0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
});
const result = txStateManager.getTransaction('1');
assert.equal(
@ -2302,8 +2322,7 @@ describe('Transaction Controller', function () {
// maxFeePerGas: '0x004',
to: VALID_ADDRESS,
from: VALID_ADDRESS,
data:
'0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
data: '0xa9059cbb000000000000000000000000e18035bf8712672935fdb4e5e431b1a0183d2dfc0000000000000000000000000000000000000000000000000de0b6b3a7640000',
},
estimateUsed: '0x005',
estimatedBaseFee: '0x006',

@ -28,8 +28,8 @@ export function migrateFromSnapshotsToDiffs(longHistory) {
* value
* with the first entry having the note and a timestamp when the change took place
*
* @param {Object} previousState - the previous state of the object
* @param {Object} newState - the update object
* @param {object} previousState - the previous state of the object
* @param {object} newState - the update object
* @param {string} [note] - a optional note for the state change
* @returns {Array}
*/
@ -49,7 +49,7 @@ export function generateHistoryEntry(previousState, newState, note) {
* Recovers previous txMeta state obj
*
* @param _shortHistory
* @returns {Object}
* @returns {object}
*/
export function replayHistory(_shortHistory) {
const shortHistory = cloneDeep(_shortHistory);
@ -61,8 +61,8 @@ export function replayHistory(_shortHistory) {
/**
* Snapshot {@code txMeta}
*
* @param {Object} txMeta - the tx metadata object
* @returns {Object} a deep clone without history
* @param {object} txMeta - the tx metadata object
* @returns {object} a deep clone without history
*/
export function snapshotFromTxMeta(txMeta) {
const shallow = { ...txMeta };

@ -32,10 +32,10 @@ export function normalizeAndValidateTxParams(txParams, lowerCase = true) {
/**
* Normalizes the given txParams
*
* @param {Object} txParams - The transaction params
* @param {object} txParams - The transaction params
* @param {boolean} [lowerCase] - Whether to lowercase the 'to' address.
* Default: true
* @returns {Object} the normalized tx params
* @returns {object} the normalized tx params
*/
export function normalizeTxParams(txParams, lowerCase = true) {
// apply only keys in the normalizers
@ -52,7 +52,7 @@ export function normalizeTxParams(txParams, lowerCase = true) {
* Given two fields, ensure that the second field is not included in txParams,
* and if it is throw an invalidParams error.
*
* @param {Object} txParams - the transaction parameters object
* @param {object} txParams - the transaction parameters object
* @param {string} fieldBeingValidated - the current field being validated
* @param {string} mutuallyExclusiveField - the field to ensure is not provided
* @throws {ethErrors.rpc.invalidParams} Throws if mutuallyExclusiveField is
@ -74,7 +74,7 @@ function ensureMutuallyExclusiveFieldsNotProvided(
* Ensures that the provided value for field is a string, throws an
* invalidParams error if field is not a string.
*
* @param {Object} txParams - the transaction parameters object
* @param {object} txParams - the transaction parameters object
* @param {string} field - the current field being validated
* @throws {ethErrors.rpc.invalidParams} Throws if field is not a string
*/
@ -91,7 +91,7 @@ function ensureFieldIsString(txParams, field) {
* given field, if it is provided. If types do not match throws an
* invalidParams error.
*
* @param {Object} txParams - the transaction parameters object
* @param {object} txParams - the transaction parameters object
* @param {'gasPrice' | 'maxFeePerGas' | 'maxPriorityFeePerGas'} field - the
* current field being validated
* @throws {ethErrors.rpc.invalidParams} Throws if type does not match the
@ -126,7 +126,7 @@ function ensureProperTransactionEnvelopeTypeProvided(txParams, field) {
/**
* Validates the given tx parameters
*
* @param {Object} txParams - the tx params
* @param {object} txParams - the tx params
* @param {boolean} eip1559Compatibility - whether or not the current network supports EIP-1559 transactions
* @throws {Error} if the tx params contains invalid fields
*/
@ -227,7 +227,7 @@ export function validateTxParams(txParams, eip1559Compatibility = true) {
/**
* Validates the {@code from} field in the given tx params
*
* @param {Object} txParams
* @param {object} txParams
* @throws {Error} if the from address isn't valid
*/
export function validateFrom(txParams) {
@ -244,8 +244,8 @@ export function validateFrom(txParams) {
/**
* Validates the {@code to} field in the given tx params
*
* @param {Object} txParams - the tx params
* @returns {Object} the tx params
* @param {object} txParams - the tx params
* @returns {object} the tx params
* @throws {Error} if the recipient is invalid OR there isn't tx data
*/
export function validateRecipient(txParams) {

@ -29,14 +29,14 @@ export default class PendingTransactionTracker extends EventEmitter {
droppedBlocksBufferByHash = new Map();
/**
* @param {Object} config - Configuration.
* @param {object} config - Configuration.
* @param {Function} config.approveTransaction - Approves a transaction.
* @param {Function} config.confirmTransaction - Set a transaction as confirmed.
* @param {Function} config.getCompletedTransactions - Returns completed transactions.
* @param {Function} config.getPendingTransactions - Returns an array of pending transactions,
* @param {Object} config.nonceTracker - see nonce tracker
* @param {Object} config.provider - A network provider.
* @param {Object} config.query - An EthQuery instance.
* @param {object} config.nonceTracker - see nonce tracker
* @param {object} config.provider - A network provider.
* @param {object} config.query - An EthQuery instance.
* @param {Function} config.publishTransaction - Publishes a raw transaction,
*/
constructor(config) {
@ -119,7 +119,7 @@ export default class PendingTransactionTracker extends EventEmitter {
*
* Will only attempt to retry the given tx every {@code 2**(txMeta.retryCount)} blocks.
*
* @param {Object} txMeta - the transaction metadata
* @param {object} txMeta - the transaction metadata
* @param {string} latestBlockNumber - the latest block number in hex
* @returns {Promise<string|undefined>} the tx hash if retried
* @fires tx:block-update
@ -160,7 +160,7 @@ export default class PendingTransactionTracker extends EventEmitter {
/**
* Query the network to see if the given {@code txMeta} has been included in a block
*
* @param {Object} txMeta - the transaction metadata
* @param {object} txMeta - the transaction metadata
* @returns {Promise<void>}
* @fires tx:confirmed
* @fires tx:dropped
@ -198,13 +198,8 @@ export default class PendingTransactionTracker extends EventEmitter {
try {
const transactionReceipt = await this.query.getTransactionReceipt(txHash);
if (transactionReceipt?.blockNumber) {
const {
baseFeePerGas,
timestamp: blockTimestamp,
} = await this.query.getBlockByHash(
transactionReceipt?.blockHash,
false,
);
const { baseFeePerGas, timestamp: blockTimestamp } =
await this.query.getBlockByHash(transactionReceipt?.blockHash, false);
this.emit(
'tx:confirmed',
@ -232,7 +227,7 @@ export default class PendingTransactionTracker extends EventEmitter {
/**
* Checks whether the nonce in the given {@code txMeta} is behind the network nonce
*
* @param {Object} txMeta - the transaction metadata
* @param {object} txMeta - the transaction metadata
* @returns {Promise<boolean>}
* @private
*/
@ -265,7 +260,7 @@ export default class PendingTransactionTracker extends EventEmitter {
/**
* Checks whether the nonce in the given {@code txMeta} is correct against the local set of transactions
*
* @param {Object} txMeta - the transaction metadata
* @param {object} txMeta - the transaction metadata
* @returns {Promise<boolean>}
* @private
*/

@ -154,8 +154,7 @@ describe('PendingTransactionTracker', function () {
it('should call _checkPendingTx for each pending transaction', async function () {
const txMeta = {
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SIGNED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -212,8 +211,7 @@ describe('PendingTransactionTracker', function () {
it('should publish a new transaction', async function () {
const txMeta = {
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SIGNED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -257,8 +255,7 @@ describe('PendingTransactionTracker', function () {
it('should publish the given transaction if more than 2**retryCount blocks have passed', async function () {
const txMeta = {
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SIGNED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -304,8 +301,7 @@ describe('PendingTransactionTracker', function () {
it('should NOT publish the given transaction if fewer than 2**retryCount blocks have passed', async function () {
const txMeta = {
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SIGNED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -404,8 +400,7 @@ describe('PendingTransactionTracker', function () {
assert.ok(
await pendingTxTracker._checkIfTxWasDropped({
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SUBMITTED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -437,8 +432,7 @@ describe('PendingTransactionTracker', function () {
const dropped = await pendingTxTracker._checkIfTxWasDropped({
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SUBMITTED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -458,8 +452,7 @@ describe('PendingTransactionTracker', function () {
const confirmedTxList = [
{
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.CONFIRMED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -471,8 +464,7 @@ describe('PendingTransactionTracker', function () {
},
{
id: 2,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.CONFIRMED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -517,8 +509,7 @@ describe('PendingTransactionTracker', function () {
const confirmedTxList = [
{
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.CONFIRMED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -530,8 +521,7 @@ describe('PendingTransactionTracker', function () {
},
{
id: 2,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.CONFIRMED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -577,8 +567,7 @@ describe('PendingTransactionTracker', function () {
it("should emit 'tx:warning' if getTransactionReceipt rejects", async function () {
const txMeta = {
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SUBMITTED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',
@ -730,8 +719,7 @@ describe('PendingTransactionTracker', function () {
txParams: { nonce: '0x1' },
id: '123',
value: '0x02',
hash:
'0x2a919d2512ec963f524bfd9730fb66b6d5a2e399d1dd957abb5e2b544a12644b',
hash: '0x2a919d2512ec963f524bfd9730fb66b6d5a2e399d1dd957abb5e2b544a12644b',
},
];
const pendingTxTracker = new PendingTransactionTracker({
@ -774,8 +762,7 @@ describe('PendingTransactionTracker', function () {
const nonceBN = new BN(2);
const txMeta = {
id: 1,
hash:
'0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
hash: '0x0593ee121b92e10d63150ad08b4b8f9c7857d1bd160195ee648fb9a0f8d00eeb',
status: TRANSACTION_STATUSES.SUBMITTED,
txParams: {
from: '0x1678a085c290ebd122dc42cba69373b5953b831d',

@ -8,10 +8,10 @@ import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util';
* Result of gas analysis, including either a gas estimate for a successful analysis, or
* debug information for a failed analysis.
*
* @typedef {Object} GasAnalysisResult
* @typedef {object} GasAnalysisResult
* @property {string} blockGasLimit - The gas limit of the block used for the analysis
* @property {string} estimatedGasHex - The estimated gas, in hexadecimal
* @property {Object} simulationFails - Debug information about why an analysis failed
* @property {object} simulationFails - Debug information about why an analysis failed
*/
/**
@ -19,7 +19,7 @@ import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util';
* its passed ethquery
* and used to do things like calculate gas of a tx.
*
* @param {Object} provider - A network provider.
* @param {object} provider - A network provider.
*/
export default class TxGasUtil {
@ -28,7 +28,7 @@ export default class TxGasUtil {
}
/**
* @param {Object} txMeta - the txMeta object
* @param {object} txMeta - the txMeta object
* @returns {GasAnalysisResult} The result of the gas analysis
*/
async analyzeGasUsage(txMeta) {
@ -56,7 +56,7 @@ export default class TxGasUtil {
/**
* Estimates the tx's gas usage
*
* @param {Object} txMeta - the txMeta object
* @param {object} txMeta - the txMeta object
* @returns {string} the estimated gas limit as a hex string
*/
async estimateTxGas(txMeta) {
@ -102,11 +102,8 @@ export default class TxGasUtil {
}
async getBufferedGasLimit(txMeta, multiplier) {
const {
blockGasLimit,
estimatedGasHex,
simulationFails,
} = await this.analyzeGasUsage(txMeta);
const { blockGasLimit, estimatedGasHex, simulationFails } =
await this.analyzeGasUsage(txMeta);
// add additional gas buffer to our estimation for safety
const gasLimit = this.addGasBuffer(

@ -39,7 +39,7 @@ export const ERROR_SUBMITTING =
*/
/**
* @typedef {Object} TransactionState
* @typedef {object} TransactionState
* @property {Record<string, TransactionMeta>} transactions - TransactionMeta
* keyed by the transaction's id.
*/
@ -49,7 +49,7 @@ export const ERROR_SUBMITTING =
* storing the transaction. It also has some convenience methods for finding
* subsets of transactions.
*
* @param {Object} opts
* @param {object} opts
* @param {TransactionState} [opts.initState={ transactions: {} }] - initial
* transactions list keyed by id
* @param {number} [opts.txHistoryLimit] - limit for how many finished
@ -300,7 +300,7 @@ export default class TransactionStateManager extends EventEmitter {
/**
* updates the txMeta in the list and adds a history entry
*
* @param {Object} txMeta - the txMeta to update
* @param {object} txMeta - the txMeta to update
* @param {string} [note] - a note about the update for history
*/
updateTransaction(txMeta, note) {

@ -2,7 +2,7 @@
// eslint-disable-next-line import/unambiguous
if (
!(typeof process !== 'undefined' && process.env.METAMASK_DEBUG) &&
typeof console !== undefined
typeof console !== 'undefined'
) {
console.log = noop;
console.info = noop;

@ -1,7 +1,7 @@
/**
* @typedef {Object} FirstTimeState
* @property {Object} config Initial configuration parameters
* @property {Object} NetworkController Network controller state
* @typedef {object} FirstTimeState
* @property {object} config Initial configuration parameters
* @property {object} NetworkController Network controller state
*/
/**

@ -16,19 +16,19 @@ export default class ComposableObservableStore extends ObservableStore {
* extends one of the two base controllers in the `@metamask/controllers`
* package.
*
* @type {Record<string, Object>}
* @type {Record<string, object>}
*/
config = {};
/**
* Create a new store
*
* @param {Object} options
* @param {Object} [options.config] - Map of internal state keys to child stores
* @param {object} options
* @param {object} [options.config] - Map of internal state keys to child stores
* @param {ControllerMessenger} options.controllerMessenger - The controller
* messenger, used for subscribing to events from BaseControllerV2-based
* controllers.
* @param {Object} [options.state] - The initial store state
* @param {object} [options.state] - The initial store state
* @param {boolean} [options.persist] - Whether or not to apply the persistence for v2 controllers
*/
constructor({ config, controllerMessenger, state, persist }) {
@ -43,7 +43,7 @@ export default class ComposableObservableStore extends ObservableStore {
/**
* Composes a new internal store subscription structure
*
* @param {Record<string, Object>} config - Describes which stores are being
* @param {Record<string, object>} config - Describes which stores are being
* composed. The key is the name of the store, and the value is either an
* ObserableStore, or a controller that extends one of the two base
* controllers in the `@metamask/controllers` package.
@ -79,7 +79,7 @@ export default class ComposableObservableStore extends ObservableStore {
* Merges all child store state into a single object rather than
* returning an object keyed by child store class name
*
* @returns {Object} Object containing merged child store state
* @returns {object} Object containing merged child store state
*/
getFlatState() {
if (!this.config) {

@ -19,6 +19,13 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
KOVAN_CHAIN_ID,
GOERLI_CHAIN_ID,
BSC_CHAIN_ID,
OPTIMISM_CHAIN_ID,
POLYGON_CHAIN_ID,
AVALANCHE_CHAIN_ID,
FANTOM_CHAIN_ID,
ARBITRUM_CHAIN_ID,
} from '../../../shared/constants/network';
import {
@ -26,6 +33,13 @@ import {
SINGLE_CALL_BALANCES_ADDRESS_RINKEBY,
SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN,
SINGLE_CALL_BALANCES_ADDRESS_KOVAN,
SINGLE_CALL_BALANCES_ADDRESS_GOERLI,
SINGLE_CALL_BALANCES_ADDRESS_BSC,
SINGLE_CALL_BALANCES_ADDRESS_OPTIMISM,
SINGLE_CALL_BALANCES_ADDRESS_POLYGON,
SINGLE_CALL_BALANCES_ADDRESS_AVALANCHE,
SINGLE_CALL_BALANCES_ADDRESS_FANTOM,
SINGLE_CALL_BALANCES_ADDRESS_ARBITRUM,
} from '../constants/contracts';
import { bnToHex } from './util';
@ -35,21 +49,21 @@ import { bnToHex } from './util';
*
* It also tracks transaction hashes, and checks their inclusion status on each new block.
*
* @typedef {Object} AccountTracker
* @property {Object} store The stored object containing all accounts to track, as well as the current block's gas limit.
* @property {Object} store.accounts The accounts currently stored in this AccountTracker
* @typedef {object} AccountTracker
* @property {object} store The stored object containing all accounts to track, as well as the current block's gas limit.
* @property {object} store.accounts The accounts currently stored in this AccountTracker
* @property {string} store.currentBlockGasLimit A hex string indicating the gas limit of the current block
* @property {Object} _provider A provider needed to create the EthQuery instance used within this AccountTracker.
* @property {object} _provider A provider needed to create the EthQuery instance used within this AccountTracker.
* @property {EthQuery} _query An EthQuery instance used to access account information from the blockchain
* @property {BlockTracker} _blockTracker A BlockTracker instance. Needed to ensure that accounts and their info updates
* when a new block is created.
* @property {Object} _currentBlockNumber Reference to a property on the _blockTracker: the number (i.e. an id) of the the current block
* @property {object} _currentBlockNumber Reference to a property on the _blockTracker: the number (i.e. an id) of the the current block
*/
export default class AccountTracker {
/**
* @param {Object} opts - Options for initializing the controller
* @param {Object} opts.provider - An EIP-1193 provider instance that uses the current global network
* @param {Object} opts.blockTracker - A block tracker, which emits events for each new block
* @param {object} opts - Options for initializing the controller
* @param {object} opts.provider - An EIP-1193 provider instance that uses the current global network
* @param {object} opts.blockTracker - A block tracker, which emits events for each new block
* @param {Function} opts.getCurrentChainId - A function that returns the `chainId` for the current global network
*/
constructor(opts = {}) {
@ -230,6 +244,55 @@ export default class AccountTracker {
);
break;
case GOERLI_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_GOERLI,
);
break;
case BSC_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_BSC,
);
break;
case OPTIMISM_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_OPTIMISM,
);
break;
case POLYGON_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_POLYGON,
);
break;
case AVALANCHE_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_AVALANCHE,
);
break;
case FANTOM_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_FANTOM,
);
break;
case ARBITRUM_CHAIN_ID:
await this._updateAccountsViaBalanceChecker(
addresses,
SINGLE_CALL_BALANCES_ADDRESS_ARBITRUM,
);
break;
default:
await Promise.all(addresses.map(this._updateAccount.bind(this)));
}
@ -243,8 +306,17 @@ export default class AccountTracker {
* @returns {Promise} after the account balance is updated
*/
async _updateAccount(address) {
let balance = '0x0';
// query balance
const balance = await this._query.getBalance(address);
try {
balance = await this._query.getBalance(address);
} catch (error) {
if (error.data.request.method !== 'eth_getBalance') {
throw error;
}
}
const result = { address, balance };
// update accounts state
const { accounts } = this.store.getState();

@ -9,7 +9,6 @@ import {
ROPSTEN_CHAIN_ID,
BUYABLE_CHAINS_MAP,
} from '../../../shared/constants/network';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
import {
TRANSAK_API_KEY,
@ -17,7 +16,7 @@ import {
COINBASEPAY_API_KEY,
} from '../constants/on-ramp';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
/**
* Create a Wyre purchase URL.
@ -83,9 +82,8 @@ const createTransakUrl = (walletAddress, chainId) => {
* @returns String
*/
const createMoonPayUrl = async (walletAddress, chainId) => {
const {
moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {},
} = BUYABLE_CHAINS_MAP[chainId];
const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} } =
BUYABLE_CHAINS_MAP[chainId];
const moonPayQueryParams = new URLSearchParams({
apiKey: MOONPAY_API_KEY,
walletAddress,
@ -141,7 +139,7 @@ const createCoinbasePayUrl = (walletAddress, chainId) => {
/**
* Gives the caller a url at which the user can acquire eth, depending on the network they are in
*
* @param {Object} opts - Options required to determine the correct url
* @param {object} opts - Options required to determine the correct url
* @param {string} opts.chainId - The chainId for which to return a url
* @param {string} opts.address - The address the bought ETH should be sent to. Only relevant if chainId === '0x1'.
* @param opts.service

@ -116,9 +116,8 @@ describe('buy-url', () => {
});
it('returns a MoonPay url with a prefilled wallet address for the Ethereum network', async () => {
const {
moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {},
} = BUYABLE_CHAINS_MAP[MAINNET.chainId];
const { moonPay: { defaultCurrencyCode, showOnlyCurrencies } = {} } =
BUYABLE_CHAINS_MAP[MAINNET.chainId];
const moonPayQueryParams = new URLSearchParams({
apiKey: MOONPAY_API_KEY,
walletAddress: MAINNET.address,

@ -1,19 +1,91 @@
import { MESSAGE_TYPE, ORIGIN_METAMASK } from '../../../shared/constants/app';
import { EVENT, EVENT_NAMES } from '../../../shared/constants/metametrics';
import { SECOND } from '../../../shared/constants/time';
const USER_PROMPTED_EVENT_NAME_MAP = {
eth_signTypedData_v4: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_signTypedData_v3: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_signTypedData: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_personal_sign: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_sign: EVENT_NAMES.SIGNATURE_REQUESTED,
eth_getEncryptionPublicKey: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED,
eth_decrypt: EVENT_NAMES.DECRYPTION_REQUESTED,
wallet_requestPermissions: EVENT_NAMES.PERMISSIONS_REQUESTED,
eth_requestAccounts: EVENT_NAMES.PERMISSIONS_REQUESTED,
/**
* These types determine how the method tracking middleware handles incoming
* requests based on the method name. There are three options right now but
* the types could be expanded to cover other options in the future.
*/
const RATE_LIMIT_TYPES = {
RATE_LIMITED: 'rate_limited',
BLOCKED: 'blocked',
NON_RATE_LIMITED: 'non_rate_limited',
};
const samplingTimeouts = {};
/**
* This object maps a method name to a RATE_LIMIT_TYPE. If not in this map the
* default is 'RATE_LIMITED'
*/
const RATE_LIMIT_MAP = {
[MESSAGE_TYPE.ETH_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.PERSONAL_SIGN]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_DECRYPT]: RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]:
RATE_LIMIT_TYPES.NON_RATE_LIMITED,
[MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: RATE_LIMIT_TYPES.RATE_LIMITED,
[MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: RATE_LIMIT_TYPES.RATE_LIMITED,
[MESSAGE_TYPE.SEND_METADATA]: RATE_LIMIT_TYPES.BLOCKED,
[MESSAGE_TYPE.GET_PROVIDER_STATE]: RATE_LIMIT_TYPES.BLOCKED,
};
/**
* For events with user interaction (approve / reject | cancel) this map will
* return an object with APPROVED, REJECTED and REQUESTED keys that map to the
* appropriate event names.
*/
const EVENT_NAME_MAP = {
[MESSAGE_TYPE.ETH_SIGN]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V3]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.PERSONAL_SIGN]: {
APPROVED: EVENT_NAMES.SIGNATURE_APPROVED,
REJECTED: EVENT_NAMES.SIGNATURE_REJECTED,
REQUESTED: EVENT_NAMES.SIGNATURE_REQUESTED,
},
[MESSAGE_TYPE.ETH_DECRYPT]: {
APPROVED: EVENT_NAMES.DECRYPTION_APPROVED,
REJECTED: EVENT_NAMES.DECRYPTION_REJECTED,
REQUESTED: EVENT_NAMES.DECRYPTION_REQUESTED,
},
[MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY]: {
APPROVED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_APPROVED,
REJECTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REJECTED,
REQUESTED: EVENT_NAMES.ENCRYPTION_PUBLIC_KEY_REQUESTED,
},
[MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS]: {
APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED,
REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED,
REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED,
},
[MESSAGE_TYPE.WALLET_REQUEST_PERMISSIONS]: {
APPROVED: EVENT_NAMES.PERMISSIONS_APPROVED,
REJECTED: EVENT_NAMES.PERMISSIONS_REJECTED,
REQUESTED: EVENT_NAMES.PERMISSIONS_REQUESTED,
},
};
const rateLimitTimeouts = {};
/**
* Returns a middleware that tracks inpage_provider usage using sampling for
@ -21,65 +93,113 @@ const samplingTimeouts = {};
* signature requests
*
* @param {object} opts - options for the rpc method tracking middleware
* @param {Function} opts.trackEvent - trackEvent method from MetaMetricsController
* @param {Function} opts.getMetricsState - get the state of MetaMetricsController
* @param {Function} opts.trackEvent - trackEvent method from
* MetaMetricsController
* @param {Function} opts.getMetricsState - get the state of
* MetaMetricsController
* @param {number} [opts.rateLimitSeconds] - number of seconds to wait before
* allowing another set of events to be tracked.
* @returns {Function}
*/
export default function createRPCMethodTrackingMiddleware({
trackEvent,
getMetricsState,
rateLimitSeconds = 60,
}) {
return function rpcMethodTrackingMiddleware(
/** @type {any} */ req,
/** @type {any} */ res,
/** @type {Function} */ next,
) {
const startTime = Date.now();
const { origin } = req;
const { origin, method } = req;
// Determine what type of rate limit to apply based on method
const rateLimitType =
RATE_LIMIT_MAP[method] ?? RATE_LIMIT_TYPES.RATE_LIMITED;
// If the rateLimitType is RATE_LIMITED check the rateLimitTimeouts
const rateLimited =
rateLimitType === RATE_LIMIT_TYPES.RATE_LIMITED &&
typeof rateLimitTimeouts[method] !== 'undefined';
// Get the participateInMetaMetrics state to determine if we should track
// anything. This is extra redundancy because this value is checked in
// the metametrics controller's trackEvent method as well.
const userParticipatingInMetaMetrics =
getMetricsState().participateInMetaMetrics === true;
// Get the event type, each of which has APPROVED, REJECTED and REQUESTED
// keys for the various events in the flow.
const eventType = EVENT_NAME_MAP[method];
// Boolean variable that reduces code duplication and increases legibility
const shouldTrackEvent =
// Don't track if the request came from our own UI or background
origin !== ORIGIN_METAMASK &&
// Don't track if this is a blocked method
rateLimitType !== RATE_LIMIT_TYPES.BLOCKED &&
// Don't track if the rate limit has been hit
rateLimited === false &&
// Don't track if the user isn't participating in metametrics
userParticipatingInMetaMetrics === true;
if (shouldTrackEvent) {
// We track an initial "requested" event as soon as the dapp calls the
// provider method. For the events not special cased this is the only
// event that will be fired and the event name will be
// 'Provider Method Called'.
const event = eventType
? eventType.REQUESTED
: EVENT_NAMES.PROVIDER_METHOD_CALLED;
const properties = {};
if (event === EVENT_NAMES.SIGNATURE_REQUESTED) {
properties.signature_type = method;
} else {
properties.method = method;
}
trackEvent({
event,
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties,
});
rateLimitTimeouts[method] = setTimeout(() => {
delete rateLimitTimeouts[method];
}, SECOND * rateLimitSeconds);
}
next((callback) => {
const endTime = Date.now();
if (!getMetricsState().participateInMetaMetrics) {
if (shouldTrackEvent === false || typeof eventType === 'undefined') {
return callback();
}
if (USER_PROMPTED_EVENT_NAME_MAP[req.method]) {
const userRejected = res.error?.code === 4001;
trackEvent({
event: USER_PROMPTED_EVENT_NAME_MAP[req.method],
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties: {
method: req.method,
status: userRejected ? 'rejected' : 'approved',
error_code: res.error?.code,
error_message: res.error?.message,
has_result: typeof res.result !== 'undefined',
duration: endTime - startTime,
},
});
} else if (typeof samplingTimeouts[req.method] === 'undefined') {
trackEvent({
event: 'Provider Method Called',
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties: {
method: req.method,
error_code: res.error?.code,
error_message: res.error?.message,
has_result: typeof res.result !== 'undefined',
duration: endTime - startTime,
},
});
// Only record one call to this method every ten seconds to avoid
// overloading network requests.
samplingTimeouts[req.method] = setTimeout(() => {
delete samplingTimeouts[req.method];
}, SECOND * 10);
// An error code of 4001 means the user rejected the request, which we
// can use here to determine which event to track.
const event =
res.error?.code === 4001 ? eventType.REJECTED : eventType.APPROVED;
const properties = {};
if (eventType.REQUESTED === EVENT_NAMES.SIGNATURE_REQUESTED) {
properties.signature_type = method;
} else {
properties.method = method;
}
trackEvent({
event,
category: EVENT.CATEGORIES.INPAGE_PROVIDER,
referrer: {
url: origin,
},
properties,
});
return callback();
});
};

@ -0,0 +1,217 @@
import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { EVENT_NAMES } from '../../../shared/constants/metametrics';
import { SECOND } from '../../../shared/constants/time';
import createRPCMethodTrackingMiddleware from './createRPCMethodTrackingMiddleware';
const trackEvent = jest.fn();
const metricsState = { participateInMetaMetrics: null };
const getMetricsState = () => metricsState;
const handler = createRPCMethodTrackingMiddleware({
trackEvent,
getMetricsState,
rateLimitSeconds: 1,
});
function getNext(timeout = 500) {
let deferred;
const promise = new Promise((resolve) => {
deferred = {
resolve,
};
});
const cb = () => deferred.resolve();
let triggerNext;
setTimeout(() => {
deferred.resolve();
}, timeout);
return {
executeMiddlewareStack: async () => {
if (triggerNext) {
triggerNext(() => cb());
}
return await deferred.resolve();
},
promise,
next: (postReqHandler) => {
triggerNext = postReqHandler;
},
};
}
const waitForSeconds = async (seconds) =>
await new Promise((resolve) => setTimeout(resolve, SECOND * seconds));
describe('createRPCMethodTrackingMiddleware', () => {
afterEach(() => {
jest.resetAllMocks();
metricsState.participateInMetaMetrics = null;
});
describe('before participateInMetaMetrics is set', () => {
it('should not track an event for a signature request', async () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { executeMiddlewareStack, next } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).not.toHaveBeenCalled();
});
});
describe('participateInMetaMetrics is set to false', () => {
beforeEach(() => {
metricsState.participateInMetaMetrics = false;
});
it('should not track an event for a signature request', async () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { executeMiddlewareStack, next } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).not.toHaveBeenCalled();
});
});
describe('participateInMetaMetrics is set to true', () => {
beforeEach(() => {
metricsState.participateInMetaMetrics = true;
});
it(`should immediately track a ${EVENT_NAMES.SIGNATURE_REQUESTED} event`, () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { next } = getNext();
handler(req, res, next);
expect(trackEvent).toHaveBeenCalledTimes(1);
expect(trackEvent.mock.calls[0][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.SIGNATURE_REQUESTED,
properties: { signature_type: MESSAGE_TYPE.ETH_SIGN },
referrer: { url: 'some.dapp' },
});
});
it(`should track a ${EVENT_NAMES.SIGNATURE_APPROVED} event if the user approves`, async () => {
const req = {
method: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4,
origin: 'some.dapp',
};
const res = {
error: null,
};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[1][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.SIGNATURE_APPROVED,
properties: { signature_type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA_V4 },
referrer: { url: 'some.dapp' },
});
});
it(`should track a ${EVENT_NAMES.SIGNATURE_REJECTED} event if the user approves`, async () => {
const req = {
method: MESSAGE_TYPE.PERSONAL_SIGN,
origin: 'some.dapp',
};
const res = {
error: { code: 4001 },
};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[1][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.SIGNATURE_REJECTED,
properties: { signature_type: MESSAGE_TYPE.PERSONAL_SIGN },
referrer: { url: 'some.dapp' },
});
});
it(`should track a ${EVENT_NAMES.PERMISSIONS_APPROVED} event if the user approves`, async () => {
const req = {
method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS,
origin: 'some.dapp',
};
const res = {};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[1][0]).toMatchObject({
category: 'inpage_provider',
event: EVENT_NAMES.PERMISSIONS_APPROVED,
properties: { method: MESSAGE_TYPE.ETH_REQUEST_ACCOUNTS },
referrer: { url: 'some.dapp' },
});
});
it(`should never track blocked methods such as ${MESSAGE_TYPE.GET_PROVIDER_STATE}`, () => {
const req = {
method: MESSAGE_TYPE.GET_PROVIDER_STATE,
origin: 'www.notadapp.com',
};
const res = {
error: null,
};
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
expect(trackEvent).not.toHaveBeenCalled();
executeMiddlewareStack();
});
it(`should only track events when not rate limited`, async () => {
const req = {
method: 'eth_chainId',
origin: 'some.dapp',
};
const res = {
error: null,
};
let callCount = 0;
while (callCount < 3) {
callCount += 1;
const { next, executeMiddlewareStack } = getNext();
handler(req, res, next);
await executeMiddlewareStack();
if (callCount !== 3) {
await waitForSeconds(0.6);
}
}
expect(trackEvent).toHaveBeenCalledTimes(2);
expect(trackEvent.mock.calls[0][0].properties.method).toBe('eth_chainId');
expect(trackEvent.mock.calls[1][0].properties.method).toBe('eth_chainId');
});
});
});

@ -15,11 +15,11 @@ const hexRe = /^[0-9A-Fa-f]+$/gu;
* Represents, and contains data about, an 'eth_decrypt' type decryption request. These are created when a
* decryption for an eth_decrypt call is requested.
*
* @typedef {Object} DecryptMessage
* @typedef {object} DecryptMessage
* @property {number} id An id to track and identify the message object
* @property {Object} msgParams The parameters to pass to the decryptMessage method once the decryption request is
* @property {object} msgParams The parameters to pass to the decryptMessage method once the decryption request is
* approved.
* @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {string} msgParams.data A hex string conversion of the raw buffer data of the decryption request
* @property {number} time The epoch time at which the this message was created
* @property {string} status Indicates whether the decryption request is 'unapproved', 'approved', 'decrypted' or 'rejected'
@ -56,7 +56,7 @@ export default class DecryptMessageManager extends EventEmitter {
/**
* A getter for the 'unapproved' DecryptMessages in this.messages
*
* @returns {Object} An index of DecryptMessage ids to DecryptMessages, for all 'unapproved' DecryptMessages in
* @returns {object} An index of DecryptMessage ids to DecryptMessages, for all 'unapproved' DecryptMessages in
* this.messages
*/
getUnapprovedMsgs() {
@ -73,8 +73,8 @@ export default class DecryptMessageManager extends EventEmitter {
* the new DecryptMessage to this.messages, and to save the unapproved DecryptMessages from that list to
* this.memStore.
*
* @param {Object} msgParams - The params for the eth_decrypt call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_decrypt call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {Promise<Buffer>} The raw decrypted message contents
*/
addUnapprovedMessageAsync(msgParams, req) {
@ -117,8 +117,8 @@ export default class DecryptMessageManager extends EventEmitter {
* the new DecryptMessage to this.messages, and to save the unapproved DecryptMessages from that list to
* this.memStore.
*
* @param {Object} msgParams - The params for the eth_decryptMsg call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_decryptMsg call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {number} The id of the newly created DecryptMessage.
*/
addUnapprovedMessage(msgParams, req) {
@ -175,8 +175,8 @@ export default class DecryptMessageManager extends EventEmitter {
* Approves a DecryptMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise
* with the message params modified for proper decryption.
*
* @param {Object} msgParams - The msgParams to be used when eth_decryptMsg is called, plus data added by MetaMask.
* @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @param {object} msgParams - The msgParams to be used when eth_decryptMsg is called, plus data added by MetaMask.
* @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @returns {Promise<object>} Promises the msgParams object with metamaskId removed.
*/
approveMessage(msgParams) {
@ -210,7 +210,7 @@ export default class DecryptMessageManager extends EventEmitter {
/**
* Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams
*
* @param {Object} msgParams - The msgParams to modify
* @param {object} msgParams - The msgParams to modify
* @returns {Promise<object>} Promises the msgParams with the metamaskId property removed
*/
prepMsgForDecryption(msgParams) {

@ -11,11 +11,11 @@ import createId from '../../../shared/modules/random-id';
* Represents, and contains data about, an 'eth_getEncryptionPublicKey' type request. These are created when
* an eth_getEncryptionPublicKey call is requested.
*
* @typedef {Object} EncryptionPublicKey
* @typedef {object} EncryptionPublicKey
* @property {number} id An id to track and identify the message object
* @property {Object} msgParams The parameters to pass to the encryptionPublicKey method once the request is
* @property {object} msgParams The parameters to pass to the encryptionPublicKey method once the request is
* approved.
* @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {string} msgParams.data A hex string conversion of the raw buffer data of the request
* @property {number} time The epoch time at which the this message was created
* @property {string} status Indicates whether the request is 'unapproved', 'approved', 'received' or 'rejected'
@ -52,7 +52,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
/**
* A getter for the 'unapproved' EncryptionPublicKeys in this.messages
*
* @returns {Object} An index of EncryptionPublicKey ids to EncryptionPublicKeys, for all 'unapproved' EncryptionPublicKeys in
* @returns {object} An index of EncryptionPublicKey ids to EncryptionPublicKeys, for all 'unapproved' EncryptionPublicKeys in
* this.messages
*/
getUnapprovedMsgs() {
@ -69,8 +69,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
* the new EncryptionPublicKey to this.messages, and to save the unapproved EncryptionPublicKeys from that list to
* this.memStore.
*
* @param {Object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {Promise<Buffer>} The raw public key contents
*/
addUnapprovedMessageAsync(address, req) {
@ -110,8 +110,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
* the new EncryptionPublicKey to this.messages, and to save the unapproved EncryptionPublicKeys from that list to
* this.memStore.
*
* @param {Object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} address - The param for the eth_getEncryptionPublicKey call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {number} The id of the newly created EncryptionPublicKey.
*/
addUnapprovedMessage(address, req) {
@ -164,8 +164,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
* Approves a EncryptionPublicKey. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise
* with any the message params modified for proper providing.
*
* @param {Object} msgParams - The msgParams to be used when eth_getEncryptionPublicKey is called, plus data added by MetaMask.
* @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @param {object} msgParams - The msgParams to be used when eth_getEncryptionPublicKey is called, plus data added by MetaMask.
* @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @returns {Promise<object>} Promises the msgParams object with metamaskId removed.
*/
approveMessage(msgParams) {
@ -199,7 +199,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
/**
* Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams
*
* @param {Object} msgParams - The msgParams to modify
* @param {object} msgParams - The msgParams to modify
* @returns {Promise<object>} Promises the msgParams with the metamaskId property removed
*/
prepMsgForEncryptionPublicKey(msgParams) {

@ -35,9 +35,8 @@ export default async function resolveEnsToIpfsContentId({ provider, name }) {
const type = contentHash.getCodec(rawContentHash);
if (type === 'ipfs-ns' || type === 'ipns-ns') {
decodedContentHash = contentHash.helpers.cidV0ToV1Base32(
decodedContentHash,
);
decodedContentHash =
contentHash.helpers.cidV0ToV1Base32(decodedContentHash);
}
return { type, hash: decodedContentHash };

@ -2,11 +2,10 @@ import base32Encode from 'base32-encode';
import base64 from 'base64-js';
import browser from 'webextension-polyfill';
import { SECOND } from '../../../../shared/constants/time';
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout';
import resolveEnsToIpfsContentId from './resolver';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
const supportedTopLevelDomains = ['eth'];

@ -16,8 +16,8 @@ import { cloneDeep } from 'lodash';
* Creates an object that represents the structure of the given object. It replaces all values with the result of their
* type.
*
* @param {Object} obj - The object for which a 'structure' will be returned. Usually a plain object and not a class.
* @returns {Object} The "mapped" version of a deep clone of the passed object, with each non-object property value
* @param {object} obj - The object for which a 'structure' will be returned. Usually a plain object and not a class.
* @returns {object} The "mapped" version of a deep clone of the passed object, with each non-object property value
* replaced with the javascript type of that value.
*/
export default function getObjStructure(obj) {
@ -31,9 +31,9 @@ export default function getObjStructure(obj) {
* Modifies all the properties and deeply nested of a passed object. Iterates recursively over all nested objects and
* their properties, and covers the entire depth of the object. At each property value which is not an object is modified.
*
* @param {Object} target - The object to modify
* @param {object} target - The object to modify
* @param {Function} visit - The modifier to apply to each non-object property value
* @returns {Object} The modified object
* @returns {object} The modified object
*/
function deepMap(target = {}, visit) {
Object.entries(target).forEach(([key, value]) => {

@ -34,7 +34,7 @@ export default class ExtensionStore {
/**
* Sets the key in local state
*
* @param {Object} state - The state to set
* @param {object} state - The state to set
* @returns {Promise<void>}
*/
async set(state) {
@ -45,7 +45,7 @@ export default class ExtensionStore {
* Returns all of the keys currently saved
*
* @private
* @returns {Object} the key-value map from local storage
* @returns {object} the key-value map from local storage
*/
_get() {
const { local } = browser.storage;
@ -64,7 +64,7 @@ export default class ExtensionStore {
/**
* Sets the key in local state
*
* @param {Object} obj - The key to set
* @param {object} obj - The key to set
* @returns {Promise<void>}
* @private
*/
@ -86,7 +86,7 @@ export default class ExtensionStore {
/**
* Returns whether or not the given object contains no keys
*
* @param {Object} obj - The object to check
* @param {object} obj - The object to check
* @returns {boolean}
*/
function isEmpty(obj) {

@ -12,10 +12,10 @@ import { EVENT } from '../../../shared/constants/metametrics';
* an eth_sign call is requested.
*
* @see {@link https://github.com/ethereum/wiki/wiki/JSON-RPC#eth_sign}
* @typedef {Object} Message
* @typedef {object} Message
* @property {number} id An id to track and identify the message object
* @property {Object} msgParams The parameters to pass to the eth_sign method once the signature request is approved.
* @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {object} msgParams The parameters to pass to the eth_sign method once the signature request is approved.
* @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request
* @property {number} time The epoch time at which the this message was created
* @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed' or 'rejected'
@ -52,7 +52,7 @@ export default class MessageManager extends EventEmitter {
/**
* A getter for the 'unapproved' Messages in this.messages
*
* @returns {Object} An index of Message ids to Messages, for all 'unapproved' Messages in this.messages
* @returns {object} An index of Message ids to Messages, for all 'unapproved' Messages in this.messages
*/
getUnapprovedMsgs() {
return this.messages
@ -67,8 +67,8 @@ export default class MessageManager extends EventEmitter {
* Creates a new Message with an 'unapproved' status using the passed msgParams. this.addMsg is called to add the
* new Message to this.messages, and to save the unapproved Messages from that list to this.memStore.
*
* @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {promise} after signature has been
*/
async addUnapprovedMessageAsync(msgParams, req) {
@ -106,8 +106,8 @@ export default class MessageManager extends EventEmitter {
* Creates a new Message with an 'unapproved' status using the passed msgParams. this.addMsg is called to add the
* new Message to this.messages, and to save the unapproved Messages from that list to this.memStore.
*
* @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {Object} [req] - The original request object where the origin may be specified
* @param {object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {object} [req] - The original request object where the origin may be specified
* @returns {number} The id of the newly created message.
*/
addUnapprovedMessage(msgParams, req) {
@ -158,8 +158,8 @@ export default class MessageManager extends EventEmitter {
* Approves a Message. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise with
* any the message params modified for proper signing.
*
* @param {Object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask.
* @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @param {object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask.
* @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @returns {Promise<object>} Promises the msgParams object with metamaskId removed.
*/
approveMessage(msgParams) {
@ -193,7 +193,7 @@ export default class MessageManager extends EventEmitter {
/**
* Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams
*
* @param {Object} msgParams - The msgParams to modify
* @param {object} msgParams - The msgParams to modify
* @returns {Promise<object>} Promises the msgParams with the metamaskId property removed
*/
prepMsgForSigning(msgParams) {

@ -1,13 +1,13 @@
import EventEmitter from 'events';
/**
* @typedef {Object} Migration
* @typedef {object} Migration
* @property {number} version - The migration version
* @property {Function} migrate - Returns a promise of the migrated data
*/
/**
* @typedef {Object} MigratorOptions
* @typedef {object} MigratorOptions
* @property {Array<Migration>} [migrations] - The list of migrations to apply
* @property {number} [defaultVersion] - The version to use in the initial state
*/
@ -82,7 +82,7 @@ export default class Migrator extends EventEmitter {
/**
* Returns the initial state for the migrator
*
* @param {Object} [data] - The data for the initial state
* @param {object} [data] - The data for the initial state
* @returns {{meta: {version: number}, data: any}}
*/
generateInitialState(data) {

@ -1,8 +1,7 @@
import log from 'loglevel';
import { SECOND } from '../../../shared/constants/time';
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout';
const fetchWithTimeout = getFetchWithTimeout(SECOND * 30);
const fetchWithTimeout = getFetchWithTimeout();
const FIXTURE_SERVER_HOST = 'localhost';
const FIXTURE_SERVER_PORT = 12345;
@ -54,7 +53,7 @@ export default class ReadOnlyNetworkStore {
/**
* Set state
*
* @param {Object} state - The state to set
* @param {object} state - The state to set
* @returns {Promise<void>}
*/
async set(state) {

@ -7,6 +7,7 @@ import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { METAMASK_CONTROLLER_EVENTS } from '../metamask-controller';
import createId from '../../../shared/modules/random-id';
import { EVENT } from '../../../shared/constants/metametrics';
import { detectSIWE } from '../../../shared/modules/siwe';
import { addHexPrefix } from './util';
const hexRe = /^[0-9A-Fa-f]+$/gu;
@ -16,11 +17,11 @@ const hexRe = /^[0-9A-Fa-f]+$/gu;
* signature for an personal_sign call is requested.
*
* @see {@link https://web3js.readthedocs.io/en/1.0/web3-eth-personal.html#sign}
* @typedef {Object} PersonalMessage
* @typedef {object} PersonalMessage
* @property {number} id An id to track and identify the message object
* @property {Object} msgParams The parameters to pass to the personal_sign method once the signature request is
* @property {object} msgParams The parameters to pass to the personal_sign method once the signature request is
* approved.
* @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request
* @property {number} time The epoch time at which the this message was created
* @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed' or 'rejected'
@ -57,7 +58,7 @@ export default class PersonalMessageManager extends EventEmitter {
/**
* A getter for the 'unapproved' PersonalMessages in this.messages
*
* @returns {Object} An index of PersonalMessage ids to PersonalMessages, for all 'unapproved' PersonalMessages in
* @returns {object} An index of PersonalMessage ids to PersonalMessages, for all 'unapproved' PersonalMessages in
* this.messages
*/
getUnapprovedMsgs() {
@ -74,8 +75,8 @@ export default class PersonalMessageManager extends EventEmitter {
* the new PersonalMessage to this.messages, and to save the unapproved PersonalMessages from that list to
* this.memStore.
*
* @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {promise} When the message has been signed or rejected
*/
addUnapprovedMessageAsync(msgParams, req) {
@ -120,8 +121,8 @@ export default class PersonalMessageManager extends EventEmitter {
* the new PersonalMessage to this.messages, and to save the unapproved PersonalMessages from that list to
* this.memStore.
*
* @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @returns {number} The id of the newly created PersonalMessage.
*/
addUnapprovedMessage(msgParams, req) {
@ -135,6 +136,11 @@ export default class PersonalMessageManager extends EventEmitter {
msgParams.origin = req.origin;
}
msgParams.data = this.normalizeMsgData(msgParams.data);
// check for SIWE message
const siwe = detectSIWE(msgParams);
msgParams.siwe = siwe;
// create txData obj with parameters and meta data
const time = new Date().getTime();
const msgId = createId();
@ -178,8 +184,8 @@ export default class PersonalMessageManager extends EventEmitter {
* Approves a PersonalMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise
* with any the message params modified for proper signing.
*
* @param {Object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask.
* @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @param {object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask.
* @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @returns {Promise<object>} Promises the msgParams object with metamaskId removed.
*/
approveMessage(msgParams) {
@ -213,7 +219,7 @@ export default class PersonalMessageManager extends EventEmitter {
/**
* Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams
*
* @param {Object} msgParams - The msgParams to modify
* @param {object} msgParams - The msgParams to modify
* @returns {Promise<object>} Promises the msgParams with the metamaskId property removed
*/
prepMsgForSigning(msgParams) {
@ -314,8 +320,9 @@ export default class PersonalMessageManager extends EventEmitter {
*/
_saveMsgList() {
const unapprovedPersonalMsgs = this.getUnapprovedMsgs();
const unapprovedPersonalMsgCount = Object.keys(unapprovedPersonalMsgs)
.length;
const unapprovedPersonalMsgCount = Object.keys(
unapprovedPersonalMsgs,
).length;
this.memStore.updateState({
unapprovedPersonalMsgs,
unapprovedPersonalMsgCount,

@ -31,7 +31,7 @@ const expectedHookNames = Array.from(
*
* @param {Record<string, unknown>} hooks - Required "hooks" into our
* controllers.
* @returns {(req: Object, res: Object, next: Function, end: Function) => void}
* @returns {(req: object, res: object, next: Function, end: Function) => void}
*/
export function createMethodMiddleware(hooks) {
// Fail immediately if we forgot to provide any expected hooks.

@ -1,7 +1,10 @@
import { ethErrors, errorCodes } from 'eth-rpc-errors';
import validUrl from 'valid-url';
import { omit } from 'lodash';
import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
import {
MESSAGE_TYPE,
UNKNOWN_TICKER_SYMBOL,
} from '../../../../../shared/constants/app';
import { EVENT } from '../../../../../shared/constants/metametrics';
import {
isPrefixedFormattedHexString,
@ -16,6 +19,7 @@ const addEthereumChain = {
hookNames: {
addCustomRpc: true,
getCurrentChainId: true,
getCurrentRpcUrl: true,
findCustomRpcBy: true,
updateRpcTarget: true,
requestUserApproval: true,
@ -32,6 +36,7 @@ async function addEthereumChainHandler(
{
addCustomRpc,
getCurrentChainId,
getCurrentRpcUrl,
findCustomRpcBy,
updateRpcTarget,
requestUserApproval,
@ -145,15 +150,21 @@ async function addEthereumChainHandler(
const existingNetwork = findCustomRpcBy({ chainId: _chainId });
if (existingNetwork) {
// if the request is to add a network that is already added and configured
// with the same RPC gateway we shouldn't try to add it again.
if (existingNetwork && existingNetwork.rpcUrl === firstValidRPCUrl) {
// If the network already exists, the request is considered successful
res.result = null;
const currentChainId = getCurrentChainId();
if (currentChainId === _chainId) {
const currentRpcUrl = getCurrentRpcUrl();
// If the current chainId and rpcUrl matches that of the incoming request
// We don't need to proceed further.
if (currentChainId === _chainId && currentRpcUrl === firstValidRPCUrl) {
return end();
}
// If this network is already added with but is not the currently selected network
// Ask the user to switch the network
try {
await updateRpcTarget(
@ -236,15 +247,32 @@ async function addEthereumChainHandler(
);
}
}
const ticker = nativeCurrency?.symbol || 'ETH';
if (typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6) {
const ticker = nativeCurrency?.symbol || UNKNOWN_TICKER_SYMBOL;
if (
ticker !== UNKNOWN_TICKER_SYMBOL &&
(typeof ticker !== 'string' || ticker.length < 2 || ticker.length > 6)
) {
return end(
ethErrors.rpc.invalidParams({
message: `Expected 2-6 character string 'nativeCurrency.symbol'. Received:\n${ticker}`,
}),
);
}
// if the chainId is the same as an existing network but the ticker is different we want to block this action
// as it is potentially malicious and confusing
if (
existingNetwork &&
existingNetwork.chainId === _chainId &&
existingNetwork.ticker !== ticker
) {
return end(
ethErrors.rpc.invalidParams({
message: `nativeCurrency.symbol does not match currency symbol for a network the user already has added with the same chainId. Received:\n${ticker}`,
}),
);
}
try {
await addCustomRpc(
@ -261,25 +289,34 @@ async function addEthereumChainHandler(
}),
);
let rpcUrlOrigin;
try {
rpcUrlOrigin = new URL(firstValidRPCUrl).origin;
} catch {
// ignore
}
sendMetrics({
event: 'Custom Network Added',
category: EVENT.CATEGORIES.NETWORK,
referrer: {
url: origin,
},
sensitiveProperties: {
properties: {
chain_id: _chainId,
rpc_url: firstValidRPCUrl,
network_name: _chainName,
// Including network to override the default network
// property included in all events. For RPC type networks
// the MetaMetrics controller uses the rpcUrl for the network
// property.
network: firstValidRPCUrl,
network: rpcUrlOrigin,
symbol: ticker,
block_explorer_url: firstValidBlockExplorerUrl,
source: EVENT.SOURCE.TRANSACTION.DAPP,
},
sensitiveProperties: {
rpc_url: rpcUrlOrigin,
},
});
// Once the network has been added, the requested is considered successful

@ -16,14 +16,14 @@ const getProviderState = {
export default getProviderState;
/**
* @typedef {Object} ProviderStateHandlerResult
* @typedef {object} ProviderStateHandlerResult
* @property {string} chainId - The current chain ID.
* @property {boolean} isUnlocked - Whether the extension is unlocked or not.
* @property {string} networkVersion - The current network ID.
*/
/**
* @typedef {Object} ProviderStateHandlerOptions
* @typedef {object} ProviderStateHandlerOptions
* @property {() => ProviderStateHandlerResult} getProviderState - A function that
* gets the current provider state.
*/

@ -20,7 +20,7 @@ const logWeb3ShimUsage = {
export default logWeb3ShimUsage;
/**
* @typedef {Object} LogWeb3ShimUsageOptions
* @typedef {object} LogWeb3ShimUsageOptions
* @property {Function} sendMetrics - A function that registers a metrics event.
* @property {Function} getWeb3ShimUsageState - A function that gets web3 shim
* usage state for the given origin.

@ -11,14 +11,14 @@ const watchAsset = {
export default watchAsset;
/**
* @typedef {Object} WatchAssetOptions
* @typedef {object} WatchAssetOptions
* @property {Function} handleWatchAssetRequest - The wallet_watchAsset method implementation.
*/
/**
* @typedef {Object} WatchAssetParam
* @typedef {object} WatchAssetParam
* @property {string} type - The type of the asset to watch.
* @property {Object} options - Watch options for the asset.
* @property {object} options - Watch options for the asset.
*/
/**

@ -15,12 +15,12 @@ import { isValidHexAddress } from '../../../shared/modules/hexstring-utils';
* Represents, and contains data about, an 'eth_signTypedData' type signature request. These are created when a
* signature for an eth_signTypedData call is requested.
*
* @typedef {Object} TypedMessage
* @typedef {object} TypedMessage
* @property {number} id An id to track and identify the message object
* @property {Object} msgParams The parameters to pass to the eth_signTypedData method once the signature request is
* @property {object} msgParams The parameters to pass to the eth_signTypedData method once the signature request is
* approved.
* @property {Object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {Object} msgParams.from The address that is making the signature request.
* @property {object} msgParams.metamaskId Added to msgParams for tracking and identification within MetaMask.
* @property {object} msgParams.from The address that is making the signature request.
* @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request
* @property {number} time The epoch time at which the this message was created
* @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed', 'rejected', or 'errored'
@ -59,7 +59,7 @@ export default class TypedMessageManager extends EventEmitter {
/**
* A getter for the 'unapproved' TypedMessages in this.messages
*
* @returns {Object} An index of TypedMessage ids to TypedMessages, for all 'unapproved' TypedMessages in
* @returns {object} An index of TypedMessage ids to TypedMessages, for all 'unapproved' TypedMessages in
* this.messages
*/
getUnapprovedMsgs() {
@ -76,8 +76,8 @@ export default class TypedMessageManager extends EventEmitter {
* the new TypedMessage to this.messages, and to save the unapproved TypedMessages from that list to
* this.memStore. Before any of this is done, msgParams are validated
*
* @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @param version
* @returns {promise} When the message has been signed or rejected
*/
@ -116,8 +116,8 @@ export default class TypedMessageManager extends EventEmitter {
* the new TypedMessage to this.messages, and to save the unapproved TypedMessages from that list to
* this.memStore. Before any of this is done, msgParams are validated
*
* @param {Object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {Object} [req] - The original request object possibly containing the origin
* @param {object} msgParams - The params for the eth_sign call to be made after the message is approved.
* @param {object} [req] - The original request object possibly containing the origin
* @param version
* @returns {number} The id of the newly created TypedMessage.
*/
@ -152,7 +152,7 @@ export default class TypedMessageManager extends EventEmitter {
/**
* Helper method for this.addUnapprovedMessage. Validates that the passed params have the required properties.
*
* @param {Object} params - The params to validate
* @param {object} params - The params to validate
*/
validateParams(params) {
assert.ok(
@ -249,8 +249,8 @@ export default class TypedMessageManager extends EventEmitter {
* Approves a TypedMessage. Sets the message status via a call to this.setMsgStatusApproved, and returns a promise
* with any the message params modified for proper signing.
*
* @param {Object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask.
* @param {Object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @param {object} msgParams - The msgParams to be used when eth_sign is called, plus data added by MetaMask.
* @param {object} msgParams.metamaskId - Added to msgParams for tracking and identification within MetaMask.
* @returns {Promise<object>} Promises the msgParams object with metamaskId removed.
*/
approveMessage(msgParams) {
@ -284,7 +284,7 @@ export default class TypedMessageManager extends EventEmitter {
/**
* Removes the metamaskId property from passed msgParams and returns a promise which resolves the updated msgParams
*
* @param {Object} msgParams - The msgParams to modify
* @param {object} msgParams - The msgParams to modify
* @returns {Promise<object>} Promises the msgParams with the metamaskId property removed
*/
prepMsgForSigning(msgParams) {
@ -391,8 +391,9 @@ export default class TypedMessageManager extends EventEmitter {
*/
_saveMsgList() {
const unapprovedTypedMessages = this.getUnapprovedMsgs();
const unapprovedTypedMessagesCount = Object.keys(unapprovedTypedMessages)
.length;
const unapprovedTypedMessagesCount = Object.keys(
unapprovedTypedMessages,
).length;
this.memStore.updateState({
unapprovedTypedMessages,
unapprovedTypedMessagesCount,

@ -76,7 +76,7 @@ const getPlatform = () => {
* Converts a hex string to a BN object
*
* @param {string} inputHex - A number represented as a hex string
* @returns {Object} A BN object
* @returns {object} A BN object
*/
function hexToBn(inputHex) {
return new BN(stripHexPrefix(inputHex), 16);

@ -74,7 +74,7 @@ try {
* We want to make globals non-writable, and we can't set the `writable`
* property and accessor properties at the same time.
*
* @param {Object} descriptor - The propertyName descriptor to check.
* @param {object} descriptor - The propertyName descriptor to check.
* @returns {boolean} Whether the propertyName descriptor has any accessors.
*/
function hasAccessor(descriptor) {

File diff suppressed because it is too large Load Diff

@ -221,9 +221,10 @@ describe('MetaMaskController', function () {
});
it('adds private key to keyrings in KeyringController', async function () {
const simpleKeyrings = metamaskController.keyringController.getKeyringsByType(
'Simple Key Pair',
);
const simpleKeyrings =
metamaskController.keyringController.getKeyringsByType(
'Simple Key Pair',
);
const privKeyBuffer = simpleKeyrings[0].wallets[0].privateKey;
const pubKeyBuffer = simpleKeyrings[0].wallets[0].publicKey;
const addressBuffer = pubToAddress(pubKeyBuffer);
@ -234,7 +235,8 @@ describe('MetaMaskController', function () {
});
it('adds 1 account', async function () {
const keyringAccounts = await metamaskController.keyringController.getAccounts();
const keyringAccounts =
await metamaskController.keyringController.getAccounts();
assert.equal(
keyringAccounts[keyringAccounts.length - 1],
'0xe18035bf8712672935fdb4e5e431b1a0183d2dfc',
@ -259,7 +261,8 @@ describe('MetaMaskController', function () {
const identities = Object.keys(
metamaskController.preferencesController.store.getState().identities,
);
const addresses = await metamaskController.keyringController.getAccounts();
const addresses =
await metamaskController.keyringController.getAccounts();
identities.forEach((identity) => {
assert.ok(
@ -486,7 +489,8 @@ describe('MetaMaskController', function () {
});
it('changes preferences controller select address', function () {
const preferenceControllerState = metamaskController.preferencesController.store.getState();
const preferenceControllerState =
metamaskController.preferencesController.store.getState();
assert.equal(preferenceControllerState.selectedAddress, address);
});
@ -517,9 +521,10 @@ describe('MetaMaskController', function () {
await metamaskController
.connectHardware(DEVICE_NAMES.TREZOR, 0)
.catch(() => null);
const keyrings = await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.TREZOR,
);
const keyrings =
await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.TREZOR,
);
assert.deepEqual(
metamaskController.keyringController.addNewKeyring.getCall(0).args,
[KEYRING_TYPES.TREZOR],
@ -532,9 +537,10 @@ describe('MetaMaskController', function () {
await metamaskController
.connectHardware(DEVICE_NAMES.LEDGER, 0)
.catch(() => null);
const keyrings = await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.LEDGER,
);
const keyrings =
await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.LEDGER,
);
assert.deepEqual(
metamaskController.keyringController.addNewKeyring.getCall(0).args,
[KEYRING_TYPES.LEDGER],
@ -586,9 +592,10 @@ describe('MetaMaskController', function () {
.connectHardware(DEVICE_NAMES.TREZOR, 0)
.catch(() => null);
await metamaskController.forgetDevice(DEVICE_NAMES.TREZOR);
const keyrings = await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.TREZOR,
);
const keyrings =
await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.TREZOR,
);
assert.deepEqual(keyrings[0].accounts, []);
assert.deepEqual(keyrings[0].page, 0);
@ -645,9 +652,10 @@ describe('MetaMaskController', function () {
});
it('should set unlockedAccount in the keyring', async function () {
const keyrings = await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.TREZOR,
);
const keyrings =
await metamaskController.keyringController.getKeyringsByType(
KEYRING_TYPES.TREZOR,
);
assert.equal(keyrings[0].unlockedAccount, accountToUnlock);
});
@ -690,7 +698,8 @@ describe('MetaMaskController', function () {
CUSTOM_RPC_URL,
CUSTOM_RPC_CHAIN_ID,
);
const networkControllerState = metamaskController.networkController.store.getState();
const networkControllerState =
metamaskController.networkController.store.getState();
assert.equal(networkControllerState.provider.rpcUrl, CUSTOM_RPC_URL);
});
});
@ -726,7 +735,8 @@ describe('MetaMaskController', function () {
it('#addNewAccount', async function () {
await metamaskController.addNewAccount();
const getAccounts = await metamaskController.keyringController.getAccounts();
const getAccounts =
await metamaskController.keyringController.getAccounts();
assert.equal(getAccounts.length, 2);
});
});
@ -959,7 +969,8 @@ describe('MetaMaskController', function () {
// handle the promise so it doesn't throw an unhandledRejection
promise.then(noop).catch(noop);
metamaskPersonalMsgs = metamaskController.personalMessageManager.getUnapprovedMsgs();
metamaskPersonalMsgs =
metamaskController.personalMessageManager.getUnapprovedMsgs();
personalMessages = metamaskController.personalMessageManager.messages;
msgId = Object.keys(metamaskPersonalMsgs)[0];
personalMessages[0].msgParams.metamaskId = parseInt(msgId, 10);
@ -1250,9 +1261,8 @@ describe('MetaMaskController', function () {
describe('markNotificationsAsRead', function () {
it('marks the notification as read', function () {
metamaskController.markNotificationsAsRead([NOTIFICATION_ID]);
const readNotification = metamaskController.getState().notifications[
NOTIFICATION_ID
];
const readNotification =
metamaskController.getState().notifications[NOTIFICATION_ID];
assert.notEqual(readNotification.readDate, null);
});
});

@ -18,11 +18,8 @@ const storage = {
describe('storage is migrated successfully where transactions that are submitted have submittedTimes', () => {
it('should add submittedTime key on the txMeta if appropriate', async () => {
const migratedData = await migration22.migrate(storage);
const [
txMeta1,
txMeta2,
txMeta3,
] = migratedData.data.TransactionController.transactions;
const [txMeta1, txMeta2, txMeta3] =
migratedData.data.TransactionController.transactions;
expect(migratedData.meta.version).toStrictEqual(22);
// should have written a submitted time

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

Loading…
Cancel
Save