diff --git a/CHANGELOG.md b/CHANGELOG.md
index cfbb7f88b7..271a9add39 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/apps/block_scout_web/assets/css/app.scss b/apps/block_scout_web/assets/css/app.scss
index cf79ee46e8..e91df91740 100644
--- a/apps/block_scout_web/assets/css/app.scss
+++ b/apps/block_scout_web/assets/css/app.scss
@@ -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;
}
diff --git a/apps/block_scout_web/assets/css/components/_navbar.scss b/apps/block_scout_web/assets/css/components/_navbar.scss
index 48c6c50f02..0d892b25ca 100644
--- a/apps/block_scout_web/assets/css/components/_navbar.scss
+++ b/apps/block_scout_web/assets/css/components/_navbar.scss
@@ -252,4 +252,10 @@ $navbar-logo-width: auto !default;
@include media-breakpoint-up(xl) {
padding-right: 0;
}
+}
+
+.nav-item-networks {
+ .topnav-nav-link {
+ transition: none !important;
+ }
}
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/components/_stakes_table.scss b/apps/block_scout_web/assets/css/components/_stakes_table.scss
index 79cdc20b38..1831dc4d5b 100644
--- a/apps/block_scout_web/assets/css/components/_stakes_table.scss
+++ b/apps/block_scout_web/assets/css/components/_stakes_table.scss
@@ -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%;
diff --git a/apps/block_scout_web/assets/css/components/_tile.scss b/apps/block_scout_web/assets/css/components/_tile.scss
index dbfd117875..e621e4fd6d 100644
--- a/apps/block_scout_web/assets/css/components/_tile.scss
+++ b/apps/block_scout_web/assets/css/components/_tile.scss
@@ -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 {
@@ -512,4 +561,4 @@ $cube-quantity: 5;
100% {
transform: scale(0);
}
-}
\ No newline at end of file
+}
diff --git a/apps/block_scout_web/assets/css/theme/_base_variables.scss b/apps/block_scout_web/assets/css/theme/_base_variables.scss
index 9f1b82c887..2238327bd4 100644
--- a/apps/block_scout_web/assets/css/theme/_base_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_base_variables.scss
@@ -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;
diff --git a/apps/block_scout_web/assets/css/theme/_dai_variables.scss b/apps/block_scout_web/assets/css/theme/_dai_variables.scss
index 50cbcfa290..0c09660240 100644
--- a/apps/block_scout_web/assets/css/theme/_dai_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_dai_variables.scss
@@ -62,4 +62,9 @@ $card-tab-active: $secondary;
// Badges
$badge-neutral-color: #20446e;
$badge-neutral-background-color: rgba(#20446e, .1);
-$api-text-monospace-color: #20446e;
\ No newline at end of file
+$api-text-monospace-color: #20446e;
+
+// Dark theme
+$dark-primary: #15bba6;
+$dark-secondary: #93d7ff;
+$dark-primary-alternate: #15bba6;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_dark-theme.scss b/apps/block_scout_web/assets/css/theme/_dark-theme.scss
new file mode 100644
index 0000000000..e648e01982
--- /dev/null
+++ b/apps/block_scout_web/assets/css/theme/_dark-theme.scss
@@ -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;
+ }
+
+}
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss b/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss
index 68feab4dfc..dff677d7cc 100644
--- a/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_ethereum_classic_variables.scss
@@ -74,4 +74,9 @@ $card-tab-active: $tertiary;
// Badges
$badge-neutral-color: $tertiary;
$badge-neutral-background-color: rgba($tertiary, .1);
-$api-text-monospace-color: $tertiary;
\ No newline at end of file
+$api-text-monospace-color: $tertiary;
+
+// Dark theme
+$dark-primary: #8588ff;
+$dark-secondary: #4ad7a7;
+$dark-primary-alternate: #5b5ed8;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss b/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss
index 0755d3e4b4..0b5cac0c43 100644
--- a/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_ethereum_variables.scss
@@ -56,4 +56,18 @@ $card-tab-active: $secondary;
$dashboard-banner-gradient-end
);
}
+}
+
+// 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;
+ }
}
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_goerli_variables.scss b/apps/block_scout_web/assets/css/theme/_goerli_variables.scss
index 7900dd4c3b..04f953b477 100644
--- a/apps/block_scout_web/assets/css/theme/_goerli_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_goerli_variables.scss
@@ -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;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_kovan_variables.scss b/apps/block_scout_web/assets/css/theme/_kovan_variables.scss
index 351f046726..a4edc629d0 100644
--- a/apps/block_scout_web/assets/css/theme/_kovan_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_kovan_variables.scss
@@ -74,4 +74,9 @@ $badge-success-color: #15bba6;
$badge-success-background-color: rgba(#15bba6, .1);
$badge-neutral-color: $tertiary;
$badge-neutral-background-color: rgba($tertiary, .1);
-$api-text-monospace-color: $tertiary;
\ No newline at end of file
+$api-text-monospace-color: $tertiary;
+
+// Dark theme
+$dark-primary: #42e2d7;
+$dark-secondary: #1f857f;
+$dark-primary-alternate: #1f857f;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_lukso_variables.scss b/apps/block_scout_web/assets/css/theme/_lukso_variables.scss
index 65f9a73b5f..a7b608bfa8 100644
--- a/apps/block_scout_web/assets/css/theme/_lukso_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_lukso_variables.scss
@@ -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;
+ }
+}
diff --git a/apps/block_scout_web/assets/css/theme/_neutral_variables.scss b/apps/block_scout_web/assets/css/theme/_neutral_variables.scss
index 4033934dd6..120a11c222 100644
--- a/apps/block_scout_web/assets/css/theme/_neutral_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_neutral_variables.scss
@@ -71,4 +71,9 @@ $api-text-monospace-color: $primary;
.dropdown-items .dropdown-item:hover {
color: $primary !important;
}
-}
\ No newline at end of file
+}
+
+// Dark theme
+$dark-primary: #9b62ff;
+$dark-secondary: #87e1a9;
+$dark-primary-alternate: #7e50d0;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_poa_variables.scss b/apps/block_scout_web/assets/css/theme/_poa_variables.scss
index 4033934dd6..120a11c222 100644
--- a/apps/block_scout_web/assets/css/theme/_poa_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_poa_variables.scss
@@ -71,4 +71,9 @@ $api-text-monospace-color: $primary;
.dropdown-items .dropdown-item:hover {
color: $primary !important;
}
-}
\ No newline at end of file
+}
+
+// Dark theme
+$dark-primary: #9b62ff;
+$dark-secondary: #87e1a9;
+$dark-primary-alternate: #7e50d0;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss b/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss
index 1e62ea6d69..4fa700c50e 100644
--- a/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_rinkeby_variables.scss
@@ -57,3 +57,8 @@ $card-tab-active: $secondary;
);
}
}
+
+// Dark theme
+$dark-primary: #38a9f5;
+$dark-secondary: #76f1ff;
+$dark-primary-alternate: #38a9f5;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss b/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss
index 1e62ea6d69..4fa700c50e 100644
--- a/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_ropsten_variables.scss
@@ -57,3 +57,8 @@ $card-tab-active: $secondary;
);
}
}
+
+// Dark theme
+$dark-primary: #38a9f5;
+$dark-secondary: #76f1ff;
+$dark-primary-alternate: #38a9f5;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/css/theme/_rsk_variables.scss b/apps/block_scout_web/assets/css/theme/_rsk_variables.scss
index 76029e1a34..d33996a89e 100644
--- a/apps/block_scout_web/assets/css/theme/_rsk_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_rsk_variables.scss
@@ -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;
diff --git a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss
index 444cdff178..8d479f397d 100644
--- a/apps/block_scout_web/assets/css/theme/_sokol_variables.scss
+++ b/apps/block_scout_web/assets/css/theme/_sokol_variables.scss
@@ -72,4 +72,9 @@ $card-tab-active: $sub-accent-color;
// Badges
$badge-neutral-color: $tertiary;
-$badge-neutral-background-color: rgba($tertiary, .1);
\ No newline at end of file
+$badge-neutral-background-color: rgba($tertiary, .1);
+
+// Dark theme
+$dark-primary: #40bfb2;
+$dark-secondary: #25c9ff;
+$dark-primary-alternate: #1c9f90;
\ No newline at end of file
diff --git a/apps/block_scout_web/assets/js/app.js b/apps/block_scout_web/assets/js/app.js
index 25de7b2688..89059dd306 100644
--- a/apps/block_scout_web/assets/js/app.js
+++ b/apps/block_scout_web/assets/js/app.js
@@ -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'
diff --git a/apps/block_scout_web/assets/js/lib/market_history_chart.js b/apps/block_scout_web/assets/js/lib/market_history_chart.js
index 615f888d8a..098faac0a8 100644
--- a/apps/block_scout_web/assets/js/lib/market_history_chart.js
+++ b/apps/block_scout_web/assets/js/lib/market_history_chart.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
}
diff --git a/apps/block_scout_web/assets/js/lib/utils.js b/apps/block_scout_web/assets/js/lib/utils.js
index e275580812..e00d06ec1b 100644
--- a/apps/block_scout_web/assets/js/lib/utils.js
+++ b/apps/block_scout_web/assets/js/lib/utils.js
@@ -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
+ }
+}
diff --git a/apps/block_scout_web/assets/js/pages/chain.js b/apps/block_scout_web/assets/js/pages/chain.js
index 154c73e455..df89d92f36 100644
--- a/apps/block_scout_web/assets/js/pages/chain.js
+++ b/apps/block_scout_web/assets/js/pages/chain.js
@@ -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"]': {
diff --git a/apps/block_scout_web/assets/js/pages/dark-mode-switcher.js b/apps/block_scout_web/assets/js/pages/dark-mode-switcher.js
new file mode 100644
index 0000000000..e9e0bdc524
--- /dev/null
+++ b/apps/block_scout_web/assets/js/pages/dark-mode-switcher.js
@@ -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)
+})
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
index 33a01959c9..8b39de91a7 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_coin_balance_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
index bc4df8c4be..5db900b12b 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_contract_controller.ex
@@ -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",
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex
index e349ecd9ef..d3ea4e5303 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_logs_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
index d57aa30807..0849689dce 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_read_contract_controller.ex
@@ -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",
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
index f6d9b8a30f..47100b972e 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/address_transaction_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex
index 91569a96da..835e19bf3e 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/block_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
index 344dbe1037..565ea4b6a5 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/rpc/transaction_controller.ex
@@ -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, %{
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex
index 1eec849380..7b783b9761 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/decompiled_smart_contract_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex
index 957dc797be..1e65fa75ba 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/health_controller.ex
@@ -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!()
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex
index 50334a1a45..8b3d3d71eb 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/api/v1/verified_smart_contract_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
index 15b06f1edd..a1e4cbeb09 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/block_transaction_controller.ex
@@ -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,
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
index 40a0fd3bbb..ba5d547cf0 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/chain_controller.ex
@@ -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:
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
index 70ec6219f3..ff0a4e67aa 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/smart_contract_controller.ex
@@ -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)
_ ->
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
index 1bedf97c1d..3f849c0e7c 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_controller.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex
index 159d144cdd..ca154a0136 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_internal_transaction_controller.ex
@@ -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)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex
index 0a87d12493..e076b9ee7b 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_log_controller.ex
@@ -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)
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex
index 3d090e8a9b..250a6b4442 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_raw_trace_controller.ex
@@ -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,
diff --git a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
index cfb215da3e..585a01301f 100644
--- a/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
+++ b/apps/block_scout_web/lib/block_scout_web/controllers/transaction_token_transfer_controller.ex
@@ -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)
diff --git a/apps/block_scout_web/lib/block_scout_web/router.ex b/apps/block_scout_web/lib/block_scout_web/router.ex
index 4f5a8e1bed..7a1f5b3ed9 100644
--- a/apps/block_scout_web/lib/block_scout_web/router.ex
+++ b/apps/block_scout_web/lib/block_scout_web/router.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex
index 9680faa2a8..56f1a2bbb2 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address/_tile.html.eex
@@ -21,7 +21,7 @@
<%= if @total_supply do %>
- (<%= balance_percentage(@address, @total_supply) %>)
+ <%= balance_percentage(@address, @total_supply) %>
<% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex
index 3aaab46ad5..c594915d9f 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address/index.html.eex
@@ -38,7 +38,7 @@
-
+ <%= render BlockScoutWeb.CommonComponentsView, "_table-loader.html" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex
index 3cb95a5331..04e7c2c036 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address/overview.html.eex
@@ -84,9 +84,11 @@
<%= gettext("Transactions Sent") %>
<% end %>
-
- <%= gettext("Last Balance Update: Block #") %><%= @address.fetched_coin_balance_block_number %>
-
+ <%= if @address.fetched_coin_balance_block_number do %>
+
+ <%= gettext("Last Balance Update: Block #") %><%= @address.fetched_coin_balance_block_number %>
+
+ <% end %>
<%= if validator?(@validation_count) do %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex
index 6b9459f5b3..2e71dd22ca 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_coin_balance/index.html.eex
@@ -40,7 +40,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
index 340765a97f..e8d6501e02 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_contract/index.html.eex
@@ -46,14 +46,18 @@
<%= @address.smart_contract.evm_version %>
<% end %>
- <%= if @address.smart_contract.constructor_arguments do %>
-
- <%= gettext "Constructor arguments" %>
- <%= @address.smart_contract.constructor_arguments %>
-
- <% end %>
-
+ <%= if @address.smart_contract.constructor_arguments do %>
+
+
+
<%= gettext "Constructor Arguments" %>
+
+
+
<%= raw(format_constructor_arguments(@address.smart_contract)) %>
+
+
+
+ <% end %>
<%= gettext "Contract source code" %>
@@ -116,7 +120,7 @@
<%= gettext "External libraries" %>
-
<%= format_external_libraries(@address.smart_contract.external_libraries) %>
+ <%= raw(format_external_libraries(@address.smart_contract.external_libraries)) %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
index 3bc2e7fe9b..f18638db0d 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_internal_transaction/index.html.eex
@@ -66,7 +66,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex
index 1b5cb5c4fd..3fb638b1d9 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/_logs.html.eex
@@ -11,6 +11,76 @@
) %>
+ <%= gettext "Decoded" %>
+
+ <%= case decode(@log, @log.transaction) do %>
+ <% {:error, :contract_not_verified} -> %>
+
+ <%= gettext "To see decoded input data, the contract must be verified." %>
+ <%= case @log.transaction do %>
+ <% %{to_address: %{hash: hash}} -> %>
+ <%= gettext "Verify the contract " %>
<%= gettext "here" %>
+ <% _ -> %>
+ <%= nil %>
+ <% end %>
+
+ <% {:error, :could_not_decode} -> %>
+
+ <%= gettext "Failed to decode log data." %>
+
+ <% {:ok, method_id, text, mapping} -> %>
+
+
+
" class="table thead-light table-bordered">
+
+
+ <%= gettext "Name" %>
+ <%= gettext "Type" %>
+ <%= gettext "Indexed?" %>
+ <%= gettext "Data" %>
+
+ <%= for {name, type, indexed?, value} <- mapping do %>
+
+
+ <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %>
+ <% :error -> %>
+ <%= nil %>
+ <% copy_text -> %>
+
+
+
+
+
+ <% end %>
+
+ <%= name %>
+ <%= type %>
+ <%= indexed? %>
+
+ <%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
+
+
+ <% end %>
+
+
+ <% _ -> %>
+ <%= nil %>
+ <% end %>
<%= gettext "Topics" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex
index 3a44e0cb2d..fabbc7f7d8 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_logs/index.html.eex
@@ -27,7 +27,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex
index 840d9cc1da..8510bdca64 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token/index.html.eex
@@ -19,7 +19,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex
index c2ab502bf0..738d70883d 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_token_transfer/index.html.eex
@@ -21,7 +21,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
index c3a4c94129..83c5454627 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_transaction/index.html.eex
@@ -65,7 +65,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex
index 3f85f03aba..03b37369bc 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/address_validation/index.html.eex
@@ -22,7 +22,9 @@
<%= gettext "Something went wrong, click to reload." %>
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex
index 92b91ce287..dd8a3ed093 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/block/index.html.eex
@@ -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 %>
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= gettext "There are no blocks." %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex
index a497ab1b7e..e0847cac86 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/block_transaction/index.html.eex
@@ -29,7 +29,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex
index 729df59a3c..706d18ec47 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/_block.html.eex
@@ -1,172 +1,5 @@
-
-
-
Block Validated, processing...
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
<%= link(
@block,
class: "tile-title",
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
index 0c29001697..53b21cb3fa 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/chain/show.html.eex
@@ -5,7 +5,7 @@
-
+
@@ -91,8 +91,8 @@
<%= gettext "Something went wrong, click to reload." %>
-
-
+
+
@@ -117,12 +117,8 @@
<%= gettext "Something went wrong, click to retry." %>
-
-
-
-
-
- <%= gettext("Loading...") %>
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/common_components/_table-loader.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/common_components/_table-loader.html.eex
new file mode 100644
index 0000000000..ac7cc71f56
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/templates/common_components/_table-loader.html.eex
@@ -0,0 +1,85 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/common_components/_tile-loader.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/common_components/_tile-loader.html.eex
new file mode 100644
index 0000000000..134613a5d1
--- /dev/null
+++ b/apps/block_scout_web/lib/block_scout_web/templates/common_components/_tile-loader.html.eex
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
index f965f20e0c..2c221e4471 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/_topnav.html.eex
@@ -1,8 +1,18 @@
-
+
+
<%= link to: chain_path(@conn, :show), class: "navbar-brand", "data-test": "header_logo" do %>
-
+
<% end %>
+
">
@@ -90,8 +100,14 @@
+
+
+
+
+
+
-
-<%= render BlockScoutWeb.LayoutView, "_network_selector.html" %>
\ No newline at end of file
+<%= render BlockScoutWeb.LayoutView, "_network_selector.html" %>
+
\ No newline at end of file
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
index b3b6ba0665..c3b0fe2ff1 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/layout/app.html.eex
@@ -24,6 +24,11 @@
+
<%= if not Explorer.Chain.finished_indexing?() do %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex
index 4c97be61e1..e819285629 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/pending_transaction/index.html.eex
@@ -23,13 +23,8 @@
<%= gettext "There are no pending transactions." %>
-
-
-
-
-
-
- <%= gettext("Loading") %>...
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/tokens/holder/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/tokens/holder/index.html.eex
index 3b24912dd5..8e83021c80 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/tokens/holder/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/tokens/holder/index.html.eex
@@ -28,7 +28,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/index.html.eex
index da834dbc88..1e78b11353 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/tokens/inventory/index.html.eex
@@ -27,7 +27,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex
index 980cc4b05a..addaa0c359 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/tokens/transfer/index.html.eex
@@ -26,7 +26,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex
index f009eeb2b3..9e68d7e1bd 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/_decoded_input_body.html.eex
@@ -1,4 +1,5 @@
-
" class="table thead-light table-bordered table-responsive transaction-info-table">
+
+
" class="table thead-light table-bordered">
<%= gettext "Method Id" %>
0x<%= @method_id %>
@@ -7,49 +8,52 @@
Call
<%= @text %>
-
+
+
<%= unless Enum.empty?(@mapping) do %>
-
" class="table thead-light table-bordered table-responsive">
-
-
- <%= gettext "Name" %>
- <%= gettext "Type" %>
- <%= gettext "Data" %>
-
- <%= for {name, type, value} <- @mapping do %>
+
+
" class="table thead-light table-bordered">
+
+
+ <%= gettext "Name" %>
+ <%= gettext "Type" %>
+ <%= gettext "Data" %>
-
- <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %>
- <% :error -> %>
- <%= nil %>
- <% copy_text -> %>
-
-
-
-
-
- <% end %>
-
- <%= name %>
- <%= type %>
-
- <%= case BlockScoutWeb.ABIEncodedValueView.value_html(type, value) do %>
- <% :error -> %>
-
- <%= gettext "Error rendering value" %>
-
- <% value -> %>
- <%= value %>
+ <%= for {name, type, value} <- @mapping do %>
+
+
+ <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %>
+ <% :error -> %>
+ <%= nil %>
+ <% copy_text -> %>
+
+
+
+
+
<% end %>
-
-
- <% end %>
-
+
+
<%= name %>
+
<%= type %>
+
+ <%= case BlockScoutWeb.ABIEncodedValueView.value_html(type, value) do %>
+ <% :error -> %>
+
+ <%= gettext "Error rendering value" %>
+
+ <% value -> %>
+ <%= value %>
+ <% end %>
+
+
+ <% end %>
+
+
<% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex
index 18928915f2..bce59eb00b 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction/index.html.eex
@@ -28,7 +28,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex
index e6623b4061..70162a3be8 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_internal_transaction/index.html.eex
@@ -16,7 +16,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
index 5a52821601..ff3e46d42a 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/_logs.html.eex
@@ -39,43 +39,45 @@
<%= text %>
- " class="table thead-light table-bordered table-responsive">
-
-
- <%= gettext "Name" %>
- <%= gettext "Type" %>
- <%= gettext "Indexed?" %>
- <%= gettext "Data" %>
-
- <%= for {name, type, indexed?, value} <- mapping do %>
+
+
" class="table thead-light table-bordered">
-
- <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %>
- <% :error -> %>
- <%= nil %>
- <% copy_text -> %>
-
-
-
-
-
- <% end %>
-
- <%= name %>
- <%= type %>
- <%= indexed? %>
-
- <%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
-
-
- <% end %>
-
+
+
<%= gettext "Name" %>
+
<%= gettext "Type" %>
+
<%= gettext "Indexed?" %>
+
<%= gettext "Data" %>
+
+ <%= for {name, type, indexed?, value} <- mapping do %>
+
+
+ <%= case BlockScoutWeb.ABIEncodedValueView.copy_text(type, value) do %>
+ <% :error -> %>
+ <%= nil %>
+ <% copy_text -> %>
+
+
+
+
+
+ <% end %>
+
+ <%= name %>
+ <%= type %>
+ <%= indexed? %>
+
+ <%= BlockScoutWeb.ABIEncodedValueView.value_html(type, value) %>
+
+
+ <% end %>
+
+
<% _ -> %>
<%= nil %>
<% end %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex
index 3c84e7c4f9..17f480b439 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_log/index.html.eex
@@ -19,7 +19,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex b/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex
index d40dedd414..8d356a450a 100644
--- a/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex
+++ b/apps/block_scout_web/lib/block_scout_web/templates/transaction_token_transfer/index.html.eex
@@ -18,7 +18,9 @@
-
+
+ <%= render BlockScoutWeb.CommonComponentsView, "_tile-loader.html" %>
+
<%= 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 %>
diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
index 5de263f820..57c6e11da7 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/address_contract_view.ex
@@ -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}] (#{type} ) : #{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}#{name} : #{address_hash} \n"
end)
end
diff --git a/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex b/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex
index 7155e65206..3cdfaf1f9b 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/address_logs_view.ex
@@ -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
diff --git a/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex b/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex
index fe12f04302..46252f72ce 100644
--- a/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex
+++ b/apps/block_scout_web/lib/block_scout_web/views/internal_transaction_view.ex
@@ -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
diff --git a/apps/block_scout_web/mix.exs b/apps/block_scout_web/mix.exs
index e431d4ecf5..623aba2089 100644
--- a/apps/block_scout_web/mix.exs
+++ b/apps/block_scout_web/mix.exs
@@ -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"},
diff --git a/apps/block_scout_web/priv/gettext/default.pot b/apps/block_scout_web/priv/gettext/default.pot
index b8e56412a6..e356d87df9 100644
--- a/apps/block_scout_web/priv/gettext/default.pot
+++ b/apps/block_scout_web/priv/gettext/default.pot
@@ -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 ""
diff --git a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
index 5333eb95aa..58e159d0bb 100644
--- a/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
+++ b/apps/block_scout_web/priv/gettext/en/LC_MESSAGES/default.po
@@ -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 ""
diff --git a/apps/block_scout_web/priv/gettext/errors.pot b/apps/block_scout_web/priv/gettext/errors.pot
index ca584666e5..cdaaac6299 100644
--- a/apps/block_scout_web/priv/gettext/errors.pot
+++ b/apps/block_scout_web/priv/gettext/errors.pot
@@ -1,52 +1,52 @@
-## This file is a PO Template file.
-##
-## `msgid`s here are often extracted from source code.
-## Add new translations manually only if they're dynamic
-## translations that can't be statically extracted.
-##
-## Run `mix gettext.extract` to bring this file up to
-## date. Leave `msgstr`s empty as changing them here as no
-## effect: edit them in PO (`.po`) files instead.
-## From Ecto.Changeset.cast/4
+## This file is a PO Template file.
+##
+## `msgid`s here are often extracted from source code.
+## Add new translations manually only if they're dynamic
+## translations that can't be statically extracted.
+##
+## Run `mix gettext.extract` to bring this file up to
+## date. Leave `msgstr`s empty as changing them here as no
+## effect: edit them in PO (`.po`) files instead.
+## From Ecto.Changeset.cast/4
msgid "can't be blank"
msgstr ""
-## From Ecto.Changeset.unique_constraint/3
+## From Ecto.Changeset.unique_constraint/3
msgid "has already been taken"
msgstr ""
-## From Ecto.Changeset.put_change/3
+## From Ecto.Changeset.put_change/3
msgid "is invalid"
msgstr ""
-## From Ecto.Changeset.validate_acceptance/3
+## From Ecto.Changeset.validate_acceptance/3
msgid "must be accepted"
msgstr ""
-## From Ecto.Changeset.validate_format/3
+## From Ecto.Changeset.validate_format/3
msgid "has invalid format"
msgstr ""
-## From Ecto.Changeset.validate_subset/3
+## From Ecto.Changeset.validate_subset/3
msgid "has an invalid entry"
msgstr ""
-## From Ecto.Changeset.validate_exclusion/3
+## From Ecto.Changeset.validate_exclusion/3
msgid "is reserved"
msgstr ""
-## From Ecto.Changeset.validate_confirmation/3
+## From Ecto.Changeset.validate_confirmation/3
msgid "does not match confirmation"
msgstr ""
-## From Ecto.Changeset.no_assoc_constraint/3
+## From Ecto.Changeset.no_assoc_constraint/3
msgid "is still associated with this entry"
msgstr ""
msgid "are still associated with this entry"
msgstr ""
-## From Ecto.Changeset.validate_length/3
+## From Ecto.Changeset.validate_length/3
msgid "should be %{count} character(s)"
msgid_plural "should be %{count} character(s)"
msgstr[0] ""
@@ -77,7 +77,7 @@ msgid_plural "should have at most %{count} item(s)"
msgstr[0] ""
msgstr[1] ""
-## From Ecto.Changeset.validate_number/3
+## From Ecto.Changeset.validate_number/3
msgid "must be less than %{number}"
msgstr ""
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
index a29d6b9be6..63a27c7f7b 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/address_transaction_controller_test.exs
@@ -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
diff --git a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs
index 41735f685a..19631ff746 100644
--- a/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs
+++ b/apps/block_scout_web/test/block_scout_web/controllers/api/v1/health_controller_test.exs
@@ -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,19 +41,50 @@ 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 %{
- "healthy" => true,
- "data" => %{
- "latest_block_number" => _,
- "latest_block_inserted_at" => _
- }
- } = Poison.decode!(request.resp_body)
+ "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" => 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" => _
+ }
+ } = Poison.decode!(request.resp_body)
+ end
end
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex
index 1555ea6c8f..c83b157324 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/call.ex
@@ -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,
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex
index 6545250b4a..cbc43fa71d 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/geth/tracer.ex
@@ -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,
diff --git a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
index f021bfa153..7992c0e63c 100644
--- a/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
+++ b/apps/ethereum_jsonrpc/lib/ethereum_jsonrpc/transaction.ex
@@ -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
diff --git a/apps/ethereum_jsonrpc/mix.exs b/apps/ethereum_jsonrpc/mix.exs
index 7c2299c4a8..58dcff8fd5 100644
--- a/apps/ethereum_jsonrpc/mix.exs
+++ b/apps/ethereum_jsonrpc/mix.exs
@@ -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`
diff --git a/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js b/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js
index 15db7d8ff9..5c3c98f871 100644
--- a/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js
+++ b/apps/ethereum_jsonrpc/priv/js/ethereum_jsonrpc/geth/debug_traceTransaction/tracer.js
@@ -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);
}
}
-
diff --git a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs
index ad7780181d..a8a8fcdfd2 100644
--- a/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs
+++ b/apps/ethereum_jsonrpc/test/ethereum_jsonrpc/transaction_test.exs
@@ -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
diff --git a/apps/explorer/config/config.exs b/apps/explorer/config/config.exs
index defd5ae9e5..fed5124a2a 100644
--- a/apps/explorer/config/config.exs
+++ b/apps/explorer/config/config.exs
@@ -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"
diff --git a/apps/explorer/lib/explorer/chain.ex b/apps/explorer/lib/explorer/chain.ex
index 17116658bf..c2e480957d 100644
--- a/apps/explorer/lib/explorer/chain.ex
+++ b/apps/explorer/lib/explorer/chain.ex
@@ -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,22 +1827,39 @@ defmodule Explorer.Chain do
limit: 1
)
- case Repo.one(query) do
- nil ->
- {:error, :no_blocks}
+ query
+ |> Repo.one()
+ |> block_status()
+ end
- {number, timestamp} ->
- now = DateTime.utc_now()
- last_block_period = DateTime.diff(now, timestamp, :millisecond)
+ 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})
- if last_block_period > Application.get_env(:explorer, :healthy_blocks_period) do
- {:error, number, timestamp}
- else
- {:ok, number, timestamp}
- end
+ _ ->
+ block_status(nil)
end
end
+ defp block_status({number, timestamp}) do
+ now = DateTime.utc_now()
+ last_block_period = DateTime.diff(now, timestamp, :millisecond)
+
+ if last_block_period > Application.get_env(:explorer, :healthy_blocks_period) do
+ {:error, number, timestamp}
+ else
+ {:ok, number, timestamp}
+ 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
diff --git a/apps/explorer/lib/explorer/chain/internal_transaction.ex b/apps/explorer/lib/explorer/chain/internal_transaction.ex
index 1231677a57..77f7d15da2 100644
--- a/apps/explorer/lib/explorer/chain/internal_transaction.ex
+++ b/apps/explorer/lib/explorer/chain/internal_transaction.ex
@@ -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
}
diff --git a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex
index 4133dcf45f..0a13587afe 100644
--- a/apps/explorer/lib/explorer/chain/internal_transaction/type.ex
+++ b/apps/explorer/lib/explorer/chain/internal_transaction/type.ex
@@ -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
diff --git a/apps/explorer/lib/explorer/counters/average_block_time.ex b/apps/explorer/lib/explorer/counters/average_block_time.ex
index 233c15f8b3..1065ede2bd 100644
--- a/apps/explorer/lib/explorer/counters/average_block_time.ex
+++ b/apps/explorer/lib/explorer/counters/average_block_time.ex
@@ -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.
diff --git a/apps/explorer/lib/explorer/market/market_history_cache.ex b/apps/explorer/lib/explorer/market/market_history_cache.ex
index 04b6193716..4ed3d9b7d2 100644
--- a/apps/explorer/lib/explorer/market/market_history_cache.ex
+++ b/apps/explorer/lib/explorer/market/market_history_cache.ex
@@ -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
diff --git a/apps/explorer/lib/explorer/smart_contract/reader.ex b/apps/explorer/lib/explorer/smart_contract/reader.ex
index 72b40f55a4..cc3aae5e83 100644
--- a/apps/explorer/lib/explorer/smart_contract/reader.ex
+++ b/apps/explorer/lib/explorer/smart_contract/reader.ex
@@ -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,14 +59,20 @@ 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 =
- address_hash
- |> Chain.address_hash_to_smart_contract()
- |> Map.get(: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
- contract_address_hash
- |> Chain.address_hash_to_smart_contract()
- |> Map.get(:abi, [])
- |> Enum.filter(& &1["constant"])
- |> fetch_current_value_from_blockchain(contract_address_hash, [])
- |> Enum.reverse()
- end
-
- def fetch_current_value_from_blockchain(
- [%{"inputs" => []} = function | tail],
- contract_address_hash,
- acc
- ) do
- values =
- fetch_from_blockchain(contract_address_hash, %{
- name: function["name"],
- args: function["inputs"],
- outputs: function["outputs"]
- })
+ abi =
+ contract_address_hash
+ |> Chain.address_hash_to_smart_contract()
+ |> Map.get(:abi)
- formatted = Map.replace!(function, "outputs", values)
+ case abi do
+ nil ->
+ []
- fetch_current_value_from_blockchain(tail, contract_address_hash, [formatted | acc])
+ _ ->
+ abi
+ |> Enum.filter(& &1["constant"])
+ |> Enum.map(&fetch_current_value_from_blockchain(&1, abi, contract_address_hash))
+ end
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"])
+ defp fetch_current_value_from_blockchain(function, abi, contract_address_hash) do
+ values =
+ case function do
+ %{"inputs" => []} ->
+ name = function["name"]
+ args = function["inputs"]
+ outputs = function["outputs"]
+
+ contract_address_hash
+ |> query_verified_contract(%{name => normalize_args(args)}, abi)
+ |> link_outputs_and_values(outputs, name)
- formatted = Map.replace!(function, "outputs", values)
+ _ ->
+ link_outputs_and_values(%{}, Map.get(function, "outputs", []), function["name"])
+ end
- 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, [])
- |> Enum.filter(fn function -> function["name"] == name end)
- |> List.first()
-
- fetch_from_blockchain(contract_address_hash, %{
- name: name,
- args: args,
- outputs: function["outputs"]
- })
- end
+ |> Map.get(:abi)
+
+ outputs =
+ case abi do
+ nil ->
+ nil
+
+ _ ->
+ function =
+ abi
+ |> Enum.filter(fn function -> function["name"] == name end)
+ |> List.first()
+
+ 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
diff --git a/apps/explorer/mix.exs b/apps/explorer/mix.exs
index 4956363cc4..b9b887f838 100644
--- a/apps/explorer/mix.exs
+++ b/apps/explorer/mix.exs
@@ -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
diff --git a/apps/explorer/test/explorer/chain_test.exs b/apps/explorer/test/explorer/chain_test.exs
index 38e61dee7d..234252dbe4 100644
--- a/apps/explorer/test/explorer/chain_test.exs
+++ b/apps/explorer/test/explorer/chain_test.exs
@@ -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
diff --git a/apps/explorer/test/explorer/smart_contract/reader_test.exs b/apps/explorer/test/explorer/smart_contract/reader_test.exs
index ab63b74d1e..82f0a54385 100644
--- a/apps/explorer/test/explorer/smart_contract/reader_test.exs
+++ b/apps/explorer/test/explorer/smart_contract/reader_test.exs
@@ -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
diff --git a/rel/commands/clear_build.sh b/rel/commands/clear_build.sh
index 5faca7ffeb..a07a11870e 100755
--- a/rel/commands/clear_build.sh
+++ b/rel/commands/clear_build.sh
@@ -2,11 +2,13 @@
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)
rm -rf ./apps/block_scout_web/priv/static;;
-esac
\ No newline at end of file
+esac