mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 01:47:00 +01:00
Merge pull request #20588 from MetaMask/Version-v10.35.1
Version 10.35.1
This commit is contained in:
commit
a7b4c20f32
17
CHANGELOG.md
17
CHANGELOG.md
@ -6,6 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [10.35.1]
|
||||
### 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))
|
||||
- Add more diagnostic information upon failure ([#20595](https://github.com/MetaMask/metamask-extension/pull/20595))
|
||||
|
||||
### Fixed
|
||||
- Fix bug resulting in custom network configuration being lost upon restart ([#20586](https://github.com/MetaMask/metamask-extension/pull/20586))
|
||||
- Fix UI crash when balances are missing ([#20385](https://github.com/MetaMask/metamask-extension/pull/20385))
|
||||
- Fix infinite rerender on network change while signature request is pending ([#20473](https://github.com/MetaMask/metamask-extension/pull/20473))
|
||||
- Fix Dapp link on NFT import screen ([#19799](https://github.com/MetaMask/metamask-extension/pull/19799))
|
||||
- Fix 'View on Opensea' link for main and testnet NFTs ([#19797](https://github.com/MetaMask/metamask-extension/pull/19797))
|
||||
- Ensure chainId comparison in switchEthereumChain handler is case insensitive ([#20149](https://github.com/MetaMask/metamask-extension/pull/20149))
|
||||
- Enforce user preferences in incoming transactions controller ([#19982](https://github.com/MetaMask/metamask-extension/pull/19982))
|
||||
|
||||
## [10.35.0]
|
||||
### Added
|
||||
- Add the ability to customize tx nonce on ERC20 approval screens ([#17945](https://github.com/MetaMask/metamask-extension/pull/17945))
|
||||
@ -3946,7 +3960,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
### Uncategorized
|
||||
- Added the ability to restore accounts from seed words.
|
||||
|
||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.35.0...HEAD
|
||||
[Unreleased]: https://github.com/MetaMask/metamask-extension/compare/v10.35.1...HEAD
|
||||
[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.34.5]: https://github.com/MetaMask/metamask-extension/compare/v10.34.4...v10.34.5
|
||||
[10.34.4]: https://github.com/MetaMask/metamask-extension/compare/v10.34.3...v10.34.4
|
||||
|
9
app/_locales/de/messages.json
generated
9
app/_locales/de/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Erweiterte Einstellungen"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Speichern Sie diese $1 als Standard für \"Erweitert\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Immer diese Werte und erweiterte Einstellung als Standard verwenden."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Erweiterte Gasgebühr"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Token importiert"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "neue Werte"
|
||||
},
|
||||
"next": {
|
||||
"message": "Weiter"
|
||||
},
|
||||
|
9
app/_locales/el/messages.json
generated
9
app/_locales/el/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Προηγμένη ρύθμιση παραμέτρων"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Αποθηκεύστε αυτά τα $1 ως προεπιλογή μου για το \"Προηγμένο\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Να χρησιμοποιούνται πάντα αυτές τις τιμές και η ρύθμιση για προχωρημένους."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Προηγμένη χρέωση τελών συναλλαγής"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Τα token εισήχθησαν"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "νέες τιμές"
|
||||
},
|
||||
"next": {
|
||||
"message": "Επόμενο"
|
||||
},
|
||||
|
18
app/_locales/en/messages.json
generated
18
app/_locales/en/messages.json
generated
@ -306,10 +306,8 @@
|
||||
"message": "Advanced configuration"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Save these $1 as my default for \"Advanced\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Always use these values and advanced setting as default."
|
||||
"message": "Save these values as my default for the $1 network.",
|
||||
"description": "$1 is the current network name."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Advanced gas fee"
|
||||
@ -2483,9 +2481,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Token imported"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "new values"
|
||||
},
|
||||
"next": {
|
||||
"message": "Next"
|
||||
},
|
||||
@ -2752,6 +2747,15 @@
|
||||
"notifications22Title": {
|
||||
"message": "Looking for your account details or the block explorer URL?"
|
||||
},
|
||||
"notifications24ActionText": {
|
||||
"message": "Got it"
|
||||
},
|
||||
"notifications24Description": {
|
||||
"message": "Advanced gas fee settings are now remembered based on the network you're using. This means you can set specific advanced gas fees for each network and avoid overpaying for gas or stuck transactions."
|
||||
},
|
||||
"notifications24Title": {
|
||||
"message": "Advanced gas fees by network"
|
||||
},
|
||||
"notifications3ActionText": {
|
||||
"message": "Read more",
|
||||
"description": "The 'call to action' on the button, or link, of the 'Stay secure' notification. Upon clicking, users will be taken to a page about security on the metamask support website."
|
||||
|
9
app/_locales/es/messages.json
generated
9
app/_locales/es/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Configuración avanzada"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Guarda estos 1$ como mi valor predeterminado para \"Avanzado\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Usar siempre estos valores y la configuración avanzada como valores predeterminados."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Tarifa de gas avanzada"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Token importado"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "nuevos valores"
|
||||
},
|
||||
"next": {
|
||||
"message": "Siguiente"
|
||||
},
|
||||
|
9
app/_locales/es_419/messages.json
generated
9
app/_locales/es_419/messages.json
generated
@ -148,12 +148,6 @@
|
||||
"advancedBaseGasFeeToolTip": {
|
||||
"message": "Cuando su transacción se incluya en el bloque, se reembolsará cualquier diferencia entre su tarifa base máxima y la tarifa base real. El importe total se calcula como tarifa base máxima (en GWEI) * límite de gas."
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Guarda estos 1$ como mi valor predeterminado para \"Avanzado\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Usar siempre estos valores y la configuración avanzada como valores predeterminados."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Tarifa de gas avanzada"
|
||||
},
|
||||
@ -1431,9 +1425,6 @@
|
||||
"newPassword": {
|
||||
"message": "Contraseña nueva (mín. de 8 caracteres)"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "nuevos valores"
|
||||
},
|
||||
"next": {
|
||||
"message": "Siguiente"
|
||||
},
|
||||
|
9
app/_locales/fr/messages.json
generated
9
app/_locales/fr/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Configuration avancée"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Enregistrer ces $1 comme valeur par défaut pour « Avancé »"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Toujours utiliser par défaut ces valeurs et les paramètres avancés."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Frais de carburant avancés"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Jeton importé"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "nouvelles valeurs"
|
||||
},
|
||||
"next": {
|
||||
"message": "Suivant"
|
||||
},
|
||||
|
9
app/_locales/hi/messages.json
generated
9
app/_locales/hi/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "उन्नत कंफिगुरेशन"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "इन $1 को \"एडवांस\" के लिए मेरे डिफॉल्ट के रूप में सहेजें"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "हमेशा इन मूल्यों और एडवांस सेटिंग को डिफॉल्ट के रूप में उपयोग करें।"
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "एडवांस गैस शुल्क"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "टोकन इम्पोर्ट हो गया"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "नए मान"
|
||||
},
|
||||
"next": {
|
||||
"message": "अगला"
|
||||
},
|
||||
|
9
app/_locales/id/messages.json
generated
9
app/_locales/id/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Konfigurasi lanjutan"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Simpan $1 ini sebagai default saya untuk \"Lanjutan\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Selalu gunakan nilai ini dan pengaturan lanjutan sebagai default."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Biaya gas lanjutan"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Token diimpor"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "nilai baru"
|
||||
},
|
||||
"next": {
|
||||
"message": "Berikutnya"
|
||||
},
|
||||
|
6
app/_locales/it/messages.json
generated
6
app/_locales/it/messages.json
generated
@ -213,12 +213,6 @@
|
||||
"advancedBaseGasFeeToolTip": {
|
||||
"message": "Quando la tua transazione viene inclusa nel blocco, ogni differenza tra la tua offerta massima di gas e il gas effettivamente utilizzato viene restituita a te. Il totale viene calcolato come offerta massima di gas (in GEWI) * limite di gas."
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Salva queste $1 come mie preferite per \"Avanzate\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Utilizzare sempre questi valori e l'impostazione avanzata come predefiniti."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Tariffa gas avanzata"
|
||||
},
|
||||
|
9
app/_locales/ja/messages.json
generated
9
app/_locales/ja/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "詳細設定"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "これらの$1を「高度な設定」のデフォルトとして保存"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "常にこれらの値と高度な設定をデフォルトとして使用します。"
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "高度なガス代"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "トークンがインポートされました"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "新しい値"
|
||||
},
|
||||
"next": {
|
||||
"message": "次へ"
|
||||
},
|
||||
|
9
app/_locales/ko/messages.json
generated
9
app/_locales/ko/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "고급 옵션"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "이 $1 옵션을 \"고급\"의 기본값으로 저장합니다"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "항상 이 값과 고급 설정을 기본값으로 사용합니다."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "고급 가스 요금"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "불러온 토큰"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "새로운 가치"
|
||||
},
|
||||
"next": {
|
||||
"message": "다음"
|
||||
},
|
||||
|
9
app/_locales/pt/messages.json
generated
9
app/_locales/pt/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Configurações avançadas"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Salvar estes $1 como meu padrão para \"Avançado\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Sempre utilizar esses valores e a configuração avançada por padrão."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Taxa de gás avançada"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Token importado"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "novos valores"
|
||||
},
|
||||
"next": {
|
||||
"message": "Próximo"
|
||||
},
|
||||
|
9
app/_locales/pt_BR/messages.json
generated
9
app/_locales/pt_BR/messages.json
generated
@ -148,12 +148,6 @@
|
||||
"advancedBaseGasFeeToolTip": {
|
||||
"message": "Quando a sua transação for incluída no bloco, qualquer diferença entre a sua taxa de base máxima e a taxa de base real será reembolsada. O cálculo do valor total é feito da seguinte forma: taxa de base máxima (em GWEI) * limite de gás."
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Salvar estes $1 como meu padrão para \"Avançado\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Sempre utilizar esses valores e a configuração avançada por padrão."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Taxa de gás avançada"
|
||||
},
|
||||
@ -1431,9 +1425,6 @@
|
||||
"newPassword": {
|
||||
"message": "Nova senha (no mínimo 8 caracteres)"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "novos valores"
|
||||
},
|
||||
"next": {
|
||||
"message": "Seguinte"
|
||||
},
|
||||
|
9
app/_locales/ru/messages.json
generated
9
app/_locales/ru/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Расширенная конфигурация"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Сохранить этот $1 в качестве моего значения по умолчанию для «Дополнительной» настройки"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Всегда использовать эти значения и дополнительную настройку по умолчанию."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Дополнительная плата за газ"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Токен импортирован"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "новые значения"
|
||||
},
|
||||
"next": {
|
||||
"message": "Далее"
|
||||
},
|
||||
|
9
app/_locales/tl/messages.json
generated
9
app/_locales/tl/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Advanced na pagsasaayos"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "I-save itong mga $1bilang aking default para sa \"Advanced\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Laging gamitin ang mga value na ito at advanced setting bilang default."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Advanced na gas fee"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Na-import ang token"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "bagong value"
|
||||
},
|
||||
"next": {
|
||||
"message": "Susunod"
|
||||
},
|
||||
|
9
app/_locales/tr/messages.json
generated
9
app/_locales/tr/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Gelişmiş yapılandırma"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "\"Gelişmiş\" için şunları varsayılanım olarak kaydet: $1"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Varsayılan olarak her zaman bu değerleri ve gelişmiş ayarı kullan."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Gelişmiş gaz ücreti"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Token içe aktarıldı"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "yeni değerler"
|
||||
},
|
||||
"next": {
|
||||
"message": "Sonraki"
|
||||
},
|
||||
|
9
app/_locales/vi/messages.json
generated
9
app/_locales/vi/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "Cấu hình nâng cao"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "Lưu $1 này làm mặc định của tôi cho \"Nâng cao\""
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "Luôn sử dụng các giá trị và thiết lập nâng cao này làm mặc định."
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "Phí gas nâng cao"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "Đã nhập token"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "giá trị mới"
|
||||
},
|
||||
"next": {
|
||||
"message": "Tiếp theo"
|
||||
},
|
||||
|
9
app/_locales/zh_CN/messages.json
generated
9
app/_locales/zh_CN/messages.json
generated
@ -275,12 +275,6 @@
|
||||
"advancedConfiguration": {
|
||||
"message": "高级配置"
|
||||
},
|
||||
"advancedGasFeeDefaultOptIn": {
|
||||
"message": "将这些 $1 保存为“高级”默认值"
|
||||
},
|
||||
"advancedGasFeeDefaultOptOut": {
|
||||
"message": "始终使用这些值和高级设置作为默认值。"
|
||||
},
|
||||
"advancedGasFeeModalTitle": {
|
||||
"message": "高级燃料费"
|
||||
},
|
||||
@ -2101,9 +2095,6 @@
|
||||
"newTokensImportedTitle": {
|
||||
"message": "已导入代币"
|
||||
},
|
||||
"newValues": {
|
||||
"message": "新的值"
|
||||
},
|
||||
"next": {
|
||||
"message": "下一步"
|
||||
},
|
||||
|
@ -360,7 +360,7 @@ async function loadPhishingWarningPage() {
|
||||
} catch (error) {
|
||||
if (error instanceof PhishingWarningPageTimeoutError) {
|
||||
console.warn(
|
||||
'Phishing warning page timeout; page not guaraneteed to work offline.',
|
||||
'Phishing warning page timeout; page not guaranteed to work offline.',
|
||||
);
|
||||
} else {
|
||||
console.error('Failed to initialize phishing warning page', error);
|
||||
|
@ -49,6 +49,10 @@ export default class AppStateController extends EventEmitter {
|
||||
showProductTour: true,
|
||||
trezorModel: null,
|
||||
currentPopupId: undefined,
|
||||
// This key is only used for checking if the user had set advancedGasFee
|
||||
// prior to Migration 92.3 where we split out the setting to support
|
||||
// multiple networks.
|
||||
hadAdvancedGasFeesSetPriorToMigration92_3: false,
|
||||
...initState,
|
||||
qrHardware: {},
|
||||
nftsDropdownState: {},
|
||||
|
@ -135,15 +135,12 @@ export default class IncomingTransactionsController {
|
||||
}
|
||||
|
||||
start() {
|
||||
const { featureFlags = {} } = this.preferencesController.store.getState();
|
||||
const { showIncomingTransactions } = featureFlags;
|
||||
const chainId = this.getCurrentChainId();
|
||||
|
||||
if (!showIncomingTransactions) {
|
||||
return;
|
||||
if (this._allowedToMakeFetchIncomingTx(chainId)) {
|
||||
this.blockTracker.removeListener('latest', this._onLatestBlock);
|
||||
this.blockTracker.addListener('latest', this._onLatestBlock);
|
||||
}
|
||||
|
||||
this.blockTracker.removeListener('latest', this._onLatestBlock);
|
||||
this.blockTracker.addListener('latest', this._onLatestBlock);
|
||||
}
|
||||
|
||||
stop() {
|
||||
@ -161,13 +158,9 @@ export default class IncomingTransactionsController {
|
||||
* @param {number} [newBlockNumberDec] - block number to begin fetching from
|
||||
*/
|
||||
async _update(address, newBlockNumberDec) {
|
||||
const { completedOnboarding } = this.onboardingController.store.getState();
|
||||
const chainId = this.getCurrentChainId();
|
||||
if (
|
||||
!Object.hasOwnProperty.call(ETHERSCAN_SUPPORTED_NETWORKS, chainId) ||
|
||||
!address ||
|
||||
!completedOnboarding
|
||||
) {
|
||||
|
||||
if (!address || !this._allowedToMakeFetchIncomingTx(chainId)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
@ -302,4 +295,26 @@ export default class IncomingTransactionsController {
|
||||
type: TransactionType.incoming,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chainId - {string} The chainId of the current network
|
||||
* @returns {boolean} Whether or not the user has consented to show incoming transactions
|
||||
*/
|
||||
_allowedToMakeFetchIncomingTx(chainId) {
|
||||
const { featureFlags = {} } = this.preferencesController.store.getState();
|
||||
const { completedOnboarding } = this.onboardingController.store.getState();
|
||||
|
||||
const hasIncomingTransactionsFeatureEnabled = Boolean(
|
||||
featureFlags.showIncomingTransactions,
|
||||
);
|
||||
|
||||
const isEtherscanSupportedNetwork = Boolean(
|
||||
ETHERSCAN_SUPPORTED_NETWORKS[chainId],
|
||||
);
|
||||
return (
|
||||
completedOnboarding &&
|
||||
isEtherscanSupportedNetwork &&
|
||||
hasIncomingTransactionsFeatureEnabled
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -78,11 +78,11 @@ function getMockPreferencesController({
|
||||
};
|
||||
}
|
||||
|
||||
function getMockOnboardingController() {
|
||||
function getMockOnboardingController({ completedOnboarding = true } = {}) {
|
||||
return {
|
||||
store: {
|
||||
getState: sinon.stub().returns({
|
||||
completedOnboarding: true,
|
||||
completedOnboarding,
|
||||
}),
|
||||
subscribe: sinon.spy(),
|
||||
},
|
||||
@ -98,6 +98,16 @@ function getMockBlockTracker() {
|
||||
};
|
||||
}
|
||||
|
||||
function getDefaultControllerOpts() {
|
||||
return {
|
||||
blockTracker: getMockBlockTracker(),
|
||||
...getMockNetworkControllerMethods(CHAIN_IDS.GOERLI),
|
||||
preferencesController: getMockPreferencesController(),
|
||||
onboardingController: getMockOnboardingController(),
|
||||
initState: getEmptyInitState(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {import(
|
||||
* '../../../../app/scripts/controllers/incoming-transactions'
|
||||
@ -226,6 +236,7 @@ describe('IncomingTransactionsController', function () {
|
||||
preferencesController: getMockPreferencesController(),
|
||||
onboardingController: getMockOnboardingController(),
|
||||
initState: {},
|
||||
getCurrentChainId: () => CHAIN_IDS.GOERLI,
|
||||
},
|
||||
);
|
||||
|
||||
@ -831,6 +842,97 @@ describe('IncomingTransactionsController', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('block explorer lookup', function () {
|
||||
let sandbox;
|
||||
|
||||
beforeEach(function () {
|
||||
sandbox = sinon.createSandbox();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
function stubFetch() {
|
||||
return sandbox.stub(window, 'fetch');
|
||||
}
|
||||
|
||||
function assertStubNotCalled(stub) {
|
||||
assert(stub.callCount === 0);
|
||||
}
|
||||
|
||||
async function triggerUpdate(incomingTransactionsController) {
|
||||
const subscription =
|
||||
incomingTransactionsController.preferencesController.store.subscribe.getCall(
|
||||
1,
|
||||
).args[0];
|
||||
|
||||
// Sets address causing a call to _update
|
||||
await subscription({ selectedAddress: MOCK_SELECTED_ADDRESS });
|
||||
}
|
||||
|
||||
it('should not happen when incoming transactions feature is disabled', async function () {
|
||||
const incomingTransactionsController = new IncomingTransactionsController(
|
||||
{
|
||||
...getDefaultControllerOpts(),
|
||||
preferencesController: getMockPreferencesController({
|
||||
showIncomingTransactions: false,
|
||||
}),
|
||||
},
|
||||
);
|
||||
const fetchStub = stubFetch();
|
||||
await triggerUpdate(incomingTransactionsController);
|
||||
assertStubNotCalled(fetchStub);
|
||||
});
|
||||
|
||||
it('should not happen when onboarding is in progress', async function () {
|
||||
const incomingTransactionsController = new IncomingTransactionsController(
|
||||
{
|
||||
...getDefaultControllerOpts(),
|
||||
onboardingController: getMockOnboardingController({
|
||||
completedOnboarding: false,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const fetchStub = stubFetch();
|
||||
await triggerUpdate(incomingTransactionsController);
|
||||
assertStubNotCalled(fetchStub);
|
||||
});
|
||||
|
||||
it('should not happen when chain id is not supported', async function () {
|
||||
const incomingTransactionsController = new IncomingTransactionsController(
|
||||
{
|
||||
...getDefaultControllerOpts(),
|
||||
getCurrentChainId: () => FAKE_CHAIN_ID,
|
||||
},
|
||||
);
|
||||
|
||||
const fetchStub = stubFetch();
|
||||
await triggerUpdate(incomingTransactionsController);
|
||||
assertStubNotCalled(fetchStub);
|
||||
});
|
||||
|
||||
it('should make api call when chain id, incoming features, and onboarding status are ok', async function () {
|
||||
const incomingTransactionsController = new IncomingTransactionsController(
|
||||
{
|
||||
...getDefaultControllerOpts(),
|
||||
getCurrentChainId: () => CHAIN_IDS.GOERLI,
|
||||
onboardingController: getMockOnboardingController({
|
||||
completedOnboarding: true,
|
||||
}),
|
||||
preferencesController: getMockPreferencesController({
|
||||
showIncomingTransactions: true,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const fetchStub = stubFetch();
|
||||
await triggerUpdate(incomingTransactionsController);
|
||||
assert(fetchStub.callCount === 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('_update', function () {
|
||||
describe('when state is empty (initialized)', function () {
|
||||
it('should use provided block number and update the latest block seen', async function () {
|
||||
|
@ -41,7 +41,7 @@ export default class PreferencesController {
|
||||
useNftDetection: false,
|
||||
useCurrencyRateCheck: true,
|
||||
openSeaEnabled: false,
|
||||
advancedGasFee: null,
|
||||
advancedGasFee: {},
|
||||
|
||||
// WARNING: Do not use feature flags for security-sensitive things.
|
||||
// Feature flag toggling is available in the global namespace
|
||||
@ -188,10 +188,18 @@ export default class PreferencesController {
|
||||
/**
|
||||
* Setter for the `advancedGasFee` property
|
||||
*
|
||||
* @param {object} val - holds the maxBaseFee and PriorityFee that the user set as default advanced settings.
|
||||
* @param {object} options
|
||||
* @param {string} options.chainId - The chainId the advancedGasFees should be set on
|
||||
* @param {object} options.gasFeePreferences - The advancedGasFee options to set
|
||||
*/
|
||||
setAdvancedGasFee(val) {
|
||||
this.store.updateState({ advancedGasFee: val });
|
||||
setAdvancedGasFee({ chainId, gasFeePreferences }) {
|
||||
const { advancedGasFee } = this.store.getState();
|
||||
this.store.updateState({
|
||||
advancedGasFee: {
|
||||
...advancedGasFee,
|
||||
[chainId]: gasFeePreferences,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,6 +2,7 @@ import { strict as assert } from 'assert';
|
||||
import sinon from 'sinon';
|
||||
import { ControllerMessenger } from '@metamask/base-controller';
|
||||
import { TokenListController } from '@metamask/assets-controllers';
|
||||
import { CHAIN_IDS } from '../../../shared/constants/network';
|
||||
import PreferencesController from './preferences';
|
||||
|
||||
describe('preferences controller', function () {
|
||||
@ -250,24 +251,31 @@ describe('preferences controller', function () {
|
||||
});
|
||||
|
||||
describe('setAdvancedGasFee', function () {
|
||||
it('should default to null', function () {
|
||||
const state = preferencesController.store.getState();
|
||||
assert.equal(state.advancedGasFee, null);
|
||||
it('should default to an empty object', function () {
|
||||
assert.deepEqual(
|
||||
preferencesController.store.getState().advancedGasFee,
|
||||
{},
|
||||
);
|
||||
});
|
||||
|
||||
it('should set the setAdvancedGasFee property in state', function () {
|
||||
const state = preferencesController.store.getState();
|
||||
assert.equal(state.advancedGasFee, null);
|
||||
assert.deepEqual(state.advancedGasFee, {});
|
||||
preferencesController.setAdvancedGasFee({
|
||||
maxBaseFee: '1.5',
|
||||
priorityFee: '2',
|
||||
chainId: CHAIN_IDS.GOERLI,
|
||||
gasFeePreferences: {
|
||||
maxBaseFee: '1.5',
|
||||
priorityFee: '2',
|
||||
},
|
||||
});
|
||||
assert.equal(
|
||||
preferencesController.store.getState().advancedGasFee.maxBaseFee,
|
||||
preferencesController.store.getState().advancedGasFee[CHAIN_IDS.GOERLI]
|
||||
.maxBaseFee,
|
||||
'1.5',
|
||||
);
|
||||
assert.equal(
|
||||
preferencesController.store.getState().advancedGasFee.priorityFee,
|
||||
preferencesController.store.getState().advancedGasFee[CHAIN_IDS.GOERLI]
|
||||
.priorityFee,
|
||||
'2',
|
||||
);
|
||||
});
|
||||
|
@ -1962,9 +1962,13 @@ export default class TransactionController extends EventEmitter {
|
||||
*/
|
||||
this.getTransactions = (opts) => this.txStateManager.getTransactions(opts);
|
||||
|
||||
/** @returns {object} the saved default values for advancedGasFee */
|
||||
/**
|
||||
* @returns {object} the saved default values for advancedGasFee
|
||||
*/
|
||||
this.getAdvancedGasFee = () =>
|
||||
this.preferencesStore.getState().advancedGasFee;
|
||||
this.preferencesStore.getState().advancedGasFee[
|
||||
this._getCurrentChainId()
|
||||
];
|
||||
}
|
||||
|
||||
// called once on startup
|
||||
|
@ -59,6 +59,7 @@ describe('Transaction Controller', function () {
|
||||
fromAccount,
|
||||
fragmentExists,
|
||||
networkStatusStore,
|
||||
preferencesStore,
|
||||
getCurrentChainId,
|
||||
messengerMock,
|
||||
resultCallbacksMock,
|
||||
@ -81,6 +82,7 @@ describe('Transaction Controller', function () {
|
||||
}).provider;
|
||||
|
||||
networkStatusStore = new ObservableStore(currentNetworkStatus);
|
||||
preferencesStore = new ObservableStore({ advancedGasFee: {} });
|
||||
|
||||
fromAccount = getTestAccounts()[0];
|
||||
const blockTrackerStub = new EventEmitter();
|
||||
@ -129,6 +131,7 @@ describe('Transaction Controller', function () {
|
||||
getAccountType: () => 'MetaMask',
|
||||
getDeviceModel: () => 'N/A',
|
||||
securityProviderRequest: () => undefined,
|
||||
preferencesStore,
|
||||
messenger: messengerMock,
|
||||
});
|
||||
|
||||
|
@ -116,7 +116,7 @@ async function switchEthereumChainHandler(
|
||||
if (
|
||||
Object.values(BUILT_IN_INFURA_NETWORKS)
|
||||
.map(({ chainId: id }) => id)
|
||||
.includes(chainId)
|
||||
.includes(_chainId)
|
||||
) {
|
||||
await setProviderType(approvedRequestData.type);
|
||||
} else {
|
||||
|
@ -0,0 +1,128 @@
|
||||
import {
|
||||
CHAIN_IDS,
|
||||
NETWORK_TYPES,
|
||||
} from '../../../../../shared/constants/network';
|
||||
import switchEthereumChain from './switch-ethereum-chain';
|
||||
|
||||
const NON_INFURA_CHAIN_ID = '0x123456789';
|
||||
|
||||
const mockRequestUserApproval = ({ requestData }) => {
|
||||
return Promise.resolve(requestData);
|
||||
};
|
||||
|
||||
const MOCK_MAINNET_CONFIGURATION = {
|
||||
id: 123,
|
||||
chainId: CHAIN_IDS.MAINNET,
|
||||
type: NETWORK_TYPES.MAINNET,
|
||||
};
|
||||
const MOCK_LINEA_MAINNET_CONFIGURATION = {
|
||||
id: 123,
|
||||
chainId: CHAIN_IDS.LINEA_MAINNET,
|
||||
type: NETWORK_TYPES.LINEA_MAINNET,
|
||||
};
|
||||
|
||||
describe('switchEthereumChainHandler', () => {
|
||||
it('should call setProviderType when switching to a built in infura network', async () => {
|
||||
const mockSetProviderType = jest.fn();
|
||||
const mockSetActiveNetwork = jest.fn();
|
||||
const switchEthereumChainHandler = switchEthereumChain.implementation;
|
||||
await switchEthereumChainHandler(
|
||||
{
|
||||
origin: 'example.com',
|
||||
params: [{ chainId: CHAIN_IDS.MAINNET }],
|
||||
},
|
||||
{},
|
||||
jest.fn(),
|
||||
jest.fn(),
|
||||
{
|
||||
getCurrentChainId: () => NON_INFURA_CHAIN_ID,
|
||||
findNetworkConfigurationBy: () => MOCK_MAINNET_CONFIGURATION,
|
||||
setProviderType: mockSetProviderType,
|
||||
setActiveNetwork: mockSetActiveNetwork,
|
||||
requestUserApproval: mockRequestUserApproval,
|
||||
},
|
||||
);
|
||||
expect(mockSetProviderType).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetProviderType).toHaveBeenCalledWith(
|
||||
MOCK_MAINNET_CONFIGURATION.type,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call setProviderType when switching to a built in infura network, when chainId from request is lower case', async () => {
|
||||
const mockSetProviderType = jest.fn();
|
||||
const mockSetActiveNetwork = jest.fn();
|
||||
const switchEthereumChainHandler = switchEthereumChain.implementation;
|
||||
await switchEthereumChainHandler(
|
||||
{
|
||||
origin: 'example.com',
|
||||
params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toLowerCase() }],
|
||||
},
|
||||
{},
|
||||
jest.fn(),
|
||||
jest.fn(),
|
||||
{
|
||||
getCurrentChainId: () => NON_INFURA_CHAIN_ID,
|
||||
findNetworkConfigurationBy: () => MOCK_LINEA_MAINNET_CONFIGURATION,
|
||||
setProviderType: mockSetProviderType,
|
||||
setActiveNetwork: mockSetActiveNetwork,
|
||||
requestUserApproval: mockRequestUserApproval,
|
||||
},
|
||||
);
|
||||
expect(mockSetProviderType).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetProviderType).toHaveBeenCalledWith(
|
||||
MOCK_LINEA_MAINNET_CONFIGURATION.type,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call setProviderType when switching to a built in infura network, when chainId from request is upper case', async () => {
|
||||
const mockSetProviderType = jest.fn();
|
||||
const mockSetActiveNetwork = jest.fn();
|
||||
const switchEthereumChainHandler = switchEthereumChain.implementation;
|
||||
await switchEthereumChainHandler(
|
||||
{
|
||||
origin: 'example.com',
|
||||
params: [{ chainId: CHAIN_IDS.LINEA_MAINNET.toUpperCase() }],
|
||||
},
|
||||
{},
|
||||
jest.fn(),
|
||||
jest.fn(),
|
||||
{
|
||||
getCurrentChainId: () => NON_INFURA_CHAIN_ID,
|
||||
findNetworkConfigurationBy: () => MOCK_LINEA_MAINNET_CONFIGURATION,
|
||||
setProviderType: mockSetProviderType,
|
||||
setActiveNetwork: mockSetActiveNetwork,
|
||||
requestUserApproval: mockRequestUserApproval,
|
||||
},
|
||||
);
|
||||
expect(mockSetProviderType).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetProviderType).toHaveBeenCalledWith(
|
||||
MOCK_LINEA_MAINNET_CONFIGURATION.type,
|
||||
);
|
||||
});
|
||||
|
||||
it('should call setActiveNetwork when switching to a custom network', async () => {
|
||||
const mockSetProviderType = jest.fn();
|
||||
const mockSetActiveNetwork = jest.fn();
|
||||
const switchEthereumChainHandler = switchEthereumChain.implementation;
|
||||
await switchEthereumChainHandler(
|
||||
{
|
||||
origin: 'example.com',
|
||||
params: [{ chainId: NON_INFURA_CHAIN_ID }],
|
||||
},
|
||||
{},
|
||||
jest.fn(),
|
||||
jest.fn(),
|
||||
{
|
||||
getCurrentChainId: () => CHAIN_IDS.MAINNET,
|
||||
findNetworkConfigurationBy: () => MOCK_MAINNET_CONFIGURATION,
|
||||
setProviderType: mockSetProviderType,
|
||||
setActiveNetwork: mockSetActiveNetwork,
|
||||
requestUserApproval: mockRequestUserApproval,
|
||||
},
|
||||
);
|
||||
expect(mockSetActiveNetwork).toHaveBeenCalledTimes(1);
|
||||
expect(mockSetActiveNetwork).toHaveBeenCalledWith(
|
||||
MOCK_MAINNET_CONFIGURATION.id,
|
||||
);
|
||||
});
|
||||
});
|
@ -1,6 +1,7 @@
|
||||
import * as Sentry from '@sentry/browser';
|
||||
import { Dedupe, ExtraErrorData } from '@sentry/integrations';
|
||||
|
||||
import { AllProperties } from '../../../shared/modules/object.utils';
|
||||
import { FilterEvents } from './sentry-filter-events';
|
||||
import extractEthjsErrorMessage from './extractEthjsErrorMessage';
|
||||
|
||||
@ -28,75 +29,254 @@ export const ERROR_URL_ALLOWLIST = {
|
||||
// debugging, and they do not contain any identifiable information.
|
||||
export const SENTRY_BACKGROUND_STATE = {
|
||||
AccountTracker: {
|
||||
accounts: false,
|
||||
currentBlockGasLimit: true,
|
||||
},
|
||||
AddressBookController: {
|
||||
addressBook: false,
|
||||
},
|
||||
AlertController: {
|
||||
alertEnabledness: true,
|
||||
unconnectedAccountAlertShownOrigins: false,
|
||||
web3ShimUsageOrigins: false,
|
||||
},
|
||||
AnnouncementController: {
|
||||
announcements: false,
|
||||
},
|
||||
AppMetadataController: {
|
||||
currentAppVersion: true,
|
||||
currentMigrationVersion: true,
|
||||
previousAppVersion: true,
|
||||
previousMigrationVersion: true,
|
||||
currentMigrationVersion: true,
|
||||
},
|
||||
ApprovalController: {
|
||||
approvalFlows: false,
|
||||
pendingApprovals: false,
|
||||
pendingApprovalCount: false,
|
||||
},
|
||||
AppStateController: {
|
||||
browserEnvironment: true,
|
||||
connectedStatusPopoverHasBeenShown: true,
|
||||
currentPopupId: false,
|
||||
defaultHomeActiveTabName: true,
|
||||
fullScreenGasPollTokens: true,
|
||||
hadAdvancedGasFeesSetPriorToMigration92_3: true,
|
||||
nftsDetectionNoticeDismissed: true,
|
||||
nftsDropdownState: true,
|
||||
notificationGasPollTokens: true,
|
||||
outdatedBrowserWarningLastShown: true,
|
||||
popupGasPollTokens: true,
|
||||
qrHardware: true,
|
||||
recoveryPhraseReminderHasBeenShown: true,
|
||||
recoveryPhraseReminderLastShown: true,
|
||||
serviceWorkerLastActiveTime: true,
|
||||
showBetaHeader: true,
|
||||
showProductTour: true,
|
||||
showTestnetMessageInDropdown: true,
|
||||
snapsInstallPrivacyWarningShown: true,
|
||||
termsOfUseLastAgreed: true,
|
||||
timeoutMinutes: true,
|
||||
trezorModel: true,
|
||||
usedNetworks: true,
|
||||
},
|
||||
CachedBalancesController: {
|
||||
cachedBalances: false,
|
||||
},
|
||||
CurrencyController: {
|
||||
conversionDate: true,
|
||||
conversionRate: true,
|
||||
currentCurrency: true,
|
||||
nativeCurrency: true,
|
||||
pendingCurrentCurrency: true,
|
||||
pendingNativeCurrency: true,
|
||||
usdConversionRate: true,
|
||||
},
|
||||
DecryptMessageController: {
|
||||
unapprovedDecryptMsgs: false,
|
||||
unapprovedDecryptMsgCount: true,
|
||||
},
|
||||
DesktopController: {
|
||||
desktopEnabled: true,
|
||||
},
|
||||
EncryptionPublicKeyController: {
|
||||
unapprovedEncryptionPublicKeyMsgs: false,
|
||||
unapprovedEncryptionPublicKeyMsgCount: true,
|
||||
},
|
||||
EnsController: {
|
||||
ensResolutionsByAddress: false,
|
||||
},
|
||||
GasFeeController: {
|
||||
estimatedGasFeeTimeBounds: true,
|
||||
gasEstimateType: true,
|
||||
gasFeeEstimates: true,
|
||||
},
|
||||
IncomingTransactionsController: {
|
||||
incomingTransactions: false,
|
||||
incomingTxLastFetchedBlockByChainId: true,
|
||||
},
|
||||
KeyringController: {
|
||||
encryptionKey: false,
|
||||
isUnlocked: true,
|
||||
keyrings: false,
|
||||
keyringTypes: false,
|
||||
},
|
||||
MetaMetricsController: {
|
||||
eventsBeforeMetricsOptIn: false,
|
||||
fragments: false,
|
||||
metaMetricsId: true,
|
||||
participateInMetaMetrics: true,
|
||||
previousUserTraits: false,
|
||||
segmentApiCalls: false,
|
||||
traits: false,
|
||||
},
|
||||
NetworkController: {
|
||||
networkConfigurations: false,
|
||||
networkDetails: false,
|
||||
networkId: true,
|
||||
networkStatus: true,
|
||||
providerConfig: {
|
||||
chainId: true,
|
||||
id: true,
|
||||
nickname: true,
|
||||
rpcPrefs: false,
|
||||
rpcUrl: false,
|
||||
ticker: true,
|
||||
type: true,
|
||||
},
|
||||
},
|
||||
NftController: {
|
||||
allNftContracts: false,
|
||||
allNfts: false,
|
||||
ignoredNfts: false,
|
||||
},
|
||||
OnboardingController: {
|
||||
completedOnboarding: true,
|
||||
firstTimeFlowType: true,
|
||||
onboardingTabs: false,
|
||||
seedPhraseBackedUp: true,
|
||||
},
|
||||
PermissionController: {
|
||||
subjects: false,
|
||||
},
|
||||
PermissionLogController: {
|
||||
permissionActivityLog: false,
|
||||
permissionHistory: false,
|
||||
},
|
||||
PhishingController: {},
|
||||
PreferencesController: {
|
||||
advancedGasFee: true,
|
||||
currentLocale: true,
|
||||
disabledRpcMethodPreferences: true,
|
||||
dismissSeedBackUpReminder: true,
|
||||
featureFlags: true,
|
||||
forgottenPassword: true,
|
||||
ipfsGateway: true,
|
||||
preferences: true,
|
||||
identities: false,
|
||||
infuraBlocked: true,
|
||||
ipfsGateway: false,
|
||||
isLineaMainnetReleased: true,
|
||||
knownMethodData: false,
|
||||
ledgerTransportType: true,
|
||||
lostIdentities: false,
|
||||
openSeaEnabled: true,
|
||||
preferences: {
|
||||
autoLockTimeLimit: true,
|
||||
hideZeroBalanceTokens: true,
|
||||
showFiatInTestnets: true,
|
||||
showTestNetworks: true,
|
||||
useNativeCurrencyAsPrimaryCurrency: true,
|
||||
},
|
||||
selectedAddress: false,
|
||||
snapRegistryList: false,
|
||||
theme: true,
|
||||
transactionSecurityCheckEnabled: true,
|
||||
useBlockie: true,
|
||||
useCurrencyRateCheck: true,
|
||||
useMultiAccountBalanceChecker: true,
|
||||
useNftDetection: true,
|
||||
useNonceField: true,
|
||||
usePhishDetect: true,
|
||||
useTokenDetection: true,
|
||||
},
|
||||
SignatureController: {
|
||||
unapprovedMsgCount: true,
|
||||
unapprovedMsgs: false,
|
||||
unapprovedPersonalMsgCount: true,
|
||||
unapprovedPersonalMsgs: false,
|
||||
unapprovedTypedMessages: false,
|
||||
unapprovedTypedMessagesCount: true,
|
||||
},
|
||||
SmartTransactionsController: {
|
||||
smartTransactionsState: {
|
||||
fees: {
|
||||
approvalTxFees: true,
|
||||
tradeTxFees: true,
|
||||
},
|
||||
liveness: true,
|
||||
smartTransactions: false,
|
||||
userOptIn: true,
|
||||
},
|
||||
},
|
||||
SubjectMetadataController: {
|
||||
subjectMetadata: false,
|
||||
},
|
||||
SwapsController: {
|
||||
swapsState: {
|
||||
approveTxId: false,
|
||||
customApproveTxData: false,
|
||||
customGasPrice: true,
|
||||
customMaxFeePerGas: true,
|
||||
customMaxGas: true,
|
||||
customMaxPriorityFeePerGas: true,
|
||||
errorKey: true,
|
||||
fetchParams: true,
|
||||
quotes: false,
|
||||
quotesLastFetched: true,
|
||||
quotesPollingLimitEnabled: true,
|
||||
routeState: true,
|
||||
saveFetchedQuotes: true,
|
||||
selectedAggId: true,
|
||||
swapsFeatureFlags: true,
|
||||
swapsFeatureIsLive: true,
|
||||
swapsQuotePrefetchingRefreshTime: true,
|
||||
swapsQuoteRefreshTime: true,
|
||||
swapsStxBatchStatusRefreshTime: true,
|
||||
swapsStxGetTransactionsRefreshTime: true,
|
||||
swapsStxMaxFeeMultiplier: true,
|
||||
swapsUserFeeLevel: true,
|
||||
tokens: false,
|
||||
topAggId: false,
|
||||
tradeTxId: false,
|
||||
},
|
||||
},
|
||||
TokenListController: {
|
||||
preventPollingOnNetworkRestart: true,
|
||||
tokenList: false,
|
||||
tokensChainsCache: {
|
||||
[AllProperties]: false,
|
||||
},
|
||||
},
|
||||
TokenRatesController: {
|
||||
contractExchangeRates: false,
|
||||
},
|
||||
TokensController: {
|
||||
allDetectedTokens: {
|
||||
[AllProperties]: false,
|
||||
},
|
||||
allIgnoredTokens: {
|
||||
[AllProperties]: false,
|
||||
},
|
||||
allTokens: {
|
||||
[AllProperties]: false,
|
||||
},
|
||||
detectedTokens: false,
|
||||
ignoredTokens: false,
|
||||
tokens: false,
|
||||
},
|
||||
TransactionController: {
|
||||
currentNetworkTxList: false,
|
||||
lastFetchedBlockNumbers: false,
|
||||
},
|
||||
TxController: {
|
||||
currentNetworkTxList: false,
|
||||
unapprovedTxs: false,
|
||||
},
|
||||
};
|
||||
|
||||
const flattenedBackgroundStateMask = Object.values(
|
||||
@ -121,7 +301,9 @@ export const SENTRY_UI_STATE = {
|
||||
// These properties are in the `metamask` slice but not in the background state
|
||||
customNonceValue: true,
|
||||
isAccountMenuOpen: true,
|
||||
isNetworkMenuOpen: true,
|
||||
nextNonce: true,
|
||||
pendingTokens: false,
|
||||
welcomeScreenSeen: true,
|
||||
},
|
||||
unconnectedAccount: true,
|
||||
|
@ -1447,6 +1447,7 @@ export default class MetamaskController extends EventEmitter {
|
||||
this.encryptionPublicKeyController.clearUnapproved();
|
||||
this.decryptMessageController.clearUnapproved();
|
||||
this.signatureController.clearUnapproved();
|
||||
this.approvalController.clear();
|
||||
},
|
||||
);
|
||||
|
||||
|
99
app/scripts/migrations/092.2.test.ts
Normal file
99
app/scripts/migrations/092.2.test.ts
Normal file
@ -0,0 +1,99 @@
|
||||
import { NetworkType, toHex } from '@metamask/controller-utils';
|
||||
import { NetworkStatus } from '@metamask/network-controller';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { version as currentStateVersion, migrate } from './092.2';
|
||||
|
||||
const TEST_NETWORK_CONTROLLER_STATE = {
|
||||
networkId: 'network-id',
|
||||
networkStatus: NetworkStatus.Available,
|
||||
providerConfig: {
|
||||
type: NetworkType.rpc,
|
||||
chainId: toHex(42),
|
||||
nickname: 'Funky Town Chain',
|
||||
ticker: 'ETH',
|
||||
id: 'test-network-client-id',
|
||||
},
|
||||
networkDetails: { EIPS: {} },
|
||||
networkConfigurations: {
|
||||
'network-configuration-id-1': {
|
||||
chainId: toHex(42),
|
||||
nickname: 'Localhost 8545',
|
||||
rpcPrefs: {},
|
||||
rpcUrl: 'http://localhost:8545',
|
||||
ticker: 'ETH',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const anyPreviousStateVersion = 91;
|
||||
|
||||
describe('migration #96', () => {
|
||||
afterEach(() => {
|
||||
jest.resetAllMocks();
|
||||
});
|
||||
|
||||
it('should update the state version number in the appropriate metadata field', async () => {
|
||||
const originalVersionedState = {
|
||||
meta: { version: anyPreviousStateVersion },
|
||||
data: {},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(cloneDeep(originalVersionedState));
|
||||
|
||||
expect(newStorage.meta).toStrictEqual({ version: currentStateVersion });
|
||||
});
|
||||
|
||||
it('should return state unaltered if there is no network controller state', async () => {
|
||||
const originalMetaMaskState = {
|
||||
anotherController: 'another-controller-state',
|
||||
};
|
||||
const originalVersionedState = {
|
||||
meta: { version: anyPreviousStateVersion },
|
||||
data: originalMetaMaskState,
|
||||
};
|
||||
|
||||
const updatedVersionedState = await migrate(
|
||||
cloneDeep(originalVersionedState),
|
||||
);
|
||||
expect(updatedVersionedState.data).toStrictEqual(originalMetaMaskState);
|
||||
});
|
||||
|
||||
it('should return unaltered state if there are no obsolete network controller state properties', async () => {
|
||||
const originalMetaMaskState = {
|
||||
anotherController: 'another-controller-state',
|
||||
NetworkController: TEST_NETWORK_CONTROLLER_STATE,
|
||||
};
|
||||
const originalVersionedState = {
|
||||
meta: { version: anyPreviousStateVersion },
|
||||
data: originalMetaMaskState,
|
||||
};
|
||||
|
||||
const updatedVersionedState = await migrate(
|
||||
cloneDeep(originalVersionedState),
|
||||
);
|
||||
expect(updatedVersionedState.data).toStrictEqual(originalMetaMaskState);
|
||||
});
|
||||
|
||||
it('should return updated state without obsolete network controller state properties', async () => {
|
||||
const originalMetaMaskState = {
|
||||
anotherController: 'another-controller-state',
|
||||
NetworkController: {
|
||||
...TEST_NETWORK_CONTROLLER_STATE,
|
||||
someSortOfRogueObsoleteStateProperty: 'exists',
|
||||
},
|
||||
};
|
||||
const originalVersionedState = {
|
||||
meta: { version: anyPreviousStateVersion },
|
||||
data: originalMetaMaskState,
|
||||
};
|
||||
|
||||
const updatedVersionedState = await migrate(
|
||||
cloneDeep(originalVersionedState),
|
||||
);
|
||||
expect(updatedVersionedState.data).not.toStrictEqual(originalMetaMaskState);
|
||||
expect(updatedVersionedState.data).toStrictEqual({
|
||||
anotherController: 'another-controller-state',
|
||||
NetworkController: TEST_NETWORK_CONTROLLER_STATE,
|
||||
});
|
||||
});
|
||||
});
|
75
app/scripts/migrations/092.2.ts
Normal file
75
app/scripts/migrations/092.2.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import { hasProperty } from '@metamask/utils';
|
||||
import { captureException } from '@sentry/browser';
|
||||
import { cloneDeep, isObject, pick } from 'lodash';
|
||||
|
||||
type MetaMaskState = Record<string, unknown>;
|
||||
type VersionedState = {
|
||||
meta: { version: number };
|
||||
data: MetaMaskState;
|
||||
};
|
||||
|
||||
export const version = 92.2;
|
||||
|
||||
/**
|
||||
* This migration removes obsolete NetworkController state properties.
|
||||
*
|
||||
* @param originalVersionedState - Versioned MetaMask extension state, exactly what we persist to dist.
|
||||
* @param originalVersionedState.meta - State metadata.
|
||||
* @param originalVersionedState.meta.version - The current state version.
|
||||
* @param originalVersionedState.data - The persisted MetaMask state, keyed by controller.
|
||||
* @returns Updated versioned of MetaMask extension state.
|
||||
*/
|
||||
export async function migrate(
|
||||
originalVersionedState: VersionedState,
|
||||
): Promise<VersionedState> {
|
||||
const updatedVersionedState = cloneDeep(originalVersionedState);
|
||||
|
||||
updatedVersionedState.meta.version = version;
|
||||
updatedVersionedState.data = transformState(updatedVersionedState.data);
|
||||
|
||||
return updatedVersionedState;
|
||||
}
|
||||
|
||||
function transformState(originalState: MetaMaskState): MetaMaskState {
|
||||
const updatedState =
|
||||
filterOutObsoleteNetworkControllerStateProperties(originalState);
|
||||
|
||||
return updatedState;
|
||||
}
|
||||
|
||||
function filterOutObsoleteNetworkControllerStateProperties(
|
||||
state: MetaMaskState,
|
||||
): MetaMaskState {
|
||||
// https://github.com/MetaMask/core/blob/%40metamask/network-controller%4010.3.1/packages/network-controller/src/NetworkController.ts#L336-L342
|
||||
const CURRENT_NETWORK_CONTROLLER_STATE_PROPS = [
|
||||
'networkId',
|
||||
'networkStatus',
|
||||
'providerConfig',
|
||||
'networkDetails',
|
||||
'networkConfigurations',
|
||||
];
|
||||
|
||||
if (
|
||||
!hasProperty(state, 'NetworkController') ||
|
||||
!isObject(state.NetworkController)
|
||||
) {
|
||||
captureException(
|
||||
`Migration ${version}: Invalid NetworkController state: ${typeof state.NetworkController}`,
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
const networkControllerState = state.NetworkController;
|
||||
|
||||
// delete network state properties that are not currently in use
|
||||
const updatedNetworkController = pick(
|
||||
networkControllerState,
|
||||
CURRENT_NETWORK_CONTROLLER_STATE_PROPS,
|
||||
);
|
||||
|
||||
return {
|
||||
...state,
|
||||
NetworkController: updatedNetworkController,
|
||||
};
|
||||
}
|
184
app/scripts/migrations/092.3.test.ts
Normal file
184
app/scripts/migrations/092.3.test.ts
Normal file
@ -0,0 +1,184 @@
|
||||
import { migrate } from './092.3';
|
||||
|
||||
const PREFERENCES_CONTROLLER_MOCK = {
|
||||
useBlockie: false,
|
||||
useNonceField: false,
|
||||
usePhishDetect: true,
|
||||
dismissSeedBackUpReminder: false,
|
||||
disabledRpcMethodPreferences: {
|
||||
eth_sign: false,
|
||||
},
|
||||
useMultiAccountBalanceChecker: true,
|
||||
useTokenDetection: false,
|
||||
useNftDetection: false,
|
||||
use4ByteResolution: true,
|
||||
useCurrencyRateCheck: true,
|
||||
openSeaEnabled: false,
|
||||
advancedGasFee: null,
|
||||
featureFlags: {
|
||||
showIncomingTransactions: true,
|
||||
},
|
||||
knownMethodData: {},
|
||||
currentLocale: 'EN',
|
||||
identities: {},
|
||||
lostIdentities: {},
|
||||
forgottenPassword: false,
|
||||
preferences: {
|
||||
autoLockTimeLimit: undefined,
|
||||
showFiatInTestnets: false,
|
||||
showTestNetworks: false,
|
||||
useNativeCurrencyAsPrimaryCurrency: true,
|
||||
hideZeroBalanceTokens: false,
|
||||
},
|
||||
// ENS decentralized website resolution
|
||||
ipfsGateway: '',
|
||||
useAddressBarEnsResolution: true,
|
||||
infuraBlocked: null,
|
||||
ledgerTransportType: 'U2F',
|
||||
snapRegistryList: {},
|
||||
transactionSecurityCheckEnabled: false,
|
||||
theme: 'OS',
|
||||
isLineaMainnetReleased: false,
|
||||
};
|
||||
|
||||
describe('migration #92.3', () => {
|
||||
it('updates the version metadata', async () => {
|
||||
const oldStorage = {
|
||||
meta: { version: 92.2 },
|
||||
data: {},
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
expect(newStorage.meta).toStrictEqual({ version: 92.3 });
|
||||
});
|
||||
|
||||
it('does nothing if no PreferencesController state', async () => {
|
||||
const oldData = {
|
||||
some: 'data',
|
||||
};
|
||||
|
||||
const oldStorage = {
|
||||
meta: { version: 92.2 },
|
||||
data: oldData,
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
expect(newStorage.data).toStrictEqual(oldData);
|
||||
});
|
||||
|
||||
it('does nothing if no AppStateController state', async () => {
|
||||
const oldData = {
|
||||
some: 'data',
|
||||
};
|
||||
|
||||
const oldStorage = {
|
||||
meta: { version: 92.2 },
|
||||
data: oldData,
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
expect(newStorage.data).toStrictEqual(oldData);
|
||||
});
|
||||
|
||||
it('changes advancedGasFee from null to an empty object, and sets hadAdvancedGasFeesSetPriorToMigration92_3 to false', async () => {
|
||||
const oldData = {
|
||||
some: 'data',
|
||||
PreferencesController: {
|
||||
...PREFERENCES_CONTROLLER_MOCK,
|
||||
},
|
||||
AppStateController: {},
|
||||
};
|
||||
|
||||
const oldStorage = {
|
||||
meta: { version: 92.2 },
|
||||
data: oldData,
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
expect(newStorage.data).toStrictEqual({
|
||||
some: oldData.some,
|
||||
PreferencesController: {
|
||||
...PREFERENCES_CONTROLLER_MOCK,
|
||||
advancedGasFee: {},
|
||||
},
|
||||
AppStateController: {
|
||||
hadAdvancedGasFeesSetPriorToMigration92_3: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('changes advancedGasFee from an object of values to an empty object and sets hadAdvancedGasFeesSetPriorToMigration92_3 to true', async () => {
|
||||
const oldData = {
|
||||
some: 'data',
|
||||
PreferencesController: {
|
||||
...PREFERENCES_CONTROLLER_MOCK,
|
||||
advancedGasFee: {
|
||||
priorityFee: '0x1',
|
||||
maxBaseFee: '0x1',
|
||||
},
|
||||
},
|
||||
AppStateController: {},
|
||||
};
|
||||
|
||||
const oldStorage = {
|
||||
meta: { version: 92.2 },
|
||||
data: oldData,
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
expect(newStorage.data).toStrictEqual({
|
||||
some: oldData.some,
|
||||
PreferencesController: {
|
||||
...PREFERENCES_CONTROLLER_MOCK,
|
||||
advancedGasFee: {},
|
||||
},
|
||||
AppStateController: {
|
||||
hadAdvancedGasFeesSetPriorToMigration92_3: true,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it('does not erase advancedGasFee if it does not contain the expected data prior to this migration', async () => {
|
||||
const oldData = {
|
||||
some: 'data',
|
||||
PreferencesController: {
|
||||
...PREFERENCES_CONTROLLER_MOCK,
|
||||
advancedGasFee: {
|
||||
'0x5': {
|
||||
priorityFee: '0x1',
|
||||
maxBaseFee: '0x1',
|
||||
},
|
||||
},
|
||||
},
|
||||
AppStateController: {},
|
||||
};
|
||||
|
||||
const oldStorage = {
|
||||
meta: { version: 92.2 },
|
||||
data: oldData,
|
||||
};
|
||||
|
||||
const newStorage = await migrate(oldStorage);
|
||||
|
||||
expect(newStorage.data).toStrictEqual({
|
||||
some: oldData.some,
|
||||
PreferencesController: {
|
||||
...PREFERENCES_CONTROLLER_MOCK,
|
||||
advancedGasFee: {
|
||||
'0x5': {
|
||||
priorityFee: '0x1',
|
||||
maxBaseFee: '0x1',
|
||||
},
|
||||
},
|
||||
},
|
||||
AppStateController: {
|
||||
hadAdvancedGasFeesSetPriorToMigration92_3: false,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
98
app/scripts/migrations/092.3.ts
Normal file
98
app/scripts/migrations/092.3.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import { hasProperty, isNullOrUndefined, isObject } from '@metamask/utils';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import log from 'loglevel';
|
||||
|
||||
type VersionedData = {
|
||||
meta: { version: number };
|
||||
data: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export const version = 92.3;
|
||||
|
||||
/**
|
||||
* This migration does the following:
|
||||
*
|
||||
* - Deletes currently stored advancedGasFee in preferences controller,
|
||||
* replacing the default with an empty object
|
||||
* - Sets hadAdvancedGasFeesSetPriorToMigration92_3 flag on AppStateController
|
||||
* to indicate if the user had previously had advancedGasFee set in their
|
||||
* preferences. This will be used to display a whats new entry to inform users
|
||||
* that we wiped these settings and made them apply per network.
|
||||
*
|
||||
* @param originalVersionedData - Versioned MetaMask extension state, exactly what we persist to dist.
|
||||
* @param originalVersionedData.meta - State metadata.
|
||||
* @param originalVersionedData.meta.version - The current state version.
|
||||
* @param originalVersionedData.data - The persisted MetaMask state, keyed by controller.
|
||||
* @returns Updated versioned MetaMask extension state.
|
||||
*/
|
||||
export async function migrate(
|
||||
originalVersionedData: VersionedData,
|
||||
): Promise<VersionedData> {
|
||||
const versionedData = cloneDeep(originalVersionedData);
|
||||
versionedData.meta.version = version;
|
||||
migrateData(versionedData.data);
|
||||
return versionedData;
|
||||
}
|
||||
|
||||
function migrateData(state: Record<string, unknown>): void {
|
||||
changeShapeAndRemoveOldAdvancedGasFeePreference(state);
|
||||
}
|
||||
|
||||
function changeShapeAndRemoveOldAdvancedGasFeePreference(
|
||||
state: Record<string, unknown>,
|
||||
) {
|
||||
if (isNullOrUndefined(state.PreferencesController)) {
|
||||
log.warn(
|
||||
`Migration #${version}: preferences controller null or undefined, skipping migration`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
hasProperty(state, 'AppStateController') &&
|
||||
isObject(state.AppStateController) &&
|
||||
hasProperty(state, 'PreferencesController') &&
|
||||
isObject(state.PreferencesController)
|
||||
) {
|
||||
const possibleOriginalValue = state.PreferencesController?.advancedGasFee;
|
||||
|
||||
// Will be false if the keys set on the object are anything other than the
|
||||
// maxBaseFee or priorityFee. Essentially if the object is already keyed
|
||||
// by chainId it won't show as hadFeesSet.
|
||||
const hadFeesSet =
|
||||
isObject(possibleOriginalValue) &&
|
||||
hasFeePreferenceKeys(possibleOriginalValue);
|
||||
|
||||
state.AppStateController.hadAdvancedGasFeesSetPriorToMigration92_3 =
|
||||
hadFeesSet;
|
||||
|
||||
if (
|
||||
state.PreferencesController.advancedGasFee === null ||
|
||||
(isObject(state.PreferencesController.advancedGasFee) &&
|
||||
hasFeePreferenceKeys(state.PreferencesController.advancedGasFee))
|
||||
) {
|
||||
state.PreferencesController.advancedGasFee = {};
|
||||
}
|
||||
} else if (isObject(state.AppStateController) === false) {
|
||||
global.sentry?.captureException?.(
|
||||
new Error(
|
||||
`typeof state.AppStateController is ${typeof state.AppStateController}`,
|
||||
),
|
||||
);
|
||||
} else if (isObject(state.PreferencesController) === false) {
|
||||
global.sentry?.captureException?.(
|
||||
new Error(
|
||||
`typeof state.PreferencesController is ${typeof state.PreferencesController}`,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function hasFeePreferenceKeys(objectToCheck: Record<string, unknown>): boolean {
|
||||
const keys = Object.keys(objectToCheck);
|
||||
|
||||
if (keys.includes('maxBaseFee') || keys.includes('priorityFee')) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
@ -97,6 +97,8 @@ import * as m090 from './090';
|
||||
import * as m091 from './091';
|
||||
import * as m092 from './092';
|
||||
import * as m092point1 from './092.1';
|
||||
import * as m092point2 from './092.2';
|
||||
import * as m092point3 from './092.3';
|
||||
|
||||
const migrations = [
|
||||
m002,
|
||||
@ -191,6 +193,8 @@ const migrations = [
|
||||
m091,
|
||||
m092,
|
||||
m092point1,
|
||||
m092point2,
|
||||
m092point3,
|
||||
];
|
||||
|
||||
export default migrations;
|
||||
|
@ -2205,7 +2205,9 @@
|
||||
"packages": {
|
||||
"@metamask/snaps-controllers-flask>concat-stream>readable-stream": true,
|
||||
"browserify>buffer": true,
|
||||
"pumpify>inherits": true
|
||||
"browserify>concat-stream>typedarray": true,
|
||||
"pumpify>inherits": true,
|
||||
"terser>source-map-support>buffer-from": true
|
||||
}
|
||||
},
|
||||
"@metamask/snaps-controllers-flask>concat-stream>readable-stream": {
|
||||
|
@ -2205,7 +2205,9 @@
|
||||
"packages": {
|
||||
"@metamask/snaps-controllers-flask>concat-stream>readable-stream": true,
|
||||
"browserify>buffer": true,
|
||||
"pumpify>inherits": true
|
||||
"browserify>concat-stream>typedarray": true,
|
||||
"pumpify>inherits": true,
|
||||
"terser>source-map-support>buffer-from": true
|
||||
}
|
||||
},
|
||||
"@metamask/snaps-controllers-flask>concat-stream>readable-stream": {
|
||||
|
@ -1752,20 +1752,7 @@
|
||||
"process.platform": true
|
||||
},
|
||||
"packages": {
|
||||
"browserify>browser-resolve>resolve": true
|
||||
}
|
||||
},
|
||||
"browserify>browser-resolve>resolve": {
|
||||
"builtin": {
|
||||
"fs.readFile": true,
|
||||
"fs.readFileSync": true,
|
||||
"fs.stat": true,
|
||||
"fs.statSync": true,
|
||||
"path": true
|
||||
},
|
||||
"globals": {
|
||||
"process.nextTick": true,
|
||||
"process.platform": true
|
||||
"brfs>resolve": true
|
||||
}
|
||||
},
|
||||
"browserify>cached-path-relative": {
|
||||
@ -1874,6 +1861,7 @@
|
||||
},
|
||||
"packages": {
|
||||
"brfs>resolve": true,
|
||||
"browserify>browser-resolve": true,
|
||||
"browserify>cached-path-relative": true,
|
||||
"browserify>concat-stream": true,
|
||||
"browserify>duplexer2": true,
|
||||
@ -1881,7 +1869,6 @@
|
||||
"browserify>module-deps>stream-combiner2": true,
|
||||
"browserify>module-deps>through2": true,
|
||||
"browserify>parents": true,
|
||||
"lavamoat-browserify>browser-resolve": true,
|
||||
"loose-envify": true,
|
||||
"pumpify>inherits": true,
|
||||
"readable-stream": true,
|
||||
@ -6149,8 +6136,8 @@
|
||||
},
|
||||
"packages": {
|
||||
"@lavamoat/lavapack": true,
|
||||
"browserify>browser-resolve": true,
|
||||
"duplexify": true,
|
||||
"lavamoat-browserify>browser-resolve": true,
|
||||
"lavamoat-browserify>concat-stream": true,
|
||||
"lavamoat-browserify>readable-stream": true,
|
||||
"lavamoat-browserify>through2": true,
|
||||
@ -6159,29 +6146,16 @@
|
||||
"lavamoat>lavamoat-core": true
|
||||
}
|
||||
},
|
||||
"lavamoat-browserify>browser-resolve": {
|
||||
"builtin": {
|
||||
"fs.readFile": true,
|
||||
"fs.readFileSync": true,
|
||||
"path": true
|
||||
},
|
||||
"globals": {
|
||||
"__dirname": true,
|
||||
"process.platform": true
|
||||
},
|
||||
"packages": {
|
||||
"brfs>resolve": true
|
||||
}
|
||||
},
|
||||
"lavamoat-browserify>concat-stream": {
|
||||
"globals": {
|
||||
"Buffer.concat": true,
|
||||
"Buffer.from": true,
|
||||
"Buffer.isBuffer": true
|
||||
},
|
||||
"packages": {
|
||||
"browserify>concat-stream>typedarray": true,
|
||||
"lavamoat-browserify>readable-stream": true,
|
||||
"pumpify>inherits": true
|
||||
"pumpify>inherits": true,
|
||||
"terser>source-map-support>buffer-from": true
|
||||
}
|
||||
},
|
||||
"lavamoat-browserify>readable-stream": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "metamask-crx",
|
||||
"version": "10.35.0",
|
||||
"version": "10.35.1",
|
||||
"private": true,
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -1,25 +1,43 @@
|
||||
/**
|
||||
* Return a "masked" copy of the given object.
|
||||
* This symbol matches all object properties when used in a mask
|
||||
*/
|
||||
export const AllProperties = Symbol('*');
|
||||
|
||||
/**
|
||||
* Return a "masked" copy of the given object. The returned object includes
|
||||
* only the properties present in the mask.
|
||||
*
|
||||
* The returned object includes only the properties present in the mask. The
|
||||
* mask is an object that mirrors the structure of the given object, except
|
||||
* the only values are `true` or a sub-mask. `true` implies the property
|
||||
* should be included, and a sub-mask implies the property should be further
|
||||
* masked according to that sub-mask.
|
||||
* The mask is an object that mirrors the structure of the given object, except
|
||||
* the only values are `true`, `false, a sub-mask, or the 'AllProperties"
|
||||
* symbol. `true` implies the property should be included, and `false` will
|
||||
* exclude it. A sub-mask implies the property should be further masked
|
||||
* according to that sub-mask. The "AllProperties" symbol is used for objects
|
||||
* with dynamic keys, and applies a rule (either `true`, `false`, or a
|
||||
* sub-mask`) to every property in that object.
|
||||
*
|
||||
* If a property is not found in the last, its type is included instead.
|
||||
* If a property is excluded, its type is included instead.
|
||||
*
|
||||
* @param {object} object - The object to mask
|
||||
* @param {Object<object | boolean>} mask - The mask to apply to the object
|
||||
*/
|
||||
export function maskObject(object, mask) {
|
||||
let maskAllProperties = false;
|
||||
if (Object.keys(mask).includes(AllProperties)) {
|
||||
if (Object.keys(mask).length > 1) {
|
||||
throw new Error('AllProperties mask key does not support sibling keys');
|
||||
}
|
||||
maskAllProperties = true;
|
||||
}
|
||||
return Object.keys(object).reduce((state, key) => {
|
||||
if (mask[key] === true) {
|
||||
const maskKey = maskAllProperties ? mask[AllProperties] : mask[key];
|
||||
if (maskKey === true) {
|
||||
state[key] = object[key];
|
||||
} else if (mask[key]) {
|
||||
state[key] = maskObject(object[key], mask[key]);
|
||||
} else {
|
||||
} else if (maskKey && typeof maskKey === 'object') {
|
||||
state[key] = maskObject(object[key], maskKey);
|
||||
} else if (maskKey === undefined || maskKey === false) {
|
||||
state[key] = typeof object[key];
|
||||
} else {
|
||||
throw new Error(`Unsupported mask entry: ${maskKey}`);
|
||||
}
|
||||
return state;
|
||||
}, {});
|
||||
|
@ -121,6 +121,10 @@ export const UI_NOTIFICATIONS = {
|
||||
src: 'images/global-menu-block-explorer.svg',
|
||||
},
|
||||
},
|
||||
24: {
|
||||
id: 24,
|
||||
date: null,
|
||||
},
|
||||
};
|
||||
|
||||
export const getTranslatedUINotifications = (t, locale) => {
|
||||
@ -331,5 +335,16 @@ export const getTranslatedUINotifications = (t, locale) => {
|
||||
)
|
||||
: '',
|
||||
},
|
||||
24: {
|
||||
...UI_NOTIFICATIONS[24],
|
||||
title: t('notifications24Title'),
|
||||
description: t('notifications24Description'),
|
||||
actionText: t('notifications24ActionText'),
|
||||
date: UI_NOTIFICATIONS[24].date
|
||||
? new Intl.DateTimeFormat(formattedLocale).format(
|
||||
new Date(UI_NOTIFICATIONS[24].date),
|
||||
)
|
||||
: '',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
@ -113,6 +113,7 @@
|
||||
"networkStatus": "available",
|
||||
"providerConfig": {
|
||||
"type": "rpc",
|
||||
"nickname": "goerli",
|
||||
"chainId": "0x5",
|
||||
"ticker": "ETH",
|
||||
"id": "chain5"
|
||||
@ -339,8 +340,10 @@
|
||||
"useTokenDetection": true,
|
||||
"useCurrencyRateCheck": true,
|
||||
"advancedGasFee": {
|
||||
"maxBaseFee": "75",
|
||||
"priorityFee": "2"
|
||||
"0x5": {
|
||||
"maxBaseFee": "75",
|
||||
"priorityFee": "2"
|
||||
}
|
||||
},
|
||||
"nftsDropdownState": {
|
||||
"0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc": {
|
||||
|
@ -4,15 +4,38 @@ const { strict: assert } = require('assert');
|
||||
const { get, has, set, unset } = require('lodash');
|
||||
const { Browser } = require('selenium-webdriver');
|
||||
const { format } = require('prettier');
|
||||
const { convertToHexValue, withFixtures } = require('../helpers');
|
||||
const { isObject } = require('@metamask/utils');
|
||||
const { SENTRY_UI_STATE } = require('../../../app/scripts/lib/setupSentry');
|
||||
const FixtureBuilder = require('../fixture-builder');
|
||||
const { convertToHexValue, withFixtures } = require('../helpers');
|
||||
|
||||
/**
|
||||
* Derive a UI state field from a background state field.
|
||||
*
|
||||
* @param {string} backgroundField - The path of a background field.
|
||||
* @returns {string} The path for the corresponding UI field.
|
||||
*/
|
||||
function backgroundToUiField(backgroundField) {
|
||||
// The controller name is lost in the UI due to state flattening
|
||||
const [, ...rest] = backgroundField.split('.');
|
||||
const flattenedBackgroundField = rest.join('.');
|
||||
// Controller state is under the 'metamask' slice in the UI
|
||||
return `metamask.${flattenedBackgroundField}`;
|
||||
}
|
||||
|
||||
const maskedBackgroundFields = [
|
||||
'CurrencyController.conversionDate', // This is a timestamp that changes each run
|
||||
// App metadata is masked so that we don't have to update the snapshot as
|
||||
// part of the release process
|
||||
'AppMetadataController.currentAppVersion',
|
||||
'AppMetadataController.currentMigrationVersion',
|
||||
'AppStateController.browserEnvironment.browser',
|
||||
'AppStateController.browserEnvironment.os',
|
||||
'AppStateController.outdatedBrowserWarningLastShown',
|
||||
'AppStateController.recoveryPhraseReminderLastShown',
|
||||
'AppStateController.termsOfUseLastAgreed',
|
||||
];
|
||||
const maskedUiFields = [
|
||||
'metamask.conversionDate', // This is a timestamp that changes each run
|
||||
];
|
||||
const maskedUiFields = maskedBackgroundFields.map(backgroundToUiField);
|
||||
|
||||
const removedBackgroundFields = [
|
||||
// This property is timing-dependent
|
||||
@ -22,13 +45,7 @@ const removedBackgroundFields = [
|
||||
'AppStateController.timeoutMinutes',
|
||||
];
|
||||
|
||||
const removedUiFields = [
|
||||
// This property is timing-dependent
|
||||
'metamask.currentBlockGasLimit',
|
||||
// These properties are set to undefined, causing inconsistencies between Chrome and Firefox
|
||||
'metamask.currentPopupId',
|
||||
'metamask.timeoutMinutes',
|
||||
];
|
||||
const removedUiFields = removedBackgroundFields.map(backgroundToUiField);
|
||||
|
||||
/**
|
||||
* Transform background state to make it consistent between test runs.
|
||||
@ -107,6 +124,38 @@ async function matchesSnapshot({
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object consisting of all properties in the complete
|
||||
* object that are missing from the given object.
|
||||
*
|
||||
* @param {object} complete - The complete object to compare to.
|
||||
* @param {object} object - The object to test for missing properties.
|
||||
*/
|
||||
function getMissingProperties(complete, object) {
|
||||
const missing = {};
|
||||
for (const [key, value] of Object.entries(complete)) {
|
||||
if (key in object) {
|
||||
if (isObject(value) && isObject(object[key])) {
|
||||
const missingNestedProperties = getMissingProperties(
|
||||
value,
|
||||
object[key],
|
||||
);
|
||||
if (Object.keys(missingNestedProperties).length > 0) {
|
||||
missing[key] = missingNestedProperties;
|
||||
} else {
|
||||
// no missing nested properties
|
||||
}
|
||||
} else {
|
||||
// Skip non-object values, they are considered as present
|
||||
// even if they represent masked data structures
|
||||
}
|
||||
} else {
|
||||
missing[key] = value;
|
||||
}
|
||||
}
|
||||
return missing;
|
||||
}
|
||||
|
||||
describe('Sentry errors', function () {
|
||||
const migrationError =
|
||||
process.env.SELENIUM_BROWSER === Browser.CHROME
|
||||
@ -312,7 +361,10 @@ describe('Sentry errors', function () {
|
||||
'Invalid version state',
|
||||
);
|
||||
await matchesSnapshot({
|
||||
data: transformBackgroundState(appState.persistedState),
|
||||
data: {
|
||||
...appState.persistedState,
|
||||
data: transformBackgroundState(appState.persistedState.data),
|
||||
},
|
||||
snapshot: 'errors-before-init-opt-in-background-state',
|
||||
});
|
||||
},
|
||||
@ -460,7 +512,10 @@ describe('Sentry errors', function () {
|
||||
'Invalid version state',
|
||||
);
|
||||
await matchesSnapshot({
|
||||
data: transformBackgroundState(appState.persistedState),
|
||||
data: {
|
||||
...appState.persistedState,
|
||||
data: transformBackgroundState(appState.persistedState.data),
|
||||
},
|
||||
snapshot: 'errors-before-init-opt-in-ui-state',
|
||||
});
|
||||
},
|
||||
@ -728,4 +783,80 @@ describe('Sentry errors', function () {
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('should have no policy gaps for UI controller state', async function () {
|
||||
await withFixtures(
|
||||
{
|
||||
fixtures: new FixtureBuilder().build(),
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
},
|
||||
async ({ driver }) => {
|
||||
await driver.navigate();
|
||||
await driver.findElement('#password');
|
||||
|
||||
const fullUiState = await driver.executeScript(() =>
|
||||
window.stateHooks?.getCleanAppState?.(),
|
||||
);
|
||||
|
||||
const missingState = getMissingProperties(
|
||||
fullUiState.metamask,
|
||||
SENTRY_UI_STATE.metamask,
|
||||
);
|
||||
assert.deepEqual(missingState, {});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it('should not have extra properties in UI state mask', async function () {
|
||||
const expectedMissingState = {
|
||||
currentPopupId: false, // Initialized as undefined
|
||||
// Part of transaction controller store, but missing from the initial
|
||||
// state
|
||||
lastFetchedBlockNumbers: false,
|
||||
preferences: {
|
||||
autoLockTimeLimit: true, // Initialized as undefined
|
||||
},
|
||||
smartTransactionsState: {
|
||||
fees: {
|
||||
approvalTxFees: true, // Initialized as undefined
|
||||
tradeTxFees: true, // Initialized as undefined
|
||||
},
|
||||
userOptIn: true, // Initialized as undefined
|
||||
},
|
||||
swapsState: {
|
||||
// This can get wiped out during initialization due to a bug in
|
||||
// the "resetState" method
|
||||
swapsFeatureFlags: true,
|
||||
},
|
||||
// This can get erased due to a bug in the app state controller's
|
||||
// preferences state change handler
|
||||
timeoutMinutes: true,
|
||||
};
|
||||
await withFixtures(
|
||||
{
|
||||
fixtures: new FixtureBuilder().build(),
|
||||
ganacheOptions,
|
||||
title: this.test.title,
|
||||
},
|
||||
async ({ driver }) => {
|
||||
await driver.navigate();
|
||||
await driver.findElement('#password');
|
||||
|
||||
const fullUiState = await driver.executeScript(() =>
|
||||
window.stateHooks?.getCleanAppState?.(),
|
||||
);
|
||||
|
||||
const extraMaskProperties = getMissingProperties(
|
||||
SENTRY_UI_STATE.metamask,
|
||||
fullUiState.metamask,
|
||||
);
|
||||
const unexpectedExtraMaskProperties = getMissingProperties(
|
||||
extraMaskProperties,
|
||||
expectedMissingState,
|
||||
);
|
||||
assert.deepEqual(unexpectedExtraMaskProperties, {});
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -1,51 +1,56 @@
|
||||
{
|
||||
"AccountTracker": { "accounts": "object" },
|
||||
"AddressBookController": "object",
|
||||
"AddressBookController": { "addressBook": "object" },
|
||||
"AlertController": {
|
||||
"alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true },
|
||||
"unconnectedAccountAlertShownOrigins": "object",
|
||||
"web3ShimUsageOrigins": "object"
|
||||
},
|
||||
"AnnouncementController": "object",
|
||||
"AnnouncementController": { "announcements": "object" },
|
||||
"AppMetadataController": {
|
||||
"currentAppVersion": "10.35.0",
|
||||
"currentAppVersion": "string",
|
||||
"previousAppVersion": "",
|
||||
"previousMigrationVersion": 0,
|
||||
"currentMigrationVersion": 92.1
|
||||
"currentMigrationVersion": "number"
|
||||
},
|
||||
"AppStateController": {
|
||||
"connectedStatusPopoverHasBeenShown": true,
|
||||
"defaultHomeActiveTabName": null,
|
||||
"browserEnvironment": "object",
|
||||
"popupGasPollTokens": "object",
|
||||
"notificationGasPollTokens": "object",
|
||||
"fullScreenGasPollTokens": "object",
|
||||
"recoveryPhraseReminderHasBeenShown": "boolean",
|
||||
"browserEnvironment": { "os": "string", "browser": "string" },
|
||||
"popupGasPollTokens": [],
|
||||
"notificationGasPollTokens": [],
|
||||
"fullScreenGasPollTokens": [],
|
||||
"recoveryPhraseReminderHasBeenShown": true,
|
||||
"recoveryPhraseReminderLastShown": "number",
|
||||
"outdatedBrowserWarningLastShown": "number",
|
||||
"nftsDetectionNoticeDismissed": "boolean",
|
||||
"showTestnetMessageInDropdown": "boolean",
|
||||
"showBetaHeader": "boolean",
|
||||
"showProductTour": "boolean",
|
||||
"trezorModel": "object",
|
||||
"nftsDropdownState": "object",
|
||||
"nftsDetectionNoticeDismissed": false,
|
||||
"showTestnetMessageInDropdown": true,
|
||||
"showBetaHeader": false,
|
||||
"showProductTour": true,
|
||||
"trezorModel": null,
|
||||
"hadAdvancedGasFeesSetPriorToMigration92_3": false,
|
||||
"nftsDropdownState": {},
|
||||
"termsOfUseLastAgreed": "number",
|
||||
"qrHardware": "object",
|
||||
"usedNetworks": "object",
|
||||
"snapsInstallPrivacyWarningShown": "boolean",
|
||||
"serviceWorkerLastActiveTime": "number"
|
||||
"qrHardware": {},
|
||||
"usedNetworks": { "0x1": true, "0x5": true, "0x539": true },
|
||||
"snapsInstallPrivacyWarningShown": true,
|
||||
"serviceWorkerLastActiveTime": 0
|
||||
},
|
||||
"ApprovalController": {
|
||||
"pendingApprovals": "object",
|
||||
"pendingApprovalCount": "number",
|
||||
"approvalFlows": "object"
|
||||
},
|
||||
"ApprovalController": "object",
|
||||
"BackupController": "undefined",
|
||||
"CachedBalancesController": "object",
|
||||
"CachedBalancesController": { "cachedBalances": "object" },
|
||||
"CurrencyController": {
|
||||
"conversionDate": "number",
|
||||
"conversionRate": 1700,
|
||||
"nativeCurrency": "ETH",
|
||||
"currentCurrency": "usd",
|
||||
"pendingCurrentCurrency": "object",
|
||||
"pendingNativeCurrency": "object",
|
||||
"usdConversionRate": "number"
|
||||
"pendingCurrentCurrency": null,
|
||||
"pendingNativeCurrency": null,
|
||||
"usdConversionRate": 1700
|
||||
},
|
||||
"DecryptMessageController": {
|
||||
"unapprovedDecryptMsgs": "object",
|
||||
@ -55,8 +60,12 @@
|
||||
"unapprovedEncryptionPublicKeyMsgs": "object",
|
||||
"unapprovedEncryptionPublicKeyMsgCount": 0
|
||||
},
|
||||
"EnsController": "object",
|
||||
"GasFeeController": "object",
|
||||
"EnsController": { "ensResolutionsByAddress": "object" },
|
||||
"GasFeeController": {
|
||||
"gasFeeEstimates": {},
|
||||
"estimatedGasFeeTimeBounds": {},
|
||||
"gasEstimateType": "none"
|
||||
},
|
||||
"IncomingTransactionsController": {
|
||||
"incomingTransactions": "object",
|
||||
"incomingTxLastFetchedBlockByChainId": {
|
||||
@ -86,38 +95,45 @@
|
||||
"networkId": "1337",
|
||||
"networkStatus": "available",
|
||||
"providerConfig": {
|
||||
"chainId": "string",
|
||||
"chainId": "0x539",
|
||||
"nickname": "Localhost 8545",
|
||||
"rpcPrefs": "object",
|
||||
"rpcUrl": "string",
|
||||
"ticker": "ETH",
|
||||
"type": "rpc",
|
||||
"id": "string"
|
||||
"id": "networkConfigurationId"
|
||||
},
|
||||
"networkDetails": "object",
|
||||
"networkConfigurations": "object"
|
||||
},
|
||||
"NftController": "object",
|
||||
"NftController": {
|
||||
"allNftContracts": "object",
|
||||
"allNfts": "object",
|
||||
"ignoredNfts": "object"
|
||||
},
|
||||
"OnboardingController": {
|
||||
"seedPhraseBackedUp": true,
|
||||
"firstTimeFlowType": "import",
|
||||
"completedOnboarding": true,
|
||||
"onboardingTabs": "object"
|
||||
},
|
||||
"PermissionController": "object",
|
||||
"PermissionLogController": "object",
|
||||
"PermissionController": { "subjects": "object" },
|
||||
"PermissionLogController": {
|
||||
"permissionHistory": "object",
|
||||
"permissionActivityLog": "object"
|
||||
},
|
||||
"PreferencesController": {
|
||||
"useBlockie": false,
|
||||
"useNonceField": false,
|
||||
"usePhishDetect": true,
|
||||
"dismissSeedBackUpReminder": "boolean",
|
||||
"disabledRpcMethodPreferences": "object",
|
||||
"useMultiAccountBalanceChecker": "boolean",
|
||||
"useTokenDetection": "boolean",
|
||||
"useNftDetection": "boolean",
|
||||
"useCurrencyRateCheck": "boolean",
|
||||
"openSeaEnabled": "boolean",
|
||||
"advancedGasFee": "object",
|
||||
"dismissSeedBackUpReminder": true,
|
||||
"disabledRpcMethodPreferences": { "eth_sign": false },
|
||||
"useMultiAccountBalanceChecker": true,
|
||||
"useTokenDetection": false,
|
||||
"useNftDetection": false,
|
||||
"useCurrencyRateCheck": true,
|
||||
"openSeaEnabled": false,
|
||||
"advancedGasFee": {},
|
||||
"featureFlags": { "showIncomingTransactions": true },
|
||||
"knownMethodData": "object",
|
||||
"currentLocale": "en",
|
||||
@ -130,13 +146,13 @@
|
||||
"showTestNetworks": false,
|
||||
"useNativeCurrencyAsPrimaryCurrency": true
|
||||
},
|
||||
"ipfsGateway": "dweb.link",
|
||||
"infuraBlocked": "boolean",
|
||||
"ledgerTransportType": "string",
|
||||
"ipfsGateway": "string",
|
||||
"infuraBlocked": false,
|
||||
"ledgerTransportType": "webhid",
|
||||
"snapRegistryList": "object",
|
||||
"transactionSecurityCheckEnabled": "boolean",
|
||||
"theme": "string",
|
||||
"isLineaMainnetReleased": "boolean",
|
||||
"transactionSecurityCheckEnabled": false,
|
||||
"theme": "light",
|
||||
"isLineaMainnetReleased": true,
|
||||
"selectedAddress": "string"
|
||||
},
|
||||
"SignatureController": {
|
||||
@ -147,11 +163,58 @@
|
||||
"unapprovedPersonalMsgCount": 0,
|
||||
"unapprovedTypedMessagesCount": 0
|
||||
},
|
||||
"SmartTransactionsController": "object",
|
||||
"SubjectMetadataController": "object",
|
||||
"SwapsController": "object",
|
||||
"TokenListController": "object",
|
||||
"TokenRatesController": "object",
|
||||
"TokensController": "object",
|
||||
"TxController": "object"
|
||||
"SmartTransactionsController": {
|
||||
"smartTransactionsState": {
|
||||
"fees": {},
|
||||
"liveness": true,
|
||||
"smartTransactions": "object"
|
||||
}
|
||||
},
|
||||
"SubjectMetadataController": { "subjectMetadata": "object" },
|
||||
"SwapsController": {
|
||||
"swapsState": {
|
||||
"quotes": "object",
|
||||
"quotesPollingLimitEnabled": false,
|
||||
"fetchParams": null,
|
||||
"tokens": "object",
|
||||
"tradeTxId": "object",
|
||||
"approveTxId": "object",
|
||||
"quotesLastFetched": null,
|
||||
"customMaxGas": "",
|
||||
"customGasPrice": null,
|
||||
"customMaxFeePerGas": null,
|
||||
"customMaxPriorityFeePerGas": null,
|
||||
"swapsUserFeeLevel": "",
|
||||
"selectedAggId": null,
|
||||
"customApproveTxData": "string",
|
||||
"errorKey": "",
|
||||
"topAggId": "object",
|
||||
"routeState": "",
|
||||
"swapsFeatureIsLive": true,
|
||||
"saveFetchedQuotes": false,
|
||||
"swapsQuoteRefreshTime": 60000,
|
||||
"swapsQuotePrefetchingRefreshTime": 60000,
|
||||
"swapsStxBatchStatusRefreshTime": 10000,
|
||||
"swapsStxGetTransactionsRefreshTime": 10000,
|
||||
"swapsStxMaxFeeMultiplier": 2
|
||||
}
|
||||
},
|
||||
"TokenListController": {
|
||||
"tokenList": "object",
|
||||
"tokensChainsCache": {},
|
||||
"preventPollingOnNetworkRestart": true
|
||||
},
|
||||
"TokenRatesController": { "contractExchangeRates": "object" },
|
||||
"TokensController": {
|
||||
"tokens": "object",
|
||||
"ignoredTokens": "object",
|
||||
"detectedTokens": "object",
|
||||
"allTokens": {},
|
||||
"allIgnoredTokens": {},
|
||||
"allDetectedTokens": {}
|
||||
},
|
||||
"TxController": {
|
||||
"unapprovedTxs": "object",
|
||||
"currentNetworkTxList": "object"
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
"isInitialized": true,
|
||||
"isUnlocked": false,
|
||||
"isAccountMenuOpen": false,
|
||||
"isNetworkMenuOpen": "boolean",
|
||||
"isNetworkMenuOpen": false,
|
||||
"identities": "object",
|
||||
"unapprovedTxs": "object",
|
||||
"networkConfigurations": "object",
|
||||
@ -38,38 +38,39 @@
|
||||
"nativeCurrency": "ETH",
|
||||
"connectedStatusPopoverHasBeenShown": true,
|
||||
"defaultHomeActiveTabName": null,
|
||||
"browserEnvironment": "object",
|
||||
"popupGasPollTokens": "object",
|
||||
"notificationGasPollTokens": "object",
|
||||
"fullScreenGasPollTokens": "object",
|
||||
"recoveryPhraseReminderHasBeenShown": "boolean",
|
||||
"browserEnvironment": { "os": "string", "browser": "string" },
|
||||
"popupGasPollTokens": [],
|
||||
"notificationGasPollTokens": [],
|
||||
"fullScreenGasPollTokens": [],
|
||||
"recoveryPhraseReminderHasBeenShown": true,
|
||||
"recoveryPhraseReminderLastShown": "number",
|
||||
"outdatedBrowserWarningLastShown": "number",
|
||||
"nftsDetectionNoticeDismissed": "boolean",
|
||||
"showTestnetMessageInDropdown": "boolean",
|
||||
"showBetaHeader": "boolean",
|
||||
"showProductTour": "boolean",
|
||||
"trezorModel": "object",
|
||||
"nftsDropdownState": "object",
|
||||
"nftsDetectionNoticeDismissed": false,
|
||||
"showTestnetMessageInDropdown": true,
|
||||
"showBetaHeader": false,
|
||||
"showProductTour": true,
|
||||
"trezorModel": null,
|
||||
"hadAdvancedGasFeesSetPriorToMigration92_3": false,
|
||||
"nftsDropdownState": {},
|
||||
"termsOfUseLastAgreed": "number",
|
||||
"qrHardware": "object",
|
||||
"usedNetworks": "object",
|
||||
"snapsInstallPrivacyWarningShown": "boolean",
|
||||
"serviceWorkerLastActiveTime": "number",
|
||||
"currentAppVersion": "10.35.0",
|
||||
"qrHardware": {},
|
||||
"usedNetworks": { "0x1": true, "0x5": true, "0x539": true },
|
||||
"snapsInstallPrivacyWarningShown": true,
|
||||
"serviceWorkerLastActiveTime": 0,
|
||||
"currentAppVersion": "string",
|
||||
"previousAppVersion": "",
|
||||
"previousMigrationVersion": 0,
|
||||
"currentMigrationVersion": 92.1,
|
||||
"currentMigrationVersion": "number",
|
||||
"networkId": "1337",
|
||||
"networkStatus": "available",
|
||||
"providerConfig": {
|
||||
"chainId": "string",
|
||||
"chainId": "0x539",
|
||||
"nickname": "Localhost 8545",
|
||||
"rpcPrefs": "object",
|
||||
"rpcUrl": "string",
|
||||
"ticker": "ETH",
|
||||
"type": "rpc",
|
||||
"id": "string"
|
||||
"id": "networkConfigurationId"
|
||||
},
|
||||
"networkDetails": "object",
|
||||
"cachedBalances": "object",
|
||||
@ -78,23 +79,23 @@
|
||||
"encryptionKey": "object",
|
||||
"useNonceField": false,
|
||||
"usePhishDetect": true,
|
||||
"dismissSeedBackUpReminder": "boolean",
|
||||
"disabledRpcMethodPreferences": "object",
|
||||
"useMultiAccountBalanceChecker": "boolean",
|
||||
"useTokenDetection": "boolean",
|
||||
"useNftDetection": "boolean",
|
||||
"useCurrencyRateCheck": "boolean",
|
||||
"openSeaEnabled": "boolean",
|
||||
"advancedGasFee": "object",
|
||||
"dismissSeedBackUpReminder": true,
|
||||
"disabledRpcMethodPreferences": { "eth_sign": false },
|
||||
"useMultiAccountBalanceChecker": true,
|
||||
"useTokenDetection": false,
|
||||
"useNftDetection": false,
|
||||
"useCurrencyRateCheck": true,
|
||||
"openSeaEnabled": false,
|
||||
"advancedGasFee": {},
|
||||
"lostIdentities": "object",
|
||||
"forgottenPassword": false,
|
||||
"ipfsGateway": "dweb.link",
|
||||
"infuraBlocked": "boolean",
|
||||
"ledgerTransportType": "string",
|
||||
"ipfsGateway": "string",
|
||||
"infuraBlocked": false,
|
||||
"ledgerTransportType": "webhid",
|
||||
"snapRegistryList": "object",
|
||||
"transactionSecurityCheckEnabled": "boolean",
|
||||
"theme": "string",
|
||||
"isLineaMainnetReleased": "boolean",
|
||||
"transactionSecurityCheckEnabled": false,
|
||||
"theme": "light",
|
||||
"isLineaMainnetReleased": true,
|
||||
"selectedAddress": "string",
|
||||
"metaMetricsId": "fake-metrics-id",
|
||||
"eventsBeforeMetricsOptIn": "object",
|
||||
@ -104,9 +105,9 @@
|
||||
"previousUserTraits": "object",
|
||||
"conversionDate": "number",
|
||||
"currentCurrency": "usd",
|
||||
"pendingCurrentCurrency": "object",
|
||||
"pendingNativeCurrency": "object",
|
||||
"usdConversionRate": "number",
|
||||
"pendingCurrentCurrency": null,
|
||||
"pendingNativeCurrency": null,
|
||||
"usdConversionRate": 1300,
|
||||
"alertEnabledness": { "unconnectedAccount": true, "web3ShimUsage": true },
|
||||
"unconnectedAccountAlertShownOrigins": "object",
|
||||
"web3ShimUsageOrigins": "object",
|
||||
@ -125,19 +126,23 @@
|
||||
"permissionActivityLog": "object",
|
||||
"subjectMetadata": "object",
|
||||
"announcements": "object",
|
||||
"gasFeeEstimates": "object",
|
||||
"estimatedGasFeeTimeBounds": "object",
|
||||
"gasEstimateType": "string",
|
||||
"gasFeeEstimates": {},
|
||||
"estimatedGasFeeTimeBounds": {},
|
||||
"gasEstimateType": "none",
|
||||
"tokenList": "object",
|
||||
"tokensChainsCache": "object",
|
||||
"preventPollingOnNetworkRestart": "boolean",
|
||||
"tokensChainsCache": {},
|
||||
"preventPollingOnNetworkRestart": true,
|
||||
"tokens": "object",
|
||||
"ignoredTokens": "object",
|
||||
"detectedTokens": "object",
|
||||
"allTokens": "object",
|
||||
"allIgnoredTokens": "object",
|
||||
"allDetectedTokens": "object",
|
||||
"smartTransactionsState": "object",
|
||||
"allTokens": {},
|
||||
"allIgnoredTokens": {},
|
||||
"allDetectedTokens": {},
|
||||
"smartTransactionsState": {
|
||||
"fees": {},
|
||||
"liveness": true,
|
||||
"smartTransactions": "object"
|
||||
},
|
||||
"allNftContracts": "object",
|
||||
"allNfts": "object",
|
||||
"ignoredNfts": "object",
|
||||
@ -153,7 +158,32 @@
|
||||
"unapprovedMsgCount": 0,
|
||||
"unapprovedPersonalMsgCount": 0,
|
||||
"unapprovedTypedMessagesCount": 0,
|
||||
"swapsState": "object",
|
||||
"swapsState": {
|
||||
"quotes": "object",
|
||||
"quotesPollingLimitEnabled": false,
|
||||
"fetchParams": null,
|
||||
"tokens": "object",
|
||||
"tradeTxId": "object",
|
||||
"approveTxId": "object",
|
||||
"quotesLastFetched": null,
|
||||
"customMaxGas": "",
|
||||
"customGasPrice": null,
|
||||
"customMaxFeePerGas": null,
|
||||
"customMaxPriorityFeePerGas": null,
|
||||
"swapsUserFeeLevel": "",
|
||||
"selectedAggId": null,
|
||||
"customApproveTxData": "string",
|
||||
"errorKey": "",
|
||||
"topAggId": "object",
|
||||
"routeState": "",
|
||||
"swapsFeatureIsLive": true,
|
||||
"saveFetchedQuotes": false,
|
||||
"swapsQuoteRefreshTime": 60000,
|
||||
"swapsQuotePrefetchingRefreshTime": 60000,
|
||||
"swapsStxBatchStatusRefreshTime": 10000,
|
||||
"swapsStxGetTransactionsRefreshTime": 10000,
|
||||
"swapsStxMaxFeeMultiplier": 2
|
||||
},
|
||||
"ensResolutionsByAddress": "object",
|
||||
"pendingApprovals": "object",
|
||||
"pendingApprovalCount": "number",
|
||||
|
@ -5,33 +5,42 @@
|
||||
"unconnectedAccountAlertShownOrigins": "object",
|
||||
"web3ShimUsageOrigins": "object"
|
||||
},
|
||||
"AnnouncementController": "object",
|
||||
"AnnouncementController": { "announcements": "object" },
|
||||
"AppStateController": {
|
||||
"browserEnvironment": "object",
|
||||
"nftsDropdownState": "object",
|
||||
"browserEnvironment": {},
|
||||
"nftsDropdownState": {},
|
||||
"connectedStatusPopoverHasBeenShown": true,
|
||||
"termsOfUseLastAgreed": "number",
|
||||
"defaultHomeActiveTabName": null,
|
||||
"fullScreenGasPollTokens": "object",
|
||||
"notificationGasPollTokens": "object",
|
||||
"popupGasPollTokens": "object",
|
||||
"qrHardware": "object",
|
||||
"recoveryPhraseReminderHasBeenShown": "boolean",
|
||||
"fullScreenGasPollTokens": [],
|
||||
"notificationGasPollTokens": [],
|
||||
"popupGasPollTokens": [],
|
||||
"qrHardware": {},
|
||||
"recoveryPhraseReminderHasBeenShown": true,
|
||||
"recoveryPhraseReminderLastShown": "number",
|
||||
"showTestnetMessageInDropdown": "boolean",
|
||||
"trezorModel": "object",
|
||||
"usedNetworks": "object",
|
||||
"snapsInstallPrivacyWarningShown": "boolean"
|
||||
"showTestnetMessageInDropdown": true,
|
||||
"trezorModel": null,
|
||||
"usedNetworks": {
|
||||
"0x1": true,
|
||||
"0xe708": true,
|
||||
"0x5": true,
|
||||
"0x539": true
|
||||
},
|
||||
"snapsInstallPrivacyWarningShown": true
|
||||
},
|
||||
"CachedBalancesController": "object",
|
||||
"CachedBalancesController": { "cachedBalances": "object" },
|
||||
"CurrencyController": {
|
||||
"conversionDate": 1665507600,
|
||||
"conversionDate": "number",
|
||||
"conversionRate": 1300,
|
||||
"currentCurrency": "usd",
|
||||
"nativeCurrency": "ETH",
|
||||
"usdConversionRate": "number"
|
||||
"usdConversionRate": 1300
|
||||
},
|
||||
"GasFeeController": {
|
||||
"estimatedGasFeeTimeBounds": {},
|
||||
"gasEstimateType": "none",
|
||||
"gasFeeEstimates": {}
|
||||
},
|
||||
"GasFeeController": "object",
|
||||
"IncomingTransactionsController": {
|
||||
"incomingTransactions": "object",
|
||||
"incomingTxLastFetchedBlockByChainId": {
|
||||
@ -54,13 +63,13 @@
|
||||
"networkId": "1337",
|
||||
"networkStatus": "available",
|
||||
"providerConfig": {
|
||||
"chainId": "string",
|
||||
"chainId": "0x539",
|
||||
"nickname": "Localhost 8545",
|
||||
"rpcPrefs": "object",
|
||||
"rpcUrl": "string",
|
||||
"ticker": "ETH",
|
||||
"type": "rpc",
|
||||
"id": "string"
|
||||
"id": "networkConfigurationId"
|
||||
},
|
||||
"networkConfigurations": "object"
|
||||
},
|
||||
@ -70,20 +79,20 @@
|
||||
"onboardingTabs": "object",
|
||||
"seedPhraseBackedUp": true
|
||||
},
|
||||
"PermissionController": "object",
|
||||
"PermissionController": { "subjects": "object" },
|
||||
"PreferencesController": {
|
||||
"advancedGasFee": "object",
|
||||
"advancedGasFee": null,
|
||||
"currentLocale": "en",
|
||||
"dismissSeedBackUpReminder": "boolean",
|
||||
"dismissSeedBackUpReminder": true,
|
||||
"featureFlags": { "showIncomingTransactions": true },
|
||||
"forgottenPassword": false,
|
||||
"identities": "object",
|
||||
"infuraBlocked": "boolean",
|
||||
"ipfsGateway": "dweb.link",
|
||||
"infuraBlocked": false,
|
||||
"ipfsGateway": "string",
|
||||
"knownMethodData": "object",
|
||||
"ledgerTransportType": "string",
|
||||
"ledgerTransportType": "webhid",
|
||||
"lostIdentities": "object",
|
||||
"openSeaEnabled": "boolean",
|
||||
"openSeaEnabled": false,
|
||||
"preferences": {
|
||||
"hideZeroBalanceTokens": false,
|
||||
"showFiatInTestnets": false,
|
||||
@ -91,19 +100,32 @@
|
||||
"useNativeCurrencyAsPrimaryCurrency": true
|
||||
},
|
||||
"selectedAddress": "string",
|
||||
"theme": "string",
|
||||
"theme": "light",
|
||||
"useBlockie": false,
|
||||
"useNftDetection": "boolean",
|
||||
"useNftDetection": false,
|
||||
"useNonceField": false,
|
||||
"usePhishDetect": true,
|
||||
"useTokenDetection": "boolean",
|
||||
"useCurrencyRateCheck": "boolean",
|
||||
"useMultiAccountBalanceChecker": "boolean"
|
||||
"useTokenDetection": false,
|
||||
"useCurrencyRateCheck": true,
|
||||
"useMultiAccountBalanceChecker": true
|
||||
},
|
||||
"SmartTransactionsController": "object",
|
||||
"SubjectMetadataController": "object",
|
||||
"TokensController": "object",
|
||||
"TransactionController": "object",
|
||||
"SmartTransactionsController": {
|
||||
"smartTransactionsState": {
|
||||
"fees": {},
|
||||
"liveness": true,
|
||||
"smartTransactions": "object"
|
||||
}
|
||||
},
|
||||
"SubjectMetadataController": { "subjectMetadata": "object" },
|
||||
"TokensController": {
|
||||
"allDetectedTokens": {},
|
||||
"allIgnoredTokens": {},
|
||||
"allTokens": {},
|
||||
"detectedTokens": "object",
|
||||
"ignoredTokens": "object",
|
||||
"tokens": "object"
|
||||
},
|
||||
"TransactionController": { "transactions": "object" },
|
||||
"config": "object",
|
||||
"firstTimeInfo": "object"
|
||||
}
|
||||
|
@ -5,33 +5,42 @@
|
||||
"unconnectedAccountAlertShownOrigins": "object",
|
||||
"web3ShimUsageOrigins": "object"
|
||||
},
|
||||
"AnnouncementController": "object",
|
||||
"AnnouncementController": { "announcements": "object" },
|
||||
"AppStateController": {
|
||||
"browserEnvironment": "object",
|
||||
"nftsDropdownState": "object",
|
||||
"browserEnvironment": {},
|
||||
"nftsDropdownState": {},
|
||||
"connectedStatusPopoverHasBeenShown": true,
|
||||
"termsOfUseLastAgreed": "number",
|
||||
"defaultHomeActiveTabName": null,
|
||||
"fullScreenGasPollTokens": "object",
|
||||
"notificationGasPollTokens": "object",
|
||||
"popupGasPollTokens": "object",
|
||||
"qrHardware": "object",
|
||||
"recoveryPhraseReminderHasBeenShown": "boolean",
|
||||
"fullScreenGasPollTokens": [],
|
||||
"notificationGasPollTokens": [],
|
||||
"popupGasPollTokens": [],
|
||||
"qrHardware": {},
|
||||
"recoveryPhraseReminderHasBeenShown": true,
|
||||
"recoveryPhraseReminderLastShown": "number",
|
||||
"showTestnetMessageInDropdown": "boolean",
|
||||
"trezorModel": "object",
|
||||
"usedNetworks": "object",
|
||||
"snapsInstallPrivacyWarningShown": "boolean"
|
||||
"showTestnetMessageInDropdown": true,
|
||||
"trezorModel": null,
|
||||
"usedNetworks": {
|
||||
"0x1": true,
|
||||
"0xe708": true,
|
||||
"0x5": true,
|
||||
"0x539": true
|
||||
},
|
||||
"snapsInstallPrivacyWarningShown": true
|
||||
},
|
||||
"CachedBalancesController": "object",
|
||||
"CachedBalancesController": { "cachedBalances": "object" },
|
||||
"CurrencyController": {
|
||||
"conversionDate": 1665507600,
|
||||
"conversionDate": "number",
|
||||
"conversionRate": 1300,
|
||||
"currentCurrency": "usd",
|
||||
"nativeCurrency": "ETH",
|
||||
"usdConversionRate": "number"
|
||||
"usdConversionRate": 1300
|
||||
},
|
||||
"GasFeeController": {
|
||||
"estimatedGasFeeTimeBounds": {},
|
||||
"gasEstimateType": "none",
|
||||
"gasFeeEstimates": {}
|
||||
},
|
||||
"GasFeeController": "object",
|
||||
"IncomingTransactionsController": {
|
||||
"incomingTransactions": "object",
|
||||
"incomingTxLastFetchedBlockByChainId": {
|
||||
@ -54,13 +63,13 @@
|
||||
"networkId": "1337",
|
||||
"networkStatus": "available",
|
||||
"providerConfig": {
|
||||
"chainId": "string",
|
||||
"chainId": "0x539",
|
||||
"nickname": "Localhost 8545",
|
||||
"rpcPrefs": "object",
|
||||
"rpcUrl": "string",
|
||||
"ticker": "ETH",
|
||||
"type": "rpc",
|
||||
"id": "string"
|
||||
"id": "networkConfigurationId"
|
||||
},
|
||||
"networkConfigurations": "object"
|
||||
},
|
||||
@ -70,20 +79,20 @@
|
||||
"onboardingTabs": "object",
|
||||
"seedPhraseBackedUp": true
|
||||
},
|
||||
"PermissionController": "object",
|
||||
"PermissionController": { "subjects": "object" },
|
||||
"PreferencesController": {
|
||||
"advancedGasFee": "object",
|
||||
"advancedGasFee": null,
|
||||
"currentLocale": "en",
|
||||
"dismissSeedBackUpReminder": "boolean",
|
||||
"dismissSeedBackUpReminder": true,
|
||||
"featureFlags": { "showIncomingTransactions": true },
|
||||
"forgottenPassword": false,
|
||||
"identities": "object",
|
||||
"infuraBlocked": "boolean",
|
||||
"ipfsGateway": "dweb.link",
|
||||
"infuraBlocked": false,
|
||||
"ipfsGateway": "string",
|
||||
"knownMethodData": "object",
|
||||
"ledgerTransportType": "string",
|
||||
"ledgerTransportType": "webhid",
|
||||
"lostIdentities": "object",
|
||||
"openSeaEnabled": "boolean",
|
||||
"openSeaEnabled": false,
|
||||
"preferences": {
|
||||
"hideZeroBalanceTokens": false,
|
||||
"showFiatInTestnets": false,
|
||||
@ -91,19 +100,32 @@
|
||||
"useNativeCurrencyAsPrimaryCurrency": true
|
||||
},
|
||||
"selectedAddress": "string",
|
||||
"theme": "string",
|
||||
"theme": "light",
|
||||
"useBlockie": false,
|
||||
"useNftDetection": "boolean",
|
||||
"useNftDetection": false,
|
||||
"useNonceField": false,
|
||||
"usePhishDetect": true,
|
||||
"useTokenDetection": "boolean",
|
||||
"useCurrencyRateCheck": "boolean",
|
||||
"useMultiAccountBalanceChecker": "boolean"
|
||||
"useTokenDetection": false,
|
||||
"useCurrencyRateCheck": true,
|
||||
"useMultiAccountBalanceChecker": true
|
||||
},
|
||||
"SmartTransactionsController": "object",
|
||||
"SubjectMetadataController": "object",
|
||||
"TokensController": "object",
|
||||
"TransactionController": "object",
|
||||
"SmartTransactionsController": {
|
||||
"smartTransactionsState": {
|
||||
"fees": {},
|
||||
"liveness": true,
|
||||
"smartTransactions": "object"
|
||||
}
|
||||
},
|
||||
"SubjectMetadataController": { "subjectMetadata": "object" },
|
||||
"TokensController": {
|
||||
"allDetectedTokens": {},
|
||||
"allIgnoredTokens": {},
|
||||
"allTokens": {},
|
||||
"detectedTokens": "object",
|
||||
"ignoredTokens": "object",
|
||||
"tokens": "object"
|
||||
},
|
||||
"TransactionController": { "transactions": "object" },
|
||||
"config": "object",
|
||||
"firstTimeInfo": "object"
|
||||
},
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
|
||||
import { capitalize } from 'lodash';
|
||||
import { useTransactionEventFragment } from '../../../../hooks/useTransactionEventFragment';
|
||||
import { EditGasModes } from '../../../../../shared/constants/gas';
|
||||
import Box from '../../../ui/box';
|
||||
@ -11,7 +12,11 @@ import {
|
||||
TextColor,
|
||||
TextVariant,
|
||||
} from '../../../../helpers/constants/design-system';
|
||||
import { getAdvancedGasFeeValues } from '../../../../selectors';
|
||||
import {
|
||||
getAdvancedGasFeeValues,
|
||||
getCurrentChainId,
|
||||
getNetworkIdentifier,
|
||||
} from '../../../../selectors';
|
||||
import { setAdvancedGasFee } from '../../../../store/actions';
|
||||
import { useGasFeeContext } from '../../../../contexts/gasFee';
|
||||
import { useAdvancedGasFeePopoverContext } from '../context';
|
||||
@ -24,6 +29,9 @@ const AdvancedGasFeeDefaults = () => {
|
||||
const { gasErrors, maxBaseFee, maxPriorityFeePerGas } =
|
||||
useAdvancedGasFeePopoverContext();
|
||||
const advancedGasFeeValues = useSelector(getAdvancedGasFeeValues);
|
||||
// This will need to use a different chainId in multinetwork
|
||||
const chainId = useSelector(getCurrentChainId);
|
||||
const networkIdentifier = useSelector(getNetworkIdentifier);
|
||||
const { updateTransactionEventFragment } = useTransactionEventFragment();
|
||||
const { editGasMode } = useGasFeeContext();
|
||||
const [isDefaultSettingsSelected, setDefaultSettingsSelected] = useState(
|
||||
@ -42,7 +50,7 @@ const AdvancedGasFeeDefaults = () => {
|
||||
|
||||
const handleUpdateDefaultSettings = () => {
|
||||
if (isDefaultSettingsSelected) {
|
||||
dispatch(setAdvancedGasFee(null));
|
||||
dispatch(setAdvancedGasFee({ chainId, gasFeePreferences: undefined }));
|
||||
setDefaultSettingsSelected(false);
|
||||
updateTransactionEventFragment({
|
||||
properties: {
|
||||
@ -53,8 +61,11 @@ const AdvancedGasFeeDefaults = () => {
|
||||
} else {
|
||||
dispatch(
|
||||
setAdvancedGasFee({
|
||||
maxBaseFee,
|
||||
priorityFee: maxPriorityFeePerGas,
|
||||
chainId,
|
||||
gasFeePreferences: {
|
||||
maxBaseFee,
|
||||
priorityFee: maxPriorityFeePerGas,
|
||||
},
|
||||
}),
|
||||
);
|
||||
updateTransactionEventFragment({
|
||||
@ -91,11 +102,7 @@ const AdvancedGasFeeDefaults = () => {
|
||||
as="h6"
|
||||
color={TextColor.textAlternative}
|
||||
>
|
||||
{isDefaultSettingsSelected
|
||||
? t('advancedGasFeeDefaultOptOut')
|
||||
: t('advancedGasFeeDefaultOptIn', [
|
||||
<strong key="default-value-change">{t('newValues')}</strong>,
|
||||
])}
|
||||
{t('advancedGasFeeDefaultOptIn', [capitalize(networkIdentifier)])}
|
||||
</Text>
|
||||
</label>
|
||||
</Box>
|
||||
|
@ -15,8 +15,11 @@ import { GasFeeContextProvider } from '../../../../contexts/gasFee';
|
||||
import configureStore from '../../../../store/store';
|
||||
|
||||
import AdvancedGasFeeInputs from '../advanced-gas-fee-inputs';
|
||||
import { CHAIN_IDS } from '../../../../../shared/constants/network';
|
||||
import AdvancedGasFeeDefaults from './advanced-gas-fee-defaults';
|
||||
|
||||
const TEXT_SELECTOR = 'Save these values as my default for the Goerli network.';
|
||||
|
||||
jest.mock('../../../../store/actions', () => ({
|
||||
disconnectGasFeeEstimatePoller: jest.fn(),
|
||||
getGasFeeEstimatesAndStartPolling: jest
|
||||
@ -62,68 +65,58 @@ const render = (defaultGasParams, contextParams) => {
|
||||
};
|
||||
describe('AdvancedGasFeeDefaults', () => {
|
||||
it('should renders correct message when the default is not set', () => {
|
||||
render({ advancedGasFee: null });
|
||||
expect(screen.queryByText('new values')).toBeInTheDocument();
|
||||
render({ advancedGasFee: {} });
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
});
|
||||
it('should renders correct message when the default values are set', () => {
|
||||
render({
|
||||
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
|
||||
advancedGasFee: {
|
||||
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
|
||||
},
|
||||
});
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Always use these values and advanced setting as default.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
});
|
||||
it('should renders correct message when the default values are set and the maxBaseFee values are updated', () => {
|
||||
render({
|
||||
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
|
||||
advancedGasFee: {
|
||||
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
|
||||
},
|
||||
});
|
||||
expect(document.getElementsByTagName('input')[2]).toBeChecked();
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Always use these values and advanced setting as default.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
fireEvent.change(document.getElementsByTagName('input')[0], {
|
||||
target: { value: 75 },
|
||||
});
|
||||
expect(document.getElementsByTagName('input')[0]).toHaveValue(75);
|
||||
expect(screen.queryByText('new values')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('Save these as my default for "Advanced"'),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
});
|
||||
it('should renders correct message when the default values are set and the priorityFee values are updated', () => {
|
||||
render({
|
||||
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
|
||||
advancedGasFee: {
|
||||
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
|
||||
},
|
||||
});
|
||||
expect(document.getElementsByTagName('input')[2]).toBeChecked();
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Always use these values and advanced setting as default.',
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
fireEvent.change(document.getElementsByTagName('input')[1], {
|
||||
target: { value: 5 },
|
||||
});
|
||||
expect(document.getElementsByTagName('input')[1]).toHaveValue(5);
|
||||
expect(screen.queryByText('new values')).toBeInTheDocument();
|
||||
expect(
|
||||
screen.queryByText('Save these as my default for "Advanced"'),
|
||||
).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
expect(screen.queryByText(TEXT_SELECTOR)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should call action setAdvancedGasFee when checkbox or label text is clicked', () => {
|
||||
render({
|
||||
advancedGasFee: { maxBaseFee: 50, priorityFee: 2 },
|
||||
advancedGasFee: {
|
||||
[CHAIN_IDS.GOERLI]: { maxBaseFee: 50, priorityFee: 2 },
|
||||
},
|
||||
});
|
||||
const mock = jest
|
||||
.spyOn(Actions, 'setAdvancedGasFee')
|
||||
.mockReturnValue({ type: 'test' });
|
||||
const checkboxLabel = screen.queryByText(
|
||||
'Always use these values and advanced setting as default.',
|
||||
);
|
||||
const checkboxLabel = screen.queryByText(TEXT_SELECTOR);
|
||||
fireEvent.click(checkboxLabel);
|
||||
expect(mock).toHaveBeenCalledTimes(1);
|
||||
const checkbox = document.querySelector('input[type=checkbox]');
|
||||
|
@ -13,6 +13,7 @@ import configureStore from '../../../../../store/store';
|
||||
|
||||
import { AdvancedGasFeePopoverContextProvider } from '../../context';
|
||||
import AdvancedGasFeeGasLimit from '../../advanced-gas-fee-gas-limit';
|
||||
import { CHAIN_IDS } from '../../../../../../shared/constants/network';
|
||||
import PriorityfeeInput from './priority-fee-input';
|
||||
|
||||
jest.mock('../../../../../store/actions', () => ({
|
||||
@ -34,7 +35,7 @@ const render = (txProps, contextProps) => {
|
||||
balance: '0x1F4',
|
||||
},
|
||||
},
|
||||
advancedGasFee: { priorityFee: 100 },
|
||||
advancedGasFee: { [CHAIN_IDS.GOERLI]: { priorityFee: 100 } },
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
gasFeeEstimates:
|
||||
mockEstimates[GasEstimateTypes.feeMarket].gasFeeEstimates,
|
||||
|
@ -61,9 +61,13 @@ const render = ({ txProps, contextProps } = {}) => {
|
||||
balance: '0x1F4',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
gasFeeEstimates: MOCK_FEE_ESTIMATE,
|
||||
advancedGasFee: {},
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -10,6 +10,7 @@ import { ETH } from '../../../../helpers/constants/common';
|
||||
import configureStore from '../../../../store/store';
|
||||
import { GasFeeContextProvider } from '../../../../contexts/gasFee';
|
||||
|
||||
import { CHAIN_IDS } from '../../../../../shared/constants/network';
|
||||
import EditGasItem from './edit-gas-item';
|
||||
|
||||
jest.mock('../../../../store/actions', () => ({
|
||||
@ -59,7 +60,9 @@ const renderComponent = ({
|
||||
const store = configureStore({
|
||||
metamask: {
|
||||
nativeCurrency: ETH,
|
||||
providerConfig: {},
|
||||
providerConfig: {
|
||||
chainId: CHAIN_IDS.GOERLI,
|
||||
},
|
||||
cachedBalances: {},
|
||||
accounts: {
|
||||
'0xAddress': {
|
||||
@ -67,13 +70,18 @@ const renderComponent = ({
|
||||
balance: '0x176e5b6f173ebe66',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
gasEstimateType: 'fee-market',
|
||||
gasFeeEstimates: MOCK_FEE_ESTIMATE,
|
||||
advancedGasFee: {
|
||||
maxBaseFee: '100',
|
||||
priorityFee: '2',
|
||||
[CHAIN_IDS.GOERLI]: {
|
||||
maxBaseFee: '100',
|
||||
priorityFee: '2',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -41,6 +41,9 @@ const renderComponent = (componentProps) => {
|
||||
balance: '0x176e5b6f173ebe66',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
featureFlags: { advancedInlineGas: true },
|
||||
},
|
||||
|
@ -28,6 +28,9 @@ const render = () => {
|
||||
balance: '0x176e5b6f173ebe66',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAddress': {},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
},
|
||||
});
|
||||
|
@ -112,12 +112,13 @@ export default function NftDetails({ nft }) {
|
||||
const getOpenSeaLink = () => {
|
||||
switch (currentNetwork) {
|
||||
case CHAIN_IDS.MAINNET:
|
||||
return `https://opensea.io/assets/${address}/${tokenId}`;
|
||||
return `https://opensea.io/assets/ethereum/${address}/${tokenId}`;
|
||||
case CHAIN_IDS.POLYGON:
|
||||
return `https://opensea.io/assets/matic/${address}/${tokenId}`;
|
||||
case CHAIN_IDS.GOERLI:
|
||||
return `https://testnets.opensea.io/assets/goerli/${address}/${tokenId}`;
|
||||
case CHAIN_IDS.SEPOLIA:
|
||||
return `https://testnets.opensea.io/assets/${address}/${tokenId}`;
|
||||
return `https://testnets.opensea.io/assets/sepolia/${address}/${tokenId}`;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -165,7 +165,7 @@ describe('NFT Details', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||
url: `https://testnets.opensea.io/assets/${nfts[5].address}/${nfts[5].tokenId}`,
|
||||
url: `https://testnets.opensea.io/assets/goerli/${nfts[5].address}/${nfts[5].tokenId}`,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -200,7 +200,7 @@ describe('NFT Details', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||
url: `https://opensea.io/assets/${nfts[5].address}/${nfts[5].tokenId}`,
|
||||
url: `https://opensea.io/assets/ethereum/${nfts[5].address}/${nfts[5].tokenId}`,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -272,7 +272,7 @@ describe('NFT Details', () => {
|
||||
|
||||
await waitFor(() => {
|
||||
expect(global.platform.openTab).toHaveBeenCalledWith({
|
||||
url: `https://testnets.opensea.io/assets/${nfts[5].address}/${nfts[5].tokenId}`,
|
||||
url: `https://testnets.opensea.io/assets/sepolia/${nfts[5].address}/${nfts[5].tokenId}`,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -61,7 +61,7 @@ exports[`SignatureRequestHeader should match snapshot 1`] = `
|
||||
<span
|
||||
class="icon-with-fallback__fallback"
|
||||
>
|
||||
U
|
||||
G
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,7 +71,7 @@ exports[`SignatureRequestHeader should match snapshot 1`] = `
|
||||
<h6
|
||||
class="box mm-text mm-text--body-sm box--flex-direction-row box--color-text-alternative"
|
||||
>
|
||||
Unknown private network
|
||||
goerli
|
||||
</h6>
|
||||
<h6
|
||||
class="box mm-text mm-text--body-sm mm-text--font-weight-bold box--flex-direction-row box--color-text-default"
|
||||
|
@ -137,7 +137,7 @@ exports[`SignatureRequestOriginal should match snapshot 1`] = `
|
||||
<span
|
||||
class="icon-with-fallback__fallback"
|
||||
>
|
||||
U
|
||||
G
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -147,7 +147,7 @@ exports[`SignatureRequestOriginal should match snapshot 1`] = `
|
||||
<h6
|
||||
class="box mm-text mm-text--body-sm box--flex-direction-row box--color-text-alternative"
|
||||
>
|
||||
Unknown private network
|
||||
goerli
|
||||
</h6>
|
||||
<h6
|
||||
class="box mm-text mm-text--body-sm mm-text--font-weight-bold box--flex-direction-row box--color-text-default"
|
||||
|
@ -134,7 +134,7 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`]
|
||||
<span
|
||||
class="icon-with-fallback__fallback"
|
||||
>
|
||||
U
|
||||
G
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -144,7 +144,7 @@ exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`]
|
||||
<h6
|
||||
class="box mm-text mm-text--body-sm box--flex-direction-row box--color-text-alternative"
|
||||
>
|
||||
Unknown private network
|
||||
goerli
|
||||
</h6>
|
||||
<h6
|
||||
class="box mm-text mm-text--body-sm mm-text--font-weight-bold box--flex-direction-row box--color-text-default"
|
||||
|
@ -89,7 +89,7 @@ exports[`SignatureRequestHeader renders correctly with fromAccount 1`] = `
|
||||
<span
|
||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h7 typography--weight-normal typography--style-normal typography--color-text-alternative"
|
||||
>
|
||||
Private network
|
||||
goerli
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -127,7 +127,7 @@ exports[`SignatureRequestHeader renders correctly without fromAccount 1`] = `
|
||||
<span
|
||||
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h7 typography--weight-normal typography--style-normal typography--color-text-alternative"
|
||||
>
|
||||
Private network
|
||||
goerli
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -103,6 +103,9 @@ function getActionFunctionById(id, history) {
|
||||
22: () => {
|
||||
updateViewedNotifications({ 22: true });
|
||||
},
|
||||
24: () => {
|
||||
updateViewedNotifications({ 24: true });
|
||||
},
|
||||
};
|
||||
|
||||
return actionFunctions[id];
|
||||
@ -364,6 +367,7 @@ export default function WhatsNewPopup({
|
||||
19: renderFirstNotification,
|
||||
21: renderFirstNotification,
|
||||
22: renderFirstNotification,
|
||||
24: renderFirstNotification,
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -11,7 +11,7 @@ import withModalProps from '../../../helpers/higher-order-components/with-modal-
|
||||
import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils';
|
||||
import { mmiActionsFactory } from '../../../store/institutional/institution-background';
|
||||
import { setSelectedAddress } from '../../../store/actions';
|
||||
import { getMetaMaskAccountsRaw } from '../../../selectors';
|
||||
import { getMetaMaskIdentities } from '../../../selectors';
|
||||
import {
|
||||
getMMIAddressFromModalOrAddress,
|
||||
getCustodyAccountDetails,
|
||||
@ -42,7 +42,7 @@ const CustodyConfirmLink = ({ hideModal }) => {
|
||||
const dispatch = useDispatch();
|
||||
const mmiActions = mmiActionsFactory();
|
||||
const trackEvent = useContext(MetaMetricsContext);
|
||||
const mmiAccounts = useSelector(getMetaMaskAccountsRaw);
|
||||
const mmiAccounts = useSelector(getMetaMaskIdentities);
|
||||
const address = useSelector(getMMIAddressFromModalOrAddress);
|
||||
const custodyAccountDetails = useSelector(getCustodyAccountDetails);
|
||||
const { custodians } = useSelector(getMMIConfiguration);
|
||||
|
@ -77,6 +77,8 @@ import { draftTransactionInitialState, editExistingTransaction } from '.';
|
||||
|
||||
const mockStore = createMockStore([thunk]);
|
||||
|
||||
const mockAddress1 = '0xdafea492d9c6733ae3d56b7ed1adb60692c98123';
|
||||
|
||||
jest.mock('./send', () => {
|
||||
const actual = jest.requireActual('./send');
|
||||
return {
|
||||
@ -1063,7 +1065,7 @@ describe('Send Slice', () => {
|
||||
describe('QR Code Detected', () => {
|
||||
const qrCodestate = getInitialSendStateWithExistingTxState({
|
||||
recipient: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1102,7 +1104,7 @@ describe('Send Slice', () => {
|
||||
|
||||
const draftTransaction = getTestUUIDTx(result);
|
||||
|
||||
expect(draftTransaction.recipient.address).toStrictEqual('0xAddress');
|
||||
expect(draftTransaction.recipient.address).toStrictEqual(mockAddress1);
|
||||
expect(draftTransaction.recipient.error).toStrictEqual(
|
||||
INVALID_RECIPIENT_ADDRESS_ERROR,
|
||||
);
|
||||
@ -1115,7 +1117,7 @@ describe('Send Slice', () => {
|
||||
...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT,
|
||||
selectedAccount: {
|
||||
balance: '0x0',
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1144,7 +1146,7 @@ describe('Send Slice', () => {
|
||||
...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT,
|
||||
selectedAccount: {
|
||||
balance: '0x0',
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1158,7 +1160,7 @@ describe('Send Slice', () => {
|
||||
const result = sendReducer(olderState, action);
|
||||
|
||||
expect(result.selectedAccount.balance).toStrictEqual('0x0');
|
||||
expect(result.selectedAccount.address).toStrictEqual('0xAddress');
|
||||
expect(result.selectedAccount.address).toStrictEqual(mockAddress1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1167,13 +1169,13 @@ describe('Send Slice', () => {
|
||||
const accountsChangedState = {
|
||||
...getInitialSendStateWithExistingTxState({
|
||||
fromAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
}),
|
||||
stage: SEND_STAGES.EDIT,
|
||||
selectedAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
};
|
||||
@ -1182,7 +1184,7 @@ describe('Send Slice', () => {
|
||||
type: 'ACCOUNT_CHANGED',
|
||||
payload: {
|
||||
account: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x1',
|
||||
},
|
||||
},
|
||||
@ -1201,13 +1203,13 @@ describe('Send Slice', () => {
|
||||
const accountsChangedState = {
|
||||
...getInitialSendStateWithExistingTxState({
|
||||
fromAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
}),
|
||||
stage: SEND_STAGES.EDIT,
|
||||
selectedAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
};
|
||||
@ -1231,7 +1233,7 @@ describe('Send Slice', () => {
|
||||
...INITIAL_SEND_STATE_FOR_EXISTING_DRAFT,
|
||||
stage: SEND_STAGES.EDIT,
|
||||
selectedAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
};
|
||||
@ -1274,23 +1276,23 @@ describe('Send Slice', () => {
|
||||
1559: true,
|
||||
},
|
||||
},
|
||||
selectedAddress: '0xAddress',
|
||||
identities: { '0xAddress': { address: '0xAddress' } },
|
||||
selectedAddress: mockAddress1,
|
||||
identities: { [mockAddress1]: { address: mockAddress1 } },
|
||||
keyrings: [
|
||||
{
|
||||
type: KeyringType.hdKeyTree,
|
||||
accounts: ['0xAddress'],
|
||||
accounts: [mockAddress1],
|
||||
},
|
||||
],
|
||||
accounts: {
|
||||
'0xAddress': {
|
||||
address: '0xAddress',
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
},
|
||||
cachedBalances: {
|
||||
0x5: {
|
||||
'0xAddress': '0x0',
|
||||
[mockAddress1]: '0x0',
|
||||
},
|
||||
},
|
||||
providerConfig: {
|
||||
@ -1580,14 +1582,17 @@ describe('Send Slice', () => {
|
||||
},
|
||||
cachedBalances: {
|
||||
[CHAIN_IDS.GOERLI]: {
|
||||
'0xAddress': '0x0',
|
||||
[mockAddress1]: '0x0',
|
||||
},
|
||||
},
|
||||
accounts: {
|
||||
'0xAddress': {
|
||||
address: '0xAddress',
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
},
|
||||
send: {
|
||||
...getInitialSendStateWithExistingTxState({
|
||||
@ -1607,7 +1612,7 @@ describe('Send Slice', () => {
|
||||
userInputHexData: '',
|
||||
}),
|
||||
selectedAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
},
|
||||
},
|
||||
};
|
||||
@ -2379,16 +2384,18 @@ describe('Send Slice', () => {
|
||||
addressBook: {
|
||||
[CHAIN_IDS.GOERLI]: {},
|
||||
},
|
||||
identities: {},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
accounts: {
|
||||
'0xAddress': {
|
||||
address: '0xAddress',
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
},
|
||||
cachedBalances: {
|
||||
[CHAIN_IDS.GOERLI]: {
|
||||
'0xAddress': '0x0',
|
||||
[mockAddress1]: '0x0',
|
||||
},
|
||||
},
|
||||
tokenList: {},
|
||||
@ -2397,7 +2404,7 @@ describe('Send Slice', () => {
|
||||
id: 1,
|
||||
txParams: {
|
||||
data: '',
|
||||
from: '0xAddress',
|
||||
from: mockAddress1,
|
||||
to: '0xRecipientAddress',
|
||||
gas: GAS_LIMITS.SIMPLE,
|
||||
gasPrice: '0x3b9aca00', // 1000000000
|
||||
@ -2414,7 +2421,7 @@ describe('Send Slice', () => {
|
||||
...getInitialSendStateWithExistingTxState({
|
||||
id: 1,
|
||||
fromAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
},
|
||||
}),
|
||||
},
|
||||
@ -2443,7 +2450,7 @@ describe('Send Slice', () => {
|
||||
type: AssetType.native,
|
||||
},
|
||||
fromAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
gas: {
|
||||
@ -2514,16 +2521,18 @@ describe('Send Slice', () => {
|
||||
addressBook: {
|
||||
[CHAIN_IDS.GOERLI]: {},
|
||||
},
|
||||
identities: {},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
accounts: {
|
||||
'0xAddress': {
|
||||
address: '0xAddress',
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
},
|
||||
cachedBalances: {
|
||||
[CHAIN_IDS.GOERLI]: {
|
||||
'0xAddress': '0x0',
|
||||
[mockAddress1]: '0x0',
|
||||
},
|
||||
},
|
||||
tokenList: {},
|
||||
@ -2533,10 +2542,10 @@ describe('Send Slice', () => {
|
||||
txParams: {
|
||||
data: generateERC721TransferData({
|
||||
toAddress: BURN_ADDRESS,
|
||||
fromAddress: '0xAddress',
|
||||
fromAddress: mockAddress1,
|
||||
tokenId: BigNumber.from(15000).toString(),
|
||||
}),
|
||||
from: '0xAddress',
|
||||
from: mockAddress1,
|
||||
to: '0xNftAddress',
|
||||
gas: GAS_LIMITS.BASE_TOKEN_ESTIMATE,
|
||||
gasPrice: '0x3b9aca00', // 1000000000
|
||||
@ -2586,7 +2595,7 @@ describe('Send Slice', () => {
|
||||
type: AssetType.native,
|
||||
},
|
||||
fromAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
gas: {
|
||||
@ -2697,16 +2706,18 @@ describe('Send Slice', () => {
|
||||
addressBook: {
|
||||
[CHAIN_IDS.GOERLI]: {},
|
||||
},
|
||||
identities: {},
|
||||
identities: {
|
||||
[mockAddress1]: {},
|
||||
},
|
||||
accounts: {
|
||||
'0xAddress': {
|
||||
address: '0xAddress',
|
||||
[mockAddress1]: {
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
},
|
||||
cachedBalances: {
|
||||
[CHAIN_IDS.GOERLI]: {
|
||||
'0xAddress': '0x0',
|
||||
[mockAddress1]: '0x0',
|
||||
},
|
||||
},
|
||||
unapprovedTxs: {
|
||||
@ -2722,7 +2733,7 @@ describe('Send Slice', () => {
|
||||
decimals: 18,
|
||||
},
|
||||
}),
|
||||
from: '0xAddress',
|
||||
from: mockAddress1,
|
||||
to: '0xTokenAddress',
|
||||
gas: GAS_LIMITS.BASE_TOKEN_ESTIMATE,
|
||||
gasPrice: '0x3b9aca00', // 1000000000
|
||||
@ -2740,7 +2751,7 @@ describe('Send Slice', () => {
|
||||
},
|
||||
}),
|
||||
selectedAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
stage: SEND_STAGES.EDIT,
|
||||
@ -2777,7 +2788,7 @@ describe('Send Slice', () => {
|
||||
type: AssetType.native,
|
||||
},
|
||||
fromAccount: {
|
||||
address: '0xAddress',
|
||||
address: mockAddress1,
|
||||
balance: '0x0',
|
||||
},
|
||||
gas: {
|
||||
|
@ -106,9 +106,12 @@ const ConfirmAddSuggestedNFT = () => {
|
||||
}, [history, mostRecentOverviewPage, suggestedNfts]);
|
||||
|
||||
let origin;
|
||||
let link;
|
||||
if (suggestedNfts.length) {
|
||||
try {
|
||||
origin = new URL(suggestedNfts[0].origin)?.host;
|
||||
const url = new URL(suggestedNfts[0].origin);
|
||||
origin = url.host;
|
||||
link = url.href;
|
||||
} catch {
|
||||
origin = 'dapp';
|
||||
}
|
||||
@ -138,7 +141,7 @@ const ConfirmAddSuggestedNFT = () => {
|
||||
<ButtonLink
|
||||
key={origin}
|
||||
size={BUTTON_SIZES.INHERIT}
|
||||
href={origin}
|
||||
href={link}
|
||||
target="_blank"
|
||||
>
|
||||
{origin}
|
||||
|
@ -281,28 +281,38 @@ export function deprecatedGetCurrentNetworkId(state) {
|
||||
return state.metamask.networkId ?? 'loading';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MetaMask accounts, including account name and balance.
|
||||
*/
|
||||
export const getMetaMaskAccounts = createSelector(
|
||||
getMetaMaskAccountsRaw,
|
||||
getMetaMaskIdentities,
|
||||
getMetaMaskAccountBalances,
|
||||
getMetaMaskCachedBalances,
|
||||
(currentAccounts, cachedBalances) =>
|
||||
Object.entries(currentAccounts).reduce(
|
||||
(selectedAccounts, [accountID, account]) => {
|
||||
if (account.balance === null || account.balance === undefined) {
|
||||
return {
|
||||
...selectedAccounts,
|
||||
[accountID]: {
|
||||
...account,
|
||||
balance: cachedBalances && cachedBalances[accountID],
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
...selectedAccounts,
|
||||
[accountID]: account,
|
||||
(identities, balances, cachedBalances) =>
|
||||
Object.keys(identities).reduce((accounts, address) => {
|
||||
// TODO: mix in the identity state here as well, consolidating this
|
||||
// selector with `accountsWithSendEtherInfoSelector`
|
||||
let account = {};
|
||||
|
||||
if (balances[address]) {
|
||||
account = {
|
||||
...account,
|
||||
...balances[address],
|
||||
};
|
||||
},
|
||||
{},
|
||||
),
|
||||
}
|
||||
|
||||
if (account.balance === null || account.balance === undefined) {
|
||||
account = {
|
||||
...account,
|
||||
balance: cachedBalances && cachedBalances[address],
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...accounts,
|
||||
[address]: account,
|
||||
};
|
||||
}, {}),
|
||||
);
|
||||
|
||||
export function getSelectedAddress(state) {
|
||||
@ -325,11 +335,23 @@ export function getMetaMaskKeyrings(state) {
|
||||
return state.metamask.keyrings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get identity state.
|
||||
*
|
||||
* @param {object} state - Redux state
|
||||
* @returns {object} A map of account addresses to identities (which includes the account name)
|
||||
*/
|
||||
export function getMetaMaskIdentities(state) {
|
||||
return state.metamask.identities;
|
||||
}
|
||||
|
||||
export function getMetaMaskAccountsRaw(state) {
|
||||
/**
|
||||
* Get account balances state.
|
||||
*
|
||||
* @param {object} state - Redux state
|
||||
* @returns {object} A map of account addresses to account objects (which includes the account balance)
|
||||
*/
|
||||
export function getMetaMaskAccountBalances(state) {
|
||||
return state.metamask.accounts;
|
||||
}
|
||||
|
||||
@ -368,7 +390,7 @@ export const getMetaMaskAccountsConnected = createSelector(
|
||||
|
||||
export function isBalanceCached(state) {
|
||||
const selectedAccountBalance =
|
||||
state.metamask.accounts[getSelectedAddress(state)].balance;
|
||||
getMetaMaskAccountBalances(state)[getSelectedAddress(state)]?.balance;
|
||||
const cachedBalance = getSelectedAccountCachedBalance(state);
|
||||
|
||||
return Boolean(!selectedAccountBalance && cachedBalance);
|
||||
@ -1009,6 +1031,7 @@ function getAllowedAnnouncementIds(state) {
|
||||
20: currentKeyringIsLedger && isFirefox,
|
||||
21: isSwapsChain,
|
||||
22: true,
|
||||
24: state.metamask.hadAdvancedGasFeesSetPriorToMigration92_3 === true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -1309,23 +1332,26 @@ export function getIsMultiLayerFeeNetwork(state) {
|
||||
* To retrieve the maxBaseFee and priorityFee the user has set as default
|
||||
*
|
||||
* @param {*} state
|
||||
* @returns Boolean
|
||||
* @returns {{maxBaseFee: string, priorityFee: string} | undefined}
|
||||
*/
|
||||
export function getAdvancedGasFeeValues(state) {
|
||||
return state.metamask.advancedGasFee;
|
||||
}
|
||||
|
||||
/**
|
||||
* To check if the user has set advanced gas fee settings as default with a non empty maxBaseFee and priotityFee.
|
||||
*
|
||||
* @param {*} state
|
||||
* @returns Boolean
|
||||
*/
|
||||
export function getIsAdvancedGasFeeDefault(state) {
|
||||
const { advancedGasFee } = state.metamask;
|
||||
return (
|
||||
Boolean(advancedGasFee?.maxBaseFee) && Boolean(advancedGasFee?.priorityFee)
|
||||
);
|
||||
// This will not work when we switch to supporting multi-chain.
|
||||
// There are four non-test files that use this selector.
|
||||
// advanced-gas-fee-defaults
|
||||
// base-fee-input
|
||||
// priority-fee-input
|
||||
// useGasItemFeeDetails
|
||||
// The first three are part of the AdvancedGasFeePopover
|
||||
// The latter is used by the EditGasPopover
|
||||
// Both of those are used in Confirmations as well as transaction-list-item
|
||||
// All of the call sites have access to the GasFeeContext, which has a
|
||||
// transaction object set on it, but there are currently no guarantees that
|
||||
// the transaction has a chainId associated with it. To have this method
|
||||
// support multichain we'll need a reliable way for the chainId of the
|
||||
// transaction being modified to be available to all callsites and either
|
||||
// pass it in to the selector as a second parameter, or access it at the
|
||||
// callsite.
|
||||
return state.metamask.advancedGasFee[getCurrentChainId(state)];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -600,11 +600,6 @@ describe('Selectors', () => {
|
||||
priorityFee: '2',
|
||||
});
|
||||
});
|
||||
it('#getIsAdvancedGasFeeDefault', () => {
|
||||
const isAdvancedGasFeeDefault =
|
||||
selectors.getIsAdvancedGasFeeDefault(mockState);
|
||||
expect(isAdvancedGasFeeDefault).toStrictEqual(true);
|
||||
});
|
||||
it('#getAppIsLoading', () => {
|
||||
const appIsLoading = selectors.getAppIsLoading(mockState);
|
||||
expect(appIsLoading).toStrictEqual(false);
|
||||
|
@ -244,6 +244,9 @@ describe('Actions', () => {
|
||||
'0xAnotherAddress': '0x0',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xAnotherAddress': {},
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
@ -1876,6 +1879,9 @@ describe('Actions', () => {
|
||||
balance: '0x0',
|
||||
},
|
||||
},
|
||||
identities: {
|
||||
'0xFirstAddress': {},
|
||||
},
|
||||
cachedBalances: {
|
||||
'0x1': {
|
||||
'0xFirstAddress': '0x0',
|
||||
|
@ -3035,7 +3035,7 @@ export function detectNfts(): ThunkAction<
|
||||
}
|
||||
|
||||
export function setAdvancedGasFee(
|
||||
val: { maxBaseFee?: Hex; priorityFee?: Hex } | null,
|
||||
val: { chainId: Hex; maxBaseFee?: Hex; priorityFee?: Hex } | null,
|
||||
): ThunkAction<void, MetaMaskReduxState, unknown, AnyAction> {
|
||||
return (dispatch: MetaMaskReduxDispatch) => {
|
||||
dispatch(showLoadingIndication());
|
||||
|
64
yarn.lock
64
yarn.lock
@ -11249,15 +11249,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browser-resolve@npm:^1.11.0":
|
||||
version: 1.11.3
|
||||
resolution: "browser-resolve@npm:1.11.3"
|
||||
dependencies:
|
||||
resolve: 1.1.7
|
||||
checksum: 431bfc1a17406362a3010a2c35503eb7d1253dbcb8081c1ce236ddb0b954a33d52dcaf0b07f64c0f20394d6eeec1be4f6551da3734ce9ed5dcc38e876c96d5d5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browser-resolve@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "browser-resolve@npm:2.0.0"
|
||||
@ -11361,13 +11352,13 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"browserify@npm:^16.5.1":
|
||||
version: 16.5.1
|
||||
resolution: "browserify@npm:16.5.1"
|
||||
version: 16.5.2
|
||||
resolution: "browserify@npm:16.5.2"
|
||||
dependencies:
|
||||
JSONStream: ^1.0.3
|
||||
assert: ^1.4.0
|
||||
browser-pack: ^6.0.1
|
||||
browser-resolve: ^1.11.0
|
||||
browser-resolve: ^2.0.0
|
||||
browserify-zlib: ~0.2.0
|
||||
buffer: ~5.2.1
|
||||
cached-path-relative: ^1.0.0
|
||||
@ -11388,7 +11379,7 @@ __metadata:
|
||||
insert-module-globals: ^7.0.0
|
||||
labeled-stream-splicer: ^2.0.0
|
||||
mkdirp-classic: ^0.5.2
|
||||
module-deps: ^6.0.0
|
||||
module-deps: ^6.2.3
|
||||
os-browserify: ~0.3.0
|
||||
parents: ^1.0.1
|
||||
path-browserify: ~0.0.0
|
||||
@ -11414,7 +11405,7 @@ __metadata:
|
||||
xtend: ^4.0.0
|
||||
bin:
|
||||
browserify: bin/cmd.js
|
||||
checksum: 71c02959ffbcedc6364fb77db75dbf9ac7d945747414774287202327b7be9ae390257acfbf788455a90a088daa18c5134ec7b46315b747ff51ccddb73ad2e3ea
|
||||
checksum: 75dacf5c82355146b49a2febb3bf9f7898893931973cf901849791827e44782afcb562be7bc3a893d9022ae528fd6fccdf24fc8812cb5aa1b081bb7ce34c46b5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -12907,11 +12898,13 @@ __metadata:
|
||||
|
||||
"concat-stream@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "concat-stream@https://github.com/hugomrdias/concat-stream.git#commit=057bc7b5d6d8df26c8cf00a3f151b6721a0a8034"
|
||||
resolution: "concat-stream@npm:2.0.0"
|
||||
dependencies:
|
||||
buffer-from: ^1.0.0
|
||||
inherits: ^2.0.3
|
||||
readable-stream: ^3.0.2
|
||||
checksum: 1cef636e7061f310088706b34fe774e3960dff60a5039158b5e5c84795f6dd8a3411659324280405b8c5f1d7e8e3d4f68fa48e55963ed14953a44fef66423329
|
||||
typedarray: ^0.0.6
|
||||
checksum: d7f75d48f0ecd356c1545d87e22f57b488172811b1181d96021c7c4b14ab8855f5313280263dca44bb06e5222f274d047da3e290a38841ef87b59719bde967c7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -14828,11 +14821,11 @@ __metadata:
|
||||
linkType: hard
|
||||
|
||||
"dot-prop@npm:^4.1.0":
|
||||
version: 5.2.0
|
||||
resolution: "dot-prop@npm:5.2.0"
|
||||
version: 4.2.1
|
||||
resolution: "dot-prop@npm:4.2.1"
|
||||
dependencies:
|
||||
is-obj: ^2.0.0
|
||||
checksum: 709a8208bff4fc4d5a11e357957a9e59ed625d7db909d14ea1e0dbeb30d26c25325a6e64ea27ed96fb17978cc13c7e38cf30bac17bb81eb9b5a740a4fe909a87
|
||||
is-obj: ^1.0.0
|
||||
checksum: 5f4f19aa440bc548670d87f2adcbd105fa6842cd1fba3165a8a2b1380568ae82862acf8ebafcc6093fa062505d7d08d7155c7ba9a88da212f7348e95ef2bdce6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -16331,11 +16324,11 @@ __metadata:
|
||||
|
||||
"ethereumjs-abi@git+https://github.com/ethereumjs/ethereumjs-abi.git, ethereumjs-abi@npm:0.6.8, ethereumjs-abi@npm:^0.6.4, ethereumjs-abi@npm:^0.6.8":
|
||||
version: 0.6.8
|
||||
resolution: "ethereumjs-abi@https://github.com/ethereumjs/ethereumjs-abi.git#commit=ee3994657fa7a427238e6ba92a84d0b529bbcde0"
|
||||
resolution: "ethereumjs-abi@npm:0.6.8"
|
||||
dependencies:
|
||||
bn.js: ^4.11.8
|
||||
ethereumjs-util: ^6.0.0
|
||||
checksum: ae074be0bb012857ab5d3ae644d1163b908a48dd724b7d2567cfde309dc72222d460438f2411936a70dc949dc604ce1ef7118f7273bd525815579143c907e336
|
||||
checksum: cede2a8ae7c7e04eeaec079c2f925601a25b2ef75cf9230e7c5da63b4ea27883b35447365a47e35c1e831af520973a2252af89022c292c18a09a4607821a366b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -20779,20 +20772,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-obj@npm:^1.0.1":
|
||||
"is-obj@npm:^1.0.0, is-obj@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "is-obj@npm:1.0.1"
|
||||
checksum: 3ccf0efdea12951e0b9c784e2b00e77e87b2f8bd30b42a498548a8afcc11b3287342a2030c308e473e93a7a19c9ea7854c99a8832a476591c727df2a9c79796c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-obj@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "is-obj@npm:2.0.0"
|
||||
checksum: c9916ac8f4621962a42f5e80e7ffdb1d79a3fab7456ceaeea394cd9e0858d04f985a9ace45be44433bf605673c8be8810540fe4cc7f4266fc7526ced95af5a08
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-object@npm:^1.0.1, is-object@npm:~1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "is-object@npm:1.0.1"
|
||||
@ -25831,7 +25817,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"module-deps@npm:^6.0.0, module-deps@npm:^6.2.3":
|
||||
"module-deps@npm:^6.2.3":
|
||||
version: 6.2.3
|
||||
resolution: "module-deps@npm:6.2.3"
|
||||
dependencies:
|
||||
@ -28723,7 +28709,7 @@ __metadata:
|
||||
bin:
|
||||
pbjs: bin/pbjs
|
||||
pbts: bin/pbts
|
||||
checksum: 6b7fd7540d74350d65c38f69f398c9995ae019da070e79d9cd464a458c6d19b40b07c9a026be4e10704c824a344b603307745863310c50026ebd661ce4da0663
|
||||
checksum: b2fc6a01897b016c2a7e43a854ab4a3c57080f61be41e552235436e7a730711b8e89e47cb4ae52f0f065b5ab5d5989fc932f390337ce3a8ccf07203415700850
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -30618,13 +30604,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@npm:1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "resolve@npm:1.1.7"
|
||||
checksum: afd20873fbde7641c9125efe3f940c2a99f6b1f90f1b7b743e744bdaac1cb105b2e4e0317bcc052ed7e31d57afa86b394a4dc9a1b33a297977be134fdf0250ab
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@npm:^1.1.4, resolve@npm:^1.1.5, resolve@npm:^1.1.6, resolve@npm:^1.1.7, resolve@npm:^1.10.0, resolve@npm:^1.10.1, resolve@npm:^1.11.1, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.18.1, resolve@npm:^1.19.0, resolve@npm:^1.20.0, resolve@npm:^1.21.0, resolve@npm:^1.22.0, resolve@npm:^1.22.1, resolve@npm:^1.22.3, resolve@npm:^1.4.0":
|
||||
version: 1.22.3
|
||||
resolution: "resolve@npm:1.22.3"
|
||||
@ -30651,13 +30630,6 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@patch:resolve@1.1.7#~builtin<compat/resolve>":
|
||||
version: 1.1.7
|
||||
resolution: "resolve@patch:resolve@npm%3A1.1.7#~builtin<compat/resolve>::version=1.1.7&hash=07638b"
|
||||
checksum: e9dbca78600ae56835c43a09f1276876c883e4b4bbd43e2683fa140671519d2bdebeb1c1576ca87c8c508ae2987b3ec481645ac5d3054b0f23254cfc1ce49942
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"resolve@patch:resolve@^1.1.4#~builtin<compat/resolve>, resolve@patch:resolve@^1.1.5#~builtin<compat/resolve>, resolve@patch:resolve@^1.1.6#~builtin<compat/resolve>, resolve@patch:resolve@^1.1.7#~builtin<compat/resolve>, resolve@patch:resolve@^1.10.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.10.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.11.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.14.2#~builtin<compat/resolve>, resolve@patch:resolve@^1.15.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.17.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.18.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.19.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.20.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.21.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.0#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.1#~builtin<compat/resolve>, resolve@patch:resolve@^1.22.3#~builtin<compat/resolve>, resolve@patch:resolve@^1.4.0#~builtin<compat/resolve>":
|
||||
version: 1.22.3
|
||||
resolution: "resolve@patch:resolve@npm%3A1.22.3#~builtin<compat/resolve>::version=1.22.3&hash=07638b"
|
||||
|
Loading…
Reference in New Issue
Block a user