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 <alaahd@Alaas-MacBook-M1-Pro-14-inch.local>
Co-authored-by: Dan Miller <danjm.com@gmail.com>
Co-authored-by: g. nicholas d'andrea <gnidan@trufflesuite.com>
feature/default_network_editable
Alaa Hadad 3 years ago committed by GitHub
parent fb60b14367
commit e056c88ba7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      app/_locales/am/messages.json
  2. 3
      app/_locales/ar/messages.json
  3. 3
      app/_locales/bg/messages.json
  4. 3
      app/_locales/bn/messages.json
  5. 3
      app/_locales/ca/messages.json
  6. 3
      app/_locales/da/messages.json
  7. 3
      app/_locales/de/messages.json
  8. 3
      app/_locales/el/messages.json
  9. 22
      app/_locales/en/messages.json
  10. 3
      app/_locales/es/messages.json
  11. 3
      app/_locales/es_419/messages.json
  12. 3
      app/_locales/et/messages.json
  13. 3
      app/_locales/fa/messages.json
  14. 3
      app/_locales/fi/messages.json
  15. 3
      app/_locales/fil/messages.json
  16. 3
      app/_locales/fr/messages.json
  17. 3
      app/_locales/he/messages.json
  18. 3
      app/_locales/hi/messages.json
  19. 3
      app/_locales/hr/messages.json
  20. 3
      app/_locales/hu/messages.json
  21. 3
      app/_locales/id/messages.json
  22. 3
      app/_locales/it/messages.json
  23. 3
      app/_locales/ja/messages.json
  24. 3
      app/_locales/kn/messages.json
  25. 3
      app/_locales/ko/messages.json
  26. 3
      app/_locales/lt/messages.json
  27. 3
      app/_locales/lv/messages.json
  28. 3
      app/_locales/ms/messages.json
  29. 3
      app/_locales/no/messages.json
  30. 3
      app/_locales/ph/messages.json
  31. 3
      app/_locales/pl/messages.json
  32. 3
      app/_locales/pt_BR/messages.json
  33. 3
      app/_locales/ro/messages.json
  34. 3
      app/_locales/ru/messages.json
  35. 3
      app/_locales/sk/messages.json
  36. 3
      app/_locales/sl/messages.json
  37. 3
      app/_locales/sr/messages.json
  38. 3
      app/_locales/sv/messages.json
  39. 3
      app/_locales/sw/messages.json
  40. 3
      app/_locales/tl/messages.json
  41. 3
      app/_locales/uk/messages.json
  42. 3
      app/_locales/vi/messages.json
  43. 3
      app/_locales/zh_CN/messages.json
  44. 3
      app/_locales/zh_TW/messages.json
  45. 26
      app/images/icons/collapse.svg
  46. 28
      app/images/icons/expand.svg
  47. 3
      package.json
  48. 13
      patches/acorn+7.4.1.patch
  49. 14
      patches/colors+1.4.0.patch
  50. 4
      test/e2e/metamask-ui.spec.js
  51. 13
      test/e2e/tests/address-book.spec.js
  52. 1
      ui/components/app/app-components.scss
  53. 7
      ui/components/app/confirm-page-container/confirm-page-container-container.test.js
  54. 9
      ui/components/app/confirm-page-container/confirm-page-container-content/confirm-page-container-content.component.js
  55. 6
      ui/components/app/confirm-page-container/confirm-page-container-content/index.scss
  56. 23
      ui/components/app/confirm-page-container/confirm-page-container.component.js
  57. 29
      ui/components/app/confirm-page-container/confirm-page-container.container.js
  58. 1
      ui/components/app/modals/nickname-popovers/index.js
  59. 72
      ui/components/app/modals/nickname-popovers/nickname-popovers.component.js
  60. 14
      ui/components/app/transaction-breakdown/index.scss
  61. 6
      ui/components/app/transaction-breakdown/transaction-breakdown-row/index.scss
  62. 9
      ui/components/app/transaction-breakdown/transaction-breakdown-row/transaction-breakdown-row.component.js
  63. 9
      ui/components/app/transaction-breakdown/transaction-breakdown.component.js
  64. 71
      ui/components/app/transaction-decoding/components/decoding/address/address.component.js
  65. 1
      ui/components/app/transaction-decoding/components/decoding/address/index.js
  66. 12
      ui/components/app/transaction-decoding/components/decoding/address/index.scss
  67. 38
      ui/components/app/transaction-decoding/components/ui/copy-raw-data/copy-raw-data.component.js
  68. 1
      ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.js
  69. 30
      ui/components/app/transaction-decoding/components/ui/copy-raw-data/index.scss
  70. 5
      ui/components/app/transaction-decoding/constants.js
  71. 1
      ui/components/app/transaction-decoding/index.js
  72. 169
      ui/components/app/transaction-decoding/index.scss
  73. 219
      ui/components/app/transaction-decoding/transaction-decoding.component.js
  74. 30
      ui/components/app/transaction-decoding/transaction-decoding.util.js
  75. 94
      ui/components/app/transaction-list-item-details/index.scss
  76. 91
      ui/components/app/transaction-list-item-details/transaction-list-item-details.component.js
  77. 10
      ui/components/app/transaction-list-item/transaction-list-item.component.js
  78. 4
      ui/components/app/transaction-status/index.scss
  79. 7
      ui/components/app/transaction-status/transaction-status.component.js
  80. 51
      ui/components/ui/disclosure/disclosure.js
  81. 46
      ui/components/ui/disclosure/disclosure.scss
  82. 1
      ui/components/ui/disclosure/index.js
  83. 9
      ui/components/ui/nickname-popover/index.scss
  84. 42
      ui/components/ui/nickname-popover/nickname-popover.component.js
  85. 39
      ui/components/ui/sender-to-recipient/sender-to-recipient.component.js
  86. 1
      ui/components/ui/ui-components.scss
  87. 12
      ui/components/ui/update-nickname-popover/index.scss
  88. 14
      ui/components/ui/update-nickname-popover/update-nickname-popover.js
  89. 50
      ui/pages/confirm-transaction-base/confirm-transaction-base.component.js
  90. 6
      ui/pages/confirm-transaction-base/confirm-transaction-base.container.js
  91. 24
      ui/pages/send/send-content/send-content.component.js
  92. 29
      ui/pages/send/send-content/send-content.container.js
  93. 309
      yarn.lock

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "ተቀድቷል"
},
"copiedTransactionId": {
"message": "የተቀዳ የግብይት መለያ ቁጥር"
},
"copyAddress": {
"message": "አድራሻን ወደ ቅንጥብ ሰሌዳ ቅዳ"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "تم النسخ."
},
"copiedTransactionId": {
"message": "تم نسخ معرف المعاملة"
},
"copyAddress": {
"message": "نسخ العنوان إلى الحافظة"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Копирано!"
},
"copiedTransactionId": {
"message": "Копиран идентификационен номер на транзакцията"
},
"copyAddress": {
"message": "Копирайте адреса в клипборда"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "কপি কর হয়!"
},
"copiedTransactionId": {
"message": "কপি করনদর আইডি"
},
"copyAddress": {
"message": "কিপবি কপি করন"
},

@ -215,9 +215,6 @@
"copiedExclamation": {
"message": "S'ha copiat!"
},
"copiedTransactionId": {
"message": "ID de transacció copiada"
},
"copyAddress": {
"message": "Copiar adreça al porta-retalls"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Kopieret!"
},
"copiedTransactionId": {
"message": "Kopieret transaktions-id"
},
"copyAddress": {
"message": "Kopier adresse til udklipsholder"
},

@ -209,9 +209,6 @@
"copiedExclamation": {
"message": "Kopiert!"
},
"copiedTransactionId": {
"message": "Transaktions-ID kopiert"
},
"copyAddress": {
"message": "Adresse in die Zwischenablage kopieren"
},

@ -215,9 +215,6 @@
"copiedExclamation": {
"message": "Έγινε αντιγραφή!"
},
"copiedTransactionId": {
"message": "Αντιγράφηκε το Αναγνωριστικό Συναλλαγής"
},
"copyAddress": {
"message": "Αντιγράψτε τη διεύθυνση στο πρόχειρο"
},

@ -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"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "¡Copiado!"
},
"copiedTransactionId": {
"message": "Id. de transacción copiado"
},
"copyAddress": {
"message": "Copiar dirección al Portapapeles"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "¡Copiado!"
},
"copiedTransactionId": {
"message": "Id. de transacción copiado"
},
"copyAddress": {
"message": "Copiar dirección al Portapapeles"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Kopeeritud!"
},
"copiedTransactionId": {
"message": "Kopeeritud tehingu ID"
},
"copyAddress": {
"message": "Kopeeri aadress lõikelauale"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "کپی شد!"
},
"copiedTransactionId": {
"message": "آی دی معامله کاپی شده"
},
"copyAddress": {
"message": "کاپی آدرس به کلیپ بورد"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Kopioitu"
},
"copiedTransactionId": {
"message": "Kopioitu tapahtuman tunnus"
},
"copyAddress": {
"message": "Kopioi osoite leikepöydälle"
},

@ -197,9 +197,6 @@
"copiedExclamation": {
"message": "Nakopya!"
},
"copiedTransactionId": {
"message": "Nakopya ang Transaction ID"
},
"copyAddress": {
"message": "Kopyahin ang address sa clipboard"
},

@ -209,9 +209,6 @@
"copiedExclamation": {
"message": "Copié!"
},
"copiedTransactionId": {
"message": "ID de transaction copié"
},
"copyAddress": {
"message": "Copier l'addresse dans le presse-papier"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "הועתק!"
},
"copiedTransactionId": {
"message": "מזהה עסקה הועתק"
},
"copyAddress": {
"message": "העתק כתובת ללוח"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "कि गय!"
},
"copiedTransactionId": {
"message": "क गई लनदन ID"
},
"copyAddress": {
"message": "किपबड पर पत कर"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Kopirano!"
},
"copiedTransactionId": {
"message": "Kopirana identifikacijska oznaka transakcije"
},
"copyAddress": {
"message": "Kopiraj adresu u međuspremnik"
},

@ -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"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "Disalin!"
},
"copiedTransactionId": {
"message": "ID Transaksi yang Disalin"
},
"copyAddress": {
"message": "Salin alamat ke clipboard"
},

@ -356,9 +356,6 @@
"copiedExclamation": {
"message": "Copiato!"
},
"copiedTransactionId": {
"message": "ID Transazione Copiato"
},
"copyAddress": {
"message": "Copia l'indirizzo"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "コピーされました!"
},
"copiedTransactionId": {
"message": "コピーされたトランザクション ID"
},
"copyAddress": {
"message": "アドレスをクリップボードにコピー"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "ನಕಲಿಸಲಿ!"
},
"copiedTransactionId": {
"message": "ವಯವಹರ ID ಅನ ನಕಲಿಸಲಿ"
},
"copyAddress": {
"message": "ವಿಸವನಿ ನಕಲಿಿ"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "복사 완료!"
},
"copiedTransactionId": {
"message": "거래 ID 복사됨"
},
"copyAddress": {
"message": "주소를 클립보드에 복사"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Nukopijuota!"
},
"copiedTransactionId": {
"message": "Nukopijuotas operacijos ID"
},
"copyAddress": {
"message": "Kopijuoti adresą į iškarpinę"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Nokopēts!"
},
"copiedTransactionId": {
"message": "Nokopētais darījuma ID"
},
"copyAddress": {
"message": "Iekopēt adresi starpliktuvē"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Disalin!"
},
"copiedTransactionId": {
"message": "ID Transaksi yang Disalin"
},
"copyAddress": {
"message": "Salin alamat kepada papan klip"
},

@ -215,9 +215,6 @@
"copiedExclamation": {
"message": "Kopiert!"
},
"copiedTransactionId": {
"message": "Kopiert transaksjonsidentifikasjon"
},
"copyAddress": {
"message": "Kopier adresse til utklippstavlen "
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "Nakopya na!"
},
"copiedTransactionId": {
"message": "Nakopya ang Transaction ID"
},
"copyAddress": {
"message": "Kopyahin ang address sa clipboard"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Skopiowane!"
},
"copiedTransactionId": {
"message": "Skopiowano identyfikator transakcji"
},
"copyAddress": {
"message": "Skopiuj adres do schowka"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "Copiado!"
},
"copiedTransactionId": {
"message": "ID da transação copiado"
},
"copyAddress": {
"message": "Copiar endereço para área de transferência"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Copiat!"
},
"copiedTransactionId": {
"message": "ID-ul tranzacției a fost copiat"
},
"copyAddress": {
"message": "Copiere adresă în clipboard"
},

@ -416,9 +416,6 @@
"copiedExclamation": {
"message": "Скопировано!"
},
"copiedTransactionId": {
"message": "Скопированный идентификатор транзакции"
},
"copyAddress": {
"message": "Скопировать адрес в буфер обмена"
},

@ -212,9 +212,6 @@
"copiedExclamation": {
"message": "Zkopírováno!"
},
"copiedTransactionId": {
"message": "Kopírované ID transakcie"
},
"copyAddress": {
"message": "Kopírovať adresu do schránky"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Kopirano!"
},
"copiedTransactionId": {
"message": "ID transakcije skopirana"
},
"copyAddress": {
"message": "Kopiraj naslov v odložišče"
},

@ -215,9 +215,6 @@
"copiedExclamation": {
"message": "Kopirano!"
},
"copiedTransactionId": {
"message": "Kopiran identifikator transakcije"
},
"copyAddress": {
"message": "Kopirajte adresu u ostavu"
},

@ -212,9 +212,6 @@
"copiedExclamation": {
"message": "Kopierades!"
},
"copiedTransactionId": {
"message": "Kopierade transaktions-ID"
},
"copyAddress": {
"message": "Kopiera adress till urklipp"
},

@ -212,9 +212,6 @@
"copiedExclamation": {
"message": "Imenakiliwa!"
},
"copiedTransactionId": {
"message": "Imenakili Utambulisho wa Muamala"
},
"copyAddress": {
"message": "Nakili anwani kwenye ubao wa kunakilia"
},

@ -344,9 +344,6 @@
"copiedExclamation": {
"message": "Nakopya na!"
},
"copiedTransactionId": {
"message": "Nakopya ang ID ng Transaksyon"
},
"copyAddress": {
"message": "Kopyahin ang address sa clipboard"
},

@ -218,9 +218,6 @@
"copiedExclamation": {
"message": "Скопійовано!"
},
"copiedTransactionId": {
"message": "ID Скопійованої транзакції"
},
"copyAddress": {
"message": "Копіювати адресу в буфер обміну"
},

@ -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"
},

@ -395,9 +395,6 @@
"copiedExclamation": {
"message": "已复制"
},
"copiedTransactionId": {
"message": "交易 ID 复制成功"
},
"copyAddress": {
"message": "复制地址到剪贴板"
},

@ -227,9 +227,6 @@
"copiedExclamation": {
"message": "已複製!"
},
"copiedTransactionId": {
"message": "已複製的交易 ID"
},
"copyAddress": {
"message": "複製到剪貼簿"
},

@ -0,0 +1,26 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" fill="#E5E5E5"/>
<g clip-path="url(#clip0_0_1)">
<rect width="413" height="679" transform="translate(-57 -402)" fill="white"/>
<g filter="url(#filter0_d_0_1)">
<path d="M-31 -376C-31 -380.418 -27.4183 -384 -23 -384H321C325.418 -384 329 -380.418 329 -376V252C329 256.418 325.418 260 321 260H-23C-27.4183 260 -31 256.418 -31 252V-376Z" fill="white"/>
</g>
<circle cx="8" cy="8" r="7.5" fill="#F2F3F4" stroke="#D6D9DC"/>
<line x1="4.1001" y1="7.83325" x2="11.7668" y2="7.83325" stroke="#D6D9DC" stroke-linecap="round"/>
</g>
<rect x="-2918.5" y="-1621.5" width="9747" height="4874" stroke="black"/>
<defs>
<filter id="filter0_d_0_1" x="-58" y="-409" width="414" height="698" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="13.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.12594 0 0 0 0 0.182502 0 0 0 0 0.305378 0 0 0 0.26 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_1"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_1" result="shape"/>
</filter>
<clipPath id="clip0_0_1">
<rect width="413" height="679" fill="white" transform="translate(-57 -402)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

@ -0,0 +1,28 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="16" height="16" fill="#E5E5E5"/>
<g clip-path="url(#clip0_0_1)">
<rect width="413" height="679" transform="translate(-57 -546)" fill="white"/>
<g filter="url(#filter0_d_0_1)">
<path d="M-31 -520C-31 -524.418 -27.4183 -528 -23 -528H321C325.418 -528 329 -524.418 329 -520V108C329 112.418 325.418 116 321 116H-23C-27.4183 116 -31 112.418 -31 108V-520Z" fill="white"/>
</g>
<line x1="7.5" y1="-128" x2="7.49999" y2="8" stroke="#D6D9DC"/>
<circle cx="8" cy="8" r="7.5" fill="white" stroke="#D6D9DC"/>
<line x1="4.1001" y1="7.83325" x2="11.7668" y2="7.83325" stroke="#D6D9DC" stroke-linecap="round"/>
<line x1="8.1001" y1="4.16699" x2="8.1001" y2="11.8337" stroke="#D6D9DC" stroke-linecap="round"/>
</g>
<rect x="-2918.5" y="-1765.5" width="9747" height="4874" stroke="black"/>
<defs>
<filter id="filter0_d_0_1" x="-58" y="-553" width="414" height="698" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="2"/>
<feGaussianBlur stdDeviation="13.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.12594 0 0 0 0 0.182502 0 0 0 0 0.305378 0 0 0 0.26 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_0_1"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_0_1" result="shape"/>
</filter>
<clipPath id="clip0_0_1">
<rect width="413" height="679" fill="white" transform="translate(-57 -546)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -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",

@ -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

@ -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() {

@ -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',

@ -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');

@ -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';

@ -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',

@ -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 (
<Tabs>
@ -67,6 +68,12 @@ export default class ConfirmPageContainerContent extends Component {
<Tab className="confirm-page-container-content__tab" name={t('data')}>
{dataComponent}
</Tab>
<Tab
className="confirm-page-container-content__tab"
name={t('dataHex')}
>
{dataHexComponent}
</Tab>
</Tabs>
);
}

@ -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 {

@ -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 {
</ConfirmPageContainerHeader>
<div>
{showAddToAddressDialog && (
<>
<Dialog
type="message"
className="send__dialog"
onClick={() => showAddToAddressBookModal()}
onClick={() => this.setState({ showNicknamePopovers: true })}
>
{this.context.t('newAccountDetectedDialogMessage')}
</Dialog>
{this.state.showNicknamePopovers ? (
<NicknamePopovers
onClose={() =>
this.setState({ showNicknamePopovers: false })
}
address={toAddress}
/>
) : null}
</>
)}
</div>
{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}

@ -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);

@ -0,0 +1 @@
export { default } from './nickname-popovers.component';

@ -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 (
<UpdateNicknamePopover
address={address}
nickname={recipientNickname || null}
memo={addressBookEntryObject?.memo}
onClose={() => setPopoverToDisplay(SHOW_NICKNAME_POPOVER)}
onAdd={(recipient, nickname, memo) =>
dispatch(addToAddressBook(recipient, nickname, memo))
}
/>
);
}
// SHOW_NICKNAME_POPOVER case
return (
<NicknamePopover
address={address}
nickname={recipientNickname || null}
onClose={onClose}
onAdd={() => setPopoverToDisplay(ADD_NICKNAME_POPOVER)}
explorerLink={explorerLink}
/>
);
};
NicknamePopovers.propTypes = {
address: PropTypes.string,
onClose: PropTypes.func,
};
export default NicknamePopovers;

@ -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;
}
}
}

@ -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;
}
}

@ -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 (
<div
className={classnames('transaction-breakdown-row', className)}
className={classnames(
'transaction-breakdown-row',
divider ? 'transaction-breakdown-row--with-bottom-border' : '',
className,
)}
data-testid="transaction-breakdown-row"
>
<div

@ -65,7 +65,7 @@ export default class TransactionBreakdown extends PureComponent {
return (
<div className={classnames('transaction-breakdown', className)}>
<div className="transaction-breakdown__title">{t('transaction')}</div>
<TransactionBreakdownRow title={t('nonce')}>
<TransactionBreakdownRow divider title={t('nonce')}>
{typeof nonce === 'undefined' ? null : (
<HexToDecimal
className="transaction-breakdown__value"
@ -76,7 +76,7 @@ export default class TransactionBreakdown extends PureComponent {
<TransactionBreakdownRow
title={isTokenApprove ? t('spendLimitAmount') : t('amount')}
>
<span className="transaction-breakdown__value">
<span className="transaction-breakdown__value transaction-breakdown__value--amount">
{primaryCurrency}
</span>
</TransactionBreakdownRow>
@ -178,7 +178,10 @@ export default class TransactionBreakdown extends PureComponent {
</TransactionBreakdownRow>
)}
{isEIP1559Transaction && (
<TransactionBreakdownRow title={t('transactionHistoryMaxFeePerGas')}>
<TransactionBreakdownRow
divider
title={t('transactionHistoryMaxFeePerGas')}
>
<UserPreferencedCurrencyDisplay
className="transaction-breakdown__value"
currency={nativeCurrency}

@ -0,0 +1,71 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import copyToClipboard from 'copy-to-clipboard';
import { shortenAddress } from '../../../../../../helpers/utils/util';
import Identicon from '../../../../../ui/identicon';
import { useI18nContext } from '../../../../../../hooks/useI18nContext';
import { getAddressBook } from '../../../../../../selectors';
import NicknamePopovers from '../../../../modals/nickname-popovers';
const Address = ({
checksummedRecipientAddress,
onRecipientClick,
addressOnly,
recipientEns,
recipientName,
}) => {
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 (
<div
className="tx-insight tx-insight-component tx-insight-component-address"
onClick={() => {
copyToClipboard(checksummedRecipientAddress);
if (onRecipientClick) {
onRecipientClick();
}
}}
>
<div className="tx-insight-component-address__sender-icon">
<Identicon address={checksummedRecipientAddress} diameter={18} />
</div>
<div
className="address__name"
onClick={() => setShowNicknamePopovers(true)}
>
{recipientToRender}
</div>
{showNicknamePopovers ? (
<NicknamePopovers
onClose={() => setShowNicknamePopovers(false)}
address={checksummedRecipientAddress}
/>
) : null}
</div>
);
};
Address.propTypes = {
checksummedRecipientAddress: PropTypes.string,
recipientName: PropTypes.string,
recipientEns: PropTypes.string,
addressOnly: PropTypes.bool,
onRecipientClick: PropTypes.func,
};
export default Address;

@ -0,0 +1 @@
export { default } from './address.component';

@ -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;
}
}
}

@ -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 (
<div className="copy-raw-data">
<Tooltip position="right" title={copied ? t('copiedExclamation') : ''}>
<button
onClick={() => {
handleCopy(data);
}}
className="copy-raw-data__button"
>
<div className="copy-raw-data__icon">
<CopyIcon size={12} color="#BBC0C5" />
</div>
<div className="copy-raw-data__label">
{t('copyRawTransactionData')}
</div>
</button>
</Tooltip>
</div>
);
};
CopyRawData.propTypes = {
data: PropTypes.string.isRequired,
};
export default CopyRawData;

@ -0,0 +1 @@
export { default } from './copy-raw-data.component';

@ -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;
}
}

@ -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`;

@ -0,0 +1 @@
export { default } from './transaction-decoding.component';

@ -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;
}
}
}
}

@ -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 (
<span className="sol-item solidity-error">
<span>Malformed data</span>
</span>
);
default:
switch (typeClass) {
case 'int':
return (
<span className="sol-item solidity-int">
{[value.asBN || value.asString].toString()}
</span>
);
case 'uint':
return (
<span className="sol-item solidity-uint">
{[value.asBN || value.asString].toString()}
</span>
);
case 'bytes':
return (
<span className="sol-item solidity-bytes">{value.asHex}</span>
);
case 'array':
return (
<details>
<summary className="typography--color-black">{name}: </summary>
<ol>
{value.map((itemValue, index) => {
return (
<li key={`${itemValue.type?.typeClass}-${index}`}>
{renderLeaf({
typeClass: itemValue.type?.typeClass,
value: itemValue.value,
kind: itemValue.kind,
})}
</li>
);
})}
</ol>
</details>
);
case 'address': {
const address = value?.asAddress;
return (
<Address
addressOnly
checksummedRecipientAddress={toChecksumHexAddress(address)}
/>
);
}
default:
return (
<pre className="sol-item solidity-raw">
{inspect(new Codec.Format.Utils.Inspect.ResultInspector(value))}
</pre>
);
}
}
};
const renderTree = (
{ name, kind, typeClass, type, value, children },
index,
) => {
return children ? (
<li key={`${typeClass}-${index}`}>
<details open={index === 0 ? 'open' : ''}>
<summary>{name}: </summary>
<ol>{children.map(renderTree)}</ol>
</details>
</li>
) : (
<li className="solidity-value">
<div className="solidity-named-item solidity-item">
{typeClass !== 'array' && !Array.isArray(value) ? (
<span className="param-name typography--color-black">{name}: </span>
) : null}
<span className="sol-item solidity-uint">
{renderLeaf({ name, typeClass, type, value, kind })}
</span>
</div>
</li>
);
};
const renderTransactionDecoding = () => {
if (loading) {
return (
<div className="tx-insight-loading">
<Spinner color="#F7C06C" />
</div>
);
}
if (hasError) {
return (
<div className="tx-insight-error">
<ErrorMessage errorMessage={errorMessage} />
</div>
);
}
return (
<div className="tx-insight-content">
<div className="tx-insight-content__tree-component">
<ol>{tx.map(renderTree)}</ol>
</div>
<div className="tx-insight-content__copy-raw-tx">
<CopyRawData data={data} />
</div>
</div>
);
};
return <div className="tx-insight">{renderTransactionDecoding()}</div>;
}
TransactionDecoding.propTypes = {
to: PropTypes.string.isRequired,
inputData: PropTypes.string.isRequired,
};

@ -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,
};
});
};

@ -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;
}
}
}

@ -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 (
<Popover title={title} onClose={onClose}>
<div className="transaction-list-item-details">
<div className="transaction-list-item-details__header">
<div>{t('details')}</div>
<div className="transaction-list-item-details__operations">
<div className="transaction-list-item-details__header-buttons">
{showSpeedUp && (
<Button
@ -161,57 +162,58 @@ export default class TransactionListItemDetails extends PureComponent {
detailsModal
/>
)}
<Tooltip
wrapperClassName="transaction-list-item-details__header-button"
containerClassName="transaction-list-item-details__header-button-tooltip-container"
title={
justCopied ? t('copiedTransactionId') : t('copyTransactionId')
}
>
{showRetry && (
<Tooltip title={t('retryTransaction')}>
<Button
type="raised"
onClick={this.handleCopyTxId}
disabled={!hash}
onClick={this.handleRetry}
className="transaction-list-item-details__header-button"
>
<Copy size={10} color="#3098DC" />
<i className="fa fa-sync"></i>
</Button>
</Tooltip>
<Tooltip
wrapperClassName="transaction-list-item-details__header-button"
containerClassName="transaction-list-item-details__header-button-tooltip-container"
title={
blockExplorerUrl
? t('viewOnCustomBlockExplorer', [
t('blockExplorerTransactionAction'),
blockExplorerUrl,
])
: t('viewOnEtherscan', [
t('blockExplorerTransactionAction'),
])
}
>
)}
</div>
</div>
<div className="transaction-list-item-details__header">
<div className="transaction-list-item-details__tx-status">
<div>Status</div>
<div>
<TransactionStatus />
</div>
</div>
<div className="transaction-list-item-details__tx-hash">
<div>
<Button
type="raised"
type="link"
onClick={this.handleBlockExplorerClick}
disabled={!hash}
>
<img src="./images/arrow-popout.svg" alt="" />
{t('viewOnBlockExplorer')}
</Button>
</Tooltip>
{showRetry && (
<Tooltip title={t('retryTransaction')}>
</div>
<div>
<Tooltip
wrapperClassName="transaction-list-item-details__header-button"
containerClassName="transaction-list-item-details__header-button-tooltip-container"
title={justCopied ? t('copiedExclamation') : null}
>
<Button
type="raised"
onClick={this.handleRetry}
className="transaction-list-item-details__header-button"
type="link"
onClick={this.handleCopyTxId}
disabled={!hash}
>
<i className="fa fa-sync"></i>
{t('copyTransactionId')}
</Button>
</Tooltip>
)}
</div>
</div>
</div>
<div className="transaction-list-item-details__body">
<div className="transaction-list-item-details__sender-to-recipient-header">
<div>{t('from')}</div>
<div>{t('to')}</div>
</div>
<div className="transaction-list-item-details__sender-to-recipient-container">
<SenderToRecipient
warnUserOnAccountMismatch={false}
@ -250,6 +252,7 @@ export default class TransactionListItemDetails extends PureComponent {
primaryCurrency={primaryCurrency}
className="transaction-list-item-details__transaction-breakdown"
/>
<Disclosure title="Activity log" size="small">
<TransactionActivityLog
transactionGroup={transactionGroup}
className="transaction-list-item-details__transaction-activity-log"
@ -257,6 +260,18 @@ export default class TransactionListItemDetails extends PureComponent {
onRetry={this.handleRetry}
isEarliestNonce={isEarliestNonce}
/>
</Disclosure>
{transactionGroup.initialTransaction?.txParams?.data ? (
<Disclosure title="Transaction data" size="small">
<TransactionDecoding
title={t('transactionData')}
to={transactionGroup.initialTransaction.txParams?.to}
inputData={
transactionGroup.initialTransaction.txParams?.data
}
/>
</Disclosure>
) : null}
</div>
</div>
</div>

@ -212,6 +212,16 @@ export default function TransactionListItem({
isEarliestNonce={isEarliestNonce}
onCancel={cancelTransaction}
showCancel={isPending && !hasCancelled}
transactionStatus={() => (
<TransactionStatus
isPending={isPending}
isEarliestNonce={isEarliestNonce}
error={err}
date={date}
status={displayedStatusKey}
statusOnly
/>
)}
/>
)}
{showRetryEditGasPopover && (

@ -1,6 +1,10 @@
.transaction-status {
display: inline;
&--confirmed {
color: $success-3;
}
&--unapproved {
color: $Orange-500;
}

@ -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 (
<Tooltip
@ -62,6 +65,7 @@ export default function TransactionStatus({
title={tooltipText}
wrapperClassName={classnames(
'transaction-status',
`transaction-status--${statusKey}`,
className,
statusToClassNameHash[statusKey],
)}
@ -77,4 +81,5 @@ TransactionStatus.propTypes = {
date: PropTypes.string,
error: PropTypes.object,
isEarliestNonce: PropTypes.bool,
statusOnly: PropTypes.bool,
};

@ -0,0 +1,51 @@
import React, { useState, useRef, useEffect } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
const Disclosure = ({ children, title, size }) => {
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 (
<div className="disclosure" onClick={() => setOpen((state) => !state)}>
{title ? (
<details>
<summary className="disclosure__title disclosure__summary typography--weight-bold typography--color-black">
{title}:{' '}
</summary>
<div className={classnames('disclosure__content', size)}>
{children}
</div>
<div ref={disclosureFooterEl} className="disclosure__footer"></div>
</details>
) : (
children
)}
</div>
);
};
Disclosure.propTypes = {
children: PropTypes.node.isRequired,
title: PropTypes.string,
size: PropTypes.string,
};
Disclosure.defaultProps = {
size: 'normal',
title: null,
};
export default Disclosure;

@ -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;
}
}
}

@ -0,0 +1 @@
export { default } from './disclosure';

@ -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;

@ -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"
/>
<div className="nickname-popover__address">
{shortenAddress(address)}
{nickname || shortenAddress(address)}
</div>
<div className="nickname-popover__public-address">
<div className="nickname-popover__public-address__constant">
{address}
</div>
<Tooltip
position="bottom"
title={copied ? t('copiedExclamation') : t('copyToClipboard')}
>
<button
type="link"
onClick={() => {
handleCopy(address);
}}
title={copied ? t('copiedExclamation') : t('copyToClipboard')}
title=""
>
<CopyIcon size={11} color="#989a9b" />
</button>
</Tooltip>
</div>
<div className="nickname-popover__view-on-block-explorer">
<Button
type="link"
className="nickname-popover__etherscan-link"
onClick={() => {
global.platform.openTab({
url: explorerLink,
});
}}
target="_blank"
rel="noopener noreferrer"
title={t('etherscanView')}
>
{t('viewOnBlockExplorer')}
</Button>
</div>
<Button
type="primary"
className="nickname-popover__footer-button"
onClick={onAddClick}
>
{t('addANickname')}
{nickname ? t('editANickname') : t('addANickname')}
</Button>
</Popover>
</div>
@ -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;

@ -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,28 +104,14 @@ function RecipientWithAddress({
recipientName,
}) {
const t = useI18nContext();
const [addressCopied, setAddressCopied] = useState(false);
const [showNicknamePopovers, setShowNicknamePopovers] = useState(false);
let tooltipHtml = <p>{t('copiedExclamation')}</p>;
if (!addressCopied) {
if (addressOnly && !recipientNickname && !recipientEns) {
tooltipHtml = <p>{t('copyAddress')}</p>;
} else {
tooltipHtml = (
<p>
{shortenAddress(checksummedRecipientAddress)}
<br />
{t('copyAddress')}
</p>
);
}
}
return (
<>
<div
className="sender-to-recipient__party sender-to-recipient__party--recipient sender-to-recipient__party--recipient-with-address"
onClick={() => {
setAddressCopied(true);
copyToClipboard(checksummedRecipientAddress);
setShowNicknamePopovers(true);
if (onRecipientClick) {
onRecipientClick();
}
@ -133,14 +120,6 @@ function RecipientWithAddress({
<div className="sender-to-recipient__sender-icon">
<Identicon address={checksummedRecipientAddress} diameter={24} />
</div>
<Tooltip
position="bottom"
html={tooltipHtml}
offset={-10}
wrapperClassName="sender-to-recipient__tooltip-wrapper"
containerClassName="sender-to-recipient__tooltip-container"
onHidden={() => setAddressCopied(false)}
>
<div className="sender-to-recipient__name">
{addressOnly
? recipientNickname ||
@ -151,8 +130,14 @@ function RecipientWithAddress({
recipientName ||
t('newContract')}
</div>
</Tooltip>
</div>
{showNicknamePopovers ? (
<NicknamePopovers
onClose={() => setShowNicknamePopovers(false)}
address={checksummedRecipientAddress}
/>
) : null}
</>
);
}

@ -55,3 +55,4 @@
@import 'unit-input/index';
@import 'url-icon/index';
@import 'update-nickname-popover/index';
@import 'disclosure/disclosure';

@ -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,

@ -42,14 +42,9 @@ export default function UpdateNicknamePopover({
onClose();
};
let title = t('addANickname');
if (nickname) {
title = t('editAddressNickname');
}
return (
<Popover
title={title}
title={nickname ? t('editAddressNickname') : t('addANickname')}
onClose={closePopover}
className="update-nickname__wrapper"
footer={
@ -61,7 +56,12 @@ export default function UpdateNicknamePopover({
>
{t('cancel')}
</Button>
<Button type="primary" onClick={onSubmit} disabled={!nickname}>
<Button
className="update-nickname__save"
type="primary"
onClick={onSubmit}
disabled={!nicknameInput}
>
{t('save')}
</Button>
</>

@ -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 || (
<div className="confirm-page-container-content__data">
<div className="confirm-page-container-content__data-box-label">
{`${t('functionType')}:`}
<span className="confirm-page-container-content__function-type">
{functionType}
</span>
</div>
<Disclosure>
<TransactionDecoding to={txParams?.to} inputData={txParams?.data} />
</Disclosure>
</div>
)
);
}
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 || (
<div className="confirm-page-container-content__data">
<div className="confirm-page-container-content__data-box-label">
{`${t('functionType')}:`}
<span className="confirm-page-container-content__function-type">
{functionType}
{`${functionType} ${functionParams}`}
</span>
</div>
{params && (
@ -664,9 +698,12 @@ export default class ConfirmTransactionBase extends Component {
</div>
)}
<div className="confirm-page-container-content__data-box-label">
{`${t('hexData')}: ${toBuffer(data).length} bytes`}
{`${t('hexData')}: ${toBuffer(txParams?.data).length} bytes`}
</div>
<div className="confirm-page-container-content__data-box">
{txParams?.data}
</div>
<div className="confirm-page-container-content__data-box">{data}</div>
<CopyRawData data={txParams?.data} />
</div>
)
);
@ -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}

@ -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,
};
};

@ -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 (
<>
<Dialog
type="message"
className="send__dialog"
onClick={showAddToAddressBookModal}
onClick={() => this.setState({ showNicknamePopovers: true })}
>
{t('newAccountDetectedDialogMessage')}
</Dialog>
{showNicknamePopovers ? (
<NicknamePopovers
onClose={() => this.setState({ showNicknamePopovers: false })}
address={to}
/>
) : null}
</>
);
}

@ -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);

@ -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"

Loading…
Cancel
Save