Merge branch 'master' into ab-upgrade-otp-version

pull/2402/head
Ayrat Badykov 5 years ago committed by GitHub
commit 7edef009fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 33
      CHANGELOG.md
  2. 3
      apps/block_scout_web/assets/css/app.scss
  3. 6
      apps/block_scout_web/assets/css/components/_navbar.scss
  4. 37
      apps/block_scout_web/assets/css/components/_stakes_table.scss
  5. 49
      apps/block_scout_web/assets/css/components/_tile.scss
  6. 3
      apps/block_scout_web/assets/css/theme/_base_variables.scss
  7. 5
      apps/block_scout_web/assets/css/theme/_dai_variables.scss
  8. 470
      apps/block_scout_web/assets/css/theme/_dark-theme.scss
  9. 5
      apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss
  10. 14
      apps/block_scout_web/assets/css/theme/_ethereum_variables.scss
  11. 5
      apps/block_scout_web/assets/css/theme/_goerli_variables.scss
  12. 5
      apps/block_scout_web/assets/css/theme/_kovan_variables.scss
  13. 17
      apps/block_scout_web/assets/css/theme/_lukso_variables.scss
  14. 5
      apps/block_scout_web/assets/css/theme/_neutral_variables.scss
  15. 5
      apps/block_scout_web/assets/css/theme/_poa_variables.scss
  16. 5
      apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss
  17. 5
      apps/block_scout_web/assets/css/theme/_ropsten_variables.scss
  18. 5
      apps/block_scout_web/assets/css/theme/_rsk_variables.scss
  19. 5
      apps/block_scout_web/assets/css/theme/_sokol_variables.scss
  20. 1
      apps/block_scout_web/assets/js/app.js
  21. 25
      apps/block_scout_web/assets/js/lib/market_history_chart.js
  22. 13
      apps/block_scout_web/assets/js/lib/utils.js
  23. 10
      apps/block_scout_web/assets/js/pages/chain.js
  24. 11
      apps/block_scout_web/assets/js/pages/dark-mode-switcher.js
  25. 12
      apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
  26. 12
      apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
  27. 10
      apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex
  28. 12
      apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
  29. 31
      apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
  30. 5
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex
  31. 2
      apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
  32. 21
      apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex
  33. 11
      apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex
  34. 21
      apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex
  35. 4
      apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
  36. 14
      apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
  37. 6
      apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
  38. 6
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
  39. 8
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex
  40. 6
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex
  41. 2
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex
  42. 9
      apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
  43. 2
      apps/block_scout_web/lib/block_scout_web/router.ex
  44. 2
      apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex
  45. 2
      apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex
  46. 2
      apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex
  47. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex
  48. 18
      apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
  49. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
  50. 70
      apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex
  51. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex
  52. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex
  53. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex
  54. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
  55. 4
      apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex
  56. 4
      apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex
  57. 4
      apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex
  58. 167
      apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex
  59. 12
      apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
  60. 85
      apps/block_scout_web/lib/block_scout_web/templates/common_components/_table-loader.html.eex
  61. 72
      apps/block_scout_web/lib/block_scout_web/templates/common_components/_tile-loader.html.eex
  62. 35
      apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
  63. 5
      apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
  64. 9
      apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex
  65. 4
      apps/block_scout_web/lib/block_scout_web/templates/tokens/holder/index.html.eex
  66. 4
      apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/index.html.eex
  67. 4
      apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex
  68. 8
      apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex
  69. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex
  70. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex
  71. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
  72. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex
  73. 4
      apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex
  74. 38
      apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
  75. 6
      apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex
  76. 1
      apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex
  77. 2
      apps/block_scout_web/mix.exs
  78. 246
      apps/block_scout_web/priv/gettext/default.pot
  79. 243
      apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
  80. 12
      apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
  81. 46
      apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs
  82. 12
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex
  83. 6
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex
  84. 4
      apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
  85. 2
      apps/ethereum_jsonrpc/mix.exs
  86. 40
      apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js
  87. 10
      apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs
  88. 18
      apps/explorer/config/config.exs
  89. 325
      apps/explorer/lib/explorer/chain.ex
  90. 6
      apps/explorer/lib/explorer/chain/internal_transaction.ex
  91. 15
      apps/explorer/lib/explorer/chain/internal_transaction/type.ex
  92. 2
      apps/explorer/lib/explorer/counters/average_block_time.ex
  93. 2
      apps/explorer/lib/explorer/market/market_history_cache.ex
  94. 82
      apps/explorer/lib/explorer/smart_contract/reader.ex
  95. 2
      apps/explorer/mix.exs
  96. 92
      apps/explorer/test/explorer/chain_test.exs
  97. 2
      apps/explorer/test/explorer/smart_contract/reader_test.exs
  98. 8
      rel/commands/clear_build.sh

@ -1,16 +1,41 @@
## Current
### Features
- [#2366](https://github.com/poanetwork/blockscout/pull/2366) - paginate eth logs
### Fixes
- [#2425](https://github.com/poanetwork/blockscout/pull/2425) - Force to show address view for checksummed address even if it is not in DB
### Chore
- [#2402](https://github.com/poanetwork/blockscout/pull/2402) - bump otp version to 22.0
- [#2450](https://github.com/poanetwork/blockscout/pull/2450) - Fix clearance of logs and node_modules folders in clearing script
- [#2434](https://github.com/poanetwork/blockscout/pull/2434) - get rid of timex warnings
## 2.0.2-beta
### Features
- [#2412](https://github.com/poanetwork/blockscout/pull/2412) - dark theme
- [#2399](https://github.com/poanetwork/blockscout/pull/2399) - decode verified smart contract's logs
- [#2391](https://github.com/poanetwork/blockscout/pull/2391) - Controllers Improvements
- [#2379](https://github.com/poanetwork/blockscout/pull/2379) - Disable network selector when is empty
- [#2374](https://github.com/poanetwork/blockscout/pull/2374) - decode constructor arguments for verified smart contracts
- [#2366](https://github.com/poanetwork/blockscout/pull/2366) - paginate eth logs
- [#2360](https://github.com/poanetwork/blockscout/pull/2360) - add default evm version to smart contract verification
- [#2352](https://github.com/poanetwork/blockscout/pull/2352) - Fetch rewards in parallel with transactions
- [#2294](https://github.com/poanetwork/blockscout/pull/2294) - add healthy block period checking endpoint
- [#2324](https://github.com/poanetwork/blockscout/pull/2324) - set timeout for loading message on the main page
### Fixes
- [#2421](https://github.com/poanetwork/blockscout/pull/2421) - Fix hiding of loader for txs on the main page
- [#2420](https://github.com/poanetwork/blockscout/pull/2420) - fetch data from cache in healthy endpoint
- [#2416](https://github.com/poanetwork/blockscout/pull/2416) - Fix "page not found" handling in the router
- [#2413](https://github.com/poanetwork/blockscout/pull/2413) - remove outer tables for decoded data
- [#2410](https://github.com/poanetwork/blockscout/pull/2410) - preload smart contract for logs decoding
- [#2405](https://github.com/poanetwork/blockscout/pull/2405) - added templates for table loader and tile loader
- [#2398](https://github.com/poanetwork/blockscout/pull/2398) - show only one decoded candidate
- [#2395](https://github.com/poanetwork/blockscout/pull/2395) - new block loading animation
- [#2389](https://github.com/poanetwork/blockscout/pull/2389) - Reduce Lodash lib size (86% of lib methods are not used)
- [#2388](https://github.com/poanetwork/blockscout/pull/2388) - add create2 support to geth's js tracer
- [#2387](https://github.com/poanetwork/blockscout/pull/2387) - fix not existing keys in transaction json rpc
- [#2378](https://github.com/poanetwork/blockscout/pull/2378) - Page performance: exclude moment.js localization files except EN, remove unused css
- [#2368](https://github.com/poanetwork/blockscout/pull/2368) - add two columns of smart contract info
- [#2375](https://github.com/poanetwork/blockscout/pull/2375) - Update created_contract_code_indexed_at on transaction import conflict
@ -28,7 +53,9 @@
- [#2326](https://github.com/poanetwork/blockscout/pull/2326) - fix nested constructor arguments
### Chore
- [#2402](https://github.com/poanetwork/blockscout/pull/2402) - bump otp version to 22.0
- [#2422](https://github.com/poanetwork/blockscout/pull/2422) - check if address_id is binary in token_transfers_csv endpoint
- [#2418](https://github.com/poanetwork/blockscout/pull/2418) - Remove parentheses in market cap percentage
- [#2401](https://github.com/poanetwork/blockscout/pull/2401) - add ENV vars to manage updating period of average block time and market history cache
- [#2363](https://github.com/poanetwork/blockscout/pull/2363) - add parameters example for eth rpc
- [#2342](https://github.com/poanetwork/blockscout/pull/2342) - Upgrade Postgres image version in Docker setup
- [#2325](https://github.com/poanetwork/blockscout/pull/2325) - Reduce function input to address' hash only where possible

@ -128,6 +128,7 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
@import "components/new_smart_contract";
@import "components/radio_big";
@import "components/btn_no_border";
@import "theme/dark-theme";
:export {
dashboardBannerChartAxisFontColor: $dashboard-banner-chart-axis-font-color;
@ -135,4 +136,6 @@ $fa-font-path: "~@fortawesome/fontawesome-free/webfonts";
dashboardLineColorPrice: $dashboard-line-color-price;
primary: $primary;
secondary: $secondary;
darkprimary: $dark-primary;
darksecondary: $dark-secondary;
}

@ -253,3 +253,9 @@ $navbar-logo-width: auto !default;
padding-right: 0;
}
}
.nav-item-networks {
.topnav-nav-link {
transition: none !important;
}
}

@ -26,6 +26,43 @@ $stakes-table-cell-separation: 25px !default;
}
}
// Loader
.table-content-loader {
display: inline-block;
height: 24px;
width: 100%;
border-radius: 4px;
background-color: #f5f6fa;
overflow: hidden;
position: relative;
&:before {
width: inherit;
height: inherit;
content: '';
position: absolute;
background: linear-gradient(to right, #f5f6fa 2%, #eee 18%, #f5f6fa 33%);
animation-duration: 1.7s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-name: placeholderAnimate;
background-size: 1300px;
}
}
@keyframes placeholderAnimate {
0%{ background-position: -650px 0; }
100% { background-position: 650px 0; }
}
.table-content-pseudo {
td {
&:last-child {
padding-right: 24px !important;
}
}
}
.stakes-table {
min-width: fit-content;
width: 100%;

@ -340,6 +340,9 @@ $tile-body-a-color: #5959d8 !default;
padding-right: 6px;
}
}
.tile-type-block {
overflow: hidden;
}
.row {
@include media-breakpoint-down(lg) {
margin-left: -6px;
@ -349,6 +352,52 @@ $tile-body-a-color: #5959d8 !default;
}
}
// Loader
.tile-type-loading {
background-color: #fff;
padding-top: 30px;
padding-bottom: 28px;
}
.tile-loader {
display: inline-block;
height: 20px;
width: 100%;
border-radius: 4px;
background-color: #f5f6fa;
overflow: hidden;
position: relative;
&:before {
width: inherit;
height: inherit;
content: '';
position: absolute;
background: linear-gradient(to right, #f5f6fa 2%, #eee 18%, #f5f6fa 33%);
animation-duration: 1.7s;
animation-fill-mode: forwards;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-name: tilePlaceholderAnimate;
background-size: 1300px;
}
}
.tile-label-loader {
height: 14px;
width: 80px;
}
.tile-address-loader {
& + .tile-address-loader {
margin-top: 6px;
}
}
@keyframes tilePlaceholderAnimate {
0%{ background-position: -650px 0; }
100% { background-position: 650px 0; }
}
// Loading Animation
@keyframes playBlockLoadingAnimation {

@ -70,7 +70,10 @@ $colors: map-merge(
);
$primary: $indigo !default;
$dark-primary: #9b62ff !default;
$dark-primary-alternate: #9b62ff !default;
$secondary: #7dd79f !default;
$dark-secondary: #87e1a9 !default;
$tertiary: $purple !default;
$success: $green !default;
$info: $cyan !default;

@ -63,3 +63,8 @@ $card-tab-active: $secondary;
$badge-neutral-color: #20446e;
$badge-neutral-background-color: rgba(#20446e, .1);
$api-text-monospace-color: #20446e;
// Dark theme
$dark-primary: #15bba6;
$dark-secondary: #93d7ff;
$dark-primary-alternate: #15bba6;

@ -0,0 +1,470 @@
$body-dark: #1c1d31; // body background
$dark-bg: #22223a; // hero shade
$dark-light-bg: #282945; // pills bg shade
$dark-light: #313355; // tile light top share
$labels-dark: #8a8dba; // header nav, labels
// Switcher
.dark-mode-changer {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
background: transparent;
border: none;
cursor: pointer;
margin-right: 5px;
outline: none !important;
box-shadow: none !important;
transition: .2s ease-in;
&:hover {
opacity: .8;
}
svg path {
fill: #828ba0;
}
&--dark {
svg path {
fill: $dark-primary;
}
}
}
.dark-theme-applied {
color: #fff;
// navbar
.navbar.navbar-primary {
background-color: $dark-light-bg;
}
.navbar-brand .navbar-logo {
filter: brightness(0) invert(1);
}
.navbar.navbar-primary .navbar-nav .nav-link {
color: $labels-dark;
.nav-link-icon {
svg path {
fill: $labels-dark;
}
}
&.active, &:hover {
.nav-link-icon {
svg path {
fill: $dark-primary;
}
}
&:before {
background-color: $dark-primary;
}
}
}
.navbar.navbar-primary .form-control {
background-color: $dark-bg;
border-color: $dark-bg;
color: #fff;
&::placeholder {
color: $labels-dark;
}
}
.navbar.navbar-primary .navbar-toggler .navbar-toggler-icon {
filter: invert(1);
}
// footer
.footer {
background: $dark-light-bg;
color: $labels-dark;
}
.footer-social-icon,
.footer-link {
color: $labels-dark;
}
.footer-social-icon:hover,
.footer-link:hover {
color: #fff;
}
.footer-list ul li::before {
background-color: $dark-secondary;
}
// hero stats
.layout-container .dashboard-banner-container {
background-image: none;
background-color: $dark-bg;
}
.dashboard-banner-network-plain-container,
.dashboard-banner-network-plain-container::after {
background-color: $dark-light-bg;
}
.dashboard-banner-network-stats-label,
.dashboard-banner-chart-legend .dashboard-banner-chart-legend-label {
color: $labels-dark;
}
.dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(1)::before {
background-color: $dark-primary;
}
.dashboard-banner-network-stats-item::before {
background-color: $dark-secondary;
}
.dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(2)::before {
background-color: $dark-secondary;
}
// main container, layout, cards
.layout-container main {
background-color: $body-dark;
}
.card {
background-color: $dark-light-bg;
box-shadow: 0 0 30px 0 rgba(23, 24, 41, 0.5);
}
.card-header {
border-bottom-color: darken($labels-dark, 30);
}
.address-detail-hash-title {
color: #fff;
}
.card-tabs {
border-bottom-color: darken($labels-dark, 30);
}
.card-tab {
background-color: transparent;
&:hover:not(.active) {
background-color: rgba($dark-primary, .15);
color: $dark-primary;
}
&.active {
background-color: $dark-primary-alternate;
color: #fff;
}
}
.card-background-1 {
background-color: $dark-primary-alternate;
}
// Components
a {
color: $dark-primary;
}
.tile {
border-top-color: $dark-light;
border-bottom-color: $dark-light;
border-right-color: $dark-light;
background-color: $dark-light;
color: $labels-dark;
&:not([class^="tile tile-type"]) {
border-left-color: $dark-light;
}
&.tile-type-coin-balance {
border-left-color: $dark-light;
}
.tile-title {
color: #fff;
}
.tile-transaction-type-block {
background-color: transparent;
}
}
.tile-bottom-contents {
background-color: $dark-bg;
}
a.tile-title {
color: #fff !important;
}
.tile.tile-type-block .tile-transaction-type-block a {
color: #fff;
}
.fade-up-blocks-chain .tile-type-block-animation {
background-color: $dark-light;
border-top-color: $dark-light;
border-right-color: $dark-light;
border-bottom-color: $dark-light;
}
.fade-up-blocks-chain .tile-type-block-animation:after {
background-color: $dark-light;
}
.cube-animation-title {
color: $labels-dark;
}
.tile .tile-body a,
.tile span[data-address-hash] { color: $dark-primary; }
.fade-up-blocks-chain .tile-type-block-animation .tile-type-line-up {
background-color: $dark-primary;
}
.tile.tile-type-block {
border-left-color: $dark-primary
}
.tile.tile-type-block .tile-status-label {
color: $dark-primary;
}
.tile.tile-type-block .tile-transaction-type-block {
border-right-color: $dark-primary;
border-top-color: $dark-primary;
border-bottom-color: $dark-primary;
}
.tile .progress {
background-color: rgba(#fff, .2);
}
.tile .progress .progress-bar {
background-color: $dark-primary;
}
.tile .tile-title-lg:not([data-balance-change-sign]) {
color: $dark-primary;
}
// btns
.btn-line {
background-color: transparent;
border-color: $dark-primary;
color: $dark-primary;
&:hover {
border-color: $dark-primary;
background-color: $dark-primary;
color: #fff;
}
}
.btn-copy-icon, .btn-qr-icon {
border-color: $dark-primary;
path {
fill: $dark-primary;
}
&:hover {
background-color: $dark-primary;
path {
fill: #fff;
}
}
}
// pagination
.pagination-container .pagination .page-link {
color: $labels-dark;
border-color: $dark-light;
background-color: $dark-light;
&:not(.no-hover):hover {
color: #fff;
background-color: $dark-primary;
path {
fill: #fff;
}
}
&[disabled] {
color: $labels-dark;
border-color: $dark-light;
background-color: $dark-light;
}
}
// dropdown
.dropdown-menu {
background-color: $dark-light;
border-left-color: $dark-light;
border-right-color: $dark-light;
border-bottom-color: $dark-light;
}
.dropdown-item {
color: #fff;
&:hover {
background-color: rgba(#fff, .1);
}
}
.dropdown-item.active {
background-color: $dark-primary;
}
.btn-dropdown-line {
background-color: $dark-light;
border-color: $dark-light;
color: $labels-dark;
}
// table
.stakes-table-th {
background-color: $dark-light;
color: $labels-dark;
}
.stakes-td {
border-bottom-color: darken($labels-dark, 30);
}
.table th, .table td {
border-top-color: darken($labels-dark, 30);
}
hr {
border-top-color: darken($labels-dark, 30);
}
// api's
.api-anchors-list {
background-color: $dark-light;
}
.api-doc-list-item {
border-bottom-color: darken($labels-dark, 30);
}
.card-subtitle,
.api-anchors-list-item-title,
.api-doc-list-item-title {
color: #fff;
}
.api-text-monospace {
color: $dark-primary;
}
.api-text-monospace-background {
background-color: rgba($dark-primary, .15);
}
.badge.badge-neutral {
background-color: rgba($dark-primary, .15);
color: $dark-primary;
}
// download csv button
.download-all-transactions .download-all-transactions-link svg path {
fill: $dark-primary;
}
//tooltips
.tooltip .arrow:before {
border-top-color: $dark-primary;
border-bottom-color: $dark-primary;
}
.tooltip > .tooltip-inner {background-color: $dark-primary;}
//network select
.network-selector-overlay {
background-color: rgba($dark-bg, .9);
}
.network-selector {
background-color: $dark-light-bg;
}
.network-selector-title {
color: #fff;
}
.network-selector-text {
color: $labels-dark;
}
.network-selector-close path {
fill: #fff;
}
.network-selector-search-container {
background-color: $dark-light;
}
.network-selector-search-container path {
fill: $labels-dark;
}
.network-selector-search-input {
color: #fff !important;
&::placeholder {
color: $labels-dark;
}
}
.network-selector-tab {
color: $labels-dark;
&:hover, &.active {
color: #fff;
}
&.active {
&:after {
background-color: $dark-primary;
}
}
}
.network-selector-item,
.network-selector-tabs-container {
border-bottom-color: darken($labels-dark, 30);
}
.network-selector-item-title {
color: #fff;
}
.network-selector-item-type {
color: $labels-dark;
}
.radio .radio-icon {
border-color: $labels-dark
}
.network-selector-item-url:hover .network-selector-item-type {
color: #fff;
}
//coin dropdown
.token-balance-dropdown.dropdown-menu {
border-color: $dark-light !important;
box-shadow: 0 0 30px 0 rgba(23, 24, 41, 0.5) !important;
}
.token-balance-dropdown .dropdown-search-icon path {
fill: $labels-dark;
}
.token-balance-dropdown .dropdown-search-field {
background-color: $dark-light;
border-color: $dark-light;
color: #fff;
&::placeholder {
color: $labels-dark;
}
}
.token-balance-dropdown[aria-labelledby="dropdown-tokens"] .dropdown-items .dropdown-item:hover {
color: #fff !important;
}
.dropdown-header {
color: $labels-dark;
}
.border-bottom {
border-bottom-color: darken($labels-dark, 30) !important;
}
// coin balance history chart
.chartjs-render-monitor[data-chart="coinBalanceHistoryChart"] {
filter: brightness(0) invert(1) !important;
}
// logs search
.logs-search-input, .logs-search-btn, .logs-search-btn-cancel {
background-color: $dark-light;
border-color: $dark-light;
color: #fff;
}
.logs-search-btn {
color: $labels-dark;
}
.logs-search-btn {
&:hover {
background-color: $dark-primary;
color: #fff;
}
}
.logs-search-input {
&::placeholder {
color: $labels-dark;
}
}
// code
pre {
color: #fff;
}
// info allert
.alert-info {
color: $labels-dark;
background-color: $dark-light;
border-color: $dark-light;
}
// dark text
.text-dark {
color: #fff;
}
}

@ -75,3 +75,8 @@ $card-tab-active: $tertiary;
$badge-neutral-color: $tertiary;
$badge-neutral-background-color: rgba($tertiary, .1);
$api-text-monospace-color: $tertiary;
// Dark theme
$dark-primary: #8588ff;
$dark-secondary: #4ad7a7;
$dark-primary-alternate: #5b5ed8;

@ -57,3 +57,17 @@ $card-tab-active: $secondary;
);
}
}
// Dark theme
$dark-primary: #49a2ee;
$dark-secondary: #4ad7a7;
$dark-primary-alternate: #49a2ee;
.dark-theme-applied {
.dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(1)::before {
background-color: $dark-primary !important;
}
.dashboard-banner-chart-legend .dashboard-banner-chart-legend-item:nth-child(2)::before {
background-color: $dark-secondary !important;
}
}

@ -78,3 +78,8 @@ $card-tab-active: $sub-accent-color;
$badge-neutral-color: $sub-accent-color;
$badge-neutral-background-color: rgba($sub-accent-color, .1);
$api-text-monospace-color: $sub-accent-color;
// Dark theme
$dark-primary: #e1995a;
$dark-secondary: #aeaeae;
$dark-primary-alternate: #e1995a;

@ -75,3 +75,8 @@ $badge-success-background-color: rgba(#15bba6, .1);
$badge-neutral-color: $tertiary;
$badge-neutral-background-color: rgba($tertiary, .1);
$api-text-monospace-color: $tertiary;
// Dark theme
$dark-primary: #42e2d7;
$dark-secondary: #1f857f;
$dark-primary-alternate: #1f857f;

@ -151,3 +151,20 @@ $dashboard-banner-network-plain-container-height: 150px;
$badge-neutral-color: $tertiary;
$badge-neutral-background-color: rgba($tertiary, .1);
$api-text-monospace-color: $tertiary;
// Dark theme
$dark-primary: #fdcec4;
$dark-secondary: #a96c55;
$dark-primary-alternate: #a96c55;
.dark-theme-applied {
.dashboard-banner-network-stats-value {
color: $dark-primary !important;
}
.layout-container .dashboard-banner-container {
background-color: #282945 !important;
}
.dashboard-banner-network-plain-container::after {
box-shadow: none !important;
}
}

@ -72,3 +72,8 @@ $api-text-monospace-color: $primary;
color: $primary !important;
}
}
// Dark theme
$dark-primary: #9b62ff;
$dark-secondary: #87e1a9;
$dark-primary-alternate: #7e50d0;

@ -72,3 +72,8 @@ $api-text-monospace-color: $primary;
color: $primary !important;
}
}
// Dark theme
$dark-primary: #9b62ff;
$dark-secondary: #87e1a9;
$dark-primary-alternate: #7e50d0;

@ -57,3 +57,8 @@ $card-tab-active: $secondary;
);
}
}
// Dark theme
$dark-primary: #38a9f5;
$dark-secondary: #76f1ff;
$dark-primary-alternate: #38a9f5;

@ -57,3 +57,8 @@ $card-tab-active: $secondary;
);
}
}
// Dark theme
$dark-primary: #38a9f5;
$dark-secondary: #76f1ff;
$dark-primary-alternate: #38a9f5;

@ -65,3 +65,8 @@ $card-tab-active: $secondary;
// Badges
$badge-neutral-color: #1a323b;
$badge-neutral-background-color: rgba(#1a323b, .1);
// Dark theme
$dark-primary: #38c5a4;
$dark-secondary: #e39a54;
$dark-primary-alternate: #30ab8d;

@ -73,3 +73,8 @@ $card-tab-active: $sub-accent-color;
// Badges
$badge-neutral-color: $tertiary;
$badge-neutral-background-color: rgba($tertiary, .1);
// Dark theme
$dark-primary: #40bfb2;
$dark-secondary: #25c9ff;
$dark-primary-alternate: #1c9f90;

@ -35,6 +35,7 @@ import './pages/favorites'
import './pages/network-search'
import './pages/layout'
import './pages/verification_form'
import './pages/dark-mode-switcher'
import './pages/admin/tasks.js'

@ -4,6 +4,7 @@ import humps from 'humps'
import numeral from 'numeral'
import { formatUsdValue } from '../lib/currency'
import sassVariables from '../../css/app.scss'
import { showLoader } from '../lib/utils'
const config = {
type: 'line',
@ -87,6 +88,17 @@ function getMarketCapData (marketHistoryData, availableSupply) {
}
}
// colors for light and dark theme
var priceLineColor
var mcapLineColor
if (localStorage.getItem('current-color-mode') === 'dark') {
priceLineColor = sassVariables.darkprimary
mcapLineColor = sassVariables.darksecondary
} else {
priceLineColor = sassVariables.dashboardLineColorPrice
mcapLineColor = sassVariables.dashboardLineColorMarket
}
class MarketHistoryChart {
constructor (el, availableSupply, marketHistoryData) {
this.price = {
@ -95,8 +107,8 @@ class MarketHistoryChart {
data: getPriceData(marketHistoryData),
fill: false,
pointRadius: 0,
backgroundColor: sassVariables.dashboardLineColorPrice,
borderColor: sassVariables.dashboardLineColorPrice,
backgroundColor: priceLineColor,
borderColor: priceLineColor,
lineTension: 0
}
this.marketCap = {
@ -105,8 +117,8 @@ class MarketHistoryChart {
data: getMarketCapData(marketHistoryData, availableSupply),
fill: false,
pointRadius: 0,
backgroundColor: sassVariables.dashboardLineColorMarket,
borderColor: sassVariables.dashboardLineColorMarket,
backgroundColor: mcapLineColor,
borderColor: mcapLineColor,
lineTension: 0
}
this.availableSupply = availableSupply
@ -129,6 +141,10 @@ class MarketHistoryChart {
export function createMarketHistoryChart (el) {
const dataPath = el.dataset.market_history_chart_path
const $chartLoading = $('[data-chart-loading-message]')
const isTimeout = true
const timeoutID = showLoader(isTimeout, $chartLoading)
const $chartError = $('[data-chart-error-message]')
const chart = new MarketHistoryChart(el, 0, [])
$.getJSON(dataPath, {type: 'JSON'})
@ -143,6 +159,7 @@ export function createMarketHistoryChart (el) {
})
.always(() => {
$chartLoading.hide()
clearTimeout(timeoutID)
})
return chart
}

@ -11,3 +11,16 @@ export function batchChannel (func) {
debouncedFunc()
}
}
export function showLoader (isTimeout, loader) {
if (isTimeout) {
const timeout = setTimeout(function () {
loader.removeAttr('hidden')
loader.show()
}, 1000)
return timeout
} else {
loader.hide()
return null
}
}

@ -9,7 +9,7 @@ import numeral from 'numeral'
import socket from '../socket'
import { exchangeRateChannel, formatUsdValue } from '../lib/currency'
import { createStore, connectElements } from '../lib/redux_helpers.js'
import { batchChannel } from '../lib/utils'
import { batchChannel, showLoader } from '../lib/utils'
import listMorph from '../lib/list_morph'
import { createMarketHistoryChart } from '../lib/market_history_chart'
@ -214,11 +214,7 @@ const elements = {
},
'[data-selector="chain-block-list"] [data-selector="loading-message"]': {
render ($el, state, oldState) {
if (state.blocksLoading) {
$el.show()
} else {
$el.hide()
}
showLoader(state.blocksLoading, $el)
}
},
'[data-selector="transactions-list"] [data-selector="error-message"]': {
@ -228,7 +224,7 @@ const elements = {
},
'[data-selector="transactions-list"] [data-selector="loading-message"]': {
render ($el, state, oldState) {
$el.toggle(state.transactionsLoading)
showLoader(state.transactionsLoading, $el)
}
},
'[data-selector="transactions-list"]': {

@ -0,0 +1,11 @@
import $ from 'jquery'
$('.dark-mode-changer').click(function () {
if (localStorage.getItem('current-color-mode') === 'dark') {
localStorage.setItem('current-color-mode', 'light')
} else {
localStorage.setItem('current-color-mode', 'dark')
}
// reload each theme switch
document.location.reload(true)
})

@ -16,7 +16,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash, [], false) do
:ok <- Chain.check_address_exists(address_hash) do
full_options = paging_options(params)
coin_balances_plus_one = Chain.address_to_coin_balances(address_hash, full_options)
@ -32,7 +32,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
address_coin_balance_path(
conn,
:index,
address,
address_hash,
Map.delete(next_page_params, "type")
)
end
@ -52,7 +52,7 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
:not_found ->
not_found(conn)
end
end
@ -68,6 +68,12 @@ defmodule BlockScoutWeb.AddressCoinBalanceController do
validation_count: validation_count(address_hash),
current_path: current_path(conn)
)
else
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
end
end
end

@ -8,8 +8,18 @@ defmodule BlockScoutWeb.AddressContractController do
alias Indexer.Fetcher.CoinBalanceOnDemand
def index(conn, %{"address_id" => address_hash_string}) do
address_options = [
necessity_by_association: %{
:contracts_creation_internal_transaction => :optional,
:names => :optional,
:smart_contract => :optional,
:token => :optional,
:contracts_creation_transaction => :optional
}
]
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_contract_address(address_hash) do
{:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do
render(
conn,
"index.html",

@ -16,7 +16,7 @@ defmodule BlockScoutWeb.AddressLogsController do
def index(conn, %{"address_id" => address_hash_string, "type" => "JSON"} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash, [], false) do
:ok <- Chain.check_address_exists(address_hash) do
logs_plus_one = Chain.address_to_logs(address_hash, paging_options(params))
{results, next_page} = split_list_by_page(logs_plus_one)
@ -26,7 +26,7 @@ defmodule BlockScoutWeb.AddressLogsController do
nil
next_page_params ->
address_logs_path(conn, :index, address, Map.delete(next_page_params, "type"))
address_logs_path(conn, :index, address_hash, Map.delete(next_page_params, "type"))
end
items =
@ -74,7 +74,7 @@ defmodule BlockScoutWeb.AddressLogsController do
def search_logs(conn, %{"topic" => topic, "address_id" => address_hash_string} = params) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash, [], false) do
:ok <- Chain.check_address_exists(address_hash) do
topic = String.trim(topic)
formatted_topic = if String.starts_with?(topic, "0x"), do: topic, else: "0x" <> topic
@ -89,7 +89,7 @@ defmodule BlockScoutWeb.AddressLogsController do
nil
next_page_params ->
address_logs_path(conn, :index, address, Map.delete(next_page_params, "type"))
address_logs_path(conn, :index, address_hash, Map.delete(next_page_params, "type"))
end
items =
@ -115,4 +115,6 @@ defmodule BlockScoutWeb.AddressLogsController do
not_found(conn)
end
end
def search_logs(conn, _), do: not_found(conn)
end

@ -15,8 +15,18 @@ defmodule BlockScoutWeb.AddressReadContractController do
import BlockScoutWeb.AddressController, only: [transaction_count: 1, validation_count: 1]
def index(conn, %{"address_id" => address_hash_string}) do
address_options = [
necessity_by_association: %{
:contracts_creation_internal_transaction => :optional,
:names => :optional,
:smart_contract => :optional,
:token => :optional,
:contracts_creation_transaction => :optional
}
]
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.find_contract_address(address_hash) do
{:ok, address} <- Chain.find_contract_address(address_hash, address_options, true) do
render(
conn,
"index.html",

@ -83,7 +83,11 @@ defmodule BlockScoutWeb.AddressTransactionController do
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
with {:ok, _} <- Chain.Hash.Address.validate(address_hash_string) do
json(conn, %{items: [], next_page_path: ""})
else
{:error, _} -> not_found(conn)
end
end
end
@ -106,11 +110,28 @@ defmodule BlockScoutWeb.AddressTransactionController do
unprocessable_entity(conn)
{:error, :not_found} ->
not_found(conn)
{:ok, address_hash} = Chain.string_to_address_hash(address_hash_string)
address = %Chain.Address{hash: address_hash, smart_contract: nil, token: nil}
with {:ok, _} <- Chain.Hash.Address.validate(address_hash_string) do
render(
conn,
"index.html",
address: address,
coin_balance_status: nil,
exchange_rate: Market.get_exchange_rate(Explorer.coin()) || Token.null(),
filter: params["filter"],
transaction_count: 0,
validation_count: 0,
current_path: current_path(conn)
)
else
{:error, _} -> not_found(conn)
end
end
end
def token_transfers_csv(conn, %{"address_id" => address_hash_string}) do
def token_transfers_csv(conn, %{"address_id" => address_hash_string}) when is_binary(address_hash_string) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
address
@ -130,6 +151,8 @@ defmodule BlockScoutWeb.AddressTransactionController do
end
end
def token_transfers_csv(conn, _), do: not_found(conn)
def transactions_csv(conn, %{"address_id" => address_hash_string}) do
with {:ok, address_hash} <- Chain.string_to_address_hash(address_hash_string),
{:ok, address} <- Chain.hash_to_address(address_hash) do
@ -149,4 +172,6 @@ defmodule BlockScoutWeb.AddressTransactionController do
not_found(conn)
end
end
def transactions_csv(conn, _), do: not_found(conn)
end

@ -8,9 +8,8 @@ defmodule BlockScoutWeb.API.RPC.BlockController do
def getblockreward(conn, params) do
with {:block_param, {:ok, unsafe_block_number}} <- {:block_param, Map.fetch(params, "blockno")},
{:ok, block_number} <- ChainWeb.param_to_block_number(unsafe_block_number),
block_options = [necessity_by_association: %{transactions: :optional}],
{:ok, block} <- Chain.number_to_block(block_number, block_options) do
reward = Chain.block_reward(block)
{:ok, block} <- Chain.number_to_block(block_number) do
reward = Chain.block_reward(block_number)
render(conn, :block_reward, block: block, reward: reward)
else

@ -10,7 +10,7 @@ defmodule BlockScoutWeb.API.RPC.TransactionController do
{:format, {:ok, transaction_hash}} <- to_transaction_hash(txhash_param),
{:transaction, {:ok, transaction}} <- transaction_from_hash(transaction_hash),
paging_options <- paging_options(params) do
logs = Chain.transaction_to_logs(transaction, paging_options)
logs = Chain.transaction_to_logs(transaction_hash, paging_options)
{logs, next_page} = split_list_by_page(logs)
render(conn, :gettxinfo, %{

@ -7,8 +7,9 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do
def create(conn, params) do
if auth_token(conn) == actual_token() do
with {:ok, hash} <- validate_address_hash(params["address_hash"]),
:ok <- smart_contract_exists?(hash),
:ok <- decompiled_contract_exists?(params["address_hash"], params["decompiler_version"]) do
:ok <- Chain.check_address_exists(hash),
{:contract, :not_found} <-
{:contract, Chain.check_decompiled_contract_exists(params["address_hash"], params["decompiler_version"])} do
case Chain.create_decompiled_smart_contract(params) do
{:ok, decompiled_smart_contract} ->
send_resp(conn, :created, Jason.encode!(decompiled_smart_contract))
@ -29,7 +30,7 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do
:not_found ->
send_resp(conn, :unprocessable_entity, encode(%{error: "address is not found"}))
:contract_exists ->
{:contract, :ok} ->
send_resp(
conn,
:unprocessable_entity,
@ -41,13 +42,6 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do
end
end
defp smart_contract_exists?(address_hash) do
case Chain.hash_to_address(address_hash) do
{:ok, _address} -> :ok
_ -> :not_found
end
end
defp validate_address_hash(address_hash) do
case Address.cast(address_hash) do
{:ok, hash} -> {:ok, hash}
@ -55,13 +49,6 @@ defmodule BlockScoutWeb.API.V1.DecompiledSmartContractController do
end
end
defp decompiled_contract_exists?(address_hash, decompiler_version) do
case Chain.decompiled_code(address_hash, decompiler_version) do
{:ok, _} -> :contract_exists
_ -> :ok
end
end
defp auth_token(conn) do
case get_req_header(conn, "auth_token") do
[token] -> token

@ -4,19 +4,22 @@ defmodule BlockScoutWeb.API.V1.HealthController do
alias Explorer.Chain
def health(conn, _) do
with {:ok, number, timestamp} <- Chain.last_block_status() do
send_resp(conn, :ok, result(number, timestamp))
with {:ok, number, timestamp} <- Chain.last_db_block_status(),
{:ok, cache_number, cache_timestamp} <- Chain.last_cache_block_status() do
send_resp(conn, :ok, result(number, timestamp, cache_number, cache_timestamp))
else
status -> send_resp(conn, :internal_server_error, error(status))
end
end
def result(number, timestamp) do
def result(number, timestamp, cache_number, cache_timestamp) do
%{
"healthy" => true,
"data" => %{
"latest_block_number" => to_string(number),
"latest_block_inserted_at" => to_string(timestamp)
"latest_block_inserted_at" => to_string(timestamp),
"cache_latest_block_number" => to_string(cache_number),
"cache_latest_block_inserted_at" => to_string(cache_timestamp)
}
}
|> Jason.encode!()

@ -7,8 +7,8 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do
def create(conn, params) do
with {:ok, hash} <- validate_address_hash(params["address_hash"]),
:ok <- smart_contract_exists?(hash),
:ok <- verified_smart_contract_exists?(hash) do
:ok <- Chain.check_address_exists(hash),
{:contract, :not_found} <- {:contract, Chain.check_verified_smart_contract_exists(hash)} do
external_libraries = fetch_external_libraries(params)
case Publisher.publish(hash, params, external_libraries) do
@ -31,7 +31,7 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do
:not_found ->
send_resp(conn, :unprocessable_entity, encode(%{error: "address is not found"}))
:contract_exists ->
{:contract, :ok} ->
send_resp(
conn,
:unprocessable_entity,
@ -40,13 +40,6 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do
end
end
defp smart_contract_exists?(address_hash) do
case Chain.hash_to_address(address_hash) do
{:ok, _address} -> :ok
_ -> :not_found
end
end
defp validate_address_hash(address_hash) do
case Address.cast(address_hash) do
{:ok, hash} -> {:ok, hash}
@ -54,14 +47,6 @@ defmodule BlockScoutWeb.API.V1.VerifiedSmartContractController do
end
end
defp verified_smart_contract_exists?(address_hash) do
if Chain.address_hash_to_smart_contract(address_hash) do
:contract_exists
else
:ok
end
end
defp encode(data) do
Jason.encode!(data)
end

@ -26,7 +26,7 @@ defmodule BlockScoutWeb.BlockTransactionController do
paging_options(params)
)
transactions_plus_one = Chain.block_to_transactions(block, full_options)
transactions_plus_one = Chain.block_to_transactions(block.hash, full_options)
{transactions, next_page} = split_list_by_page(transactions_plus_one)
@ -89,7 +89,7 @@ defmodule BlockScoutWeb.BlockTransactionController do
:rewards => :optional
}
) do
block_transaction_count = Chain.block_to_transaction_count(block)
block_transaction_count = Chain.block_to_transaction_count(block.hash)
render(
conn,

@ -2,7 +2,7 @@ defmodule BlockScoutWeb.ChainController do
use BlockScoutWeb, :controller
alias BlockScoutWeb.ChainView
alias Explorer.{Chain, PagingOptions, Repo}
alias Explorer.{Chain, PagingOptions}
alias Explorer.Chain.{Address, Block, Transaction}
alias Explorer.Chain.Supply.RSK
alias Explorer.Counters.AverageBlockTime
@ -52,6 +52,8 @@ defmodule BlockScoutWeb.ChainController do
end
end
def search(conn, _), do: not_found(conn)
def token_autocomplete(conn, %{"q" => term}) when is_binary(term) do
if term == "" do
json(conn, "{}")
@ -72,9 +74,15 @@ defmodule BlockScoutWeb.ChainController do
def chain_blocks(conn, _params) do
if ajax?(conn) do
blocks =
[paging_options: %PagingOptions{page_size: 4}]
[
paging_options: %PagingOptions{page_size: 4},
necessity_by_association: %{
[miner: :names] => :optional,
:transactions => :optional,
:rewards => :optional
}
]
|> Chain.list_blocks()
|> Repo.preload([[miner: :names], :transactions, :rewards])
|> Enum.map(fn block ->
%{
chain_block_html:

@ -30,10 +30,12 @@ defmodule BlockScoutWeb.SmartContractController do
end
end
def index(conn, _), do: not_found(conn)
def show(conn, params) do
with true <- ajax?(conn),
{:ok, address_hash} <- Chain.string_to_address_hash(params["id"]),
{:ok, _address} <- Chain.find_contract_address(address_hash),
:ok <- Chain.check_contract_address_exists(address_hash),
outputs =
Reader.query_function(
address_hash,
@ -51,7 +53,7 @@ defmodule BlockScoutWeb.SmartContractController do
:error ->
unprocessable_entity(conn)
{:error, :not_found} ->
:not_found ->
not_found(conn)
_ ->

@ -62,15 +62,15 @@ defmodule BlockScoutWeb.TransactionController do
def show(conn, %{"id" => id}) do
with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(id),
{:ok, %Chain.Transaction{} = transaction} <- Chain.hash_to_transaction(transaction_hash) do
if Chain.transaction_has_token_transfers?(transaction.hash) do
:ok <- Chain.check_transaction_exists(transaction_hash) do
if Chain.transaction_has_token_transfers?(transaction_hash) do
redirect(conn, to: transaction_token_transfer_path(conn, :index, id))
else
redirect(conn, to: transaction_internal_transaction_path(conn, :index, id))
end
else
:error -> conn |> put_status(422) |> render("invalid.html", transaction_hash: id)
{:error, :not_found} -> conn |> put_status(404) |> render("not_found.html", transaction_hash: id)
:not_found -> conn |> put_status(404) |> render("not_found.html", transaction_hash: id)
end
end
end

@ -10,7 +10,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do
def index(conn, %{"transaction_id" => hash_string, "type" => "JSON"} = params) do
with {:ok, hash} <- Chain.string_to_transaction_hash(hash_string),
{:ok, transaction} <- Chain.hash_to_transaction(hash) do
:ok <- Chain.check_transaction_exists(hash) do
full_options =
Keyword.merge(
[
@ -24,7 +24,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do
paging_options(params)
)
internal_transactions_plus_one = Chain.transaction_to_internal_transactions(transaction, full_options)
internal_transactions_plus_one = Chain.transaction_to_internal_transactions(hash, full_options)
{internal_transactions, next_page} = split_list_by_page(internal_transactions_plus_one)
@ -37,7 +37,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do
transaction_internal_transaction_path(
conn,
:index,
transaction,
hash,
Map.delete(next_page_params, "type")
)
end
@ -66,7 +66,7 @@ defmodule BlockScoutWeb.TransactionInternalTransactionController do
|> put_view(TransactionView)
|> render("invalid.html", transaction_hash: hash_string)
{:error, :not_found} ->
:not_found ->
conn
|> put_status(404)
|> put_view(TransactionView)

@ -11,7 +11,9 @@ defmodule BlockScoutWeb.TransactionLogController do
def index(conn, %{"transaction_id" => transaction_hash_string, "type" => "JSON"} = params) do
with {:ok, transaction_hash} <- Chain.string_to_transaction_hash(transaction_hash_string),
{:ok, transaction} <-
Chain.hash_to_transaction(transaction_hash) do
Chain.hash_to_transaction(transaction_hash,
necessity_by_association: %{[to_address: :smart_contract] => :optional}
) do
full_options =
Keyword.merge(
[
@ -22,7 +24,7 @@ defmodule BlockScoutWeb.TransactionLogController do
paging_options(params)
)
logs_plus_one = Chain.transaction_to_logs(transaction, full_options)
logs_plus_one = Chain.transaction_to_logs(transaction_hash, full_options)
{logs, next_page} = split_list_by_page(logs_plus_one)

@ -19,7 +19,7 @@ defmodule BlockScoutWeb.TransactionRawTraceController do
:token_transfers => :optional
}
) do
internal_transactions = Chain.transaction_to_internal_transactions(transaction)
internal_transactions = Chain.transaction_to_internal_transactions(hash)
render(
conn,

@ -10,8 +10,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do
def index(conn, %{"transaction_id" => hash_string, "type" => "JSON"} = params) do
with {:ok, hash} <- Chain.string_to_transaction_hash(hash_string),
{:ok, transaction} <-
Chain.hash_to_transaction(hash) do
:ok <- Chain.check_transaction_exists(hash) do
full_options =
Keyword.merge(
[
@ -24,7 +23,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do
paging_options(params)
)
token_transfers_plus_one = Chain.transaction_to_token_transfers(transaction, full_options)
token_transfers_plus_one = Chain.transaction_to_token_transfers(hash, full_options)
{token_transfers, next_page} = split_list_by_page(token_transfers_plus_one)
@ -34,7 +33,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do
nil
next_page_params ->
transaction_token_transfer_path(conn, :index, transaction, Map.delete(next_page_params, "type"))
transaction_token_transfer_path(conn, :index, hash, Map.delete(next_page_params, "type"))
end
items =
@ -62,7 +61,7 @@ defmodule BlockScoutWeb.TransactionTokenTransferController do
|> put_view(TransactionView)
|> render("invalid.html", transaction_hash: hash_string)
{:error, :not_found} ->
:not_found ->
conn
|> put_status(404)
|> put_view(TransactionView)

@ -261,6 +261,6 @@ defmodule BlockScoutWeb.Router do
get("/api_docs", APIDocsController, :index)
get("/eth_rpc_api_docs", APIDocsController, :eth_rpc)
get("/:page", PageNotFoundController, :index)
get("/*path", PageNotFoundController, :index)
end
end

@ -21,7 +21,7 @@
<td class="stakes-td color-lighten">
<!-- percentage of coins from total supply -->
<%= if @total_supply do %>
(<%= balance_percentage(@address, @total_supply) %>)
<%= balance_percentage(@address, @total_supply) %>
<% end %>
</td>
<td class="stakes-td">

@ -38,7 +38,7 @@
</tr>
</thead>
<tbody data-items data-selector="top-addresses-list">
<%= render BlockScoutWeb.CommonComponentsView, "_table-loader.html" %>
</tbody>
</table>
</div>

@ -84,9 +84,11 @@
<%= gettext("Transactions Sent") %>
<% end %>
</span>
<%= if @address.fetched_coin_balance_block_number do %>
<span class="address-detail-item">
<%= gettext("Last Balance Update: Block #") %><span data-selector="fetched-coin-balance-block-number"><%= @address.fetched_coin_balance_block_number %></span>
</span>
<% end %>
<%= if validator?(@validation_count) do %>
<span class="address-detail-item">
<span data-selector="validation-count">

@ -40,7 +40,9 @@
</div>
</div>
<div data-selector="coin-balances-list" data-items></div>
<div data-selector="coin-balances-list" data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -46,14 +46,18 @@
<dd class="col-sm-8 col-md-10"><%= @address.smart_contract.evm_version %></dd>
</dl>
<% end %>
<hr/>
<%= if @address.smart_contract.constructor_arguments do %>
<dl class="row">
<dt class="col-sm-4 col-md-2 text-muted"><%= gettext "Constructor arguments" %></dt>
<dd class="col-sm-8 col-md-10"><%= @address.smart_contract.constructor_arguments %></dd>
</dl>
<% end %>
<section>
<div class="d-flex justify-content-between align-items-baseline">
<h3><%= gettext "Constructor Arguments" %></h3>
</div>
<hr/>
<div class="tile tile-muted mb-4">
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= raw(format_constructor_arguments(@address.smart_contract)) %></code>
</pre>
</div>
</section>
<% end %>
<section>
<div class="d-flex justify-content-between align-items-baseline">
<h3><%= gettext "Contract source code" %></h3>
@ -116,7 +120,7 @@
<h3><%= gettext "External libraries" %></h3>
</div>
<div class="tile tile-muted mb-4">
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= format_external_libraries(@address.smart_contract.external_libraries) %></code>
<pre class="pre-wrap pre-scrollable"><code class="nohighlight"><%= raw(format_external_libraries(@address.smart_contract.external_libraries)) %></code>
</pre>
</div>
</section>

@ -66,7 +66,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -11,6 +11,76 @@
) %>
</h3>
</dd>
<dt class="col-md-2"><%= gettext "Decoded" %></dt>
<dd class="col-md-10">
<%= case decode(@log, @log.transaction) do %>
<% {:error, :contract_not_verified} -> %>
<div class="alert alert-info">
<%= gettext "To see decoded input data, the contract must be verified." %>
<%= case @log.transaction do %>
<% %{to_address: %{hash: hash}} -> %>
<%= gettext "Verify the contract " %><a href="<%= address_verify_contract_path(@conn, :new, hash)%>"><%= gettext "here" %></a>
<% _ -> %>
<%= nil %>
<% end %>
</div>
<% {:error, :could_not_decode} -> %>
<div class="alert alert-danger">
<%= gettext "Failed to decode log data." %>
</div>
<% {:ok, method_id, text, mapping} -> %>
<table summary="Transaction Info" class="table thead-light table-bordered transaction-input-table">
<tr>
<td>Method Id</td>
<td colspan="3"><code>0x<%= method_id %></code></td>
</tr>
<tr>
<td>Call</td>
<td colspan="3"><code><%= text %></code></td>
</tr>
</table>
<div class="table-responsive text-center">
<table style="color: black;" summary="<%= gettext "Log Data" %>" class="table thead-light table-bordered">
<tr>
<th scope="col"></th>
<th scope="col"><%= gettext "Name" %></th>
<th scope="col"><%= gettext "Type" %></th>
<th scope="col"><%= gettext "Indexed?" %></th>
<th scope="col"><%= gettext "Data" %></th>
<tr>
<%= for {name, type, indexed?, value} <- mapping do %>
<tr>
<th scope="row">
<%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %>
<% :error -> %>
<%= nil %>
<% copy_text -> %>
<span
aria-label='<%= gettext "Copy Value" %>'
class="btn-copy-ico"
data-clipboard-text="<%= copy_text %>"
data-placement="top"
data-toggle="tooltip"
>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32.5 32.5" width="32" height="32">
<path fill-rule="evenodd" d="M23.5 20.5a1 1 0 0 1-1-1v-9h-9a1 1 0 0 1 0-2h10a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1zm-3-7v10a1 1 0 0 1-1 1h-10a1 1 0 0 1-1-1v-10a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1zm-2 1h-8v8h8v-8z"/>
</svg>
</span>
<% end %>
</th>
<td><%= name %></td>
<td><%= type %></td>
<td><%= indexed? %></td>
<td>
<pre class="transaction-input-text tile"><code><%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %></code></pre>
</td>
</tr>
<% end %>
</table>
</div>
<% _ -> %>
<%= nil %>
<% end %>
<dt class="col-md-2"><%= gettext "Topics" %></dt>
<dd class="col-md-10">
<div class="raw-transaction-log-topics">

@ -27,7 +27,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -19,7 +19,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<div class="transaction-bottom-panel">
<div csv-download class="download-all-transactions">

@ -21,7 +21,9 @@
</span>
</button>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -65,7 +65,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<div class="transaction-bottom-panel">
<div class="download-all-transactions">

@ -22,7 +22,9 @@
<%= gettext "Something went wrong, click to reload." %>
</span>
</button>
<div data-items data-selector="validations-list"></div>
<div data-items data-selector="validations-list">
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -11,7 +11,9 @@
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "top", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<div data-empty-response-message style="display: none;">
<span><%= gettext "There are no blocks." %></span>
</div>

@ -29,7 +29,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -1,172 +1,5 @@
<div class="col-lg-3 fade-up-blocks-chain" data-selector="chain-block" data-block-number="<%= @block.number %>">
<div class="tile tile-type-block n-p d-flex flex-column">
<div class="tile-type-block-animation">
<div class="tile-type-line-up"></div>
<span class="cube-animation-title">Block Validated, processing...</span>
<div class="cube-animation-wrapper">
<div class="cube-animation-center">
<div class="cube-animation-row">
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
</div>
<div class="cube-animation-row">
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
</div>
<div class="cube-animation-row">
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
<div class="cube-animation-column">
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
<svg class="cube" viewBox="0 0 86.6 100" x="0px" y="0px">
<polygon class="side" points="43.3,0 0,25 0,75 43.3,100 86.6,75 86.6,25 "></polygon>
<polygon class="side" points="86.6,25 43.3,50 43.3,100 86.6,75 "></polygon>
<polygon class="side" points="0,25 43.3,0 86.6,25 43.3,50 "></polygon>
</svg>
</div>
</div>
</div>
</div>
</div>
<%= link(
@block,
class: "tile-title",

@ -5,7 +5,7 @@
<div class="dashboard-banner-network-graph">
<!-- Graph -->
<div class="dashboard-banner-chart">
<div data-chart-loading-message class="tile tile-muted text-center mt-5">
<div hidden data-chart-loading-message class="tile tile-muted text-center mt-5">
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
@ -91,7 +91,7 @@
<%= gettext "Something went wrong, click to reload." %>
</span>
</button>
<div data-selector="loading-message" class="tile tile-muted text-center mt-3 w-100">
<div hidden data-selector="loading-message" class="tile tile-muted text-center mt-3 w-100" >
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
@ -117,12 +117,8 @@
<%= gettext "Something went wrong, click to retry." %>
</span>
</button>
<div data-selector="loading-message" class="tile tile-muted text-center mt-3">
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading...") %>
<div hidden data-selector="loading-message">
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
</span>
</div>

@ -0,0 +1,85 @@
<tr class="table-content-pseudo">
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
</tr>
<tr class="table-content-pseudo">
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
</tr>
<tr class="table-content-pseudo">
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
</tr>
<tr class="table-content-pseudo">
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
</tr>
<tr class="table-content-pseudo">
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
<td class="stakes-td">
<span class="table-content-loader"></span>
</td>
</tr>

@ -0,0 +1,72 @@
<div data-selector="loading-message" class="tile tile-type-loading">
<div class="row tile-body">
<div class="tile-transaction-type-block col-md-2 d-flex flex-row flex-md-column">
<span class="tile-label">
<span class="tile-loader tile-label-loader"></span>
</span>
<span class="tile-status-label ml-2 ml-md-0">
<span class="tile-loader tile-label-loader"></span>
</span>
</div>
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<span class="tile-loader tile-address-loader"></span>
<span class="tile-loader tile-address-loader"></span>
</div>
<div class="col-md-3 col-lg-2 d-flex flex-row flex-md-column flex-nowrap justify-content-center text-md-right mt-3 mt-md-0 tile-bottom">
<span class="mr-2 mr-md-0 order-1">
<span class="tile-loader tile-label-loader"></span>
</span>
<span class="mr-2 mr-md-0 order-2">
<span class="tile-loader tile-label-loader"></span>
</span>
</div>
</div>
</div>
<div data-selector="loading-message" class="tile tile-type-loading">
<div class="row tile-body">
<div class="tile-transaction-type-block col-md-2 d-flex flex-row flex-md-column">
<span class="tile-label">
<span class="tile-loader tile-label-loader"></span>
</span>
<span class="tile-status-label ml-2 ml-md-0">
<span class="tile-loader tile-label-loader"></span>
</span>
</div>
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<span class="tile-loader tile-address-loader"></span>
<span class="tile-loader tile-address-loader"></span>
</div>
<div class="col-md-3 col-lg-2 d-flex flex-row flex-md-column flex-nowrap justify-content-center text-md-right mt-3 mt-md-0 tile-bottom">
<span class="mr-2 mr-md-0 order-1">
<span class="tile-loader tile-label-loader"></span>
</span>
<span class="mr-2 mr-md-0 order-2">
<span class="tile-loader tile-label-loader"></span>
</span>
</div>
</div>
</div>
<div data-selector="loading-message" class="tile tile-type-loading">
<div class="row tile-body">
<div class="tile-transaction-type-block col-md-2 d-flex flex-row flex-md-column">
<span class="tile-label">
<span class="tile-loader tile-label-loader"></span>
</span>
<span class="tile-status-label ml-2 ml-md-0">
<span class="tile-loader tile-label-loader"></span>
</span>
</div>
<div class="col-md-7 col-lg-8 d-flex flex-column pr-2 pr-sm-2 pr-md-0">
<span class="tile-loader tile-address-loader"></span>
<span class="tile-loader tile-address-loader"></span>
</div>
<div class="col-md-3 col-lg-2 d-flex flex-row flex-md-column flex-nowrap justify-content-center text-md-right mt-3 mt-md-0 tile-bottom">
<span class="mr-2 mr-md-0 order-1">
<span class="tile-loader tile-label-loader"></span>
</span>
<span class="mr-2 mr-md-0 order-2">
<span class="tile-loader tile-label-loader"></span>
</span>
</div>
</div>
</div>

@ -1,8 +1,18 @@
<nav class="navbar navbar-dark navbar-expand-lg navbar-primary" data-selector="navbar">
<nav class="navbar navbar-dark navbar-expand-lg navbar-primary" data-selector="navbar" id="top-navbar">
<script>
if (localStorage.getItem("current-color-mode") === "dark") {
document.getElementById("top-navbar").style.backgroundColor = "#282945";
}
</script>
<div class="container-fluid navbar-container">
<%= link to: chain_path(@conn, :show), class: "navbar-brand", "data-test": "header_logo" do %>
<img class="navbar-logo" src="<%= logo() %>" alt="<%= subnetwork_title() %>" />
<img class="navbar-logo" id="navbar-logo" src="<%= logo() %>" alt="<%= subnetwork_title() %>" />
<% end %>
<script>
if (localStorage.getItem("current-color-mode") === "dark") {
document.getElementById("navbar-logo").style.filter = "brightness(0) invert(1)";
}
</script>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="<%= gettext("Toggle navigation") %>">
<span class="navbar-toggler-icon"></span>
</button>
@ -90,8 +100,14 @@
</a>
</li>
</ul>
<!-- Dark mode changer -->
<button class="dark-mode-changer" id="dark-mode-changer">
<svg xmlns="http://www.w3.org/2000/svg" width="15" height="16">
<path fill="#9B62FF" fill-rule="evenodd" d="M14.88 11.578a.544.544 0 0 0-.599-.166 5.7 5.7 0 0 1-1.924.321c-3.259 0-5.91-2.632-5.91-5.866 0-1.947.968-3.759 2.59-4.849a.534.534 0 0 0-.225-.97A5.289 5.289 0 0 0 8.059 0C3.615 0 0 3.588 0 8s3.615 8 8.059 8c2.82 0 5.386-1.423 6.862-3.806a.533.533 0 0 0-.041-.616z"/>
</svg>
</button>
<!-- Search navbar -->
<div class="search-form d-lg-flex d-inline-block">
<div class="search-form d-lg-flex d-inline-block" style="background-color: #22223a">
<%= form_for @conn, chain_path(@conn, :search), [class: "form-inline my-2 my-lg-0", method: :get, enforce_utf8: false], fn f -> %>
<div class="input-group" title='<%= gettext("Search by address, token symbol name, transaction hash, or block number") %>'>
<%= awesomplete(f, :q,
@ -117,9 +133,22 @@
</div>
</div>
<button class="btn btn-outline-success my-2 my-sm-0 sr-only hidden" type="submit"><%= gettext "Search" %></button>
<script>
if (localStorage.getItem("current-color-mode") === "dark") {
document.getElementById("q").style.backgroundColor = "#22223a";
document.getElementById("q").style.borderColor = "#22223a";
}
</script>
<% end %>
</div>
</div>
</div>
</nav>
<%= render BlockScoutWeb.LayoutView, "_network_selector.html" %>
<script>
if (localStorage.getItem("current-color-mode") === "dark") {
var modeChanger = document.getElementById("dark-mode-changer");
modeChanger.className += " " + "dark-mode-changer--dark";
document.body.className += " " + "dark-theme-applied";
}
</script>

@ -24,6 +24,11 @@
</head>
<body>
<script>
if (localStorage.getItem("current-color-mode") === "dark") {
document.body.style.backgroundColor = "#1c1d31";
}
</script>
<div class="layout-container">
<%= if not Explorer.Chain.finished_indexing?() do %>
<div class="alert alert-warning text-center mb-0 p-3" data-selector="indexed-status">

@ -23,13 +23,8 @@
<%= gettext "There are no pending transactions." %>
</span>
</div>
<div data-items data-selector="transactions-pending-list"></div>
<div data-loading-message class="tile tile-muted text-center mt-3" style="display: none;">
<span class="loading-spinner-small mr-2">
<span class="loading-spinner-block-1"></span>
<span class="loading-spinner-block-2"></span>
</span>
<%= gettext("Loading") %>...
<div data-items data-selector="transactions-pending-list">
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -28,7 +28,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -27,7 +27,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -26,7 +26,9 @@
</span>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -1,4 +1,5 @@
<table summary="<%= gettext "Transaction Info" %>" class="table thead-light table-bordered table-responsive transaction-info-table">
<div class="table-responsive text-center">
<table style="color: black;" summary="<%= gettext "Transaction Inputs" %>" class="table thead-light table-bordered">
<tr>
<td><%= gettext "Method Id" %></td>
<td colspan="3"><code>0x<%= @method_id %></code></td>
@ -8,9 +9,11 @@
<td colspan="3"><code><%= @text %></code></td>
</tr>
</table>
</div>
<%= unless Enum.empty?(@mapping) do %>
<table summary="<%= gettext "Transaction Inputs" %>" class="table thead-light table-bordered table-responsive">
<div class="table-responsive text-center">
<table style="color: black;" summary="<%= gettext "Transaction Inputs" %>" class="table thead-light table-bordered">
<tr>
<th scope="col"></th>
<th scope="col"><%= gettext "Name" %></th>
@ -52,4 +55,5 @@
</tr>
<% end %>
</table>
</div>
<% end %>

@ -28,7 +28,9 @@
</div>
</div>
<div data-selector="transactions-list" data-items></div>
<div data-selector="transactions-list" data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -16,7 +16,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>
</div>

@ -39,7 +39,8 @@
<td colspan="3"><code><%= text %></code></td>
</tr>
</table>
<table style="color: black;" summary="<%= gettext "Log Data" %>" class="table thead-light table-bordered table-responsive">
<div class="table-responsive text-center">
<table style="color: black;" summary="<%= gettext "Log Data" %>" class="table thead-light table-bordered">
<tr>
<th scope="col"></th>
<th scope="col"><%= gettext "Name" %></th>
@ -76,6 +77,7 @@
</tr>
<% end %>
</table>
</div>
<% _ -> %>
<%= nil %>
<% end %>

@ -19,7 +19,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -18,7 +18,9 @@
</div>
</div>
<div data-items></div>
<div data-items>
<%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
</div>
<%= render BlockScoutWeb.CommonComponentsView, "_pagination_container.html", position: "bottom", cur_page_number: "1", show_pagination_limit: true, data_next_page_button: true, data_prev_page_button: true %>

@ -1,6 +1,7 @@
defmodule BlockScoutWeb.AddressContractView do
use BlockScoutWeb, :view
alias ABI.{FunctionSelector, TypeDecoder}
alias Explorer.Chain.{Address, Data, InternalTransaction}
def render("scripts.html", %{conn: conn}) do
@ -21,9 +22,44 @@ defmodule BlockScoutWeb.AddressContractView do
def format_optimization_text(true), do: gettext("true")
def format_optimization_text(false), do: gettext("false")
def format_constructor_arguments(contract) do
constructor_abi = Enum.find(contract.abi, fn el -> el["type"] == "constructor" && el["inputs"] != [] end)
input_types = Enum.map(constructor_abi["inputs"], &FunctionSelector.parse_specification_type/1)
{_, result} =
contract.constructor_arguments
|> decode_data(input_types)
|> Enum.zip(constructor_abi["inputs"])
|> Enum.reduce({0, "#{contract.constructor_arguments}\n\n"}, fn {val, %{"type" => type}}, {count, acc} ->
formatted_val =
if is_binary(val) do
Base.encode16(val, case: :lower)
else
val
end
{count + 1, "#{acc}Arg [#{count}] (<b>#{type}</b>) : #{formatted_val}\n"}
end)
result
rescue
_ -> contract.constructor_arguments
end
defp decode_data("0x" <> encoded_data, types) do
decode_data(encoded_data, types)
end
defp decode_data(encoded_data, types) do
encoded_data
|> Base.decode16!(case: :mixed)
|> TypeDecoder.decode_raw(types)
end
def format_external_libraries(libraries) do
Enum.reduce(libraries, "", fn %{name: name, address_hash: address_hash}, acc ->
acc <> name <> " : " <> address_hash <> "\n"
"#{acc}<span class=\"hljs-title\">#{name}</span> : #{address_hash} \n"
end)
end

@ -1,3 +1,9 @@
defmodule BlockScoutWeb.AddressLogsView do
use BlockScoutWeb, :view
alias Explorer.Chain.Log
def decode(log, transaction) do
Log.decode(log, transaction)
end
end

@ -23,6 +23,7 @@ defmodule BlockScoutWeb.InternalTransactionView do
def type(%InternalTransaction{type: :call, call_type: :delegatecall}), do: gettext("Delegate Call")
def type(%InternalTransaction{type: :call, call_type: :staticcall}), do: gettext("Static Call")
def type(%InternalTransaction{type: :create}), do: gettext("Create")
def type(%InternalTransaction{type: :create2}), do: gettext("Create2")
def type(%InternalTransaction{type: :selfdestruct}), do: gettext("Self-Destruct")
def type(%InternalTransaction{type: :reward}), do: gettext("Reward")
end

@ -125,7 +125,7 @@ defmodule BlockScoutWeb.Mixfile do
{:spandex_datadog, "~> 0.4.0"},
# `:spandex` tracing of `:phoenix`
{:spandex_phoenix, "~> 0.3.1"},
{:timex, "~> 3.4"},
{:timex, "~> 3.6"},
{:wallaby, "~> 0.22", only: [:test], runtime: false},
# `:cowboy` `~> 2.0` and Phoenix 1.4 compatibility
{:wobserver, "~> 0.2.0", github: "poanetwork/wobserver", branch: "support-https"},

@ -34,7 +34,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:21
#: lib/block_scout_web/templates/chain/_block.html.eex:178
#: lib/block_scout_web/templates/chain/_block.html.eex:11
msgid "%{count} Transactions"
msgstr ""
@ -62,7 +62,7 @@ msgid "(query)"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:35
#: lib/block_scout_web/templates/layout/app.html.eex:40
msgid "- We're indexing this chain right now. Some of the counts may be inaccurate."
msgstr ""
@ -87,7 +87,7 @@ msgid "API for the %{subnetwork} - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:56
#: lib/block_scout_web/templates/layout/_topnav.html.eex:66
msgid "Accounts"
msgstr ""
@ -157,7 +157,7 @@ msgid "Block Height: %{height}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:50
#: lib/block_scout_web/templates/layout/app.html.eex:55
msgid "Block Mined, awaiting import..."
msgstr ""
@ -178,19 +178,19 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:87
#: lib/block_scout_web/templates/layout/_topnav.html.eex:16
#: lib/block_scout_web/templates/layout/_topnav.html.eex:20
#: lib/block_scout_web/templates/layout/_topnav.html.eex:26
#: lib/block_scout_web/templates/layout/_topnav.html.eex:30
msgid "Blocks"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:49
#: lib/block_scout_web/templates/layout/app.html.eex:54
msgid "Blocks Indexed"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:32
#: lib/block_scout_web/templates/address/overview.html.eex:95
#: lib/block_scout_web/templates/address/overview.html.eex:97
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
#: lib/block_scout_web/views/address_view.ex:311
msgid "Blocks Validated"
@ -209,8 +209,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:37
#: lib/block_scout_web/templates/address/overview.html.eex:144
#: lib/block_scout_web/templates/address/overview.html.eex:152
#: lib/block_scout_web/templates/address/overview.html.eex:146
#: lib/block_scout_web/templates/address/overview.html.eex:154
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:107
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:115
msgid "Close"
@ -258,7 +258,7 @@ msgid "Connection Lost, click to load newer validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:71
#: lib/block_scout_web/templates/address_contract/index.html.eex:75
msgid "Contract ABI"
msgstr ""
@ -296,7 +296,7 @@ msgid "Contract name:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:59
#: lib/block_scout_web/templates/address_contract/index.html.eex:63
msgid "Contract source code"
msgstr ""
@ -319,7 +319,7 @@ msgid "Copy Txn Hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:105
#: lib/block_scout_web/templates/address/overview.html.eex:107
msgid "Created by"
msgstr ""
@ -328,14 +328,6 @@ msgstr ""
msgid "Curl"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:44
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:18
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113
msgid "Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:53
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:188
@ -376,7 +368,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_balance_card.html.eex:15
#: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:21
#: lib/block_scout_web/templates/layout/app.html.eex:55
#: lib/block_scout_web/templates/layout/app.html.eex:60
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:30
#: lib/block_scout_web/templates/transaction/overview.html.eex:196
@ -400,7 +392,7 @@ msgid "Fetching tokens..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:26
#: lib/block_scout_web/templates/layout/_topnav.html.eex:36
msgid "Forked Blocks (Reorgs)"
msgstr ""
@ -454,7 +446,7 @@ msgid "IN"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:51
#: lib/block_scout_web/templates/layout/app.html.eex:56
msgid "Indexing Tokens"
msgstr ""
@ -486,7 +478,7 @@ msgid "Inventory"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:52
#: lib/block_scout_web/templates/layout/app.html.eex:57
msgid "Less than"
msgstr ""
@ -507,7 +499,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:31
#: lib/block_scout_web/templates/layout/app.html.eex:53
#: lib/block_scout_web/templates/layout/app.html.eex:58
#: lib/block_scout_web/views/address_view.ex:121
#: lib/block_scout_web/views/address_view.ex:121
msgid "Market Cap"
@ -522,7 +514,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:38
#: lib/block_scout_web/templates/block/overview.html.eex:121
#: lib/block_scout_web/templates/chain/_block.html.eex:182
#: lib/block_scout_web/templates/chain/_block.html.eex:15
msgid "Miner"
msgstr ""
@ -555,9 +547,10 @@ msgid "Must be set to:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:46
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:45
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:19
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46
msgid "Name"
msgstr ""
@ -604,7 +597,7 @@ msgid "Parent Hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
#: lib/block_scout_web/templates/layout/_topnav.html.eex:54
#: lib/block_scout_web/views/transaction_view.ex:143
#: lib/block_scout_web/views/transaction_view.ex:177
msgid "Pending"
@ -622,13 +615,13 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:24
#: lib/block_scout_web/templates/layout/app.html.eex:54
#: lib/block_scout_web/templates/layout/app.html.eex:59
msgid "Price"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:33
#: lib/block_scout_web/templates/address/overview.html.eex:143
#: lib/block_scout_web/templates/address/overview.html.eex:145
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:106
msgid "QR Code"
@ -669,8 +662,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:102
#: lib/block_scout_web/templates/layout/_topnav.html.eex:119
#: lib/block_scout_web/templates/layout/_topnav.html.eex:118
#: lib/block_scout_web/templates/layout/_topnav.html.eex:135
msgid "Search"
msgstr ""
@ -774,7 +767,7 @@ msgid "To"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:6
#: lib/block_scout_web/templates/layout/_topnav.html.eex:16
msgid "Toggle navigation"
msgstr ""
@ -825,12 +818,6 @@ msgstr ""
msgid "Top Accounts - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:83
msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:67
msgid "Total Difficulty"
@ -873,7 +860,7 @@ msgstr ""
#: lib/block_scout_web/templates/block_transaction/index.html.eex:10
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:108
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/templates/layout/_topnav.html.eex:45
#: lib/block_scout_web/views/address_view.ex:305
msgid "Transactions"
msgstr ""
@ -900,7 +887,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:80
#: lib/block_scout_web/templates/layout/_topnav.html.eex:23
#: lib/block_scout_web/templates/layout/_topnav.html.eex:33
msgid "Uncles"
msgstr ""
@ -915,7 +902,7 @@ msgid "Used"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:39
#: lib/block_scout_web/templates/layout/_topnav.html.eex:49
msgid "Validated"
msgstr ""
@ -996,12 +983,12 @@ msgid "Yes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:111
#: lib/block_scout_web/templates/address/overview.html.eex:113
msgid "at"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_contract_view.ex:22
#: lib/block_scout_web/views/address_contract_view.ex:23
msgid "false"
msgstr ""
@ -1019,7 +1006,7 @@ msgid "string"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_contract_view.ex:21
#: lib/block_scout_web/views/address_contract_view.ex:22
msgid "true"
msgstr ""
@ -1039,14 +1026,7 @@ msgid "Delegate Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:47
#: lib/block_scout_web/templates/chain/_block.html.eex:190
#: lib/block_scout_web/views/internal_transaction_view.ex:27
msgid "Reward"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/internal_transaction_view.ex:26
msgid "Self-Destruct"
msgstr ""
@ -1058,7 +1038,6 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_read_contract/index.html.eex:14
#: lib/block_scout_web/templates/chain/show.html.eex:99
#: lib/block_scout_web/templates/chain/show.html.eex:125
#: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:21
msgid "Loading..."
msgstr ""
@ -1069,22 +1048,17 @@ msgid "Loading...."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:64
#: lib/block_scout_web/templates/layout/_topnav.html.eex:74
msgid "APIs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:68
#: lib/block_scout_web/templates/layout/_topnav.html.eex:78
msgid "GraphQL"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:32
msgid "Loading"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/templates/layout/_topnav.html.eex:83
msgid "RPC"
msgstr ""
@ -1134,48 +1108,37 @@ msgid "Static Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:14
msgid "Decoded"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47
msgid "Indexed?"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:17
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46
msgid "Type"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:3
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:4
msgid "Method Id"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:19
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19
msgid "To see decoded input data, the contract must be verified."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:1
msgid "Transaction Info"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:13
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:2
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16
msgid "Transaction Inputs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22
msgid "Verify the contract "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22
msgid "here"
@ -1187,26 +1150,10 @@ msgid "Failed to decode input data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:46
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:49
msgid "Error rendering value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:28
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:58
msgid "Copy Value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29
msgid "Failed to decode log data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42
msgid "Log Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34
#: lib/block_scout_web/templates/address_internal_transaction/index.html.eex:61
@ -1277,7 +1224,7 @@ msgid "There are no pending transactions."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/index.html.eex:16
#: lib/block_scout_web/templates/block/index.html.eex:18
msgid "There are no blocks."
msgstr ""
@ -1407,17 +1354,17 @@ msgid "Support"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:73
#: lib/block_scout_web/templates/address_contract/index.html.eex:77
msgid "Copy ABI"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:89
#: lib/block_scout_web/templates/address_contract/index.html.eex:93
msgid "Copy Contract Creation Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:61
#: lib/block_scout_web/templates/address_contract/index.html.eex:65
msgid "Copy Source Code"
msgstr ""
@ -1432,7 +1379,7 @@ msgid "Contract Libraries"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:88
#: lib/block_scout_web/templates/address/overview.html.eex:89
msgid "Last Balance Update: Block #"
msgstr ""
@ -1478,13 +1425,13 @@ msgid "Incoming Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:119
#: lib/block_scout_web/templates/address/overview.html.eex:121
msgid "Error: Could not determine contract creator."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:96
#: lib/block_scout_web/templates/layout/_topnav.html.eex:100
#: lib/block_scout_web/templates/layout/_topnav.html.eex:112
#: lib/block_scout_web/templates/layout/_topnav.html.eex:116
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@ -1587,27 +1534,27 @@ msgid "Block Details"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:101
#: lib/block_scout_web/templates/address_contract/index.html.eex:105
msgid "Contract Byte Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:87
#: lib/block_scout_web/templates/address_contract/index.html.eex:91
msgid "Contract Creation Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:93
#: lib/block_scout_web/templates/address_contract/index.html.eex:97
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:103
#: lib/block_scout_web/templates/address_contract/index.html.eex:107
msgid "Copy Contract Byte Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:94
#: lib/block_scout_web/templates/address_contract/index.html.eex:98
msgid "Displaying the init data provided of the creating transaction."
msgstr ""
@ -1710,7 +1657,7 @@ msgid "ETH RPC API Documentation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:78
#: lib/block_scout_web/templates/layout/_topnav.html.eex:88
msgid "Eth RPC"
msgstr ""
@ -1745,8 +1692,8 @@ msgid "here."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/index.html.eex:26
#: lib/block_scout_web/templates/address_transaction/index.html.eex:72
#: lib/block_scout_web/templates/address_token/index.html.eex:28
#: lib/block_scout_web/templates/address_transaction/index.html.eex:74
msgid "CSV"
msgstr ""
@ -1755,11 +1702,6 @@ msgstr ""
msgid "Change Network"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:51
msgid "Constructor arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:44
msgid "ERC-20 "
@ -1771,7 +1713,7 @@ msgid "ERC-721 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:116
#: lib/block_scout_web/templates/address_contract/index.html.eex:120
msgid "External libraries"
msgstr ""
@ -1804,3 +1746,67 @@ msgstr ""
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4
msgid "Connection Lost"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:53
msgid "Constructor Arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:31
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:59
msgid "Copy Value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/internal_transaction_view.ex:26
msgid "Create2"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:21
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:49
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:115
msgid "Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29
msgid "Failed to decode log data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48
msgid "Indexed?"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:43
msgid "Log Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:47
#: lib/block_scout_web/templates/chain/_block.html.eex:23
#: lib/block_scout_web/views/internal_transaction_view.ex:28
msgid "Reward"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:85
msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47
msgid "Type"
msgstr ""

@ -62,7 +62,7 @@ msgid "(query)"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:35
#: lib/block_scout_web/templates/layout/app.html.eex:40
msgid "- We're indexing this chain right now. Some of the counts may be inaccurate."
msgstr ""
@ -87,7 +87,7 @@ msgid "API for the %{subnetwork} - BlockScout"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:56
#: lib/block_scout_web/templates/layout/_topnav.html.eex:66
msgid "Accounts"
msgstr ""
@ -157,7 +157,7 @@ msgid "Block Height: %{height}"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:50
#: lib/block_scout_web/templates/layout/app.html.eex:55
msgid "Block Mined, awaiting import..."
msgstr ""
@ -178,19 +178,19 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:87
#: lib/block_scout_web/templates/layout/_topnav.html.eex:16
#: lib/block_scout_web/templates/layout/_topnav.html.eex:20
#: lib/block_scout_web/templates/layout/_topnav.html.eex:26
#: lib/block_scout_web/templates/layout/_topnav.html.eex:30
msgid "Blocks"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:49
#: lib/block_scout_web/templates/layout/app.html.eex:54
msgid "Blocks Indexed"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_tabs.html.eex:32
#: lib/block_scout_web/templates/address/overview.html.eex:95
#: lib/block_scout_web/templates/address/overview.html.eex:97
#: lib/block_scout_web/templates/address_validation/index.html.eex:13
#: lib/block_scout_web/views/address_view.ex:311
msgid "Blocks Validated"
@ -209,8 +209,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_validator_metadata_modal.html.eex:37
#: lib/block_scout_web/templates/address/overview.html.eex:144
#: lib/block_scout_web/templates/address/overview.html.eex:152
#: lib/block_scout_web/templates/address/overview.html.eex:146
#: lib/block_scout_web/templates/address/overview.html.eex:154
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:107
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:115
msgid "Close"
@ -258,7 +258,7 @@ msgid "Connection Lost, click to load newer validations"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:71
#: lib/block_scout_web/templates/address_contract/index.html.eex:75
msgid "Contract ABI"
msgstr ""
@ -296,7 +296,7 @@ msgid "Contract name:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:59
#: lib/block_scout_web/templates/address_contract/index.html.eex:63
msgid "Contract source code"
msgstr ""
@ -319,7 +319,7 @@ msgid "Copy Txn Hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:105
#: lib/block_scout_web/templates/address/overview.html.eex:107
msgid "Created by"
msgstr ""
@ -328,14 +328,6 @@ msgstr ""
msgid "Curl"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:44
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:18
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:113
msgid "Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:53
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:188
@ -376,7 +368,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/_balance_card.html.eex:15
#: lib/block_scout_web/templates/internal_transaction/_tile.html.eex:21
#: lib/block_scout_web/templates/layout/app.html.eex:55
#: lib/block_scout_web/templates/layout/app.html.eex:60
#: lib/block_scout_web/templates/transaction/_pending_tile.html.eex:20
#: lib/block_scout_web/templates/transaction/_tile.html.eex:30
#: lib/block_scout_web/templates/transaction/overview.html.eex:196
@ -400,7 +392,7 @@ msgid "Fetching tokens..."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:26
#: lib/block_scout_web/templates/layout/_topnav.html.eex:36
msgid "Forked Blocks (Reorgs)"
msgstr ""
@ -454,7 +446,7 @@ msgid "IN"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:51
#: lib/block_scout_web/templates/layout/app.html.eex:56
msgid "Indexing Tokens"
msgstr ""
@ -486,7 +478,7 @@ msgid "Inventory"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/app.html.eex:52
#: lib/block_scout_web/templates/layout/app.html.eex:57
msgid "Less than"
msgstr ""
@ -507,7 +499,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:31
#: lib/block_scout_web/templates/layout/app.html.eex:53
#: lib/block_scout_web/templates/layout/app.html.eex:58
#: lib/block_scout_web/views/address_view.ex:121
#: lib/block_scout_web/views/address_view.ex:121
msgid "Market Cap"
@ -555,9 +547,10 @@ msgid "Must be set to:"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:46
#: lib/block_scout_web/templates/api_docs/_action_tile.html.eex:52
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:45
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:19
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46
msgid "Name"
msgstr ""
@ -604,7 +597,7 @@ msgid "Parent Hash"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:44
#: lib/block_scout_web/templates/layout/_topnav.html.eex:54
#: lib/block_scout_web/views/transaction_view.ex:143
#: lib/block_scout_web/views/transaction_view.ex:177
msgid "Pending"
@ -622,13 +615,13 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/chain/show.html.eex:24
#: lib/block_scout_web/templates/layout/app.html.eex:54
#: lib/block_scout_web/templates/layout/app.html.eex:59
msgid "Price"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:33
#: lib/block_scout_web/templates/address/overview.html.eex:143
#: lib/block_scout_web/templates/address/overview.html.eex:145
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:36
#: lib/block_scout_web/templates/tokens/overview/_details.html.eex:106
msgid "QR Code"
@ -669,8 +662,8 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/index.html.eex:14
#: lib/block_scout_web/templates/layout/_topnav.html.eex:102
#: lib/block_scout_web/templates/layout/_topnav.html.eex:119
#: lib/block_scout_web/templates/layout/_topnav.html.eex:118
#: lib/block_scout_web/templates/layout/_topnav.html.eex:135
msgid "Search"
msgstr ""
@ -774,7 +767,7 @@ msgid "To"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:6
#: lib/block_scout_web/templates/layout/_topnav.html.eex:16
msgid "Toggle navigation"
msgstr ""
@ -825,12 +818,6 @@ msgstr ""
msgid "Top Accounts - %{subnetwork} Explorer"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:83
msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:67
msgid "Total Difficulty"
@ -873,7 +860,7 @@ msgstr ""
#: lib/block_scout_web/templates/block_transaction/index.html.eex:10
#: lib/block_scout_web/templates/block_transaction/index.html.eex:18
#: lib/block_scout_web/templates/chain/show.html.eex:108
#: lib/block_scout_web/templates/layout/_topnav.html.eex:35
#: lib/block_scout_web/templates/layout/_topnav.html.eex:45
#: lib/block_scout_web/views/address_view.ex:305
msgid "Transactions"
msgstr ""
@ -900,7 +887,7 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/overview.html.eex:80
#: lib/block_scout_web/templates/layout/_topnav.html.eex:23
#: lib/block_scout_web/templates/layout/_topnav.html.eex:33
msgid "Uncles"
msgstr ""
@ -915,7 +902,7 @@ msgid "Used"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:39
#: lib/block_scout_web/templates/layout/_topnav.html.eex:49
msgid "Validated"
msgstr ""
@ -996,12 +983,12 @@ msgid "Yes"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:111
#: lib/block_scout_web/templates/address/overview.html.eex:113
msgid "at"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_contract_view.ex:22
#: lib/block_scout_web/views/address_contract_view.ex:23
msgid "false"
msgstr ""
@ -1019,7 +1006,7 @@ msgid "string"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/address_contract_view.ex:21
#: lib/block_scout_web/views/address_contract_view.ex:22
msgid "true"
msgstr ""
@ -1039,14 +1026,7 @@ msgid "Delegate Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:47
#: lib/block_scout_web/templates/chain/_block.html.eex:23
#: lib/block_scout_web/views/internal_transaction_view.ex:27
msgid "Reward"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/internal_transaction_view.ex:26
msgid "Self-Destruct"
msgstr ""
@ -1058,7 +1038,6 @@ msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_read_contract/index.html.eex:14
#: lib/block_scout_web/templates/chain/show.html.eex:99
#: lib/block_scout_web/templates/chain/show.html.eex:125
#: lib/block_scout_web/templates/tokens/read_contract/index.html.eex:21
msgid "Loading..."
msgstr ""
@ -1069,22 +1048,17 @@ msgid "Loading...."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:64
#: lib/block_scout_web/templates/layout/_topnav.html.eex:74
msgid "APIs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:68
#: lib/block_scout_web/templates/layout/_topnav.html.eex:78
msgid "GraphQL"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/pending_transaction/index.html.eex:32
msgid "Loading"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:73
#: lib/block_scout_web/templates/layout/_topnav.html.eex:83
msgid "RPC"
msgstr ""
@ -1134,48 +1108,37 @@ msgid "Static Call"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:14
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:14
msgid "Decoded"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47
msgid "Indexed?"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:17
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:46
msgid "Type"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:3
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:4
msgid "Method Id"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:19
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:19
msgid "To see decoded input data, the contract must be verified."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:1
msgid "Transaction Info"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:13
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:2
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:16
msgid "Transaction Inputs"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22
msgid "Verify the contract "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:22
#: lib/block_scout_web/templates/transaction/_decoded_input.html.eex:11
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:22
msgid "here"
@ -1187,25 +1150,10 @@ msgid "Failed to decode input data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:46
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:49
msgid "Error rendering value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:28
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:58
msgid "Copy Value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29
msgid "Failed to decode log data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:42
msgid "Log Data"
msgstr ""
""
#, elixir-format
#: lib/block_scout_web/templates/address_coin_balance/index.html.eex:34
@ -1277,7 +1225,7 @@ msgid "There are no pending transactions."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/index.html.eex:16
#: lib/block_scout_web/templates/block/index.html.eex:18
msgid "There are no blocks."
msgstr ""
@ -1407,17 +1355,17 @@ msgid "Support"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:73
#: lib/block_scout_web/templates/address_contract/index.html.eex:77
msgid "Copy ABI"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:89
#: lib/block_scout_web/templates/address_contract/index.html.eex:93
msgid "Copy Contract Creation Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:61
#: lib/block_scout_web/templates/address_contract/index.html.eex:65
msgid "Copy Source Code"
msgstr ""
@ -1432,7 +1380,7 @@ msgid "Contract Libraries"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:88
#: lib/block_scout_web/templates/address/overview.html.eex:89
msgid "Last Balance Update: Block #"
msgstr ""
@ -1478,13 +1426,13 @@ msgid "Incoming Transactions"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address/overview.html.eex:119
#: lib/block_scout_web/templates/address/overview.html.eex:121
msgid "Error: Could not determine contract creator."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:96
#: lib/block_scout_web/templates/layout/_topnav.html.eex:100
#: lib/block_scout_web/templates/layout/_topnav.html.eex:112
#: lib/block_scout_web/templates/layout/_topnav.html.eex:116
msgid "Search by address, token symbol name, transaction hash, or block number"
msgstr ""
@ -1587,27 +1535,27 @@ msgid "Block Details"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:101
#: lib/block_scout_web/templates/address_contract/index.html.eex:105
msgid "Contract Byte Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:87
#: lib/block_scout_web/templates/address_contract/index.html.eex:91
msgid "Contract Creation Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:93
#: lib/block_scout_web/templates/address_contract/index.html.eex:97
msgid "Contracts that self destruct in their constructors have no contract code published and cannot be verified."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:103
#: lib/block_scout_web/templates/address_contract/index.html.eex:107
msgid "Copy Contract Byte Code"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:94
#: lib/block_scout_web/templates/address_contract/index.html.eex:98
msgid "Displaying the init data provided of the creating transaction."
msgstr ""
@ -1710,7 +1658,7 @@ msgid "ETH RPC API Documentation"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/layout/_topnav.html.eex:78
#: lib/block_scout_web/templates/layout/_topnav.html.eex:88
msgid "Eth RPC"
msgstr ""
@ -1745,8 +1693,8 @@ msgid "here."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_token/index.html.eex:26
#: lib/block_scout_web/templates/address_transaction/index.html.eex:72
#: lib/block_scout_web/templates/address_token/index.html.eex:28
#: lib/block_scout_web/templates/address_transaction/index.html.eex:74
msgid "CSV"
msgstr ""
@ -1755,11 +1703,6 @@ msgstr ""
msgid "Change Network"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:51
msgid "Constructor arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/transaction_view.ex:44
msgid "ERC-20 "
@ -1771,7 +1714,7 @@ msgid "ERC-721 "
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:116
#: lib/block_scout_web/templates/address_contract/index.html.eex:120
msgid "External libraries"
msgstr ""
@ -1804,3 +1747,67 @@ msgstr ""
#: lib/block_scout_web/templates/address_contract_verification/new.html.eex:4
msgid "Connection Lost"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_contract/index.html.eex:53
msgid "Constructor Arguments"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:59
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:31
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:59
msgid "Copy Value"
msgstr ""
#, elixir-format
#: lib/block_scout_web/views/internal_transaction_view.ex:26
msgid "Create2"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:49
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:114
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:21
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:49
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:115
msgid "Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:29
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:29
msgid "Failed to decode log data."
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:48
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:48
msgid "Indexed?"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:43
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:43
msgid "Log Data"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/block/_tile.html.eex:47
#: lib/block_scout_web/templates/chain/_block.html.eex:23
#: lib/block_scout_web/views/internal_transaction_view.ex:28
msgid "Reward"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:84
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:85
msgid "Topics"
msgstr ""
#, elixir-format
#: lib/block_scout_web/templates/address_logs/_logs.html.eex:47
#: lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex:20
#: lib/block_scout_web/templates/transaction_log/_logs.html.eex:47
msgid "Type"
msgstr ""

@ -13,10 +13,16 @@ defmodule BlockScoutWeb.AddressTransactionControllerTest do
assert html_response(conn, 422)
end
test "with valid address hash without address", %{conn: conn} do
conn = get(conn, address_transaction_path(conn, :index, "0x8bf38d4764929064f2d4d3a56520a76ab3df415b"))
test "with valid address hash without address in the DB", %{conn: conn} do
conn =
get(
conn,
address_transaction_path(conn, :index, "0x8bf38d4764929064f2d4d3a56520a76ab3df415b", %{"type" => "JSON"})
)
assert html_response(conn, 404)
assert json_response(conn, 200)
transaction_tiles = json_response(conn, 200)["items"]
assert transaction_tiles |> length() == 0
end
test "returns transactions for the address", %{conn: conn} do

@ -1,6 +1,15 @@
defmodule BlockScoutWeb.API.V1.HealthControllerTest do
use BlockScoutWeb.ConnCase
alias Explorer.{Chain, PagingOptions}
setup do
Supervisor.terminate_child(Explorer.Supervisor, {ConCache, Explorer.Chain.Cache.Blocks.cache_name()})
Supervisor.restart_child(Explorer.Supervisor, {ConCache, Explorer.Chain.Cache.Blocks.cache_name()})
:ok
end
describe "GET last_block_status/0" do
test "returns error when there are no blocks in db", %{conn: conn} do
request = get(conn, api_v1_health_path(conn, :health))
@ -32,14 +41,46 @@ defmodule BlockScoutWeb.API.V1.HealthControllerTest do
end
test "returns ok when last block is not stale", %{conn: conn} do
insert(:block, consensus: true, timestamp: DateTime.utc_now())
block1 = insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 2)
insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 1)
request = get(conn, api_v1_health_path(conn, :health))
assert request.status == 200
result = Poison.decode!(request.resp_body)
assert result["healthy"] == true
assert %{
"latest_block_number" => to_string(block1.number),
"latest_block_inserted_at" => to_string(block1.timestamp),
"cache_latest_block_number" => to_string(block1.number),
"cache_latest_block_inserted_at" => to_string(block1.timestamp)
} == result["data"]
end
end
test "return error when cache is stale", %{conn: conn} do
stale_block = insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50), number: 3)
state_block_hash = stale_block.hash
assert [%{hash: ^state_block_hash}] = Chain.list_blocks(paging_options: %PagingOptions{page_size: 1})
insert(:block, consensus: true, timestamp: DateTime.utc_now(), number: 1)
assert [%{hash: ^state_block_hash}] = Chain.list_blocks(paging_options: %PagingOptions{page_size: 1})
request = get(conn, api_v1_health_path(conn, :health))
assert request.status == 500
assert %{
"healthy" => true,
"healthy" => false,
"error_code" => 5001,
"error_title" => "blocks fetching is stuck",
"error_description" =>
"There are no new blocks in the DB for the last 5 mins. Check the healthiness of Ethereum archive node or the Blockscout DB instance",
"data" => %{
"latest_block_number" => _,
"latest_block_inserted_at" => _
@ -47,4 +88,3 @@ defmodule BlockScoutWeb.API.V1.HealthControllerTest do
} = Poison.decode!(request.resp_body)
end
end
end

@ -426,13 +426,14 @@ defmodule EthereumJSONRPC.Geth.Call do
"transactionHash" => transaction_hash,
"index" => index,
"traceAddress" => trace_address,
"type" => "create" = type,
"type" => type,
"from" => from_address_hash,
"error" => error,
"gas" => gas,
"init" => init,
"value" => value
}) do
})
when type in ~w(create create2) do
%{
block_number: block_number,
transaction_index: transaction_index,
@ -454,7 +455,7 @@ defmodule EthereumJSONRPC.Geth.Call do
"transactionHash" => transaction_hash,
"index" => index,
"traceAddress" => trace_address,
"type" => "create",
"type" => type,
"from" => from_address_hash,
"createdContractAddressHash" => created_contract_address_hash,
"gas" => gas,
@ -462,14 +463,15 @@ defmodule EthereumJSONRPC.Geth.Call do
"init" => init,
"createdContractCode" => created_contract_code,
"value" => value
}) do
})
when type in ~w(create create2) do
%{
block_number: block_number,
transaction_index: transaction_index,
transaction_hash: transaction_hash,
index: index,
trace_address: trace_address,
type: "create",
type: type,
from_address_hash: from_address_hash,
gas: gas,
gas_used: gas_used,

@ -113,6 +113,7 @@ defmodule EthereumJSONRPC.Geth.Tracer do
end
defp op(%{"op" => "CREATE"} = log, ctx), do: create_op(log, ctx)
defp op(%{"op" => "CREATE2"} = log, ctx), do: create_op(log, ctx, "create2")
defp op(%{"op" => "SELFDESTRUCT"} = log, ctx), do: self_destruct_op(log, ctx)
defp op(%{"op" => "CALL"} = log, ctx), do: call_op(log, "call", ctx)
defp op(%{"op" => "CALLCODE"} = log, ctx), do: call_op(log, "callcode", ctx)
@ -155,7 +156,8 @@ defmodule EthereumJSONRPC.Geth.Tracer do
defp create_op(
%{"stack" => log_stack, "memory" => log_memory},
%{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx
%{depth: stack_depth, stack: stack, trace_address: trace_address, calls: calls} = ctx,
type \\ "create"
) do
[value, input_offset, input_length | _] = Enum.reverse(log_stack)
@ -165,7 +167,7 @@ defmodule EthereumJSONRPC.Geth.Tracer do
|> String.slice(quantity_to_integer("0x" <> input_offset) * 2, quantity_to_integer("0x" <> input_length) * 2)
call = %{
"type" => "create",
"type" => type,
"from" => nil,
"traceAddress" => Enum.reverse(trace_address),
"init" => "0x" <> init,

@ -353,4 +353,8 @@ defmodule EthereumJSONRPC.Transaction do
_ -> {key, quantity_to_integer(chain_id)}
end
end
defp entry_to_elixir(_) do
{nil, nil}
end
end

@ -82,7 +82,7 @@ defmodule EthereumJsonrpc.MixProject do
# `:spandex` integration with Datadog
{:spandex_datadog, "~> 0.4.0"},
# Convert unix timestamps in JSONRPC to DateTimes
{:timex, "~> 3.4"},
{:timex, "~> 3.6"},
# Encode/decode function names and arguments
{:ex_abi, "~> 0.1.18"},
# `:verify_fun` for `Socket.Web.connect`

@ -91,6 +91,9 @@
case 'CREATE':
this.createOp(log);
break;
case 'CREATE2':
this.create2Op(log);
break;
case 'SELFDESTRUCT':
this.selfDestructOp(log, db);
break;
@ -127,7 +130,7 @@
const ret = log.stack.peek(0);
if (!ret.equals(0)) {
if (call.type === 'create') {
if (call.type === 'create' || call.type === 'create2') {
call.createdContractAddressHash = toHex(toAddress(ret.toString(16)));
call.createdContractCode = toHex(db.getCode(toAddress(ret.toString(16))));
} else {
@ -162,6 +165,21 @@
this.callStack.push(call);
},
create2Op(log) {
const inputOffset = log.stack.peek(1).valueOf();
const inputLength = log.stack.peek(2).valueOf();
const inputEnd = inputOffset + inputLength;
const stackValue = log.stack.peek(0);
const call = {
type: 'create2',
from: toHex(log.contract.getAddress()),
init: toHex(log.memory.slice(inputOffset, inputEnd)),
valueBigInt: bigInt(stackValue.toString(10))
};
this.callStack.push(call);
},
selfDestructOp(log, db) {
const contractAddress = log.contract.getAddress();
@ -243,6 +261,9 @@
case 'CREATE':
result = this.ctxToCreate(ctx, db);
break;
case 'CREATE2':
result = this.ctxToCreate2(ctx, db);
break;
}
return result;
@ -292,6 +313,22 @@
return result;
},
ctxToCreate2(ctx, db) {
const result = {
type: 'create2',
from: toHex(ctx.from),
init: toHex(ctx.input),
valueBigInt: bigInt(ctx.value.toString(10)),
gasBigInt: bigInt(ctx.gas),
gasUsedBigInt: bigInt(ctx.gasUsed)
};
this.putBottomChildCalls(result);
this.putErrorOrCreatedContract(result, ctx, db);
return result;
},
putBottomChildCalls(result) {
const bottomCall = this.bottomCall();
const bottomChildCalls = bottomCall.calls;
@ -422,4 +459,3 @@
call.gasUsed = '0x' + gasUsedBigInt.toString(16);
}
}

@ -2,4 +2,14 @@ defmodule EthereumJSONRPC.TransactionTest do
use ExUnit.Case, async: true
doctest EthereumJSONRPC.Transaction
alias EthereumJSONRPC.Transaction
describe "to_elixir/1" do
test "skips unsupported keys" do
map = %{"key" => "value", "key1" => "value1"}
assert %{nil: nil} = Transaction.to_elixir(map)
end
end
end

@ -17,7 +17,15 @@ config :explorer,
if(System.get_env("UNCLES_IN_AVERAGE_BLOCK_TIME") == "false", do: false, else: true),
healthy_blocks_period: System.get_env("HEALTHY_BLOCKS_PERIOD") || :timer.minutes(5)
config :explorer, Explorer.Counters.AverageBlockTime, enabled: true
average_block_period =
case Integer.parse(System.get_env("AVERAGE_BLOCK_CACHE_PERIOD", "")) do
{secs, ""} -> :timer.seconds(secs)
_ -> :timer.minutes(30)
end
config :explorer, Explorer.Counters.AverageBlockTime,
enabled: true,
period: average_block_period
config :explorer, Explorer.Chain.Cache.BlockNumber, enabled: true
@ -106,6 +114,14 @@ config :spandex_ecto, SpandexEcto.EctoLogger,
tracer: Explorer.Tracer,
otp_app: :explorer
market_history_cache_period =
case Integer.parse(System.get_env("MARKET_HISTORY_CACHE_PERIOD", "")) do
{secs, ""} -> :timer.seconds(secs)
_ -> :timer.hours(6)
end
config :explorer, Explorer.Market.MarketHistoryCache, period: market_history_cache_period
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{Mix.env()}.exs"

@ -273,7 +273,7 @@ defmodule Explorer.Chain do
from(log in Log,
inner_join: transaction in assoc(log, :transaction),
order_by: [desc: transaction.block_number, desc: transaction.index],
preload: [:transaction],
preload: [:transaction, transaction: [to_address: :smart_contract]],
where: transaction.block_number < ^block_number,
or_where: transaction.block_number == ^block_number and transaction.index > ^transaction_index,
or_where:
@ -364,8 +364,8 @@ defmodule Explorer.Chain do
Uncles are not currently accounted for.
"""
@spec block_reward(Block.t()) :: Wei.t()
def block_reward(%Block{number: block_number}) do
@spec block_reward(Block.block_number()) :: Wei.t()
def block_reward(block_number) do
query =
from(
block in Block,
@ -415,8 +415,8 @@ defmodule Explorer.Chain do
`:key` (a tuple of the lowest/oldest `{index}`) and. Results will be the transactions older than
the `index` that are passed.
"""
@spec block_to_transactions(Block.t(), [paging_options | necessity_by_association_option]) :: [Transaction.t()]
def block_to_transactions(%Block{hash: block_hash}, options \\ []) when is_list(options) do
@spec block_to_transactions(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [Transaction.t()]
def block_to_transactions(block_hash, options \\ []) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
options
@ -432,8 +432,8 @@ defmodule Explorer.Chain do
@doc """
Counts the number of `t:Explorer.Chain.Transaction.t/0` in the `block`.
"""
@spec block_to_transaction_count(Block.t()) :: non_neg_integer()
def block_to_transaction_count(%Block{hash: block_hash}) do
@spec block_to_transaction_count(Hash.Full.t()) :: non_neg_integer()
def block_to_transaction_count(block_hash) do
query =
from(
transaction in Transaction,
@ -843,7 +843,7 @@ defmodule Explorer.Chain do
Returns `{:error, :not_found}` if there is no address by that hash present.
Returns `{:error, :no_balance}` if there is no balance for that address at that block.
"""
@spec get_balance_as_of_block(Hash.Address.t(), integer | :earliest | :latest | :pending) ::
@spec get_balance_as_of_block(Hash.Address.t(), Block.block_number() | :earliest | :latest | :pending) ::
{:ok, Wei.t()} | {:error, :no_balance} | {:error, :not_found}
def get_balance_as_of_block(address, block) when is_integer(block) do
coin_balance_query =
@ -930,33 +930,44 @@ defmodule Explorer.Chain do
Repo.all(query)
end
@spec find_contract_address(Hash.t()) :: {:ok, Address.t()} | {:error, :not_found}
def find_contract_address(%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash) do
@doc """
Finds an `t:Explorer.Chain.Address.t/0` that has the provided `t:Explorer.Chain.Address.t/0` `hash` and a contract.
## Options
* `:necessity_by_association` - use to load `t:association/0` as `:required` or `:optional`. If an association is
`:required`, and the `t:Explorer.Chain.Address.t/0` has no associated record for that association,
then the `t:Explorer.Chain.Address.t/0` will not be included in the list.
Optionally it also accepts a boolean to fetch the `has_decompiled_code?` virtual field or not
"""
@spec find_contract_address(Hash.Address.t(), [necessity_by_association_option], boolean()) ::
{:ok, Address.t()} | {:error, :not_found}
def find_contract_address(
%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash,
options \\ [],
query_decompiled_code_flag \\ false
) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
query =
from(
address in Address,
preload: [
:contracts_creation_internal_transaction,
:names,
:smart_contract,
:token,
:contracts_creation_transaction
],
where: address.hash == ^hash and not is_nil(address.contract_code)
)
query_with_decompiled_flag = with_decompiled_code_flag(query, hash)
address = Repo.one(query_with_decompiled_flag)
if address do
{:ok, address}
else
{:error, :not_found}
query
|> join_associations(necessity_by_association)
|> with_decompiled_code_flag(hash, query_decompiled_code_flag)
|> Repo.one()
|> case do
nil -> {:error, :not_found}
address -> {:ok, address}
end
end
@spec find_decompiled_contract_address(Hash.t()) :: {:ok, Address.t()} | {:error, :not_found}
@spec find_decompiled_contract_address(Hash.Address.t()) :: {:ok, Address.t()} | {:error, :not_found}
def find_decompiled_contract_address(%Hash{byte_count: unquote(Hash.Address.byte_count())} = hash) do
query =
from(
@ -1807,7 +1818,7 @@ defmodule Explorer.Chain do
Repo.one!(query)
end
def last_block_status do
def last_db_block_status do
query =
from(block in Block,
select: {block.number, block.timestamp},
@ -1816,11 +1827,27 @@ defmodule Explorer.Chain do
limit: 1
)
case Repo.one(query) do
nil ->
{:error, :no_blocks}
query
|> Repo.one()
|> block_status()
end
{number, timestamp} ->
def last_cache_block_status do
[
paging_options: %PagingOptions{page_size: 1}
]
|> list_blocks()
|> List.last()
|> case do
%{timestamp: timestamp, number: number} ->
block_status({number, timestamp})
_ ->
block_status(nil)
end
end
defp block_status({number, timestamp}) do
now = DateTime.utc_now()
last_block_period = DateTime.diff(now, timestamp, :millisecond)
@ -1830,7 +1857,8 @@ defmodule Explorer.Chain do
{:ok, number, timestamp}
end
end
end
defp block_status(nil), do: {:error, :no_blocks}
@doc """
Calculates the ranges of missing consensus blocks in `range`.
@ -2209,14 +2237,10 @@ defmodule Explorer.Chain do
"""
@spec transaction_to_internal_transactions(Transaction.t(), [paging_options | necessity_by_association_option]) :: [
@spec transaction_to_internal_transactions(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [
InternalTransaction.t()
]
def transaction_to_internal_transactions(
%Transaction{hash: %Hash{byte_count: unquote(Hash.Full.byte_count())} = hash},
options \\ []
)
when is_list(options) do
def transaction_to_internal_transactions(hash, options \\ []) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
@ -2244,12 +2268,8 @@ defmodule Explorer.Chain do
the `index` that are passed.
"""
@spec transaction_to_logs(Transaction.t(), [paging_options | necessity_by_association_option]) :: [Log.t()]
def transaction_to_logs(
%Transaction{hash: %Hash{byte_count: unquote(Hash.Full.byte_count())} = transaction_hash},
options \\ []
)
when is_list(options) do
@spec transaction_to_logs(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [Log.t()]
def transaction_to_logs(transaction_hash, options \\ []) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
@ -2276,14 +2296,10 @@ defmodule Explorer.Chain do
the `index` that are passed.
"""
@spec transaction_to_token_transfers(Transaction.t(), [paging_options | necessity_by_association_option]) :: [
@spec transaction_to_token_transfers(Hash.Full.t(), [paging_options | necessity_by_association_option]) :: [
TokenTransfer.t()
]
def transaction_to_token_transfers(
%Transaction{hash: %Hash{byte_count: unquote(Hash.Full.byte_count())} = transaction_hash},
options \\ []
)
when is_list(options) do
def transaction_to_token_transfers(transaction_hash, options \\ []) when is_list(options) do
necessity_by_association = Keyword.get(options, :necessity_by_association, %{})
paging_options = Keyword.get(options, :paging_options, @default_paging_options)
@ -2510,16 +2526,16 @@ defmodule Explorer.Chain do
|> repo.insert(on_conflict: :nothing, conflict_target: [:address_hash, :name])
end
@spec address_hash_to_address_with_source_code(%Explorer.Chain.Hash{}) :: %Explorer.Chain.Address{} | nil
def address_hash_to_address_with_source_code(%Explorer.Chain.Hash{} = address_hash) do
@spec address_hash_to_address_with_source_code(Hash.Address.t()) :: Address.t() | nil
def address_hash_to_address_with_source_code(address_hash) do
case Repo.get(Address, address_hash) do
nil -> nil
address -> Repo.preload(address, [:smart_contract, :decompiled_smart_contracts])
end
end
@spec address_hash_to_smart_contract(%Explorer.Chain.Hash{}) :: %Explorer.Chain.SmartContract{} | nil
def address_hash_to_smart_contract(%Explorer.Chain.Hash{} = address_hash) do
@spec address_hash_to_smart_contract(Hash.Address.t()) :: SmartContract.t() | nil
def address_hash_to_smart_contract(address_hash) do
query =
from(
smart_contract in SmartContract,
@ -3276,8 +3292,6 @@ defmodule Explorer.Chain do
defp staking_pool_filter(query, _), do: query
defp with_decompiled_code_flag(query, hash, use_option \\ true)
defp with_decompiled_code_flag(query, _hash, false), do: query
defp with_decompiled_code_flag(query, hash, true) do
@ -3300,4 +3314,203 @@ defmodule Explorer.Chain do
|> Base.decode16!(case: :mixed)
|> TypeDecoder.decode_raw(types)
end
@doc """
Checks if an `t:Explorer.Chain.Address.t/0` with the given `hash` exists.
Returns `:ok` if found
iex> {:ok, %Explorer.Chain.Address{hash: hash}} = Explorer.Chain.create_address(
...> %{hash: "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"}
...> )
iex> Explorer.Chain.check_address_exists(hash)
:ok
Returns `:not_found` if not found
iex> {:ok, hash} = Explorer.Chain.string_to_address_hash("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
iex> Explorer.Chain.check_address_exists(hash)
:not_found
"""
@spec check_address_exists(Hash.Address.t()) :: :ok | :not_found
def check_address_exists(address_hash) do
address_hash
|> address_exists?()
|> boolean_to_check_result()
end
@doc """
Checks if an `t:Explorer.Chain.Address.t/0` with the given `hash` exists.
Returns `true` if found
iex> {:ok, %Explorer.Chain.Address{hash: hash}} = Explorer.Chain.create_address(
...> %{hash: "0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed"}
...> )
iex> Explorer.Chain.address_exists?(hash)
true
Returns `false` if not found
iex> {:ok, hash} = Explorer.Chain.string_to_address_hash("0x5aaeb6053f3e94c9b9a09f33669435e7ef1beaed")
iex> Explorer.Chain.address_exists?(hash)
false
"""
@spec address_exists?(Hash.Address.t()) :: boolean()
def address_exists?(address_hash) do
query =
from(
address in Address,
where: address.hash == ^address_hash
)
Repo.exists?(query)
end
@doc """
Checks if it exists an `t:Explorer.Chain.Address.t/0` that has the provided
`t:Explorer.Chain.Address.t/0` `hash` and a contract.
Returns `:ok` if found and `:not_found` otherwise.
"""
@spec check_contract_address_exists(Hash.Address.t()) :: :ok | :not_found
def check_contract_address_exists(address_hash) do
address_hash
|> contract_address_exists?()
|> boolean_to_check_result()
end
@doc """
Checks if it exists an `t:Explorer.Chain.Address.t/0` that has the provided
`t:Explorer.Chain.Address.t/0` `hash` and a contract.
Returns `true` if found and `false` otherwise.
"""
@spec contract_address_exists?(Hash.Address.t()) :: boolean()
def contract_address_exists?(address_hash) do
query =
from(
address in Address,
where: address.hash == ^address_hash and not is_nil(address.contract_code)
)
Repo.exists?(query)
end
@doc """
Checks if it exists a `t:Explorer.Chain.DecompiledSmartContract.t/0` for the
`t:Explorer.Chain.Address.t/0` with the provided `hash` and with the provided version.
Returns `:ok` if found and `:not_found` otherwise.
"""
@spec check_decompiled_contract_exists(Hash.Address.t(), String.t()) :: :ok | :not_found
def check_decompiled_contract_exists(address_hash, version) do
address_hash
|> decompiled_contract_exists?(version)
|> boolean_to_check_result()
end
@doc """
Checks if it exists a `t:Explorer.Chain.DecompiledSmartContract.t/0` for the
`t:Explorer.Chain.Address.t/0` with the provided `hash` and with the provided version.
Returns `true` if found and `false` otherwise.
"""
@spec decompiled_contract_exists?(Hash.Address.t(), String.t()) :: boolean()
def decompiled_contract_exists?(address_hash, version) do
query =
from(contract in DecompiledSmartContract,
where: contract.address_hash == ^address_hash and contract.decompiler_version == ^version
)
Repo.exists?(query)
end
@doc """
Checks if it exists a verified `t:Explorer.Chain.SmartContract.t/0` for the
`t:Explorer.Chain.Address.t/0` with the provided `hash`.
Returns `:ok` if found and `:not_found` otherwise.
"""
@spec check_verified_smart_contract_exists(Hash.Address.t()) :: :ok | :not_found
def check_verified_smart_contract_exists(address_hash) do
address_hash
|> verified_smart_contract_exists?()
|> boolean_to_check_result()
end
@doc """
Checks if it exists a verified `t:Explorer.Chain.SmartContract.t/0` for the
`t:Explorer.Chain.Address.t/0` with the provided `hash`.
Returns `true` if found and `false` otherwise.
"""
@spec verified_smart_contract_exists?(Hash.Address.t()) :: boolean()
def verified_smart_contract_exists?(address_hash) do
query =
from(
smart_contract in SmartContract,
where: smart_contract.address_hash == ^address_hash
)
Repo.exists?(query)
end
@doc """
Checks if a `t:Explorer.Chain.Transaction.t/0` with the given `hash` exists.
Returns `:ok` if found
iex> %Transaction{hash: hash} = insert(:transaction)
iex> Explorer.Chain.check_transaction_exists(hash)
:ok
Returns `:not_found` if not found
iex> {:ok, hash} = Explorer.Chain.string_to_transaction_hash(
...> "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b"
...> )
iex> Explorer.Chain.check_transaction_exists(hash)
:not_found
"""
@spec check_transaction_exists(Hash.Full.t()) :: :ok | :not_found
def check_transaction_exists(hash) do
hash
|> transaction_exists?()
|> boolean_to_check_result()
end
@doc """
Checks if a `t:Explorer.Chain.Transaction.t/0` with the given `hash` exists.
Returns `true` if found
iex> %Transaction{hash: hash} = insert(:transaction)
iex> Explorer.Chain.transaction_exists?(hash)
true
Returns `false` if not found
iex> {:ok, hash} = Explorer.Chain.string_to_transaction_hash(
...> "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b"
...> )
iex> Explorer.Chain.transaction_exists?(hash)
false
"""
@spec transaction_exists?(Hash.Full.t()) :: boolean()
def transaction_exists?(hash) do
query =
from(
transaction in Transaction,
where: transaction.hash == ^hash
)
Repo.exists?(query)
end
defp boolean_to_check_result(true), do: :ok
defp boolean_to_check_result(false), do: :not_found
end

@ -392,7 +392,7 @@ defmodule Explorer.Chain.InternalTransaction do
@create_required_fields ~w(from_address_hash gas index init trace_address transaction_hash value)a
@create_allowed_fields @create_optional_fields ++ @create_required_fields
defp type_changeset(changeset, attrs, :create) do
defp type_changeset(changeset, attrs, type) when type in [:create, :create2] do
changeset
|> cast(attrs, @create_allowed_fields)
|> validate_required(@create_required_fields)
@ -537,7 +537,7 @@ defmodule Explorer.Chain.InternalTransaction do
|> put_raw_call_error_or_result(transaction)
end
defp internal_transaction_to_raw(%{type: :create} = transaction) do
defp internal_transaction_to_raw(%{type: type} = transaction) when type in [:create, :create2] do
%{
from_address_hash: from_address_hash,
gas: gas,
@ -549,7 +549,7 @@ defmodule Explorer.Chain.InternalTransaction do
action = %{"from" => from_address_hash, "gas" => gas, "init" => init, "value" => value}
%{
"type" => "create",
"type" => Atom.to_string(type),
"action" => Action.to_raw(action),
"traceAddress" => trace_address
}

@ -11,7 +11,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do
* `:reward`
* `:selfdestruct`
"""
@type t :: :call | :create | :reward | :selfdestruct
@type t :: :call | :create | :create2 | :reward | :selfdestruct
@doc """
Casts `term` to `t:t/0`
@ -22,6 +22,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do
{:ok, :call}
iex> Explorer.Chain.InternalTransaction.Type.cast(:create)
{:ok, :create}
iex> Explorer.Chain.InternalTransaction.Type.cast(:create2)
{:ok, :create2}
iex> Explorer.Chain.InternalTransaction.Type.cast(:reward)
{:ok, :reward}
iex> Explorer.Chain.InternalTransaction.Type.cast(:selfdestruct)
@ -33,6 +35,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do
{:ok, :call}
iex> Explorer.Chain.InternalTransaction.Type.cast("create")
{:ok, :create}
iex> Explorer.Chain.InternalTransaction.Type.cast("create2")
{:ok, :create2}
iex> Explorer.Chain.InternalTransaction.Type.cast("reward")
{:ok, :reward}
iex> Explorer.Chain.InternalTransaction.Type.cast("selfdestruct")
@ -53,9 +57,10 @@ defmodule Explorer.Chain.InternalTransaction.Type do
"""
@impl Ecto.Type
@spec cast(term()) :: {:ok, t()} | :error
def cast(t) when t in ~w(call create selfdestruct reward)a, do: {:ok, t}
def cast(t) when t in ~w(call create create2 selfdestruct reward)a, do: {:ok, t}
def cast("call"), do: {:ok, :call}
def cast("create"), do: {:ok, :create}
def cast("create2"), do: {:ok, :create2}
def cast("reward"), do: {:ok, :reward}
def cast("selfdestruct"), do: {:ok, :selfdestruct}
def cast(_), do: :error
@ -67,6 +72,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do
{:ok, "call"}
iex> Explorer.Chain.InternalTransaction.Type.dump(:create)
{:ok, "create"}
iex> Explorer.Chain.InternalTransaction.Type.dump(:create2)
{:ok, "create2"}
iex> Explorer.Chain.InternalTransaction.Type.dump(:reward)
{:ok, "reward"}
iex> Explorer.Chain.InternalTransaction.Type.dump(:selfdestruct)
@ -87,6 +94,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do
@spec dump(term()) :: {:ok, String.t()} | :error
def dump(:call), do: {:ok, "call"}
def dump(:create), do: {:ok, "create"}
def dump(:create2), do: {:ok, "create2"}
def dump(:reward), do: {:ok, "reward"}
def dump(:selfdestruct), do: {:ok, "selfdestruct"}
def dump(_), do: :error
@ -98,6 +106,8 @@ defmodule Explorer.Chain.InternalTransaction.Type do
{:ok, :call}
iex> Explorer.Chain.InternalTransaction.Type.load("create")
{:ok, :create}
iex> Explorer.Chain.InternalTransaction.Type.load("create2")
{:ok, :create2}
iex> Explorer.Chain.InternalTransaction.Type.load("reward")
{:ok, :reward}
iex> Explorer.Chain.InternalTransaction.Type.load("selfdestruct")
@ -118,6 +128,7 @@ defmodule Explorer.Chain.InternalTransaction.Type do
@spec load(term()) :: {:ok, t()} | :error
def load("call"), do: {:ok, :call}
def load("create"), do: {:ok, :create}
def load("create2"), do: {:ok, :create2}
def load("reward"), do: {:ok, :reward}
def load("selfdestruct"), do: {:ok, :selfdestruct}
# deprecated

@ -11,7 +11,7 @@ defmodule Explorer.Counters.AverageBlockTime do
alias Explorer.Repo
alias Timex.Duration
@refresh_period 30 * 60 * 1_000
@refresh_period Application.get_env(:explorer, __MODULE__)[:period]
@doc """
Starts a process to periodically update the counter of the token holders.

@ -12,7 +12,7 @@ defmodule Explorer.Market.MarketHistoryCache do
@last_update_key :last_update
@history_key :history
# 6 hours
@cache_period 1_000 * 60 * 60 * 6
@cache_period Application.get_env(:explorer, __MODULE__)[:period]
@recent_days 30
def fetch do

@ -8,7 +8,7 @@ defmodule Explorer.SmartContract.Reader do
alias EthereumJSONRPC.Contract
alias Explorer.Chain
alias Explorer.Chain.Hash
alias Explorer.Chain.{Hash, SmartContract}
@typedoc """
Map of functions to call with the values for the function to be called with.
@ -34,6 +34,8 @@ defmodule Explorer.SmartContract.Reader do
@doc """
Queries the contract functions on the blockchain and returns the call results.
Optionally accepts the abi if it has already been fetched.
## Examples
Note that for this example to work the database must be up to date with the
@ -57,15 +59,21 @@ defmodule Explorer.SmartContract.Reader do
)
# => %{"sum" => {:error, "Data overflow encoding int, data `abc` cannot fit in 256 bits"}}
"""
@spec query_verified_contract(Hash.Address.t(), functions()) :: functions_results()
def query_verified_contract(address_hash, functions) do
@spec query_verified_contract(Hash.Address.t(), functions(), SmartContract.abi() | nil) :: functions_results()
def query_verified_contract(address_hash, functions, mabi \\ nil) do
contract_address = Hash.to_string(address_hash)
abi =
case mabi do
nil ->
address_hash
|> Chain.address_hash_to_smart_contract()
|> Map.get(:abi)
_ ->
mabi
end
query_contract(contract_address, abi, functions)
end
@ -156,41 +164,41 @@ defmodule Explorer.SmartContract.Reader do
"""
@spec read_only_functions(Hash.t()) :: [%{}]
def read_only_functions(contract_address_hash) do
abi =
contract_address_hash
|> Chain.address_hash_to_smart_contract()
|> Map.get(:abi, [])
|> Map.get(:abi)
case abi do
nil ->
[]
_ ->
abi
|> Enum.filter(& &1["constant"])
|> fetch_current_value_from_blockchain(contract_address_hash, [])
|> Enum.reverse()
|> Enum.map(&fetch_current_value_from_blockchain(&1, abi, contract_address_hash))
end
end
def fetch_current_value_from_blockchain(
[%{"inputs" => []} = function | tail],
contract_address_hash,
acc
) do
defp fetch_current_value_from_blockchain(function, abi, contract_address_hash) do
values =
fetch_from_blockchain(contract_address_hash, %{
name: function["name"],
args: function["inputs"],
outputs: function["outputs"]
})
case function do
%{"inputs" => []} ->
name = function["name"]
args = function["inputs"]
outputs = function["outputs"]
formatted = Map.replace!(function, "outputs", values)
contract_address_hash
|> query_verified_contract(%{name => normalize_args(args)}, abi)
|> link_outputs_and_values(outputs, name)
fetch_current_value_from_blockchain(tail, contract_address_hash, [formatted | acc])
_ ->
link_outputs_and_values(%{}, Map.get(function, "outputs", []), function["name"])
end
def fetch_current_value_from_blockchain([function | tail], contract_address_hash, acc) do
values = link_outputs_and_values(%{}, Map.get(function, "outputs", []), function["name"])
formatted = Map.replace!(function, "outputs", values)
fetch_current_value_from_blockchain(tail, contract_address_hash, [formatted | acc])
Map.replace!(function, "outputs", values)
end
def fetch_current_value_from_blockchain([], _contract_address_hash, acc), do: acc
@doc """
Fetches the blockchain value of a function that requires arguments.
"""
@ -201,23 +209,27 @@ defmodule Explorer.SmartContract.Reader do
@spec query_function(Hash.t(), %{name: String.t(), args: [term()]}) :: [%{}]
def query_function(contract_address_hash, %{name: name, args: args}) do
function =
abi =
contract_address_hash
|> Chain.address_hash_to_smart_contract()
|> Map.get(:abi, [])
|> Map.get(:abi)
outputs =
case abi do
nil ->
nil
_ ->
function =
abi
|> Enum.filter(fn function -> function["name"] == name end)
|> List.first()
fetch_from_blockchain(contract_address_hash, %{
name: name,
args: args,
outputs: function["outputs"]
})
function["outputs"]
end
defp fetch_from_blockchain(contract_address_hash, %{name: name, args: args, outputs: outputs}) do
contract_address_hash
|> query_verified_contract(%{name => normalize_args(args)})
|> query_verified_contract(%{name => normalize_args(args)}, abi)
|> link_outputs_and_values(outputs, name)
end

@ -117,7 +117,7 @@ defmodule Explorer.Mixfile do
# Attach `:prometheus_ecto` to `:ecto`
{:telemetry, "~> 0.3.0"},
# `Timex.Duration` for `Explorer.Counters.AverageBlockTime.average_block_time/0`
{:timex, "~> 3.4"},
{:timex, "~> 3.6"},
{:con_cache, "~> 0.13"}
]
end

@ -50,21 +50,35 @@ defmodule Explorer.ChainTest do
end
end
describe "last_block_status/0" do
describe "last_db_block_status/0" do
test "return no_blocks errors if db is empty" do
assert {:error, :no_blocks} = Chain.last_block_status()
assert {:error, :no_blocks} = Chain.last_db_block_status()
end
test "returns {:ok, last_block_period} if block is in healthy period" do
insert(:block, consensus: true)
assert {:ok, _, _} = Chain.last_block_status()
assert {:ok, _, _} = Chain.last_db_block_status()
end
test "return {:ok, last_block_period} if block is not in healthy period" do
insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50))
assert {:error, _, _} = Chain.last_block_status()
assert {:error, _, _} = Chain.last_db_block_status()
end
end
describe "last_cache_block_status/0" do
test "returns success if cache is not stale" do
insert(:block, consensus: true)
assert {:ok, _, _} = Chain.last_cache_block_status()
end
test "return error if cache is stale" do
insert(:block, consensus: true, timestamp: Timex.shift(DateTime.utc_now(), hours: -50))
assert {:error, _, _} = Chain.last_cache_block_status()
end
end
@ -630,7 +644,7 @@ defmodule Explorer.ChainTest do
assert Repo.aggregate(Transaction, :count, :hash) == 0
assert [] = Chain.block_to_transactions(block)
assert [] = Chain.block_to_transactions(block.hash)
end
test "with transactions" do
@ -639,7 +653,7 @@ defmodule Explorer.ChainTest do
|> insert()
|> with_block()
assert [%Transaction{hash: ^transaction_hash}] = Chain.block_to_transactions(block)
assert [%Transaction{hash: ^transaction_hash}] = Chain.block_to_transactions(block.hash)
end
test "with transactions can be paginated by {index}" do
@ -657,7 +671,7 @@ defmodule Explorer.ChainTest do
|> with_block(block)
assert second_page_hashes ==
block
block.hash
|> Chain.block_to_transactions(paging_options: %PagingOptions{key: {index}, page_size: 50})
|> Enum.map(& &1.hash)
|> Enum.reverse()
@ -683,7 +697,7 @@ defmodule Explorer.ChainTest do
token: token
)
fetched_transaction = List.first(Explorer.Chain.block_to_transactions(block))
fetched_transaction = List.first(Explorer.Chain.block_to_transactions(block.hash))
assert fetched_transaction.hash == transaction.hash
assert length(fetched_transaction.token_transfers) == 2
end
@ -693,7 +707,7 @@ defmodule Explorer.ChainTest do
test "without transactions" do
block = insert(:block)
assert Chain.block_to_transaction_count(block) == 0
assert Chain.block_to_transaction_count(block.hash) == 0
end
test "with transactions" do
@ -702,7 +716,7 @@ defmodule Explorer.ChainTest do
|> insert()
|> with_block()
assert Chain.block_to_transaction_count(block) == 1
assert Chain.block_to_transaction_count(block.hash) == 1
end
end
@ -2090,7 +2104,7 @@ defmodule Explorer.ChainTest do
test "with transaction without internal transactions" do
transaction = insert(:transaction)
assert [] = Chain.transaction_to_internal_transactions(transaction)
assert [] = Chain.transaction_to_internal_transactions(transaction.hash)
end
test "with transaction with internal transactions returns all internal transactions for a given transaction hash" do
@ -2117,7 +2131,7 @@ defmodule Explorer.ChainTest do
transaction_index: transaction.index
)
results = [internal_transaction | _] = Chain.transaction_to_internal_transactions(transaction)
results = [internal_transaction | _] = Chain.transaction_to_internal_transactions(transaction.hash)
assert 2 == length(results)
@ -2151,7 +2165,7 @@ defmodule Explorer.ChainTest do
to_address: %Ecto.Association.NotLoaded{},
transaction: %Transaction{block: %Ecto.Association.NotLoaded{}}
}
] = Chain.transaction_to_internal_transactions(transaction)
] = Chain.transaction_to_internal_transactions(transaction.hash)
assert [
%InternalTransaction{
@ -2161,7 +2175,7 @@ defmodule Explorer.ChainTest do
}
] =
Chain.transaction_to_internal_transactions(
transaction,
transaction.hash,
necessity_by_association: %{
:from_address => :optional,
:to_address => :optional,
@ -2183,7 +2197,7 @@ defmodule Explorer.ChainTest do
transaction_index: transaction.index
)
result = Chain.transaction_to_internal_transactions(transaction)
result = Chain.transaction_to_internal_transactions(transaction.hash)
assert Enum.empty?(result)
end
@ -2202,7 +2216,7 @@ defmodule Explorer.ChainTest do
transaction_index: transaction.index
)
actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0)
actual = Enum.at(Chain.transaction_to_internal_transactions(transaction.hash), 0)
assert {actual.transaction_hash, actual.index} == {expected.transaction_hash, expected.index}
end
@ -2222,7 +2236,7 @@ defmodule Explorer.ChainTest do
transaction_index: transaction.index
)
actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0)
actual = Enum.at(Chain.transaction_to_internal_transactions(transaction.hash), 0)
assert {actual.transaction_hash, actual.index} == {expected.transaction_hash, expected.index}
end
@ -2243,7 +2257,7 @@ defmodule Explorer.ChainTest do
transaction_index: transaction.index
)
actual = Enum.at(Chain.transaction_to_internal_transactions(transaction), 0)
actual = Enum.at(Chain.transaction_to_internal_transactions(transaction.hash), 0)
assert {actual.transaction_hash, actual.index} == {expected.transaction_hash, expected.index}
end
@ -2271,7 +2285,7 @@ defmodule Explorer.ChainTest do
)
result =
transaction
transaction.hash
|> Chain.transaction_to_internal_transactions()
|> Enum.map(&{&1.transaction_hash, &1.index})
@ -2301,17 +2315,17 @@ defmodule Explorer.ChainTest do
)
assert [{first_transaction_hash, first_index}, {second_transaction_hash, second_index}] ==
transaction
transaction.hash
|> Chain.transaction_to_internal_transactions(paging_options: %PagingOptions{key: {-1}, page_size: 2})
|> Enum.map(&{&1.transaction_hash, &1.index})
assert [{first_transaction_hash, first_index}] ==
transaction
transaction.hash
|> Chain.transaction_to_internal_transactions(paging_options: %PagingOptions{key: {-1}, page_size: 1})
|> Enum.map(&{&1.transaction_hash, &1.index})
assert [{second_transaction_hash, second_index}] ==
transaction
transaction.hash
|> Chain.transaction_to_internal_transactions(paging_options: %PagingOptions{key: {0}, page_size: 2})
|> Enum.map(&{&1.transaction_hash, &1.index})
end
@ -2321,7 +2335,7 @@ defmodule Explorer.ChainTest do
test "without logs" do
transaction = insert(:transaction)
assert [] = Chain.transaction_to_logs(transaction)
assert [] = Chain.transaction_to_logs(transaction.hash)
end
test "with logs" do
@ -2332,7 +2346,7 @@ defmodule Explorer.ChainTest do
%Log{transaction_hash: transaction_hash, index: index} = insert(:log, transaction: transaction)
assert [%Log{transaction_hash: ^transaction_hash, index: ^index}] = Chain.transaction_to_logs(transaction)
assert [%Log{transaction_hash: ^transaction_hash, index: ^index}] = Chain.transaction_to_logs(transaction.hash)
end
test "with logs can be paginated" do
@ -2349,7 +2363,7 @@ defmodule Explorer.ChainTest do
|> Enum.map(& &1.index)
assert second_page_indexes ==
transaction
transaction.hash
|> Chain.transaction_to_logs(paging_options: %PagingOptions{key: {log.index}, page_size: 50})
|> Enum.map(& &1.index)
end
@ -2364,7 +2378,7 @@ defmodule Explorer.ChainTest do
assert [%Log{address: %Address{}, transaction: %Transaction{}}] =
Chain.transaction_to_logs(
transaction,
transaction.hash,
necessity_by_association: %{
address: :optional,
transaction: :optional
@ -2376,7 +2390,7 @@ defmodule Explorer.ChainTest do
address: %Ecto.Association.NotLoaded{},
transaction: %Ecto.Association.NotLoaded{}
}
] = Chain.transaction_to_logs(transaction)
] = Chain.transaction_to_logs(transaction.hash)
end
end
@ -2384,7 +2398,7 @@ defmodule Explorer.ChainTest do
test "without token transfers" do
transaction = insert(:transaction)
assert [] = Chain.transaction_to_token_transfers(transaction)
assert [] = Chain.transaction_to_token_transfers(transaction.hash)
end
test "with token transfers" do
@ -2397,7 +2411,7 @@ defmodule Explorer.ChainTest do
insert(:token_transfer, transaction: transaction)
assert [%TokenTransfer{transaction_hash: ^transaction_hash, log_index: ^log_index}] =
Chain.transaction_to_token_transfers(transaction)
Chain.transaction_to_token_transfers(transaction.hash)
end
test "token transfers necessity_by_association loads associations" do
@ -2410,7 +2424,7 @@ defmodule Explorer.ChainTest do
assert [%TokenTransfer{token: %Token{}, transaction: %Transaction{}}] =
Chain.transaction_to_token_transfers(
transaction,
transaction.hash,
necessity_by_association: %{
token: :optional,
transaction: :optional
@ -2422,7 +2436,7 @@ defmodule Explorer.ChainTest do
token: %Ecto.Association.NotLoaded{},
transaction: %Ecto.Association.NotLoaded{}
}
] = Chain.transaction_to_token_transfers(transaction)
] = Chain.transaction_to_token_transfers(transaction.hash)
end
end
@ -2480,7 +2494,17 @@ defmodule Explorer.ChainTest do
insert(:address, contract_code: Factory.data("contract_code"), smart_contract: nil, names: [])
|> Repo.preload([:contracts_creation_internal_transaction, :contracts_creation_transaction, :token])
response = Chain.find_contract_address(address.hash)
options = [
necessity_by_association: %{
:contracts_creation_internal_transaction => :optional,
:names => :optional,
:smart_contract => :optional,
:token => :optional,
:contracts_creation_transaction => :optional
}
]
response = Chain.find_contract_address(address.hash, options, true)
assert response == {:ok, address}
end
@ -2523,11 +2547,11 @@ defmodule Explorer.ChainTest do
|> Decimal.add(Decimal.new(3))
|> Wei.from(:wei)
assert expected == Chain.block_reward(block)
assert expected == Chain.block_reward(block.number)
end
test "with block without transactions", %{block: block, emission_reward: emission_reward} do
assert emission_reward.reward == Chain.block_reward(block)
assert emission_reward.reward == Chain.block_reward(block.number)
end
end

@ -102,7 +102,7 @@ defmodule Explorer.SmartContract.ReaderTest do
end
end
describe "query_verified_contract/2" do
describe "query_verified_contract/3" do
test "correctly returns the results of the smart contract functions" do
hash =
:smart_contract

@ -2,9 +2,11 @@
rm -rf ./_build
rm -rf ./deps
rm -rf ./logs/dev
rm -rf ./apps/explorer/node_modules
rm -rf ./apps/block_scout_web/assets/node_modules
logs=$(find . -not -path '*/\.*' -name "logs" -type d)
dev=$(find ${logs} -name "dev")
rm -rf {ls -la ${dev}}
find . -name "node_modules" -type d -exec rm -rf '{}' +
case "$1" in
-f)

Loading…
Cancel
Save