From e056c88ba7daf20fe1f02c7cbe66cc967fdda362 Mon Sep 17 00:00:00 2001 From: Alaa Hadad Date: Wed, 1 Dec 2021 21:22:08 +0400 Subject: [PATCH] Feature: Transaction Insights (#12881) * integration for tx decoding confirmation and history view * upgrading @truffle/decoder to latest release 5.1.0 * Update acorn and colors patches * feat: remove redundant styling * feat: basic integration for nickname components * feat: wiring functionality of adding new nickname * feat: wire functionality of showing nickname modal * feat: link the nickname popover with add/update popover * feat: moving forward with address nicknames integration * feat: fixing a bug related to passing chainId in addressBook * feat: populating memo prop in addressbook entry * feat: add explorer link * feat: bug fixing update nickname component * feat: fix proptypes * feat: adding tooltip for copying nickname address * featL fix styling for tx-details page * feat: optimize code for error handling * feat: limiting transaction decoding to tx with data * feat: remove tree UI component * feat: adding request to check for tx decoding supported networks * feat: showing data hex component * feat: fix react warnings * feat: remove extra margin in tx decoding * Remove unused package @truffle/source-map-utils * Ensure messages get translated * feat: link tx-decoding addresses with nicknames * Omit value for boolean attributes * Fix props reading in CopyRawData * fix: fixing issue with transaltion * Fix lint errors in TransactionDecoding - Remove unused import - Reorder imports - Address conflict between caught `error` and error state flag by renaming state flag to `hasError` - Fix requestUrl identifier casing and use of template string - Ensure `useEffect` gets passed the deps it needs - Add scope braces around case statement where it's needed - Omit literal `true` for boolean jsx attribute - Refactor nested ternary as `if` statements * fix: revert fetchWithCache modifications * Fix linting for TransactionListItemDetails - Remove unused import - Fix import spacing - Remove unused prop dereference - Fix string interpolation for translated From/To * Moving to popover pattern * fix: sass color variable * Omit value for boolean attribute * Remove changes from modal.js * fix: refactor nickname popovers * Ensure const gets declared before it's used * Fix linting for ConfirmTransactionBase - Remove unused prop chainId - Stop destructuring an unused field * fix: refactor usage of nicknames popovers in send-content-container * fix: remove extra prop updateAccountNicknameModal * fix: refactor code for address.component * fix: remove extra tooltip * Ensure NicknamePopovers always returns component * Fix linting for NicknamePopover component - Fix useCallback deps - Switch ternary to logical-or * Fix linting for SenderToRecipient ... by fixing import order * Remove unused addressCopied state * Delete empty file * fix: remove sender-to-recipient.container * fix: refactor usage of nickname popovers in confirm-page-container * fix: bug related to state variable * Stylelint fix * Lint fix * Change "Total Amount" to "Total" * Lint fix locales * Update address-book.spec.js * e2e test update * Update e2e tests * Fix issue where absence of function params in data hex tab would result in rendering a string * Fix border radius, and width and height in small notification windows, of the update-nickname-popover * Remove fake await * Clean up * Clean up Co-authored-by: Alaa Hadad Co-authored-by: Dan Miller Co-authored-by: g. nicholas d'andrea --- app/_locales/am/messages.json | 3 - app/_locales/ar/messages.json | 3 - app/_locales/bg/messages.json | 3 - app/_locales/bn/messages.json | 3 - app/_locales/ca/messages.json | 3 - app/_locales/da/messages.json | 3 - app/_locales/de/messages.json | 3 - app/_locales/el/messages.json | 3 - app/_locales/en/messages.json | 22 +- app/_locales/es/messages.json | 3 - app/_locales/es_419/messages.json | 3 - app/_locales/et/messages.json | 3 - app/_locales/fa/messages.json | 3 - app/_locales/fi/messages.json | 3 - app/_locales/fil/messages.json | 3 - app/_locales/fr/messages.json | 3 - app/_locales/he/messages.json | 3 - app/_locales/hi/messages.json | 3 - app/_locales/hr/messages.json | 3 - app/_locales/hu/messages.json | 3 - app/_locales/id/messages.json | 3 - app/_locales/it/messages.json | 3 - app/_locales/ja/messages.json | 3 - app/_locales/kn/messages.json | 3 - app/_locales/ko/messages.json | 3 - app/_locales/lt/messages.json | 3 - app/_locales/lv/messages.json | 3 - app/_locales/ms/messages.json | 3 - app/_locales/no/messages.json | 3 - app/_locales/ph/messages.json | 3 - app/_locales/pl/messages.json | 3 - app/_locales/pt_BR/messages.json | 3 - app/_locales/ro/messages.json | 3 - app/_locales/ru/messages.json | 3 - app/_locales/sk/messages.json | 3 - app/_locales/sl/messages.json | 3 - app/_locales/sr/messages.json | 3 - app/_locales/sv/messages.json | 3 - app/_locales/sw/messages.json | 3 - app/_locales/tl/messages.json | 3 - app/_locales/uk/messages.json | 3 - app/_locales/vi/messages.json | 3 - app/_locales/zh_CN/messages.json | 3 - app/_locales/zh_TW/messages.json | 3 - app/images/icons/collapse.svg | 26 ++ app/images/icons/expand.svg | 28 ++ package.json | 3 + patches/acorn+7.4.1.patch | 13 + patches/colors+1.4.0.patch | 14 + test/e2e/metamask-ui.spec.js | 4 +- test/e2e/tests/address-book.spec.js | 13 +- ui/components/app/app-components.scss | 1 + .../confirm-page-container-container.test.js | 7 - ...onfirm-page-container-content.component.js | 9 +- .../confirm-page-container-content/index.scss | 6 +- .../confirm-page-container.component.js | 35 +- .../confirm-page-container.container.js | 29 +- .../app/modals/nickname-popovers/index.js | 1 + .../nickname-popovers.component.js | 72 ++++ .../app/transaction-breakdown/index.scss | 14 +- .../transaction-breakdown-row/index.scss | 6 +- .../transaction-breakdown-row.component.js | 9 +- .../transaction-breakdown.component.js | 9 +- .../decoding/address/address.component.js | 71 ++++ .../components/decoding/address/index.js | 1 + .../components/decoding/address/index.scss | 12 + .../copy-raw-data/copy-raw-data.component.js | 38 +++ .../components/ui/copy-raw-data/index.js | 1 + .../components/ui/copy-raw-data/index.scss | 30 ++ .../app/transaction-decoding/constants.js | 5 + .../app/transaction-decoding/index.js | 1 + .../app/transaction-decoding/index.scss | 169 ++++++++++ .../transaction-decoding.component.js | 219 +++++++++++++ .../transaction-decoding.util.js | 30 ++ .../transaction-list-item-details/index.scss | 94 +++++- ...transaction-list-item-details.component.js | 111 ++++--- .../transaction-list-item.component.js | 10 + .../app/transaction-status/index.scss | 4 + .../transaction-status.component.js | 7 +- ui/components/ui/disclosure/disclosure.js | 51 +++ ui/components/ui/disclosure/disclosure.scss | 46 +++ ui/components/ui/disclosure/index.js | 1 + ui/components/ui/nickname-popover/index.scss | 9 +- .../nickname-popover.component.js | 56 +++- .../sender-to-recipient.component.js | 61 ++-- ui/components/ui/ui-components.scss | 1 + .../ui/update-nickname-popover/index.scss | 12 +- .../update-nickname-popover.js | 14 +- .../confirm-transaction-base.component.js | 50 ++- .../confirm-transaction-base.container.js | 6 +- .../send-content/send-content.component.js | 36 +- .../send-content/send-content.container.js | 29 +- yarn.lock | 309 +++++++++++++++++- 93 files changed, 1571 insertions(+), 363 deletions(-) create mode 100644 app/images/icons/collapse.svg create mode 100644 app/images/icons/expand.svg create mode 100644 patches/acorn+7.4.1.patch create mode 100644 patches/colors+1.4.0.patch create mode 100644 ui/components/app/modals/nickname-popovers/index.js create mode 100644 ui/components/app/modals/nickname-popovers/nickname-popovers.component.js create mode 100644 ui/components/app/transaction-decoding/components/decoding/address/address.component.js create mode 100644 ui/components/app/transaction-decoding/components/decoding/address/index.js create mode 100644 ui/components/app/transaction-decoding/components/decoding/address/index.scss create mode 100644 ui/components/app/transaction-decoding/components/ui/copy-raw-data/copy-raw-data.component.js create mode 100644 ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.js create mode 100644 ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.scss create mode 100644 ui/components/app/transaction-decoding/constants.js create mode 100644 ui/components/app/transaction-decoding/index.js create mode 100644 ui/components/app/transaction-decoding/index.scss create mode 100644 ui/components/app/transaction-decoding/transaction-decoding.component.js create mode 100644 ui/components/app/transaction-decoding/transaction-decoding.util.js create mode 100644 ui/components/ui/disclosure/disclosure.js create mode 100644 ui/components/ui/disclosure/disclosure.scss create mode 100644 ui/components/ui/disclosure/index.js diff --git a/app/_locales/am/messages.json b/app/_locales/am/messages.json index aa341612d..1d962c06e 100644 --- a/app/_locales/am/messages.json +++ b/app/_locales/am/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "ተቀድቷል" }, - "copiedTransactionId": { - "message": "የተቀዳ የግብይት መለያ ቁጥር" - }, "copyAddress": { "message": "አድራሻን ወደ ቅንጥብ ሰሌዳ ቅዳ" }, diff --git a/app/_locales/ar/messages.json b/app/_locales/ar/messages.json index aa6a76276..1966aab0b 100644 --- a/app/_locales/ar/messages.json +++ b/app/_locales/ar/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "تم النسخ." }, - "copiedTransactionId": { - "message": "تم نسخ معرف المعاملة" - }, "copyAddress": { "message": "نسخ العنوان إلى الحافظة" }, diff --git a/app/_locales/bg/messages.json b/app/_locales/bg/messages.json index f9cabde5d..ab7c09e24 100644 --- a/app/_locales/bg/messages.json +++ b/app/_locales/bg/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Копирано!" }, - "copiedTransactionId": { - "message": "Копиран идентификационен номер на транзакцията" - }, "copyAddress": { "message": "Копирайте адреса в клипборда" }, diff --git a/app/_locales/bn/messages.json b/app/_locales/bn/messages.json index 5d36aabe9..ff4fe49a6 100644 --- a/app/_locales/bn/messages.json +++ b/app/_locales/bn/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "কপি করা হয়েছে!" }, - "copiedTransactionId": { - "message": "কপি করা লেনদেনের আইডি" - }, "copyAddress": { "message": "ক্লিপবোর্ডে ঠিকানা কপি করুন" }, diff --git a/app/_locales/ca/messages.json b/app/_locales/ca/messages.json index b29188344..beea7d58a 100644 --- a/app/_locales/ca/messages.json +++ b/app/_locales/ca/messages.json @@ -215,9 +215,6 @@ "copiedExclamation": { "message": "S'ha copiat!" }, - "copiedTransactionId": { - "message": "ID de transacció copiada" - }, "copyAddress": { "message": "Copiar adreça al porta-retalls" }, diff --git a/app/_locales/da/messages.json b/app/_locales/da/messages.json index 8d288c33f..72fd08ac5 100644 --- a/app/_locales/da/messages.json +++ b/app/_locales/da/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Kopieret!" }, - "copiedTransactionId": { - "message": "Kopieret transaktions-id" - }, "copyAddress": { "message": "Kopier adresse til udklipsholder" }, diff --git a/app/_locales/de/messages.json b/app/_locales/de/messages.json index bca6b887a..88a3b99c7 100644 --- a/app/_locales/de/messages.json +++ b/app/_locales/de/messages.json @@ -209,9 +209,6 @@ "copiedExclamation": { "message": "Kopiert!" }, - "copiedTransactionId": { - "message": "Transaktions-ID kopiert" - }, "copyAddress": { "message": "Adresse in die Zwischenablage kopieren" }, diff --git a/app/_locales/el/messages.json b/app/_locales/el/messages.json index 1b880074b..c74b44875 100644 --- a/app/_locales/el/messages.json +++ b/app/_locales/el/messages.json @@ -215,9 +215,6 @@ "copiedExclamation": { "message": "Έγινε αντιγραφή!" }, - "copiedTransactionId": { - "message": "Αντιγράφηκε το Αναγνωριστικό Συναλλαγής" - }, "copyAddress": { "message": "Αντιγράψτε τη διεύθυνση στο πρόχειρο" }, diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 2075b8642..3aef9a1a8 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -351,10 +351,6 @@ "message": "Swap", "description": "This is used with viewOnEtherscan e.g View Swap on Etherscan" }, - "blockExplorerTransactionAction": { - "message": "Transaction", - "description": "This is used with viewOnCustomBlockExplorer and viewOnEtherscan e.g View Transaction on Etherscan" - }, "blockExplorerUrl": { "message": "Block Explorer URL" }, @@ -581,15 +577,15 @@ "copiedExclamation": { "message": "Copied!" }, - "copiedTransactionId": { - "message": "Copied Transaction ID" - }, "copyAddress": { "message": "Copy address to clipboard" }, "copyPrivateKey": { "message": "This is your private key (click to copy)" }, + "copyRawTransactionData": { + "message": "Copy raw transaction data" + }, "copyToClipboard": { "message": "Copy to clipboard" }, @@ -666,6 +662,9 @@ "dataBackupFoundInfo": { "message": "Some of your account data was backed up during a previous installation of MetaMask. This could include your settings, contacts, and tokens. Would you like to restore this data now?" }, + "dataHex": { + "message": "Hex" + }, "decimal": { "message": "Token Decimal" }, @@ -767,6 +766,9 @@ "edit": { "message": "Edit" }, + "editANickname": { + "message": "Edit nickname" + }, "editAddressNickname": { "message": "Edit address nickname" }, @@ -3043,6 +3045,12 @@ "transactionCreated": { "message": "Transaction created with a value of $1 at $2." }, + "transactionData": { + "message": "Transaction data" + }, + "transactionDecodingUnsupportedNetworkError": { + "message": "Transaction decoding is not available for chainId $1" + }, "transactionDetailDappGasMoreInfo": { "message": "Site suggested" }, diff --git a/app/_locales/es/messages.json b/app/_locales/es/messages.json index 8418ba8e6..dfa9b60f3 100644 --- a/app/_locales/es/messages.json +++ b/app/_locales/es/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "¡Copiado!" }, - "copiedTransactionId": { - "message": "Id. de transacción copiado" - }, "copyAddress": { "message": "Copiar dirección al Portapapeles" }, diff --git a/app/_locales/es_419/messages.json b/app/_locales/es_419/messages.json index 8418ba8e6..dfa9b60f3 100644 --- a/app/_locales/es_419/messages.json +++ b/app/_locales/es_419/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "¡Copiado!" }, - "copiedTransactionId": { - "message": "Id. de transacción copiado" - }, "copyAddress": { "message": "Copiar dirección al Portapapeles" }, diff --git a/app/_locales/et/messages.json b/app/_locales/et/messages.json index 66ce15ec5..a3297815c 100644 --- a/app/_locales/et/messages.json +++ b/app/_locales/et/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Kopeeritud!" }, - "copiedTransactionId": { - "message": "Kopeeritud tehingu ID" - }, "copyAddress": { "message": "Kopeeri aadress lõikelauale" }, diff --git a/app/_locales/fa/messages.json b/app/_locales/fa/messages.json index f6fd7e476..d76b2f99c 100644 --- a/app/_locales/fa/messages.json +++ b/app/_locales/fa/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "کپی شد!" }, - "copiedTransactionId": { - "message": "آی دی معامله کاپی شده" - }, "copyAddress": { "message": "کاپی آدرس به کلیپ بورد" }, diff --git a/app/_locales/fi/messages.json b/app/_locales/fi/messages.json index 8260f9ad4..1f453fb70 100644 --- a/app/_locales/fi/messages.json +++ b/app/_locales/fi/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Kopioitu" }, - "copiedTransactionId": { - "message": "Kopioitu tapahtuman tunnus" - }, "copyAddress": { "message": "Kopioi osoite leikepöydälle" }, diff --git a/app/_locales/fil/messages.json b/app/_locales/fil/messages.json index 23001c136..2a12119cf 100644 --- a/app/_locales/fil/messages.json +++ b/app/_locales/fil/messages.json @@ -197,9 +197,6 @@ "copiedExclamation": { "message": "Nakopya!" }, - "copiedTransactionId": { - "message": "Nakopya ang Transaction ID" - }, "copyAddress": { "message": "Kopyahin ang address sa clipboard" }, diff --git a/app/_locales/fr/messages.json b/app/_locales/fr/messages.json index 7ed3dbcdd..8fd682d8c 100644 --- a/app/_locales/fr/messages.json +++ b/app/_locales/fr/messages.json @@ -209,9 +209,6 @@ "copiedExclamation": { "message": "Copié!" }, - "copiedTransactionId": { - "message": "ID de transaction copié" - }, "copyAddress": { "message": "Copier l'addresse dans le presse-papier" }, diff --git a/app/_locales/he/messages.json b/app/_locales/he/messages.json index 905020755..1e49f42db 100644 --- a/app/_locales/he/messages.json +++ b/app/_locales/he/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "הועתק!" }, - "copiedTransactionId": { - "message": "מזהה עסקה הועתק" - }, "copyAddress": { "message": "העתק כתובת ללוח" }, diff --git a/app/_locales/hi/messages.json b/app/_locales/hi/messages.json index 65f6640c1..eabbe333d 100644 --- a/app/_locales/hi/messages.json +++ b/app/_locales/hi/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "कॉपी किया गया!" }, - "copiedTransactionId": { - "message": "कॉपी की गई लेनदेन ID" - }, "copyAddress": { "message": "क्लिपबोर्ड पर पता कॉपी करें" }, diff --git a/app/_locales/hr/messages.json b/app/_locales/hr/messages.json index 7a3a94c8f..39d3f0f0e 100644 --- a/app/_locales/hr/messages.json +++ b/app/_locales/hr/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Kopirano!" }, - "copiedTransactionId": { - "message": "Kopirana identifikacijska oznaka transakcije" - }, "copyAddress": { "message": "Kopiraj adresu u međuspremnik" }, diff --git a/app/_locales/hu/messages.json b/app/_locales/hu/messages.json index 18f2cf317..9a36bbaa4 100644 --- a/app/_locales/hu/messages.json +++ b/app/_locales/hu/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Kimásolva!" }, - "copiedTransactionId": { - "message": "Másolt tranzakció-azonosító" - }, "copyAddress": { "message": "Másolja a címet a vágólapra" }, diff --git a/app/_locales/id/messages.json b/app/_locales/id/messages.json index 9f0744379..b3d4f6679 100644 --- a/app/_locales/id/messages.json +++ b/app/_locales/id/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "Disalin!" }, - "copiedTransactionId": { - "message": "ID Transaksi yang Disalin" - }, "copyAddress": { "message": "Salin alamat ke clipboard" }, diff --git a/app/_locales/it/messages.json b/app/_locales/it/messages.json index 1e8c000de..640ad8ba6 100644 --- a/app/_locales/it/messages.json +++ b/app/_locales/it/messages.json @@ -356,9 +356,6 @@ "copiedExclamation": { "message": "Copiato!" }, - "copiedTransactionId": { - "message": "ID Transazione Copiato" - }, "copyAddress": { "message": "Copia l'indirizzo" }, diff --git a/app/_locales/ja/messages.json b/app/_locales/ja/messages.json index cea2eda8c..cb626fa73 100644 --- a/app/_locales/ja/messages.json +++ b/app/_locales/ja/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "コピーされました!" }, - "copiedTransactionId": { - "message": "コピーされたトランザクション ID" - }, "copyAddress": { "message": "アドレスをクリップボードにコピー" }, diff --git a/app/_locales/kn/messages.json b/app/_locales/kn/messages.json index bf17d9ce0..25f870717 100644 --- a/app/_locales/kn/messages.json +++ b/app/_locales/kn/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "ನಕಲಿಸಲಾಗಿದೆ!" }, - "copiedTransactionId": { - "message": "ವ್ಯವಹಾರ ID ಅನ್ನು ನಕಲಿಸಲಾಗಿದೆ" - }, "copyAddress": { "message": "ವಿಳಾಸವನ್ನು ಕ್ಲಿಪ್‌ಬೋರ್ಡ್‌ಗೆ ನಕಲಿಸಿ" }, diff --git a/app/_locales/ko/messages.json b/app/_locales/ko/messages.json index f4c30767d..b4bcaa6f8 100644 --- a/app/_locales/ko/messages.json +++ b/app/_locales/ko/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "복사 완료!" }, - "copiedTransactionId": { - "message": "거래 ID 복사됨" - }, "copyAddress": { "message": "주소를 클립보드에 복사" }, diff --git a/app/_locales/lt/messages.json b/app/_locales/lt/messages.json index 80536f454..702c4784d 100644 --- a/app/_locales/lt/messages.json +++ b/app/_locales/lt/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Nukopijuota!" }, - "copiedTransactionId": { - "message": "Nukopijuotas operacijos ID" - }, "copyAddress": { "message": "Kopijuoti adresą į iškarpinę" }, diff --git a/app/_locales/lv/messages.json b/app/_locales/lv/messages.json index 4531820a4..4de401ac7 100644 --- a/app/_locales/lv/messages.json +++ b/app/_locales/lv/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Nokopēts!" }, - "copiedTransactionId": { - "message": "Nokopētais darījuma ID" - }, "copyAddress": { "message": "Iekopēt adresi starpliktuvē" }, diff --git a/app/_locales/ms/messages.json b/app/_locales/ms/messages.json index 85d021235..10ea16960 100644 --- a/app/_locales/ms/messages.json +++ b/app/_locales/ms/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Disalin!" }, - "copiedTransactionId": { - "message": "ID Transaksi yang Disalin" - }, "copyAddress": { "message": "Salin alamat kepada papan klip" }, diff --git a/app/_locales/no/messages.json b/app/_locales/no/messages.json index 249ea5d10..a567c8762 100644 --- a/app/_locales/no/messages.json +++ b/app/_locales/no/messages.json @@ -215,9 +215,6 @@ "copiedExclamation": { "message": "Kopiert!" }, - "copiedTransactionId": { - "message": "Kopiert transaksjonsidentifikasjon" - }, "copyAddress": { "message": "Kopier adresse til utklippstavlen " }, diff --git a/app/_locales/ph/messages.json b/app/_locales/ph/messages.json index 571178bc1..a821a4374 100644 --- a/app/_locales/ph/messages.json +++ b/app/_locales/ph/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "Nakopya na!" }, - "copiedTransactionId": { - "message": "Nakopya ang Transaction ID" - }, "copyAddress": { "message": "Kopyahin ang address sa clipboard" }, diff --git a/app/_locales/pl/messages.json b/app/_locales/pl/messages.json index 0d0f59571..c58abc6f2 100644 --- a/app/_locales/pl/messages.json +++ b/app/_locales/pl/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Skopiowane!" }, - "copiedTransactionId": { - "message": "Skopiowano identyfikator transakcji" - }, "copyAddress": { "message": "Skopiuj adres do schowka" }, diff --git a/app/_locales/pt_BR/messages.json b/app/_locales/pt_BR/messages.json index bd2e54f12..6ea9d5a1a 100644 --- a/app/_locales/pt_BR/messages.json +++ b/app/_locales/pt_BR/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "Copiado!" }, - "copiedTransactionId": { - "message": "ID da transação copiado" - }, "copyAddress": { "message": "Copiar endereço para área de transferência" }, diff --git a/app/_locales/ro/messages.json b/app/_locales/ro/messages.json index 167fb1c26..0aa456017 100644 --- a/app/_locales/ro/messages.json +++ b/app/_locales/ro/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Copiat!" }, - "copiedTransactionId": { - "message": "ID-ul tranzacției a fost copiat" - }, "copyAddress": { "message": "Copiere adresă în clipboard" }, diff --git a/app/_locales/ru/messages.json b/app/_locales/ru/messages.json index 40ccc7d45..9fa8ea319 100644 --- a/app/_locales/ru/messages.json +++ b/app/_locales/ru/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "Скопировано!" }, - "copiedTransactionId": { - "message": "Скопированный идентификатор транзакции" - }, "copyAddress": { "message": "Скопировать адрес в буфер обмена" }, diff --git a/app/_locales/sk/messages.json b/app/_locales/sk/messages.json index 47097b3d1..c4d6facaa 100644 --- a/app/_locales/sk/messages.json +++ b/app/_locales/sk/messages.json @@ -212,9 +212,6 @@ "copiedExclamation": { "message": "Zkopírováno!" }, - "copiedTransactionId": { - "message": "Kopírované ID transakcie" - }, "copyAddress": { "message": "Kopírovať adresu do schránky" }, diff --git a/app/_locales/sl/messages.json b/app/_locales/sl/messages.json index e5b7b9e44..6d6bef812 100644 --- a/app/_locales/sl/messages.json +++ b/app/_locales/sl/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Kopirano!" }, - "copiedTransactionId": { - "message": "ID transakcije skopirana" - }, "copyAddress": { "message": "Kopiraj naslov v odložišče" }, diff --git a/app/_locales/sr/messages.json b/app/_locales/sr/messages.json index 08eed9bf0..ce980b88e 100644 --- a/app/_locales/sr/messages.json +++ b/app/_locales/sr/messages.json @@ -215,9 +215,6 @@ "copiedExclamation": { "message": "Kopirano!" }, - "copiedTransactionId": { - "message": "Kopiran identifikator transakcije" - }, "copyAddress": { "message": "Kopirajte adresu u ostavu" }, diff --git a/app/_locales/sv/messages.json b/app/_locales/sv/messages.json index 1c07f7dfc..f3e651032 100644 --- a/app/_locales/sv/messages.json +++ b/app/_locales/sv/messages.json @@ -212,9 +212,6 @@ "copiedExclamation": { "message": "Kopierades!" }, - "copiedTransactionId": { - "message": "Kopierade transaktions-ID" - }, "copyAddress": { "message": "Kopiera adress till urklipp" }, diff --git a/app/_locales/sw/messages.json b/app/_locales/sw/messages.json index 05436654c..ec712cc65 100644 --- a/app/_locales/sw/messages.json +++ b/app/_locales/sw/messages.json @@ -212,9 +212,6 @@ "copiedExclamation": { "message": "Imenakiliwa!" }, - "copiedTransactionId": { - "message": "Imenakili Utambulisho wa Muamala" - }, "copyAddress": { "message": "Nakili anwani kwenye ubao wa kunakilia" }, diff --git a/app/_locales/tl/messages.json b/app/_locales/tl/messages.json index cbd9275ce..0c7649881 100644 --- a/app/_locales/tl/messages.json +++ b/app/_locales/tl/messages.json @@ -344,9 +344,6 @@ "copiedExclamation": { "message": "Nakopya na!" }, - "copiedTransactionId": { - "message": "Nakopya ang ID ng Transaksyon" - }, "copyAddress": { "message": "Kopyahin ang address sa clipboard" }, diff --git a/app/_locales/uk/messages.json b/app/_locales/uk/messages.json index 8968e2f2e..c18062e0b 100644 --- a/app/_locales/uk/messages.json +++ b/app/_locales/uk/messages.json @@ -218,9 +218,6 @@ "copiedExclamation": { "message": "Скопійовано!" }, - "copiedTransactionId": { - "message": "ID Скопійованої транзакції" - }, "copyAddress": { "message": "Копіювати адресу в буфер обміну" }, diff --git a/app/_locales/vi/messages.json b/app/_locales/vi/messages.json index 584c892c3..22523a6f0 100644 --- a/app/_locales/vi/messages.json +++ b/app/_locales/vi/messages.json @@ -416,9 +416,6 @@ "copiedExclamation": { "message": "Đã sao chép!" }, - "copiedTransactionId": { - "message": "Đã sao chép mã giao dịch" - }, "copyAddress": { "message": "Sao chép địa chỉ vào khay nhớ tạm" }, diff --git a/app/_locales/zh_CN/messages.json b/app/_locales/zh_CN/messages.json index c65164366..92e09313c 100644 --- a/app/_locales/zh_CN/messages.json +++ b/app/_locales/zh_CN/messages.json @@ -395,9 +395,6 @@ "copiedExclamation": { "message": "已复制" }, - "copiedTransactionId": { - "message": "交易 ID 复制成功" - }, "copyAddress": { "message": "复制地址到剪贴板" }, diff --git a/app/_locales/zh_TW/messages.json b/app/_locales/zh_TW/messages.json index 91a527f48..966e0d924 100644 --- a/app/_locales/zh_TW/messages.json +++ b/app/_locales/zh_TW/messages.json @@ -227,9 +227,6 @@ "copiedExclamation": { "message": "已複製!" }, - "copiedTransactionId": { - "message": "已複製的交易 ID" - }, "copyAddress": { "message": "複製到剪貼簿" }, diff --git a/app/images/icons/collapse.svg b/app/images/icons/collapse.svg new file mode 100644 index 000000000..74d6207c9 --- /dev/null +++ b/app/images/icons/collapse.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/images/icons/expand.svg b/app/images/icons/expand.svg new file mode 100644 index 000000000..6a6146840 --- /dev/null +++ b/app/images/icons/expand.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json index 5b6ef5d1f..219c64f3b 100644 --- a/package.json +++ b/package.json @@ -125,6 +125,8 @@ "@reduxjs/toolkit": "^1.6.2", "@sentry/browser": "^6.0.0", "@sentry/integrations": "^6.0.0", + "@truffle/codec": "^0.11.18", + "@truffle/decoder": "^5.1.0", "@zxing/browser": "^0.0.10", "@zxing/library": "0.8.0", "analytics-node": "^3.4.0-beta.3", @@ -260,6 +262,7 @@ "babelify": "^10.0.0", "bify-module-groups": "^1.0.0", "brfs": "^2.0.2", + "browser-util-inspect": "^0.2.0", "browserify": "^16.5.1", "chalk": "^3.0.0", "chromedriver": "^95.0.0", diff --git a/patches/acorn+7.4.1.patch b/patches/acorn+7.4.1.patch new file mode 100644 index 000000000..061aa1281 --- /dev/null +++ b/patches/acorn+7.4.1.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/acorn/dist/acorn.js b/node_modules/acorn/dist/acorn.js +index 0523f0e..9d3d5c2 100644 +--- a/node_modules/acorn/dist/acorn.js ++++ b/node_modules/acorn/dist/acorn.js +@@ -1835,7 +1835,7 @@ + if (checkClashes) { + if (has(checkClashes, expr.name)) + { this.raiseRecoverable(expr.start, "Argument name clash"); } +- checkClashes[expr.name] = true; ++ Object.defineProperty(checkClashes, expr.name, { value: true, writable: true, enumerable: true, configurable: true }) + } + if (bindingType !== BIND_NONE && bindingType !== BIND_OUTSIDE) { this.declareName(expr.name, bindingType, expr.start); } + break diff --git a/patches/colors+1.4.0.patch b/patches/colors+1.4.0.patch new file mode 100644 index 000000000..9ea49d833 --- /dev/null +++ b/patches/colors+1.4.0.patch @@ -0,0 +1,14 @@ +diff --git a/node_modules/colors/lib/extendStringPrototype.js b/node_modules/colors/lib/extendStringPrototype.js +index 46fd386..c7d0fc5 100644 +--- a/node_modules/colors/lib/extendStringPrototype.js ++++ b/node_modules/colors/lib/extendStringPrototype.js +@@ -5,7 +5,8 @@ module['exports'] = function() { + // Extends prototype of native string object to allow for "foo".red syntax + // + var addProperty = function(color, func) { +- String.prototype.__defineGetter__(color, func); ++ // remove prototype mutation so this plays well with LavaMoat ++ // String.prototype.__defineGetter__(color, func); + }; + + addProperty('strip', function() { diff --git a/test/e2e/metamask-ui.spec.js b/test/e2e/metamask-ui.spec.js index f12b8a090..e6ec801d5 100644 --- a/test/e2e/metamask-ui.spec.js +++ b/test/e2e/metamask-ui.spec.js @@ -349,14 +349,14 @@ describe('MetaMask', function () { }); it('displays the token transfer data', async function () { - await driver.clickElement({ text: 'Data', tag: 'button' }); + await driver.clickElement({ text: 'Hex', tag: 'button' }); await driver.delay(regularDelayMs); const functionType = await driver.findElement( '.confirm-page-container-content__function-type', ); const functionTypeText = await functionType.getText(); - assert.equal(functionTypeText, 'Transfer'); + assert(functionTypeText.match('Transfer')); const tokenAmount = await driver.findElement( '.confirm-page-container-summary__title-text', diff --git a/test/e2e/tests/address-book.spec.js b/test/e2e/tests/address-book.spec.js index 4f047fe1b..1468c5734 100644 --- a/test/e2e/tests/address-book.spec.js +++ b/test/e2e/tests/address-book.spec.js @@ -34,13 +34,16 @@ describe('Address Book', function () { await driver.clickElement('.dialog.send__dialog.dialog--message'); // wait for address book modal to be visible - const addressModal = await driver.findElement('span .modal'); + const addressModal = await driver.findElement('.nickname-popover'); - await driver.findElement('.add-to-address-book-modal'); - await driver.fill('.add-to-address-book-modal__input', 'Test Name 1'); - await driver.clickElement( - '.add-to-address-book-modal__footer .btn-primary', + await driver.clickElement('.nickname-popover__footer-button'); + await driver.findElement('.update-nickname__wrapper'); + + await driver.fill( + '.update-nickname__content__text-field input', + 'Test Name 1', ); + await driver.clickElement('.update-nickname__save'); // wait for address book modal to be removed from DOM await addressModal.waitForElementState('hidden'); diff --git a/ui/components/app/app-components.scss b/ui/components/app/app-components.scss index cf0e8524f..f602a82cc 100644 --- a/ui/components/app/app-components.scss +++ b/ui/components/app/app-components.scss @@ -58,3 +58,4 @@ @import 'advanced-gas-fee-popover/advanced-gas-fee-inputs/index'; @import 'advanced-gas-fee-popover/advanced-gas-fee-inputs/base-fee-input/index'; @import 'advanced-gas-fee-popover/advanced-gas-fee-input-subtext/index'; +@import 'transaction-decoding/index'; diff --git a/ui/components/app/confirm-page-container/confirm-page-container-container.test.js b/ui/components/app/confirm-page-container/confirm-page-container-container.test.js index fc0a5f669..757e86670 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-container.test.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-container.test.js @@ -58,7 +58,6 @@ describe('Confirm Page Container Container Test', () => { handleCloseEditGas: sinon.spy(), // Gas Popover currentTransaction: {}, - showAddToAddressBookModal: sinon.spy(), contact: undefined, isOwnedAccount: false, }; @@ -118,12 +117,6 @@ describe('Confirm Page Container Container Test', () => { ); }); - it('should simulate click on Dialog', () => { - const DialogWrapper = wrapper.find(Dialog); - DialogWrapper.first().simulate('click'); - expect(props.showAddToAddressBookModal.calledOnce).toStrictEqual(true); - }); - it('should not show add to address dialog if contact is not undefined', () => { props.contact = { address: '0x7a1A4Ad9cc746a70ee58568466f7996dD0aCE4E8', diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js index 069d58da1..346864d96 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js @@ -15,6 +15,7 @@ export default class ConfirmPageContainerContent extends Component { static propTypes = { action: PropTypes.string, dataComponent: PropTypes.node, + dataHexComponent: PropTypes.node, detailsComponent: PropTypes.node, errorKey: PropTypes.string, errorMessage: PropTypes.string, @@ -54,7 +55,7 @@ export default class ConfirmPageContainerContent extends Component { renderTabs() { const { t } = this.context; - const { detailsComponent, dataComponent } = this.props; + const { detailsComponent, dataComponent, dataHexComponent } = this.props; return ( @@ -67,6 +68,12 @@ export default class ConfirmPageContainerContent extends Component { {dataComponent} + + {dataHexComponent} + ); } diff --git a/ui/components/app/confirm-page-container/confirm-page-container-content/index.scss b/ui/components/app/confirm-page-container/confirm-page-container-content/index.scss index c7655165b..2783e08d4 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container-content/index.scss +++ b/ui/components/app/confirm-page-container/confirm-page-container-content/index.scss @@ -20,6 +20,10 @@ &__data { padding: 16px; color: $oslo-gray; + + & > .disclosure { + margin-top: 0; + } } &__data-box { @@ -27,9 +31,7 @@ background-color: #f9fafa; padding: 12px; - margin-bottom: 16px; word-wrap: break-word; - max-height: 200px; overflow-y: auto; &-label { diff --git a/ui/components/app/confirm-page-container/confirm-page-container.component.js b/ui/components/app/confirm-page-container/confirm-page-container.component.js index 996dd4019..351a6e37d 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container.component.js +++ b/ui/components/app/confirm-page-container/confirm-page-container.component.js @@ -10,6 +10,8 @@ import Dialog from '../../ui/dialog'; import ErrorMessage from '../../ui/error-message'; import SenderToRecipient from '../../ui/sender-to-recipient'; +import NicknamePopovers from '../modals/nickname-popovers'; + import AdvancedGasFeePopover from '../advanced-gas-fee-popover'; import EditGasFeePopover from '../edit-gas-fee-popover/edit-gas-fee-popover'; import EditGasPopover from '../edit-gas-popover'; @@ -21,6 +23,10 @@ import { } from '.'; export default class ConfirmPageContainer extends Component { + state = { + showNicknamePopovers: false, + }; + static contextTypes = { t: PropTypes.func, }; @@ -48,6 +54,7 @@ export default class ConfirmPageContainer extends Component { errorKey: PropTypes.string, errorMessage: PropTypes.string, dataComponent: PropTypes.node, + dataHexComponent: PropTypes.node, detailsComponent: PropTypes.node, identiconAddress: PropTypes.string, nonce: PropTypes.string, @@ -75,7 +82,6 @@ export default class ConfirmPageContainer extends Component { handleCloseEditGas: PropTypes.func, // Gas Popover currentTransaction: PropTypes.object.isRequired, - showAddToAddressBookModal: PropTypes.func, contact: PropTypes.object, isOwnedAccount: PropTypes.bool, supportsEIP1559V2: PropTypes.bool, @@ -102,6 +108,7 @@ export default class ConfirmPageContainer extends Component { hideSubtitle, detailsComponent, dataComponent, + dataHexComponent, onCancelAll, onCancel, onSubmit, @@ -126,7 +133,6 @@ export default class ConfirmPageContainer extends Component { editingGas, handleCloseEditGas, currentTransaction, - showAddToAddressBookModal, contact = {}, isOwnedAccount, supportsEIP1559V2, @@ -177,13 +183,23 @@ export default class ConfirmPageContainer extends Component {
{showAddToAddressDialog && ( - showAddToAddressBookModal()} - > - {this.context.t('newAccountDetectedDialogMessage')} - + <> + this.setState({ showNicknamePopovers: true })} + > + {this.context.t('newAccountDetectedDialogMessage')} + + {this.state.showNicknamePopovers ? ( + + this.setState({ showNicknamePopovers: false }) + } + address={toAddress} + /> + ) : null} + )}
{contentComponent || ( @@ -195,6 +211,7 @@ export default class ConfirmPageContainer extends Component { hideSubtitle={hideSubtitle} detailsComponent={detailsComponent} dataComponent={dataComponent} + dataHexComponent={dataHexComponent} errorMessage={errorMessage} errorKey={errorKey} identiconAddress={identiconAddress} diff --git a/ui/components/app/confirm-page-container/confirm-page-container.container.js b/ui/components/app/confirm-page-container/confirm-page-container.container.js index c5bc0396c..ec5ba84c0 100644 --- a/ui/components/app/confirm-page-container/confirm-page-container.container.js +++ b/ui/components/app/confirm-page-container/confirm-page-container.container.js @@ -1,6 +1,5 @@ import { connect } from 'react-redux'; import { getAccountsWithLabels, getAddressBookEntry } from '../../../selectors'; -import * as actions from '../../../store/actions'; import ConfirmPageContainer from './confirm-page-container.component'; function mapStateToProps(state, ownProps) { @@ -17,30 +16,4 @@ function mapStateToProps(state, ownProps) { }; } -function mapDispatchToProps(dispatch) { - return { - showAddToAddressBookModal: (recipient) => - dispatch( - actions.showModal({ - name: 'ADD_TO_ADDRESSBOOK', - recipient, - }), - ), - }; -} - -function mergeProps(stateProps, dispatchProps, ownProps) { - const { to, ...restStateProps } = stateProps; - return { - ...ownProps, - ...restStateProps, - showAddToAddressBookModal: () => - dispatchProps.showAddToAddressBookModal(to), - }; -} - -export default connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, -)(ConfirmPageContainer); +export default connect(mapStateToProps)(ConfirmPageContainer); diff --git a/ui/components/app/modals/nickname-popovers/index.js b/ui/components/app/modals/nickname-popovers/index.js new file mode 100644 index 000000000..b18a3fcb7 --- /dev/null +++ b/ui/components/app/modals/nickname-popovers/index.js @@ -0,0 +1 @@ +export { default } from './nickname-popovers.component'; diff --git a/ui/components/app/modals/nickname-popovers/nickname-popovers.component.js b/ui/components/app/modals/nickname-popovers/nickname-popovers.component.js new file mode 100644 index 000000000..664358a66 --- /dev/null +++ b/ui/components/app/modals/nickname-popovers/nickname-popovers.component.js @@ -0,0 +1,72 @@ +import React, { useState } from 'react'; +import { useDispatch, useSelector } from 'react-redux'; +import PropTypes from 'prop-types'; +import { getAccountLink } from '@metamask/etherscan-link'; +import { addToAddressBook } from '../../../../store/actions'; +import { + getRpcPrefsForCurrentProvider, + getCurrentChainId, + getAddressBook, +} from '../../../../selectors'; +import NicknamePopover from '../../../ui/nickname-popover'; +import UpdateNicknamePopover from '../../../ui/update-nickname-popover/update-nickname-popover'; + +const SHOW_NICKNAME_POPOVER = 'SHOW_NICKNAME_POPOVER'; +const ADD_NICKNAME_POPOVER = 'ADD_NICKNAME_POPOVER'; + +const NicknamePopovers = ({ address, onClose }) => { + const dispatch = useDispatch(); + + const [popoverToDisplay, setPopoverToDisplay] = useState( + SHOW_NICKNAME_POPOVER, + ); + + const addressBook = useSelector(getAddressBook); + const chainId = useSelector(getCurrentChainId); + + const addressBookEntryObject = addressBook.find( + (entry) => entry.address === address, + ); + + const recipientNickname = addressBookEntryObject?.name; + const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); + + const explorerLink = getAccountLink( + address, + chainId, + { blockExplorerUrl: rpcPrefs?.blockExplorerUrl ?? null }, + null, + ); + + if (popoverToDisplay === ADD_NICKNAME_POPOVER) { + return ( + setPopoverToDisplay(SHOW_NICKNAME_POPOVER)} + onAdd={(recipient, nickname, memo) => + dispatch(addToAddressBook(recipient, nickname, memo)) + } + /> + ); + } + + // SHOW_NICKNAME_POPOVER case + return ( + setPopoverToDisplay(ADD_NICKNAME_POPOVER)} + explorerLink={explorerLink} + /> + ); +}; + +NicknamePopovers.propTypes = { + address: PropTypes.string, + onClose: PropTypes.func, +}; + +export default NicknamePopovers; diff --git a/ui/components/app/transaction-breakdown/index.scss b/ui/components/app/transaction-breakdown/index.scss index 7df517d1b..87aa3c72e 100644 --- a/ui/components/app/transaction-breakdown/index.scss +++ b/ui/components/app/transaction-breakdown/index.scss @@ -2,8 +2,11 @@ .transaction-breakdown { &__title { - border-bottom: 1px solid #d8d8d8; padding-bottom: 4px; + padding-top: 8px; + font-size: 14px; + color: $Black-100; + font-weight: bold; text-transform: capitalize; } @@ -15,12 +18,17 @@ display: flex; justify-content: flex-end; text-align: end; - white-space: nowrap; overflow: hidden; text-overflow: ellipsis; &--eth-total { - font-weight: 500; + font-weight: bold; + color: $Black-100; + } + + &--amount { + font-weight: bold; + color: $Black-100; } } } diff --git a/ui/components/app/transaction-breakdown/transaction-breakdown-row/index.scss b/ui/components/app/transaction-breakdown/transaction-breakdown-row/index.scss index 372a40e4b..ac6111af2 100644 --- a/ui/components/app/transaction-breakdown/transaction-breakdown-row/index.scss +++ b/ui/components/app/transaction-breakdown/transaction-breakdown-row/index.scss @@ -1,20 +1,22 @@ .transaction-breakdown-row { @include H7; - color: $scorpion; + color: $Grey-500; display: flex; justify-content: space-between; padding: 8px 0; - &:not(:last-child) { + &--with-bottom-border { border-bottom: 1px solid #d8d8d8; } &__title { padding-right: 8px; + min-width: 40%; } &__value { min-width: 0; + word-break: break-word; } } diff --git a/ui/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js b/ui/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js index 99c2b1e30..e4c7c56bc 100644 --- a/ui/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js +++ b/ui/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js @@ -7,14 +7,19 @@ export default class TransactionBreakdownRow extends PureComponent { title: PropTypes.string, children: PropTypes.node, className: PropTypes.string, + divider: PropTypes.bool, }; render() { - const { title, children, className } = this.props; + const { title, children, className, divider = false } = this.props; return (
{t('transaction')}
- + {typeof nonce === 'undefined' ? null : ( - + {primaryCurrency} @@ -178,7 +178,10 @@ export default class TransactionBreakdown extends PureComponent { )} {isEIP1559Transaction && ( - + { + const t = useI18nContext(); + const [showNicknamePopovers, setShowNicknamePopovers] = useState(false); + + const addressBook = useSelector(getAddressBook); + const addressBookEntryObject = addressBook.find( + (entry) => entry.address === checksummedRecipientAddress, + ); + const recipientNickname = addressBookEntryObject?.name; + + const recipientToRender = addressOnly + ? recipientNickname || + recipientEns || + shortenAddress(checksummedRecipientAddress) + : recipientNickname || recipientEns || recipientName || t('newContract'); + + return ( +
{ + copyToClipboard(checksummedRecipientAddress); + if (onRecipientClick) { + onRecipientClick(); + } + }} + > +
+ +
+ +
setShowNicknamePopovers(true)} + > + {recipientToRender} +
+ {showNicknamePopovers ? ( + setShowNicknamePopovers(false)} + address={checksummedRecipientAddress} + /> + ) : null} +
+ ); +}; + +Address.propTypes = { + checksummedRecipientAddress: PropTypes.string, + recipientName: PropTypes.string, + recipientEns: PropTypes.string, + addressOnly: PropTypes.bool, + onRecipientClick: PropTypes.func, +}; + +export default Address; diff --git a/ui/components/app/transaction-decoding/components/decoding/address/index.js b/ui/components/app/transaction-decoding/components/decoding/address/index.js new file mode 100644 index 000000000..6909aec4e --- /dev/null +++ b/ui/components/app/transaction-decoding/components/decoding/address/index.js @@ -0,0 +1 @@ +export { default } from './address.component'; diff --git a/ui/components/app/transaction-decoding/components/decoding/address/index.scss b/ui/components/app/transaction-decoding/components/decoding/address/index.scss new file mode 100644 index 000000000..ca821dae8 --- /dev/null +++ b/ui/components/app/transaction-decoding/components/decoding/address/index.scss @@ -0,0 +1,12 @@ +.tx-insight-content { + .tx-insight-component-address { + display: flex; + align-items: center; + cursor: pointer; + overflow: visible; + + &__sender-icon { + padding-right: 5px; + } + } +} diff --git a/ui/components/app/transaction-decoding/components/ui/copy-raw-data/copy-raw-data.component.js b/ui/components/app/transaction-decoding/components/ui/copy-raw-data/copy-raw-data.component.js new file mode 100644 index 000000000..8e9361e70 --- /dev/null +++ b/ui/components/app/transaction-decoding/components/ui/copy-raw-data/copy-raw-data.component.js @@ -0,0 +1,38 @@ +import React, { useContext } from 'react'; +import PropTypes from 'prop-types'; +import Tooltip from '../../../../../ui/tooltip/tooltip'; +import CopyIcon from '../../../../../ui/icon/copy-icon.component'; +import { I18nContext } from '../../../../../../contexts/i18n'; + +import { useCopyToClipboard } from '../../../../../../hooks/useCopyToClipboard'; + +const CopyRawData = ({ data }) => { + const t = useContext(I18nContext); + const [copied, handleCopy] = useCopyToClipboard(); + + return ( +
+ + + +
+ ); +}; + +CopyRawData.propTypes = { + data: PropTypes.string.isRequired, +}; + +export default CopyRawData; diff --git a/ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.js b/ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.js new file mode 100644 index 000000000..c586d6272 --- /dev/null +++ b/ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.js @@ -0,0 +1 @@ +export { default } from './copy-raw-data.component'; diff --git a/ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.scss b/ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.scss new file mode 100644 index 000000000..4deb4c525 --- /dev/null +++ b/ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.scss @@ -0,0 +1,30 @@ +.copy-raw-data { + display: flex; + align-items: center; + + &__button { + border-radius: 20px; + display: flex; + align-items: center; + justify-content: center; + padding: 8px; + margin-top: 5px; + background-color: transparent; + + &:hover { + background-color: $Grey-000; + } + + &:active { + background-color: #ededed; + } + } + + &__icon { + padding-inline-end: 6px; + } + + &__label { + color: #6a737d; + } +} diff --git a/ui/components/app/transaction-decoding/constants.js b/ui/components/app/transaction-decoding/constants.js new file mode 100644 index 000000000..36e45ebee --- /dev/null +++ b/ui/components/app/transaction-decoding/constants.js @@ -0,0 +1,5 @@ +const TX_INSIGHTS_BASE_URI = + 'https://tx-insights-api.metaswap-dev.codefi.network'; + +export const FETCH_PROJECT_INFO_URI = `${TX_INSIGHTS_BASE_URI}/fetch-project`; +export const FETCH_SUPPORTED_NETWORKS_URI = `${TX_INSIGHTS_BASE_URI}/networks`; diff --git a/ui/components/app/transaction-decoding/index.js b/ui/components/app/transaction-decoding/index.js new file mode 100644 index 000000000..005447c73 --- /dev/null +++ b/ui/components/app/transaction-decoding/index.js @@ -0,0 +1 @@ +export { default } from './transaction-decoding.component'; diff --git a/ui/components/app/transaction-decoding/index.scss b/ui/components/app/transaction-decoding/index.scss new file mode 100644 index 000000000..43abeb82b --- /dev/null +++ b/ui/components/app/transaction-decoding/index.scss @@ -0,0 +1,169 @@ +//styling for ui components +@import './components/ui/copy-raw-data/index'; + +//styling for decoding components +@import './components/decoding/address/index'; + +.tx-insight { + overflow-x: hidden; + + &-loading { + display: flex; + justify-content: center; + align-items: center; + min-height: 100px; + + .spinner { + width: 30px; + } + } + + & > details { + margin: 20px 0; + } + + & > details > summary { + &.tx-insight-title { + font-size: 14px; + position: relative; + margin: 12px 0 4px; + padding-inline-start: 22px; + cursor: pointer; + + & + .tx-insight-content { + padding-inline-start: 14px; + padding-top: 5px; + } + } + } + + + + .tx-insight-content { + &__tree-component { + line-height: 175%; + + & > ol { + padding-left: 0; + } + + .eth-tx-params { + padding: 8px; + width: 343px; + background: white; + text-align: left; + display: flex; + flex-direction: column; + align-items: left; + font-family: Euclid Circular B, sans-serif; + font-style: normal; + font-weight: normal; + font-size: 14px; + line-height: 172%; + } + + ol ol { + padding-left: 22px; + margin-left: 4px; + } + + details > summary { + position: relative; + cursor: pointer; + padding-bottom: 5px; + } + + .eth-tx-params .solidity-func-name { + width: fit-content; + padding: 4px; + text-transform: uppercase; + border: 1px solid rgb(149, 149, 149); + color: rgb(149, 149, 149); + border-radius: 4px; + } + + .eth-tx-params .sol-value { + display: flex; + flex-flow: row wrap; + } + + .eth-tx-params .sol-value > { + overflow: ellipses; + } + + .eth-tx-params ol { + list-style: none; + padding: 0; + max-width: inherit; + } + + .eth-tx-params > ol { + margin-left: 16px; + } + + /* + Use this parameter to change the indentation!! */ + .eth-tx-params ol ol:not(:first-child) { + padding-left: 8px; + } + + pre.solidity-raw { + text-align: left; + } + + .solidity-address { + display: flex; + flex-direction: row; + } + + .solidity-address :first-child { + width: 16px; + height: 16px; + margin: 0 8px; + } + + .solidity-item .param-name { + padding-right: 4px; + } + + .solidity-value { + color: #6a737d; + overflow-x: hidden; + padding-bottom: 5px; + + & > div { + display: flex; + flex-wrap: wrap; + word-break: break-all; + } + } + + .solidity-error { + display: flex; + align-items: center; + + & > .error-message__icon { + width: 14px; + margin-right: 5px; + } + } + + .eth-tx-params details > summary { + color: black; + font-family: sans-serif; + } + + .eth-tx-params footer { + text-align: center; + color: #8d959e; + } + + .eth-tx-params footer a { + text-align: center; + color: #8d959e; + } + } + } +} + + diff --git a/ui/components/app/transaction-decoding/transaction-decoding.component.js b/ui/components/app/transaction-decoding/transaction-decoding.component.js new file mode 100644 index 000000000..e025efbd6 --- /dev/null +++ b/ui/components/app/transaction-decoding/transaction-decoding.component.js @@ -0,0 +1,219 @@ +import React, { useContext, useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import inspect from 'browser-util-inspect'; +import { forAddress } from '@truffle/decoder'; +import { useSelector } from 'react-redux'; +import * as Codec from '@truffle/codec'; +import Spinner from '../../ui/spinner'; +import ErrorMessage from '../../ui/error-message'; +import fetchWithCache from '../../../helpers/utils/fetch-with-cache'; +import { getSelectedAccount, getCurrentChainId } from '../../../selectors'; +import { hexToDecimal } from '../../../helpers/utils/conversions.util'; +import { I18nContext } from '../../../contexts/i18n'; +import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; +import { transformTxDecoding } from './transaction-decoding.util'; +import { + FETCH_PROJECT_INFO_URI, + FETCH_SUPPORTED_NETWORKS_URI, +} from './constants'; + +import Address from './components/decoding/address'; +import CopyRawData from './components/ui/copy-raw-data'; + +export default function TransactionDecoding({ to = '', inputData: data = '' }) { + const t = useContext(I18nContext); + const [tx, setTx] = useState([]); + const { address: from } = useSelector(getSelectedAccount); + const network = hexToDecimal(useSelector(getCurrentChainId)); + + const [loading, setLoading] = useState(false); + const [hasError, setError] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + + useEffect(() => { + (async () => { + setLoading(true); + try { + const networks = await fetchWithCache(FETCH_SUPPORTED_NETWORKS_URI, { + method: 'GET', + }); + + if ( + !networks.some( + (n) => n.active && Number(n.chainId) === Number(network), + ) + ) { + throw new Error( + t('transactionDecodingUnsupportedNetworkError', [network]), + ); + } + + const requestUrl = `${FETCH_PROJECT_INFO_URI}?${new URLSearchParams({ + to, + 'network-id': network, + })}`; + + const response = await fetchWithCache(requestUrl, { method: 'GET' }); + + const { info: projectInfo } = response; + + // creating instance of the truffle decoder + const decoder = await forAddress(to, { + provider: global.ethereumProvider, + projectInfo, + }); + + // decode tx input data + const decoding = await decoder.decodeTransaction({ + from, + to, + input: data, + blockNumber: null, + }); + + // transform tx decoding arguments into tree data + const params = transformTxDecoding(decoding?.arguments); + setTx(params); + + setLoading(false); + } catch (error) { + setLoading(false); + setError(true); + setErrorMessage(error?.message); + } + })(); + }, [t, from, to, network, data]); + + // *********************************************************** + // component rendering methods + // *********************************************************** + const renderLeaf = ({ name, kind, typeClass, value }) => { + switch (kind) { + case 'error': + return ( + + Malformed data + + ); + + default: + switch (typeClass) { + case 'int': + return ( + + {[value.asBN || value.asString].toString()} + + ); + + case 'uint': + return ( + + {[value.asBN || value.asString].toString()} + + ); + + case 'bytes': + return ( + {value.asHex} + ); + + case 'array': + return ( +
+ {name}: +
    + {value.map((itemValue, index) => { + return ( +
  1. + {renderLeaf({ + typeClass: itemValue.type?.typeClass, + value: itemValue.value, + kind: itemValue.kind, + })} +
  2. + ); + })} +
+
+ ); + + case 'address': { + const address = value?.asAddress; + return ( +
+ ); + } + default: + return ( +
+                {inspect(new Codec.Format.Utils.Inspect.ResultInspector(value))}
+              
+ ); + } + } + }; + + const renderTree = ( + { name, kind, typeClass, type, value, children }, + index, + ) => { + return children ? ( +
  • +
    + {name}: +
      {children.map(renderTree)}
    +
    +
  • + ) : ( +
  • +
    + {typeClass !== 'array' && !Array.isArray(value) ? ( + {name}: + ) : null} + + {renderLeaf({ name, typeClass, type, value, kind })} + +
    +
  • + ); + }; + + const renderTransactionDecoding = () => { + if (loading) { + return ( +
    + +
    + ); + } + + if (hasError) { + return ( +
    + +
    + ); + } + + return ( +
    +
    +
      {tx.map(renderTree)}
    +
    +
    + +
    +
    + ); + }; + + return
    {renderTransactionDecoding()}
    ; +} + +TransactionDecoding.propTypes = { + to: PropTypes.string.isRequired, + inputData: PropTypes.string.isRequired, +}; diff --git a/ui/components/app/transaction-decoding/transaction-decoding.util.js b/ui/components/app/transaction-decoding/transaction-decoding.util.js new file mode 100644 index 000000000..fa351a565 --- /dev/null +++ b/ui/components/app/transaction-decoding/transaction-decoding.util.js @@ -0,0 +1,30 @@ +// ********************************************* +// data transformation utils +// ********************************************* +export const transformTxDecoding = (params) => { + return params.map((node) => { + const nodeName = node.name; + const nodeValue = node.value; + const nodeKind = nodeValue.kind; + const nodeTypeClass = nodeValue.type.typeClass; + + const treeItem = { + name: nodeName, + kind: nodeKind, + typeClass: nodeTypeClass, + type: nodeValue.type, + }; + + if (nodeTypeClass === 'struct') { + return { + ...treeItem, + children: transformTxDecoding(nodeValue.value), + }; + } + + return { + ...treeItem, + value: nodeValue.value ? nodeValue.value : nodeValue, + }; + }); +}; diff --git a/ui/components/app/transaction-list-item-details/index.scss b/ui/components/app/transaction-list-item-details/index.scss index a0f95f470..2df231e14 100644 --- a/ui/components/app/transaction-list-item-details/index.scss +++ b/ui/components/app/transaction-list-item-details/index.scss @@ -1,11 +1,82 @@ .transaction-list-item-details { + div.disclosure + div.disclosure { + margin-top: 0; + } + + .sender-to-recipient--flat .sender-to-recipient__party.sender-to-recipient__party--sender { + padding: 0; + justify-content: flex-start; + } + + .sender-to-recipient--flat .sender-to-recipient__party.sender-to-recipient__party--recipient { + padding: 0; + justify-content: flex-end; + } + + &__sender-to-recipient-header { + display: flex; + font-size: 14px; + color: $Black-100; + font-weight: bold; + padding-bottom: 7px; + + & > div:first-child { + flex: 1; + } + } + + &__tx-status { + display: flex; + flex-direction: column; + align-items: flex-start; + height: 44px; + justify-content: space-between; + + & > div:first-child { + font-size: 14px; + color: $Black-100; + font-weight: bold; + } + + & > div:last-child { + font-weight: bold; + } + } + + &__tx-hash { + display: flex; + flex-direction: column; + align-items: flex-end; + + .btn-link { + font-size: 12px; + line-height: 100%; + padding: 0; + } + + & > div:first-child { + padding-bottom: 16px; + } + } + + &__operations { + margin: 0 0 16px 16px; + display: flex; + justify-content: end; + } + &__header { + font-size: 12px; margin: 8px 16px; display: flex; justify-content: space-between; align-items: center; } + &__body { + padding: 8px 16px; + } + &__header-buttons { display: flex; flex-direction: row; @@ -31,12 +102,25 @@ &__sender-to-recipient-container { margin-bottom: 8px; + + .sender-to-recipient { + .sender-to-recipient__party { + border: none; + + &--sender { + padding-left: 0; + } + + &--recipient { + padding-right: 0; + } + } + } } &__cards-container { display: flex; flex-direction: column; - padding: 8px 16px; } &__transaction-breakdown { @@ -49,5 +133,13 @@ &__transaction-activity-log { flex: 2; min-width: 0; + + .transaction-activity-log__activities-container { + padding-top: 0; + } + + .transaction-activity-log__title { + display: none; + } } } diff --git a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js index 335859aa3..4dc58919a 100644 --- a/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js +++ b/ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js @@ -4,16 +4,17 @@ import copyToClipboard from 'copy-to-clipboard'; import { getBlockExplorerLink } from '@metamask/etherscan-link'; import SenderToRecipient from '../../ui/sender-to-recipient'; import { DEFAULT_VARIANT } from '../../ui/sender-to-recipient/sender-to-recipient.constants'; +import Disclosure from '../../ui/disclosure'; import TransactionActivityLog from '../transaction-activity-log'; import TransactionBreakdown from '../transaction-breakdown'; import Button from '../../ui/button'; import Tooltip from '../../ui/tooltip'; -import Copy from '../../ui/icon/copy-icon.component'; import CancelButton from '../cancel-button'; import Popover from '../../ui/popover'; import { SECOND } from '../../../../shared/constants/time'; import { TRANSACTION_TYPES } from '../../../../shared/constants/transaction'; import { getURLHostName } from '../../../helpers/utils/util'; +import TransactionDecoding from '../transaction-decoding'; export default class TransactionListItemDetails extends PureComponent { static contextTypes = { @@ -44,6 +45,7 @@ export default class TransactionListItemDetails extends PureComponent { tryReverseResolveAddress: PropTypes.func.isRequired, senderNickname: PropTypes.string.isRequired, recipientNickname: PropTypes.string, + transactionStatus: PropTypes.func, }; state = { @@ -124,7 +126,6 @@ export default class TransactionListItemDetails extends PureComponent { showRetry, recipientEns, recipientAddress, - rpcPrefs: { blockExplorerUrl } = {}, senderAddress, isEarliestNonce, senderNickname, @@ -132,6 +133,7 @@ export default class TransactionListItemDetails extends PureComponent { onClose, recipientNickname, showCancel, + transactionStatus: TransactionStatus, } = this.props; const { primaryTransaction: transaction, @@ -142,8 +144,7 @@ export default class TransactionListItemDetails extends PureComponent { return (
    -
    -
    {t('details')}
    +
    {showSpeedUp && ( - - - - {showRetry && (
    +
    +
    +
    Status
    +
    + +
    +
    +
    +
    + +
    +
    + + + +
    +
    +
    +
    +
    {t('from')}
    +
    {t('to')}
    +
    - + + + + {transactionGroup.initialTransaction?.txParams?.data ? ( + + + + ) : null}
    diff --git a/ui/components/app/transaction-list-item/transaction-list-item.component.js b/ui/components/app/transaction-list-item/transaction-list-item.component.js index 88227e7d0..b5f215c15 100644 --- a/ui/components/app/transaction-list-item/transaction-list-item.component.js +++ b/ui/components/app/transaction-list-item/transaction-list-item.component.js @@ -212,6 +212,16 @@ export default function TransactionListItem({ isEarliestNonce={isEarliestNonce} onCancel={cancelTransaction} showCancel={isPending && !hasCancelled} + transactionStatus={() => ( + + )} /> )} {showRetryEditGasPopover && ( diff --git a/ui/components/app/transaction-status/index.scss b/ui/components/app/transaction-status/index.scss index 0896aa7f8..18af1f0df 100644 --- a/ui/components/app/transaction-status/index.scss +++ b/ui/components/app/transaction-status/index.scss @@ -1,6 +1,10 @@ .transaction-status { display: inline; + &--confirmed { + color: $success-3; + } + &--unapproved { color: $Orange-500; } diff --git a/ui/components/app/transaction-status/transaction-status.component.js b/ui/components/app/transaction-status/transaction-status.component.js index f8f5f8018..584989adb 100644 --- a/ui/components/app/transaction-status/transaction-status.component.js +++ b/ui/components/app/transaction-status/transaction-status.component.js @@ -43,6 +43,7 @@ export default function TransactionStatus({ error, isEarliestNonce, className, + statusOnly, }) { const t = useI18nContext(); const tooltipText = error?.rpc?.message || error?.message; @@ -54,7 +55,9 @@ export default function TransactionStatus({ } const statusText = - statusKey === TRANSACTION_STATUSES.CONFIRMED ? date : t(statusKey); + statusKey === TRANSACTION_STATUSES.CONFIRMED && !statusOnly + ? date + : t(statusKey); return ( { + const disclosureFooterEl = useRef(null); + const [open, setOpen] = useState(false); + + const scrollToBottom = () => { + disclosureFooterEl && + disclosureFooterEl.current && + disclosureFooterEl.current.scrollIntoView({ behavior: 'smooth' }); + }; + + useEffect(() => { + if (open) { + scrollToBottom(); + } + }, [open]); + + return ( +
    setOpen((state) => !state)}> + {title ? ( +
    + + {title}:{' '} + +
    + {children} +
    +
    +
    + ) : ( + children + )} +
    + ); +}; + +Disclosure.propTypes = { + children: PropTypes.node.isRequired, + title: PropTypes.string, + size: PropTypes.string, +}; + +Disclosure.defaultProps = { + size: 'normal', + title: null, +}; + +export default Disclosure; diff --git a/ui/components/ui/disclosure/disclosure.scss b/ui/components/ui/disclosure/disclosure.scss new file mode 100644 index 000000000..8a0fe8b4b --- /dev/null +++ b/ui/components/ui/disclosure/disclosure.scss @@ -0,0 +1,46 @@ +.disclosure { + margin: 12px 0; + cursor: pointer; + font-size: 14px; + + & > details[open] > summary { + &::before { + background-image: url("images/icons/collapse.svg"); + } + } + + &__summary { + position: relative; + padding-left: 24px; + padding-bottom: 10px; + + &::-webkit-details-marker, + &::marker { + display: none; + content: ""; + } + + &::before { + position: absolute; + content: " "; + flex: 0 0 auto; + height: 16px; + width: 16px; + background-image: url("images/icons/expand.svg"); + background-size: contain; + background-repeat: no-repeat; + cursor: pointer; + left: 0; + top: 2px; + } + } + + &__content { + margin-left: 12px; + font-size: 14px; + + &.small { + font-size: 12px; + } + } +} diff --git a/ui/components/ui/disclosure/index.js b/ui/components/ui/disclosure/index.js new file mode 100644 index 000000000..cd9bc820d --- /dev/null +++ b/ui/components/ui/disclosure/index.js @@ -0,0 +1 @@ +export { default } from './disclosure'; diff --git a/ui/components/ui/nickname-popover/index.scss b/ui/components/ui/nickname-popover/index.scss index 39fae062d..c7b91d246 100644 --- a/ui/components/ui/nickname-popover/index.scss +++ b/ui/components/ui/nickname-popover/index.scss @@ -1,10 +1,11 @@ .nickname-popover { &__popover-wrap { height: 232px; - border-radius: 8px; + border-radius: 4px; background: $ui-white; display: flex; justify-content: center; + width: auto; .popover-header { padding: 16px 16px 0 0; @@ -57,6 +58,12 @@ margin-top: 12px; } + &__etherscan-link { + @include H7; + + padding: 0; + } + &__footer-button { margin-top: 16px; width: 152px; diff --git a/ui/components/ui/nickname-popover/nickname-popover.component.js b/ui/components/ui/nickname-popover/nickname-popover.component.js index 106df9fed..0ffea24e4 100644 --- a/ui/components/ui/nickname-popover/nickname-popover.component.js +++ b/ui/components/ui/nickname-popover/nickname-popover.component.js @@ -1,6 +1,7 @@ import React, { useCallback, useContext } from 'react'; import PropTypes from 'prop-types'; import { I18nContext } from '../../../contexts/i18n'; +import Tooltip from '../tooltip'; import Popover from '../popover'; import Button from '../button'; import Identicon from '../identicon/identicon.component'; @@ -8,13 +9,18 @@ import { shortenAddress } from '../../../helpers/utils/util'; import CopyIcon from '../icon/copy-icon.component'; import { useCopyToClipboard } from '../../../hooks/useCopyToClipboard'; -const NicknamePopover = ({ address, onClose = null, onAdd = null }) => { +const NicknamePopover = ({ + address, + nickname, + onClose = null, + onAdd = null, + explorerLink, +}) => { const t = useContext(I18nContext); const onAddClick = useCallback(() => { - onAdd(address); - onClose(); - }, [address, onClose, onAdd]); + onAdd(); + }, [onAdd]); const [copied, handleCopy] = useCopyToClipboard(); @@ -27,31 +33,51 @@ const NicknamePopover = ({ address, onClose = null, onAdd = null }) => { className="nickname-popover__identicon" />
    - {shortenAddress(address)} + {nickname || shortenAddress(address)}
    {address}
    - + +
    +
    - {t('viewOnBlockExplorer')} +
    @@ -60,8 +86,10 @@ const NicknamePopover = ({ address, onClose = null, onAdd = null }) => { NicknamePopover.propTypes = { address: PropTypes.string, + nickname: PropTypes.string, onClose: PropTypes.func, onAdd: PropTypes.func, + explorerLink: PropTypes.string, }; export default NicknamePopover; diff --git a/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js b/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js index 4f92a3016..ef229d84c 100644 --- a/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js +++ b/ui/components/ui/sender-to-recipient/sender-to-recipient.component.js @@ -8,6 +8,7 @@ import { shortenAddress } from '../../../helpers/utils/util'; import AccountMismatchWarning from '../account-mismatch-warning/account-mismatch-warning.component'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { toChecksumHexAddress } from '../../../../shared/modules/hexstring-utils'; +import NicknamePopovers from '../../app/modals/nickname-popovers'; import { DEFAULT_VARIANT, CARDS_VARIANT, @@ -94,7 +95,7 @@ SenderAddress.propTypes = { warnUserOnAccountMismatch: PropTypes.bool, }; -function RecipientWithAddress({ +export function RecipientWithAddress({ checksummedRecipientAddress, onRecipientClick, addressOnly, @@ -103,44 +104,22 @@ function RecipientWithAddress({ recipientName, }) { const t = useI18nContext(); - const [addressCopied, setAddressCopied] = useState(false); + const [showNicknamePopovers, setShowNicknamePopovers] = useState(false); - let tooltipHtml =

    {t('copiedExclamation')}

    ; - if (!addressCopied) { - if (addressOnly && !recipientNickname && !recipientEns) { - tooltipHtml =

    {t('copyAddress')}

    ; - } else { - tooltipHtml = ( -

    - {shortenAddress(checksummedRecipientAddress)} -
    - {t('copyAddress')} -

    - ); - } - } return ( -
    { - setAddressCopied(true); - copyToClipboard(checksummedRecipientAddress); - if (onRecipientClick) { - onRecipientClick(); - } - }} - > -
    - -
    - setAddressCopied(false)} + <> +
    { + setShowNicknamePopovers(true); + if (onRecipientClick) { + onRecipientClick(); + } + }} > +
    + +
    {addressOnly ? recipientNickname || @@ -151,8 +130,14 @@ function RecipientWithAddress({ recipientName || t('newContract')}
    - -
    +
    + {showNicknamePopovers ? ( + setShowNicknamePopovers(false)} + address={checksummedRecipientAddress} + /> + ) : null} + ); } diff --git a/ui/components/ui/ui-components.scss b/ui/components/ui/ui-components.scss index b31e24e32..34c435acd 100644 --- a/ui/components/ui/ui-components.scss +++ b/ui/components/ui/ui-components.scss @@ -55,3 +55,4 @@ @import 'unit-input/index'; @import 'url-icon/index'; @import 'update-nickname-popover/index'; +@import 'disclosure/disclosure'; diff --git a/ui/components/ui/update-nickname-popover/index.scss b/ui/components/ui/update-nickname-popover/index.scss index 845cff195..650edf11d 100644 --- a/ui/components/ui/update-nickname-popover/index.scss +++ b/ui/components/ui/update-nickname-popover/index.scss @@ -3,12 +3,19 @@ &__wrapper { height: 620px; width: 360px; - border-radius: 0; + border-radius: 10px; + max-height: 100vh; + width: auto; .popover-header { border-bottom: 1px solid #d2d8dd; margin-bottom: 16px; - border-radius: 0; + border-radius: 10px; + } + + @media screen and (max-width: $break-small) { + width: 96%; + height: 96%; } } @@ -37,6 +44,7 @@ font-size: 13px; color: #bbc0c5; margin-bottom: 16px; + overflow-wrap: break-word; } &__label, diff --git a/ui/components/ui/update-nickname-popover/update-nickname-popover.js b/ui/components/ui/update-nickname-popover/update-nickname-popover.js index 8f81ffe7d..2713d7b70 100644 --- a/ui/components/ui/update-nickname-popover/update-nickname-popover.js +++ b/ui/components/ui/update-nickname-popover/update-nickname-popover.js @@ -42,14 +42,9 @@ export default function UpdateNicknamePopover({ onClose(); }; - let title = t('addANickname'); - if (nickname) { - title = t('editAddressNickname'); - } - return ( {t('cancel')} - diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js index 4547528aa..39ae8bd59 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.component.js @@ -1,6 +1,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ConfirmPageContainer from '../../components/app/confirm-page-container'; +import TransactionDecoding from '../../components/app/transaction-decoding'; import { isBalanceSufficient } from '../send/send.utils'; import { addHexes, @@ -18,9 +19,12 @@ import { GAS_PRICE_FETCH_FAILURE_ERROR_KEY, } from '../../helpers/constants/error-keys'; import UserPreferencedCurrencyDisplay from '../../components/app/user-preferenced-currency-display'; +import CopyRawData from '../../components/app/transaction-decoding/components/ui/copy-raw-data'; + import { PRIMARY, SECONDARY } from '../../helpers/constants/common'; import TextField from '../../components/ui/text-field'; import ActionableMessage from '../../components/ui/actionable-message'; +import Disclosure from '../../components/ui/disclosure'; import { TRANSACTION_TYPES, TRANSACTION_STATUSES, @@ -110,6 +114,7 @@ export default class ConfirmTransactionBase extends Component { actionKey: PropTypes.string, contentComponent: PropTypes.node, dataComponent: PropTypes.node, + dataHexComponent: PropTypes.node, hideData: PropTypes.bool, hideSubtitle: PropTypes.bool, identiconAddress: PropTypes.string, @@ -632,25 +637,54 @@ export default class ConfirmTransactionBase extends Component { } renderData(functionType) { + const { t } = this.context; + const { txData: { txParams } = {}, hideData, dataComponent } = this.props; + + if (hideData) { + return null; + } + + return ( + dataComponent || ( +
    +
    + {`${t('functionType')}:`} + + {functionType} + +
    + + + +
    + ) + ); + } + + renderDataHex(functionType) { const { t } = this.context; const { - txData: { txParams: { data } = {} } = {}, + txData: { txParams } = {}, methodData: { params } = {}, hideData, - dataComponent, + dataHexComponent, } = this.props; if (hideData) { return null; } + const functionParams = params + ? `(${params.map(({ type }) => type).join(', ')}` + : ''; + return ( - dataComponent || ( + dataHexComponent || (
    {`${t('functionType')}:`} - {functionType} + {`${functionType} ${functionParams}`}
    {params && ( @@ -664,9 +698,12 @@ export default class ConfirmTransactionBase extends Component {
    )}
    - {`${t('hexData')}: ${toBuffer(data).length} bytes`} + {`${t('hexData')}: ${toBuffer(txParams?.data).length} bytes`} +
    +
    + {txParams?.data}
    -
    {data}
    +
    ) ); @@ -1019,6 +1056,7 @@ export default class ConfirmTransactionBase extends Component { hideSubtitle={hideSubtitle} detailsComponent={this.renderDetails()} dataComponent={this.renderData(functionType)} + dataHexComponent={this.renderDataHex(functionType)} contentComponent={contentComponent} nonce={customNonceValue || nonce} unapprovedTxCount={unapprovedTxCount} diff --git a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js index 1185c81d1..7361ad8aa 100644 --- a/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js +++ b/ui/pages/confirm-transaction-base/confirm-transaction-base.container.js @@ -120,7 +120,10 @@ const mapStateToProps = (state, ownProps) => { shortenAddress(toChecksumHexAddress(toAddress)); const checksummedAddress = toChecksumHexAddress(toAddress); - const addressBookObject = addressBook[checksummedAddress]; + const addressBookObject = + addressBook && + addressBook[chainId] && + addressBook[chainId][checksummedAddress]; const toEns = ensResolutionsByAddress[checksummedAddress] || ''; const toNickname = addressBookObject ? addressBookObject.name : ''; const transactionStatus = transaction ? transaction.status : ''; @@ -231,6 +234,7 @@ const mapStateToProps = (state, ownProps) => { nativeCurrency, hardwareWalletRequiresConnection, isMultiLayerFeeNetwork, + chainId, }; }; diff --git a/ui/pages/send/send-content/send-content.component.js b/ui/pages/send/send-content/send-content.component.js index fd44a1c41..9f9acd944 100644 --- a/ui/pages/send/send-content/send-content.component.js +++ b/ui/pages/send/send-content/send-content.component.js @@ -2,6 +2,7 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import PageContainerContent from '../../../components/ui/page-container/page-container-content.component'; import Dialog from '../../../components/ui/dialog'; +import NicknamePopovers from '../../../components/app/modals/nickname-popovers'; import { ETH_GAS_PRICE_FETCH_WARNING_KEY, GAS_PRICE_FETCH_FAILURE_ERROR_KEY, @@ -16,13 +17,16 @@ import SendAssetRow from './send-asset-row'; import SendGasRow from './send-gas-row'; export default class SendContent extends Component { + state = { + showNicknamePopovers: false, + }; + static contextTypes = { t: PropTypes.func, }; static propTypes = { isAssetSendable: PropTypes.bool, - showAddToAddressBookModal: PropTypes.func, showHexData: PropTypes.bool, contact: PropTypes.object, isOwnedAccount: PropTypes.bool, @@ -34,6 +38,7 @@ export default class SendContent extends Component { networkOrAccountNotSupports1559: PropTypes.bool, getIsBalanceInsufficient: PropTypes.bool, asset: PropTypes.object, + to: PropTypes.string, }; render() { @@ -81,24 +86,29 @@ export default class SendContent extends Component { maybeRenderAddContact() { const { t } = this.context; - const { - isOwnedAccount, - showAddToAddressBookModal, - contact = {}, - } = this.props; + const { isOwnedAccount, contact = {}, to } = this.props; + const { showNicknamePopovers } = this.state; if (isOwnedAccount || contact.name) { return null; } return ( - - {t('newAccountDetectedDialogMessage')} - + <> + this.setState({ showNicknamePopovers: true })} + > + {t('newAccountDetectedDialogMessage')} + + {showNicknamePopovers ? ( + this.setState({ showNicknamePopovers: false })} + address={to} + /> + ) : null} + ); } diff --git a/ui/pages/send/send-content/send-content.container.js b/ui/pages/send/send-content/send-content.container.js index e5d1c62b9..814af712d 100644 --- a/ui/pages/send/send-content/send-content.container.js +++ b/ui/pages/send/send-content/send-content.container.js @@ -13,7 +13,6 @@ import { getSendAsset, } from '../../../ducks/send'; -import * as actions from '../../../store/actions'; import SendContent from './send-content.component'; function mapStateToProps(state) { @@ -38,30 +37,4 @@ function mapStateToProps(state) { }; } -function mapDispatchToProps(dispatch) { - return { - showAddToAddressBookModal: (recipient) => - dispatch( - actions.showModal({ - name: 'ADD_TO_ADDRESSBOOK', - recipient, - }), - ), - }; -} - -function mergeProps(stateProps, dispatchProps, ownProps) { - const { to, ...restStateProps } = stateProps; - return { - ...ownProps, - ...restStateProps, - showAddToAddressBookModal: () => - dispatchProps.showAddToAddressBookModal(to), - }; -} - -export default connect( - mapStateToProps, - mapDispatchToProps, - mergeProps, -)(SendContent); +export default connect(mapStateToProps)(SendContent); diff --git a/yarn.lock b/yarn.lock index 0ffc3abdf..a6f1638e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3955,6 +3955,79 @@ optionalDependencies: secp256k1 "^3.5.2" +"@truffle/abi-utils@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@truffle/abi-utils/-/abi-utils-0.2.4.tgz#9fc8bfc95bbe29a33cca3ab9028865b078e2f051" + integrity sha512-ICr5Sger6r5uj2G5GN9Zp9OQDCaCqe2ZyAEyvavDoFB+jX0zZFUCfDnv5jllGRhgzdYJ3mec2390mjUyz9jSZA== + dependencies: + change-case "3.0.2" + faker "^5.3.1" + fast-check "^2.12.1" + +"@truffle/code-utils@^1.2.30": + version "1.2.30" + resolved "https://registry.yarnpkg.com/@truffle/code-utils/-/code-utils-1.2.30.tgz#aa0a2a11eea40e3c76824729467f27d6cb76819b" + integrity sha512-/GFtGkmSZlLpIbIjBTunvhQQ4K2xaHK63QCEKydt3xRMPhpaeVAIaBNH53Z1ulOMDi6BZcSgwQHkquHf/omvMQ== + dependencies: + cbor "^5.1.0" + +"@truffle/codec@^0.11.18", "@truffle/codec@^0.11.19": + version "0.11.19" + resolved "https://registry.yarnpkg.com/@truffle/codec/-/codec-0.11.19.tgz#c3da4b823d1f730a1114f94406fccfa5459b6bdd" + integrity sha512-ZxsfRWBE4wcQ01NCpMWH6VRJ/q3mGTl3ku8ln+WJ2P6McIMsS37imO3d8N9NWiQ49klc9kJfT3mKnOVMLTJhIg== + dependencies: + "@truffle/abi-utils" "^0.2.4" + "@truffle/compile-common" "^0.7.22" + big.js "^5.2.2" + bn.js "^5.1.3" + cbor "^5.1.0" + debug "^4.3.1" + lodash.clonedeep "^4.5.0" + lodash.escaperegexp "^4.1.2" + lodash.partition "^4.6.0" + lodash.sum "^4.0.2" + semver "^7.3.4" + utf8 "^3.0.0" + web3-utils "1.5.3" + +"@truffle/compile-common@^0.7.22": + version "0.7.22" + resolved "https://registry.yarnpkg.com/@truffle/compile-common/-/compile-common-0.7.22.tgz#c376eea36f59dc770ece3bc8cbb7132f49352846" + integrity sha512-afFKh0Wphn8JrCSjOORKjO8/E1X0EtQv6GpFJpQCAWo3/i4VGcSVKR1rjkknnExtjEGe9PJH/Ym/opGH3pQyDw== + dependencies: + "@truffle/error" "^0.0.14" + colors "^1.4.0" + +"@truffle/decoder@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@truffle/decoder/-/decoder-5.1.0.tgz#79cb9f6131ed81f69ec67a241fd5bbfd079d1501" + integrity sha512-bfNIqSlJviZjpHSiQ76IQvrJewKAzqnpIlC6V73tnhmJn2v21OQ945dXeQdVn/1V9gTkqSUgcXfNjB0wBKaevg== + dependencies: + "@truffle/abi-utils" "^0.2.4" + "@truffle/codec" "^0.11.19" + "@truffle/compile-common" "^0.7.22" + "@truffle/source-map-utils" "^1.3.63" + bn.js "^5.1.3" + debug "^4.3.1" + web3-utils "1.5.3" + +"@truffle/error@^0.0.14": + version "0.0.14" + resolved "https://registry.yarnpkg.com/@truffle/error/-/error-0.0.14.tgz#59683b5407bede7bddf16d80dc5592f9c5e5fa05" + integrity sha512-utJx+SZYoMqk8wldQG4gCVKhV8GwMJbWY7sLXFT/D8wWZTnE2peX7URFJh/cxkjTRCO328z1s2qewkhyVsu2HA== + +"@truffle/source-map-utils@^1.3.63": + version "1.3.63" + resolved "https://registry.yarnpkg.com/@truffle/source-map-utils/-/source-map-utils-1.3.63.tgz#6fa26d6b7a0874e99d6d78a5cacc13903dbcffd4" + integrity sha512-JmRnhONsjAdB5sTDl2xy7DUoIxg2KUGpXsPcu1EggBcojY1fZoD3wsdWWLysRDW5Od+npn/BWSdjzGdQknyVPA== + dependencies: + "@truffle/code-utils" "^1.2.30" + "@truffle/codec" "^0.11.19" + debug "^4.3.1" + json-pointer "^0.6.0" + node-interval-tree "^1.3.3" + web3-utils "1.5.3" + "@types/aria-query@^4.2.0": version "4.2.0" resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" @@ -6926,7 +6999,7 @@ bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.11.0, bn.js@^4.11.6, bn.js@^4 resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== -bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0: +bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.1.3, bn.js@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== @@ -7141,6 +7214,11 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browser-util-inspect@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browser-util-inspect/-/browser-util-inspect-0.2.0.tgz#cdda8ce1a4a07a4386035168a228c8777bff459c" + integrity sha1-zdqM4aSgekOGA1FooijId3v/RZw= + browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.0.6, browserify-aes@^1.1.1, browserify-aes@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -7694,6 +7772,14 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camel-case@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + camel-case@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" @@ -7785,6 +7871,14 @@ cbor-web@^7.0.6: resolved "https://registry.yarnpkg.com/cbor-web/-/cbor-web-7.0.6.tgz#6e23a0c58db4c38e485e395de511b9e2f628961c" integrity sha512-A6ZH12jcDJG9PS7StugO78G+ok23SAjxMugGInPBy4IItiH6hYzybi6HQkGjWw9jBEGQpIBkleB2mizxYZIpLw== +cbor@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-5.2.0.tgz#4cca67783ccd6de7b50ab4ed62636712f287a67c" + integrity sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A== + dependencies: + bignumber.js "^9.0.1" + nofilter "^1.0.4" + ccount@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.0.4.tgz#9cf2de494ca84060a2a8d2854edd6dfb0445f386" @@ -7871,6 +7965,30 @@ chalk@~0.4.0: has-color "~0.1.0" strip-ansi "~0.1.0" +change-case@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.0.2.tgz#fd48746cce02f03f0a672577d1d3a8dc2eceb037" + integrity sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA== + dependencies: + camel-case "^3.0.0" + constant-case "^2.0.0" + dot-case "^2.1.0" + header-case "^1.0.0" + is-lower-case "^1.1.0" + is-upper-case "^1.1.0" + lower-case "^1.1.1" + lower-case-first "^1.0.0" + no-case "^2.3.2" + param-case "^2.1.0" + pascal-case "^2.0.0" + path-case "^2.1.0" + sentence-case "^2.1.0" + snake-case "^2.1.0" + swap-case "^1.1.0" + title-case "^2.1.0" + upper-case "^1.1.1" + upper-case-first "^1.1.0" + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -8373,7 +8491,7 @@ colors@0.5.x: resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774" integrity sha1-fQAj6usVTo7p/Oddy5I9DtFmd3Q= -colors@^1.1.2: +colors@^1.1.2, colors@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== @@ -8583,6 +8701,14 @@ consolidate@^0.16.0: dependencies: bluebird "^3.7.2" +constant-case@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46" + integrity sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY= + dependencies: + snake-case "^2.1.0" + upper-case "^1.1.1" + constants-browserify@^1.0.0, constants-browserify@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" @@ -10039,6 +10165,13 @@ domutils@^1.5.1: dom-serializer "0" domelementtype "1" +dot-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee" + integrity sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4= + dependencies: + no-case "^2.2.0" + dot-case@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.3.tgz#21d3b52efaaba2ea5fda875bb1aa8124521cf4aa" @@ -12223,6 +12356,11 @@ fake-merkle-patricia-tree@^1.0.1: dependencies: checkpoint-store "^1.1.0" +faker@^5.3.1: + version "5.5.3" + resolved "https://registry.yarnpkg.com/faker/-/faker-5.5.3.tgz#c57974ee484431b25205c2c8dc09fda861e51e0e" + integrity sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g== + fancy-log@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/fancy-log/-/fancy-log-1.3.2.tgz#f41125e3d84f2e7d89a43d06d958c8f78be16be1" @@ -12242,6 +12380,13 @@ fancy-log@^1.3.2, fancy-log@^1.3.3: parse-node-version "^1.0.0" time-stamp "^1.0.0" +fast-check@^2.12.1: + version "2.19.0" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-2.19.0.tgz#e87666450e417cd163a564bd546ee763d27c0f19" + integrity sha512-qY4Rc0Nljl2aJx2qgbK3o6wPBjL9QvhKdD/VqJgaKd5ewn8l4ViqgDpUHJq/JkHTBnFKomYYvkFkOYGDVTT8bw== + dependencies: + pure-rand "^5.0.0" + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -12797,7 +12942,7 @@ for-own@^1.0.0: dependencies: for-in "^1.0.1" -foreach@^2.0.5: +foreach@^2.0.4, foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= @@ -14236,6 +14381,14 @@ he@1.2.0, he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +header-case@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d" + integrity sha1-lTWXMZfBRLCWE81l0xfvGZY70C0= + dependencies: + no-case "^2.2.0" + upper-case "^1.1.3" + heap@0.2.6, heap@~0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.6.tgz#087e1f10b046932fc8594dd9e6d378afc9d1e5ac" @@ -15744,6 +15897,13 @@ is-ipfs@~0.6.1: multibase "~0.6.0" multihashes "~0.4.13" +is-lower-case@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393" + integrity sha1-fhR75HaNxGbbO/shzGCzHmrWk5M= + dependencies: + lower-case "^1.1.0" + is-mergeable-object@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-mergeable-object/-/is-mergeable-object-1.1.1.tgz#faaa3ed1cfce87d6f7d2f5885e92cc30af3e2ebf" @@ -16037,6 +16197,13 @@ is-unc-path@^1.0.0: dependencies: unc-path-regex "^0.1.2" +is-upper-case@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f" + integrity sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8= + dependencies: + upper-case "^1.1.0" + is-url@^1.2.2, is-url@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/is-url/-/is-url-1.2.4.tgz#04a4df46d28c4cff3d73d01ff06abeb318a1aa52" @@ -16825,6 +16992,13 @@ json-parse-even-better-errors@^2.3.0: resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-pointer@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/json-pointer/-/json-pointer-0.6.1.tgz#3c6caa6ac139e2599f5a1659d39852154015054d" + integrity sha512-3OvjqKdCBvH41DLpV4iSt6v2XhZXV1bPB4OROuknvUXI7ZQNofieCPkmE26stEJ9zdQuvIxDHCuYhfgxFAAs+Q== + dependencies: + foreach "^2.0.4" + json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0: version "3.8.0" resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.8.0.tgz#9d4ff447241792e1d0a232f6ef927302bb0c62a9" @@ -18331,6 +18505,11 @@ lodash.escape@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.escape/-/lodash.escape-4.0.1.tgz#c9044690c21e04294beaa517712fded1fa88de98" integrity sha1-yQRGkMIeBClL6qUXcS/e0fqI3pg= +lodash.escaperegexp@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" + integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c= + lodash.filter@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" @@ -18396,11 +18575,21 @@ lodash.memoize@~3.0.3: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" integrity sha1-LcvSwofLwKVcxCMovQxzYVDVPj8= +lodash.partition@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.partition/-/lodash.partition-4.6.0.tgz#a38e46b73469e0420b0da1212e66d414be364ba4" + integrity sha1-o45GtzRp4EILDaEhLmbUFL42S6Q= + lodash.sortby@^4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash.sum@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lodash.sum/-/lodash.sum-4.0.2.tgz#ad90e397965d803d4f1ff7aa5b2d0197f3b4637b" + integrity sha1-rZDjl5ZdgD1PH/eqWy0Bl/O0Y3s= + lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" @@ -18494,6 +18683,18 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3 dependencies: js-tokens "^3.0.0 || ^4.0.0" +lower-case-first@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1" + integrity sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E= + dependencies: + lower-case "^1.1.2" + +lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw= + lower-case@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.1.tgz#39eeb36e396115cc05e29422eaea9e692c9408c7" @@ -19809,6 +20010,13 @@ nise@^4.0.1: just-extend "^4.0.2" path-to-regexp "^1.7.0" +no-case@^2.2.0, no-case@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + no-case@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.3.tgz#c21b434c1ffe48b39087e86cfb4d2582e9df18f8" @@ -19952,6 +20160,13 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= +node-interval-tree@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/node-interval-tree/-/node-interval-tree-1.3.3.tgz#15ffb904cde08270214acace8dc7653e89ae32b7" + integrity sha512-K9vk96HdTK5fEipJwxSvIIqwTqr4e3HRJeJrNxBSeVMNSC/JWARRaX7etOLOuTmrRMeOI/K5TCJu3aWIwZiNTw== + dependencies: + shallowequal "^1.0.2" + node-libs-browser@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" @@ -20067,6 +20282,11 @@ nodeify@^1.0.1: is-promise "~1.0.0" promise "~1.3.0" +nofilter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/nofilter/-/nofilter-1.0.4.tgz#78d6f4b6a613e7ced8b015cec534625f7667006e" + integrity sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA== + nomnom@1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" @@ -21061,6 +21281,13 @@ parallel-transform@^1.1.0: inherits "^2.0.3" readable-stream "^2.1.5" +param-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc= + dependencies: + no-case "^2.2.0" + param-case@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.3.tgz#4be41f8399eff621c56eebb829a5e451d9801238" @@ -21223,6 +21450,14 @@ parseurl@^1.3.2, parseurl@~1.3.2, parseurl@~1.3.3: resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +pascal-case@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e" + integrity sha1-LVeNNFX2YNpl7KGO+VtODekSdh4= + dependencies: + camel-case "^3.0.0" + upper-case-first "^1.1.0" + pascal-case@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.1.tgz#5ac1975133ed619281e88920973d2cd1f279de5f" @@ -21283,6 +21518,13 @@ path-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== +path-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5" + integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU= + dependencies: + no-case "^2.2.0" + path-dirname@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" @@ -22668,6 +22910,11 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-rand@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-5.0.0.tgz#87f5bdabeadbd8904e316913a5c0b8caac517b37" + integrity sha512-lD2/y78q+7HqBx2SaT6OT4UcwtvXNRfEpzYEzl0EQ+9gZq2Qi3fa0HDnYPeqQwhlHJFBUhT7AO3mLU3+8bynHA== + pushdata-bitcoin@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz#15931d3cd967ade52206f523aa7331aef7d43af7" @@ -24705,6 +24952,14 @@ send@0.17.1: range-parser "~1.2.1" statuses "~1.5.0" +sentence-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4" + integrity sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ= + dependencies: + no-case "^2.2.0" + upper-case-first "^1.1.2" + serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -25060,6 +25315,13 @@ smart-buffer@^4.0.2, smart-buffer@^4.1.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== +snake-case@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f" + integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8= + dependencies: + no-case "^2.2.0" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -26141,6 +26403,14 @@ svg-tags@^1.0.0: resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= +swap-case@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3" + integrity sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM= + dependencies: + lower-case "^1.1.1" + upper-case "^1.1.1" + swappable-obj-proxy@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/swappable-obj-proxy/-/swappable-obj-proxy-1.1.0.tgz#fe23c60a0df22499e85d94b71297d9c39ff05fa4" @@ -26593,6 +26863,14 @@ tiny-worker@^2.3.0: dependencies: esm "^3.2.25" +title-case@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa" + integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o= + dependencies: + no-case "^2.2.0" + upper-case "^1.0.3" + tmp@0.0.30: version "0.0.30" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.30.tgz#72419d4a8be7d6ce75148fd8b324e593a711c2ed" @@ -27367,6 +27645,18 @@ uport-base64url@3.0.2-alpha.0: dependencies: buffer "^5.2.1" +upper-case-first@^1.1.0, upper-case-first@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115" + integrity sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU= + dependencies: + upper-case "^1.1.1" + +upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg= + uri-js@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" @@ -28176,6 +28466,19 @@ web3-utils@1.2.11: underscore "1.9.1" utf8 "3.0.0" +web3-utils@1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.5.3.tgz#e914c9320cd663b2a09a5cb920ede574043eb437" + integrity sha512-56nRgA+Ad9SEyCv39g36rTcr5fpsd4L9LgV3FK0aB66nAMazLAA6Qz4lH5XrUKPDyBIPGJIR+kJsyRtwcu2q1Q== + dependencies: + bn.js "^4.11.9" + eth-lib "0.2.8" + ethereum-bloom-filters "^1.0.6" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + web3@1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/web3/-/web3-1.2.11.tgz#50f458b2e8b11aa37302071c170ed61cff332975"