1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-21 17:37:01 +01:00

Merge branch 'develop' of github.com:MetaMask/metamask-extension into minimal

This commit is contained in:
Matthias Kretschmann 2023-09-07 12:13:58 +01:00
commit 961407be2d
Signed by: m
GPG Key ID: 606EEEF3C479A91F
111 changed files with 7751 additions and 6076 deletions

View File

@ -27,7 +27,7 @@ const state = {
image: { image: {
src: 'images/global-menu-block-explorer.svg', src: 'images/global-menu-block-explorer.svg',
}, },
} },
}, },
tokenList: { tokenList: {
'0x514910771af9ca656af840dff83e8264ecf986ca': { '0x514910771af9ca656af840dff83e8264ecf986ca': {
@ -314,8 +314,8 @@ const state = {
address: '0x9d0ba4ddac06032527b140912ec808ab9451b788', address: '0x9d0ba4ddac06032527b140912ec808ab9451b788',
}, },
}, },
unapprovedTxs: { transactions: [
3111025347726181: { {
id: 3111025347726181, id: 3111025347726181,
time: 1620710815484, time: 1620710815484,
status: 'unapproved', status: 'unapproved',
@ -365,7 +365,7 @@ const state = {
], ],
], ],
}, },
}, ],
addressBook: { addressBook: {
undefined: { undefined: {
0: { 0: {
@ -574,7 +574,7 @@ const state = {
}, },
}, },
currentBlockGasLimit: '0x793af4', currentBlockGasLimit: '0x793af4',
currentNetworkTxList: [ transactions: [
{ {
chainId: '0x38', chainId: '0x38',
dappSuggestedGasFees: null, dappSuggestedGasFees: null,

View File

@ -6,6 +6,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
## [11.0.0]
### Added
- [FLASK] Added snaps lifecycle hooks ([#20230](https://github.com/MetaMask/metamask-extension/pull/20230))
### Changed
- [FLASK] Unblock `personal_sign` for snaps ([#19998](https://github.com/MetaMask/metamask-extension/pull/19998))
- [FLASK] Allow disabling markdown in snaps UI ([#20069](https://github.com/MetaMask/metamask-extension/pull/20069))
### Fixed
- [FLASK] Fix regression in transaction confirmation tabs ([#20267](https://github.com/MetaMask/metamask-extension/pull/20267))
## [10.35.1] ## [10.35.1]
### Changed ### Changed
- Store default gas settings by network ([#20576](https://github.com/MetaMask/metamask-extension/pull/20576), [#20632](https://github.com/MetaMask/metamask-extension/pull/20632)) - Store default gas settings by network ([#20576](https://github.com/MetaMask/metamask-extension/pull/20576), [#20632](https://github.com/MetaMask/metamask-extension/pull/20632))
@ -3960,7 +3971,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Uncategorized ### Uncategorized
- Added the ability to restore accounts from seed words. - Added the ability to restore accounts from seed words.
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.35.1...HEAD [Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v11.0.0...HEAD
[11.0.0]: https://github.com/MetaMask/metamask-extension/compare/v10.35.1...v11.0.0
[10.35.1]: https://github.com/MetaMask/metamask-extension/compare/v10.35.0...v10.35.1 [10.35.1]: https://github.com/MetaMask/metamask-extension/compare/v10.35.0...v10.35.1
[10.35.0]: https://github.com/MetaMask/metamask-extension/compare/v10.34.5...v10.35.0 [10.35.0]: https://github.com/MetaMask/metamask-extension/compare/v10.34.5...v10.35.0
[10.34.5]: https://github.com/MetaMask/metamask-extension/compare/v10.34.4...v10.34.5 [10.34.5]: https://github.com/MetaMask/metamask-extension/compare/v10.34.4...v10.34.5

View File

@ -52,9 +52,7 @@ To learn how to contribute to the MetaMask project itself, visit our [Internal D
- Install [Node.js](https://nodejs.org) version 18 - Install [Node.js](https://nodejs.org) version 18
- If you are using [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) (recommended) running `nvm use` will automatically choose the right node version for you. - If you are using [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) (recommended) running `nvm use` will automatically choose the right node version for you.
- Install [Yarn v3](https://yarnpkg.com/getting-started/install) - Enable Corepack by executing the command `corepack enable` within the metamask-extension project. Corepack is a utility included with Node.js by default. It manages Yarn on a per-project basis, using the version specified by the `packageManager` property in the project's package.json file. Please note that modern releases of [Yarn](https://yarnpkg.com/getting-started/install) are not intended to be installed globally or via npm.
- ONLY follow the steps in the "Install Corepack" and "Updating the global Yarn version" sections
- DO NOT take any of the steps in the "Initializing your project", "Updating to the latest versions" or "Installing the latest build fresh from master" sections. These steps could result in your repo being reset or installing the wrong yarn version, which can break your build.
- Duplicate `.metamaskrc.dist` within the root and rename it to `.metamaskrc` - Duplicate `.metamaskrc.dist` within the root and rename it to `.metamaskrc`
- Replace the `INFURA_PROJECT_ID` value with your own personal [Infura Project ID](https://infura.io/docs). - Replace the `INFURA_PROJECT_ID` value with your own personal [Infura Project ID](https://infura.io/docs).
- If debugging MetaMetrics, you'll need to add a value for `SEGMENT_WRITE_KEY` [Segment write key](https://segment.com/docs/connections/find-writekey/), see [Developing on MetaMask - Segment](./development/README.md#segment). - If debugging MetaMetrics, you'll need to add a value for `SEGMENT_WRITE_KEY` [Segment write key](https://segment.com/docs/connections/find-writekey/), see [Developing on MetaMask - Segment](./development/README.md#segment).

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -2900,6 +2900,21 @@
"notificationsMarkAllAsRead": { "notificationsMarkAllAsRead": {
"message": "Mark all as read" "message": "Mark all as read"
}, },
"notificationsOpenBetaSnapsActionText": {
"message": "Learn more"
},
"notificationsOpenBetaSnapsDescriptionOne": {
"message": "🎉 We're excited to announce the Open Beta of MetaMask Snaps!"
},
"notificationsOpenBetaSnapsDescriptionThree": {
"message": "Personalize your wallet with snaps built by the developer community!"
},
"notificationsOpenBetaSnapsDescriptionTwo": {
"message": "Snaps help you do more with MetaMask — like connect to more networks, see transaction insights, and get custom notifications."
},
"notificationsOpenBetaSnapsTitle": {
"message": "Introducing MetaMask Snaps"
},
"numberOfNewTokensDetectedPlural": { "numberOfNewTokensDetectedPlural": {
"message": "$1 new tokens found in this account", "message": "$1 new tokens found in this account",
"description": "$1 is the number of new tokens detected" "description": "$1 is the number of new tokens detected"
@ -4085,7 +4100,7 @@
"message": "The snap didn't return any insight" "message": "The snap didn't return any insight"
}, },
"snapsPrivacyWarningFirstMessage": { "snapsPrivacyWarningFirstMessage": {
"message": "You acknowledge that the snap that you are about to install is a Third Party Service as defined in the Consensys $1. Your use of Third Party Services is governed by separate terms and conditions set forth by the Third Party Service provider. You access, rely upon or use the Third Party Service at your own risk. Consensys disclaims all responsibility and liability for any losses on account of your use of Third Party Services.", "message": "You acknowledge that any Snap that you install is a Third Party Service, unless otherwise identified, as defined in the Consensys $1. Your use of Third Party Services is governed by separate terms and conditions set forth by the Third Party Service provider. Consensys does not recommend the use of any Snap by any particular person for any particular reason. You access, rely upon or use the Third Party Service at your own risk. Consensys disclaims all responsibility and liability for any losses on account of your use of Third Party Services.",
"description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link." "description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link."
}, },
"snapsPrivacyWarningSecondMessage": { "snapsPrivacyWarningSecondMessage": {
@ -4093,7 +4108,7 @@
"description": "Second part of a message in popup modal displayed when installing a snap for the first time." "description": "Second part of a message in popup modal displayed when installing a snap for the first time."
}, },
"snapsPrivacyWarningThirdMessage": { "snapsPrivacyWarningThirdMessage": {
"message": "Consensys has no access to information you share with these third parties.", "message": "Consensys has no access to information you share with Third Party Services.",
"description": "Third part of a message in popup modal displayed when installing a snap for the first time." "description": "Third part of a message in popup modal displayed when installing a snap for the first time."
}, },
"snapsSettingsDescription": { "snapsSettingsDescription": {

File diff suppressed because it is too large Load Diff

View File

@ -287,6 +287,9 @@
"address": { "address": {
"message": "Adresse" "message": "Adresse"
}, },
"addressCopied": {
"message": "Adresse copiée !"
},
"advanced": { "advanced": {
"message": "Paramètres avancés" "message": "Paramètres avancés"
}, },
@ -296,6 +299,10 @@
"advancedConfiguration": { "advancedConfiguration": {
"message": "Configuration avancée" "message": "Configuration avancée"
}, },
"advancedGasFeeDefaultOptIn": {
"message": "Enregistrer ces valeurs comme valeurs par défaut pour le réseau $1.",
"description": "$1 is the current network name."
},
"advancedGasFeeModalTitle": { "advancedGasFeeModalTitle": {
"message": "Frais de carburant avancés" "message": "Frais de carburant avancés"
}, },
@ -409,7 +416,7 @@
"message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT suivants." "message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT suivants."
}, },
"approveTokenDescriptionWithoutSymbol": { "approveTokenDescriptionWithoutSymbol": {
"message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT via $1.", "message": "Tant que vous naurez pas révoqué cette autorisation, lautre partie pourra accéder à votre portefeuille et transférer sans préavis les NFT via $1$.",
"description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name" "description": "$1 is a link to contract on the block explorer when we're not able to retrieve a erc721 or erc1155 name"
}, },
"approveTokenTitle": { "approveTokenTitle": {
@ -589,6 +596,12 @@
"bridge": { "bridge": {
"message": "Pont" "message": "Pont"
}, },
"bridgeDescription": {
"message": "Transférez des jetons provenant de différents réseaux"
},
"bridgeDisabled": {
"message": "La passerelle nest pas disponible sur ce réseau"
},
"browserNotSupported": { "browserNotSupported": {
"message": "Votre navigateur internet nest pas compatible..." "message": "Votre navigateur internet nest pas compatible..."
}, },
@ -608,6 +621,12 @@
"message": "Acheter $1", "message": "Acheter $1",
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
}, },
"buyDescription": {
"message": "Conservez vos crypto-actifs et dégagez des bénéfices potentiels"
},
"buyDisabled": {
"message": "Impossible deffectuer un achat sur ce réseau"
},
"buyMoreAsset": { "buyMoreAsset": {
"message": "Acheter plus de $1", "message": "Acheter plus de $1",
"description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase" "description": "$1 is the ticker symbol of a an asset the user is being prompted to purchase"
@ -828,6 +847,9 @@
"connectionRequest": { "connectionRequest": {
"message": "Demande de connexion" "message": "Demande de connexion"
}, },
"connections": {
"message": "Connexions"
},
"contactUs": { "contactUs": {
"message": "Nous contacter" "message": "Nous contacter"
}, },
@ -1137,6 +1159,9 @@
"message": "Description provenant de $1", "message": "Description provenant de $1",
"description": "$1 represents the name of the snap" "description": "$1 represents the name of the snap"
}, },
"desktopApp": {
"message": "Application de bureau"
},
"desktopConnectionCriticalErrorDescription": { "desktopConnectionCriticalErrorDescription": {
"message": "Cette erreur peut être passagère essayez de redémarrer lextension ou de désactiver MetaMask Desktop." "message": "Cette erreur peut être passagère essayez de redémarrer lextension ou de désactiver MetaMask Desktop."
}, },
@ -1550,7 +1575,7 @@
"message": "Explorer les Snaps MetaMask" "message": "Explorer les Snaps MetaMask"
}, },
"extendWalletWithSnaps": { "extendWalletWithSnaps": {
"message": "Prolongez lexpérience avec ce portefeuille." "message": "Personnalisez votre expérience de portefeuille."
}, },
"externalExtension": { "externalExtension": {
"message": "Extension externe" "message": "Extension externe"
@ -2755,12 +2780,24 @@
"notifications23ActionText": { "notifications23ActionText": {
"message": "Activer les alertes de sécurité" "message": "Activer les alertes de sécurité"
}, },
"notifications23DescriptionOne": {
"message": "Évitez de vous faire arnaquer et protégez vos données personnelles grâce aux alertes de sécurité fournies par Blockaid sur le réseau principal Ethereum."
},
"notifications23DescriptionTwo": { "notifications23DescriptionTwo": {
"message": "Vous devez faire preuve de diligence raisonnable avant dapprouver toute demande." "message": "Vous devez faire preuve de diligence raisonnable avant dapprouver toute demande."
}, },
"notifications23Title": { "notifications23Title": {
"message": "Restez en sécurité grâce aux alertes de sécurité" "message": "Restez en sécurité grâce aux alertes de sécurité"
}, },
"notifications24ActionText": {
"message": "Jai compris"
},
"notifications24Description": {
"message": "Les paramètres des frais de gaz avancés sont désormais ajustés en fonction du réseau que vous utilisez. Cela signifie que vous pouvez définir des frais de gaz avancés pour chaque réseau et éviter de payer trop cher pour le gaz ou le blocage des transactions."
},
"notifications24Title": {
"message": "Frais de gaz avancés pour chaque réseau"
},
"notifications3ActionText": { "notifications3ActionText": {
"message": "En savoir plus", "message": "En savoir plus",
"description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a page about security on the metamask support website." "description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a page about security on the metamask support website."
@ -2842,8 +2879,16 @@
"notifications9Title": { "notifications9Title": {
"message": "👓 Nous simplifions la lisibilité des transactions." "message": "👓 Nous simplifions la lisibilité des transactions."
}, },
"notificationsDropLedgerFirefoxDescription": {
"message": "Firefox ne prend plus en charge la norme dauthentification U2F, donc Ledger ne fonctionnera pas avec MetaMask sur Firefox. Essayez plutôt dutiliser MetaMask sur Google Chrome.",
"description": "Description of a notification in the 'See What's New' popup. Describes that ledger will not longer be supported for firefox users and they should use MetaMask on chrome for ledger support instead."
},
"notificationsDropLedgerFirefoxTitle": {
"message": "La prise en charge de Ledger ne sera plus assurée sur Firefox",
"description": "Title for a notification in the 'See What's New' popup. Tells firefox users that ledger support is being dropped."
},
"notificationsEmptyText": { "notificationsEmptyText": {
"message": "Rien à voir ici." "message": "Ici, vous pouvez trouver des notifications de vos snaps installés."
}, },
"notificationsHeader": { "notificationsHeader": {
"message": "Notifications" "message": "Notifications"
@ -2855,6 +2900,21 @@
"notificationsMarkAllAsRead": { "notificationsMarkAllAsRead": {
"message": "Marquer tout comme lu" "message": "Marquer tout comme lu"
}, },
"notificationsOpenBetaSnapsActionText": {
"message": "En savoir plus"
},
"notificationsOpenBetaSnapsDescriptionOne": {
"message": "🎉 Nous sommes ravis dannoncer le lancement de la version bêta publique de MetaMask Snaps !"
},
"notificationsOpenBetaSnapsDescriptionThree": {
"message": "Personnalisez votre portefeuille avec des snaps conçus par la communauté de développeurs !"
},
"notificationsOpenBetaSnapsDescriptionTwo": {
"message": "Les snaps vous aident à profiter pleinement de MetaMask, par exemple vous connecter à plus de réseaux, voir un aperçu des transactions et recevoir des notifications personnalisées."
},
"notificationsOpenBetaSnapsTitle": {
"message": "Présentation de MetaMask Snaps"
},
"numberOfNewTokensDetectedPlural": { "numberOfNewTokensDetectedPlural": {
"message": "$1 nouveaux jetons trouvés dans ce compte", "message": "$1 nouveaux jetons trouvés dans ce compte",
"description": "$1 is the number of new tokens detected" "description": "$1 is the number of new tokens detected"
@ -3640,9 +3700,16 @@
"securityAlerts": { "securityAlerts": {
"message": "Alertes de sécurité" "message": "Alertes de sécurité"
}, },
"securityAlertsDescription": {
"message": "Cette fonctionnalité vous avertit de toute activité malveillante sur le réseau principal Ethereum en examinant activement les transactions et les demandes de signature tout en protégeant vos données personnelles. Vos données ne sont pas partagées avec la tierce partie qui fournit ce service. Vous devez faire preuve de diligence raisonnable avant dapprouver toute demande. Rien ne garantit que toutes les activités malveillantes seront détectées par cette fonctionnalité."
},
"securityAndPrivacy": { "securityAndPrivacy": {
"message": "Sécurité et confidentialité" "message": "Sécurité et confidentialité"
}, },
"securityProviderPoweredBy": {
"message": "Service fourni par $1",
"description": "The security provider that is providing data"
},
"seeDetails": { "seeDetails": {
"message": "Voir les détails" "message": "Voir les détails"
}, },
@ -3724,6 +3791,9 @@
"selectAnAccountHelp": { "selectAnAccountHelp": {
"message": "Sélectionnez les comptes de dépôt que vous voulez utiliser dans MetaMask Institutional." "message": "Sélectionnez les comptes de dépôt que vous voulez utiliser dans MetaMask Institutional."
}, },
"selectAnAction": {
"message": "Sélectionner une action"
},
"selectHdPath": { "selectHdPath": {
"message": "Sélectionner le chemin HD" "message": "Sélectionner le chemin HD"
}, },
@ -3748,6 +3818,9 @@
"sendBugReport": { "sendBugReport": {
"message": "Envoyez-nous un rapport de bogue." "message": "Envoyez-nous un rapport de bogue."
}, },
"sendDescription": {
"message": "Transférez des crypto-actifs vers nimporte quel compte"
},
"sendSpecifiedTokens": { "sendSpecifiedTokens": {
"message": "Envoyer $1", "message": "Envoyer $1",
"description": "Symbol of the specified token" "description": "Symbol of the specified token"
@ -4026,18 +4099,10 @@
"snapsNoInsight": { "snapsNoInsight": {
"message": "Le snap na renvoyé aucun aperçu" "message": "Le snap na renvoyé aucun aperçu"
}, },
"snapsPrivacyWarningFirstMessage": {
"message": "Vous reconnaissez que le snap que vous êtes sur le point dinstaller est un « Service tiers » tel que défini dans les $1 de Consensys. Lutilisation des services tiers est régie par des conditions distinctes définies par le fournisseur du service tiers. Si vous décidez dutiliser ce service tiers, vous le faites à vos propres risques. Consensys décline toute responsabilité pour toute perte liée à lutilisation des services tiers.",
"description": "First part of a message in popup modal displayed when installing a snap for the first time. $1 is terms of use link."
},
"snapsPrivacyWarningSecondMessage": { "snapsPrivacyWarningSecondMessage": {
"message": "Toute information que vous partagez avec des services tiers sera collectée directement par ces services tiers conformément à leur politique de confidentialité. Pour plus dinformations, veuillez consulter leur politique de confidentialité.", "message": "Toute information que vous partagez avec des services tiers sera collectée directement par ces services tiers conformément à leur politique de confidentialité. Pour plus dinformations, veuillez consulter leur politique de confidentialité.",
"description": "Second part of a message in popup modal displayed when installing a snap for the first time." "description": "Second part of a message in popup modal displayed when installing a snap for the first time."
}, },
"snapsPrivacyWarningThirdMessage": {
"message": "Consensys na pas accès aux informations que vous partagez avec ces tiers.",
"description": "Third part of a message in popup modal displayed when installing a snap for the first time."
},
"snapsSettingsDescription": { "snapsSettingsDescription": {
"message": "Gérez vos Snaps" "message": "Gérez vos Snaps"
}, },
@ -4194,6 +4259,9 @@
"stake": { "stake": {
"message": "Staker" "message": "Staker"
}, },
"stakeDescription": {
"message": "Conservez vos crypto-actifs et dégagez des bénéfices potentiels"
},
"stateLogError": { "stateLogError": {
"message": "Erreur lors du chargement des journaux détat." "message": "Erreur lors du chargement des journaux détat."
}, },
@ -4330,6 +4398,9 @@
"swap": { "swap": {
"message": "Swap" "message": "Swap"
}, },
"swapAdjustSlippage": {
"message": "Ajuster leffet de glissement"
},
"swapAggregator": { "swapAggregator": {
"message": "Agrégateur" "message": "Agrégateur"
}, },
@ -4382,9 +4453,15 @@
"swapDecentralizedExchange": { "swapDecentralizedExchange": {
"message": "Échange décentralisé" "message": "Échange décentralisé"
}, },
"swapDescription": {
"message": "Échangez vos jetons"
},
"swapDirectContract": { "swapDirectContract": {
"message": "Contrat direct" "message": "Contrat direct"
}, },
"swapDisabled": {
"message": "Impossible deffectuer un échange sur ce réseau"
},
"swapEditLimit": { "swapEditLimit": {
"message": "Modifier la limite" "message": "Modifier la limite"
}, },
@ -4448,6 +4525,9 @@
"message": "Les frais de carburant sont payés aux mineurs de cryptomonnaies qui traitent les transactions sur le réseau $1. MetaMask ne tire aucun profit des frais de carburant.", "message": "Les frais de carburant sont payés aux mineurs de cryptomonnaies qui traitent les transactions sur le réseau $1. MetaMask ne tire aucun profit des frais de carburant.",
"description": "$1 is the selected network, e.g. Ethereum or BSC" "description": "$1 is the selected network, e.g. Ethereum or BSC"
}, },
"swapHighSlippage": {
"message": "Important effet de glissement"
},
"swapHighSlippageWarning": { "swapHighSlippageWarning": {
"message": "Le montant du glissement est très élevé." "message": "Le montant du glissement est très élevé."
}, },
@ -4462,6 +4542,9 @@
"swapLearnMore": { "swapLearnMore": {
"message": "En savoir plus sur les swaps" "message": "En savoir plus sur les swaps"
}, },
"swapLowSlippage": {
"message": "Faible effet de glissement"
},
"swapLowSlippageError": { "swapLowSlippageError": {
"message": "La transaction peut échouer, car le glissement maximal est trop faible." "message": "La transaction peut échouer, car le glissement maximal est trop faible."
}, },
@ -4572,6 +4655,20 @@
"swapShowLatestQuotes": { "swapShowLatestQuotes": {
"message": "Afficher les dernières cotations" "message": "Afficher les dernières cotations"
}, },
"swapSlippageHighDescription": {
"message": "Leffet de glissement saisi ($1 %) est considéré comme très élevé et peut donner lieu à un taux de change désavantageux",
"description": "$1 is the amount of % for slippage"
},
"swapSlippageHighTitle": {
"message": "Important effet de glissement"
},
"swapSlippageLowDescription": {
"message": "Une valeur aussi faible ($1 %) peut entraîner léchec de laccord de swap",
"description": "$1 is the amount of % for slippage"
},
"swapSlippageLowTitle": {
"message": "Faible effet de glissement"
},
"swapSlippageNegative": { "swapSlippageNegative": {
"message": "Le glissement doit être supérieur ou égal à zéro" "message": "Le glissement doit être supérieur ou égal à zéro"
}, },
@ -4639,6 +4736,9 @@
"message": "Nous navons pas pu récupérer votre solde de $1", "message": "Nous navons pas pu récupérer votre solde de $1",
"description": "This message communicates to the user that their balance of a given token is currently unavailable. $1 will be replaced by a token symbol" "description": "This message communicates to the user that their balance of a given token is currently unavailable. $1 will be replaced by a token symbol"
}, },
"swapTokenNotAvailable": {
"message": "Impossible déchanger ce jeton dans cette région"
},
"swapTokenToToken": { "swapTokenToToken": {
"message": "Swap de $1 vers $2", "message": "Swap de $1 vers $2",
"description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap." "description": "Used in the transaction display list to describe a swap. $1 and $2 are the symbols of tokens in involved in a swap."
@ -5259,6 +5359,9 @@
"visitWebSite": { "visitWebSite": {
"message": "Visitez notre site web" "message": "Visitez notre site web"
}, },
"wallet": {
"message": "Portefeuille"
},
"walletConnectionGuide": { "walletConnectionGuide": {
"message": "notre guide de connexion des portefeuilles matériels" "message": "notre guide de connexion des portefeuilles matériels"
}, },
@ -5286,8 +5389,7 @@
"message": "Voulez-vous ajouter ce réseau ?" "message": "Voulez-vous ajouter ce réseau ?"
}, },
"wantsToAddThisAsset": { "wantsToAddThisAsset": {
"message": "$1 veut ajouter cet actif à votre portefeuille", "message": "$1 veut ajouter cet actif à votre portefeuille."
"description": "$1 is the name of the website that wants to add an asset to your wallet"
}, },
"warning": { "warning": {
"message": "Avertissement" "message": "Avertissement"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,93 @@
<svg width="296" height="114" viewBox="0 0 296 114" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1357_4712)">
<rect width="296" height="114" rx="8" fill="#F2F4F6"/>
<g opacity="0.8" filter="url(#filter0_f_1357_4712)">
<path d="M277.679 215.325L152.424 402.875L598.645 423.026L583.771 -53.5996L277.679 215.325Z" fill="#E27625" stroke="#E27625" stroke-width="7.65217" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M-293.003 -294.625L-225.679 26.2251L-268.735 58.0001L-204.542 106.05L-253.078 143.25L-189.668 200.6L-229.593 229.275L-138 335.45L277.69 215.325L572.039 -31.1249L-192.799 -593L-293.003 -294.625Z" fill="#763E1A" stroke="#763E1A" stroke-width="7.65217" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<rect width="328" height="136" fill="url(#paint0_linear_1357_4712)"/>
<g clip-path="url(#clip1_1357_4712)">
<path opacity="0.5" d="M253.868 140.582C247.795 152.08 232.314 157.285 212.081 156.317C191.864 155.35 166.98 148.219 142.228 135.146C117.475 122.072 97.5563 105.54 85.3601 89.3881C73.1534 73.2222 68.725 57.5013 74.7978 46.0034C80.8706 34.5055 96.3515 29.3 116.585 30.2679C136.802 31.235 161.685 38.3657 186.438 51.4392C211.191 64.5128 231.109 81.045 243.306 97.197C255.512 113.363 259.941 129.084 253.868 140.582Z" fill="url(#paint1_radial_1357_4712)" fill-opacity="0.75" stroke="white" stroke-width="0.394925"/>
<path opacity="0.5" d="M226.842 122.668C219.528 136.517 203.475 144.122 183.364 145.168C163.258 146.215 139.14 140.701 115.784 128.365C92.428 116.029 74.2766 99.2183 63.8055 82.0222C53.3314 64.8213 50.5624 47.2762 57.8772 33.4267C65.192 19.5773 81.244 11.9728 101.356 10.9262C121.462 9.87988 145.58 15.394 168.936 27.7298C192.292 40.0655 210.443 56.8763 220.914 74.0724C231.388 91.2733 234.157 108.818 226.842 122.668Z" fill="url(#paint2_radial_1357_4712)" fill-opacity="0.5" stroke="white" stroke-width="0.474924"/>
<path opacity="0.5" d="M249.145 25.0877C251.823 29.726 251.557 35.808 248.719 42.8719C245.882 49.933 240.487 57.9416 232.969 66.3966C217.933 83.305 194.434 101.965 166.034 118.362C137.633 134.759 109.724 145.78 87.5628 150.347C76.4812 152.631 66.8482 153.298 59.3146 152.225C51.778 151.151 46.3779 148.34 43.7 143.702C41.0221 139.063 41.2881 132.981 44.1262 125.918C46.9632 118.856 52.3579 110.848 59.8766 102.393C74.9125 85.4844 98.4117 66.8245 126.812 50.4277C155.212 34.0308 183.122 23.0099 205.283 18.4427C216.364 16.1588 225.997 15.4911 233.531 16.5648C241.067 17.6389 246.468 20.4495 249.145 25.0877Z" fill="url(#paint3_radial_1357_4712)" fill-opacity="0.5" stroke="white" stroke-width="0.394925"/>
<path opacity="0.5" d="M269.805 75.1055C270.009 76.9384 269.375 78.8376 267.946 80.7825C266.517 82.7285 264.301 84.708 261.368 86.6911C255.502 90.6569 246.803 94.6129 235.908 98.3353C214.121 105.779 183.592 112.274 149.489 116.053C115.385 119.833 84.1756 120.179 61.2872 117.685C49.8413 116.439 40.4873 114.483 33.8953 111.898C30.5991 110.605 28.0036 109.159 26.1832 107.573C24.3638 105.988 23.3294 104.274 23.1263 102.441C22.9232 100.608 23.5571 98.7086 24.9854 96.7637C26.4144 94.8177 28.6303 92.8381 31.5635 90.8551C37.4296 86.8893 46.1285 82.9333 57.0237 79.2109C78.811 71.7672 109.339 65.2719 143.443 61.4928C177.546 57.7137 208.756 57.3677 231.645 59.8607C243.09 61.1074 252.444 63.0629 259.036 65.6482C262.333 66.941 264.928 68.3873 266.749 69.9733C268.568 71.5583 269.602 73.2726 269.805 75.1055Z" fill="url(#paint4_radial_1357_4712)" stroke="white" stroke-width="0.394925"/>
<rect x="35.9463" y="72.946" width="20.1589" height="20.1589" rx="10.0794" fill="#0376C9" fill-opacity="0.58"/>
<path d="M50.5298 79.1965L46.6773 77.1627C46.2718 76.9461 45.7802 76.9461 45.3747 77.1627L41.5222 79.1965C41.2395 79.3469 41.0675 79.6357 41.0675 79.9666C41.0675 80.2916 41.2395 80.5864 41.5222 80.7368L45.3747 82.7706C45.5775 82.8789 45.8048 82.9331 46.026 82.9331C46.2472 82.9331 46.4745 82.8789 46.6773 82.7706L50.5298 80.7368C50.8124 80.5864 50.9845 80.2976 50.9845 79.9666C50.9845 79.6357 50.8124 79.3469 50.5298 79.1965Z" fill="white"/>
<path d="M44.8689 83.309L41.3675 81.4499C41.0905 81.3167 40.6775 81.4203 40.419 81.5777C40.1544 81.7412 40.0005 82.0136 40.0005 82.3162V85.6516C40.0005 86.2266 40.3267 86.7825 40.8498 87.0428L44.4381 88.9586C44.5611 89.0191 44.6966 89.0494 44.832 89.0494C44.992 89.0494 45.152 89.007 45.2936 88.9222C45.5582 88.7649 45.7121 88.3029 45.7121 88.0002V84.6649C45.7182 84.0838 45.392 83.5632 44.8689 83.309Z" fill="white"/>
<path d="M51.633 81.5801C51.3683 81.4228 50.9528 81.3107 50.682 81.4499L47.1892 83.3108C46.666 83.571 46.3398 84.0854 46.3398 84.6663V88.0005C46.3398 88.3031 46.4937 88.7669 46.7584 88.9242C46.8999 89.0089 47.0599 89.0513 47.22 89.0513C47.3554 89.0513 47.4908 89.021 47.6139 88.9605L51.2021 87.0428C51.7253 86.7826 52.0515 86.2336 52.0515 85.6526V82.3184C52.0515 82.0158 51.8976 81.7435 51.633 81.5801Z" fill="white"/>
<rect x="35.9463" y="72.946" width="20.1589" height="20.1589" rx="10.0794" stroke="#ADD5F3" stroke-width="0.5"/>
<rect x="158.946" y="15.946" width="20.1589" height="20.1589" rx="10.0794" fill="#0376C9" fill-opacity="0.58"/>
<path d="M173.53 22.1965L169.677 20.1627C169.272 19.9461 168.78 19.9461 168.375 20.1627L164.522 22.1965C164.24 22.3469 164.068 22.6357 164.068 22.9666C164.068 23.2916 164.24 23.5864 164.522 23.7368L168.375 25.7706C168.577 25.8789 168.805 25.9331 169.026 25.9331C169.247 25.9331 169.475 25.8789 169.677 25.7706L173.53 23.7368C173.812 23.5864 173.984 23.2976 173.984 22.9666C173.984 22.6357 173.812 22.3469 173.53 22.1965Z" fill="white"/>
<path d="M167.869 26.309L164.368 24.4499C164.091 24.3167 163.678 24.4203 163.419 24.5777C163.154 24.7412 163 25.0136 163 25.3162V28.6516C163 29.2266 163.327 29.7825 163.85 30.0428L167.438 31.9586C167.561 32.0191 167.697 32.0494 167.832 32.0494C167.992 32.0494 168.152 32.007 168.294 31.9222C168.558 31.7649 168.712 31.3029 168.712 31.0002V27.6649C168.718 27.0838 168.392 26.5632 167.869 26.309Z" fill="white"/>
<path d="M174.633 24.5801C174.368 24.4228 173.953 24.3107 173.682 24.4499L170.189 26.3108C169.666 26.571 169.34 27.0854 169.34 27.6663V31.0005C169.34 31.3031 169.494 31.7669 169.758 31.9242C169.9 32.0089 170.06 32.0513 170.22 32.0513C170.355 32.0513 170.491 32.021 170.614 31.9605L174.202 30.0428C174.725 29.7826 175.052 29.2336 175.052 28.6526V25.3184C175.052 25.0158 174.898 24.7435 174.633 24.5801Z" fill="white"/>
<rect x="158.946" y="15.946" width="20.1589" height="20.1589" rx="10.0794" stroke="#D1E8FA" stroke-width="0.5"/>
<rect x="66.9463" y="6.94604" width="20.1589" height="20.1589" rx="10.0794" fill="#0376C9" fill-opacity="0.58"/>
<path d="M81.5298 13.1965L77.6773 11.1627C77.2718 10.9461 76.7802 10.9461 76.3747 11.1627L72.5222 13.1965C72.2395 13.3469 72.0675 13.6357 72.0675 13.9666C72.0675 14.2916 72.2395 14.5864 72.5222 14.7368L76.3747 16.7706C76.5775 16.8789 76.8048 16.9331 77.026 16.9331C77.2472 16.9331 77.4745 16.8789 77.6773 16.7706L81.5298 14.7368C81.8124 14.5864 81.9845 14.2976 81.9845 13.9666C81.9845 13.6357 81.8124 13.3469 81.5298 13.1965Z" fill="white"/>
<path d="M75.8689 17.309L72.3675 15.4499C72.0905 15.3167 71.6775 15.4203 71.419 15.5777C71.1544 15.7412 71.0005 16.0136 71.0005 16.3162V19.6516C71.0005 20.2266 71.3267 20.7825 71.8498 21.0428L75.4381 22.9586C75.5611 23.0191 75.6966 23.0494 75.832 23.0494C75.992 23.0494 76.152 23.007 76.2936 22.9222C76.5582 22.7649 76.7121 22.3029 76.7121 22.0002V18.6649C76.7182 18.0838 76.392 17.5632 75.8689 17.309Z" fill="white"/>
<path d="M82.633 15.5801C82.3683 15.4228 81.9528 15.3107 81.682 15.4499L78.1892 17.3108C77.666 17.571 77.3398 18.0854 77.3398 18.6663V22.0005C77.3398 22.3031 77.4937 22.7669 77.7584 22.9242C77.8999 23.0089 78.0599 23.0513 78.22 23.0513C78.3554 23.0513 78.4908 23.021 78.6139 22.9605L82.2021 21.0428C82.7253 20.7826 83.0515 20.2336 83.0515 19.6526V16.3184C83.0515 16.0158 82.8976 15.7435 82.633 15.5801Z" fill="white"/>
<rect x="66.9463" y="6.94604" width="20.1589" height="20.1589" rx="10.0794" stroke="#D1E8FA" stroke-width="0.5"/>
<rect x="228.946" y="7.94604" width="20.1589" height="20.1589" rx="10.0794" fill="#0376C9" fill-opacity="0.58"/>
<path d="M243.53 14.1965L239.677 12.1627C239.272 11.9461 238.78 11.9461 238.375 12.1627L234.522 14.1965C234.24 14.3469 234.068 14.6357 234.068 14.9666C234.068 15.2916 234.24 15.5864 234.522 15.7368L238.375 17.7706C238.577 17.8789 238.805 17.9331 239.026 17.9331C239.247 17.9331 239.475 17.8789 239.677 17.7706L243.53 15.7368C243.812 15.5864 243.984 15.2976 243.984 14.9666C243.984 14.6357 243.812 14.3469 243.53 14.1965Z" fill="white"/>
<path d="M237.869 18.309L234.368 16.4499C234.091 16.3167 233.678 16.4203 233.419 16.5777C233.154 16.7412 233 17.0136 233 17.3162V20.6516C233 21.2266 233.327 21.7825 233.85 22.0428L237.438 23.9586C237.561 24.0191 237.697 24.0494 237.832 24.0494C237.992 24.0494 238.152 24.007 238.294 23.9222C238.558 23.7649 238.712 23.3029 238.712 23.0002V19.6649C238.718 19.0838 238.392 18.5632 237.869 18.309Z" fill="white"/>
<path d="M244.633 16.5801C244.368 16.4228 243.953 16.3107 243.682 16.4499L240.189 18.3108C239.666 18.571 239.34 19.0854 239.34 19.6663V23.0005C239.34 23.3031 239.494 23.7669 239.758 23.9242C239.9 24.0089 240.06 24.0513 240.22 24.0513C240.355 24.0513 240.491 24.021 240.614 23.9605L244.202 22.0428C244.725 21.7826 245.052 21.2336 245.052 20.6526V17.3184C245.052 17.0158 244.898 16.7435 244.633 16.5801Z" fill="white"/>
<rect x="228.946" y="7.94604" width="20.1589" height="20.1589" rx="10.0794" stroke="#D1E8FA" stroke-width="0.5"/>
<rect x="234.095" y="84.0952" width="19.8607" height="19.8607" rx="9.93033" fill="#0376C9" fill-opacity="0.58"/>
<path d="M248.53 90.1965L244.677 88.1627C244.272 87.9461 243.78 87.9461 243.375 88.1627L239.522 90.1965C239.24 90.3469 239.068 90.6357 239.068 90.9666C239.068 91.2916 239.24 91.5864 239.522 91.7368L243.375 93.7706C243.577 93.8789 243.805 93.9331 244.026 93.9331C244.247 93.9331 244.475 93.8789 244.677 93.7706L248.53 91.7368C248.812 91.5864 248.984 91.2976 248.984 90.9666C248.984 90.6357 248.812 90.3469 248.53 90.1965Z" fill="white"/>
<path d="M242.869 94.309L239.368 92.4499C239.091 92.3167 238.678 92.4203 238.419 92.5777C238.154 92.7412 238 93.0136 238 93.3162V96.6516C238 97.2266 238.327 97.7825 238.85 98.0428L242.438 99.9586C242.561 100.019 242.697 100.049 242.832 100.049C242.992 100.049 243.152 100.007 243.294 99.9222C243.558 99.7649 243.712 99.3029 243.712 99.0002V95.6649C243.718 95.0838 243.392 94.5632 242.869 94.309Z" fill="white"/>
<path d="M249.633 92.5801C249.368 92.4228 248.953 92.3107 248.682 92.4499L245.189 94.3108C244.666 94.571 244.34 95.0854 244.34 95.6663V99.0005C244.34 99.3031 244.494 99.7669 244.758 99.9242C244.9 100.009 245.06 100.051 245.22 100.051C245.355 100.051 245.491 100.021 245.614 99.9605L249.202 98.0428C249.725 97.7826 250.052 97.2336 250.052 96.6526V93.3184C250.052 93.0158 249.898 92.7435 249.633 92.5801Z" fill="white"/>
<rect x="234.095" y="84.0952" width="19.8607" height="19.8607" rx="9.93033" stroke="#ADD5F3" stroke-width="0.79823"/>
</g>
<path d="M203.089 37L155.379 72.0625L164.251 51.399L203.089 37Z" fill="#E17726" stroke="#E17726" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M93.04 37L140.325 72.3898L131.878 51.399L93.04 37Z" fill="#E27625" stroke="#E27625" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M121.401 85.7603L113.851 97.0738L140.749 98.2893L139.853 69.5381L121.401 85.7603Z" fill="#E27625" stroke="#E27625" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M174.728 85.7602L155.993 69.2107L155.379 98.2892L182.278 97.0737L174.728 85.7602Z" fill="#E27625" stroke="#E27625" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M138.249 111.987L124.752 108.06L134.285 103.712L138.249 111.987Z" fill="#233447" stroke="#233447" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M157.881 111.987L161.845 103.712L171.425 108.06L157.881 111.987Z" fill="#233447" stroke="#233447" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M182.278 97.0737L155.379 98.2892L157.881 111.987L161.845 103.712L171.424 108.06L182.278 97.0737Z" fill="#CC6228" stroke="#CC6228" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M124.752 108.06L134.285 103.712L138.249 111.987L140.75 98.2892L113.851 97.0737L124.752 108.06Z" fill="#CC6228" stroke="#CC6228" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M113.851 97.0737L125.13 118.906L124.752 108.06L113.851 97.0737Z" fill="#E27525" stroke="#E27525" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M171.424 108.06L170.999 118.906L182.278 97.0737L171.424 108.06Z" fill="#E27525" stroke="#E27525" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M140.75 98.2893L138.249 111.987L141.41 128.163L142.118 106.845L140.75 98.2893Z" fill="#E27525" stroke="#E27525" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M155.378 98.2893L154.057 106.798L154.718 128.163L157.88 111.987L155.378 98.2893Z" fill="#E27525" stroke="#E27525" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M157.881 111.987L154.719 128.163L156.984 129.752L171 118.906L171.425 108.06L157.881 111.987Z" fill="#F5841F" stroke="#F5841F" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M124.752 108.06L125.13 118.906L139.146 129.752L141.411 128.163L138.249 111.987L124.752 108.06Z" fill="#F5841F" stroke="#F5841F" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M205.118 74.3533L209.129 54.9988L203.089 37L156.983 70.8938L174.727 85.7603L199.786 93.0065L205.307 86.6018L202.9 84.872L206.723 81.4125L203.797 79.1685L207.619 76.27L205.118 74.3533Z" fill="#763E1A" stroke="#763E1A" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M87 54.9988L91.0584 74.3533L88.4629 76.27L92.3326 79.1685L89.4067 81.4125L93.2292 84.872L90.8225 86.6018L96.3438 93.0065L121.402 85.7603L139.146 70.8938L93.0404 37L87 54.9988Z" fill="#763E1A" stroke="#763E1A" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M199.785 93.0065L174.727 85.7603L182.278 97.0738L170.999 118.906L185.911 118.719H208.185L199.785 93.0065Z" fill="#F5841F" stroke="#F5841F" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M121.402 85.7603L96.344 93.0065L87.9912 118.719H110.218L125.13 118.906L113.852 97.0738L121.402 85.7603Z" fill="#F5841F" stroke="#F5841F" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M155.379 98.2894L156.983 70.8939L164.25 51.3992H131.877L139.145 70.8939L140.749 98.2894L141.363 106.891L141.41 128.163H154.718L154.765 106.891L155.379 98.2894Z" fill="#F5841F" stroke="#F5841F" stroke-width="1.62609" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<filter id="filter0_f_1357_4712" x="-552.83" y="-852.827" width="2545.64" height="2379.65" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feGaussianBlur stdDeviation="128" result="effect1_foregroundBlur_1357_4712"/>
</filter>
<linearGradient id="paint0_linear_1357_4712" x1="164" y1="0" x2="164" y2="136" gradientUnits="userSpaceOnUse">
<stop stop-color="#D2E9FF"/>
<stop offset="1" stop-color="#2F93DC"/>
</linearGradient>
<radialGradient id="paint1_radial_1357_4712" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(164.333 93.2925) rotate(117.841) scale(47.5298 101.454)">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="#EBEBEB"/>
</radialGradient>
<radialGradient id="paint2_radial_1357_4712" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(142.36 78.0473) rotate(117.841) scale(57.142 95.7796)">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="#EBEBEB"/>
</radialGradient>
<radialGradient id="paint3_radial_1357_4712" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(146.423 84.3947) rotate(60) scale(39.4193 118.811)">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="#EBEBEB"/>
</radialGradient>
<radialGradient id="paint4_radial_1357_4712" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(146.466 88.7731) rotate(83.6767) scale(27.6448 124.292)">
<stop stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="#EBEBEB"/>
</radialGradient>
<clipPath id="clip0_1357_4712">
<rect width="296" height="114" rx="8" fill="white"/>
</clipPath>
<clipPath id="clip1_1357_4712">
<rect width="262.027" height="130.9" fill="white" transform="translate(11 5)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -218,7 +218,6 @@ browser.runtime.onConnectExternal.addListener(async (...args) => {
* @property {boolean} isAccountMenuOpen - Represents whether the main account selection UI is currently displayed. * @property {boolean} isAccountMenuOpen - Represents whether the main account selection UI is currently displayed.
* @property {boolean} isNetworkMenuOpen - Represents whether the main network selection UI is currently displayed. * @property {boolean} isNetworkMenuOpen - Represents whether the main network 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} 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} networkConfigurations - A list of network configurations, containing RPC provider details (eg chainId, rpcUrl, rpcPreferences). * @property {object} networkConfigurations - A list of network configurations, containing RPC provider details (eg chainId, rpcUrl, rpcPreferences).
* @property {Array} addressBook - A list of previously sent to addresses. * @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.
@ -235,7 +234,6 @@ browser.runtime.onConnectExternal.addListener(async (...args) => {
* @property {string} networkStatus - Either "unknown", "available", "unavailable", or "blocked", depending on the status of the currently selected network. * @property {string} networkStatus - Either "unknown", "available", "unavailable", or "blocked", depending on the status of the currently selected network.
* @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 {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 {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.

View File

@ -172,11 +172,12 @@ export default class SwapsController {
} }
async fetchSwapsNetworkConfig(chainId) { async fetchSwapsNetworkConfig(chainId) {
const response = await fetchWithCache( const response = await fetchWithCache({
getBaseApi('network', chainId), url: getBaseApi('network', chainId),
{ method: 'GET' }, fetchOptions: { method: 'GET' },
{ cacheRefreshTime: 600000 }, cacheOptions: { cacheRefreshTime: 600000 },
); functionName: 'fetchSwapsNetworkConfig',
});
const { refreshRates, parameters = {} } = response || {}; const { refreshRates, parameters = {} } = response || {};
if ( if (
!refreshRates || !refreshRates ||

View File

@ -229,7 +229,7 @@ export default class TransactionController extends EventEmitter {
isEnabled: () => isEnabled: () =>
Boolean( Boolean(
this.preferencesStore.getState().incomingTransactionsPreferences?.[ this.preferencesStore.getState().incomingTransactionsPreferences?.[
this._getChainId() this._getCurrentChainId()
] && this._hasCompletedOnboarding(), ] && this._hasCompletedOnboarding(),
), ),
lastFetchedBlockNumbers: opts.initState?.lastFetchedBlockNumbers || {}, lastFetchedBlockNumbers: opts.initState?.lastFetchedBlockNumbers || {},
@ -2135,16 +2135,12 @@ export default class TransactionController extends EventEmitter {
* Updates the memStore in transaction controller * Updates the memStore in transaction controller
*/ */
_updateMemstore() { _updateMemstore() {
const { transactions } = this.store.getState(); const transactions = this.getTransactions({
const unapprovedTxs = this.txStateManager.getUnapprovedTxList(); filterToCurrentNetwork: false,
const currentNetworkTxList = this.txStateManager.getTransactions({
limit: MAX_MEMSTORE_TX_LIST_SIZE, limit: MAX_MEMSTORE_TX_LIST_SIZE,
}); });
this.memStore.updateState({ this.memStore.updateState({
unapprovedTxs,
currentNetworkTxList,
transactions, transactions,
}); });
} }

View File

@ -56,10 +56,10 @@ const TRANSACTION_META_MOCK = {
hash: '0x1', hash: '0x1',
id: 1, id: 1,
status: TransactionStatus.confirmed, status: TransactionStatus.confirmed,
transaction: { time: 123456789,
txParams: {
from: VALID_ADDRESS, from: VALID_ADDRESS,
}, },
time: 123456789,
}; };
async function flushPromises() { async function flushPromises() {
@ -186,21 +186,10 @@ describe('Transaction Controller', function () {
it('should return a state object with the right keys and data types', function () { it('should return a state object with the right keys and data types', function () {
const exposedState = txController.getState(); const exposedState = txController.getState();
assert.ok( assert.ok(
'unapprovedTxs' in exposedState, 'transactions' in exposedState,
'state should have the key unapprovedTxs', 'state should have the key transactions',
);
assert.ok(
'currentNetworkTxList' in exposedState,
'state should have the key currentNetworkTxList',
);
assert.ok(
typeof exposedState?.unapprovedTxs === 'object',
'should be an object',
);
assert.ok(
Array.isArray(exposedState.currentNetworkTxList),
'should be an array',
); );
assert.ok(Array.isArray(exposedState.transactions), 'should be an array');
}); });
}); });

View File

@ -1,7 +1,8 @@
import log from 'loglevel'; import log from 'loglevel';
/** /**
* Returns a middleware that logs RPC activity * Returns a middleware that logs RPC activity. Logging is detailed in
* development builds, but more limited in production builds.
* *
* @param {{ origin: string }} opts - The middleware options * @param {{ origin: string }} opts - The middleware options
* @returns {Function} * @returns {Function}
@ -14,12 +15,20 @@ export default function createLoggerMiddleware(opts) {
) { ) {
next((/** @type {Function} */ cb) => { next((/** @type {Function} */ cb) => {
if (res.error) { if (res.error) {
log.error('Error in RPC response:\n', res); log.debug('Error in RPC response:\n', res);
} }
if (req.isMetamaskInternal) { if (req.isMetamaskInternal) {
return; return;
} }
if (process.env.METAMASK_DEBUG) {
log.info(`RPC (${opts.origin}):`, req, '->', res); log.info(`RPC (${opts.origin}):`, req, '->', res);
} else {
log.info(
`RPC (${opts.origin}): ${req.method} -> ${
res.error ? 'error' : 'success'
}`,
);
}
cb(); cb();
}); });
}; };

View File

@ -1,3 +1,4 @@
import { CHAIN_IDS } from '../../../../shared/constants/network';
import { import {
BlockaidReason, BlockaidReason,
BlockaidResultType, BlockaidResultType,
@ -14,38 +15,48 @@ Object.defineProperty(globalThis, 'performance', {
value: () => undefined, value: () => undefined,
}); });
describe('PPOMMiddleware', () => { const createMiddleWare = (
it('should call ppomController.usePPOM for requests of type confirmation', async () => { usePPOM?: any,
const useMock = jest.fn(); securityAlertsEnabled?: boolean,
chainId?: string,
) => {
const usePPOMMock = jest.fn();
const ppomController = { const ppomController = {
usePPOM: useMock, usePPOM: usePPOM || usePPOMMock,
}; };
const preferenceController = { const preferenceController = {
store: { getState: () => ({ securityAlertsEnabled: true }) }, store: {
getState: () => ({
securityAlertsEnabled:
securityAlertsEnabled === undefined ?? securityAlertsEnabled,
}),
},
}; };
const middlewareFunction = createPPOMMiddleware( const networkController = {
state: { providerConfig: { chainId: chainId || CHAIN_IDS.MAINNET } },
};
return createPPOMMiddleware(
ppomController as any, ppomController as any,
preferenceController as any, preferenceController as any,
networkController as any,
); );
};
describe('PPOMMiddleware', () => {
it('should call ppomController.usePPOM for requests of type confirmation', async () => {
const usePPOMMock = jest.fn();
const middlewareFunction = createMiddleWare(usePPOMMock);
await middlewareFunction( await middlewareFunction(
{ method: 'eth_sendTransaction' }, { method: 'eth_sendTransaction' },
undefined, undefined,
() => undefined, () => undefined,
); );
expect(useMock).toHaveBeenCalledTimes(1); expect(usePPOMMock).toHaveBeenCalledTimes(1);
}); });
it('should add validation response on confirmation requests', async () => { it('should add validation response on confirmation requests', async () => {
const ppomController = { const usePPOM = async () => Promise.resolve('VALIDATION_RESULT');
usePPOM: async () => Promise.resolve('VALIDATION_RESULT'), const middlewareFunction = createMiddleWare(usePPOM);
};
const preferenceController = {
store: { getState: () => ({ securityAlertsEnabled: true }) },
};
const middlewareFunction = createPPOMMiddleware(
ppomController as any,
preferenceController as any,
);
const req = { const req = {
method: 'eth_sendTransaction', method: 'eth_sendTransaction',
securityAlertResponse: undefined, securityAlertResponse: undefined,
@ -55,16 +66,19 @@ describe('PPOMMiddleware', () => {
}); });
it('should not do validation if user has not enabled preference', async () => { it('should not do validation if user has not enabled preference', async () => {
const ppomController = { const usePPOM = async () => Promise.resolve('VALIDATION_RESULT');
usePPOM: async () => Promise.resolve('VALIDATION_RESULT'), const middlewareFunction = createMiddleWare(usePPOM, false);
const req = {
method: 'eth_sendTransaction',
securityAlertResponse: undefined,
}; };
const preferenceController = { await middlewareFunction(req, undefined, () => undefined);
store: { getState: () => ({ securityAlertsEnabled: false }) }, expect(req.securityAlertResponse).toBeUndefined();
}; });
const middlewareFunction = createPPOMMiddleware(
ppomController as any, it('should not do validation if user is not on mainnet', async () => {
preferenceController as any, const usePPOM = async () => Promise.resolve('VALIDATION_RESULT');
); const middlewareFunction = createMiddleWare(usePPOM, false, '0x2');
const req = { const req = {
method: 'eth_sendTransaction', method: 'eth_sendTransaction',
securityAlertResponse: undefined, securityAlertResponse: undefined,
@ -74,18 +88,10 @@ describe('PPOMMiddleware', () => {
}); });
it('should set Failed type in response if usePPOM throw error', async () => { it('should set Failed type in response if usePPOM throw error', async () => {
const ppomController = { const usePPOM = async () => {
usePPOM: async () => {
throw new Error('some error'); throw new Error('some error');
},
}; };
const preferenceController = { const middlewareFunction = createMiddleWare(usePPOM);
store: { getState: () => ({ securityAlertsEnabled: true }) },
};
const middlewareFunction = createPPOMMiddleware(
ppomController as any,
preferenceController as any,
);
const req = { const req = {
method: 'eth_sendTransaction', method: 'eth_sendTransaction',
securityAlertResponse: undefined, securityAlertResponse: undefined,
@ -103,18 +109,10 @@ describe('PPOMMiddleware', () => {
const ppom = { const ppom = {
validateJsonRpc: () => undefined, validateJsonRpc: () => undefined,
}; };
const ppomController = { const usePPOM = async (callback: any) => {
usePPOM: async (callback: any) => {
callback(ppom); callback(ppom);
},
}; };
const preferenceController = { const middlewareFunction = createMiddleWare(usePPOM);
store: { getState: () => ({ securityAlertsEnabled: true }) },
};
const middlewareFunction = createPPOMMiddleware(
ppomController as any,
preferenceController as any,
);
const nextMock = jest.fn(); const nextMock = jest.fn();
await middlewareFunction( await middlewareFunction(
{ method: 'eth_sendTransaction' }, { method: 'eth_sendTransaction' },
@ -125,18 +123,10 @@ describe('PPOMMiddleware', () => {
}); });
it('should call next method when ppomController.usePPOM throws error', async () => { it('should call next method when ppomController.usePPOM throws error', async () => {
const ppomController = { const usePPOM = async (_callback: any) => {
usePPOM: async (_callback: any) => {
throw Error('Some error'); throw Error('Some error');
},
}; };
const preferenceController = { const middlewareFunction = createMiddleWare(usePPOM);
store: { getState: () => ({ securityAlertsEnabled: true }) },
};
const middlewareFunction = createPPOMMiddleware(
ppomController as any,
preferenceController as any,
);
const nextMock = jest.fn(); const nextMock = jest.fn();
await middlewareFunction( await middlewareFunction(
{ method: 'eth_sendTransaction' }, { method: 'eth_sendTransaction' },
@ -151,18 +141,10 @@ describe('PPOMMiddleware', () => {
const ppom = { const ppom = {
validateJsonRpc: validateMock, validateJsonRpc: validateMock,
}; };
const ppomController = { const usePPOM = async (callback: any) => {
usePPOM: async (callback: any) => {
callback(ppom); callback(ppom);
},
}; };
const preferenceController = { const middlewareFunction = createMiddleWare(usePPOM);
store: { getState: () => ({ securityAlertsEnabled: true }) },
};
const middlewareFunction = createPPOMMiddleware(
ppomController as any,
preferenceController as any,
);
await middlewareFunction( await middlewareFunction(
{ method: 'eth_sendTransaction' }, { method: 'eth_sendTransaction' },
undefined, undefined,
@ -176,18 +158,10 @@ describe('PPOMMiddleware', () => {
const ppom = { const ppom = {
validateJsonRpc: validateMock, validateJsonRpc: validateMock,
}; };
const ppomController = { const usePPOM = async (callback: any) => {
usePPOM: async (callback: any) => {
callback(ppom); callback(ppom);
},
}; };
const preferenceController = { const middlewareFunction = createMiddleWare(usePPOM);
store: { getState: () => ({ securityAlertsEnabled: true }) },
};
const middlewareFunction = createPPOMMiddleware(
ppomController as any,
preferenceController as any,
);
await middlewareFunction( await middlewareFunction(
{ method: 'eth_someRequest' }, { method: 'eth_someRequest' },
undefined, undefined,

View File

@ -1,10 +1,12 @@
import { PPOM } from '@blockaid/ppom_release'; import { PPOM } from '@blockaid/ppom_release';
import { PPOMController } from '@metamask/ppom-validator'; import { PPOMController } from '@metamask/ppom-validator';
import { NetworkController } from '@metamask/network-controller';
import { import {
BlockaidReason, BlockaidReason,
BlockaidResultType, BlockaidResultType,
} from '../../../../shared/constants/security-provider'; } from '../../../../shared/constants/security-provider';
import { CHAIN_IDS } from '../../../../shared/constants/network';
import PreferencesController from '../../controllers/preferences'; import PreferencesController from '../../controllers/preferences';
const { sentry } = global as any; const { sentry } = global as any;
@ -31,17 +33,24 @@ const ConfirmationMethods = Object.freeze([
* *
* @param ppomController - Instance of PPOMController. * @param ppomController - Instance of PPOMController.
* @param preferencesController - Instance of PreferenceController. * @param preferencesController - Instance of PreferenceController.
* @param networkController - Instance of NetworkController.
* @returns PPOMMiddleware function. * @returns PPOMMiddleware function.
*/ */
export function createPPOMMiddleware( export function createPPOMMiddleware(
ppomController: PPOMController, ppomController: PPOMController,
preferencesController: PreferencesController, preferencesController: PreferencesController,
networkController: NetworkController,
) { ) {
return async (req: any, _res: any, next: () => void) => { return async (req: any, _res: any, next: () => void) => {
try { try {
const securityAlertsEnabled = const securityAlertsEnabled =
preferencesController.store.getState()?.securityAlertsEnabled; preferencesController.store.getState()?.securityAlertsEnabled;
if (securityAlertsEnabled && ConfirmationMethods.includes(req.method)) { const { chainId } = networkController.state.providerConfig;
if (
securityAlertsEnabled &&
ConfirmationMethods.includes(req.method) &&
chainId === CHAIN_IDS.MAINNET
) {
// eslint-disable-next-line require-atomic-updates // eslint-disable-next-line require-atomic-updates
req.securityAlertResponse = await ppomController.usePPOM( req.securityAlertResponse = await ppomController.usePPOM(
async (ppom: PPOM) => { async (ppom: PPOM) => {

View File

@ -23,9 +23,7 @@ function takeObject(idx) {
return ret; return ret;
} }
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); let WASM_VECTOR_LEN = 0;
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
let cachedUint8Memory0 = null; let cachedUint8Memory0 = null;
@ -36,22 +34,6 @@ function getUint8Memory0() {
return cachedUint8Memory0; return cachedUint8Memory0;
} }
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
let WASM_VECTOR_LEN = 0;
const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
@ -118,6 +100,24 @@ function getInt32Memory0() {
return cachedInt32Memory0; return cachedInt32Memory0;
} }
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
function debugString(val) { function debugString(val) {
// primitive types // primitive types
const type = typeof val; const type = typeof val;
@ -207,16 +207,12 @@ function makeMutClosure(arg0, arg1, dtor, f) {
return real; return real;
} }
function __wbg_adapter_20(arg0, arg1) { function __wbg_adapter_20(arg0, arg1, arg2) {
wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h71774d49975c327c(arg0, arg1); wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke(arg0, arg1, addHeapObject(arg2));
} }
function __wbg_adapter_23(arg0, arg1, arg2) { function __wbg_adapter_21(arg0, arg1) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h3f3246d02d2f05cb(arg0, arg1, addHeapObject(arg2)); wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(arg0, arg1);
}
function __wbg_adapter_24(arg0, arg1) {
wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy__h2b1bef6683dbac4f(arg0, arg1);
} }
/** /**
@ -251,8 +247,8 @@ function handleError(f, args) {
wasm.__wbindgen_exn_store(addHeapObject(e)); wasm.__wbindgen_exn_store(addHeapObject(e));
} }
} }
function __wbg_adapter_52(arg0, arg1, arg2, arg3) { function __wbg_adapter_39(arg0, arg1, arg2, arg3) {
wasm.wasm_bindgen__convert__closures__invoke2_mut__h724d112298dfe4d5(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); wasm.wasm_bindgen__convert__closures__invoke2_mut(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3));
} }
/** /**
@ -346,22 +342,10 @@ function __wbg_get_imports() {
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2), getObject(arg3)); const ret = getObject(arg0).call(getObject(arg1), getObject(arg2), getObject(arg3));
return addHeapObject(ret); return addHeapObject(ret);
}, arguments) }; }, arguments) };
imports.wbg.__wbg_clearTimeout_76877dbc010e786d = function(arg0) {
const ret = clearTimeout(takeObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_from_d7c216d4616bb368 = function(arg0) { imports.wbg.__wbg_from_d7c216d4616bb368 = function(arg0) {
const ret = Array.from(getObject(arg0)); const ret = Array.from(getObject(arg0));
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbg_getTime_5e2054f832d82ec9 = function(arg0) {
const ret = getObject(arg0).getTime();
return ret;
};
imports.wbg.__wbg_getTimezoneOffset_8aee3445f323973e = function(arg0) {
const ret = getObject(arg0).getTimezoneOffset();
return ret;
};
imports.wbg.__wbg_get_44be0491f933a435 = function(arg0, arg1) { imports.wbg.__wbg_get_44be0491f933a435 = function(arg0, arg1) {
const ret = getObject(arg0)[arg1 >>> 0]; const ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret); return addHeapObject(ret);
@ -378,10 +362,6 @@ function __wbg_get_imports() {
const ret = getObject(arg0).length; const ret = getObject(arg0).length;
return ret; return ret;
}; };
imports.wbg.__wbg_new0_c0be7df4b6bd481f = function() {
const ret = new Date();
return addHeapObject(ret);
};
imports.wbg.__wbg_new_43f1b47c28813cbd = function(arg0, arg1) { imports.wbg.__wbg_new_43f1b47c28813cbd = function(arg0, arg1) {
try { try {
var state0 = {a: arg0, b: arg1}; var state0 = {a: arg0, b: arg1};
@ -389,7 +369,7 @@ function __wbg_get_imports() {
const a = state0.a; const a = state0.a;
state0.a = 0; state0.a = 0;
try { try {
return __wbg_adapter_52(a, state0.b, arg0, arg1); return __wbg_adapter_39(a, state0.b, arg0, arg1);
} finally { } finally {
state0.a = a; state0.a = a;
} }
@ -416,10 +396,6 @@ function __wbg_get_imports() {
const ret = Promise.resolve(getObject(arg0)); const ret = Promise.resolve(getObject(arg0));
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbg_setTimeout_75cb9b6991a4031d = function() { return handleError(function (arg0, arg1) {
const ret = setTimeout(getObject(arg0), arg1);
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_set_5cf90238115182c3 = function(arg0, arg1, arg2) { imports.wbg.__wbg_set_5cf90238115182c3 = function(arg0, arg1, arg2) {
getObject(arg0).set(getObject(arg1), arg2 >>> 0); getObject(arg0).set(getObject(arg1), arg2 >>> 0);
}; };
@ -444,12 +420,8 @@ function __wbg_get_imports() {
const ret = false; const ret = false;
return ret; return ret;
}; };
imports.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined__h1d7bf0f00ff7214d = function(arg0, arg1, arg2) { imports.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, __wbg_adapter_20, __wbg_adapter_20); const ret = makeMutClosure(arg0, arg1, __wbg_adapter_21, __wbg_adapter_20);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined__hc2986dfcd9d6621f = function(arg0, arg1, arg2) {
const ret = makeMutClosure(arg0, arg1, __wbg_adapter_24, __wbg_adapter_23);
return addHeapObject(ret); return addHeapObject(ret);
}; };
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {

View File

@ -65,7 +65,9 @@ export function createMethodMiddleware(hooks) {
selectHooks(hooks, hookNames), selectHooks(hooks, hookNames),
); );
} catch (error) { } catch (error) {
if (process.env.METAMASK_DEBUG) {
console.error(error); console.error(error);
}
return end(error); return end(error);
} }
} }
@ -101,7 +103,9 @@ export function createSnapMethodMiddleware(isSnap, hooks) {
selectHooks(hooks, hookNames), selectHooks(hooks, hookNames),
); );
} catch (error) { } catch (error) {
if (process.env.METAMASK_DEBUG) {
console.error(error); console.error(error);
}
return end(error); return end(error);
} }
} }

View File

@ -283,14 +283,11 @@ export const SENTRY_BACKGROUND_STATE = {
tokens: false, tokens: false,
}, },
TransactionController: { TransactionController: {
currentNetworkTxList: false,
transactions: false, transactions: false,
lastFetchedBlockNumbers: false, lastFetchedBlockNumbers: false,
}, },
TxController: { TxController: {
currentNetworkTxList: false,
transactions: false, transactions: false,
unapprovedTxs: false,
}, },
}; };

View File

@ -4076,7 +4076,11 @@ export default class MetamaskController extends EventEmitter {
///: BEGIN:ONLY_INCLUDE_IN(blockaid) ///: BEGIN:ONLY_INCLUDE_IN(blockaid)
engine.push( engine.push(
createPPOMMiddleware(this.ppomController, this.preferencesController), createPPOMMiddleware(
this.ppomController,
this.preferencesController,
this.networkController,
),
); );
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN

View File

@ -1,5 +1,8 @@
import log from 'loglevel';
import { migrate } from './088'; import { migrate } from './088';
jest.mock('loglevel');
const sentryCaptureExceptionMock = jest.fn(); const sentryCaptureExceptionMock = jest.fn();
global.sentry = { global.sentry = {
@ -725,7 +728,7 @@ describe('migration #88', () => {
}); });
it('logs a warning if it has no TokenListController property', async () => { it('logs a warning if it has no TokenListController property', async () => {
const mockWarnFn = jest.spyOn(console, 'warn'); const mockWarnFn = jest.spyOn(log, 'warn');
const oldData = { const oldData = {
TokensController: {}, TokensController: {},
@ -762,14 +765,15 @@ describe('migration #88', () => {
}; };
await migrate(oldStorage); await migrate(oldStorage);
expect(mockWarnFn).toHaveBeenCalledTimes(1); expect(mockWarnFn).toHaveBeenCalledTimes(4);
expect(mockWarnFn).toHaveBeenCalledWith( expect(mockWarnFn).toHaveBeenNthCalledWith(
new Error(`typeof state.TokenListController is undefined`), 1,
'typeof state.TokenListController is undefined',
); );
}); });
it('logs a warning if the TokenListController property is not an object', async () => { it('logs a warning if the TokenListController property is not an object', async () => {
const mockWarnFn = jest.spyOn(console, 'warn'); const mockWarnFn = jest.spyOn(log, 'warn');
const oldData = { const oldData = {
TokensController: {}, TokensController: {},
@ -807,9 +811,10 @@ describe('migration #88', () => {
}; };
await migrate(oldStorage); await migrate(oldStorage);
expect(mockWarnFn).toHaveBeenCalledTimes(1); expect(mockWarnFn).toHaveBeenCalledTimes(4);
expect(mockWarnFn).toHaveBeenCalledWith( expect(mockWarnFn).toHaveBeenNthCalledWith(
new Error(`typeof state.TokenListController is boolean`), 1,
'typeof state.TokenListController is boolean',
); );
}); });

View File

@ -164,10 +164,8 @@ function migrateData(state: Record<string, unknown>): void {
); );
} }
} else { } else {
console.warn( log.warn(
new Error(
`typeof state.TokenListController is ${typeof state.TokenListController}`, `typeof state.TokenListController is ${typeof state.TokenListController}`,
),
); );
} }

View File

@ -2298,7 +2298,6 @@
"@truffle/codec>@truffle/compile-common": true, "@truffle/codec>@truffle/compile-common": true,
"@truffle/codec>big.js": true, "@truffle/codec>big.js": true,
"@truffle/codec>cbor": true, "@truffle/codec>cbor": true,
"@truffle/codec>semver": true,
"@truffle/codec>utf8": true, "@truffle/codec>utf8": true,
"@truffle/codec>web3-utils": true, "@truffle/codec>web3-utils": true,
"bn.js": true, "bn.js": true,
@ -2306,7 +2305,8 @@
"browserify>os-browserify": true, "browserify>os-browserify": true,
"browserify>util": true, "browserify>util": true,
"lodash": true, "lodash": true,
"nock>debug": true "nock>debug": true,
"semver": true
} }
}, },
"@truffle/codec>@truffle/abi-utils": { "@truffle/codec>@truffle/abi-utils": {
@ -2485,15 +2485,6 @@
"browserify>util": true "browserify>util": true
} }
}, },
"@truffle/codec>semver": {
"globals": {
"console.error": true
},
"packages": {
"browserify>process": true,
"semver>lru-cache": true
}
},
"@truffle/codec>web3-utils": { "@truffle/codec>web3-utils": {
"globals": { "globals": {
"setTimeout": true "setTimeout": true

View File

@ -2833,7 +2833,6 @@
"@truffle/codec>@truffle/compile-common": true, "@truffle/codec>@truffle/compile-common": true,
"@truffle/codec>big.js": true, "@truffle/codec>big.js": true,
"@truffle/codec>cbor": true, "@truffle/codec>cbor": true,
"@truffle/codec>semver": true,
"@truffle/codec>utf8": true, "@truffle/codec>utf8": true,
"@truffle/codec>web3-utils": true, "@truffle/codec>web3-utils": true,
"bn.js": true, "bn.js": true,
@ -2841,7 +2840,8 @@
"browserify>os-browserify": true, "browserify>os-browserify": true,
"browserify>util": true, "browserify>util": true,
"lodash": true, "lodash": true,
"nock>debug": true "nock>debug": true,
"semver": true
} }
}, },
"@truffle/codec>@truffle/abi-utils": { "@truffle/codec>@truffle/abi-utils": {
@ -3020,15 +3020,6 @@
"browserify>util": true "browserify>util": true
} }
}, },
"@truffle/codec>semver": {
"globals": {
"console.error": true
},
"packages": {
"browserify>process": true,
"semver>lru-cache": true
}
},
"@truffle/codec>web3-utils": { "@truffle/codec>web3-utils": {
"globals": { "globals": {
"setTimeout": true "setTimeout": true

View File

@ -2849,7 +2849,6 @@
"@truffle/codec>@truffle/compile-common": true, "@truffle/codec>@truffle/compile-common": true,
"@truffle/codec>big.js": true, "@truffle/codec>big.js": true,
"@truffle/codec>cbor": true, "@truffle/codec>cbor": true,
"@truffle/codec>semver": true,
"@truffle/codec>utf8": true, "@truffle/codec>utf8": true,
"@truffle/codec>web3-utils": true, "@truffle/codec>web3-utils": true,
"bn.js": true, "bn.js": true,
@ -2857,7 +2856,8 @@
"browserify>os-browserify": true, "browserify>os-browserify": true,
"browserify>util": true, "browserify>util": true,
"lodash": true, "lodash": true,
"nock>debug": true "nock>debug": true,
"semver": true
} }
}, },
"@truffle/codec>@truffle/abi-utils": { "@truffle/codec>@truffle/abi-utils": {
@ -3036,15 +3036,6 @@
"browserify>util": true "browserify>util": true
} }
}, },
"@truffle/codec>semver": {
"globals": {
"console.error": true
},
"packages": {
"browserify>process": true,
"semver>lru-cache": true
}
},
"@truffle/codec>web3-utils": { "@truffle/codec>web3-utils": {
"globals": { "globals": {
"setTimeout": true "setTimeout": true

View File

@ -2577,7 +2577,6 @@
"@truffle/codec>@truffle/compile-common": true, "@truffle/codec>@truffle/compile-common": true,
"@truffle/codec>big.js": true, "@truffle/codec>big.js": true,
"@truffle/codec>cbor": true, "@truffle/codec>cbor": true,
"@truffle/codec>semver": true,
"@truffle/codec>utf8": true, "@truffle/codec>utf8": true,
"@truffle/codec>web3-utils": true, "@truffle/codec>web3-utils": true,
"bn.js": true, "bn.js": true,
@ -2585,7 +2584,8 @@
"browserify>os-browserify": true, "browserify>os-browserify": true,
"browserify>util": true, "browserify>util": true,
"lodash": true, "lodash": true,
"nock>debug": true "nock>debug": true,
"semver": true
} }
}, },
"@truffle/codec>@truffle/abi-utils": { "@truffle/codec>@truffle/abi-utils": {
@ -2764,15 +2764,6 @@
"browserify>util": true "browserify>util": true
} }
}, },
"@truffle/codec>semver": {
"globals": {
"console.error": true
},
"packages": {
"browserify>process": true,
"semver>lru-cache": true
}
},
"@truffle/codec>web3-utils": { "@truffle/codec>web3-utils": {
"globals": { "globals": {
"setTimeout": true "setTimeout": true

View File

@ -2439,7 +2439,6 @@
"@truffle/codec>@truffle/compile-common": true, "@truffle/codec>@truffle/compile-common": true,
"@truffle/codec>big.js": true, "@truffle/codec>big.js": true,
"@truffle/codec>cbor": true, "@truffle/codec>cbor": true,
"@truffle/codec>semver": true,
"@truffle/codec>utf8": true, "@truffle/codec>utf8": true,
"@truffle/codec>web3-utils": true, "@truffle/codec>web3-utils": true,
"bn.js": true, "bn.js": true,
@ -2447,7 +2446,8 @@
"browserify>os-browserify": true, "browserify>os-browserify": true,
"browserify>util": true, "browserify>util": true,
"lodash": true, "lodash": true,
"nock>debug": true "nock>debug": true,
"semver": true
} }
}, },
"@truffle/codec>@truffle/abi-utils": { "@truffle/codec>@truffle/abi-utils": {
@ -2626,15 +2626,6 @@
"browserify>util": true "browserify>util": true
} }
}, },
"@truffle/codec>semver": {
"globals": {
"console.error": true
},
"packages": {
"browserify>process": true,
"semver>lru-cache": true
}
},
"@truffle/codec>web3-utils": { "@truffle/codec>web3-utils": {
"globals": { "globals": {
"setTimeout": true "setTimeout": true

View File

@ -1,6 +1,6 @@
{ {
"name": "metamask-crx", "name": "metamask-crx",
"version": "10.35.1", "version": "11.0.0",
"private": true, "private": true,
"repository": { "repository": {
"type": "git", "type": "git",
@ -202,7 +202,9 @@
"request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch", "request@^2.85.0": "patch:request@npm%3A2.88.2#./.yarn/patches/request-npm-2.88.2-f4a57c72c4.patch",
"lavamoat-core@^14.2.0": "patch:lavamoat-core@npm%3A14.2.0#./.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch", "lavamoat-core@^14.2.0": "patch:lavamoat-core@npm%3A14.2.0#./.yarn/patches/lavamoat-core-npm-14.2.0-c453f4f755.patch",
"@metamask/keyring-controller@^7.2.0": "patch:@metamask/keyring-controller@npm%3A7.2.0#~/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch", "@metamask/keyring-controller@^7.2.0": "patch:@metamask/keyring-controller@npm%3A7.2.0#~/.yarn/patches/@metamask-keyring-controller-npm-7.2.0-fcc0c7893b.patch",
"@metamask/signature-controller@^5.3.0": "patch:@metamask/signature-controller@npm%3A5.3.0#./.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch" "@metamask/signature-controller@^5.3.0": "patch:@metamask/signature-controller@npm%3A5.3.0#./.yarn/patches/@metamask-signature-controller-npm-5.3.0-225628460b.patch",
"semver@7.3.7": "^7.5.4",
"semver@7.3.8": "^7.5.4"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.18.9", "@babel/runtime": "^7.18.9",
@ -259,7 +261,7 @@
"@metamask/permission-controller": "^4.0.0", "@metamask/permission-controller": "^4.0.0",
"@metamask/phishing-controller": "^6.0.0", "@metamask/phishing-controller": "^6.0.0",
"@metamask/post-message-stream": "^6.2.0", "@metamask/post-message-stream": "^6.2.0",
"@metamask/ppom-validator": "^0.3.0", "@metamask/ppom-validator": "^0.5.0",
"@metamask/providers": "^11.1.0", "@metamask/providers": "^11.1.0",
"@metamask/rate-limit-controller": "^3.0.0", "@metamask/rate-limit-controller": "^3.0.0",
"@metamask/rpc-methods": "^1.0.2", "@metamask/rpc-methods": "^1.0.2",

View File

@ -140,6 +140,8 @@ export const CHAIN_IDS = {
OPTIMISM_TESTNET: '0x1a4', OPTIMISM_TESTNET: '0x1a4',
BASE: '0x2105', BASE: '0x2105',
BASE_TESTNET: '0x14a33', BASE_TESTNET: '0x14a33',
OPBNB: '0xcc',
OPBNB_TESTNET: '0x15eb',
POLYGON: '0x89', POLYGON: '0x89',
POLYGON_TESTNET: '0x13881', POLYGON_TESTNET: '0x13881',
AVALANCHE: '0xa86a', AVALANCHE: '0xa86a',
@ -557,6 +559,8 @@ export const BUYABLE_CHAINS_MAP: {
| typeof CHAIN_IDS.OPTIMISM_TESTNET | typeof CHAIN_IDS.OPTIMISM_TESTNET
| typeof CHAIN_IDS.BASE_TESTNET | typeof CHAIN_IDS.BASE_TESTNET
| typeof CHAIN_IDS.BASE | typeof CHAIN_IDS.BASE
| typeof CHAIN_IDS.OPBNB_TESTNET
| typeof CHAIN_IDS.OPBNB
| typeof CHAIN_IDS.BSC_TESTNET | typeof CHAIN_IDS.BSC_TESTNET
| typeof CHAIN_IDS.POLYGON_TESTNET | typeof CHAIN_IDS.POLYGON_TESTNET
| typeof CHAIN_IDS.AVALANCHE_TESTNET | typeof CHAIN_IDS.AVALANCHE_TESTNET

View File

@ -115,11 +115,21 @@ export const SNAPS_DERIVATION_PATHS: SnapsDerivationPath[] = [
curve: 'secp256k1', curve: 'secp256k1',
name: 'Bitcoin Cash', name: 'Bitcoin Cash',
}, },
{
path: ['m', `44'`, `637'`],
curve: 'ed25519',
name: 'Aptos',
},
{ {
path: ['m', `44'`, `714'`], path: ['m', `44'`, `714'`],
curve: 'secp256k1', curve: 'secp256k1',
name: 'Binance (BNB)', name: 'Binance (BNB)',
}, },
{
path: ['m', `44'`, `784'`],
curve: 'ed25519',
name: 'Sui',
},
{ {
path: ['m', `44'`, `931'`], path: ['m', `44'`, `931'`],
curve: 'secp256k1', curve: 'secp256k1',

View File

@ -1,2 +1,2 @@
export const TERMS_OF_USE_LINK = 'https://consensys.net/terms-of-use/'; export const TERMS_OF_USE_LINK = 'https://consensys.io/terms-of-use/';
export const TERMS_OF_USE_LAST_UPDATED = '2023-03-25'; export const TERMS_OF_USE_LAST_UPDATED = '2023-03-25';

View File

@ -21,9 +21,11 @@ describe('Fetch with cache', () => {
.get('/price') .get('/price')
.reply(200, '{"average": 1}'); .reply(200, '{"average": 1}');
const response = await fetchWithCache( const response = await fetchWithCache({
'https://fetchwithcache.metamask.io/price', url: 'https://fetchwithcache.metamask.io/price',
); functionName: 'fetchPrice',
});
expect(response).toStrictEqual({ expect(response).toStrictEqual({
average: 1, average: 1,
}); });
@ -39,9 +41,10 @@ describe('Fetch with cache', () => {
cachedTime: Date.now(), cachedTime: Date.now(),
}); });
const response = await fetchWithCache( const response = await fetchWithCache({
'https://fetchwithcache.metamask.io/price', url: 'https://fetchwithcache.metamask.io/price',
); functionName: 'fetchPrice',
});
expect(response).toStrictEqual({ expect(response).toStrictEqual({
average: 1, average: 1,
}); });
@ -57,11 +60,11 @@ describe('Fetch with cache', () => {
cachedTime: Date.now() - 1000, cachedTime: Date.now() - 1000,
}); });
const response = await fetchWithCache( const response = await fetchWithCache({
'https://fetchwithcache.metamask.io/price', url: 'https://fetchwithcache.metamask.io/price',
{}, cacheOptions: { cacheRefreshTime: 123 },
{ cacheRefreshTime: 123 }, functionName: 'fetchPrice',
); });
expect(response).toStrictEqual({ expect(response).toStrictEqual({
average: 3, average: 3,
}); });
@ -74,11 +77,11 @@ describe('Fetch with cache', () => {
.reply(200, '{"average": 4}'); .reply(200, '{"average": 4}');
await expect(() => await expect(() =>
fetchWithCache( fetchWithCache({
'https://fetchwithcache.metamask.io/price', url: 'https://fetchwithcache.metamask.io/price',
{}, cacheOptions: { timeout: 20 },
{ timeout: 20 }, functionName: 'fetchPrice',
), }),
).rejects.toThrow({ ).rejects.toThrow({
name: 'AbortError', name: 'AbortError',
message: 'The user aborted a request.', message: 'The user aborted a request.',
@ -91,7 +94,10 @@ describe('Fetch with cache', () => {
.reply(500, '{"average": 6}'); .reply(500, '{"average": 6}');
await expect(() => await expect(() =>
fetchWithCache('https://fetchwithcache.metamask.io/price'), fetchWithCache({
url: 'https://fetchwithcache.metamask.io/price',
functionName: 'fetchPrice',
}),
).rejects.toThrow(''); ).rejects.toThrow('');
}); });
@ -101,8 +107,10 @@ describe('Fetch with cache', () => {
.reply(200, '{"average": 7}'); .reply(200, '{"average": 7}');
await expect(() => await expect(() =>
fetchWithCache('https://fetchwithcache.metamask.io/price', { fetchWithCache({
method: 'POST', url: 'https://fetchwithcache.metamask.io/price',
fetchOptions: { method: 'POST' },
functionName: 'fetchPrice',
}), }),
).rejects.toThrow(''); ).rejects.toThrow('');
}); });
@ -113,7 +121,11 @@ describe('Fetch with cache', () => {
.reply(200, '{"average": 8}'); .reply(200, '{"average": 8}');
await expect(() => await expect(() =>
fetchWithCache('https://fetchwithcache.metamask.io/price', { body: 1 }), fetchWithCache({
url: 'https://fetchwithcache.metamask.io/price',
fetchOptions: { body: 1 },
functionName: 'fetchPrice',
}),
).rejects.toThrow(''); ).rejects.toThrow('');
}); });
@ -123,8 +135,10 @@ describe('Fetch with cache', () => {
.reply(200, '{"average": 9}'); .reply(200, '{"average": 9}');
await expect(() => await expect(() =>
fetchWithCache('https://fetchwithcache.metamask.io/price', { fetchWithCache({
headers: { 'Content-Type': 'text/plain' }, url: 'https://fetchwithcache.metamask.io/price',
fetchOptions: { headers: { 'Content-Type': 'text/plain' } },
functionName: 'fetchPrice',
}), }),
).rejects.toThrow({ ).rejects.toThrow({
message: 'fetchWithCache only supports JSON responses', message: 'fetchWithCache only supports JSON responses',
@ -147,16 +161,16 @@ describe('Fetch with cache', () => {
}); });
await Promise.all([ await Promise.all([
fetchWithCache( fetchWithCache({
'https://fetchwithcache.metamask.io/foo', url: 'https://fetchwithcache.metamask.io/foo',
{}, cacheOptions: { cacheRefreshTime: 123 },
{ cacheRefreshTime: 123 }, functionName: 'fetchFoo',
), }),
fetchWithCache( fetchWithCache({
'https://fetchwithcache.metamask.io/bar', url: 'https://fetchwithcache.metamask.io/bar',
{}, cacheOptions: { cacheRefreshTime: 123 },
{ cacheRefreshTime: 123 }, functionName: 'fetchFoo',
), }),
]); ]);
expect( expect(

View File

@ -2,11 +2,17 @@ import { MINUTE, SECOND } from '../constants/time';
import getFetchWithTimeout from '../modules/fetch-with-timeout'; import getFetchWithTimeout from '../modules/fetch-with-timeout';
import { getStorageItem, setStorageItem } from './storage-helpers'; import { getStorageItem, setStorageItem } from './storage-helpers';
const fetchWithCache = async ( const fetchWithCache = async ({
url, url,
fetchOptions = {}, fetchOptions = {},
{ cacheRefreshTime = MINUTE * 6, timeout = SECOND * 30 } = {}, cacheOptions: { cacheRefreshTime = MINUTE * 6, timeout = SECOND * 30 } = {},
) => { functionName = '',
}: {
url: string;
fetchOptions?: Record<string, any>;
cacheOptions?: Record<string, any>;
functionName: string;
}) => {
if ( if (
fetchOptions.body || fetchOptions.body ||
(fetchOptions.method && fetchOptions.method !== 'GET') (fetchOptions.method && fetchOptions.method !== 'GET')
@ -40,7 +46,7 @@ const fetchWithCache = async (
}); });
if (!response.ok) { if (!response.ok) {
throw new Error( throw new Error(
`Fetch failed with status '${response.status}': '${response.statusText}'`, `Fetch with cache failed within function ${functionName} with status'${response.status}': '${response.statusText}'`,
); );
} }
const responseJson = await response.json(); const responseJson = await response.json();

View File

@ -274,11 +274,12 @@ export async function fetchTradesInfo(
const queryString = new URLSearchParams(urlParams).toString(); const queryString = new URLSearchParams(urlParams).toString();
const tradeURL = `${getBaseApi('trade', chainId)}${queryString}`; const tradeURL = `${getBaseApi('trade', chainId)}${queryString}`;
const tradesResponse = await fetchWithCache( const tradesResponse = await fetchWithCache({
tradeURL, url: tradeURL,
{ method: 'GET', headers: clientIdHeader }, fetchOptions: { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: 0, timeout: SECOND * 15 }, cacheOptions: { cacheRefreshTime: 0, timeout: SECOND * 15 },
); functionName: 'fetchTradesInfo',
});
const newQuotes = tradesResponse.reduce((aggIdTradeMap, quote) => { const newQuotes = tradesResponse.reduce((aggIdTradeMap, quote) => {
if ( if (
quote.trade && quote.trade &&

View File

@ -5,6 +5,7 @@
* into numbers in only one place. This should make merge conflicts easier. * into numbers in only one place. This should make merge conflicts easier.
*/ */
export const NOTIFICATION_DROP_LEDGER_FIREFOX = 25; export const NOTIFICATION_DROP_LEDGER_FIREFOX = 25;
export const NOTIFICATION_OPEN_BETA_SNAPS = 26;
export const UI_NOTIFICATIONS = { export const UI_NOTIFICATIONS = {
1: { 1: {
@ -147,6 +148,14 @@ export const UI_NOTIFICATIONS = {
id: Number(NOTIFICATION_DROP_LEDGER_FIREFOX), id: Number(NOTIFICATION_DROP_LEDGER_FIREFOX),
date: null, date: null,
}, },
[NOTIFICATION_OPEN_BETA_SNAPS]: {
id: Number(NOTIFICATION_OPEN_BETA_SNAPS),
date: null,
image: {
src: 'images/introducing-snaps.svg',
width: '100%',
},
},
}; };
export const getTranslatedUINotifications = (t, locale) => { export const getTranslatedUINotifications = (t, locale) => {
@ -395,5 +404,20 @@ export const getTranslatedUINotifications = (t, locale) => {
) )
: '', : '',
}, },
[NOTIFICATION_OPEN_BETA_SNAPS]: {
...UI_NOTIFICATIONS[NOTIFICATION_OPEN_BETA_SNAPS],
title: t('notificationsOpenBetaSnapsTitle'),
description: [
t('notificationsOpenBetaSnapsDescriptionOne'),
t('notificationsOpenBetaSnapsDescriptionTwo'),
t('notificationsOpenBetaSnapsDescriptionThree'),
],
actionText: t('notificationsOpenBetaSnapsActionText'),
date: UI_NOTIFICATIONS[NOTIFICATION_OPEN_BETA_SNAPS].date
? new Intl.DateTimeFormat(formattedLocale).format(
new Date(UI_NOTIFICATIONS[NOTIFICATION_OPEN_BETA_SNAPS].date),
)
: '',
},
}; };
}; };

View File

@ -180,57 +180,6 @@
} }
}, },
"cachedBalances": {}, "cachedBalances": {},
"incomingTransactions": {},
"unapprovedTxs": {
"8393540981007587": {
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": false,
"txParams": {
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
},
"history": [
{
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": true,
"txParams": {
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
}
},
[
{
"op": "replace",
"path": "/loadingDefaults",
"value": false,
"timestamp": 1536268017685
}
],
[
{
"op": "add",
"path": "/origin",
"value": "MetaMask",
"note": "#newUnapprovedTransaction - adding the origin",
"timestamp": 1536268017686
}
]
],
"origin": "MetaMask"
}
},
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", "selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"accounts": { "accounts": {
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
@ -347,7 +296,55 @@
"occurrences": 12 "occurrences": 12
} }
}, },
"currentNetworkTxList": [ "transactions": [
{
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": false,
"txParams": {
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
},
"history": [
{
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": true,
"txParams": {
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
}
},
[
{
"op": "replace",
"path": "/loadingDefaults",
"value": false,
"timestamp": 1536268017685
}
],
[
{
"op": "add",
"path": "/origin",
"value": "MetaMask",
"note": "#newUnapprovedTransaction - adding the origin",
"timestamp": 1536268017686
}
]
],
"origin": "MetaMask"
},
{ {
"id": 3387511061307736, "id": 3387511061307736,
"time": 1528133130531, "time": 1528133130531,

View File

@ -227,59 +227,6 @@
"0xaa36a7": true, "0xaa36a7": true,
"0xe704": true "0xe704": true
}, },
"unapprovedTxs": {
"8393540981007587": {
"chainId": "0x5",
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": false,
"txParams": {
"data": "0xa9059cbb000000000000000000000000b19ac54efa18cc3a14a5b821bfec73d284bf0c5e0000000000000000000000000000000000000000000000003782dace9d900000",
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
},
"history": [
{
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": true,
"txParams": {
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
}
},
[
{
"op": "replace",
"path": "/loadingDefaults",
"value": false,
"timestamp": 1536268017685
}
],
[
{
"op": "add",
"path": "/origin",
"value": "MetaMask",
"note": "#newUnapprovedTransaction - adding the origin",
"timestamp": 1536268017686
}
]
],
"origin": "metamask"
}
},
"selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc", "selectedAddress": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"accounts": { "accounts": {
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": { "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
@ -643,7 +590,57 @@
"occurrences": 12 "occurrences": 12
} }
}, },
"currentNetworkTxList": [ "transactions": [
{
"chainId": "0x5",
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": false,
"txParams": {
"data": "0xa9059cbb000000000000000000000000b19ac54efa18cc3a14a5b821bfec73d284bf0c5e0000000000000000000000000000000000000000000000003782dace9d900000",
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
},
"history": [
{
"id": 8393540981007587,
"time": 1536268017676,
"status": "unapproved",
"metamaskNetworkId": "4",
"loadingDefaults": true,
"txParams": {
"from": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc",
"to": "0xc42edfcc21ed14dda456aa0756c153f7985d8813",
"value": "0x0",
"gas": "0x5208",
"gasPrice": "0x3b9aca00"
}
},
[
{
"op": "replace",
"path": "/loadingDefaults",
"value": false,
"timestamp": 1536268017685
}
],
[
{
"op": "add",
"path": "/origin",
"value": "MetaMask",
"note": "#newUnapprovedTransaction - adding the origin",
"timestamp": 1536268017686
}
]
],
"origin": "metamask"
},
{ {
"id": 3387511061307736, "id": 3387511061307736,
"time": 1528133130531, "time": 1528133130531,

View File

@ -2,5 +2,5 @@ module.exports = {
TEST_SNAPS_WEBSITE_URL: TEST_SNAPS_WEBSITE_URL:
'https://metamask.github.io/snaps/test-snaps/0.38.0-flask.1/', 'https://metamask.github.io/snaps/test-snaps/0.38.0-flask.1/',
TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL: TEST_SNAPS_SIMPLE_KEYRING_WEBSITE_URL:
'https://metamask.github.io/snap-simple-keyring/latest/', 'https://metamask.github.io/snap-simple-keyring/0.1.4/',
}; };

View File

@ -218,8 +218,6 @@
"allDetectedTokens": {} "allDetectedTokens": {}
}, },
"TxController": { "TxController": {
"unapprovedTxs": "object",
"currentNetworkTxList": "object",
"transactions": "object" "transactions": "object"
} }
} }

View File

@ -13,7 +13,6 @@
"isAccountMenuOpen": false, "isAccountMenuOpen": false,
"isNetworkMenuOpen": false, "isNetworkMenuOpen": false,
"identities": "object", "identities": "object",
"unapprovedTxs": "object",
"networkConfigurations": "object", "networkConfigurations": "object",
"addressBook": "object", "addressBook": "object",
"contractExchangeRates": "object", "contractExchangeRates": "object",
@ -153,7 +152,6 @@
"lastUpdated": "object", "lastUpdated": "object",
"notifications": "object", "notifications": "object",
"accounts": "object", "accounts": "object",
"currentNetworkTxList": "object",
"transactions": "object", "transactions": "object",
"unapprovedDecryptMsgs": "object", "unapprovedDecryptMsgs": "object",
"unapprovedDecryptMsgCount": 0, "unapprovedDecryptMsgCount": 0,

View File

@ -154,7 +154,7 @@ export const createSwapsMockStore = () => {
showFiatInTestnets: true, showFiatInTestnets: true,
}, },
currentCurrency: 'ETH', currentCurrency: 'ETH',
currentNetworkTxList: [ transactions: [
{ {
id: 6571648590592143, id: 6571648590592143,
time: 1667403993369, time: 1667403993369,
@ -162,7 +162,7 @@ export const createSwapsMockStore = () => {
metamaskNetworkId: '5', metamaskNetworkId: '5',
originalGasEstimate: '0x7548', originalGasEstimate: '0x7548',
userEditedGasLimit: false, userEditedGasLimit: false,
chainId: '0x5', chainId: CHAIN_IDS.MAINNET,
loadingDefaults: false, loadingDefaults: false,
dappSuggestedGasFees: null, dappSuggestedGasFees: null,
sendFlowHistory: null, sendFlowHistory: null,

View File

@ -18,19 +18,6 @@ const mmState = {
balance: '0x1F4', balance: '0x1F4',
}, },
}, },
unapprovedTxs: {
8393540981007587: {
...mockState.metamask.unapprovedTxs[8393540981007587],
txParams: {
from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813',
value: '0x0',
gas: '0x5208',
gasPrice: '0x3b9aca00',
type: '0x0',
},
},
},
preferences: { preferences: {
useNativeCurrencyAsPrimaryCurrency: true, useNativeCurrencyAsPrimaryCurrency: true,
}, },
@ -52,6 +39,15 @@ const mmState = {
}, },
}; };
mmState.metamask.transactions[0].txParams = {
from: '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc',
to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813',
value: '0x0',
gas: '0x5208',
gasPrice: '0x3b9aca00',
type: '0x0',
};
const render = ({ contextProps, state = mmState } = {}) => { const render = ({ contextProps, state = mmState } = {}) => {
const store = configureStore({ ...state, ...contextProps }); const store = configureStore({ ...state, ...contextProps });

View File

@ -7,7 +7,9 @@ import {
TextColor, TextColor,
TextVariant, TextVariant,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas'; import { PRIORITY_LEVEL_ICON_MAP } from '../../../helpers/constants/gas';
///: END:ONLY_INCLUDE_IN
import { useGasFeeContext } from '../../../contexts/gasFee'; import { useGasFeeContext } from '../../../contexts/gasFee';
import { useI18nContext } from '../../../hooks/useI18nContext'; import { useI18nContext } from '../../../hooks/useI18nContext';
import { useTransactionEventFragment } from '../../../hooks/useTransactionEventFragment'; import { useTransactionEventFragment } from '../../../hooks/useTransactionEventFragment';
@ -35,17 +37,22 @@ export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
if (!supportsEIP1559 || !estimateUsed || !editEnabled) { if (!supportsEIP1559 || !estimateUsed || !editEnabled) {
return null; return null;
} }
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
let icon = estimateUsed; let icon = estimateUsed;
///: END:ONLY_INCLUDE_IN
let title = estimateUsed; let title = estimateUsed;
if ( if (
estimateUsed === PriorityLevels.high && estimateUsed === PriorityLevels.high &&
editGasMode === EditGasModes.swaps editGasMode === EditGasModes.swaps
) { ) {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon = 'swapSuggested'; icon = 'swapSuggested';
///: END:ONLY_INCLUDE_IN
title = 'swapSuggested'; title = 'swapSuggested';
} else if (estimateUsed === PriorityLevels.tenPercentIncreased) { } else if (estimateUsed === PriorityLevels.tenPercentIncreased) {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon = undefined; icon = undefined;
///: END:ONLY_INCLUDE_IN
title = 'tenPercentIncreased'; title = 'tenPercentIncreased';
} }
@ -66,11 +73,15 @@ export default function EditGasFeeButton({ userAcknowledgedGasMissing }) {
return ( return (
<div className="edit-gas-fee-button"> <div className="edit-gas-fee-button">
<button onClick={openEditGasFeeModal} data-testid="edit-gas-fee-button"> <button onClick={openEditGasFeeModal} data-testid="edit-gas-fee-button">
{icon && ( {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon && (
<span className="edit-gas-fee-button__icon"> <span className="edit-gas-fee-button__icon">
{PRIORITY_LEVEL_ICON_MAP[icon]} {PRIORITY_LEVEL_ICON_MAP[icon]}
</span> </span>
)} )
///: END:ONLY_INCLUDE_IN
}
<span className="edit-gas-fee-button__label">{t(title)}</span> <span className="edit-gas-fee-button__label">{t(title)}</span>
<Icon <Icon
name={IconName.ArrowRight} name={IconName.ArrowRight}

View File

@ -6,7 +6,9 @@ import {
EditGasModes, EditGasModes,
PriorityLevels, PriorityLevels,
} from '../../../../../shared/constants/gas'; } from '../../../../../shared/constants/gas';
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
import { PRIORITY_LEVEL_ICON_MAP } from '../../../../helpers/constants/gas'; import { PRIORITY_LEVEL_ICON_MAP } from '../../../../helpers/constants/gas';
///: END:ONLY_INCLUDE_IN
import { PRIMARY } from '../../../../helpers/constants/common'; import { PRIMARY } from '../../../../helpers/constants/common';
import { toHumanReadableTime } from '../../../../helpers/utils/util'; import { toHumanReadableTime } from '../../../../helpers/utils/util';
import { useGasFeeContext } from '../../../../contexts/gasFee'; import { useGasFeeContext } from '../../../../contexts/gasFee';
@ -21,23 +23,34 @@ import EditGasToolTip from '../edit-gas-tooltip/edit-gas-tooltip';
import { useGasItemFeeDetails } from './useGasItemFeeDetails'; import { useGasItemFeeDetails } from './useGasItemFeeDetails';
const getTitleAndIcon = (priorityLevel, editGasMode) => { const getTitleAndIcon = (priorityLevel, editGasMode) => {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
let icon = priorityLevel; let icon = priorityLevel;
///: END:ONLY_INCLUDE_IN
let title = priorityLevel; let title = priorityLevel;
if (priorityLevel === PriorityLevels.dAppSuggested) { if (priorityLevel === PriorityLevels.dAppSuggested) {
title = 'dappSuggestedShortLabel'; title = 'dappSuggestedShortLabel';
} else if (priorityLevel === PriorityLevels.dappSuggestedHigh) { } else if (priorityLevel === PriorityLevels.dappSuggestedHigh) {
title = 'dappSuggestedHighShortLabel'; title = 'dappSuggestedHighShortLabel';
} else if (priorityLevel === PriorityLevels.tenPercentIncreased) { } else if (priorityLevel === PriorityLevels.tenPercentIncreased) {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon = null; icon = null;
///: END:ONLY_INCLUDE_IN
title = 'tenPercentIncreased'; title = 'tenPercentIncreased';
} else if ( } else if (
priorityLevel === PriorityLevels.high && priorityLevel === PriorityLevels.high &&
editGasMode === EditGasModes.swaps editGasMode === EditGasModes.swaps
) { ) {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon = 'swapSuggested'; icon = 'swapSuggested';
///: END:ONLY_INCLUDE_IN
title = 'swapSuggested'; title = 'swapSuggested';
} }
return { title, icon }; return {
title,
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon,
///: END:ONLY_INCLUDE_IN
};
}; };
const EditGasItem = ({ priorityLevel }) => { const EditGasItem = ({ priorityLevel }) => {
@ -100,7 +113,12 @@ const EditGasItem = ({ priorityLevel }) => {
} }
}; };
const { title, icon } = getTitleAndIcon(priorityLevel, editGasMode); const {
title,
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon,
///: END:ONLY_INCLUDE_IN
} = getTitleAndIcon(priorityLevel, editGasMode);
return ( return (
<button <button
@ -115,13 +133,17 @@ const EditGasItem = ({ priorityLevel }) => {
data-testid={`edit-gas-fee-item-${priorityLevel}`} data-testid={`edit-gas-fee-item-${priorityLevel}`}
> >
<span className="edit-gas-item__name"> <span className="edit-gas-item__name">
{icon && ( {
///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask)
icon && (
<span <span
className={`edit-gas-item__icon edit-gas-item__icon-${priorityLevel}`} className={`edit-gas-item__icon edit-gas-item__icon-${priorityLevel}`}
> >
{PRIORITY_LEVEL_ICON_MAP[icon]} {PRIORITY_LEVEL_ICON_MAP[icon]}
</span> </span>
)} )
///: END:ONLY_INCLUDE_IN
}
{t(title)} {t(title)}
</span> </span>
<span <span

View File

@ -177,12 +177,13 @@ describe('SignatureRequestSIWE (Sign in with Ethereum)', () => {
...mockStoreInitialState, ...mockStoreInitialState,
metamask: { metamask: {
...mockStoreInitialState.metamask, ...mockStoreInitialState.metamask,
unapprovedTxs: { transactions: [
...mockStoreInitialState.metamask.unapprovedTxs, ...mockStoreInitialState.metamask.transactions,
'0x12333': { {
chainId: mockStoreInitialState.metamask.providerConfig.chainId, chainId: mockStoreInitialState.metamask.providerConfig.chainId,
status: 'unapproved',
}, },
}, ],
unapprovedMsgCount: 2, unapprovedMsgCount: 2,
}, },
}); });

View File

@ -12,6 +12,7 @@ import {
TextAlign, TextAlign,
JustifyContent, JustifyContent,
FontWeight, FontWeight,
Display,
} from '../../../../helpers/constants/design-system'; } from '../../../../helpers/constants/design-system';
import Popover from '../../../ui/popover'; import Popover from '../../../ui/popover';
import Button from '../../../ui/button'; import Button from '../../../ui/button';
@ -86,7 +87,11 @@ export default function SnapInstallWarning({
footerProps={{ padding: [4, 6] }} footerProps={{ padding: [4, 6] }}
onClose={onCancel} onClose={onCancel}
> >
<Box justifyContent={JustifyContent.center} marginBottom={6}> <Box
display={Display.Flex}
justifyContent={JustifyContent.center}
marginBottom={6}
>
<AvatarIcon <AvatarIcon
iconName={IconName.Danger} iconName={IconName.Danger}
backgroundColor={BackgroundColor.warningMuted} backgroundColor={BackgroundColor.warningMuted}

View File

@ -21,7 +21,7 @@ describe('Snap Privacy Warning Popover', () => {
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(
screen.getByText( screen.getByText(
'Consensys has no access to information you share with these third parties.', 'Consensys has no access to information you share with Third Party Services.',
), ),
).toBeInTheDocument(); ).toBeInTheDocument();
expect( expect(

View File

@ -38,8 +38,10 @@ export default function TransactionDecoding({ to = '', inputData: data = '' }) {
(async () => { (async () => {
setLoading(true); setLoading(true);
try { try {
const networks = await fetchWithCache(FETCH_SUPPORTED_NETWORKS_URI, { const networks = await fetchWithCache({
method: 'GET', url: FETCH_SUPPORTED_NETWORKS_URI,
fetchOptions: { method: 'GET' },
functionName: 'fetchSupportedNetworks',
}); });
if ( if (
@ -57,7 +59,11 @@ export default function TransactionDecoding({ to = '', inputData: data = '' }) {
'network-id': network, 'network-id': network,
})}`; })}`;
const response = await fetchWithCache(requestUrl, { method: 'GET' }); const response = await fetchWithCache({
url: requestUrl,
fetchOptions: { method: 'GET' },
functionName: 'fetchProject',
});
const { info: projectInfo, fetchedVia, address } = response; const { info: projectInfo, fetchedVia, address } = response;

View File

@ -9,6 +9,7 @@ const render = () => {
const store = configureStore({ const store = configureStore({
metamask: { metamask: {
...mockState.metamask, ...mockState.metamask,
transactions: [],
}, },
}); });
return renderWithProvider(<TransactionList />, store); return renderWithProvider(<TransactionList />, store);

View File

@ -18,6 +18,7 @@ import {
import { updateViewedNotifications } from '../../../store/actions'; import { updateViewedNotifications } from '../../../store/actions';
import { import {
NOTIFICATION_DROP_LEDGER_FIREFOX, NOTIFICATION_DROP_LEDGER_FIREFOX,
NOTIFICATION_OPEN_BETA_SNAPS,
getTranslatedUINotifications, getTranslatedUINotifications,
} from '../../../../shared/notifications'; } from '../../../../shared/notifications';
import { getSortedAnnouncementsToShow } from '../../../selectors'; import { getSortedAnnouncementsToShow } from '../../../selectors';
@ -115,6 +116,15 @@ function getActionFunctionById(id, history) {
24: () => { 24: () => {
updateViewedNotifications({ 24: true }); updateViewedNotifications({ 24: true });
}, },
[NOTIFICATION_DROP_LEDGER_FIREFOX]: () => {
updateViewedNotifications({ [NOTIFICATION_DROP_LEDGER_FIREFOX]: true });
},
[NOTIFICATION_OPEN_BETA_SNAPS]: () => {
updateViewedNotifications({ [NOTIFICATION_OPEN_BETA_SNAPS]: true });
global.platform.openTab({
url: 'https://metamask.io/snaps/',
});
},
}; };
return actionFunctions[id]; return actionFunctions[id];
@ -400,6 +410,7 @@ export default function WhatsNewPopup({
24: renderFirstNotification, 24: renderFirstNotification,
// This syntax is unusual, but very helpful here. It's equivalent to `notificationRenderers[NOTIFICATION_DROP_LEDGER_FIREFOX] =` // This syntax is unusual, but very helpful here. It's equivalent to `notificationRenderers[NOTIFICATION_DROP_LEDGER_FIREFOX] =`
[NOTIFICATION_DROP_LEDGER_FIREFOX]: renderFirstNotification, [NOTIFICATION_DROP_LEDGER_FIREFOX]: renderFirstNotification,
[NOTIFICATION_OPEN_BETA_SNAPS]: renderFirstNotification,
}; };
return ( return (

View File

@ -2,12 +2,12 @@
exports[`ModalContent should match snapshot 1`] = ` exports[`ModalContent should match snapshot 1`] = `
<div <div
class="mm-box mm-modal-content mm-box--padding-4 mm-box--display-flex mm-box--justify-content-center mm-box--align-items-flex-start mm-box--width-screen mm-box--height-screen" class="mm-box mm-modal-content mm-box--padding-top-4 mm-box--sm:padding-top-8 mm-box--md:padding-top-12 mm-box--padding-right-4 mm-box--padding-bottom-4 mm-box--sm:padding-bottom-8 mm-box--md:padding-bottom-12 mm-box--padding-left-4 mm-box--display-flex mm-box--justify-content-center mm-box--align-items-flex-start mm-box--width-screen mm-box--height-screen"
data-testid="test" data-testid="test"
> >
<section <section
aria-modal="true" aria-modal="true"
class="mm-box mm-modal-content__dialog mm-modal-content__dialog--size-sm mm-box--sm:margin-top-8 mm-box--md:margin-top-12 mm-box--sm:margin-bottom-8 mm-box--md:margin-bottom-12 mm-box--padding-4 mm-box--width-full mm-box--background-color-background-default mm-box--rounded-lg" class="mm-box mm-modal-content__dialog mm-modal-content__dialog--size-sm mm-box--padding-4 mm-box--width-full mm-box--background-color-background-default mm-box--rounded-lg"
role="dialog" role="dialog"
> >
test test

View File

@ -6,6 +6,22 @@
overflow: auto; overflow: auto;
overscroll-behavior-y: none; overscroll-behavior-y: none;
// Scroll bar styles
// Firefox
scrollbar-width: thin;
scrollbar-color: var(--color-icon-muted) transparent;
// Webkit: Chrome, Brave
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-thumb {
-webkit-border-radius: 8px;
border-radius: 8px;
background: var(--color-icon-muted);
}
&__dialog { &__dialog {
--modal-content-size: var(--size, 360px); --modal-content-size: var(--size, 360px);

View File

@ -55,11 +55,14 @@ describe('ModalContent', () => {
'mm-modal-content__dialog--size-sm', 'mm-modal-content__dialog--size-sm',
); );
}); });
it('should render with additional props being passed to modalDialogProps', () => { it('should render with additional props being passed to modalDialogProps and not override default class name', () => {
const { getByTestId } = render( const { getByTestId } = render(
<Modal isOpen onClose={onClose}> <Modal isOpen onClose={onClose}>
<ModalContent <ModalContent
modalDialogProps={{ 'data-testid': 'test' }} modalDialogProps={{
'data-testid': 'test',
className: 'custom-dialog-class',
}}
data-testid="modal-content" data-testid="modal-content"
> >
test test
@ -67,6 +70,9 @@ describe('ModalContent', () => {
</Modal>, </Modal>,
); );
expect(getByTestId('test')).toBeDefined(); expect(getByTestId('test')).toBeDefined();
expect(getByTestId('test')).toHaveClass(
'mm-modal-content__dialog custom-dialog-class',
);
}); });
it('should close when escape key is pressed', () => { it('should close when escape key is pressed', () => {
const { getByRole } = render( const { getByRole } = render(

View File

@ -86,25 +86,27 @@ export const ModalContent = forwardRef(
height={BlockSize.Screen} height={BlockSize.Screen}
justifyContent={JustifyContent.center} justifyContent={JustifyContent.center}
alignItems={AlignItems.flexStart} alignItems={AlignItems.flexStart}
padding={4} paddingRight={4}
paddingLeft={4}
paddingTop={[4, 8, 12]}
paddingBottom={[4, 8, 12]}
{...props} {...props}
> >
<Box <Box
className={classnames(
'mm-modal-content__dialog',
`mm-modal-content__dialog--size-${size}`,
)}
as="section" as="section"
role="dialog" role="dialog"
aria-modal="true" aria-modal="true"
backgroundColor={BackgroundColor.backgroundDefault} backgroundColor={BackgroundColor.backgroundDefault}
borderRadius={BorderRadius.LG} borderRadius={BorderRadius.LG}
width={BlockSize.Full} width={BlockSize.Full}
marginTop={[null, 8, 12]}
marginBottom={[null, 8, 12]}
padding={4} padding={4}
ref={modalDialogRef} ref={modalDialogRef}
{...modalDialogProps} {...modalDialogProps}
className={classnames(
'mm-modal-content__dialog',
`mm-modal-content__dialog--size-${size}`,
modalDialogProps?.className,
)}
> >
{children} {children}
</Box> </Box>

View File

@ -19,6 +19,8 @@ import {
BlockSize, BlockSize,
Size, Size,
TextColor, TextColor,
Display,
FlexDirection,
} from '../../../helpers/constants/design-system'; } from '../../../helpers/constants/design-system';
import { useI18nContext } from '../../../hooks/useI18nContext'; import { useI18nContext } from '../../../hooks/useI18nContext';
import { MetaMetricsContext } from '../../../contexts/metametrics'; import { MetaMetricsContext } from '../../../contexts/metametrics';
@ -85,24 +87,22 @@ export const AccountListMenu = ({ onClose }) => {
<ModalOverlay /> <ModalOverlay />
<ModalContent <ModalContent
className="multichain-account-menu-popover" className="multichain-account-menu-popover"
modalDialogProps={{ padding: 0, marginBottom: 0 }} modalDialogProps={{
className: 'multichain-account-menu-popover__dialog',
padding: 0,
display: Display.Flex,
flexDirection: FlexDirection.Column,
}}
> >
<ModalHeader <ModalHeader
paddingTop={4} padding={4}
paddingRight={4}
paddingBottom={6}
onClose={onClose} onClose={onClose}
onBack={actionMode === '' ? null : () => setActionMode('')} onBack={actionMode === '' ? null : () => setActionMode('')}
> >
{title} {title}
</ModalHeader> </ModalHeader>
{actionMode === 'add' ? ( {actionMode === 'add' ? (
<Box <Box paddingLeft={4} paddingRight={4} paddingBottom={4}>
paddingLeft={4}
paddingRight={4}
paddingBottom={4}
paddingTop={0}
>
<CreateAccount <CreateAccount
onActionComplete={(confirmed) => { onActionComplete={(confirmed) => {
if (confirmed) { if (confirmed) {
@ -133,7 +133,7 @@ export const AccountListMenu = ({ onClose }) => {
</Box> </Box>
) : null} ) : null}
{actionMode === '' ? ( {actionMode === '' ? (
<Box> <>
{/* Search box */} {/* Search box */}
{accounts.length > 100 ? ( {accounts.length > 100 ? (
<Box <Box
@ -315,7 +315,7 @@ export const AccountListMenu = ({ onClose }) => {
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
} }
</Box> </Box>
</Box> </>
) : null} ) : null}
</ModalContent> </ModalContent>
</Modal> </Modal>

View File

@ -1,4 +1,8 @@
.multichain-account-menu-popover { .multichain-account-menu-popover {
&__dialog {
max-height: 100%;
}
.popover-content { .popover-content {
border-radius: 0; border-radius: 0;
} }

View File

@ -44,6 +44,7 @@ import {
getSelectedIdentity, getSelectedIdentity,
getShowProductTour, getShowProductTour,
getTestNetworkBackgroundColor, getTestNetworkBackgroundColor,
getUnapprovedTransactions,
getSelectedAddress, getSelectedAddress,
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
getTheme, getTheme,
@ -136,9 +137,10 @@ export const AppHeader = ({ location }) => {
matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }), matchPath(location.pathname, { path: BUILD_QUOTE_ROUTE, exact: false }),
); );
const hasUnapprovedTransactions = useSelector( const unapprovedTransactions = useSelector(getUnapprovedTransactions);
(state) => Object.keys(state.metamask.unapprovedTxs).length > 0,
); const hasUnapprovedTransactions =
Object.keys(unapprovedTransactions).length > 0;
const disableAccountPicker = const disableAccountPicker =
isConfirmationPage || (isSwapsPage && !isSwapsBuildQuotePage); isConfirmationPage || (isSwapsPage && !isSwapsBuildQuotePage);

View File

@ -44,7 +44,7 @@ export const CreateAccount = ({ onActionComplete }) => {
const { isValidAccountName, errorMessage } = getAccountNameErrorMessage( const { isValidAccountName, errorMessage } = getAccountNameErrorMessage(
accounts, accounts,
{ t }, { t },
trimmedAccountName ?? defaultAccountName, trimmedAccountName || defaultAccountName,
defaultAccountName, defaultAccountName,
); );

View File

@ -44,6 +44,7 @@ import {
getMetaMetricsId, getMetaMetricsId,
///: END:ONLY_INCLUDE_IN(build-mmi) ///: END:ONLY_INCLUDE_IN(build-mmi)
getSelectedAddress, getSelectedAddress,
getUnapprovedTransactions,
///: BEGIN:ONLY_INCLUDE_IN(snaps) ///: BEGIN:ONLY_INCLUDE_IN(snaps)
getUnreadNotificationsCount, getUnreadNotificationsCount,
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
@ -69,10 +70,11 @@ export const GlobalMenu = ({ closeMenu, anchorElement }) => {
const trackEvent = useContext(MetaMetricsContext); const trackEvent = useContext(MetaMetricsContext);
const history = useHistory(); const history = useHistory();
const address = useSelector(getSelectedAddress); const address = useSelector(getSelectedAddress);
const unapprovedTransactons = useSelector(getUnapprovedTransactions);
const hasUnapprovedTransactions =
Object.keys(unapprovedTransactons).length > 0;
const hasUnapprovedTransactions = useSelector(
(state) => Object.keys(state.metamask.unapprovedTxs).length > 0,
);
///: BEGIN:ONLY_INCLUDE_IN(build-mmi) ///: BEGIN:ONLY_INCLUDE_IN(build-mmi)
const metaMetricsId = useSelector(getMetaMetricsId); const metaMetricsId = useSelector(getMetaMetricsId);
const mmiPortfolioUrl = useSelector(getMmiPortfolioUrl); const mmiPortfolioUrl = useSelector(getMmiPortfolioUrl);

View File

@ -51,7 +51,7 @@ describe('AccountListItem', () => {
}); });
it('enables the settings item when there is no active transaction', async () => { it('enables the settings item when there is no active transaction', async () => {
const { getByTestId } = render({ unapprovedTxs: {} }); const { getByTestId } = render({ transactions: [] });
await waitFor(() => { await waitFor(() => {
expect(getByTestId('global-menu-settings')).toBeEnabled(); expect(getByTestId('global-menu-settings')).toBeEnabled();
}); });
@ -65,7 +65,7 @@ describe('AccountListItem', () => {
}); });
it('enables the connected sites item when there is no active transaction', async () => { it('enables the connected sites item when there is no active transaction', async () => {
const { getByTestId } = render({ unapprovedTxs: {} }); const { getByTestId } = render({ transactions: [] });
await waitFor(() => { await waitFor(() => {
expect(getByTestId('global-menu-connected-sites')).toBeEnabled(); expect(getByTestId('global-menu-connected-sites')).toBeEnabled();
}); });

View File

@ -49,9 +49,10 @@ const NewNetworkInfo = () => {
}; };
const getIsTokenDetectionSupported = async () => { const getIsTokenDetectionSupported = async () => {
const fetchedTokenData = await fetchWithCache( const fetchedTokenData = await fetchWithCache({
`${TOKEN_API_METASWAP_CODEFI_URL}${providerConfig.chainId}`, url: `${TOKEN_API_METASWAP_CODEFI_URL}${providerConfig.chainId}`,
); functionName: 'getIsTokenDetectionSupported',
});
return !fetchedTokenData.error; return !fetchedTokenData.error;
}; };

View File

@ -33,9 +33,10 @@ describe('NewNetworkInfo', () => {
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]', '[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
); );
const updateTokenDetectionSupportStatus = await fetchWithCache( const updateTokenDetectionSupportStatus = await fetchWithCache({
'https://token-api.metaswap.codefi.network/tokens/0x1', url: 'https://token-api.metaswap.codefi.network/tokens/0x1',
); functionName: 'getTokenDetectionSupportStatus',
});
const store = configureMockStore()( const store = configureMockStore()(
state, state,
@ -54,9 +55,10 @@ describe('NewNetworkInfo', () => {
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]', '[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
); );
const updateTokenDetectionSupportStatus = await fetchWithCache( const updateTokenDetectionSupportStatus = await fetchWithCache({
'https://token-api.metaswap.codefi.network/tokens/0x1', url: 'https://token-api.metaswap.codefi.network/tokens/0x1',
); functionName: 'getTokenDetectionSupportStatus',
});
state.metamask.nativeCurrency = ''; state.metamask.nativeCurrency = '';
@ -77,10 +79,10 @@ describe('NewNetworkInfo', () => {
200, 200,
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]', '[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
); );
const updateTokenDetectionSupportStatus = await fetchWithCache({
const updateTokenDetectionSupportStatus = await fetchWithCache( url: 'https://token-api.metaswap.codefi.network/tokens/0x1',
'https://token-api.metaswap.codefi.network/tokens/0x1', functionName: 'getTokenDetectionSupportStatus',
); });
const store = configureMockStore()( const store = configureMockStore()(
state, state,
@ -99,9 +101,10 @@ describe('NewNetworkInfo', () => {
'[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]', '[{"address":"0xc011a73ee8576fb46f5e1c5751ca3b9fe0af2a6f","symbol":"SNX","decimals":18,"name":"Synthetix Network Token","iconUrl":"https://assets.coingecko.com/coins/images/3406/large/SNX.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","synthetix","zapper","zerion","zeroEx"],"occurrences":12},{"address":"0x1f9840a85d5af5bf1d1762f925bdaddc4201f984","symbol":"UNI","decimals":18,"name":"Uniswap","iconUrl":"https://images.prismic.io/token-price-prod/d0352dd9-5de8-4633-839d-bc3422c44d9c_UNI%404x.png","aggregators":["aave","bancor","cmc","cryptocom","coinGecko","oneInch","paraswap","pmm","zapper","zerion","zeroEx"],"occurrences":11}]',
); );
const updateTokenDetectionSupportStatus = await fetchWithCache( const updateTokenDetectionSupportStatus = await fetchWithCache({
'https://token-api.metaswap.codefi.network/tokens/0x1', url: 'https://token-api.metaswap.codefi.network/tokens/0x1',
); functionName: 'getTokenDetectionSupportStatus',
});
const store = configureMockStore()( const store = configureMockStore()(
state, state,
@ -117,9 +120,10 @@ describe('NewNetworkInfo', () => {
.get('/tokens/0x3') .get('/tokens/0x3')
.reply(200, '{"error":"ChainId 0x3 is not supported"}'); .reply(200, '{"error":"ChainId 0x3 is not supported"}');
const updateTokenDetectionSupportStatus = await fetchWithCache( const updateTokenDetectionSupportStatus = await fetchWithCache({
'https://token-api.metaswap.codefi.network/tokens/0x3', url: 'https://token-api.metaswap.codefi.network/tokens/0x3',
); functionName: 'getTokenDetectionSupportStatus',
});
const store = configureMockStore()( const store = configureMockStore()(
state, state,
@ -135,9 +139,10 @@ describe('NewNetworkInfo', () => {
.get('/tokens/0x3') .get('/tokens/0x3')
.reply(200, '{"error":"ChainId 0x3 is not supported"}'); .reply(200, '{"error":"ChainId 0x3 is not supported"}');
const updateTokenDetectionSupportStatus = await fetchWithCache( const updateTokenDetectionSupportStatus = await fetchWithCache({
'https://token-api.metaswap.codefi.network/tokens/0x3', url: 'https://token-api.metaswap.codefi.network/tokens/0x3',
); functionName: 'getTokenDetectionSupportStatus',
});
state.metamask.providerConfig.ticker = null; state.metamask.providerConfig.ticker = null;
@ -156,9 +161,10 @@ describe('NewNetworkInfo', () => {
.get('/tokens/0x3') .get('/tokens/0x3')
.reply(200, '{"error":"ChainId 0x3 is not supported"}'); .reply(200, '{"error":"ChainId 0x3 is not supported"}');
const updateTokenDetectionSupportStatus = await fetchWithCache( const updateTokenDetectionSupportStatus = await fetchWithCache({
'https://token-api.metaswap.codefi.network/tokens/0x3', url: 'https://token-api.metaswap.codefi.network/tokens/0x3',
); functionName: 'getTokenDetectionSupportStatus',
});
const store = configureMockStore()( const store = configureMockStore()(
state, state,

View File

@ -152,14 +152,14 @@ describe('App State', () => {
it('shows confirm tx page', () => { it('shows confirm tx page', () => {
const txs = { const txs = {
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
}, },
2: { {
id: 2, id: 2,
}, },
}, ],
}; };
const oldState = { ...metamaskState, ...txs }; const oldState = { ...metamaskState, ...txs };
const state = reduceApp(oldState, { const state = reduceApp(oldState, {
@ -174,14 +174,14 @@ describe('App State', () => {
it('completes tx continues to show pending txs current view context', () => { it('completes tx continues to show pending txs current view context', () => {
const txs = { const txs = {
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
}, },
2: { {
id: 2, id: 2,
}, },
}, ],
}; };
const oldState = { ...metamaskState, ...txs }; const oldState = { ...metamaskState, ...txs };

View File

@ -356,8 +356,8 @@ describe('Confirm Transaction Duck', () => {
providerConfig: { providerConfig: {
chainId: '0x5', chainId: '0x5',
}, },
unapprovedTxs: { transactions: [
2603411941761054: { {
history: [], history: [],
id: 2603411941761054, id: 2603411941761054,
loadingDefaults: false, loadingDefaults: false,
@ -373,7 +373,7 @@ describe('Confirm Transaction Duck', () => {
value: '0xde0b6b3a7640000', value: '0xde0b6b3a7640000',
}, },
}, },
}, ],
}, },
confirmTransaction: {}, confirmTransaction: {},
}; };

View File

@ -27,7 +27,7 @@ const initialState = {
isAccountMenuOpen: false, isAccountMenuOpen: false,
isNetworkMenuOpen: false, isNetworkMenuOpen: false,
identities: {}, identities: {},
unapprovedTxs: {}, transactions: [],
networkConfigurations: {}, networkConfigurations: {},
addressBook: [], addressBook: [],
contractExchangeRates: {}, contractExchangeRates: {},
@ -111,8 +111,8 @@ export default function reduceMetamask(state = initialState, action) {
case actionConstants.UPDATE_TRANSACTION_PARAMS: { case actionConstants.UPDATE_TRANSACTION_PARAMS: {
const { id: txId, value } = action; const { id: txId, value } = action;
let { currentNetworkTxList } = metamaskState; let { transactions } = metamaskState;
currentNetworkTxList = currentNetworkTxList.map((tx) => { transactions = transactions.map((tx) => {
if (tx.id === txId) { if (tx.id === txId) {
const newTx = { ...tx }; const newTx = { ...tx };
newTx.txParams = value; newTx.txParams = value;
@ -123,7 +123,7 @@ export default function reduceMetamask(state = initialState, action) {
return { return {
...metamaskState, ...metamaskState,
currentNetworkTxList, transactions,
}; };
} }
@ -300,10 +300,6 @@ export function getSendToAccounts(state) {
return [...fromAccounts, ...addressBookAccounts]; return [...fromAccounts, ...addressBookAccounts];
} }
export function getUnapprovedTxs(state) {
return state.metamask.unapprovedTxs;
}
/** /**
* Function returns true if network details are fetched and it is found to not support EIP-1559 * Function returns true if network details are fetched and it is found to not support EIP-1559
* *

View File

@ -9,7 +9,6 @@ import reduceMetamask, {
getNativeCurrency, getNativeCurrency,
getSendHexDataFeatureFlagState, getSendHexDataFeatureFlagState,
getSendToAccounts, getSendToAccounts,
getUnapprovedTxs,
isNotEIP1559Network, isNotEIP1559Network,
} from './metamask'; } from './metamask';
@ -91,8 +90,8 @@ describe('MetaMask Reducers', () => {
}, },
}, },
}, },
unapprovedTxs: { transactions: [
4768706228115573: { {
id: 4768706228115573, id: 4768706228115573,
time: 1487363153561, time: 1487363153561,
status: TransactionStatus.unapproved, status: TransactionStatus.unapproved,
@ -111,7 +110,7 @@ describe('MetaMask Reducers', () => {
maxCost: 'de234b52e4a0800', maxCost: 'de234b52e4a0800',
gasPrice: '4a817c800', gasPrice: '4a817c800',
}, },
}, ],
}, },
{}, {},
), ),
@ -175,7 +174,7 @@ describe('MetaMask Reducers', () => {
it('updates value of tx by id', () => { it('updates value of tx by id', () => {
const oldState = { const oldState = {
currentNetworkTxList: [ transactions: [
{ {
id: 1, id: 1,
txParams: 'foo', txParams: 'foo',
@ -189,7 +188,7 @@ describe('MetaMask Reducers', () => {
value: 'bar', value: 'bar',
}); });
expect(state.currentNetworkTxList[0].txParams).toStrictEqual('bar'); expect(state.transactions[0].txParams).toStrictEqual('bar');
}); });
it('close welcome screen', () => { it('close welcome screen', () => {
@ -326,30 +325,6 @@ describe('MetaMask Reducers', () => {
]); ]);
}); });
}); });
it('should return the unapproved txs', () => {
expect(getUnapprovedTxs(mockState)).toStrictEqual({
4768706228115573: {
id: 4768706228115573,
time: 1487363153561,
status: TransactionStatus.unapproved,
gasMultiplier: 1,
metamaskNetworkId: '5',
txParams: {
from: '0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb',
to: '0x18a3462427bcc9133bb46e88bcbe39cd7ef0e761',
value: '0xde0b6b3a7640000',
metamaskId: 4768706228115573,
metamaskNetworkId: '5',
gas: '0x5209',
},
txFee: '17e0186e60800',
txValue: 'de0b6b3a7640000',
maxCost: 'de234b52e4a0800',
gasPrice: '4a817c800',
},
});
});
}); });
describe('isNotEIP1559Network()', () => { describe('isNotEIP1559Network()', () => {

View File

@ -39,6 +39,7 @@ import {
getEnsResolutionByAddress, getEnsResolutionByAddress,
getSelectedAccount, getSelectedAccount,
getSelectedAddress, getSelectedAddress,
getUnapprovedTransactions,
} from '../../selectors'; } from '../../selectors';
import { import {
disconnectGasFeeEstimatePoller, disconnectGasFeeEstimatePoller,
@ -80,7 +81,6 @@ import {
getGasEstimateType, getGasEstimateType,
getProviderConfig, getProviderConfig,
getTokens, getTokens,
getUnapprovedTxs,
} from '../metamask/metamask'; } from '../metamask/metamask';
import { resetDomainResolution } from '../domains'; import { resetDomainResolution } from '../domains';
@ -499,7 +499,7 @@ export const computeEstimatedGasLimit = createAsyncThunk(
const { send, metamask } = state; const { send, metamask } = state;
const draftTransaction = const draftTransaction =
send.draftTransactions[send.currentTransactionUUID]; send.draftTransactions[send.currentTransactionUUID];
const unapprovedTxs = getUnapprovedTxs(state); const unapprovedTxs = getUnapprovedTransactions(state);
const isMultiLayerFeeNetwork = getIsMultiLayerFeeNetwork(state); const isMultiLayerFeeNetwork = getIsMultiLayerFeeNetwork(state);
const transaction = unapprovedTxs[draftTransaction.id]; const transaction = unapprovedTxs[draftTransaction.id];
const isNonStandardEthChain = getIsNonStandardEthChain(state); const isNonStandardEthChain = getIsNonStandardEthChain(state);
@ -1731,7 +1731,7 @@ export function editExistingTransaction(assetType, transactionId) {
return async (dispatch, getState) => { return async (dispatch, getState) => {
await dispatch(actions.clearPreviousDrafts()); await dispatch(actions.clearPreviousDrafts());
const state = getState(); const state = getState();
const unapprovedTransactions = getUnapprovedTxs(state); const unapprovedTransactions = getUnapprovedTransactions(state);
const transaction = unapprovedTransactions[transactionId]; const transaction = unapprovedTransactions[transactionId];
const account = getTargetAccount(state, transaction.txParams.from); const account = getTargetAccount(state, transaction.txParams.from);
@ -2033,7 +2033,7 @@ export function updateSendAsset(
getSelectedAddress(state); getSelectedAddress(state);
const account = getTargetAccount(state, sendingAddress); const account = getTargetAccount(state, sendingAddress);
if (type === AssetType.native) { if (type === AssetType.native) {
const unapprovedTxs = getUnapprovedTxs(state); const unapprovedTxs = getUnapprovedTransactions(state);
const unapprovedTx = unapprovedTxs?.[draftTransaction.id]; const unapprovedTx = unapprovedTxs?.[draftTransaction.id];
await dispatch( await dispatch(
@ -2274,7 +2274,7 @@ export function signTransaction() {
// We first must grab the previous transaction object from state and then // We first must grab the previous transaction object from state and then
// merge in the modified txParams. Once the transaction has been modified // merge in the modified txParams. Once the transaction has been modified
// we can send that to the background to update the transaction in state. // we can send that to the background to update the transaction in state.
const unapprovedTxs = getUnapprovedTxs(state); const unapprovedTxs = getUnapprovedTransactions(state);
const unapprovedTx = cloneDeep(unapprovedTxs[draftTransaction.id]); const unapprovedTx = cloneDeep(unapprovedTxs[draftTransaction.id]);
// We only update the tx params that can be changed via the edit flow UX // We only update the tx params that can be changed via the edit flow UX
const eip1559OnlyTxParamsToUpdate = { const eip1559OnlyTxParamsToUpdate = {

View File

@ -1479,7 +1479,10 @@ describe('Send Slice', () => {
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[3].type).toStrictEqual( expect(actionResult[3].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[4].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
}); });
@ -1531,7 +1534,10 @@ describe('Send Slice', () => {
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[3].type).toStrictEqual( expect(actionResult[3].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[4].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
}); });
@ -1568,14 +1574,17 @@ describe('Send Slice', () => {
const actionResult = store.getActions(); const actionResult = store.getActions();
expect(actionResult).toHaveLength(4); expect(actionResult).toHaveLength(5);
expect(actionResult[0].type).toStrictEqual('send/addHistoryEntry'); expect(actionResult[0].type).toStrictEqual('send/addHistoryEntry');
expect(actionResult[1].type).toStrictEqual('send/updateSendAmount'); expect(actionResult[1].type).toStrictEqual('send/updateSendAmount');
expect(actionResult[2].type).toStrictEqual( expect(actionResult[2].type).toStrictEqual(
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[3].type).toStrictEqual( expect(actionResult[3].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[4].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
}); });
}); });
@ -1636,7 +1645,7 @@ describe('Send Slice', () => {
const actionResult = store.getActions(); const actionResult = store.getActions();
expect(actionResult).toHaveLength(4); expect(actionResult).toHaveLength(5);
expect(actionResult[0]).toMatchObject({ expect(actionResult[0]).toMatchObject({
type: 'send/addHistoryEntry', type: 'send/addHistoryEntry',
@ -1657,7 +1666,10 @@ describe('Send Slice', () => {
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[3].type).toStrictEqual( expect(actionResult[3].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[4].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
}); });
@ -1692,7 +1704,7 @@ describe('Send Slice', () => {
const actionResult = store.getActions(); const actionResult = store.getActions();
expect(actionResult).toHaveLength(6); expect(actionResult).toHaveLength(7);
expect(actionResult[0].type).toStrictEqual('SHOW_LOADING_INDICATION'); expect(actionResult[0].type).toStrictEqual('SHOW_LOADING_INDICATION');
expect(actionResult[1].type).toStrictEqual('HIDE_LOADING_INDICATION'); expect(actionResult[1].type).toStrictEqual('HIDE_LOADING_INDICATION');
expect(actionResult[2]).toMatchObject({ expect(actionResult[2]).toMatchObject({
@ -1719,7 +1731,10 @@ describe('Send Slice', () => {
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[5].type).toStrictEqual( expect(actionResult[5].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[6].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
}); });
@ -2092,7 +2107,7 @@ describe('Send Slice', () => {
await store.dispatch(resetRecipientInput()); await store.dispatch(resetRecipientInput());
const actionResult = store.getActions(); const actionResult = store.getActions();
expect(actionResult).toHaveLength(11); expect(actionResult).toHaveLength(12);
expect(actionResult[0]).toMatchObject({ expect(actionResult[0]).toMatchObject({
type: 'send/addHistoryEntry', type: 'send/addHistoryEntry',
payload: 'sendFlow - user cleared recipient input', payload: 'sendFlow - user cleared recipient input',
@ -2118,10 +2133,15 @@ describe('Send Slice', () => {
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[8].type).toStrictEqual( expect(actionResult[8].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[9].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
expect(actionResult[9].type).toStrictEqual('DNS/resetDomainResolution');
expect(actionResult[10].type).toStrictEqual( expect(actionResult[10].type).toStrictEqual(
'DNS/resetDomainResolution',
);
expect(actionResult[11].type).toStrictEqual(
'send/validateRecipientUserInput', 'send/validateRecipientUserInput',
); );
}); });
@ -2238,7 +2258,7 @@ describe('Send Slice', () => {
const actionResult = store.getActions(); const actionResult = store.getActions();
expect(actionResult).toHaveLength(5); expect(actionResult).toHaveLength(6);
expect(actionResult[0].type).toStrictEqual('send/updateAmountMode'); expect(actionResult[0].type).toStrictEqual('send/updateAmountMode');
expect(actionResult[1].type).toStrictEqual('send/updateSendAmount'); expect(actionResult[1].type).toStrictEqual('send/updateSendAmount');
expect(actionResult[2]).toMatchObject({ expect(actionResult[2]).toMatchObject({
@ -2249,7 +2269,10 @@ describe('Send Slice', () => {
'send/computeEstimatedGasLimit/pending', 'send/computeEstimatedGasLimit/pending',
); );
expect(actionResult[4].type).toStrictEqual( expect(actionResult[4].type).toStrictEqual(
'send/computeEstimatedGasLimit/rejected', 'metamask/gas/SET_CUSTOM_GAS_LIMIT',
);
expect(actionResult[5].type).toStrictEqual(
'send/computeEstimatedGasLimit/fulfilled',
); );
}); });
}); });
@ -2287,14 +2310,19 @@ describe('Send Slice', () => {
it('should pass the correct transaction parameters to addTransactionAndRouteToConfirmationPage', async () => { it('should pass the correct transaction parameters to addTransactionAndRouteToConfirmationPage', async () => {
const tokenTransferTxState = { const tokenTransferTxState = {
metamask: { metamask: {
unapprovedTxs: { providerConfig: {
1: { chainId: CHAIN_IDS.GOERLI,
},
transactions: [
{
id: 1, id: 1,
chainId: CHAIN_IDS.GOERLI,
status: 'unapproved',
txParams: { txParams: {
value: 'oldTxValue', value: 'oldTxValue',
}, },
}, },
}, ],
}, },
send: { send: {
...getInitialSendStateWithExistingTxState({ ...getInitialSendStateWithExistingTxState({
@ -2339,14 +2367,19 @@ describe('Send Slice', () => {
it('should create actions for updateTransaction rejecting', async () => { it('should create actions for updateTransaction rejecting', async () => {
const editStageSignTxState = { const editStageSignTxState = {
metamask: { metamask: {
unapprovedTxs: { providerConfig: {
1: { chainId: '0x1',
},
transactions: [
{
id: 1, id: 1,
chainId: '0x1',
status: 'unapproved',
txParams: { txParams: {
value: 'oldTxValue', value: 'oldTxValue',
}, },
}, },
}, ],
}, },
send: { send: {
...signTransactionState.send, ...signTransactionState.send,
@ -2405,19 +2438,21 @@ describe('Send Slice', () => {
}, },
}, },
tokenList: {}, tokenList: {},
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
chainId: CHAIN_IDS.GOERLI,
status: 'unapproved',
txParams: { txParams: {
data: '', data: '',
from: mockAddress1, from: mockAddress1,
to: '0xRecipientAddress', to: '0xRecipientAddress',
gas: GAS_LIMITS.SIMPLE, gas: GAS_LIMITS.SIMPLE,
gasPrice: '0x3b9aca00', // 1000000000 gasPrice: '0x3b9aca00', // 1000000000
value: '0xde0b6b3a7640000', // 1000000000000000000 value: '0xde0b6b3a7640000', // 1000000000000000000,
},
}, },
}, },
],
}, },
send: { send: {
// We are going to remove this transaction as a part of the flow, // We are going to remove this transaction as a part of the flow,
@ -2542,9 +2577,11 @@ describe('Send Slice', () => {
}, },
}, },
tokenList: {}, tokenList: {},
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
chainId: CHAIN_IDS.GOERLI,
status: 'unapproved',
txParams: { txParams: {
data: generateERC721TransferData({ data: generateERC721TransferData({
toAddress: BURN_ADDRESS, toAddress: BURN_ADDRESS,
@ -2558,7 +2595,7 @@ describe('Send Slice', () => {
value: '0x0', value: '0x0',
}, },
}, },
}, ],
}, },
send: { send: {
...getInitialSendStateWithExistingTxState({ ...getInitialSendStateWithExistingTxState({
@ -2626,7 +2663,7 @@ describe('Send Slice', () => {
status: SEND_STATUSES.VALID, status: SEND_STATUSES.VALID,
transactionType: '0x0', transactionType: '0x0',
userInputHexData: userInputHexData:
editTransactionState.metamask.unapprovedTxs[1].txParams.data, editTransactionState.metamask.transactions[0].txParams.data,
}, },
}); });
expect(actionResult[2].type).toStrictEqual('SHOW_LOADING_INDICATION'); expect(actionResult[2].type).toStrictEqual('SHOW_LOADING_INDICATION');
@ -2726,9 +2763,11 @@ describe('Send Slice', () => {
[mockAddress1]: '0x0', [mockAddress1]: '0x0',
}, },
}, },
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
chainId: CHAIN_IDS.GOERLI,
status: 'unapproved',
txParams: { txParams: {
data: generateERC20TransferData({ data: generateERC20TransferData({
toAddress: BURN_ADDRESS, toAddress: BURN_ADDRESS,
@ -2746,7 +2785,7 @@ describe('Send Slice', () => {
value: '0x0', value: '0x0',
}, },
}, },
}, ],
}, },
send: { send: {
...getInitialSendStateWithExistingTxState({ ...getInitialSendStateWithExistingTxState({
@ -2819,7 +2858,7 @@ describe('Send Slice', () => {
status: SEND_STATUSES.VALID, status: SEND_STATUSES.VALID,
transactionType: '0x0', transactionType: '0x0',
userInputHexData: userInputHexData:
editTransactionState.metamask.unapprovedTxs[1].txParams.data, editTransactionState.metamask.transactions[0].txParams.data,
}, },
}); });
expect(actionResult[2].type).toStrictEqual('SHOW_LOADING_INDICATION'); expect(actionResult[2].type).toStrictEqual('SHOW_LOADING_INDICATION');

View File

@ -26,15 +26,16 @@ import fetchWithCache from '../../../shared/lib/fetch-with-cache';
*/ */
async function getMethodFrom4Byte(fourBytePrefix) { async function getMethodFrom4Byte(fourBytePrefix) {
const fourByteResponse = await fetchWithCache( const fourByteResponse = await fetchWithCache({
`https://www.4byte.directory/api/v1/signatures/?hex_signature=${fourBytePrefix}`, url: `https://www.4byte.directory/api/v1/signatures/?hex_signature=${fourBytePrefix}`,
{ fetchOptions: {
referrerPolicy: 'no-referrer-when-downgrade', referrerPolicy: 'no-referrer-when-downgrade',
body: null, body: null,
method: 'GET', method: 'GET',
mode: 'cors', mode: 'cors',
}, },
); functionName: 'getMethodFrom4Byte',
});
fourByteResponse.results.sort((a, b) => { fourByteResponse.results.sort((a, b) => {
return new Date(a.created_at).getTime() < new Date(b.created_at).getTime() return new Date(a.created_at).getTime() < new Date(b.created_at).getTime()
? -1 ? -1

View File

@ -17,6 +17,7 @@ import configureStore from './store/store';
import { import {
getPermittedAccountsForCurrentTab, getPermittedAccountsForCurrentTab,
getSelectedAddress, getSelectedAddress,
getUnapprovedTransactions,
} from './selectors'; } from './selectors';
import { ALERT_STATE } from './ducks/alerts'; import { ALERT_STATE } from './ducks/alerts';
import { import {
@ -152,9 +153,11 @@ async function startApp(metamaskState, backgroundConnection, opts) {
const store = configureStore(draftInitialState); const store = configureStore(draftInitialState);
reduxStore = store; reduxStore = store;
const unapprovedTxs = getUnapprovedTransactions(metamaskState);
// if unconfirmed txs, start on txConf page // if unconfirmed txs, start on txConf page
const unapprovedTxsAll = txHelper( const unapprovedTxsAll = txHelper(
metamaskState.unapprovedTxs, unapprovedTxs,
metamaskState.unapprovedMsgs, metamaskState.unapprovedMsgs,
metamaskState.unapprovedPersonalMsgs, metamaskState.unapprovedPersonalMsgs,
metamaskState.unapprovedDecryptMsgs, metamaskState.unapprovedDecryptMsgs,

View File

@ -4,7 +4,7 @@ import { text } from '@storybook/addon-knobs';
import { useParams } from 'react-router-dom'; import { useParams } from 'react-router-dom';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import { updateMetamaskState } from '../../store/actions'; import { updateMetamaskState } from '../../store/actions';
import { currentNetworkTxListSelector } from '../../selectors/transactions'; import { getCurrentNetworkTransactions } from '../../selectors/transactions';
import { store, getNewState } from '../../../.storybook/preview'; import { store, getNewState } from '../../../.storybook/preview';
import { subjectMetadata } from '../../../.storybook/initial-states/approval-screens/token-approval'; import { subjectMetadata } from '../../../.storybook/initial-states/approval-screens/token-approval';
@ -15,7 +15,7 @@ export default {
title: 'Pages/ConfirmApprove', title: 'Pages/ConfirmApprove',
}; };
// transaction ID, maps to entry in state.metamask.currentNetworkTxList // transaction ID, maps to entry in state.metamask.transactions
const txId = 7900715443136469; const txId = 7900715443136469;
const PageSet = ({ children }) => { const PageSet = ({ children }) => {
@ -25,7 +25,7 @@ const PageSet = ({ children }) => {
'https://metamask.github.io/test-dapp/metamask-fox.svg', 'https://metamask.github.io/test-dapp/metamask-fox.svg',
); );
const state = store.getState(); const state = store.getState();
const currentNetworkTxList = useSelector(currentNetworkTxListSelector); const currentNetworkTxList = useSelector(getCurrentNetworkTransactions);
const transaction = currentNetworkTxList.find(({ id }) => id === txId); const transaction = currentNetworkTxList.find(({ id }) => id === txId);
useEffect(() => { useEffect(() => {
@ -33,7 +33,7 @@ const PageSet = ({ children }) => {
store.dispatch( store.dispatch(
updateMetamaskState( updateMetamaskState(
getNewState(state.metamask, { getNewState(state.metamask, {
currentNetworkTxList: [transaction], transactions: [transaction],
}), }),
), ),
); );

View File

@ -40,10 +40,12 @@ const sendEther = {
}, },
}; };
mockState.metamask.unapprovedTxs[sendEther.id] = sendEther; mockState.metamask.transactions.push(sendEther);
mockState.confirmTransaction = { mockState.confirmTransaction = {
txData: sendEther, txData: sendEther,
}; };
const store = configureStore(mockState); const store = configureStore(mockState);
export default { export default {

View File

@ -50,10 +50,12 @@ const sendEther = {
}, },
}; };
mockState.metamask.unapprovedTxs[sendEther.id] = sendEther; mockState.metamask.transactions.push(sendEther);
mockState.confirmTransaction = { mockState.confirmTransaction = {
txData: sendEther, txData: sendEther,
}; };
const store = configureStore(mockState); const store = configureStore(mockState);
describe('ConfirmSendEther', () => { describe('ConfirmSendEther', () => {

View File

@ -18,6 +18,8 @@ import {
getSelectedAccount, getSelectedAccount,
///: END:ONLY_INCLUDE_IN ///: END:ONLY_INCLUDE_IN
getTargetSubjectMetadata, getTargetSubjectMetadata,
getCurrentNetworkTransactions,
getUnapprovedTransactions,
} from '../../selectors'; } from '../../selectors';
import { MESSAGE_TYPE } from '../../../shared/constants/app'; import { MESSAGE_TYPE } from '../../../shared/constants/app';
import { TransactionStatus } from '../../../shared/constants/transaction'; import { TransactionStatus } from '../../../shared/constants/transaction';
@ -53,9 +55,7 @@ const ConfirmTxScreen = ({ match }) => {
); );
const sendTo = useSelector(getSendTo); const sendTo = useSelector(getSendTo);
const { const {
unapprovedTxs,
identities, identities,
currentNetworkTxList,
currentCurrency, currentCurrency,
unapprovedMsgs, unapprovedMsgs,
unapprovedPersonalMsgs, unapprovedPersonalMsgs,
@ -63,6 +63,8 @@ const ConfirmTxScreen = ({ match }) => {
networkId, networkId,
blockGasLimit, blockGasLimit,
} = useSelector((state) => state.metamask); } = useSelector((state) => state.metamask);
const unapprovedTxs = useSelector(getUnapprovedTransactions);
const currentNetworkTxList = useSelector(getCurrentNetworkTransactions);
const { chainId } = useSelector(getProviderConfig); const { chainId } = useSelector(getProviderConfig);
const { txId: index } = useSelector((state) => state.appState); const { txId: index } = useSelector((state) => state.appState);

View File

@ -41,6 +41,7 @@ import {
getUnapprovedTransaction, getUnapprovedTransaction,
getFullTxData, getFullTxData,
getUseCurrencyRateCheck, getUseCurrencyRateCheck,
getUnapprovedTransactions,
} from '../../selectors'; } from '../../selectors';
import { getMostRecentOverviewPage } from '../../ducks/history/history'; import { getMostRecentOverviewPage } from '../../ducks/history/history';
import { import {
@ -121,14 +122,9 @@ const mapStateToProps = (state, ownProps) => {
const gasLoadingAnimationIsShowing = getGasLoadingAnimationIsShowing(state); const gasLoadingAnimationIsShowing = getGasLoadingAnimationIsShowing(state);
const isBuyableChain = getIsBuyableChain(state); const isBuyableChain = getIsBuyableChain(state);
const { confirmTransaction, metamask } = state; const { confirmTransaction, metamask } = state;
const { const { conversionRate, identities, addressBook, networkId, nextNonce } =
conversionRate, metamask;
identities, const unapprovedTxs = getUnapprovedTransactions(state);
addressBook,
networkId,
unapprovedTxs,
nextNonce,
} = metamask;
const { chainId } = getProviderConfig(state); const { chainId } = getProviderConfig(state);
const { tokenData, txData, tokenProps, nonce } = confirmTransaction; const { tokenData, txData, tokenProps, nonce } = confirmTransaction;
const { txParams = {}, id: transactionId, type } = txData; const { txParams = {}, id: transactionId, type } = txData;

View File

@ -66,13 +66,14 @@ const baseStore = {
}, },
history: { mostRecentOverviewPage: '/' }, history: { mostRecentOverviewPage: '/' },
metamask: { metamask: {
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
metamaskNetworkId: mockNetworkId, metamaskNetworkId: mockNetworkId,
txParams: { ...mockTxParams }, txParams: { ...mockTxParams },
status: 'unapproved',
}, },
}, ],
gasEstimateType: GasEstimateTypes.legacy, gasEstimateType: GasEstimateTypes.legacy,
gasFeeEstimates: { gasFeeEstimates: {
low: '0', low: '0',
@ -175,7 +176,7 @@ const baseStore = {
const mockedStore = jest.mocked(baseStore); const mockedStore = jest.mocked(baseStore);
const mockedStoreWithConfirmTxParams = (_mockTxParams = mockTxParams) => { const mockedStoreWithConfirmTxParams = (_mockTxParams = mockTxParams) => {
mockedStore.metamask.unapprovedTxs[1].txParams = { ..._mockTxParams }; mockedStore.metamask.transactions[0].txParams = { ..._mockTxParams };
mockedStore.confirmTransaction.txData.txParams = { ..._mockTxParams }; mockedStore.confirmTransaction.txData.txParams = { ..._mockTxParams };
}; };

View File

@ -1,11 +1,12 @@
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { unconfirmedTransactionsListSelector } from '../../selectors'; import {
getUnapprovedTransactions,
unconfirmedTransactionsListSelector,
} from '../../selectors';
import ConfirmTransactionSwitch from './confirm-transaction-switch.component'; import ConfirmTransactionSwitch from './confirm-transaction-switch.component';
const mapStateToProps = (state, ownProps) => { const mapStateToProps = (state, ownProps) => {
const { const unapprovedTxs = getUnapprovedTransactions(state);
metamask: { unapprovedTxs },
} = state;
const { const {
match: { params = {}, url }, match: { params = {}, url },
} = ownProps; } = ownProps;

View File

@ -22,7 +22,7 @@ import {
import ConfirmTransaction from '.'; import ConfirmTransaction from '.';
const mockUnapprovedTx = Object.values(_mockState.metamask.unapprovedTxs)[0]; const mockUnapprovedTx = _mockState.metamask.transactions[0];
const middleware = [thunk]; const middleware = [thunk];
@ -137,7 +137,7 @@ describe('Confirmation Transaction Page', () => {
...mockState, ...mockState,
metamask: { metamask: {
...mockState.metamask, ...mockState.metamask,
unapprovedTxs: {}, transactions: [],
}, },
}); });
const { container } = renderWithProvider(<ConfirmTransaction />, mockStore); const { container } = renderWithProvider(<ConfirmTransaction />, mockStore);
@ -177,12 +177,12 @@ describe('Confirmation Transaction Page', () => {
...mockState, ...mockState,
metamask: { metamask: {
...mockState.metamask, ...mockState.metamask,
unapprovedTxs: { transactions: [
[mockUnapprovedTx.id]: { {
...mockUnapprovedTx, ...mockUnapprovedTx,
type: 'transfer', type: 'transfer',
}, },
}, ],
}, },
}); });
const { container } = renderWithProvider( const { container } = renderWithProvider(
@ -237,7 +237,7 @@ describe('Confirmation Transaction Page', () => {
it('should not call setTransactionToConfirm when transaction id is not provided', () => { it('should not call setTransactionToConfirm when transaction id is not provided', () => {
const mockStore = configureMockStore(middleware)({ const mockStore = configureMockStore(middleware)({
...mockState, ...mockState,
metamask: { ...mockState.metamask, unapprovedTxs: {} }, metamask: { ...mockState.metamask, transactions: [] },
}); });
jest.spyOn(ReactRouterDOM, 'useParams').mockImplementation(() => { jest.spyOn(ReactRouterDOM, 'useParams').mockImplementation(() => {
return { id: null }; return { id: null };
@ -272,7 +272,7 @@ describe('Confirmation Transaction Page', () => {
...mockState, ...mockState,
metamask: { metamask: {
...mockState.metamask, ...mockState.metamask,
unapprovedTxs: {}, transactions: [],
}, },
}); });
const replaceSpy = jest.fn(); const replaceSpy = jest.fn();

View File

@ -25,13 +25,13 @@ setBackgroundConnection({
describe('Confirm Transaction', () => { describe('Confirm Transaction', () => {
const unapprovedTransactionId = Object.keys( const unapprovedTransactionId = Object.keys(
mockState.metamask.unapprovedTxs, mockState.metamask.transactions,
)[0]; )[0];
it('should render correct information for approve transaction with value', () => { it('should render correct information for approve transaction with value', () => {
const store = configureMockStore(middleware)({ const store = configureMockStore(middleware)({
...mockState, ...mockState,
confirmTransaction: { confirmTransaction: {
txData: mockState.metamask.unapprovedTxs[unapprovedTransactionId], txData: mockState.metamask.transactions[0],
}, },
}); });
const { getByText, getByRole } = renderWithProvider( const { getByText, getByRole } = renderWithProvider(

View File

@ -134,7 +134,10 @@ const ERROR_CONNECTING_TO_RPC = {
async function getAlerts(pendingApproval) { async function getAlerts(pendingApproval) {
const alerts = []; const alerts = [];
const safeChainsList = const safeChainsList =
(await fetchWithCache('https://chainid.network/chains.json')) || []; (await fetchWithCache({
url: 'https://chainid.network/chains.json',
functionName: 'getSafeChainsList',
})) || [];
const matchedChain = safeChainsList.find( const matchedChain = safeChainsList.find(
(chain) => (chain) =>
chain.chainId === parseInt(pendingApproval.requestData.chainId, 16), chain.chainId === parseInt(pendingApproval.requestData.chainId, 16),

View File

@ -51,6 +51,10 @@ describe('success template', () => {
type: ApprovalType.ResultSuccess, type: ApprovalType.ResultSuccess,
}, },
}, },
providerConfig: {
chainId: '0x1',
},
transactions: [],
}, },
}; };
const store = configureMockStore(middleware)(testStore); const store = configureMockStore(middleware)(testStore);

View File

@ -63,6 +63,7 @@ describe('switch-ethereum-chain confirmation', () => {
type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN,
}, },
}, },
transactions: [],
}, },
}; };
const store = configureMockStore(middleware)(testStore); const store = configureMockStore(middleware)(testStore);
@ -83,11 +84,12 @@ describe('switch-ethereum-chain confirmation', () => {
type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN, type: MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN,
}, },
}, },
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
status: 'unapproved',
}, },
}, ],
}, },
}; };

View File

@ -27,6 +27,7 @@ import {
transactionFeeSelector, transactionFeeSelector,
getIsTestnet, getIsTestnet,
getUseCurrencyRateCheck, getUseCurrencyRateCheck,
getUnapprovedTransactions,
} from '../../../selectors'; } from '../../../selectors';
import { INSUFFICIENT_TOKENS_ERROR } from '../send.constants'; import { INSUFFICIENT_TOKENS_ERROR } from '../send.constants';
@ -62,7 +63,7 @@ export default function GasDisplay({ gasError }) {
const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck); const useCurrencyRateCheck = useSelector(getUseCurrencyRateCheck);
const { showFiatInTestnets, useNativeCurrencyAsPrimaryCurrency } = const { showFiatInTestnets, useNativeCurrencyAsPrimaryCurrency } =
useSelector(getPreferences); useSelector(getPreferences);
const { unapprovedTxs } = useSelector((state) => state.metamask); const unapprovedTxs = useSelector(getUnapprovedTransactions);
const nativeCurrency = useSelector(getNativeCurrency); const nativeCurrency = useSelector(getNativeCurrency);
const { chainId } = providerConfig; const { chainId } = providerConfig;
const networkName = NETWORK_TO_NAME_MAP[chainId]; const networkName = NETWORK_TO_NAME_MAP[chainId];

View File

@ -3,7 +3,7 @@ import {
getAddressBook, getAddressBook,
getAddressBookEntry, getAddressBookEntry,
getMetaMaskAccountsOrdered, getMetaMaskAccountsOrdered,
currentNetworkTxListSelector, getCurrentNetworkTransactions,
} from '../../../../selectors'; } from '../../../../selectors';
import { import {
@ -35,7 +35,7 @@ function mapStateToProps(state) {
const addressBook = getAddressBook(state); const addressBook = getAddressBook(state);
const txList = [...currentNetworkTxListSelector(state)].reverse(); const txList = [...getCurrentNetworkTransactions(state)].reverse();
const nonContacts = addressBook const nonContacts = addressBook
.filter(({ name }) => !name) .filter(({ name }) => !name)

View File

@ -16,7 +16,7 @@ jest.mock('../../../../selectors', () => ({
{ name: `account1:mockState` }, { name: `account1:mockState` },
{ name: `account2:mockState` }, { name: `account2:mockState` },
], ],
currentNetworkTxListSelector: (s) => `currentNetworkTxListSelector:${s}`, getCurrentNetworkTransactions: (s) => `getCurrentNetworkTransactions:${s}`,
})); }));
jest.mock('../../../../ducks/domains', () => ({ jest.mock('../../../../ducks/domains', () => ({

View File

@ -65,14 +65,14 @@ const baseStore = {
}, },
history: { mostRecentOverviewPage: 'activity' }, history: { mostRecentOverviewPage: 'activity' },
metamask: { metamask: {
unapprovedTxs: { transactions: [
1: { {
id: 1, id: 1,
txParams: { txParams: {
value: 'oldTxValue', value: 'oldTxValue',
}, },
}, },
}, ],
gasEstimateType: GasEstimateTypes.legacy, gasEstimateType: GasEstimateTypes.legacy,
gasFeeEstimates: { gasFeeEstimates: {
low: '0', low: '0',
@ -108,7 +108,6 @@ const baseStore = {
addressBook: { addressBook: {
[CHAIN_IDS.GOERLI]: [], [CHAIN_IDS.GOERLI]: [],
}, },
currentNetworkTxList: [],
cachedBalances: { cachedBalances: {
[CHAIN_IDS.GOERLI]: {}, [CHAIN_IDS.GOERLI]: {},
}, },

View File

@ -356,7 +356,10 @@ const NetworksForm = ({
try { try {
safeChainsList = safeChainsList =
(await fetchWithCache('https://chainid.network/chains.json')) || []; (await fetchWithCache({
url: 'https://chainid.network/chains.json',
functionName: 'getSafeChainsList',
})) || [];
} catch (err) { } catch (err) {
log.warn('Failed to fetch the chainList from chainid.network', err); log.warn('Failed to fetch the chainList from chainid.network', err);
providerError = err; providerError = err;

View File

@ -54,7 +54,7 @@ import {
} from '../../ducks/swaps/swaps'; } from '../../ducks/swaps/swaps';
import { import {
checkNetworkAndAccountSupports1559, checkNetworkAndAccountSupports1559,
currentNetworkTxListSelector, getCurrentNetworkTransactions,
} from '../../selectors'; } from '../../selectors';
import { import {
AWAITING_SIGNATURES_ROUTE, AWAITING_SIGNATURES_ROUTE,
@ -137,7 +137,7 @@ export default function Swap() {
const selectedAccount = useSelector(getSelectedAccount, shallowEqual); const selectedAccount = useSelector(getSelectedAccount, shallowEqual);
const quotes = useSelector(getQuotes, isEqual); const quotes = useSelector(getQuotes, isEqual);
const latestAddedTokenTo = useSelector(getLatestAddedTokenTo, isEqual); const latestAddedTokenTo = useSelector(getLatestAddedTokenTo, isEqual);
const txList = useSelector(currentNetworkTxListSelector, shallowEqual); const txList = useSelector(getCurrentNetworkTransactions, shallowEqual);
const tradeTxId = useSelector(getTradeTxId); const tradeTxId = useSelector(getTradeTxId);
const approveTxId = useSelector(getApproveTxId); const approveTxId = useSelector(getApproveTxId);
const aggregatorMetadata = useSelector(getAggregatorMetadata, shallowEqual); const aggregatorMetadata = useSelector(getAggregatorMetadata, shallowEqual);

View File

@ -117,11 +117,12 @@ export async function fetchToken(
chainId: any, chainId: any,
): Promise<Json> { ): Promise<Json> {
const tokenUrl = getBaseApi('token', chainId); const tokenUrl = getBaseApi('token', chainId);
return await fetchWithCache( return await fetchWithCache({
`${tokenUrl}?address=${contractAddress}`, url: `${tokenUrl}?address=${contractAddress}`,
{ method: 'GET', headers: clientIdHeader }, fetchOptions: { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, cacheOptions: { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
); functionName: 'fetchToken',
});
} }
type Token = { symbol: string; address: string }; type Token = { symbol: string; address: string };
@ -129,11 +130,12 @@ export async function fetchTokens(
chainId: keyof typeof SWAPS_CHAINID_DEFAULT_TOKEN_MAP, chainId: keyof typeof SWAPS_CHAINID_DEFAULT_TOKEN_MAP,
): Promise<SwapsTokenObject[]> { ): Promise<SwapsTokenObject[]> {
const tokensUrl = getBaseApi('tokens', chainId); const tokensUrl = getBaseApi('tokens', chainId);
const tokens = await fetchWithCache( const tokens = await fetchWithCache({
tokensUrl, url: tokensUrl,
{ method: 'GET', headers: clientIdHeader }, fetchOptions: { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, cacheOptions: { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
); functionName: 'fetchTokens',
});
const logError = false; const logError = false;
const tokenObject = SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId] || null; const tokenObject = SWAPS_CHAINID_DEFAULT_TOKEN_MAP[chainId] || null;
return [ return [
@ -152,11 +154,12 @@ export async function fetchTokens(
export async function fetchAggregatorMetadata(chainId: any): Promise<object> { export async function fetchAggregatorMetadata(chainId: any): Promise<object> {
const aggregatorMetadataUrl = getBaseApi('aggregatorMetadata', chainId); const aggregatorMetadataUrl = getBaseApi('aggregatorMetadata', chainId);
const aggregators = await fetchWithCache( const aggregators = await fetchWithCache({
aggregatorMetadataUrl, url: aggregatorMetadataUrl,
{ method: 'GET', headers: clientIdHeader }, fetchOptions: { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, cacheOptions: { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
); functionName: 'fetchAggregatorMetadata',
});
const filteredAggregators = {} as any; const filteredAggregators = {} as any;
for (const aggKey in aggregators) { for (const aggKey in aggregators) {
if ( if (
@ -175,11 +178,12 @@ export async function fetchAggregatorMetadata(chainId: any): Promise<object> {
export async function fetchTopAssets(chainId: any): Promise<object> { export async function fetchTopAssets(chainId: any): Promise<object> {
const topAssetsUrl = getBaseApi('topAssets', chainId); const topAssetsUrl = getBaseApi('topAssets', chainId);
const response = const response =
(await fetchWithCache( (await fetchWithCache({
topAssetsUrl, url: topAssetsUrl,
{ method: 'GET', headers: clientIdHeader }, functionName: 'fetchTopAssets',
{ cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES }, fetchOptions: { method: 'GET', headers: clientIdHeader },
)) || []; cacheOptions: { cacheRefreshTime: CACHE_REFRESH_FIVE_MINUTES },
})) || [];
const topAssetsMap = response.reduce( const topAssetsMap = response.reduce(
(_topAssetsMap: any, asset: { address: string }, index: number) => { (_topAssetsMap: any, asset: { address: string }, index: number) => {
if (validateData(TOP_ASSET_VALIDATORS, asset, topAssetsUrl)) { if (validateData(TOP_ASSET_VALIDATORS, asset, topAssetsUrl)) {
@ -196,21 +200,23 @@ export async function fetchSwapsFeatureFlags(): Promise<any> {
const v2ApiBaseUrl = process.env.SWAPS_USE_DEV_APIS const v2ApiBaseUrl = process.env.SWAPS_USE_DEV_APIS
? SWAPS_DEV_API_V2_BASE_URL ? SWAPS_DEV_API_V2_BASE_URL
: SWAPS_API_V2_BASE_URL; : SWAPS_API_V2_BASE_URL;
return await fetchWithCache( return await fetchWithCache({
`${v2ApiBaseUrl}/featureFlags`, url: `${v2ApiBaseUrl}/featureFlags`,
{ method: 'GET', headers: clientIdHeader }, fetchOptions: { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: 600000 }, cacheOptions: { cacheRefreshTime: 600000 },
); functionName: 'fetchSwapsFeatureFlags',
});
} }
export async function fetchTokenPrice(address: string): Promise<any> { export async function fetchTokenPrice(address: string): Promise<any> {
const query = `contract_addresses=${address}&vs_currencies=eth`; const query = `contract_addresses=${address}&vs_currencies=eth`;
const prices = await fetchWithCache( const prices = await fetchWithCache({
`https://api.coingecko.com/api/v3/simple/token_price/ethereum?${query}`, url: `https://api.coingecko.com/api/v3/simple/token_price/ethereum?${query}`,
{ method: 'GET' }, fetchOptions: { method: 'GET' },
{ cacheRefreshTime: 60000 }, cacheOptions: { cacheRefreshTime: 60000 },
); functionName: 'fetchTokenPrice',
});
return prices?.[address]?.eth; return prices?.[address]?.eth;
} }
@ -223,11 +229,12 @@ export async function fetchSwapsGasPrices(chainId: any): Promise<
} }
> { > {
const gasPricesUrl = getBaseApi('gasPrices', chainId); const gasPricesUrl = getBaseApi('gasPrices', chainId);
const response = await fetchWithCache( const response = await fetchWithCache({
gasPricesUrl, url: gasPricesUrl,
{ method: 'GET', headers: clientIdHeader }, fetchOptions: { method: 'GET', headers: clientIdHeader },
{ cacheRefreshTime: 30000 }, cacheOptions: { cacheRefreshTime: 30000 },
); functionName: 'fetchSwapsGasPrices',
});
const responseIsValid = validateData( const responseIsValid = validateData(
SWAP_GAS_PRICE_VALIDATOR, SWAP_GAS_PRICE_VALIDATOR,
response, response,

View File

@ -73,7 +73,7 @@ const state = {
isERC721: false, isERC721: false,
}, },
], ],
unapprovedTxs: {}, transactions: [],
keyringTypes: [], keyringTypes: [],
keyrings: [ keyrings: [
{ {

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